@xyo-network/event-kit-node 0.1.1 → 0.1.2

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 (36) hide show
  1. package/README.md +23 -3
  2. package/dist/node/handshake.mjs +122 -249
  3. package/dist/node/handshake.mjs.map +2 -2
  4. package/dist/node/handshakeClients.d.ts +7 -4
  5. package/dist/node/handshakeClients.d.ts.map +1 -1
  6. package/dist/node/handshakeMutationIntent.d.ts +118 -34
  7. package/dist/node/handshakeMutationIntent.d.ts.map +1 -1
  8. package/dist/node/index.d.ts +1 -0
  9. package/dist/node/index.d.ts.map +1 -1
  10. package/dist/node/index.mjs +1582 -291
  11. package/dist/node/index.mjs.map +4 -4
  12. package/dist/node/runtime/abort.d.ts +6 -0
  13. package/dist/node/runtime/abort.d.ts.map +1 -0
  14. package/dist/node/runtime/boundedFetch.d.ts +20 -0
  15. package/dist/node/runtime/boundedFetch.d.ts.map +1 -0
  16. package/dist/node/runtime/handshakeDiscovery.d.ts +16 -0
  17. package/dist/node/runtime/handshakeDiscovery.d.ts.map +1 -0
  18. package/dist/node/runtime/httpsTransport.d.ts +24 -0
  19. package/dist/node/runtime/httpsTransport.d.ts.map +1 -0
  20. package/dist/node/runtime/publisherRuntime.d.ts +84 -0
  21. package/dist/node/runtime/publisherRuntime.d.ts.map +1 -0
  22. package/dist/node/runtime/restGateway.d.ts +36 -0
  23. package/dist/node/runtime/restGateway.d.ts.map +1 -0
  24. package/dist/node/runtime/sourceSigner.d.ts +41 -0
  25. package/dist/node/runtime/sourceSigner.d.ts.map +1 -0
  26. package/dist/node/runtime/sources.d.ts +35 -0
  27. package/dist/node/runtime/sources.d.ts.map +1 -0
  28. package/dist/node/runtime/sqliteHandshakeStores.d.ts +15 -0
  29. package/dist/node/runtime/sqliteHandshakeStores.d.ts.map +1 -0
  30. package/dist/node/runtime/sqlitePublisherState.d.ts +21 -0
  31. package/dist/node/runtime/sqlitePublisherState.d.ts.map +1 -0
  32. package/dist/node/runtime.d.ts +10 -0
  33. package/dist/node/runtime.d.ts.map +1 -0
  34. package/dist/node/runtime.mjs +1640 -0
  35. package/dist/node/runtime.mjs.map +7 -0
  36. package/package.json +16 -11
@@ -1,3 +1,14 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+
1
12
  // src/filesystemCursorStore.ts
