@mattrglobal/verifier-sdk-web 2.0.0-preview-digital-credential-api.4 → 2.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.
Files changed (29) hide show
  1. package/README.md +71 -86
  2. package/dist/lib/verifier-js-no-deps.cjs.js +608 -336
  3. package/dist/lib/verifier-js-no-deps.cjs.js.map +1 -1
  4. package/dist/lib/verifier-js.cjs.js +911 -511
  5. package/dist/lib/verifier-js.cjs.js.map +1 -1
  6. package/dist/typings/common/safeFetch.d.ts +6 -3
  7. package/dist/typings/common/sleep.d.ts +1 -0
  8. package/dist/typings/index.d.ts +6 -7
  9. package/dist/typings/verifier/abortCredentialRequest.d.ts +6 -0
  10. package/dist/typings/verifier/handleRedirectCallback.d.ts +1 -1
  11. package/dist/typings/verifier/index.d.ts +3 -1
  12. package/dist/typings/verifier/initialize.d.ts +12 -0
  13. package/dist/typings/verifier/instanceContext.d.ts +7 -0
  14. package/dist/typings/verifier/requestCredentials.d.ts +2 -2
  15. package/dist/typings/verifier/requestCredentialsCrossDevice.d.ts +3 -47
  16. package/dist/typings/verifier/requestCredentialsDigitalCredentialsApi.d.ts +17 -0
  17. package/dist/typings/verifier/requestCredentialsSameDevice.d.ts +1 -1
  18. package/dist/typings/verifier/types/credential-presentation.d.ts +136 -37
  19. package/dist/typings/verifier/types/verifier-web-sdk.d.ts +153 -214
  20. package/dist/typings/verifier/utils.d.ts +23 -37
  21. package/dist/verifier-js.development.js +866 -499
  22. package/dist/verifier-js.development.js.map +1 -1
  23. package/dist/verifier-js.production.esm.js +4 -4
  24. package/dist/verifier-js.production.esm.js.map +1 -1
  25. package/dist/verifier-js.production.js +4 -4
  26. package/dist/verifier-js.production.js.map +1 -1
  27. package/package.json +3 -3
  28. package/dist/typings/verifier/initialise.d.ts +0 -12
  29. package/dist/typings/verifier/requestCredentialsViaDigitalCredentialsApi.d.ts +0 -7
@@ -7,8 +7,8 @@
7
7
  * Do Not Translate or Localize
8
8
  *
9
9
  * Bundle of @mattrglobal/verifier-sdk-web
10
- * Generated: 2025-03-25
11
- * Version: 2.0.0-preview-digital-credential-api.4
10
+ * Generated: 2025-05-28
11
+ * Version: 2.0.0
12
12
  * Dependencies:
13
13
  */
14
14
 
@@ -69,10 +69,20 @@ const unwrap = (result, errMessage) => {
69
69
 
70
70
  const isType = validator => value => v__namespace.safeParse(validator, value).success;
71
71
 
72
- const getValidationErrors = issues => issues.map((({message: message, path: path}) => ({
73
- message: message,
74
- path: path === null || path === void 0 ? void 0 : path.map((path => path.key))
75
- })));
72
+ const getValidationErrors = issues => {
73
+ const formatIssue = ({message: message, path: path}) => ({
74
+ message: message,
75
+ path: path === null || path === void 0 ? void 0 : path.map((p => p.key))
76
+ });
77
+ const uniqueErrors = new Map;
78
+ issues.flatMap((issue => issue.type === "union" && issue.issues ? issue.issues.map(formatIssue) : [ formatIssue(issue) ])).forEach((error => {
79
+ const key = `${error.message}-${JSON.stringify(error.path)}`;
80
+ if (!uniqueErrors.has(key)) {
81
+ uniqueErrors.set(key, error);
82
+ }
83
+ }));
84
+ return Array.from(uniqueErrors.values());
85
+ };
76
86
 
77
87
  const validateType = (value, validator) => {
78
88
  const result = v__namespace.safeParse(validator, value);
@@ -89,47 +99,21 @@ const assertType = (validator, message) => data => {
89
99
  }
90
100
  };
91
101
 
92
- var SafeFetchCommonRespondErrorType;
93
-
94
- (function(SafeFetchCommonRespondErrorType) {
95
- SafeFetchCommonRespondErrorType["UnexpectedRespond"] = "UnexpectedRespond";
96
- })(SafeFetchCommonRespondErrorType || (SafeFetchCommonRespondErrorType = {}));
97
-
98
- var SafeFetchErrorType;
99
-
100
- (function(SafeFetchErrorType) {
101
- SafeFetchErrorType["HttpError"] = "HttpError";
102
- SafeFetchErrorType["UnknownError"] = "UnknownError";
103
- })(SafeFetchErrorType || (SafeFetchErrorType = {}));
104
-
105
- const safeFetch = async (input, init) => {
106
- try {
107
- const response = await fetch(input, init);
108
- if (response.status > 299 || response.status < 200) {
109
- return neverthrow.err({
110
- type: SafeFetchErrorType.HttpError,
111
- message: `HTTP error, status = ${response.status}`,
112
- status: response.status
113
- });
114
- }
115
- return neverthrow.ok(response);
116
- } catch (error) {
117
- return neverthrow.err({
118
- type: SafeFetchErrorType.UnknownError,
119
- message: "Unknown error",
120
- cause: error
121
- });
122
- }
123
- };
124
-
125
102
  exports.MobileCredentialVerificationReasonType = void 0;
126
103
 
127
104
  (function(MobileCredentialVerificationReasonType) {
128
- MobileCredentialVerificationReasonType["Expired"] = "expired";
129
- MobileCredentialVerificationReasonType["Inactive"] = "inactive";
130
- MobileCredentialVerificationReasonType["StatusRevoked"] = "invalid";
131
- MobileCredentialVerificationReasonType["StatusSuspended"] = "suspended";
132
- MobileCredentialVerificationReasonType["StatusUnknown"] = "unknown";
105
+ MobileCredentialVerificationReasonType["TrustedIssuerCertificateExpired"] = "TrustedIssuerCertificateExpired";
106
+ MobileCredentialVerificationReasonType["TrustedIssuerCertificateNotYetValid"] = "TrustedIssuerCertificateNotYetValid";
107
+ MobileCredentialVerificationReasonType["IssuerNotTrusted"] = "IssuerNotTrusted";
108
+ MobileCredentialVerificationReasonType["MobileCredentialInvalid"] = "MobileCredentialInvalid";
109
+ MobileCredentialVerificationReasonType["MobileCredentialExpired"] = "MobileCredentialExpired";
110
+ MobileCredentialVerificationReasonType["MobileCredentialNotYetValid"] = "MobileCredentialNotYetValid";
111
+ MobileCredentialVerificationReasonType["InvalidSignerCertificate"] = "InvalidSignerCertificate";
112
+ MobileCredentialVerificationReasonType["DeviceKeyInvalid"] = "DeviceKeyInvalid";
113
+ MobileCredentialVerificationReasonType["UnsupportedCurve"] = "UnsupportedCurve";
114
+ MobileCredentialVerificationReasonType["StatusRevoked"] = "StatusRevoked";
115
+ MobileCredentialVerificationReasonType["StatusSuspended"] = "StatusSuspended";
116
+ MobileCredentialVerificationReasonType["StatusUnknown"] = "StatusUnknown";
133
117
  })(exports.MobileCredentialVerificationReasonType || (exports.MobileCredentialVerificationReasonType = {}));
134
118
 
135
119
  exports.ClaimType = void 0;
@@ -164,6 +148,15 @@ exports.OpenidPresentationCredentialProfileSupported = void 0;
164
148
  OpenidPresentationCredentialProfileSupported["MOBILE"] = "mobile";
165
149
  })(exports.OpenidPresentationCredentialProfileSupported || (exports.OpenidPresentationCredentialProfileSupported = {}));
166
150
 
