1import assert from 'node:assert/strict';
2import { createRequire } from 'node:module';
3import { resolve } from 'node:path';
4import { webcrypto } from 'node:crypto';
5import { setTimeout } from 'node:timers';
6
7globalThis.crypto ??= webcrypto;
8let failure = 0;
9let phase = 'initializing wasm';
10let early = true;
11globalThis.setTimeout = (callback, delay, ...args) => {
12 if (early && failure === 2 && delay <= 1000) {
13 early = false;
14 delay = 0;
15 }
16 return setTimeout(callback, delay, ...args).unref();
17};
18const failures = [0, 0, 0];
19globalThis.snowboundReceiptPhase = value => { phase = value; };
20globalThis.snowboundReceiptFailure = value => { failure = value; };
21globalThis.snowboundReceiptTurn = () => new Promise(resolve => setTimeout(resolve, 10));
22globalThis.snowboundFlushStorage = () => {
23 failures[failure]++;
24 if (failure === 1) {
25 throw 'Injected persistent storage failure';
26 }
27 if (failure === 2) return Promise.reject('Injected asynchronous storage failure');
28 return Promise.resolve();
29};
30const wasm = createRequire(import.meta.url)(resolve(process.argv[2]));
31const timeout = setTimeout(() => { throw Error(`Receipt retry stalled while ${phase}: mode ${failure}, flushes ${failures}`); }, 10000);
32try {
33 await wasm.receipt_probe();
34 assert.ok(failures[1] >= 2, 'The active and dropped owner each retry synchronous storage failure');
35 assert.ok(failures[2] >= 1, 'An asynchronous storage rejection also keeps the receipt pending');
36 assert.equal(early, false, 'A retry timer fired before its deadline');
37 console.log(`Actual wasm receipts passed: ${failures[1]} throws, ${failures[2]} rejections, early timer, one publication, responsive reads, retained ownership`);
38} finally {
39 clearTimeout(timeout);
40}