2
13
  import {
3
14
  mkdir,
@@ -765,8 +776,8 @@ function createMemoryHandshakeMutationIntentStore() {
765
776
  const intents = /* @__PURE__ */ new Map();
766
777
  return {
767
778
  async get(rawLookup) {
768
- const lookup = parseHandshakeMutationIntentLookup(rawLookup);
769
- return intents.get(intentLookupKey(lookup));
779
+ const lookup2 = parseHandshakeMutationIntentLookup(rawLookup);
780
+ return intents.get(intentLookupKey(lookup2));
770
781
  },
771
782
  async getOrCreate(rawIntent) {
772
783
  const proposed = await parseHandshakeMutationIntent(rawIntent);
@@ -781,8 +792,8 @@ function createMemoryHandshakeMutationIntentStore() {
781
792
  }
782
793
  };
783
794
  }
784
- function intentLookupKey(lookup) {
785
- const parsed = parseHandshakeMutationIntentLookup(lookup);
795
+ function intentLookupKey(lookup2) {
796
+ const parsed = parseHandshakeMutationIntentLookup(lookup2);
786
797
  return [parsed.chainId, parsed.publisher, parsed.source, parsed.kind, parsed.operationId].join("/");
787
798
  }
788
799
  function assertSameIntentBinding(left, right) {
@@ -853,22 +864,22 @@ async function assertRevocationIntent(intent) {
853
864
  function createFilesystemHandshakeMutationIntentStore(options) {
854
865
  const root = PATH9.resolve(options.path);
855
866
  function pathFor(rawLookup) {
856
- const lookup = parseHandshakeMutationIntentLookup(rawLookup);
867
+ const lookup2 = parseHandshakeMutationIntentLookup(rawLookup);
857
868
  return PATH9.join(
858
869
  root,
859
- lookup.chainId,
860
- lookup.publisher,
861
- lookup.source,
862
- lookup.kind,
863
- `${lookup.operationId}.json`
870
+ lookup2.chainId,
871
+ lookup2.publisher,
872
+ lookup2.source,
873
+ lookup2.kind,
874
+ `${lookup2.operationId}.json`
864
875
  );
865
876
  }
866
- async function readIntent(lookup) {
867
- const path = pathFor(lookup);
877
+ async function readIntent(lookup2) {
878
+ const path = pathFor(lookup2);
868
879
  const raw = await readJsonFileStrict(path);
869
880
  if (raw === void 0) return void 0;
870
881
  const intent = await parseHandshakeMutationIntent(raw);
871
- const parsedLookup = parseHandshakeMutationIntentLookup(lookup);
882
+ const parsedLookup = parseHandshakeMutationIntentLookup(lookup2);
872
883
  if (intent.chainId !== parsedLookup.chainId || intent.kind !== parsedLookup.kind || intent.operationId !== parsedLookup.operationId || intent.publisher !== parsedLookup.publisher || intent.source !== parsedLookup.source) {
873
884
  throw new Error("handshake mutation intent does not match its immutable path");
874
885
  }
@@ -877,8 +888,8 @@ function createFilesystemHandshakeMutationIntentStore(options) {
877
888
  return intent;
878
889
  }
879
890
  return {
880
- async get(lookup) {
881
- return await readIntent(parseHandshakeMutationIntentLookup(lookup));
891
+ async get(lookup2) {
892
+ return await readIntent(parseHandshakeMutationIntentLookup(lookup2));
882
893
  },
883
894
  async getOrCreate(rawIntent) {
884
895
  const proposed = await parseHandshakeMutationIntent(rawIntent);
@@ -906,35 +917,35 @@ import {
906
917
  } from "@xyo-network/event-kit-schemas";
907
918
  function createFilesystemPublisherEncryptionKeyStore(options) {
908
919
  const root = PATH10.resolve(options.path);
909
- function parseLookup(lookup) {
920
+ function parseLookup(lookup2) {
910
921
  return {
911
- encryptionKey: HashZod2.parse(lookup.encryptionKey),
912
- keyId: HandshakeIdZod2.parse(lookup.keyId),
913
- publisher: NormalizedAddressZod2.parse(lookup.publisher)
922
+ encryptionKey: HashZod2.parse(lookup2.encryptionKey),
923
+ keyId: HandshakeIdZod2.parse(lookup2.keyId),
924
+ publisher: NormalizedAddressZod2.parse(lookup2.publisher)
914
925
  };
915
926
  }
916
- function pathFor(lookup) {
917
- return PATH10.join(root, lookup.publisher, `${lookup.encryptionKey}-${lookup.keyId}.json`);
927
+ function pathFor(lookup2) {
928
+ return PATH10.join(root, lookup2.publisher, `${lookup2.encryptionKey}-${lookup2.keyId}.json`);
918
929
  }
919
- function keyIdPath(lookup) {
920
- return PATH10.join(root, lookup.publisher, "key-ids", `${lookup.keyId}.json`);
930
+ function keyIdPath(lookup2) {
931
+ return PATH10.join(root, lookup2.publisher, "key-ids", `${lookup2.keyId}.json`);
921
932
  }
922
- async function readRecord2(lookup) {
923
- const path = pathFor(lookup);
933
+ async function readRecord2(lookup2) {
934
+ const path = pathFor(lookup2);
924
935
  const raw = await readJsonFileStrict(path);
925
936
  if (raw === void 0) return void 0;
926
937
  const parsed = parsePrivateKeyRecord(raw);
927
- if (parsed.publisher !== lookup.publisher || parsed.encryptionKey !== lookup.encryptionKey || parsed.keyId !== lookup.keyId) throw new Error("publisher encryption-key record does not match its immutable path");
928
- const keyIdRecord = parseKeyIdRecord(await readJsonFileStrict(keyIdPath(lookup)));
929
- if (keyIdRecord.publisher !== lookup.publisher || keyIdRecord.encryptionKey !== lookup.encryptionKey || keyIdRecord.keyId !== lookup.keyId) throw new Error("publisher encryption-key keyId index does not match its immutable path");
938
+ if (parsed.publisher !== lookup2.publisher || parsed.encryptionKey !== lookup2.encryptionKey || parsed.keyId !== lookup2.keyId) throw new Error("publisher encryption-key record does not match its immutable path");
939
+ const keyIdRecord = parseKeyIdRecord(await readJsonFileStrict(keyIdPath(lookup2)));
940
+ if (keyIdRecord.publisher !== lookup2.publisher || keyIdRecord.encryptionKey !== lookup2.encryptionKey || keyIdRecord.keyId !== lookup2.keyId) throw new Error("publisher encryption-key keyId index does not match its immutable path");
930
941
  const metadata = await stat2(path);
931
942
  if ((metadata.mode & 63) !== 0) throw new Error("publisher encryption-key record permissions are too broad");
932
943
  return parsed;
933
944
  }
934
945
  return {
935
946
  async getPrivateKey(rawLookup) {
936
- const lookup = parseLookup(rawLookup);
937
- const record = await readRecord2(lookup);
947
+ const lookup2 = parseLookup(rawLookup);
948
+ const record = await readRecord2(lookup2);
938
949
  if (record === void 0) return void 0;
939
950
  return Object.freeze({
940
951
  encryptionKey: record.encryptionKey,
@@ -944,25 +955,25 @@ function createFilesystemPublisherEncryptionKeyStore(options) {
944
955
  },
945
956
  async putPrivateKey(input) {
946
957
  const record = parsePrivateKeyRecord({ ...input.key, publisher: input.publisher });
947
- const lookup = parseLookup(record);
948
- const path = pathFor(lookup);
958
+ const lookup2 = parseLookup(record);
959
+ const path = pathFor(lookup2);
949
960
  const keyIdRecord = {
950
961
  encryptionKey: record.encryptionKey,
951
962
  keyId: record.keyId,
952
963
  publisher: record.publisher
953
964
  };
954
965
  if (!await publishJsonFile(
955
- keyIdPath(lookup),
966
+ keyIdPath(lookup2),
956
967
  keyIdRecord,
957
968
  { directoryMode: 448, mode: 384 }
958
969
  )) {
959
- const existingKeyId = parseKeyIdRecord(await readJsonFileStrict(keyIdPath(lookup)));
970
+ const existingKeyId = parseKeyIdRecord(await readJsonFileStrict(keyIdPath(lookup2)));
960
971
  if (stringifyJson(existingKeyId) !== stringifyJson(keyIdRecord)) {
961
972
  throw new Error(`publisher encryption-key keyId collision for ${record.keyId}`);
962
973
  }
963
974
  }
964
975
  if (await publishJsonFile(path, record, { directoryMode: 448, mode: 384 })) return "stored";
965
- const existing = await readRecord2(lookup);
976
+ const existing = await readRecord2(lookup2);
966
977
  if (stringifyJson(existing) !== stringifyJson(record)) {
967
978
  throw new Error(`publisher encryption-key collision for ${record.encryptionKey}/${record.keyId}`);
968
979
  }
@@ -1143,6 +1154,7 @@ function requireTime(value) {
1143
1154
  // src/handshakeClients.ts
1144
1155
  import {
1145
1156
  beginPublisherEndpointChallengeAttempt,
1157
+ canonicalJson,
1146
1158
  completePublisherEndpointChallenge,
1147
1159
  createEncryptedWakeSubscription,
1148
1160
  createPublisherEncryptionKeyRevocation,
@@ -1191,10 +1203,7 @@ function createSynchronizedEventKitHandshakeReader(options) {
1191
1203
  function assertIdentity() {
1192
1204
  const checkpoint = options.replay.snapshot();
1193
1205
  if (checkpoint.chainId !== chainId || checkpoint.network !== options.session.network || checkpoint.publisher !== publisher) {
1194
- throw new EventKitHandshakeClientError(
1195
- "identity-mismatch",
1196
- "Finalized replay identity does not match the pinned Event Kit network and publisher"
1197
- );
1206
+ throw new EventKitHandshakeClientError("identity-mismatch", "Finalized replay identity does not match the pinned Event Kit network and publisher");
1198
1207
  }
1199
1208
  }
1200
1209
  return Object.freeze({
@@ -1247,10 +1256,7 @@ function createEventKitHandshakePublicationPort(transport) {
1247
1256
  const raw = String(await transport.signer.address());
1248
1257
  const normalized = NormalizedAddressZod3.parse(normalizeAddress(raw));
1249
1258
  if (raw !== normalized) {
1250
- throw new EventKitHandshakeClientError(
1251
- "identity-mismatch",
1252
- "XL1 publication signer address is not canonical lowercase hexadecimal without 0x"
1253
- );
1259
+ throw new EventKitHandshakeClientError("identity-mismatch", "XL1 publication signer address is not canonical lowercase hexadecimal without 0x");
1254
1260
  }
1255
1261
  return normalized;
1256
1262
  }
@@ -1266,10 +1272,7 @@ function nextBlock(head) {
1266
1272
  function samplePublisherClock(nowSeconds) {
1267
1273
  const sampled = nowSeconds();
1268
1274
  if (!Number.isSafeInteger(sampled) || sampled < 0) {
1269
- throw new EventKitHandshakeClientError(
1270
- "challenge-rejected",
1271
- "Publisher clock must return a nonnegative JSON-safe Unix second"
1272
- );
1275
+ throw new EventKitHandshakeClientError("challenge-rejected", "Publisher clock must return a nonnegative JSON-safe Unix second");
1273
1276
  }
1274
1277
  return sampled;
1275
1278
  }
@@ -1292,37 +1295,25 @@ function serviceQuery(reader, snapshot, serviceId) {
1292
1295
  }
1293
1296
  function requireService(discovery) {
1294
1297
  if (!discovery.ok) {
1295
- throw new EventKitHandshakeClientError(
1296
- "service-unavailable",
1297
- `Publisher service is unavailable: ${discovery.reason}`
1298
- );
1298
+ throw new EventKitHandshakeClientError("service-unavailable", `Publisher service is unavailable: ${discovery.reason}`);
1299
1299
  }
1300
1300
  return discovery;
1301
1301
  }
1302
1302
  function requireExpectedService(discovery, expected) {
1303
1303
  const expectedHash = HashZod4.parse(expected);
1304
1304
  if (discovery.service.objectHash !== expectedHash) {
1305
- throw new EventKitHandshakeClientError(
1306
- "service-mismatch",
1307
- "Currently selected publisher service does not match the expected object hash"
1308
- );
1305
+ throw new EventKitHandshakeClientError("service-mismatch", "Currently selected publisher service does not match the expected object hash");
1309
1306
  }
1310
1307
  return expectedHash;
1311
1308
  }
1312
1309
  function assertPublicationIdentity(publication, reader) {
1313
1310
  if (publication.chainId !== reader.chainId) {
1314
- throw new EventKitHandshakeClientError(
1315
- "identity-mismatch",
1316
- "Publication transport chain ID does not match the synchronized handshake reader"
1317
- );
1311
+ throw new EventKitHandshakeClientError("identity-mismatch", "Publication transport chain ID does not match the synchronized handshake reader");
1318
1312
  }
1319
1313
  }
1320
1314
  async function assertPublicationSource(publication, expected) {
1321
1315
  if (await publication.source() !== expected) {
1322
- throw new EventKitHandshakeClientError(
1323
- "identity-mismatch",
1324
- "Publication signer does not match the required handshake Claim source"
1325
- );
1316
+ throw new EventKitHandshakeClientError("identity-mismatch", "Publication signer does not match the required handshake Claim source");
1326
1317
  }
1327
1318
  }
1328
1319
  function intentLookup(reader, kind, operationId, source) {
@@ -1335,15 +1326,13 @@ function intentLookup(reader, kind, operationId, source) {
1335
1326
  };
1336
1327
  }
1337
1328
  function mutationIntentError(error) {
1338
- return error instanceof HandshakeMutationIntentConflictError ? new EventKitHandshakeClientError("mutation-intent-conflict", error.message) : new EventKitHandshakeClientError(
1339
- "mutation-intent-unavailable",
1340
- "Handshake mutation intent storage is unavailable or invalid"
1341
- );
1329
+ return error instanceof HandshakeMutationIntentConflictError ? new EventKitHandshakeClientError("mutation-intent-conflict", error.message) : new EventKitHandshakeClientError("mutation-intent-unavailable", "Handshake mutation intent storage is unavailable or invalid");
1342
1330
  }
1343
1331
  async function loadMutationIntent(store, reader, kind, operationId, source, requestFingerprint) {
1344
1332
  try {
1345
1333
  const existing = await store.get(intentLookup(reader, kind, operationId, source));
1346
- if (existing === void 0) return void 0;
1334
+ if (existing === void 0)
1335
+ return void 0;
1347
1336
  if (existing.kind !== kind || existing.requestFingerprint !== requestFingerprint) {
1348
1337
  throw new HandshakeMutationIntentConflictError();
1349
1338
  }
@@ -1362,7 +1351,8 @@ async function persistMutationIntent(store, intent) {
1362
1351
  async function publisherServiceRequestFingerprint(input) {
1363
1352
  return await handshakeMutationRequestFingerprint({
1364
1353
  expiresAtBlock: input.expiresAtBlock ?? null,
1365
- maxBlocksPerWake: input.maxBlocksPerWake,
1354
+ maxPositionsPerWake: input.maxPositionsPerWake,
1355
+ sources: input.sources,
1366
1356
  maxSubscriptionLifetimeBlocks: input.maxSubscriptionLifetimeBlocks,
1367
1357
  validFromBlock: input.validFromBlock ?? null
1368
1358
  });
@@ -1371,7 +1361,7 @@ async function publisherRotationRequestFingerprint(input) {
1371
1361
  return await handshakeMutationRequestFingerprint({
1372
1362
  expiresAtBlock: input.expiresAtBlock ?? null,
1373
1363
  keyExpiresAtBlock: input.keyExpiresAtBlock ?? null,
1374
- maxBlocksPerWake: input.maxBlocksPerWake ?? null,
1364
+ maxPositionsPerWake: input.maxPositionsPerWake ?? null,
1375
1365
  maxSubscriptionLifetimeBlocks: input.maxSubscriptionLifetimeBlocks ?? null,
1376
1366
  service: HashZod4.parse(input.service),
1377
1367
  validFromBlock: input.validFromBlock ?? null
@@ -1385,7 +1375,9 @@ async function subscriberSubscriptionRequestFingerprint(input) {
1385
1375
  endpoint: input.endpoint,
1386
1376
  expiresAtBlock: input.expiresAtBlock,
1387
1377
  grantId: input.grantId ?? null,
1388
- maxBlocksPerWake: input.maxBlocksPerWake ?? null,
1378
+ source: input.source,
1379
+ fromPosition: input.fromPosition,
1380
+ maxPositionsPerWake: input.maxPositionsPerWake ?? null,
1389
1381
  queueId: input.queueId ?? null,
1390
1382
  revision: input.revision ?? null,
1391
1383
  subscriptionId: input.subscriptionId ?? null,
@@ -1428,10 +1420,7 @@ function protocolCandidate(reader, discovery, candidate, keys) {
1428
1420
  };
1429
1421
  }
1430
1422
  function validationError(reason) {
1431
- return new EventKitHandshakeClientError(
1432
- "subscription-invalid",
1433
- `Publisher subscription candidate failed validation: ${reason}`
1434
- );
1423
+ return new EventKitHandshakeClientError("subscription-invalid", `Publisher subscription candidate failed validation: ${reason}`);
1435
1424
  }
1436
1425
  function challengeError(result) {
1437
1426
  const reason = result.ok ? "unknown" : result.reason;
@@ -1456,7 +1445,8 @@ function createPublisherHandshakeClient(options) {
1456
1445
  }
1457
1446
  async function resolveCandidate(selector) {
1458
1447
  const found = await candidateDiscovery(selector);
1459
- if (!found.ok) throw new EventKitHandshakeClientError("service-unavailable", `Publisher service is unavailable: ${found.reason}`);
1448
+ if (!found.ok)
1449
+ throw new EventKitHandshakeClientError("service-unavailable", `Publisher service is unavailable: ${found.reason}`);
1460
1450
  const subscriber = NormalizedAddressZod3.parse(selector.subscriber);
1461
1451
  const subscription = selector.subscription === void 0 ? void 0 : HashZod4.parse(selector.subscription);
1462
1452
  const candidates = found.candidates.filter((candidate2) => candidate2.subscriber === subscriber && (subscription === void 0 || candidate2.tuple.subscription.objectHash === subscription));
@@ -1467,10 +1457,9 @@ function createPublisherHandshakeClient(options) {
1467
1457
  throw new EventKitHandshakeClientError("candidate-ambiguous", "More than one finalized acceptance candidate matched");
1468
1458
  }
1469
1459
  const candidate = candidates[0];
1470
- const validated = await validateAndDecryptPublisherSubscription(
1471
- protocolCandidate(options.reader, found, candidate, options.keys)
1472
- );
1473
- if (!validated.ok) throw validationError(validated.reason);
1460
+ const validated = await validateAndDecryptPublisherSubscription(protocolCandidate(options.reader, found, candidate, options.keys));
1461
+ if (!validated.ok)
1462
+ throw validationError(validated.reason);
1474
1463
  return { candidate, validated };
1475
1464
  }
1476
1465
  async function candidateForChallenge(challenge) {
@@ -1479,10 +1468,7 @@ function createPublisherHandshakeClient(options) {
1479
1468
  subscription: challenge.subscription
1480
1469
  });
1481
1470
  if (!endpointChallengeMatchesPublisherContext(challenge, resolved.validated.context)) {
1482
- throw new EventKitHandshakeClientError(
1483
- "challenge-context-invalid",
1484
- "Endpoint challenge does not match the current finalized subscription candidate"
1485
- );
1471
+ throw new EventKitHandshakeClientError("challenge-context-invalid", "Endpoint challenge does not match the current finalized subscription candidate");
1486
1472
  }
1487
1473
  return resolved;
1488
1474
  }
@@ -1572,12 +1558,7 @@ function createPublisherHandshakeClient(options) {
1572
1558
  operationId: intent.operationId,
1573
1559
  response: intent.response
1574
1560
  });
1575
- const reconciliation = await reconcileAcceptance(
1576
- acceptanceHash,
1577
- publication,
1578
- intent.challenge.subscriber,
1579
- intent.challenge.subscription
1580
- );
1561
+ const reconciliation = await reconcileAcceptance(acceptanceHash, publication, intent.challenge.subscriber, intent.challenge.subscription);
1581
1562
  return Object.freeze({
1582
1563
  acceptance: Object.freeze({ body: intent.acceptance, objectHash: acceptanceHash }),
1583
1564
  challenge: intent.operationId,
@@ -1598,10 +1579,7 @@ function createPublisherHandshakeClient(options) {
1598
1579
  publisher: options.reader.publisher
1599
1580
  });
1600
1581
  } catch {
1601
- throw new EventKitHandshakeClientError(
1602
- "key-custody-failed",
1603
- "Publisher encryption private key was not durably retained; publication was not attempted"
1604
- );
1582
+ throw new EventKitHandshakeClientError("key-custody-failed", "Publisher encryption private key was not durably retained; publication was not attempted");
1605
1583
  }
1606
1584
  const [keyHash, serviceHash] = await Promise.all([
1607
1585
  handshakeObjectHash2(intent.encryptionKey),
@@ -1624,19 +1602,19 @@ function createPublisherHandshakeClient(options) {
1624
1602
  const client = {
1625
1603
  async acceptanceCandidates(selector = {}) {
1626
1604
  const found = await candidateDiscovery(selector);
1627
- if (!found.ok || selector.subscription === void 0) return found;
1605
+ if (!found.ok || selector.subscription === void 0)
1606
+ return found;
1628
1607
  const subscription = HashZod4.parse(selector.subscription);
1629
1608
  return Object.freeze({
1630
1609
  ...found,
1631
- candidates: found.candidates.filter(
1632
- (candidate) => candidate.tuple.subscription.objectHash === subscription
1633
- )
1610
+ candidates: found.candidates.filter((candidate) => candidate.tuple.subscription.objectHash === subscription)
1634
1611
  });
1635
1612
  },
1636
1613
  async beginChallenge(input) {
1637
1614
  const challengeHash = HashZod4.parse(input.challengeHash);
1638
1615
  const record = await options.challenges.get(challengeHash);
1639
- if (record === void 0) return { kind: "missing" };
1616
+ if (record === void 0)
1617
+ return { kind: "missing" };
1640
1618
  const resolved = await candidateForChallenge(record.challenge);
1641
1619
  const begun = await beginPublisherEndpointChallengeAttempt({
1642
1620
  challengeHash,
@@ -1671,10 +1649,7 @@ function createPublisherHandshakeClient(options) {
1671
1649
  throw new EventKitHandshakeClientError("challenge-not-found", "Endpoint challenge was not found");
1672
1650
  }
1673
1651
  if (record.challenge.subscriber !== subscriber || record.challenge.subscription !== subscription) {
1674
- throw new EventKitHandshakeClientError(
1675
- "challenge-context-invalid",
1676
- "Stored endpoint challenge does not match the caller expected subscriber and subscription"
1677
- );
1652
+ throw new EventKitHandshakeClientError("challenge-context-invalid", "Stored endpoint challenge does not match the caller expected subscriber and subscription");
1678
1653
  }
1679
1654
  const responseHash = await handshakeObjectHash2(input.response);
1680
1655
  const requestFingerprint = await exactMutationRequestFingerprint({
@@ -1683,20 +1658,10 @@ function createPublisherHandshakeClient(options) {
1683
1658
  subscriber,
1684
1659
  subscription
1685
1660
  });
1686
- const existing = await loadMutationIntent(
1687
- options.intents,
1688
- options.reader,
1689
- "publisher-subscription-accept",
1690
- challengeHash,
1691
- options.reader.publisher,
1692
- requestFingerprint
1693
- );
1661
+ const existing = await loadMutationIntent(options.intents, options.reader, "publisher-subscription-accept", challengeHash, options.reader.publisher, requestFingerprint);
1694
1662
  if (existing !== void 0) {
1695
1663
  if (record.state !== "verified" || record.responseHash !== responseHash) {
1696
- throw new EventKitHandshakeClientError(
1697
- "mutation-intent-conflict",
1698
- "Acceptance intent does not match the durable verified challenge decision"
1699
- );
1664
+ throw new EventKitHandshakeClientError("mutation-intent-conflict", "Acceptance intent does not match the durable verified challenge decision");
1700
1665
  }
1701
1666
  return await publishAcceptanceIntent(existing, "resumed");
1702
1667
  }
@@ -1708,36 +1673,22 @@ function createPublisherHandshakeClient(options) {
1708
1673
  store: options.challenges,
1709
1674
  subscription: resolved.validated
1710
1675
  });
1711
- if (!completed.ok) throw challengeError(completed);
1712
- const concurrentlyPersisted = await loadMutationIntent(
1713
- options.intents,
1714
- options.reader,
1715
- "publisher-subscription-accept",
1716
- challengeHash,
1717
- options.reader.publisher,
1718
- requestFingerprint
1719
- );
1720
- if (concurrentlyPersisted !== void 0) return await publishAcceptanceIntent(concurrentlyPersisted, "resumed");
1676
+ if (!completed.ok)
1677
+ throw challengeError(completed);
1678
+ const concurrentlyPersisted = await loadMutationIntent(options.intents, options.reader, "publisher-subscription-accept", challengeHash, options.reader.publisher, requestFingerprint);
1679
+ if (concurrentlyPersisted !== void 0)
1680
+ return await publishAcceptanceIntent(concurrentlyPersisted, "resumed");
1721
1681
  let current;
1722
1682
  try {
1723
1683
  current = await candidateForChallenge(record.challenge);
1724
1684
  } catch (error) {
1725
- const recovered = await loadMutationIntent(
1726
- options.intents,
1727
- options.reader,
1728
- "publisher-subscription-accept",
1729
- challengeHash,
1730
- options.reader.publisher,
1731
- requestFingerprint
1732
- );
1733
- if (recovered !== void 0) return await publishAcceptanceIntent(recovered, "resumed");
1685
+ const recovered = await loadMutationIntent(options.intents, options.reader, "publisher-subscription-accept", challengeHash, options.reader.publisher, requestFingerprint);
1686
+ if (recovered !== void 0)
1687
+ return await publishAcceptanceIntent(recovered, "resumed");
1734
1688
  throw error;
1735
1689
  }
1736
1690
  if (!endpointChallengeMatchesPublisherContext(record.challenge, current.validated.context)) {
1737
- throw new EventKitHandshakeClientError(
1738
- "challenge-context-invalid",
1739
- "Endpoint challenge candidate changed before acceptance publication"
1740
- );
1691
+ throw new EventKitHandshakeClientError("challenge-context-invalid", "Endpoint challenge candidate changed before acceptance publication");
1741
1692
  }
1742
1693
  const resolvedIntent = await persistMutationIntent(options.intents, {
1743
1694
  acceptance: completed.acceptance,
@@ -1779,42 +1730,35 @@ function createPublisherHandshakeClient(options) {
1779
1730
  async publishService(input) {
1780
1731
  await assertPublicationSource(options.publication, options.reader.publisher);
1781
1732
  if (serviceId !== void 0) {
1782
- throw new EventKitHandshakeClientError(
1783
- "service-root-requires-fresh-id",
1784
- "Root service publication requires an unconfigured client so a fresh serviceId is generated"
1785
- );
1733
+ throw new EventKitHandshakeClientError("service-root-requires-fresh-id", "Root service publication requires an unconfigured client so a fresh serviceId is generated");
1786
1734
  }
1787
1735
  const operationId = HandshakeIdZod3.parse(input.operationId);
1788
1736
  const requestFingerprint = await publisherServiceRequestFingerprint(input);
1789
- const priorIntent = await loadMutationIntent(
1790
- options.intents,
1791
- options.reader,
1792
- "publisher-service-publish",
1793
- operationId,
1794
- options.reader.publisher,
1795
- requestFingerprint
1796
- );
1797
- if (priorIntent !== void 0) return await publishPublisherServiceIntent(priorIntent, "resumed");
1737
+ const priorIntent = await loadMutationIntent(options.intents, options.reader, "publisher-service-publish", operationId, options.reader.publisher, requestFingerprint);
1738
+ if (priorIntent !== void 0)
1739
+ return await publishPublisherServiceIntent(priorIntent, "resumed");
1798
1740
  const current = await snapshot();
1799
1741
  const existing = await discovery(current);
1800
1742
  if (existing.ok) {
1801
- throw new EventKitHandshakeClientError(
1802
- "service-already-exists",
1803
- "An active publisher service already exists; rotate its key to publish a successor"
1804
- );
1743
+ throw new EventKitHandshakeClientError("service-already-exists", "An active publisher service already exists; rotate its key to publish a successor");
1805
1744
  }
1806
1745
  if (existing.reason !== "service-not-found") {
1807
1746
  throw new EventKitHandshakeClientError("service-unavailable", `Cannot declare service: ${existing.reason}`);
1808
1747
  }
1809
1748
  const validFromBlock = input.validFromBlock ?? nextBlock(current.finalizedHead);
1810
1749
  const generated = await generatePublisherEncryptionKey({ validFromBlock });
1811
- const service = createPublisherService({
1750
+ const serviceInput = {
1812
1751
  encryptionKeys: [generated.descriptorHash],
1813
1752
  ...input.expiresAtBlock === void 0 ? {} : { expiresAtBlock: input.expiresAtBlock },
1814
- maxBlocksPerWake: input.maxBlocksPerWake,
1815
1753
  maxSubscriptionLifetimeBlocks: input.maxSubscriptionLifetimeBlocks,
1816
1754
  preferredEncryptionKey: generated.descriptorHash,
1817
1755
  validFromBlock
1756
+ };
1757
+ const service = createPublisherService({
1758
+ ...serviceInput,
1759
+ authorizationChainId: options.reader.chainId,
1760
+ sources: input.sources,
1761
+ maxPositionsPerWake: input.maxPositionsPerWake
1818
1762
  });
1819
1763
  const resolvedIntent = await persistMutationIntent(options.intents, {
1820
1764
  chainId: options.reader.chainId,
@@ -1834,23 +1778,13 @@ function createPublisherHandshakeClient(options) {
1834
1778
  await assertPublicationSource(options.publication, options.reader.publisher);
1835
1779
  const keyHash = HashZod4.parse(key);
1836
1780
  const requestFingerprint = await exactMutationRequestFingerprint({ key: keyHash });
1837
- let resolvedIntent = await loadMutationIntent(
1838
- options.intents,
1839
- options.reader,
1840
- "publisher-encryption-key-retire",
1841
- keyHash,
1842
- options.reader.publisher,
1843
- requestFingerprint
1844
- );
1781
+ let resolvedIntent = await loadMutationIntent(options.intents, options.reader, "publisher-encryption-key-retire", keyHash, options.reader.publisher, requestFingerprint);
1845
1782
  let intentDisposition = "resumed";
1846
1783
  if (resolvedIntent === void 0) {
1847
1784
  const current = await snapshot();
1848
1785
  const selected = requireService(await discovery(current));
1849
1786
  if (selected.key.objectHash !== keyHash || !selected.service.body.encryptionKeys.includes(keyHash) || selected.service.body.preferredEncryptionKey !== keyHash) {
1850
- throw new EventKitHandshakeClientError(
1851
- "key-mismatch",
1852
- "Encryption key does not match the exact current preferred descriptor evidence"
1853
- );
1787
+ throw new EventKitHandshakeClientError("key-mismatch", "Encryption key does not match the exact current preferred descriptor evidence");
1854
1788
  }
1855
1789
  const persisted = await persistMutationIntent(options.intents, {
1856
1790
  chainId: options.reader.chainId,
@@ -1882,14 +1816,7 @@ function createPublisherHandshakeClient(options) {
1882
1816
  await assertPublicationSource(options.publication, options.reader.publisher);
1883
1817
  const service = HashZod4.parse(expectedService);
1884
1818
  const requestFingerprint = await exactMutationRequestFingerprint({ service });
1885
- let resolvedIntent = await loadMutationIntent(
1886
- options.intents,
1887
- options.reader,
1888
- "publisher-service-retire",
1889
- service,
1890
- options.reader.publisher,
1891
- requestFingerprint
1892
- );
1819
+ let resolvedIntent = await loadMutationIntent(options.intents, options.reader, "publisher-service-retire", service, options.reader.publisher, requestFingerprint);
1893
1820
  let intentDisposition = "resumed";
1894
1821
  if (resolvedIntent === void 0) {
1895
1822
  const current = await snapshot();
@@ -1925,15 +1852,9 @@ function createPublisherHandshakeClient(options) {
1925
1852
  await assertPublicationSource(options.publication, options.reader.publisher);
1926
1853
  const operationId = HandshakeIdZod3.parse(input.operationId);
1927
1854
  const requestFingerprint = await publisherRotationRequestFingerprint(input);
1928
- const priorIntent = await loadMutationIntent(
1929
- options.intents,
1930
- options.reader,
1931
- "publisher-service-rotate-key",
1932
- operationId,
1933
- options.reader.publisher,
1934
- requestFingerprint
1935
- );
1936
- if (priorIntent !== void 0) return await publishPublisherServiceIntent(priorIntent, "resumed");
1855
+ const priorIntent = await loadMutationIntent(options.intents, options.reader, "publisher-service-rotate-key", operationId, options.reader.publisher, requestFingerprint);
1856
+ if (priorIntent !== void 0)
1857
+ return await publishPublisherServiceIntent(priorIntent, "resumed");
1937
1858
  const current = await snapshot();
1938
1859
  const selected = requireService(await discovery(current));
1939
1860
  requireExpectedService(selected, input.service);
@@ -1942,16 +1863,21 @@ function createPublisherHandshakeClient(options) {
1942
1863
  ...input.keyExpiresAtBlock === void 0 ? {} : { expiresAtBlock: input.keyExpiresAtBlock },
1943
1864
  validFromBlock
1944
1865
  });
1945
- const service = createPublisherService({
1866
+ const serviceInput = {
1946
1867
  encryptionKeys: [generated.descriptorHash],
1947
1868
  ...input.expiresAtBlock === void 0 ? selected.service.body.expiresAtBlock === void 0 ? {} : { expiresAtBlock: selected.service.body.expiresAtBlock } : { expiresAtBlock: input.expiresAtBlock },
1948
- maxBlocksPerWake: input.maxBlocksPerWake ?? selected.service.body.limits.maxBlocksPerWake,
1949
1869
  maxSubscriptionLifetimeBlocks: input.maxSubscriptionLifetimeBlocks ?? selected.service.body.limits.maxSubscriptionLifetimeBlocks,
1950
1870
  preferredEncryptionKey: generated.descriptorHash,
1951
1871
  revision: selected.service.body.revision + 1,
1952
1872
  serviceId: selected.service.body.serviceId,
1953
1873
  supersedes: HashZod4.parse(selected.service.objectHash),
1954
1874
  validFromBlock
1875
+ };
1876
+ const service = createPublisherService({
1877
+ ...serviceInput,
1878
+ authorizationChainId: options.reader.chainId,
1879
+ sources: selected.service.body.events.map((event) => event.source),
1880
+ maxPositionsPerWake: input.maxPositionsPerWake ?? selected.service.body.limits.maxPositionsPerWake
1955
1881
  });
1956
1882
  const resolvedIntent = await persistMutationIntent(options.intents, {
1957
1883
  chainId: options.reader.chainId,
@@ -1995,11 +1921,9 @@ function createSubscriberHandshakeClient(options) {
1995
1921
  return readySnapshot(await options.reader.sync());
1996
1922
  }
1997
1923
  async function serviceAt(current) {
1998
- return requireService(
1999
- await current.readModel.discoverPublisherService(serviceQuery(options.reader, current, serviceId))
2000
- );
1924
+ return requireService(await current.readModel.discoverPublisherService(serviceQuery(options.reader, current, serviceId)));
2001
1925
  }
2002
- async function lookup(subscriptionId) {
1926
+ async function lookup2(subscriptionId) {
2003
1927
  const current = await options.reader.sync();
2004
1928
  return await lookupAt(current, subscriptionId);
2005
1929
  }
@@ -2014,29 +1938,21 @@ function createSubscriberHandshakeClient(options) {
2014
1938
  const revision = input.revision ?? 1;
2015
1939
  if (revision === 1) {
2016
1940
  if (input.supersedes !== void 0) {
2017
- throw new EventKitHandshakeClientError(
2018
- "subscription-invalid",
2019
- "Subscription revision 1 must not declare supersedes"
2020
- );
1941
+ throw new EventKitHandshakeClientError("subscription-invalid", "Subscription revision 1 must not declare supersedes");
2021
1942
  }
2022
- if (input.subscriptionId === void 0) return;
1943
+ if (input.subscriptionId === void 0)
1944
+ return;
2023
1945
  const view2 = await lookupAt(current, input.subscriptionId);
2024
1946
  if (!view2.ok) {
2025
1947
  throw new EventKitHandshakeClientError("service-unavailable", `Cannot validate subscription identity: ${view2.reason}`);
2026
1948
  }
2027
1949
  if (view2.subscriptions.some((item) => item.subscriptionId === input.subscriptionId)) {
2028
- throw new EventKitHandshakeClientError(
2029
- "subscription-invalid",
2030
- "Subscription revision 1 would duplicate an existing finalized stable identity"
2031
- );
1950
+ throw new EventKitHandshakeClientError("subscription-invalid", "Subscription revision 1 would duplicate an existing finalized stable identity");
2032
1951
  }
2033
1952
  return;
2034
1953
  }
2035
1954
  if (input.subscriptionId === void 0 || input.supersedes === void 0) {
2036
- throw new EventKitHandshakeClientError(
2037
- "subscription-invalid",
2038
- "A replacement subscription requires subscriptionId and supersedes"
2039
- );
1955
+ throw new EventKitHandshakeClientError("subscription-invalid", "A replacement subscription requires subscriptionId and supersedes");
2040
1956
  }
2041
1957
  const view = await lookupAt(current, input.subscriptionId);
2042
1958
  if (!view.ok) {
@@ -2044,24 +1960,15 @@ function createSubscriberHandshakeClient(options) {
2044
1960
  }
2045
1961
  const lifecycles = view.subscriptions.filter((item) => item.subscriptionId === input.subscriptionId);
2046
1962
  if (lifecycles.length !== 1) {
2047
- throw new EventKitHandshakeClientError(
2048
- "subscription-invalid",
2049
- "Replacement subscription does not resolve one finalized stable identity"
2050
- );
1963
+ throw new EventKitHandshakeClientError("subscription-invalid", "Replacement subscription does not resolve one finalized stable identity");
2051
1964
  }
2052
1965
  if (lifecycles[0].state === "rejected") {
2053
- throw new EventKitHandshakeClientError(
2054
- "subscription-invalid",
2055
- "Replacement subscription cannot extend a rejected finalized revision chain"
2056
- );
1966
+ throw new EventKitHandshakeClientError("subscription-invalid", "Replacement subscription cannot extend a rejected finalized revision chain");
2057
1967
  }
2058
1968
  const highestRevision = Math.max(...lifecycles[0].tuples.map((tuple) => tuple.subscription.body.revision));
2059
1969
  const latest = lifecycles[0].tuples.filter((tuple) => tuple.subscription.body.revision === highestRevision);
2060
1970
  if (latest.length !== 1 || revision !== highestRevision + 1 || latest[0].subscription.objectHash !== input.supersedes) {
2061
- throw new EventKitHandshakeClientError(
2062
- "subscription-invalid",
2063
- "Replacement subscription revision and supersedes must extend the exact finalized chain tip"
2064
- );
1971
+ throw new EventKitHandshakeClientError("subscription-invalid", "Replacement subscription revision and supersedes must extend the exact finalized chain tip");
2065
1972
  }
2066
1973
  }
2067
1974
  async function publishSubscriberSubscriptionIntent(intent, intentDisposition) {
@@ -2090,23 +1997,13 @@ function createSubscriberHandshakeClient(options) {
2090
1997
  await assertPublicationSource(options.publication, subscriber);
2091
1998
  const grantHash = HashZod4.parse(grant);
2092
1999
  const requestFingerprint = await exactMutationRequestFingerprint({ grant: grantHash });
2093
- let resolvedIntent = await loadMutationIntent(
2094
- options.intents,
2095
- options.reader,
2096
- "subscriber-grant-revoke",
2097
- grantHash,
2098
- subscriber,
2099
- requestFingerprint
2100
- );
2000
+ let resolvedIntent = await loadMutationIntent(options.intents, options.reader, "subscriber-grant-revoke", grantHash, subscriber, requestFingerprint);
2101
2001
  let intentDisposition = "resumed";
2102
2002
  if (resolvedIntent === void 0) {
2103
2003
  const current = await snapshot();
2104
2004
  const view = await current.readModel.subscriber({ ...serviceQuery(options.reader, current, serviceId), subscriber });
2105
2005
  if (!view.ok || !tupleHashes(view).grants.has(grantHash)) {
2106
- throw new EventKitHandshakeClientError(
2107
- "subscription-not-found",
2108
- "Grant is not present in this subscriber finalization view"
2109
- );
2006
+ throw new EventKitHandshakeClientError("subscription-not-found", "Grant is not present in this subscriber finalization view");
2110
2007
  }
2111
2008
  const persisted = await persistMutationIntent(options.intents, {
2112
2009
  chainId: options.reader.chainId,
@@ -2139,23 +2036,13 @@ function createSubscriberHandshakeClient(options) {
2139
2036
  await assertPublicationSource(options.publication, subscriber);
2140
2037
  const subscriptionHash = HashZod4.parse(subscription);
2141
2038
  const requestFingerprint = await exactMutationRequestFingerprint({ subscription: subscriptionHash });
2142
- let resolvedIntent = await loadMutationIntent(
2143
- options.intents,
2144
- options.reader,
2145
- "subscriber-subscription-revoke",
2146
- subscriptionHash,
2147
- subscriber,
2148
- requestFingerprint
2149
- );
2039
+ let resolvedIntent = await loadMutationIntent(options.intents, options.reader, "subscriber-subscription-revoke", subscriptionHash, subscriber, requestFingerprint);
2150
2040
  let intentDisposition = "resumed";
2151
2041
  if (resolvedIntent === void 0) {
2152
2042
  const current = await snapshot();
2153
2043
  const view = await current.readModel.subscriber({ ...serviceQuery(options.reader, current, serviceId), subscriber });
2154
2044
  if (!view.ok || !tupleHashes(view).subscriptions.has(subscriptionHash)) {
2155
- throw new EventKitHandshakeClientError(
2156
- "subscription-not-found",
2157
- "Subscription is not present in this subscriber finalization view"
2158
- );
2045
+ throw new EventKitHandshakeClientError("subscription-not-found", "Subscription is not present in this subscriber finalization view");
2159
2046
  }
2160
2047
  const persisted = await persistMutationIntent(options.intents, {
2161
2048
  chainId: options.reader.chainId,
@@ -2192,19 +2079,18 @@ function createSubscriberHandshakeClient(options) {
2192
2079
  const subscriptionHash = HashZod4.parse(subscription);
2193
2080
  const current = await options.reader.sync();
2194
2081
  const view = await lookupAt(current);
2195
- if (!view.ok) return view;
2082
+ if (!view.ok)
2083
+ return view;
2196
2084
  const matches = view.subscriptions.flatMap((lifecycle) => lifecycle.tuples.filter((tuple) => tuple.subscription.objectHash === subscriptionHash).map((tuple) => ({ lifecycle, tuple })));
2197
2085
  if (matches.length > 1) {
2198
- throw new EventKitHandshakeClientError(
2199
- "subscription-invalid",
2200
- "Exact subscription hash appears more than once in the subscriber view"
2201
- );
2086
+ throw new EventKitHandshakeClientError("subscription-invalid", "Exact subscription hash appears more than once in the subscriber view");
2202
2087
  }
2203
- if (matches.length === 0) return Object.freeze({
2204
- found: false,
2205
- lookup: view,
2206
- ok: true
2207
- });
2088
+ if (matches.length === 0)
2089
+ return Object.freeze({
2090
+ found: false,
2091
+ lookup: view,
2092
+ ok: true
2093
+ });
2208
2094
  return Object.freeze({
2209
2095
  found: true,
2210
2096
  lifecycle: matches[0].lifecycle,
@@ -2217,36 +2103,22 @@ function createSubscriberHandshakeClient(options) {
2217
2103
  await assertPublicationSource(options.publication, subscriber);
2218
2104
  const operationId = HandshakeIdZod3.parse(input.operationId);
2219
2105
  const requestFingerprint = await subscriberSubscriptionRequestFingerprint(input);
2220
- const priorIntent = await loadMutationIntent(
2221
- options.intents,
2222
- options.reader,
2223
- "subscriber-subscription-subscribe",
2224
- operationId,
2225
- subscriber,
2226
- requestFingerprint
2227
- );
2228
- if (priorIntent !== void 0) return await publishSubscriberSubscriptionIntent(priorIntent, "resumed");
2106
+ const priorIntent = await loadMutationIntent(options.intents, options.reader, "subscriber-subscription-subscribe", operationId, subscriber, requestFingerprint);
2107
+ if (priorIntent !== void 0)
2108
+ return await publishSubscriberSubscriptionIntent(priorIntent, "resumed");
2229
2109
  const current = await snapshot();
2230
2110
  const selected = await serviceAt(current);
2231
2111
  if (input.expiresAtBlock - current.finalizedHead <= 3) {
2232
- throw new EventKitHandshakeClientError(
2233
- "subscription-invalid",
2234
- "Requested subscription expiry must leave finalized blocks for tuple publication, acceptance, and activation"
2235
- );
2112
+ throw new EventKitHandshakeClientError("subscription-invalid", "Requested subscription expiry must leave finalized blocks for tuple publication, acceptance, and activation");
2236
2113
  }
2237
2114
  await validateRevision(current, input);
2238
- const maxBlocksPerWake = input.maxBlocksPerWake ?? selected.service.body.limits.maxBlocksPerWake;
2239
- if (maxBlocksPerWake > selected.service.body.limits.maxBlocksPerWake) {
2240
- throw new EventKitHandshakeClientError(
2241
- "subscription-invalid",
2242
- "Requested maxBlocksPerWake exceeds the selected publisher service limit"
2243
- );
2115
+ const maximum = selected.service.body.limits.maxPositionsPerWake;
2116
+ const maxPositionsPerWake = input.maxPositionsPerWake ?? maximum;
2117
+ if (maxPositionsPerWake > maximum) {
2118
+ throw new EventKitHandshakeClientError("subscription-invalid", "Requested maxPositionsPerWake exceeds the selected publisher service limit");
2244
2119
  }
2245
2120
  if (input.expiresAtBlock > current.finalizedHead + selected.service.body.limits.maxSubscriptionLifetimeBlocks) {
2246
- throw new EventKitHandshakeClientError(
2247
- "subscription-invalid",
2248
- "Requested subscription expiry exceeds the selected publisher service lifetime limit"
2249
- );
2121
+ throw new EventKitHandshakeClientError("subscription-invalid", "Requested subscription expiry exceeds the selected publisher service lifetime limit");
2250
2122
  }
2251
2123
  const grant = createWakeGrant({
2252
2124
  deploymentId: input.deploymentId,
@@ -2255,19 +2127,11 @@ function createSubscriberHandshakeClient(options) {
2255
2127
  ...input.queueId === void 0 || input.queueId === null ? {} : { queueId: input.queueId }
2256
2128
  });
2257
2129
  const grantHash = await handshakeObjectHash2(grant);
2258
- const plaintext = createWakeSubscriptionPlaintext({
2259
- audience: input.audience,
2260
- challengeSecret: input.challengeSecret,
2261
- deploymentId: input.deploymentId,
2262
- endpoint: input.endpoint,
2263
- maxBlocksPerWake,
2264
- queueId: input.queueId
2265
- });
2266
- const subscription = await createEncryptedWakeSubscription({
2130
+ const plaintext = subscriberPlaintext(selected.service.body, input, maxPositionsPerWake);
2131
+ const subscriptionInput = {
2267
2132
  chainId: options.reader.chainId,
2268
2133
  expiresAtBlock: input.expiresAtBlock,
2269
2134
  grant: grantHash,
2270
- plaintext,
2271
2135
  publisher: options.reader.publisher,
2272
2136
  publisherKey: {
2273
2137
  encryptionKey: HashZod4.parse(selected.key.objectHash),
@@ -2279,7 +2143,8 @@ function createSubscriberHandshakeClient(options) {
2279
2143
  subscriber,
2280
2144
  ...input.subscriptionId === void 0 ? {} : { subscriptionId: input.subscriptionId },
2281
2145
  ...input.supersedes === void 0 ? {} : { supersedes: input.supersedes }
2282
- });
2146
+ };
2147
+ const subscription = await createEncryptedWakeSubscription({ ...subscriptionInput, plaintext });
2283
2148
  const resolvedIntent = await persistMutationIntent(options.intents, {
2284
2149
  chainId: options.reader.chainId,
2285
2150
  encryptionKey: selected.key.body,
@@ -2298,20 +2163,1430 @@ function createSubscriberHandshakeClient(options) {
2298
2163
  return await publishSubscriberSubscriptionIntent(resolvedIntent.intent, resolvedIntent.disposition);
2299
2164
  },
2300
2165
  async subscriptions(subscriptionId) {
2301
- return await lookup(subscriptionId);
2166
+ return await lookup2(subscriptionId);
2302
2167
  }
2303
2168
  };
2304
2169
  return Object.freeze(client);
2305
2170
  }
2171
+ function subscriberPlaintext(service, input, maxPositionsPerWake) {
2172
+ const plaintextInput = {
2173
+ audience: input.audience,
2174
+ challengeSecret: input.challengeSecret,
2175
+ deploymentId: input.deploymentId,
2176
+ endpoint: input.endpoint,
2177
+ queueId: input.queueId
2178
+ };
2179
+ const source = input.source;
2180
+ if (!service.events.some((event) => canonicalJson(event.source) === canonicalJson(source))) {
2181
+ throw new Error("Requested source is not advertised by the selected service");
2182
+ }
2183
+ return createWakeSubscriptionPlaintext({
2184
+ ...plaintextInput,
2185
+ source,
2186
+ fromPosition: input.fromPosition,
2187
+ maxPositionsPerWake
2188
+ });
2189
+ }
2306
2190
 
2307
- // src/sqliteWakeQueue.ts
2308
- import { mkdir as mkdir5 } from "node:fs/promises";
2191
+ // src/runtime/boundedFetch.ts
2192
+ import { Buffer as Buffer2 } from "node:buffer";
2193
+
2194
+ // src/runtime/abort.ts
2195
+ import { clearTimeout, setTimeout } from "node:timers";
2196
+ function publisherAbortScope(signals, timeoutMs) {
2197
+ const controller = new AbortController();
2198
+ const abort = () => controller.abort();
2199
+ const timer = timeoutMs === void 0 ? void 0 : setTimeout(abort, timeoutMs);
2200
+ timer?.unref();
2201
+ for (const signal of signals) {
2202
+ if (signal.aborted) controller.abort();
2203
+ else signal.addEventListener("abort", abort, { once: true });
2204
+ }
2205
+ return {
2206
+ signal: controller.signal,
2207
+ dispose() {
2208
+ if (timer !== void 0) clearTimeout(timer);
2209
+ for (const signal of signals) signal.removeEventListener("abort", abort);
2210
+ }
2211
+ };
2212
+ }
2213
+
2214
+ // src/runtime/boundedFetch.ts
2215
+ function createBoundedPublisherFetch(options = {}) {
2216
+ const owner = new AbortController();
2217
+ const timeout = options.requestTimeoutMs ?? 1e4;
2218
+ const maximum = options.maxResponseBytes ?? 16 * 1024 * 1024;
2219
+ const concurrency = options.maxConcurrency ?? 16;
2220
+ if (!Number.isSafeInteger(timeout) || timeout < 100 || timeout > 6e4 || !Number.isSafeInteger(maximum) || maximum < 1 || maximum > 64 * 1024 * 1024 || !Number.isSafeInteger(concurrency) || concurrency < 1 || concurrency > 64)
2221
+ throw new Error("Invalid publisher fetch limits");
2222
+ const active = /* @__PURE__ */ new Set();
2223
+ const nativeFetch = globalThis.fetch.bind(globalThis);
2224
+ const fetchFn = (input, init) => {
2225
+ if (active.size >= concurrency)
2226
+ return Promise.reject(new Error("Publisher HTTP concurrency limit exceeded"));
2227
+ const operation = (async () => {
2228
+ const signals = [
2229
+ owner.signal,
2230
+ ...options.signal === void 0 ? [] : [options.signal],
2231
+ ...init?.signal == null ? [] : [init.signal],
2232
+ ...input instanceof Request ? [input.signal] : []
2233
+ ];
2234
+ const scope = publisherAbortScope(signals, timeout);
2235
+ try {
2236
+ scope.signal.throwIfAborted();
2237
+ const response = await nativeFetch(input, {
2238
+ ...init,
2239
+ redirect: "error",
2240
+ signal: scope.signal
2241
+ });
2242
+ if (response.body === null)
2243
+ return response;
2244
+ const reader = response.body.getReader();
2245
+ const chunks = [];
2246
+ let size = 0;
2247
+ try {
2248
+ for (; ; ) {
2249
+ const chunk = await reader.read();
2250
+ if (chunk.done)
2251
+ break;
2252
+ const bytes = chunk.value;
2253
+ if (!(bytes instanceof Uint8Array)) throw new Error("Publisher HTTP body returned a non-byte chunk");
2254
+ size += bytes.byteLength;
2255
+ if (size > maximum) {
2256
+ await reader.cancel();
2257
+ throw new Error("Publisher HTTP body exceeds its bound");
2258
+ }
2259
+ chunks.push(bytes);
2260
+ }
2261
+ } finally {
2262
+ reader.releaseLock();
2263
+ }
2264
+ const headers = new Headers(response.headers);
2265
+ headers.delete("content-encoding");
2266
+ headers.delete("transfer-encoding");
2267
+ headers.set("content-length", String(size));
2268
+ return new Response(Buffer2.concat(chunks), {
2269
+ status: response.status,
2270
+ statusText: response.statusText,
2271
+ headers
2272
+ });
2273
+ } finally {
2274
+ scope.dispose();
2275
+ }
2276
+ })();
2277
+ active.add(operation);
2278
+ void operation.then(() => active.delete(operation), () => active.delete(operation));
2279
+ return operation;
2280
+ };
2281
+ return {
2282
+ fetchFn,
2283
+ async close() {
2284
+ owner.abort();
2285
+ await Promise.allSettled(active);
2286
+ },
2287
+ get activeRequests() {
2288
+ return active.size;
2289
+ }
2290
+ };
2291
+ }
2292
+ function createBoundedPublisherEthersTransport(options = {}) {
2293
+ const bounded = createBoundedPublisherFetch(options);
2294
+ const getUrl = async (request2, cancellation) => {
2295
+ const controller = new AbortController();
2296
+ cancellation?.addListener(() => controller.abort());
2297
+ cancellation?.checkSignal();
2298
+ const response = await bounded.fetchFn(request2.url, {
2299
+ body: request2.body === null ? void 0 : Buffer2.from(request2.body),
2300
+ headers: request2.headers,
2301
+ method: request2.method,
2302
+ signal: controller.signal
2303
+ });
2304
+ return {
2305
+ body: new Uint8Array(await response.arrayBuffer()),
2306
+ headers: Object.fromEntries(response.headers),
2307
+ statusCode: response.status,
2308
+ statusMessage: response.statusText
2309
+ };
2310
+ };
2311
+ return {
2312
+ getUrl,
2313
+ async close() {
2314
+ await bounded.close();
2315
+ },
2316
+ get activeRequests() {
2317
+ return bounded.activeRequests;
2318
+ }
2319
+ };
2320
+ }
2321
+
2322
+ // src/runtime/handshakeDiscovery.ts
2323
+ import { decryptWakeSubscription, sourceWakeFilterHash } from "@xyo-network/event-kit-protocol";
2324
+ import { EndpointChallengeResponseZod as EndpointChallengeResponseZod2 } from "@xyo-network/event-kit-schemas";
2325
+ function createPublisherHandshakeDiscovery(options) {
2326
+ const clock = options.nowSeconds ?? (() => Math.floor(Date.now() / 1e3));
2327
+ const owner = new AbortController();
2328
+ let accepting;
2329
+ let viewing;
2330
+ let status = {
2331
+ authorizationChainId: options.authorizationChainId,
2332
+ keyLoaded: false,
2333
+ activeKeyIds: [],
2334
+ pendingSubscriptions: 0,
2335
+ rejectedSubscriptions: 0,
2336
+ challengeFailures: 0
2337
+ };
2338
+ async function activeView(signal) {
2339
+ signal.throwIfAborted();
2340
+ viewing ??= options.client.subscriptions().finally(() => {
2341
+ viewing = void 0;
2342
+ });
2343
+ const view = await viewing;
2344
+ signal.throwIfAborted();
2345
+ if (!view.ok || view.indexedThrough !== view.finalizedHead)
2346
+ throw new Error("Publisher subscription view is unavailable or stale");
2347
+ status = {
2348
+ ...status,
2349
+ finalizedHead: view.finalizedHead,
2350
+ indexedThrough: view.indexedThrough,
2351
+ pendingSubscriptions: view.subscriptions.filter((item) => item.state === "pending").length,
2352
+ rejectedSubscriptions: view.rejections.length
2353
+ };
2354
+ return view;
2355
+ }
2356
+ async function acceptCandidate(subscriber, subscription, signal) {
2357
+ try {
2358
+ let pending = options.state.get("outbound-challenges", subscription);
2359
+ if (pending !== void 0 && pending.response === void 0 && clock() >= pending.expiresAt)
2360
+ pending = void 0;
2361
+ if (pending === void 0) {
2362
+ const issued = await options.client.issueChallenge({
2363
+ issuedAt: clock(),
2364
+ lifetimeSeconds: 300,
2365
+ subscriber,
2366
+ subscription
2367
+ });
2368
+ pending = {
2369
+ challengeHash: issued.challengeHash,
2370
+ subscriber,
2371
+ subscription,
2372
+ expiresAt: issued.challenge.expiresAt
2373
+ };
2374
+ options.state.set("outbound-challenges", subscription, pending);
2375
+ }
2376
+ if (pending.response === void 0) {
2377
+ const begun = await options.client.beginChallenge({ challengeHash: pending.challengeHash, nowSeconds: clock });
2378
+ if (begun.kind !== "started")
2379
+ return;
2380
+ signal.throwIfAborted();
2381
+ const response2 = await options.transport.post(begun.target.endpoint, begun.challenge, signal);
2382
+ if (response2.status !== 200)
2383
+ throw new Error("Endpoint challenge was rejected");
2384
+ pending = { ...pending, response: EndpointChallengeResponseZod2.parse(response2.body) };
2385
+ options.state.set("outbound-challenges", subscription, pending);
2386
+ }
2387
+ signal.throwIfAborted();
2388
+ const response = pending.response;
2389
+ if (response === void 0)
2390
+ throw new Error("Endpoint proof is unavailable");
2391
+ await options.client.completeChallengeAndAccept({
2392
+ ...pending,
2393
+ response,
2394
+ nowSeconds: clock
2395
+ });
2396
+ } catch {
2397
+ if (signal.aborted)
2398
+ return;
2399
+ const failures = options.state.get("challenge-failures", subscription) ?? 0;
2400
+ options.state.set("challenge-failures", subscription, failures + 1);
2401
+ const pending = options.state.get("outbound-challenges", subscription);
2402
+ if (pending !== void 0 && clock() >= pending.expiresAt)
2403
+ options.state.remove("outbound-challenges", subscription);
2404
+ }
2405
+ }
2406
+ async function accept(signal) {
2407
+ signal.throwIfAborted();
2408
+ const now = clock();
2409
+ if (now < (options.state.get("challenge-rate", "next-pass") ?? 0))
2410
+ return;
2411
+ options.state.set("challenge-rate", "next-pass", now + 10);
2412
+ const found = await options.client.acceptanceCandidates();
2413
+ if (!found.ok)
2414
+ throw new Error("Publisher acceptance candidates are unavailable");
2415
+ const offset = options.state.get("challenge-rate", "offset") ?? 0;
2416
+ const candidates = found.candidates;
2417
+ let attempted = 0;
2418
+ for (let index = 0; index < Math.min(candidates.length, 128) && attempted < 4; index += 1) {
2419
+ const candidate = candidates[(offset + index) % candidates.length];
2420
+ if (candidate === void 0)
2421
+ break;
2422
+ options.state.set("challenge-rate", "offset", (offset + index + 1) % candidates.length);
2423
+ const next = options.state.get("challenge-controller-rate", candidate.subscriber) ?? 0;
2424
+ if (now < next)
2425
+ continue;
2426
+ options.state.set("challenge-controller-rate", candidate.subscriber, now + 30);
2427
+ attempted += 1;
2428
+ signal.throwIfAborted();
2429
+ await acceptCandidate(candidate.subscriber, candidate.tuple.subscription.objectHash, signal);
2430
+ }
2431
+ }
2432
+ return {
2433
+ async discover(signal) {
2434
+ const view = await activeView(signal);
2435
+ const key = view.hasCurrentAdvertisement ? view.key : void 0;
2436
+ const loaded = key === void 0 ? void 0 : await options.keys.getPrivateKey({
2437
+ encryptionKey: key.objectHash,
2438
+ keyId: key.body.keyId,
2439
+ publisher: options.publisher
2440
+ });
2441
+ status = {
2442
+ ...status,
2443
+ keyLoaded: loaded !== void 0,
2444
+ activeKeyIds: key === void 0 ? [] : [key.body.keyId]
2445
+ };
2446
+ const subscriptions = [];
2447
+ const active = view.subscriptions.filter((item) => item.state === "active");
2448
+ if (active.length > (options.maxSubscriptions ?? 64))
2449
+ throw new Error("Publisher active subscription limit exceeded");
2450
+ for (const lifecycle of active) {
2451
+ if (lifecycle.state !== "active" || lifecycle.activeFromBlock === void 0)
2452
+ continue;
2453
+ try {
2454
+ const tuple = lifecycle.tuples.find((item) => item.subscription.objectHash === lifecycle.selectedSubscription);
2455
+ if (tuple === void 0)
2456
+ throw new Error("Active publisher subscription has no selected tuple");
2457
+ const encrypted = tuple.subscription.body;
2458
+ if (encrypted.chainId !== options.authorizationChainId)
2459
+ throw new Error("Subscription authorization chain mismatch");
2460
+ const publisherKey = await options.keys.getPrivateKey({
2461
+ encryptionKey: encrypted.encryptionKey,
2462
+ keyId: encrypted.keyId,
2463
+ publisher: options.publisher
2464
+ });
2465
+ if (publisherKey === void 0)
2466
+ throw new Error("Subscription encryption key is unavailable");
2467
+ const plaintext = await decryptWakeSubscription({
2468
+ publisherKey,
2469
+ subscriber: tuple.subscriber,
2470
+ subscription: encrypted
2471
+ });
2472
+ options.transport.assertAllowed(plaintext.endpoint);
2473
+ subscriptions.push({
2474
+ subscriptionHash: tuple.subscription.objectHash,
2475
+ authorizationChainId: options.authorizationChainId,
2476
+ controller: tuple.subscriber,
2477
+ audience: plaintext.audience,
2478
+ endpoint: plaintext.endpoint,
2479
+ deploymentId: plaintext.deploymentId,
2480
+ ...plaintext.queueId === null ? {} : { queueId: plaintext.queueId },
2481
+ source: plaintext.filter.source,
2482
+ fromPosition: plaintext.filter.fromPosition,
2483
+ maxPositionsPerWake: plaintext.filter.maxPositionsPerWake,
2484
+ filterHash: await sourceWakeFilterHash(plaintext.filter)
2485
+ });
2486
+ } catch {
2487
+ status = { ...status, rejectedSubscriptions: status.rejectedSubscriptions + 1 };
2488
+ }
2489
+ }
2490
+ return subscriptions;
2491
+ },
2492
+ async isActive(subscription, signal) {
2493
+ const view = await activeView(signal);
2494
+ return view.subscriptions.some((item) => item.state === "active" && item.selectedSubscription === subscription.subscriptionHash && item.tuples.some((tuple) => tuple.subscription.objectHash === subscription.subscriptionHash && tuple.subscriber === subscription.controller));
2495
+ },
2496
+ async acceptPending(signal) {
2497
+ if (accepting === void 0) {
2498
+ const scope = publisherAbortScope([owner.signal, signal]);
2499
+ accepting = accept(scope.signal).finally(() => {
2500
+ scope.dispose();
2501
+ accepting = void 0;
2502
+ });
2503
+ }
2504
+ await accepting;
2505
+ },
2506
+ async close() {
2507
+ await Promise.allSettled([accepting, viewing].filter((item) => item !== void 0));
2508
+ },
2509
+ status() {
2510
+ return { ...status, challengeFailures: options.state.entries("challenge-failures").reduce((sum, item) => sum + item.value, 0) };
2511
+ }
2512
+ };
2513
+ }
2514
+
2515
+ // src/runtime/httpsTransport.ts
2516
+ import { Buffer as Buffer3 } from "node:buffer";
2517
+ import { lookup } from "node:dns/promises";
2518
+ import { request } from "node:https";
2519
+ import { BlockList, isIP } from "node:net";
2520
+ import { z as z2 } from "zod";
2521
+
2522
+ // src/runtime/sources.ts
2523
+ import { createHash as createHash3 } from "node:crypto";
2524
+ import { canonicalJson as canonicalJson2 } from "@xyo-network/event-kit-protocol";
2525
+ import { completedUtcIntervalPosition, WakeSourceZod } from "@xyo-network/event-kit-schemas";
2526
+ import { PayloadBuilder } from "@xyo-network/sdk";
2527
+ import { asXL1BlockNumber } from "@xyo-network/xl1-sdk";
2528
+ import { FetchRequest, JsonRpcProvider } from "ethers";
2529
+ function publisherSourceKey(source) {
2530
+ return createHash3("sha256").update(canonicalJson2(WakeSourceZod.parse(source))).digest("hex");
2531
+ }
2532
+ async function boundedPublisherOperation(operation, signal, timeoutMs = 1e4) {
2533
+ const scope = publisherAbortScope([signal], timeoutMs);
2534
+ const combined = scope.signal;
2535
+ let rejectAbort;
2536
+ const aborted = new Promise((_resolve, reject) => {
2537
+ rejectAbort = () => reject(new Error("Publisher operation aborted or timed out"));
2538
+ combined.addEventListener("abort", rejectAbort, { once: true });
2539
+ });
2540
+ try {
2541
+ combined.throwIfAborted();
2542
+ return await Promise.race([operation, aborted]);
2543
+ } finally {
2544
+ if (rejectAbort !== void 0)
2545
+ combined.removeEventListener("abort", rejectAbort);
2546
+ scope.dispose();
2547
+ }
2548
+ }
2549
+ function createXl1PublisherSource(options) {
2550
+ const source = WakeSourceZod.parse(options.source);
2551
+ if (source.kind !== "xl1-finalized")
2552
+ throw new Error("Expected an XL1 finalized source");
2553
+ return {
2554
+ source,
2555
+ async head(signal) {
2556
+ const chainId = String(await boundedPublisherOperation(Promise.resolve(options.viewer.chainId()), signal));
2557
+ if (chainId !== source.chainId)
2558
+ throw new Error("XL1 source chain identity changed");
2559
+ const position = Number(await boundedPublisherOperation(Promise.resolve(options.viewer.finalization.headNumber()), signal));
2560
+ if (!Number.isSafeInteger(position) || position < 0)
2561
+ throw new Error("XL1 finalized head is invalid");
2562
+ const block = await boundedPublisherOperation(Promise.resolve(options.viewer.block.blockByNumber(asXL1BlockNumber(position, true))), signal);
2563
+ if (block?.[0].block !== position || !/^[0-9a-f]{64}$/u.test(block[0]._hash)) {
2564
+ throw new Error("XL1 finalized head block is unavailable or inconsistent");
2565
+ }
2566
+ if (String(block[0].chain) !== source.chainId || await PayloadBuilder.hash(block[0]) !== block[0]._hash) {
2567
+ throw new Error("XL1 finalized head block chain or hash is inconsistent");
2568
+ }
2569
+ return { position, hash: block[0]._hash };
2570
+ }
2571
+ };
2572
+ }
2573
+ function createEthereumFinalizedPublisherSource(options) {
2574
+ const source = WakeSourceZod.parse(options.source);
2575
+ if (source.kind !== "ethereum-finalized")
2576
+ throw new Error("Expected an Ethereum finalized source");
2577
+ const { chainId, genesisHash } = source;
2578
+ const url = new URL(options.rpcUrl);
2579
+ if (url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.hash !== "") {
2580
+ throw new Error("Ethereum source RPC must use HTTPS without URL credentials or fragments");
2581
+ }
2582
+ const connection = new FetchRequest(url.href);
2583
+ connection.timeout = options.requestTimeoutMs ?? 1e4;
2584
+ const transport = createBoundedPublisherEthersTransport({
2585
+ requestTimeoutMs: options.requestTimeoutMs,
2586
+ maxResponseBytes: 2 * 1024 * 1024,
2587
+ maxConcurrency: 8
2588
+ });
2589
+ connection.getUrlFunc = transport.getUrl;
2590
+ connection.setThrottleParams({ maxAttempts: 1 });
2591
+ const provider = new JsonRpcProvider(connection, void 0, { batchMaxCount: 1, cacheTimeout: -1 });
2592
+ let reading;
2593
+ let closed = false;
2594
+ let closing;
2595
+ const close = () => closing ??= (async () => {
2596
+ closed = true;
2597
+ provider.destroy();
2598
+ await transport.close();
2599
+ })();
2600
+ const onAbort = () => {
2601
+ void close();
2602
+ };
2603
+ async function read() {
2604
+ const requests = [provider.getNetwork(), provider.getBlock(0), provider.getBlock("finalized")];
2605
+ const values = await Promise.all(requests).catch(async (error) => {
2606
+ await Promise.allSettled(requests);
2607
+ throw error;
2608
+ });
2609
+ const [network, genesis, block] = values;
2610
+ if (network.chainId.toString() !== chainId || genesis?.hash?.slice(2).toLowerCase() !== genesisHash) {
2611
+ throw new Error("Ethereum source chain identity mismatch");
2612
+ }
2613
+ if (block?.hash === null || block === null || !/^0x[0-9a-fA-F]{64}$/u.test(block.hash) || !Number.isSafeInteger(block.number) || block.number < 0) throw new Error("Ethereum finalized head is unavailable");
2614
+ return { position: block.number, hash: block.hash.slice(2).toLowerCase() };
2615
+ }
2616
+ return {
2617
+ source,
2618
+ close,
2619
+ async head(signal) {
2620
+ signal.throwIfAborted();
2621
+ if (closed) throw new Error("Ethereum source is closed");
2622
+ signal.addEventListener("abort", onAbort, { once: true });
2623
+ reading ??= read().finally(() => {
2624
+ reading = void 0;
2625
+ });
2626
+ try {
2627
+ return await boundedPublisherOperation(reading, signal, options.requestTimeoutMs ?? 1e4);
2628
+ } finally {
2629
+ signal.removeEventListener("abort", onAbort);
2630
+ }
2631
+ }
2632
+ };
2633
+ }
2634
+ function createUtcIntervalPublisherSource(options) {
2635
+ const source = WakeSourceZod.parse(options.source);
2636
+ if (source.kind !== "utc-interval")
2637
+ throw new Error("Expected a UTC interval source");
2638
+ const nowSeconds = options.nowSeconds ?? (() => Math.floor(Date.now() / 1e3));
2639
+ return {
2640
+ source,
2641
+ async head(signal) {
2642
+ signal.throwIfAborted();
2643
+ const now = nowSeconds();
2644
+ if (!Number.isSafeInteger(now) || now < 0)
2645
+ throw new Error("UTC interval clock is invalid");
2646
+ return { position: completedUtcIntervalPosition(source, now) ?? -1 };
2647
+ }
2648
+ };
2649
+ }
2650
+
2651
+ // src/runtime/httpsTransport.ts
2652
+ var OptionsZod = z2.strictObject({
2653
+ allowedEndpoints: z2.array(z2.url()).min(1).max(64),
2654
+ endpointHeaders: z2.array(z2.strictObject({
2655
+ endpoint: z2.url(),
2656
+ headers: z2.strictObject({ "x-vercel-protection-bypass": z2.string().min(1).max(4096).regex(/^[\x21-\x7E]+$/u) })
2657
+ })).max(64).default([]),
2658
+ maxResponseBytes: z2.number().int().min(1).max(1048576).default(65536),
2659
+ requestTimeoutMs: z2.number().int().min(100).max(6e4).default(1e4)
2660
+ });
2661
+ var nonPublicIpv4 = new BlockList();
2662
+ for (const [address, prefix] of [
2663
+ ["0.0.0.0", 8],
2664
+ ["10.0.0.0", 8],
2665
+ ["100.64.0.0", 10],
2666
+ ["127.0.0.0", 8],
2667
+ ["169.254.0.0", 16],
2668
+ ["172.16.0.0", 12],
2669
+ ["192.0.0.0", 24],
2670
+ ["192.0.2.0", 24],
2671
+ ["192.88.99.0", 24],
2672
+ ["192.168.0.0", 16],
2673
+ ["198.18.0.0", 15],
2674
+ ["198.51.100.0", 24],
2675
+ ["203.0.113.0", 24],
2676
+ ["224.0.0.0", 4],
2677
+ ["240.0.0.0", 4]
2678
+ ])
2679
+ nonPublicIpv4.addSubnet(address, prefix, "ipv4");
2680
+ var globalIpv6 = new BlockList();
2681
+ globalIpv6.addSubnet("2000::", 3, "ipv6");
2682
+ var nonPublicIpv6 = new BlockList();
2683
+ for (const [address, prefix] of [
2684
+ ["2001::", 23],
2685
+ ["2001:db8::", 32],
2686
+ ["2002::", 16],
2687
+ ["3fff::", 20]
2688
+ ])
2689
+ nonPublicIpv6.addSubnet(address, prefix, "ipv6");
2690
+ function isPublicPublisherAddress(address) {
2691
+ if (isIP(address) === 4)
2692
+ return !nonPublicIpv4.check(address, "ipv4");
2693
+ if (isIP(address) !== 6)
2694
+ return false;
2695
+ return globalIpv6.check(address, "ipv6") && !nonPublicIpv6.check(address, "ipv6");
2696
+ }
2697
+ function createPublisherHttpsTransport(input) {
2698
+ const parsed = OptionsZod.safeParse(input);
2699
+ if (!parsed.success) throw new Error("Invalid publisher HTTPS transport configuration");
2700
+ const options = parsed.data;
2701
+ const allowed = new Set(options.allowedEndpoints.map((endpoint) => {
2702
+ const url = new URL(endpoint);
2703
+ if (url.href !== endpoint || url.protocol !== "https:" || url.port !== "" && url.port !== "443" || url.username !== "" || url.password !== "" || url.hash !== "")
2704
+ throw new Error("Publisher destinations must be canonical public HTTPS URLs on port 443");
2705
+ const literal = url.hostname.replaceAll(/^\[|\]$/gu, "");
2706
+ if (isIP(literal) !== 0 && !isPublicPublisherAddress(literal))
2707
+ throw new Error("Publisher destination is not public");
2708
+ if (url.hostname === "localhost" || url.hostname.endsWith(".localhost") || url.hostname.endsWith(".local"))
2709
+ throw new Error("Publisher destination is not public");
2710
+ return endpoint;
2711
+ }));
2712
+ const assertAllowed = (endpoint) => {
2713
+ if (!allowed.has(endpoint))
2714
+ throw new Error("Publisher destination is not explicitly allowed");
2715
+ };
2716
+ const endpointHeaders = /* @__PURE__ */ new Map();
2717
+ for (const entry of options.endpointHeaders) {
2718
+ assertAllowed(entry.endpoint);
2719
+ if (endpointHeaders.has(entry.endpoint)) throw new Error("Duplicate publisher endpoint header configuration");
2720
+ endpointHeaders.set(entry.endpoint, entry.headers);
2721
+ }
2722
+ return {
2723
+ assertAllowed,
2724
+ async post(endpoint, body, signal, jwt) {
2725
+ assertAllowed(endpoint);
2726
+ signal.throwIfAborted();
2727
+ const url = new URL(endpoint);
2728
+ const scope = publisherAbortScope([signal], options.requestTimeoutMs);
2729
+ const combined = scope.signal;
2730
+ try {
2731
+ const addresses = await boundedPublisherOperation(lookup(url.hostname.replaceAll(/^\[|\]$/gu, ""), { all: true, verbatim: true }), combined, options.requestTimeoutMs);
2732
+ combined.throwIfAborted();
2733
+ if (addresses.length === 0 || addresses.some((item) => !isPublicPublisherAddress(item.address)))
2734
+ throw new Error("Publisher DNS answer includes a non-public address");
2735
+ const selected = addresses[0];
2736
+ if (selected === void 0)
2737
+ throw new Error("Publisher DNS lookup was empty");
2738
+ const encoded = Buffer3.from(JSON.stringify(body));
2739
+ if (encoded.byteLength > 65536)
2740
+ throw new Error("Publisher request body is too large");
2741
+ return await new Promise((resolve, reject) => {
2742
+ const call = request(url, {
2743
+ agent: false,
2744
+ headers: {
2745
+ ...endpointHeaders.get(endpoint),
2746
+ "content-length": encoded.byteLength,
2747
+ "content-type": "application/json",
2748
+ ...jwt === void 0 ? {} : { authorization: `Bearer ${jwt}` }
2749
+ },
2750
+ lookup(_hostname, lookupOptions, callback) {
2751
+ if (lookupOptions.all)
2752
+ callback(null, [{ address: selected.address, family: selected.family }]);
2753
+ else
2754
+ callback(null, selected.address, selected.family);
2755
+ },
2756
+ method: "POST",
2757
+ rejectUnauthorized: true,
2758
+ signal: combined
2759
+ }, (response) => {
2760
+ const status = response.statusCode ?? 500;
2761
+ if (status >= 300 && status < 400) {
2762
+ response.destroy();
2763
+ reject(new Error("Publisher HTTPS redirects are forbidden"));
2764
+ return;
2765
+ }
2766
+ let size = 0;
2767
+ const chunks = [];
2768
+ response.on("data", (chunk) => {
2769
+ size += chunk.byteLength;
2770
+ if (size > options.maxResponseBytes) {
2771
+ response.destroy();
2772
+ reject(new Error("Publisher HTTPS response is too large"));
2773
+ } else
2774
+ chunks.push(chunk);
2775
+ });
2776
+ response.on("error", () => reject(new Error("Publisher HTTPS response failed")));
2777
+ response.on("end", () => {
2778
+ try {
2779
+ const responseBody = size === 0 ? null : JSON.parse(Buffer3.concat(chunks).toString("utf8"));
2780
+ const retry = Number(response.headers["retry-after"]);
2781
+ resolve({
2782
+ status,
2783
+ body: responseBody,
2784
+ ...Number.isFinite(retry) && retry > 0 ? { retryAfterMs: Math.min(retry * 1e3, 36e5) } : {}
2785
+ });
2786
+ } catch {
2787
+ reject(new Error("Publisher HTTPS response is not JSON"));
2788
+ }
2789
+ });
2790
+ });
2791
+ call.on("error", () => reject(new Error("Publisher HTTPS request failed")));
2792
+ call.end(encoded);
2793
+ });
2794
+ } finally {
2795
+ scope.dispose();
2796
+ }
2797
+ }
2798
+ };
2799
+ }
2800
+
2801
+ // src/runtime/publisherRuntime.ts
2802
+ import { randomBytes as randomBytes6 } from "node:crypto";
2803
+ import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
2804
+ import { createMemoryLocator, PeriodicActor } from "@ariestools/actor";
2805
+ import { creatable } from "@ariestools/sdk";
2806
+ import { WakeEnvelopeSchema, WakeEnvelopeZod as WakeEnvelopeZod2 } from "@xyo-network/event-kit-schemas";
2807
+ import { z as z3 } from "zod";
2808
+
2809
+ // src/runtime/sourceSigner.ts
2810
+ import { randomBytes as randomBytes5 } from "node:crypto";
2811
+ import {
2812
+ NormalizedAddressZod as NormalizedAddressZod4,
2813
+ WakeEnvelopeZod,
2814
+ WakeJwtSchema
2815
+ } from "@xyo-network/event-kit-schemas";
2816
+ import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk";
2817
+ function createAccountSourceWakeSigner(options) {
2818
+ const publisher = NormalizedAddressZod4.parse(options.publisher);
2819
+ if (String(options.account.address).replace(/^0x/u, "").toLowerCase() !== publisher)
2820
+ throw new Error("Publisher signing account mismatch");
2821
+ return {
2822
+ async sign(input, audience) {
2823
+ const event = WakeEnvelopeZod.parse(input);
2824
+ const eventHash = await PayloadBuilder2.dataHash(event);
2825
+ const now = options.nowSeconds?.() ?? Math.floor(Date.now() / 1e3);
2826
+ if (!Number.isSafeInteger(now) || now < 0)
2827
+ throw new Error("Publisher signing clock is invalid");
2828
+ const { token: jwt } = await options.account.signJwt({
2829
+ audience,
2830
+ claims: { eventHash, jti: randomBytes5(16).toString("hex") },
2831
+ now,
2832
+ schema: WakeJwtSchema,
2833
+ ttl: 60
2834
+ });
2835
+ return {
2836
+ event,
2837
+ eventHash,
2838
+ jwt,
2839
+ publisher
2840
+ };
2841
+ }
2842
+ };
2843
+ }
2844
+
2845
+ // src/runtime/publisherRuntime.ts
2846
+ function activationReady(status) {
2847
+ return (status?.keyLoaded ?? true) && (status?.pendingSubscriptions ?? 0) === 0;
2848
+ }
2849
+ function assertDeliveryState(record, subscription) {
2850
+ if (!isDeepStrictEqual2(record.subscription, subscription))
2851
+ throw new Error("Subscription revision changed without a new identity");
2852
+ if (!Number.isSafeInteger(record.cursor) || record.cursor < subscription.fromPosition - 1 || ![record.delivered, record.failures, record.nextAttemptMs].every((value) => Number.isSafeInteger(value) && value >= 0) || !["active", "blocked", "cancelled"].includes(record.state))
2853
+ throw new Error("Persisted publisher delivery state is invalid");
2854
+ if (record.pending !== void 0) {
2855
+ const pending = WakeEnvelopeZod2.parse(record.pending);
2856
+ if (pending.fromPosition !== record.cursor + 1 || pending.toPosition - pending.fromPosition + 1 > subscription.maxPositionsPerWake || pending.authorizationChainId !== subscription.authorizationChainId || pending.deploymentId !== subscription.deploymentId || pending.queueId !== subscription.queueId || pending.filterHash !== subscription.filterHash || !isDeepStrictEqual2(pending.source, subscription.source))
2857
+ throw new Error("Persisted publisher outbox binding is invalid");
2858
+ }
2859
+ }
2860
+ function makeEvent(subscription, fromPosition, toPosition, now, wakeId = randomBytes6(16).toString("hex")) {
2861
+ return WakeEnvelopeZod2.parse({
2862
+ schema: WakeEnvelopeSchema,
2863
+ authorizationChainId: subscription.authorizationChainId,
2864
+ deploymentId: subscription.deploymentId,
2865
+ filterHash: subscription.filterHash,
2866
+ fromPosition,
2867
+ issuedAt: now,
2868
+ source: subscription.source,
2869
+ toPosition,
2870
+ wakeId,
2871
+ ...subscription.queueId === void 0 ? {} : { queueId: subscription.queueId }
2872
+ });
2873
+ }
2874
+ var PublisherRuntimeActor = class extends PeriodicActor {
2875
+ async runPass(context) {
2876
+ await this.params.tick(context.signal);
2877
+ }
2878
+ };
2879
+ PublisherRuntimeActor = __decorateClass([
2880
+ creatable()
2881
+ ], PublisherRuntimeActor);
2882
+ var TimingZod = z3.object({
2883
+ concurrency: z3.number().int().min(1).max(32).default(4),
2884
+ intervalMs: z3.number().int().min(100).max(6e4).default(1e3),
2885
+ maxSubscriptions: z3.number().int().min(1).max(1024).default(64),
2886
+ requestTimeoutMs: z3.number().int().min(100).max(6e4).default(1e4)
2887
+ });
2888
+ var DeliveryResponseError = class extends Error {
2889
+ retryAfterMs;
2890
+ status;
2891
+ constructor(status, retryAfterMs) {
2892
+ super("Publisher admission failed");
2893
+ this.status = status;
2894
+ this.retryAfterMs = retryAfterMs;
2895
+ }
2896
+ get retryable() {
2897
+ return this.status === 408 || this.status === 429 || this.status >= 500;
2898
+ }
2899
+ };
2900
+ async function createPersistentEventPublisherRuntime(options) {
2901
+ const timing = TimingZod.parse(options);
2902
+ if (options.sources.length < 1 || options.sources.length > 16)
2903
+ throw new Error("Publisher requires between one and sixteen bounded sources");
2904
+ const clock = options.nowSeconds ?? (() => Math.floor(Date.now() / 1e3));
2905
+ const signer = createAccountSourceWakeSigner({
2906
+ account: options.account,
2907
+ publisher: options.publisher,
2908
+ nowSeconds: clock
2909
+ });
2910
+ const sourceReaders = new Map(options.sources.map((reader) => [publisherSourceKey(reader.source), reader]));
2911
+ if (sourceReaders.size !== options.sources.length)
2912
+ throw new Error("Duplicate publisher source identity");
2913
+ const abort = new AbortController();
2914
+ let running = false;
2915
+ let ready = false;
2916
+ let clockHealthy = true;
2917
+ let passes = 0;
2918
+ let lastError;
2919
+ let sourcesHealthy = false;
2920
+ let stop;
2921
+ const state = options.state;
2922
+ const timed = (promise, signal) => boundedPublisherOperation(promise, signal, timing.requestTimeoutMs);
2923
+ function loadDelivery(subscription, now) {
2924
+ const key = subscription.subscriptionHash;
2925
+ let record = state.get("deliveries", key);
2926
+ if (record === void 0) {
2927
+ makeEvent(subscription, subscription.fromPosition, subscription.fromPosition, now, "0".repeat(32));
2928
+ if (!Number.isSafeInteger(subscription.maxPositionsPerWake) || subscription.maxPositionsPerWake < 1 || subscription.maxPositionsPerWake > 4096) {
2929
+ throw new Error("Invalid source range budget");
2930
+ }
2931
+ record = {
2932
+ subscription,
2933
+ cursor: subscription.fromPosition - 1,
2934
+ delivered: 0,
2935
+ failures: 0,
2936
+ nextAttemptMs: 0,
2937
+ state: "active"
2938
+ };
2939
+ state.set("deliveries", key, record);
2940
+ }
2941
+ assertDeliveryState(record, subscription);
2942
+ return record;
2943
+ }
2944
+ function prepareDelivery(record, now, heads) {
2945
+ if (record.pending !== void 0) return { ...record, pending: record.pending };
2946
+ const subscription = record.subscription;
2947
+ const head = heads.get(publisherSourceKey(subscription.source));
2948
+ if (head === void 0 || head instanceof Error) throw new Error("Configured source is unavailable");
2949
+ if (head.position <= record.cursor) return;
2950
+ const fromPosition = record.cursor + 1;
2951
+ const pending = makeEvent(subscription, fromPosition, Math.min(head.position, fromPosition + subscription.maxPositionsPerWake - 1), now);
2952
+ const prepared = { ...record, pending };
2953
+ state.transaction(() => {
2954
+ const logicalKey = JSON.stringify([subscription.subscriptionHash, pending.fromPosition, pending.toPosition]);
2955
+ if (!state.insert("delivery-events", logicalKey, pending)) throw new Error("Publisher logical range already exists outside its contiguous cursor");
2956
+ state.set("deliveries", subscription.subscriptionHash, prepared);
2957
+ });
2958
+ return prepared;
2959
+ }
2960
+ async function stillActive(record, signal) {
2961
+ if (await timed(options.discovery.isActive(record.subscription, signal), signal)) return true;
2962
+ state.set("deliveries", record.subscription.subscriptionHash, {
2963
+ ...record,
2964
+ pending: void 0,
2965
+ state: "cancelled"
2966
+ });
2967
+ return false;
2968
+ }
2969
+ async function sendDelivery(record, signal, now) {
2970
+ const { pending, subscription } = record;
2971
+ signal.throwIfAborted();
2972
+ const signed = await signer.sign(pending, subscription.audience);
2973
+ signal.throwIfAborted();
2974
+ const attempt = state.get("delivery-attempts", pending.wakeId)?.count ?? 0;
2975
+ state.set("delivery-attempts", pending.wakeId, {
2976
+ count: attempt + 1,
2977
+ startedAt: now,
2978
+ status: "in-flight"
2979
+ });
2980
+ const response = await options.transport.post(subscription.endpoint, signed.event, signal, signed.jwt);
2981
+ state.set("delivery-attempts", pending.wakeId, {
2982
+ count: attempt + 1,
2983
+ startedAt: now,
2984
+ status: response.status
2985
+ });
2986
+ if (response.status !== 200 && response.status !== 202) throw new DeliveryResponseError(response.status, response.retryAfterMs);
2987
+ const receipt = z3.object({ receiptId: z3.string().min(1), wakeId: z3.literal(pending.wakeId) }).safeParse(response.body);
2988
+ if (!receipt.success) throw new Error("Publisher admission did not return a matching durable receipt");
2989
+ signal.throwIfAborted();
2990
+ state.transaction(() => {
2991
+ state.set("delivery-receipts", pending.wakeId, { receiptId: receipt.data.receiptId, receivedAt: now });
2992
+ state.set("deliveries", subscription.subscriptionHash, {
2993
+ subscription,
2994
+ cursor: pending.toPosition,
2995
+ delivered: record.delivered + 1,
2996
+ failures: 0,
2997
+ nextAttemptMs: 0,
2998
+ state: "active"
2999
+ });
3000
+ });
3001
+ }
3002
+ async function deliver(subscription, signal, now, heads) {
3003
+ let record = loadDelivery(subscription, now);
3004
+ if (record.state !== "active" || record.nextAttemptMs > now * 1e3) return;
3005
+ try {
3006
+ if (!await stillActive(record, signal)) return;
3007
+ options.transport.assertAllowed(subscription.endpoint);
3008
+ if (!sourceReaders.has(publisherSourceKey(subscription.source))) throw new Error("Subscription source is not configured");
3009
+ const prepared = prepareDelivery(record, now, heads);
3010
+ if (prepared === void 0) return;
3011
+ record = prepared;
3012
+ if (!await stillActive(record, signal)) return;
3013
+ await sendDelivery(prepared, signal, now);
3014
+ } catch (error) {
3015
+ if (signal.aborted) return;
3016
+ state.set("deliveries", subscription.subscriptionHash, {
3017
+ ...record,
3018
+ failures: record.failures + 1,
3019
+ state: error instanceof DeliveryResponseError && !error.retryable ? "blocked" : "active",
3020
+ nextAttemptMs: now * 1e3 + Math.min(36e5, error instanceof DeliveryResponseError && error.retryAfterMs !== void 0 ? error.retryAfterMs : Math.min(3e5, 1e3 * 2 ** Math.min(record.failures, 8))),
3021
+ lastError: "delivery-failed"
3022
+ });
3023
+ }
3024
+ }
3025
+ async function readSources(signal) {
3026
+ const heads = /* @__PURE__ */ new Map();
3027
+ const results = await Promise.allSettled([...sourceReaders].map(async ([key, reader]) => {
3028
+ const head = await timed(reader.head(signal), signal);
3029
+ if (!Number.isSafeInteger(head.position) || head.position < -1)
3030
+ throw new Error("Source head is invalid");
3031
+ const previous = state.get("source-heads", key);
3032
+ if (previous !== void 0 && (head.position < previous.position || head.position === previous.position && head.hash !== previous.hash)) {
3033
+ throw new Error("Finalized source regressed or changed hash");
3034
+ }
3035
+ signal.throwIfAborted();
3036
+ state.set("source-heads", key, head);
3037
+ heads.set(key, head);
3038
+ }));
3039
+ sourcesHealthy = results.every((item) => item.status === "fulfilled");
3040
+ for (const [index, result] of results.entries())
3041
+ if (result.status === "rejected") {
3042
+ const key = [...sourceReaders.keys()][index];
3043
+ if (key !== void 0)
3044
+ heads.set(key, new Error("Source read failed"));
3045
+ }
3046
+ return heads;
3047
+ }
3048
+ async function reconcileDeliveries(subscriptions, signal) {
3049
+ if (subscriptions.length > timing.maxSubscriptions) throw new Error("Publisher subscription limit exceeded");
3050
+ const active = new Set(subscriptions.map((subscription) => subscription.subscriptionHash));
3051
+ if (active.size !== subscriptions.length) throw new Error("Duplicate subscription identity");
3052
+ const unavailable = state.entries("deliveries").filter((item) => !active.has(item.key) && item.value.state !== "cancelled");
3053
+ let available = true;
3054
+ for (let offset = 0; offset < unavailable.length; offset += timing.concurrency) {
3055
+ signal.throwIfAborted();
3056
+ const results = await Promise.allSettled(unavailable.slice(offset, offset + timing.concurrency).map(async ({ key, value }) => {
3057
+ const stillAuthorized = await timed(options.discovery.isActive(value.subscription, signal), signal);
3058
+ if (!stillAuthorized) state.set("deliveries", key, {
3059
+ ...value,
3060
+ pending: void 0,
3061
+ state: "cancelled"
3062
+ });
3063
+ return stillAuthorized;
3064
+ }));
3065
+ available = available && results.every((result) => result.status === "fulfilled" && !result.value);
3066
+ }
3067
+ return available;
3068
+ }
3069
+ async function tick(actorSignal) {
3070
+ const scope = publisherAbortScope([abort.signal, actorSignal]);
3071
+ const signal = scope.signal;
3072
+ try {
3073
+ signal.throwIfAborted();
3074
+ const now = clock();
3075
+ const prior = state.get("runtime", "highest-wall-clock") ?? 0;
3076
+ clockHealthy = Number.isSafeInteger(now) && now >= prior;
3077
+ if (!clockHealthy)
3078
+ throw new Error("Publisher clock moved backwards");
3079
+ state.set("runtime", "highest-wall-clock", now);
3080
+ const subscriptions = await timed(options.discovery.discover(signal), signal);
3081
+ const subscriptionsAvailable = await reconcileDeliveries(subscriptions, signal);
3082
+ const heads = await readSources(signal);
3083
+ for (let offset = 0; offset < subscriptions.length; offset += timing.concurrency) {
3084
+ signal.throwIfAborted();
3085
+ const outcomes = await Promise.allSettled(subscriptions.slice(offset, offset + timing.concurrency).map((subscription) => deliver(subscription, signal, now, heads)));
3086
+ const failed = outcomes.find((result) => result.status === "rejected");
3087
+ if (failed?.status === "rejected")
3088
+ throw failed.reason;
3089
+ }
3090
+ if (options.discovery.acceptPending !== void 0)
3091
+ await timed(options.discovery.acceptPending(signal), signal);
3092
+ const discoveryStatus = options.discovery.status?.();
3093
+ ready = subscriptionsAvailable && sourcesHealthy && activationReady(discoveryStatus);
3094
+ lastError = subscriptionsAvailable ? void 0 : "publisher-subscription-unavailable";
3095
+ passes += 1;
3096
+ } catch (error) {
3097
+ ready = false;
3098
+ lastError = clockHealthy ? "publisher-pass-failed" : "publisher-clock-unhealthy";
3099
+ if (!signal.aborted)
3100
+ throw error;
3101
+ } finally {
3102
+ scope.dispose();
3103
+ }
3104
+ }
3105
+ const actor = await PublisherRuntimeActor.create({
3106
+ locator: createMemoryLocator({}),
3107
+ intervalMs: timing.intervalMs,
3108
+ firstRun: "immediate",
3109
+ readiness: "immediate",
3110
+ tick
3111
+ });
3112
+ return {
3113
+ async start() {
3114
+ if (stop !== void 0)
3115
+ throw new Error("Publisher is stopped");
3116
+ if (!running) {
3117
+ await actor.start();
3118
+ running = true;
3119
+ }
3120
+ },
3121
+ async runOnce() {
3122
+ if (stop !== void 0)
3123
+ throw new Error("Publisher is stopped");
3124
+ await actor.runOnce();
3125
+ },
3126
+ stop() {
3127
+ return stop ??= (async () => {
3128
+ abort.abort();
3129
+ const failures = [];
3130
+ try {
3131
+ await actor.stop();
3132
+ } catch (error) {
3133
+ failures.push(error);
3134
+ }
3135
+ try {
3136
+ await options.discovery.close?.();
3137
+ } catch (error) {
3138
+ failures.push(error);
3139
+ }
3140
+ for (const source of options.sources)
3141
+ try {
3142
+ await source.close?.();
3143
+ } catch (error) {
3144
+ failures.push(error);
3145
+ }
3146
+ running = false;
3147
+ ready = false;
3148
+ if (failures.length > 0)
3149
+ throw new AggregateError(failures, "Publisher runtime shutdown failed");
3150
+ })();
3151
+ },
3152
+ status() {
3153
+ const deliveries = state.entries("deliveries").map((item) => item.value);
3154
+ return {
3155
+ running,
3156
+ ready: running && ready,
3157
+ clockHealthy,
3158
+ degraded: !ready || deliveries.some((item) => item.state !== "cancelled" && item.failures > 0),
3159
+ publisher: options.publisher,
3160
+ activeSubscriptions: deliveries.filter((item) => item.state === "active").length,
3161
+ pendingDeliveries: deliveries.filter((item) => item.pending !== void 0).length,
3162
+ delivered: deliveries.reduce((sum, item) => sum + item.delivered, 0),
3163
+ failures: deliveries.reduce((sum, item) => sum + item.failures, 0),
3164
+ passes,
3165
+ ...lastError === void 0 ? {} : { lastError },
3166
+ ...options.discovery.status === void 0 ? {} : { handshake: options.discovery.status() },
3167
+ sources: state.entries("source-heads").map((item) => ({ id: item.key, ...item.value })),
3168
+ subscriptions: state.entries("deliveries").map((item) => ({
3169
+ id: item.key,
3170
+ cursor: item.value.cursor,
3171
+ state: item.value.state,
3172
+ pending: item.value.pending !== void 0,
3173
+ failures: item.value.failures
3174
+ }))
3175
+ };
3176
+ }
3177
+ };
3178
+ }
3179
+
3180
+ // src/runtime/restGateway.ts
3181
+ import { FetchJsonClient } from "@ariestools/sdk";
3182
+ import {
3183
+ baseConfigFactoryLocator,
3184
+ basicRestRunnerLocator,
3185
+ basicRestViewerLocator,
3186
+ creatableProvider,
3187
+ releaseProviderFactoryLocator,
3188
+ RestDataLakeRunner,
3189
+ RestDataLakeViewer,
3190
+ XyoGatewayMoniker,
3191
+ XyoGatewayRunnerMoniker
3192
+ } from "@xyo-network/xl1-sdk";
3193
+ async function openPublisherRestGateway(options) {
3194
+ const rest = {
3195
+ finalized: { type: "rest", baseUrl: options.finalizedUrl },
3196
+ chainState: { type: "rest", baseUrl: options.chainStateUrl },
3197
+ index: { type: "rest", baseUrl: options.indexUrl ?? options.finalizedUrl }
3198
+ };
3199
+ const locator = options.account === void 0 ? await basicRestViewerLocator("event-kit-publisher-read", rest, void 0, { fetchFn: options.fetchFn, primeCaches: "off" }) : await basicRestRunnerLocator("event-kit-publisher-write", rest, void 0, {
3200
+ fetchFn: options.fetchFn,
3201
+ primeCaches: "off",
3202
+ rpcUrl: options.rpcUrl,
3203
+ signerAccount: options.account
3204
+ });
3205
+ try {
3206
+ const gateway = options.account === void 0 ? await locator.getInstance(XyoGatewayMoniker) : await locator.getInstance(XyoGatewayRunnerMoniker);
3207
+ let stopping;
3208
+ return Object.freeze({ gateway, stop: () => stopping ??= releaseProviderFactoryLocator(locator) });
3209
+ } catch (error) {
3210
+ await releaseProviderFactoryLocator(locator);
3211
+ throw error;
3212
+ }
3213
+ }
3214
+ var BoundedRestDataLakeViewer = class extends RestDataLakeViewer {
3215
+ get client() {
3216
+ if (this.context.fetchFn === void 0)
3217
+ throw new Error("Publisher datalake requires its bounded fetch transport");
3218
+ return new FetchJsonClient({ fetcher: this.context.fetchFn });
3219
+ }
3220
+ };
3221
+ BoundedRestDataLakeViewer = __decorateClass([
3222
+ creatableProvider()
3223
+ ], BoundedRestDataLakeViewer);
3224
+ var BoundedRestDataLakeRunner = class extends RestDataLakeRunner {
3225
+ get client() {
3226
+ if (this.context.fetchFn === void 0)
3227
+ throw new Error("Publisher datalake requires its bounded fetch transport");
3228
+ return new FetchJsonClient({ fetcher: this.context.fetchFn });
3229
+ }
3230
+ };
3231
+ BoundedRestDataLakeRunner = __decorateClass([
3232
+ creatableProvider()
3233
+ ], BoundedRestDataLakeRunner);
3234
+ async function openPublisherDataLake(options) {
3235
+ const locator = await baseConfigFactoryLocator({
3236
+ connections: { "event-kit-lake": { type: "rest", baseUrl: options.url } },
3237
+ providerBindings: { DataLakeViewer: { connection: "event-kit-lake" }, DataLakeRunner: { connection: "event-kit-lake" } }
3238
+ });
3239
+ locator.context.fetchFn = options.fetchFn;
3240
+ locator.register(BoundedRestDataLakeViewer.factory(BoundedRestDataLakeViewer.dependencies));
3241
+ if (options.writable)
3242
+ locator.register(BoundedRestDataLakeRunner.factory(BoundedRestDataLakeRunner.dependencies));
3243
+ locator.freeze();
3244
+ try {
3245
+ const reader = await locator.getInstance(BoundedRestDataLakeViewer.defaultMoniker);
3246
+ const writer = options.writable ? await locator.getInstance(BoundedRestDataLakeRunner.defaultMoniker) : void 0;
3247
+ return {
3248
+ reader,
3249
+ writer,
3250
+ async close() {
3251
+ await releaseProviderFactoryLocator(locator);
3252
+ }
3253
+ };
3254
+ } catch (error) {
3255
+ await releaseProviderFactoryLocator(locator);
3256
+ throw error;
3257
+ }
3258
+ }
3259
+
3260
+ // src/runtime/sqliteHandshakeStores.ts
3261
+ import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
3262
+ import { endpointChallengeHash as endpointChallengeHash2 } from "@xyo-network/event-kit-protocol";
3263
+ import {
3264
+ Base64Url32BytesZod as Base64Url32BytesZod3,
3265
+ EndpointChallengeZod as EndpointChallengeZod3,
3266
+ HandshakeIdZod as HandshakeIdZod4,
3267
+ HashZod as HashZod5,
3268
+ NormalizedAddressZod as NormalizedAddressZod5
3269
+ } from "@xyo-network/event-kit-schemas";
3270
+ import { z as z4 } from "zod";
3271
+ var KeyZod = z4.strictObject({
3272
+ encryptionKey: HashZod5,
3273
+ keyId: HandshakeIdZod4,
3274
+ privateKey: Base64Url32BytesZod3,
3275
+ publisher: NormalizedAddressZod5
3276
+ });
3277
+ var phases = ["signed", "content-written", "content-verified", "broadcast", "included", "finalized"];
3278
+ function requireTime2(value) {
3279
+ if (!Number.isSafeInteger(value) || value < 0) throw new Error("Publisher clock is invalid");
3280
+ }
3281
+ function samePublicationIntent(left, right) {
3282
+ return left.chainId === right.chainId && left.source === right.source && left.operationId === right.operationId && isDeepStrictEqual3(left.eventHashes, right.eventHashes) && isDeepStrictEqual3(left.attachmentHashes, right.attachmentHashes);
3283
+ }
3284
+ function publicationKey(intent) {
3285
+ if (!/^[0-9a-f]{40}$/u.test(intent.chainId) || !/^[0-9a-f]{40}$/u.test(intent.source) || intent.operationId.length === 0 || intent.operationId.length > 256 || ![...intent.eventHashes, ...intent.attachmentHashes].every((hash) => HashZod5.safeParse(hash).success)) {
3286
+ throw new Error("Invalid publication intent");
3287
+ }
3288
+ return JSON.stringify([intent.chainId, intent.source, intent.operationId]);
3289
+ }
3290
+ function createSqlitePublisherHandshakeStores(state) {
3291
+ const replay = {
3292
+ async load() {
3293
+ return state.get("replay", "checkpoint");
3294
+ },
3295
+ async save(checkpoint) {
3296
+ state.set("replay", "checkpoint", checkpoint);
3297
+ }
3298
+ };
3299
+ const intents = {
3300
+ async get(lookup2) {
3301
+ const value = state.get("intents", intentLookupKey(lookup2));
3302
+ return value === void 0 ? void 0 : await parseHandshakeMutationIntent(value);
3303
+ },
3304
+ async getOrCreate(raw) {
3305
+ const proposed = await parseHandshakeMutationIntent(raw);
3306
+ return state.transaction(() => {
3307
+ const key = intentLookupKey(proposed);
3308
+ const winner = state.get("intents", key);
3309
+ if (winner !== void 0) {
3310
+ assertSameIntentBinding(winner, proposed);
3311
+ return { disposition: "resumed", intent: winner };
3312
+ }
3313
+ state.set("intents", key, proposed);
3314
+ return { disposition: "created", intent: proposed };
3315
+ });
3316
+ }
3317
+ };
3318
+ const keys = {
3319
+ async getPrivateKey(input) {
3320
+ const key = `${NormalizedAddressZod5.parse(input.publisher)}:${HandshakeIdZod4.parse(input.keyId)}`;
3321
+ const raw = state.get("encryption-keys", key);
3322
+ if (raw === void 0) return;
3323
+ const record = KeyZod.parse(raw);
3324
+ if (record.encryptionKey !== HashZod5.parse(input.encryptionKey)) throw new Error("Encryption key identity mismatch");
3325
+ const { publisher: _publisher, ...privateKey } = record;
3326
+ return privateKey;
3327
+ },
3328
+ async putPrivateKey(input) {
3329
+ const record = KeyZod.parse({ ...input.key, publisher: input.publisher });
3330
+ return state.transaction(() => {
3331
+ const key = `${record.publisher}:${record.keyId}`;
3332
+ const prior = state.get("encryption-keys", key);
3333
+ if (prior !== void 0) {
3334
+ if (!isDeepStrictEqual3(prior, record)) throw new Error("Encryption key collision");
3335
+ return "duplicate";
3336
+ }
3337
+ state.set("encryption-keys", key, record);
3338
+ return "stored";
3339
+ });
3340
+ }
3341
+ };
3342
+ const current = (hash) => state.get("challenges", HashZod5.parse(hash));
3343
+ const live = (record, now) => record.challenge.issuedAt <= now && now < record.challenge.expiresAt;
3344
+ const challenges = {
3345
+ async get(hash) {
3346
+ return current(hash);
3347
+ },
3348
+ async issue(input) {
3349
+ const challenge = EndpointChallengeZod3.parse(input.challenge);
3350
+ const hash = HashZod5.parse(input.challengeHash);
3351
+ if (await endpointChallengeHash2(challenge) !== hash) return { kind: "collision" };
3352
+ return state.transaction(() => {
3353
+ const priorNonce = state.get("challenge-nonces", challenge.nonce);
3354
+ if (priorNonce !== void 0 && priorNonce !== hash) return { kind: "collision" };
3355
+ const prior = current(hash);
3356
+ if (prior !== void 0) return isDeepStrictEqual3(prior.challenge, challenge) ? { kind: "duplicate", record: prior } : { kind: "collision" };
3357
+ const record = {
3358
+ challenge,
3359
+ challengeHash: hash,
3360
+ state: "issued"
3361
+ };
3362
+ state.set("challenge-nonces", challenge.nonce, hash);
3363
+ state.set("challenges", hash, record);
3364
+ return { kind: "issued", record };
3365
+ });
3366
+ },
3367
+ async beginAttempt(input) {
3368
+ requireTime2(input.nowSeconds);
3369
+ return state.transaction(() => {
3370
+ const record = current(input.challengeHash);
3371
+ if (record === void 0) return { kind: "missing" };
3372
+ if (record.state === "verified") return { kind: "verified", record };
3373
+ if (record.state === "attempted") return { kind: "already-attempted", record };
3374
+ if (!live(record, input.nowSeconds)) return { kind: "expired", record };
3375
+ const attempted = { ...record, state: "attempted" };
3376
+ state.set("challenges", input.challengeHash, attempted);
3377
+ return { kind: "started", record: attempted };
3378
+ });
3379
+ },
3380
+ async completeVerified(input) {
3381
+ requireTime2(input.nowSeconds);
3382
+ const responseHash = HashZod5.parse(input.responseHash);
3383
+ return state.transaction(() => {
3384
+ const record = current(input.challengeHash);
3385
+ if (record === void 0) return { kind: "missing" };
3386
+ if (record.state === "verified") return { kind: record.responseHash === responseHash ? "duplicate" : "collision", record };
3387
+ if (record.state !== "attempted") return { kind: "not-attempted", record };
3388
+ if (!live(record, input.nowSeconds)) return { kind: "expired", record };
3389
+ const verified = {
3390
+ ...record,
3391
+ responseHash,
3392
+ state: "verified"
3393
+ };
3394
+ state.set("challenges", input.challengeHash, verified);
3395
+ return { kind: "verified", record: verified };
3396
+ });
3397
+ }
3398
+ };
3399
+ const journal = {
3400
+ async load(intent) {
3401
+ const key = publicationKey(intent);
3402
+ const signed = state.get("publication:signed", key);
3403
+ if (signed === void 0) return;
3404
+ if (!samePublicationIntent(signed, intent)) throw new Error("Publication intent collision");
3405
+ let latest = signed;
3406
+ for (const phase of phases) {
3407
+ const record = state.get(`publication:${phase}`, key);
3408
+ if (record === void 0) continue;
3409
+ if (record.phase !== phase || !samePublicationIntent(record, intent) || !isDeepStrictEqual3(record.evidence, signed.evidence)) {
3410
+ throw new Error("Publication evidence collision");
3411
+ }
3412
+ latest = record;
3413
+ }
3414
+ return latest;
3415
+ },
3416
+ async save(record) {
3417
+ const key = publicationKey(record);
3418
+ HashZod5.parse(record.evidence.transactionHash);
3419
+ if (!phases.includes(record.phase)) throw new Error("Unknown publication phase");
3420
+ state.transaction(() => {
3421
+ const signed = state.get("publication:signed", key);
3422
+ if (signed === void 0 && record.phase !== "signed") throw new Error("Publication must bind signed evidence first");
3423
+ if (signed !== void 0 && (!samePublicationIntent(signed, record) || !isDeepStrictEqual3(signed.evidence, record.evidence))) {
3424
+ throw new Error("Publication intent or evidence collision");
3425
+ }
3426
+ const namespace = `publication:${record.phase}`;
3427
+ const prior = state.get(namespace, key);
3428
+ if (prior !== void 0 && !isDeepStrictEqual3(prior, record)) throw new Error("Publication phase collision");
3429
+ if (prior === void 0) state.set(namespace, key, record);
3430
+ });
3431
+ }
3432
+ };
3433
+ return {
3434
+ challenges,
3435
+ intents,
3436
+ journal,
3437
+ keys,
3438
+ replay
3439
+ };
3440
+ }
3441
+
3442
+ // src/runtime/sqlitePublisherState.ts
3443
+ import { randomBytes as randomBytes7 } from "node:crypto";
3444
+ import { constants } from "node:fs";
3445
+ import {
3446
+ lstat,
3447
+ mkdir as mkdir5,
3448
+ open as open5
3449
+ } from "node:fs/promises";
3450
+ import { hostname } from "node:os";
2309
3451
  import PATH12 from "node:path";
3452
+ function decode(value) {
3453
+ return JSON.parse(value, (_key, candidate) => {
3454
+ if (typeof candidate === "object" && candidate !== null && Object.keys(candidate).length === 1 && "$eventKitBigInt" in candidate && typeof candidate.$eventKitBigInt === "string" && /^(?:0|[1-9][0-9]*)$/u.test(candidate.$eventKitBigInt))
3455
+ return BigInt(candidate.$eventKitBigInt);
3456
+ return candidate;
3457
+ });
3458
+ }
3459
+ function processExists(pid) {
3460
+ if (!Number.isSafeInteger(pid) || pid < 1)
3461
+ throw new Error("Invalid publisher owner record");
3462
+ try {
3463
+ process.kill(pid, 0);
3464
+ return true;
3465
+ } catch (error) {
3466
+ if (typeof error === "object" && error !== null && "code" in error && error.code === "ESRCH")
3467
+ return false;
3468
+ return true;
3469
+ }
3470
+ }
3471
+ async function openSqlitePublisherState(options) {
3472
+ if (options.path === ":memory:" || options.identity.length === 0)
3473
+ throw new Error("Persistent publisher needs a file and an identity");
3474
+ const path = PATH12.resolve(options.path);
3475
+ const directory = PATH12.dirname(path);
3476
+ await mkdir5(directory, { recursive: true, mode: 448 });
3477
+ const metadata = await lstat(directory);
3478
+ if (!metadata.isDirectory() || (metadata.mode & 63) !== 0)
3479
+ throw new Error("Publisher state directory must be a real directory with 0700 permissions");
3480
+ const file = await open5(path, constants.O_CREAT | constants.O_RDWR | constants.O_NOFOLLOW, 384);
3481
+ try {
3482
+ const metadata2 = await file.stat();
3483
+ if (!metadata2.isFile() || (metadata2.mode & 63) !== 0)
3484
+ throw new Error("Publisher database permissions must be 0600");
3485
+ await file.sync();
3486
+ } finally {
3487
+ await file.close();
3488
+ }
3489
+ const { DatabaseSync: DatabaseSync2 } = await import("node:sqlite");
3490
+ const database = new DatabaseSync2(path);
3491
+ const token = randomBytes7(16).toString("hex");
3492
+ let closed = false;
3493
+ let inTransaction = false;
3494
+ const transaction = (work) => {
3495
+ if (closed)
3496
+ throw new Error("Publisher state is closed");
3497
+ if (inTransaction)
3498
+ return work();
3499
+ database.exec("BEGIN IMMEDIATE");
3500
+ inTransaction = true;
3501
+ try {
3502
+ const result = work();
3503
+ if (result instanceof Promise)
3504
+ throw new Error("Publisher state transactions must be synchronous");
3505
+ database.exec("COMMIT");
3506
+ return result;
3507
+ } catch (error) {
3508
+ database.exec("ROLLBACK");
3509
+ throw error;
3510
+ } finally {
3511
+ inTransaction = false;
3512
+ }
3513
+ };
3514
+ try {
3515
+ database.exec(`
3516
+ PRAGMA journal_mode = WAL;
3517
+ PRAGMA synchronous = FULL;
3518
+ PRAGMA busy_timeout = 5000;
3519
+ CREATE TABLE IF NOT EXISTS publisher_records (namespace TEXT NOT NULL, key TEXT NOT NULL, value TEXT NOT NULL, PRIMARY KEY(namespace, key));
3520
+ CREATE TABLE IF NOT EXISTS publisher_owner (id INTEGER PRIMARY KEY CHECK(id = 1), host TEXT NOT NULL, pid INTEGER NOT NULL, token TEXT NOT NULL);
3521
+ `);
3522
+ transaction(() => {
3523
+ const prior = database.prepare("SELECT host, pid, token FROM publisher_owner WHERE id = 1").get();
3524
+ if (prior !== void 0 && (prior.host !== hostname() || processExists(prior.pid))) {
3525
+ throw new Error("Publisher database already has an active owner; a shared or multi-host database is not supported");
3526
+ }
3527
+ const binding = database.prepare("SELECT value FROM publisher_records WHERE namespace = ? AND key = ?").get("metadata", "identity");
3528
+ if (binding !== void 0 && decode(binding.value) !== options.identity)
3529
+ throw new Error("Publisher database identity mismatch");
3530
+ database.prepare("INSERT OR IGNORE INTO publisher_records(namespace,key,value) VALUES (?,?,?)").run("metadata", "identity", stringifyJson(options.identity));
3531
+ database.prepare("INSERT OR REPLACE INTO publisher_owner(id,host,pid,token) VALUES (1,?,?,?)").run(hostname(), process.pid, token);
3532
+ });
3533
+ } catch (error) {
3534
+ database.close();
3535
+ throw error;
3536
+ }
3537
+ const read = database.prepare("SELECT value FROM publisher_records WHERE namespace = ? AND key = ?");
3538
+ const list = database.prepare("SELECT key, value FROM publisher_records WHERE namespace = ? ORDER BY key");
3539
+ const write = database.prepare("INSERT INTO publisher_records(namespace,key,value) VALUES (?,?,?) ON CONFLICT(namespace,key) DO UPDATE SET value = excluded.value");
3540
+ const insert = database.prepare("INSERT OR IGNORE INTO publisher_records(namespace,key,value) VALUES (?,?,?)");
3541
+ const remove = database.prepare("DELETE FROM publisher_records WHERE namespace = ? AND key = ?");
3542
+ const assertOpen = () => {
3543
+ if (closed)
3544
+ throw new Error("Publisher state is closed");
3545
+ };
3546
+ return {
3547
+ path,
3548
+ get(namespace, key) {
3549
+ assertOpen();
3550
+ const row = read.get(namespace, key);
3551
+ return row === void 0 ? void 0 : decode(row.value);
3552
+ },
3553
+ entries(namespace) {
3554
+ assertOpen();
3555
+ return list.all(namespace).map((row) => ({ key: row.key, value: decode(row.value) }));
3556
+ },
3557
+ set(namespace, key, value) {
3558
+ assertOpen();
3559
+ write.run(namespace, key, stringifyJson(value));
3560
+ },
3561
+ insert(namespace, key, value) {
3562
+ assertOpen();
3563
+ return insert.run(namespace, key, stringifyJson(value)).changes === 1;
3564
+ },
3565
+ remove(namespace, key) {
3566
+ assertOpen();
3567
+ remove.run(namespace, key);
3568
+ },
3569
+ transaction,
3570
+ close() {
3571
+ if (closed)
3572
+ return;
3573
+ transaction(() => {
3574
+ database.prepare("DELETE FROM publisher_owner WHERE id = 1 AND token = ?").run(token);
3575
+ });
3576
+ database.close();
3577
+ closed = true;
3578
+ }
3579
+ };
3580
+ }
3581
+
3582
+ // src/sqliteWakeQueue.ts
3583
+ import { mkdir as mkdir6 } from "node:fs/promises";
3584
+ import PATH13 from "node:path";
2310
3585
  import { DatabaseSync } from "node:sqlite";
2311
3586
  async function createSqliteWakeQueue(options) {
2312
3587
  const inMemory = options.path === ":memory:";
2313
- const file = inMemory ? options.path : PATH12.resolve(options.path);
2314
- if (!inMemory) await mkdir5(PATH12.dirname(file), { recursive: true });
3588
+ const file = inMemory ? options.path : PATH13.resolve(options.path);
3589
+ if (!inMemory) await mkdir6(PATH13.dirname(file), { recursive: true });
2315
3590
  const database = new DatabaseSync(file);
2316
3591
  database.exec(`
2317
3592
  PRAGMA journal_mode = WAL;
@@ -2377,6 +3652,11 @@ export {
2377
3652
  HandshakeMutationIntentKinds,
2378
3653
  HandshakeMutationIntentZod,
2379
3654
  assertSameIntentBinding,
3655
+ boundedPublisherOperation,
3656
+ createAccountSourceWakeSigner,
3657
+ createBoundedPublisherEthersTransport,
3658
+ createBoundedPublisherFetch,
3659
+ createEthereumFinalizedPublisherSource,
2380
3660
  createEventKitHandshakePublicationPort,
2381
3661
  createFilesystemCursorStore,
2382
3662
  createFilesystemEventKitReplayCheckpointStore,
@@ -2388,13 +3668,24 @@ export {
2388
3668
  createFilesystemWakeInbox,
2389
3669
  createFilesystemWakeQueue,
2390
3670
  createMemoryHandshakeMutationIntentStore,
3671
+ createPersistentEventPublisherRuntime,
2391
3672
  createPublisherHandshakeClient,
3673
+ createPublisherHandshakeDiscovery,
3674
+ createPublisherHttpsTransport,
3675
+ createSqlitePublisherHandshakeStores,
2392
3676
  createSqliteWakeQueue,
2393
3677
  createSubscriberHandshakeClient,
2394
3678
  createSynchronizedEventKitHandshakeReader,
3679
+ createUtcIntervalPublisherSource,
3680
+ createXl1PublisherSource,
2395
3681
  handshakeMutationRequestFingerprint,
2396
3682
  intentLookupKey,
3683
+ isPublicPublisherAddress,
3684
+ openPublisherDataLake,
3685
+ openPublisherRestGateway,
3686
+ openSqlitePublisherState,
2397
3687
  parseHandshakeMutationIntent,
2398
- parseHandshakeMutationIntentLookup
3688
+ parseHandshakeMutationIntentLookup,
3689
+ publisherSourceKey
2399
3690
  };
2400
3691
  //# sourceMappingURL=index.mjs.map