@xyo-network/event-kit-protocol 1.0.0 → 2.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.
@@ -12,9 +12,8 @@ async function admitVerifiedWake(input) {
12
12
  if (!isNonnegativeSafeInteger(input.expectedHead)) {
13
13
  return reject("grant-view-invalid", ["expectedHead must be a nonnegative safe integer"]);
14
14
  }
15
- const authorization = await authorize(input);
16
- if (!authorization.ok) return authorization.failure;
17
- return await commitAuthorizedWake(input.inbox, attempt, authorization.grant, wake);
15
+ const authorization = await authorizeVerifiedWake(input);
16
+ return authorization.ok ? await commitAuthorizedWake(input.inbox, attempt, authorization.grant, wake) : authorization.failure;
18
17
  }
19
18
  async function resolvePriorAttempt(inbox, attempt, wake) {
20
19
  let resolution;
@@ -33,10 +32,7 @@ async function resolvePriorAttempt(inbox, attempt, wake) {
33
32
  const receiptFailure = validateReceipt(resolution.receipt, attempt);
34
33
  return completed(receiptFailure ?? success("duplicate", snapshotReceipt(resolution.receipt), wake));
35
34
  }
36
- if (resolution.kind !== "new") {
37
- return completed(reject("inbox-unavailable", ["inbox returned an unknown attempt resolution"]));
38
- }
39
- return Object.freeze({ pending: true });
35
+ return resolution.kind === "new" ? Object.freeze({ pending: true }) : completed(reject("inbox-unavailable", ["inbox returned an unknown attempt resolution"]));
40
36
  }
41
37
  async function commitAuthorizedWake(inbox, attempt, grant, wake) {
42
38
  let committed;
@@ -59,8 +55,7 @@ async function commitAuthorizedWake(inbox, attempt, grant, wake) {
59
55
  return reject("inbox-unavailable", ["inbox returned an unknown commit result"]);
60
56
  }
61
57
  const receiptFailure = validateReceipt(committed.receipt, attempt);
62
- if (receiptFailure !== void 0) return receiptFailure;
63
- return success(committed.kind, snapshotReceipt(committed.receipt), wake);
58
+ return receiptFailure ?? success(committed.kind, snapshotReceipt(committed.receipt), wake);
64
59
  }
65
60
  function completed(result) {
66
61
  return Object.freeze({ pending: false, result });
@@ -84,7 +79,7 @@ function createAttempt(verified) {
84
79
  ok: true
85
80
  };
86
81
  }
