@mattrglobal/verifier-sdk-web 1.1.1-unstable.91 → 1.1.1-unstable.94

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -203,15 +203,13 @@ const result = await MATTRVerifierSDK.requestCredentials({
203
203
  challenge: MATTRVerifierSDK.utils.generateChallenge(), // Pass a unique challenge
204
204
  walletProviderId, // Define the wallet identifier
205
205
  redirectUri, // Define the redirect URI (not required for cross-device only requests)
206
- crossDeviceCallback: { // Define how to handle completion/failure of cross-device flows (not required for same-device only requests)
207
- onComplete: (result) => {
208
- console.info("<<< MATTRVerifierSDK.requestCredentials crossDeviceCallback.onComplete", result);
209
- },
210
- onFailure: (error) => {
211
- console.info("<<< MATTRVerifierSDK.requestCredentials crossDeviceCallback.onFailure", error);
212
- },
213
- },
214
206
  });
207
+
208
+ if (result.isErr()) {
209
+ console.info("<<< MATTRVerifierSDK.requestCredentials succeed", result.error);
210
+ } else {
211
+ console.info("<<< MATTRVerifierSDK.requestCredentials failure", result.value);
212
+ }
215
213
  ```
216
214
  * `apiBaseUrl` : Replace with the [`tenant_url`](https://learn.mattr.global/docs/platform-management/authentication) of your MATTR VII verifier tenant.
217
215
  * `credentialQuery`: The credential query to be used in the request.
@@ -219,7 +217,6 @@ const result = await MATTRVerifierSDK.requestCredentials({
219
217
  * `walletProviderId`: Replace with a wallet identifier that matches one of the values in the [`walletProviders` array](https://learn.mattr.global/api-reference/latest/tag/mDocs-verification#operation/putVerifierConfiguration!path=walletProviders/id&t=request) of the MATTR VII tenant's verifier configuration.
220
218
  * `mode`: When omitted, the SDK defaults to automatically selecting a flow based on the browser's user agent (set to `undefined` in the example for clarity).
221
219
  * `redirectUri` Replace with a URI that matches one of the values in the [`redirectUris` array](https://learn.mattr.global/api-reference/latest/tag/mDocs-verification#operation/postVerifierApplication!path=openid4vpConfiguration/redirectUris&t=request) in the MATTR VII tenant's verifier application configuration.
222
- * `crossDeviceCallback`: Defines how to handle completion (`onComplete`) or failure (`onFailure`) of the verification workflow.
223
220
 
224
221
  ## Request credentials with explicit same-device flow
225
222
 
@@ -253,15 +250,13 @@ const result = await MATTRVerifierSDK.requestCredentials({
253
250
  challenge: MATTRVerifierSDK.utils.generateChallenge(),
254
251
  walletProviderId,
255
252
  mode: "crossDevice",
256
- crossDeviceCallback: {
257
- onComplete: (result) => {
258
- console.info("<<< MATTRVerifierSDK.requestCredentials crossDeviceCallback.onComplete", result);
259
- },
260
- onFailure: (error) => {
261
- console.info("<<< MATTRVerifierSDK.requestCredentials crossDeviceCallback.onFailure", error);
262
- },
263
- },
264
253
  });
254
+
255
+ if (result.isErr()) {
256
+ console.info("<<< MATTRVerifierSDK.requestCredentials succeed", result.error);
257
+ } else {
258
+ console.info("<<< MATTRVerifierSDK.requestCredentials failure", result.value);
259
+ }
265
260
  ```
266
261
 
267
262
  * `mode`: When set to `crossDevice`, the SDK will only support cross-device flow in this verification workflow.
@@ -7,7 +7,7 @@
7
7
  * Do Not Translate or Localize
8
8
  *
9
9
  * Bundle of @mattrglobal/verifier-sdk-web
10
- * Generated: 2025-02-24
10
+ * Generated: 2025-02-25
11
11
  * Version: 1.1.0
12
12
  * Dependencies:
13
13
  */
