@4xeoz/re-entry 0.2.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.
Files changed (29) hide show
  1. package/README.md +337 -0
  2. package/node_modules/@webmcp-challenge/reentry-core/README.md +112 -0
  3. package/node_modules/@webmcp-challenge/reentry-core/package.json +38 -0
  4. package/node_modules/@webmcp-challenge/reentry-core/protocol/test-vectors/v0.1.json +47 -0
  5. package/node_modules/@webmcp-challenge/reentry-core/src/agent-adapter.mjs +438 -0
  6. package/node_modules/@webmcp-challenge/reentry-core/src/cloud-receiver-http.mjs +268 -0
  7. package/node_modules/@webmcp-challenge/reentry-core/src/host-sdk.mjs +278 -0
  8. package/node_modules/@webmcp-challenge/reentry-core/src/index.mjs +3 -0
  9. package/node_modules/@webmcp-challenge/reentry-core/src/local-connector-client.mjs +530 -0
  10. package/node_modules/@webmcp-challenge/reentry-core/src/managed-context-adapter.mjs +275 -0
  11. package/node_modules/@webmcp-challenge/reentry-core/src/protocol.mjs +845 -0
  12. package/node_modules/@webmcp-challenge/reentry-core/src/receiver-core.mjs +867 -0
  13. package/node_modules/@webmcp-challenge/reentry-core/src/receiver-delivery.mjs +613 -0
  14. package/node_modules/@webmcp-challenge/reentry-core/src/receiver-http-contract.mjs +24 -0
  15. package/node_modules/@webmcp-challenge/reentry-core/src/receiver-support.mjs +151 -0
  16. package/node_modules/@webmcp-challenge/reentry-core/src/sqlite-receiver-schema.mjs +184 -0
  17. package/node_modules/@webmcp-challenge/reentry-core/src/sqlite-receiver-store.mjs +573 -0
  18. package/package.json +44 -0
  19. package/src/browser-prompt.mjs +18 -0
  20. package/src/codex-discovery.mjs +246 -0
  21. package/src/codex-exec-adapter.mjs +197 -0
  22. package/src/codex-queue-adapter.mjs +214 -0
  23. package/src/credentials.mjs +87 -0
  24. package/src/index.mjs +6 -0
  25. package/src/local-connector.mjs +82 -0
  26. package/src/macos-service.mjs +184 -0
  27. package/src/main.mjs +733 -0
  28. package/src/pairing-client.mjs +545 -0
  29. package/src/terminal-ui.mjs +99 -0