151
+ var PresentationStatusCode;
152
+
153
+ (function(PresentationStatusCode) {
154
+ PresentationStatusCode["AwaitingRequestRetrieval"] = "AwaitingRequestRetrieval";
155
+ PresentationStatusCode["AwaitingResponse"] = "AwaitingResponse";
156
+ PresentationStatusCode["ResponseSubmitted"] = "ResponseSubmitted";
157
+ PresentationStatusCode["ResultReady"] = "ResultReady";
158
+ })(PresentationStatusCode || (PresentationStatusCode = {}));
159
+
167
160
  const CredentialQueryValidator = v__namespace.object({
168
161
  profile: v__namespace.picklist([ exports.OpenidPresentationCredentialProfileSupported.MOBILE ]),
169
162
  docType: v__namespace.string(),
@@ -191,23 +184,63 @@ const PresentationResultRelaxValidator = v__namespace.object({
191
184
  error: v__namespace.optional(v__namespace.unknown())
192
185
  });
193
186
 
187
+ exports.Mode = void 0;
188
+
189
+ (function(Mode) {
190
+ Mode["SameDevice"] = "sameDevice";
191
+ Mode["CrossDevice"] = "crossDevice";
192
+ })(exports.Mode || (exports.Mode = {}));
193
+
194
+ var SessionType;
195
+
196
+ (function(SessionType) {
197
+ SessionType["DigitalCredentialsApi"] = "digital-credentials-api";
198
+ SessionType["Openid4vp"] = "openid4vp";
199
+ })(SessionType || (SessionType = {}));
200
+
194
201
  v__namespace.object({
195
202
  credentialQuery: v__namespace.array(CredentialQueryValidator),
196
203
  challenge: v__namespace.string(),
197
204
  redirectUri: v__namespace.optional(v__namespace.string()),
198
- walletProviderId: v__namespace.optional(v__namespace.string())
205
+ walletProviderId: v__namespace.optional(v__namespace.string()),
206
+ dcApiSupported: v__namespace.optional(v__namespace.boolean())
199
207
  });
200
208
 
201
- const CreateSessionResponseValidator = v__namespace.object({
209
+ const CreateSessionDigitalCredentialsValidator = v__namespace.object({
210
+ type: v__namespace.literal(SessionType.DigitalCredentialsApi),
202
211
  sessionId: v__namespace.string(),
212
+ sessionKey: v__namespace.string(),
213
+ sessionTtl: v__namespace.number(),
214
+ request: v__namespace.record(v__namespace.string(), v__namespace.any())
215
+ });
216
+
217
+ const CreateSessionOpenId4vpResponseValidator = v__namespace.object({
218
+ type: v__namespace.optional(v__namespace.literal(SessionType.Openid4vp)),
219
+ sessionId: v__namespace.string(),
220
+ sessionKey: v__namespace.string(),
203
221
  sessionUrl: v__namespace.string()
204
222
  });
205
223
 
206
- const CreateDigitalCredentialsApiSessionResponseValidator = v__namespace.object({
224
+ const CreateSessionResponseValidator = v__namespace.union([ CreateSessionDigitalCredentialsValidator, CreateSessionOpenId4vpResponseValidator ]);
225
+
226
+ v__namespace.object({
227
+ sessionId: v__namespace.string(),
228
+ sessionKey: v__namespace.string(),
229
+ apiBaseUrl: v__namespace.string()
230
+ });
231
+
232
+ v__namespace.object({
207
233
  sessionId: v__namespace.string(),
208
- request: v__namespace.object({})
234
+ sessionKey: v__namespace.string()
209
235
  });
210
236
 
237
+ const GetSessionStatusResponseValidator = v__namespace.union([ v__namespace.object({
238
+ status: v__namespace.picklist([ PresentationStatusCode.ResultReady ]),
239
+ responseCode: v__namespace.optional(v__namespace.string())
240
+ }), v__namespace.object({
241
+ status: v__namespace.string()
242
+ }) ]);
243
+
211
244
  var LocalStorageKey;
212
245
 
213
246
  (function(LocalStorageKey) {
@@ -215,12 +248,9 @@ var LocalStorageKey;
215
248
  LocalStorageKey["sessionId"] = "mattr_sid";
216
249
  })(LocalStorageKey || (LocalStorageKey = {}));
217
250
 
218
- exports.Mode = void 0;
251
+ const MATTR_SDK_VERSION_HEADER = "x-mattr-sdk-version";
219
252
 
220
- (function(Mode) {
221
- Mode["sameDevice"] = "sameDevice";
222
- Mode["crossDevice"] = "crossDevice";
223
- })(exports.Mode || (exports.Mode = {}));
253
+ const MATTR_SDK_VERSION_VALUE = "2.0.0";
224
254
 
225
255
  var MessageEventDataType;
226
256
 
@@ -230,71 +260,210 @@ var MessageEventDataType;
230
260
  MessageEventDataType["PresentationAbort"] = "PresentationAbort";
231
261
  })(MessageEventDataType || (MessageEventDataType = {}));
232
262
 
233
- const RequestCredentialsSameDeviceOptionsValidator = v__namespace.object({
234
- credentialQuery: v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()),
235
- redirectUri: v__namespace.string(),
236
- challenge: v__namespace.optional(v__namespace.string()),
263
+ const OpenId4vpConfigSameDeviceOptionsValidator = v__namespace.object({
237
264
  walletProviderId: v__namespace.optional(v__namespace.string()),
238
- mode: v__namespace.picklist([ exports.Mode.sameDevice ])
265
+ mode: v__namespace.literal(exports.Mode.SameDevice),
266
+ redirectUri: v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty("Must not be empty"), v__namespace.url())
239
267
  });
240
268
 
241
- const RequestCredentialsCrossDeviceOptionsValidator = v__namespace.object({
242
- credentialQuery: v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()),
243
- crossDeviceCallback: v__namespace.object({
244
- onComplete: v__namespace.function(),
245
- onFailure: v__namespace.function()
246
- }),
247
- challenge: v__namespace.optional(v__namespace.string()),
269
+ const OpenId4vpConfigCrossDeviceOptionsValidator = v__namespace.object({
248
270
  walletProviderId: v__namespace.optional(v__namespace.string()),
249
- mode: v__namespace.picklist([ exports.Mode.crossDevice ])
271
+ mode: v__namespace.literal(exports.Mode.CrossDevice)
250
272
  });
251
273
 
252
- const RequestCredentialsAutoDetectDeviceOptionsValidator = v__namespace.object({
253
- credentialQuery: v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()),
254
- crossDeviceCallback: v__namespace.object({
255
- onComplete: v__namespace.function(),
256
- onFailure: v__namespace.function()
257
- }),
258
- redirectUri: v__namespace.string(),
259
- challenge: v__namespace.optional(v__namespace.string()),
274
+ const OpenId4vpConfigAutoDetectOptionsValidator = v__namespace.object({
260
275
  walletProviderId: v__namespace.optional(v__namespace.string()),
261
- mode: v__namespace.optional(v__namespace.picklist([ exports.Mode.crossDevice, exports.Mode.sameDevice ]))
276
+ redirectUri: v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty("Must not be empty"), v__namespace.url()),
277
+ mode: v__namespace.optional(v__namespace.picklist([ exports.Mode.CrossDevice, exports.Mode.SameDevice ]))
262
278
  });
263
279
 
264
- const RequestCredentialsOptionsValidator = v__namespace.union([ RequestCredentialsSameDeviceOptionsValidator, RequestCredentialsCrossDeviceOptionsValidator, RequestCredentialsAutoDetectDeviceOptionsValidator ]);
280
+ const RequestCredentialsOptionsValidator = v__namespace.object({
281
+ credentialQuery: v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()),
282
+ challenge: v__namespace.optional(v__namespace.string()),
283
+ openid4vpConfiguration: v__namespace.optional(v__namespace.union([ OpenId4vpConfigSameDeviceOptionsValidator, OpenId4vpConfigCrossDeviceOptionsValidator, OpenId4vpConfigAutoDetectOptionsValidator ]))
284
+ });
265
285
 
266
286
  exports.RequestCredentialsErrorType = void 0;
267
287
 
268
288
  (function(RequestCredentialsErrorType) {
269
289
  RequestCredentialsErrorType["RequestCredentialsFailed"] = "RequestCredentialsFailed";
290
+ RequestCredentialsErrorType["Timeout"] = "Timeout";
291
+ RequestCredentialsErrorType["Abort"] = "Abort";
270
292
  })(exports.RequestCredentialsErrorType || (exports.RequestCredentialsErrorType = {}));
271
293
 
272
- const InitialiseOptionsValidator = v__namespace.object({
273
- apiBaseUrl: v__namespace.string(),
274
- applicationId: v__namespace.optional(v__namespace.string()),
275
- enableDigitalCredentialsApiSameDeviceFlow: v__namespace.optional(v__namespace.boolean()),
276
- enableDigitalCredentialsApiCrossDeviceFlow: v__namespace.optional(v__namespace.boolean())
294
+ var RequestCredentialsErrorMessage;
295
+
296
+ (function(RequestCredentialsErrorMessage) {
297
+ RequestCredentialsErrorMessage["FailedToGetSessionResult"] = "Failed to get session result";
298
+ RequestCredentialsErrorMessage["FailedToGetSessionStatus"] = "Failed to get session status";
299
+ RequestCredentialsErrorMessage["FailedToCreateSession"] = "Failed to create session";
300
+ RequestCredentialsErrorMessage["FailedToVerifyCredentialResponse"] = "Failed to verify credential response";
301
+ RequestCredentialsErrorMessage["MissingOpenId4vpConfig"] = "Identified openid4vp session, but missing openId4vpConfiguration on `requestCredentials`";
302
+ RequestCredentialsErrorMessage["DcApiError"] = "Failed to request credentials with Digital Credentials API";
303
+ RequestCredentialsErrorMessage["DcApiResponseParseError"] = "Failed to parse response from Digital Credentials API";
304
+ RequestCredentialsErrorMessage["Abort"] = "User aborted the session";
305
+ RequestCredentialsErrorMessage["Timeout"] = "User session timeout";
306
+ })(RequestCredentialsErrorMessage || (RequestCredentialsErrorMessage = {}));
307
+
308
+ exports.AbortSessionErrorType = void 0;
309
+
310
+ (function(AbortSessionErrorType) {
311
+ AbortSessionErrorType["AbortSessionFailed"] = "AbortSessionFailed";
312
+ })(exports.AbortSessionErrorType || (exports.AbortSessionErrorType = {}));
313
+
314
+ var AbortSessionErrorMessage;
315
+
316
+ (function(AbortSessionErrorMessage) {
317
+ AbortSessionErrorMessage["FailedToAbortSession"] = "Failed to abort session";
318
+ })(AbortSessionErrorMessage || (AbortSessionErrorMessage = {}));
319
+
320
+ const InitializeOptionsValidator = v__namespace.object({
321
+ apiBaseUrl: v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty("Must not be empty"), v__namespace.url()),
322
+ applicationId: v__namespace.pipe(v__namespace.string(), v__namespace.nonEmpty("Must not be empty"))
277
323
  });
278
324
 
279
- let initialiseOptions = undefined;
325
+ var SafeFetchCommonResponseErrorType;
326
+
327
+ (function(SafeFetchCommonResponseErrorType) {
328
+ SafeFetchCommonResponseErrorType["UnexpectedResponse"] = "UnexpectedResponse";
329
+ })(SafeFetchCommonResponseErrorType || (SafeFetchCommonResponseErrorType = {}));
330
+
331
+ var SafeFetchErrorType;
332
+
333
+ (function(SafeFetchErrorType) {
334
+ SafeFetchErrorType["HttpError"] = "HttpError";
335
+ SafeFetchErrorType["UnknownError"] = "UnknownError";
336
+ })(SafeFetchErrorType || (SafeFetchErrorType = {}));
337
+
338
+ const safeFetch = async (input, init) => {
339
+ try {
340
+ const headers = Object.assign(Object.assign({}, init === null || init === void 0 ? void 0 : init.headers), {
341
+ [MATTR_SDK_VERSION_HEADER]: `verifier-sdk-web/${MATTR_SDK_VERSION_VALUE}`
342
+ });
343
+ const response = await fetch(input, Object.assign(Object.assign({}, init), {
344
+ headers: headers
345
+ }));
346
+ const defaultHttpErrorMessage = `HTTP error, status = ${response.status}`;
347
+ if (response.status >= 400 && response.status < 500) {
348
+ try {
349
+ const errorBody = await response.json();
350
+ if (typeof (errorBody === null || errorBody === void 0 ? void 0 : errorBody.message) === "string") {
351
+ return neverthrow.err({
352
+ type: SafeFetchErrorType.HttpError,
353
+ message: errorBody.message,
354
+ status: response.status
355
+ });
356
+ }
357
+ } catch (_a) {
358
+ return neverthrow.err({
359
+ type: SafeFetchErrorType.HttpError,
360
+ message: defaultHttpErrorMessage,
361
+ status: response.status
362
+ });
363
+ }
364
+ }
365
+ if (response.status > 299 || response.status < 200) {
366
+ return neverthrow.err({
367
+ type: SafeFetchErrorType.HttpError,
368
+ message: defaultHttpErrorMessage,
369
+ status: response.status
370
+ });
371
+ }
372
+ return neverthrow.ok(response);
373
+ } catch (error) {
374
+ return neverthrow.err({
375
+ type: SafeFetchErrorType.UnknownError,
376
+ message: "Unknown error",
377
+ cause: error
378
+ });
379
+ }
380
+ };
381
+
382
+ let initializeOptions = undefined;
383
+
384
+ var InitializeErrorMessage;
385
+
386
+ (function(InitializeErrorMessage) {
387
+ InitializeErrorMessage["SdkNotInitialized"] = "SDK not initialized";
388
+ })(InitializeErrorMessage || (InitializeErrorMessage = {}));
389
+
390
+ const initialize = options => {
391
+ assertType(InitializeOptionsValidator, "Invalid initialize options")(options);
392
+ const {apiBaseUrl: apiBaseUrl} = options;
393
+ const trimmedApiBaseUrl = apiBaseUrl.trim();
394
+ initializeOptions = {
395
+ apiBaseUrl: trimmedApiBaseUrl,
396
+ applicationId: options.applicationId
397
+ };
398
+ };
399
+
400
+ const getInitializeOptions = () => initializeOptions;
401
+
402
+ let sessionAbortController = undefined;
403
+
404
+ let _sessionId = undefined;
405
+
406
+ let _sessionKey = undefined;
280
407
 
281
- var InitialiseErrorMessage;
408
+ let _sessionTimeoutId = undefined;
282
409
 
283
- (function(InitialiseErrorMessage) {
284
- InitialiseErrorMessage["SdkNotInitialised"] = "SDK not initialised";
285
- })(InitialiseErrorMessage || (InitialiseErrorMessage = {}));
410
+ const getActiveSession = () => {
411
+ const sessionId = _sessionId;
412
+ const sessionKey = _sessionKey;
413
+ const sessionTimeoutId = _sessionTimeoutId;
414
+ if (sessionId) {
415
+ return {
416
+ sessionId: sessionId,
417
+ sessionKey: sessionKey,
418
+ sessionTimeoutId: sessionTimeoutId
419
+ };
420
+ }
421
+ return undefined;
422
+ };
286
423
 
287
- const initialise = options => {
288
- assertType(InitialiseOptionsValidator, "Invalid initialise options")(options);
289
- initialiseOptions = options;
424
+ const setActiveSession = session => {
425
+ const {sessionId: sessionId, sessionKey: sessionKey, sessionTimeoutId: sessionTimeoutId} = session;
426
+ _sessionId = sessionId;
427
+ _sessionKey = sessionKey;
428
+ _sessionTimeoutId = sessionTimeoutId;
429
+ const abortController = new AbortController;
430
+ sessionAbortController = abortController;
431
+ return abortController;
290
432
  };
291
433
 
292
- const getInitialiseOptions = () => initialiseOptions;
434
+ const removeActiveSession = () => {
435
+ sessionAbortController === null || sessionAbortController === void 0 ? void 0 : sessionAbortController.abort();
436
+ if (_sessionTimeoutId) {
437
+ window.clearTimeout(_sessionTimeoutId);
438
+ }
439
+ sessionAbortController = undefined;
440
+ _sessionKey = undefined;
441
+ _sessionId = undefined;
442
+ _sessionTimeoutId = undefined;
443
+ };
293
444
 
294
445
  const defaultRetryDelay = attempt => Math.pow(2, attempt) * 1e3;
295
446
 
296
447
  const defaultRetry = 2;
297
448
 
449
+ const withRetry = async (fn, options) => {
450
+ const {retries: retries = defaultRetry, retryDelay: retryDelay = defaultRetryDelay, attempt: attempt = 0} = options;
451
+ try {
452
+ return await fn();
453
+ } catch (err) {
454
+ if (retries > 0) {
455
+ const delay = typeof retryDelay === "function" ? retryDelay(attempt) : retryDelay;
456
+ await new Promise((resolve => setTimeout(resolve, delay)));
457
+ return await withRetry(fn, Object.assign(Object.assign({}, options), {
458
+ retries: retries - 1,
459
+ retryDelay: retryDelay,
460
+ attempt: attempt + 1
461
+ }));
462
+ }
463
+ throw err;
464
+ }
465
+ };
466
+
298
467
  const withRetrySafeFetch = async (fn, options) => {
299
468
  const {retries: retries = defaultRetry, retryDelay: retryDelay = defaultRetryDelay, attempt: attempt = 0, retryHttpStatus: retryHttpStatus} = options;
300
469
  const result = await fn();
@@ -323,17 +492,15 @@ const getHashParamValue = (hash, param) => {
323
492
  return urlParams.get(param);
324
493
  };
325
494
 
326
- const createSession = async ({credentialQuery: credentialQuery, challenge: challenge, redirectUri: redirectUri, apiBaseUrl: apiBaseUrl, applicationId: applicationId, walletProviderId: walletProviderId}) => {
327
- const postData = Object.assign(Object.assign(Object.assign({
495
+ const createSession = async ({credentialQuery: credentialQuery, challenge: challenge, redirectUri: redirectUri, apiBaseUrl: apiBaseUrl, walletProviderId: walletProviderId, dcApiSupported: dcApiSupported, applicationId: applicationId}) => {
496
+ const postData = {
328
497
  credentialQuery: credentialQuery,
329
- challenge: challenge
330
- }, redirectUri ? {
331
- redirectUri: redirectUri
332
- } : {}), applicationId ? {
333
- applicationId: applicationId
334
- } : {}), walletProviderId ? {
335
- walletProviderId: walletProviderId
336
- } : {});
498
+ challenge: challenge,
499
+ applicationId: applicationId,
500
+ redirectUri: redirectUri,
501
+ walletProviderId: walletProviderId,
502
+ dcApiSupported: dcApiSupported
503
+ };
337
504
  const responseResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions`, {
338
505
  method: "POST",
339
506
  headers: {
@@ -347,94 +514,53 @@ const createSession = async ({credentialQuery: credentialQuery, challenge: chall
347
514
  const data = await responseResult.value.json();
348
515
  if (!isType(CreateSessionResponseValidator)(data)) {
349
516
  return neverthrow.err({
350
- type: SafeFetchCommonRespondErrorType.UnexpectedRespond,
351
- message: "Create session return unsupported response"
517
+ type: SafeFetchCommonResponseErrorType.UnexpectedResponse,
518
+ message: "Create session returned unsupported response"
352
519
  });
353
520
  }
354
521
  return neverthrow.ok(data);
355
522
  };
356
523
 
357
- const exchangeSessionResult = async ({challenge: challenge, responseCode: responseCode, sessionId: sessionId, apiBaseUrl: apiBaseUrl}) => {
358
- const postData = {
359
- challenge: challenge,
360
- responseCode: responseCode
361
- };
362
- const fetchResultFn = async () => await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/${sessionId}/result`, {
524
+ const abortSession = async ({apiBaseUrl: apiBaseUrl, sessionId: sessionId, sessionKey: sessionKey}) => {
525
+ const responseResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/${sessionId}/abort`, {
363
526
  method: "POST",
364
527
  headers: {
365
- "Content-Type": "application/json"
366
- },
367
- body: JSON.stringify(postData)
368
- });
369
- const responseResult = await withRetrySafeFetch(fetchResultFn, {
370
- retries: 2,
371
- retryHttpStatus: 404
528
+ "Content-Type": "application/json",
529
+ Authorization: `Bearer ${sessionKey}`
530
+ }
372
531
  });
373
532
  if (responseResult.isErr()) {
374
533
  return neverthrow.err(responseResult.error);
375
534
  }
376
- const data = await responseResult.value.json();
377
- if (!isType(PresentationResultRelaxValidator)(data)) {
378
- return neverthrow.err({
379
- type: SafeFetchCommonRespondErrorType.UnexpectedRespond,
380
- message: "Exchange session result return unsupported response",
381
- details: {
382
- data: data
383
- }
384
- });
385
- }
386
- return neverthrow.ok(data);
535
+ return neverthrow.ok(undefined);
387
536
  };
388
537
 
389
- const isMobileDetect = userAgent => isMobile.isMobile({
390
- ua: userAgent,
391
- tablet: false
392
- });
393
-
394
- const isDigitalCredentialsApiSupported = () => {
395
- var _a;
396
- try {
397
- return typeof ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.identity) === null || _a === void 0 ? void 0 : _a.get) === "function";
398
- } catch (error) {
399
- return false;
400
- }
401
- };
402
-
403
- const createDigitalCredentialsApiSession = async ({credentialQuery: credentialQuery, challenge: challenge, apiBaseUrl: apiBaseUrl, protocol: protocol}) => {
404
- const postData = Object.assign({
405
- credentialQuery: credentialQuery,
406
- challenge: challenge
407
- }, protocol && {
408
- protocol: protocol
409
- });
410
- const responseResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/web/request`, {
411
- method: "POST",
538
+ const getSessionStatus = async ({apiBaseUrl: apiBaseUrl, sessionId: sessionId, sessionKey: sessionKey}) => {
539
+ const responseResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/${sessionId}/status`, {
540
+ method: "GET",
412
541
  headers: {
413
- "Content-Type": "application/json"
414
- },
415
- body: JSON.stringify(postData)
542
+ Authorization: `Bearer ${sessionKey}`
543
+ }
416
544
  });
417
545
  if (responseResult.isErr()) {
418
546
  return neverthrow.err(responseResult.error);
419
547
  }
420
548
  const data = await responseResult.value.json();
421
- if (!isType(CreateDigitalCredentialsApiSessionResponseValidator)(data)) {
549
+ if (!isType(GetSessionStatusResponseValidator)(data)) {
422
550
  return neverthrow.err({
423
- type: SafeFetchCommonRespondErrorType.UnexpectedRespond,
424
- message: "Create digital credentials api session return unsupported response"
551
+ type: SafeFetchCommonResponseErrorType.UnexpectedResponse,
552
+ message: "Get session status return unsupported response"
425
553
  });
426
554
  }
427
555
  return neverthrow.ok(data);
428
556
  };
429
557
 
430
- const getDigitalCredentialsApiSessionResult = async ({challenge: challenge, sessionId: sessionId, response: response, apiBaseUrl: apiBaseUrl, protocol: protocol}) => {
558
+ const exchangeSessionResult = async ({challenge: challenge, responseCode: responseCode, sessionId: sessionId, apiBaseUrl: apiBaseUrl}) => {
431
559
  const postData = {
432
560
  challenge: challenge,
433
- sessionId: sessionId,
434
- response: response,
435
- protocol: protocol
561
+ responseCode: responseCode
436
562
  };
437
- const fetchResultFn = async () => await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/web/response`, {
563
+ const fetchResultFn = async () => await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/${sessionId}/result`, {
438
564
  method: "POST",
439
565
  headers: {
440
566
  "Content-Type": "application/json"
@@ -449,25 +575,24 @@ const getDigitalCredentialsApiSessionResult = async ({challenge: challenge, sess
449
575
  return neverthrow.err(responseResult.error);
450
576
  }
451
577
  const data = await responseResult.value.json();
578
+ if (!isType(PresentationResultRelaxValidator)(data)) {
579
+ return neverthrow.err({
580
+ type: SafeFetchCommonResponseErrorType.UnexpectedResponse,
581
+ message: "Exchange session result return unsupported response",
582
+ details: {
583
+ data: data
584
+ }
585
+ });
586
+ }
452
587
  return neverthrow.ok(data);
453
588
  };
454
589
 
455
- exports.CrossDeviceCallbackErrorType = void 0;
456
-
457
- (function(CrossDeviceCallbackErrorType) {
458
- CrossDeviceCallbackErrorType["Timeout"] = "Timeout";
459
- CrossDeviceCallbackErrorType["Abort"] = "Abort";
460
- CrossDeviceCallbackErrorType["RequestCredentialsFailed"] = "RequestCredentialsFailed";
461
- })(exports.CrossDeviceCallbackErrorType || (exports.CrossDeviceCallbackErrorType = {}));
462
-
463
- var CrossDeviceRequestCredentialsErrorMessage;
590
+ const isMobileDetect = userAgent => isMobile.isMobile({
591
+ ua: userAgent,
592
+ tablet: false
593
+ });
464
594
 
465
- (function(CrossDeviceRequestCredentialsErrorMessage) {
466
- CrossDeviceRequestCredentialsErrorMessage["FailedToGetSessionResult"] = "Failed to get session result";
467
- CrossDeviceRequestCredentialsErrorMessage["FailedToCreateSession"] = "Failed to create session";
468
- CrossDeviceRequestCredentialsErrorMessage["Abort"] = "User aborted the session";
469
- CrossDeviceRequestCredentialsErrorMessage["Timeout"] = "User session timeout";
470
- })(CrossDeviceRequestCredentialsErrorMessage || (CrossDeviceRequestCredentialsErrorMessage = {}));
595
+ const getVersion = () => MATTR_SDK_VERSION_VALUE;
471
596
 
472
597
  var WindowEventListenerType;
473
598
 
@@ -475,10 +600,13 @@ var WindowEventListenerType;
475
600
  WindowEventListenerType["message"] = "message";
476
601
  })(WindowEventListenerType || (WindowEventListenerType = {}));
477
602
 
478
- let listener;
603
+ let listener = undefined;
479
604
 
480
605
  const removeWindowMessageEventListener = () => {
481
- window.removeEventListener(WindowEventListenerType.message, listener, false);
606
+ if (listener) {
607
+ window.removeEventListener(WindowEventListenerType.message, listener, false);
608
+ }
609
+ listener = undefined;
482
610
  };
483
611
 
484
612
  const closeCrossDeviceModal = options => {
@@ -490,8 +618,7 @@ const closeCrossDeviceModal = options => {
490
618
  };
491
619
 
492
620
  const receiveMessageHandler = options => async event => {
493
- const {crossDeviceCallback: crossDeviceCallback, container: container, sessionId: sessionId, apiBaseUrl: apiBaseUrl, challenge: challenge} = options;
494
- const {onComplete: onComplete, onFailure: onFailure} = crossDeviceCallback;
621
+ const {onComplete: onComplete, onFailure: onFailure, container: container, sessionId: sessionId, apiBaseUrl: apiBaseUrl, challenge: challenge} = options;
495
622
  if (event.origin !== apiBaseUrl) {
496
623
  return;
497
624
  }
@@ -505,8 +632,8 @@ const receiveMessageHandler = options => async event => {
505
632
  });
506
633
  if (result.isErr()) {
507
634
  onFailure({
508
- type: exports.CrossDeviceCallbackErrorType.RequestCredentialsFailed,
509
- message: CrossDeviceRequestCredentialsErrorMessage.FailedToGetSessionResult
635
+ type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
636
+ message: RequestCredentialsErrorMessage.FailedToGetSessionResult
510
637
  });
511
638
  closeCrossDeviceModal({
512
639
  container: container
@@ -514,8 +641,9 @@ const receiveMessageHandler = options => async event => {
514
641
  return;
515
642
  }
516
643
  onComplete({
517
- result: result.value,
518
- sessionId: result.value.sessionId
644
+ result: "challenge" in result.value ? result.value : undefined,
645
+ sessionId: result.value.sessionId,
646
+ sessionCompletedInRedirect: false
519
647
  });
520
648
  closeCrossDeviceModal({
521
649
  container: container
@@ -524,8 +652,8 @@ const receiveMessageHandler = options => async event => {
524
652
  }
525
653
  if (event.data.type === MessageEventDataType.PresentationTimeout) {
526
654
  onFailure({
527
- type: exports.CrossDeviceCallbackErrorType.Timeout,
528
- message: CrossDeviceRequestCredentialsErrorMessage.Timeout
655
+ type: exports.RequestCredentialsErrorType.Timeout,
656
+ message: RequestCredentialsErrorMessage.Timeout
529
657
  });
530
658
  closeCrossDeviceModal({
531
659
  container: container
@@ -534,8 +662,8 @@ const receiveMessageHandler = options => async event => {
534
662
  }
535
663
  if (event.data.type === MessageEventDataType.PresentationAbort) {
536
664
  onFailure({
537
- type: exports.CrossDeviceCallbackErrorType.Abort,
538
- message: CrossDeviceRequestCredentialsErrorMessage.Abort
665
+ type: exports.RequestCredentialsErrorType.Abort,
666
+ message: RequestCredentialsErrorMessage.Abort
539
667
  });
540
668
  closeCrossDeviceModal({
541
669
  container: container
@@ -560,82 +688,202 @@ const openCrossDeviceModal = options => {
560
688
  return modalContainer;
561
689
  };
562
690
 
563
- const requestCredentialsCrossDevice = async options => {
564
- const {challenge: challenge, walletProviderId: walletProviderId, credentialQuery: credentialQuery, crossDeviceCallback: crossDeviceCallback, initialiseOptions: initialiseOptions} = options;
565
- const {apiBaseUrl: apiBaseUrl, applicationId: applicationId} = initialiseOptions;
566
- const createSessionResult = await createSession({
567
- credentialQuery: credentialQuery,
568
- challenge: challenge,
691
+ const requestCredentialsWithCrossDevice = async options => {
692
+ const {challenge: challenge, apiBaseUrl: apiBaseUrl, sessionUrl: sessionUrl, sessionId: sessionId, sessionKey: sessionKey} = options;
693
+ const container = openCrossDeviceModal({
694
+ sessionUrl: sessionUrl
695
+ });
696
+ return await new Promise((resolve => {
697
+ const abortController = setActiveSession({
698
+ sessionId: sessionId,
699
+ sessionKey: sessionKey
700
+ });
701
+ abortController.signal.addEventListener("abort", (() => {
702
+ closeCrossDeviceModal({
703
+ container: container
704
+ });
705
+ resolve(neverthrow.err({
706
+ type: exports.RequestCredentialsErrorType.Abort,
707
+ message: RequestCredentialsErrorMessage.Abort
708
+ }));
709
+ }));
710
+ removeWindowMessageEventListener();
711
+ listener = receiveMessageHandler({
712
+ container: container,
713
+ sessionId: sessionId,
714
+ apiBaseUrl: apiBaseUrl,
715
+ challenge: challenge,
716
+ onComplete: data => resolve(neverthrow.ok(data)),
717
+ onFailure: error => resolve(neverthrow.err(error))
718
+ });
719
+ window.addEventListener(WindowEventListenerType.message, listener, false);
720
+ }));
721
+ };
722
+
723
+ const abortCredentialRequest = async () => {
724
+ const initializeOptions = getInitializeOptions();
725
+ if (!initializeOptions) {
726
+ throw new Exception(InitializeErrorMessage.SdkNotInitialized);
727
+ }
728
+ const {apiBaseUrl: apiBaseUrl} = initializeOptions;
729
+ const session = getActiveSession();
730
+ if (!session || !session.sessionKey) {
731
+ return neverthrow.ok(undefined);
732
+ }
733
+ const {sessionId: sessionId, sessionKey: sessionKey} = session;
734
+ removeActiveSession();
735
+ const abortSessionResult = await abortSession({
569
736
  apiBaseUrl: apiBaseUrl,
570
- applicationId: applicationId,
571
- walletProviderId: walletProviderId
737
+ sessionId: sessionId,
738
+ sessionKey: sessionKey
572
739
  });
573
- if (createSessionResult.isErr()) {
740
+ if (abortSessionResult.isErr()) {
574
741
  return neverthrow.err({
575
- type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
576
- message: CrossDeviceRequestCredentialsErrorMessage.FailedToCreateSession,
577
- cause: createSessionResult.error
742
+ type: exports.AbortSessionErrorType.AbortSessionFailed,
743
+ message: AbortSessionErrorMessage.FailedToAbortSession,
744
+ cause: abortSessionResult.error
578
745
  });
579
746
  }
580
- const {sessionUrl: sessionUrl, sessionId: sessionId} = createSessionResult.value;
581
- const container = openCrossDeviceModal({
582
- sessionUrl: sessionUrl,
583
- crossDeviceCallback: crossDeviceCallback
584
- });
585
- listener = receiveMessageHandler({
586
- crossDeviceCallback: crossDeviceCallback,
587
- container: container,
747
+ return neverthrow.ok(undefined);
748
+ };
749
+
750
+ const requestCredentialsWithDigitalCredentialsApi = async options => {
751
+ const {apiBaseUrl: apiBaseUrl, sessionId: sessionId, sessionKey: sessionKey, challenge: challenge, request: request, sessionTtl: sessionTtl} = options;
752
+ const sessionTimeoutId = window.setTimeout((() => removeActiveSession()), sessionTtl * 1e3);
753
+ const abortController = setActiveSession({
588
754
  sessionId: sessionId,
755
+ sessionKey: sessionKey,
756
+ sessionTimeoutId: sessionTimeoutId
757
+ });
758
+ const credentialResponseResult = await getCredentials(request, abortController);
759
+ if (credentialResponseResult.isErr()) {
760
+ await abortCredentialRequest();
761
+ return neverthrow.err(credentialResponseResult.error);
762
+ }
763
+ const credentialResponse = credentialResponseResult.value;
764
+ const parsedCredentialResponseResult = parseCredentialResponse(credentialResponse);
765
+ if (parsedCredentialResponseResult.isErr()) {
766
+ await abortCredentialRequest();
767
+ return neverthrow.err(parsedCredentialResponseResult.error);
768
+ }
769
+ const parsedCredentialResponse = parsedCredentialResponseResult.value;
770
+ const credentialVerificationResult = await verifyCredentialResponse({
589
771
  apiBaseUrl: apiBaseUrl,
590
- challenge: challenge
772
+ sessionId: sessionId,
773
+ sessionKey: sessionKey,
774
+ challenge: challenge,
775
+ protocol: parsedCredentialResponse.protocol,
776
+ data: parsedCredentialResponse.data
591
777
  });
592
- window.addEventListener(WindowEventListenerType.message, listener, false);
778
+ if (credentialVerificationResult.isErr()) {
779
+ return neverthrow.err({
780
+ type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
781
+ message: RequestCredentialsErrorMessage.FailedToVerifyCredentialResponse,
782
+ cause: credentialVerificationResult.error
783
+ });
784
+ }
785
+ const verificationResult = credentialVerificationResult.value;
593
786
  return neverthrow.ok({
787
+ result: "challenge" in verificationResult ? verificationResult : undefined,
594
788
  sessionId: sessionId
595
789
  });
596
790
  };
597
791
 
598
- var SameDeviceRequestCredentialsErrorMessage$1;
599
-
600
- (function(SameDeviceRequestCredentialsErrorMessage) {
601
- SameDeviceRequestCredentialsErrorMessage["FailedToStoreChallenge"] = "Failed to store challenge";
602
- SameDeviceRequestCredentialsErrorMessage["FailedToCreateSession"] = "Failed to create session";
603
- })(SameDeviceRequestCredentialsErrorMessage$1 || (SameDeviceRequestCredentialsErrorMessage$1 = {}));
604
-
605
- const requestCredentialsSameDevice = async options => {
606
- const {challenge: challenge, credentialQuery: credentialQuery, redirectUri: redirectUri, walletProviderId: walletProviderId, initialiseOptions: initialiseOptions} = options;
607
- const {apiBaseUrl: apiBaseUrl, applicationId: applicationId} = initialiseOptions;
608
- window.localStorage.setItem(LocalStorageKey.challenge, challenge);
609
- const storedChallenge = window.localStorage.getItem(LocalStorageKey.challenge);
610
- if (!storedChallenge) {
792
+ const getCredentials = async (request, abortController) => {
793
+ try {
794
+ const credentialResponse = await navigator.credentials.get(Object.assign(Object.assign({}, request), {
795
+ signal: abortController.signal
796
+ }));
797
+ return neverthrow.ok(credentialResponse);
798
+ } catch (exception) {
611
799
  return neverthrow.err({
612
800
  type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
613
- message: SameDeviceRequestCredentialsErrorMessage$1.FailedToStoreChallenge
801
+ message: RequestCredentialsErrorMessage.DcApiError,
802
+ cause: exception
614
803
  });
615
804
  }
616
- const createSessionResult = await createSession({
617
- credentialQuery: credentialQuery,
618
- challenge: storedChallenge,
619
- redirectUri: redirectUri,
620
- apiBaseUrl: apiBaseUrl,
621
- applicationId: applicationId,
622
- walletProviderId: walletProviderId
623
- });
624
- if (createSessionResult.isErr()) {
805
+ };
806
+
807
+ const parseCredentialResponse = credentialResponse => {
808
+ if (!credentialResponse) {
625
809
  return neverthrow.err({
626
810
  type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
627
- message: SameDeviceRequestCredentialsErrorMessage$1.FailedToCreateSession,
628
- cause: createSessionResult.error
811
+ message: RequestCredentialsErrorMessage.DcApiResponseParseError,
812
+ details: {
813
+ response: credentialResponse
814
+ }
629
815
  });
630
816
  }
631
- const {sessionUrl: sessionUrl, sessionId: sessionId} = createSessionResult.value;
632
- window.localStorage.setItem(LocalStorageKey.sessionId, sessionId);
633
- window.location.assign(sessionUrl);
634
- return neverthrow.ok({
635
- sessionId: sessionId
817
+ if (typeof credentialResponse === "object") {
818
+ return neverthrow.ok(credentialResponse);
819
+ }
820
+ if (typeof credentialResponse === "string") {
821
+ try {
822
+ const parsed = JSON.parse(credentialResponse);
823
+ return neverthrow.ok(parsed);
824
+ } catch (_a) {
825
+ return neverthrow.err({
826
+ type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
827
+ message: RequestCredentialsErrorMessage.DcApiResponseParseError,
828
+ details: {
829
+ response: credentialResponse
830
+ }
831
+ });
832
+ }
833
+ }
834
+ return neverthrow.err({
835
+ type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
836
+ message: RequestCredentialsErrorMessage.DcApiResponseParseError,
837
+ details: {
838
+ response: credentialResponse
839
+ }
636
840
  });
637
841
  };
638
842
 
843
+ const verifyCredentialResponse = async options => {
844
+ const {apiBaseUrl: apiBaseUrl, sessionId: sessionId, sessionKey: sessionKey, challenge: challenge, protocol: protocol, data: data} = options;
845
+ const requestBody = {
846
+ protocol: protocol,
847
+ data: data,
848
+ challenge: challenge
849
+ };
850
+ const credentialVerificationResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/${sessionId}/dc-api/response`, {
851
+ method: "POST",
852
+ headers: {
853
+ "Content-Type": "application/json",
854
+ Authorization: `Bearer ${sessionKey}`
855
+ },
856
+ body: JSON.stringify(requestBody)
857
+ });
858
+ if (credentialVerificationResult.isErr()) {
859
+ return neverthrow.err(credentialVerificationResult.error);
860
+ }
861
+ const credentialVerificationResponse = await credentialVerificationResult.value.json();
862
+ if (!isType(PresentationResultRelaxValidator)(credentialVerificationResponse)) {
863
+ return neverthrow.err({
864
+ type: SafeFetchCommonResponseErrorType.UnexpectedResponse,
865
+ message: "Verify credential returned unsupported response",
866
+ details: {
867
+ response: credentialVerificationResponse
868
+ }
869
+ });
870
+ }
871
+ return neverthrow.ok(credentialVerificationResponse);
872
+ };
873
+
874
+ const isDigitalCredentialsApiSupported = () => {
875
+ var _a;
876
+ return "DigitalCredential" in window && typeof window.DigitalCredential === "function" && typeof ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.credentials) === null || _a === void 0 ? void 0 : _a.get) === "function";
877
+ };
878
+
879
+ const sleep = ms => new Promise((resolve => setTimeout(resolve, ms)));
880
+
881
+ const SESSION_STATUS_POLLING_MAX_RETRY = 1e3;
882
+
883
+ const SESSION_STATUS_POLLING_INTERVAL_MS = 3e3;
884
+
885
+ const SESSION_STATUS_POLLING_INITIAL_DELAY_MS = 3e3;
886
+
639
887
  var SameDeviceRequestCredentialsErrorMessage;
640
888
 
641
889
  (function(SameDeviceRequestCredentialsErrorMessage) {
@@ -643,110 +891,136 @@ var SameDeviceRequestCredentialsErrorMessage;
643
891
  SameDeviceRequestCredentialsErrorMessage["FailedToCreateSession"] = "Failed to create session";
644
892
  })(SameDeviceRequestCredentialsErrorMessage || (SameDeviceRequestCredentialsErrorMessage = {}));
645
893
 
646
- const requestCredentialsDigitalCredentialsApi = async options => {
647
- const {challenge: challenge, credentialQuery: credentialQuery, initialiseOptions: initialiseOptions} = options;
648
- const {apiBaseUrl: apiBaseUrl, digitalCredentialsApiProtocol: digitalCredentialsApiProtocol} = initialiseOptions;
894
+ const requestCredentialsSameDevice = async options => {
895
+ const {challenge: challenge, apiBaseUrl: apiBaseUrl, applicationId: applicationId, sessionUrl: sessionUrl, sessionKey: sessionKey, sessionId: sessionId} = options;
896
+ const abortController = setActiveSession({
897
+ sessionId: sessionId,
898
+ sessionKey: sessionKey
899
+ });
900
+ window.localStorage.setItem(LocalStorageKey.sessionId, sessionId);
649
901
  window.localStorage.setItem(LocalStorageKey.challenge, challenge);
650
- const storedChallenge = window.localStorage.getItem(LocalStorageKey.challenge);
651
- if (!storedChallenge) {
652
- return neverthrow.err({
653
- type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
654
- message: SameDeviceRequestCredentialsErrorMessage.FailedToStoreChallenge
902
+ window.location.assign(sessionUrl);
903
+ await sleep(SESSION_STATUS_POLLING_INITIAL_DELAY_MS);
904
+ const checkResult = await withRetry((async () => {
905
+ const statusResult = await getSessionStatus({
906
+ apiBaseUrl: apiBaseUrl,
907
+ applicationId: applicationId,
908
+ sessionId: sessionId,
909
+ sessionKey: sessionKey
655
910
  });
911
+ if (abortController.signal.aborted) {
912
+ return neverthrow.err({
913
+ type: exports.RequestCredentialsErrorType.Abort,
914
+ message: RequestCredentialsErrorMessage.Abort
915
+ });
916
+ }
917
+ if (statusResult.isErr()) {
918
+ if (statusResult.error.status === 404) {
919
+ return neverthrow.err({
920
+ type: exports.RequestCredentialsErrorType.Timeout,
921
+ message: RequestCredentialsErrorMessage.Timeout
922
+ });
923
+ }
924
+ throw Error("Unexpected status response. Retry");
925
+ }
926
+ if (statusResult.value.status !== PresentationStatusCode.ResultReady) {
927
+ throw Error("Result is not ready. Retry");
928
+ }
929
+ return neverthrow.ok(undefined);
930
+ }), {
931
+ retries: SESSION_STATUS_POLLING_MAX_RETRY,
932
+ retryDelay: SESSION_STATUS_POLLING_INTERVAL_MS
933
+ });
934
+ if (checkResult.isErr()) {
935
+ return neverthrow.err(checkResult.error);
936
+ }
937
+ window.close();
938
+ return neverthrow.ok({
939
+ sessionId: sessionId,
940
+ sessionCompletedInRedirect: true
941
+ });
942
+ };
943
+
944
+ const requestCredentials = async options => {
945
+ var _a;
946
+ const initializeOptions = getInitializeOptions();
947
+ if (!initializeOptions) {
948
+ throw new Exception(InitializeErrorMessage.SdkNotInitialized);
656
949
  }
657
- const createSessionResult = await createDigitalCredentialsApiSession({
950
+ assertType(RequestCredentialsOptionsValidator, "Invalid request credential options")(options);
951
+ const {apiBaseUrl: apiBaseUrl, applicationId: applicationId} = initializeOptions;
952
+ const {challenge: challenge = generateChallenge(), credentialQuery: credentialQuery, openid4vpConfiguration: openid4vpConfiguration} = options;
953
+ const dcApiSupported = isDigitalCredentialsApiSupported();
954
+ const openId4VpRedirectUri = deriveOpenId4vpRedirectUri(openid4vpConfiguration);
955
+ const createSessionResult = await createSession({
658
956
  credentialQuery: credentialQuery,
659
- challenge: storedChallenge,
957
+ challenge: challenge,
958
+ redirectUri: openId4VpRedirectUri,
959
+ walletProviderId: (_a = openid4vpConfiguration === null || openid4vpConfiguration === void 0 ? void 0 : openid4vpConfiguration.walletProviderId) !== null && _a !== void 0 ? _a : undefined,
660
960
  apiBaseUrl: apiBaseUrl,
661
- protocol: digitalCredentialsApiProtocol
961
+ applicationId: applicationId,
962
+ dcApiSupported: dcApiSupported
662
963
  });
663
964
  if (createSessionResult.isErr()) {
664
965
  return neverthrow.err({
665
966
  type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
666
- message: SameDeviceRequestCredentialsErrorMessage.FailedToCreateSession,
967
+ message: RequestCredentialsErrorMessage.FailedToCreateSession,
667
968
  cause: createSessionResult.error
668
969
  });
669
970
  }
670
- const {request: request, sessionId: sessionId} = createSessionResult.value;
671
- window.localStorage.setItem(LocalStorageKey.sessionId, sessionId);
672
- let rawResponse;
673
- try {
674
- rawResponse = await navigator.identity.get(request);
675
- } catch (_a) {
971
+ const session = createSessionResult.value;
972
+ const {sessionKey: sessionKey, sessionId: sessionId} = session;
973
+ if (session.type === SessionType.DigitalCredentialsApi) {
974
+ const {request: request, sessionTtl: sessionTtl} = session;
975
+ return await requestCredentialsWithDigitalCredentialsApi({
976
+ apiBaseUrl: apiBaseUrl,
977
+ request: request,
978
+ sessionId: sessionId,
979
+ sessionKey: sessionKey,
980
+ challenge: challenge,
981
+ sessionTtl: sessionTtl
982
+ });
983
+ }
984
+ if (!openid4vpConfiguration) {
676
985
  return neverthrow.err({
677
986
  type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
678
- message: "Failed call to digital credentials api"
987
+ message: RequestCredentialsErrorMessage.MissingOpenId4vpConfig
679
988
  });
680
989
  }
681
- let response;
682
- try {
683
- response = JSON.parse(rawResponse.data);
684
- } catch (_b) {
685
- response = rawResponse.data;
990
+ const {sessionUrl: sessionUrl} = session;
991
+ if (openId4VpRedirectUri) {
992
+ return await requestCredentialsSameDevice({
993
+ challenge: challenge,
994
+ apiBaseUrl: apiBaseUrl,
995
+ applicationId: applicationId,
996
+ sessionUrl: sessionUrl,
997
+ sessionKey: sessionKey,
998
+ sessionId: sessionId
999
+ });
686
1000
  }
687
- const result = await getDigitalCredentialsApiSessionResult({
1001
+ return await requestCredentialsWithCrossDevice({
688
1002
  challenge: challenge,
689
- sessionId: sessionId,
690
- response: response,
691
1003
  apiBaseUrl: apiBaseUrl,
692
- protocol: digitalCredentialsApiProtocol !== null && digitalCredentialsApiProtocol !== void 0 ? digitalCredentialsApiProtocol : "preview"
693
- });
694
- if (result.isOk()) {
695
- return neverthrow.ok({
696
- sessionId: sessionId,
697
- result: result.value
698
- });
699
- }
700
- return neverthrow.err({
701
- type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
702
- message: "Invalid response from digital credentials api"
1004
+ sessionUrl: sessionUrl,
1005
+ sessionKey: sessionKey,
1006
+ sessionId: sessionId
703
1007
  });
704
1008
  };
705
1009
 
706
- const requestCredentials = async options => {
707
- var _a;
708
- const initialiseOptions = getInitialiseOptions();
709
- if (!initialiseOptions) {
710
- throw new Exception(InitialiseErrorMessage.SdkNotInitialised);
1010
+ const deriveOpenId4vpRedirectUri = openid4vpConfiguration => {
1011
+ if (!openid4vpConfiguration) {
1012
+ return undefined;
711
1013
  }
712
- assertType(RequestCredentialsOptionsValidator, "Invalid request credential options")(options);
713
- const {challenge: challenge = generateChallenge()} = options;
714
- const mode = (_a = options.mode) !== null && _a !== void 0 ? _a : isMobileDetect(navigator.userAgent) ? exports.Mode.sameDevice : exports.Mode.crossDevice;
715
- if (initialiseOptions.enableDigitalCredentialsApiCrossDeviceFlow && isDigitalCredentialsApiSupported() && mode === exports.Mode.crossDevice) {
716
- console.log("Digital Credentials API support found, proceeding with request using API in cross device flow");
717
- return await requestCredentialsDigitalCredentialsApi(Object.assign(Object.assign({}, options), {
718
- initialiseOptions: initialiseOptions,
719
- challenge: challenge
720
- }));
721
- } else if (initialiseOptions.enableDigitalCredentialsApiCrossDeviceFlow) {
722
- console.log("Digital Credentials API support not found, falling back to OpenID4VP");
723
- }
724
- if (initialiseOptions.enableDigitalCredentialsApiSameDeviceFlow && isDigitalCredentialsApiSupported() && mode === exports.Mode.sameDevice) {
725
- console.log("Digital Credentials API support found, proceeding with request using API in same device flow");
726
- return await requestCredentialsDigitalCredentialsApi(Object.assign(Object.assign({}, options), {
727
- initialiseOptions: initialiseOptions,
728
- challenge: challenge
729
- }));
730
- } else if (initialiseOptions.enableDigitalCredentialsApiSameDeviceFlow) {
731
- console.log("Digital Credentials API support not found, falling back to OpenID4VP");
1014
+ let detectedMode;
1015
+ if (openid4vpConfiguration && openid4vpConfiguration.mode) {
1016
+ detectedMode = openid4vpConfiguration.mode;
1017
+ } else {
1018
+ detectedMode = isMobileDetect(navigator.userAgent) ? exports.Mode.SameDevice : exports.Mode.CrossDevice;
732
1019
  }
733
- if (mode === exports.Mode.sameDevice && "redirectUri" in options) {
734
- return await requestCredentialsSameDevice(Object.assign(Object.assign({}, options), {
735
- initialiseOptions: initialiseOptions,
736
- challenge: challenge,
737
- mode: mode
738
- }));
1020
+ if (detectedMode === exports.Mode.SameDevice && !isType(OpenId4vpConfigCrossDeviceOptionsValidator)(openid4vpConfiguration) && openid4vpConfiguration.redirectUri) {
1021
+ return openid4vpConfiguration.redirectUri.trim();
739
1022
  }
740
- if (mode === exports.Mode.crossDevice && "crossDeviceCallback" in options) {
741
- return await requestCredentialsCrossDevice(Object.assign(Object.assign({}, options), {
742
- initialiseOptions: initialiseOptions,
743
- challenge: challenge,
744
- mode: mode
745
- }));
746
- }
747
- throw new Exception("Invalid request credential options", {
748
- data: options
749
- });
1023
+ return undefined;
750
1024
  };
751
1025
 
752
1026
  exports.HandleRedirectCallbackErrorType = void 0;
@@ -760,16 +1034,16 @@ var HandleRedirectCallbackErrorMessage;
760
1034
  (function(HandleRedirectCallbackErrorMessage) {
761
1035
  HandleRedirectCallbackErrorMessage["FailedToFindResponseCode"] = "Failed to find response code";
762
1036
  HandleRedirectCallbackErrorMessage["FailedToFindChallenge"] = "Failed to find challenge";
763
- HandleRedirectCallbackErrorMessage["FailedToFindSessionId"] = "Failed to find sessionId";
1037
+ HandleRedirectCallbackErrorMessage["FailedToFindActiveSession"] = "Failed to find active session";
764
1038
  HandleRedirectCallbackErrorMessage["FailedToGetSessionResult"] = "Failed to get session result";
765
1039
  })(HandleRedirectCallbackErrorMessage || (HandleRedirectCallbackErrorMessage = {}));
766
1040
 
767
1041
  const handleRedirectCallback = async () => {
768
- const initialiseOptions = getInitialiseOptions();
769
- if (!initialiseOptions) {
770
- throw new Exception(InitialiseErrorMessage.SdkNotInitialised);
1042
+ const initializeOptions = getInitializeOptions();
1043
+ if (!initializeOptions) {
1044
+ throw new Exception(InitializeErrorMessage.SdkNotInitialized);
771
1045
  }
772
- const {apiBaseUrl: apiBaseUrl} = initialiseOptions;
1046
+ const {apiBaseUrl: apiBaseUrl} = initializeOptions;
773
1047
  const responseCode = getHashParamValue(window.location.hash, "response_code");
774
1048
  if (!responseCode) {
775
1049
  return neverthrow.err({
@@ -777,18 +1051,12 @@ const handleRedirectCallback = async () => {
777
1051
  message: HandleRedirectCallbackErrorMessage.FailedToFindResponseCode
778
1052
  });
779
1053
  }
780
- const challenge = window.localStorage.getItem(LocalStorageKey.challenge);
781
- if (!challenge) {
782
- return neverthrow.err({
783
- type: exports.HandleRedirectCallbackErrorType.HandleRedirectCallbackFailed,
784
- message: HandleRedirectCallbackErrorMessage.FailedToFindChallenge
785
- });
786
- }
787
1054
  const sessionId = window.localStorage.getItem(LocalStorageKey.sessionId);
788
- if (!sessionId) {
1055
+ const challenge = window.localStorage.getItem(LocalStorageKey.challenge);
1056
+ if (!sessionId || !challenge) {
789
1057
  return neverthrow.err({
790
1058
  type: exports.HandleRedirectCallbackErrorType.HandleRedirectCallbackFailed,
791
- message: HandleRedirectCallbackErrorMessage.FailedToFindSessionId
1059
+ message: HandleRedirectCallbackErrorMessage.FailedToFindActiveSession
792
1060
  });
793
1061
  }
794
1062
  const result = await exchangeSessionResult({
@@ -805,20 +1073,24 @@ const handleRedirectCallback = async () => {
805
1073
  });
806
1074
  }
807
1075
  return neverthrow.ok({
808
- result: result.value,
1076
+ result: "challenge" in result.value ? result.value : undefined,
809
1077
  sessionId: result.value.sessionId
810
1078
  });
811
1079
  };
812
1080
 
813
1081
  const utils = {
814
1082
  generateChallenge: generateChallenge,
815
- unwrap: unwrap,
816
- isDigitalCredentialsApiSupported: isDigitalCredentialsApiSupported
1083
+ getVersion: getVersion,
1084
+ unwrap: unwrap
817
1085
  };
818
1086
 
1087
+ exports.abortCredentialRequest = abortCredentialRequest;
1088
+
819
1089
  exports.handleRedirectCallback = handleRedirectCallback;
820
1090
 
821
- exports.initialise = initialise;
1091
+ exports.initialize = initialize;
1092
+
1093
+ exports.isDigitalCredentialsApiSupported = isDigitalCredentialsApiSupported;
822
1094
 
823
1095
  exports.requestCredentials = requestCredentials;
824
1096