87
- async function authorize(input) {
82
+ async function authorizeVerifiedWake(input) {
88
83
  const { route } = input.verified;
89
84
  let decision;
90
85
  try {
@@ -132,10 +127,7 @@ function validateGrantView(decision, expectedHead, maxGrantLagBlocks) {
132
127
  if (decision.lag !== void 0 && decision.lag !== lag) {
133
128
  return reject("grant-view-invalid", ["grant diagnostic lag disagrees with the recomputed lag"]);
134
129
  }
135
- if (lag > maxGrantLagBlocks) {
136
- return reject("grant-view-stale", [`grantLag=${lag} max=${maxGrantLagBlocks}`]);
137
- }
138
- return void 0;
130
+ return lag > maxGrantLagBlocks ? reject("grant-view-stale", [`grantLag=${lag} max=${maxGrantLagBlocks}`]) : void 0;
139
131
  }
140
132
  function validateGrantEvidence(evidence, verified, atBlock) {
141
133
  if (!isRecord(evidence)) return reject("grant-view-invalid", ["enabled grant decision omitted evidence"]);
@@ -170,10 +162,7 @@ function validateGrantEvidence(evidence, verified, atBlock) {
170
162
  }
171
163
  const evidenceHasQueue = Object.hasOwn(evidence, "queueId");
172
164
  const routeHasQueue = Object.hasOwn(verified.route, "queueId");
173
- if (evidence.deploymentId !== verified.route.deploymentId || evidenceHasQueue !== routeHasQueue || evidence.queueId !== verified.route.queueId) {
174
- return reject("grant-view-invalid", ["grant scope does not exactly match the configured route"]);
175
- }
176
- return void 0;
165
+ return evidence.deploymentId !== verified.route.deploymentId || evidenceHasQueue !== routeHasQueue || evidence.queueId !== verified.route.queueId ? reject("grant-view-invalid", ["grant scope does not exactly match the configured route"]) : void 0;
177
166
  }
178
167
  function validateReceipt(receipt, attempt) {
179
168
  const requiredFields = [
@@ -186,10 +175,7 @@ function validateReceipt(receipt, attempt) {
186
175
  if (!isRecord(receipt) || requiredFields.some((field) => !Object.hasOwn(receipt, field)) || typeof receipt.id !== "string" || receipt.id.length === 0) {
187
176
  return reject("inbox-unavailable", ["inbox returned an invalid receipt"]);
188
177
  }
189
- if (receipt.audience !== attempt.audience || receipt.publisher !== attempt.publisher || receipt.eventHash !== attempt.eventHash || receipt.wakeId !== attempt.wakeId) {
190
- return reject("inbox-unavailable", ["inbox receipt is not bound to the verified attempt"]);
191
- }
192
- return void 0;
178
+ return receipt.audience !== attempt.audience || receipt.publisher !== attempt.publisher || receipt.eventHash !== attempt.eventHash || receipt.wakeId !== attempt.wakeId ? reject("inbox-unavailable", ["inbox receipt is not bound to the verified attempt"]) : void 0;
193
179
  }
194
180
  function snapshotGrantEvidence(evidence) {
195
181
  return Object.freeze({
@@ -280,6 +266,7 @@ async function parseAdmittedWake(value) {
280
266
  // src/admitAndEnqueue.ts
281
267
  async function admitAndEnqueue(input) {
282
268
  const { verified } = input;
269
+ if (verified.route.deliveryMode !== "durable") throw new TypeError("Durable admission requires explicit durable delivery mode");
283
270
  const wake = AdmittedWakeZod.parse({
284
271
  audience: verified.audience,
285
272
  deploymentId: verified.deploymentId,
@@ -295,6 +282,53 @@ async function admitAndEnqueue(input) {
295
282
  return await admitVerifiedWake({ ...input, wake });
296
283
  }
297
284
 
285
+ // src/bestEffortAdmission.ts
286
+ import {
287
+ HashZod as HashZod3,
288
+ NonnegativeJsonSafeIntegerZod as NonnegativeJsonSafeIntegerZod3,
289
+ NormalizedAddressZod as NormalizedAddressZod3,
290
+ WakeIdZod as WakeIdZod2,
291
+ WakeJwtAudienceZod as WakeJwtAudienceZod3,
292
+ WakeJwtIdZod as WakeJwtIdZod2
293
+ } from "@xyo-network/event-kit-schemas";
294
+ import { z as z3 } from "zod";
295
+
296
+ // src/verifyWakeRequest.ts
297
+ import {
298
+ ChainIdZod,
299
+ DeploymentIdZod as DeploymentIdZod2,
300
+ HashZod as HashZod2,
301
+ MAX_POSITIONS_PER_SUBSCRIPTION_WAKE,
302
+ NonnegativeJsonSafeIntegerZod as NonnegativeJsonSafeIntegerZod2,
303
+ NormalizedAddressZod as NormalizedAddressZod2,
304
+ PositiveJsonSafeIntegerZod,
305
+ SOURCE_WAKE_FILTER_PROFILE,
306
+ validWakeDeliveryTerms,
307
+ WakeDeliveryTermsFields,
308
+ WakeEnvelopeZod as WakeEnvelopeZod2,
309
+ WakeJwtAudienceZod as WakeJwtAudienceZod2,
310
+ WakeJwtHeaderZod,
311
+ WakeJwtPayloadZod,
312
+ WakeJwtSchema,
313
+ WakeSourceZod as WakeSourceZod2
314
+ } from "@xyo-network/event-kit-schemas";
315
+ import {
316
+ Account,
317
+ PayloadBuilder as PayloadBuilder3
318
+ } from "@xyo-network/sdk";
319
+ import { z as z2 } from "zod";
320
+
321
+ // src/sourceWakeIdentity.ts
322
+ import {
323
+ SourceWakeSubscriptionFilterZod,
324
+ WakeSourceSchema,
325
+ WakeSourceZod
326
+ } from "@xyo-network/event-kit-schemas";
327
+ import {
328
+ asSchema,
329
+ PayloadBuilder as PayloadBuilder2
330
+ } from "@xyo-network/sdk";
331
+
298
332
  // src/canonicalJson.ts
299
333
  var textEncoder = new TextEncoder();
300
334
  function hasUnpairedSurrogate(value) {
@@ -344,6 +378,379 @@ function canonicalJsonBytes(value) {
344
378
  return textEncoder.encode(canonicalize(value));
345
379
  }
346
380
 
381
+ // src/sourceWakeIdentity.ts
382
+ async function wakeSourceHash(source) {
383
+ return await PayloadBuilder2.dataHash({ schema: WakeSourceSchema, ...WakeSourceZod.parse(source) });
384
+ }
385
+ function wakeSourcesEqual(left, right) {
386
+ return canonicalJson(WakeSourceZod.parse(left)) === canonicalJson(WakeSourceZod.parse(right));
387
+ }
388
+ async function sourceWakeFilterHash(filter) {
389
+ const parsed = SourceWakeSubscriptionFilterZod.parse(filter);
390
+ return await PayloadBuilder2.dataHash({ ...parsed, schema: asSchema(parsed.schema, true) });
391
+ }
392
+
393
+ // src/verifyWakeRequest.ts
394
+ var EVENT_KIT_MAX_JWT_LIFETIME_SECONDS = 300;
395
+ var EVENT_KIT_MAX_FUTURE_IAT_SECONDS = 60;
396
+ var WakeAdmissionRouteZod = z2.strictObject({
397
+ ...WakeDeliveryTermsFields,
398
+ audience: WakeJwtAudienceZod2,
399
+ authorizationChainId: ChainIdZod,
400
+ controller: NormalizedAddressZod2,
401
+ deploymentId: DeploymentIdZod2,
402
+ queueId: z2.string().min(1).max(255).optional(),
403
+ source: WakeSourceZod2,
404
+ filterHash: HashZod2,
405
+ subscriptionHash: HashZod2,
406
+ fromPosition: NonnegativeJsonSafeIntegerZod2,
407
+ maxPositionsPerWake: PositiveJsonSafeIntegerZod.max(MAX_POSITIONS_PER_SUBSCRIPTION_WAKE),
408
+ maxGrantLagBlocks: NonnegativeJsonSafeIntegerZod2
409
+ }).refine((route) => validWakeDeliveryTerms(route) && (route.deliveryMode !== "best-effort" || route.maxPositionsPerWake === 1), "Invalid explicit delivery terms");
410
+ function verifyEventBinding(event, route, nowSeconds) {
411
+ if (event.authorizationChainId !== route.authorizationChainId) {
412
+ return { ok: false, reason: "event-authorization-chain-mismatch" };
413
+ }
414
+ if (!wakeSourcesEqual(event.source, route.source)) return { ok: false, reason: "event-source-mismatch" };
415
+ if (event.filterHash !== route.filterHash) return { ok: false, reason: "event-filter-mismatch" };
416
+ if (event.deploymentId !== route.deploymentId || event.queueId !== route.queueId) {
417
+ return { ok: false, reason: "event-target-mismatch" };
418
+ }
419
+ if (event.deliveryMode !== route.deliveryMode) return { ok: false, reason: "event-mode-mismatch" };
420
+ if (route.deliveryMode === "best-effort") {
421
+ if (event.issuedAt > nowSeconds + EVENT_KIT_MAX_FUTURE_IAT_SECONDS) return { ok: false, reason: "hint-future-issued-at" };
422
+ if (route.bestEffort === void 0 || nowSeconds > event.issuedAt + route.bestEffort.maxHintAgeSeconds) return { ok: false, reason: "hint-expired" };
423
+ }
424
+ if (event.fromPosition < route.fromPosition) return { ok: false, reason: "range-before-floor" };
425
+ if (event.toPosition - event.fromPosition >= route.maxPositionsPerWake) return { ok: false, reason: "range-too-large" };
426
+ }
427
+ async function verifyWakeRequest(input) {
428
+ const routeResult = WakeAdmissionRouteZod.safeParse(input.route);
429
+ if (!routeResult.success || !NonnegativeJsonSafeIntegerZod2.safeParse(input.nowSeconds).success) {
430
+ return { ok: false, reason: "configuration-invalid" };
431
+ }
432
+ const eventResult = WakeEnvelopeZod2.safeParse(input.body);
433
+ if (!eventResult.success) return malformedWake(input.body, eventResult.error.issues);
434
+ const route = routeResult.data;
435
+ if (route.filterHash !== await sourceWakeFilterHash({
436
+ schema: SOURCE_WAKE_FILTER_PROFILE,
437
+ deliveryMode: route.deliveryMode,
438
+ ...route.bestEffort === void 0 ? {} : { bestEffort: route.bestEffort },
439
+ source: route.source,
440
+ fromPosition: route.fromPosition,
441
+ maxPositionsPerWake: route.maxPositionsPerWake
442
+ })) return { ok: false, reason: "configuration-invalid" };
443
+ const event = Object.freeze({ ...eventResult.data, source: Object.freeze(eventResult.data.source) });
444
+ const mismatch = verifyEventBinding(event, route, input.nowSeconds);
445
+ if (mismatch !== void 0) return mismatch;
446
+ const jwt = await verifyJwtProfile(input.jwt, route.audience, input.nowSeconds);
447
+ if (!jwt.ok) return jwt;
448
+ let eventHash;
449
+ try {
450
+ eventHash = await PayloadBuilder3.dataHash(event);
451
+ } catch {
452
+ return { ok: false, reason: "event-hash-failed" };
453
+ }
454
+ if (eventHash !== jwt.jwt.eventHash) return { ok: false, reason: "event-hash-mismatch" };
455
+ const sourceHash = await wakeSourceHash(route.source);
456
+ return Object.freeze({
457
+ ok: true,
458
+ verified: Object.freeze({
459
+ audience: route.audience,
460
+ deploymentId: event.deploymentId,
461
+ event,
462
+ eventHash,
463
+ expiresAt: jwt.jwt.expiresAt,
464
+ fromPosition: event.fromPosition,
465
+ issuedAt: event.issuedAt,
466
+ jwtId: jwt.jwt.jwtId,
467
+ publisher: jwt.jwt.publisher,
468
+ ...event.queueId === void 0 ? {} : { queueId: event.queueId },
469
+ route: Object.freeze({
470
+ ...route,
471
+ source: Object.freeze(route.source),
472
+ sourceHash,
473
+ ...route.bestEffort === void 0 ? {} : { bestEffort: Object.freeze(route.bestEffort) }
474
+ }),
475
+ toPosition: event.toPosition,
476
+ tokenIssuedAt: jwt.jwt.issuedAt,
477
+ wakeId: event.wakeId
478
+ })
479
+ });
480
+ }
481
+ async function verifyJwtProfile(token, audience, nowSeconds) {
482
+ let verified;
483
+ try {
484
+ verified = await Account.verifyJwt(token, { audience, now: nowSeconds });
485
+ } catch (error) {
486
+ return reject2("jwt-malformed", [errorMessage2(error)]);
487
+ }
488
+ if (!verified.ok) {
489
+ return Object.hasOwn(verified.payload ?? {}, "nbf") ? reject2("jwt-nbf-not-allowed") : reject2(classifySdkJwtFailure(verified.reasons), verified.reasons);
490
+ }
491
+ const wireResult = parseStrictJwtWire(verified.header, verified.payload, audience);
492
+ if (!wireResult.ok) return wireResult;
493
+ const { header: strictHeader, payload: strictPayload } = wireResult;
494
+ if (strictHeader.kid !== strictPayload.iss) return reject2("jwt-identity-invalid");
495
+ if (strictPayload.exp <= nowSeconds) return reject2("jwt-expired");
496
+ if (strictPayload.exp - strictPayload.iat > EVENT_KIT_MAX_JWT_LIFETIME_SECONDS) return reject2("jwt-lifetime-invalid");
497
+ if (strictPayload.iat - nowSeconds > EVENT_KIT_MAX_FUTURE_IAT_SECONDS) return reject2("jwt-future-iat");
498
+ const jwt = Object.freeze({
499
+ eventHash: strictPayload.eventHash,
500
+ expiresAt: strictPayload.exp,
501
+ issuedAt: strictPayload.iat,
502
+ jwtId: strictPayload.jti,
503
+ publisher: strictPayload.iss
504
+ });
505
+ return Object.freeze({ jwt, ok: true });
506
+ }
507
+ function parseStrictJwtWire(header, payload, audience) {
508
+ const headerResult = WakeJwtHeaderZod.safeParse(header);
509
+ if (!headerResult.success) {
510
+ return NormalizedAddressZod2.safeParse(header.kid).success ? reject2("jwt-header-invalid", zodDetails(headerResult.error.issues)) : reject2("jwt-identity-invalid");
511
+ }
512
+ if (Object.hasOwn(payload, "nbf")) return reject2("jwt-nbf-not-allowed");
513
+ if (!NormalizedAddressZod2.safeParse(payload.iss).success) return reject2("jwt-identity-invalid");
514
+ if (payload.schema !== WakeJwtSchema) return reject2("jwt-schema-mismatch");
515
+ if (payload.aud !== audience) return reject2("jwt-audience-mismatch");
516
+ if (!isNonnegativeSafeInteger2(payload.iat) || !isNonnegativeSafeInteger2(payload.exp) || payload.exp <= payload.iat) {
517
+ return reject2("jwt-lifetime-invalid");
518
+ }
519
+ const payloadResult = WakeJwtPayloadZod.safeParse(payload);
520
+ if (!payloadResult.success) return reject2("jwt-claims-invalid", zodDetails(payloadResult.error.issues));
521
+ return Object.freeze({
522
+ header: headerResult.data,
523
+ ok: true,
524
+ payload: payloadResult.data
525
+ });
526
+ }
527
+ function classifySdkJwtFailure(reasons) {
528
+ if (reasons.some((reason) => reason.startsWith("audience mismatch:"))) return "jwt-audience-mismatch";
529
+ if (reasons.some((reason) => reason.startsWith("expired:"))) return "jwt-expired";
530
+ if (reasons.some((reason) => reason.startsWith("unsupported alg:") || reason.startsWith("unsupported typ:"))) {
531
+ return "jwt-header-invalid";
532
+ }
533
+ return reasons.some((reason) => reason.startsWith("invalid public key:") || reason.startsWith("public key does not derive to kid:") || reason === "header.kid does not match payload.iss") ? "jwt-identity-invalid" : "jwt-invalid";
534
+ }
535
+ function malformedWake(body, issues) {
536
+ const details = zodDetails(issues);
537
+ if (hasInvertedSafeRange(body)) return reject2("range-invalid", details);
538
+ return reject2(isRecord2(body) && Object.hasOwn(body, "wakeId") && issues.some((issue) => issue.path[0] === "wakeId") ? "wake-id-invalid" : "event-malformed", details);
539
+ }
540
+ function hasInvertedSafeRange(value) {
541
+ if (!isRecord2(value)) return false;
542
+ const { fromPosition, toPosition } = value;
543
+ return typeof fromPosition === "number" && typeof toPosition === "number" && isNonnegativeSafeInteger2(fromPosition) && isNonnegativeSafeInteger2(toPosition) && fromPosition > toPosition;
544
+ }
545
+ function isNonnegativeSafeInteger2(value) {
546
+ return Number.isSafeInteger(value) && value >= 0;
547
+ }
548
+ function isRecord2(value) {
549
+ return typeof value === "object" && value !== null && !Array.isArray(value);
550
+ }
551
+ function zodDetails(issues) {
552
+ return issues.map((issue) => {
553
+ const path = issue.path.map(String).join(".") || "<root>";
554
+ return `${path}: ${issue.message}`;
555
+ });
556
+ }
557
+ function reject2(reason, details) {
558
+ if (details === void 0) return Object.freeze({ ok: false, reason });
559
+ return Object.freeze({
560
+ details: Object.freeze([...details]),
561
+ ok: false,
562
+ reason
563
+ });
564
+ }
565
+ function errorMessage2(error) {
566
+ return error instanceof Error ? error.message : String(error);
567
+ }
568
+
569
+ // src/bestEffortAdmission.ts
570
+ function hintRetention(input) {
571
+ const { verified, nowSeconds } = input;
572
+ const policy = verified.route.bestEffort;
573
+ if (verified.route.deliveryMode !== "best-effort" || verified.event.deliveryMode !== "best-effort" || policy === void 0 || verified.fromPosition !== verified.toPosition || !Number.isSafeInteger(nowSeconds) || nowSeconds < 0 || !Number.isSafeInteger(input.expectedHead) || input.expectedHead < 0)
574
+ return { ok: false, reason: "configuration-invalid" };
575
+ if (verified.issuedAt > nowSeconds + EVENT_KIT_MAX_FUTURE_IAT_SECONDS) return { ok: false, reason: "hint-future-issued-at" };
576
+ const bodyDeadline = verified.issuedAt + policy.maxHintAgeSeconds;
577
+ const retainWakeUntil = bodyDeadline + EVENT_KIT_REPLAY_RETENTION_SKEW_SECONDS;
578
+ const retainJwtUntil = verified.expiresAt + EVENT_KIT_REPLAY_RETENTION_SKEW_SECONDS;
579
+ if (!Number.isSafeInteger(retainWakeUntil) || !Number.isSafeInteger(retainJwtUntil)) return { ok: false, reason: "configuration-invalid" };
580
+ return nowSeconds > bodyDeadline ? { ok: false, reason: "hint-expired" } : {
581
+ ok: true,
582
+ retainJwtUntil,
583
+ retainWakeUntil
584
+ };
585
+ }
586
+ async function admitBestEffortHint(input) {
587
+ const retention = hintRetention(input);
588
+ if (!retention.ok) return retention;
589
+ const { retainJwtUntil, retainWakeUntil } = retention;
590
+ const { verified, nowSeconds } = input;
591
+ const authorization = await authorizeVerifiedWake(input);
592
+ if (!authorization.ok) return authorization.failure;
593
+ const wake = AdmittedWakeZod.parse({
594
+ audience: verified.audience,
595
+ deploymentId: verified.deploymentId,
596
+ event: verified.event,
597
+ eventHash: verified.eventHash,
598
+ fromPosition: verified.fromPosition,
599
+ toPosition: verified.toPosition,
600
+ jti: verified.jwtId,
601
+ publisher: verified.publisher,
602
+ wakeId: verified.wakeId,
603
+ ...verified.queueId === void 0 ? {} : { queueId: verified.queueId }
604
+ });
605
+ const attempt = {
606
+ audience: verified.audience,
607
+ eventHash: verified.eventHash,
608
+ jwtId: verified.jwtId,
609
+ publisher: verified.publisher,
610
+ retainJwtUntil,
611
+ retainWakeUntil,
612
+ wakeId: verified.wakeId
613
+ };
614
+ try {
615
+ const committed = await input.inbox.commitAuthorized({
616
+ attempt,
617
+ grant: authorization.grant,
618
+ wake,
619
+ nowSeconds
620
+ });
621
+ if (committed.kind !== "accepted" && committed.kind !== "duplicate") return { ok: false, reason: committed.kind };
622
+ const acknowledgment = committed.acknowledgment;
623
+ return acknowledgmentMatches(acknowledgment, attempt, nowSeconds) ? {
624
+ ok: true,
625
+ disposition: committed.kind,
626
+ acknowledgment,
627
+ wake
628
+ } : { ok: false, reason: "inbox-unavailable" };
629
+ } catch {
630
+ return { ok: false, reason: "inbox-unavailable" };
631
+ }
632
+ }
633
+ function acknowledgmentMatches(value, attempt, now) {
634
+ return BestEffortAdmissionAcknowledgmentZod.safeParse(value).success && value.eventHash === attempt.eventHash && value.wakeId === attempt.wakeId && value.acceptedAt <= now && value.expiresAt === attempt.retainWakeUntil;
635
+ }
636
+ var BestEffortAdmissionAcknowledgmentZod = z3.strictObject({
637
+ admissionId: z3.string().min(1).max(4096),
638
+ eventHash: HashZod3,
639
+ wakeId: WakeIdZod2,
640
+ acceptedAt: NonnegativeJsonSafeIntegerZod3,
641
+ expiresAt: NonnegativeJsonSafeIntegerZod3
642
+ }).refine((value) => value.expiresAt > value.acceptedAt, "Acknowledgment expiry must follow admission");
643
+ var JwtSecurityRecordZod = z3.strictObject({
644
+ audience: WakeJwtAudienceZod3,
645
+ publisher: NormalizedAddressZod3,
646
+ jwtId: WakeJwtIdZod2,
647
+ wakeId: WakeIdZod2,
648
+ eventHash: HashZod3,
649
+ expiresAt: NonnegativeJsonSafeIntegerZod3
650
+ });
651
+ var WakeSecurityRecordZod = z3.strictObject({
652
+ audience: WakeJwtAudienceZod3,
653
+ publisher: NormalizedAddressZod3,
654
+ wakeId: WakeIdZod2,
655
+ eventHash: HashZod3,
656
+ acknowledgment: BestEffortAdmissionAcknowledgmentZod
657
+ }).refine(
658
+ (value) => value.wakeId === value.acknowledgment.wakeId && value.eventHash === value.acknowledgment.eventHash,
659
+ "Security identity must match acknowledgment"
660
+ );
661
+ var BestEffortSecurityStateZod = z3.strictObject({
662
+ highestNowSeconds: NonnegativeJsonSafeIntegerZod3,
663
+ jwtRecords: z3.array(JwtSecurityRecordZod).max(65536),
664
+ wakeRecords: z3.array(WakeSecurityRecordZod).max(65536)
665
+ }).superRefine((value, context) => {
666
+ const jwtKeys = value.jwtRecords.map((record) => JSON.stringify([record.audience, record.publisher, record.jwtId]));
667
+ if (value.wakeRecords.some((record) => record.acknowledgment.acceptedAt > value.highestNowSeconds))
668
+ context.addIssue({ code: "custom", message: "Acknowledgment cannot precede stored admission clock" });
669
+ const wakeKeys = value.wakeRecords.map((record) => JSON.stringify([record.audience, record.publisher, record.wakeId]));
670
+ const jwtIdentities = new Set(jwtKeys);
671
+ const wakeIdentities = new Set(wakeKeys);
672
+ if (jwtIdentities.size !== jwtKeys.length || wakeIdentities.size !== wakeKeys.length)
673
+ context.addIssue({ code: "custom", message: "Persisted security identities must be unique" });
674
+ });
675
+ function parseBestEffortSecurityState(value) {
676
+ return BestEffortSecurityStateZod.parse(value);
677
+ }
678
+ var BestEffortAdmissionAttemptZod = z3.strictObject({
679
+ audience: WakeJwtAudienceZod3,
680
+ eventHash: HashZod3,
681
+ jwtId: WakeJwtIdZod2,
682
+ publisher: NormalizedAddressZod3,
683
+ retainJwtUntil: NonnegativeJsonSafeIntegerZod3,
684
+ retainWakeUntil: NonnegativeJsonSafeIntegerZod3,
685
+ wakeId: WakeIdZod2
686
+ });
687
+ function createBestEffortSecurityState() {
688
+ return {
689
+ highestNowSeconds: 0,
690
+ jwtRecords: [],
691
+ wakeRecords: []
692
+ };
693
+ }
694
+ function securityConflict(attempt, priorJwt, priorWake, jwtCount, wakeCount, maxRecords) {
695
+ if (priorJwt !== void 0 && (priorJwt.eventHash !== attempt.eventHash || priorJwt.wakeId !== attempt.wakeId))
696
+ return "jwt-id-collision";
697
+ if (priorWake !== void 0 && priorWake.eventHash !== attempt.eventHash)
698
+ return "wake-id-collision";
699
+ if (priorJwt === void 0 && jwtCount >= maxRecords || priorWake === void 0 && wakeCount >= maxRecords)
700
+ return "capacity-exceeded";
701
+ }
702
+ function validateTransaction(input, maxRecords) {
703
+ const attempt = BestEffortAdmissionAttemptZod.parse(input.attempt);
704
+ const wake = AdmittedWakeZod.parse(input.wake);
705
+ const nowSeconds = NonnegativeJsonSafeIntegerZod3.parse(input.nowSeconds);
706
+ if (attempt.audience !== wake.audience || attempt.publisher !== wake.publisher || attempt.jwtId !== wake.jti || attempt.wakeId !== wake.wakeId || attempt.eventHash !== wake.eventHash || wake.event.deliveryMode !== "best-effort" || attempt.retainJwtUntil <= nowSeconds || attempt.retainWakeUntil <= nowSeconds)
707
+ throw new TypeError("Best Effort transaction attempt does not match admitted hint");
708
+ if (!Number.isSafeInteger(maxRecords) || maxRecords < 1 || maxRecords > 65536) throw new TypeError("Invalid finite security capacity");
709
+ return { attempt, nowSeconds };
710
+ }
711
+ function commitBestEffortSecurity(state, input, maxRecords) {
712
+ state = parseBestEffortSecurityState(state);
713
+ const { attempt, nowSeconds } = validateTransaction(input, maxRecords);
714
+ if (nowSeconds < state.highestNowSeconds) return { state, result: { kind: "clock-regressed" } };
715
+ const jwtRecords = state.jwtRecords.filter((record) => record.expiresAt > nowSeconds).map((record) => ({ ...record }));
716
+ const wakeRecords = state.wakeRecords.filter((record) => record.acknowledgment.expiresAt > nowSeconds);
717
+ const priorJwt = jwtRecords.find((record) => record.audience === attempt.audience && record.publisher === attempt.publisher && record.jwtId === attempt.jwtId);
718
+ const priorWake = wakeRecords.find((record) => record.audience === attempt.audience && record.publisher === attempt.publisher && record.wakeId === attempt.wakeId);
719
+ const conflict = securityConflict(attempt, priorJwt, priorWake, jwtRecords.length, wakeRecords.length, maxRecords);
720
+ if (conflict !== void 0) return { state, result: { kind: conflict } };
721
+ const acknowledgment = priorWake?.acknowledgment ?? {
722
+ admissionId: JSON.stringify([attempt.audience, attempt.publisher, attempt.wakeId, attempt.eventHash]),
723
+ eventHash: attempt.eventHash,
724
+ wakeId: attempt.wakeId,
725
+ acceptedAt: nowSeconds,
726
+ expiresAt: attempt.retainWakeUntil
727
+ };
728
+ if (priorJwt !== void 0) priorJwt.expiresAt = Math.max(priorJwt.expiresAt, attempt.retainJwtUntil);
729
+ if (priorJwt === void 0) jwtRecords.push({
730
+ audience: attempt.audience,
731
+ publisher: attempt.publisher,
732
+ jwtId: attempt.jwtId,
733
+ wakeId: attempt.wakeId,
734
+ eventHash: attempt.eventHash,
735
+ expiresAt: attempt.retainJwtUntil
736
+ });
737
+ if (priorWake === void 0) wakeRecords.push({
738
+ audience: attempt.audience,
739
+ publisher: attempt.publisher,
740
+ wakeId: attempt.wakeId,
741
+ eventHash: attempt.eventHash,
742
+ acknowledgment
743
+ });
744
+ return {
745
+ state: {
746
+ highestNowSeconds: nowSeconds,
747
+ jwtRecords,
748
+ wakeRecords
749
+ },
750
+ result: { kind: priorWake === void 0 ? "accepted" : "duplicate", acknowledgment }
751
+ };
752
+ }
753
+
347
754
  // src/endpointChallenge.ts
348
755
  import {
349
756
  Base64Url32BytesZod,
@@ -357,7 +764,7 @@ import {
357
764
  generateHandshakeId,
358
765
  MAX_ENDPOINT_CHALLENGE_LIFETIME_SECONDS
359
766
  } from "@xyo-network/event-kit-schemas";
360
- import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk";
767
+ import { PayloadBuilder as PayloadBuilder4 } from "@xyo-network/sdk";
361
768
  function hashBytes(hash) {
362
769
  return Uint8Array.from({ length: 32 }, (_, index) => Number.parseInt(hash.slice(index * 2, index * 2 + 2), 16));
363
770
  }
@@ -384,7 +791,7 @@ function equalProof(left, right) {
384
791
  }
385
792
  async function endpointChallengeHash(challenge) {
386
793
  const parsed = EndpointChallengeZod.parse(challenge);
387
- return await PayloadBuilder2.dataHash(parsed);
794
+ return await PayloadBuilder4.dataHash(parsed);
388
795
  }
389
796
  function createEndpointChallenge(input) {
390
797
  const lifetimeSeconds = input.lifetimeSeconds ?? MAX_ENDPOINT_CHALLENGE_LIFETIME_SECONDS;
@@ -397,7 +804,7 @@ function createEndpointChallenge(input) {
397
804
  if (input.issuedAt > Number.MAX_SAFE_INTEGER - lifetimeSeconds) {
398
805
  throw new RangeError("Challenge expiry exceeds the JSON safe-integer range");
399
806
  }
400
- const builder = new PayloadBuilder2({ schema: EndpointChallengeSchema });
807
+ const builder = new PayloadBuilder4({ schema: EndpointChallengeSchema });
401
808
  return EndpointChallengeZod.parse(builder.fields({
402
809
  challengeId: generateHandshakeId(),
403
810
  chainId: input.chainId,
@@ -416,7 +823,7 @@ function createEndpointChallenge(input) {
416
823
  }
417
824
  async function createEndpointChallengeResponse(challenge, secret) {
418
825
  const challengeHash = await endpointChallengeHash(challenge);
419
- const builder = new PayloadBuilder2({ schema: EndpointChallengeResponseSchema });
826
+ const builder = new PayloadBuilder4({ schema: EndpointChallengeResponseSchema });
420
827
  return EndpointChallengeResponseZod.parse(builder.fields({
421
828
  challenge: challengeHash,
422
829
  proof: await hmacProof(secret, challengeHash)
@@ -427,8 +834,7 @@ async function verifyEndpointChallengeProof(input) {
427
834
  const challenge = EndpointChallengeZod.parse(input.challenge);
428
835
  const response = EndpointChallengeResponseZod.parse(input.response);
429
836
  const challengeHash = await endpointChallengeHash(challenge);
430
- if (response.challenge !== challengeHash) return false;
431
- return equalProof(response.proof, await hmacProof(input.secret, challengeHash));
837
+ return response.challenge === challengeHash && equalProof(response.proof, await hmacProof(input.secret, challengeHash));
432
838
  } catch {
433
839
  return false;
434
840
  }
@@ -436,8 +842,7 @@ async function verifyEndpointChallengeProof(input) {
436
842
  async function verifyEndpointChallengeResponse(input) {
437
843
  try {
438
844
  const challenge = EndpointChallengeZod.parse(input.challenge);
439
- if (!Number.isSafeInteger(input.nowSeconds) || input.nowSeconds < challenge.issuedAt || input.nowSeconds >= challenge.expiresAt) return false;
440
- return await verifyEndpointChallengeProof(input);
845
+ return Number.isSafeInteger(input.nowSeconds) && input.nowSeconds >= challenge.issuedAt && input.nowSeconds < challenge.expiresAt && await verifyEndpointChallengeProof(input);
441
846
  } catch {
442
847
  return false;
443
848
  }
@@ -453,7 +858,7 @@ import {
453
858
  EndpointChallengeZod as EndpointChallengeZod2,
454
859
  generateGrantId,
455
860
  generateHandshakeId as generateHandshakeId2,
456
- HashZod as HashZod3,
861
+ HashZod as HashZod5,
457
862
  MAX_SUBSCRIPTION_PLAINTEXT_BYTES as MAX_SUBSCRIPTION_PLAINTEXT_BYTES2,
458
863
  PublisherEncryptionKeyRevocationSchema,
459
864
  PublisherEncryptionKeyRevocationZod,
@@ -464,7 +869,7 @@ import {
464
869
  PublisherServiceSchema,
465
870
  PublisherServiceZod,
466
871
  SOURCE_WAKE_EVENT_KIND,
467
- SOURCE_WAKE_FILTER_PROFILE,
872
+ SOURCE_WAKE_FILTER_PROFILE as SOURCE_WAKE_FILTER_PROFILE2,
468
873
  WAKE_SUBSCRIPTION_HPKE_PROFILE as WAKE_SUBSCRIPTION_HPKE_PROFILE3,
469
874
  WAKE_WALLET_JWT_DELIVERY_PROFILE,
470
875
  WakeGrantObjectSchema,
@@ -481,7 +886,7 @@ import {
481
886
  WakeSubscriptionRevocationSchema,
482
887
  WakeSubscriptionRevocationZod
483
888
  } from "@xyo-network/event-kit-schemas";
484
- import { PayloadBuilder as PayloadBuilder3 } from "@xyo-network/sdk";
889
+ import { PayloadBuilder as PayloadBuilder5 } from "@xyo-network/sdk";
485
890
 
486
891
  // src/wakeSubscriptionHpke.ts
487
892
  import {
@@ -496,8 +901,8 @@ import {
496
901
  canonicalBase64UrlToBytes as canonicalBase64UrlToBytes2,
497
902
  EncryptedWakeSubscriptionZod as EncryptedWakeSubscriptionZod2,
498
903
  HandshakeIdZod,
499
- HashZod as HashZod2,
500
- NormalizedAddressZod as NormalizedAddressZod3,
904
+ HashZod as HashZod4,
905
+ NormalizedAddressZod as NormalizedAddressZod5,
501
906
  WAKE_SUBSCRIPTION_HPKE_PROFILE as WAKE_SUBSCRIPTION_HPKE_PROFILE2,
502
907
  WakeSubscriptionCleartextZod as WakeSubscriptionCleartextZod2
503
908
  } from "@xyo-network/event-kit-schemas";
@@ -506,7 +911,7 @@ import {
506
911
  import {
507
912
  EncryptedWakeSubscriptionZod,
508
913
  MAX_SUBSCRIPTION_PLAINTEXT_BYTES,
509
- NormalizedAddressZod as NormalizedAddressZod2,
914
+ NormalizedAddressZod as NormalizedAddressZod4,
510
915
  WAKE_SUBSCRIPTION_HPKE_PROFILE,
511
916
  WakeSubscriptionCleartextZod,
512
917
  WakeSubscriptionPlaintextZod
@@ -523,7 +928,7 @@ function cleartextFromEncrypted(subscription) {
523
928
  return cleartext;
524
929
  }
525
930
  function wakeSubscriptionAadBytes(subscription, subscriber) {
526
- const parsedSubscriber = NormalizedAddressZod2.parse(subscriber);
931
+ const parsedSubscriber = NormalizedAddressZod4.parse(subscriber);
527
932
  const parsedSubscription = "encryption" in subscription ? cleartextFromEncrypted(EncryptedWakeSubscriptionZod.parse(subscription)) : WakeSubscriptionCleartextZod.parse(subscription);
528
933
  return canonicalJsonBytes({
529
934
  schema: parsedSubscription.schema,
@@ -538,6 +943,7 @@ function wakeSubscriptionAadBytes(subscription, subscriber) {
538
943
  revision: parsedSubscription.revision,
539
944
  supersedes: parsedSubscription.supersedes ?? null,
540
945
  eventKind: parsedSubscription.eventKind,
946
+ deliveryMode: parsedSubscription.deliveryMode,
541
947
  expiresAtBlock: parsedSubscription.expiresAtBlock,
542
948
  profile: WAKE_SUBSCRIPTION_HPKE_PROFILE
543
949
  });
@@ -587,14 +993,14 @@ var WakeSubscriptionDecryptionError = class extends Error {
587
993
  };
588
994
  function parsePublicKey(value) {
589
995
  return {
590
- encryptionKey: HashZod2.parse(value.encryptionKey),
996
+ encryptionKey: HashZod4.parse(value.encryptionKey),
591
997
  keyId: HandshakeIdZod.parse(value.keyId),
592
998
  publicKey: Base64Url32BytesZod2.parse(value.publicKey)
593
999
  };
594
1000
  }
595
1001
  function parsePrivateKey(value) {
596
1002
  return {
597
- encryptionKey: HashZod2.parse(value.encryptionKey),
1003
+ encryptionKey: HashZod4.parse(value.encryptionKey),
598
1004
  keyId: HandshakeIdZod.parse(value.keyId),
599
1005
  privateKey: Base64Url32BytesZod2.parse(value.privateKey)
600
1006
  };
@@ -618,7 +1024,7 @@ async function generateWakeSubscriptionEncryptionKeyPair() {
618
1024
  }
619
1025
  async function encryptWakeSubscription(input) {
620
1026
  const subscription = WakeSubscriptionCleartextZod2.parse(input.subscription);
621
- const subscriber = NormalizedAddressZod3.parse(input.subscriber);
1027
+ const subscriber = NormalizedAddressZod5.parse(input.subscriber);
622
1028
  const publisherKey = parsePublicKey(input.publisherKey);
623
1029
  if (subscription.encryptionKey !== publisherKey.encryptionKey || subscription.keyId !== publisherKey.keyId) {
624
1030
  throw new TypeError("Subscription key reference does not match the supplied publisher key");
@@ -641,7 +1047,7 @@ async function encryptWakeSubscription(input) {
641
1047
  async function decryptWakeSubscription(input) {
642
1048
  try {
643
1049
  const subscription = EncryptedWakeSubscriptionZod2.parse(input.subscription);
644
- const subscriber = NormalizedAddressZod3.parse(input.subscriber);
1050
+ const subscriber = NormalizedAddressZod5.parse(input.subscriber);
645
1051
  const publisherKey = parsePrivateKey(input.publisherKey);
646
1052
  if (subscription.encryptionKey !== publisherKey.encryptionKey || subscription.keyId !== publisherKey.keyId) throw new TypeError("Key reference mismatch");
647
1053
  const recipientKey = await suite.kem.deserializePrivateKey(decoded32(publisherKey.privateKey));
@@ -684,13 +1090,13 @@ function parseHandshakePublicObject(value) {
684
1090
  throw new TypeError("Expected a strict Event Kit handshake public object");
685
1091
  }
686
1092
  async function handshakeObjectHash(object) {
687
- return HashZod3.parse(await PayloadBuilder3.dataHash(parseHandshakePublicObject(object)));
1093
+ return HashZod5.parse(await PayloadBuilder5.dataHash(parseHandshakePublicObject(object)));
688
1094
  }
689
1095
  async function withHandshakeObjectHash(body) {
690
1096
  return Object.freeze({ body, objectHash: await handshakeObjectHash(body) });
691
1097
  }
692
1098
  function createPublisherEncryptionKey(input) {
693
- const builder = new PayloadBuilder3({ schema: PublisherEncryptionKeySchema });
1099
+ const builder = new PayloadBuilder5({ schema: PublisherEncryptionKeySchema });
694
1100
  return PublisherEncryptionKeyZod.parse(builder.fields({
695
1101
  keyId: input.keyId ?? generateHandshakeId2(),
696
1102
  profile: WAKE_SUBSCRIPTION_HPKE_PROFILE3,
@@ -722,7 +1128,7 @@ async function generatePublisherEncryptionKey(input) {
722
1128
  });
723
1129
  }
724
1130
  function createPublisherService(input) {
725
- const builder = new PayloadBuilder3({ schema: PublisherServiceSchema });
1131
+ const builder = new PayloadBuilder5({ schema: PublisherServiceSchema });
726
1132
  return PublisherServiceZod.parse(builder.fields({
727
1133
  authorizationChainId: input.authorizationChainId,
728
1134
  serviceId: input.serviceId ?? generateHandshakeId2(),
@@ -732,9 +1138,11 @@ function createPublisherService(input) {
732
1138
  ...input.expiresAtBlock === void 0 ? {} : { expiresAtBlock: input.expiresAtBlock },
733
1139
  events: input.sources.map((source) => ({
734
1140
  kind: SOURCE_WAKE_EVENT_KIND,
735
- filterProfile: SOURCE_WAKE_FILTER_PROFILE,
1141
+ filterProfile: SOURCE_WAKE_FILTER_PROFILE2,
736
1142
  source
737
1143
  })),
1144
+ deliveryMode: input.deliveryMode,
1145
+ ...input.bestEffort === void 0 ? {} : { bestEffort: input.bestEffort },
738
1146
  deliveryProfile: WAKE_WALLET_JWT_DELIVERY_PROFILE,
739
1147
  challengeProfile: ENDPOINT_CHALLENGE_HMAC_SHA256_PROFILE,
740
1148
  encryptionProfile: WAKE_SUBSCRIPTION_HPKE_PROFILE3,
@@ -749,7 +1157,7 @@ function createPublisherService(input) {
749
1157
  }).build());
750
1158
  }
751
1159
  function createWakeGrant(input) {
752
- const builder = new PayloadBuilder3({ schema: WakeGrantObjectSchema });
1160
+ const builder = new PayloadBuilder5({ schema: WakeGrantObjectSchema });
753
1161
  return WakeGrantObjectZod.parse(builder.fields({
754
1162
  grantId: input.grantId ?? generateGrantId(),
755
1163
  deploymentId: input.deploymentId,
@@ -764,14 +1172,16 @@ function createWakeSubscriptionPlaintext(input) {
764
1172
  globalThis.crypto.getRandomValues(secretBytes);
765
1173
  }
766
1174
  const challengeSecret = input.challengeSecret ?? bytesToCanonicalBase64Url3(secretBytes);
767
- const builder = new PayloadBuilder3({ schema: WakeSubscriptionPlaintextSchema });
1175
+ const builder = new PayloadBuilder5({ schema: WakeSubscriptionPlaintextSchema });
768
1176
  return WakeSubscriptionPlaintextZod2.parse(builder.fields({
769
1177
  endpoint: input.endpoint,
770
1178
  audience: input.audience,
771
1179
  deploymentId: input.deploymentId,
772
1180
  queueId: input.queueId ?? null,
773
1181
  filter: {
774
- schema: SOURCE_WAKE_FILTER_PROFILE,
1182
+ schema: SOURCE_WAKE_FILTER_PROFILE2,
1183
+ deliveryMode: input.deliveryMode,
1184
+ ...input.bestEffort === void 0 ? {} : { bestEffort: input.bestEffort },
775
1185
  source: input.source,
776
1186
  fromPosition: input.fromPosition,
777
1187
  maxPositionsPerWake: input.maxPositionsPerWake
@@ -783,7 +1193,7 @@ function createWakeSubscriptionPlaintext(input) {
783
1193
  }).build());
784
1194
  }
785
1195
  async function createEncryptedWakeSubscription(input) {
786
- const builder = new PayloadBuilder3({ schema: EncryptedWakeSubscriptionSchema });
1196
+ const builder = new PayloadBuilder5({ schema: EncryptedWakeSubscriptionSchema });
787
1197
  const cleartext = WakeSubscriptionCleartextZod3.parse(builder.fields({
788
1198
  subscriptionId: input.subscriptionId ?? generateHandshakeId2(),
789
1199
  revision: input.revision ?? 1,
@@ -795,6 +1205,7 @@ async function createEncryptedWakeSubscription(input) {
795
1205
  keyId: input.publisherKey.keyId,
796
1206
  grant: input.grant,
797
1207
  eventKind: SOURCE_WAKE_EVENT_KIND,
1208
+ deliveryMode: input.plaintext.filter.deliveryMode,
798
1209
  expiresAtBlock: input.expiresAtBlock
799
1210
  }).build());
800
1211
  return await encryptWakeSubscription({
@@ -805,7 +1216,7 @@ async function createEncryptedWakeSubscription(input) {
805
1216
  });
806
1217
  }
807
1218
  function createWakeSubscriptionAcceptance(input) {
808
- const builder = new PayloadBuilder3({ schema: WakeSubscriptionAcceptanceSchema });
1219
+ const builder = new PayloadBuilder5({ schema: WakeSubscriptionAcceptanceSchema });
809
1220
  return WakeSubscriptionAcceptanceZod.parse(builder.fields({
810
1221
  challenge: input.challenge,
811
1222
  encryptionKey: input.encryptionKey,
@@ -816,47 +1227,45 @@ function createWakeSubscriptionAcceptance(input) {
816
1227
  }).build());
817
1228
  }
818
1229
  function createPublisherServiceRevocation(service) {
819
- const builder = new PayloadBuilder3({ schema: PublisherServiceRevocationSchema });
1230
+ const builder = new PayloadBuilder5({ schema: PublisherServiceRevocationSchema });
820
1231
  return PublisherServiceRevocationZod.parse(builder.fields({ service }).build());
821
1232
  }
822
1233
  function createPublisherEncryptionKeyRevocation(key) {
823
- const builder = new PayloadBuilder3({ schema: PublisherEncryptionKeyRevocationSchema });
1234
+ const builder = new PayloadBuilder5({ schema: PublisherEncryptionKeyRevocationSchema });
824
1235
  return PublisherEncryptionKeyRevocationZod.parse(builder.fields({ key }).build());
825
1236
  }
826
1237
  function createWakeGrantRevocation(grant) {
827
- const builder = new PayloadBuilder3({ schema: WakeGrantRevocationSchema });
1238
+ const builder = new PayloadBuilder5({ schema: WakeGrantRevocationSchema });
828
1239
  return WakeGrantRevocationZod.parse(builder.fields({ grant }).build());
829
1240
  }
830
1241
  function createWakeSubscriptionRevocation(subscription) {
831
- const builder = new PayloadBuilder3({ schema: WakeSubscriptionRevocationSchema });
1242
+ const builder = new PayloadBuilder5({ schema: WakeSubscriptionRevocationSchema });
832
1243
  return WakeSubscriptionRevocationZod.parse(builder.fields({ subscription }).build());
833
1244
  }
834
1245
  function createWakeSubscriptionAcceptanceRevocation(acceptance) {
835
- const builder = new PayloadBuilder3({ schema: WakeSubscriptionAcceptanceRevocationSchema });
1246
+ const builder = new PayloadBuilder5({ schema: WakeSubscriptionAcceptanceRevocationSchema });
836
1247
  return WakeSubscriptionAcceptanceRevocationZod.parse(builder.fields({ acceptance }).build());
837
1248
  }
838
1249
 
839
1250
  // src/lifecycleSelection.ts
840
- function isNonnegativeSafeInteger2(value) {
1251
+ function isNonnegativeSafeInteger3(value) {
841
1252
  return Number.isSafeInteger(value) && value >= 0;
842
1253
  }
843
1254
  function isVisible(claimedAtBlock, finalizedHead) {
844
- return isNonnegativeSafeInteger2(claimedAtBlock) && claimedAtBlock <= finalizedHead;
1255
+ return isNonnegativeSafeInteger3(claimedAtBlock) && claimedAtBlock <= finalizedHead;
845
1256
  }
846
1257
  function isRevoked(revokedAtBlock, finalizedHead) {
847
1258
  return revokedAtBlock !== void 0 && revokedAtBlock <= finalizedHead;
848
1259
  }
849
1260
  function isUnrevokedEvidence(claimedAtBlock, revokedAtBlock, finalizedHead) {
850
- return isVisible(claimedAtBlock, finalizedHead) && (revokedAtBlock === void 0 || isNonnegativeSafeInteger2(revokedAtBlock) && revokedAtBlock >= claimedAtBlock) && !isRevoked(revokedAtBlock, finalizedHead);
1261
+ return isVisible(claimedAtBlock, finalizedHead) && (revokedAtBlock === void 0 || isNonnegativeSafeInteger3(revokedAtBlock) && revokedAtBlock >= claimedAtBlock) && !isRevoked(revokedAtBlock, finalizedHead);
851
1262
  }
852
1263
  function isInsideExclusiveWindow(finalizedHead, validFromBlock, expiresAtBlock) {
853
- if (!isNonnegativeSafeInteger2(validFromBlock) || finalizedHead < validFromBlock) return false;
854
- return expiresAtBlock === void 0 || isNonnegativeSafeInteger2(expiresAtBlock) && expiresAtBlock > validFromBlock && finalizedHead < expiresAtBlock;
1264
+ return isNonnegativeSafeInteger3(validFromBlock) && finalizedHead >= validFromBlock && (expiresAtBlock === void 0 || isNonnegativeSafeInteger3(expiresAtBlock) && expiresAtBlock > validFromBlock && finalizedHead < expiresAtBlock);
855
1265
  }
856
1266
  function isRevisionShapeValid(revision) {
857
- if (!Number.isSafeInteger(revision.revision) || revision.revision < 1) return false;
858
- if (!isNonnegativeSafeInteger2(revision.claimedAtBlock)) return false;
859
- if (revision.revokedAtBlock !== void 0 && (!isNonnegativeSafeInteger2(revision.revokedAtBlock) || revision.revokedAtBlock < revision.claimedAtBlock)) return false;
1267
+ if (!Number.isSafeInteger(revision.revision) || revision.revision < 1 || !isNonnegativeSafeInteger3(revision.claimedAtBlock)) return false;
1268
+ if (revision.revokedAtBlock !== void 0 && (!isNonnegativeSafeInteger3(revision.revokedAtBlock) || revision.revokedAtBlock < revision.claimedAtBlock)) return false;
860
1269
  return revision.revision === 1 ? revision.supersedes === void 0 : revision.supersedes !== void 0;
861
1270
  }
862
1271
  function resolveLinearChain(revisions, finalizedHead) {
@@ -929,8 +1338,7 @@ function selectPublisherService(input) {
929
1338
  }
930
1339
  }
931
1340
  if (selectable.length === 0) return { ok: false, reason: "service-not-found" };
932
- if (selectable.length > 1) return { ok: false, reason: "ambiguous-service" };
933
- return { ok: true, service: selectable[0] };
1341
+ return selectable.length > 1 ? { ok: false, reason: "ambiguous-service" } : { ok: true, service: selectable[0] };
934
1342
  }
935
1343
  function resolvePreferredEncryptionKey(input) {
936
1344
  const preferredHash = input.service.preferredEncryptionKey;
@@ -943,10 +1351,7 @@ function resolvePreferredEncryptionKey(input) {
943
1351
  const key = exact[0];
944
1352
  const sameStableIdentity = input.keys.filter((candidate) => candidate.source === key.source && candidate.keyId === key.keyId && candidate.objectHash !== key.objectHash && isVisible(candidate.claimedAtBlock, input.finalizedHead));
945
1353
  if (sameStableIdentity.length > 0) return { ok: false, reason: "ambiguous-key" };
946
- if (!isUnrevokedEvidence(key.claimedAtBlock, key.revokedAtBlock, input.finalizedHead) || !isInsideExclusiveWindow(input.finalizedHead, key.validFromBlock, key.expiresAtBlock)) {
947
- return { ok: false, reason: "preferred-key-inactive" };
948
- }
949
- return { ok: true, key };
1354
+ return !isUnrevokedEvidence(key.claimedAtBlock, key.revokedAtBlock, input.finalizedHead) || !isInsideExclusiveWindow(input.finalizedHead, key.validFromBlock, key.expiresAtBlock) ? { ok: false, reason: "preferred-key-inactive" } : { ok: true, key };
950
1355
  }
951
1356
  function acceptanceFor(subscription, input) {
952
1357
  return input.acceptances.filter((acceptance) => acceptance.source === input.publisherSource && acceptance.subscription === subscription.objectHash && isVisible(acceptance.acceptanceBlock, input.finalizedHead));
@@ -955,7 +1360,7 @@ function acceptedSubscription(subscription, input) {
955
1360
  const acceptances = acceptanceFor(subscription, input);
956
1361
  if (acceptances.length > 1) return "ambiguous";
957
1362
  const acceptance = acceptances[0];
958
- if (acceptance === void 0 || !isNonnegativeSafeInteger2(acceptance.acceptanceBlock)) return void 0;
1363
+ if (acceptance === void 0 || !isNonnegativeSafeInteger3(acceptance.acceptanceBlock)) return void 0;
959
1364
  if (!Number.isSafeInteger(subscription.expiresAtBlock) || subscription.expiresAtBlock < 1) return void 0;
960
1365
  if (acceptance.acceptanceBlock <= subscription.claimedAtBlock || acceptance.acceptanceBlock >= Number.MAX_SAFE_INTEGER) return void 0;
961
1366
  const activeFromBlock = acceptance.acceptanceBlock + 1;
@@ -991,10 +1396,7 @@ function selectSubscriptionActivation(input) {
991
1396
  if (selected === void 0) return { ok: false, reason: "subscription-pending" };
992
1397
  const latest = resolution.chain.at(-1);
993
1398
  if (!isActiveAcceptedSubscription(selected, input.finalizedHead)) {
994
- if (latest?.objectHash !== selected.subscription.objectHash) {
995
- return { ok: false, reason: "subscription-pending" };
996
- }
997
- return { ok: false, reason: "subscription-inactive" };
1399
+ return { ok: false, reason: latest?.objectHash === selected.subscription.objectHash ? "subscription-inactive" : "subscription-pending" };
998
1400
  }
999
1401
  return {
1000
1402
  acceptance: selected.acceptance,
@@ -1225,43 +1627,20 @@ function createMemoryWakeQueue() {
1225
1627
 
1226
1628
  // src/publisherSubscription.ts
1227
1629
  import {
1228
- ChainIdZod,
1630
+ ChainIdZod as ChainIdZod2,
1229
1631
  EncryptedWakeSubscriptionZod as EncryptedWakeSubscriptionZod4,
1230
1632
  EndpointChallengeZod as EndpointChallengeZod3,
1231
- HashZod as HashZod4,
1633
+ HashZod as HashZod6,
1232
1634
  hasMatchingHandshakeProfile,
1233
- NormalizedAddressZod as NormalizedAddressZod4,
1635
+ NormalizedAddressZod as NormalizedAddressZod6,
1234
1636
  PublisherEncryptionKeyZod as PublisherEncryptionKeyZod2,
1235
1637
  PublisherServiceZod as PublisherServiceZod2,
1236
1638
  WakeGrantObjectZod as WakeGrantObjectZod2
1237
1639
  } from "@xyo-network/event-kit-schemas";
1238
-
1239
- // src/sourceWakeIdentity.ts
1240
- import {
1241
- SourceWakeSubscriptionFilterZod,
1242
- WakeSourceSchema,
1243
- WakeSourceZod
1244
- } from "@xyo-network/event-kit-schemas";
1245
- import {
1246
- asSchema,
1247
- PayloadBuilder as PayloadBuilder4
1248
- } from "@xyo-network/sdk";
1249
- async function wakeSourceHash(source) {
1250
- return await PayloadBuilder4.dataHash({ schema: WakeSourceSchema, ...WakeSourceZod.parse(source) });
1251
- }
1252
- function wakeSourcesEqual(left, right) {
1253
- return canonicalJson(WakeSourceZod.parse(left)) === canonicalJson(WakeSourceZod.parse(right));
1254
- }
1255
- async function sourceWakeFilterHash(filter) {
1256
- const parsed = SourceWakeSubscriptionFilterZod.parse(filter);
1257
- return await PayloadBuilder4.dataHash({ ...parsed, schema: asSchema(parsed.schema, true) });
1258
- }
1259
-
1260
- // src/publisherSubscription.ts
1261
1640
  function rejectPublisherSubscription(reason) {
1262
1641
  return Object.freeze({ ok: false, reason });
1263
1642
  }
1264
- function isNonnegativeSafeInteger3(value) {
1643
+ function isNonnegativeSafeInteger4(value) {
1265
1644
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
1266
1645
  }
1267
1646
  function isActiveAt(value, block) {
@@ -1278,7 +1657,7 @@ function hasExactQueueScope(grant, plaintext) {
1278
1657
  return plaintext.deploymentId === grant.deploymentId && plaintext.queueId === grantQueue;
1279
1658
  }
1280
1659
  function hasExactSubscriptionBinding(candidate, subscription) {
1281
- return subscription.chainId === candidate.chainId && subscription.publisher === candidate.publisher && subscription.service === candidate.service.objectHash && subscription.encryptionKey === candidate.key.objectHash && subscription.keyId === candidate.key.body.keyId && subscription.grant === candidate.grant.objectHash;
1660
+ return subscription.deliveryMode === candidate.service.body.deliveryMode && subscription.chainId === candidate.chainId && subscription.publisher === candidate.publisher && subscription.service === candidate.service.objectHash && subscription.encryptionKey === candidate.key.objectHash && subscription.keyId === candidate.key.body.keyId && subscription.grant === candidate.grant.objectHash;
1282
1661
  }
1283
1662
  function hasExactKeyBinding(service, key, subscription) {
1284
1663
  return service.encryptionKeys.includes(key.objectHash) && service.preferredEncryptionKey === key.objectHash && key.body.keyId === subscription.keyId && key.objectHash === subscription.encryptionKey;
@@ -1289,22 +1668,22 @@ function expiryWithinServicePolicy(subscription, service, tupleBlock) {
1289
1668
  function parsePublisherSubscriptionCandidate(candidate) {
1290
1669
  try {
1291
1670
  return {
1292
- chainId: ChainIdZod.parse(candidate.chainId),
1671
+ chainId: ChainIdZod2.parse(candidate.chainId),
1293
1672
  grant: WakeGrantObjectZod2.parse(candidate.grant.body),
1294
1673
  key: PublisherEncryptionKeyZod2.parse(candidate.key.body),
1295
- publisher: NormalizedAddressZod4.parse(candidate.publisher),
1674
+ publisher: NormalizedAddressZod6.parse(candidate.publisher),
1296
1675
  service: PublisherServiceZod2.parse(candidate.service.body),
1297
- subscriber: NormalizedAddressZod4.parse(candidate.subscriber),
1676
+ subscriber: NormalizedAddressZod6.parse(candidate.subscriber),
1298
1677
  subscription: EncryptedWakeSubscriptionZod4.parse(candidate.subscription.body),
1299
- tupleObjectHashes: candidate.tupleObjectHashes.map((hash) => HashZod4.parse(hash)),
1300
- tupleSubject: NormalizedAddressZod4.parse(candidate.tupleSubject)
1678
+ tupleObjectHashes: candidate.tupleObjectHashes.map((hash) => HashZod6.parse(hash)),
1679
+ tupleSubject: NormalizedAddressZod6.parse(candidate.tupleSubject)
1301
1680
  };
1302
1681
  } catch {
1303
1682
  return void 0;
1304
1683
  }
1305
1684
  }
1306
1685
  function tupleBindingIsValid(candidate, parsed) {
1307
- return isNonnegativeSafeInteger3(candidate.tupleBlock) && isNonnegativeSafeInteger3(candidate.finalizedHead) && candidate.finalizedHead >= candidate.tupleBlock && parsed.tupleSubject === parsed.publisher && occursExactlyOnce(parsed.tupleObjectHashes, candidate.service.objectHash) && occursExactlyOnce(parsed.tupleObjectHashes, candidate.grant.objectHash) && occursExactlyOnce(parsed.tupleObjectHashes, candidate.subscription.objectHash);
1686
+ return isNonnegativeSafeInteger4(candidate.tupleBlock) && isNonnegativeSafeInteger4(candidate.finalizedHead) && candidate.finalizedHead >= candidate.tupleBlock && parsed.tupleSubject === parsed.publisher && occursExactlyOnce(parsed.tupleObjectHashes, candidate.service.objectHash) && occursExactlyOnce(parsed.tupleObjectHashes, candidate.grant.objectHash) && occursExactlyOnce(parsed.tupleObjectHashes, candidate.subscription.objectHash);
1308
1687
  }
1309
1688
  async function bodyHashesAreValid(candidate, parsed) {
1310
1689
  const canonicalHashes = await Promise.all([
@@ -1323,8 +1702,7 @@ function publicBindingFailure(candidate, parsed) {
1323
1702
  if (!hasExactKeyBinding(parsed.service, hashedKey, parsed.subscription)) return "key-binding-invalid";
1324
1703
  if (!isActiveAt(parsed.service, candidate.tupleBlock) || !isActiveAt(parsed.service, candidate.finalizedHead)) return "service-inactive";
1325
1704
  if (!isActiveAt(parsed.key, candidate.tupleBlock) || !isActiveAt(parsed.key, candidate.finalizedHead)) return "key-inactive";
1326
- if (!expiryWithinServicePolicy(parsed.subscription, parsed.service, candidate.tupleBlock) || parsed.subscription.expiresAtBlock - candidate.finalizedHead <= 2) return "subscription-expiry-invalid";
1327
- return void 0;
1705
+ return !expiryWithinServicePolicy(parsed.subscription, parsed.service, candidate.tupleBlock) || parsed.subscription.expiresAtBlock - candidate.finalizedHead <= 2 ? "subscription-expiry-invalid" : void 0;
1328
1706
  }
1329
1707
  async function decryptCandidate(candidate, parsed) {
1330
1708
  let privateKey;
@@ -1388,19 +1766,14 @@ async function validateAndDecryptPublisherSubscription(candidate) {
1388
1766
  if (!hasExactQueueScope(parsed.grant, decrypted.plaintext)) {
1389
1767
  return rejectPublisherSubscription("grant-scope-invalid");
1390
1768
  }
1391
- if (!filterWithinServicePolicy(parsed.service, decrypted.plaintext)) {
1392
- return rejectPublisherSubscription("service-limit-invalid");
1393
- }
1394
- return validatedPublisherSubscription(candidate, parsed, decrypted.plaintext);
1769
+ return filterWithinServicePolicy(parsed.service, decrypted.plaintext) ? validatedPublisherSubscription(candidate, parsed, decrypted.plaintext) : rejectPublisherSubscription("service-limit-invalid");
1395
1770
  }
1396
1771
  function endpointChallengeMatchesPublisherContext(challenge, context) {
1397
1772
  const parsed = EndpointChallengeZod3.safeParse(challenge);
1398
- if (!parsed.success) return false;
1399
- return parsed.data.chainId === context.chainId && parsed.data.publisher === context.publisher && parsed.data.subscriber === context.subscriber && parsed.data.service === context.service && parsed.data.encryptionKey === context.encryptionKey && parsed.data.keyId === context.keyId && parsed.data.subscription === context.subscription && parsed.data.grant === context.grant && parsed.data.eventKind === context.eventKind;
1773
+ return parsed.success && parsed.data.chainId === context.chainId && parsed.data.publisher === context.publisher && parsed.data.subscriber === context.subscriber && parsed.data.service === context.service && parsed.data.encryptionKey === context.encryptionKey && parsed.data.keyId === context.keyId && parsed.data.subscription === context.subscription && parsed.data.grant === context.grant && parsed.data.eventKind === context.eventKind;
1400
1774
  }
1401
1775
  async function challengeRecordMatches(record, challenge, challengeHash, responseHash) {
1402
- if (record.challengeHash !== challengeHash || await endpointChallengeHash(record.challenge) !== challengeHash || await endpointChallengeHash(challenge) !== challengeHash) return false;
1403
- return responseHash === void 0 || record.responseHash === responseHash;
1776
+ return record.challengeHash === challengeHash && await endpointChallengeHash(record.challenge) === challengeHash && await endpointChallengeHash(challenge) === challengeHash && (responseHash === void 0 || record.responseHash === responseHash);
1404
1777
  }
1405
1778
  async function issuePublisherEndpointChallenge(input) {
1406
1779
  const context = input.subscription.context;
@@ -1428,10 +1801,10 @@ async function issuePublisherEndpointChallenge(input) {
1428
1801
  }
1429
1802
  }
1430
1803
  async function beginPublisherEndpointChallengeAttempt(input) {
1431
- if (!isNonnegativeSafeInteger3(input.nowSeconds)) return { kind: "store-invalid" };
1804
+ if (!isNonnegativeSafeInteger4(input.nowSeconds)) return { kind: "store-invalid" };
1432
1805
  try {
1433
1806
  const result = await input.store.beginAttempt({
1434
- challengeHash: HashZod4.parse(input.challengeHash),
1807
+ challengeHash: HashZod6.parse(input.challengeHash),
1435
1808
  nowSeconds: input.nowSeconds
1436
1809
  });
1437
1810
  if (!["already-attempted", "expired", "missing", "started", "verified"].includes(result.kind)) {
@@ -1440,11 +1813,10 @@ async function beginPublisherEndpointChallengeAttempt(input) {
1440
1813
  if (result.kind !== "missing" && !await challengeRecordMatches(
1441
1814
  result.record,
1442
1815
  result.record.challenge,
1443
- HashZod4.parse(input.challengeHash)
1816
+ HashZod6.parse(input.challengeHash)
1444
1817
  )) return { kind: "store-invalid" };
1445
1818
  if ((result.kind === "started" || result.kind === "already-attempted") && result.record.state !== "attempted") return { kind: "store-invalid" };
1446
- if (result.kind === "verified" && result.record.state !== "verified") return { kind: "store-invalid" };
1447
- return result;
1819
+ return result.kind === "verified" && result.record.state !== "verified" ? { kind: "store-invalid" } : result;
1448
1820
  } catch {
1449
1821
  return { kind: "store-unavailable" };
1450
1822
  }
@@ -1461,16 +1833,13 @@ async function validateChallengeCompletion(input, result, challengeHash, respons
1461
1833
  if (result.kind === "expired") return completeFailure("challenge-expired");
1462
1834
  if (result.kind === "not-attempted") return completeFailure("challenge-not-attempted");
1463
1835
  if (result.kind === "collision") return completeFailure("challenge-response-collision");
1464
- if (result.kind !== "duplicate" && result.kind !== "verified" || !await challengeRecordMatches(result.record, input.challenge, challengeHash, responseHash)) {
1465
- return completeFailure("challenge-store-invalid");
1466
- }
1467
- return result;
1836
+ return result.kind !== "duplicate" && result.kind !== "verified" || !await challengeRecordMatches(result.record, input.challenge, challengeHash, responseHash) ? completeFailure("challenge-store-invalid") : result;
1468
1837
  }
1469
1838
  async function completePublisherEndpointChallenge(input) {
1470
1839
  if (!endpointChallengeMatchesPublisherContext(input.challenge, input.subscription.context)) {
1471
1840
  return completeFailure("challenge-context-invalid");
1472
1841
  }
1473
- if (!isNonnegativeSafeInteger3(input.nowSeconds)) return completeFailure("challenge-expired");
1842
+ if (!isNonnegativeSafeInteger4(input.nowSeconds)) return completeFailure("challenge-expired");
1474
1843
  const insideDecisionWindow = input.challenge.issuedAt <= input.nowSeconds && input.nowSeconds < input.challenge.expiresAt;
1475
1844
  const proofInput = {
1476
1845
  challenge: input.challenge,
@@ -1520,33 +1889,33 @@ async function completePublisherEndpointChallenge(input) {
1520
1889
  }
1521
1890
  function filterWithinServicePolicy(service, plaintext) {
1522
1891
  const filter = plaintext.filter;
1523
- return filter.maxPositionsPerWake <= service.limits.maxPositionsPerWake && service.events.some((event) => wakeSourcesEqual(event.source, filter.source));
1892
+ return service.deliveryMode === filter.deliveryMode && JSON.stringify(service.bestEffort) === JSON.stringify(filter.bestEffort) && filter.maxPositionsPerWake <= service.limits.maxPositionsPerWake && service.events.some((event) => wakeSourcesEqual(event.source, filter.source));
1524
1893
  }
1525
1894
 
1526
1895
  // src/sourceWakeActivation.ts
1527
1896
  import {
1528
- ChainIdZod as ChainIdZod2,
1529
- DeploymentIdZod as DeploymentIdZod2,
1530
- HashZod as HashZod5,
1531
- NonnegativeJsonSafeIntegerZod as NonnegativeJsonSafeIntegerZod2,
1532
- NormalizedAddressZod as NormalizedAddressZod5,
1533
- PositiveJsonSafeIntegerZod
1897
+ ChainIdZod as ChainIdZod3,
1898
+ DeploymentIdZod as DeploymentIdZod3,
1899
+ HashZod as HashZod7,
1900
+ NonnegativeJsonSafeIntegerZod as NonnegativeJsonSafeIntegerZod4,
1901
+ NormalizedAddressZod as NormalizedAddressZod7,
1902
+ PositiveJsonSafeIntegerZod as PositiveJsonSafeIntegerZod2
1534
1903
  } from "@xyo-network/event-kit-schemas";
1535
- import { z as z2 } from "zod";
1536
- var SourceWakeSubscriptionActivationZod = z2.strictObject({
1537
- atBlock: NonnegativeJsonSafeIntegerZod2,
1538
- activeFromBlock: NonnegativeJsonSafeIntegerZod2,
1539
- expiresAtBlock: PositiveJsonSafeIntegerZod,
1540
- authorizationChainId: ChainIdZod2,
1541
- controller: NormalizedAddressZod5,
1542
- publisher: NormalizedAddressZod5,
1543
- deploymentId: DeploymentIdZod2,
1544
- queueId: z2.string().min(1).max(255).optional(),
1545
- sourceHash: HashZod5,
1546
- filterHash: HashZod5,
1547
- subscriptionHash: HashZod5,
1548
- serviceHash: HashZod5,
1549
- grantHash: HashZod5
1904
+ import { z as z4 } from "zod";
1905
+ var SourceWakeSubscriptionActivationZod = z4.strictObject({
1906
+ atBlock: NonnegativeJsonSafeIntegerZod4,
1907
+ activeFromBlock: NonnegativeJsonSafeIntegerZod4,
1908
+ expiresAtBlock: PositiveJsonSafeIntegerZod2,
1909
+ authorizationChainId: ChainIdZod3,
1910
+ controller: NormalizedAddressZod7,
1911
+ publisher: NormalizedAddressZod7,
1912
+ deploymentId: DeploymentIdZod3,
1913
+ queueId: z4.string().min(1).max(255).optional(),
1914
+ sourceHash: HashZod7,
1915
+ filterHash: HashZod7,
1916
+ subscriptionHash: HashZod7,
1917
+ serviceHash: HashZod7,
1918
+ grantHash: HashZod7
1550
1919
  }).refine(
1551
1920
  (value) => value.activeFromBlock <= value.atBlock && value.atBlock < value.expiresAtBlock,
1552
1921
  "Subscription must be active at the exact finalized authorization snapshot"
@@ -1554,17 +1923,17 @@ var SourceWakeSubscriptionActivationZod = z2.strictObject({
1554
1923
 
1555
1924
  // src/statementGraphWakeGrantAuthorizer.ts
1556
1925
  import {
1557
- ChainIdZod as ChainIdZod3,
1558
- WakeSourceZod as WakeSourceZod2
1926
+ ChainIdZod as ChainIdZod4,
1927
+ WakeSourceZod as WakeSourceZod3
1559
1928
  } from "@xyo-network/event-kit-schemas";
1560
1929
 
1561
1930
  // src/grantEvidence.ts
1562
1931
  import {
1563
1932
  asWakeGrantObject,
1564
1933
  asWakeGrantRevocation,
1565
- DeploymentIdZod as DeploymentIdZod3,
1566
- HashZod as HashZod6,
1567
- NormalizedAddressZod as NormalizedAddressZod6,
1934
+ DeploymentIdZod as DeploymentIdZod4,
1935
+ HashZod as HashZod8,
1936
+ NormalizedAddressZod as NormalizedAddressZod8,
1568
1937
  WakeGrantObjectSchema as WakeGrantObjectSchema3,
1569
1938
  WakeGrantRevocationSchema as WakeGrantRevocationSchema3
1570
1939
  } from "@xyo-network/event-kit-schemas";
@@ -1620,9 +1989,7 @@ async function readRevocations(viewer, controller, subject, atBlock) {
1620
1989
  for (const claim of claims) {
1621
1990
  if (!isLiveClaim(claim, controller, subject, WakeGrantRevocationSchema3, atBlock)) continue;
1622
1991
  const object = await viewer.object(claim.objectHash);
1623
- if (object?.assurance !== "resolved") continue;
1624
- if (object.declaredSchema !== WakeGrantRevocationSchema3 || object.objectHash !== claim.objectHash) continue;
1625
- if (!isRecord2(object.params) || Object.hasOwn(object.params, "schema")) continue;
1992
+ if (object?.assurance !== "resolved" || object.declaredSchema !== WakeGrantRevocationSchema3 || object.objectHash !== claim.objectHash || !isRecord3(object.params) || Object.hasOwn(object.params, "schema")) continue;
1626
1993
  const revocation = asWakeGrantRevocation({ ...object.params, schema: object.declaredSchema });
1627
1994
  if (revocation !== void 0) revoked.add(revocation.grant);
1628
1995
  }
@@ -1654,61 +2021,55 @@ async function resolveEvidence(viewer, claim, request, atBlock, revokedGrantHash
1654
2021
  });
1655
2022
  }
1656
2023
  function isLiveClaim(claim, controller, subject, declaredObjectSchema, atBlock) {
1657
- if (claim.source !== controller) return false;
1658
- if (claim.subject !== subject) return false;
1659
- if (claim.declaredObjectSchema !== declaredObjectSchema) return false;
1660
- if (!isNonnegativeSafeInteger4(claim.firstBlock) || claim.firstBlock > atBlock) return false;
1661
- if (!isNonnegativeSafeInteger4(claim.lastBlock) || claim.lastBlock < claim.firstBlock) return false;
1662
- if (!HashZod6.safeParse(claim.firstEventHash).success) return false;
1663
- return HashZod6.safeParse(claim.objectHash).success;
2024
+ return claim.source === controller && claim.subject === subject && claim.declaredObjectSchema === declaredObjectSchema && isNonnegativeSafeInteger5(claim.firstBlock) && claim.firstBlock <= atBlock && isNonnegativeSafeInteger5(claim.lastBlock) && claim.lastBlock >= claim.firstBlock && HashZod8.safeParse(claim.firstEventHash).success && HashZod8.safeParse(claim.objectHash).success;
1664
2025
  }
1665
2026
  function parseExactGrantObject(object, expectedObjectHash) {
1666
2027
  if (object?.assurance !== "resolved") return void 0;
1667
2028
  if (object.declaredSchema !== WakeGrantObjectSchema3 || object.objectHash !== expectedObjectHash) return void 0;
1668
- if (!isRecord2(object.params) || Object.hasOwn(object.params, "schema")) return void 0;
2029
+ if (!isRecord3(object.params) || Object.hasOwn(object.params, "schema")) return void 0;
1669
2030
  return asWakeGrantObject({
1670
2031
  ...object.params,
1671
2032
  schema: object.declaredSchema
1672
2033
  });
1673
2034
  }
1674
2035
  function assertValidRequest(request) {
1675
- if (request.exactGrantHash !== void 0 && !HashZod6.safeParse(request.exactGrantHash).success) {
2036
+ if (request.exactGrantHash !== void 0 && !HashZod8.safeParse(request.exactGrantHash).success) {
1676
2037
  throw new TypeError("Exact grant hash must be canonical lowercase hexadecimal");
1677
2038
  }
1678
- if (!NormalizedAddressZod6.safeParse(request.controller).success) {
2039
+ if (!NormalizedAddressZod8.safeParse(request.controller).success) {
1679
2040
  throw new TypeError("Grant controller must be a normalized address");
1680
2041
  }
1681
- if (!NormalizedAddressZod6.safeParse(request.publisher).success) {
2042
+ if (!NormalizedAddressZod8.safeParse(request.publisher).success) {
1682
2043
  throw new TypeError("Grant publisher must be a normalized address");
1683
2044
  }
1684
- if (!DeploymentIdZod3.safeParse(request.deploymentId).success) {
2045
+ if (!DeploymentIdZod4.safeParse(request.deploymentId).success) {
1685
2046
  throw new TypeError("Grant deploymentId must contain 1 to 255 characters");
1686
2047
  }
1687
2048
  if (request.queueId !== void 0 && (request.queueId.length === 0 || request.queueId.length > 255)) {
1688
2049
  throw new TypeError("Grant queueId must contain 1 to 255 characters when configured");
1689
2050
  }
1690
- if (!isNonnegativeSafeInteger4(request.expectedHead)) {
2051
+ if (!isNonnegativeSafeInteger5(request.expectedHead)) {
1691
2052
  throw new RangeError("Grant expectedHead must be a nonnegative safe integer");
1692
2053
  }
1693
2054
  }
1694
2055
  async function readHead(viewer) {
1695
2056
  const head = await viewer.head();
1696
- if (!isNonnegativeSafeInteger4(head)) {
2057
+ if (!isNonnegativeSafeInteger5(head)) {
1697
2058
  throw new RangeError("Statement Graph head must be a nonnegative safe integer");
1698
2059
  }
1699
2060
  return head;
1700
2061
  }
1701
- function isNonnegativeSafeInteger4(value) {
2062
+ function isNonnegativeSafeInteger5(value) {
1702
2063
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
1703
2064
  }
1704
- function isRecord2(value) {
2065
+ function isRecord3(value) {
1705
2066
  return typeof value === "object" && value !== null && !Array.isArray(value);
1706
2067
  }
1707
2068
 
1708
2069
  // src/statementGraphWakeGrantAuthorizer.ts
1709
2070
  function createStatementGraphWakeGrantAuthorizer(options) {
1710
- const authorizationChainId = ChainIdZod3.parse(options.authorizationChainId);
1711
- const source = WakeSourceZod2.parse(options.source);
2071
+ const authorizationChainId = ChainIdZod4.parse(options.authorizationChainId);
2072
+ const source = WakeSourceZod3.parse(options.source);
1712
2073
  const grants = createDeploymentGrantAuthorizer({ viewer: options.viewer });
1713
2074
  return Object.freeze({
1714
2075
  async authorizePublisher(request) {
@@ -1740,196 +2101,6 @@ function createStatementGraphWakeGrantAuthorizer(options) {
1740
2101
  });
1741
2102
  }
1742
2103
 
1743
- // src/verifyWakeRequest.ts
1744
- import {
1745
- ChainIdZod as ChainIdZod4,
1746
- DeploymentIdZod as DeploymentIdZod4,
1747
- HashZod as HashZod7,
1748
- MAX_POSITIONS_PER_SUBSCRIPTION_WAKE,
1749
- NonnegativeJsonSafeIntegerZod as NonnegativeJsonSafeIntegerZod3,
1750
- NormalizedAddressZod as NormalizedAddressZod7,
1751
- PositiveJsonSafeIntegerZod as PositiveJsonSafeIntegerZod2,
1752
- SOURCE_WAKE_FILTER_PROFILE as SOURCE_WAKE_FILTER_PROFILE2,
1753
- WakeEnvelopeZod as WakeEnvelopeZod2,
1754
- WakeJwtAudienceZod as WakeJwtAudienceZod2,
1755
- WakeJwtHeaderZod,
1756
- WakeJwtPayloadZod,
1757
- WakeJwtSchema,
1758
- WakeSourceZod as WakeSourceZod3
1759
- } from "@xyo-network/event-kit-schemas";
1760
- import {
1761
- Account,
1762
- PayloadBuilder as PayloadBuilder5
1763
- } from "@xyo-network/sdk";
1764
- import { z as z3 } from "zod";
1765
- var EVENT_KIT_MAX_JWT_LIFETIME_SECONDS = 300;
1766
- var EVENT_KIT_MAX_FUTURE_IAT_SECONDS = 60;
1767
- var WakeAdmissionRouteZod = z3.strictObject({
1768
- audience: WakeJwtAudienceZod2,
1769
- authorizationChainId: ChainIdZod4,
1770
- controller: NormalizedAddressZod7,
1771
- deploymentId: DeploymentIdZod4,
1772
- queueId: z3.string().min(1).max(255).optional(),
1773
- source: WakeSourceZod3,
1774
- filterHash: HashZod7,
1775
- subscriptionHash: HashZod7,
1776
- fromPosition: NonnegativeJsonSafeIntegerZod3,
1777
- maxPositionsPerWake: PositiveJsonSafeIntegerZod2.max(MAX_POSITIONS_PER_SUBSCRIPTION_WAKE),
1778
- maxGrantLagBlocks: NonnegativeJsonSafeIntegerZod3
1779
- });
1780
- async function verifyWakeRequest(input) {
1781
- const routeResult = WakeAdmissionRouteZod.safeParse(input.route);
1782
- if (!routeResult.success || !NonnegativeJsonSafeIntegerZod3.safeParse(input.nowSeconds).success) {
1783
- return { ok: false, reason: "configuration-invalid" };
1784
- }
1785
- const eventResult = WakeEnvelopeZod2.safeParse(input.body);
1786
- if (!eventResult.success) return malformedWake(input.body, eventResult.error.issues);
1787
- const route = routeResult.data;
1788
- if (route.filterHash !== await sourceWakeFilterHash({
1789
- schema: SOURCE_WAKE_FILTER_PROFILE2,
1790
- source: route.source,
1791
- fromPosition: route.fromPosition,
1792
- maxPositionsPerWake: route.maxPositionsPerWake
1793
- })) return { ok: false, reason: "configuration-invalid" };
1794
- const event = Object.freeze({ ...eventResult.data, source: Object.freeze(eventResult.data.source) });
1795
- if (event.authorizationChainId !== route.authorizationChainId) {
1796
- return { ok: false, reason: "event-authorization-chain-mismatch" };
1797
- }
1798
- if (!wakeSourcesEqual(event.source, route.source)) return { ok: false, reason: "event-source-mismatch" };
1799
- if (event.filterHash !== route.filterHash) return { ok: false, reason: "event-filter-mismatch" };
1800
- if (event.deploymentId !== route.deploymentId || event.queueId !== route.queueId) {
1801
- return { ok: false, reason: "event-target-mismatch" };
1802
- }
1803
- if (event.fromPosition < route.fromPosition) return { ok: false, reason: "range-before-floor" };
1804
- if (event.toPosition - event.fromPosition >= route.maxPositionsPerWake) return { ok: false, reason: "range-too-large" };
1805
- const jwt = await verifyJwtProfile(input.jwt, route.audience, input.nowSeconds);
1806
- if (!jwt.ok) return jwt;
1807
- let eventHash;
1808
- try {
1809
- eventHash = await PayloadBuilder5.dataHash(event);
1810
- } catch {
1811
- return { ok: false, reason: "event-hash-failed" };
1812
- }
1813
- if (eventHash !== jwt.jwt.eventHash) return { ok: false, reason: "event-hash-mismatch" };
1814
- const sourceHash = await wakeSourceHash(route.source);
1815
- return Object.freeze({
1816
- ok: true,
1817
- verified: Object.freeze({
1818
- audience: route.audience,
1819
- deploymentId: event.deploymentId,
1820
- event,
1821
- eventHash,
1822
- expiresAt: jwt.jwt.expiresAt,
1823
- fromPosition: event.fromPosition,
1824
- issuedAt: event.issuedAt,
1825
- jwtId: jwt.jwt.jwtId,
1826
- publisher: jwt.jwt.publisher,
1827
- ...event.queueId === void 0 ? {} : { queueId: event.queueId },
1828
- route: Object.freeze({
1829
- ...route,
1830
- source: Object.freeze(route.source),
1831
- sourceHash
1832
- }),
1833
- toPosition: event.toPosition,
1834
- tokenIssuedAt: jwt.jwt.issuedAt,
1835
- wakeId: event.wakeId
1836
- })
1837
- });
1838
- }
1839
- async function verifyJwtProfile(token, audience, nowSeconds) {
1840
- let verified;
1841
- try {
1842
- verified = await Account.verifyJwt(token, { audience, now: nowSeconds });
1843
- } catch (error) {
1844
- return reject2("jwt-malformed", [errorMessage2(error)]);
1845
- }
1846
- if (!verified.ok) {
1847
- if (Object.hasOwn(verified.payload ?? {}, "nbf")) return reject2("jwt-nbf-not-allowed");
1848
- return reject2(classifySdkJwtFailure(verified.reasons), verified.reasons);
1849
- }
1850
- const wireResult = parseStrictJwtWire(verified.header, verified.payload, audience);
1851
- if (!wireResult.ok) return wireResult;
1852
- const { header: strictHeader, payload: strictPayload } = wireResult;
1853
- if (strictHeader.kid !== strictPayload.iss) return reject2("jwt-identity-invalid");
1854
- if (strictPayload.exp <= nowSeconds) return reject2("jwt-expired");
1855
- if (strictPayload.exp - strictPayload.iat > EVENT_KIT_MAX_JWT_LIFETIME_SECONDS) return reject2("jwt-lifetime-invalid");
1856
- if (strictPayload.iat - nowSeconds > EVENT_KIT_MAX_FUTURE_IAT_SECONDS) return reject2("jwt-future-iat");
1857
- const jwt = Object.freeze({
1858
- eventHash: strictPayload.eventHash,
1859
- expiresAt: strictPayload.exp,
1860
- issuedAt: strictPayload.iat,
1861
- jwtId: strictPayload.jti,
1862
- publisher: strictPayload.iss
1863
- });
1864
- return Object.freeze({ jwt, ok: true });
1865
- }
1866
- function parseStrictJwtWire(header, payload, audience) {
1867
- const headerResult = WakeJwtHeaderZod.safeParse(header);
1868
- if (!headerResult.success) {
1869
- if (!NormalizedAddressZod7.safeParse(header.kid).success) return reject2("jwt-identity-invalid");
1870
- return reject2("jwt-header-invalid", zodDetails(headerResult.error.issues));
1871
- }
1872
- if (Object.hasOwn(payload, "nbf")) return reject2("jwt-nbf-not-allowed");
1873
- if (!NormalizedAddressZod7.safeParse(payload.iss).success) return reject2("jwt-identity-invalid");
1874
- if (payload.schema !== WakeJwtSchema) return reject2("jwt-schema-mismatch");
1875
- if (payload.aud !== audience) return reject2("jwt-audience-mismatch");
1876
- if (!isNonnegativeSafeInteger5(payload.iat) || !isNonnegativeSafeInteger5(payload.exp) || payload.exp <= payload.iat) {
1877
- return reject2("jwt-lifetime-invalid");
1878
- }
1879
- const payloadResult = WakeJwtPayloadZod.safeParse(payload);
1880
- if (!payloadResult.success) return reject2("jwt-claims-invalid", zodDetails(payloadResult.error.issues));
1881
- return Object.freeze({
1882
- header: headerResult.data,
1883
- ok: true,
1884
- payload: payloadResult.data
1885
- });
1886
- }
1887
- function classifySdkJwtFailure(reasons) {
1888
- if (reasons.some((reason) => reason.startsWith("audience mismatch:"))) return "jwt-audience-mismatch";
1889
- if (reasons.some((reason) => reason.startsWith("expired:"))) return "jwt-expired";
1890
- if (reasons.some((reason) => reason.startsWith("unsupported alg:") || reason.startsWith("unsupported typ:"))) {
1891
- return "jwt-header-invalid";
1892
- }
1893
- if (reasons.some((reason) => reason.startsWith("invalid public key:") || reason.startsWith("public key does not derive to kid:") || reason === "header.kid does not match payload.iss")) {
1894
- return "jwt-identity-invalid";
1895
- }
1896
- return "jwt-invalid";
1897
- }
1898
- function malformedWake(body, issues) {
1899
- const details = zodDetails(issues);
1900
- if (hasInvertedSafeRange(body)) return reject2("range-invalid", details);
1901
- if (isRecord3(body) && Object.hasOwn(body, "wakeId") && issues.some((issue) => issue.path[0] === "wakeId")) return reject2("wake-id-invalid", details);
1902
- return reject2("event-malformed", details);
1903
- }
1904
- function hasInvertedSafeRange(value) {
1905
- if (!isRecord3(value)) return false;
1906
- const { fromPosition, toPosition } = value;
1907
- return typeof fromPosition === "number" && typeof toPosition === "number" && isNonnegativeSafeInteger5(fromPosition) && isNonnegativeSafeInteger5(toPosition) && fromPosition > toPosition;
1908
- }
1909
- function isNonnegativeSafeInteger5(value) {
1910
- return Number.isSafeInteger(value) && value >= 0;
1911
- }
1912
- function isRecord3(value) {
1913
- return typeof value === "object" && value !== null && !Array.isArray(value);
1914
- }
1915
- function zodDetails(issues) {
1916
- return issues.map((issue) => {
1917
- const path = issue.path.map(String).join(".") || "<root>";
1918
- return `${path}: ${issue.message}`;
1919
- });
1920
- }
1921
- function reject2(reason, details) {
1922
- if (details === void 0) return Object.freeze({ ok: false, reason });
1923
- return Object.freeze({
1924
- details: Object.freeze([...details]),
1925
- ok: false,
1926
- reason
1927
- });
1928
- }
1929
- function errorMessage2(error) {
1930
- return error instanceof Error ? error.message : String(error);
1931
- }
1932
-
1933
2104
  // src/wakeQueue.ts
1934
2105
  async function drainQueue(queue, handler) {
1935
2106
  let handled = 0;
@@ -1948,6 +2119,8 @@ async function drainQueue(queue, handler) {
1948
2119
  }
1949
2120
  export {
1950
2121
  AdmittedWakeZod,
2122
+ BestEffortAdmissionAcknowledgmentZod,
2123
+ BestEffortSecurityStateZod,
1951
2124
  EVENT_KIT_MAX_FUTURE_IAT_SECONDS,
1952
2125
  EVENT_KIT_MAX_JWT_LIFETIME_SECONDS,
1953
2126
  EVENT_KIT_REPLAY_RETENTION_SKEW_SECONDS,
@@ -1955,10 +2128,13 @@ export {
1955
2128
  WakeAdmissionRouteZod,
1956
2129
  WakeSubscriptionDecryptionError,
1957
2130
  admitAndEnqueue,
2131
+ admitBestEffortHint,
1958
2132
  beginPublisherEndpointChallengeAttempt,
1959
2133
  canonicalJson,
1960
2134
  canonicalJsonBytes,
2135
+ commitBestEffortSecurity,
1961
2136
  completePublisherEndpointChallenge,
2137
+ createBestEffortSecurityState,
1962
2138
  createEncryptedWakeSubscription,
1963
2139
  createEndpointChallenge,
1964
2140
  createEndpointChallengeResponse,
@@ -1986,6 +2162,7 @@ export {
1986
2162
  handshakeObjectHash,
1987
2163
  issuePublisherEndpointChallenge,
1988
2164
  parseAdmittedWake,
2165
+ parseBestEffortSecurityState,
1989
2166
  resolvePreferredEncryptionKey,
1990
2167
  selectPublisherService,
1991
2168
  selectSubscriptionActivation,