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

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 (31) hide show
  1. package/LICENSE +310 -0
  2. package/README.md +17 -2
  3. package/dist/neutral/canonicalJson.d.ts +5 -0
  4. package/dist/neutral/canonicalJson.d.ts.map +1 -0
  5. package/dist/neutral/endpointChallenge.d.ts +36 -0
  6. package/dist/neutral/endpointChallenge.d.ts.map +1 -0
  7. package/dist/neutral/handshakeConstruction.d.ts +91 -0
  8. package/dist/neutral/handshakeConstruction.d.ts.map +1 -0
  9. package/dist/neutral/index.d.ts +13 -0
  10. package/dist/neutral/index.d.ts.map +1 -1
  11. package/dist/neutral/index.mjs +1067 -47
  12. package/dist/neutral/index.mjs.map +4 -4
  13. package/dist/neutral/lifecycleSelection.d.ts +105 -0
  14. package/dist/neutral/lifecycleSelection.d.ts.map +1 -0
  15. package/dist/neutral/memoryStatementGrantGraph.d.ts +4 -0
  16. package/dist/neutral/memoryStatementGrantGraph.d.ts.map +1 -1
  17. package/dist/neutral/memoryWakeInbox.d.ts +3 -2
  18. package/dist/neutral/memoryWakeInbox.d.ts.map +1 -1
  19. package/dist/neutral/publisherHandshakeStores.d.ts +97 -0
  20. package/dist/neutral/publisherHandshakeStores.d.ts.map +1 -0
  21. package/dist/neutral/publisherSubscription.d.ts +127 -0
  22. package/dist/neutral/publisherSubscription.d.ts.map +1 -0
  23. package/dist/neutral/statementGraphPorts.d.ts +5 -2
  24. package/dist/neutral/statementGraphPorts.d.ts.map +1 -1
  25. package/dist/neutral/statementGraphWakeGrantAuthorizer.d.ts +4 -4
  26. package/dist/neutral/statementGraphWakeGrantAuthorizer.d.ts.map +1 -1
  27. package/dist/neutral/wakeSubscriptionEncoding.d.ts +12 -0
  28. package/dist/neutral/wakeSubscriptionEncoding.d.ts.map +1 -0
  29. package/dist/neutral/wakeSubscriptionHpke.d.ts +52 -0
  30. package/dist/neutral/wakeSubscriptionHpke.d.ts.map +1 -0
  31. package/package.json +12 -11
@@ -239,28 +239,723 @@ function errorMessage(error) {
239
239
  return error instanceof Error ? error.message : String(error);
240
240
  }
241
241
 