@@ -0,0 +1,613 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ import {
4
+ PROTOCOL_VERSION,
5
+ canonicalJson,
6
+ parseContinuationEventBody,
7
+ validateContinuationReceipt,
8
+ } from "./protocol.mjs";
9
+ import {
10
+ authorization,
11
+ conflict,
12
+ deepFreeze,
13
+ invariant,
14
+ notFound,
15
+ requireExactInput,
16
+ requireIdentifier,
17
+ requireOpaqueToken,
18
+ requireTimestamp,
19
+ } from "./receiver-support.mjs";
20
+
21
+ export const CONNECTOR_IDENTITY_TYPE = "webmcp.connector_identity";
22
+ export const DELIVERY_LEASE_TYPE = "webmcp.delivery_lease";
23
+ export const HOST_EFFECT_ATTESTATION_TYPE = "webmcp.host_effect_attestation";
24
+ export const DELIVERY_ACKNOWLEDGEMENT_TYPE = "webmcp.delivery_acknowledgement";
25
+ export const HOST_EFFECT_OUTCOME = "effect_applied_awaiting_human";
26
+
27
+ const CLAIM_DELIVERY_FIELDS = Object.freeze(["connectorToken", "claimToken"]);
28
+ const ACKNOWLEDGE_DELIVERY_FIELDS = Object.freeze([
29
+ "connectorToken",
30
+ "deliveryId",
31
+ "leaseToken",
32
+ "effectToken",
33
+ ]);
34
+ const CONNECTOR_IDENTITY_FIELDS = Object.freeze([
35
+ "type",
36
+ "protocol_version",
37
+ "connector_id",
38
+ "subject_id",
39
+ "delivery_target_id",
40
+ "authenticated_at",
41
+ "expires_at",
42
+ ]);
43
+ const HOST_EFFECT_ATTESTATION_FIELDS = Object.freeze([
44
+ "type",
45
+ "protocol_version",
46
+ "effect_id",
47
+ "delivery_id",
48
+ "event_id",
49
+ "correlation_id",
50
+ "workflow_id",
51
+ "outcome",
52
+ "confirmed_at",
53
+ ]);
54
+ const DELIVERY_STORE_METHODS = Object.freeze([
55
+ "transaction",
56
+ "getDeliveryById",
57
+ "getDeliveryByEffectId",
58
+ "getDeliveryByCurrentLeaseTokenDigest",
59
+ "hasDeliveryAttemptTokenDigest",
60
+ "getActiveDeliveryByTarget",
61
+ "getNextDeliveryByTarget",
62
+ "claimDelivery",
63
+ "cancelDelivery",
64
+ "exhaustDelivery",
65
+ "acknowledgeDelivery",
66
+ ]);
67
+ const AUTHORITY_FUTURE_SKEW_MS = 60 * 1_000;
68
+ const CLAIM_TOKEN_PATTERN = /^[A-Za-z0-9_-]{43}$/;
69
+
70
+ export class ReceiverDelivery {
71
+ #store;
72
+ #connectorAuthority;
73
+ #effectAuthority;
74
+ #leaseDurationMs;
75
+ #clock;
76
+
77
+ constructor({ store, connectorAuthority, effectAuthority, leaseDurationMs, clock }) {
78
+ requireDeliveryStore(store);
79
+ if (typeof connectorAuthority?.verifyConnector !== "function") {
80
+ throw new TypeError("Receiver delivery connectorAuthority must implement verifyConnector");
81
+ }
82
+ if (typeof effectAuthority?.verifyEffect !== "function") {
83
+ throw new TypeError("Receiver delivery effectAuthority must implement verifyEffect");
84
+ }
85
+ if (!Number.isSafeInteger(leaseDurationMs) || leaseDurationMs < 1_000) {
86
+ throw new TypeError("Receiver delivery leaseDurationMs must be at least one second");
87
+ }
88
+ if (typeof clock !== "function") {
89
+ throw new TypeError("Receiver delivery clock must be a function");
90
+ }
91
+ this.#store = store;
92
+ this.#connectorAuthority = connectorAuthority;
93
+ this.#effectAuthority = effectAuthority;
94
+ this.#leaseDurationMs = leaseDurationMs;
95
+ this.#clock = clock;
96
+ }
97
+
98
+ claimDelivery(input) {
99
+ requireExactInput(
100
+ input,
101
+ CLAIM_DELIVERY_FIELDS,
102
+ CLAIM_DELIVERY_FIELDS,
103
+ "Delivery claim input",
104
+ );
105
+ const connectorToken = requireOpaqueToken(
106
+ input.connectorToken,
107
+ "Connector token",
108
+ "connector_token_invalid",
109
+ );
110
+ const claimToken = requireClaimToken(input.claimToken);
111
+ const claimTokenDigest = digestToken(claimToken);
112
+ const now = this.#readClock();
113
+ const identity = this.#verifyConnector(connectorToken, now);
114
+ const nowIso = now.toISOString();
115
+
116
+ return this.#store.transaction((transaction) => {
117
+ const replay = transaction.getDeliveryByCurrentLeaseTokenDigest(claimTokenDigest);
118
+ if (replay) {
119
+ assertConnectorScope(identity, replay);
120
+ if (replay.current_connector_id !== identity.connector_id) {
121
+ throw authorization(
122
+ "delivery_lease_scope_invalid",
123
+ "Delivery lease is owned by another Connector",
124
+ );
125
+ }
126
+ const authorityEndReason = getGrantAuthorityEndReason(replay, now);
127
+ if (replay.status === "leased" && authorityEndReason) {
128
+ const exhausted = transaction.exhaustDelivery({
129
+ delivery_id: replay.delivery_id,
130
+ expected_attempt: replay.current_attempt,
131
+ expected_connector_id: replay.current_connector_id,
132
+ expected_lease_token_digest: replay.current_lease_token_digest,
133
+ expected_lease_expires_at: replay.lease_expires_at,
134
+ reason: authorityEndReason,
135
+ updated_at: nowIso,
136
+ });
137
+ if (!exhausted) {
138
+ throw conflict("delivery_claim_race", "Delivery exhaustion claim was lost");
139
+ }
140
+ return null;
141
+ }
142
+ if (
143
+ replay.status === "leased" &&
144
+ parseStoredTimestamp(replay.lease_expires_at, "lease_expires_at") > now.getTime()
145
+ ) {
146
+ return buildDeliveryLeaseResult(replay, claimToken, true);
147
+ }
148
+ throw conflict("claim_token_retired", "Delivery claim token is no longer claimable");
149
+ }
150
+
151
+ if (transaction.hasDeliveryAttemptTokenDigest(claimTokenDigest)) {
152
+ throw conflict("claim_token_retired", "Delivery claim token was already used");
153
+ }
154
+ if (transaction.getActiveDeliveryByTarget(identity.delivery_target_id, nowIso)) {
155
+ return null;
156
+ }
157
+
158
+ const candidate = transaction.getNextDeliveryByTarget(
159
+ identity.delivery_target_id,
160
+ nowIso,
161
+ );
162
+ if (!candidate) return null;
163
+ assertConnectorScope(identity, candidate);
164
+
165
+ const authorityEndReason = getGrantAuthorityEndReason(candidate, now);
166
+ if (candidate.status === "pending") {
167
+ if (candidate.current_attempt !== 0) {
168
+ throw invariant("delivery_state_invalid", "Pending delivery has an invalid attempt count");
169
+ }
170
+ if (authorityEndReason) {
171
+ const cancelled = transaction.cancelDelivery({
172
+ delivery_id: candidate.delivery_id,
173
+ reason: authorityEndReason,
174
+ updated_at: nowIso,
175
+ });
176
+ if (!cancelled) {
177
+ throw conflict("delivery_claim_race", "Delivery cancellation claim was lost");
178
+ }
179
+ return null;
180
+ }
181
+ } else if (candidate.status === "leased") {
182
+ if (parseStoredTimestamp(candidate.lease_expires_at, "lease_expires_at") > now.getTime()) {
183
+ throw invariant("delivery_state_invalid", "Claim candidate still has an active lease");
184
+ }
185
+ if (authorityEndReason || candidate.current_attempt >= candidate.maximum_attempts) {
186
+ const exhausted = transaction.exhaustDelivery({
187
+ delivery_id: candidate.delivery_id,
188
+ expected_attempt: candidate.current_attempt,
189
+ expected_connector_id: candidate.current_connector_id,
190
+ expected_lease_token_digest: candidate.current_lease_token_digest,
191
+ expected_lease_expires_at: candidate.lease_expires_at,
192
+ reason: authorityEndReason ?? "attempt_limit_reached",
193
+ updated_at: nowIso,
194
+ });
195
+ if (!exhausted) {
196
+ throw conflict("delivery_claim_race", "Delivery exhaustion claim was lost");
197
+ }
198
+ return null;
199
+ }
200
+ } else {
201
+ throw invariant("delivery_state_invalid", "Delivery claim candidate has an invalid state");
202
+ }
203
+
204
+ const leaseExpiresAtMs = Math.min(
205
+ now.getTime() + this.#leaseDurationMs,
206
+ parseStoredTimestamp(candidate.grant_expires_at, "grant_expires_at"),
207
+ Date.parse(identity.expires_at),
208
+ );
209
+ if (!Number.isFinite(leaseExpiresAtMs) || leaseExpiresAtMs <= now.getTime()) {
210
+ throw authorization(
211
+ "connector_identity_expired",
212
+ "Connector identity cannot support a live delivery lease",
213
+ );
214
+ }
215
+ const attempt = candidate.current_attempt + 1;
216
+ const leaseExpiresAt = new Date(leaseExpiresAtMs).toISOString();
217
+ const claimed = transaction.claimDelivery({
218
+ delivery_id: candidate.delivery_id,
219
+ expected_status: candidate.status,
220
+ expected_attempt: candidate.current_attempt,
221
+ expected_connector_id: candidate.current_connector_id,
222
+ expected_lease_token_digest: candidate.current_lease_token_digest,
223
+ expected_lease_expires_at: candidate.lease_expires_at,
224
+ attempt,
225
+ connector_id: identity.connector_id,
226
+ lease_token_digest: claimTokenDigest,
227
+ leased_at: nowIso,
228
+ lease_expires_at: leaseExpiresAt,
229
+ updated_at: nowIso,
230
+ });
231
+ if (!claimed) {
232
+ throw conflict("delivery_claim_race", "Delivery lease claim was lost");
233
+ }
234
+ return buildDeliveryLeaseResult({
235
+ ...candidate,
236
+ status: "leased",
237
+ current_attempt: attempt,
238
+ current_connector_id: identity.connector_id,
239
+ current_lease_token_digest: claimTokenDigest,
240
+ leased_at: nowIso,
241
+ lease_expires_at: leaseExpiresAt,
242
+ terminal_reason: null,
243
+ updated_at: nowIso,
244
+ }, claimToken, false);
245
+ });
246
+ }
247
+
248
+ acknowledgeDelivery(input) {
249
+ requireExactInput(
250
+ input,
251
+ ACKNOWLEDGE_DELIVERY_FIELDS,
252
+ ACKNOWLEDGE_DELIVERY_FIELDS,
253
+ "Delivery acknowledgement input",
254
+ );
255
+ const connectorToken = requireOpaqueToken(
256
+ input.connectorToken,
257
+ "Connector token",
258
+ "connector_token_invalid",
259
+ );
260
+ const deliveryId = requireIdentifier(input.deliveryId, "deliveryId");
261
+ const leaseToken = requireClaimToken(input.leaseToken, "Delivery lease token");
262
+ const effectToken = requireOpaqueToken(
263
+ input.effectToken,
264
+ "Host-effect token",
265
+ "host_effect_token_invalid",
266
+ );
267
+ const leaseTokenDigest = digestToken(leaseToken);
268
+ const now = this.#readClock();
269
+ const identity = this.#verifyConnector(connectorToken, now);
270
+ const initial = this.#store.getDeliveryById(deliveryId);
271
+ if (!initial) {
272
+ throw notFound("delivery_not_found", "Delivery was not found");
273
+ }
274
+ assertCurrentLease(identity, initial, leaseTokenDigest);
275
+ const effect = this.#verifyEffect(effectToken, initial, now);
276
+ assertEffectWindow(effect, initial, now);
277
+ const effectJson = canonicalJson(effect);
278
+
279
+ return this.#store.transaction((transaction) => {
280
+ const current = transaction.getDeliveryById(deliveryId);
281
+ if (!current) {
282
+ throw invariant("delivery_disappeared", "Delivery disappeared during acknowledgement");
283
+ }
284
+ assertCurrentLease(identity, current, leaseTokenDigest);
285
+ assertEffectMatchesDelivery(effect, current);
286
+ assertEffectWindow(effect, current, now);
287
+ const effectOwner = transaction.getDeliveryByEffectId(effect.effect_id);
288
+ if (effectOwner && effectOwner.delivery_id !== deliveryId) {
289
+ throw conflict(
290
+ "effect_identity_conflict",
291
+ "Host effect identity is already attached to another delivery",
292
+ );
293
+ }
294
+
295
+ if (current.status === "acknowledged") {
296
+ if (
297
+ current.effect_id !== effect.effect_id ||
298
+ current.effect_attestation_json !== effectJson
299
+ ) {
300
+ throw conflict(
301
+ "delivery_effect_conflict",
302
+ "Delivery is already acknowledged by a different Host effect",
303
+ );
304
+ }
305
+ return buildDeliveryAcknowledgement(current, effect.effect_id, true);
306
+ }
307
+ if (!["leased", "retry_exhausted"].includes(current.status)) {
308
+ throw conflict(
309
+ "delivery_not_acknowledgeable",
310
+ "Delivery is not in an acknowledgeable state",
311
+ );
312
+ }
313
+
314
+ const acknowledgedAt = now.toISOString();
315
+ const acknowledged = transaction.acknowledgeDelivery({
316
+ delivery_id: deliveryId,
317
+ expected_status: current.status,
318
+ expected_attempt: current.current_attempt,
319
+ expected_connector_id: current.current_connector_id,
320
+ expected_lease_token_digest: current.current_lease_token_digest,
321
+ expected_lease_expires_at: current.lease_expires_at,
322
+ effect_id: effect.effect_id,
323
+ effect_attestation_json: effectJson,
324
+ acknowledged_at: acknowledgedAt,
325
+ updated_at: acknowledgedAt,
326
+ });
327
+ if (!acknowledged) {
328
+ throw conflict("delivery_acknowledgement_race", "Delivery acknowledgement claim was lost");
329
+ }
330
+ return buildDeliveryAcknowledgement(current, effect.effect_id, false);
331
+ });
332
+ }
333
+
334
+ #verifyConnector(token, now) {
335
+ try {
336
+ const value = this.#connectorAuthority.verifyConnector({ connectorToken: token });
337
+ return normalizeConnectorIdentity(value, now);
338
+ } catch {
339
+ throw authorization(
340
+ "connector_identity_invalid",
341
+ "Connector identity could not be verified by the Receiver authority",
342
+ );
343
+ }
344
+ }
345
+
346
+ #verifyEffect(token, delivery, now) {
347
+ const expected = deepFreeze({
348
+ delivery_id: delivery.delivery_id,
349
+ event_id: delivery.event_id,
350
+ correlation_id: delivery.correlation_id,
351
+ workflow_id: delivery.workflow_id,
352
+ canonical_url: delivery.canonical_url,
353
+ human_boundary: delivery.human_boundary,
354
+ outcome: HOST_EFFECT_OUTCOME,
355
+ });
356
+ try {
357
+ const value = this.#effectAuthority.verifyEffect({
358
+ effectToken: token,
359
+ expected,
360
+ });
361
+ const effect = normalizeHostEffectAttestation(value, now);
362
+ assertEffectMatchesDelivery(effect, delivery);
363
+ return effect;
364
+ } catch {
365
+ throw authorization(
366
+ "host_effect_invalid",
367
+ "Host effect could not be verified by the Receiver authority",
368
+ );
369
+ }
370
+ }
371
+
372
+ #readClock() {
373
+ const value = this.#clock();
374
+ if (!(value instanceof Date) || !Number.isFinite(value.getTime())) {
375
+ throw new TypeError("Receiver delivery clock must return a valid Date");
376
+ }
377
+ return new Date(value.getTime());
378
+ }
379
+ }
380
+
381
+ function normalizeConnectorIdentity(value, now) {
382
+ requireExactInput(
383
+ value,
384
+ CONNECTOR_IDENTITY_FIELDS,
385
+ CONNECTOR_IDENTITY_FIELDS,
386
+ "Connector identity attestation",
387
+ );
388
+ if (value.type !== CONNECTOR_IDENTITY_TYPE || value.protocol_version !== PROTOCOL_VERSION) {
389
+ throw authorization("connector_identity_version_invalid", "Connector identity version is unsupported");
390
+ }
391
+ const identity = {
392
+ type: CONNECTOR_IDENTITY_TYPE,
393
+ protocol_version: PROTOCOL_VERSION,
394
+ connector_id: requireIdentifier(value.connector_id, "connector_id"),
395
+ subject_id: requireIdentifier(value.subject_id, "Connector subject_id"),
396
+ delivery_target_id: requireIdentifier(
397
+ value.delivery_target_id,
398
+ "Connector delivery_target_id",
399
+ ),
400
+ authenticated_at: requireTimestamp(value.authenticated_at, "Connector authenticated_at"),
401
+ expires_at: requireTimestamp(value.expires_at, "Connector expires_at"),
402
+ };
403
+ const authenticatedAt = Date.parse(identity.authenticated_at);
404
+ const expiresAt = Date.parse(identity.expires_at);
405
+ if (
406
+ authenticatedAt > now.getTime() + AUTHORITY_FUTURE_SKEW_MS ||
407
+ expiresAt <= now.getTime() ||
408
+ expiresAt <= authenticatedAt
409
+ ) {
410
+ throw authorization("connector_identity_time_invalid", "Connector identity is outside its valid window");
411
+ }
412
+ return deepFreeze(identity);
413
+ }
414
+
415
+ function normalizeHostEffectAttestation(value, now) {
416
+ requireExactInput(
417
+ value,
418
+ HOST_EFFECT_ATTESTATION_FIELDS,
419
+ HOST_EFFECT_ATTESTATION_FIELDS,
420
+ "Host-effect attestation",
421
+ );
422
+ if (
423
+ value.type !== HOST_EFFECT_ATTESTATION_TYPE ||
424
+ value.protocol_version !== PROTOCOL_VERSION ||
425
+ value.outcome !== HOST_EFFECT_OUTCOME
426
+ ) {
427
+ throw authorization("host_effect_version_invalid", "Host-effect attestation is unsupported");
428
+ }
429
+ const effect = {
430
+ type: HOST_EFFECT_ATTESTATION_TYPE,
431
+ protocol_version: PROTOCOL_VERSION,
432
+ effect_id: requireIdentifier(value.effect_id, "effect_id"),
433
+ delivery_id: requireIdentifier(value.delivery_id, "effect delivery_id"),
434
+ event_id: requireIdentifier(value.event_id, "effect event_id"),
435
+ correlation_id: requireIdentifier(value.correlation_id, "effect correlation_id"),
436
+ workflow_id: requireIdentifier(value.workflow_id, "effect workflow_id"),
437
+ outcome: HOST_EFFECT_OUTCOME,
438
+ confirmed_at: requireTimestamp(value.confirmed_at, "effect confirmed_at"),
439
+ };
440
+ if (Date.parse(effect.confirmed_at) > now.getTime() + AUTHORITY_FUTURE_SKEW_MS) {
441
+ throw authorization("host_effect_time_invalid", "Host effect is outside its valid time window");
442
+ }
443
+ return deepFreeze(effect);
444
+ }
445
+
446
+ function assertConnectorScope(identity, delivery) {
447
+ if (
448
+ identity.subject_id !== delivery.subject_id ||
449
+ identity.delivery_target_id !== delivery.delivery_target_id
450
+ ) {
451
+ throw authorization(
452
+ "connector_delivery_scope_invalid",
453
+ "Connector identity is outside the delivery scope",
454
+ );
455
+ }
456
+ }
457
+
458
+ function assertCurrentLease(identity, delivery, leaseTokenDigest) {
459
+ assertConnectorScope(identity, delivery);
460
+ if (!["leased", "retry_exhausted", "acknowledged"].includes(delivery.status)) {
461
+ throw conflict("delivery_not_leased", "Delivery has no acknowledgeable lease");
462
+ }
463
+ if (
464
+ delivery.current_connector_id !== identity.connector_id ||
465
+ delivery.current_lease_token_digest !== leaseTokenDigest
466
+ ) {
467
+ throw authorization("delivery_lease_invalid", "Delivery lease token is invalid or stale");
468
+ }
469
+ }
470
+
471
+ function getGrantAuthorityEndReason(delivery, now) {
472
+ if (delivery.grant_revoked_at !== null) return "grant_revoked";
473
+ if (
474
+ parseStoredTimestamp(delivery.grant_expires_at, "grant_expires_at") <= now.getTime()
475
+ ) {
476
+ return "grant_expired";
477
+ }
478
+ return null;
479
+ }
480
+
481
+ function assertEffectMatchesDelivery(effect, delivery) {
482
+ if (
483
+ effect.delivery_id !== delivery.delivery_id ||
484
+ effect.event_id !== delivery.event_id ||
485
+ effect.correlation_id !== delivery.correlation_id ||
486
+ effect.workflow_id !== delivery.workflow_id ||
487
+ effect.outcome !== HOST_EFFECT_OUTCOME
488
+ ) {
489
+ throw authorization("host_effect_scope_invalid", "Host effect is outside the delivery scope");
490
+ }
491
+ }
492
+
493
+ function assertEffectWindow(effect, delivery, now) {
494
+ const confirmedAt = Date.parse(effect.confirmed_at);
495
+ const leasedAt = parseStoredTimestamp(delivery.leased_at, "leased_at");
496
+ const leaseExpiresAt = parseStoredTimestamp(delivery.lease_expires_at, "lease_expires_at");
497
+ const grantExpiresAt = parseStoredTimestamp(delivery.grant_expires_at, "grant_expires_at");
498
+ const revokedAt = delivery.grant_revoked_at === null
499
+ ? null
500
+ : parseStoredTimestamp(delivery.grant_revoked_at, "grant_revoked_at");
501
+ if (
502
+ confirmedAt < leasedAt ||
503
+ confirmedAt >= leaseExpiresAt ||
504
+ confirmedAt >= grantExpiresAt ||
505
+ confirmedAt > now.getTime() + AUTHORITY_FUTURE_SKEW_MS ||
506
+ (revokedAt !== null && confirmedAt >= revokedAt)
507
+ ) {
508
+ throw authorization("host_effect_time_invalid", "Host effect is outside the delivery authority window");
509
+ }
510
+ }
511
+
512
+ function buildDeliveryLeaseResult(delivery, leaseToken, duplicate) {
513
+ let event;
514
+ let receipt;
515
+ try {
516
+ event = parseContinuationEventBody(delivery.canonical_body);
517
+ receipt = validateContinuationReceipt(JSON.parse(delivery.receipt_json));
518
+ } catch {
519
+ throw invariant("delivery_private_state_invalid", "Delivery private state is invalid");
520
+ }
521
+ if (
522
+ event.event_id !== delivery.event_id ||
523
+ event.binding_id !== delivery.grant_binding_id ||
524
+ event.correlation_id !== delivery.correlation_id ||
525
+ event.issuer_origin !== delivery.grant_issuer_origin ||
526
+ event.workflow_id !== delivery.workflow_id ||
527
+ event.event_type !== delivery.event_type ||
528
+ event.canonical_url !== delivery.canonical_url ||
529
+ receipt.grant_id !== delivery.grant_id ||
530
+ receipt.correlation_id !== delivery.correlation_id ||
531
+ receipt.issuer_origin !== delivery.grant_issuer_origin ||
532
+ receipt.workflow_id !== delivery.workflow_id ||
533
+ receipt.event_type !== delivery.event_type ||
534
+ receipt.canonical_url !== delivery.canonical_url ||
535
+ receipt.expires_at !== delivery.grant_expires_at ||
536
+ receipt.human_boundary !== delivery.human_boundary
537
+ ) {
538
+ throw invariant("delivery_private_state_invalid", "Delivery private state is inconsistent");
539
+ }
540
+ return deepFreeze({
541
+ duplicate,
542
+ lease: {
543
+ type: DELIVERY_LEASE_TYPE,
544
+ protocol_version: PROTOCOL_VERSION,
545
+ delivery_id: delivery.delivery_id,
546
+ event_id: delivery.event_id,
547
+ attempt: delivery.current_attempt,
548
+ lease_token: leaseToken,
549
+ lease_expires_at: delivery.lease_expires_at,
550
+ continuation: {
551
+ correlation_id: event.correlation_id,
552
+ workflow_id: event.workflow_id,
553
+ event_type: event.event_type,
554
+ event_sequence: event.event_sequence,
555
+ state_version: event.state_version,
556
+ occurred_at: event.occurred_at,
557
+ canonical_url: event.canonical_url,
558
+ },
559
+ receipt,
560
+ },
561
+ });
562
+ }
563
+
564
+ function buildDeliveryAcknowledgement(delivery, effectId, duplicate) {
565
+ return deepFreeze({
566
+ type: DELIVERY_ACKNOWLEDGEMENT_TYPE,
567
+ protocol_version: PROTOCOL_VERSION,
568
+ delivery_id: delivery.delivery_id,
569
+ event_id: delivery.event_id,
570
+ effect_id: effectId,
571
+ acknowledged: true,
572
+ duplicate,
573
+ status: "acknowledged",
574
+ });
575
+ }
576
+
577
+ function requireClaimToken(value, label = "Delivery claim token") {
578
+ if (typeof value !== "string" || !CLAIM_TOKEN_PATTERN.test(value)) {
579
+ throw authorization("delivery_claim_token_invalid", `${label} is invalid`);
580
+ }
581
+ const decoded = Buffer.from(value, "base64url");
582
+ if (decoded.length !== 32 || decoded.toString("base64url") !== value) {
583
+ throw authorization("delivery_claim_token_invalid", `${label} is invalid`);
584
+ }
585
+ return value;
586
+ }
587
+
588
+ function digestToken(value) {
589
+ return createHash("sha256").update(value, "utf8").digest("base64url");
590
+ }
591
+
592
+ function parseStoredTimestamp(value, label) {
593
+ const parsed = Date.parse(value);
594
+ if (
595
+ typeof value !== "string" ||
596
+ !Number.isFinite(parsed) ||
597
+ new Date(parsed).toISOString() !== value
598
+ ) {
599
+ throw invariant("delivery_private_state_invalid", `Stored ${label} is invalid`);
600
+ }
601
+ return parsed;
602
+ }
603
+
604
+ function requireDeliveryStore(store) {
605
+ if (!store || typeof store !== "object") {
606
+ throw new TypeError("Receiver delivery store must implement the persistence port");
607
+ }
608
+ for (const method of DELIVERY_STORE_METHODS) {
609
+ if (typeof store[method] !== "function") {
610
+ throw new TypeError(`Receiver delivery store is missing ${method}`);
611
+ }
612
+ }
613
+ }
@@ -0,0 +1,24 @@
1
+ export const RECEIVER_HTTP_ROUTES = Object.freeze({
2
+ event: "/v0.1/events",
3
+ claim: "/v0.1/delivery-claims",
4
+ acknowledgement: "/v0.1/delivery-acknowledgements",
5
+ });
6
+
7
+ export const RECEIVER_HTTP_LIMITS = Object.freeze({
8
+ requestBytes: 16 * 1_024,
9
+ responseBytes: 32 * 1_024,
10
+ });
11
+
12
+ export const RECEIVER_HTTP_CONTENT_TYPE = "application/json";
13
+
14
+ export const CLAIM_REQUEST_FIELDS = Object.freeze([
15
+ "connector_token",
16
+ "claim_token",
17
+ ]);
18
+
19
+ export const ACKNOWLEDGEMENT_REQUEST_FIELDS = Object.freeze([
20
+ "connector_token",
21
+ "delivery_id",
22
+ "lease_token",
23
+ "effect_token",
24
+ ]);