Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Packages without a separate changelog are covered by the cross-package notes bel

- Cloudflare D1 no longer rejects full 100-message history reads when attachment metadata is hydrated.
- DM history query failures reach Relaycast Cloud's D1 overload handler and shared exception telemetry instead of becoming opaque route-level 500 responses.
- Node enrollment no longer lets a workspace key alone rotate, rename, reshape, or reset an established node; existing rows require proof of their current node token while genuinely new node IDs remain enrollable. Keyed rotations retain a bounded, request-bound recovery record so a lost committed response returns the same replacement token on retry. Hosts must apply `0063_node_rotation_recovery.sql` before upgrading.
- Node enrollment no longer lets a workspace key alone rotate, rename, reshape, or reset an established node; existing rows require proof of their current node token while genuinely new node IDs remain enrollable. Keyed rotations retain a bounded, request-bound recovery record so a lost committed response returns the same replacement token on retry. Hosts must apply `0066_node_rotation_recovery.sql` before upgrading.
- Direct-message idempotency is now enforced atomically across direct and A2A routing, so concurrent retries reaching different server isolates cannot create duplicate rows or lose post-commit notification recovery.
- Server telemetry events can no longer be emitted with an unlisted name, a missing required property, or an overridden `workspace_id`, any of which made hosted ingestion silently drop them.
- Fix webhook listing responses so published SDKs can deserialize them, restoring webhook cleanup for integrations.
Expand Down
4 changes: 2 additions & 2 deletions packages/engine/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ and this project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.ht

- DM, channel, thread, and delivery attachment hydration splits large message-ID lookups into D1-safe chunks, so full 100-message history pages stay within Cloudflare D1's bound-parameter limit.
- `GET /v1/dm/:conversation_id/messages` lets query failures reach the global error handler for exception telemetry and host-specific error classification.
- `POST /v1/nodes` requires an established node's current token in `X-Relaycast-Node-Token` before rotating or modifying the row; workspace-key-only enrollment remains valid for genuinely new nodes and returns `409 node_token_proof_required` without mutation for existing rows. A high-entropy `Idempotency-Key` binds the prior proof and exact request for 24 hours so a retry after a lost committed response recovers the same replacement token without another mutation. Hosts must apply `0063_node_rotation_recovery.sql` before upgrading.
- `POST /v1/dm` admits one idempotency claim and durable notification state atomically across direct and A2A routing, preventing concurrent retries on different server isolates from creating duplicate messages or losing post-commit recovery. Hosts must apply `0062_direct_dm_idempotency.sql` before upgrading.
- `POST /v1/nodes` requires an established node's current token in `X-Relaycast-Node-Token` before rotating or modifying the row; workspace-key-only enrollment remains valid for genuinely new nodes and returns `409 node_token_proof_required` without mutation for existing rows. A high-entropy `Idempotency-Key` binds the prior proof and exact request for 24 hours so a retry after a lost committed response recovers the same replacement token without another mutation. Hosts must apply `0066_node_rotation_recovery.sql` before upgrading.
- `POST /v1/dm` admits one idempotency claim and durable notification state atomically across direct and A2A routing, preventing concurrent retries on different server isolates from creating duplicate messages or losing post-commit recovery. Hosts must apply `0065_direct_dm_idempotency.sql` before upgrading.
- `emitServerEvent` only accepts `SERVER_TELEMETRY_EVENTS` names and requires each event's required properties at compile time; `workspace_id` always comes from the `workspaceId` argument.
- `GET /v1/webhooks` returns `workspace_id`, `channel_id`, `channel_name`, and `created_by` for SDK compatibility while retaining `channel` for existing REST clients.

Expand Down
4 changes: 2 additions & 2 deletions packages/engine/src/db/__tests__/compactMigrations.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ function snapshot(handle: SqliteDbHandle) {
const { status_updated_at: _statusUpdatedAt, ...existing } = row as Record<string, unknown>;
return JSON.stringify(existing);
}
// 0063 adds only bounded node-rotation recovery metadata. Exclude those
// 0066 adds only bounded node-rotation recovery metadata. Exclude those
// nullable fields so this comparison remains byte-for-byte over every
// pre-existing value while the explicit schema assertions below cover
// the new columns.
Expand Down Expand Up @@ -118,7 +118,7 @@ function expectConstraintsPreserved(before: ReturnType<typeof constraints>, afte
if (table.name === 'agents' && original) {
return { ...table, sql: original.sql };
}
// 0063 appends four nullable recovery fields. Remove only their exact
// 0066 appends four nullable recovery fields. Remove only their exact
// additive DDL so changes to every pre-existing node constraint remain
// visible to this preservation assertion.
if (table.name === 'nodes') {
Expand Down
4 changes: 2 additions & 2 deletions packages/engine/src/db/__tests__/taskMigration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ it('upgrades existing actions and results additively, preserving rows and every
expect(runMigrations(handle).applied).toEqual([
'0060_durable_task_invocations.sql',
'0061_messages_workspace_length_id_index.sql',
'0062_direct_dm_idempotency.sql',
'0063_node_rotation_recovery.sql',
'0065_direct_dm_idempotency.sql',
'0066_node_rotation_recovery.sql',
]);
for (const table of before) {
const columns = db.pragma(`table_info(${table.name})`) as { name: string }[];
Expand Down
Loading