@xyo-network/event-kit-node 1.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,10 +23,7 @@ function createFilesystemCursorStore(options) {
23
23
  try {
24
24
  const raw = await readFile(filePath, "utf8");
25
25
  const parsed = JSON.parse(raw);
26
- if (typeof parsed.lastProcessedBlock !== "number" || !Number.isFinite(parsed.lastProcessedBlock)) {
27
- return void 0;
28
- }
29
- return parsed.lastProcessedBlock;
26
+ return typeof parsed.lastProcessedBlock !== "number" || !Number.isFinite(parsed.lastProcessedBlock) ? void 0 : parsed.lastProcessedBlock;
30
27
  } catch (error) {
31
28
  if (isNotFound(error)) return void 0;
32
29
  throw error;
@@ -481,10 +478,7 @@ function replaceJsonValue(_key, candidate) {
481
478
  return typeof candidate === "bigint" ? { $eventKitBigInt: candidate.toString() } : candidate;
482
479
  }
483
480
  function reviveJson(_key, candidate) {
484
- 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)) {
485
- return BigInt(candidate.$eventKitBigInt);
486
- }
487
- return candidate;
481
+ return 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) ? BigInt(candidate.$eventKitBigInt) : candidate;
488
482
  }
489
483
  async function unlinkIfMissing3(path) {
490
484
  try {
@@ -1076,7 +1070,7 @@ function createFilesystemPublisherEndpointChallengeStore(options) {
1076
1070
  if (await publish(attempted)) return { kind: "started", record: attempted };
1077
1071
  const winner = await current(challengeHash);
1078
1072
  if (winner === void 0) throw new Error("challenge attempt winner vanished");
1079
- return winner.state === "verified" ? { kind: "verified", record: winner } : { kind: "already-attempted", record: winner };
1073
+ return { kind: winner.state === "verified" ? "verified" : "already-attempted", record: winner };
1080
1074
  },
1081
1075
  async completeVerified(input) {
1082
1076
  const challengeHash = HashZod3.parse(input.challengeHash);
@@ -1085,7 +1079,7 @@ function createFilesystemPublisherEndpointChallengeStore(options) {
1085
1079
  const observed = await current(challengeHash);
1086
1080
  if (observed === void 0) return { kind: "missing" };
1087
1081
  if (observed.state === "verified") {
1088
- return observed.responseHash === responseHash ? { kind: "duplicate", record: observed } : { kind: "collision", record: observed };
1082
+ return { kind: observed.responseHash === responseHash ? "duplicate" : "collision", record: observed };
1089
1083
  }
1090
1084
  if (observed.state !== "attempted") return { kind: "not-attempted", record: observed };
1091
1085
  if (!isLive(observed, input.nowSeconds)) return { kind: "expired", record: observed };
@@ -1097,7 +1091,7 @@ function createFilesystemPublisherEndpointChallengeStore(options) {
1097
1091
  if (await publish(verified)) return { kind: "verified", record: verified };
1098
1092
  const winner = await readState(challengeHash, "verified");
1099
1093
  if (winner === void 0) throw new Error("verified challenge winner vanished");
1100
- return winner.responseHash === responseHash ? { kind: "duplicate", record: winner } : { kind: "collision", record: winner };
1094
+ return { kind: winner.responseHash === responseHash ? "duplicate" : "collision", record: winner };
1101
1095
  },
1102
1096
  get: async (rawHash) => await current(HashZod3.parse(rawHash)),
1103
1097
  async issue(input) {
@@ -1355,6 +1349,8 @@ async function persistMutationIntent(store, intent) {
1355
1349
  }
1356
1350
  async function publisherServiceRequestFingerprint(input) {
1357
1351
  return await handshakeMutationRequestFingerprint({
1352
+ deliveryMode: input.deliveryMode,
1353
+ bestEffort: input.bestEffort ?? null,
1358
1354
  expiresAtBlock: input.expiresAtBlock ?? null,
1359
1355
  maxPositionsPerWake: input.maxPositionsPerWake,
1360
1356
  sources: input.sources,
@@ -1374,6 +1370,8 @@ async function publisherRotationRequestFingerprint(input) {
1374
1370
  }
1375
1371
  async function subscriberSubscriptionRequestFingerprint(input) {
1376
1372
  return await handshakeMutationRequestFingerprint({
1373
+ deliveryMode: input.deliveryMode,
1374
+ bestEffort: input.bestEffort ?? null,
1377
1375
  audience: input.audience,
1378
1376
  challengeSecret: input.challengeSecret,
1379
1377
  deploymentId: input.deploymentId,
@@ -1760,6 +1758,8 @@ function createPublisherHandshakeClient(options) {
1760
1758
  validFromBlock
1761
1759
  };
1762
1760
  const service = createPublisherService({
1761
+ deliveryMode: input.deliveryMode,
1762
+ ...input.bestEffort === void 0 ? {} : { bestEffort: input.bestEffort },
1763
1763
  ...serviceInput,
1764
1764
  authorizationChainId: options.reader.chainId,
1765
1765
  sources: input.sources,
@@ -1879,6 +1879,8 @@ function createPublisherHandshakeClient(options) {
1879
1879
  validFromBlock
1880
1880
  };
1881
1881
  const service = createPublisherService({
1882
+ deliveryMode: selected.service.body.deliveryMode,
1883
+ ...selected.service.body.bestEffort === void 0 ? {} : { bestEffort: selected.service.body.bestEffort },
1882
1884
  ...serviceInput,
1883
1885
  authorizationChainId: options.reader.chainId,
1884
1886
  sources: selected.service.body.events.map((event) => event.source),
@@ -2172,6 +2174,8 @@ function createSubscriberHandshakeClient(options) {
2172
2174
  return Object.freeze(client);
2173
2175
  }
2174
2176
  function subscriberPlaintext(service, input, maxPositionsPerWake) {
2177
+ if (input.deliveryMode !== service.deliveryMode || canonicalJson(input.bestEffort ?? null) !== canonicalJson(service.bestEffort ?? null))
2178
+ throw new Error("Requested delivery terms do not match exact selected service");
2175
2179
  const plaintextInput = {
2176
2180
  audience: input.audience,
2177
2181
  challengeSecret: input.challengeSecret,
@@ -2184,6 +2188,8 @@ function subscriberPlaintext(service, input, maxPositionsPerWake) {
2184
2188
  throw new Error("Requested source is not advertised by the selected service");
2185
2189
  }
2186
2190
  return createWakeSubscriptionPlaintext({
2191
+ deliveryMode: input.deliveryMode,
2192
+ ...input.bestEffort === void 0 ? {} : { bestEffort: input.bestEffort },
2187
2193
  ...plaintextInput,
2188
2194
  source,
2189
2195
  fromPosition: input.fromPosition,
@@ -2323,6 +2329,7 @@ function createBoundedPublisherEthersTransport(options = {}) {
2323
2329
  }
2324
2330
 
2325
2331
  // src/runtime/handshakeDiscovery.ts
2332
+ import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
2326
2333
  import { decryptWakeSubscription, sourceWakeFilterHash } from "@xyo-network/event-kit-protocol";
2327
2334
  import { EndpointChallengeResponseZod as EndpointChallengeResponseZod2 } from "@xyo-network/event-kit-schemas";
2328
2335
  function createPublisherHandshakeDiscovery(options) {
@@ -2338,6 +2345,9 @@ function createPublisherHandshakeDiscovery(options) {
2338
2345
  rejectedSubscriptions: 0,
2339
2346
  challengeFailures: 0
2340
2347
  };
2348
+ function selectedTuple(tuple) {
2349
+ return (options.serviceHash === void 0 || tuple.service.objectHash === options.serviceHash) && (options.deliveryMode === void 0 || tuple.service.body.deliveryMode === options.deliveryMode) && (options.deliveryMode === void 0 || tuple.subscription.body.deliveryMode === options.deliveryMode) && (options.deliveryMode === void 0 || isDeepStrictEqual2(tuple.service.body.bestEffort, options.bestEffort));
2350
+ }
2341
2351
  async function activeView(signal) {
2342
2352
  signal.throwIfAborted();
2343
2353
  viewing ??= (async () => {
@@ -2355,7 +2365,7 @@ function createPublisherHandshakeDiscovery(options) {
2355
2365
  ...status,
2356
2366
  finalizedHead: view.finalizedHead,
2357
2367
  indexedThrough: view.indexedThrough,
2358
- pendingSubscriptions: view.subscriptions.filter((item) => item.state === "pending").length,
2368
+ pendingSubscriptions: view.subscriptions.filter((item) => item.state === "pending" && item.tuples.some(selectedTuple)).length,
2359
2369
  rejectedSubscriptions: view.rejections.length
2360
2370
  };
2361
2371
  return view;
@@ -2420,7 +2430,7 @@ function createPublisherHandshakeDiscovery(options) {
2420
2430
  if (!found.ok)
2421
2431
  throw new Error("Publisher acceptance candidates are unavailable");
2422
2432
  const offset = options.state.get("challenge-rate", "offset") ?? 0;
2423
- const candidates = found.candidates;
2433
+ const candidates = found.candidates.filter((candidate) => selectedTuple(candidate.tuple));
2424
2434
  let attempted = 0;
2425
2435
  for (let index = 0; index < Math.min(candidates.length, 128) && attempted < 4; index += 1) {
2426
2436
  const candidate = candidates[(offset + index) % candidates.length];
@@ -2436,30 +2446,40 @@ function createPublisherHandshakeDiscovery(options) {
2436
2446
  await acceptCandidate(candidate.subscriber, candidate.tuple.subscription.objectHash, signal);
2437
2447
  }
2438
2448
  }
2449
+ async function loadScopedKeys(view, active) {
2450
+ const scopedKeys = active.flatMap((item) => item.tuples.filter((tuple) => tuple.subscription.objectHash === item.selectedSubscription).map((tuple) => ({
2451
+ encryptionKey: tuple.subscription.body.encryptionKey,
2452
+ keyId: tuple.subscription.body.keyId,
2453
+ publisher: options.publisher
2454
+ })));
2455
+ if (view.hasCurrentAdvertisement && (options.serviceHash === void 0 || view.service.objectHash === options.serviceHash) && (options.deliveryMode === void 0 || view.service.body.deliveryMode === options.deliveryMode)) {
2456
+ scopedKeys.push({
2457
+ encryptionKey: view.key.objectHash,
2458
+ keyId: view.key.body.keyId,
2459
+ publisher: options.publisher
2460
+ });
2461
+ }
2462
+ const loadedKeys = await Promise.all(scopedKeys.map(async (key) => await options.keys.getPrivateKey(key)));
2463
+ status = {
2464
+ ...status,
2465
+ keyLoaded: scopedKeys.length > 0 && loadedKeys.every((key) => key !== void 0),
2466
+ activeKeyIds: [...new Set(scopedKeys.map((key) => key.keyId))]
2467
+ };
2468
+ }
2439
2469
  return {
2440
2470
  async discover(signal) {
2441
2471
  const view = await activeView(signal);
2442
- const key = view.hasCurrentAdvertisement ? view.key : void 0;
2443
- const loaded = key === void 0 ? void 0 : await options.keys.getPrivateKey({
2444
- encryptionKey: key.objectHash,
2445
- keyId: key.body.keyId,
2446
- publisher: options.publisher
2447
- });
2448
- status = {
2449
- ...status,
2450
- keyLoaded: loaded !== void 0,
2451
- activeKeyIds: key === void 0 ? [] : [key.body.keyId]
2452
- };
2453
- const subscriptions = [];
2454
- const active = view.subscriptions.filter((item) => item.state === "active");
2472
+ const active = view.subscriptions.filter((item) => item.state === "active" && item.tuples.some((tuple) => tuple.subscription.objectHash === item.selectedSubscription && selectedTuple(tuple)));
2473
+ await loadScopedKeys(view, active);
2455
2474
  if (active.length > (options.maxSubscriptions ?? 64))
2456
2475
  throw new Error("Publisher active subscription limit exceeded");
2476
+ const subscriptions = [];
2457
2477
  for (const lifecycle of active) {
2458
2478
  if (lifecycle.state !== "active" || lifecycle.activeFromBlock === void 0)
2459
2479
  continue;
2460
2480
  try {
2461
2481
  const tuple = lifecycle.tuples.find((item) => item.subscription.objectHash === lifecycle.selectedSubscription);
2462
- if (tuple === void 0)
2482
+ if (tuple === void 0 || !selectedTuple(tuple))
2463
2483
  throw new Error("Active publisher subscription has no selected tuple");
2464
2484
  const encrypted = tuple.subscription.body;
2465
2485
  if (encrypted.chainId !== options.authorizationChainId)
@@ -2479,6 +2499,9 @@ function createPublisherHandshakeDiscovery(options) {
2479
2499
  options.transport.assertAllowed(plaintext.endpoint);
2480
2500
  subscriptions.push({
2481
2501
  subscriptionHash: tuple.subscription.objectHash,
2502
+ serviceHash: tuple.service.objectHash,
2503
+ deliveryMode: plaintext.filter.deliveryMode,
2504
+ ...plaintext.filter.bestEffort === void 0 ? {} : { bestEffort: plaintext.filter.bestEffort },
2482
2505
  authorizationChainId: options.authorizationChainId,
2483
2506
  controller: tuple.subscriber,
2484
2507
  audience: plaintext.audience,
@@ -2498,7 +2521,7 @@ function createPublisherHandshakeDiscovery(options) {
2498
2521
  },
2499
2522
  async isActive(subscription, signal) {
2500
2523
  const view = await activeView(signal);
2501
- 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));
2524
+ 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 && selectedTuple(tuple)));
2502
2525
  },
2503
2526
  async acceptPending(signal) {
2504
2527
  if (accepting === void 0) {
@@ -2717,11 +2740,7 @@ function loadPublisherAddressPolicy() {
2717
2740
  }
2718
2741
  function isPublicPublisherAddress(address) {
2719
2742
  const policy = loadPublisherAddressPolicy();
2720
- if (isIP(address) === 4)
2721
- return !policy.nonPublicIpv4.check(address, "ipv4");
2722
- if (isIP(address) !== 6)
2723
- return false;
2724
- return policy.globalIpv6.check(address, "ipv6") && !policy.nonPublicIpv6.check(address, "ipv6");
2743
+ return isIP(address) === 4 ? !policy.nonPublicIpv4.check(address, "ipv4") : isIP(address) === 6 && policy.globalIpv6.check(address, "ipv6") && !policy.nonPublicIpv6.check(address, "ipv6");
2725
2744
  }
2726
2745
  function createPublisherHttpsTransport(input) {
2727
2746
  const parsed = OptionsZod.safeParse(input);
@@ -2828,18 +2847,128 @@ function createPublisherHttpsTransport(input) {
2828
2847
  }
2829
2848
 
2830
2849
  // src/runtime/publisherRuntime.ts
2831
- import { randomBytes as randomBytes6 } from "node:crypto";
2832
- import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
2850
+ import { isDeepStrictEqual as isDeepStrictEqual4 } from "node:util";
2833
2851
  import { createMemoryLocator, PeriodicActor } from "@ariestools/actor";
2834
2852
  import { creatable } from "@ariestools/sdk";
2835
- import { WakeEnvelopeSchema, WakeEnvelopeZod as WakeEnvelopeZod2 } from "@xyo-network/event-kit-schemas";
2853
+ import { BestEffortAdmissionAcknowledgmentZod } from "@xyo-network/event-kit-protocol";
2854
+ import { BestEffortDeliveryPolicyZod, WakeDeliveryModeZod } from "@xyo-network/event-kit-schemas";
2836
2855
  import { z as z3 } from "zod";
2837
2856
 
2838
- // src/runtime/sourceSigner.ts
2857
+ // src/runtime/publisherDeliveryState.ts
2839
2858
  import { randomBytes as randomBytes5 } from "node:crypto";
2859
+ import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
2860
+ import { WakeEnvelopeSchema, WakeEnvelopeZod } from "@xyo-network/event-kit-schemas";
2861
+ function assertDeliveryState(record, subscription) {
2862
+ if (!isDeepStrictEqual3(record.subscription, subscription))
2863
+ throw new Error("Subscription revision changed without a new identity");
2864
+ if (!Number.isSafeInteger(record.cursor) || record.cursor < subscription.fromPosition - 1 || [record.delivered, record.failures, record.nextAttemptMs].some((value) => !(Number.isSafeInteger(value) && value >= 0)) || [record.attempts, record.superseded, record.abandoned, record.totalAttempts, record.lastHintAt, record.lastNotifiedAt, record.lastHintTarget].some((value) => value !== void 0 && !(Number.isSafeInteger(value) && value >= 0)) || !["active", "blocked", "cancelled"].includes(record.state))
2865
+ throw new Error("Persisted publisher delivery state is invalid");
2866
+ if (record.pending === void 0) return;
2867
+ const pending = WakeEnvelopeZod.parse(record.pending);
2868
+ if (subscription.deliveryMode === "durable" && pending.fromPosition !== record.cursor + 1 || pending.deliveryMode !== subscription.deliveryMode || pending.toPosition - pending.fromPosition + 1 > subscription.maxPositionsPerWake || pending.authorizationChainId !== subscription.authorizationChainId || pending.deploymentId !== subscription.deploymentId || pending.queueId !== subscription.queueId || pending.filterHash !== subscription.filterHash || !isDeepStrictEqual3(pending.source, subscription.source))
2869
+ throw new Error("Persisted publisher outbox binding is invalid");
2870
+ }
2871
+ function makeEvent(subscription, fromPosition, toPosition, now, wakeId = randomBytes5(16).toString("hex")) {
2872
+ return WakeEnvelopeZod.parse({
2873
+ schema: WakeEnvelopeSchema,
2874
+ authorizationChainId: subscription.authorizationChainId,
2875
+ deliveryMode: subscription.deliveryMode,
2876
+ deploymentId: subscription.deploymentId,
2877
+ filterHash: subscription.filterHash,
2878
+ fromPosition,
2879
+ issuedAt: now,
2880
+ source: subscription.source,
2881
+ toPosition,
2882
+ wakeId,
2883
+ ...subscription.queueId === void 0 ? {} : { queueId: subscription.queueId }
2884
+ });
2885
+ }
2886
+ var DeliveryResponseError = class extends Error {
2887
+ retryAfterMs;
2888
+ status;
2889
+ constructor(status, retryAfterMs) {
2890
+ super("Publisher admission failed");
2891
+ this.status = status;
2892
+ this.retryAfterMs = retryAfterMs;
2893
+ }
2894
+ get retryable() {
2895
+ return this.status === 408 || this.status === 429 || this.status >= 500;
2896
+ }
2897
+ };
2898
+ function prepareBestEffortDelivery(options) {
2899
+ const {
2900
+ bestEffort,
2901
+ first,
2902
+ heads,
2903
+ now,
2904
+ record,
2905
+ state
2906
+ } = options;
2907
+ const subscription = record.subscription;
2908
+ const head = heads.get(publisherSourceKey(subscription.source));
2909
+ const prior = record.pending;
2910
+ const expired = isHintExpired(record, now, bestEffort);
2911
+ if (head === void 0 || head instanceof Error || head.position < subscription.fromPosition) {
2912
+ if (prior !== void 0 && !expired) return { ...record, pending: prior };
2913
+ if (prior !== void 0) state.set("best-effort-deliveries", subscription.subscriptionHash, {
2914
+ ...record,
2915
+ pending: void 0,
2916
+ abandoned: (record.abandoned ?? 0) + 1
2917
+ });
2918
+ return;
2919
+ }
2920
+ const refresh = refreshDue(record, now, bestEffort);
2921
+ if (freshHintRequired(record, head.position, first, refresh, expired)) {
2922
+ const pending = makeEvent(subscription, head.position, head.position, now);
2923
+ const prepared = {
2924
+ ...record,
2925
+ pending,
2926
+ attempts: 0,
2927
+ lastHintAt: now,
2928
+ lastHintTarget: head.position,
2929
+ superseded: (record.superseded ?? 0) + (prior !== void 0 && !expired ? 1 : 0),
2930
+ abandoned: (record.abandoned ?? 0) + (expired ? 1 : 0),
2931
+ nextAttemptMs: 0,
2932
+ state: "active"
2933
+ };
2934
+ state.set("best-effort-deliveries", subscription.subscriptionHash, prepared);
2935
+ return prepared;
2936
+ }
2937
+ if (expired) state.set("best-effort-deliveries", subscription.subscriptionHash, {
2938
+ ...record,
2939
+ pending: void 0,
2940
+ abandoned: (record.abandoned ?? 0) + 1
2941
+ });
2942
+ return prior === void 0 || expired ? void 0 : { ...record, pending: prior };
2943
+ }
2944
+ function isHintExpired(record, now, policy) {
2945
+ return record.pending !== void 0 && (now > record.pending.issuedAt + policy.maxHintAgeSeconds || (record.attempts ?? 0) >= policy.maxAttempts);
2946
+ }
2947
+ function refreshDue(record, now, policy) {
2948
+ return now - (record.lastHintAt ?? record.lastNotifiedAt ?? 0) >= policy.refreshIntervalSeconds;
2949
+ }
2950
+ function freshHintRequired(record, head, first, refresh, expired) {
2951
+ return first || head > (record.pending?.toPosition ?? record.lastHintTarget ?? record.cursor) || refresh && (record.pending === void 0 || expired);
2952
+ }
2953
+ function failedDelivery(record, current, mode, error, now) {
2954
+ const bestEffort = mode === "best-effort";
2955
+ const wait = error instanceof DeliveryResponseError && error.retryAfterMs !== void 0 ? error.retryAfterMs : Math.min(3e5, 1e3 * 2 ** Math.min(record.failures, 8));
2956
+ return {
2957
+ ...record,
2958
+ failures: record.failures + 1,
2959
+ totalAttempts: bestEffort ? current?.totalAttempts ?? record.totalAttempts ?? 0 : record.totalAttempts,
2960
+ attempts: bestEffort ? current?.attempts ?? record.attempts ?? 0 : record.attempts,
2961
+ state: !bestEffort && error instanceof DeliveryResponseError && !error.retryable ? "blocked" : "active",
2962
+ nextAttemptMs: now * 1e3 + Math.min(36e5, wait),
2963
+ lastError: "delivery-failed"
2964
+ };
2965
+ }
2966
+
2967
+ // src/runtime/sourceSigner.ts
2968
+ import { randomBytes as randomBytes6 } from "node:crypto";
2840
2969
  import {
2841
2970
  NormalizedAddressZod as NormalizedAddressZod4,
2842
- WakeEnvelopeZod,
2971
+ WakeEnvelopeZod as WakeEnvelopeZod2,
2843
2972
  WakeJwtSchema
2844
2973
  } from "@xyo-network/event-kit-schemas";
2845
2974
  import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk";
@@ -2849,14 +2978,14 @@ function createAccountSourceWakeSigner(options) {
2849
2978
  throw new Error("Publisher signing account mismatch");
2850
2979
  return {
2851
2980
  async sign(input, audience) {
2852
- const event = WakeEnvelopeZod.parse(input);
2981
+ const event = WakeEnvelopeZod2.parse(input);
2853
2982
  const eventHash = await PayloadBuilder2.dataHash(event);
2854
2983
  const now = options.nowSeconds?.() ?? Math.floor(Date.now() / 1e3);
2855
2984
  if (!Number.isSafeInteger(now) || now < 0)
2856
2985
  throw new Error("Publisher signing clock is invalid");
2857
2986
  const { token: jwt } = await options.account.signJwt({
2858
2987
  audience,
2859
- claims: { eventHash, jti: randomBytes5(16).toString("hex") },
2988
+ claims: { eventHash, jti: randomBytes6(16).toString("hex") },
2860
2989
  now,
2861
2990
  schema: WakeJwtSchema,
2862
2991
  ttl: 60
@@ -2875,31 +3004,6 @@ function createAccountSourceWakeSigner(options) {
2875
3004
  function activationReady(status) {
2876
3005
  return (status?.keyLoaded ?? true) && (status?.pendingSubscriptions ?? 0) === 0;
2877
3006
  }
2878
- function assertDeliveryState(record, subscription) {
2879
- if (!isDeepStrictEqual2(record.subscription, subscription))
2880
- throw new Error("Subscription revision changed without a new identity");
2881
- if (!Number.isSafeInteger(record.cursor) || record.cursor < subscription.fromPosition - 1 || [record.delivered, record.failures, record.nextAttemptMs].some((value) => !(Number.isSafeInteger(value) && value >= 0)) || !["active", "blocked", "cancelled"].includes(record.state))
2882
- throw new Error("Persisted publisher delivery state is invalid");
2883
- if (record.pending !== void 0) {
2884
- const pending = WakeEnvelopeZod2.parse(record.pending);
2885
- 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))
2886
- throw new Error("Persisted publisher outbox binding is invalid");
2887
- }
2888
- }
2889
- function makeEvent(subscription, fromPosition, toPosition, now, wakeId = randomBytes6(16).toString("hex")) {
2890
- return WakeEnvelopeZod2.parse({
2891
- schema: WakeEnvelopeSchema,
2892
- authorizationChainId: subscription.authorizationChainId,
2893
- deploymentId: subscription.deploymentId,
2894
- filterHash: subscription.filterHash,
2895
- fromPosition,
2896
- issuedAt: now,
2897
- source: subscription.source,
2898
- toPosition,
2899
- wakeId,
2900
- ...subscription.queueId === void 0 ? {} : { queueId: subscription.queueId }
2901
- });
2902
- }
2903
3007
  var PublisherRuntimeActor = class extends PeriodicActor {
2904
3008
  async runPass(context) {
2905
3009
  await this.params.tick(context.signal);
@@ -2914,20 +3018,24 @@ var TimingZod = z3.object({
2914
3018
  maxSubscriptions: z3.number().int().min(1).max(1024).default(64),
2915
3019
  requestTimeoutMs: z3.number().int().min(100).max(6e4).default(1e4)
2916
3020
  });
2917
- var DeliveryResponseError = class extends Error {
2918
- retryAfterMs;
2919
- status;
2920
- constructor(status, retryAfterMs) {
2921
- super("Publisher admission failed");
2922
- this.status = status;
2923
- this.retryAfterMs = retryAfterMs;
2924
- }
2925
- get retryable() {
2926
- return this.status === 408 || this.status === 429 || this.status >= 500;
2927
- }
2928
- };
3021
+ function runtimeSettings(options) {
3022
+ const deliveryMode = WakeDeliveryModeZod.parse(options.deliveryMode);
3023
+ const bestEffort = options.bestEffort === void 0 ? void 0 : BestEffortDeliveryPolicyZod.parse(options.bestEffort);
3024
+ if (deliveryMode === "best-effort" !== (bestEffort !== void 0)) throw new TypeError("Explicit delivery mode requires its exact policy");
3025
+ return {
3026
+ bestEffort,
3027
+ deliveryMode,
3028
+ deliveryNamespace: deliveryMode === "best-effort" ? "best-effort-deliveries" : "deliveries",
3029
+ timing: TimingZod.parse(options)
3030
+ };
3031
+ }
2929
3032
  async function createPersistentEventPublisherRuntime(options) {
2930
- const timing = TimingZod.parse(options);
3033
+ const {
3034
+ bestEffort,
3035
+ deliveryMode,
3036
+ deliveryNamespace,
3037
+ timing
3038
+ } = runtimeSettings(options);
2931
3039
  if (options.sources.length < 1 || options.sources.length > 16)
2932
3040
  throw new Error("Publisher requires between one and sixteen bounded sources");
2933
3041
  const clock = options.nowSeconds ?? (() => Math.floor(Date.now() / 1e3));
@@ -2939,7 +3047,12 @@ async function createPersistentEventPublisherRuntime(options) {
2939
3047
  const sourceReaders = new Map(options.sources.map((reader) => [publisherSourceKey(reader.source), reader]));
2940
3048
  if (sourceReaders.size !== options.sources.length)
2941
3049
  throw new Error("Duplicate publisher source identity");
3050
+ const state = options.state;
3051
+ const existingMode = state.get("metadata", "runtime-delivery-mode");
3052
+ if (existingMode !== void 0 && existingMode !== deliveryMode) throw new Error("Publisher state delivery mode mismatch; preserve custody and use an explicitly qualified state binding");
3053
+ state.set("metadata", "runtime-delivery-mode", deliveryMode);
2942
3054
  const abort = new AbortController();
3055
+ const seenThisProcess = /* @__PURE__ */ new Set();
2943
3056
  let running = false;
2944
3057
  let ready = false;
2945
3058
  let clockHealthy = true;
@@ -2947,11 +3060,16 @@ async function createPersistentEventPublisherRuntime(options) {
2947
3060
  let lastError;
2948
3061
  let sourcesHealthy = false;
2949
3062
  let stop;
2950
- const state = options.state;
2951
3063
  const timed = (promise, signal) => boundedPublisherOperation(promise, signal, timing.requestTimeoutMs);
2952
3064
  function loadDelivery(subscription, now) {
3065
+ if (subscription.deliveryMode !== deliveryMode || !isDeepStrictEqual4(subscription.bestEffort, bestEffort))
3066
+ throw new Error("Subscription delivery mode or policy disagrees with runtime");
3067
+ if (deliveryMode === "best-effort" && (subscription.maxPositionsPerWake !== 1 || subscription.serviceHash === void 0)) throw new Error("Best Effort requires point range");
3068
+ if (options.serviceHash !== void 0 && subscription.serviceHash !== options.serviceHash)
3069
+ throw new Error("Subscription does not match the configured exact service descriptor");
2953
3070
  const key = subscription.subscriptionHash;
2954
- let record = state.get("deliveries", key);
3071
+ if (deliveryMode === "best-effort" && state.get(deliveryNamespace, key) === void 0 && state.entries(deliveryNamespace).length >= timing.maxSubscriptions) throw new Error("Best Effort state capacity exceeded; live records are not evicted");
3072
+ let record = state.get(deliveryNamespace, key);
2955
3073
  if (record === void 0) {
2956
3074
  makeEvent(subscription, subscription.fromPosition, subscription.fromPosition, now, "0".repeat(32));
2957
3075
  if (!Number.isSafeInteger(subscription.maxPositionsPerWake) || subscription.maxPositionsPerWake < 1 || subscription.maxPositionsPerWake > 4096) {
@@ -2965,12 +3083,26 @@ async function createPersistentEventPublisherRuntime(options) {
2965
3083
  nextAttemptMs: 0,
2966
3084
  state: "active"
2967
3085
  };
2968
- state.set("deliveries", key, record);
3086
+ state.set(deliveryNamespace, key, record);
2969
3087
  }
2970
3088
  assertDeliveryState(record, subscription);
2971
3089
  return record;
2972
3090
  }
2973
3091
  function prepareDelivery(record, now, heads) {
3092
+ if (deliveryMode === "best-effort" && bestEffort !== void 0) {
3093
+ const first = !seenThisProcess.has(record.subscription.subscriptionHash);
3094
+ const head2 = heads.get(publisherSourceKey(record.subscription.source));
3095
+ if (head2 !== void 0 && !(head2 instanceof Error) && head2.position >= record.subscription.fromPosition)
3096
+ seenThisProcess.add(record.subscription.subscriptionHash);
3097
+ return prepareBestEffortDelivery({
3098
+ bestEffort,
3099
+ first,
3100
+ heads,
3101
+ now,
3102
+ record,
3103
+ state
3104
+ });
3105
+ }
2974
3106
  if (record.pending !== void 0) return { ...record, pending: record.pending };
2975
3107
  const subscription = record.subscription;
2976
3108
  const head = heads.get(publisherSourceKey(subscription.source));
@@ -2982,43 +3114,74 @@ async function createPersistentEventPublisherRuntime(options) {
2982
3114
  state.transaction(() => {
2983
3115
  const logicalKey = JSON.stringify([subscription.subscriptionHash, pending.fromPosition, pending.toPosition]);
2984
3116
  if (!state.insert("delivery-events", logicalKey, pending)) throw new Error("Publisher logical range already exists outside its contiguous cursor");
2985
- state.set("deliveries", subscription.subscriptionHash, prepared);
3117
+ state.set(deliveryNamespace, subscription.subscriptionHash, prepared);
2986
3118
  });
2987
3119
  return prepared;
2988
3120
  }
2989
3121
  async function stillActive(record, signal) {
2990
3122
  if (await timed(options.discovery.isActive(record.subscription, signal), signal)) return true;
2991
- state.set("deliveries", record.subscription.subscriptionHash, {
3123
+ state.set(deliveryNamespace, record.subscription.subscriptionHash, {
2992
3124
  ...record,
2993
3125
  pending: void 0,
2994
3126
  state: "cancelled"
2995
3127
  });
2996
3128
  return false;
2997
3129
  }
3130
+ function acknowledgeBestEffort(record, body, eventHash, signal, now) {
3131
+ const { pending, subscription } = record;
3132
+ const acknowledgment = BestEffortAdmissionAcknowledgmentZod.safeParse(body);
3133
+ if (!acknowledgment.success || acknowledgment.data.eventHash !== eventHash || acknowledgment.data.wakeId !== pending.wakeId || acknowledgment.data.expiresAt !== pending.issuedAt + (bestEffort?.maxHintAgeSeconds ?? 0) + 60 || acknowledgment.data.acceptedAt < pending.issuedAt - 60 || acknowledgment.data.acceptedAt > now + 60)
3134
+ throw new Error("Publisher did not receive a matching finite acknowledgment");
3135
+ signal.throwIfAborted();
3136
+ state.set(deliveryNamespace, subscription.subscriptionHash, {
3137
+ subscription,
3138
+ cursor: pending.toPosition,
3139
+ delivered: record.delivered + 1,
3140
+ failures: 0,
3141
+ attempts: 0,
3142
+ superseded: record.superseded ?? 0,
3143
+ abandoned: record.abandoned ?? 0,
3144
+ totalAttempts: (record.totalAttempts ?? 0) + 1,
3145
+ lastNotifiedAt: now,
3146
+ lastHintAt: pending.issuedAt,
3147
+ lastHintTarget: pending.toPosition,
3148
+ nextAttemptMs: 0,
3149
+ state: "active"
3150
+ });
3151
+ }
2998
3152
  async function sendDelivery(record, signal, now) {
2999
3153
  const { pending, subscription } = record;
3000
3154
  signal.throwIfAborted();
3001
3155
  const signed = await signer.sign(pending, subscription.audience);
3002
3156
  signal.throwIfAborted();
3003
- const attempt = state.get("delivery-attempts", pending.wakeId)?.count ?? 0;
3004
- state.set("delivery-attempts", pending.wakeId, {
3157
+ const attempt = deliveryMode === "best-effort" ? record.attempts ?? 0 : state.get("delivery-attempts", pending.wakeId)?.count ?? 0;
3158
+ if (deliveryMode === "best-effort") state.set(deliveryNamespace, subscription.subscriptionHash, {
3159
+ ...record,
3160
+ attempts: attempt + 1,
3161
+ totalAttempts: (record.totalAttempts ?? 0) + 1
3162
+ });
3163
+ else state.set("delivery-attempts", pending.wakeId, {
3005
3164
  count: attempt + 1,
3006
3165
  startedAt: now,
3007
3166
  status: "in-flight"
3008
3167
  });
3009
3168
  const response = await options.transport.post(subscription.endpoint, signed.event, signal, signed.jwt);
3010
- state.set("delivery-attempts", pending.wakeId, {
3169
+ if (deliveryMode === "durable") state.set("delivery-attempts", pending.wakeId, {
3011
3170
  count: attempt + 1,
3012
3171
  startedAt: now,
3013
3172
  status: response.status
3014
3173
  });
3015
3174
  if (response.status !== 200 && response.status !== 202) throw new DeliveryResponseError(response.status, response.retryAfterMs);
3175
+ if (deliveryMode === "best-effort") {
3176
+ acknowledgeBestEffort(record, response.body, signed.eventHash, signal, now);
3177
+ return;
3178
+ }
3016
3179
  const receipt = z3.object({ receiptId: z3.string().min(1), wakeId: z3.literal(pending.wakeId) }).safeParse(response.body);
3017
3180
  if (!receipt.success) throw new Error("Publisher admission did not return a matching durable receipt");
3018
3181
  signal.throwIfAborted();
3019
3182
  state.transaction(() => {
3020
3183
  state.set("delivery-receipts", pending.wakeId, { receiptId: receipt.data.receiptId, receivedAt: now });
3021
- state.set("deliveries", subscription.subscriptionHash, {
3184
+ state.set(deliveryNamespace, subscription.subscriptionHash, {
3022
3185
  subscription,
3023
3186
  cursor: pending.toPosition,
3024
3187
  delivered: record.delivered + 1,
@@ -3030,7 +3193,7 @@ async function createPersistentEventPublisherRuntime(options) {
3030
3193
  }
3031
3194
  async function deliver(subscription, signal, now, heads) {
3032
3195
  let record = loadDelivery(subscription, now);
3033
- if (record.state !== "active" || record.nextAttemptMs > now * 1e3) return;
3196
+ if (deliveryMode === "durable" && (record.state !== "active" || record.nextAttemptMs > now * 1e3)) return;
3034
3197
  try {
3035
3198
  if (!await stillActive(record, signal)) return;
3036
3199
  options.transport.assertAllowed(subscription.endpoint);
@@ -3038,17 +3201,16 @@ async function createPersistentEventPublisherRuntime(options) {
3038
3201
  const prepared = prepareDelivery(record, now, heads);
3039
3202
  if (prepared === void 0) return;
3040
3203
  record = prepared;
3204
+ if (record.nextAttemptMs > now * 1e3) return;
3041
3205
  if (!await stillActive(record, signal)) return;
3042
3206
  await sendDelivery(prepared, signal, now);
3043
3207
  } catch (error) {
3044
3208
  if (signal.aborted) return;
3045
- state.set("deliveries", subscription.subscriptionHash, {
3046
- ...record,
3047
- failures: record.failures + 1,
3048
- state: error instanceof DeliveryResponseError && !error.retryable ? "blocked" : "active",
3049
- 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))),
3050
- lastError: "delivery-failed"
3051
- });
3209
+ state.set(
3210
+ deliveryNamespace,
3211
+ subscription.subscriptionHash,
3212
+ failedDelivery(record, state.get(deliveryNamespace, subscription.subscriptionHash), deliveryMode, error, now)
3213
+ );
3052
3214
  }
3053
3215
  }
3054
3216
  async function readSources(signal) {
@@ -3078,13 +3240,13 @@ async function createPersistentEventPublisherRuntime(options) {
3078
3240
  if (subscriptions.length > timing.maxSubscriptions) throw new Error("Publisher subscription limit exceeded");
3079
3241
  const active = new Set(subscriptions.map((subscription) => subscription.subscriptionHash));
3080
3242
  if (active.size !== subscriptions.length) throw new Error("Duplicate subscription identity");
3081
- const unavailable = state.entries("deliveries").filter((item) => !active.has(item.key) && item.value.state !== "cancelled");
3243
+ const unavailable = state.entries(deliveryNamespace).filter((item) => !active.has(item.key) && item.value.state !== "cancelled");
3082
3244
  let available = true;
3083
3245
  for (let offset = 0; offset < unavailable.length; offset += timing.concurrency) {
3084
3246
  signal.throwIfAborted();
3085
3247
  const results = await Promise.allSettled(unavailable.slice(offset, offset + timing.concurrency).map(async ({ key, value }) => {
3086
3248
  const stillAuthorized = await timed(options.discovery.isActive(value.subscription, signal), signal);
3087
- if (!stillAuthorized) state.set("deliveries", key, {
3249
+ if (!stillAuthorized) state.set(deliveryNamespace, key, {
3088
3250
  ...value,
3089
3251
  pending: void 0,
3090
3252
  state: "cancelled"
@@ -3142,10 +3304,11 @@ async function createPersistentEventPublisherRuntime(options) {
3142
3304
  async start() {
3143
3305
  if (stop !== void 0)
3144
3306
  throw new Error("Publisher is stopped");
3145
- if (!running) {
3146
- await actor.start();
3147
- running = true;
3307
+ if (running) {
3308
+ return;
3148
3309
  }
3310
+ await actor.start();
3311
+ running = true;
3149
3312
  },
3150
3313
  async runOnce() {
3151
3314
  if (stop !== void 0)
@@ -3177,9 +3340,14 @@ async function createPersistentEventPublisherRuntime(options) {
3177
3340
  throw new AggregateError(failures, "Publisher runtime shutdown failed");
3178
3341
  })(),
3179
3342
  status() {
3180
- const deliveries = state.entries("deliveries").map((item) => item.value);
3343
+ const deliveries = state.entries(deliveryNamespace).map((item) => item.value);
3181
3344
  return {
3182
3345
  running,
3346
+ deliveryMode,
3347
+ ...bestEffort === void 0 ? {} : { bestEffort: Object.freeze({ ...bestEffort }) },
3348
+ superseded: deliveries.reduce((sum, item) => sum + (item.superseded ?? 0), 0),
3349
+ abandoned: deliveries.reduce((sum, item) => sum + (item.abandoned ?? 0), 0),
3350
+ totalAttempts: deliveries.reduce((sum, item) => sum + (item.totalAttempts ?? 0), 0),
3183
3351
  ready: running && ready,
3184
3352
  clockHealthy,
3185
3353
  degraded: !ready || deliveries.some((item) => item.state !== "cancelled" && item.failures > 0),
@@ -3191,10 +3359,15 @@ async function createPersistentEventPublisherRuntime(options) {
3191
3359
  passes,
3192
3360
  ...lastError === void 0 ? {} : { lastError },
3193
3361
  ...options.discovery.status === void 0 ? {} : { handshake: options.discovery.status() },
3194
- sources: state.entries("source-heads").map((item) => ({ id: item.key, ...item.value })),
3195
- subscriptions: state.entries("deliveries").map((item) => ({
3362
+ sources: state.entries("source-heads").filter((item) => sourceReaders.has(item.key)).map((item) => ({ id: item.key, ...item.value })),
3363
+ subscriptions: state.entries(deliveryNamespace).map((item) => ({
3196
3364
  id: item.key,
3197
3365
  cursor: item.value.cursor,
3366
+ ...deliveryMode === "best-effort" ? {
3367
+ ...item.value.cursor < item.value.subscription.fromPosition ? {} : { lastAdmissionTarget: item.value.cursor },
3368
+ attempts: item.value.attempts ?? 0,
3369
+ lastHintAt: item.value.lastHintAt
3370
+ } : {},
3198
3371
  state: item.value.state,
3199
3372
  pending: item.value.pending !== void 0,
3200
3373
  failures: item.value.failures
@@ -3285,7 +3458,7 @@ async function openPublisherDataLake(options) {
3285
3458
  }
3286
3459
 
3287
3460
  // src/runtime/sqliteHandshakeStores.ts
3288
- import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
3461
+ import { isDeepStrictEqual as isDeepStrictEqual5 } from "node:util";
3289
3462
  import { endpointChallengeHash as endpointChallengeHash2 } from "@xyo-network/event-kit-protocol";
3290
3463
  import {
3291
3464
  Base64Url32BytesZod as Base64Url32BytesZod3,
@@ -3306,7 +3479,7 @@ function requireTime2(value) {
3306
3479
  if (!Number.isSafeInteger(value) || value < 0) throw new Error("Publisher clock is invalid");
3307
3480
  }
3308
3481
  function samePublicationIntent(left, right) {
3309
- return left.chainId === right.chainId && left.source === right.source && left.operationId === right.operationId && isDeepStrictEqual3(left.eventHashes, right.eventHashes) && isDeepStrictEqual3(left.attachmentHashes, right.attachmentHashes);
3482
+ return left.chainId === right.chainId && left.source === right.source && left.operationId === right.operationId && isDeepStrictEqual5(left.eventHashes, right.eventHashes) && isDeepStrictEqual5(left.attachmentHashes, right.attachmentHashes);
3310
3483
  }
3311
3484
  function publicationKey(intent) {
3312
3485
  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].some((hash) => !HashZod5.safeParse(hash).success)) {
@@ -3314,11 +3487,12 @@ function publicationKey(intent) {
3314
3487
  }
3315
3488
  return JSON.stringify([intent.chainId, intent.source, intent.operationId]);
3316
3489
  }
3317
- function createSqlitePublisherHandshakeStores(state) {
3490
+ function createSqlitePublisherHandshakeStores(state, options = {}) {
3491
+ const replayKey = options.replayNamespace === void 0 ? "checkpoint" : `checkpoint:${z4.string().min(1).max(128).regex(/^[A-Za-z0-9_-]+$/u).parse(options.replayNamespace)}`;
3318
3492
  const replay = {
3319
- load: async () => state.get("replay", "checkpoint"),
3493
+ load: async () => state.get("replay", replayKey),
3320
3494
  async save(checkpoint) {
3321
- state.set("replay", "checkpoint", checkpoint);
3495
+ state.set("replay", replayKey, checkpoint);
3322
3496
  }
3323
3497
  };
3324
3498
  const intents = {
@@ -3356,7 +3530,7 @@ function createSqlitePublisherHandshakeStores(state) {
3356
3530
  const key = `${record.publisher}:${record.keyId}`;
3357
3531
  const prior = state.get("encryption-keys", key);
3358
3532
  if (prior !== void 0) {
3359
- if (!isDeepStrictEqual3(prior, record)) throw new Error("Encryption key collision");
3533
+ if (!isDeepStrictEqual5(prior, record)) throw new Error("Encryption key collision");
3360
3534
  return "duplicate";
3361
3535
  }
3362
3536
  state.set("encryption-keys", key, record);
@@ -3376,7 +3550,7 @@ function createSqlitePublisherHandshakeStores(state) {
3376
3550
  const priorNonce = state.get("challenge-nonces", challenge.nonce);
3377
3551
  if (priorNonce !== void 0 && priorNonce !== hash) return { kind: "collision" };
3378
3552
  const prior = current(hash);
3379
- if (prior !== void 0) return isDeepStrictEqual3(prior.challenge, challenge) ? { kind: "duplicate", record: prior } : { kind: "collision" };
3553
+ if (prior !== void 0) return isDeepStrictEqual5(prior.challenge, challenge) ? { kind: "duplicate", record: prior } : { kind: "collision" };
3380
3554
  const record = {
3381
3555
  challenge,
3382
3556
  challengeHash: hash,
@@ -3429,7 +3603,7 @@ function createSqlitePublisherHandshakeStores(state) {
3429
3603
  for (const phase of phases) {
3430
3604
  const record = state.get(`publication:${phase}`, key);
3431
3605
  if (record === void 0) continue;
3432
- if (record.phase !== phase || !samePublicationIntent(record, intent) || !isDeepStrictEqual3(record.evidence, signed.evidence)) {
3606
+ if (record.phase !== phase || !samePublicationIntent(record, intent) || !isDeepStrictEqual5(record.evidence, signed.evidence)) {
3433
3607
  throw new Error("Publication evidence collision");
3434
3608
  }
3435
3609
  latest = record;
@@ -3443,12 +3617,12 @@ function createSqlitePublisherHandshakeStores(state) {
3443
3617
  state.transaction(() => {
3444
3618
  const signed = state.get("publication:signed", key);
3445
3619
  if (signed === void 0 && record.phase !== "signed") throw new Error("Publication must bind signed evidence first");
3446
- if (signed !== void 0 && (!samePublicationIntent(signed, record) || !isDeepStrictEqual3(signed.evidence, record.evidence))) {
3620
+ if (signed !== void 0 && (!samePublicationIntent(signed, record) || !isDeepStrictEqual5(signed.evidence, record.evidence))) {
3447
3621
  throw new Error("Publication intent or evidence collision");
3448
3622
  }
3449
3623
  const namespace = `publication:${record.phase}`;
3450
3624
  const prior = state.get(namespace, key);
3451
- if (prior !== void 0 && !isDeepStrictEqual3(prior, record)) throw new Error("Publication phase collision");
3625
+ if (prior !== void 0 && !isDeepStrictEqual5(prior, record)) throw new Error("Publication phase collision");
3452
3626
  if (prior === void 0) state.set(namespace, key, record);
3453
3627
  });
3454
3628
  }
@@ -3474,9 +3648,7 @@ import { hostname } from "node:os";
3474
3648
  import PATH12 from "node:path";
3475
3649
  function decode(value) {
3476
3650
  return JSON.parse(value, (_key, candidate) => {
3477
- 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))
3478
- return BigInt(candidate.$eventKitBigInt);
3479
- return candidate;
3651
+ return 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) ? BigInt(candidate.$eventKitBigInt) : candidate;
3480
3652
  });
3481
3653
  }
3482
3654
  function processExists(pid) {