@invonetwork/web-sdk 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -98,11 +98,11 @@ var _Http = class _Http {
98
98
  * (e.g. single-use WebAuthn assertions) are NEVER auto-retried.
99
99
  */
100
100
  async post(path, body, auth, opts) {
101
- return this.request("POST", path, body, auth, opts?.idempotent ?? false);
101
+ return this.request("POST", path, body, auth, opts?.idempotent ?? false, opts?.signal);
102
102
  }
103
103
  // GET is always idempotent → safe to retry.
104
- async get(path, auth) {
105
- return this.request("GET", path, void 0, auth, true);
104
+ async get(path, auth, opts) {
105
+ return this.request("GET", path, void 0, auth, true, opts?.signal);
106
106
  }
107
107
  authHeaders(auth) {
108
108
  switch (auth.kind) {
@@ -114,7 +114,7 @@ var _Http = class _Http {
114
114
  return {};
115
115
  }
116
116
  }
117
- async request(method, path, body, auth, idempotent) {
117
+ async request(method, path, body, auth, idempotent, signal) {
118
118
  const url = `${this.baseUrl}${path}`;
119
119
  const headers = {
120
120
  Accept: "application/json",
@@ -124,10 +124,13 @@ var _Http = class _Http {
124
124
  if (body !== void 0) headers["Content-Type"] = "application/json";
125
125
  const payload = body !== void 0 ? JSON.stringify(body) : void 0;
126
126
  for (let attempt = 0; ; attempt++) {
127
+ if (signal?.aborted) throw abortError(path);
127
128
  const start = Date.now();
128
129
  this.fire("onRequest", { method, url, attempt });
129
130
  const controller = new AbortController();
130
131
  const timer = setTimeout(() => controller.abort(), this.timeoutMs);
132
+ const onAbort = () => controller.abort();
133
+ signal?.addEventListener("abort", onAbort, { once: true });
131
134
  let res;
132
135
  let networkError;
133
136
  try {
@@ -140,12 +143,14 @@ var _Http = class _Http {
140
143
  });
141
144
  } finally {
142
145
  clearTimeout(timer);
146
+ signal?.removeEventListener("abort", onAbort);
143
147
  }
144
148
  if (networkError) {
149
+ if (signal?.aborted) throw abortError(path);
145
150
  const willRetry = idempotent && attempt < this.maxRetries;
146
151
  this.fire("onError", { method, url, attempt, error: networkError, willRetry });
147
152
  if (willRetry) {
148
- await sleep(this.backoff(attempt));
153
+ await sleep(this.backoff(attempt), signal);
149
154
  continue;
150
155
  }
151
156
  throw networkError;
@@ -181,7 +186,7 @@ var _Http = class _Http {
181
186
  }
182
187
  this.fire("onError", { method, url, attempt, error: err, willRetry: wait !== void 0 });
183
188
  if (wait !== void 0) {
184
- await sleep(wait);
189
+ await sleep(wait, signal);
185
190
  continue;
186
191
  }
187
192
  throw err;
@@ -207,8 +212,21 @@ var _Http = class _Http {
207
212
  /** HTTP statuses worth retrying — rate limit + transient gateway/server errors. */
208
213
  _Http.RETRIABLE_STATUS = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
209
214
  var Http = _Http;
210
- function sleep(ms) {
211
- return new Promise((resolve) => setTimeout(resolve, ms));
215
+ function sleep(ms, signal) {
216
+ return new Promise((resolve) => {
217
+ if (signal?.aborted) return resolve();
218
+ const timer = setTimeout(done, ms);
219
+ const onAbort = () => done();
220
+ function done() {
221
+ clearTimeout(timer);
222
+ signal?.removeEventListener("abort", onAbort);
223
+ resolve();
224
+ }
225
+ signal?.addEventListener("abort", onAbort, { once: true });
226
+ });
227
+ }
228
+ function abortError(path) {
229
+ return new InvoError({ message: `Request to ${path} was aborted`, code: "ABORTED", status: 0 });
212
230
  }
213
231
  function pickRequestId(headers) {
214
232
  if (!headers || typeof headers.get !== "function") return void 0;
@@ -333,38 +351,43 @@ var InvoClient = class {
333
351
  }
334
352
  }
335
353
  /** Enroll a passkey for the token's identity (register/begin -> create() -> register/complete). */
336
- async enrollPasskey() {
354
+ async enrollPasskey(opts) {
337
355
  this.assertWebAuthn();
356
+ const signal = opts?.signal;
338
357
  return this.withTokenRetry(async () => {
339
358
  const options = await this.post(
340
- "/api/sdk/webauthn/register/begin"
359
+ "/api/sdk/webauthn/register/begin",
360
+ void 0,
361
+ signal
341
362
  );
342
363
  const cred = await navigator.credentials.create({
343
- publicKey: toCreationOptions(options)
364
+ publicKey: toCreationOptions(options),
365
+ signal
344
366
  });
345
367
  if (!cred) throw new Error("Passkey creation was cancelled or returned no credential.");
346
368
  const raw = await this.post(
347
369
  "/api/sdk/webauthn/register/complete",
348
- { credential: registrationToJSON(cred) }
370
+ { credential: registrationToJSON(cred) },
371
+ signal
349
372
  );
350
373
  return { status: String(raw["status"] ?? ""), device: raw["device"] ?? null, raw };
351
374
  });
352
375
  }
353
376
  /** Approve a SEND with the player's passkey. */
354
- async approveSend(transactionId) {
355
- return this.approve("send", transactionId);
377
+ async approveSend(transactionId, opts) {
378
+ return this.approve("send", transactionId, opts);
356
379
  }
357
380
  /** Approve a TRANSFER with the player's passkey (returns the sender's claim code). */
358
- async approveTransfer(transactionId) {
359
- return this.approve("transfers", transactionId);
381
+ async approveTransfer(transactionId, opts) {
382
+ return this.approve("transfers", transactionId, opts);
360
383
  }
361
384
  /** Recipient self-claims a SEND with their passkey. */
362
- async confirmReceiptSend(transactionId) {
363
- return this.confirmReceipt("send", transactionId);
385
+ async confirmReceiptSend(transactionId, opts) {
386
+ return this.confirmReceipt("send", transactionId, opts);
364
387
  }
365
388
  /** Recipient self-claims a TRANSFER with their passkey. */
366
- async confirmReceiptTransfer(transactionId) {
367
- return this.confirmReceipt("transfers", transactionId);
389
+ async confirmReceiptTransfer(transactionId, opts) {
390
+ return this.confirmReceipt("transfers", transactionId, opts);
368
391
  }
369
392
  /**
370
393
  * Interchangeable methods (§4.6): prove an *already-enrolled* method (e.g. the
@@ -374,15 +397,19 @@ var InvoClient = class {
374
397
  *
375
398
  * begin -> navigator.credentials.get() -> complete with { link_id, webauthn_assertion }.
376
399
  */
377
- async linkDevice(linkId) {
400
+ async linkDevice(linkId, opts) {
378
401
  if (!linkId) throw new Error("linkDevice requires a `linkId`.");
402
+ const signal = opts?.signal;
379
403
  return this.withTokenRetry(async () => {
380
- const assertion = await this.runAssertion("/api/sdk/device/link/webauthn/begin", {
381
- link_id: linkId
382
- });
404
+ const assertion = await this.runAssertion(
405
+ "/api/sdk/device/link/webauthn/begin",
406
+ { link_id: linkId },
407
+ signal
408
+ );
383
409
  const raw = await this.post(
384
410
  "/api/sdk/device/link/webauthn/complete",
385
- { link_id: linkId, webauthn_assertion: assertion }
411
+ { link_id: linkId, webauthn_assertion: assertion },
412
+ signal
386
413
  );
387
414
  return { status: String(raw["status"] ?? ""), raw };
388
415
  });
@@ -390,8 +417,8 @@ var InvoClient = class {
390
417
  // --- internals ---
391
418
  /** POST with the current player token. Token-expiry retry is handled one level
392
419
  * up by withTokenRetry (which re-runs the whole ceremony, not a single call). */
393
- async post(path, body) {
394
- return this.http.post(path, body, this.auth);
420
+ async post(path, body, signal) {
421
+ return this.http.post(path, body, this.auth, { signal });
395
422
  }
396
423
  /**
397
424
  * Run a whole flow, retrying it ONCE if any call fails with SDK_TOKEN_EXPIRED
@@ -422,22 +449,29 @@ var InvoClient = class {
422
449
  this.auth = { kind: "bearer", token: fresh };
423
450
  return true;
424
451
  }
425
- async runAssertion(beginPath, beginBody) {
452
+ async runAssertion(beginPath, beginBody, signal) {
426
453
  this.assertWebAuthn();
427
- const options = await this.post(beginPath, beginBody);
454
+ const options = await this.post(beginPath, beginBody, signal);
428
455
  const cred = await navigator.credentials.get({
429
- publicKey: toRequestOptions(options)
456
+ publicKey: toRequestOptions(options),
457
+ signal
430
458
  });
431
459
  if (!cred) throw new Error("Passkey assertion was cancelled or returned no credential.");
432
460
  return assertionToJSON(cred);
433
461
  }
434
- async approve(flow, transactionId) {
462
+ async approve(flow, transactionId, opts) {
435
463
  const id = encodeURIComponent(transactionId);
464
+ const signal = opts?.signal;
436
465
  return this.withTokenRetry(async () => {
437
- const assertion = await this.runAssertion(`/api/sdk/${flow}/${id}/approve/webauthn/begin`);
466
+ const assertion = await this.runAssertion(
467
+ `/api/sdk/${flow}/${id}/approve/webauthn/begin`,
468
+ void 0,
469
+ signal
470
+ );
438
471
  const raw = await this.post(
439
472
  `/api/sdk/${flow}/${id}/approve`,
440
- { webauthn_assertion: assertion }
473
+ { webauthn_assertion: assertion },
474
+ signal
441
475
  );
442
476
  return {
443
477
  status: String(raw["status"] ?? ""),
@@ -449,15 +483,19 @@ var InvoClient = class {
449
483
  };
450
484
  });
451
485
  }
452
- async confirmReceipt(flow, transactionId) {
486
+ async confirmReceipt(flow, transactionId, opts) {
453
487
  const id = encodeURIComponent(transactionId);
488
+ const signal = opts?.signal;
454
489
  return this.withTokenRetry(async () => {
455
490
  const assertion = await this.runAssertion(
456
- `/api/sdk/${flow}/${id}/confirm-receipt/webauthn/begin`
491
+ `/api/sdk/${flow}/${id}/confirm-receipt/webauthn/begin`,
492
+ void 0,
493
+ signal
457
494
  );
458
495
  const raw = await this.post(
459
496
  `/api/sdk/${flow}/${id}/confirm-receipt`,
460
- { webauthn_assertion: assertion }
497
+ { webauthn_assertion: assertion },
498
+ signal
461
499
  );
462
500
  return { status: String(raw["status"] ?? ""), raw };
463
501
  });
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as ClientConfig, A as ApproveResult, a as ConfirmReceiptResult, L as LinkDeviceResult } from './types-CBkoUymV.cjs';
2
- export { I as InvoError, b as InvoErrorInfo, c as InvoHooks, d as InvoRequestInfo, e as InvoResponseInfo, R as Rail, V as VerificationMethod } from './types-CBkoUymV.cjs';
1
+ import { C as ClientConfig, a as CallOptions, A as ApproveResult, b as ConfirmReceiptResult, L as LinkDeviceResult } from './types-CBMLNwbe.cjs';
2
+ export { I as InvoError, c as InvoErrorInfo, d as InvoHooks, e as InvoRequestInfo, f as InvoResponseInfo, R as Rail, V as VerificationMethod } from './types-CBMLNwbe.cjs';
3
3
 
4
4
  declare class InvoClient {
5
5
  private readonly http;
@@ -10,19 +10,19 @@ declare class InvoClient {
10
10
  constructor(config: ClientConfig);
11
11
  private assertWebAuthn;
12
12
  /** Enroll a passkey for the token's identity (register/begin -> create() -> register/complete). */
13
- enrollPasskey(): Promise<{
13
+ enrollPasskey(opts?: CallOptions): Promise<{
14
14
  status: string;
15
15
  device: unknown;
16
16
  raw: Record<string, unknown>;
17
17
  }>;
18
18
  /** Approve a SEND with the player's passkey. */
19
- approveSend(transactionId: string): Promise<ApproveResult>;
19
+ approveSend(transactionId: string, opts?: CallOptions): Promise<ApproveResult>;
20
20
  /** Approve a TRANSFER with the player's passkey (returns the sender's claim code). */
21
- approveTransfer(transactionId: string): Promise<ApproveResult>;
21
+ approveTransfer(transactionId: string, opts?: CallOptions): Promise<ApproveResult>;
22
22
  /** Recipient self-claims a SEND with their passkey. */
23
- confirmReceiptSend(transactionId: string): Promise<ConfirmReceiptResult>;
23
+ confirmReceiptSend(transactionId: string, opts?: CallOptions): Promise<ConfirmReceiptResult>;
24
24
  /** Recipient self-claims a TRANSFER with their passkey. */
25
- confirmReceiptTransfer(transactionId: string): Promise<ConfirmReceiptResult>;
25
+ confirmReceiptTransfer(transactionId: string, opts?: CallOptions): Promise<ConfirmReceiptResult>;
26
26
  /**
27
27
  * Interchangeable methods (§4.6): prove an *already-enrolled* method (e.g. the
28
28
  * INVO app device key) to authorize adding a new partner passkey. The returned
@@ -31,7 +31,7 @@ declare class InvoClient {
31
31
  *
32
32
  * begin -> navigator.credentials.get() -> complete with { link_id, webauthn_assertion }.
33
33
  */
34
- linkDevice(linkId: string): Promise<LinkDeviceResult>;
34
+ linkDevice(linkId: string, opts?: CallOptions): Promise<LinkDeviceResult>;
35
35
  /** POST with the current player token. Token-expiry retry is handled one level
36
36
  * up by withTokenRetry (which re-runs the whole ceremony, not a single call). */
37
37
  private post;
@@ -49,4 +49,4 @@ declare class InvoClient {
49
49
  private confirmReceipt;
50
50
  }
51
51
 
52
- export { ApproveResult, ClientConfig, ConfirmReceiptResult, InvoClient, LinkDeviceResult };
52
+ export { ApproveResult, CallOptions, ClientConfig, ConfirmReceiptResult, InvoClient, LinkDeviceResult };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { C as ClientConfig, A as ApproveResult, a as ConfirmReceiptResult, L as LinkDeviceResult } from './types-CBkoUymV.js';
2
- export { I as InvoError, b as InvoErrorInfo, c as InvoHooks, d as InvoRequestInfo, e as InvoResponseInfo, R as Rail, V as VerificationMethod } from './types-CBkoUymV.js';
1
+ import { C as ClientConfig, a as CallOptions, A as ApproveResult, b as ConfirmReceiptResult, L as LinkDeviceResult } from './types-CBMLNwbe.js';
2
+ export { I as InvoError, c as InvoErrorInfo, d as InvoHooks, e as InvoRequestInfo, f as InvoResponseInfo, R as Rail, V as VerificationMethod } from './types-CBMLNwbe.js';
3
3
 
4
4
  declare class InvoClient {
5
5
  private readonly http;
@@ -10,19 +10,19 @@ declare class InvoClient {
10
10
  constructor(config: ClientConfig);
11
11
  private assertWebAuthn;
12
12
  /** Enroll a passkey for the token's identity (register/begin -> create() -> register/complete). */
13
- enrollPasskey(): Promise<{
13
+ enrollPasskey(opts?: CallOptions): Promise<{
14
14
  status: string;
15
15
  device: unknown;
16
16
  raw: Record<string, unknown>;
17
17
  }>;
18
18
  /** Approve a SEND with the player's passkey. */
19
- approveSend(transactionId: string): Promise<ApproveResult>;
19
+ approveSend(transactionId: string, opts?: CallOptions): Promise<ApproveResult>;
20
20
  /** Approve a TRANSFER with the player's passkey (returns the sender's claim code). */
21
- approveTransfer(transactionId: string): Promise<ApproveResult>;
21
+ approveTransfer(transactionId: string, opts?: CallOptions): Promise<ApproveResult>;
22
22
  /** Recipient self-claims a SEND with their passkey. */
23
- confirmReceiptSend(transactionId: string): Promise<ConfirmReceiptResult>;
23
+ confirmReceiptSend(transactionId: string, opts?: CallOptions): Promise<ConfirmReceiptResult>;
24
24
  /** Recipient self-claims a TRANSFER with their passkey. */
25
- confirmReceiptTransfer(transactionId: string): Promise<ConfirmReceiptResult>;
25
+ confirmReceiptTransfer(transactionId: string, opts?: CallOptions): Promise<ConfirmReceiptResult>;
26
26
  /**
27
27
  * Interchangeable methods (§4.6): prove an *already-enrolled* method (e.g. the
28
28
  * INVO app device key) to authorize adding a new partner passkey. The returned
@@ -31,7 +31,7 @@ declare class InvoClient {
31
31
  *
32
32
  * begin -> navigator.credentials.get() -> complete with { link_id, webauthn_assertion }.
33
33
  */
34
- linkDevice(linkId: string): Promise<LinkDeviceResult>;
34
+ linkDevice(linkId: string, opts?: CallOptions): Promise<LinkDeviceResult>;
35
35
  /** POST with the current player token. Token-expiry retry is handled one level
36
36
  * up by withTokenRetry (which re-runs the whole ceremony, not a single call). */
37
37
  private post;
@@ -49,4 +49,4 @@ declare class InvoClient {
49
49
  private confirmReceipt;
50
50
  }
51
51
 
52
- export { ApproveResult, ClientConfig, ConfirmReceiptResult, InvoClient, LinkDeviceResult };
52
+ export { ApproveResult, CallOptions, ClientConfig, ConfirmReceiptResult, InvoClient, LinkDeviceResult };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { assertSecureBaseUrl, Http, InvoError } from './chunk-DV3WZGMH.js';
2
- export { InvoError } from './chunk-DV3WZGMH.js';
1
+ import { assertSecureBaseUrl, Http, InvoError } from './chunk-EEWOAUXO.js';
2
+ export { InvoError } from './chunk-EEWOAUXO.js';
3
3
 
4
4
  // src/shared/webauthn.ts
5
5
  function b64urlToBuffer(value) {
@@ -106,38 +106,43 @@ var InvoClient = class {
106
106
  }
107
107
  }
108
108
  /** Enroll a passkey for the token's identity (register/begin -> create() -> register/complete). */
109
- async enrollPasskey() {
109
+ async enrollPasskey(opts) {
110
110
  this.assertWebAuthn();
111
+ const signal = opts?.signal;
111
112
  return this.withTokenRetry(async () => {
112
113
  const options = await this.post(
113
- "/api/sdk/webauthn/register/begin"
114
+ "/api/sdk/webauthn/register/begin",
115
+ void 0,
116
+ signal
114
117
  );
115
118
  const cred = await navigator.credentials.create({
116
- publicKey: toCreationOptions(options)
119
+ publicKey: toCreationOptions(options),
120
+ signal
117
121
  });
118
122
  if (!cred) throw new Error("Passkey creation was cancelled or returned no credential.");
119
123
  const raw = await this.post(
120
124
  "/api/sdk/webauthn/register/complete",
121
- { credential: registrationToJSON(cred) }
125
+ { credential: registrationToJSON(cred) },
126
+ signal
122
127
  );
123
128
  return { status: String(raw["status"] ?? ""), device: raw["device"] ?? null, raw };
124
129
  });
125
130
  }
126
131
  /** Approve a SEND with the player's passkey. */
127
- async approveSend(transactionId) {
128
- return this.approve("send", transactionId);
132
+ async approveSend(transactionId, opts) {
133
+ return this.approve("send", transactionId, opts);
129
134
  }
130
135
  /** Approve a TRANSFER with the player's passkey (returns the sender's claim code). */
131
- async approveTransfer(transactionId) {
132
- return this.approve("transfers", transactionId);
136
+ async approveTransfer(transactionId, opts) {
137
+ return this.approve("transfers", transactionId, opts);
133
138
  }
134
139
  /** Recipient self-claims a SEND with their passkey. */
135
- async confirmReceiptSend(transactionId) {
136
- return this.confirmReceipt("send", transactionId);
140
+ async confirmReceiptSend(transactionId, opts) {
141
+ return this.confirmReceipt("send", transactionId, opts);
137
142
  }
138
143
  /** Recipient self-claims a TRANSFER with their passkey. */
139
- async confirmReceiptTransfer(transactionId) {
140
- return this.confirmReceipt("transfers", transactionId);
144
+ async confirmReceiptTransfer(transactionId, opts) {
145
+ return this.confirmReceipt("transfers", transactionId, opts);
141
146
  }
142
147
  /**
143
148
  * Interchangeable methods (§4.6): prove an *already-enrolled* method (e.g. the
@@ -147,15 +152,19 @@ var InvoClient = class {
147
152
  *
148
153
  * begin -> navigator.credentials.get() -> complete with { link_id, webauthn_assertion }.
149
154
  */
150
- async linkDevice(linkId) {
155
+ async linkDevice(linkId, opts) {
151
156
  if (!linkId) throw new Error("linkDevice requires a `linkId`.");
157
+ const signal = opts?.signal;
152
158
  return this.withTokenRetry(async () => {
153
- const assertion = await this.runAssertion("/api/sdk/device/link/webauthn/begin", {
154
- link_id: linkId
155
- });
159
+ const assertion = await this.runAssertion(
160
+ "/api/sdk/device/link/webauthn/begin",
161
+ { link_id: linkId },
162
+ signal
163
+ );
156
164
  const raw = await this.post(
157
165
  "/api/sdk/device/link/webauthn/complete",
158
- { link_id: linkId, webauthn_assertion: assertion }
166
+ { link_id: linkId, webauthn_assertion: assertion },
167
+ signal
159
168
  );
160
169
  return { status: String(raw["status"] ?? ""), raw };
161
170
  });
@@ -163,8 +172,8 @@ var InvoClient = class {
163
172
  // --- internals ---
164
173
  /** POST with the current player token. Token-expiry retry is handled one level
165
174
  * up by withTokenRetry (which re-runs the whole ceremony, not a single call). */
166
- async post(path, body) {
167
- return this.http.post(path, body, this.auth);
175
+ async post(path, body, signal) {
176
+ return this.http.post(path, body, this.auth, { signal });
168
177
  }
169
178
  /**
170
179
  * Run a whole flow, retrying it ONCE if any call fails with SDK_TOKEN_EXPIRED
@@ -195,22 +204,29 @@ var InvoClient = class {
195
204
  this.auth = { kind: "bearer", token: fresh };
196
205
  return true;
197
206
  }
198
- async runAssertion(beginPath, beginBody) {
207
+ async runAssertion(beginPath, beginBody, signal) {
199
208
  this.assertWebAuthn();
200
- const options = await this.post(beginPath, beginBody);
209
+ const options = await this.post(beginPath, beginBody, signal);
201
210
  const cred = await navigator.credentials.get({
202
- publicKey: toRequestOptions(options)
211
+ publicKey: toRequestOptions(options),
212
+ signal
203
213
  });
204
214
  if (!cred) throw new Error("Passkey assertion was cancelled or returned no credential.");
205
215
  return assertionToJSON(cred);
206
216
  }
207
- async approve(flow, transactionId) {
217
+ async approve(flow, transactionId, opts) {
208
218
  const id = encodeURIComponent(transactionId);
219
+ const signal = opts?.signal;
209
220
  return this.withTokenRetry(async () => {
210
- const assertion = await this.runAssertion(`/api/sdk/${flow}/${id}/approve/webauthn/begin`);
221
+ const assertion = await this.runAssertion(
222
+ `/api/sdk/${flow}/${id}/approve/webauthn/begin`,
223
+ void 0,
224
+ signal
225
+ );
211
226
  const raw = await this.post(
212
227
  `/api/sdk/${flow}/${id}/approve`,
213
- { webauthn_assertion: assertion }
228
+ { webauthn_assertion: assertion },
229
+ signal
214
230
  );
215
231
  return {
216
232
  status: String(raw["status"] ?? ""),
@@ -222,15 +238,19 @@ var InvoClient = class {
222
238
  };
223
239
  });
224
240
  }
225
- async confirmReceipt(flow, transactionId) {
241
+ async confirmReceipt(flow, transactionId, opts) {
226
242
  const id = encodeURIComponent(transactionId);
243
+ const signal = opts?.signal;
227
244
  return this.withTokenRetry(async () => {
228
245
  const assertion = await this.runAssertion(
229
- `/api/sdk/${flow}/${id}/confirm-receipt/webauthn/begin`
246
+ `/api/sdk/${flow}/${id}/confirm-receipt/webauthn/begin`,
247
+ void 0,
248
+ signal
230
249
  );
231
250
  const raw = await this.post(
232
251
  `/api/sdk/${flow}/${id}/confirm-receipt`,
233
- { webauthn_assertion: assertion }
252
+ { webauthn_assertion: assertion },
253
+ signal
234
254
  );
235
255
  return { status: String(raw["status"] ?? ""), raw };
236
256
  });