@xyo-network/event-kit-protocol 0.1.1 → 0.1.3

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 (39) hide show
  1. package/README.md +21 -6
  2. package/dist/neutral/admissionCore.d.ts +30 -0
  3. package/dist/neutral/admissionCore.d.ts.map +1 -0
  4. package/dist/neutral/admissionTypes.d.ts +16 -3
  5. package/dist/neutral/admissionTypes.d.ts.map +1 -1
  6. package/dist/neutral/admitAndEnqueue.d.ts +6 -21
  7. package/dist/neutral/admitAndEnqueue.d.ts.map +1 -1
  8. package/dist/neutral/endpointChallenge.d.ts +2 -2
  9. package/dist/neutral/endpointChallenge.d.ts.map +1 -1
  10. package/dist/neutral/grantEvidence.d.ts +20 -0
  11. package/dist/neutral/grantEvidence.d.ts.map +1 -0
  12. package/dist/neutral/handshakeConstruction.d.ts +8 -4
  13. package/dist/neutral/handshakeConstruction.d.ts.map +1 -1
  14. package/dist/neutral/index.d.ts +4 -1
  15. package/dist/neutral/index.d.ts.map +1 -1
  16. package/dist/neutral/index.mjs +345 -167
  17. package/dist/neutral/index.mjs.map +4 -4
  18. package/dist/neutral/memoryStatementGrantGraph.d.ts.map +1 -1
  19. package/dist/neutral/memoryWakeInbox.d.ts +5 -5
  20. package/dist/neutral/memoryWakeInbox.d.ts.map +1 -1
  21. package/dist/neutral/memoryWakeQueue.d.ts +3 -2
  22. package/dist/neutral/memoryWakeQueue.d.ts.map +1 -1
  23. package/dist/neutral/publisherSubscription.d.ts.map +1 -1
  24. package/dist/neutral/sourceWakeActivation.d.ts +24 -0
  25. package/dist/neutral/sourceWakeActivation.d.ts.map +1 -0
  26. package/dist/neutral/sourceWakeIdentity.d.ts +6 -0
  27. package/dist/neutral/sourceWakeIdentity.d.ts.map +1 -0
  28. package/dist/neutral/statementGraphWakeGrantAuthorizer.d.ts +9 -11
  29. package/dist/neutral/statementGraphWakeGrantAuthorizer.d.ts.map +1 -1
  30. package/dist/neutral/types.d.ts +41 -19
  31. package/dist/neutral/types.d.ts.map +1 -1
  32. package/dist/neutral/verifiedAdmissionWake.d.ts +22 -0
  33. package/dist/neutral/verifiedAdmissionWake.d.ts.map +1 -0
  34. package/dist/neutral/verifyWakeRequest.d.ts +41 -30
  35. package/dist/neutral/verifyWakeRequest.d.ts.map +1 -1
  36. package/dist/neutral/wakeQueue.d.ts +7 -7
  37. package/dist/neutral/wakeQueue.d.ts.map +1 -1
  38. package/dist/neutral/wakeSubscriptionHpke.d.ts.map +1 -1
  39. package/package.json +8 -8
@@ -1,12 +1,12 @@
1
1
  // src/admissionTypes.ts
2
2
  var EVENT_KIT_REPLAY_RETENTION_SKEW_SECONDS = 60;
3
3
 