@@ -164,6 +164,15 @@ exports.OpenidPresentationCredentialProfileSupported = void 0;
164
164
  OpenidPresentationCredentialProfileSupported["MOBILE"] = "mobile";
165
165
  })(exports.OpenidPresentationCredentialProfileSupported || (exports.OpenidPresentationCredentialProfileSupported = {}));
166
166
 
167
+ var PresentationStatusCode;
168
+
169
+ (function(PresentationStatusCode) {
170
+ PresentationStatusCode["AwaitingRequestRetrieval"] = "AwaitingRequestRetrieval";
171
+ PresentationStatusCode["AwaitingResponse"] = "AwaitingResponse";
172
+ PresentationStatusCode["ResponseSubmitted"] = "ResponseSubmitted";
173
+ PresentationStatusCode["ResultReady"] = "ResultReady";
174
+ })(PresentationStatusCode || (PresentationStatusCode = {}));
175
+
167
176
  const CredentialQueryValidator = v__namespace.object({
168
177
  profile: v__namespace.picklist([ exports.OpenidPresentationCredentialProfileSupported.MOBILE ]),
169
178
  docType: v__namespace.string(),
@@ -200,9 +209,27 @@ v__namespace.object({
200
209
 
201
210
  const CreateSessionResponseValidator = v__namespace.object({
202
211
  sessionId: v__namespace.string(),
212
+ sessionKey: v__namespace.string(),
203
213
  sessionUrl: v__namespace.string()
204
214
  });
205
215
 
216
+ v__namespace.object({
217
+ sessionId: v__namespace.string(),
218
+ sessionKey: v__namespace.string()
219
+ });
220
+
221
+ v__namespace.object({
222
+ sessionId: v__namespace.string(),
223
+ sessionKey: v__namespace.string()
224
+ });
225
+
226
+ const GetSessionStatusResponseValidator = v__namespace.union([ v__namespace.object({
227
+ status: v__namespace.picklist([ PresentationStatusCode.ResultReady ]),
228
+ responseCode: v__namespace.optional(v__namespace.string())
229
+ }), v__namespace.object({
230
+ status: v__namespace.string()
231
+ }) ]);
232
+
206
233
  var LocalStorageKey;
207
234
 
208
235
  (function(LocalStorageKey) {
@@ -235,10 +262,6 @@ const RequestCredentialsSameDeviceOptionsValidator = v__namespace.object({
235
262
 
236
263
  const RequestCredentialsCrossDeviceOptionsValidator = v__namespace.object({
237
264
  credentialQuery: v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()),
238
- crossDeviceCallback: v__namespace.object({
239
- onComplete: v__namespace.function(),
240
- onFailure: v__namespace.function()
241
- }),
242
265
  challenge: v__namespace.optional(v__namespace.string()),
243
266
  walletProviderId: v__namespace.optional(v__namespace.string()),
244
267
  mode: v__namespace.picklist([ exports.Mode.crossDevice ])
@@ -246,10 +269,6 @@ const RequestCredentialsCrossDeviceOptionsValidator = v__namespace.object({
246
269
 
247
270
  const RequestCredentialsAutoDetectDeviceOptionsValidator = v__namespace.object({
248
271
  credentialQuery: v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()),
249
- crossDeviceCallback: v__namespace.object({
250
- onComplete: v__namespace.function(),
251
- onFailure: v__namespace.function()
252
- }),
253
272
  redirectUri: v__namespace.string(),
254
273
  challenge: v__namespace.optional(v__namespace.string()),
255
274
  walletProviderId: v__namespace.optional(v__namespace.string()),
@@ -262,11 +281,35 @@ exports.RequestCredentialsErrorType = void 0;
262
281
 
263
282
  (function(RequestCredentialsErrorType) {
264
283
  RequestCredentialsErrorType["RequestCredentialsFailed"] = "RequestCredentialsFailed";
284
+ RequestCredentialsErrorType["Timeout"] = "Timeout";
285
+ RequestCredentialsErrorType["Abort"] = "Abort";
265
286
  })(exports.RequestCredentialsErrorType || (exports.RequestCredentialsErrorType = {}));
266
287
 
288
+ var RequestCredentialsErrorMessage;
289
+
290
+ (function(RequestCredentialsErrorMessage) {
291
+ RequestCredentialsErrorMessage["FailedToGetSessionResult"] = "Failed to get session result";
292
+ RequestCredentialsErrorMessage["FailedToGetSessionStatus"] = "Failed to get session status";
293
+ RequestCredentialsErrorMessage["FailedToCreateSession"] = "Failed to create session";
294
+ RequestCredentialsErrorMessage["Abort"] = "User aborted the session";
295
+ RequestCredentialsErrorMessage["Timeout"] = "User session timeout";
296
+ })(RequestCredentialsErrorMessage || (RequestCredentialsErrorMessage = {}));
297
+
298
+ exports.AbortSessionErrorType = void 0;
299
+
300
+ (function(AbortSessionErrorType) {
301
+ AbortSessionErrorType["AbortSessionFailed"] = "AbortSessionFailed";
302
+ })(exports.AbortSessionErrorType || (exports.AbortSessionErrorType = {}));
303
+
304
+ var AbortSessionErrorMessage;
305
+
306
+ (function(AbortSessionErrorMessage) {
307
+ AbortSessionErrorMessage["FailedToAbortSession"] = "Failed to abort session";
308
+ })(AbortSessionErrorMessage || (AbortSessionErrorMessage = {}));
309
+
267
310
  const InitialiseOptionsValidator = v__namespace.object({
268
- apiBaseUrl: v__namespace.string(),
269
- applicationId: v__namespace.optional(v__namespace.string())
311
+ apiBaseUrl: v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty("Must not be empty")),
312
+ applicationId: v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty("Must not be empty"))
270
313
  });
271
314
 
272
315
  let initialiseOptions = undefined;
@@ -284,10 +327,62 @@ const initialise = options => {
284
327
 
285
328
  const getInitialiseOptions = () => initialiseOptions;
286
329
 
330
+ let sessionAbortController = undefined;
331
+
332
+ let _sessionId = undefined;
333
+
334
+ let _sessionKey = undefined;
335
+
336
+ const getActiveSession = () => {
337
+ const sessionId = _sessionId;
338
+ const sessionKey = _sessionKey;
339
+ if (sessionId) {
340
+ return {
341
+ sessionId: sessionId,
342
+ sessionKey: sessionKey
343
+ };
344
+ }
345
+ return undefined;
346
+ };
347
+
348
+ const setActiveSession = session => {
349
+ const {sessionId: sessionId, sessionKey: sessionKey} = session;
350
+ _sessionId = sessionId;
351
+ _sessionKey = sessionKey;
352
+ const abortController = new AbortController;
353
+ sessionAbortController = abortController;
354
+ return abortController;
355
+ };
356
+
357
+ const removeActiveSession = () => {
358
+ sessionAbortController === null || sessionAbortController === void 0 ? void 0 : sessionAbortController.abort();
359
+ sessionAbortController = undefined;
360
+ _sessionKey = undefined;
361
+ _sessionId = undefined;
362
+ };
363
+
287
364
  const defaultRetryDelay = attempt => Math.pow(2, attempt) * 1e3;
288
365
 
289
366
  const defaultRetry = 2;
290
367
 
368
+ const withRetry = async (fn, options) => {
369
+ const {retries: retries = defaultRetry, retryDelay: retryDelay = defaultRetryDelay, attempt: attempt = 0} = options;
370
+ try {
371
+ return await fn();
372
+ } catch (err) {
373
+ if (retries > 0) {
374
+ const delay = typeof retryDelay === "function" ? retryDelay(attempt) : retryDelay;
375
+ await new Promise((resolve => setTimeout(resolve, delay)));
376
+ return await withRetry(fn, Object.assign(Object.assign({}, options), {
377
+ retries: retries - 1,
378
+ retryDelay: retryDelay,
379
+ attempt: attempt + 1
380
+ }));
381
+ }
382
+ throw err;
383
+ }
384
+ };
385
+
291
386
  const withRetrySafeFetch = async (fn, options) => {
292
387
  const {retries: retries = defaultRetry, retryDelay: retryDelay = defaultRetryDelay, attempt: attempt = 0, retryHttpStatus: retryHttpStatus} = options;
293
388
  const result = await fn();
@@ -317,13 +412,12 @@ const getHashParamValue = (hash, param) => {
317
412
  };
318
413
 
319
414
  const createSession = async ({credentialQuery: credentialQuery, challenge: challenge, redirectUri: redirectUri, apiBaseUrl: apiBaseUrl, applicationId: applicationId, walletProviderId: walletProviderId}) => {
320
- const postData = Object.assign(Object.assign(Object.assign({
415
+ const postData = Object.assign(Object.assign({
321
416
  credentialQuery: credentialQuery,
322
- challenge: challenge
417
+ challenge: challenge,
418
+ applicationId: applicationId
323
419
  }, redirectUri ? {
324
420
  redirectUri: redirectUri
325
- } : {}), applicationId ? {
326
- applicationId: applicationId
327
421
  } : {}), walletProviderId ? {
328
422
  walletProviderId: walletProviderId
329
423
  } : {});
@@ -347,6 +441,40 @@ const createSession = async ({credentialQuery: credentialQuery, challenge: chall
347
441
  return neverthrow.ok(data);
348
442
  };
349
443
 
444
+ const abortSession = async ({apiBaseUrl: apiBaseUrl, sessionId: sessionId, sessionKey: sessionKey}) => {
445
+ const responseResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/${sessionId}/abort`, {
446
+ method: "POST",
447
+ headers: {
448
+ "Content-Type": "application/json",
449
+ Authorization: `Bearer ${sessionKey}`
450
+ }
451
+ });
452
+ if (responseResult.isErr()) {
453
+ return neverthrow.err(responseResult.error);
454
+ }
455
+ return neverthrow.ok(undefined);
456
+ };
457
+
458
+ const getSessionStatus = async ({apiBaseUrl: apiBaseUrl, sessionId: sessionId, sessionKey: sessionKey}) => {
459
+ const responseResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/${sessionId}/status`, {
460
+ method: "GET",
461
+ headers: {
462
+ Authorization: `Bearer ${sessionKey}`
463
+ }
464
+ });
465
+ if (responseResult.isErr()) {
466
+ return neverthrow.err(responseResult.error);
467
+ }
468
+ const data = await responseResult.value.json();
469
+ if (!isType(GetSessionStatusResponseValidator)(data)) {
470
+ return neverthrow.err({
471
+ type: SafeFetchCommonRespondErrorType.UnexpectedRespond,
472
+ message: "Get session status return unsupported response"
473
+ });
474
+ }
475
+ return neverthrow.ok(data);
476
+ };
477
+
350
478
  const exchangeSessionResult = async ({challenge: challenge, responseCode: responseCode, sessionId: sessionId, apiBaseUrl: apiBaseUrl}) => {
351
479
  const postData = {
352
480
  challenge: challenge,
@@ -384,33 +512,19 @@ const isMobileDetect = userAgent => isMobile.isMobile({
384
512
  tablet: false
385
513
  });
386
514
 
387
- exports.CrossDeviceCallbackErrorType = void 0;
388
-
389
- (function(CrossDeviceCallbackErrorType) {
390
- CrossDeviceCallbackErrorType["Timeout"] = "Timeout";
391
- CrossDeviceCallbackErrorType["Abort"] = "Abort";
392
- CrossDeviceCallbackErrorType["RequestCredentialsFailed"] = "RequestCredentialsFailed";
393
- })(exports.CrossDeviceCallbackErrorType || (exports.CrossDeviceCallbackErrorType = {}));
394
-
395
- var CrossDeviceRequestCredentialsErrorMessage;
396
-
397
- (function(CrossDeviceRequestCredentialsErrorMessage) {
398
- CrossDeviceRequestCredentialsErrorMessage["FailedToGetSessionResult"] = "Failed to get session result";
399
- CrossDeviceRequestCredentialsErrorMessage["FailedToCreateSession"] = "Failed to create session";
400
- CrossDeviceRequestCredentialsErrorMessage["Abort"] = "User aborted the session";
401
- CrossDeviceRequestCredentialsErrorMessage["Timeout"] = "User session timeout";
402
- })(CrossDeviceRequestCredentialsErrorMessage || (CrossDeviceRequestCredentialsErrorMessage = {}));
403
-
404
515
  var WindowEventListenerType;
405
516
 
406
517
  (function(WindowEventListenerType) {
407
518
  WindowEventListenerType["message"] = "message";
408
519
  })(WindowEventListenerType || (WindowEventListenerType = {}));
409
520
 
410
- let listener;
521
+ let listener = undefined;
411
522
 
412
523
  const removeWindowMessageEventListener = () => {
413
- window.removeEventListener(WindowEventListenerType.message, listener, false);
524
+ if (listener) {
525
+ window.removeEventListener(WindowEventListenerType.message, listener, false);
526
+ }
527
+ listener = undefined;
414
528
  };
415
529
 
416
530
  const closeCrossDeviceModal = options => {
@@ -422,8 +536,7 @@ const closeCrossDeviceModal = options => {
422
536
  };
423
537
 
424
538
  const receiveMessageHandler = options => async event => {
425
- const {crossDeviceCallback: crossDeviceCallback, container: container, sessionId: sessionId, apiBaseUrl: apiBaseUrl, challenge: challenge} = options;
426
- const {onComplete: onComplete, onFailure: onFailure} = crossDeviceCallback;
539
+ const {onComplete: onComplete, onFailure: onFailure, container: container, sessionId: sessionId, apiBaseUrl: apiBaseUrl, challenge: challenge} = options;
427
540
  if (event.origin !== apiBaseUrl) {
428
541
  return;
429
542
  }
@@ -437,8 +550,8 @@ const receiveMessageHandler = options => async event => {
437
550
  });
438
551
  if (result.isErr()) {
439
552
  onFailure({
440
- type: exports.CrossDeviceCallbackErrorType.RequestCredentialsFailed,
441
- message: CrossDeviceRequestCredentialsErrorMessage.FailedToGetSessionResult
553
+ type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
554
+ message: RequestCredentialsErrorMessage.FailedToGetSessionResult
442
555
  });
443
556
  closeCrossDeviceModal({
444
557
  container: container
@@ -446,8 +559,9 @@ const receiveMessageHandler = options => async event => {
446
559
  return;
447
560
  }
448
561
  onComplete({
449
- result: result.value,
450
- sessionId: result.value.sessionId
562
+ result: "challenge" in result.value ? result.value : undefined,
563
+ sessionId: result.value.sessionId,
564
+ sessionCompletedInRedirect: false
451
565
  });
452
566
  closeCrossDeviceModal({
453
567
  container: container
@@ -456,8 +570,8 @@ const receiveMessageHandler = options => async event => {
456
570
  }
457
571
  if (event.data.type === MessageEventDataType.PresentationTimeout) {
458
572
  onFailure({
459
- type: exports.CrossDeviceCallbackErrorType.Timeout,
460
- message: CrossDeviceRequestCredentialsErrorMessage.Timeout
573
+ type: exports.RequestCredentialsErrorType.Timeout,
574
+ message: RequestCredentialsErrorMessage.Timeout
461
575
  });
462
576
  closeCrossDeviceModal({
463
577
  container: container
@@ -466,8 +580,8 @@ const receiveMessageHandler = options => async event => {
466
580
  }
467
581
  if (event.data.type === MessageEventDataType.PresentationAbort) {
468
582
  onFailure({
469
- type: exports.CrossDeviceCallbackErrorType.Abort,
470
- message: CrossDeviceRequestCredentialsErrorMessage.Abort
583
+ type: exports.RequestCredentialsErrorType.Abort,
584
+ message: RequestCredentialsErrorMessage.Abort
471
585
  });
472
586
  closeCrossDeviceModal({
473
587
  container: container
@@ -493,7 +607,7 @@ const openCrossDeviceModal = options => {
493
607
  };
494
608
 
495
609
  const requestCredentialsCrossDevice = async options => {
496
- const {challenge: challenge, walletProviderId: walletProviderId, credentialQuery: credentialQuery, crossDeviceCallback: crossDeviceCallback, initialiseOptions: initialiseOptions} = options;
610
+ const {challenge: challenge, walletProviderId: walletProviderId, credentialQuery: credentialQuery, initialiseOptions: initialiseOptions} = options;
497
611
  const {apiBaseUrl: apiBaseUrl, applicationId: applicationId} = initialiseOptions;
498
612
  const createSessionResult = await createSession({
499
613
  credentialQuery: credentialQuery,
@@ -505,28 +619,49 @@ const requestCredentialsCrossDevice = async options => {
505
619
  if (createSessionResult.isErr()) {
506
620
  return neverthrow.err({
507
621
  type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
508
- message: CrossDeviceRequestCredentialsErrorMessage.FailedToCreateSession,
622
+ message: RequestCredentialsErrorMessage.FailedToCreateSession,
509
623
  cause: createSessionResult.error
510
624
  });
511
625
  }
512
- const {sessionUrl: sessionUrl, sessionId: sessionId} = createSessionResult.value;
626
+ const {sessionUrl: sessionUrl, sessionId: sessionId, sessionKey: sessionKey} = createSessionResult.value;
513
627
  const container = openCrossDeviceModal({
514
- sessionUrl: sessionUrl,
515
- crossDeviceCallback: crossDeviceCallback
516
- });
517
- listener = receiveMessageHandler({
518
- crossDeviceCallback: crossDeviceCallback,
519
- container: container,
520
- sessionId: sessionId,
521
- apiBaseUrl: apiBaseUrl,
522
- challenge: challenge
523
- });
524
- window.addEventListener(WindowEventListenerType.message, listener, false);
525
- return neverthrow.ok({
526
- sessionId: sessionId
628
+ sessionUrl: sessionUrl
527
629
  });
630
+ return await new Promise((resolve => {
631
+ const abortController = setActiveSession({
632
+ sessionId: sessionId,
633
+ sessionKey: sessionKey
634
+ });
635
+ abortController.signal.addEventListener("abort", (() => {
636
+ closeCrossDeviceModal({
637
+ container: container
638
+ });
639
+ resolve(neverthrow.err({
640
+ type: exports.RequestCredentialsErrorType.Abort,
641
+ message: RequestCredentialsErrorMessage.Abort
642
+ }));
643
+ }));
644
+ removeWindowMessageEventListener();
645
+ listener = receiveMessageHandler({
646
+ container: container,
647
+ sessionId: sessionId,
648
+ apiBaseUrl: apiBaseUrl,
649
+ challenge: challenge,
650
+ onComplete: data => resolve(neverthrow.ok(data)),
651
+ onFailure: error => resolve(neverthrow.err(error))
652
+ });
653
+ window.addEventListener(WindowEventListenerType.message, listener, false);
654
+ }));
528
655
  };
529
656
 
657
+ const sleep = ms => new Promise((resolve => setTimeout(resolve, ms)));
658
+
659
+ const SESSION_STATUS_POLLING_MAX_RETRY = 1e3;
660
+
661
+ const SESSION_STATUS_POLLING_INTERVAL_MS = 3e3;
662
+
663
+ const SESSION_STATUS_POLLING_INITIAL_DELAY_MS = 3e3;
664
+
530
665
  var SameDeviceRequestCredentialsErrorMessage;
531
666
 
532
667
  (function(SameDeviceRequestCredentialsErrorMessage) {
@@ -537,17 +672,9 @@ var SameDeviceRequestCredentialsErrorMessage;
537
672
  const requestCredentialsSameDevice = async options => {
538
673
  const {challenge: challenge, credentialQuery: credentialQuery, redirectUri: redirectUri, walletProviderId: walletProviderId, initialiseOptions: initialiseOptions} = options;
539
674
  const {apiBaseUrl: apiBaseUrl, applicationId: applicationId} = initialiseOptions;
540
- window.localStorage.setItem(LocalStorageKey.challenge, challenge);
541
- const storedChallenge = window.localStorage.getItem(LocalStorageKey.challenge);
542
- if (!storedChallenge) {
543
- return neverthrow.err({
544
- type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
545
- message: SameDeviceRequestCredentialsErrorMessage.FailedToStoreChallenge
546
- });
547
- }
548
675
  const createSessionResult = await createSession({
549
676
  credentialQuery: credentialQuery,
550
- challenge: storedChallenge,
677
+ challenge: challenge,
551
678
  redirectUri: redirectUri,
552
679
  apiBaseUrl: apiBaseUrl,
553
680
  applicationId: applicationId,
@@ -560,11 +687,52 @@ const requestCredentialsSameDevice = async options => {
560
687
  cause: createSessionResult.error
561
688
  });
562
689
  }
563
- const {sessionUrl: sessionUrl, sessionId: sessionId} = createSessionResult.value;
690
+ const {sessionUrl: sessionUrl, sessionKey: sessionKey, sessionId: sessionId} = createSessionResult.value;
691
+ const abortController = setActiveSession({
692
+ sessionId: sessionId,
693
+ sessionKey: sessionKey
694
+ });
564
695
  window.localStorage.setItem(LocalStorageKey.sessionId, sessionId);
696
+ window.localStorage.setItem(LocalStorageKey.challenge, challenge);
565
697
  window.location.assign(sessionUrl);
698
+ await sleep(SESSION_STATUS_POLLING_INITIAL_DELAY_MS);
699
+ const checkResult = await withRetry((async () => {
700
+ const statusResult = await getSessionStatus({
701
+ apiBaseUrl: apiBaseUrl,
702
+ applicationId: applicationId,
703
+ sessionId: sessionId,
704
+ sessionKey: sessionKey
705
+ });
706
+ if (abortController.signal.aborted) {
707
+ return neverthrow.err({
708
+ type: exports.RequestCredentialsErrorType.Abort,
709
+ message: RequestCredentialsErrorMessage.Abort
710
+ });
711
+ }
712
+ if (statusResult.isErr()) {
713
+ if (statusResult.error.status === 404) {
714
+ return neverthrow.err({
715
+ type: exports.RequestCredentialsErrorType.Timeout,
716
+ message: RequestCredentialsErrorMessage.Timeout
717
+ });
718
+ }
719
+ throw Error("Unexpected status response. Retry");
720
+ }
721
+ if (statusResult.value.status !== PresentationStatusCode.ResultReady) {
722
+ throw Error("Result is not ready. Retry");
723
+ }
724
+ return neverthrow.ok(undefined);
725
+ }), {
726
+ retries: SESSION_STATUS_POLLING_MAX_RETRY,
727
+ retryDelay: SESSION_STATUS_POLLING_INTERVAL_MS
728
+ });
729
+ if (checkResult.isErr()) {
730
+ return neverthrow.err(checkResult.error);
731
+ }
732
+ window.close();
566
733
  return neverthrow.ok({
567
- sessionId: sessionId
734
+ sessionId: sessionId,
735
+ sessionCompletedInRedirect: true
568
736
  });
569
737
  };
570
738
 
@@ -584,16 +752,11 @@ const requestCredentials = async options => {
584
752
  mode: mode
585
753
  }));
586
754
  }
587
- if (mode === exports.Mode.crossDevice && "crossDeviceCallback" in options) {
588
- return await requestCredentialsCrossDevice(Object.assign(Object.assign({}, options), {
589
- initialiseOptions: initialiseOptions,
590
- challenge: challenge,
591
- mode: mode
592
- }));
593
- }
594
- throw new Exception("Invalid request credential options", {
595
- data: options
596
- });
755
+ return await requestCredentialsCrossDevice(Object.assign(Object.assign({}, options), {
756
+ initialiseOptions: initialiseOptions,
757
+ challenge: challenge,
758
+ mode: exports.Mode.crossDevice
759
+ }));
597
760
  };
598
761
 
599
762
  exports.HandleRedirectCallbackErrorType = void 0;
@@ -607,7 +770,7 @@ var HandleRedirectCallbackErrorMessage;
607
770
  (function(HandleRedirectCallbackErrorMessage) {
608
771
  HandleRedirectCallbackErrorMessage["FailedToFindResponseCode"] = "Failed to find response code";
609
772
  HandleRedirectCallbackErrorMessage["FailedToFindChallenge"] = "Failed to find challenge";
610
- HandleRedirectCallbackErrorMessage["FailedToFindSessionId"] = "Failed to find sessionId";
773
+ HandleRedirectCallbackErrorMessage["FailedToFindActiveSession"] = "Failed to find active session";
611
774
  HandleRedirectCallbackErrorMessage["FailedToGetSessionResult"] = "Failed to get session result";
612
775
  })(HandleRedirectCallbackErrorMessage || (HandleRedirectCallbackErrorMessage = {}));
613
776
 
@@ -624,18 +787,12 @@ const handleRedirectCallback = async () => {
624
787
  message: HandleRedirectCallbackErrorMessage.FailedToFindResponseCode
625
788
  });
626
789
  }
627
- const challenge = window.localStorage.getItem(LocalStorageKey.challenge);
628
- if (!challenge) {
629
- return neverthrow.err({
630
- type: exports.HandleRedirectCallbackErrorType.HandleRedirectCallbackFailed,
631
- message: HandleRedirectCallbackErrorMessage.FailedToFindChallenge
632
- });
633
- }
634
790
  const sessionId = window.localStorage.getItem(LocalStorageKey.sessionId);
635
- if (!sessionId) {
791
+ const challenge = window.localStorage.getItem(LocalStorageKey.challenge);
792
+ if (!sessionId || !challenge) {
636
793
  return neverthrow.err({
637
794
  type: exports.HandleRedirectCallbackErrorType.HandleRedirectCallbackFailed,
638
- message: HandleRedirectCallbackErrorMessage.FailedToFindSessionId
795
+ message: HandleRedirectCallbackErrorMessage.FailedToFindActiveSession
639
796
  });
640
797
  }
641
798
  const result = await exchangeSessionResult({
@@ -652,16 +809,46 @@ const handleRedirectCallback = async () => {
652
809
  });
653
810
  }
654
811
  return neverthrow.ok({
655
- result: result.value,
812
+ result: "challenge" in result.value ? result.value : undefined,
656
813
  sessionId: result.value.sessionId
657
814
  });
658
815
  };
659
816
 
817
+ const abortCredentialRequest = async () => {
818
+ const initialiseOptions = getInitialiseOptions();
819
+ if (!initialiseOptions) {
820
+ throw new Exception(InitialiseErrorMessage.SdkNotInitialised);
821
+ }
822
+ const {apiBaseUrl: apiBaseUrl, applicationId: applicationId} = initialiseOptions;
823
+ const session = getActiveSession();
824
+ if (!session || !session.sessionKey) {
825
+ return neverthrow.ok(undefined);
826
+ }
827
+ const {sessionId: sessionId, sessionKey: sessionKey} = session;
828
+ removeActiveSession();
829
+ const abortSessionResult = await abortSession({
830
+ apiBaseUrl: apiBaseUrl,
831
+ applicationId: applicationId,
832
+ sessionId: sessionId,
833
+ sessionKey: sessionKey
834
+ });
835
+ if (abortSessionResult.isErr()) {
836
+ return neverthrow.err({
837
+ type: exports.AbortSessionErrorType.AbortSessionFailed,
838
+ message: AbortSessionErrorMessage.FailedToAbortSession,
839
+ cause: abortSessionResult.error
840
+ });
841
+ }
842
+ return neverthrow.ok(undefined);
843
+ };
844
+
660
845
  const utils = {
661
846
  generateChallenge: generateChallenge,
662
847
  unwrap: unwrap
663
848
  };
664
849
 
850
+ exports.abortCredentialRequest = abortCredentialRequest;
851
+
665
852
  exports.handleRedirectCallback = handleRedirectCallback;
666
853
 
667
854
  exports.initialise = initialise;