@relaycast/engine 9.0.0 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/node/event-queue.d.ts +7 -2
- package/dist/adapters/node/event-queue.d.ts.map +1 -1
- package/dist/adapters/node/event-queue.js +19 -4
- package/dist/adapters/node/event-queue.js.map +1 -1
- package/dist/adapters/node/index.d.ts.map +1 -1
- package/dist/adapters/node/index.js +18 -2
- package/dist/adapters/node/index.js.map +1 -1
- package/dist/adapters/node/ssrf-fetch.d.ts +12 -0
- package/dist/adapters/node/ssrf-fetch.d.ts.map +1 -0
- package/dist/adapters/node/ssrf-fetch.js +81 -0
- package/dist/adapters/node/ssrf-fetch.js.map +1 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +16 -4
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/workspaceExpiry.d.ts +28 -0
- package/dist/auth/workspaceExpiry.d.ts.map +1 -0
- package/dist/auth/workspaceExpiry.js +39 -0
- package/dist/auth/workspaceExpiry.js.map +1 -0
- package/dist/db/migrations/0064_action_invocations_status_dispatched_index.sql +9 -0
- package/dist/db/migrations/0065_action_invocations_task_deadline_any_status.sql +10 -0
- package/dist/db/migrations/0066_action_invocations_status_sweep_ranges.sql +15 -0
- package/dist/db/migrations/0067_webhook_delivery_reliability.sql +37 -0
- package/dist/db/schema.d.ts +225 -0
- package/dist/db/schema.d.ts.map +1 -1
- package/dist/db/schema.js +39 -1
- package/dist/db/schema.js.map +1 -1
- package/dist/engine/dm.d.ts.map +1 -1
- package/dist/engine/dm.js +9 -1
- package/dist/engine/dm.js.map +1 -1
- package/dist/engine/eventDelivery.d.ts +50 -1
- package/dist/engine/eventDelivery.d.ts.map +1 -1
- package/dist/engine/eventDelivery.js +435 -75
- package/dist/engine/eventDelivery.js.map +1 -1
- package/dist/engine/eventDispatch.d.ts.map +1 -1
- package/dist/engine/eventDispatch.js +2 -0
- package/dist/engine/eventDispatch.js.map +1 -1
- package/dist/engine/eventQueue.d.ts +3 -2
- package/dist/engine/eventQueue.d.ts.map +1 -1
- package/dist/engine/eventQueue.js +9 -4
- package/dist/engine/eventQueue.js.map +1 -1
- package/dist/engine/eventSubscription.d.ts +5 -0
- package/dist/engine/eventSubscription.d.ts.map +1 -1
- package/dist/engine/eventSubscription.js +4 -0
- package/dist/engine/eventSubscription.js.map +1 -1
- package/dist/engine/httpPushDispatch.d.ts +1 -0
- package/dist/engine/httpPushDispatch.d.ts.map +1 -1
- package/dist/engine/httpPushDispatch.js +21 -8
- package/dist/engine/httpPushDispatch.js.map +1 -1
- package/dist/engine/invocationCompletion.d.ts.map +1 -1
- package/dist/engine/invocationCompletion.js +2 -0
- package/dist/engine/invocationCompletion.js.map +1 -1
- package/dist/engine/nodeContext.d.ts +1 -0
- package/dist/engine/nodeContext.d.ts.map +1 -1
- package/dist/engine/nodeContext.js +1 -0
- package/dist/engine/nodeContext.js.map +1 -1
- package/dist/engine/nodeDeliver.d.ts +1 -0
- package/dist/engine/nodeDeliver.d.ts.map +1 -1
- package/dist/engine/nodeDeliver.js +1 -0
- package/dist/engine/nodeDeliver.js.map +1 -1
- package/dist/engine/workspace.d.ts +7 -0
- package/dist/engine/workspace.d.ts.map +1 -1
- package/dist/engine/workspace.js +11 -0
- package/dist/engine/workspace.js.map +1 -1
- package/dist/engine/wsAuth.d.ts +2 -1
- package/dist/engine/wsAuth.d.ts.map +1 -1
- package/dist/engine/wsAuth.js +27 -2
- package/dist/engine/wsAuth.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/ssrf.d.ts +16 -17
- package/dist/lib/ssrf.d.ts.map +1 -1
- package/dist/lib/ssrf.js +160 -46
- package/dist/lib/ssrf.js.map +1 -1
- package/dist/lib/standardWebhook.d.ts +15 -0
- package/dist/lib/standardWebhook.d.ts.map +1 -0
- package/dist/lib/standardWebhook.js +89 -0
- package/dist/lib/standardWebhook.js.map +1 -0
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +3 -2
- package/dist/middleware/auth.js.map +1 -1
- package/dist/ports/index.d.ts +6 -0
- package/dist/ports/index.d.ts.map +1 -1
- package/dist/routes/a2a.d.ts.map +1 -1
- package/dist/routes/a2a.js +9 -1
- package/dist/routes/a2a.js.map +1 -1
- package/dist/routes/action.js +1 -0
- package/dist/routes/action.js.map +1 -1
- package/dist/routes/agent.d.ts.map +1 -1
- package/dist/routes/agent.js +12 -1
- package/dist/routes/agent.js.map +1 -1
- package/dist/routes/deliveryRouting.d.ts.map +1 -1
- package/dist/routes/deliveryRouting.js +3 -2
- package/dist/routes/deliveryRouting.js.map +1 -1
- package/dist/routes/eventSubscription.d.ts.map +1 -1
- package/dist/routes/eventSubscription.js +64 -3
- package/dist/routes/eventSubscription.js.map +1 -1
- package/dist/routes/node.d.ts.map +1 -1
- package/dist/routes/node.js +15 -1
- package/dist/routes/node.js.map +1 -1
- package/dist/routes/reaction.js +2 -0
- package/dist/routes/reaction.js.map +1 -1
- package/dist/routes/receipt.js +1 -0
- package/dist/routes/receipt.js.map +1 -1
- package/dist/routes/workspace.d.ts.map +1 -1
- package/dist/routes/workspace.js +2 -1
- package/dist/routes/workspace.js.map +1 -1
- package/package.json +4 -4
|
@@ -22,14 +22,18 @@ export interface DurableEventQueueOptions {
|
|
|
22
22
|
* `defaults.messageTtlDays` (self-host: `RELAYCAST_MESSAGE_TTL_DAYS`).
|
|
23
23
|
*/
|
|
24
24
|
retention?: PruneOptions | false;
|
|
25
|
+
/** Platform fetch hardened for outbound webhooks (Node pins validated DNS answers). */
|
|
26
|
+
fetch?: typeof globalThis.fetch;
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
27
29
|
* Durable webhook delivery for self-host, replacing the Cloudflare Queue + DLQ.
|
|
28
30
|
* `send` persists a `pending_events` outbox row first, then a background poller
|
|
29
31
|
* claims due rows and fans them out via `deliverEvent` (HMAC signing and
|
|
30
|
-
* retryable-vs-terminal classification unchanged). Success
|
|
31
|
-
* terminal failures settle it as `failed`; retryable failures back off
|
|
32
|
+
* retryable-vs-terminal classification unchanged). Success settles the row as
|
|
33
|
+
* `completed`; terminal failures settle it as `failed`; retryable failures back off
|
|
32
34
|
* exponentially and survive process restarts — `start()` resumes whatever is due.
|
|
35
|
+
* A platform SSRF-safe `fetch` is mandatory; `createNodeRuntime` supplies the
|
|
36
|
+
* DNS-pinning Node implementation.
|
|
33
37
|
*/
|
|
34
38
|
export declare class DurableEventQueue implements EventQueue {
|
|
35
39
|
private readonly db;
|
|
@@ -41,6 +45,7 @@ export declare class DurableEventQueue implements EventQueue {
|
|
|
41
45
|
private readonly batchSize;
|
|
42
46
|
private readonly cleanupIntervalMs;
|
|
43
47
|
private readonly retention;
|
|
48
|
+
private readonly fetchImpl;
|
|
44
49
|
private timer;
|
|
45
50
|
private polling;
|
|
46
51
|
private stopped;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-queue.d.ts","sourceRoot":"","sources":["../../../src/adapters/node/event-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAYxD,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"event-queue.d.ts","sourceRoot":"","sources":["../../../src/adapters/node/event-queue.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC1E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAYxD,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAU5E,MAAM,WAAW,wBAAwB;IACvC,mGAAmG;IACnG,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,6CAA6C;IAC7C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mGAAmG;IACnG,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oEAAoE;IACpE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,YAAY,GAAG,KAAK,CAAC;IACjC,uFAAuF;IACvF,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAED;;;;;;;;;GASG;AACH,qBAAa,iBAAkB,YAAW,UAAU;IAehD,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAf1B,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAS;IACvC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAuB;IACjD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA0B;IACpD,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,aAAa,CAAK;gBAGP,EAAE,EAAE,QAAQ,EACZ,OAAO,GAAE,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAe,EACzF,OAAO,GAAE,wBAA6B;IAexC;;;;;;;;OAQG;IACG,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAO/C,+FAA+F;IAC/F,KAAK,IAAI,IAAI;IAYb,kEAAkE;IAClE,IAAI,IAAI,IAAI;IAMZ;;;;OAIG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAsBb,OAAO;YAyCP,YAAY;CAe3B;AAED,OAAO,EAAE,iBAAiB,IAAI,mBAAmB,EAAE,CAAC;AACpD,MAAM,MAAM,0BAA0B,GAAG,wBAAwB,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { deliverEvent } from '../../engine/eventDelivery.js';
|
|
2
2
|
import { enqueueEvent, claimDueEvents, completeEvent, failEvent, failExhaustedDueEvents, rescheduleEvent, cleanupOldEvents, } from '../../engine/eventQueue.js';
|
|
3
3
|
import { pruneExpired } from '../../engine/retention.js';
|
|
4
|
+
import { asCodedError } from '../../lib/httpError.js';
|
|
4
5
|
const DEFAULT_POLL_INTERVAL_MS = 5_000;
|
|
5
6
|
const DEFAULT_BASE_BACKOFF_MS = 30_000;
|
|
6
7
|
const DEFAULT_MAX_BACKOFF_MS = 15 * 60_000;
|
|
@@ -11,9 +12,11 @@ const DEFAULT_CLEANUP_INTERVAL_MS = 60 * 60_000;
|
|
|
11
12
|
* Durable webhook delivery for self-host, replacing the Cloudflare Queue + DLQ.
|
|
12
13
|
* `send` persists a `pending_events` outbox row first, then a background poller
|
|
13
14
|
* claims due rows and fans them out via `deliverEvent` (HMAC signing and
|
|
14
|
-
* retryable-vs-terminal classification unchanged). Success
|
|
15
|
-
* terminal failures settle it as `failed`; retryable failures back off
|
|
15
|
+
* retryable-vs-terminal classification unchanged). Success settles the row as
|
|
16
|
+
* `completed`; terminal failures settle it as `failed`; retryable failures back off
|
|
16
17
|
* exponentially and survive process restarts — `start()` resumes whatever is due.
|
|
18
|
+
* A platform SSRF-safe `fetch` is mandatory; `createNodeRuntime` supplies the
|
|
19
|
+
* DNS-pinning Node implementation.
|
|
17
20
|
*/
|
|
18
21
|
export class DurableEventQueue {
|
|
19
22
|
db;
|
|
@@ -25,6 +28,7 @@ export class DurableEventQueue {
|
|
|
25
28
|
batchSize;
|
|
26
29
|
cleanupIntervalMs;
|
|
27
30
|
retention;
|
|
31
|
+
fetchImpl;
|
|
28
32
|
timer;
|
|
29
33
|
polling = false;
|
|
30
34
|
stopped = false;
|
|
@@ -39,6 +43,10 @@ export class DurableEventQueue {
|
|
|
39
43
|
this.batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
40
44
|
this.cleanupIntervalMs = options.cleanupIntervalMs ?? DEFAULT_CLEANUP_INTERVAL_MS;
|
|
41
45
|
this.retention = options.retention ?? {};
|
|
46
|
+
if (!options.fetch) {
|
|
47
|
+
throw new Error('DurableEventQueue requires an SSRF-safe fetch implementation');
|
|
48
|
+
}
|
|
49
|
+
this.fetchImpl = options.fetch;
|
|
42
50
|
}
|
|
43
51
|
/**
|
|
44
52
|
* Persist the outbox row first (awaited — the event is durable once `send`
|
|
@@ -107,7 +115,11 @@ export class DurableEventQueue {
|
|
|
107
115
|
}
|
|
108
116
|
async process(event) {
|
|
109
117
|
try {
|
|
110
|
-
const summary = await deliverEvent(this.db, event.workspaceId, event.eventType, event.payload
|
|
118
|
+
const summary = await deliverEvent(this.db, event.workspaceId, event.eventType, event.payload, {
|
|
119
|
+
eventId: event.id,
|
|
120
|
+
eventTimestamp: event.createdAt,
|
|
121
|
+
fetch: this.fetchImpl,
|
|
122
|
+
});
|
|
111
123
|
if (summary.failed > 0) {
|
|
112
124
|
// deliverEvent resolved with failures and no retryables — terminal
|
|
113
125
|
// (non-408/429 4xx). Settle the row; retrying won't change the outcome.
|
|
@@ -132,7 +144,10 @@ export class DurableEventQueue {
|
|
|
132
144
|
});
|
|
133
145
|
}
|
|
134
146
|
else {
|
|
135
|
-
const
|
|
147
|
+
const diagnosticBackoff = asCodedError(err).diagnostics?.retry_after_ms;
|
|
148
|
+
const backoff = typeof diagnosticBackoff === 'number'
|
|
149
|
+
? diagnosticBackoff
|
|
150
|
+
: Math.min(this.baseBackoffMs * 2 ** (event.attempts - 1), this.maxBackoffMs);
|
|
136
151
|
await rescheduleEvent(this.db, event.id, message, backoff);
|
|
137
152
|
}
|
|
138
153
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-queue.js","sourceRoot":"","sources":["../../../src/adapters/node/event-queue.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAC7D,OAAO,EACL,YAAY,EACZ,cAAc,EACd,aAAa,EACb,SAAS,EACT,sBAAsB,EACtB,eAAe,EACf,gBAAgB,GAEjB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,YAAY,EAAqB,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"event-queue.js","sourceRoot":"","sources":["../../../src/adapters/node/event-queue.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/node/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAI9D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AACzG,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/node/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAI9D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,KAAK,wBAAwB,EAAE,MAAM,eAAe,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,KAAK,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AACzG,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAUzF,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,gBAAgB,EAChB,sBAAsB,EACtB,iBAAiB,EACjB,WAAW,EACX,aAAa,GACd,CAAC;AACF,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAChE,YAAY,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,YAAY,EAAE,wBAAwB,EAAE,MAAM,eAAe,CAAC;AAC9D,YAAY,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,kBAAkB,CAAC;AAE7F,MAAM,WAAW,kBAAkB;IACjC,iDAAiD;IACjD,MAAM,EAAE,MAAM,CAAC;IACf,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,6EAA6E;IAC7E,YAAY,CAAC,EAAE,oBAAoB,CAAC;IACpC,oDAAoD;IACpD,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,2IAA2I;IAC3I,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,6DAA6D;IAC7D,QAAQ,CAAC,EAAE,wBAAwB,CAAC;IACpC,+EAA+E;IAC/E,UAAU,CAAC,EAAE,wBAAwB,CAAC;CACvC;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,QAAQ,EAAE,iBAAiB,CAAC;IAC5B,yFAAyF;IACzF,YAAY,EAAE,iBAAiB,CAAC;IAChC,mFAAmF;IACnF,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACrD,MAAM,EAAE,cAAc,CAAC;IACvB,gDAAgD;IAChD,KAAK,IAAI,IAAI,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,WAAW,CA2I1E"}
|
|
@@ -16,6 +16,7 @@ import { sendNodePresenceContext } from '../../engine/nodeContext.js';
|
|
|
16
16
|
import { createDeliveryMaintenanceRunner } from './delivery-maintenance.js';
|
|
17
17
|
import { sweepPendingA2aEgress } from '../../engine/a2aEgress.js';
|
|
18
18
|
import { reapExpiredWorkspaces } from '../../engine/workspace.js';
|
|
19
|
+
import { createNodeOutboundWebhookFetch } from './ssrf-fetch.js';
|
|
19
20
|
export { InProcessRealtime, InProcessPresence, InProcessRateLimiter, InProcessKeyValueStore, InProcessEventQueue, DurableEventQueue, LocalFileStorage, createFileRouteHandler, FILE_ROUTE_PREFIX, getSqliteDb, runMigrations, };
|
|
20
21
|
/**
|
|
21
22
|
* Construct the in-process Node + SQLite runtime. Wires the realtime bus to the
|
|
@@ -39,6 +40,12 @@ export function createNodeRuntime(options) {
|
|
|
39
40
|
}
|
|
40
41
|
const db = handle.db;
|
|
41
42
|
const telemetry = options.telemetry ?? new NoopTelemetrySink();
|
|
43
|
+
const testEnvironment = options.config?.environment === 'test';
|
|
44
|
+
const testFetch = (input, init) => globalThis.fetch(input, init);
|
|
45
|
+
const outboundWebhookFetch = options.config?.outboundWebhookFetch
|
|
46
|
+
?? (testEnvironment
|
|
47
|
+
? testFetch
|
|
48
|
+
: createNodeOutboundWebhookFetch(options.config?.httpPushProxy?.url));
|
|
42
49
|
const realtime = new InProcessRealtime(db);
|
|
43
50
|
const upstreamOnPresenceEvent = options.presence?.onPresenceEvent;
|
|
44
51
|
const presence = new InProcessPresence(realtime, {
|
|
@@ -53,7 +60,15 @@ export function createNodeRuntime(options) {
|
|
|
53
60
|
// Fire-and-forget: presence broadcasts/offline sweeps await this handler,
|
|
54
61
|
// so a slow or black-holed http_push receiver must not stall them. WS
|
|
55
62
|
// context sends are in-memory; the http_push POST runs detached.
|
|
56
|
-
void sendNodePresenceContext({
|
|
63
|
+
void sendNodePresenceContext({
|
|
64
|
+
db,
|
|
65
|
+
nodeConnections: realtime,
|
|
66
|
+
realtime,
|
|
67
|
+
workspaceId,
|
|
68
|
+
environment: options.config?.environment,
|
|
69
|
+
httpPushProxy: options.config?.httpPushProxy,
|
|
70
|
+
outboundWebhookFetch,
|
|
71
|
+
}, {
|
|
57
72
|
subjectAgentId,
|
|
58
73
|
event: eventType,
|
|
59
74
|
data: {
|
|
@@ -67,7 +82,7 @@ export function createNodeRuntime(options) {
|
|
|
67
82
|
const rateLimiter = new InProcessRateLimiter();
|
|
68
83
|
const kv = new InProcessKeyValueStore();
|
|
69
84
|
const fileStorage = new LocalFileStorage(options.fileDir ?? `${process.cwd()}/relaycast-files`, options.baseUrl, options.fileSecret ?? randomBytes(32).toString('hex'));
|
|
70
|
-
const webhookQueue = new DurableEventQueue(db, (err, ctx) => telemetry.captureException(err, ctx), options.eventQueue);
|
|
85
|
+
const webhookQueue = new DurableEventQueue(db, (err, ctx) => telemetry.captureException(err, ctx), { ...options.eventQueue, fetch: options.eventQueue?.fetch ?? outboundWebhookFetch });
|
|
71
86
|
// Resume any deliveries left over from a previous process (the outbox's point).
|
|
72
87
|
webhookQueue.start();
|
|
73
88
|
const auth = options.auth ?? new SqliteApiKeyAuthProvider();
|
|
@@ -81,6 +96,7 @@ export function createNodeRuntime(options) {
|
|
|
81
96
|
: retentionOptions?.defaults?.messageTtlDays ?? null;
|
|
82
97
|
const config = {
|
|
83
98
|
...options.config,
|
|
99
|
+
outboundWebhookFetch,
|
|
84
100
|
retention: options.config?.retention ?? { messageTtlDays },
|
|
85
101
|
};
|
|
86
102
|
const deps = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/node/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAK1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,0BAA0B,EAAE,MAAM,wCAAwC,CAAC;AACpF,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAuB,MAAM,eAAe,CAAC;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAiC,MAAM,eAAe,CAAC;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAiC,MAAM,kBAAkB,CAAC;AACzG,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AACzF,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAC;AACtE,OAAO,EAAE,+BAA+B,EAAE,MAAM,2BAA2B,CAAC;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/node/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { fetch as undiciFetch } from 'undici';
|
|
2
|
+
/** HTTPS-only fetch whose connector validates and pins DNS answers at connect time. */
|
|
3
|
+
export declare function createNodeSafeWebhookFetch(fetchImpl?: typeof undiciFetch): typeof globalThis.fetch;
|
|
4
|
+
export declare const nodeSafeWebhookFetch: typeof fetch;
|
|
5
|
+
/**
|
|
6
|
+
* Keep direct webhook connections on the DNS-pinning transport while allowing
|
|
7
|
+
* an exact operator-configured egress proxy URL to use the platform transport.
|
|
8
|
+
* The proxy is a trusted deployment boundary and may intentionally be private
|
|
9
|
+
* or plain HTTP; untrusted node destinations are validated before proxying.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createNodeOutboundWebhookFetch(proxyUrl?: string, safeFetch?: typeof globalThis.fetch, proxyFetch?: typeof globalThis.fetch): typeof globalThis.fetch;
|
|
12
|
+
//# sourceMappingURL=ssrf-fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssrf-fetch.d.ts","sourceRoot":"","sources":["../../../src/adapters/node/ssrf-fetch.ts"],"names":[],"mappings":"AACA,OAAO,EAAS,KAAK,IAAI,WAAW,EAAyC,MAAM,QAAQ,CAAC;AAiC5F,uFAAuF;AACvF,wBAAgB,0BAA0B,CACxC,SAAS,GAAE,OAAO,WAAyB,GAC1C,OAAO,UAAU,CAAC,KAAK,CAmBzB;AAED,eAAO,MAAM,oBAAoB,cAA+B,CAAC;AAejE;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,CAAC,EAAE,MAAM,EACjB,SAAS,GAAE,OAAO,UAAU,CAAC,KAA4B,EACzD,UAAU,GAAE,OAAO,UAAU,CAAC,KAAwB,GACrD,OAAO,UAAU,CAAC,KAAK,CAQzB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { lookup } from 'node:dns';
|
|
2
|
+
import { Agent, fetch as undiciFetch } from 'undici';
|
|
3
|
+
import { isGlobalIpAddress, isSafeExternalUrl } from '../../lib/ssrf.js';
|
|
4
|
+
const dispatcher = new Agent({
|
|
5
|
+
connect: {
|
|
6
|
+
// This callback is the connection's DNS lookup, not a preflight lookup.
|
|
7
|
+
// Undici therefore opens the socket to the exact address classified here
|
|
8
|
+
// while preserving the URL hostname for Host/SNI/TLS verification.
|
|
9
|
+
lookup(hostname, options, callback) {
|
|
10
|
+
lookup(hostname, { all: true, verbatim: true }, (error, addresses) => {
|
|
11
|
+
if (error) {
|
|
12
|
+
callback(error, '', 0);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
const unsafe = addresses.find((entry) => !isGlobalIpAddress(entry.address));
|
|
16
|
+
if (unsafe || addresses.length === 0) {
|
|
17
|
+
const rejection = Object.assign(new Error(`Outbound webhook DNS resolved to a non-global address for ${hostname}`), { code: 'ENOTFOUND' });
|
|
18
|
+
callback(rejection, '', 0);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (options.all) {
|
|
22
|
+
callback(null, addresses);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
callback(null, addresses[0].address, addresses[0].family);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
/** HTTPS-only fetch whose connector validates and pins DNS answers at connect time. */
|
|
32
|
+
export function createNodeSafeWebhookFetch(fetchImpl = undiciFetch) {
|
|
33
|
+
return async (input, init) => {
|
|
34
|
+
const rawUrl = typeof input === 'string'
|
|
35
|
+
? input
|
|
36
|
+
: input instanceof URL
|
|
37
|
+
? input.toString()
|
|
38
|
+
: input.url;
|
|
39
|
+
if (!isSafeExternalUrl(rawUrl, { strict: true, requireHttps: true })) {
|
|
40
|
+
throw new Error('Unsafe outbound webhook URL');
|
|
41
|
+
}
|
|
42
|
+
const requestInput = input instanceof Request
|
|
43
|
+
? input
|
|
44
|
+
: rawUrl;
|
|
45
|
+
return fetchImpl(requestInput, {
|
|
46
|
+
...init,
|
|
47
|
+
redirect: 'manual',
|
|
48
|
+
dispatcher,
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export const nodeSafeWebhookFetch = createNodeSafeWebhookFetch();
|
|
53
|
+
function normalizedUrl(input) {
|
|
54
|
+
try {
|
|
55
|
+
const rawUrl = typeof input === 'string'
|
|
56
|
+
? input
|
|
57
|
+
: input instanceof URL
|
|
58
|
+
? input.toString()
|
|
59
|
+
: input.url;
|
|
60
|
+
return new URL(rawUrl).href;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Keep direct webhook connections on the DNS-pinning transport while allowing
|
|
68
|
+
* an exact operator-configured egress proxy URL to use the platform transport.
|
|
69
|
+
* The proxy is a trusted deployment boundary and may intentionally be private
|
|
70
|
+
* or plain HTTP; untrusted node destinations are validated before proxying.
|
|
71
|
+
*/
|
|
72
|
+
export function createNodeOutboundWebhookFetch(proxyUrl, safeFetch = nodeSafeWebhookFetch, proxyFetch = globalThis.fetch) {
|
|
73
|
+
const trustedProxyUrl = proxyUrl ? normalizedUrl(proxyUrl) : null;
|
|
74
|
+
return (input, init) => {
|
|
75
|
+
if (trustedProxyUrl && normalizedUrl(input) === trustedProxyUrl) {
|
|
76
|
+
return proxyFetch(input, { ...init, redirect: 'manual' });
|
|
77
|
+
}
|
|
78
|
+
return safeFetch(input, init);
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=ssrf-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssrf-fetch.js","sourceRoot":"","sources":["../../../src/adapters/node/ssrf-fetch.ts"],"names":[],"mappings":"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"}
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { AuthProvider, AuthResult, AuthRequire } from '../ports/auth.js';
|
|
2
2
|
import type { EngineDb } from '../ports/database.js';
|
|
3
|
+
export { isWorkspaceExpired, authenticateUnexpired, workspaceExpiredAuthResult, WORKSPACE_EXPIRED_CODE, WORKSPACE_EXPIRED_MESSAGE, } from './workspaceExpiry.js';
|
|
3
4
|
/** SHA-256 hash of a raw token to its stored form. */
|
|
4
5
|
export declare function hashToken(token: string): Promise<string>;
|
|
5
6
|
/**
|
package/dist/auth/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC9E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAIrD,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,0BAA0B,EAC1B,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAE9B,sDAAsD;AACtD,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAExD;AAmBD;;;;;;;GAOG;AACH,qBAAa,wBAAyB,YAAW,YAAY;IAC3D,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAInC,YAAY,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,WAAW,CAAC;QAAC,EAAE,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC,UAAU,CAAC;CA0DrG"}
|
package/dist/auth/index.js
CHANGED
|
@@ -3,6 +3,8 @@ import { workspaces, agents, nodes } from '../db/schema.js';
|
|
|
3
3
|
import { sha256Hex } from '../lib/crypto.js';
|
|
4
4
|
import { getActiveObserverTokenByHash } from '../engine/observerToken.js';
|
|
5
5
|
import { parseAuthToken, validateTokenRequirement } from './tokenKind.js';
|
|
6
|
+
import { isWorkspaceExpired, workspaceExpiredAuthResult } from './workspaceExpiry.js';
|
|
7
|
+
export { isWorkspaceExpired, authenticateUnexpired, workspaceExpiredAuthResult, WORKSPACE_EXPIRED_CODE, WORKSPACE_EXPIRED_MESSAGE, } from './workspaceExpiry.js';
|
|
6
8
|
/** SHA-256 hash of a raw token to its stored form. */
|
|
7
9
|
export function hashToken(token) {
|
|
8
10
|
return sha256Hex(token);
|
|
@@ -10,6 +12,16 @@ export function hashToken(token) {
|
|
|
10
12
|
function unauthorized(message, code = 'unauthorized') {
|
|
11
13
|
return { ok: false, status: 401, code, message };
|
|
12
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Admit a resolved workspace only while it is live. An expiring workspace is a
|
|
17
|
+
* room boundary for its callers, so every credential that resolves to it stops
|
|
18
|
+
* working at `expires_at` rather than at the next reap.
|
|
19
|
+
*/
|
|
20
|
+
function resolved(workspace, extra = {}) {
|
|
21
|
+
if (isWorkspaceExpired(workspace))
|
|
22
|
+
return workspaceExpiredAuthResult();
|
|
23
|
+
return { ok: true, workspace, ...extra };
|
|
24
|
+
}
|
|
13
25
|
/**
|
|
14
26
|
* The built-in, self-host authentication provider.
|
|
15
27
|
*
|
|
@@ -37,7 +49,7 @@ export class SqliteApiKeyAuthProvider {
|
|
|
37
49
|
const [workspace] = await db.select().from(workspaces).where(eq(workspaces.apiKeyHash, hash));
|
|
38
50
|
if (!workspace)
|
|
39
51
|
return unauthorized('Invalid API key');
|
|
40
|
-
return
|
|
52
|
+
return resolved(workspace);
|
|
41
53
|
}
|
|
42
54
|
if (parsedToken.kind === 'agent') {
|
|
43
55
|
// Current slot first — the common case is a token that has not been
|
|
@@ -58,7 +70,7 @@ export class SqliteApiKeyAuthProvider {
|
|
|
58
70
|
const [workspace] = await db.select().from(workspaces).where(eq(workspaces.id, agent.workspaceId));
|
|
59
71
|
if (!workspace)
|
|
60
72
|
return unauthorized('Workspace not found');
|
|
61
|
-
return
|
|
73
|
+
return resolved(workspace, { agent });
|
|
62
74
|
}
|
|
63
75
|
if (parsedToken.kind === 'node') {
|
|
64
76
|
const [node] = await db.select().from(nodes).where(eq(nodes.tokenHash, hash));
|
|
@@ -67,7 +79,7 @@ export class SqliteApiKeyAuthProvider {
|
|
|
67
79
|
const [workspace] = await db.select().from(workspaces).where(eq(workspaces.id, node.workspaceId));
|
|
68
80
|
if (!workspace)
|
|
69
81
|
return unauthorized('Workspace not found');
|
|
70
|
-
return
|
|
82
|
+
return resolved(workspace, { node });
|
|
71
83
|
}
|
|
72
84
|
if (parsedToken.kind === 'observer') {
|
|
73
85
|
const observerToken = await getActiveObserverTokenByHash(db, hash);
|
|
@@ -76,7 +88,7 @@ export class SqliteApiKeyAuthProvider {
|
|
|
76
88
|
const [workspace] = await db.select().from(workspaces).where(eq(workspaces.id, observerToken.workspaceId));
|
|
77
89
|
if (!workspace)
|
|
78
90
|
return unauthorized('Workspace not found');
|
|
79
|
-
return
|
|
91
|
+
return resolved(workspace, { observerToken });
|
|
80
92
|
}
|
|
81
93
|
return unauthorized('Invalid token format');
|
|
82
94
|
}
|
package/dist/auth/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAG1E,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAG1E,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAEtF,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,0BAA0B,EAC1B,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,sBAAsB,CAAC;AAE9B,sDAAsD;AACtD,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;AAC1B,CAAC;AAED,SAAS,YAAY,CAAC,OAAe,EAAE,IAAI,GAAG,cAAc;IAC1D,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,SAAS,QAAQ,CACf,SAAyC,EACzC,QAAqE,EAAE;IAEvE,IAAI,kBAAkB,CAAC,SAAS,CAAC;QAAE,OAAO,0BAA0B,EAAE,CAAC;IACvE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,OAAO,wBAAwB;IACnC,SAAS,CAAC,KAAa;QACrB,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC;IAC1B,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,IAA2D;QAC5E,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC;QACpC,MAAM,WAAW,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,WAAW,EAAE,CAAC;YACjB,OAAO,YAAY,CAAC,sBAAsB,CAAC,CAAC;QAC9C,CAAC;QAED,MAAM,WAAW,GAAG,wBAAwB,CAAC,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACxE,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE,CAAC;YACpB,OAAO,YAAY,CAAC,WAAW,CAAC,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,CAAC;QAC7D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,KAAK,CAAC,CAAC;QAEpC,IAAI,WAAW,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;YACrC,MAAM,CAAC,SAAS,CAAC,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,CAAC;YAC9F,IAAI,CAAC,SAAS;gBAAE,OAAO,YAAY,CAAC,iBAAiB,CAAC,CAAC;YACvD,OAAO,QAAQ,CAAC,SAAS,CAAC,CAAC;QAC7B,CAAC;QAED,IAAI,WAAW,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACjC,oEAAoE;YACpE,sCAAsC;YACtC,IAAI,CAAC,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;YAC/E,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,sEAAsE;gBACtE,oEAAoE;gBACpE,uEAAuE;gBACvE,sCAAsC;gBACtC,CAAC,KAAK,CAAC,GAAG,MAAM,EAAE;qBACf,MAAM,EAAE;qBACR,IAAI,CAAC,MAAM,CAAC;qBACZ,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,iBAAiB,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,sBAAsB,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;YACnG,CAAC;YACD,IAAI,CAAC,KAAK;gBAAE,OAAO,YAAY,CAAC,qBAAqB,EAAE,qBAAqB,CAAC,CAAC;YAC9E,MAAM,CAAC,SAAS,CAAC,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC;YACnG,IAAI,CAAC,SAAS;gBAAE,OAAO,YAAY,CAAC,qBAAqB,CAAC,CAAC;YAC3D,OAAO,QAAQ,CAAC,SAAS,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACxC,CAAC;QAED,IAAI,WAAW,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YAChC,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;YAC9E,IAAI,CAAC,IAAI;gBAAE,OAAO,YAAY,CAAC,oBAAoB,EAAE,oBAAoB,CAAC,CAAC;YAC3E,MAAM,CAAC,SAAS,CAAC,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC;YAClG,IAAI,CAAC,SAAS;gBAAE,OAAO,YAAY,CAAC,qBAAqB,CAAC,CAAC;YAC3D,OAAO,QAAQ,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QACvC,CAAC;QAED,IAAI,WAAW,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YACpC,MAAM,aAAa,GAAG,MAAM,4BAA4B,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACnE,IAAI,CAAC,aAAa;gBAAE,OAAO,YAAY,CAAC,wBAAwB,EAAE,wBAAwB,CAAC,CAAC;YAC5F,MAAM,CAAC,SAAS,CAAC,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,EAAE,EAAE,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC;YAC3G,IAAI,CAAC,SAAS;gBAAE,OAAO,YAAY,CAAC,qBAAqB,CAAC,CAAC;YAC3D,OAAO,QAAQ,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,CAAC,CAAC;QAChD,CAAC;QAED,OAAO,YAAY,CAAC,sBAAsB,CAAC,CAAC;IAC9C,CAAC;CACF"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { AuthProvider, AuthRequire, AuthResult, Workspace } from '../ports/auth.js';
|
|
2
|
+
import type { EngineDb } from '../ports/database.js';
|
|
3
|
+
/** Error code every credential path returns for a workspace past `expires_at`. */
|
|
4
|
+
export declare const WORKSPACE_EXPIRED_CODE = "workspace_expired";
|
|
5
|
+
export declare const WORKSPACE_EXPIRED_MESSAGE = "Workspace has expired";
|
|
6
|
+
/**
|
|
7
|
+
* True once a workspace that opted into an expiry deadline has reached it.
|
|
8
|
+
*
|
|
9
|
+
* Reaping is a bounded background batch, so a workspace stays readable in the
|
|
10
|
+
* database for some time after its deadline. Authentication must not wait for
|
|
11
|
+
* that batch: expiry is the boundary callers were promised (relaycast#464).
|
|
12
|
+
*/
|
|
13
|
+
export declare function isWorkspaceExpired(workspace: Pick<Workspace, 'expiresAt'>, now?: Date): boolean;
|
|
14
|
+
export declare function workspaceExpiredAuthResult(): AuthResult;
|
|
15
|
+
/**
|
|
16
|
+
* Authenticate through `auth` and reject an expired workspace.
|
|
17
|
+
*
|
|
18
|
+
* The built-in provider already enforces this, but authentication is a hosting
|
|
19
|
+
* seam: a cloud provider backed by its own identity store must not be able to
|
|
20
|
+
* admit an expired workspace. Every credential-accepting path in the engine
|
|
21
|
+
* goes through this wrapper so the check holds whatever provider is installed.
|
|
22
|
+
*/
|
|
23
|
+
export declare function authenticateUnexpired(auth: AuthProvider, args: {
|
|
24
|
+
token: string;
|
|
25
|
+
require: AuthRequire;
|
|
26
|
+
db: EngineDb;
|
|
27
|
+
}): Promise<AuthResult>;
|
|
28
|
+
//# sourceMappingURL=workspaceExpiry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaceExpiry.d.ts","sourceRoot":"","sources":["../../src/auth/workspaceExpiry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,kFAAkF;AAClF,eAAO,MAAM,sBAAsB,sBAAsB,CAAC;AAC1D,eAAO,MAAM,yBAAyB,0BAA0B,CAAC;AAEjE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,EACvC,GAAG,GAAE,IAAiB,GACrB,OAAO,CAGT;AAED,wBAAgB,0BAA0B,IAAI,UAAU,CAOvD;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,YAAY,EAClB,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,WAAW,CAAC;IAAC,EAAE,EAAE,QAAQ,CAAA;CAAE,GAC1D,OAAO,CAAC,UAAU,CAAC,CAKrB"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** Error code every credential path returns for a workspace past `expires_at`. */
|
|
2
|
+
export const WORKSPACE_EXPIRED_CODE = 'workspace_expired';
|
|
3
|
+
export const WORKSPACE_EXPIRED_MESSAGE = 'Workspace has expired';
|
|
4
|
+
/**
|
|
5
|
+
* True once a workspace that opted into an expiry deadline has reached it.
|
|
6
|
+
*
|
|
7
|
+
* Reaping is a bounded background batch, so a workspace stays readable in the
|
|
8
|
+
* database for some time after its deadline. Authentication must not wait for
|
|
9
|
+
* that batch: expiry is the boundary callers were promised (relaycast#464).
|
|
10
|
+
*/
|
|
11
|
+
export function isWorkspaceExpired(workspace, now = new Date()) {
|
|
12
|
+
const expiresAt = workspace.expiresAt;
|
|
13
|
+
return expiresAt != null && expiresAt.getTime() <= now.getTime();
|
|
14
|
+
}
|
|
15
|
+
export function workspaceExpiredAuthResult() {
|
|
16
|
+
return {
|
|
17
|
+
ok: false,
|
|
18
|
+
status: 401,
|
|
19
|
+
code: WORKSPACE_EXPIRED_CODE,
|
|
20
|
+
message: WORKSPACE_EXPIRED_MESSAGE,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Authenticate through `auth` and reject an expired workspace.
|
|
25
|
+
*
|
|
26
|
+
* The built-in provider already enforces this, but authentication is a hosting
|
|
27
|
+
* seam: a cloud provider backed by its own identity store must not be able to
|
|
28
|
+
* admit an expired workspace. Every credential-accepting path in the engine
|
|
29
|
+
* goes through this wrapper so the check holds whatever provider is installed.
|
|
30
|
+
*/
|
|
31
|
+
export async function authenticateUnexpired(auth, args) {
|
|
32
|
+
const result = await auth.authenticate(args);
|
|
33
|
+
if (!result.ok)
|
|
34
|
+
return result;
|
|
35
|
+
if (isWorkspaceExpired(result.workspace))
|
|
36
|
+
return workspaceExpiredAuthResult();
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=workspaceExpiry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaceExpiry.js","sourceRoot":"","sources":["../../src/auth/workspaceExpiry.ts"],"names":[],"mappings":"AAGA,kFAAkF;AAClF,MAAM,CAAC,MAAM,sBAAsB,GAAG,mBAAmB,CAAC;AAC1D,MAAM,CAAC,MAAM,yBAAyB,GAAG,uBAAuB,CAAC;AAEjE;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAChC,SAAuC,EACvC,MAAY,IAAI,IAAI,EAAE;IAEtB,MAAM,SAAS,GAAG,SAAS,CAAC,SAAS,CAAC;IACtC,OAAO,SAAS,IAAI,IAAI,IAAI,SAAS,CAAC,OAAO,EAAE,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO;QACL,EAAE,EAAE,KAAK;QACT,MAAM,EAAE,GAAG;QACX,IAAI,EAAE,sBAAsB;QAC5B,OAAO,EAAE,yBAAyB;KACnC,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,IAAkB,EAClB,IAA2D;IAE3D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,MAAM,CAAC;IAC9B,IAAI,kBAAkB,CAAC,MAAM,CAAC,SAAS,CAAC;QAAE,OAAO,0BAA0B,EAAE,CAAC;IAC9E,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
-- The dispatched-invocation timeout sweep filters on
|
|
2
|
+
-- status IN (?) AND dispatched_at <= ? and had no usable index, so every run
|
|
3
|
+
-- scanned all of action_invocations (~232k rows, ~1.1 s per query in
|
|
4
|
+
-- production). D1 runs one query at a time per database, so each run queued
|
|
5
|
+
-- every other request behind it, surfacing as "D1 DB is overloaded. Requests
|
|
6
|
+
-- queued for too long." The pending retry sweep (status = ? AND
|
|
7
|
+
-- retry_after_at <= ?) also uses the status prefix. No data changes.
|
|
8
|
+
CREATE INDEX IF NOT EXISTS idx_action_invocations_status_dispatched
|
|
9
|
+
ON action_invocations(status, dispatched_at);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
-- idx_action_invocations_task_deadline (0060) is partial on
|
|
2
|
+
-- status IN ('pending', 'dispatched', 'running'). The task deadline sweep binds
|
|
3
|
+
-- those statuses as parameters, and SQLite cannot prove a bound parameter
|
|
4
|
+
-- satisfies a partial index's WHERE clause, so the sweep scanned all of
|
|
5
|
+
-- action_invocations (~232k rows, ~0.9 s per update in production). This index
|
|
6
|
+
-- keeps only the literal task_state IS NOT NULL condition, which the sweep
|
|
7
|
+
-- states verbatim. No data changes.
|
|
8
|
+
CREATE INDEX IF NOT EXISTS idx_action_invocations_task_deadline_any_status
|
|
9
|
+
ON action_invocations(json_extract(task_state, '$.deadline'))
|
|
10
|
+
WHERE task_state IS NOT NULL;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
-- 0064 and 0065 left two sweeps reading every row of a status. The pending
|
|
2
|
+
-- retry sweep (status = ? AND retry_after_at <= ?) could seek only on status,
|
|
3
|
+
-- so it visited every pending row. The task deadline sweep
|
|
4
|
+
-- (task_state IS NOT NULL AND status IN (?, ?, ?) AND deadline <= ?) was
|
|
5
|
+
-- planned through the (status, dispatched_at) index rather than the
|
|
6
|
+
-- deadline-only expression index, so it visited every live row. These indexes
|
|
7
|
+
-- give each sweep a range on its timestamp within each status, and the
|
|
8
|
+
-- deadline-only index from 0065 is dropped because this one supersedes it.
|
|
9
|
+
-- No data changes.
|
|
10
|
+
CREATE INDEX IF NOT EXISTS idx_action_invocations_status_retry_after
|
|
11
|
+
ON action_invocations(status, retry_after_at);
|
|
12
|
+
CREATE INDEX IF NOT EXISTS idx_action_invocations_status_task_deadline
|
|
13
|
+
ON action_invocations(status, json_extract(task_state, '$.deadline'))
|
|
14
|
+
WHERE task_state IS NOT NULL;
|
|
15
|
+
DROP INDEX IF EXISTS idx_action_invocations_task_deadline_any_status;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
-- Standard Webhooks remains opt-in; existing subscriptions retain the legacy
|
|
2
|
+
-- X-Relay-Signature contract.
|
|
3
|
+
ALTER TABLE event_subscriptions
|
|
4
|
+
ADD COLUMN signature_scheme TEXT NOT NULL DEFAULT 'legacy';
|
|
5
|
+
|
|
6
|
+
ALTER TABLE pending_events
|
|
7
|
+
ADD COLUMN webhook_initialized INTEGER NOT NULL DEFAULT 0;
|
|
8
|
+
|
|
9
|
+
-- One durable retry state per (outbox event, subscription). Successful
|
|
10
|
+
-- subscribers are never re-sent when another target is down, and exhausted
|
|
11
|
+
-- rows remain queryable/replayable for the parent's bounded post-settlement
|
|
12
|
+
-- retention window.
|
|
13
|
+
CREATE TABLE webhook_deliveries (
|
|
14
|
+
id TEXT PRIMARY KEY NOT NULL,
|
|
15
|
+
event_id TEXT NOT NULL REFERENCES pending_events(id) ON DELETE CASCADE,
|
|
16
|
+
subscription_id TEXT NOT NULL REFERENCES event_subscriptions(id) ON DELETE CASCADE,
|
|
17
|
+
status TEXT NOT NULL DEFAULT 'pending',
|
|
18
|
+
attempts INTEGER NOT NULL DEFAULT 0,
|
|
19
|
+
next_attempt_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
20
|
+
last_error TEXT,
|
|
21
|
+
last_status INTEGER,
|
|
22
|
+
created_at INTEGER NOT NULL DEFAULT (unixepoch()),
|
|
23
|
+
completed_at INTEGER
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
CREATE UNIQUE INDEX webhook_deliveries_event_subscription_unique
|
|
27
|
+
ON webhook_deliveries(event_id, subscription_id);
|
|
28
|
+
CREATE INDEX idx_webhook_deliveries_due
|
|
29
|
+
ON webhook_deliveries(status, next_attempt_at);
|
|
30
|
+
CREATE INDEX idx_webhook_deliveries_subscription
|
|
31
|
+
ON webhook_deliveries(subscription_id, created_at);
|
|
32
|
+
|
|
33
|
+
-- Older queued events used five parent attempts. Per-target delivery now owns
|
|
34
|
+
-- the seven-attempt retry horizon; give in-flight parents crash/lease headroom.
|
|
35
|
+
UPDATE pending_events
|
|
36
|
+
SET max_attempts = 32
|
|
37
|
+
WHERE status = 'pending' AND max_attempts < 32;
|