@parity/product-sdk-signer 0.1.0 → 0.2.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/dist/index.d.ts +3 -2
- package/dist/index.js +14 -691
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/index.ts +12 -0
- package/src/providers/dev.ts +1 -0
- package/src/providers/host.ts +7 -7
package/dist/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { createLogger } from '@parity/product-sdk-logger';
|
|
2
|
+
import { getHostLocalStorage } from '@parity/product-sdk-host';
|
|
3
|
+
import { seedToAccount } from '@parity/product-sdk-keys';
|
|
4
|
+
import { ss58Encode, deriveH160 } from '@parity/product-sdk-address';
|
|
5
|
+
|
|
1
6
|
// src/signer-manager.ts
|
|
2
|
-
import { createLogger as createLogger3 } from "@parity/product-sdk-logger";
|
|
3
7
|
|
|
4
8
|
// src/errors.ts
|
|
5
9
|
var SignerError = class extends Error {
|
|
@@ -70,103 +74,6 @@ var DestroyedError = class extends SignerError {
|
|
|
70
74
|
function isHostError(e) {
|
|
71
75
|
return e instanceof HostUnavailableError || e instanceof HostRejectedError || e instanceof HostDisconnectedError;
|
|
72
76
|
}
|
|
73
|
-
if (void 0) {
|
|
74
|
-
const { test, expect, describe } = void 0;
|
|
75
|
-
describe("error classes", () => {
|
|
76
|
-
test("SignerError is the base class", () => {
|
|
77
|
-
const e = new HostUnavailableError();
|
|
78
|
-
expect(e).toBeInstanceOf(SignerError);
|
|
79
|
-
expect(e).toBeInstanceOf(Error);
|
|
80
|
-
});
|
|
81
|
-
test("HostUnavailableError with default message", () => {
|
|
82
|
-
const e = new HostUnavailableError();
|
|
83
|
-
expect(e.name).toBe("HostUnavailableError");
|
|
84
|
-
expect(e.message).toBe("Host API is not available");
|
|
85
|
-
});
|
|
86
|
-
test("HostUnavailableError with custom message", () => {
|
|
87
|
-
const e = new HostUnavailableError("custom");
|
|
88
|
-
expect(e.message).toBe("custom");
|
|
89
|
-
});
|
|
90
|
-
test("HostRejectedError", () => {
|
|
91
|
-
const e = new HostRejectedError();
|
|
92
|
-
expect(e).toBeInstanceOf(SignerError);
|
|
93
|
-
expect(e.message).toContain("rejected");
|
|
94
|
-
});
|
|
95
|
-
test("HostDisconnectedError", () => {
|
|
96
|
-
const e = new HostDisconnectedError();
|
|
97
|
-
expect(e).toBeInstanceOf(SignerError);
|
|
98
|
-
expect(e.message).toContain("lost");
|
|
99
|
-
});
|
|
100
|
-
test("SigningFailedError with Error cause", () => {
|
|
101
|
-
const cause = new Error("bad signature");
|
|
102
|
-
const e = new SigningFailedError(cause);
|
|
103
|
-
expect(e).toBeInstanceOf(SignerError);
|
|
104
|
-
expect(e.cause).toBe(cause);
|
|
105
|
-
expect(e.message).toContain("bad signature");
|
|
106
|
-
});
|
|
107
|
-
test("SigningFailedError with string cause", () => {
|
|
108
|
-
const e = new SigningFailedError("oops");
|
|
109
|
-
expect(e.message).toContain("oops");
|
|
110
|
-
});
|
|
111
|
-
test("SigningFailedError with custom message", () => {
|
|
112
|
-
const e = new SigningFailedError("oops", "custom msg");
|
|
113
|
-
expect(e.message).toBe("custom msg");
|
|
114
|
-
});
|
|
115
|
-
test("NoAccountsError", () => {
|
|
116
|
-
const e = new NoAccountsError("host");
|
|
117
|
-
expect(e).toBeInstanceOf(SignerError);
|
|
118
|
-
expect(e.provider).toBe("host");
|
|
119
|
-
expect(e.message).toContain("host");
|
|
120
|
-
});
|
|
121
|
-
test("NoAccountsError with custom message", () => {
|
|
122
|
-
const e = new NoAccountsError("dev", "none found");
|
|
123
|
-
expect(e.message).toBe("none found");
|
|
124
|
-
});
|
|
125
|
-
test("TimeoutError", () => {
|
|
126
|
-
const e = new TimeoutError("connect", 5e3);
|
|
127
|
-
expect(e).toBeInstanceOf(SignerError);
|
|
128
|
-
expect(e.operation).toBe("connect");
|
|
129
|
-
expect(e.ms).toBe(5e3);
|
|
130
|
-
expect(e.message).toContain("5000");
|
|
131
|
-
});
|
|
132
|
-
test("AccountNotFoundError", () => {
|
|
133
|
-
const e = new AccountNotFoundError("5GrwvaEF...");
|
|
134
|
-
expect(e).toBeInstanceOf(SignerError);
|
|
135
|
-
expect(e.address).toBe("5GrwvaEF...");
|
|
136
|
-
});
|
|
137
|
-
test("DestroyedError", () => {
|
|
138
|
-
const e = new DestroyedError();
|
|
139
|
-
expect(e).toBeInstanceOf(SignerError);
|
|
140
|
-
expect(e.message).toContain("destroyed");
|
|
141
|
-
});
|
|
142
|
-
test("all errors have stack traces", () => {
|
|
143
|
-
const e = new HostUnavailableError();
|
|
144
|
-
expect(e.stack).toBeDefined();
|
|
145
|
-
expect(e.stack).toContain("HostUnavailableError");
|
|
146
|
-
});
|
|
147
|
-
});
|
|
148
|
-
describe("type guards", () => {
|
|
149
|
-
test("isHostError returns true for host errors", () => {
|
|
150
|
-
expect(isHostError(new HostUnavailableError())).toBe(true);
|
|
151
|
-
expect(isHostError(new HostRejectedError())).toBe(true);
|
|
152
|
-
expect(isHostError(new HostDisconnectedError())).toBe(true);
|
|
153
|
-
});
|
|
154
|
-
test("isHostError returns false for non-host errors", () => {
|
|
155
|
-
expect(isHostError(new SigningFailedError("x"))).toBe(false);
|
|
156
|
-
expect(isHostError(new NoAccountsError("dev"))).toBe(false);
|
|
157
|
-
expect(isHostError(new TimeoutError("op", 100))).toBe(false);
|
|
158
|
-
expect(isHostError(new AccountNotFoundError("x"))).toBe(false);
|
|
159
|
-
expect(isHostError(new DestroyedError())).toBe(false);
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
// src/signer-manager.ts
|
|
165
|
-
import { getHostLocalStorage } from "@parity/product-sdk-host";
|
|
166
|
-
|
|
167
|
-
// src/providers/dev.ts
|
|
168
|
-
import { seedToAccount } from "@parity/product-sdk-keys";
|
|
169
|
-
import { createLogger } from "@parity/product-sdk-logger";
|
|
170
77
|
|
|
171
78
|
// src/types.ts
|
|
172
79
|
function ok(value) {
|
|
@@ -175,66 +82,6 @@ function ok(value) {
|
|
|
175
82
|
function err(error) {
|
|
176
83
|
return { ok: false, error };
|
|
177
84
|
}
|
|
178
|
-
if (void 0) {
|
|
179
|
-
const { test, expect, describe } = void 0;
|
|
180
|
-
describe("ok", () => {
|
|
181
|
-
test("produces ok result with value", () => {
|
|
182
|
-
const result = ok(42);
|
|
183
|
-
expect(result.ok).toBe(true);
|
|
184
|
-
expect(result).toEqual({ ok: true, value: 42 });
|
|
185
|
-
});
|
|
186
|
-
test("works with complex values", () => {
|
|
187
|
-
const result = ok({ name: "Alice", age: 30 });
|
|
188
|
-
expect(result.ok).toBe(true);
|
|
189
|
-
if (result.ok) {
|
|
190
|
-
expect(result.value.name).toBe("Alice");
|
|
191
|
-
}
|
|
192
|
-
});
|
|
193
|
-
test("works with null value", () => {
|
|
194
|
-
const result = ok(null);
|
|
195
|
-
expect(result).toEqual({ ok: true, value: null });
|
|
196
|
-
});
|
|
197
|
-
test("works with undefined value", () => {
|
|
198
|
-
const result = ok(void 0);
|
|
199
|
-
expect(result).toEqual({ ok: true, value: void 0 });
|
|
200
|
-
});
|
|
201
|
-
});
|
|
202
|
-
describe("err", () => {
|
|
203
|
-
test("produces error result", () => {
|
|
204
|
-
const result = err("something went wrong");
|
|
205
|
-
expect(result.ok).toBe(false);
|
|
206
|
-
expect(result).toEqual({ ok: false, error: "something went wrong" });
|
|
207
|
-
});
|
|
208
|
-
test("works with typed error objects", () => {
|
|
209
|
-
const error = { type: "HOST_UNAVAILABLE", message: "no host" };
|
|
210
|
-
const result = err(error);
|
|
211
|
-
expect(result.ok).toBe(false);
|
|
212
|
-
if (!result.ok) {
|
|
213
|
-
expect(result.error.type).toBe("HOST_UNAVAILABLE");
|
|
214
|
-
}
|
|
215
|
-
});
|
|
216
|
-
});
|
|
217
|
-
describe("Result type narrowing", () => {
|
|
218
|
-
test("ok narrows to value access", () => {
|
|
219
|
-
const result = ok(42);
|
|
220
|
-
if (result.ok) {
|
|
221
|
-
const value = result.value;
|
|
222
|
-
expect(value).toBe(42);
|
|
223
|
-
} else {
|
|
224
|
-
expect.unreachable("should be ok");
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
test("err narrows to error access", () => {
|
|
228
|
-
const result = err("fail");
|
|
229
|
-
if (!result.ok) {
|
|
230
|
-
const error = result.error;
|
|
231
|
-
expect(error).toBe("fail");
|
|
232
|
-
} else {
|
|
233
|
-
expect.unreachable("should be err");
|
|
234
|
-
}
|
|
235
|
-
});
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
85
|
|
|
239
86
|
// src/providers/dev.ts
|
|
240
87
|
var log = createLogger("signer:dev");
|
|
@@ -284,184 +131,6 @@ var DevProvider = class {
|
|
|
284
131
|
};
|
|
285
132
|
}
|
|
286
133
|
};
|
|
287
|
-
if (void 0) {
|
|
288
|
-
const { test, expect, describe } = void 0;
|
|
289
|
-
const ALICE_ADDRESS = "5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY";
|
|
290
|
-
describe("DevProvider", () => {
|
|
291
|
-
test("connect returns 6 accounts by default", async () => {
|
|
292
|
-
const provider = new DevProvider();
|
|
293
|
-
const result = await provider.connect();
|
|
294
|
-
expect(result.ok).toBe(true);
|
|
295
|
-
if (result.ok) {
|
|
296
|
-
expect(result.value).toHaveLength(6);
|
|
297
|
-
expect(result.value.map((a) => a.name)).toEqual([
|
|
298
|
-
"Alice",
|
|
299
|
-
"Bob",
|
|
300
|
-
"Charlie",
|
|
301
|
-
"Dave",
|
|
302
|
-
"Eve",
|
|
303
|
-
"Ferdie"
|
|
304
|
-
]);
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
|
-
test("all accounts have source 'dev'", async () => {
|
|
308
|
-
const provider = new DevProvider();
|
|
309
|
-
const result = await provider.connect();
|
|
310
|
-
if (result.ok) {
|
|
311
|
-
for (const account of result.value) {
|
|
312
|
-
expect(account.source).toBe("dev");
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
test("Alice has well-known address", async () => {
|
|
317
|
-
const provider = new DevProvider();
|
|
318
|
-
const result = await provider.connect();
|
|
319
|
-
if (result.ok) {
|
|
320
|
-
expect(result.value[0].address).toBe(ALICE_ADDRESS);
|
|
321
|
-
}
|
|
322
|
-
});
|
|
323
|
-
test("addresses are deterministic", async () => {
|
|
324
|
-
const a = new DevProvider();
|
|
325
|
-
const b = new DevProvider();
|
|
326
|
-
const ra = await a.connect();
|
|
327
|
-
const rb = await b.connect();
|
|
328
|
-
if (ra.ok && rb.ok) {
|
|
329
|
-
expect(ra.value.map((x) => x.address)).toEqual(rb.value.map((x) => x.address));
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
test("each account has 32-byte publicKey", async () => {
|
|
333
|
-
const provider = new DevProvider();
|
|
334
|
-
const result = await provider.connect();
|
|
335
|
-
if (result.ok) {
|
|
336
|
-
for (const account of result.value) {
|
|
337
|
-
expect(account.publicKey).toBeInstanceOf(Uint8Array);
|
|
338
|
-
expect(account.publicKey.length).toBe(32);
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
});
|
|
342
|
-
test("getSigner returns signer with matching publicKey", async () => {
|
|
343
|
-
const provider = new DevProvider();
|
|
344
|
-
const result = await provider.connect();
|
|
345
|
-
if (result.ok) {
|
|
346
|
-
for (const account of result.value) {
|
|
347
|
-
const signer = account.getSigner();
|
|
348
|
-
expect(signer.publicKey).toEqual(account.publicKey);
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
});
|
|
352
|
-
test("custom names subset", async () => {
|
|
353
|
-
const provider = new DevProvider({ names: ["Alice", "Bob"] });
|
|
354
|
-
const result = await provider.connect();
|
|
355
|
-
if (result.ok) {
|
|
356
|
-
expect(result.value).toHaveLength(2);
|
|
357
|
-
expect(result.value.map((a) => a.name)).toEqual(["Alice", "Bob"]);
|
|
358
|
-
}
|
|
359
|
-
});
|
|
360
|
-
test("custom mnemonic produces different addresses", async () => {
|
|
361
|
-
const customMnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
|
|
362
|
-
const defaultProvider = new DevProvider();
|
|
363
|
-
const customProvider = new DevProvider({ mnemonic: customMnemonic });
|
|
364
|
-
const defResult = await defaultProvider.connect();
|
|
365
|
-
const cusResult = await customProvider.connect();
|
|
366
|
-
if (defResult.ok && cusResult.ok) {
|
|
367
|
-
expect(defResult.value[0].address).not.toBe(cusResult.value[0].address);
|
|
368
|
-
}
|
|
369
|
-
});
|
|
370
|
-
test("custom ss58Prefix changes address encoding", async () => {
|
|
371
|
-
const generic = new DevProvider({ ss58Prefix: 42 });
|
|
372
|
-
const polkadot = new DevProvider({ ss58Prefix: 0 });
|
|
373
|
-
const rg = await generic.connect();
|
|
374
|
-
const rp = await polkadot.connect();
|
|
375
|
-
if (rg.ok && rp.ok) {
|
|
376
|
-
expect(rg.value[0].address).not.toBe(rp.value[0].address);
|
|
377
|
-
expect(rg.value[0].publicKey).toEqual(rp.value[0].publicKey);
|
|
378
|
-
}
|
|
379
|
-
});
|
|
380
|
-
test("disconnect is idempotent", () => {
|
|
381
|
-
const provider = new DevProvider();
|
|
382
|
-
provider.disconnect();
|
|
383
|
-
provider.disconnect();
|
|
384
|
-
});
|
|
385
|
-
test("onStatusChange returns no-op unsubscribe", () => {
|
|
386
|
-
const provider = new DevProvider();
|
|
387
|
-
const callback = () => {
|
|
388
|
-
};
|
|
389
|
-
const unsub = provider.onStatusChange(callback);
|
|
390
|
-
expect(typeof unsub).toBe("function");
|
|
391
|
-
unsub();
|
|
392
|
-
});
|
|
393
|
-
test("onAccountsChange returns no-op unsubscribe", () => {
|
|
394
|
-
const provider = new DevProvider();
|
|
395
|
-
const callback = () => {
|
|
396
|
-
};
|
|
397
|
-
const unsub = provider.onAccountsChange(callback);
|
|
398
|
-
expect(typeof unsub).toBe("function");
|
|
399
|
-
unsub();
|
|
400
|
-
});
|
|
401
|
-
test("type is 'dev'", () => {
|
|
402
|
-
const provider = new DevProvider();
|
|
403
|
-
expect(provider.type).toBe("dev");
|
|
404
|
-
});
|
|
405
|
-
test("empty names array returns zero accounts", async () => {
|
|
406
|
-
const provider = new DevProvider({ names: [] });
|
|
407
|
-
const result = await provider.connect();
|
|
408
|
-
if (result.ok) {
|
|
409
|
-
expect(result.value).toHaveLength(0);
|
|
410
|
-
}
|
|
411
|
-
});
|
|
412
|
-
test("default keyType is sr25519 (backward compatible)", async () => {
|
|
413
|
-
const provider = new DevProvider();
|
|
414
|
-
const result = await provider.connect();
|
|
415
|
-
if (result.ok) {
|
|
416
|
-
expect(result.value[0].address).toBe(ALICE_ADDRESS);
|
|
417
|
-
}
|
|
418
|
-
});
|
|
419
|
-
});
|
|
420
|
-
describe("DevProvider ed25519", () => {
|
|
421
|
-
test("ed25519 produces different addresses than sr25519", async () => {
|
|
422
|
-
const sr = new DevProvider({ keyType: "sr25519" });
|
|
423
|
-
const ed = new DevProvider({ keyType: "ed25519" });
|
|
424
|
-
const srResult = await sr.connect();
|
|
425
|
-
const edResult = await ed.connect();
|
|
426
|
-
if (srResult.ok && edResult.ok) {
|
|
427
|
-
expect(srResult.value[0].address).not.toBe(edResult.value[0].address);
|
|
428
|
-
}
|
|
429
|
-
});
|
|
430
|
-
test("ed25519 addresses are deterministic", async () => {
|
|
431
|
-
const a = new DevProvider({ keyType: "ed25519" });
|
|
432
|
-
const b = new DevProvider({ keyType: "ed25519" });
|
|
433
|
-
const ra = await a.connect();
|
|
434
|
-
const rb = await b.connect();
|
|
435
|
-
if (ra.ok && rb.ok) {
|
|
436
|
-
expect(ra.value.map((x) => x.address)).toEqual(rb.value.map((x) => x.address));
|
|
437
|
-
}
|
|
438
|
-
});
|
|
439
|
-
test("ed25519 getSigner has matching publicKey", async () => {
|
|
440
|
-
const provider = new DevProvider({ keyType: "ed25519" });
|
|
441
|
-
const result = await provider.connect();
|
|
442
|
-
if (result.ok) {
|
|
443
|
-
for (const account of result.value) {
|
|
444
|
-
const signer = account.getSigner();
|
|
445
|
-
expect(signer.publicKey).toEqual(account.publicKey);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
});
|
|
449
|
-
test("ed25519 accounts have 32-byte publicKey", async () => {
|
|
450
|
-
const provider = new DevProvider({ keyType: "ed25519" });
|
|
451
|
-
const result = await provider.connect();
|
|
452
|
-
if (result.ok) {
|
|
453
|
-
for (const account of result.value) {
|
|
454
|
-
expect(account.publicKey).toBeInstanceOf(Uint8Array);
|
|
455
|
-
expect(account.publicKey.length).toBe(32);
|
|
456
|
-
}
|
|
457
|
-
}
|
|
458
|
-
});
|
|
459
|
-
});
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
// src/providers/host.ts
|
|
463
|
-
import { deriveH160, ss58Encode } from "@parity/product-sdk-address";
|
|
464
|
-
import { createLogger as createLogger2 } from "@parity/product-sdk-logger";
|
|
465
134
|
|
|
466
135
|
// src/sleep.ts
|
|
467
136
|
function sleep(ms, signal) {
|
|
@@ -479,67 +148,6 @@ function sleep(ms, signal) {
|
|
|
479
148
|
signal?.addEventListener("abort", onDone, { once: true });
|
|
480
149
|
});
|
|
481
150
|
}
|
|
482
|
-
if (void 0) {
|
|
483
|
-
const { test, expect, describe, vi, beforeEach, afterEach } = void 0;
|
|
484
|
-
beforeEach(() => {
|
|
485
|
-
vi.useFakeTimers();
|
|
486
|
-
});
|
|
487
|
-
afterEach(() => {
|
|
488
|
-
vi.useRealTimers();
|
|
489
|
-
});
|
|
490
|
-
describe("sleep", () => {
|
|
491
|
-
test("resolves after specified duration", async () => {
|
|
492
|
-
let resolved = false;
|
|
493
|
-
sleep(100).then(() => {
|
|
494
|
-
resolved = true;
|
|
495
|
-
});
|
|
496
|
-
expect(resolved).toBe(false);
|
|
497
|
-
await vi.advanceTimersByTimeAsync(99);
|
|
498
|
-
expect(resolved).toBe(false);
|
|
499
|
-
await vi.advanceTimersByTimeAsync(1);
|
|
500
|
-
expect(resolved).toBe(true);
|
|
501
|
-
});
|
|
502
|
-
test("resolves immediately when signal is already aborted", async () => {
|
|
503
|
-
const controller = new AbortController();
|
|
504
|
-
controller.abort();
|
|
505
|
-
let resolved = false;
|
|
506
|
-
sleep(1e4, controller.signal).then(() => {
|
|
507
|
-
resolved = true;
|
|
508
|
-
});
|
|
509
|
-
await vi.advanceTimersByTimeAsync(0);
|
|
510
|
-
expect(resolved).toBe(true);
|
|
511
|
-
});
|
|
512
|
-
test("resolves early when signal is aborted during sleep", async () => {
|
|
513
|
-
const controller = new AbortController();
|
|
514
|
-
let resolved = false;
|
|
515
|
-
sleep(1e4, controller.signal).then(() => {
|
|
516
|
-
resolved = true;
|
|
517
|
-
});
|
|
518
|
-
await vi.advanceTimersByTimeAsync(50);
|
|
519
|
-
expect(resolved).toBe(false);
|
|
520
|
-
controller.abort();
|
|
521
|
-
await vi.advanceTimersByTimeAsync(0);
|
|
522
|
-
expect(resolved).toBe(true);
|
|
523
|
-
});
|
|
524
|
-
test("works without a signal", async () => {
|
|
525
|
-
let resolved = false;
|
|
526
|
-
sleep(50).then(() => {
|
|
527
|
-
resolved = true;
|
|
528
|
-
});
|
|
529
|
-
await vi.advanceTimersByTimeAsync(50);
|
|
530
|
-
expect(resolved).toBe(true);
|
|
531
|
-
});
|
|
532
|
-
test("cleans up abort listener after natural timer expiry", async () => {
|
|
533
|
-
const controller = new AbortController();
|
|
534
|
-
const addSpy = vi.spyOn(controller.signal, "addEventListener");
|
|
535
|
-
const removeSpy = vi.spyOn(controller.signal, "removeEventListener");
|
|
536
|
-
sleep(50, controller.signal);
|
|
537
|
-
expect(addSpy).toHaveBeenCalledTimes(1);
|
|
538
|
-
await vi.advanceTimersByTimeAsync(50);
|
|
539
|
-
expect(removeSpy).toHaveBeenCalledTimes(1);
|
|
540
|
-
});
|
|
541
|
-
});
|
|
542
|
-
}
|
|
543
151
|
|
|
544
152
|
// src/retry.ts
|
|
545
153
|
var DEFAULT_MAX_ATTEMPTS = 3;
|
|
@@ -569,135 +177,14 @@ async function withRetry(fn, options) {
|
|
|
569
177
|
}
|
|
570
178
|
return lastResult;
|
|
571
179
|
}
|
|
572
|
-
if (void 0) {
|
|
573
|
-
const { test, expect, describe, vi, beforeEach, afterEach } = void 0;
|
|
574
|
-
const { ok: ok2, err: err2 } = await null;
|
|
575
|
-
beforeEach(() => {
|
|
576
|
-
vi.useFakeTimers();
|
|
577
|
-
});
|
|
578
|
-
afterEach(() => {
|
|
579
|
-
vi.useRealTimers();
|
|
580
|
-
});
|
|
581
|
-
describe("withRetry", () => {
|
|
582
|
-
test("succeeds on first attempt with no delay", async () => {
|
|
583
|
-
const fn = vi.fn().mockResolvedValue(ok2("done"));
|
|
584
|
-
const promise = withRetry(fn);
|
|
585
|
-
const result = await promise;
|
|
586
|
-
expect(result).toEqual(ok2("done"));
|
|
587
|
-
expect(fn).toHaveBeenCalledTimes(1);
|
|
588
|
-
expect(fn).toHaveBeenCalledWith(0);
|
|
589
|
-
});
|
|
590
|
-
test("retries on failure and succeeds on second attempt", async () => {
|
|
591
|
-
const fn = vi.fn().mockResolvedValueOnce(err2("fail1")).mockResolvedValueOnce(ok2("success"));
|
|
592
|
-
const promise = withRetry(fn, { initialDelay: 100 });
|
|
593
|
-
await vi.advanceTimersByTimeAsync(100);
|
|
594
|
-
const result = await promise;
|
|
595
|
-
expect(result).toEqual(ok2("success"));
|
|
596
|
-
expect(fn).toHaveBeenCalledTimes(2);
|
|
597
|
-
expect(fn).toHaveBeenNthCalledWith(1, 0);
|
|
598
|
-
expect(fn).toHaveBeenNthCalledWith(2, 1);
|
|
599
|
-
});
|
|
600
|
-
test("exhausts maxAttempts and returns last error", async () => {
|
|
601
|
-
const fn = vi.fn().mockResolvedValueOnce(err2("fail1")).mockResolvedValueOnce(err2("fail2")).mockResolvedValueOnce(err2("fail3"));
|
|
602
|
-
const promise = withRetry(fn, {
|
|
603
|
-
maxAttempts: 3,
|
|
604
|
-
initialDelay: 100,
|
|
605
|
-
backoffMultiplier: 2
|
|
606
|
-
});
|
|
607
|
-
await vi.advanceTimersByTimeAsync(100);
|
|
608
|
-
await vi.advanceTimersByTimeAsync(200);
|
|
609
|
-
const result = await promise;
|
|
610
|
-
expect(result).toEqual(err2("fail3"));
|
|
611
|
-
expect(fn).toHaveBeenCalledTimes(3);
|
|
612
|
-
});
|
|
613
|
-
test("respects AbortSignal cancellation", async () => {
|
|
614
|
-
const controller = new AbortController();
|
|
615
|
-
const fn = vi.fn().mockResolvedValue(err2("fail"));
|
|
616
|
-
const promise = withRetry(fn, {
|
|
617
|
-
maxAttempts: 5,
|
|
618
|
-
initialDelay: 1e3,
|
|
619
|
-
signal: controller.signal
|
|
620
|
-
});
|
|
621
|
-
await vi.advanceTimersByTimeAsync(0);
|
|
622
|
-
controller.abort();
|
|
623
|
-
await vi.advanceTimersByTimeAsync(0);
|
|
624
|
-
const result = await promise;
|
|
625
|
-
expect(result.ok).toBe(false);
|
|
626
|
-
expect(fn.mock.calls.length).toBeLessThan(5);
|
|
627
|
-
});
|
|
628
|
-
test("backoff delay increases correctly", async () => {
|
|
629
|
-
const fn = vi.fn().mockResolvedValueOnce(err2("e1")).mockResolvedValueOnce(err2("e2")).mockResolvedValueOnce(err2("e3")).mockResolvedValueOnce(ok2("done"));
|
|
630
|
-
const promise = withRetry(fn, {
|
|
631
|
-
maxAttempts: 4,
|
|
632
|
-
initialDelay: 100,
|
|
633
|
-
backoffMultiplier: 2
|
|
634
|
-
});
|
|
635
|
-
await vi.advanceTimersByTimeAsync(100);
|
|
636
|
-
await vi.advanceTimersByTimeAsync(200);
|
|
637
|
-
await vi.advanceTimersByTimeAsync(400);
|
|
638
|
-
const result = await promise;
|
|
639
|
-
expect(result).toEqual(ok2("done"));
|
|
640
|
-
expect(fn).toHaveBeenCalledTimes(4);
|
|
641
|
-
});
|
|
642
|
-
test("caps delay at maxDelay", async () => {
|
|
643
|
-
const fn = vi.fn().mockImplementation(async () => {
|
|
644
|
-
return err2("fail");
|
|
645
|
-
});
|
|
646
|
-
const promise = withRetry(fn, {
|
|
647
|
-
maxAttempts: 4,
|
|
648
|
-
initialDelay: 5e3,
|
|
649
|
-
backoffMultiplier: 3,
|
|
650
|
-
maxDelay: 8e3
|
|
651
|
-
});
|
|
652
|
-
await vi.advanceTimersByTimeAsync(5e3);
|
|
653
|
-
await vi.advanceTimersByTimeAsync(8e3);
|
|
654
|
-
await vi.advanceTimersByTimeAsync(8e3);
|
|
655
|
-
const result = await promise;
|
|
656
|
-
expect(result.ok).toBe(false);
|
|
657
|
-
expect(fn).toHaveBeenCalledTimes(4);
|
|
658
|
-
});
|
|
659
|
-
test("attempt number is passed correctly to fn", async () => {
|
|
660
|
-
const attempts = [];
|
|
661
|
-
const fn = vi.fn().mockImplementation(async (attempt) => {
|
|
662
|
-
attempts.push(attempt);
|
|
663
|
-
return attempt < 2 ? err2("retry") : ok2("done");
|
|
664
|
-
});
|
|
665
|
-
const promise = withRetry(fn, {
|
|
666
|
-
maxAttempts: 3,
|
|
667
|
-
initialDelay: 50
|
|
668
|
-
});
|
|
669
|
-
await vi.advanceTimersByTimeAsync(50);
|
|
670
|
-
await vi.advanceTimersByTimeAsync(100);
|
|
671
|
-
await promise;
|
|
672
|
-
expect(attempts).toEqual([0, 1, 2]);
|
|
673
|
-
});
|
|
674
|
-
test("single attempt with maxAttempts=1", async () => {
|
|
675
|
-
const fn = vi.fn().mockResolvedValue(err2("fail"));
|
|
676
|
-
const result = await withRetry(fn, { maxAttempts: 1 });
|
|
677
|
-
expect(result).toEqual(err2("fail"));
|
|
678
|
-
expect(fn).toHaveBeenCalledTimes(1);
|
|
679
|
-
});
|
|
680
|
-
test("signal already aborted before first attempt \u2014 fn still called once", async () => {
|
|
681
|
-
const controller = new AbortController();
|
|
682
|
-
controller.abort();
|
|
683
|
-
const fn = vi.fn().mockResolvedValue(err2("fail"));
|
|
684
|
-
const result = await withRetry(fn, {
|
|
685
|
-
maxAttempts: 3,
|
|
686
|
-
signal: controller.signal
|
|
687
|
-
});
|
|
688
|
-
expect(result.ok).toBe(false);
|
|
689
|
-
expect(fn).toHaveBeenCalledTimes(1);
|
|
690
|
-
});
|
|
691
|
-
});
|
|
692
|
-
}
|
|
693
180
|
|
|
694
181
|
// src/providers/host.ts
|
|
695
|
-
var log2 =
|
|
182
|
+
var log2 = createLogger("signer:host");
|
|
696
183
|
async function defaultLoadSdk() {
|
|
697
|
-
return await import(
|
|
184
|
+
return await import('@novasamatech/product-sdk');
|
|
698
185
|
}
|
|
699
186
|
async function defaultLoadHostApiEnum() {
|
|
700
|
-
return await import(
|
|
187
|
+
return await import('@novasamatech/host-api');
|
|
701
188
|
}
|
|
702
189
|
var HostProvider = class {
|
|
703
190
|
type = "host";
|
|
@@ -897,7 +384,7 @@ var HostProvider = class {
|
|
|
897
384
|
this.accountsProvider = provider;
|
|
898
385
|
let rawAccounts;
|
|
899
386
|
try {
|
|
900
|
-
rawAccounts = await provider.
|
|
387
|
+
rawAccounts = await provider.getLegacyAccounts().match(
|
|
901
388
|
(accounts2) => accounts2,
|
|
902
389
|
(error) => {
|
|
903
390
|
throw new Error(`Host rejected account request: ${formatError(error)}`);
|
|
@@ -961,7 +448,7 @@ var HostProvider = class {
|
|
|
961
448
|
if (!this.accountsProvider) {
|
|
962
449
|
throw new Error("Host provider is disconnected");
|
|
963
450
|
}
|
|
964
|
-
return this.accountsProvider.
|
|
451
|
+
return this.accountsProvider.getLegacyAccountSigner({
|
|
965
452
|
dotNsIdentifier: "",
|
|
966
453
|
derivationIndex: 0,
|
|
967
454
|
publicKey: raw.publicKey
|
|
@@ -977,157 +464,9 @@ function formatError(error) {
|
|
|
977
464
|
}
|
|
978
465
|
return String(error);
|
|
979
466
|
}
|
|
980
|
-
if (void 0) {
|
|
981
|
-
let createMockProvider = function(options = {}) {
|
|
982
|
-
const accounts = options.accounts ?? [];
|
|
983
|
-
const shouldReject = options.shouldReject ?? false;
|
|
984
|
-
const mockSigner = {
|
|
985
|
-
publicKey: new Uint8Array(32).fill(187)
|
|
986
|
-
};
|
|
987
|
-
return {
|
|
988
|
-
getNonProductAccounts: vi.fn().mockReturnValue({
|
|
989
|
-
match: async (onOk, onErr) => {
|
|
990
|
-
if (shouldReject) {
|
|
991
|
-
return onErr(options.error ?? "Unknown");
|
|
992
|
-
}
|
|
993
|
-
return onOk(accounts);
|
|
994
|
-
}
|
|
995
|
-
}),
|
|
996
|
-
getNonProductAccountSigner: vi.fn().mockReturnValue(mockSigner),
|
|
997
|
-
getProductAccount: vi.fn().mockReturnValue({
|
|
998
|
-
match: async (onOk, onErr) => {
|
|
999
|
-
if (shouldReject) {
|
|
1000
|
-
return onErr(options.error ?? "Unknown");
|
|
1001
|
-
}
|
|
1002
|
-
return onOk(accounts[0] ?? { publicKey: new Uint8Array(32), name: void 0 });
|
|
1003
|
-
}
|
|
1004
|
-
}),
|
|
1005
|
-
getProductAccountSigner: vi.fn().mockReturnValue(mockSigner),
|
|
1006
|
-
getProductAccountAlias: vi.fn().mockReturnValue({
|
|
1007
|
-
match: async (onOk, onErr) => {
|
|
1008
|
-
if (shouldReject) {
|
|
1009
|
-
return onErr(options.error ?? "Unknown");
|
|
1010
|
-
}
|
|
1011
|
-
return onOk({
|
|
1012
|
-
context: new Uint8Array(32).fill(1),
|
|
1013
|
-
alias: new Uint8Array(64).fill(2)
|
|
1014
|
-
});
|
|
1015
|
-
}
|
|
1016
|
-
}),
|
|
1017
|
-
createRingVRFProof: vi.fn().mockReturnValue({
|
|
1018
|
-
match: async (onOk, onErr) => {
|
|
1019
|
-
if (shouldReject) {
|
|
1020
|
-
return onErr(options.error ?? "Unknown");
|
|
1021
|
-
}
|
|
1022
|
-
return onOk(new Uint8Array(128).fill(3));
|
|
1023
|
-
}
|
|
1024
|
-
}),
|
|
1025
|
-
subscribeAccountConnectionStatus: vi.fn().mockReturnValue(() => {
|
|
1026
|
-
})
|
|
1027
|
-
};
|
|
1028
|
-
}, createMockSdk = function(mockProvider, opts) {
|
|
1029
|
-
return {
|
|
1030
|
-
createAccountsProvider: () => mockProvider,
|
|
1031
|
-
...opts?.hostApi ? { hostApi: opts.hostApi } : {}
|
|
1032
|
-
};
|
|
1033
|
-
}, fakeResult = function(value, error) {
|
|
1034
|
-
return {
|
|
1035
|
-
match: async (onOk, onErr) => {
|
|
1036
|
-
if (error !== void 0) return onErr(error);
|
|
1037
|
-
return onOk(value);
|
|
1038
|
-
}
|
|
1039
|
-
};
|
|
1040
|
-
};
|
|
1041
|
-
createMockProvider2 = createMockProvider, createMockSdk2 = createMockSdk, fakeResult2 = fakeResult;
|
|
1042
|
-
const { test, expect, describe, vi, beforeEach } = void 0;
|
|
1043
|
-
const fakeHostApiEnum = {
|
|
1044
|
-
enumValue: (version, value) => ({ version, value })
|
|
1045
|
-
};
|
|
1046
|
-
beforeEach(() => {
|
|
1047
|
-
vi.restoreAllMocks();
|
|
1048
|
-
});
|
|
1049
|
-
describe("HostProvider", () => {
|
|
1050
|
-
test("returns HOST_UNAVAILABLE when SDK load fails", async () => {
|
|
1051
|
-
const provider = new HostProvider({
|
|
1052
|
-
maxRetries: 1,
|
|
1053
|
-
loadSdk: () => Promise.reject(new Error("Cannot find module"))
|
|
1054
|
-
});
|
|
1055
|
-
const result = await provider.connect();
|
|
1056
|
-
expect(result.ok).toBe(false);
|
|
1057
|
-
if (!result.ok) {
|
|
1058
|
-
expect(result.error).toBeInstanceOf(HostUnavailableError);
|
|
1059
|
-
expect(result.error.message).toContain("Cannot find module");
|
|
1060
|
-
}
|
|
1061
|
-
});
|
|
1062
|
-
test("returns HOST_REJECTED when getNonProductAccounts fails", async () => {
|
|
1063
|
-
const mockProvider = createMockProvider({ shouldReject: true, error: "Rejected" });
|
|
1064
|
-
const provider = new HostProvider({
|
|
1065
|
-
maxRetries: 1,
|
|
1066
|
-
loadSdk: () => Promise.resolve(createMockSdk(mockProvider))
|
|
1067
|
-
});
|
|
1068
|
-
const result = await provider.connect();
|
|
1069
|
-
expect(result.ok).toBe(false);
|
|
1070
|
-
if (!result.ok) {
|
|
1071
|
-
expect(result.error).toBeInstanceOf(HostRejectedError);
|
|
1072
|
-
}
|
|
1073
|
-
});
|
|
1074
|
-
test("returns NO_ACCOUNTS when host returns empty list", async () => {
|
|
1075
|
-
const mockProvider = createMockProvider({ accounts: [] });
|
|
1076
|
-
const provider = new HostProvider({
|
|
1077
|
-
maxRetries: 1,
|
|
1078
|
-
loadSdk: () => Promise.resolve(createMockSdk(mockProvider))
|
|
1079
|
-
});
|
|
1080
|
-
const result = await provider.connect();
|
|
1081
|
-
expect(result.ok).toBe(false);
|
|
1082
|
-
if (!result.ok) {
|
|
1083
|
-
expect(result.error).toBeInstanceOf(NoAccountsError);
|
|
1084
|
-
}
|
|
1085
|
-
});
|
|
1086
|
-
test("maps accounts correctly on success", async () => {
|
|
1087
|
-
const rawAccounts = [
|
|
1088
|
-
{ publicKey: new Uint8Array(32).fill(170), name: "Alice" },
|
|
1089
|
-
{ publicKey: new Uint8Array(32).fill(187), name: void 0 }
|
|
1090
|
-
];
|
|
1091
|
-
const mockProvider = createMockProvider({ accounts: rawAccounts });
|
|
1092
|
-
const provider = new HostProvider({
|
|
1093
|
-
maxRetries: 1,
|
|
1094
|
-
loadSdk: () => Promise.resolve(createMockSdk(mockProvider))
|
|
1095
|
-
});
|
|
1096
|
-
const result = await provider.connect();
|
|
1097
|
-
expect(result.ok).toBe(true);
|
|
1098
|
-
if (result.ok) {
|
|
1099
|
-
expect(result.value).toHaveLength(2);
|
|
1100
|
-
expect(result.value[0].name).toBe("Alice");
|
|
1101
|
-
expect(result.value[0].source).toBe("host");
|
|
1102
|
-
expect(result.value[0].publicKey).toEqual(rawAccounts[0].publicKey);
|
|
1103
|
-
expect(result.value[1].name).toBeNull();
|
|
1104
|
-
}
|
|
1105
|
-
});
|
|
1106
|
-
test("disconnect is idempotent", () => {
|
|
1107
|
-
const provider = new HostProvider();
|
|
1108
|
-
provider.disconnect();
|
|
1109
|
-
provider.disconnect();
|
|
1110
|
-
});
|
|
1111
|
-
test("type is 'host'", () => {
|
|
1112
|
-
const provider = new HostProvider();
|
|
1113
|
-
expect(provider.type).toBe("host");
|
|
1114
|
-
});
|
|
1115
|
-
test("onAccountsChange adds and removes listener", () => {
|
|
1116
|
-
const provider = new HostProvider();
|
|
1117
|
-
const cb = () => {
|
|
1118
|
-
};
|
|
1119
|
-
const unsub = provider.onAccountsChange(cb);
|
|
1120
|
-
expect(typeof unsub).toBe("function");
|
|
1121
|
-
unsub();
|
|
1122
|
-
});
|
|
1123
|
-
});
|
|
1124
|
-
}
|
|
1125
|
-
var createMockProvider2;
|
|
1126
|
-
var createMockSdk2;
|
|
1127
|
-
var fakeResult2;
|
|
1128
467
|
|
|
1129
468
|
// src/signer-manager.ts
|
|
1130
|
-
var log3 =
|
|
469
|
+
var log3 = createLogger("signer");
|
|
1131
470
|
var DEFAULT_HOST_TIMEOUT = 1e4;
|
|
1132
471
|
var DEFAULT_MAX_RETRIES = 3;
|
|
1133
472
|
var DEFAULT_SS58_PREFIX = 42;
|
|
@@ -1556,23 +895,7 @@ var SignerManager = class {
|
|
|
1556
895
|
}
|
|
1557
896
|
}
|
|
1558
897
|
};
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
DevProvider,
|
|
1563
|
-
HostDisconnectedError,
|
|
1564
|
-
HostProvider,
|
|
1565
|
-
HostRejectedError,
|
|
1566
|
-
HostUnavailableError,
|
|
1567
|
-
NoAccountsError,
|
|
1568
|
-
SignerError,
|
|
1569
|
-
SignerManager,
|
|
1570
|
-
SigningFailedError,
|
|
1571
|
-
TimeoutError,
|
|
1572
|
-
err,
|
|
1573
|
-
isHostError,
|
|
1574
|
-
ok,
|
|
1575
|
-
sleep,
|
|
1576
|
-
withRetry
|
|
1577
|
-
};
|
|
898
|
+
|
|
899
|
+
export { AccountNotFoundError, DestroyedError, DevProvider, HostDisconnectedError, HostProvider, HostRejectedError, HostUnavailableError, NoAccountsError, SignerError, SignerManager, SigningFailedError, TimeoutError, err, isHostError, ok, sleep, withRetry };
|
|
900
|
+
//# sourceMappingURL=index.js.map
|
|
1578
901
|
//# sourceMappingURL=index.js.map
|