@xyo-network/event-kit-node 0.1.9 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/node/filesystemCursorStore.d.ts.map +1 -1
- package/dist/node/filesystemEventKitReplayCheckpointStore.d.ts.map +1 -1
- package/dist/node/filesystemHandshakeMutationIntentStore.d.ts.map +1 -1
- package/dist/node/filesystemPublisherEndpointChallengeStore.d.ts.map +1 -1
- package/dist/node/filesystemPublisherOutbox.d.ts.map +1 -1
- package/dist/node/filesystemWakeInbox.d.ts.map +1 -1
- package/dist/node/handshake.mjs +36 -45
- package/dist/node/handshake.mjs.map +2 -2
- package/dist/node/handshakeClients.d.ts.map +1 -1
- package/dist/node/index.mjs +193 -186
- package/dist/node/index.mjs.map +3 -3
- package/dist/node/runtime/handshakeDiscovery.d.ts.map +1 -1
- package/dist/node/runtime/httpsTransport.d.ts.map +1 -1
- package/dist/node/runtime/publisherRuntime.d.ts.map +1 -1
- package/dist/node/runtime/sources.d.ts.map +1 -1
- package/dist/node/runtime.mjs +92 -78
- package/dist/node/runtime.mjs.map +2 -2
- package/dist/node/sqliteWakeQueue.d.ts.map +1 -1
- package/package.json +32 -32
package/dist/node/index.mjs
CHANGED
|
@@ -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
|
-
|
|
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;
|
|
@@ -126,7 +123,7 @@ function createFilesystemWakeQueue(options) {
|
|
|
126
123
|
} catch (error) {
|
|
127
124
|
if (!isAlreadyExists(error) && !isNotFound2(error)) throw error;
|
|
128
125
|
}
|
|
129
|
-
await
|
|
126
|
+
await unlinkIfMissing(PATH3.join(inflightDir, name));
|
|
130
127
|
}
|
|
131
128
|
return {
|
|
132
129
|
async append(wake) {
|
|
@@ -139,12 +136,12 @@ function createFilesystemWakeQueue(options) {
|
|
|
139
136
|
await link(tempPath, PATH3.join(pendingDir, name));
|
|
140
137
|
await syncDirectory(pendingDir);
|
|
141
138
|
} finally {
|
|
142
|
-
await
|
|
139
|
+
await unlinkIfMissing(tempPath);
|
|
143
140
|
}
|
|
144
141
|
},
|
|
145
142
|
async claim() {
|
|
146
143
|
await ensureDirs();
|
|
147
|
-
const names = (await readdir(pendingDir)).
|
|
144
|
+
const names = (await readdir(pendingDir)).toSorted();
|
|
148
145
|
for (const name of names) {
|
|
149
146
|
const inflightPath = PATH3.join(inflightDir, name);
|
|
150
147
|
const pendingPath = PATH3.join(pendingDir, name);
|
|
@@ -154,16 +151,16 @@ function createFilesystemWakeQueue(options) {
|
|
|
154
151
|
if (isAlreadyExists(error) || isNotFound2(error)) continue;
|
|
155
152
|
throw error;
|
|
156
153
|
}
|
|
157
|
-
await
|
|
154
|
+
await unlinkIfMissing(pendingPath);
|
|
158
155
|
const wake = await readJsonFile(inflightPath);
|
|
159
156
|
if (wake === void 0) {
|
|
160
|
-
await
|
|
157
|
+
await unlinkIfMissing(inflightPath);
|
|
161
158
|
continue;
|
|
162
159
|
}
|
|
163
160
|
return {
|
|
164
161
|
wake,
|
|
165
162
|
async ack() {
|
|
166
|
-
await
|
|
163
|
+
await unlinkIfMissing(inflightPath);
|
|
167
164
|
},
|
|
168
165
|
async release() {
|
|
169
166
|
await returnToPending(name);
|
|
@@ -206,8 +203,12 @@ function entryName(wake, sequence) {
|
|
|
206
203
|
const ordinal = String(sequence).padStart(6, "0");
|
|
207
204
|
return `${stamp}-${ordinal}-${randomBytes(6).toString("hex")}-${wake.wakeId}.json`;
|
|
208
205
|
}
|
|
209
|
-
function
|
|
210
|
-
|
|
206
|
+
async function unlinkIfMissing(path) {
|
|
207
|
+
try {
|
|
208
|
+
await unlink(path);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
if (!isNotFound2(error)) throw error;
|
|
211
|
+
}
|
|
211
212
|
}
|
|
212
213
|
function isNotFound2(error) {
|
|
213
214
|
return errorCode2(error) === "ENOENT";
|
|
@@ -230,9 +231,7 @@ function createFilesystemPublisherOutbox(options) {
|
|
|
230
231
|
if (!isNotFound3(error)) throw error;
|
|
231
232
|
}
|
|
232
233
|
},
|
|
233
|
-
async
|
|
234
|
-
return await readJsonFile(filePath);
|
|
235
|
-
},
|
|
234
|
+
load: async () => await readJsonFile(filePath),
|
|
236
235
|
async save(pending) {
|
|
237
236
|
await mkdir3(PATH4.dirname(filePath), { recursive: true });
|
|
238
237
|
const tempPath = `${filePath}.${process.pid}.${randomBytes2(6).toString("hex")}.tmp`;
|
|
@@ -271,7 +270,14 @@ function createFilesystemWakeInbox(options) {
|
|
|
271
270
|
const tempDir = PATH5.join(root, "tmp");
|
|
272
271
|
let tail = Promise.resolve();
|
|
273
272
|
function exclusive(work) {
|
|
274
|
-
const
|
|
273
|
+
const previous = tail;
|
|
274
|
+
const run = (async () => {
|
|
275
|
+
try {
|
|
276
|
+
await previous;
|
|
277
|
+
} catch {
|
|
278
|
+
}
|
|
279
|
+
return await work();
|
|
280
|
+
})();
|
|
275
281
|
tail = Promise.allSettled([run]);
|
|
276
282
|
return run;
|
|
277
283
|
}
|
|
@@ -306,44 +312,40 @@ function createFilesystemWakeInbox(options) {
|
|
|
306
312
|
return { kind: "duplicate", receipt: wake.receipt };
|
|
307
313
|
}
|
|
308
314
|
return {
|
|
309
|
-
async
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
id: digest([attempt.audience, attempt.publisher, attempt.wakeId]),
|
|
324
|
-
publisher: attempt.publisher,
|
|
325
|
-
wakeId: attempt.wakeId
|
|
326
|
-
});
|
|
327
|
-
const record = {
|
|
328
|
-
audience: attempt.audience,
|
|
329
|
-
eventHash: attempt.eventHash,
|
|
330
|
-
publisher: attempt.publisher,
|
|
331
|
-
receipt,
|
|
332
|
-
wakeId: attempt.wakeId
|
|
333
|
-
};
|
|
334
|
-
await options.queue.append(wake);
|
|
335
|
-
const claimed = await writeRecordExclusive(tempDir, wakePath(attempt), record);
|
|
336
|
-
if (!claimed) {
|
|
337
|
-
const winner = await readRecord(wakePath(attempt));
|
|
338
|
-
if (winner === void 0) throw new Error("wake record vanished during commit");
|
|
339
|
-
if (winner.eventHash !== attempt.eventHash) return { kind: "wake-id-collision" };
|
|
340
|
-
await bindToken(attempt, winner);
|
|
341
|
-
return { kind: "duplicate", receipt: winner.receipt };
|
|
342
|
-
}
|
|
343
|
-
await bindToken(attempt, record);
|
|
344
|
-
return { kind: "enqueued", receipt };
|
|
315
|
+
resolveAttempt: async (attempt) => await exclusive(async () => {
|
|
316
|
+
await ensureDirs();
|
|
317
|
+
return await matchRecorded(attempt) ?? { kind: "new" };
|
|
318
|
+
}),
|
|
319
|
+
commitAuthorized: async ({ attempt, wake }) => await exclusive(async () => {
|
|
320
|
+
await ensureDirs();
|
|
321
|
+
const recorded = await matchRecorded(attempt);
|
|
322
|
+
if (recorded !== void 0) return recorded;
|
|
323
|
+
const receipt = Object.freeze({
|
|
324
|
+
audience: attempt.audience,
|
|
325
|
+
eventHash: attempt.eventHash,
|
|
326
|
+
id: digest([attempt.audience, attempt.publisher, attempt.wakeId]),
|
|
327
|
+
publisher: attempt.publisher,
|
|
328
|
+
wakeId: attempt.wakeId
|
|
345
329
|
});
|
|
346
|
-
|
|
330
|
+
const record = {
|
|
331
|
+
audience: attempt.audience,
|
|
332
|
+
eventHash: attempt.eventHash,
|
|
333
|
+
publisher: attempt.publisher,
|
|
334
|
+
receipt,
|
|
335
|
+
wakeId: attempt.wakeId
|
|
336
|
+
};
|
|
337
|
+
await options.queue.append(wake);
|
|
338
|
+
const claimed = await writeRecordExclusive(tempDir, wakePath(attempt), record);
|
|
339
|
+
if (!claimed) {
|
|
340
|
+
const winner = await readRecord(wakePath(attempt));
|
|
341
|
+
if (winner === void 0) throw new Error("wake record vanished during commit");
|
|
342
|
+
if (winner.eventHash !== attempt.eventHash) return { kind: "wake-id-collision" };
|
|
343
|
+
await bindToken(attempt, winner);
|
|
344
|
+
return { kind: "duplicate", receipt: winner.receipt };
|
|
345
|
+
}
|
|
346
|
+
await bindToken(attempt, record);
|
|
347
|
+
return { kind: "enqueued", receipt };
|
|
348
|
+
}),
|
|
347
349
|
async pruneExpiredTokens(nowSeconds) {
|
|
348
350
|
await ensureDirs();
|
|
349
351
|
let removed = 0;
|
|
@@ -351,7 +353,7 @@ function createFilesystemWakeInbox(options) {
|
|
|
351
353
|
const path = PATH5.join(tokensDir, name);
|
|
352
354
|
const token = await readRecord(path);
|
|
353
355
|
if (token === void 0 || token.retainJwtUntil > nowSeconds) continue;
|
|
354
|
-
await
|
|
356
|
+
await unlinkIfMissing2(path);
|
|
355
357
|
removed += 1;
|
|
356
358
|
}
|
|
357
359
|
return removed;
|
|
@@ -370,7 +372,7 @@ async function writeRecordExclusive(tempDir, path, record) {
|
|
|
370
372
|
if (isAlreadyExists2(error)) return false;
|
|
371
373
|
throw error;
|
|
372
374
|
} finally {
|
|
373
|
-
await
|
|
375
|
+
await unlinkIfMissing2(tempPath);
|
|
374
376
|
}
|
|
375
377
|
}
|
|
376
378
|
async function readRecord(path) {
|
|
@@ -393,8 +395,12 @@ function digest(parts) {
|
|
|
393
395
|
function randomSuffix() {
|
|
394
396
|
return randomBytes3(8).toString("hex");
|
|
395
397
|
}
|
|
396
|
-
function
|
|
397
|
-
|
|
398
|
+
async function unlinkIfMissing2(path) {
|
|
399
|
+
try {
|
|
400
|
+
await unlink3(path);
|
|
401
|
+
} catch (error) {
|
|
402
|
+
if (!isNotFound4(error)) throw error;
|
|
403
|
+
}
|
|
398
404
|
}
|
|
399
405
|
function isNotFound4(error) {
|
|
400
406
|
return errorCode3(error) === "ENOENT";
|
|
@@ -441,7 +447,7 @@ async function replaceJsonFile(path, value, options = {}) {
|
|
|
441
447
|
await rename2(tempPath, path);
|
|
442
448
|
await syncDirectory(directory);
|
|
443
449
|
} catch (error) {
|
|
444
|
-
await
|
|
450
|
+
await unlinkIfMissing3(tempPath);
|
|
445
451
|
throw error;
|
|
446
452
|
}
|
|
447
453
|
}
|
|
@@ -459,7 +465,7 @@ async function publishJsonFile(path, value, options = {}) {
|
|
|
459
465
|
if (errorCode4(error) === "EEXIST") return false;
|
|
460
466
|
throw error;
|
|
461
467
|
} finally {
|
|
462
|
-
await
|
|
468
|
+
await unlinkIfMissing3(tempPath);
|
|
463
469
|
}
|
|
464
470
|
}
|
|
465
471
|
function suffix() {
|
|
@@ -472,13 +478,14 @@ function replaceJsonValue(_key, candidate) {
|
|
|
472
478
|
return typeof candidate === "bigint" ? { $eventKitBigInt: candidate.toString() } : candidate;
|
|
473
479
|
}
|
|
474
480
|
function reviveJson(_key, candidate) {
|
|
475
|
-
|
|
476
|
-
return BigInt(candidate.$eventKitBigInt);
|
|
477
|
-
}
|
|
478
|
-
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;
|
|
479
482
|
}
|
|
480
|
-
function
|
|
481
|
-
|
|
483
|
+
async function unlinkIfMissing3(path) {
|
|
484
|
+
try {
|
|
485
|
+
await unlink4(path);
|
|
486
|
+
} catch (error) {
|
|
487
|
+
if (errorCode4(error) !== "ENOENT") throw error;
|
|
488
|
+
}
|
|
482
489
|
}
|
|
483
490
|
function errorCode4(error) {
|
|
484
491
|
return typeof error === "object" && error !== null && "code" in error ? error.code : void 0;
|
|
@@ -494,8 +501,18 @@ function createFilesystemEventKitReplayCheckpointStore(options) {
|
|
|
494
501
|
return await readJsonFileStrict(path);
|
|
495
502
|
},
|
|
496
503
|
async save(checkpoint) {
|
|
497
|
-
const
|
|
498
|
-
|
|
504
|
+
const previous = tail;
|
|
505
|
+
const save = (async () => {
|
|
506
|
+
await previous;
|
|
507
|
+
await replaceJsonFile(path, checkpoint);
|
|
508
|
+
})();
|
|
509
|
+
tail = (async () => {
|
|
510
|
+
try {
|
|
511
|
+
await save;
|
|
512
|
+
} catch {
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
})();
|
|
499
516
|
await save;
|
|
500
517
|
}
|
|
501
518
|
};
|
|
@@ -527,7 +544,7 @@ function assertIntentShape(intent) {
|
|
|
527
544
|
if (!/^[0-9a-f]{40}$/u.test(intent.chainId)) {
|
|
528
545
|
throw new TypeError("publication chainId must be a canonical 20-byte lowercase hexadecimal chain id");
|
|
529
546
|
}
|
|
530
|
-
if (
|
|
547
|
+
if ([...intent.eventHashes, ...intent.attachmentHashes].some((hash) => !/^[0-9a-f]{64}$/u.test(hash))) {
|
|
531
548
|
throw new TypeError("publication intent hashes must be 32-byte lowercase hexadecimal");
|
|
532
549
|
}
|
|
533
550
|
}
|
|
@@ -888,9 +905,7 @@ function createFilesystemHandshakeMutationIntentStore(options) {
|
|
|
888
905
|
return intent;
|
|
889
906
|
}
|
|
890
907
|
return {
|
|
891
|
-
async
|
|
892
|
-
return await readIntent(parseHandshakeMutationIntentLookup(lookup2));
|
|
893
|
-
},
|
|
908
|
+
get: async (lookup2) => await readIntent(parseHandshakeMutationIntentLookup(lookup2)),
|
|
894
909
|
async getOrCreate(rawIntent) {
|
|
895
910
|
const proposed = await parseHandshakeMutationIntent(rawIntent);
|
|
896
911
|
const path = pathFor(proposed);
|
|
@@ -1055,7 +1070,7 @@ function createFilesystemPublisherEndpointChallengeStore(options) {
|
|
|
1055
1070
|
if (await publish(attempted)) return { kind: "started", record: attempted };
|
|
1056
1071
|
const winner = await current(challengeHash);
|
|
1057
1072
|
if (winner === void 0) throw new Error("challenge attempt winner vanished");
|
|
1058
|
-
return winner.state === "verified" ?
|
|
1073
|
+
return { kind: winner.state === "verified" ? "verified" : "already-attempted", record: winner };
|
|
1059
1074
|
},
|
|
1060
1075
|
async completeVerified(input) {
|
|
1061
1076
|
const challengeHash = HashZod3.parse(input.challengeHash);
|
|
@@ -1064,7 +1079,7 @@ function createFilesystemPublisherEndpointChallengeStore(options) {
|
|
|
1064
1079
|
const observed = await current(challengeHash);
|
|
1065
1080
|
if (observed === void 0) return { kind: "missing" };
|
|
1066
1081
|
if (observed.state === "verified") {
|
|
1067
|
-
return observed.responseHash === responseHash ?
|
|
1082
|
+
return { kind: observed.responseHash === responseHash ? "duplicate" : "collision", record: observed };
|
|
1068
1083
|
}
|
|
1069
1084
|
if (observed.state !== "attempted") return { kind: "not-attempted", record: observed };
|
|
1070
1085
|
if (!isLive(observed, input.nowSeconds)) return { kind: "expired", record: observed };
|
|
@@ -1076,11 +1091,9 @@ function createFilesystemPublisherEndpointChallengeStore(options) {
|
|
|
1076
1091
|
if (await publish(verified)) return { kind: "verified", record: verified };
|
|
1077
1092
|
const winner = await readState(challengeHash, "verified");
|
|
1078
1093
|
if (winner === void 0) throw new Error("verified challenge winner vanished");
|
|
1079
|
-
return winner.responseHash === responseHash ?
|
|
1080
|
-
},
|
|
1081
|
-
async get(rawHash) {
|
|
1082
|
-
return await current(HashZod3.parse(rawHash));
|
|
1094
|
+
return { kind: winner.responseHash === responseHash ? "duplicate" : "collision", record: winner };
|
|
1083
1095
|
},
|
|
1096
|
+
get: async (rawHash) => await current(HashZod3.parse(rawHash)),
|
|
1084
1097
|
async issue(input) {
|
|
1085
1098
|
const challenge = EndpointChallengeZod2.parse(input.challenge);
|
|
1086
1099
|
const challengeHash = HashZod3.parse(input.challengeHash);
|
|
@@ -1231,27 +1244,13 @@ function createEventKitHandshakePublicationPort(transport) {
|
|
|
1231
1244
|
const chainId = ChainIdZod2.parse(transport.session.chainId);
|
|
1232
1245
|
const port = {
|
|
1233
1246
|
chainId,
|
|
1234
|
-
async
|
|
1235
|
-
|
|
1236
|
-
},
|
|
1237
|
-
async
|
|
1238
|
-
|
|
1239
|
-
},
|
|
1240
|
-
async
|
|
1241
|
-
return await publishPublisherServiceRevocation({ ...transport, ...input });
|
|
1242
|
-
},
|
|
1243
|
-
async publishWakeGrantRevocation(input) {
|
|
1244
|
-
return await publishWakeGrantRevocation({ ...transport, ...input });
|
|
1245
|
-
},
|
|
1246
|
-
async publishWakeSubscription(input) {
|
|
1247
|
-
return await publishWakeSubscription({ ...transport, ...input });
|
|
1248
|
-
},
|
|
1249
|
-
async publishWakeSubscriptionAcceptance(input) {
|
|
1250
|
-
return await publishWakeSubscriptionAcceptance({ ...transport, ...input });
|
|
1251
|
-
},
|
|
1252
|
-
async publishWakeSubscriptionRevocation(input) {
|
|
1253
|
-
return await publishWakeSubscriptionRevocation({ ...transport, ...input });
|
|
1254
|
-
},
|
|
1247
|
+
publishPublisherEncryptionKeyRevocation: async (input) => await publishPublisherEncryptionKeyRevocation({ ...transport, ...input }),
|
|
1248
|
+
publishPublisherService: async (input) => await publishPublisherService({ ...transport, ...input }),
|
|
1249
|
+
publishPublisherServiceRevocation: async (input) => await publishPublisherServiceRevocation({ ...transport, ...input }),
|
|
1250
|
+
publishWakeGrantRevocation: async (input) => await publishWakeGrantRevocation({ ...transport, ...input }),
|
|
1251
|
+
publishWakeSubscription: async (input) => await publishWakeSubscription({ ...transport, ...input }),
|
|
1252
|
+
publishWakeSubscriptionAcceptance: async (input) => await publishWakeSubscriptionAcceptance({ ...transport, ...input }),
|
|
1253
|
+
publishWakeSubscriptionRevocation: async (input) => await publishWakeSubscriptionRevocation({ ...transport, ...input }),
|
|
1255
1254
|
async source() {
|
|
1256
1255
|
const raw = String(await transport.signer.address());
|
|
1257
1256
|
const normalized = NormalizedAddressZod3.parse(normalizeAddress(raw));
|
|
@@ -2162,9 +2161,7 @@ function createSubscriberHandshakeClient(options) {
|
|
|
2162
2161
|
});
|
|
2163
2162
|
return await publishSubscriberSubscriptionIntent(resolvedIntent.intent, resolvedIntent.disposition);
|
|
2164
2163
|
},
|
|
2165
|
-
async
|
|
2166
|
-
return await lookup2(subscriptionId);
|
|
2167
|
-
}
|
|
2164
|
+
subscriptions: async (subscriptionId) => await lookup2(subscriptionId)
|
|
2168
2165
|
};
|
|
2169
2166
|
return Object.freeze(client);
|
|
2170
2167
|
}
|
|
@@ -2177,7 +2174,7 @@ function subscriberPlaintext(service, input, maxPositionsPerWake) {
|
|
|
2177
2174
|
queueId: input.queueId
|
|
2178
2175
|
};
|
|
2179
2176
|
const source = input.source;
|
|
2180
|
-
if (
|
|
2177
|
+
if (service.events.every((event) => canonicalJson(event.source) !== canonicalJson(source))) {
|
|
2181
2178
|
throw new Error("Requested source is not advertised by the selected service");
|
|
2182
2179
|
}
|
|
2183
2180
|
return createWakeSubscriptionPlaintext({
|
|
@@ -2337,9 +2334,13 @@ function createPublisherHandshakeDiscovery(options) {
|
|
|
2337
2334
|
};
|
|
2338
2335
|
async function activeView(signal) {
|
|
2339
2336
|
signal.throwIfAborted();
|
|
2340
|
-
viewing ??=
|
|
2341
|
-
|
|
2342
|
-
|
|
2337
|
+
viewing ??= (async () => {
|
|
2338
|
+
try {
|
|
2339
|
+
return await options.client.subscriptions();
|
|
2340
|
+
} finally {
|
|
2341
|
+
viewing = void 0;
|
|
2342
|
+
}
|
|
2343
|
+
})();
|
|
2343
2344
|
const view = await viewing;
|
|
2344
2345
|
signal.throwIfAborted();
|
|
2345
2346
|
if (!view.ok || view.indexedThrough !== view.finalizedHead)
|
|
@@ -2496,19 +2497,21 @@ function createPublisherHandshakeDiscovery(options) {
|
|
|
2496
2497
|
async acceptPending(signal) {
|
|
2497
2498
|
if (accepting === void 0) {
|
|
2498
2499
|
const scope = publisherAbortScope([owner.signal, signal]);
|
|
2499
|
-
accepting =
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2500
|
+
accepting = (async () => {
|
|
2501
|
+
try {
|
|
2502
|
+
await accept(scope.signal);
|
|
2503
|
+
} finally {
|
|
2504
|
+
scope.dispose();
|
|
2505
|
+
accepting = void 0;
|
|
2506
|
+
}
|
|
2507
|
+
})();
|
|
2503
2508
|
}
|
|
2504
2509
|
await accepting;
|
|
2505
2510
|
},
|
|
2506
2511
|
async close() {
|
|
2507
2512
|
await Promise.allSettled([accepting, viewing].filter((item) => item !== void 0));
|
|
2508
2513
|
},
|
|
2509
|
-
status() {
|
|
2510
|
-
return { ...status, challengeFailures: options.state.entries("challenge-failures").reduce((sum, item) => sum + item.value, 0) };
|
|
2511
|
-
}
|
|
2514
|
+
status: () => ({ ...status, challengeFailures: options.state.entries("challenge-failures").reduce((sum, item) => sum + item.value, 0) })
|
|
2512
2515
|
};
|
|
2513
2516
|
}
|
|
2514
2517
|
|
|
@@ -2602,16 +2605,17 @@ function createEthereumFinalizedPublisherSource(options) {
|
|
|
2602
2605
|
};
|
|
2603
2606
|
async function read() {
|
|
2604
2607
|
const requests = [provider.getNetwork(), provider.getBlock(0), provider.getBlock("finalized")];
|
|
2605
|
-
|
|
2608
|
+
try {
|
|
2609
|
+
const [network, genesis, block] = await Promise.all(requests);
|
|
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
|
+
} catch (error) {
|
|
2606
2616
|
await Promise.allSettled(requests);
|
|
2607
2617
|
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
2618
|
}
|
|
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
2619
|
}
|
|
2616
2620
|
return {
|
|
2617
2621
|
source,
|
|
@@ -2620,9 +2624,13 @@ function createEthereumFinalizedPublisherSource(options) {
|
|
|
2620
2624
|
signal.throwIfAborted();
|
|
2621
2625
|
if (closed) throw new Error("Ethereum source is closed");
|
|
2622
2626
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
2623
|
-
reading ??=
|
|
2624
|
-
|
|
2625
|
-
|
|
2627
|
+
reading ??= (async () => {
|
|
2628
|
+
try {
|
|
2629
|
+
return await read();
|
|
2630
|
+
} finally {
|
|
2631
|
+
reading = void 0;
|
|
2632
|
+
}
|
|
2633
|
+
})();
|
|
2626
2634
|
try {
|
|
2627
2635
|
return await boundedPublisherOperation(reading, signal, options.requestTimeoutMs ?? 1e4);
|
|
2628
2636
|
} finally {
|
|
@@ -2653,13 +2661,12 @@ var OptionsZod = z2.strictObject({
|
|
|
2653
2661
|
allowedEndpoints: z2.array(z2.url()).min(1).max(64),
|
|
2654
2662
|
endpointHeaders: z2.array(z2.strictObject({
|
|
2655
2663
|
endpoint: z2.url(),
|
|
2656
|
-
headers: z2.strictObject({ "x-vercel-protection-bypass": z2.string().min(1).max(4096).regex(/^[\
|
|
2664
|
+
headers: z2.strictObject({ "x-vercel-protection-bypass": z2.string().min(1).max(4096).regex(/^[\u{21}-\u{7E}]+$/u) })
|
|
2657
2665
|
})).max(64).default([]),
|
|
2658
2666
|
maxResponseBytes: z2.number().int().min(1).max(1048576).default(65536),
|
|
2659
2667
|
requestTimeoutMs: z2.number().int().min(100).max(6e4).default(1e4)
|
|
2660
2668
|
});
|
|
2661
|
-
var
|
|
2662
|
-
for (const [address, prefix] of [
|
|
2669
|
+
var NON_PUBLIC_IPV4_SUBNETS = [
|
|
2663
2670
|
["0.0.0.0", 8],
|
|
2664
2671
|
["10.0.0.0", 8],
|
|
2665
2672
|
["100.64.0.0", 10],
|
|
@@ -2675,24 +2682,36 @@ for (const [address, prefix] of [
|
|
|
2675
2682
|
["203.0.113.0", 24],
|
|
2676
2683
|
["224.0.0.0", 4],
|
|
2677
2684
|
["240.0.0.0", 4]
|
|
2678
|
-
]
|
|
2679
|
-
|
|
2680
|
-
var globalIpv6 = new BlockList();
|
|
2681
|
-
globalIpv6.addSubnet("2000::", 3, "ipv6");
|
|
2682
|
-
var nonPublicIpv6 = new BlockList();
|
|
2683
|
-
for (const [address, prefix] of [
|
|
2685
|
+
];
|
|
2686
|
+
var NON_PUBLIC_IPV6_SUBNETS = [
|
|
2684
2687
|
["2001::", 23],
|
|
2685
2688
|
["2001:db8::", 32],
|
|
2686
2689
|
["2002::", 16],
|
|
2687
2690
|
["3fff::", 20]
|
|
2688
|
-
]
|
|
2689
|
-
|
|
2691
|
+
];
|
|
2692
|
+
var publisherAddressPolicy;
|
|
2693
|
+
function loadPublisherAddressPolicy() {
|
|
2694
|
+
if (publisherAddressPolicy !== void 0) return publisherAddressPolicy;
|
|
2695
|
+
const nonPublicIpv4 = new BlockList();
|
|
2696
|
+
for (const [address, prefix] of NON_PUBLIC_IPV4_SUBNETS) {
|
|
2697
|
+
nonPublicIpv4.addSubnet(address, prefix, "ipv4");
|
|
2698
|
+
}
|
|
2699
|
+
const globalIpv6 = new BlockList();
|
|
2700
|
+
globalIpv6.addSubnet("2000::", 3, "ipv6");
|
|
2701
|
+
const nonPublicIpv6 = new BlockList();
|
|
2702
|
+
for (const [address, prefix] of NON_PUBLIC_IPV6_SUBNETS) {
|
|
2703
|
+
nonPublicIpv6.addSubnet(address, prefix, "ipv6");
|
|
2704
|
+
}
|
|
2705
|
+
publisherAddressPolicy = {
|
|
2706
|
+
globalIpv6,
|
|
2707
|
+
nonPublicIpv4,
|
|
2708
|
+
nonPublicIpv6
|
|
2709
|
+
};
|
|
2710
|
+
return publisherAddressPolicy;
|
|
2711
|
+
}
|
|
2690
2712
|
function isPublicPublisherAddress(address) {
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
if (isIP(address) !== 6)
|
|
2694
|
-
return false;
|
|
2695
|
-
return globalIpv6.check(address, "ipv6") && !nonPublicIpv6.check(address, "ipv6");
|
|
2713
|
+
const policy = loadPublisherAddressPolicy();
|
|
2714
|
+
return isIP(address) === 4 ? !policy.nonPublicIpv4.check(address, "ipv4") : isIP(address) === 6 && policy.globalIpv6.check(address, "ipv6") && !policy.nonPublicIpv6.check(address, "ipv6");
|
|
2696
2715
|
}
|
|
2697
2716
|
function createPublisherHttpsTransport(input) {
|
|
2698
2717
|
const parsed = OptionsZod.safeParse(input);
|
|
@@ -2849,13 +2868,12 @@ function activationReady(status) {
|
|
|
2849
2868
|
function assertDeliveryState(record, subscription) {
|
|
2850
2869
|
if (!isDeepStrictEqual2(record.subscription, subscription))
|
|
2851
2870
|
throw new Error("Subscription revision changed without a new identity");
|
|
2852
|
-
if (!Number.isSafeInteger(record.cursor) || record.cursor < subscription.fromPosition - 1 ||
|
|
2871
|
+
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))
|
|
2853
2872
|
throw new Error("Persisted publisher delivery state is invalid");
|
|
2854
|
-
if (record.pending
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
}
|
|
2873
|
+
if (record.pending === void 0) return;
|
|
2874
|
+
const pending = WakeEnvelopeZod2.parse(record.pending);
|
|
2875
|
+
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))
|
|
2876
|
+
throw new Error("Persisted publisher outbox binding is invalid");
|
|
2859
2877
|
}
|
|
2860
2878
|
function makeEvent(subscription, fromPosition, toPosition, now, wakeId = randomBytes6(16).toString("hex")) {
|
|
2861
2879
|
return WakeEnvelopeZod2.parse({
|
|
@@ -3039,7 +3057,7 @@ async function createPersistentEventPublisherRuntime(options) {
|
|
|
3039
3057
|
sourcesHealthy = results.every((item) => item.status === "fulfilled");
|
|
3040
3058
|
for (const [index, result] of results.entries())
|
|
3041
3059
|
if (result.status === "rejected") {
|
|
3042
|
-
const key =
|
|
3060
|
+
const key = sourceReaders.keys().toArray()[index];
|
|
3043
3061
|
if (key !== void 0)
|
|
3044
3062
|
heads.set(key, new Error("Source read failed"));
|
|
3045
3063
|
}
|
|
@@ -3113,42 +3131,41 @@ async function createPersistentEventPublisherRuntime(options) {
|
|
|
3113
3131
|
async start() {
|
|
3114
3132
|
if (stop !== void 0)
|
|
3115
3133
|
throw new Error("Publisher is stopped");
|
|
3116
|
-
if (
|
|
3117
|
-
|
|
3118
|
-
running = true;
|
|
3134
|
+
if (running) {
|
|
3135
|
+
return;
|
|
3119
3136
|
}
|
|
3137
|
+
await actor.start();
|
|
3138
|
+
running = true;
|
|
3120
3139
|
},
|
|
3121
3140
|
async runOnce() {
|
|
3122
3141
|
if (stop !== void 0)
|
|
3123
3142
|
throw new Error("Publisher is stopped");
|
|
3124
3143
|
await actor.runOnce();
|
|
3125
3144
|
},
|
|
3126
|
-
stop() {
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3145
|
+
stop: () => stop ??= (async () => {
|
|
3146
|
+
abort.abort();
|
|
3147
|
+
const failures = [];
|
|
3148
|
+
try {
|
|
3149
|
+
await actor.stop();
|
|
3150
|
+
} catch (error) {
|
|
3151
|
+
failures.push(error);
|
|
3152
|
+
}
|
|
3153
|
+
try {
|
|
3154
|
+
await options.discovery.close?.();
|
|
3155
|
+
} catch (error) {
|
|
3156
|
+
failures.push(error);
|
|
3157
|
+
}
|
|
3158
|
+
for (const source of options.sources)
|
|
3135
3159
|
try {
|
|
3136
|
-
await
|
|
3160
|
+
await source.close?.();
|
|
3137
3161
|
} catch (error) {
|
|
3138
3162
|
failures.push(error);
|
|
3139
3163
|
}
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
}
|
|
3146
|
-
running = false;
|
|
3147
|
-
ready = false;
|
|
3148
|
-
if (failures.length > 0)
|
|
3149
|
-
throw new AggregateError(failures, "Publisher runtime shutdown failed");
|
|
3150
|
-
})();
|
|
3151
|
-
},
|
|
3164
|
+
running = false;
|
|
3165
|
+
ready = false;
|
|
3166
|
+
if (failures.length > 0)
|
|
3167
|
+
throw new AggregateError(failures, "Publisher runtime shutdown failed");
|
|
3168
|
+
})(),
|
|
3152
3169
|
status() {
|
|
3153
3170
|
const deliveries = state.entries("deliveries").map((item) => item.value);
|
|
3154
3171
|
return {
|
|
@@ -3282,16 +3299,14 @@ function samePublicationIntent(left, right) {
|
|
|
3282
3299
|
return left.chainId === right.chainId && left.source === right.source && left.operationId === right.operationId && isDeepStrictEqual3(left.eventHashes, right.eventHashes) && isDeepStrictEqual3(left.attachmentHashes, right.attachmentHashes);
|
|
3283
3300
|
}
|
|
3284
3301
|
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 ||
|
|
3302
|
+
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)) {
|
|
3286
3303
|
throw new Error("Invalid publication intent");
|
|
3287
3304
|
}
|
|
3288
3305
|
return JSON.stringify([intent.chainId, intent.source, intent.operationId]);
|
|
3289
3306
|
}
|
|
3290
3307
|
function createSqlitePublisherHandshakeStores(state) {
|
|
3291
3308
|
const replay = {
|
|
3292
|
-
async
|
|
3293
|
-
return state.get("replay", "checkpoint");
|
|
3294
|
-
},
|
|
3309
|
+
load: async () => state.get("replay", "checkpoint"),
|
|
3295
3310
|
async save(checkpoint) {
|
|
3296
3311
|
state.set("replay", "checkpoint", checkpoint);
|
|
3297
3312
|
}
|
|
@@ -3342,9 +3357,7 @@ function createSqlitePublisherHandshakeStores(state) {
|
|
|
3342
3357
|
const current = (hash) => state.get("challenges", HashZod5.parse(hash));
|
|
3343
3358
|
const live = (record, now) => record.challenge.issuedAt <= now && now < record.challenge.expiresAt;
|
|
3344
3359
|
const challenges = {
|
|
3345
|
-
async
|
|
3346
|
-
return current(hash);
|
|
3347
|
-
},
|
|
3360
|
+
get: async (hash) => current(hash),
|
|
3348
3361
|
async issue(input) {
|
|
3349
3362
|
const challenge = EndpointChallengeZod3.parse(input.challenge);
|
|
3350
3363
|
const hash = HashZod5.parse(input.challengeHash);
|
|
@@ -3451,9 +3464,7 @@ import { hostname } from "node:os";
|
|
|
3451
3464
|
import PATH12 from "node:path";
|
|
3452
3465
|
function decode(value) {
|
|
3453
3466
|
return JSON.parse(value, (_key, candidate) => {
|
|
3454
|
-
|
|
3455
|
-
return BigInt(candidate.$eventKitBigInt);
|
|
3456
|
-
return candidate;
|
|
3467
|
+
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;
|
|
3457
3468
|
});
|
|
3458
3469
|
}
|
|
3459
3470
|
function processExists(pid) {
|
|
@@ -3638,12 +3649,8 @@ async function createSqliteWakeQueue(options) {
|
|
|
3638
3649
|
close() {
|
|
3639
3650
|
database.close();
|
|
3640
3651
|
},
|
|
3641
|
-
async
|
|
3642
|
-
|
|
3643
|
-
},
|
|
3644
|
-
async recoverInflight() {
|
|
3645
|
-
return Number(recoverAll.run().changes);
|
|
3646
|
-
}
|
|
3652
|
+
pendingCount: async () => Number(countPending.get().total),
|
|
3653
|
+
recoverInflight: async () => Number(recoverAll.run().changes)
|
|
3647
3654
|
};
|
|
3648
3655
|
}
|
|
3649
3656
|
export {
|