242
+ // src/canonicalJson.ts
243
+ var textEncoder = new TextEncoder();
244
+ function hasUnpairedSurrogate(value) {
245
+ for (let index = 0; index < value.length; index += 1) {
246
+ const codePoint = value.codePointAt(index);
247
+ if (codePoint === void 0 || codePoint >= 55296 && codePoint <= 57343) return true;
248
+ if (codePoint > 65535) index += 1;
249
+ }
250
+ return false;
251
+ }
252
+ function canonicalize(value) {
253
+ if (value === null) return "null";
254
+ switch (typeof value) {
255
+ case "boolean":
256
+ return value ? "true" : "false";
257
+ case "number": {
258
+ if (!Number.isFinite(value)) throw new TypeError("Canonical JSON numbers must be finite");
259
+ return JSON.stringify(value);
260
+ }
261
+ case "string": {
262
+ if (hasUnpairedSurrogate(value)) throw new TypeError("Canonical JSON strings must be valid Unicode");
263
+ return JSON.stringify(value);
264
+ }
265
+ case "object": {
266
+ if (Array.isArray(value)) return `[${value.map((item) => canonicalize(item)).join(",")}]`;
267
+ const prototype = Reflect.getPrototypeOf(value);
268
+ if (prototype !== Object.prototype && prototype !== null) {
269
+ throw new TypeError("Canonical JSON objects must be plain records");
270
+ }
271
+ const record = value;
272
+ const members = Object.keys(record).sort().map((key) => {
273
+ if (hasUnpairedSurrogate(key)) throw new TypeError("Canonical JSON keys must be valid Unicode");
274
+ const member = record[key];
275
+ if (member === void 0) throw new TypeError("Canonical JSON does not permit undefined members");
276
+ return `${JSON.stringify(key)}:${canonicalize(member)}`;
277
+ });
278
+ return `{${members.join(",")}}`;
279
+ }
280
+ default:
281
+ throw new TypeError(`Canonical JSON cannot encode ${typeof value}`);
282
+ }
283
+ }
284
+ function canonicalJson(value) {
285
+ return canonicalize(value);
286
+ }
287
+ function canonicalJsonBytes(value) {
288
+ return textEncoder.encode(canonicalize(value));
289
+ }
290
+
291
+ // src/endpointChallenge.ts
292
+ import {
293
+ Base64Url32BytesZod,
294
+ bytesToCanonicalBase64Url,
295
+ canonicalBase64UrlToBytes,
296
+ EndpointChallengeResponseSchema,
297
+ EndpointChallengeResponseZod,
298
+ EndpointChallengeSchema,
299
+ EndpointChallengeZod,
300
+ generateChallengeNonce,
301
+ generateHandshakeId,
302
+ MAX_ENDPOINT_CHALLENGE_LIFETIME_SECONDS
303
+ } from "@xyo-network/event-kit-schemas";
304
+ import { PayloadBuilder } from "@xyo-network/sdk";
305
+ function hashBytes(hash) {
306
+ return Uint8Array.from({ length: 32 }, (_, index) => Number.parseInt(hash.slice(index * 2, index * 2 + 2), 16));
307
+ }
308
+ async function hmacProof(secret, challengeHash) {
309
+ const secretBytes = canonicalBase64UrlToBytes(Base64Url32BytesZod.parse(secret));
310
+ if (secretBytes?.length !== 32) throw new TypeError("Expected 32-byte challenge secret");
311
+ const cryptoKey = await globalThis.crypto.subtle.importKey(
312
+ "raw",
313
+ Uint8Array.from(secretBytes),
314
+ { name: "HMAC", hash: "SHA-256" },
315
+ false,
316
+ ["sign"]
317
+ );
318
+ const signature = await globalThis.crypto.subtle.sign("HMAC", cryptoKey, hashBytes(challengeHash));
319
+ return Base64Url32BytesZod.parse(bytesToCanonicalBase64Url(new Uint8Array(signature)));
320
+ }
321
+ function equalProof(left, right) {
322
+ const leftBytes = canonicalBase64UrlToBytes(left);
323
+ const rightBytes = canonicalBase64UrlToBytes(right);
324
+ if (leftBytes?.length !== 32 || rightBytes?.length !== 32) return false;
325
+ let difference = 0;
326
+ for (let index = 0; index < 32; index += 1) difference |= leftBytes[index] ^ rightBytes[index];
327
+ return difference === 0;
328
+ }
329
+ async function endpointChallengeHash(challenge) {
330
+ const parsed = EndpointChallengeZod.parse(challenge);
331
+ return await PayloadBuilder.dataHash(parsed);
332
+ }
333
+ function createEndpointChallenge(input) {
334
+ const lifetimeSeconds = input.lifetimeSeconds ?? MAX_ENDPOINT_CHALLENGE_LIFETIME_SECONDS;
335
+ if (!Number.isSafeInteger(lifetimeSeconds) || lifetimeSeconds < 1) {
336
+ throw new RangeError("Challenge lifetime must be a positive safe integer");
337
+ }
338
+ if (!Number.isSafeInteger(input.issuedAt) || input.issuedAt < 0) {
339
+ throw new RangeError("Challenge issuedAt must be a nonnegative safe integer");
340
+ }
341
+ if (input.issuedAt > Number.MAX_SAFE_INTEGER - lifetimeSeconds) {
342
+ throw new RangeError("Challenge expiry exceeds the JSON safe-integer range");
343
+ }
344
+ return EndpointChallengeZod.parse(new PayloadBuilder({ schema: EndpointChallengeSchema }).fields({
345
+ challengeId: generateHandshakeId(),
346
+ chainId: input.chainId,
347
+ publisher: input.publisher,
348
+ subscriber: input.subscriber,
349
+ service: input.service,
350
+ encryptionKey: input.encryptionKey,
351
+ keyId: input.keyId,
352
+ subscription: input.subscription,
353
+ grant: input.grant,
354
+ eventKind: input.eventKind,
355
+ nonce: generateChallengeNonce(),
356
+ issuedAt: input.issuedAt,
357
+ expiresAt: input.issuedAt + lifetimeSeconds
358
+ }).build());
359
+ }
360
+ async function createEndpointChallengeResponse(challenge, secret) {
361
+ const challengeHash = await endpointChallengeHash(challenge);
362
+ return EndpointChallengeResponseZod.parse(new PayloadBuilder({ schema: EndpointChallengeResponseSchema }).fields({
363
+ challenge: challengeHash,
364
+ proof: await hmacProof(secret, challengeHash)
365
+ }).build());
366
+ }
367
+ async function verifyEndpointChallengeProof(input) {
368
+ try {
369
+ const challenge = EndpointChallengeZod.parse(input.challenge);
370
+ const response = EndpointChallengeResponseZod.parse(input.response);
371
+ const challengeHash = await endpointChallengeHash(challenge);
372
+ if (response.challenge !== challengeHash) return false;
373
+ return equalProof(response.proof, await hmacProof(input.secret, challengeHash));
374
+ } catch {
375
+ return false;
376
+ }
377
+ }
378
+ async function verifyEndpointChallengeResponse(input) {
379
+ try {
380
+ const challenge = EndpointChallengeZod.parse(input.challenge);
381
+ if (!Number.isSafeInteger(input.nowSeconds) || input.nowSeconds < challenge.issuedAt || input.nowSeconds >= challenge.expiresAt) return false;
382
+ return await verifyEndpointChallengeProof(input);
383
+ } catch {
384
+ return false;
385
+ }
386
+ }
387
+
388
+ // src/handshakeConstruction.ts
389
+ import {
390
+ bytesToCanonicalBase64Url as bytesToCanonicalBase64Url3,
391
+ EncryptedWakeSubscriptionSchema,
392
+ EncryptedWakeSubscriptionZod as EncryptedWakeSubscriptionZod3,
393
+ ENDPOINT_CHALLENGE_HMAC_SHA256_PROFILE,
394
+ EndpointChallengeResponseZod as EndpointChallengeResponseZod2,
395
+ EndpointChallengeZod as EndpointChallengeZod2,
396
+ FINALIZED_HEAD_EVENT_KIND,
397
+ FINALIZED_HEAD_FILTER_PROFILE,
398
+ generateGrantId,
399
+ generateHandshakeId as generateHandshakeId2,
400
+ HashZod as HashZod2,
401
+ MAX_SUBSCRIPTION_PLAINTEXT_BYTES as MAX_SUBSCRIPTION_PLAINTEXT_BYTES2,
402
+ PublisherEncryptionKeyRevocationSchema,
403
+ PublisherEncryptionKeyRevocationZod,
404
+ PublisherEncryptionKeySchema,
405
+ PublisherEncryptionKeyZod,
406
+ PublisherServiceRevocationSchema,
407
+ PublisherServiceRevocationZod,
408
+ PublisherServiceSchema,
409
+ PublisherServiceZod,
410
+ WAKE_SUBSCRIPTION_HPKE_PROFILE as WAKE_SUBSCRIPTION_HPKE_PROFILE3,
411
+ WAKE_WALLET_JWT_DELIVERY_PROFILE,
412
+ WakeGrantObjectSchema,
413
+ WakeGrantObjectZod,
414
+ WakeGrantRevocationSchema,
415
+ WakeGrantRevocationZod,
416
+ WakeSubscriptionAcceptanceRevocationSchema,
417
+ WakeSubscriptionAcceptanceRevocationZod,
418
+ WakeSubscriptionAcceptanceSchema,
419
+ WakeSubscriptionAcceptanceZod,
420
+ WakeSubscriptionCleartextZod as WakeSubscriptionCleartextZod3,
421
+ WakeSubscriptionPlaintextSchema,
422
+ WakeSubscriptionPlaintextZod as WakeSubscriptionPlaintextZod2,
423
+ WakeSubscriptionRevocationSchema,
424
+ WakeSubscriptionRevocationZod
425
+ } from "@xyo-network/event-kit-schemas";
426
+ import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk";
427
+
428
+ // src/wakeSubscriptionHpke.ts
429
+ import {
430
+ Aes128Gcm,
431
+ CipherSuite,
432
+ DhkemX25519HkdfSha256,
433
+ HkdfSha256
434
+ } from "@hpke/core";
435
+ import {
436
+ Base64Url32BytesZod as Base64Url32BytesZod2,
437
+ bytesToCanonicalBase64Url as bytesToCanonicalBase64Url2,
438
+ canonicalBase64UrlToBytes as canonicalBase64UrlToBytes2,
439
+ EncryptedWakeSubscriptionZod as EncryptedWakeSubscriptionZod2,
440
+ HandshakeIdZod,
441
+ HashZod,
442
+ NormalizedAddressZod as NormalizedAddressZod2,
443
+ WAKE_SUBSCRIPTION_HPKE_PROFILE as WAKE_SUBSCRIPTION_HPKE_PROFILE2,
444
+ WakeSubscriptionCleartextZod as WakeSubscriptionCleartextZod2
445
+ } from "@xyo-network/event-kit-schemas";
446
+
447
+ // src/wakeSubscriptionEncoding.ts
448
+ import {
449
+ EncryptedWakeSubscriptionZod,
450
+ MAX_SUBSCRIPTION_PLAINTEXT_BYTES,
451
+ NormalizedAddressZod,
452
+ WAKE_SUBSCRIPTION_HPKE_PROFILE,
453
+ WakeSubscriptionCleartextZod,
454
+ WakeSubscriptionPlaintextZod
455
+ } from "@xyo-network/event-kit-schemas";
456
+ var textDecoder = new TextDecoder("utf-8", { fatal: true });
457
+ function equalBytes(left, right) {
458
+ if (left.length !== right.length) return false;
459
+ let difference = 0;
460
+ for (let index = 0; index < left.length; index += 1) difference |= left[index] ^ right[index];
461
+ return difference === 0;
462
+ }
463
+ function cleartextFromEncrypted(subscription) {
464
+ const { encryption: _encryption, ...cleartext } = subscription;
465
+ return cleartext;
466
+ }
467
+ function wakeSubscriptionAadBytes(subscription, subscriber) {
468
+ const parsedSubscriber = NormalizedAddressZod.parse(subscriber);
469
+ const parsedSubscription = "encryption" in subscription ? cleartextFromEncrypted(EncryptedWakeSubscriptionZod.parse(subscription)) : WakeSubscriptionCleartextZod.parse(subscription);
470
+ return canonicalJsonBytes({
471
+ schema: parsedSubscription.schema,
472
+ chainId: parsedSubscription.chainId,
473
+ subscriber: parsedSubscriber,
474
+ publisher: parsedSubscription.publisher,
475
+ service: parsedSubscription.service,
476
+ encryptionKey: parsedSubscription.encryptionKey,
477
+ keyId: parsedSubscription.keyId,
478
+ grant: parsedSubscription.grant,
479
+ subscriptionId: parsedSubscription.subscriptionId,
480
+ revision: parsedSubscription.revision,
481
+ supersedes: parsedSubscription.supersedes ?? null,
482
+ eventKind: parsedSubscription.eventKind,
483
+ expiresAtBlock: parsedSubscription.expiresAtBlock,
484
+ profile: WAKE_SUBSCRIPTION_HPKE_PROFILE
485
+ });
486
+ }
487
+ function wakeSubscriptionPlaintextBytes(plaintext) {
488
+ const parsed = WakeSubscriptionPlaintextZod.parse(plaintext);
489
+ const encoded = canonicalJsonBytes(parsed);
490
+ if (encoded.length > MAX_SUBSCRIPTION_PLAINTEXT_BYTES) {
491
+ throw new RangeError(`Wake subscription plaintext exceeds ${MAX_SUBSCRIPTION_PLAINTEXT_BYTES} bytes`);
492
+ }
493
+ return encoded;
494
+ }
495
+ function wakeSubscriptionPlaintextFromBytes(encoded) {
496
+ if (encoded.length > MAX_SUBSCRIPTION_PLAINTEXT_BYTES) {
497
+ throw new RangeError(`Wake subscription plaintext exceeds ${MAX_SUBSCRIPTION_PLAINTEXT_BYTES} bytes`);
498
+ }
499
+ const decoded = textDecoder.decode(encoded);
500
+ const parsed = WakeSubscriptionPlaintextZod.parse(JSON.parse(decoded));
501
+ if (!equalBytes(encoded, canonicalJsonBytes(parsed))) {
502
+ throw new TypeError("Wake subscription plaintext is not canonically encoded");
503
+ }
504
+ return parsed;
505
+ }
506
+
507
+ // src/wakeSubscriptionHpke.ts
508
+ var suite = new CipherSuite({
509
+ kem: new DhkemX25519HkdfSha256(),
510
+ kdf: new HkdfSha256(),
511
+ aead: new Aes128Gcm()
512
+ });
513
+ var hpkeInfo = new TextEncoder().encode(WAKE_SUBSCRIPTION_HPKE_PROFILE2);
514
+ function asInternalHpkeKeyPair(value) {
515
+ if (typeof value !== "object" || value === null || !("privateKey" in value) || !("publicKey" in value)) {
516
+ throw new TypeError("HPKE implementation returned an invalid key pair");
517
+ }
518
+ return {
519
+ privateKey: value.privateKey,
520
+ publicKey: value.publicKey
521
+ };
522
+ }
523
+ var WakeSubscriptionDecryptionError = class extends Error {
524
+ name = "WakeSubscriptionDecryptionError";
525
+ constructor() {
526
+ super("Wake subscription cryptographic validation failed");
527
+ }
528
+ };
529
+ function parsePublicKey(value) {
530
+ return {
531
+ encryptionKey: HashZod.parse(value.encryptionKey),
532
+ keyId: HandshakeIdZod.parse(value.keyId),
533
+ publicKey: Base64Url32BytesZod2.parse(value.publicKey)
534
+ };
535
+ }
536
+ function parsePrivateKey(value) {
537
+ return {
538
+ encryptionKey: HashZod.parse(value.encryptionKey),
539
+ keyId: HandshakeIdZod.parse(value.keyId),
540
+ privateKey: Base64Url32BytesZod2.parse(value.privateKey)
541
+ };
542
+ }
543
+ function decoded32(value) {
544
+ const decoded = canonicalBase64UrlToBytes2(value);
545
+ if (decoded?.length !== 32) throw new TypeError("Expected 32 canonical bytes");
546
+ return decoded;
547
+ }
548
+ async function generateWakeSubscriptionEncryptionKeyPair() {
549
+ const generated = await suite.kem.generateKeyPair();
550
+ const keyPair = asInternalHpkeKeyPair(generated);
551
+ const [publicKey, privateKey] = await Promise.all([
552
+ suite.kem.serializePublicKey(keyPair.publicKey),
553
+ suite.kem.serializePrivateKey(keyPair.privateKey)
554
+ ]);
555
+ return {
556
+ publicKey: Base64Url32BytesZod2.parse(bytesToCanonicalBase64Url2(new Uint8Array(publicKey))),
557
+ privateKey: Base64Url32BytesZod2.parse(bytesToCanonicalBase64Url2(new Uint8Array(privateKey)))
558
+ };
559
+ }
560
+ async function encryptWakeSubscription(input) {
561
+ const subscription = WakeSubscriptionCleartextZod2.parse(input.subscription);
562
+ const subscriber = NormalizedAddressZod2.parse(input.subscriber);
563
+ const publisherKey = parsePublicKey(input.publisherKey);
564
+ if (subscription.encryptionKey !== publisherKey.encryptionKey || subscription.keyId !== publisherKey.keyId) {
565
+ throw new TypeError("Subscription key reference does not match the supplied publisher key");
566
+ }
567
+ const recipientPublicKey = await suite.kem.deserializePublicKey(decoded32(publisherKey.publicKey));
568
+ const { ct, enc } = await suite.seal(
569
+ { recipientPublicKey, info: hpkeInfo },
570
+ wakeSubscriptionPlaintextBytes(input.plaintext),
571
+ wakeSubscriptionAadBytes(subscription, subscriber)
572
+ );
573
+ return EncryptedWakeSubscriptionZod2.parse({
574
+ ...subscription,
575
+ encryption: {
576
+ profile: WAKE_SUBSCRIPTION_HPKE_PROFILE2,
577
+ enc: bytesToCanonicalBase64Url2(new Uint8Array(enc)),
578
+ ciphertext: bytesToCanonicalBase64Url2(new Uint8Array(ct))
579
+ }
580
+ });
581
+ }
582
+ async function decryptWakeSubscription(input) {
583
+ try {
584
+ const subscription = EncryptedWakeSubscriptionZod2.parse(input.subscription);
585
+ const subscriber = NormalizedAddressZod2.parse(input.subscriber);
586
+ const publisherKey = parsePrivateKey(input.publisherKey);
587
+ if (subscription.encryptionKey !== publisherKey.encryptionKey || subscription.keyId !== publisherKey.keyId) throw new TypeError("Key reference mismatch");
588
+ const recipientKey = await suite.kem.deserializePrivateKey(decoded32(publisherKey.privateKey));
589
+ const plaintext = await suite.open(
590
+ {
591
+ recipientKey,
592
+ enc: decoded32(subscription.encryption.enc),
593
+ info: hpkeInfo
594
+ },
595
+ canonicalBase64UrlToBytes2(subscription.encryption.ciphertext) ?? new Uint8Array(),
596
+ wakeSubscriptionAadBytes(subscription, subscriber)
597
+ );
598
+ return wakeSubscriptionPlaintextFromBytes(new Uint8Array(plaintext));
599
+ } catch {
600
+ throw new WakeSubscriptionDecryptionError();
601
+ }
602
+ }
603
+
604
+ // src/handshakeConstruction.ts
605
+ var publicObjectParsers = [
606
+ PublisherServiceZod,
607
+ PublisherEncryptionKeyZod,
608
+ PublisherServiceRevocationZod,
609
+ PublisherEncryptionKeyRevocationZod,
610
+ EncryptedWakeSubscriptionZod3,
611
+ WakeGrantObjectZod,
612
+ WakeGrantRevocationZod,
613
+ WakeSubscriptionRevocationZod,
614
+ WakeSubscriptionAcceptanceZod,
615
+ WakeSubscriptionAcceptanceRevocationZod,
616
+ EndpointChallengeZod2,
617
+ EndpointChallengeResponseZod2
618
+ ];
619
+ function parseHandshakePublicObject(value) {
620
+ for (const parser of publicObjectParsers) {
621
+ const parsed = parser.safeParse(value);
622
+ if (parsed.success) return parsed.data;
623
+ }
624
+ throw new TypeError("Expected a strict Event Kit handshake public object");
625
+ }
626
+ async function handshakeObjectHash(object) {
627
+ return HashZod2.parse(await PayloadBuilder2.dataHash(parseHandshakePublicObject(object)));
628
+ }
629
+ async function withHandshakeObjectHash(body) {
630
+ return Object.freeze({ body, objectHash: await handshakeObjectHash(body) });
631
+ }
632
+ function createPublisherEncryptionKey(input) {
633
+ return PublisherEncryptionKeyZod.parse(new PayloadBuilder2({ schema: PublisherEncryptionKeySchema }).fields({
634
+ keyId: input.keyId ?? generateHandshakeId2(),
635
+ profile: WAKE_SUBSCRIPTION_HPKE_PROFILE3,
636
+ publicKey: input.publicKey,
637
+ validFromBlock: input.validFromBlock,
638
+ ...input.expiresAtBlock === void 0 ? {} : { expiresAtBlock: input.expiresAtBlock }
639
+ }).build());
640
+ }
641
+ async function generatePublisherEncryptionKey(input) {
642
+ const material = await generateWakeSubscriptionEncryptionKeyPair();
643
+ const descriptor = createPublisherEncryptionKey({
644
+ ...input,
645
+ publicKey: material.publicKey
646
+ });
647
+ const descriptorHash = await handshakeObjectHash(descriptor);
648
+ return Object.freeze({
649
+ descriptor,
650
+ descriptorHash,
651
+ privateKey: Object.freeze({
652
+ encryptionKey: descriptorHash,
653
+ keyId: descriptor.keyId,
654
+ privateKey: material.privateKey
655
+ }),
656
+ publicKey: Object.freeze({
657
+ encryptionKey: descriptorHash,
658
+ keyId: descriptor.keyId,
659
+ publicKey: descriptor.publicKey
660
+ })
661
+ });
662
+ }
663
+ function createPublisherService(input) {
664
+ return PublisherServiceZod.parse(new PayloadBuilder2({ schema: PublisherServiceSchema }).fields({
665
+ serviceId: input.serviceId ?? generateHandshakeId2(),
666
+ revision: input.revision ?? 1,
667
+ ...input.supersedes === void 0 ? {} : { supersedes: input.supersedes },
668
+ validFromBlock: input.validFromBlock,
669
+ ...input.expiresAtBlock === void 0 ? {} : { expiresAtBlock: input.expiresAtBlock },
670
+ events: [{ kind: FINALIZED_HEAD_EVENT_KIND, filterProfile: FINALIZED_HEAD_FILTER_PROFILE }],
671
+ deliveryProfile: WAKE_WALLET_JWT_DELIVERY_PROFILE,
672
+ challengeProfile: ENDPOINT_CHALLENGE_HMAC_SHA256_PROFILE,
673
+ encryptionProfile: WAKE_SUBSCRIPTION_HPKE_PROFILE3,
674
+ encryptionKeys: [...input.encryptionKeys],
675
+ preferredEncryptionKey: input.preferredEncryptionKey,
676
+ limits: {
677
+ maxBlocksPerWake: input.maxBlocksPerWake,
678
+ maxSubscriptionLifetimeBlocks: input.maxSubscriptionLifetimeBlocks,
679
+ maxPlaintextBytes: MAX_SUBSCRIPTION_PLAINTEXT_BYTES2
680
+ },
681
+ retirementPolicy: "existing-acceptances-continue"
682
+ }).build());
683
+ }
684
+ function createWakeGrant(input) {
685
+ return WakeGrantObjectZod.parse(new PayloadBuilder2({ schema: WakeGrantObjectSchema }).fields({
686
+ grantId: input.grantId ?? generateGrantId(),
687
+ deploymentId: input.deploymentId,
688
+ publisher: input.publisher,
689
+ ...input.queueId === void 0 ? {} : { queueId: input.queueId },
690
+ permissions: ["enqueue"]
691
+ }).build());
692
+ }
693
+ function createWakeSubscriptionPlaintext(input) {
694
+ const secretBytes = new Uint8Array(32);
695
+ if (input.challengeSecret === void 0) {
696
+ globalThis.crypto.getRandomValues(secretBytes);
697
+ }
698
+ const challengeSecret = input.challengeSecret ?? bytesToCanonicalBase64Url3(secretBytes);
699
+ return WakeSubscriptionPlaintextZod2.parse(new PayloadBuilder2({ schema: WakeSubscriptionPlaintextSchema }).fields({
700
+ endpoint: input.endpoint,
701
+ audience: input.audience,
702
+ deploymentId: input.deploymentId,
703
+ queueId: input.queueId ?? null,
704
+ filter: {
705
+ schema: FINALIZED_HEAD_FILTER_PROFILE,
706
+ maxBlocksPerWake: input.maxBlocksPerWake
707
+ },
708
+ challenge: {
709
+ profile: ENDPOINT_CHALLENGE_HMAC_SHA256_PROFILE,
710
+ secret: challengeSecret
711
+ }
712
+ }).build());
713
+ }
714
+ async function createEncryptedWakeSubscription(input) {
715
+ const cleartext = WakeSubscriptionCleartextZod3.parse(
716
+ new PayloadBuilder2({ schema: EncryptedWakeSubscriptionSchema }).fields({
717
+ subscriptionId: input.subscriptionId ?? generateHandshakeId2(),
718
+ revision: input.revision ?? 1,
719
+ ...input.supersedes === void 0 ? {} : { supersedes: input.supersedes },
720
+ chainId: input.chainId,
721
+ publisher: input.publisher,
722
+ service: input.service,
723
+ encryptionKey: input.publisherKey.encryptionKey,
724
+ keyId: input.publisherKey.keyId,
725
+ grant: input.grant,
726
+ eventKind: FINALIZED_HEAD_EVENT_KIND,
727
+ expiresAtBlock: input.expiresAtBlock
728
+ }).build()
729
+ );
730
+ return await encryptWakeSubscription({
731
+ plaintext: input.plaintext,
732
+ publisherKey: input.publisherKey,
733
+ subscriber: input.subscriber,
734
+ subscription: cleartext
735
+ });
736
+ }
737
+ function createWakeSubscriptionAcceptance(input) {
738
+ return WakeSubscriptionAcceptanceZod.parse(new PayloadBuilder2({ schema: WakeSubscriptionAcceptanceSchema }).fields({
739
+ challenge: input.challenge,
740
+ encryptionKey: input.encryptionKey,
741
+ grant: input.grant,
742
+ response: input.response,
743
+ service: input.service,
744
+ subscription: input.subscription
745
+ }).build());
746
+ }
747
+ function createPublisherServiceRevocation(service) {
748
+ return PublisherServiceRevocationZod.parse(new PayloadBuilder2({ schema: PublisherServiceRevocationSchema }).fields({ service }).build());
749
+ }
750
+ function createPublisherEncryptionKeyRevocation(key) {
751
+ return PublisherEncryptionKeyRevocationZod.parse(
752
+ new PayloadBuilder2({ schema: PublisherEncryptionKeyRevocationSchema }).fields({ key }).build()
753
+ );
754
+ }
755
+ function createWakeGrantRevocation(grant) {
756
+ return WakeGrantRevocationZod.parse(new PayloadBuilder2({ schema: WakeGrantRevocationSchema }).fields({ grant }).build());
757
+ }
758
+ function createWakeSubscriptionRevocation(subscription) {
759
+ return WakeSubscriptionRevocationZod.parse(new PayloadBuilder2({ schema: WakeSubscriptionRevocationSchema }).fields({ subscription }).build());
760
+ }
761
+ function createWakeSubscriptionAcceptanceRevocation(acceptance) {
762
+ return WakeSubscriptionAcceptanceRevocationZod.parse(
763
+ new PayloadBuilder2({ schema: WakeSubscriptionAcceptanceRevocationSchema }).fields({ acceptance }).build()
764
+ );
765
+ }
766
+
767
+ // src/lifecycleSelection.ts
768
+ function isNonnegativeSafeInteger2(value) {
769
+ return Number.isSafeInteger(value) && value >= 0;
770
+ }
771
+ function isVisible(claimedAtBlock, finalizedHead) {
772
+ return isNonnegativeSafeInteger2(claimedAtBlock) && claimedAtBlock <= finalizedHead;
773
+ }
774
+ function isRevoked(revokedAtBlock, finalizedHead) {
775
+ return revokedAtBlock !== void 0 && revokedAtBlock <= finalizedHead;
776
+ }
777
+ function isUnrevokedEvidence(claimedAtBlock, revokedAtBlock, finalizedHead) {
778
+ return isVisible(claimedAtBlock, finalizedHead) && (revokedAtBlock === void 0 || isNonnegativeSafeInteger2(revokedAtBlock) && revokedAtBlock >= claimedAtBlock) && !isRevoked(revokedAtBlock, finalizedHead);
779
+ }
780
+ function isInsideExclusiveWindow(finalizedHead, validFromBlock, expiresAtBlock) {
781
+ if (!isNonnegativeSafeInteger2(validFromBlock) || finalizedHead < validFromBlock) return false;
782
+ return expiresAtBlock === void 0 || isNonnegativeSafeInteger2(expiresAtBlock) && expiresAtBlock > validFromBlock && finalizedHead < expiresAtBlock;
783
+ }
784
+ function isRevisionShapeValid(revision) {
785
+ if (!Number.isSafeInteger(revision.revision) || revision.revision < 1) return false;
786
+ if (!isNonnegativeSafeInteger2(revision.claimedAtBlock)) return false;
787
+ if (revision.revokedAtBlock !== void 0 && (!isNonnegativeSafeInteger2(revision.revokedAtBlock) || revision.revokedAtBlock < revision.claimedAtBlock)) return false;
788
+ return revision.revision === 1 ? revision.supersedes === void 0 : revision.supersedes !== void 0;
789
+ }
790
+ function resolveLinearChain(revisions, finalizedHead) {
791
+ const visible = revisions.filter((revision) => isVisible(revision.claimedAtBlock, finalizedHead));
792
+ if (visible.length === 0) return { ok: true, chain: [] };
793
+ if (visible.some((revision) => !isRevisionShapeValid(revision))) return { ok: false };
794
+ const byHash = /* @__PURE__ */ new Map();
795
+ const childByParent = /* @__PURE__ */ new Map();
796
+ let root;
797
+ for (const revision of visible) {
798
+ if (byHash.has(revision.objectHash)) return { ok: false };
799
+ byHash.set(revision.objectHash, revision);
800
+ if (revision.revision === 1) {
801
+ if (root !== void 0) return { ok: false };
802
+ root = revision;
803
+ }
804
+ }
805
+ if (root === void 0) return { ok: false };
806
+ for (const revision of visible) {
807
+ if (revision.revision === 1) continue;
808
+ const parentHash = revision.supersedes;
809
+ if (parentHash === void 0 || childByParent.has(parentHash)) return { ok: false };
810
+ const parent = byHash.get(parentHash);
811
+ if (parent === void 0 || revision.revision !== parent.revision + 1 || revision.claimedAtBlock < parent.claimedAtBlock) return { ok: false };
812
+ childByParent.set(parentHash, revision);
813
+ }
814
+ const chain = [root];
815
+ let current = root;
816
+ while (childByParent.has(current.objectHash)) {
817
+ const child = childByParent.get(current.objectHash);
818
+ if (child === void 0) return { ok: false };
819
+ chain.push(child);
820
+ current = child;
821
+ }
822
+ return chain.length === visible.length ? { ok: true, chain } : { ok: false };
823
+ }
824
+ function groupServicesByIdentity(services, input) {
825
+ const groups = /* @__PURE__ */ new Map();
826
+ for (const service of services) {
827
+ if (service.source !== input.publisherSource) continue;
828
+ if (input.serviceId !== void 0 && service.serviceId !== input.serviceId) continue;
829
+ const group = groups.get(service.serviceId) ?? [];
830
+ group.push(service);
831
+ groups.set(service.serviceId, group);
832
+ }
833
+ return groups;
834
+ }
835
+ function authoritativeService(chain, finalizedHead) {
836
+ let authoritative;
837
+ for (const service of chain) {
838
+ if (service.validFromBlock <= finalizedHead) authoritative = service;
839
+ }
840
+ return authoritative;
841
+ }
842
+ function isActiveService(service, finalizedHead) {
843
+ return isUnrevokedEvidence(service.claimedAtBlock, service.revokedAtBlock, finalizedHead) && isInsideExclusiveWindow(finalizedHead, service.validFromBlock, service.expiresAtBlock);
844
+ }
845
+ function selectPublisherService(input) {
846
+ const groups = groupServicesByIdentity(input.services, input);
847
+ const selectable = [];
848
+ for (const revisions of groups.values()) {
849
+ if (input.serviceId === void 0 && !revisions.some((service2) => service2.eventKinds.includes(input.eventKind))) {
850
+ continue;
851
+ }
852
+ const resolution = resolveLinearChain(revisions, input.finalizedHead);
853
+ if (!resolution.ok) return { ok: false, reason: "invalid-revision-chain" };
854
+ const service = authoritativeService(resolution.chain, input.finalizedHead);
855
+ if (service?.eventKinds.includes(input.eventKind) && isActiveService(service, input.finalizedHead)) {
856
+ selectable.push(service);
857
+ }
858
+ }
859
+ if (selectable.length === 0) return { ok: false, reason: "service-not-found" };
860
+ if (selectable.length > 1) return { ok: false, reason: "ambiguous-service" };
861
+ return { ok: true, service: selectable[0] };
862
+ }
863
+ function resolvePreferredEncryptionKey(input) {
864
+ const preferredHash = input.service.preferredEncryptionKey;
865
+ if (!input.service.encryptionKeys.includes(preferredHash)) {
866
+ return { ok: false, reason: "preferred-key-not-referenced" };
867
+ }
868
+ const exact = input.keys.filter((key2) => key2.source === input.service.source && key2.objectHash === preferredHash && isVisible(key2.claimedAtBlock, input.finalizedHead));
869
+ if (exact.length === 0) return { ok: false, reason: "preferred-key-not-found" };
870
+ if (exact.length > 1) return { ok: false, reason: "ambiguous-key" };
871
+ const key = exact[0];
872
+ const sameStableIdentity = input.keys.filter((candidate) => candidate.source === key.source && candidate.keyId === key.keyId && candidate.objectHash !== key.objectHash && isVisible(candidate.claimedAtBlock, input.finalizedHead));
873
+ if (sameStableIdentity.length > 0) return { ok: false, reason: "ambiguous-key" };
874
+ if (!isUnrevokedEvidence(key.claimedAtBlock, key.revokedAtBlock, input.finalizedHead) || !isInsideExclusiveWindow(input.finalizedHead, key.validFromBlock, key.expiresAtBlock)) {
875
+ return { ok: false, reason: "preferred-key-inactive" };
876
+ }
877
+ return { ok: true, key };
878
+ }
879
+ function acceptanceFor(subscription, input) {
880
+ return input.acceptances.filter((acceptance) => acceptance.source === input.publisherSource && acceptance.subscription === subscription.objectHash && isVisible(acceptance.acceptanceBlock, input.finalizedHead));
881
+ }
882
+ function acceptedSubscription(subscription, input) {
883
+ const acceptances = acceptanceFor(subscription, input);
884
+ if (acceptances.length > 1) return "ambiguous";
885
+ const acceptance = acceptances[0];
886
+ if (acceptance === void 0 || !isNonnegativeSafeInteger2(acceptance.acceptanceBlock)) return void 0;
887
+ if (!Number.isSafeInteger(subscription.expiresAtBlock) || subscription.expiresAtBlock < 1) return void 0;
888
+ if (acceptance.acceptanceBlock <= subscription.claimedAtBlock || acceptance.acceptanceBlock >= Number.MAX_SAFE_INTEGER) return void 0;
889
+ const activeFromBlock = acceptance.acceptanceBlock + 1;
890
+ if (activeFromBlock >= subscription.expiresAtBlock) return void 0;
891
+ return {
892
+ acceptance,
893
+ activeFromBlock,
894
+ subscription
895
+ };
896
+ }
897
+ function isActiveAcceptedSubscription(accepted, finalizedHead) {
898
+ return isUnrevokedEvidence(
899
+ accepted.subscription.claimedAtBlock,
900
+ accepted.subscription.revokedAtBlock,
901
+ finalizedHead
902
+ ) && isUnrevokedEvidence(
903
+ accepted.acceptance.acceptanceBlock,
904
+ accepted.acceptance.revokedAtBlock,
905
+ finalizedHead
906
+ ) && finalizedHead < accepted.subscription.expiresAtBlock;
907
+ }
908
+ function selectSubscriptionActivation(input) {
909
+ const revisions = input.subscriptions.filter((subscription) => subscription.source === input.subscriberSource && subscription.subscriptionId === input.subscriptionId);
910
+ const resolution = resolveLinearChain(revisions, input.finalizedHead);
911
+ if (!resolution.ok) return { ok: false, reason: "invalid-revision-chain" };
912
+ if (resolution.chain.length === 0) return { ok: false, reason: "subscription-not-found" };
913
+ let selected;
914
+ for (const subscription of resolution.chain) {
915
+ const accepted = acceptedSubscription(subscription, input);
916
+ if (accepted === "ambiguous") return { ok: false, reason: "ambiguous-acceptance" };
917
+ if (accepted !== void 0 && accepted.activeFromBlock <= input.finalizedHead) selected = accepted;
918
+ }
919
+ if (selected === void 0) return { ok: false, reason: "subscription-pending" };
920
+ const latest = resolution.chain.at(-1);
921
+ if (!isActiveAcceptedSubscription(selected, input.finalizedHead)) {
922
+ if (latest?.objectHash !== selected.subscription.objectHash) {
923
+ return { ok: false, reason: "subscription-pending" };
924
+ }
925
+ return { ok: false, reason: "subscription-inactive" };
926
+ }
927
+ return {
928
+ acceptance: selected.acceptance,
929
+ activeFromBlock: selected.activeFromBlock,
930
+ ok: true,
931
+ pendingReplacement: latest?.objectHash !== selected.subscription.objectHash,
932
+ subscription: selected.subscription
933
+ };
934
+ }
935
+
242
936
  // src/memoryStatementGrantGraph.ts
