@partylayer/testing 1.0.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/LICENSE +21 -0
- package/README.md +141 -0
- package/dist/index.d.mts +177 -0
- package/dist/index.d.ts +177 -0
- package/dist/index.js +481 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +467 -0
- package/dist/index.mjs.map +1 -0
- package/dist/offline-CELeTEq9.d.mts +146 -0
- package/dist/offline-CELeTEq9.d.ts +146 -0
- package/dist/query.d.mts +53 -0
- package/dist/query.d.ts +53 -0
- package/dist/query.js +206 -0
- package/dist/query.js.map +1 -0
- package/dist/query.mjs +200 -0
- package/dist/query.mjs.map +1 -0
- package/package.json +70 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var provider = require('@partylayer/provider');
|
|
4
|
+
var core = require('@partylayer/core');
|
|
5
|
+
var session = require('@partylayer/session');
|
|
6
|
+
|
|
7
|
+
// src/mock-wallet.ts
|
|
8
|
+
var PRESETS = {
|
|
9
|
+
userRejected: () => provider.userRejected("User rejected the request"),
|
|
10
|
+
insufficientTraffic: () => provider.resourceUnavailable("Insufficient traffic credits to submit the transaction"),
|
|
11
|
+
synchronizerError: () => provider.chainDisconnected("Synchronizer error"),
|
|
12
|
+
transactionTimeout: () => provider.transactionRejected("Transaction timed out"),
|
|
13
|
+
genericError: () => provider.internalError("RPC handler error")
|
|
14
|
+
};
|
|
15
|
+
var MOCK_SCENARIO_NAMES = Object.keys(PRESETS);
|
|
16
|
+
function scenarioToError(scenario) {
|
|
17
|
+
if (scenario instanceof provider.ProviderRpcError) return scenario;
|
|
18
|
+
if (typeof scenario === "string") return PRESETS[scenario]();
|
|
19
|
+
return new provider.ProviderRpcError(scenario.message, scenario.code);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// src/mock-wallet.ts
|
|
23
|
+
var DEFAULT_PARTY = "party::mock-1";
|
|
24
|
+
var DEFAULT_NETWORK = "devnet";
|
|
25
|
+
function wait(ms) {
|
|
26
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
27
|
+
}
|
|
28
|
+
function createMockWalletClient(config = {}) {
|
|
29
|
+
const partyId = config.partyId ?? DEFAULT_PARTY;
|
|
30
|
+
const network = config.network ?? DEFAULT_NETWORK;
|
|
31
|
+
let connected = config.connected ?? false;
|
|
32
|
+
const handlers = /* @__PURE__ */ new Map();
|
|
33
|
+
function makeSession() {
|
|
34
|
+
return {
|
|
35
|
+
sessionId: "sess-mock-1",
|
|
36
|
+
walletId: "mock",
|
|
37
|
+
partyId,
|
|
38
|
+
network,
|
|
39
|
+
expiresAt: Number.MAX_SAFE_INTEGER,
|
|
40
|
+
capabilitiesSnapshot: [
|
|
41
|
+
"connect",
|
|
42
|
+
"signMessage",
|
|
43
|
+
"signTransaction",
|
|
44
|
+
"submitTransaction",
|
|
45
|
+
"ledgerApi"
|
|
46
|
+
]
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
async function gate(method) {
|
|
50
|
+
const delay = config.delays?.[method];
|
|
51
|
+
if (delay && delay > 0) await wait(delay);
|
|
52
|
+
const scenario = config.scenarios?.[method];
|
|
53
|
+
if (scenario) throw scenarioToError(scenario);
|
|
54
|
+
}
|
|
55
|
+
function fire(event, payload) {
|
|
56
|
+
handlers.get(event)?.forEach((handler) => handler(payload));
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
async connect() {
|
|
60
|
+
await gate("connect");
|
|
61
|
+
connected = true;
|
|
62
|
+
const session = makeSession();
|
|
63
|
+
fire("session:connected", { type: "session:connected", session });
|
|
64
|
+
return session;
|
|
65
|
+
},
|
|
66
|
+
async disconnect() {
|
|
67
|
+
await gate("disconnect");
|
|
68
|
+
connected = false;
|
|
69
|
+
fire("session:disconnected", { type: "session:disconnected" });
|
|
70
|
+
},
|
|
71
|
+
async getActiveSession() {
|
|
72
|
+
await gate("getActiveSession");
|
|
73
|
+
return connected ? makeSession() : null;
|
|
74
|
+
},
|
|
75
|
+
async signMessage() {
|
|
76
|
+
await gate("signMessage");
|
|
77
|
+
return { signature: "mock-signature" };
|
|
78
|
+
},
|
|
79
|
+
async signTransaction() {
|
|
80
|
+
await gate("signTransaction");
|
|
81
|
+
return {
|
|
82
|
+
transactionHash: "mock-tx-hash",
|
|
83
|
+
signedTx: { data: "mock-signed-payload" },
|
|
84
|
+
partyId
|
|
85
|
+
};
|
|
86
|
+
},
|
|
87
|
+
async submitTransaction() {
|
|
88
|
+
await gate("submitTransaction");
|
|
89
|
+
return {
|
|
90
|
+
transactionHash: "mock-tx-hash",
|
|
91
|
+
submittedAt: 0,
|
|
92
|
+
commandId: "mock-command-1",
|
|
93
|
+
updateId: "mock-update-1"
|
|
94
|
+
};
|
|
95
|
+
},
|
|
96
|
+
async ledgerApi(params) {
|
|
97
|
+
await gate("ledgerApi");
|
|
98
|
+
return {
|
|
99
|
+
response: JSON.stringify({
|
|
100
|
+
requestMethod: params.requestMethod,
|
|
101
|
+
resource: params.resource
|
|
102
|
+
})
|
|
103
|
+
};
|
|
104
|
+
},
|
|
105
|
+
getRegistryStatus() {
|
|
106
|
+
return null;
|
|
107
|
+
},
|
|
108
|
+
on(event, handler) {
|
|
109
|
+
let set = handlers.get(event);
|
|
110
|
+
if (!set) {
|
|
111
|
+
set = /* @__PURE__ */ new Set();
|
|
112
|
+
handlers.set(event, set);
|
|
113
|
+
}
|
|
114
|
+
set.add(handler);
|
|
115
|
+
return () => {
|
|
116
|
+
handlers.get(event)?.delete(handler);
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function createMockWallet(config = {}) {
|
|
122
|
+
return provider.createProviderBridge(createMockWalletClient(config));
|
|
123
|
+
}
|
|
124
|
+
var FORWARD = [
|
|
125
|
+
"idle",
|
|
126
|
+
"preparing",
|
|
127
|
+
"submitting",
|
|
128
|
+
"confirming",
|
|
129
|
+
"finalized"
|
|
130
|
+
];
|
|
131
|
+
function wait2(ms) {
|
|
132
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
133
|
+
}
|
|
134
|
+
function createTransactionLifecycle(config = {}) {
|
|
135
|
+
const commandId = config.commandId ?? "mock-command-1";
|
|
136
|
+
const party = config.party ?? "party::mock-1";
|
|
137
|
+
const signature = config.signature ?? "mock-signature";
|
|
138
|
+
const updateId = config.updateId ?? "mock-update-1";
|
|
139
|
+
const bus = new provider.CIP0103EventBus();
|
|
140
|
+
const state = { phase: "idle" };
|
|
141
|
+
function emit(event) {
|
|
142
|
+
bus.emit(core.CIP0103_EVENTS.TX_CHANGED, event);
|
|
143
|
+
config.provider?.emit(core.CIP0103_EVENTS.TX_CHANGED, event);
|
|
144
|
+
}
|
|
145
|
+
function emitFor(next) {
|
|
146
|
+
switch (next) {
|
|
147
|
+
case "preparing":
|
|
148
|
+
emit({ status: "pending", commandId });
|
|
149
|
+
break;
|
|
150
|
+
case "submitting":
|
|
151
|
+
emit({
|
|
152
|
+
status: "signed",
|
|
153
|
+
commandId,
|
|
154
|
+
payload: { signature, signedBy: party, party }
|
|
155
|
+
});
|
|
156
|
+
break;
|
|
157
|
+
case "confirming":
|
|
158
|
+
break;
|
|
159
|
+
case "finalized":
|
|
160
|
+
emit({
|
|
161
|
+
status: "executed",
|
|
162
|
+
commandId,
|
|
163
|
+
payload: { updateId, completionOffset: 0 }
|
|
164
|
+
});
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
function advance() {
|
|
169
|
+
if (state.phase === "finalized" || state.phase === "failed") return state.phase;
|
|
170
|
+
const idx = FORWARD.indexOf(state.phase);
|
|
171
|
+
const next = FORWARD[idx + 1];
|
|
172
|
+
if (!next) return state.phase;
|
|
173
|
+
state.phase = next;
|
|
174
|
+
emitFor(next);
|
|
175
|
+
return state.phase;
|
|
176
|
+
}
|
|
177
|
+
function fail() {
|
|
178
|
+
if (state.phase === "finalized" || state.phase === "failed") return;
|
|
179
|
+
state.phase = "failed";
|
|
180
|
+
emit({ status: "failed", commandId });
|
|
181
|
+
}
|
|
182
|
+
async function start() {
|
|
183
|
+
if (state.phase !== "idle") return;
|
|
184
|
+
const order = [
|
|
185
|
+
"preparing",
|
|
186
|
+
"submitting",
|
|
187
|
+
"confirming",
|
|
188
|
+
"finalized"
|
|
189
|
+
];
|
|
190
|
+
for (const step of order) {
|
|
191
|
+
await wait2(config.delays?.[step] ?? 0);
|
|
192
|
+
if (state.phase === "failed") return;
|
|
193
|
+
advance();
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function reset() {
|
|
197
|
+
state.phase = "idle";
|
|
198
|
+
}
|
|
199
|
+
return {
|
|
200
|
+
get commandId() {
|
|
201
|
+
return commandId;
|
|
202
|
+
},
|
|
203
|
+
get phase() {
|
|
204
|
+
return state.phase;
|
|
205
|
+
},
|
|
206
|
+
get isPreparing() {
|
|
207
|
+
return state.phase === "preparing";
|
|
208
|
+
},
|
|
209
|
+
get isSubmitting() {
|
|
210
|
+
return state.phase === "submitting";
|
|
211
|
+
},
|
|
212
|
+
get isConfirming() {
|
|
213
|
+
return state.phase === "confirming";
|
|
214
|
+
},
|
|
215
|
+
get isFinalized() {
|
|
216
|
+
return state.phase === "finalized";
|
|
217
|
+
},
|
|
218
|
+
get isFailed() {
|
|
219
|
+
return state.phase === "failed";
|
|
220
|
+
},
|
|
221
|
+
on(event, listener) {
|
|
222
|
+
bus.on(event, listener);
|
|
223
|
+
return () => bus.removeListener(event, listener);
|
|
224
|
+
},
|
|
225
|
+
advance,
|
|
226
|
+
fail,
|
|
227
|
+
start,
|
|
228
|
+
reset
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
var DEFAULT_PARTY2 = "party::harness-1";
|
|
232
|
+
var DEFAULT_NETWORK2 = "canton:da-devnet";
|
|
233
|
+
function toAccount(partyId, networkId) {
|
|
234
|
+
return {
|
|
235
|
+
primary: true,
|
|
236
|
+
partyId,
|
|
237
|
+
status: "allocated",
|
|
238
|
+
hint: "harness",
|
|
239
|
+
publicKey: "pk",
|
|
240
|
+
namespace: "ns",
|
|
241
|
+
networkId,
|
|
242
|
+
signingProviderId: "webauthn-prf"
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function createChannelHub() {
|
|
246
|
+
const instances = /* @__PURE__ */ new Set();
|
|
247
|
+
const factory = (name) => {
|
|
248
|
+
const inst = {
|
|
249
|
+
_name: name,
|
|
250
|
+
onmessage: null,
|
|
251
|
+
postMessage(data) {
|
|
252
|
+
for (const other of instances) {
|
|
253
|
+
if (other !== inst && other._name === name && other.onmessage) other.onmessage({ data });
|
|
254
|
+
}
|
|
255
|
+
},
|
|
256
|
+
close() {
|
|
257
|
+
instances.delete(inst);
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
instances.add(inst);
|
|
261
|
+
return inst;
|
|
262
|
+
};
|
|
263
|
+
return { factory };
|
|
264
|
+
}
|
|
265
|
+
function createControllableProvider(opts) {
|
|
266
|
+
const listeners = /* @__PURE__ */ new Map();
|
|
267
|
+
let connected = false;
|
|
268
|
+
let account = toAccount(opts.partyId, opts.networkId);
|
|
269
|
+
function emit(event, ...args) {
|
|
270
|
+
listeners.get(event)?.forEach((l) => l(...args));
|
|
271
|
+
}
|
|
272
|
+
const provider = {
|
|
273
|
+
on(event, listener) {
|
|
274
|
+
(listeners.get(event) ?? listeners.set(event, /* @__PURE__ */ new Set()).get(event)).add(listener);
|
|
275
|
+
return provider;
|
|
276
|
+
},
|
|
277
|
+
removeListener(event, listener) {
|
|
278
|
+
listeners.get(event)?.delete(listener);
|
|
279
|
+
return provider;
|
|
280
|
+
},
|
|
281
|
+
async request({ method }) {
|
|
282
|
+
const scenario = opts.scenarios?.[method];
|
|
283
|
+
if (scenario) throw scenarioToError(scenario);
|
|
284
|
+
switch (method) {
|
|
285
|
+
case "status":
|
|
286
|
+
return { connection: { isConnected: connected }, network: { networkId: opts.networkId } };
|
|
287
|
+
case "listAccounts":
|
|
288
|
+
return [account];
|
|
289
|
+
case "connect":
|
|
290
|
+
connected = true;
|
|
291
|
+
return {};
|
|
292
|
+
case "disconnect":
|
|
293
|
+
connected = false;
|
|
294
|
+
return null;
|
|
295
|
+
case "getActiveNetwork":
|
|
296
|
+
return { networkId: opts.networkId };
|
|
297
|
+
default:
|
|
298
|
+
return {};
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
// ── harness controls (real CIP-0103 events) ──
|
|
302
|
+
_setConnected(v) {
|
|
303
|
+
connected = v;
|
|
304
|
+
emit("statusChanged", {
|
|
305
|
+
connection: { isConnected: v },
|
|
306
|
+
network: { networkId: opts.networkId }
|
|
307
|
+
});
|
|
308
|
+
},
|
|
309
|
+
_setPrimary(partyId) {
|
|
310
|
+
account = toAccount(partyId, opts.networkId);
|
|
311
|
+
emit("accountsChanged", [account]);
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
return provider;
|
|
315
|
+
}
|
|
316
|
+
function createSessionHarness(config = {}) {
|
|
317
|
+
const partyId = config.partyId ?? DEFAULT_PARTY2;
|
|
318
|
+
const networkId = config.networkId ?? DEFAULT_NETWORK2;
|
|
319
|
+
const ttlMs = config.ttlMs ?? 6e4;
|
|
320
|
+
const hub = config._hub ?? createChannelHub();
|
|
321
|
+
const provider = createControllableProvider({ partyId, networkId });
|
|
322
|
+
const store = session.createSessionStore(provider, {
|
|
323
|
+
storage: session.createMemoryStorage(),
|
|
324
|
+
// offline, deterministic
|
|
325
|
+
expiry: { ttlMs, onReauthRequired: config.onReauthRequired },
|
|
326
|
+
...config.reconnect !== void 0 ? { reconnect: config.reconnect } : {},
|
|
327
|
+
broadcast: { channelFactory: hub.factory }
|
|
328
|
+
});
|
|
329
|
+
function requireAdvance() {
|
|
330
|
+
if (!config.advanceTimers) {
|
|
331
|
+
throw new Error(
|
|
332
|
+
"SessionHarness.expire() drives the store's real expiry timer \u2014 pass `advanceTimers` (e.g. vi.advanceTimersByTimeAsync) and install fake timers."
|
|
333
|
+
);
|
|
334
|
+
}
|
|
335
|
+
return config.advanceTimers;
|
|
336
|
+
}
|
|
337
|
+
const harness = {
|
|
338
|
+
store,
|
|
339
|
+
provider,
|
|
340
|
+
async connect() {
|
|
341
|
+
const state = await store.connect();
|
|
342
|
+
provider._setPrimary(partyId);
|
|
343
|
+
return state;
|
|
344
|
+
},
|
|
345
|
+
dropConnection() {
|
|
346
|
+
provider._setConnected(false);
|
|
347
|
+
},
|
|
348
|
+
restoreConnection() {
|
|
349
|
+
provider._setConnected(true);
|
|
350
|
+
},
|
|
351
|
+
switchParty(nextPartyId) {
|
|
352
|
+
provider._setPrimary(nextPartyId);
|
|
353
|
+
},
|
|
354
|
+
async expire() {
|
|
355
|
+
const advance = requireAdvance();
|
|
356
|
+
await advance(ttlMs);
|
|
357
|
+
},
|
|
358
|
+
openTab(childConfig = {}) {
|
|
359
|
+
return createSessionHarness({ ...childConfig, _hub: hub });
|
|
360
|
+
},
|
|
361
|
+
destroy() {
|
|
362
|
+
store.destroy();
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
return harness;
|
|
366
|
+
}
|
|
367
|
+
function recordTxEvents(provider) {
|
|
368
|
+
const events = [];
|
|
369
|
+
const listener = (event) => {
|
|
370
|
+
events.push(event);
|
|
371
|
+
};
|
|
372
|
+
provider.on(core.CIP0103_EVENTS.TX_CHANGED, listener);
|
|
373
|
+
return {
|
|
374
|
+
events,
|
|
375
|
+
statuses() {
|
|
376
|
+
return events.map((e) => e.status);
|
|
377
|
+
},
|
|
378
|
+
stop() {
|
|
379
|
+
provider.removeListener(core.CIP0103_EVENTS.TX_CHANGED, listener);
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
async function connectMock(provider) {
|
|
384
|
+
return provider.request({ method: "connect" });
|
|
385
|
+
}
|
|
386
|
+
function createOfflineHarness(config = {}) {
|
|
387
|
+
const provider = createMockWallet(config.wallet);
|
|
388
|
+
const store = session.createSessionStore(provider, {
|
|
389
|
+
storage: session.createMemoryStorage(),
|
|
390
|
+
...config.session
|
|
391
|
+
});
|
|
392
|
+
return {
|
|
393
|
+
provider,
|
|
394
|
+
store,
|
|
395
|
+
destroy() {
|
|
396
|
+
store.destroy();
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// src/browser.ts
|
|
402
|
+
function mockWalletInjectionScript(options = {}) {
|
|
403
|
+
const walletId = options.walletId ?? "mock";
|
|
404
|
+
const partyId = options.partyId ?? "party::e2e-1";
|
|
405
|
+
const networkId = options.networkId ?? "canton:da-devnet";
|
|
406
|
+
return `
|
|
407
|
+
(() => {
|
|
408
|
+
const partyId = ${JSON.stringify(partyId)};
|
|
409
|
+
const networkId = ${JSON.stringify(networkId)};
|
|
410
|
+
let connected = false;
|
|
411
|
+
const listeners = new Map();
|
|
412
|
+
const emit = (e, ...a) => (listeners.get(e) || []).forEach((l) => l(...a));
|
|
413
|
+
const account = {
|
|
414
|
+
primary: true, partyId, status: 'allocated', hint: 'e2e',
|
|
415
|
+
publicKey: 'pk', namespace: 'ns', networkId, signingProviderId: 'webauthn-prf',
|
|
416
|
+
};
|
|
417
|
+
const provider = {
|
|
418
|
+
isPartyLayer: true,
|
|
419
|
+
request: async ({ method }) => {
|
|
420
|
+
switch (method) {
|
|
421
|
+
case 'connect': connected = true;
|
|
422
|
+
emit('statusChanged', { connection: { isConnected: true }, network: { networkId } });
|
|
423
|
+
emit('accountsChanged', [account]); return { isConnected: true };
|
|
424
|
+
case 'disconnect': connected = false;
|
|
425
|
+
emit('statusChanged', { connection: { isConnected: false } }); return null;
|
|
426
|
+
case 'status': return { connection: { isConnected: connected }, network: { networkId } };
|
|
427
|
+
case 'listAccounts': return [account];
|
|
428
|
+
case 'getActiveNetwork': return { networkId };
|
|
429
|
+
default: return {};
|
|
430
|
+
}
|
|
431
|
+
},
|
|
432
|
+
on: (e, l) => { if (!listeners.has(e)) listeners.set(e, new Set()); listeners.get(e).add(l); return provider; },
|
|
433
|
+
removeListener: (e, l) => { (listeners.get(e) || new Set()).delete(l); return provider; },
|
|
434
|
+
};
|
|
435
|
+
window.canton = window.canton || {};
|
|
436
|
+
window.canton[${JSON.stringify(walletId)}] = provider;
|
|
437
|
+
})();
|
|
438
|
+
`.trim();
|
|
439
|
+
}
|
|
440
|
+
function idbEntryCountScript(dbName) {
|
|
441
|
+
return `
|
|
442
|
+
(async () => {
|
|
443
|
+
const name = ${JSON.stringify(dbName)};
|
|
444
|
+
const exists = (await indexedDB.databases?.() || []).some((d) => d.name === name);
|
|
445
|
+
if (!exists) return -1;
|
|
446
|
+
const db = await new Promise((res, rej) => {
|
|
447
|
+
const r = indexedDB.open(name);
|
|
448
|
+
r.onsuccess = () => res(r.result); r.onerror = () => rej(r.error);
|
|
449
|
+
});
|
|
450
|
+
let total = 0;
|
|
451
|
+
for (const store of Array.from(db.objectStoreNames)) {
|
|
452
|
+
const count = await new Promise((res) => {
|
|
453
|
+
const c = db.transaction(store, 'readonly').objectStore(store).count();
|
|
454
|
+
c.onsuccess = () => res(c.result); c.onerror = () => res(0);
|
|
455
|
+
});
|
|
456
|
+
total += count;
|
|
457
|
+
}
|
|
458
|
+
db.close();
|
|
459
|
+
return total;
|
|
460
|
+
})()
|
|
461
|
+
`.trim();
|
|
462
|
+
}
|
|
463
|
+
function sessionKeyDbName(origin) {
|
|
464
|
+
return `partylayer-session-key::${origin}`;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
exports.MOCK_SCENARIO_NAMES = MOCK_SCENARIO_NAMES;
|
|
468
|
+
exports.connectMock = connectMock;
|
|
469
|
+
exports.createChannelHub = createChannelHub;
|
|
470
|
+
exports.createMockWallet = createMockWallet;
|
|
471
|
+
exports.createMockWalletClient = createMockWalletClient;
|
|
472
|
+
exports.createOfflineHarness = createOfflineHarness;
|
|
473
|
+
exports.createSessionHarness = createSessionHarness;
|
|
474
|
+
exports.createTransactionLifecycle = createTransactionLifecycle;
|
|
475
|
+
exports.idbEntryCountScript = idbEntryCountScript;
|
|
476
|
+
exports.mockWalletInjectionScript = mockWalletInjectionScript;
|
|
477
|
+
exports.recordTxEvents = recordTxEvents;
|
|
478
|
+
exports.scenarioToError = scenarioToError;
|
|
479
|
+
exports.sessionKeyDbName = sessionKeyDbName;
|
|
480
|
+
//# sourceMappingURL=index.js.map
|
|
481
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/scenarios.ts","../src/mock-wallet.ts","../src/lifecycle.ts","../src/session-harness.ts","../src/offline.ts","../src/browser.ts"],"names":["userRejected","resourceUnavailable","chainDisconnected","transactionRejected","internalError","ProviderRpcError","createProviderBridge","wait","CIP0103EventBus","CIP0103_EVENTS","DEFAULT_PARTY","DEFAULT_NETWORK","createSessionStore","createMemoryStorage"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Failure scenarios for the mock CIP-0103 wallet.\n *\n * IMPORTANT: every scenario maps to an EXISTING code in the repo's error\n * model (`@partylayer/provider` ProviderRpcError + RPC_ERRORS / JSON_RPC_ERRORS).\n * No new error codes are invented here. The named presets below are a\n * convenience layer over the existing convenience constructors; you can also\n * pass a raw `ProviderRpcError` or a `{ code, message }` pair to model any\n * other failure the provider error model already supports.\n *\n * Scenario → code mapping (all pre-existing codes):\n * userRejected → 4001 (RPC_ERRORS.USER_REJECTED) via userRejected()\n * insufficientTraffic → -32002 (JSON_RPC_ERRORS.RESOURCE_UNAVAILABLE) via resourceUnavailable()\n * synchronizerError → 4901 (RPC_ERRORS.CHAIN_DISCONNECTED) via chainDisconnected()\n * transactionTimeout → -32003 (JSON_RPC_ERRORS.TRANSACTION_REJECTED) via transactionRejected()\n * genericError → -32603 (JSON_RPC_ERRORS.INTERNAL_ERROR) via internalError()\n */\n\nimport {\n ProviderRpcError,\n chainDisconnected,\n internalError,\n resourceUnavailable,\n transactionRejected,\n userRejected,\n} from '@partylayer/provider';\n\n/** Built-in named failure scenarios. */\nexport type MockScenarioName =\n | 'userRejected'\n | 'insufficientTraffic'\n | 'synchronizerError'\n | 'transactionTimeout'\n | 'genericError';\n\n/**\n * A scenario is either a built-in name, a fully-formed `ProviderRpcError`, or\n * a `{ code, message }` pair (which must use an existing numeric code).\n */\nexport type MockScenario =\n | MockScenarioName\n | ProviderRpcError\n | { code: number; message: string };\n\nconst PRESETS: Record<MockScenarioName, () => ProviderRpcError> = {\n userRejected: () => userRejected('User rejected the request'),\n insufficientTraffic: () =>\n resourceUnavailable('Insufficient traffic credits to submit the transaction'),\n synchronizerError: () => chainDisconnected('Synchronizer error'),\n transactionTimeout: () => transactionRejected('Transaction timed out'),\n genericError: () => internalError('RPC handler error'),\n};\n\n/** All built-in scenario names (useful for table-driven tests). */\nexport const MOCK_SCENARIO_NAMES = Object.keys(PRESETS) as MockScenarioName[];\n\n/** Resolve a `MockScenario` into the `ProviderRpcError` the mock will throw. */\nexport function scenarioToError(scenario: MockScenario): ProviderRpcError {\n if (scenario instanceof ProviderRpcError) return scenario;\n if (typeof scenario === 'string') return PRESETS[scenario]();\n return new ProviderRpcError(scenario.message, scenario.code);\n}\n","/**\n * Mock CIP-0103 wallet provider.\n *\n * `createMockWallet(config)` returns a real, CIP-0103-compliant\n * `CIP0103Provider`. It is built by wrapping a configurable in-memory client\n * in the repo's canonical `createProviderBridge` from `@partylayer/provider`,\n * so the default/happy config passes `runCIP0103ConformanceTests` by\n * construction (it IS the conformance reference implementation, just with a\n * mock backend instead of a live wallet).\n *\n * Failure scenarios are toggled per-method (see ./scenarios). A test can make\n * `connect` succeed while `submitTransaction` fails, etc.\n *\n * Everything here is in-memory and synchronous-by-default — no DevNet, no live\n * wallet, no network. Optional per-method `delays` use `setTimeout` and are\n * fake-timer friendly (see ./offline).\n */\n\nimport type { CIP0103Provider } from '@partylayer/core';\nimport { createProviderBridge } from '@partylayer/provider';\nimport { scenarioToError, type MockScenario } from './scenarios';\n\n/**\n * The client shape `createProviderBridge` accepts. `@partylayer/provider` does\n * not export its `BridgeableClient` type publicly, so we derive it from the\n * factory signature — this stays correct automatically if the bridge's\n * contract changes, and contextually types the mock object literal below.\n */\nexport type MockWalletClient = Parameters<typeof createProviderBridge>[0];\n\n/** Methods on the mock client that can carry a scenario / delay. */\nexport type MockMethod =\n | 'connect'\n | 'disconnect'\n | 'getActiveSession'\n | 'signMessage'\n | 'signTransaction'\n | 'submitTransaction'\n | 'ledgerApi';\n\nexport interface MockWalletConfig {\n /** Party id reported by the mock session/accounts. */\n partyId?: string;\n /** Network id the bridge maps to CAIP-2 (e.g. 'devnet'). */\n network?: string;\n /** Whether a session is already active before `connect()` is called. */\n connected?: boolean;\n /** Per-method failure scenarios. Absent ⇒ that method succeeds. */\n scenarios?: Partial<Record<MockMethod, MockScenario>>;\n /** Per-method artificial delay in ms (fake-timer friendly). Default 0. */\n delays?: Partial<Record<MockMethod, number>>;\n}\n\nconst DEFAULT_PARTY = 'party::mock-1';\nconst DEFAULT_NETWORK = 'devnet';\n\nfunction wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Build the underlying `BridgeableClient`. Exposed as an extension point for\n * tests that want to wrap it differently or inspect it; most callers should\n * use `createMockWallet` instead.\n */\nexport function createMockWalletClient(config: MockWalletConfig = {}): MockWalletClient {\n const partyId = config.partyId ?? DEFAULT_PARTY;\n const network = config.network ?? DEFAULT_NETWORK;\n let connected = config.connected ?? false;\n\n const handlers = new Map<string, Set<(event: unknown) => void>>();\n\n function makeSession() {\n return {\n sessionId: 'sess-mock-1',\n walletId: 'mock',\n partyId,\n network,\n expiresAt: Number.MAX_SAFE_INTEGER,\n capabilitiesSnapshot: [\n 'connect',\n 'signMessage',\n 'signTransaction',\n 'submitTransaction',\n 'ledgerApi',\n ],\n };\n }\n\n /** Apply the configured delay, then throw the configured scenario (if any). */\n async function gate(method: MockMethod): Promise<void> {\n const delay = config.delays?.[method];\n if (delay && delay > 0) await wait(delay);\n const scenario = config.scenarios?.[method];\n if (scenario) throw scenarioToError(scenario);\n }\n\n function fire(event: string, payload: unknown): void {\n handlers.get(event)?.forEach((handler) => handler(payload));\n }\n\n return {\n async connect() {\n await gate('connect');\n connected = true;\n const session = makeSession();\n fire('session:connected', { type: 'session:connected', session });\n return session;\n },\n async disconnect() {\n await gate('disconnect');\n connected = false;\n fire('session:disconnected', { type: 'session:disconnected' });\n },\n async getActiveSession() {\n await gate('getActiveSession');\n return connected ? makeSession() : null;\n },\n async signMessage() {\n await gate('signMessage');\n return { signature: 'mock-signature' };\n },\n async signTransaction() {\n await gate('signTransaction');\n return {\n transactionHash: 'mock-tx-hash',\n signedTx: { data: 'mock-signed-payload' },\n partyId,\n };\n },\n async submitTransaction() {\n await gate('submitTransaction');\n return {\n transactionHash: 'mock-tx-hash',\n submittedAt: 0,\n commandId: 'mock-command-1',\n updateId: 'mock-update-1',\n };\n },\n async ledgerApi(params) {\n await gate('ledgerApi');\n return {\n response: JSON.stringify({\n requestMethod: params.requestMethod,\n resource: params.resource,\n }),\n };\n },\n getRegistryStatus() {\n return null;\n },\n on(event, handler) {\n let set = handlers.get(event);\n if (!set) {\n set = new Set();\n handlers.set(event, set);\n }\n set.add(handler as (event: unknown) => void);\n return () => {\n handlers.get(event)?.delete(handler as (event: unknown) => void);\n };\n },\n };\n}\n\n/**\n * Create a CIP-0103-compliant mock provider.\n *\n * Default config ⇒ a fully conformant happy-path provider. Pass `scenarios`\n * to make specific methods fail with the repo's existing error codes.\n *\n * @example\n * const provider = createMockWallet(); // happy path\n * const provider = createMockWallet({ // connect ok, submit fails\n * scenarios: { submitTransaction: 'synchronizerError' },\n * });\n */\nexport function createMockWallet(config: MockWalletConfig = {}): CIP0103Provider {\n return createProviderBridge(createMockWalletClient(config));\n}\n","/**\n * Simulated, controllable transaction lifecycle.\n *\n * Exposes the session-layer view (boolean phase flags\n * isPreparing → isSubmitting → isConfirming → isFinalized, plus a `failed`\n * terminal) AND emits the SAME CIP-0103 `txChanged` events the real provider\n * emits, so tests can assert against either view.\n *\n * Two drive modes:\n * - manual: `advance()` steps one phase at a time; `fail()` terminates.\n * - auto: `start()` walks all phases using configurable per-phase delays\n * (uses setTimeout — fake-timer friendly).\n *\n * Phase → CIP-0103 `txChanged.status` mapping:\n * preparing → 'pending'\n * submitting → 'signed' (payload: { signature, signedBy, party })\n * confirming → (no CIP-0103 status — see note)\n * finalized → 'executed' (payload: { updateId, completionOffset })\n * failed → 'failed'\n *\n * NOTE — 'confirming' has no CIP-0103 `txChanged` status: the spec's tx union\n * goes signed → executed with no intermediate \"confirming\" state. We still\n * model `isConfirming` as the post-signed waiting window because the session\n * layer surfaces it as a UI flag. The session-lifecycle harness\n * (`createSessionHarness`) and the TanStack Query utilities\n * (`@partylayer/testing/query`) build on top of this controller.\n */\n\nimport { CIP0103_EVENTS } from '@partylayer/core';\nimport type { CIP0103Provider, CIP0103TxChangedEvent } from '@partylayer/core';\nimport { CIP0103EventBus } from '@partylayer/provider';\n\nexport type LifecyclePhase =\n | 'idle'\n | 'preparing'\n | 'submitting'\n | 'confirming'\n | 'finalized'\n | 'failed';\n\n/** Non-terminal forward order used by advance()/start(). */\nconst FORWARD: LifecyclePhase[] = [\n 'idle',\n 'preparing',\n 'submitting',\n 'confirming',\n 'finalized',\n];\n\nexport type LifecycleDelays = Partial<\n Record<'preparing' | 'submitting' | 'confirming' | 'finalized', number>\n>;\n\nexport interface LifecycleConfig {\n /** Command id stamped on every emitted event. */\n commandId?: string;\n /** Party id used in the 'signed' payload. */\n party?: string;\n /** Signature used in the 'signed' payload. */\n signature?: string;\n /** Update id used in the 'executed' payload. */\n updateId?: string;\n /**\n * Optional provider to ALSO emit `txChanged` onto (in addition to this\n * controller's own listeners), so events surface on a mock wallet's bus.\n */\n provider?: CIP0103Provider;\n /** Per-phase delays for auto mode (`start()`). Default 0. */\n delays?: LifecycleDelays;\n}\n\nexport interface TransactionLifecycle {\n readonly commandId: string;\n readonly phase: LifecyclePhase;\n readonly isPreparing: boolean;\n readonly isSubmitting: boolean;\n readonly isConfirming: boolean;\n readonly isFinalized: boolean;\n readonly isFailed: boolean;\n /** Subscribe to `txChanged`. Returns an unsubscribe function. */\n on(event: string, listener: (event: CIP0103TxChangedEvent) => void): () => void;\n /** Manual step to the next phase; emits the mapped event. Returns the new phase. */\n advance(): LifecyclePhase;\n /** Terminal failure: emits `txChanged` `{ status: 'failed' }`. */\n fail(): void;\n /** Auto mode: walk every phase with configured delays. Resolves at 'finalized'. */\n start(): Promise<void>;\n /** Reset back to 'idle' (does not emit). */\n reset(): void;\n}\n\nfunction wait(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport function createTransactionLifecycle(\n config: LifecycleConfig = {},\n): TransactionLifecycle {\n const commandId = config.commandId ?? 'mock-command-1';\n const party = config.party ?? 'party::mock-1';\n const signature = config.signature ?? 'mock-signature';\n const updateId = config.updateId ?? 'mock-update-1';\n\n const bus = new CIP0103EventBus();\n // Held in an object so TypeScript does not flow-narrow `phase` to a literal\n // across the `await`s in start() (it is mutated indirectly via advance/fail).\n const state: { phase: LifecyclePhase } = { phase: 'idle' };\n\n function emit(event: CIP0103TxChangedEvent): void {\n bus.emit<CIP0103TxChangedEvent>(CIP0103_EVENTS.TX_CHANGED, event);\n // Mirror onto the linked provider's bus, if one was supplied.\n config.provider?.emit(CIP0103_EVENTS.TX_CHANGED, event);\n }\n\n /** Emit the CIP-0103 event mapped to `next` (confirming maps to nothing). */\n function emitFor(next: LifecyclePhase): void {\n switch (next) {\n case 'preparing':\n emit({ status: 'pending', commandId });\n break;\n case 'submitting':\n emit({\n status: 'signed',\n commandId,\n payload: { signature, signedBy: party, party },\n });\n break;\n case 'confirming':\n // No CIP-0103 status for 'confirming' — flag-only (see file note).\n break;\n case 'finalized':\n emit({\n status: 'executed',\n commandId,\n payload: { updateId, completionOffset: 0 },\n });\n break;\n default:\n break;\n }\n }\n\n function advance(): LifecyclePhase {\n if (state.phase === 'finalized' || state.phase === 'failed') return state.phase;\n const idx = FORWARD.indexOf(state.phase);\n const next = FORWARD[idx + 1];\n if (!next) return state.phase;\n state.phase = next;\n emitFor(next);\n return state.phase;\n }\n\n function fail(): void {\n if (state.phase === 'finalized' || state.phase === 'failed') return;\n state.phase = 'failed';\n emit({ status: 'failed', commandId });\n }\n\n async function start(): Promise<void> {\n // Only meaningful from a fresh/idle lifecycle.\n if (state.phase !== 'idle') return;\n const order: Array<'preparing' | 'submitting' | 'confirming' | 'finalized'> = [\n 'preparing',\n 'submitting',\n 'confirming',\n 'finalized',\n ];\n for (const step of order) {\n await wait(config.delays?.[step] ?? 0);\n // Cast widens past the `!== 'idle'` guard's narrowing above: a fail()\n // during an await can move us to the terminal state mid-loop.\n if ((state.phase as LifecyclePhase) === 'failed') return;\n advance();\n }\n }\n\n function reset(): void {\n state.phase = 'idle';\n }\n\n return {\n get commandId() {\n return commandId;\n },\n get phase() {\n return state.phase;\n },\n get isPreparing() {\n return state.phase === 'preparing';\n },\n get isSubmitting() {\n return state.phase === 'submitting';\n },\n get isConfirming() {\n return state.phase === 'confirming';\n },\n get isFinalized() {\n return state.phase === 'finalized';\n },\n get isFailed() {\n return state.phase === 'failed';\n },\n on(event, listener) {\n bus.on(event, listener);\n return () => bus.removeListener(event, listener);\n },\n advance,\n fail,\n start,\n reset,\n };\n}\n","/**\n * Session-lifecycle simulation harness.\n *\n * Drives a REAL `@partylayer/session` store through a controllable CIP-0103\n * provider, so every scenario exercises the store's own machinery — not\n * synthetic shortcuts:\n * - `expire()` advances the store's REAL expiry timer (the\n * `session:expired` / `onReauthRequired` path); it never\n * emits a fake `session:expired`. Requires fake-timer\n * control via `advanceTimers` (the store arms expiry\n * with `setTimeout`).\n * - `dropConnection()` / emit the provider's real `statusChanged` CIP-0103\n * `restoreConnection()` event — the same signal a live wallet sends — driving\n * the store's transient-disconnect / reconnect path.\n * - `switchParty()` emits a real `accountsChanged` with a new primary,\n * driving the store's `party:changed` detection.\n * - `openTab()` returns a second harness whose store shares this\n * harness's in-memory BroadcastChannel hub, so a\n * disconnect in one tab propagates to the other.\n *\n * Lifecycle: each harness OWNS its own store; `destroy()` is per-harness (a\n * child from `openTab()` must be destroyed by the caller — it is not torn down\n * with its parent).\n */\nimport {\n createSessionStore,\n createMemoryStorage,\n type BroadcastChannelLike,\n type ChannelFactory,\n type ExpiryOptions,\n type RetryPolicy,\n type SessionAccount,\n type SessionState,\n type SessionStore,\n} from '@partylayer/session';\nimport type { CIP0103Account, CIP0103Provider } from '@partylayer/core';\nimport { scenarioToError, type MockScenario } from './scenarios';\n\nexport interface SessionHarnessConfig {\n /** Initial primary party id. Default `party::harness-1`. */\n partyId?: string;\n /** CAIP-2 network id reported by the provider. Default `canton:da-devnet`. */\n networkId?: string;\n /** Expiry TTL (ms) armed on connect. Default `60_000`. Drive it with `expire()`. */\n ttlMs?: number;\n /** App re-auth hook invoked by the store's real expiry path. */\n onReauthRequired?: ExpiryOptions['onReauthRequired'];\n /** Reconnect policy passed straight to the store (default: store default). */\n reconnect?: RetryPolicy | false;\n /**\n * Advance timers to fire the store's REAL `setTimeout`-based expiry/backoff —\n * e.g. `vi.advanceTimersByTimeAsync`. Required for `expire()` and for\n * deterministic reconnect timing. Omit only if you don't call `expire()`.\n */\n advanceTimers?: (ms: number) => void | Promise<void>;\n /** @internal shared multi-tab hub (set by `openTab`). */\n _hub?: ChannelHub;\n}\n\nexport interface SessionHarness {\n /** The live session store under test. */\n readonly store: SessionStore;\n /** The controllable CIP-0103 provider backing the store. */\n readonly provider: CIP0103Provider;\n /** Connect via the real store flow (arms the expiry timer). */\n connect(): Promise<SessionState>;\n /** Fire a real transient `statusChanged(false)` (NOT an explicit disconnect). */\n dropConnection(): void;\n /** Fire a real `statusChanged(true)` to restore the connection. */\n restoreConnection(): void;\n /** Fire a real `accountsChanged` with a new primary → `party:changed`. */\n switchParty(partyId: string): void;\n /** Advance the store's REAL expiry timer past its TTL (no synthetic emit). */\n expire(): Promise<void>;\n /** A second harness sharing this one's broadcast hub (simulates another tab). */\n openTab(config?: Omit<SessionHarnessConfig, '_hub'>): SessionHarness;\n /** Tear down THIS harness's store/provider (per-harness; children are separate). */\n destroy(): void;\n}\n\nconst DEFAULT_PARTY = 'party::harness-1';\nconst DEFAULT_NETWORK = 'canton:da-devnet';\n\nfunction toAccount(partyId: string, networkId: string): CIP0103Account {\n return {\n primary: true,\n partyId,\n status: 'allocated' as CIP0103Account['status'],\n hint: 'harness',\n publicKey: 'pk',\n namespace: 'ns',\n networkId,\n signingProviderId: 'webauthn-prf',\n };\n}\n\n/** A synchronous in-memory BroadcastChannel hub shared across tabs. */\nexport interface ChannelHub {\n factory: ChannelFactory;\n}\n\n/** Build a hub whose channels deliver to OTHER instances only (no echo to sender). */\nexport function createChannelHub(): ChannelHub {\n const instances = new Set<BroadcastChannelLike & { _name: string }>();\n const factory: ChannelFactory = (name) => {\n const inst: BroadcastChannelLike & { _name: string } = {\n _name: name,\n onmessage: null,\n postMessage(data) {\n for (const other of instances) {\n if (other !== inst && other._name === name && other.onmessage) other.onmessage({ data });\n }\n },\n close() {\n instances.delete(inst);\n },\n };\n instances.add(inst);\n return inst;\n };\n return { factory };\n}\n\n/** Controllable CIP-0103 provider: scriptable status/accounts + real event bus. */\nfunction createControllableProvider(opts: {\n partyId: string;\n networkId: string;\n scenarios?: Partial<Record<'connect' | 'disconnect' | 'status' | 'listAccounts', MockScenario>>;\n}) {\n const listeners = new Map<string, Set<(...args: unknown[]) => void>>();\n let connected = false;\n let account = toAccount(opts.partyId, opts.networkId);\n\n function emit(event: string, ...args: unknown[]): void {\n listeners.get(event)?.forEach((l) => l(...args));\n }\n\n const provider = {\n on(event: string, listener: (...args: unknown[]) => void) {\n (listeners.get(event) ?? listeners.set(event, new Set()).get(event)!).add(listener);\n return provider;\n },\n removeListener(event: string, listener: (...args: unknown[]) => void) {\n listeners.get(event)?.delete(listener);\n return provider;\n },\n async request({ method }: { method: string }) {\n const scenario = opts.scenarios?.[method as 'connect'];\n if (scenario) throw scenarioToError(scenario);\n switch (method) {\n case 'status':\n return { connection: { isConnected: connected }, network: { networkId: opts.networkId } };\n case 'listAccounts':\n return [account];\n case 'connect':\n connected = true;\n return {};\n case 'disconnect':\n connected = false;\n return null;\n case 'getActiveNetwork':\n return { networkId: opts.networkId };\n default:\n return {};\n }\n },\n // ── harness controls (real CIP-0103 events) ──\n _setConnected(v: boolean) {\n connected = v;\n emit('statusChanged', {\n connection: { isConnected: v },\n network: { networkId: opts.networkId },\n });\n },\n _setPrimary(partyId: string) {\n account = toAccount(partyId, opts.networkId);\n emit('accountsChanged', [account]);\n },\n };\n return provider;\n}\n\nexport function createSessionHarness(config: SessionHarnessConfig = {}): SessionHarness {\n const partyId = config.partyId ?? DEFAULT_PARTY;\n const networkId = config.networkId ?? DEFAULT_NETWORK;\n const ttlMs = config.ttlMs ?? 60_000;\n const hub = config._hub ?? createChannelHub();\n\n const provider = createControllableProvider({ partyId, networkId });\n\n const store = createSessionStore(provider as unknown as CIP0103Provider, {\n storage: createMemoryStorage(), // offline, deterministic\n expiry: { ttlMs, onReauthRequired: config.onReauthRequired },\n ...(config.reconnect !== undefined ? { reconnect: config.reconnect } : {}),\n broadcast: { channelFactory: hub.factory },\n });\n\n function requireAdvance(): NonNullable<SessionHarnessConfig['advanceTimers']> {\n if (!config.advanceTimers) {\n throw new Error(\n 'SessionHarness.expire() drives the store\\'s real expiry timer — pass `advanceTimers` ' +\n '(e.g. vi.advanceTimersByTimeAsync) and install fake timers.',\n );\n }\n return config.advanceTimers;\n }\n\n const harness: SessionHarness = {\n store,\n provider: provider as unknown as CIP0103Provider,\n async connect() {\n const state = await store.connect();\n // Establish the initial primary account (real accountsChanged) so a later\n // switchParty() registers a genuine delta rather than an initial set.\n provider._setPrimary(partyId);\n return state;\n },\n dropConnection() {\n provider._setConnected(false); // real statusChanged(false) → transient drop\n },\n restoreConnection() {\n provider._setConnected(true); // real statusChanged(true)\n },\n switchParty(nextPartyId: string) {\n provider._setPrimary(nextPartyId); // real accountsChanged → party:changed\n },\n async expire() {\n const advance = requireAdvance();\n await advance(ttlMs); // fire the store's REAL setTimeout-based expiry\n },\n openTab(childConfig: Omit<SessionHarnessConfig, '_hub'> = {}) {\n return createSessionHarness({ ...childConfig, _hub: hub });\n },\n destroy() {\n store.destroy();\n },\n };\n return harness;\n}\n\n/** Re-export for callers building primary-account fixtures. */\nexport type { SessionAccount };\n","/**\n * Offline test helpers.\n *\n * These let unit/integration tests run with NO DevNet / live-wallet\n * dependency. Everything is deterministic and fake-timer friendly: the mock\n * wallet and lifecycle use `setTimeout` only for optional configured delays,\n * so `vi.useFakeTimers()` + `vi.advanceTimersByTimeAsync()` fully control time.\n *\n * See ./__tests__/offline-example.test.ts for a full connect → submit →\n * finalize assertion against the mock with zero network access.\n */\n\nimport { CIP0103_EVENTS } from '@partylayer/core';\nimport type { CIP0103Provider, CIP0103TxChangedEvent } from '@partylayer/core';\nimport {\n createSessionStore,\n createMemoryStorage,\n type SessionStore,\n type SessionStoreOptions,\n} from '@partylayer/session';\nimport { createMockWallet, type MockWalletConfig } from './mock-wallet';\n\nexport interface TxEventRecorder {\n /** All `txChanged` events captured, in emission order. */\n readonly events: CIP0103TxChangedEvent[];\n /** Just the `status` field of each captured event, in order. */\n statuses(): CIP0103TxChangedEvent['status'][];\n /** Stop recording (removes the listener). */\n stop(): void;\n}\n\n/**\n * Subscribe to a provider's `txChanged` stream and collect every event.\n * Returns a recorder whose `events` array fills as events fire.\n */\nexport function recordTxEvents(provider: CIP0103Provider): TxEventRecorder {\n const events: CIP0103TxChangedEvent[] = [];\n const listener = (event: CIP0103TxChangedEvent): void => {\n events.push(event);\n };\n provider.on(CIP0103_EVENTS.TX_CHANGED, listener);\n return {\n events,\n statuses() {\n return events.map((e) => e.status);\n },\n stop() {\n provider.removeListener(CIP0103_EVENTS.TX_CHANGED, listener);\n },\n };\n}\n\n/**\n * Convenience: connect a mock provider via the CIP-0103 `connect` method.\n * Returns the `CIP0103ConnectResult`-shaped response.\n */\nexport async function connectMock(\n provider: CIP0103Provider,\n): Promise<{ isConnected: boolean }> {\n return provider.request<{ isConnected: boolean }>({ method: 'connect' });\n}\n\n/** A fully offline mock wallet + session store, wired together. */\nexport interface OfflineHarness {\n readonly provider: CIP0103Provider;\n readonly store: SessionStore;\n destroy(): void;\n}\n\n/**\n * Compose a mock CIP-0103 wallet and a real `@partylayer/session` store with NO\n * network/DevNet. `wallet` configures the mock (failure scenarios, delays,\n * party); `session` overrides store options (storage defaults to in-memory).\n * For TanStack Query-inclusive composition, see `@partylayer/testing/query`.\n */\nexport function createOfflineHarness(\n config: { wallet?: MockWalletConfig; session?: Partial<SessionStoreOptions> } = {},\n): OfflineHarness {\n const provider = createMockWallet(config.wallet);\n const store = createSessionStore(provider, {\n storage: createMemoryStorage(),\n ...config.session,\n });\n return {\n provider,\n store,\n destroy() {\n store.destroy();\n },\n };\n}\n","/**\n * Reusable browser-test primitives for a real-browser (Playwright) smoke —\n * framework-agnostic: every helper returns a STRING of JS to run via\n * `page.addInitScript(...)` / `page.evaluate(...)`, so this package takes NO\n * dependency on Playwright. The actual smoke lives in `apps/demo/e2e`.\n */\n\nexport interface MockWalletInjectionOptions {\n /** Key on `window.canton` the wallet registers under. Default `mock`. */\n walletId?: string;\n /** Primary party id the mock reports. Default `party::e2e-1`. */\n partyId?: string;\n /** CAIP-2 network id. Default `canton:da-devnet`. */\n networkId?: string;\n}\n\n/**\n * An init script that installs a minimal CIP-0103-shaped provider at\n * `window.canton[walletId]` BEFORE the app loads, so a real-browser test can\n * drive the connect flow with no extension/live wallet. Inject via\n * `page.addInitScript({ content: mockWalletInjectionScript() })`.\n */\nexport function mockWalletInjectionScript(options: MockWalletInjectionOptions = {}): string {\n const walletId = options.walletId ?? 'mock';\n const partyId = options.partyId ?? 'party::e2e-1';\n const networkId = options.networkId ?? 'canton:da-devnet';\n return `\n(() => {\n const partyId = ${JSON.stringify(partyId)};\n const networkId = ${JSON.stringify(networkId)};\n let connected = false;\n const listeners = new Map();\n const emit = (e, ...a) => (listeners.get(e) || []).forEach((l) => l(...a));\n const account = {\n primary: true, partyId, status: 'allocated', hint: 'e2e',\n publicKey: 'pk', namespace: 'ns', networkId, signingProviderId: 'webauthn-prf',\n };\n const provider = {\n isPartyLayer: true,\n request: async ({ method }) => {\n switch (method) {\n case 'connect': connected = true;\n emit('statusChanged', { connection: { isConnected: true }, network: { networkId } });\n emit('accountsChanged', [account]); return { isConnected: true };\n case 'disconnect': connected = false;\n emit('statusChanged', { connection: { isConnected: false } }); return null;\n case 'status': return { connection: { isConnected: connected }, network: { networkId } };\n case 'listAccounts': return [account];\n case 'getActiveNetwork': return { networkId };\n default: return {};\n }\n },\n on: (e, l) => { if (!listeners.has(e)) listeners.set(e, new Set()); listeners.get(e).add(l); return provider; },\n removeListener: (e, l) => { (listeners.get(e) || new Set()).delete(l); return provider; },\n };\n window.canton = window.canton || {};\n window.canton[${JSON.stringify(walletId)}] = provider;\n})();\n`.trim();\n}\n\n/**\n * A script returning the number of object stores' total entries for an IndexedDB\n * database (or -1 if the DB does not exist) — used to assert encrypted-session\n * persistence engaged after a connect. Run via `page.evaluate(idbEntryCountScript(db))`.\n */\nexport function idbEntryCountScript(dbName: string): string {\n return `\n(async () => {\n const name = ${JSON.stringify(dbName)};\n const exists = (await indexedDB.databases?.() || []).some((d) => d.name === name);\n if (!exists) return -1;\n const db = await new Promise((res, rej) => {\n const r = indexedDB.open(name);\n r.onsuccess = () => res(r.result); r.onerror = () => rej(r.error);\n });\n let total = 0;\n for (const store of Array.from(db.objectStoreNames)) {\n const count = await new Promise((res) => {\n const c = db.transaction(store, 'readonly').objectStore(store).count();\n c.onsuccess = () => res(c.result); c.onerror = () => res(0);\n });\n total += count;\n }\n db.close();\n return total;\n})()\n`.trim();\n}\n\n/** The origin-bound IndexedDB name the session key store uses for a given origin. */\nexport function sessionKeyDbName(origin: string): string {\n return `partylayer-session-key::${origin}`;\n}\n"]}
|