@xyo-network/event-kit-xl1 0.0.1 → 0.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.
- package/README.md +77 -2
- package/dist/neutral/finalizedStatementPublication.d.ts +66 -0
- package/dist/neutral/finalizedStatementPublication.d.ts.map +1 -0
- package/dist/neutral/handshakePublication.d.ts +91 -0
- package/dist/neutral/handshakePublication.d.ts.map +1 -0
- package/dist/neutral/index.d.ts +6 -0
- package/dist/neutral/index.d.ts.map +1 -1
- package/dist/neutral/index.mjs +851 -1
- package/dist/neutral/index.mjs.map +4 -4
- package/dist/neutral/memoryFinalizedStatementPublicationJournal.d.ts +5 -0
- package/dist/neutral/memoryFinalizedStatementPublicationJournal.d.ts.map +1 -0
- package/dist/neutral/networkSession.d.ts +42 -0
- package/dist/neutral/networkSession.d.ts.map +1 -0
- package/package.json +24 -9
package/dist/neutral/index.mjs
CHANGED
|
@@ -16,7 +16,857 @@ function createXl1FinalizedHeadSource(options) {
|
|
|
16
16
|
}
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
|
+
|
|
20
|
+
// src/finalizedStatementPublication.ts
|
|
21
|
+
import {
|
|
22
|
+
WakeSubscriptionAcceptanceSchema,
|
|
23
|
+
WakeSubscriptionAcceptanceZod
|
|
24
|
+
} from "@xyo-network/event-kit-schemas";
|
|
25
|
+
import { PayloadBuilder } from "@xyo-network/sdk";
|
|
26
|
+
import {
|
|
27
|
+
broadcastXl1Transaction,
|
|
28
|
+
buildXl1Transaction,
|
|
29
|
+
createSignedXl1TransactionEvidence,
|
|
30
|
+
observeXl1TransactionFinality,
|
|
31
|
+
observeXl1TransactionInclusion,
|
|
32
|
+
signXl1Transaction,
|
|
33
|
+
verifyXl1TransactionContent,
|
|
34
|
+
writeXl1TransactionContent
|
|
35
|
+
} from "@xyo-network/xl1-sdk";
|
|
36
|
+
import { insertVerified, prepareStatements } from "@xyo-network/xl1-statement-graph-sdk";
|
|
37
|
+
|
|
38
|
+
// src/memoryFinalizedStatementPublicationJournal.ts
|
|
39
|
+
var PublicationPhases = [
|
|
40
|
+
"signed",
|
|
41
|
+
"content-written",
|
|
42
|
+
"content-verified",
|
|
43
|
+
"broadcast",
|
|
44
|
+
"included",
|
|
45
|
+
"finalized"
|
|
46
|
+
];
|
|
47
|
+
function sameStrings(left, right) {
|
|
48
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
49
|
+
}
|
|
50
|
+
function sameValue(left, right) {
|
|
51
|
+
if (Object.is(left, right)) return true;
|
|
52
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
53
|
+
return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => sameValue(value, right[index]));
|
|
54
|
+
}
|
|
55
|
+
if (typeof left !== "object" || left === null || typeof right !== "object" || right === null) return false;
|
|
56
|
+
const leftRecord = left;
|
|
57
|
+
const rightRecord = right;
|
|
58
|
+
const leftKeys = Object.keys(leftRecord).sort();
|
|
59
|
+
const rightKeys = Object.keys(rightRecord).sort();
|
|
60
|
+
return sameStrings(leftKeys, rightKeys) && leftKeys.every((key) => sameValue(leftRecord[key], rightRecord[key]));
|
|
61
|
+
}
|
|
62
|
+
function sameIntent(left, right) {
|
|
63
|
+
return left.operationId === right.operationId && left.source === right.source && left.chainId === right.chainId && sameStrings(left.eventHashes, right.eventHashes) && sameStrings(left.attachmentHashes, right.attachmentHashes);
|
|
64
|
+
}
|
|
65
|
+
function publicationKey(intent) {
|
|
66
|
+
return `${intent.chainId}\0${intent.source}\0${intent.operationId}`;
|
|
67
|
+
}
|
|
68
|
+
function intentFromRecord(record2) {
|
|
69
|
+
return {
|
|
70
|
+
attachmentHashes: record2.attachmentHashes,
|
|
71
|
+
chainId: record2.chainId,
|
|
72
|
+
eventHashes: record2.eventHashes,
|
|
73
|
+
operationId: record2.operationId,
|
|
74
|
+
source: record2.source
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function createMemoryFinalizedStatementPublicationJournal() {
|
|
78
|
+
const records = [];
|
|
79
|
+
const publications = /* @__PURE__ */ new Map();
|
|
80
|
+
function phasesForExactIntent(intent) {
|
|
81
|
+
const phases = publications.get(publicationKey(intent));
|
|
82
|
+
const signed = phases?.get("signed");
|
|
83
|
+
if (signed !== void 0 && !sameIntent(intentFromRecord(signed), intent)) {
|
|
84
|
+
throw new Error("publication journal intent collision");
|
|
85
|
+
}
|
|
86
|
+
return phases;
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
records,
|
|
90
|
+
async load(intent) {
|
|
91
|
+
const phases = phasesForExactIntent(intent);
|
|
92
|
+
if (phases === void 0) return void 0;
|
|
93
|
+
for (const phase of PublicationPhases.toReversed()) {
|
|
94
|
+
const candidate = phases.get(phase);
|
|
95
|
+
if (candidate !== void 0) return structuredClone(candidate);
|
|
96
|
+
}
|
|
97
|
+
throw new Error("publication journal has an intent without signed evidence");
|
|
98
|
+
},
|
|
99
|
+
async save(record2) {
|
|
100
|
+
let phases = phasesForExactIntent(record2);
|
|
101
|
+
if (phases === void 0) {
|
|
102
|
+
if (record2.phase !== "signed") throw new Error("publication journal must bind signed evidence first");
|
|
103
|
+
phases = /* @__PURE__ */ new Map();
|
|
104
|
+
publications.set(publicationKey(record2), phases);
|
|
105
|
+
}
|
|
106
|
+
const signed = phases.get("signed");
|
|
107
|
+
if (signed !== void 0 && !sameValue(signed.evidence, record2.evidence)) {
|
|
108
|
+
throw new Error("publication journal evidence collision");
|
|
109
|
+
}
|
|
110
|
+
const existing = phases.get(record2.phase);
|
|
111
|
+
if (existing !== void 0) {
|
|
112
|
+
if (!sameValue(existing, record2)) throw new Error(`publication journal collision at ${record2.phase}`);
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const durable = structuredClone(record2);
|
|
116
|
+
phases.set(record2.phase, durable);
|
|
117
|
+
records.push(structuredClone(durable));
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/finalizedStatementPublication.ts
|
|
123
|
+
function positiveInteger(value, fallback, name) {
|
|
124
|
+
const selected = value ?? fallback;
|
|
125
|
+
if (!Number.isSafeInteger(selected) || selected < 1) throw new TypeError(`${name} must be a positive safe integer`);
|
|
126
|
+
return selected;
|
|
127
|
+
}
|
|
128
|
+
function nonnegativeInteger(value, fallback, name) {
|
|
129
|
+
const selected = value ?? fallback;
|
|
130
|
+
if (!Number.isSafeInteger(selected) || selected < 0) throw new TypeError(`${name} must be a nonnegative safe integer`);
|
|
131
|
+
return selected;
|
|
132
|
+
}
|
|
133
|
+
function safeBlockNumber(value, name) {
|
|
134
|
+
if (typeof value === "bigint") {
|
|
135
|
+
if (value < 0n || value > BigInt(Number.MAX_SAFE_INTEGER)) {
|
|
136
|
+
throw new TypeError(`${name} must be a nonnegative safe integer`);
|
|
137
|
+
}
|
|
138
|
+
return Number(value);
|
|
139
|
+
}
|
|
140
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
141
|
+
throw new TypeError(`${name} must be a nonnegative safe integer`);
|
|
142
|
+
}
|
|
143
|
+
return value;
|
|
144
|
+
}
|
|
145
|
+
function validateInclusion(inclusion, name) {
|
|
146
|
+
const blockNumber = safeBlockNumber(inclusion.blockNumber, `${name}.blockNumber`);
|
|
147
|
+
if (!Number.isSafeInteger(inclusion.transactionIndex) || inclusion.transactionIndex < 0) {
|
|
148
|
+
throw new TypeError(`${name}.transactionIndex must be a nonnegative safe integer`);
|
|
149
|
+
}
|
|
150
|
+
return blockNumber;
|
|
151
|
+
}
|
|
152
|
+
function assertSameInclusion(inclusion, inclusionBlock, finalized, finalizedBlock) {
|
|
153
|
+
if (finalized.blockHash !== inclusion.blockHash || finalizedBlock !== inclusionBlock || finalized.transactionHash !== inclusion.transactionHash || finalized.transactionIndex !== inclusion.transactionIndex) {
|
|
154
|
+
throw new Error("Finality evidence does not match the observed transaction inclusion");
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function sameStrings2(left, right) {
|
|
158
|
+
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
159
|
+
}
|
|
160
|
+
var PublicationPhases2 = [
|
|
161
|
+
"signed",
|
|
162
|
+
"content-written",
|
|
163
|
+
"content-verified",
|
|
164
|
+
"broadcast",
|
|
165
|
+
"included",
|
|
166
|
+
"finalized"
|
|
167
|
+
];
|
|
168
|
+
var PublicationPhaseSet = new Set(PublicationPhases2);
|
|
169
|
+
function publicationOperationId(value) {
|
|
170
|
+
if (typeof value !== "string" || value.length === 0 || value.length > 256) {
|
|
171
|
+
throw new TypeError("operationId must be a nonempty string of at most 256 characters");
|
|
172
|
+
}
|
|
173
|
+
return value;
|
|
174
|
+
}
|
|
175
|
+
function sameValue2(left, right) {
|
|
176
|
+
if (Object.is(left, right)) return true;
|
|
177
|
+
if (Array.isArray(left) || Array.isArray(right)) {
|
|
178
|
+
return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((value, index) => sameValue2(value, right[index]));
|
|
179
|
+
}
|
|
180
|
+
if (typeof left !== "object" || left === null || typeof right !== "object" || right === null) return false;
|
|
181
|
+
const leftRecord = left;
|
|
182
|
+
const rightRecord = right;
|
|
183
|
+
const leftKeys = Object.keys(leftRecord).sort();
|
|
184
|
+
const rightKeys = Object.keys(rightRecord).sort();
|
|
185
|
+
return sameStrings2(leftKeys, rightKeys) && leftKeys.every((key) => sameValue2(leftRecord[key], rightRecord[key]));
|
|
186
|
+
}
|
|
187
|
+
function sameIntent2(left, right) {
|
|
188
|
+
return left.operationId === right.operationId && left.source === right.source && left.chainId === right.chainId && sameStrings2(left.eventHashes, right.eventHashes) && sameStrings2(left.attachmentHashes, right.attachmentHashes);
|
|
189
|
+
}
|
|
190
|
+
function intentFromRecord2(record2) {
|
|
191
|
+
return {
|
|
192
|
+
attachmentHashes: record2.attachmentHashes,
|
|
193
|
+
chainId: record2.chainId,
|
|
194
|
+
eventHashes: record2.eventHashes,
|
|
195
|
+
operationId: record2.operationId,
|
|
196
|
+
source: record2.source
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
function acceptanceAttachmentHashes(statements) {
|
|
200
|
+
const hashes = /* @__PURE__ */ new Set();
|
|
201
|
+
for (const statement of statements) {
|
|
202
|
+
for (const object of statement.objects) {
|
|
203
|
+
if (object.schema !== WakeSubscriptionAcceptanceSchema) continue;
|
|
204
|
+
const acceptance = WakeSubscriptionAcceptanceZod.safeParse(object);
|
|
205
|
+
if (!acceptance.success) throw new TypeError("Claimed wake subscription acceptance is malformed");
|
|
206
|
+
hashes.add(acceptance.data.challenge);
|
|
207
|
+
hashes.add(acceptance.data.response);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return hashes;
|
|
211
|
+
}
|
|
212
|
+
async function assertExactAcceptanceAttachments(statements, attachments) {
|
|
213
|
+
const missing = acceptanceAttachmentHashes(statements);
|
|
214
|
+
const supplied = /* @__PURE__ */ new Set();
|
|
215
|
+
const hashes = [];
|
|
216
|
+
for (const attachment of attachments) {
|
|
217
|
+
const hash = String(await PayloadBuilder.dataHash(attachment));
|
|
218
|
+
if (supplied.has(hash)) {
|
|
219
|
+
throw new Error(`Duplicate publication attachment ${hash}`);
|
|
220
|
+
}
|
|
221
|
+
if (!missing.delete(hash)) {
|
|
222
|
+
throw new Error(`Publication attachment ${hash} is not referenced by a wake subscription acceptance`);
|
|
223
|
+
}
|
|
224
|
+
supplied.add(hash);
|
|
225
|
+
hashes.push(hash);
|
|
226
|
+
}
|
|
227
|
+
if (missing.size > 0) {
|
|
228
|
+
throw new Error(`Wake subscription acceptance is missing publication attachment ${[...missing].join(", ")}`);
|
|
229
|
+
}
|
|
230
|
+
return hashes;
|
|
231
|
+
}
|
|
232
|
+
function signingIntent(transaction) {
|
|
233
|
+
const intent = structuredClone(transaction);
|
|
234
|
+
intent.$signatures.splice(0);
|
|
235
|
+
intent.addresses.splice(0);
|
|
236
|
+
intent.previous_hashes.splice(0);
|
|
237
|
+
return intent;
|
|
238
|
+
}
|
|
239
|
+
async function assertSignedPublicationIntent(unsigned, evidence, signerAddress) {
|
|
240
|
+
const signed = evidence.transaction;
|
|
241
|
+
if (String(evidence.from) !== signerAddress || String(signed[0].from) !== signerAddress) {
|
|
242
|
+
throw new Error("Signed transaction from address does not match the requested signer");
|
|
243
|
+
}
|
|
244
|
+
if (signed[0].addresses.length !== 1 || String(signed[0].addresses[0]) !== signerAddress) {
|
|
245
|
+
throw new Error("Signed transaction witness does not contain exactly the requested signer");
|
|
246
|
+
}
|
|
247
|
+
const [unsignedIntentHash, signedIntentHash, unsignedPayloadHashes, signedPayloadHashes] = await Promise.all([
|
|
248
|
+
PayloadBuilder.hash(signingIntent(unsigned[0])),
|
|
249
|
+
PayloadBuilder.hash(signingIntent(signed[0])),
|
|
250
|
+
PayloadBuilder.hashes([...unsigned[1]]),
|
|
251
|
+
PayloadBuilder.hashes([...signed[1]])
|
|
252
|
+
]);
|
|
253
|
+
if (unsignedIntentHash !== signedIntentHash || !sameStrings2(unsignedPayloadHashes, signedPayloadHashes)) {
|
|
254
|
+
throw new Error("Signed transaction content differs from the transaction submitted for signing");
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
async function assertPreparedPublicationIntent(prepared, evidence, intent) {
|
|
258
|
+
const signed = evidence.transaction;
|
|
259
|
+
if (String(evidence.from) !== intent.source || String(signed[0].from) !== intent.source) {
|
|
260
|
+
throw new Error("Signed transaction from address does not match the requested signer");
|
|
261
|
+
}
|
|
262
|
+
if (signed[0].addresses.length !== 1 || String(signed[0].addresses[0]) !== intent.source) {
|
|
263
|
+
throw new Error("Signed transaction witness does not contain exactly the requested signer");
|
|
264
|
+
}
|
|
265
|
+
if (String(evidence.chainId) !== intent.chainId || String(signed[0].chain) !== intent.chainId) {
|
|
266
|
+
throw new Error("Signed transaction chain does not match the requested publication chain");
|
|
267
|
+
}
|
|
268
|
+
const [expectedPayloadHashes, signedPayloadHashes, elevatedHashes] = await Promise.all([
|
|
269
|
+
PayloadBuilder.hashes([...prepared.transactionPayloads]),
|
|
270
|
+
PayloadBuilder.hashes([...signed[1]]),
|
|
271
|
+
PayloadBuilder.hashes([...prepared.onChainPayloads])
|
|
272
|
+
]);
|
|
273
|
+
const expectedSchemas = prepared.transactionPayloads.map((payload) => String(payload.schema));
|
|
274
|
+
const expectedScript = elevatedHashes.map((hash) => `elevate|${hash}`);
|
|
275
|
+
if (!sameStrings2(expectedPayloadHashes, signedPayloadHashes) || !sameStrings2(expectedPayloadHashes, signed[0].payload_hashes) || !sameStrings2(expectedSchemas, signed[0].payload_schemas) || !sameStrings2(expectedScript, signed[0].script ?? [])) {
|
|
276
|
+
throw new Error("Signed transaction content differs from the requested publication intent");
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
async function assertResumableEvidence(evidence) {
|
|
280
|
+
const reconstructed = await createSignedXl1TransactionEvidence(evidence.transaction);
|
|
281
|
+
if (!sameValue2(reconstructed, evidence)) {
|
|
282
|
+
throw new Error("Publication journal evidence does not match its signed transaction");
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
async function assertPublicationRecord(record2, intent, prepared) {
|
|
286
|
+
if (typeof record2 !== "object" || record2 === null) {
|
|
287
|
+
throw new Error("Publication journal returned a malformed record");
|
|
288
|
+
}
|
|
289
|
+
if (!PublicationPhaseSet.has(record2.phase)) throw new Error("Publication journal returned an unknown phase");
|
|
290
|
+
if (!sameIntent2(intentFromRecord2(record2), intent)) {
|
|
291
|
+
throw new Error("Publication journal returned a different publication intent");
|
|
292
|
+
}
|
|
293
|
+
await assertResumableEvidence(record2.evidence);
|
|
294
|
+
await assertPreparedPublicationIntent(prepared, record2.evidence, intent);
|
|
295
|
+
const requiresInclusion = record2.phase === "included" || record2.phase === "finalized";
|
|
296
|
+
if (requiresInclusion !== (record2.inclusion !== void 0)) {
|
|
297
|
+
throw new Error(`Publication journal ${record2.phase} record has invalid inclusion evidence`);
|
|
298
|
+
}
|
|
299
|
+
if (record2.inclusion !== void 0) {
|
|
300
|
+
validateInclusion(record2.inclusion, record2.phase);
|
|
301
|
+
if (record2.inclusion.transactionHash !== record2.evidence.transactionHash) {
|
|
302
|
+
throw new Error("Publication journal inclusion does not identify the signed transaction");
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
async function defaultWait(delayMs) {
|
|
307
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
308
|
+
}
|
|
309
|
+
async function poll(operation, options, label) {
|
|
310
|
+
const attempts = positiveInteger(options?.attempts, 120, "polling.attempts");
|
|
311
|
+
const delayMs = nonnegativeInteger(options?.delayMs, 500, "polling.delayMs");
|
|
312
|
+
const wait = options?.wait ?? defaultWait;
|
|
313
|
+
for (let attempt = 1; attempt <= attempts; attempt += 1) {
|
|
314
|
+
const result = await operation();
|
|
315
|
+
if (result !== null) return result;
|
|
316
|
+
if (attempt < attempts) await wait(delayMs);
|
|
317
|
+
}
|
|
318
|
+
throw new Error(`${label} was not observed after ${attempts} attempts`);
|
|
319
|
+
}
|
|
320
|
+
async function record(journal, phase, evidence, intent, inclusion) {
|
|
321
|
+
const result = {
|
|
322
|
+
...intent,
|
|
323
|
+
evidence,
|
|
324
|
+
...inclusion === void 0 ? {} : { inclusion },
|
|
325
|
+
phase
|
|
326
|
+
};
|
|
327
|
+
await journal.save(result);
|
|
328
|
+
return result;
|
|
329
|
+
}
|
|
330
|
+
function finalizedResult(record2) {
|
|
331
|
+
if (record2.phase !== "finalized" || record2.inclusion === void 0) {
|
|
332
|
+
throw new Error("Cannot construct finalized publication result from an incomplete record");
|
|
333
|
+
}
|
|
334
|
+
const finalizedBlock = validateInclusion(record2.inclusion, "finality");
|
|
335
|
+
if (record2.inclusion.transactionHash !== record2.evidence.transactionHash) throw new Error("Inclusion does not identify signed publication");
|
|
336
|
+
return {
|
|
337
|
+
attachmentHashes: record2.attachmentHashes,
|
|
338
|
+
eventHashes: record2.eventHashes,
|
|
339
|
+
evidence: record2.evidence,
|
|
340
|
+
finalizedBlock,
|
|
341
|
+
inclusion: record2.inclusion,
|
|
342
|
+
transactionHash: record2.evidence.transactionHash
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
async function bindSignedPublication(options, prepared, intent) {
|
|
346
|
+
const pinnedSigner = {
|
|
347
|
+
address: () => intent.source,
|
|
348
|
+
signTransaction: (transaction) => options.signer.signTransaction(transaction)
|
|
349
|
+
};
|
|
350
|
+
const pinnedViewer = {
|
|
351
|
+
chainId: () => intent.chainId,
|
|
352
|
+
currentBlockNumber: () => options.viewer.currentBlockNumber()
|
|
353
|
+
};
|
|
354
|
+
const unsigned = await buildXl1Transaction(
|
|
355
|
+
pinnedViewer,
|
|
356
|
+
pinnedSigner,
|
|
357
|
+
// Statement Graph 0.5 guarantees this partition contains only the Claim
|
|
358
|
+
// events from StatementToPublish. Its published PreparedStatements type is
|
|
359
|
+
// broader (`Payload[]`) than that runtime contract, while XL1 correctly
|
|
360
|
+
// requires the narrower elevated-payload union.
|
|
361
|
+
prepared.onChainPayloads,
|
|
362
|
+
prepared.offChainPayloads,
|
|
363
|
+
options.broadcast
|
|
364
|
+
);
|
|
365
|
+
const evidence = await signXl1Transaction(pinnedSigner, unsigned);
|
|
366
|
+
await assertSignedPublicationIntent(unsigned, evidence, intent.source);
|
|
367
|
+
await assertPreparedPublicationIntent(prepared, evidence, intent);
|
|
368
|
+
return await record(options.journal, "signed", evidence, intent);
|
|
369
|
+
}
|
|
370
|
+
async function exactPublicationInclusion(options, evidence) {
|
|
371
|
+
const inclusion = await observeXl1TransactionInclusion(options.viewer.block, evidence.transactionHash);
|
|
372
|
+
if (inclusion === null) return null;
|
|
373
|
+
validateInclusion(inclusion, "inclusion");
|
|
374
|
+
if (inclusion.transactionHash !== evidence.transactionHash) throw new Error("Inclusion does not identify signed publication");
|
|
375
|
+
return inclusion;
|
|
376
|
+
}
|
|
377
|
+
async function advanceBroadcast(options, intent, publication, resumed) {
|
|
378
|
+
const evidence = publication.evidence;
|
|
379
|
+
if (resumed) {
|
|
380
|
+
const inclusion = await exactPublicationInclusion(options, evidence);
|
|
381
|
+
if (inclusion !== null) return await record(options.journal, "included", evidence, intent, inclusion);
|
|
382
|
+
}
|
|
383
|
+
try {
|
|
384
|
+
await broadcastXl1Transaction(options.runner, evidence);
|
|
385
|
+
} catch (error) {
|
|
386
|
+
if (!resumed) throw error;
|
|
387
|
+
const inclusion = await exactPublicationInclusion(options, evidence);
|
|
388
|
+
if (inclusion === null) throw error;
|
|
389
|
+
return await record(options.journal, "included", evidence, intent, inclusion);
|
|
390
|
+
}
|
|
391
|
+
return publication.phase === "content-verified" ? await record(options.journal, "broadcast", evidence, intent) : publication;
|
|
392
|
+
}
|
|
393
|
+
async function completePublication(options, intent, initial, resumedFromBroadcastBoundary) {
|
|
394
|
+
let publication = initial;
|
|
395
|
+
const evidence = publication.evidence;
|
|
396
|
+
if (publication.phase === "signed") {
|
|
397
|
+
await writeXl1TransactionContent(options.bodyWriter, evidence);
|
|
398
|
+
publication = await record(options.journal, "content-written", evidence, intent);
|
|
399
|
+
}
|
|
400
|
+
if (publication.phase === "content-written") {
|
|
401
|
+
await verifyXl1TransactionContent(options.bodyReader, evidence);
|
|
402
|
+
publication = await record(options.journal, "content-verified", evidence, intent);
|
|
403
|
+
}
|
|
404
|
+
if (publication.phase === "content-verified" || publication.phase === "broadcast") {
|
|
405
|
+
publication = await advanceBroadcast(options, intent, publication, resumedFromBroadcastBoundary);
|
|
406
|
+
}
|
|
407
|
+
if (publication.phase === "broadcast") {
|
|
408
|
+
const inclusion = await poll(
|
|
409
|
+
async () => await observeXl1TransactionInclusion(options.viewer.block, evidence.transactionHash),
|
|
410
|
+
options.polling,
|
|
411
|
+
`transaction ${evidence.transactionHash} inclusion`
|
|
412
|
+
);
|
|
413
|
+
validateInclusion(inclusion, "inclusion");
|
|
414
|
+
if (inclusion.transactionHash !== evidence.transactionHash) throw new Error("Inclusion does not identify signed publication");
|
|
415
|
+
publication = await record(options.journal, "included", evidence, intent, inclusion);
|
|
416
|
+
}
|
|
417
|
+
if (publication.phase === "included") {
|
|
418
|
+
const inclusion = publication.inclusion;
|
|
419
|
+
if (inclusion === void 0) throw new Error("Included publication is missing inclusion evidence");
|
|
420
|
+
const inclusionBlock = validateInclusion(inclusion, "inclusion");
|
|
421
|
+
const finalized = await poll(
|
|
422
|
+
async () => await observeXl1TransactionFinality(options.viewer.block, inclusion),
|
|
423
|
+
options.polling,
|
|
424
|
+
`transaction ${evidence.transactionHash} finality`
|
|
425
|
+
);
|
|
426
|
+
const finalizedBlock = validateInclusion(finalized, "finality");
|
|
427
|
+
assertSameInclusion(inclusion, inclusionBlock, finalized, finalizedBlock);
|
|
428
|
+
publication = await record(options.journal, "finalized", evidence, intent, finalized);
|
|
429
|
+
}
|
|
430
|
+
return publication;
|
|
431
|
+
}
|
|
432
|
+
async function publishFinalizedStatements(options) {
|
|
433
|
+
const chainId = String(await options.viewer.chainId());
|
|
434
|
+
if (options.expectedChainId !== void 0 && chainId !== options.expectedChainId) {
|
|
435
|
+
throw new Error("XL1 viewer chain does not match the expected publication chain");
|
|
436
|
+
}
|
|
437
|
+
const signerAddress = String(await options.signer.address());
|
|
438
|
+
if (options.expectedSource !== void 0 && signerAddress !== options.expectedSource) {
|
|
439
|
+
throw new Error("XL1 signer does not match the expected publication source");
|
|
440
|
+
}
|
|
441
|
+
const prepared = await prepareStatements(options.statements, [signerAddress]);
|
|
442
|
+
const attachmentHashes = await assertExactAcceptanceAttachments(
|
|
443
|
+
options.statements,
|
|
444
|
+
options.attachments ?? []
|
|
445
|
+
);
|
|
446
|
+
const intent = {
|
|
447
|
+
attachmentHashes,
|
|
448
|
+
chainId,
|
|
449
|
+
eventHashes: prepared.eventHashes,
|
|
450
|
+
operationId: publicationOperationId(options.operationId),
|
|
451
|
+
source: signerAddress
|
|
452
|
+
};
|
|
453
|
+
let publication = await options.journal.load(intent);
|
|
454
|
+
const resumedFromBroadcastBoundary = publication?.phase === "content-verified" || publication?.phase === "broadcast";
|
|
455
|
+
if (publication !== void 0) {
|
|
456
|
+
await assertPublicationRecord(publication, intent, prepared);
|
|
457
|
+
if (publication.phase === "finalized") return finalizedResult(publication);
|
|
458
|
+
}
|
|
459
|
+
const verifiedAttachmentHashes = await insertVerified(
|
|
460
|
+
{
|
|
461
|
+
get: async (hashes) => await options.bodyReader.get(hashes),
|
|
462
|
+
insert: async (payloads) => await options.bodyWriter.insert(payloads)
|
|
463
|
+
},
|
|
464
|
+
options.attachments ?? []
|
|
465
|
+
);
|
|
466
|
+
if (!sameStrings2(attachmentHashes, verifiedAttachmentHashes)) {
|
|
467
|
+
throw new Error("Verified publication attachment hashes differ from the supplied attachment bodies");
|
|
468
|
+
}
|
|
469
|
+
publication ??= await bindSignedPublication(options, prepared, intent);
|
|
470
|
+
publication = await completePublication(options, intent, publication, resumedFromBroadcastBoundary);
|
|
471
|
+
return finalizedResult(publication);
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// src/handshakePublication.ts
|
|
475
|
+
import {
|
|
476
|
+
EncryptedWakeSubscriptionZod,
|
|
477
|
+
EndpointChallengeResponseZod,
|
|
478
|
+
EndpointChallengeZod,
|
|
479
|
+
normalizeAddress,
|
|
480
|
+
NormalizedAddressZod,
|
|
481
|
+
PublisherEncryptionKeyRevocationZod,
|
|
482
|
+
PublisherEncryptionKeyZod,
|
|
483
|
+
PublisherServiceRevocationZod,
|
|
484
|
+
PublisherServiceZod,
|
|
485
|
+
WakeGrantObjectZod,
|
|
486
|
+
WakeGrantRevocationZod,
|
|
487
|
+
WakeSubscriptionAcceptanceRevocationZod,
|
|
488
|
+
WakeSubscriptionAcceptanceZod as WakeSubscriptionAcceptanceZod2,
|
|
489
|
+
WakeSubscriptionRevocationZod
|
|
490
|
+
} from "@xyo-network/event-kit-schemas";
|
|
491
|
+
import { PayloadBuilder as PayloadBuilder2 } from "@xyo-network/sdk";
|
|
492
|
+
import { buildClaim } from "@xyo-network/xl1-statement-graph-sdk";
|
|
493
|
+
|
|
494
|
+
// src/networkSession.ts
|
|
495
|
+
import { ChainIdZod } from "@xyo-network/event-kit-schemas";
|
|
496
|
+
import {
|
|
497
|
+
DefaultNetworks,
|
|
498
|
+
MainNetwork,
|
|
499
|
+
NetworkDataLakeUrls,
|
|
500
|
+
SequenceNetwork
|
|
501
|
+
} from "@xyo-network/xl1-sdk";
|
|
502
|
+
var EVENT_KIT_NETWORK_IDS = ["local", "sequence", "mainnet"];
|
|
503
|
+
function configuredNetwork(network) {
|
|
504
|
+
const found = DefaultNetworks.find((candidate) => candidate.id === network);
|
|
505
|
+
if (found === void 0) {
|
|
506
|
+
throw new Error(`XL1 SDK does not define the Event Kit network ${network}`);
|
|
507
|
+
}
|
|
508
|
+
return found;
|
|
509
|
+
}
|
|
510
|
+
function parseNetworkId(value) {
|
|
511
|
+
if (EVENT_KIT_NETWORK_IDS.includes(value)) return value;
|
|
512
|
+
throw new TypeError(`network must be one of ${EVENT_KIT_NETWORK_IDS.join("|")}`);
|
|
513
|
+
}
|
|
514
|
+
function endpoint(value, name) {
|
|
515
|
+
const trimmed = value.trim();
|
|
516
|
+
let parsed;
|
|
517
|
+
try {
|
|
518
|
+
parsed = new URL(trimmed);
|
|
519
|
+
} catch {
|
|
520
|
+
throw new TypeError(`${name} must be an absolute HTTP(S) URL`);
|
|
521
|
+
}
|
|
522
|
+
if (!["http:", "https:"].includes(parsed.protocol) || parsed.username !== "" || parsed.password !== "" || parsed.hash !== "") {
|
|
523
|
+
throw new TypeError(`${name} must be an absolute HTTP(S) URL without userinfo or a fragment`);
|
|
524
|
+
}
|
|
525
|
+
return parsed.href;
|
|
526
|
+
}
|
|
527
|
+
function defaultRpcUrl(network) {
|
|
528
|
+
return `${network.url.replace(/\/$/u, "")}/rpc`;
|
|
529
|
+
}
|
|
530
|
+
function sdkChainId(network) {
|
|
531
|
+
return network.chain === void 0 ? void 0 : ChainIdZod.parse(String(network.chain).toLowerCase());
|
|
532
|
+
}
|
|
533
|
+
function publicNetworkForChain(chainId) {
|
|
534
|
+
if (chainId === sdkChainId(MainNetwork)) return "mainnet";
|
|
535
|
+
if (chainId === sdkChainId(SequenceNetwork)) return "sequence";
|
|
536
|
+
return void 0;
|
|
537
|
+
}
|
|
538
|
+
function assertResolutionChain(resolution, chainId) {
|
|
539
|
+
const publicNetwork = publicNetworkForChain(chainId);
|
|
540
|
+
if (publicNetwork !== void 0 && publicNetwork !== resolution.network) {
|
|
541
|
+
throw new Error(`Connected chain ${chainId} is ${publicNetwork}, not ${resolution.network}`);
|
|
542
|
+
}
|
|
543
|
+
if (resolution.expectedChainId !== void 0 && resolution.expectedChainId !== chainId) {
|
|
544
|
+
throw new Error(
|
|
545
|
+
`Connected chain ID ${chainId} does not match ${resolution.network} chain ID ${resolution.expectedChainId}`
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
async function observedChainId(viewer) {
|
|
550
|
+
return ChainIdZod.parse(String(await viewer.chainId()).toLowerCase());
|
|
551
|
+
}
|
|
552
|
+
function resolveEventKitNetwork(options) {
|
|
553
|
+
const networkId = parseNetworkId(options.network);
|
|
554
|
+
const network = configuredNetwork(networkId);
|
|
555
|
+
const defaultDataLake = NetworkDataLakeUrls[networkId];
|
|
556
|
+
if (defaultDataLake === void 0) throw new Error(`XL1 SDK does not define a datalake for ${networkId}`);
|
|
557
|
+
const expectedChainId = sdkChainId(network);
|
|
558
|
+
return Object.freeze({
|
|
559
|
+
dataLakeUrl: endpoint(options.dataLakeUrl ?? defaultDataLake, "dataLakeUrl"),
|
|
560
|
+
...expectedChainId === void 0 ? {} : { expectedChainId },
|
|
561
|
+
network: networkId,
|
|
562
|
+
rpcUrl: endpoint(options.rpcUrl ?? defaultRpcUrl(network), "rpcUrl")
|
|
563
|
+
});
|
|
564
|
+
}
|
|
565
|
+
async function pinEventKitNetworkSession(options) {
|
|
566
|
+
const chainId = await observedChainId(options.viewer);
|
|
567
|
+
const requestedPin = options.expectedChainId === void 0 ? void 0 : ChainIdZod.parse(options.expectedChainId.toLowerCase());
|
|
568
|
+
if (requestedPin !== void 0 && requestedPin !== chainId) {
|
|
569
|
+
throw new Error(`Connected chain ID ${chainId} does not match requested chain ID ${requestedPin}`);
|
|
570
|
+
}
|
|
571
|
+
assertResolutionChain(options.resolution, chainId);
|
|
572
|
+
return Object.freeze({ ...options.resolution, chainId });
|
|
573
|
+
}
|
|
574
|
+
async function assertEventKitNetworkSession(session, viewer) {
|
|
575
|
+
const network = parseNetworkId(session.network);
|
|
576
|
+
const chainId = ChainIdZod.parse(session.chainId.toLowerCase());
|
|
577
|
+
assertResolutionChain({ ...session, network }, chainId);
|
|
578
|
+
const observed = await observedChainId(viewer);
|
|
579
|
+
if (observed !== chainId) {
|
|
580
|
+
throw new Error(`Connected chain ID ${observed} does not match pinned chain ID ${chainId}`);
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
async function assertEventKitNetworkWrite(session, viewer) {
|
|
584
|
+
if (session.network === "mainnet" || session.chainId === sdkChainId(MainNetwork)) {
|
|
585
|
+
throw new Error("Event Kit Mainnet writes are disabled until the Phase 7 canary interlock exists");
|
|
586
|
+
}
|
|
587
|
+
await assertEventKitNetworkSession(session, viewer);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// src/handshakePublication.ts
|
|
591
|
+
async function objectHash(object) {
|
|
592
|
+
return String(await PayloadBuilder2.dataHash(object));
|
|
593
|
+
}
|
|
594
|
+
async function signerSource(options) {
|
|
595
|
+
const raw = String(await options.signer.address());
|
|
596
|
+
const normalized = NormalizedAddressZod.parse(normalizeAddress(raw));
|
|
597
|
+
if (raw !== normalized) {
|
|
598
|
+
throw new TypeError("XL1 signer address must be canonical lowercase hexadecimal without 0x");
|
|
599
|
+
}
|
|
600
|
+
return normalized;
|
|
601
|
+
}
|
|
602
|
+
function failBinding(message) {
|
|
603
|
+
throw new Error(`Invalid Event Kit handshake publication: ${message}`);
|
|
604
|
+
}
|
|
605
|
+
async function publishHandshakeObjects(transport, source, subject, objects, identities, attachments = []) {
|
|
606
|
+
await assertEventKitNetworkWrite(transport.session, transport.viewer);
|
|
607
|
+
if (source !== await signerSource(transport)) failBinding("Claim source does not match the transaction signer");
|
|
608
|
+
const hashes = identities.map((identity) => identity.objectHash);
|
|
609
|
+
const claim = buildClaim({
|
|
610
|
+
hashes,
|
|
611
|
+
source,
|
|
612
|
+
subject
|
|
613
|
+
});
|
|
614
|
+
const claimHash = await objectHash(claim);
|
|
615
|
+
const { session: _session, ...publication } = transport;
|
|
616
|
+
const result = await publishFinalizedStatements({
|
|
617
|
+
...publication,
|
|
618
|
+
attachments,
|
|
619
|
+
expectedChainId: transport.session.chainId,
|
|
620
|
+
expectedSource: source,
|
|
621
|
+
statements: [{ event: claim, objects }]
|
|
622
|
+
});
|
|
623
|
+
if (result.eventHashes.length !== 1 || result.eventHashes[0] !== claimHash) {
|
|
624
|
+
throw new Error("Finalized publication evidence does not identify the exact Event Kit Claim");
|
|
625
|
+
}
|
|
626
|
+
return {
|
|
627
|
+
...result,
|
|
628
|
+
chainId: transport.session.chainId,
|
|
629
|
+
claim,
|
|
630
|
+
claimHash,
|
|
631
|
+
network: transport.session.network,
|
|
632
|
+
objects: identities,
|
|
633
|
+
source,
|
|
634
|
+
subject
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
async function publishPublisherService(options) {
|
|
638
|
+
const {
|
|
639
|
+
encryptionKeys: rawKeys,
|
|
640
|
+
service: rawService,
|
|
641
|
+
...transport
|
|
642
|
+
} = options;
|
|
643
|
+
const service = PublisherServiceZod.parse(rawService);
|
|
644
|
+
const keys = rawKeys.map((key) => PublisherEncryptionKeyZod.parse(key));
|
|
645
|
+
const source = await signerSource(transport);
|
|
646
|
+
const [serviceHash, keyEntries] = await Promise.all([
|
|
647
|
+
objectHash(service),
|
|
648
|
+
Promise.all(keys.map(async (key) => ({ hash: await objectHash(key), key })))
|
|
649
|
+
]);
|
|
650
|
+
const keysByHash = new Map(keyEntries.map((entry) => [entry.hash, entry.key]));
|
|
651
|
+
if (keysByHash.size !== keyEntries.length) failBinding("encryption key descriptor bodies must be unique");
|
|
652
|
+
if (keysByHash.size !== service.encryptionKeys.length || service.encryptionKeys.some((hash) => !keysByHash.has(hash))) {
|
|
653
|
+
failBinding("service.encryptionKeys must exactly identify the supplied key descriptors");
|
|
654
|
+
}
|
|
655
|
+
const orderedKeys = service.encryptionKeys.map((hash) => {
|
|
656
|
+
const key = keysByHash.get(hash);
|
|
657
|
+
if (key === void 0) return failBinding(`missing encryption key descriptor ${hash}`);
|
|
658
|
+
return { hash, key };
|
|
659
|
+
});
|
|
660
|
+
return await publishHandshakeObjects(
|
|
661
|
+
transport,
|
|
662
|
+
source,
|
|
663
|
+
source,
|
|
664
|
+
[service, ...orderedKeys.map((entry) => entry.key)],
|
|
665
|
+
[
|
|
666
|
+
{
|
|
667
|
+
kind: "publisher-service",
|
|
668
|
+
objectHash: serviceHash,
|
|
669
|
+
revision: service.revision,
|
|
670
|
+
schema: service.schema,
|
|
671
|
+
serviceId: service.serviceId
|
|
672
|
+
},
|
|
673
|
+
...orderedKeys.map(({ hash, key }) => ({
|
|
674
|
+
keyId: key.keyId,
|
|
675
|
+
kind: "publisher-encryption-key",
|
|
676
|
+
objectHash: hash,
|
|
677
|
+
schema: key.schema
|
|
678
|
+
}))
|
|
679
|
+
]
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
async function publishWakeSubscription(options) {
|
|
683
|
+
const {
|
|
684
|
+
encryptionKey: rawKey,
|
|
685
|
+
grant: rawGrant,
|
|
686
|
+
service: rawService,
|
|
687
|
+
subscription: rawSubscription,
|
|
688
|
+
...transport
|
|
689
|
+
} = options;
|
|
690
|
+
const key = PublisherEncryptionKeyZod.parse(rawKey);
|
|
691
|
+
const grant = WakeGrantObjectZod.parse(rawGrant);
|
|
692
|
+
const service = PublisherServiceZod.parse(rawService);
|
|
693
|
+
const subscription = EncryptedWakeSubscriptionZod.parse(rawSubscription);
|
|
694
|
+
const [keyHash, grantHash, serviceHash, subscriptionHash] = await Promise.all([
|
|
695
|
+
objectHash(key),
|
|
696
|
+
objectHash(grant),
|
|
697
|
+
objectHash(service),
|
|
698
|
+
objectHash(subscription)
|
|
699
|
+
]);
|
|
700
|
+
if (subscription.chainId !== transport.session.chainId) failBinding("subscription chainId does not match the pinned session");
|
|
701
|
+
if (subscription.publisher !== grant.publisher) failBinding("subscription publisher does not match grant.publisher");
|
|
702
|
+
if (subscription.service !== serviceHash) failBinding("subscription service does not match the supplied service");
|
|
703
|
+
if (subscription.grant !== grantHash) failBinding("subscription grant does not match the supplied grant");
|
|
704
|
+
if (subscription.encryptionKey !== keyHash || subscription.keyId !== key.keyId) {
|
|
705
|
+
failBinding("subscription encryption key does not match the supplied descriptor");
|
|
706
|
+
}
|
|
707
|
+
if (service.preferredEncryptionKey !== keyHash || !service.encryptionKeys.includes(keyHash)) {
|
|
708
|
+
failBinding("subscription must use the selected service preferred encryption key");
|
|
709
|
+
}
|
|
710
|
+
const source = await signerSource(transport);
|
|
711
|
+
const subject = NormalizedAddressZod.parse(subscription.publisher);
|
|
712
|
+
return await publishHandshakeObjects(
|
|
713
|
+
transport,
|
|
714
|
+
source,
|
|
715
|
+
subject,
|
|
716
|
+
[service, grant, subscription],
|
|
717
|
+
[
|
|
718
|
+
{
|
|
719
|
+
kind: "publisher-service",
|
|
720
|
+
objectHash: serviceHash,
|
|
721
|
+
revision: service.revision,
|
|
722
|
+
schema: service.schema,
|
|
723
|
+
serviceId: service.serviceId
|
|
724
|
+
},
|
|
725
|
+
{
|
|
726
|
+
deploymentId: grant.deploymentId,
|
|
727
|
+
grantId: grant.grantId,
|
|
728
|
+
kind: "wake-grant",
|
|
729
|
+
objectHash: grantHash,
|
|
730
|
+
schema: grant.schema
|
|
731
|
+
},
|
|
732
|
+
{
|
|
733
|
+
kind: "wake-subscription",
|
|
734
|
+
objectHash: subscriptionHash,
|
|
735
|
+
revision: subscription.revision,
|
|
736
|
+
schema: subscription.schema,
|
|
737
|
+
subscriptionId: subscription.subscriptionId
|
|
738
|
+
}
|
|
739
|
+
]
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
async function publishWakeSubscriptionAcceptance(options) {
|
|
743
|
+
const {
|
|
744
|
+
acceptance: rawAcceptance,
|
|
745
|
+
challenge: rawChallenge,
|
|
746
|
+
response: rawResponse,
|
|
747
|
+
...transport
|
|
748
|
+
} = options;
|
|
749
|
+
const acceptance = WakeSubscriptionAcceptanceZod2.parse(rawAcceptance);
|
|
750
|
+
const challenge = EndpointChallengeZod.parse(rawChallenge);
|
|
751
|
+
const response = EndpointChallengeResponseZod.parse(rawResponse);
|
|
752
|
+
const [acceptanceHash, challengeHash, responseHash] = await Promise.all([
|
|
753
|
+
objectHash(acceptance),
|
|
754
|
+
objectHash(challenge),
|
|
755
|
+
objectHash(response)
|
|
756
|
+
]);
|
|
757
|
+
const source = await signerSource(transport);
|
|
758
|
+
if (challenge.publisher !== source) failBinding("challenge publisher does not match the transaction signer");
|
|
759
|
+
if (challenge.chainId !== transport.session.chainId) failBinding("challenge chainId does not match the pinned session");
|
|
760
|
+
if (response.challenge !== challengeHash) failBinding("response does not reference the supplied challenge");
|
|
761
|
+
if (acceptance.challenge !== challengeHash || acceptance.response !== responseHash) {
|
|
762
|
+
failBinding("acceptance does not reference the supplied challenge and response");
|
|
763
|
+
}
|
|
764
|
+
if (acceptance.service !== challenge.service || acceptance.encryptionKey !== challenge.encryptionKey || acceptance.subscription !== challenge.subscription || acceptance.grant !== challenge.grant) {
|
|
765
|
+
failBinding("acceptance tuple does not match the supplied challenge");
|
|
766
|
+
}
|
|
767
|
+
return await publishHandshakeObjects(
|
|
768
|
+
transport,
|
|
769
|
+
source,
|
|
770
|
+
source,
|
|
771
|
+
[acceptance],
|
|
772
|
+
[{
|
|
773
|
+
challenge: challengeHash,
|
|
774
|
+
kind: "wake-subscription-acceptance",
|
|
775
|
+
objectHash: acceptanceHash,
|
|
776
|
+
response: responseHash,
|
|
777
|
+
schema: acceptance.schema,
|
|
778
|
+
subscription: acceptance.subscription
|
|
779
|
+
}],
|
|
780
|
+
[challenge, response]
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
async function publishRevocation(transport, publisher, revocation, kind, targetHash) {
|
|
784
|
+
const source = await signerSource(transport);
|
|
785
|
+
const subject = NormalizedAddressZod.parse(publisher);
|
|
786
|
+
const revocationHash = await objectHash(revocation);
|
|
787
|
+
return await publishHandshakeObjects(
|
|
788
|
+
transport,
|
|
789
|
+
source,
|
|
790
|
+
subject,
|
|
791
|
+
[revocation],
|
|
792
|
+
[{
|
|
793
|
+
kind,
|
|
794
|
+
objectHash: revocationHash,
|
|
795
|
+
schema: String(revocation.schema),
|
|
796
|
+
targetHash
|
|
797
|
+
}]
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
async function publishPublisherServiceRevocation(options) {
|
|
801
|
+
const { revocation: rawRevocation, ...transport } = options;
|
|
802
|
+
const revocation = PublisherServiceRevocationZod.parse(rawRevocation);
|
|
803
|
+
const publisher = await signerSource(transport);
|
|
804
|
+
return await publishRevocation(transport, publisher, revocation, "publisher-service-revocation", revocation.service);
|
|
805
|
+
}
|
|
806
|
+
async function publishPublisherEncryptionKeyRevocation(options) {
|
|
807
|
+
const { revocation: rawRevocation, ...transport } = options;
|
|
808
|
+
const revocation = PublisherEncryptionKeyRevocationZod.parse(rawRevocation);
|
|
809
|
+
const publisher = await signerSource(transport);
|
|
810
|
+
return await publishRevocation(
|
|
811
|
+
transport,
|
|
812
|
+
publisher,
|
|
813
|
+
revocation,
|
|
814
|
+
"publisher-encryption-key-revocation",
|
|
815
|
+
revocation.key
|
|
816
|
+
);
|
|
817
|
+
}
|
|
818
|
+
async function publishWakeSubscriptionRevocation(options) {
|
|
819
|
+
const {
|
|
820
|
+
publisher,
|
|
821
|
+
revocation: rawRevocation,
|
|
822
|
+
...transport
|
|
823
|
+
} = options;
|
|
824
|
+
const revocation = WakeSubscriptionRevocationZod.parse(rawRevocation);
|
|
825
|
+
return await publishRevocation(
|
|
826
|
+
transport,
|
|
827
|
+
publisher,
|
|
828
|
+
revocation,
|
|
829
|
+
"wake-subscription-revocation",
|
|
830
|
+
revocation.subscription
|
|
831
|
+
);
|
|
832
|
+
}
|
|
833
|
+
async function publishWakeGrantRevocation(options) {
|
|
834
|
+
const {
|
|
835
|
+
publisher,
|
|
836
|
+
revocation: rawRevocation,
|
|
837
|
+
...transport
|
|
838
|
+
} = options;
|
|
839
|
+
const revocation = WakeGrantRevocationZod.parse(rawRevocation);
|
|
840
|
+
return await publishRevocation(transport, publisher, revocation, "wake-grant-revocation", revocation.grant);
|
|
841
|
+
}
|
|
842
|
+
async function publishWakeSubscriptionAcceptanceRevocation(options) {
|
|
843
|
+
const { revocation: rawRevocation, ...transport } = options;
|
|
844
|
+
const revocation = WakeSubscriptionAcceptanceRevocationZod.parse(rawRevocation);
|
|
845
|
+
const publisher = await signerSource(transport);
|
|
846
|
+
return await publishRevocation(
|
|
847
|
+
transport,
|
|
848
|
+
publisher,
|
|
849
|
+
revocation,
|
|
850
|
+
"wake-subscription-acceptance-revocation",
|
|
851
|
+
revocation.acceptance
|
|
852
|
+
);
|
|
853
|
+
}
|
|
19
854
|
export {
|
|
20
|
-
|
|
855
|
+
EVENT_KIT_NETWORK_IDS,
|
|
856
|
+
assertEventKitNetworkSession,
|
|
857
|
+
assertEventKitNetworkWrite,
|
|
858
|
+
createMemoryFinalizedStatementPublicationJournal,
|
|
859
|
+
createXl1FinalizedHeadSource,
|
|
860
|
+
pinEventKitNetworkSession,
|
|
861
|
+
publishFinalizedStatements,
|
|
862
|
+
publishPublisherEncryptionKeyRevocation,
|
|
863
|
+
publishPublisherService,
|
|
864
|
+
publishPublisherServiceRevocation,
|
|
865
|
+
publishWakeGrantRevocation,
|
|
866
|
+
publishWakeSubscription,
|
|
867
|
+
publishWakeSubscriptionAcceptance,
|
|
868
|
+
publishWakeSubscriptionAcceptanceRevocation,
|
|
869
|
+
publishWakeSubscriptionRevocation,
|
|
870
|
+
resolveEventKitNetwork
|
|
21
871
|
};
|
|
22
872
|
//# sourceMappingURL=index.mjs.map
|