4
- // src/admitAndEnqueue.ts
5
- async function admitAndEnqueue(input) {
4
+ // src/admissionCore.ts
5
+ async function admitVerifiedWake(input) {
6
6
  const attemptResult = createAttempt(input.verified);
7
7
  if (!attemptResult.ok) return attemptResult.failure;
8
8
  const { attempt } = attemptResult;
9
- const wake = toAdmittedWake(input.verified);
9
+ const { wake } = input;
10
10
  const prior = await resolvePriorAttempt(input.inbox, attempt, wake);
11
11
  if (!prior.pending) return prior.result;
12
12
  if (!isNonnegativeSafeInteger(input.expectedHead)) {
@@ -90,6 +90,10 @@ async function authorize(input) {
90
90
  try {
91
91
  decision = await input.grants.authorizePublisher({
92
92
  controller: route.controller,
93
+ authorizationChainId: route.authorizationChainId,
94
+ sourceHash: route.sourceHash,
95
+ filterHash: route.filterHash,
96
+ subscriptionHash: route.subscriptionHash,
93
97
  deploymentId: route.deploymentId,
94
98
  expectedHead: input.expectedHead,
95
99
  publisher: input.verified.publisher,
@@ -137,6 +141,10 @@ function validateGrantEvidence(evidence, verified, atBlock) {
137
141
  if (!isRecord(evidence)) return reject("grant-view-invalid", ["enabled grant decision omitted evidence"]);
138
142
  const requiredFields = [
139
143
  "assertedAtBlock",
144
+ "authorizationChainId",
145
+ "filterHash",
146
+ "sourceHash",
147
+ "subscriptionHash",
140
148
  "controller",
141
149
  "deploymentId",
142
150
  "id",
@@ -154,6 +162,9 @@ function validateGrantEvidence(evidence, verified, atBlock) {
154
162
  if (evidence.controller !== verified.route.controller) {
155
163
  return reject("grant-view-invalid", ["grant controller does not match the configured controller"]);
156
164
  }
165
+ if (evidence.authorizationChainId !== verified.route.authorizationChainId || evidence.sourceHash !== verified.route.sourceHash || evidence.filterHash !== verified.route.filterHash || evidence.subscriptionHash !== verified.route.subscriptionHash) {
166
+ return reject("grant-view-invalid", ["grant authorization chain or source does not match the configured route"]);
167
+ }
157
168
  if (evidence.target !== verified.publisher) {
158
169
  return reject("grant-view-invalid", ["grant target does not match the verified publisher"]);
159
170
  }
@@ -183,6 +194,11 @@ function validateReceipt(receipt, attempt) {
183
194
  function snapshotGrantEvidence(evidence) {
184
195
  return Object.freeze({
185
196
  assertedAtBlock: evidence.assertedAtBlock,
197
+ authorizationChainId: evidence.authorizationChainId,
198
+ sourceHash: evidence.sourceHash,
199
+ filterHash: evidence.filterHash,
200
+ subscriptionHash: evidence.subscriptionHash,
201
+ ...evidence.objectHash === void 0 ? {} : { objectHash: evidence.objectHash },
186
202
  controller: evidence.controller,
187
203
  deploymentId: evidence.deploymentId,
188
204
  id: evidence.id,
@@ -199,20 +215,6 @@ function snapshotReceipt(receipt) {
199
215
  wakeId: receipt.wakeId
200
216
  });
201
217
  }
202
- function toAdmittedWake(verified) {
203
- return Object.freeze({
204
- audience: verified.audience,
205
- deploymentId: verified.deploymentId,
206
- event: verified.event,
207
- eventHash: verified.eventHash,
208
- fromBlock: verified.fromBlock,
209
- jti: verified.jwtId,
210
- publisher: verified.publisher,
211
- ...verified.queueId === void 0 ? {} : { queueId: verified.queueId },
212
- toBlock: verified.toBlock,
213
- wakeId: verified.wakeId
214
- });
215
- }
216
218
  function success(disposition, receipt, wake) {
217
219
  return Object.freeze({
218
220
  disposition,
@@ -239,6 +241,60 @@ function errorMessage(error) {
239
241
  return error instanceof Error ? error.message : String(error);
240
242
  }
241
243
 
244
+ // src/types.ts
245
+ import {
246
+ DeploymentIdZod,
247
+ HashZod,
248
+ NonnegativeJsonSafeIntegerZod,
249
+ NormalizedAddressZod,
250
+ WakeEnvelopeZod,
251
+ WakeIdZod,
252
+ WakeJwtAudienceZod,
253
+ WakeJwtIdZod
254
+ } from "@xyo-network/event-kit-schemas";
255
+ import { PayloadBuilder } from "@xyo-network/sdk";
256
+ import { z } from "zod";
257
+ var AdmittedWakeZod = z.strictObject({
258
+ audience: WakeJwtAudienceZod,
259
+ deploymentId: DeploymentIdZod,
260
+ event: WakeEnvelopeZod,
261
+ eventHash: HashZod,
262
+ fromPosition: NonnegativeJsonSafeIntegerZod,
263
+ toPosition: NonnegativeJsonSafeIntegerZod,
264
+ jti: WakeJwtIdZod,
265
+ publisher: NormalizedAddressZod,
266
+ queueId: z.string().min(1).max(255).optional(),
267
+ wakeId: WakeIdZod
268
+ }).refine(
269
+ (wake) => wake.deploymentId === wake.event.deploymentId && wake.queueId === wake.event.queueId && wake.wakeId === wake.event.wakeId && wake.fromPosition === wake.event.fromPosition && wake.toPosition === wake.event.toPosition,
270
+ "Persisted admission metadata must exactly match its signed envelope"
271
+ );
272
+ async function parseAdmittedWake(value) {
273
+ const wake = AdmittedWakeZod.parse(value);
274
+ if (await PayloadBuilder.dataHash(wake.event) !== wake.eventHash) {
275
+ throw new TypeError("Persisted wake content does not match its admitted event hash");
276
+ }
277
+ return wake;
278
+ }
279
+
280
+ // src/admitAndEnqueue.ts
281
+ async function admitAndEnqueue(input) {
282
+ const { verified } = input;
283
+ const wake = AdmittedWakeZod.parse({
284
+ audience: verified.audience,
285
+ deploymentId: verified.deploymentId,
286
+ event: verified.event,
287
+ eventHash: verified.eventHash,
288
+ fromPosition: verified.fromPosition,
289
+ toPosition: verified.toPosition,
290
+ jti: verified.jwtId,
291
+ publisher: verified.publisher,
292
+ ...verified.queueId === void 0 ? {} : { queueId: verified.queueId },
293
+ wakeId: verified.wakeId
294
+ });
295
+ return await admitVerifiedWake({ ...input, wake });
296
+ }
297
+
242
298
  // src/canonicalJson.ts
243
299
  var textEncoder = new TextEncoder();
244
300
  function hasUnpairedSurrogate(value) {
@@ -301,7 +357,7 @@ import {
301
357
  generateHandshakeId,
302
358
  MAX_ENDPOINT_CHALLENGE_LIFETIME_SECONDS
303
359
  } from "@xyo-network/event-kit-schemas";
304
- import { PayloadBuilder } from "@xyo-network/sdk";
360
+ import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk";
305
361
  function hashBytes(hash) {
306
362
  return Uint8Array.from({ length: 32 }, (_, index) => Number.parseInt(hash.slice(index * 2, index * 2 + 2), 16));
307
363
  }
@@ -328,7 +384,7 @@ function equalProof(left, right) {
328
384
  }
329
385
  async function endpointChallengeHash(challenge) {
330
386
  const parsed = EndpointChallengeZod.parse(challenge);
331
- return await PayloadBuilder.dataHash(parsed);
387
+ return await PayloadBuilder2.dataHash(parsed);
332
388
  }
333
389
  function createEndpointChallenge(input) {
334
390
  const lifetimeSeconds = input.lifetimeSeconds ?? MAX_ENDPOINT_CHALLENGE_LIFETIME_SECONDS;
@@ -341,7 +397,7 @@ function createEndpointChallenge(input) {
341
397
  if (input.issuedAt > Number.MAX_SAFE_INTEGER - lifetimeSeconds) {
342
398
  throw new RangeError("Challenge expiry exceeds the JSON safe-integer range");
343
399
  }
344
- return EndpointChallengeZod.parse(new PayloadBuilder({ schema: EndpointChallengeSchema }).fields({
400
+ return EndpointChallengeZod.parse(new PayloadBuilder2({ schema: EndpointChallengeSchema }).fields({
345
401
  challengeId: generateHandshakeId(),
346
402
  chainId: input.chainId,
347
403
  publisher: input.publisher,
@@ -359,7 +415,7 @@ function createEndpointChallenge(input) {
359
415
  }
360
416
  async function createEndpointChallengeResponse(challenge, secret) {
361
417
  const challengeHash = await endpointChallengeHash(challenge);
362
- return EndpointChallengeResponseZod.parse(new PayloadBuilder({ schema: EndpointChallengeResponseSchema }).fields({
418
+ return EndpointChallengeResponseZod.parse(new PayloadBuilder2({ schema: EndpointChallengeResponseSchema }).fields({
363
419
  challenge: challengeHash,
364
420
  proof: await hmacProof(secret, challengeHash)
365
421
  }).build());
@@ -393,11 +449,9 @@ import {
393
449
  ENDPOINT_CHALLENGE_HMAC_SHA256_PROFILE,
394
450
  EndpointChallengeResponseZod as EndpointChallengeResponseZod2,
395
451
  EndpointChallengeZod as EndpointChallengeZod2,
396
- FINALIZED_HEAD_EVENT_KIND,
397
- FINALIZED_HEAD_FILTER_PROFILE,
398
452
  generateGrantId,
399
453
  generateHandshakeId as generateHandshakeId2,
400
- HashZod as HashZod2,
454
+ HashZod as HashZod3,
401
455
  MAX_SUBSCRIPTION_PLAINTEXT_BYTES as MAX_SUBSCRIPTION_PLAINTEXT_BYTES2,
402
456
  PublisherEncryptionKeyRevocationSchema,
403
457
  PublisherEncryptionKeyRevocationZod,
@@ -407,6 +461,8 @@ import {
407
461
  PublisherServiceRevocationZod,
408
462
  PublisherServiceSchema,
409
463
  PublisherServiceZod,
464
+ SOURCE_WAKE_EVENT_KIND,
465
+ SOURCE_WAKE_FILTER_PROFILE,
410
466
  WAKE_SUBSCRIPTION_HPKE_PROFILE as WAKE_SUBSCRIPTION_HPKE_PROFILE3,
411
467
  WAKE_WALLET_JWT_DELIVERY_PROFILE,
412
468
  WakeGrantObjectSchema,
@@ -423,7 +479,7 @@ import {
423
479
  WakeSubscriptionRevocationSchema,
424
480
  WakeSubscriptionRevocationZod
425
481
  } from "@xyo-network/event-kit-schemas";
426
- import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk";
482
+ import { PayloadBuilder as PayloadBuilder3 } from "@xyo-network/sdk";
427
483
 
428
484
  // src/wakeSubscriptionHpke.ts
429
485
  import {
@@ -438,8 +494,8 @@ import {
438
494
  canonicalBase64UrlToBytes as canonicalBase64UrlToBytes2,
439
495
  EncryptedWakeSubscriptionZod as EncryptedWakeSubscriptionZod2,
440
496
  HandshakeIdZod,
441
- HashZod,
442
- NormalizedAddressZod as NormalizedAddressZod2,
497
+ HashZod as HashZod2,
498
+ NormalizedAddressZod as NormalizedAddressZod3,
443
499
  WAKE_SUBSCRIPTION_HPKE_PROFILE as WAKE_SUBSCRIPTION_HPKE_PROFILE2,
444
500
  WakeSubscriptionCleartextZod as WakeSubscriptionCleartextZod2
445
501
  } from "@xyo-network/event-kit-schemas";
@@ -448,7 +504,7 @@ import {
448
504
  import {
449
505
  EncryptedWakeSubscriptionZod,
450
506
  MAX_SUBSCRIPTION_PLAINTEXT_BYTES,
451
- NormalizedAddressZod,
507
+ NormalizedAddressZod as NormalizedAddressZod2,
452
508
  WAKE_SUBSCRIPTION_HPKE_PROFILE,
453
509
  WakeSubscriptionCleartextZod,
454
510
  WakeSubscriptionPlaintextZod
@@ -465,7 +521,7 @@ function cleartextFromEncrypted(subscription) {
465
521
  return cleartext;
466
522
  }
467
523
  function wakeSubscriptionAadBytes(subscription, subscriber) {
468
- const parsedSubscriber = NormalizedAddressZod.parse(subscriber);
524
+ const parsedSubscriber = NormalizedAddressZod2.parse(subscriber);
469
525
  const parsedSubscription = "encryption" in subscription ? cleartextFromEncrypted(EncryptedWakeSubscriptionZod.parse(subscription)) : WakeSubscriptionCleartextZod.parse(subscription);
470
526
  return canonicalJsonBytes({
471
527
  schema: parsedSubscription.schema,
@@ -528,14 +584,14 @@ var WakeSubscriptionDecryptionError = class extends Error {
528
584
  };
529
585
  function parsePublicKey(value) {
530
586
  return {
531
- encryptionKey: HashZod.parse(value.encryptionKey),
587
+ encryptionKey: HashZod2.parse(value.encryptionKey),
532
588
  keyId: HandshakeIdZod.parse(value.keyId),
533
589
  publicKey: Base64Url32BytesZod2.parse(value.publicKey)
534
590
  };
535
591
  }
536
592
  function parsePrivateKey(value) {
537
593
  return {
538
- encryptionKey: HashZod.parse(value.encryptionKey),
594
+ encryptionKey: HashZod2.parse(value.encryptionKey),
539
595
  keyId: HandshakeIdZod.parse(value.keyId),
540
596
  privateKey: Base64Url32BytesZod2.parse(value.privateKey)
541
597
  };
@@ -559,7 +615,7 @@ async function generateWakeSubscriptionEncryptionKeyPair() {
559
615
  }
560
616
  async function encryptWakeSubscription(input) {
561
617
  const subscription = WakeSubscriptionCleartextZod2.parse(input.subscription);
562
- const subscriber = NormalizedAddressZod2.parse(input.subscriber);
618
+ const subscriber = NormalizedAddressZod3.parse(input.subscriber);
563
619
  const publisherKey = parsePublicKey(input.publisherKey);
564
620
  if (subscription.encryptionKey !== publisherKey.encryptionKey || subscription.keyId !== publisherKey.keyId) {
565
621
  throw new TypeError("Subscription key reference does not match the supplied publisher key");
@@ -582,7 +638,7 @@ async function encryptWakeSubscription(input) {
582
638
  async function decryptWakeSubscription(input) {
583
639
  try {
584
640
  const subscription = EncryptedWakeSubscriptionZod2.parse(input.subscription);
585
- const subscriber = NormalizedAddressZod2.parse(input.subscriber);
641
+ const subscriber = NormalizedAddressZod3.parse(input.subscriber);
586
642
  const publisherKey = parsePrivateKey(input.publisherKey);
587
643
  if (subscription.encryptionKey !== publisherKey.encryptionKey || subscription.keyId !== publisherKey.keyId) throw new TypeError("Key reference mismatch");
588
644
  const recipientKey = await suite.kem.deserializePrivateKey(decoded32(publisherKey.privateKey));
@@ -595,7 +651,8 @@ async function decryptWakeSubscription(input) {
595
651
  canonicalBase64UrlToBytes2(subscription.encryption.ciphertext) ?? new Uint8Array(),
596
652
  wakeSubscriptionAadBytes(subscription, subscriber)
597
653
  );
598
- return wakeSubscriptionPlaintextFromBytes(new Uint8Array(plaintext));
654
+ const parsed = wakeSubscriptionPlaintextFromBytes(new Uint8Array(plaintext));
655
+ return parsed;
599
656
  } catch {
600
657
  throw new WakeSubscriptionDecryptionError();
601
658
  }
@@ -624,13 +681,13 @@ function parseHandshakePublicObject(value) {
624
681
  throw new TypeError("Expected a strict Event Kit handshake public object");
625
682
  }
626
683
  async function handshakeObjectHash(object) {
627
- return HashZod2.parse(await PayloadBuilder2.dataHash(parseHandshakePublicObject(object)));
684
+ return HashZod3.parse(await PayloadBuilder3.dataHash(parseHandshakePublicObject(object)));
628
685
  }
629
686
  async function withHandshakeObjectHash(body) {
630
687
  return Object.freeze({ body, objectHash: await handshakeObjectHash(body) });
631
688
  }
632
689
  function createPublisherEncryptionKey(input) {
633
- return PublisherEncryptionKeyZod.parse(new PayloadBuilder2({ schema: PublisherEncryptionKeySchema }).fields({
690
+ return PublisherEncryptionKeyZod.parse(new PayloadBuilder3({ schema: PublisherEncryptionKeySchema }).fields({
634
691
  keyId: input.keyId ?? generateHandshakeId2(),
635
692
  profile: WAKE_SUBSCRIPTION_HPKE_PROFILE3,
636
693
  publicKey: input.publicKey,
@@ -661,20 +718,25 @@ async function generatePublisherEncryptionKey(input) {
661
718
  });
662
719
  }
663
720
  function createPublisherService(input) {
664
- return PublisherServiceZod.parse(new PayloadBuilder2({ schema: PublisherServiceSchema }).fields({
721
+ return PublisherServiceZod.parse(new PayloadBuilder3({ schema: PublisherServiceSchema }).fields({
722
+ authorizationChainId: input.authorizationChainId,
665
723
  serviceId: input.serviceId ?? generateHandshakeId2(),
666
724
  revision: input.revision ?? 1,
667
725
  ...input.supersedes === void 0 ? {} : { supersedes: input.supersedes },
668
726
  validFromBlock: input.validFromBlock,
669
727
  ...input.expiresAtBlock === void 0 ? {} : { expiresAtBlock: input.expiresAtBlock },
670
- events: [{ kind: FINALIZED_HEAD_EVENT_KIND, filterProfile: FINALIZED_HEAD_FILTER_PROFILE }],
728
+ events: input.sources.map((source) => ({
729
+ kind: SOURCE_WAKE_EVENT_KIND,
730
+ filterProfile: SOURCE_WAKE_FILTER_PROFILE,
731
+ source
732
+ })),
671
733
  deliveryProfile: WAKE_WALLET_JWT_DELIVERY_PROFILE,
672
734
  challengeProfile: ENDPOINT_CHALLENGE_HMAC_SHA256_PROFILE,
673
735
  encryptionProfile: WAKE_SUBSCRIPTION_HPKE_PROFILE3,
674
736
  encryptionKeys: [...input.encryptionKeys],
675
737
  preferredEncryptionKey: input.preferredEncryptionKey,
676
738
  limits: {
677
- maxBlocksPerWake: input.maxBlocksPerWake,
739
+ maxPositionsPerWake: input.maxPositionsPerWake,
678
740
  maxSubscriptionLifetimeBlocks: input.maxSubscriptionLifetimeBlocks,
679
741
  maxPlaintextBytes: MAX_SUBSCRIPTION_PLAINTEXT_BYTES2
680
742
  },
@@ -682,7 +744,7 @@ function createPublisherService(input) {
682
744
  }).build());
683
745
  }
684
746
  function createWakeGrant(input) {
685
- return WakeGrantObjectZod.parse(new PayloadBuilder2({ schema: WakeGrantObjectSchema }).fields({
747
+ return WakeGrantObjectZod.parse(new PayloadBuilder3({ schema: WakeGrantObjectSchema }).fields({
686
748
  grantId: input.grantId ?? generateGrantId(),
687
749
  deploymentId: input.deploymentId,
688
750
  publisher: input.publisher,
@@ -696,14 +758,16 @@ function createWakeSubscriptionPlaintext(input) {
696
758
  globalThis.crypto.getRandomValues(secretBytes);
697
759
  }
698
760
  const challengeSecret = input.challengeSecret ?? bytesToCanonicalBase64Url3(secretBytes);
699
- return WakeSubscriptionPlaintextZod2.parse(new PayloadBuilder2({ schema: WakeSubscriptionPlaintextSchema }).fields({
761
+ return WakeSubscriptionPlaintextZod2.parse(new PayloadBuilder3({ schema: WakeSubscriptionPlaintextSchema }).fields({
700
762
  endpoint: input.endpoint,
701
763
  audience: input.audience,
702
764
  deploymentId: input.deploymentId,
703
765
  queueId: input.queueId ?? null,
704
766
  filter: {
705
- schema: FINALIZED_HEAD_FILTER_PROFILE,
706
- maxBlocksPerWake: input.maxBlocksPerWake
767
+ schema: SOURCE_WAKE_FILTER_PROFILE,
768
+ source: input.source,
769
+ fromPosition: input.fromPosition,
770
+ maxPositionsPerWake: input.maxPositionsPerWake
707
771
  },
708
772
  challenge: {
709
773
  profile: ENDPOINT_CHALLENGE_HMAC_SHA256_PROFILE,
@@ -713,7 +777,7 @@ function createWakeSubscriptionPlaintext(input) {
713
777
  }
714
778
  async function createEncryptedWakeSubscription(input) {
715
779
  const cleartext = WakeSubscriptionCleartextZod3.parse(
716
- new PayloadBuilder2({ schema: EncryptedWakeSubscriptionSchema }).fields({
780
+ new PayloadBuilder3({ schema: EncryptedWakeSubscriptionSchema }).fields({
717
781
  subscriptionId: input.subscriptionId ?? generateHandshakeId2(),
718
782
  revision: input.revision ?? 1,
719
783
  ...input.supersedes === void 0 ? {} : { supersedes: input.supersedes },
@@ -723,7 +787,7 @@ async function createEncryptedWakeSubscription(input) {
723
787
  encryptionKey: input.publisherKey.encryptionKey,
724
788
  keyId: input.publisherKey.keyId,
725
789
  grant: input.grant,
726
- eventKind: FINALIZED_HEAD_EVENT_KIND,
790
+ eventKind: SOURCE_WAKE_EVENT_KIND,
727
791
  expiresAtBlock: input.expiresAtBlock
728
792
  }).build()
729
793
  );
@@ -735,7 +799,7 @@ async function createEncryptedWakeSubscription(input) {
735
799
  });
736
800
  }
737
801
  function createWakeSubscriptionAcceptance(input) {
738
- return WakeSubscriptionAcceptanceZod.parse(new PayloadBuilder2({ schema: WakeSubscriptionAcceptanceSchema }).fields({
802
+ return WakeSubscriptionAcceptanceZod.parse(new PayloadBuilder3({ schema: WakeSubscriptionAcceptanceSchema }).fields({
739
803
  challenge: input.challenge,
740
804
  encryptionKey: input.encryptionKey,
741
805
  grant: input.grant,
@@ -745,22 +809,22 @@ function createWakeSubscriptionAcceptance(input) {
745
809
  }).build());
746
810
  }
747
811
  function createPublisherServiceRevocation(service) {
748
- return PublisherServiceRevocationZod.parse(new PayloadBuilder2({ schema: PublisherServiceRevocationSchema }).fields({ service }).build());
812
+ return PublisherServiceRevocationZod.parse(new PayloadBuilder3({ schema: PublisherServiceRevocationSchema }).fields({ service }).build());
749
813
  }
750
814
  function createPublisherEncryptionKeyRevocation(key) {
751
815
  return PublisherEncryptionKeyRevocationZod.parse(
752
- new PayloadBuilder2({ schema: PublisherEncryptionKeyRevocationSchema }).fields({ key }).build()
816
+ new PayloadBuilder3({ schema: PublisherEncryptionKeyRevocationSchema }).fields({ key }).build()
753
817
  );
754
818
  }
755
819
  function createWakeGrantRevocation(grant) {
756
- return WakeGrantRevocationZod.parse(new PayloadBuilder2({ schema: WakeGrantRevocationSchema }).fields({ grant }).build());
820
+ return WakeGrantRevocationZod.parse(new PayloadBuilder3({ schema: WakeGrantRevocationSchema }).fields({ grant }).build());
757
821
  }
758
822
  function createWakeSubscriptionRevocation(subscription) {
759
- return WakeSubscriptionRevocationZod.parse(new PayloadBuilder2({ schema: WakeSubscriptionRevocationSchema }).fields({ subscription }).build());
823
+ return WakeSubscriptionRevocationZod.parse(new PayloadBuilder3({ schema: WakeSubscriptionRevocationSchema }).fields({ subscription }).build());
760
824
  }
761
825
  function createWakeSubscriptionAcceptanceRevocation(acceptance) {
762
826
  return WakeSubscriptionAcceptanceRevocationZod.parse(
763
- new PayloadBuilder2({ schema: WakeSubscriptionAcceptanceRevocationSchema }).fields({ acceptance }).build()
827
+ new PayloadBuilder3({ schema: WakeSubscriptionAcceptanceRevocationSchema }).fields({ acceptance }).build()
764
828
  );
765
829
  }
766
830
 
@@ -1161,12 +1225,36 @@ import {
1161
1225
  ChainIdZod,
1162
1226
  EncryptedWakeSubscriptionZod as EncryptedWakeSubscriptionZod4,
1163
1227
  EndpointChallengeZod as EndpointChallengeZod3,
1164
- HashZod as HashZod3,
1165
- NormalizedAddressZod as NormalizedAddressZod3,
1228
+ HashZod as HashZod4,
1229
+ hasMatchingHandshakeProfile,
1230
+ NormalizedAddressZod as NormalizedAddressZod4,
1166
1231
  PublisherEncryptionKeyZod as PublisherEncryptionKeyZod2,
1167
1232
  PublisherServiceZod as PublisherServiceZod2,
1168
1233
  WakeGrantObjectZod as WakeGrantObjectZod2
1169
1234
  } from "@xyo-network/event-kit-schemas";
1235
+
1236
+ // src/sourceWakeIdentity.ts
1237
+ import {
1238
+ SourceWakeSubscriptionFilterZod,
1239
+ WakeSourceSchema,
1240
+ WakeSourceZod
1241
+ } from "@xyo-network/event-kit-schemas";
1242
+ import {
1243
+ asSchema,
1244
+ PayloadBuilder as PayloadBuilder4
1245
+ } from "@xyo-network/sdk";
1246
+ async function wakeSourceHash(source) {
1247
+ return await PayloadBuilder4.dataHash({ schema: WakeSourceSchema, ...WakeSourceZod.parse(source) });
1248
+ }
1249
+ function wakeSourcesEqual(left, right) {
1250
+ return canonicalJson(WakeSourceZod.parse(left)) === canonicalJson(WakeSourceZod.parse(right));
1251
+ }
1252
+ async function sourceWakeFilterHash(filter) {
1253
+ const parsed = SourceWakeSubscriptionFilterZod.parse(filter);
1254
+ return await PayloadBuilder4.dataHash({ ...parsed, schema: asSchema(parsed.schema, true) });
1255
+ }
1256
+
1257
+ // src/publisherSubscription.ts
1170
1258
  function rejectPublisherSubscription(reason) {
1171
1259
  return Object.freeze({ ok: false, reason });
1172
1260
  }
@@ -1201,12 +1289,12 @@ function parsePublisherSubscriptionCandidate(candidate) {
1201
1289
  chainId: ChainIdZod.parse(candidate.chainId),
1202
1290
  grant: WakeGrantObjectZod2.parse(candidate.grant.body),
1203
1291
  key: PublisherEncryptionKeyZod2.parse(candidate.key.body),
1204
- publisher: NormalizedAddressZod3.parse(candidate.publisher),
1292
+ publisher: NormalizedAddressZod4.parse(candidate.publisher),
1205
1293
  service: PublisherServiceZod2.parse(candidate.service.body),
1206
- subscriber: NormalizedAddressZod3.parse(candidate.subscriber),
1294
+ subscriber: NormalizedAddressZod4.parse(candidate.subscriber),
1207
1295
  subscription: EncryptedWakeSubscriptionZod4.parse(candidate.subscription.body),
1208
- tupleObjectHashes: candidate.tupleObjectHashes.map((hash) => HashZod3.parse(hash)),
1209
- tupleSubject: NormalizedAddressZod3.parse(candidate.tupleSubject)
1296
+ tupleObjectHashes: candidate.tupleObjectHashes.map((hash) => HashZod4.parse(hash)),
1297
+ tupleSubject: NormalizedAddressZod4.parse(candidate.tupleSubject)
1210
1298
  };
1211
1299
  } catch {
1212
1300
  return void 0;
@@ -1225,6 +1313,7 @@ async function bodyHashesAreValid(candidate, parsed) {
1225
1313
  return canonicalHashes[0] === candidate.service.objectHash && canonicalHashes[1] === candidate.key.objectHash && canonicalHashes[2] === candidate.grant.objectHash && canonicalHashes[3] === candidate.subscription.objectHash;
1226
1314
  }
1227
1315
  function publicBindingFailure(candidate, parsed) {
1316
+ if (!hasMatchingHandshakeProfile(parsed.service, parsed.subscription, parsed.chainId)) return "subscription-binding-invalid";
1228
1317
  if (!hasExactGrantBinding(parsed.grant, parsed.publisher)) return "grant-binding-invalid";
1229
1318
  if (!hasExactSubscriptionBinding(candidate, parsed.subscription)) return "subscription-binding-invalid";
1230
1319
  const hashedKey = { body: parsed.key, objectHash: candidate.key.objectHash };
@@ -1296,7 +1385,7 @@ async function validateAndDecryptPublisherSubscription(candidate) {
1296
1385
  if (!hasExactQueueScope(parsed.grant, decrypted.plaintext)) {
1297
1386
  return rejectPublisherSubscription("grant-scope-invalid");
1298
1387
  }
1299
- if (decrypted.plaintext.filter.maxBlocksPerWake > parsed.service.limits.maxBlocksPerWake) {
1388
+ if (!filterWithinServicePolicy(parsed.service, decrypted.plaintext)) {
1300
1389
  return rejectPublisherSubscription("service-limit-invalid");
1301
1390
  }
1302
1391
  return validatedPublisherSubscription(candidate, parsed, decrypted.plaintext);
@@ -1311,11 +1400,13 @@ async function challengeRecordMatches(record, challenge, challengeHash, response
1311
1400
  return responseHash === void 0 || record.responseHash === responseHash;
1312
1401
  }
1313
1402
  async function issuePublisherEndpointChallenge(input) {
1314
- const challenge = createEndpointChallenge({
1315
- ...input.subscription.context,
1403
+ const context = input.subscription.context;
1404
+ const common = {
1405
+ ...context,
1316
1406
  issuedAt: input.issuedAt,
1317
1407
  ...input.lifetimeSeconds === void 0 ? {} : { lifetimeSeconds: input.lifetimeSeconds }
1318
- });
1408
+ };
1409
+ const challenge = createEndpointChallenge(common);
1319
1410
  const challengeHash = await endpointChallengeHash(challenge);
1320
1411
  try {
1321
1412
  const result = await input.store.issue({ challenge, challengeHash });
@@ -1337,7 +1428,7 @@ async function beginPublisherEndpointChallengeAttempt(input) {
1337
1428
  if (!isNonnegativeSafeInteger3(input.nowSeconds)) return { kind: "store-invalid" };
1338
1429
  try {
1339
1430
  const result = await input.store.beginAttempt({
1340
- challengeHash: HashZod3.parse(input.challengeHash),
1431
+ challengeHash: HashZod4.parse(input.challengeHash),
1341
1432
  nowSeconds: input.nowSeconds
1342
1433
  });
1343
1434
  if (!["already-attempted", "expired", "missing", "started", "verified"].includes(result.kind)) {
@@ -1346,7 +1437,7 @@ async function beginPublisherEndpointChallengeAttempt(input) {
1346
1437
  if (result.kind !== "missing" && !await challengeRecordMatches(
1347
1438
  result.record,
1348
1439
  result.record.challenge,
1349
- HashZod3.parse(input.challengeHash)
1440
+ HashZod4.parse(input.challengeHash)
1350
1441
  )) return { kind: "store-invalid" };
1351
1442
  if ((result.kind === "started" || result.kind === "already-attempted") && result.record.state !== "attempted") return { kind: "store-invalid" };
1352
1443
  if (result.kind === "verified" && result.record.state !== "verified") return { kind: "store-invalid" };
@@ -1424,18 +1515,57 @@ async function completePublisherEndpointChallenge(input) {
1424
1515
  return completeFailure("challenge-store-unavailable");
1425
1516
  }
1426
1517
  }
1518
+ function filterWithinServicePolicy(service, plaintext) {
1519
+ const filter = plaintext.filter;
1520
+ return filter.maxPositionsPerWake <= service.limits.maxPositionsPerWake && service.events.some((event) => wakeSourcesEqual(event.source, filter.source));
1521
+ }
1522
+
1523
+ // src/sourceWakeActivation.ts
1524
+ import {
1525
+ ChainIdZod as ChainIdZod2,
1526
+ DeploymentIdZod as DeploymentIdZod2,
1527
+ HashZod as HashZod5,
1528
+ NonnegativeJsonSafeIntegerZod as NonnegativeJsonSafeIntegerZod2,
1529
+ NormalizedAddressZod as NormalizedAddressZod5,
1530
+ PositiveJsonSafeIntegerZod
1531
+ } from "@xyo-network/event-kit-schemas";
1532
+ import { z as z2 } from "zod";
1533
+ var SourceWakeSubscriptionActivationZod = z2.strictObject({
1534
+ atBlock: NonnegativeJsonSafeIntegerZod2,
1535
+ activeFromBlock: NonnegativeJsonSafeIntegerZod2,
1536
+ expiresAtBlock: PositiveJsonSafeIntegerZod,
1537
+ authorizationChainId: ChainIdZod2,
1538
+ controller: NormalizedAddressZod5,
1539
+ publisher: NormalizedAddressZod5,
1540
+ deploymentId: DeploymentIdZod2,
1541
+ queueId: z2.string().min(1).max(255).optional(),
1542
+ sourceHash: HashZod5,
1543
+ filterHash: HashZod5,
1544
+ subscriptionHash: HashZod5,
1545
+ serviceHash: HashZod5,
1546
+ grantHash: HashZod5
1547
+ }).refine(
1548
+ (value) => value.activeFromBlock <= value.atBlock && value.atBlock < value.expiresAtBlock,
1549
+ "Subscription must be active at the exact finalized authorization snapshot"
1550
+ );
1427
1551
 
1428
1552
  // src/statementGraphWakeGrantAuthorizer.ts
1553
+ import {
1554
+ ChainIdZod as ChainIdZod3,
1555
+ WakeSourceZod as WakeSourceZod2
1556
+ } from "@xyo-network/event-kit-schemas";
1557
+
1558
+ // src/grantEvidence.ts
1429
1559
  import {
1430
1560
  asWakeGrantObject,
1431
1561
  asWakeGrantRevocation,
1432
- DeploymentIdZod,
1433
- HashZod as HashZod4,
1434
- NormalizedAddressZod as NormalizedAddressZod4,
1562
+ DeploymentIdZod as DeploymentIdZod3,
1563
+ HashZod as HashZod6,
1564
+ NormalizedAddressZod as NormalizedAddressZod6,
1435
1565
  WakeGrantObjectSchema as WakeGrantObjectSchema3,
1436
1566
  WakeGrantRevocationSchema as WakeGrantRevocationSchema3
1437
1567
  } from "@xyo-network/event-kit-schemas";
1438
- function createStatementGraphWakeGrantAuthorizer(options) {
1568
+ function createDeploymentGrantAuthorizer(options) {
1439
1569
  const { viewer } = options;
1440
1570
  return Object.freeze({
1441
1571
  async authorizePublisher(request) {
@@ -1446,6 +1576,7 @@ function createStatementGraphWakeGrantAuthorizer(options) {
1446
1576
  }
1447
1577
  const claims = await viewer.claims(request.controller, {
1448
1578
  declaredObjectSchemaPrefix: WakeGrantObjectSchema3,
1579
+ ...request.exactGrantHash === void 0 ? {} : { objectHash: request.exactGrantHash },
1449
1580
  subject: request.publisher
1450
1581
  });
1451
1582
  const revokedGrantHashes = await readRevocations(viewer, request.controller, request.publisher, atBlock);
@@ -1497,6 +1628,7 @@ async function readRevocations(viewer, controller, subject, atBlock) {
1497
1628
  async function resolveEvidence(viewer, claim, request, atBlock, revokedGrantHashes) {
1498
1629
  if (!isLiveClaim(claim, request.controller, request.publisher, WakeGrantObjectSchema3, atBlock)) return void 0;
1499
1630
  if (revokedGrantHashes.has(claim.objectHash)) return void 0;
1631
+ if (request.exactGrantHash !== void 0 && claim.objectHash !== request.exactGrantHash) return void 0;
1500
1632
  const object = await viewer.object(claim.objectHash);
1501
1633
  const grant = parseExactGrantObject(object, claim.objectHash);
1502
1634
  if (grant === void 0) return void 0;
@@ -1506,9 +1638,14 @@ async function resolveEvidence(viewer, claim, request, atBlock, revokedGrantHash
1506
1638
  if (!grant.permissions.includes("enqueue")) return void 0;
1507
1639
  return Object.freeze({
1508
1640
  assertedAtBlock: claim.firstBlock,
1641
+ authorizationChainId: request.authorizationChainId,
1642
+ sourceHash: request.sourceHash,
1643
+ filterHash: request.filterHash,
1644
+ subscriptionHash: request.subscriptionHash,
1509
1645
  controller: request.controller,
1510
1646
  deploymentId: grant.deploymentId,
1511
1647
  id: claim.firstEventHash,
1648
+ ...request.exactGrantHash === void 0 ? {} : { objectHash: claim.objectHash },
1512
1649
  ...grant.queueId === void 0 ? {} : { queueId: grant.queueId },
1513
1650
  target: grant.publisher
1514
1651
  });
@@ -1519,8 +1656,8 @@ function isLiveClaim(claim, controller, subject, declaredObjectSchema, atBlock)
1519
1656
  if (claim.declaredObjectSchema !== declaredObjectSchema) return false;
1520
1657
  if (!isNonnegativeSafeInteger4(claim.firstBlock) || claim.firstBlock > atBlock) return false;
1521
1658
  if (!isNonnegativeSafeInteger4(claim.lastBlock) || claim.lastBlock < claim.firstBlock) return false;
1522
- if (!HashZod4.safeParse(claim.firstEventHash).success) return false;
1523
- return HashZod4.safeParse(claim.objectHash).success;
1659
+ if (!HashZod6.safeParse(claim.firstEventHash).success) return false;
1660
+ return HashZod6.safeParse(claim.objectHash).success;
1524
1661
  }
1525
1662
  function parseExactGrantObject(object, expectedObjectHash) {
1526
1663
  if (object?.assurance !== "resolved") return void 0;
@@ -1532,13 +1669,16 @@ function parseExactGrantObject(object, expectedObjectHash) {
1532
1669
  });
1533
1670
  }
1534
1671
  function assertValidRequest(request) {
1535
- if (!NormalizedAddressZod4.safeParse(request.controller).success) {
1672
+ if (request.exactGrantHash !== void 0 && !HashZod6.safeParse(request.exactGrantHash).success) {
1673
+ throw new TypeError("Exact grant hash must be canonical lowercase hexadecimal");
1674
+ }
1675
+ if (!NormalizedAddressZod6.safeParse(request.controller).success) {
1536
1676
  throw new TypeError("Grant controller must be a normalized address");
1537
1677
  }
1538
- if (!NormalizedAddressZod4.safeParse(request.publisher).success) {
1678
+ if (!NormalizedAddressZod6.safeParse(request.publisher).success) {
1539
1679
  throw new TypeError("Grant publisher must be a normalized address");
1540
1680
  }
1541
- if (!DeploymentIdZod.safeParse(request.deploymentId).success) {
1681
+ if (!DeploymentIdZod3.safeParse(request.deploymentId).success) {
1542
1682
  throw new TypeError("Grant deploymentId must contain 1 to 255 characters");
1543
1683
  }
1544
1684
  if (request.queueId !== void 0 && (request.queueId.length === 0 || request.queueId.length > 255)) {
@@ -1562,98 +1702,136 @@ function isRecord2(value) {
1562
1702
  return typeof value === "object" && value !== null && !Array.isArray(value);
1563
1703
  }
1564
1704
 
1705
+ // src/statementGraphWakeGrantAuthorizer.ts
1706
+ function createStatementGraphWakeGrantAuthorizer(options) {
1707
+ const authorizationChainId = ChainIdZod3.parse(options.authorizationChainId);
1708
+ const source = WakeSourceZod2.parse(options.source);
1709
+ const grants = createDeploymentGrantAuthorizer({ viewer: options.viewer });
1710
+ return Object.freeze({
1711
+ async authorizePublisher(request) {
1712
+ const sourceHash = await wakeSourceHash(source);
1713
+ if (request.authorizationChainId !== authorizationChainId || request.sourceHash !== sourceHash) {
1714
+ throw new TypeError("Grant request does not match the independently pinned authorization chain and source");
1715
+ }
1716
+ const read = await options.activation.read(request);
1717
+ if (read === void 0) return { enabled: false, atBlock: request.expectedHead };
1718
+ const activation = SourceWakeSubscriptionActivationZod.parse(read);
1719
+ if (activation.atBlock !== request.expectedHead || activation.authorizationChainId !== authorizationChainId || activation.sourceHash !== sourceHash || activation.filterHash !== request.filterHash || activation.subscriptionHash !== request.subscriptionHash || activation.controller !== request.controller || activation.publisher !== request.publisher || activation.deploymentId !== request.deploymentId || activation.queueId !== request.queueId) {
1720
+ throw new TypeError("Finalized subscription activation does not match the exact admission binding");
1721
+ }
1722
+ const decision = await grants.authorizePublisher({ ...request, exactGrantHash: activation.grantHash });
1723
+ if (decision.atBlock !== activation.atBlock) {
1724
+ throw new TypeError("Grant and active subscription snapshots do not identify the same finalized authorization head");
1725
+ }
1726
+ return decision.enabled ? Object.freeze({
1727
+ ...decision,
1728
+ grant: Object.freeze({
1729
+ ...decision.grant,
1730
+ authorizationChainId,
1731
+ sourceHash,
1732
+ filterHash: activation.filterHash,
1733
+ subscriptionHash: activation.subscriptionHash
1734
+ })
1735
+ }) : decision;
1736
+ }
1737
+ });
1738
+ }
1739
+
1565
1740
  // src/verifyWakeRequest.ts
1566
1741
  import {
1567
- DeploymentIdZod as DeploymentIdZod2,
1568
- NormalizedAddressZod as NormalizedAddressZod5,
1569
- WakeEnvelopeZod,
1570
- WakeIdRegExp,
1571
- WakeJwtAudienceZod,
1742
+ ChainIdZod as ChainIdZod4,
1743
+ DeploymentIdZod as DeploymentIdZod4,
1744
+ HashZod as HashZod7,
1745
+ MAX_POSITIONS_PER_SUBSCRIPTION_WAKE,
1746
+ NonnegativeJsonSafeIntegerZod as NonnegativeJsonSafeIntegerZod3,
1747
+ NormalizedAddressZod as NormalizedAddressZod7,
1748
+ PositiveJsonSafeIntegerZod as PositiveJsonSafeIntegerZod2,
1749
+ SOURCE_WAKE_FILTER_PROFILE as SOURCE_WAKE_FILTER_PROFILE2,
1750
+ WakeEnvelopeZod as WakeEnvelopeZod2,
1751
+ WakeJwtAudienceZod as WakeJwtAudienceZod2,
1572
1752
  WakeJwtHeaderZod,
1573
1753
  WakeJwtPayloadZod,
1574
- WakeJwtSchema
1754
+ WakeJwtSchema,
1755
+ WakeSourceZod as WakeSourceZod3
1575
1756
  } from "@xyo-network/event-kit-schemas";
1576
- import { Account, PayloadBuilder as PayloadBuilder3 } from "@xyo-network/sdk";
1757
+ import {
1758
+ Account,
1759
+ PayloadBuilder as PayloadBuilder5
1760
+ } from "@xyo-network/sdk";
1761
+ import { z as z3 } from "zod";
1577
1762
  var EVENT_KIT_MAX_JWT_LIFETIME_SECONDS = 300;
1578
1763
  var EVENT_KIT_MAX_FUTURE_IAT_SECONDS = 60;
1764
+ var WakeAdmissionRouteZod = z3.strictObject({
1765
+ audience: WakeJwtAudienceZod2,
1766
+ authorizationChainId: ChainIdZod4,
1767
+ controller: NormalizedAddressZod7,
1768
+ deploymentId: DeploymentIdZod4,
1769
+ queueId: z3.string().min(1).max(255).optional(),
1770
+ source: WakeSourceZod3,
1771
+ filterHash: HashZod7,
1772
+ subscriptionHash: HashZod7,
1773
+ fromPosition: NonnegativeJsonSafeIntegerZod3,
1774
+ maxPositionsPerWake: PositiveJsonSafeIntegerZod2.max(MAX_POSITIONS_PER_SUBSCRIPTION_WAKE),
1775
+ maxGrantLagBlocks: NonnegativeJsonSafeIntegerZod3
1776
+ });
1579
1777
  async function verifyWakeRequest(input) {
1580
- const { nowSeconds } = input;
1581
- const route = snapshotRoute(input.route);
1582
- const configurationFailure = validateConfiguration(route, nowSeconds);
1583
- if (configurationFailure !== void 0) return configurationFailure;
1584
- const parsed = WakeEnvelopeZod.safeParse(input.body);
1585
- if (!parsed.success) {
1586
- const details = parsed.error.issues.map((issue) => `${issue.path.join(".") || "<root>"}: ${issue.message}`);
1587
- if (hasInvertedSafeRange(input.body)) return reject2("range-invalid", details);
1588
- if (isRecord3(input.body) && Object.hasOwn(input.body, "wakeId") && parsed.error.issues.some((issue) => issue.path[0] === "wakeId")) {
1589
- return reject2("wake-id-invalid", details);
1590
- }
1591
- return reject2(
1592
- "event-malformed",
1593
- details
1594
- );
1595
- }
1596
- const event = parsed.data;
1597
- if (!WakeIdRegExp.test(event.wakeId)) return reject2("wake-id-invalid");
1598
- if (!hasSafeEventNumbers(event)) return reject2("event-malformed", ["wake numeric fields must be nonnegative safe integers"]);
1778
+ const routeResult = WakeAdmissionRouteZod.safeParse(input.route);
1779
+ if (!routeResult.success || !NonnegativeJsonSafeIntegerZod3.safeParse(input.nowSeconds).success) {
1780
+ return { ok: false, reason: "configuration-invalid" };
1781
+ }
1782
+ const eventResult = WakeEnvelopeZod2.safeParse(input.body);
1783
+ if (!eventResult.success) return malformedWake(input.body, eventResult.error.issues);
1784
+ const route = routeResult.data;
1785
+ if (route.filterHash !== await sourceWakeFilterHash({
1786
+ schema: SOURCE_WAKE_FILTER_PROFILE2,
1787
+ source: route.source,
1788
+ fromPosition: route.fromPosition,
1789
+ maxPositionsPerWake: route.maxPositionsPerWake
1790
+ })) return { ok: false, reason: "configuration-invalid" };
1791
+ const event = Object.freeze({ ...eventResult.data, source: Object.freeze(eventResult.data.source) });
1792
+ if (event.authorizationChainId !== route.authorizationChainId) {
1793
+ return { ok: false, reason: "event-authorization-chain-mismatch" };
1794
+ }
1795
+ if (!wakeSourcesEqual(event.source, route.source)) return { ok: false, reason: "event-source-mismatch" };
1796
+ if (event.filterHash !== route.filterHash) return { ok: false, reason: "event-filter-mismatch" };
1599
1797
  if (event.deploymentId !== route.deploymentId || event.queueId !== route.queueId) {
1600
- return reject2("event-target-mismatch");
1798
+ return { ok: false, reason: "event-target-mismatch" };
1601
1799
  }
1602
- if (event.fromBlock > event.toBlock) return reject2("range-invalid");
1603
- if (event.toBlock - event.fromBlock >= route.maxBlocksPerWake) {
1604
- return reject2("range-too-large", [`maxBlocksPerWake=${route.maxBlocksPerWake}`]);
1605
- }
1606
- const jwtResult = await verifyJwtProfile(input.jwt, route.audience, nowSeconds);
1607
- if (!jwtResult.ok) return jwtResult;
1800
+ if (event.fromPosition < route.fromPosition) return { ok: false, reason: "range-before-floor" };
1801
+ if (event.toPosition - event.fromPosition >= route.maxPositionsPerWake) return { ok: false, reason: "range-too-large" };
1802
+ const jwt = await verifyJwtProfile(input.jwt, route.audience, input.nowSeconds);
1803
+ if (!jwt.ok) return jwt;
1608
1804
  let eventHash;
1609
1805
  try {
1610
- eventHash = await PayloadBuilder3.dataHash(event);
1611
- } catch (error) {
1612
- return reject2("event-hash-failed", [errorMessage2(error)]);
1613
- }
1614
- if (eventHash !== jwtResult.jwt.eventHash) return reject2("event-hash-mismatch");
1615
- const frozenEvent = Object.freeze({ ...event });
1616
- const verified = Object.freeze({
1617
- audience: route.audience,
1618
- deploymentId: event.deploymentId,
1619
- event: frozenEvent,
1620
- eventHash,
1621
- expiresAt: jwtResult.jwt.expiresAt,
1622
- fromBlock: event.fromBlock,
1623
- issuedAt: event.issuedAt,
1624
- jwtId: jwtResult.jwt.jwtId,
1625
- publisher: jwtResult.jwt.publisher,
1626
- ...event.queueId === void 0 ? {} : { queueId: event.queueId },
1627
- route,
1628
- toBlock: event.toBlock,
1629
- tokenIssuedAt: jwtResult.jwt.issuedAt,
1630
- wakeId: event.wakeId
1631
- });
1632
- return Object.freeze({ ok: true, verified });
1633
- }
1634
- function validateConfiguration(route, nowSeconds) {
1635
- if (!WakeJwtAudienceZod.safeParse(route.audience).success) {
1636
- return reject2("configuration-invalid", ["audience must not be empty"]);
1637
- }
1638
- if (!DeploymentIdZod2.safeParse(route.deploymentId).success) {
1639
- return reject2("configuration-invalid", ["deploymentId must contain 1 to 255 characters"]);
1640
- }
1641
- if (route.queueId !== void 0 && (route.queueId.length === 0 || route.queueId.length > 255)) {
1642
- return reject2("configuration-invalid", ["queueId must contain 1 to 255 characters when configured"]);
1643
- }
1644
- if (!NormalizedAddressZod5.safeParse(route.controller).success) {
1645
- return reject2("configuration-invalid", ["controller must be a normalized 40-character lowercase-hex address"]);
1646
- }
1647
- if (!isNonnegativeSafeInteger5(nowSeconds)) {
1648
- return reject2("configuration-invalid", ["nowSeconds must be a nonnegative safe integer"]);
1649
- }
1650
- if (!Number.isSafeInteger(route.maxBlocksPerWake) || route.maxBlocksPerWake < 1) {
1651
- return reject2("configuration-invalid", ["maxBlocksPerWake must be a positive safe integer"]);
1652
- }
1653
- if (!isNonnegativeSafeInteger5(route.maxGrantLagBlocks)) {
1654
- return reject2("configuration-invalid", ["maxGrantLagBlocks must be a nonnegative safe integer"]);
1806
+ eventHash = await PayloadBuilder5.dataHash(event);
1807
+ } catch {
1808
+ return { ok: false, reason: "event-hash-failed" };
1655
1809
  }
1656
- return void 0;
1810
+ if (eventHash !== jwt.jwt.eventHash) return { ok: false, reason: "event-hash-mismatch" };
1811
+ const sourceHash = await wakeSourceHash(route.source);
1812
+ return Object.freeze({
1813
+ ok: true,
1814
+ verified: Object.freeze({
1815
+ audience: route.audience,
1816
+ deploymentId: event.deploymentId,
1817
+ event,
1818
+ eventHash,
1819
+ expiresAt: jwt.jwt.expiresAt,
1820
+ fromPosition: event.fromPosition,
1821
+ issuedAt: event.issuedAt,
1822
+ jwtId: jwt.jwt.jwtId,
1823
+ publisher: jwt.jwt.publisher,
1824
+ ...event.queueId === void 0 ? {} : { queueId: event.queueId },
1825
+ route: Object.freeze({
1826
+ ...route,
1827
+ source: Object.freeze(route.source),
1828
+ sourceHash
1829
+ }),
1830
+ toPosition: event.toPosition,
1831
+ tokenIssuedAt: jwt.jwt.issuedAt,
1832
+ wakeId: event.wakeId
1833
+ })
1834
+ });
1657
1835
  }
1658
1836
  async function verifyJwtProfile(token, audience, nowSeconds) {
1659
1837
  let verified;
@@ -1685,11 +1863,11 @@ async function verifyJwtProfile(token, audience, nowSeconds) {
1685
1863
  function parseStrictJwtWire(header, payload, audience) {
1686
1864
  const headerResult = WakeJwtHeaderZod.safeParse(header);
1687
1865
  if (!headerResult.success) {
1688
- if (!NormalizedAddressZod5.safeParse(header.kid).success) return reject2("jwt-identity-invalid");
1866
+ if (!NormalizedAddressZod7.safeParse(header.kid).success) return reject2("jwt-identity-invalid");
1689
1867
  return reject2("jwt-header-invalid", zodDetails(headerResult.error.issues));
1690
1868
  }
1691
1869
  if (Object.hasOwn(payload, "nbf")) return reject2("jwt-nbf-not-allowed");
1692
- if (!NormalizedAddressZod5.safeParse(payload.iss).success) return reject2("jwt-identity-invalid");
1870
+ if (!NormalizedAddressZod7.safeParse(payload.iss).success) return reject2("jwt-identity-invalid");
1693
1871
  if (payload.schema !== WakeJwtSchema) return reject2("jwt-schema-mismatch");
1694
1872
  if (payload.aud !== audience) return reject2("jwt-audience-mismatch");
1695
1873
  if (!isNonnegativeSafeInteger5(payload.iat) || !isNonnegativeSafeInteger5(payload.exp) || payload.exp <= payload.iat) {
@@ -1714,13 +1892,16 @@ function classifySdkJwtFailure(reasons) {
1714
1892
  }
1715
1893
  return "jwt-invalid";
1716
1894
  }
1717
- function hasSafeEventNumbers(event) {
1718
- return isNonnegativeSafeInteger5(event.fromBlock) && isNonnegativeSafeInteger5(event.toBlock) && isNonnegativeSafeInteger5(event.issuedAt);
1895
+ function malformedWake(body, issues) {
1896
+ const details = zodDetails(issues);
1897
+ if (hasInvertedSafeRange(body)) return reject2("range-invalid", details);
1898
+ if (isRecord3(body) && Object.hasOwn(body, "wakeId") && issues.some((issue) => issue.path[0] === "wakeId")) return reject2("wake-id-invalid", details);
1899
+ return reject2("event-malformed", details);
1719
1900
  }
1720
1901
  function hasInvertedSafeRange(value) {
1721
1902
  if (!isRecord3(value)) return false;
1722
- const { fromBlock, toBlock } = value;
1723
- return typeof fromBlock === "number" && typeof toBlock === "number" && isNonnegativeSafeInteger5(fromBlock) && isNonnegativeSafeInteger5(toBlock) && fromBlock > toBlock;
1903
+ const { fromPosition, toPosition } = value;
1904
+ return typeof fromPosition === "number" && typeof toPosition === "number" && isNonnegativeSafeInteger5(fromPosition) && isNonnegativeSafeInteger5(toPosition) && fromPosition > toPosition;
1724
1905
  }
1725
1906
  function isNonnegativeSafeInteger5(value) {
1726
1907
  return Number.isSafeInteger(value) && value >= 0;
@@ -1728,16 +1909,6 @@ function isNonnegativeSafeInteger5(value) {
1728
1909
  function isRecord3(value) {
1729
1910
  return typeof value === "object" && value !== null && !Array.isArray(value);
1730
1911
  }
1731
- function snapshotRoute(route) {
1732
- return Object.freeze({
1733
- audience: route.audience,
1734
- controller: route.controller,
1735
- deploymentId: route.deploymentId,
1736
- maxBlocksPerWake: route.maxBlocksPerWake,
1737
- maxGrantLagBlocks: route.maxGrantLagBlocks,
1738
- ...route.queueId === void 0 ? {} : { queueId: route.queueId }
1739
- });
1740
- }
1741
1912
  function zodDetails(issues) {
1742
1913
  return issues.map((issue) => {
1743
1914
  const path = issue.path.map(String).join(".") || "<root>";
@@ -1773,9 +1944,12 @@ async function drainQueue(queue, handler) {
1773
1944
  }
1774
1945
  }
1775
1946
  export {
1947
+ AdmittedWakeZod,
1776
1948
  EVENT_KIT_MAX_FUTURE_IAT_SECONDS,
1777
1949
  EVENT_KIT_MAX_JWT_LIFETIME_SECONDS,
1778
1950
  EVENT_KIT_REPLAY_RETENTION_SKEW_SECONDS,
1951
+ SourceWakeSubscriptionActivationZod,
1952
+ WakeAdmissionRouteZod,
1779
1953
  WakeSubscriptionDecryptionError,
1780
1954
  admitAndEnqueue,
1781
1955
  beginPublisherEndpointChallengeAttempt,
@@ -1808,12 +1982,16 @@ export {
1808
1982
  generateWakeSubscriptionEncryptionKeyPair,
1809
1983
  handshakeObjectHash,
1810
1984
  issuePublisherEndpointChallenge,
1985
+ parseAdmittedWake,
1811
1986
  resolvePreferredEncryptionKey,
1812
1987
  selectPublisherService,
1813
1988
  selectSubscriptionActivation,
1989
+ sourceWakeFilterHash,
1814
1990
  validateAndDecryptPublisherSubscription,
1815
1991
  verifyEndpointChallengeResponse,
1816
1992
  verifyWakeRequest,
1993
+ wakeSourceHash,
1994
+ wakeSourcesEqual,
1817
1995
  wakeSubscriptionAadBytes,
1818
1996
  wakeSubscriptionPlaintextBytes,
1819
1997
  wakeSubscriptionPlaintextFromBytes,