243
937
  import {
244
938
  normalizeAddress,
245
- WakeGrantObjectSchema,
246
- WakeGrantRevocationSchema
939
+ WakeGrantObjectSchema as WakeGrantObjectSchema2,
940
+ WakeGrantRevocationSchema as WakeGrantRevocationSchema2
247
941
  } from "@xyo-network/event-kit-schemas";
248
942
  function createMemoryStatementGrantGraph(initialHead = 0) {
249
943
  let head = initialHead;
250
944
  const claims = /* @__PURE__ */ new Map();
251
945
  const objects = /* @__PURE__ */ new Map();
252
- function claimKey(source, objectHash) {
253
- return `${normalizeAddress(source)}|${objectHash}`;
946
+ function claimKey(source, subject, objectHash) {
947
+ return `${normalizeAddress(source)}|${normalizeAddress(subject)}|${objectHash}`;
254
948
  }
255
949
  function materialize(input) {
256
950
  const source = normalizeAddress(input.source);
951
+ const subject = normalizeAddress(input.subject);
257
952
  objects.set(input.objectHash, Object.freeze({
258
953
  assurance: "resolved",
259
954
  declaredSchema: input.declaredSchema,
260
955
  objectHash: input.objectHash,
261
956
  params: Object.freeze({ ...input.params })
262
957
  }));
263
- const key = claimKey(source, input.objectHash);
958
+ const key = claimKey(source, subject, input.objectHash);
264
959
  const existing = claims.get(key);
265
960
  claims.set(key, Object.freeze(existing === void 0 ? {
266
961
  declaredObjectSchema: input.declaredSchema,
@@ -268,7 +963,8 @@ function createMemoryStatementGrantGraph(initialHead = 0) {
268
963
  firstEventHash: input.eventHash,
269
964
  lastBlock: input.block,
270
965
  objectHash: input.objectHash,
271
- source
966
+ source,
967
+ subject
272
968
  } : { ...existing, lastBlock: Math.max(existing.lastBlock, input.block) }));
273
969
  if (input.block > head) head = input.block;
274
970
  }
@@ -284,6 +980,7 @@ function createMemoryStatementGrantGraph(initialHead = 0) {
284
980
  const records = [];
285
981
  for (const record of claims.values()) {
286
982
  if (record.source !== normalizedSource) continue;
983
+ if (query?.subject !== void 0 && record.subject !== normalizeAddress(query.subject)) continue;
287
984
  if (query?.objectHash !== void 0 && record.objectHash !== query.objectHash) continue;
288
985
  if (query?.declaredObjectSchemaPrefix !== void 0 && !record.declaredObjectSchema.startsWith(query.declaredObjectSchemaPrefix)) {
289
986
  continue;
@@ -296,31 +993,43 @@ function createMemoryStatementGrantGraph(initialHead = 0) {
296
993
  return objects.get(objectHash);
297
994
  },
298
995
  claim(input) {
299
- if (input.grant.schema !== WakeGrantObjectSchema) {
300
- throw new Error(`expected ${WakeGrantObjectSchema}`);
996
+ if (input.grant.schema !== WakeGrantObjectSchema2) {
997
+ throw new Error(`expected ${WakeGrantObjectSchema2}`);
301
998
  }
302
999
  const { schema: _schema, ...params } = input.grant;
303
1000
  materialize({
304
1001
  block: input.block,
305
- declaredSchema: WakeGrantObjectSchema,
1002
+ declaredSchema: WakeGrantObjectSchema2,
306
1003
  eventHash: input.eventHash,
307
1004
  objectHash: input.objectHash,
308
1005
  params: {
309
1006
  ...params,
310
1007
  permissions: Object.freeze([...params.permissions])
311
1008
  },
312
- source: input.source
1009
+ source: input.source,
1010
+ subject: input.subject ?? input.grant.publisher
313
1011
  });
314
1012
  },
315
1013
  revoke(input) {
316
1014
  const revocation = { grant: input.grantObjectHash };
1015
+ const source = normalizeAddress(input.source);
1016
+ const subjects = [...claims.values()].filter((claim) => claim.source === source && claim.objectHash === input.grantObjectHash).map((claim) => claim.subject);
1017
+ const uniqueSubjects = [...new Set(subjects)];
1018
+ if (input.subject === void 0 && uniqueSubjects.length > 1) {
1019
+ throw new Error(`cannot infer one subject for ambiguous grant Claim ${input.grantObjectHash}`);
1020
+ }
1021
+ const subject = input.subject ?? uniqueSubjects[0];
1022
+ if (subject === void 0) {
1023
+ throw new Error(`cannot infer subject for unknown grant Claim ${input.grantObjectHash}`);
1024
+ }
317
1025
  materialize({
318
1026
  block: input.block,
319
- declaredSchema: WakeGrantRevocationSchema,
1027
+ declaredSchema: WakeGrantRevocationSchema2,
320
1028
  eventHash: input.eventHash,
321
1029
  objectHash: input.objectHash,
322
1030
  params: revocation,
323
- source: input.source
1031
+ source: input.source,
1032
+ subject
324
1033
  });
325
1034
  }
326
1035
  };
@@ -447,15 +1156,284 @@ function createMemoryWakeQueue() {
447
1156
  };
448
1157
  }
449
1158
 
1159
+ // src/publisherSubscription.ts
1160
+ import {
1161
+ ChainIdZod,
1162
+ EncryptedWakeSubscriptionZod as EncryptedWakeSubscriptionZod4,
1163
+ EndpointChallengeZod as EndpointChallengeZod3,
1164
+ HashZod as HashZod3,
1165
+ NormalizedAddressZod as NormalizedAddressZod3,
1166
+ PublisherEncryptionKeyZod as PublisherEncryptionKeyZod2,
1167
+ PublisherServiceZod as PublisherServiceZod2,
1168
+ WakeGrantObjectZod as WakeGrantObjectZod2
1169
+ } from "@xyo-network/event-kit-schemas";
1170
+ function rejectPublisherSubscription(reason) {
1171
+ return Object.freeze({ ok: false, reason });
1172
+ }
1173
+ function isNonnegativeSafeInteger3(value) {
1174
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
1175
+ }
1176
+ function isActiveAt(value, block) {
1177
+ return value.validFromBlock <= block && (value.expiresAtBlock === void 0 || block < value.expiresAtBlock);
1178
+ }
1179
+ function occursExactlyOnce(hashes, expected) {
1180
+ return hashes.filter((hash) => hash === expected).length === 1;
1181
+ }
1182
+ function hasExactGrantBinding(grant, publisher) {
1183
+ return grant.publisher === publisher && grant.permissions.length === 1 && grant.permissions[0] === "enqueue";
1184
+ }
1185
+ function hasExactQueueScope(grant, plaintext) {
1186
+ const grantQueue = Object.hasOwn(grant, "queueId") ? grant.queueId : null;
1187
+ return plaintext.deploymentId === grant.deploymentId && plaintext.queueId === grantQueue;
1188
+ }
1189
+ function hasExactSubscriptionBinding(candidate, subscription) {
1190
+ 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;
1191
+ }
1192
+ function hasExactKeyBinding(service, key, subscription) {
1193
+ return service.encryptionKeys.includes(key.objectHash) && service.preferredEncryptionKey === key.objectHash && key.body.keyId === subscription.keyId && key.objectHash === subscription.encryptionKey;
1194
+ }
1195
+ function expiryWithinServicePolicy(subscription, service, tupleBlock) {
1196
+ return subscription.expiresAtBlock > tupleBlock && subscription.expiresAtBlock - tupleBlock <= service.limits.maxSubscriptionLifetimeBlocks;
1197
+ }
1198
+ function parsePublisherSubscriptionCandidate(candidate) {
1199
+ try {
1200
+ return {
1201
+ chainId: ChainIdZod.parse(candidate.chainId),
1202
+ grant: WakeGrantObjectZod2.parse(candidate.grant.body),
1203
+ key: PublisherEncryptionKeyZod2.parse(candidate.key.body),
1204
+ publisher: NormalizedAddressZod3.parse(candidate.publisher),
1205
+ service: PublisherServiceZod2.parse(candidate.service.body),
1206
+ subscriber: NormalizedAddressZod3.parse(candidate.subscriber),
1207
+ subscription: EncryptedWakeSubscriptionZod4.parse(candidate.subscription.body),
1208
+ tupleObjectHashes: candidate.tupleObjectHashes.map((hash) => HashZod3.parse(hash)),
1209
+ tupleSubject: NormalizedAddressZod3.parse(candidate.tupleSubject)
1210
+ };
1211
+ } catch {
1212
+ return void 0;
1213
+ }
1214
+ }
1215
+ function tupleBindingIsValid(candidate, parsed) {
1216
+ 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);
1217
+ }
1218
+ async function bodyHashesAreValid(candidate, parsed) {
1219
+ const canonicalHashes = await Promise.all([
1220
+ handshakeObjectHash(parsed.service),
1221
+ handshakeObjectHash(parsed.key),
1222
+ handshakeObjectHash(parsed.grant),
1223
+ handshakeObjectHash(parsed.subscription)
1224
+ ]);
1225
+ return canonicalHashes[0] === candidate.service.objectHash && canonicalHashes[1] === candidate.key.objectHash && canonicalHashes[2] === candidate.grant.objectHash && canonicalHashes[3] === candidate.subscription.objectHash;
1226
+ }
1227
+ function publicBindingFailure(candidate, parsed) {
1228
+ if (!hasExactGrantBinding(parsed.grant, parsed.publisher)) return "grant-binding-invalid";
1229
+ if (!hasExactSubscriptionBinding(candidate, parsed.subscription)) return "subscription-binding-invalid";
1230
+ const hashedKey = { body: parsed.key, objectHash: candidate.key.objectHash };
1231
+ if (!hasExactKeyBinding(parsed.service, hashedKey, parsed.subscription)) return "key-binding-invalid";
1232
+ if (!isActiveAt(parsed.service, candidate.tupleBlock) || !isActiveAt(parsed.service, candidate.finalizedHead)) return "service-inactive";
1233
+ if (!isActiveAt(parsed.key, candidate.tupleBlock) || !isActiveAt(parsed.key, candidate.finalizedHead)) return "key-inactive";
1234
+ if (!expiryWithinServicePolicy(parsed.subscription, parsed.service, candidate.tupleBlock) || parsed.subscription.expiresAtBlock - candidate.finalizedHead <= 2) return "subscription-expiry-invalid";
1235
+ return void 0;
1236
+ }
1237
+ async function decryptCandidate(candidate, parsed) {
1238
+ let privateKey;
1239
+ try {
1240
+ privateKey = await candidate.keys.getPrivateKey({
1241
+ encryptionKey: candidate.key.objectHash,
1242
+ keyId: parsed.key.keyId,
1243
+ publisher: parsed.publisher
1244
+ });
1245
+ } catch {
1246
+ return rejectPublisherSubscription("key-store-unavailable");
1247
+ }
1248
+ if (privateKey === void 0) return rejectPublisherSubscription("private-key-not-found");
1249
+ if (privateKey.encryptionKey !== candidate.key.objectHash || privateKey.keyId !== parsed.key.keyId) {
1250
+ return rejectPublisherSubscription("key-binding-invalid");
1251
+ }
1252
+ try {
1253
+ return {
1254
+ plaintext: await decryptWakeSubscription({
1255
+ publisherKey: privateKey,
1256
+ subscriber: parsed.subscriber,
1257
+ subscription: parsed.subscription
1258
+ })
1259
+ };
1260
+ } catch {
1261
+ return rejectPublisherSubscription("decryption-failed");
1262
+ }
1263
+ }
1264
+ function validatedPublisherSubscription(candidate, parsed, plaintext) {
1265
+ return Object.freeze({
1266
+ context: Object.freeze({
1267
+ chainId: parsed.chainId,
1268
+ encryptionKey: candidate.key.objectHash,
1269
+ eventKind: parsed.subscription.eventKind,
1270
+ grant: candidate.grant.objectHash,
1271
+ keyId: parsed.subscription.keyId,
1272
+ publisher: parsed.publisher,
1273
+ service: candidate.service.objectHash,
1274
+ subscriber: parsed.subscriber,
1275
+ subscription: candidate.subscription.objectHash
1276
+ }),
1277
+ finalizedHead: candidate.finalizedHead,
1278
+ grant: Object.freeze({ body: parsed.grant, objectHash: candidate.grant.objectHash }),
1279
+ key: Object.freeze({ body: parsed.key, objectHash: candidate.key.objectHash }),
1280
+ ok: true,
1281
+ plaintext,
1282
+ service: Object.freeze({ body: parsed.service, objectHash: candidate.service.objectHash }),
1283
+ subscription: Object.freeze({ body: parsed.subscription, objectHash: candidate.subscription.objectHash }),
1284
+ tupleBlock: candidate.tupleBlock
1285
+ });
1286
+ }
1287
+ async function validateAndDecryptPublisherSubscription(candidate) {
1288
+ const parsed = parsePublisherSubscriptionCandidate(candidate);
1289
+ if (parsed === void 0) return rejectPublisherSubscription("malformed-candidate");
1290
+ if (!tupleBindingIsValid(candidate, parsed)) return rejectPublisherSubscription("tuple-binding-invalid");
1291
+ if (!await bodyHashesAreValid(candidate, parsed)) return rejectPublisherSubscription("body-hash-mismatch");
1292
+ const publicFailure = publicBindingFailure(candidate, parsed);
1293
+ if (publicFailure !== void 0) return rejectPublisherSubscription(publicFailure);
1294
+ const decrypted = await decryptCandidate(candidate, parsed);
1295
+ if ("ok" in decrypted) return decrypted;
1296
+ if (!hasExactQueueScope(parsed.grant, decrypted.plaintext)) {
1297
+ return rejectPublisherSubscription("grant-scope-invalid");
1298
+ }
1299
+ if (decrypted.plaintext.filter.maxBlocksPerWake > parsed.service.limits.maxBlocksPerWake) {
1300
+ return rejectPublisherSubscription("service-limit-invalid");
1301
+ }
1302
+ return validatedPublisherSubscription(candidate, parsed, decrypted.plaintext);
1303
+ }
1304
+ function endpointChallengeMatchesPublisherContext(challenge, context) {
1305
+ const parsed = EndpointChallengeZod3.safeParse(challenge);
1306
+ if (!parsed.success) return false;
1307
+ 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;
1308
+ }
1309
+ async function challengeRecordMatches(record, challenge, challengeHash, responseHash) {
1310
+ if (record.challengeHash !== challengeHash || await endpointChallengeHash(record.challenge) !== challengeHash || await endpointChallengeHash(challenge) !== challengeHash) return false;
1311
+ return responseHash === void 0 || record.responseHash === responseHash;
1312
+ }
1313
+ async function issuePublisherEndpointChallenge(input) {
1314
+ const challenge = createEndpointChallenge({
1315
+ ...input.subscription.context,
1316
+ issuedAt: input.issuedAt,
1317
+ ...input.lifetimeSeconds === void 0 ? {} : { lifetimeSeconds: input.lifetimeSeconds }
1318
+ });
1319
+ const challengeHash = await endpointChallengeHash(challenge);
1320
+ try {
1321
+ const result = await input.store.issue({ challenge, challengeHash });
1322
+ if (result.kind === "collision") return { ok: false, reason: "challenge-collision" };
1323
+ if (result.kind !== "duplicate" && result.kind !== "issued" || !await challengeRecordMatches(result.record, challenge, challengeHash)) {
1324
+ return { ok: false, reason: "challenge-store-invalid" };
1325
+ }
1326
+ return Object.freeze({
1327
+ challenge,
1328
+ challengeHash,
1329
+ disposition: result.kind,
1330
+ ok: true
1331
+ });
1332
+ } catch {
1333
+ return { ok: false, reason: "challenge-store-unavailable" };
1334
+ }
1335
+ }
1336
+ async function beginPublisherEndpointChallengeAttempt(input) {
1337
+ if (!isNonnegativeSafeInteger3(input.nowSeconds)) return { kind: "store-invalid" };
1338
+ try {
1339
+ const result = await input.store.beginAttempt({
1340
+ challengeHash: HashZod3.parse(input.challengeHash),
1341
+ nowSeconds: input.nowSeconds
1342
+ });
1343
+ if (!["already-attempted", "expired", "missing", "started", "verified"].includes(result.kind)) {
1344
+ return { kind: "store-invalid" };
1345
+ }
1346
+ if (result.kind !== "missing" && !await challengeRecordMatches(
1347
+ result.record,
1348
+ result.record.challenge,
1349
+ HashZod3.parse(input.challengeHash)
1350
+ )) return { kind: "store-invalid" };
1351
+ if ((result.kind === "started" || result.kind === "already-attempted") && result.record.state !== "attempted") return { kind: "store-invalid" };
1352
+ if (result.kind === "verified" && result.record.state !== "verified") return { kind: "store-invalid" };
1353
+ return result;
1354
+ } catch {
1355
+ return { kind: "store-unavailable" };
1356
+ }
1357
+ }
1358
+ function completeFailure(reason) {
1359
+ return Object.freeze({ ok: false, reason });
1360
+ }
1361
+ async function validateChallengeCompletion(input, result, challengeHash, responseHash, insideDecisionWindow, proofValid) {
1362
+ if (!insideDecisionWindow && result.kind !== "duplicate") {
1363
+ return completeFailure(result.kind === "collision" ? "challenge-response-collision" : "challenge-expired");
1364
+ }
1365
+ if (!proofValid) return completeFailure("invalid-proof");
1366
+ if (result.kind === "missing") return completeFailure("challenge-not-found");
1367
+ if (result.kind === "expired") return completeFailure("challenge-expired");
1368
+ if (result.kind === "not-attempted") return completeFailure("challenge-not-attempted");
1369
+ if (result.kind === "collision") return completeFailure("challenge-response-collision");
1370
+ if (result.kind !== "duplicate" && result.kind !== "verified" || !await challengeRecordMatches(result.record, input.challenge, challengeHash, responseHash)) {
1371
+ return completeFailure("challenge-store-invalid");
1372
+ }
1373
+ return result;
1374
+ }
1375
+ async function completePublisherEndpointChallenge(input) {
1376
+ if (!endpointChallengeMatchesPublisherContext(input.challenge, input.subscription.context)) {
1377
+ return completeFailure("challenge-context-invalid");
1378
+ }
1379
+ if (!isNonnegativeSafeInteger3(input.nowSeconds)) return completeFailure("challenge-expired");
1380
+ const insideDecisionWindow = input.challenge.issuedAt <= input.nowSeconds && input.nowSeconds < input.challenge.expiresAt;
1381
+ const proofInput = {
1382
+ challenge: input.challenge,
1383
+ response: input.response,
1384
+ secret: input.subscription.plaintext.challenge.secret
1385
+ };
1386
+ const proofValid = insideDecisionWindow ? await verifyEndpointChallengeResponse({ ...proofInput, nowSeconds: input.nowSeconds }) : await verifyEndpointChallengeProof(proofInput);
1387
+ if (insideDecisionWindow && !proofValid) return completeFailure("invalid-proof");
1388
+ const [challengeHash, responseHash] = await Promise.all([
1389
+ endpointChallengeHash(input.challenge),
1390
+ handshakeObjectHash(input.response)
1391
+ ]);
1392
+ try {
1393
+ const result = await input.store.completeVerified({
1394
+ challengeHash,
1395
+ nowSeconds: input.nowSeconds,
1396
+ responseHash
1397
+ });
1398
+ const completion = await validateChallengeCompletion(
1399
+ input,
1400
+ result,
1401
+ challengeHash,
1402
+ responseHash,
1403
+ insideDecisionWindow,
1404
+ proofValid
1405
+ );
1406
+ if ("ok" in completion) return completion;
1407
+ const acceptance = createWakeSubscriptionAcceptance({
1408
+ challenge: challengeHash,
1409
+ encryptionKey: input.subscription.context.encryptionKey,
1410
+ grant: input.subscription.context.grant,
1411
+ response: responseHash,
1412
+ service: input.subscription.context.service,
1413
+ subscription: input.subscription.context.subscription
1414
+ });
1415
+ return Object.freeze({
1416
+ acceptance,
1417
+ acceptanceHash: await handshakeObjectHash(acceptance),
1418
+ challengeHash,
1419
+ disposition: completion.kind,
1420
+ ok: true,
1421
+ responseHash
1422
+ });
1423
+ } catch {
1424
+ return completeFailure("challenge-store-unavailable");
1425
+ }
1426
+ }
1427
+
450
1428
  // src/statementGraphWakeGrantAuthorizer.ts
451
1429
  import {
452
1430
  asWakeGrantObject,
453
1431
  asWakeGrantRevocation,
454
1432
  DeploymentIdZod,
455
- HashZod,
456
- NormalizedAddressZod,
457
- WakeGrantObjectSchema as WakeGrantObjectSchema2,
458
- WakeGrantRevocationSchema as WakeGrantRevocationSchema2
1433
+ HashZod as HashZod4,
1434
+ NormalizedAddressZod as NormalizedAddressZod4,
1435
+ WakeGrantObjectSchema as WakeGrantObjectSchema3,
1436
+ WakeGrantRevocationSchema as WakeGrantRevocationSchema3
459
1437
  } from "@xyo-network/event-kit-schemas";
460
1438
  function createStatementGraphWakeGrantAuthorizer(options) {
461
1439
  const { viewer } = options;
@@ -466,8 +1444,11 @@ function createStatementGraphWakeGrantAuthorizer(options) {
466
1444
  if (atBlock > request.expectedHead) {
467
1445
  throw new Error(`Statement Graph head ${atBlock} is ahead of expected head ${request.expectedHead}`);
468
1446
  }
469
- const claims = await viewer.claims(request.controller, { declaredObjectSchemaPrefix: WakeGrantObjectSchema2 });
470
- const revokedGrantHashes = await readRevocations(viewer, request.controller, atBlock);
1447
+ const claims = await viewer.claims(request.controller, {
1448
+ declaredObjectSchemaPrefix: WakeGrantObjectSchema3,
1449
+ subject: request.publisher
1450
+ });
1451
+ const revokedGrantHashes = await readRevocations(viewer, request.controller, request.publisher, atBlock);
471
1452
  let evidence;
472
1453
  for (const claim of claims) {
473
1454
  evidence = await resolveEvidence(viewer, claim, request, atBlock, revokedGrantHashes);
@@ -496,14 +1477,17 @@ function createStatementGraphWakeGrantAuthorizer(options) {
496
1477
  }
497
1478
  });
498
1479
  }
499
- async function readRevocations(viewer, controller, atBlock) {
1480
+ async function readRevocations(viewer, controller, subject, atBlock) {
500
1481
  const revoked = /* @__PURE__ */ new Set();
501
- const claims = await viewer.claims(controller, { declaredObjectSchemaPrefix: WakeGrantRevocationSchema2 });
1482
+ const claims = await viewer.claims(controller, {
1483
+ declaredObjectSchemaPrefix: WakeGrantRevocationSchema3,
1484
+ subject
1485
+ });
502
1486
  for (const claim of claims) {
503
- if (!isLiveClaim(claim, controller, WakeGrantRevocationSchema2, atBlock)) continue;
1487
+ if (!isLiveClaim(claim, controller, subject, WakeGrantRevocationSchema3, atBlock)) continue;
504
1488
  const object = await viewer.object(claim.objectHash);
505
1489
  if (object?.assurance !== "resolved") continue;
506
- if (object.declaredSchema !== WakeGrantRevocationSchema2 || object.objectHash !== claim.objectHash) continue;
1490
+ if (object.declaredSchema !== WakeGrantRevocationSchema3 || object.objectHash !== claim.objectHash) continue;
507
1491
  if (!isRecord2(object.params) || Object.hasOwn(object.params, "schema")) continue;
508
1492
  const revocation = asWakeGrantRevocation({ ...object.params, schema: object.declaredSchema });
509
1493
  if (revocation !== void 0) revoked.add(revocation.grant);
@@ -511,7 +1495,7 @@ async function readRevocations(viewer, controller, atBlock) {
511
1495
  return revoked;
512
1496
  }
513
1497
  async function resolveEvidence(viewer, claim, request, atBlock, revokedGrantHashes) {
514
- if (!isLiveClaim(claim, request.controller, WakeGrantObjectSchema2, atBlock)) return void 0;
1498
+ if (!isLiveClaim(claim, request.controller, request.publisher, WakeGrantObjectSchema3, atBlock)) return void 0;
515
1499
  if (revokedGrantHashes.has(claim.objectHash)) return void 0;
516
1500
  const object = await viewer.object(claim.objectHash);
517
1501
  const grant = parseExactGrantObject(object, claim.objectHash);
@@ -529,17 +1513,18 @@ async function resolveEvidence(viewer, claim, request, atBlock, revokedGrantHash
529
1513
  target: grant.publisher
530
1514
  });
531
1515
  }
532
- function isLiveClaim(claim, controller, declaredObjectSchema, atBlock) {
1516
+ function isLiveClaim(claim, controller, subject, declaredObjectSchema, atBlock) {
533
1517
  if (claim.source !== controller) return false;
1518
+ if (claim.subject !== subject) return false;
534
1519
  if (claim.declaredObjectSchema !== declaredObjectSchema) return false;
535
- if (!isNonnegativeSafeInteger2(claim.firstBlock) || claim.firstBlock > atBlock) return false;
536
- if (!isNonnegativeSafeInteger2(claim.lastBlock) || claim.lastBlock < claim.firstBlock) return false;
537
- if (!HashZod.safeParse(claim.firstEventHash).success) return false;
538
- return HashZod.safeParse(claim.objectHash).success;
1520
+ if (!isNonnegativeSafeInteger4(claim.firstBlock) || claim.firstBlock > atBlock) return false;
1521
+ 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;
539
1524
  }
540
1525
  function parseExactGrantObject(object, expectedObjectHash) {
541
1526
  if (object?.assurance !== "resolved") return void 0;
542
- if (object.declaredSchema !== WakeGrantObjectSchema2 || object.objectHash !== expectedObjectHash) return void 0;
1527
+ if (object.declaredSchema !== WakeGrantObjectSchema3 || object.objectHash !== expectedObjectHash) return void 0;
543
1528
  if (!isRecord2(object.params) || Object.hasOwn(object.params, "schema")) return void 0;
544
1529
  return asWakeGrantObject({
545
1530
  ...object.params,
@@ -547,10 +1532,10 @@ function parseExactGrantObject(object, expectedObjectHash) {
547
1532
  });
548
1533
  }
549
1534
  function assertValidRequest(request) {
550
- if (!NormalizedAddressZod.safeParse(request.controller).success) {
1535
+ if (!NormalizedAddressZod4.safeParse(request.controller).success) {
551
1536
  throw new TypeError("Grant controller must be a normalized address");
552
1537
  }
553
- if (!NormalizedAddressZod.safeParse(request.publisher).success) {
1538
+ if (!NormalizedAddressZod4.safeParse(request.publisher).success) {
554
1539
  throw new TypeError("Grant publisher must be a normalized address");
555
1540
  }
556
1541
  if (!DeploymentIdZod.safeParse(request.deploymentId).success) {
@@ -559,18 +1544,18 @@ function assertValidRequest(request) {
559
1544
  if (request.queueId !== void 0 && (request.queueId.length === 0 || request.queueId.length > 255)) {
560
1545
  throw new TypeError("Grant queueId must contain 1 to 255 characters when configured");
561
1546
  }
562
- if (!isNonnegativeSafeInteger2(request.expectedHead)) {
1547
+ if (!isNonnegativeSafeInteger4(request.expectedHead)) {
563
1548
  throw new RangeError("Grant expectedHead must be a nonnegative safe integer");
564
1549
  }
565
1550
  }
566
1551
  async function readHead(viewer) {
567
1552
  const head = await viewer.head();
568
- if (!isNonnegativeSafeInteger2(head)) {
1553
+ if (!isNonnegativeSafeInteger4(head)) {
569
1554
  throw new RangeError("Statement Graph head must be a nonnegative safe integer");
570
1555
  }
571
1556
  return head;
572
1557
  }
573
- function isNonnegativeSafeInteger2(value) {
1558
+ function isNonnegativeSafeInteger4(value) {
574
1559
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
575
1560
  }
576
1561
  function isRecord2(value) {
@@ -580,7 +1565,7 @@ function isRecord2(value) {
580
1565
  // src/verifyWakeRequest.ts
581
1566
  import {
582
1567
  DeploymentIdZod as DeploymentIdZod2,
583
- NormalizedAddressZod as NormalizedAddressZod2,
1568
+ NormalizedAddressZod as NormalizedAddressZod5,
584
1569
  WakeEnvelopeZod,
585
1570
  WakeIdRegExp,
586
1571
  WakeJwtAudienceZod,
@@ -588,7 +1573,7 @@ import {
588
1573
  WakeJwtPayloadZod,
589
1574
  WakeJwtSchema
590
1575
  } from "@xyo-network/event-kit-schemas";
591
- import { Account, PayloadBuilder } from "@xyo-network/sdk";
1576
+ import { Account, PayloadBuilder as PayloadBuilder3 } from "@xyo-network/sdk";
592
1577
  var EVENT_KIT_MAX_JWT_LIFETIME_SECONDS = 300;
593
1578
  var EVENT_KIT_MAX_FUTURE_IAT_SECONDS = 60;
594
1579
  async function verifyWakeRequest(input) {
@@ -622,7 +1607,7 @@ async function verifyWakeRequest(input) {
622
1607
  if (!jwtResult.ok) return jwtResult;
623
1608
  let eventHash;
624
1609
  try {
625
- eventHash = await PayloadBuilder.dataHash(event);
1610
+ eventHash = await PayloadBuilder3.dataHash(event);
626
1611
  } catch (error) {
627
1612
  return reject2("event-hash-failed", [errorMessage2(error)]);
628
1613
  }
@@ -656,16 +1641,16 @@ function validateConfiguration(route, nowSeconds) {
656
1641
  if (route.queueId !== void 0 && (route.queueId.length === 0 || route.queueId.length > 255)) {
657
1642
  return reject2("configuration-invalid", ["queueId must contain 1 to 255 characters when configured"]);
658
1643
  }
659
- if (!NormalizedAddressZod2.safeParse(route.controller).success) {
1644
+ if (!NormalizedAddressZod5.safeParse(route.controller).success) {
660
1645
  return reject2("configuration-invalid", ["controller must be a normalized 40-character lowercase-hex address"]);
661
1646
  }
662
- if (!isNonnegativeSafeInteger3(nowSeconds)) {
1647
+ if (!isNonnegativeSafeInteger5(nowSeconds)) {
663
1648
  return reject2("configuration-invalid", ["nowSeconds must be a nonnegative safe integer"]);
664
1649
  }
665
1650
  if (!Number.isSafeInteger(route.maxBlocksPerWake) || route.maxBlocksPerWake < 1) {
666
1651
  return reject2("configuration-invalid", ["maxBlocksPerWake must be a positive safe integer"]);
667
1652
  }
668
- if (!isNonnegativeSafeInteger3(route.maxGrantLagBlocks)) {
1653
+ if (!isNonnegativeSafeInteger5(route.maxGrantLagBlocks)) {
669
1654
  return reject2("configuration-invalid", ["maxGrantLagBlocks must be a nonnegative safe integer"]);
670
1655
  }
671
1656
  return void 0;
@@ -700,14 +1685,14 @@ async function verifyJwtProfile(token, audience, nowSeconds) {
700
1685
  function parseStrictJwtWire(header, payload, audience) {
701
1686
  const headerResult = WakeJwtHeaderZod.safeParse(header);
702
1687
  if (!headerResult.success) {
703
- if (!NormalizedAddressZod2.safeParse(header.kid).success) return reject2("jwt-identity-invalid");
1688
+ if (!NormalizedAddressZod5.safeParse(header.kid).success) return reject2("jwt-identity-invalid");
704
1689
  return reject2("jwt-header-invalid", zodDetails(headerResult.error.issues));
705
1690
  }
706
1691
  if (Object.hasOwn(payload, "nbf")) return reject2("jwt-nbf-not-allowed");
707
- if (!NormalizedAddressZod2.safeParse(payload.iss).success) return reject2("jwt-identity-invalid");
1692
+ if (!NormalizedAddressZod5.safeParse(payload.iss).success) return reject2("jwt-identity-invalid");
708
1693
  if (payload.schema !== WakeJwtSchema) return reject2("jwt-schema-mismatch");
709
1694
  if (payload.aud !== audience) return reject2("jwt-audience-mismatch");
710
- if (!isNonnegativeSafeInteger3(payload.iat) || !isNonnegativeSafeInteger3(payload.exp) || payload.exp <= payload.iat) {
1695
+ if (!isNonnegativeSafeInteger5(payload.iat) || !isNonnegativeSafeInteger5(payload.exp) || payload.exp <= payload.iat) {
711
1696
  return reject2("jwt-lifetime-invalid");
712
1697
  }
713
1698
  const payloadResult = WakeJwtPayloadZod.safeParse(payload);
@@ -730,14 +1715,14 @@ function classifySdkJwtFailure(reasons) {
730
1715
  return "jwt-invalid";
731
1716
  }
732
1717
  function hasSafeEventNumbers(event) {
733
- return isNonnegativeSafeInteger3(event.fromBlock) && isNonnegativeSafeInteger3(event.toBlock) && isNonnegativeSafeInteger3(event.issuedAt);
1718
+ return isNonnegativeSafeInteger5(event.fromBlock) && isNonnegativeSafeInteger5(event.toBlock) && isNonnegativeSafeInteger5(event.issuedAt);
734
1719
  }
735
1720
  function hasInvertedSafeRange(value) {
736
1721
  if (!isRecord3(value)) return false;
737
1722
  const { fromBlock, toBlock } = value;
738
- return typeof fromBlock === "number" && typeof toBlock === "number" && isNonnegativeSafeInteger3(fromBlock) && isNonnegativeSafeInteger3(toBlock) && fromBlock > toBlock;
1723
+ return typeof fromBlock === "number" && typeof toBlock === "number" && isNonnegativeSafeInteger5(fromBlock) && isNonnegativeSafeInteger5(toBlock) && fromBlock > toBlock;
739
1724
  }
740
- function isNonnegativeSafeInteger3(value) {
1725
+ function isNonnegativeSafeInteger5(value) {
741
1726
  return Number.isSafeInteger(value) && value >= 0;
742
1727
  }
743
1728
  function isRecord3(value) {
@@ -791,12 +1776,47 @@ export {
791
1776
  EVENT_KIT_MAX_FUTURE_IAT_SECONDS,
792
1777
  EVENT_KIT_MAX_JWT_LIFETIME_SECONDS,
793
1778
  EVENT_KIT_REPLAY_RETENTION_SKEW_SECONDS,
1779
+ WakeSubscriptionDecryptionError,
794
1780
  admitAndEnqueue,
1781
+ beginPublisherEndpointChallengeAttempt,
1782
+ canonicalJson,
1783
+ canonicalJsonBytes,
1784
+ completePublisherEndpointChallenge,
1785
+ createEncryptedWakeSubscription,
1786
+ createEndpointChallenge,
1787
+ createEndpointChallengeResponse,
795
1788
  createMemoryStatementGrantGraph,
796
1789
  createMemoryWakeInbox,
797
1790
  createMemoryWakeQueue,
1791
+ createPublisherEncryptionKey,
1792
+ createPublisherEncryptionKeyRevocation,
1793
+ createPublisherService,
1794
+ createPublisherServiceRevocation,
798
1795
  createStatementGraphWakeGrantAuthorizer,
1796
+ createWakeGrant,
1797
+ createWakeGrantRevocation,
1798
+ createWakeSubscriptionAcceptance,
1799
+ createWakeSubscriptionAcceptanceRevocation,
1800
+ createWakeSubscriptionPlaintext,
1801
+ createWakeSubscriptionRevocation,
1802
+ decryptWakeSubscription,
799
1803
  drainQueue,
800
- verifyWakeRequest
1804
+ encryptWakeSubscription,
1805
+ endpointChallengeHash,
1806
+ endpointChallengeMatchesPublisherContext,
1807
+ generatePublisherEncryptionKey,
1808
+ generateWakeSubscriptionEncryptionKeyPair,
1809
+ handshakeObjectHash,
1810
+ issuePublisherEndpointChallenge,
1811
+ resolvePreferredEncryptionKey,
1812
+ selectPublisherService,
1813
+ selectSubscriptionActivation,
1814
+ validateAndDecryptPublisherSubscription,
1815
+ verifyEndpointChallengeResponse,
1816
+ verifyWakeRequest,
1817
+ wakeSubscriptionAadBytes,
1818
+ wakeSubscriptionPlaintextBytes,
1819
+ wakeSubscriptionPlaintextFromBytes,
1820
+ withHandshakeObjectHash
801
1821
  };
802
1822
  //# sourceMappingURL=index.mjs.map