@mattrglobal/verifier-sdk-web 2.0.0-preview-digital-credential-api.5 → 2.0.1-unstable.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 +609 -353
  3. package/dist/lib/verifier-js-no-deps.cjs.js.map +1 -1
  4. package/dist/lib/verifier-js.cjs.js +912 -528
  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 +140 -85
  19. package/dist/typings/verifier/types/verifier-web-sdk.d.ts +155 -272
  20. package/dist/typings/verifier/utils.d.ts +23 -37
  21. package/dist/verifier-js.development.js +868 -516
  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-04-28
11
- * Version: 2.0.0-preview-digital-credential-api.5
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(),
@@ -172,22 +165,6 @@ const CredentialQueryValidator = v__namespace.object({
172
165
  })))
173
166
  });
174
167
 
175
- const DcqlCredentialQueryValidator = v__namespace.object({
176
- credentials: v__namespace.array(v__namespace.object({
177
- id: v__namespace.string(),
178
- format: v__namespace.string(),
179
- meta: v__namespace.optional(v__namespace.unknown()),
180
- claims: v__namespace.array(v__namespace.object({
181
- path: v__namespace.array(v__namespace.string())
182
- }))
183
- })),
184
- credential_sets: v__namespace.optional(v__namespace.array(v__namespace.object({
185
- options: v__namespace.array(v__namespace.array(v__namespace.string())),
186
- required: v__namespace.optional(v__namespace.boolean()),
187
- purpose: v__namespace.optional(v__namespace.unknown())
188
- })))
189
- });
190
-
191
168
  var PresentationErrorType;
192
169
 
193
170
  (function(PresentationErrorType) {
@@ -207,23 +184,63 @@ const PresentationResultRelaxValidator = v__namespace.object({
207
184
  error: v__namespace.optional(v__namespace.unknown())
208
185
  });
209
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
+
210
201
  v__namespace.object({
211
- credentialQuery: v__namespace.union([ v__namespace.array(CredentialQueryValidator), DcqlCredentialQueryValidator ]),
202
+ credentialQuery: v__namespace.array(CredentialQueryValidator),
212
203
  challenge: v__namespace.string(),
213
204
  redirectUri: v__namespace.optional(v__namespace.string()),
214
- walletProviderId: v__namespace.optional(v__namespace.string())
205
+ walletProviderId: v__namespace.optional(v__namespace.string()),
206
+ dcApiSupported: v__namespace.optional(v__namespace.boolean())
215
207
  });
216
208
 
217
- const CreateSessionResponseValidator = v__namespace.object({
209
+ const CreateSessionDigitalCredentialsValidator = v__namespace.object({
210
+ type: v__namespace.literal(SessionType.DigitalCredentialsApi),
218
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(),
219
221
  sessionUrl: v__namespace.string()
220
222
  });
221
223
 
222
- const CreateDigitalCredentialsApiSessionResponseValidator = v__namespace.object({
224
+ const CreateSessionResponseValidator = v__namespace.union([ CreateSessionDigitalCredentialsValidator, CreateSessionOpenId4vpResponseValidator ]);
225
+
226
+ v__namespace.object({
223
227
  sessionId: v__namespace.string(),
224
- request: v__namespace.object({})
228
+ sessionKey: v__namespace.string(),
229
+ apiBaseUrl: v__namespace.string()
225
230
  });
226
231
 
232
+ v__namespace.object({
233
+ sessionId: v__namespace.string(),
234
+ sessionKey: v__namespace.string()
235
+ });
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
+
227
244
  var LocalStorageKey;
228
245
 
229
246
  (function(LocalStorageKey) {
@@ -231,12 +248,9 @@ var LocalStorageKey;
231
248
  LocalStorageKey["sessionId"] = "mattr_sid";
232
249
  })(LocalStorageKey || (LocalStorageKey = {}));
233
250
 
234
- exports.Mode = void 0;
251
+ const MATTR_SDK_VERSION_HEADER = "x-mattr-sdk-version";
235
252
 
236
- (function(Mode) {
237
- Mode["sameDevice"] = "sameDevice";
238
- Mode["crossDevice"] = "crossDevice";
239
- })(exports.Mode || (exports.Mode = {}));
253
+ const MATTR_SDK_VERSION_VALUE = "2.0.0";
240
254
 
241
255
  var MessageEventDataType;
242
256
 
@@ -246,71 +260,210 @@ var MessageEventDataType;
246
260
  MessageEventDataType["PresentationAbort"] = "PresentationAbort";
247
261
  })(MessageEventDataType || (MessageEventDataType = {}));
248
262
 
249
- const RequestCredentialsSameDeviceOptionsValidator = v__namespace.object({
250
- credentialQuery: v__namespace.union([ v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()), DcqlCredentialQueryValidator ]),
251
- redirectUri: v__namespace.string(),
252
- challenge: v__namespace.optional(v__namespace.string()),
263
+ const OpenId4vpConfigSameDeviceOptionsValidator = v__namespace.object({
253
264
  walletProviderId: v__namespace.optional(v__namespace.string()),
254
- 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())
255
267
  });
256
268
 
257
- const RequestCredentialsCrossDeviceOptionsValidator = v__namespace.object({
258
- credentialQuery: v__namespace.union([ v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()), DcqlCredentialQueryValidator ]),
259
- crossDeviceCallback: v__namespace.object({
260
- onComplete: v__namespace.function(),
261
- onFailure: v__namespace.function()
262
- }),
263
- challenge: v__namespace.optional(v__namespace.string()),
269
+ const OpenId4vpConfigCrossDeviceOptionsValidator = v__namespace.object({
264
270
  walletProviderId: v__namespace.optional(v__namespace.string()),
265
- mode: v__namespace.picklist([ exports.Mode.crossDevice ])
271
+ mode: v__namespace.literal(exports.Mode.CrossDevice)
266
272
  });
267
273
 
268
- const RequestCredentialsAutoDetectDeviceOptionsValidator = v__namespace.object({
269
- credentialQuery: v__namespace.union([ v__namespace.pipe(v__namespace.array(CredentialQueryValidator), v__namespace.nonEmpty()), DcqlCredentialQueryValidator ]),
270
- crossDeviceCallback: v__namespace.object({
271
- onComplete: v__namespace.function(),
272
- onFailure: v__namespace.function()
273
- }),
274
- redirectUri: v__namespace.string(),
275
- challenge: v__namespace.optional(v__namespace.string()),
274
+ const OpenId4vpConfigAutoDetectOptionsValidator = v__namespace.object({
276
275
  walletProviderId: v__namespace.optional(v__namespace.string()),
277
- 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 ]))
278
278
  });
279
279
 
280
- 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
+ });
281
285
 
282
286
  exports.RequestCredentialsErrorType = void 0;
283
287
 
284
288
  (function(RequestCredentialsErrorType) {
285
289
  RequestCredentialsErrorType["RequestCredentialsFailed"] = "RequestCredentialsFailed";
290
+ RequestCredentialsErrorType["Timeout"] = "Timeout";
291
+ RequestCredentialsErrorType["Abort"] = "Abort";
286
292
  })(exports.RequestCredentialsErrorType || (exports.RequestCredentialsErrorType = {}));
287
293
 
288
- const InitialiseOptionsValidator = v__namespace.object({
289
- apiBaseUrl: v__namespace.string(),
290
- applicationId: v__namespace.optional(v__namespace.string()),
291
- enableDigitalCredentialsApiSameDeviceFlow: v__namespace.optional(v__namespace.boolean()),
292
- 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"))
293
323
  });
294
324
 
295
- let initialiseOptions = undefined;
325
+ var SafeFetchCommonResponseErrorType;
296
326
 
297
- var InitialiseErrorMessage;
327
+ (function(SafeFetchCommonResponseErrorType) {
328
+ SafeFetchCommonResponseErrorType["UnexpectedResponse"] = "UnexpectedResponse";
329
+ })(SafeFetchCommonResponseErrorType || (SafeFetchCommonResponseErrorType = {}));
298
330
 
299
- (function(InitialiseErrorMessage) {
300
- InitialiseErrorMessage["SdkNotInitialised"] = "SDK not initialised";
301
- })(InitialiseErrorMessage || (InitialiseErrorMessage = {}));
331
+ var SafeFetchErrorType;
302
332
 
303
- const initialise = options => {
304
- assertType(InitialiseOptionsValidator, "Invalid initialise options")(options);
305
- initialiseOptions = options;
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
+ };
306
398
  };
307
399
 
308
- const getInitialiseOptions = () => initialiseOptions;
400
+ const getInitializeOptions = () => initializeOptions;
401
+
402
+ let sessionAbortController = undefined;
403
+
404
+ let _sessionId = undefined;
405
+
406
+ let _sessionKey = undefined;
407
+
408
+ let _sessionTimeoutId = undefined;
409
+
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
+ };
423
+
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;
432
+ };
433
+
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
+ };
309
444
 
310
445
  const defaultRetryDelay = attempt => Math.pow(2, attempt) * 1e3;
311
446
 
312
447
  const defaultRetry = 2;
313
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
+
314
467
  const withRetrySafeFetch = async (fn, options) => {
315
468
  const {retries: retries = defaultRetry, retryDelay: retryDelay = defaultRetryDelay, attempt: attempt = 0, retryHttpStatus: retryHttpStatus} = options;
316
469
  const result = await fn();
@@ -339,17 +492,15 @@ const getHashParamValue = (hash, param) => {
339
492
  return urlParams.get(param);
340
493
  };
341
494
 
342
- const createSession = async ({credentialQuery: credentialQuery, challenge: challenge, redirectUri: redirectUri, apiBaseUrl: apiBaseUrl, applicationId: applicationId, walletProviderId: walletProviderId}) => {
343
- 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 = {
344
497
  credentialQuery: credentialQuery,
345
- challenge: challenge
346
- }, redirectUri ? {
347
- redirectUri: redirectUri
348
- } : {}), applicationId ? {
349
- applicationId: applicationId
350
- } : {}), walletProviderId ? {
351
- walletProviderId: walletProviderId
352
- } : {});
498
+ challenge: challenge,
499
+ applicationId: applicationId,
500
+ redirectUri: redirectUri,
501
+ walletProviderId: walletProviderId,
502
+ dcApiSupported: dcApiSupported
503
+ };
353
504
  const responseResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions`, {
354
505
  method: "POST",
355
506
  headers: {
@@ -363,94 +514,53 @@ const createSession = async ({credentialQuery: credentialQuery, challenge: chall
363
514
  const data = await responseResult.value.json();
364
515
  if (!isType(CreateSessionResponseValidator)(data)) {
365
516
  return neverthrow.err({
366
- type: SafeFetchCommonRespondErrorType.UnexpectedRespond,
367
- message: "Create session return unsupported response"
517
+ type: SafeFetchCommonResponseErrorType.UnexpectedResponse,
518
+ message: "Create session returned unsupported response"
368
519
  });
369
520
  }
370
521
  return neverthrow.ok(data);
371
522
  };
372
523
 
373
- const exchangeSessionResult = async ({challenge: challenge, responseCode: responseCode, sessionId: sessionId, apiBaseUrl: apiBaseUrl}) => {
374
- const postData = {
375
- challenge: challenge,
376
- responseCode: responseCode
377
- };
378
- 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`, {
379
526
  method: "POST",
380
527
  headers: {
381
- "Content-Type": "application/json"
382
- },
383
- body: JSON.stringify(postData)
384
- });
385
- const responseResult = await withRetrySafeFetch(fetchResultFn, {
386
- retries: 2,
387
- retryHttpStatus: 404
528
+ "Content-Type": "application/json",
529
+ Authorization: `Bearer ${sessionKey}`
530
+ }
388
531
  });
389
532
  if (responseResult.isErr()) {
390
533
  return neverthrow.err(responseResult.error);
391
534
  }
392
- const data = await responseResult.value.json();
393
- if (!isType(PresentationResultRelaxValidator)(data)) {
394
- return neverthrow.err({
395
- type: SafeFetchCommonRespondErrorType.UnexpectedRespond,
396
- message: "Exchange session result return unsupported response",
397
- details: {
398
- data: data
399
- }
400
- });
401
- }
402
- return neverthrow.ok(data);
535
+ return neverthrow.ok(undefined);
403
536
  };
404
537
 
405
- const isMobileDetect = userAgent => isMobile.isMobile({
406
- ua: userAgent,
407
- tablet: false
408
- });
409
-
410
- const isDigitalCredentialsApiSupported = () => {
411
- var _a;
412
- try {
413
- return typeof ((_a = navigator === null || navigator === void 0 ? void 0 : navigator.identity) === null || _a === void 0 ? void 0 : _a.get) === "function";
414
- } catch (error) {
415
- return false;
416
- }
417
- };
418
-
419
- const createDigitalCredentialsApiSession = async ({credentialQuery: credentialQuery, challenge: challenge, apiBaseUrl: apiBaseUrl, protocol: protocol}) => {
420
- const postData = Object.assign({
421
- credentialQuery: credentialQuery,
422
- challenge: challenge
423
- }, protocol && {
424
- protocol: protocol
425
- });
426
- const responseResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/web/request`, {
427
- 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",
428
541
  headers: {
429
- "Content-Type": "application/json"
430
- },
431
- body: JSON.stringify(postData)
542
+ Authorization: `Bearer ${sessionKey}`
543
+ }
432
544
  });
433
545
  if (responseResult.isErr()) {
434
546
  return neverthrow.err(responseResult.error);
435
547
  }
436
548
  const data = await responseResult.value.json();
437
- if (!isType(CreateDigitalCredentialsApiSessionResponseValidator)(data)) {
549
+ if (!isType(GetSessionStatusResponseValidator)(data)) {
438
550
  return neverthrow.err({
439
- type: SafeFetchCommonRespondErrorType.UnexpectedRespond,
440
- message: "Create digital credentials api session return unsupported response"
551
+ type: SafeFetchCommonResponseErrorType.UnexpectedResponse,
552
+ message: "Get session status return unsupported response"
441
553
  });
442
554
  }
443
555
  return neverthrow.ok(data);
444
556
  };
445
557
 
446
- 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}) => {
447
559
  const postData = {
448
560
  challenge: challenge,
449
- sessionId: sessionId,
450
- response: response,
451
- protocol: protocol
561
+ responseCode: responseCode
452
562
  };
453
- const fetchResultFn = async () => await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/web/response`, {
563
+ const fetchResultFn = async () => await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/${sessionId}/result`, {
454
564
  method: "POST",
455
565
  headers: {
456
566
  "Content-Type": "application/json"
@@ -465,25 +575,24 @@ const getDigitalCredentialsApiSessionResult = async ({challenge: challenge, sess
465
575
  return neverthrow.err(responseResult.error);
466
576
  }
467
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
+ }
468
587
  return neverthrow.ok(data);
469
588
  };
470
589
 
471
- exports.CrossDeviceCallbackErrorType = void 0;
472
-
473
- (function(CrossDeviceCallbackErrorType) {
474
- CrossDeviceCallbackErrorType["Timeout"] = "Timeout";
475
- CrossDeviceCallbackErrorType["Abort"] = "Abort";
476
- CrossDeviceCallbackErrorType["RequestCredentialsFailed"] = "RequestCredentialsFailed";
477
- })(exports.CrossDeviceCallbackErrorType || (exports.CrossDeviceCallbackErrorType = {}));
478
-
479
- var CrossDeviceRequestCredentialsErrorMessage;
590
+ const isMobileDetect = userAgent => isMobile.isMobile({
591
+ ua: userAgent,
592
+ tablet: false
593
+ });
480
594
 
481
- (function(CrossDeviceRequestCredentialsErrorMessage) {
482
- CrossDeviceRequestCredentialsErrorMessage["FailedToGetSessionResult"] = "Failed to get session result";
483
- CrossDeviceRequestCredentialsErrorMessage["FailedToCreateSession"] = "Failed to create session";
484
- CrossDeviceRequestCredentialsErrorMessage["Abort"] = "User aborted the session";
485
- CrossDeviceRequestCredentialsErrorMessage["Timeout"] = "User session timeout";
486
- })(CrossDeviceRequestCredentialsErrorMessage || (CrossDeviceRequestCredentialsErrorMessage = {}));
595
+ const getVersion = () => MATTR_SDK_VERSION_VALUE;
487
596
 
488
597
  var WindowEventListenerType;
489
598
 
@@ -491,10 +600,13 @@ var WindowEventListenerType;
491
600
  WindowEventListenerType["message"] = "message";
492
601
  })(WindowEventListenerType || (WindowEventListenerType = {}));
493
602
 
494
- let listener;
603
+ let listener = undefined;
495
604
 
496
605
  const removeWindowMessageEventListener = () => {
497
- window.removeEventListener(WindowEventListenerType.message, listener, false);
606
+ if (listener) {
607
+ window.removeEventListener(WindowEventListenerType.message, listener, false);
608
+ }
609
+ listener = undefined;
498
610
  };
499
611
 
500
612
  const closeCrossDeviceModal = options => {
@@ -506,8 +618,7 @@ const closeCrossDeviceModal = options => {
506
618
  };
507
619
 
508
620
  const receiveMessageHandler = options => async event => {
509
- const {crossDeviceCallback: crossDeviceCallback, container: container, sessionId: sessionId, apiBaseUrl: apiBaseUrl, challenge: challenge} = options;
510
- const {onComplete: onComplete, onFailure: onFailure} = crossDeviceCallback;
621
+ const {onComplete: onComplete, onFailure: onFailure, container: container, sessionId: sessionId, apiBaseUrl: apiBaseUrl, challenge: challenge} = options;
511
622
  if (event.origin !== apiBaseUrl) {
512
623
  return;
513
624
  }
@@ -521,8 +632,8 @@ const receiveMessageHandler = options => async event => {
521
632
  });
522
633
  if (result.isErr()) {
523
634
  onFailure({
524
- type: exports.CrossDeviceCallbackErrorType.RequestCredentialsFailed,
525
- message: CrossDeviceRequestCredentialsErrorMessage.FailedToGetSessionResult
635
+ type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
636
+ message: RequestCredentialsErrorMessage.FailedToGetSessionResult
526
637
  });
527
638
  closeCrossDeviceModal({
528
639
  container: container
@@ -530,8 +641,9 @@ const receiveMessageHandler = options => async event => {
530
641
  return;
531
642
  }
532
643
  onComplete({
533
- result: result.value,
534
- sessionId: result.value.sessionId
644
+ result: "challenge" in result.value ? result.value : undefined,
645
+ sessionId: result.value.sessionId,
646
+ sessionCompletedInRedirect: false
535
647
  });
536
648
  closeCrossDeviceModal({
537
649
  container: container
@@ -540,8 +652,8 @@ const receiveMessageHandler = options => async event => {
540
652
  }
541
653
  if (event.data.type === MessageEventDataType.PresentationTimeout) {
542
654
  onFailure({
543
- type: exports.CrossDeviceCallbackErrorType.Timeout,
544
- message: CrossDeviceRequestCredentialsErrorMessage.Timeout
655
+ type: exports.RequestCredentialsErrorType.Timeout,
656
+ message: RequestCredentialsErrorMessage.Timeout
545
657
  });
546
658
  closeCrossDeviceModal({
547
659
  container: container
@@ -550,8 +662,8 @@ const receiveMessageHandler = options => async event => {
550
662
  }
551
663
  if (event.data.type === MessageEventDataType.PresentationAbort) {
552
664
  onFailure({
553
- type: exports.CrossDeviceCallbackErrorType.Abort,
554
- message: CrossDeviceRequestCredentialsErrorMessage.Abort
665
+ type: exports.RequestCredentialsErrorType.Abort,
666
+ message: RequestCredentialsErrorMessage.Abort
555
667
  });
556
668
  closeCrossDeviceModal({
557
669
  container: container
@@ -576,82 +688,202 @@ const openCrossDeviceModal = options => {
576
688
  return modalContainer;
577
689
  };
578
690
 
579
- const requestCredentialsCrossDevice = async options => {
580
- const {challenge: challenge, walletProviderId: walletProviderId, credentialQuery: credentialQuery, crossDeviceCallback: crossDeviceCallback, initialiseOptions: initialiseOptions} = options;
581
- const {apiBaseUrl: apiBaseUrl, applicationId: applicationId} = initialiseOptions;
582
- const createSessionResult = await createSession({
583
- credentialQuery: credentialQuery,
584
- 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({
585
736
  apiBaseUrl: apiBaseUrl,
586
- applicationId: applicationId,
587
- walletProviderId: walletProviderId
737
+ sessionId: sessionId,
738
+ sessionKey: sessionKey
588
739
  });
589
- if (createSessionResult.isErr()) {
740
+ if (abortSessionResult.isErr()) {
590
741
  return neverthrow.err({
591
- type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
592
- message: CrossDeviceRequestCredentialsErrorMessage.FailedToCreateSession,
593
- cause: createSessionResult.error
742
+ type: exports.AbortSessionErrorType.AbortSessionFailed,
743
+ message: AbortSessionErrorMessage.FailedToAbortSession,
744
+ cause: abortSessionResult.error
594
745
  });
595
746
  }
596
- const {sessionUrl: sessionUrl, sessionId: sessionId} = createSessionResult.value;
597
- const container = openCrossDeviceModal({
598
- sessionUrl: sessionUrl,
599
- crossDeviceCallback: crossDeviceCallback
600
- });
601
- listener = receiveMessageHandler({
602
- crossDeviceCallback: crossDeviceCallback,
603
- 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({
604
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({
605
771
  apiBaseUrl: apiBaseUrl,
606
- challenge: challenge
772
+ sessionId: sessionId,
773
+ sessionKey: sessionKey,
774
+ challenge: challenge,
775
+ protocol: parsedCredentialResponse.protocol,
776
+ data: parsedCredentialResponse.data
607
777
  });
608
- 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;
609
786
  return neverthrow.ok({
787
+ result: "challenge" in verificationResult ? verificationResult : undefined,
610
788
  sessionId: sessionId
611
789
  });
612
790
  };
613
791
 
614
- var SameDeviceRequestCredentialsErrorMessage$1;
615
-
616
- (function(SameDeviceRequestCredentialsErrorMessage) {
617
- SameDeviceRequestCredentialsErrorMessage["FailedToStoreChallenge"] = "Failed to store challenge";
618
- SameDeviceRequestCredentialsErrorMessage["FailedToCreateSession"] = "Failed to create session";
619
- })(SameDeviceRequestCredentialsErrorMessage$1 || (SameDeviceRequestCredentialsErrorMessage$1 = {}));
620
-
621
- const requestCredentialsSameDevice = async options => {
622
- const {challenge: challenge, credentialQuery: credentialQuery, redirectUri: redirectUri, walletProviderId: walletProviderId, initialiseOptions: initialiseOptions} = options;
623
- const {apiBaseUrl: apiBaseUrl, applicationId: applicationId} = initialiseOptions;
624
- window.localStorage.setItem(LocalStorageKey.challenge, challenge);
625
- const storedChallenge = window.localStorage.getItem(LocalStorageKey.challenge);
626
- 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) {
627
799
  return neverthrow.err({
628
800
  type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
629
- message: SameDeviceRequestCredentialsErrorMessage$1.FailedToStoreChallenge
801
+ message: RequestCredentialsErrorMessage.DcApiError,
802
+ cause: exception
630
803
  });
631
804
  }
632
- const createSessionResult = await createSession({
633
- credentialQuery: credentialQuery,
634
- challenge: storedChallenge,
635
- redirectUri: redirectUri,
636
- apiBaseUrl: apiBaseUrl,
637
- applicationId: applicationId,
638
- walletProviderId: walletProviderId
639
- });
640
- if (createSessionResult.isErr()) {
805
+ };
806
+
807
+ const parseCredentialResponse = credentialResponse => {
808
+ if (!credentialResponse) {
641
809
  return neverthrow.err({
642
810
  type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
643
- message: SameDeviceRequestCredentialsErrorMessage$1.FailedToCreateSession,
644
- cause: createSessionResult.error
811
+ message: RequestCredentialsErrorMessage.DcApiResponseParseError,
812
+ details: {
813
+ response: credentialResponse
814
+ }
645
815
  });
646
816
  }
647
- const {sessionUrl: sessionUrl, sessionId: sessionId} = createSessionResult.value;
648
- window.localStorage.setItem(LocalStorageKey.sessionId, sessionId);
649
- window.location.assign(sessionUrl);
650
- return neverthrow.ok({
651
- 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
+ }
652
840
  });
653
841
  };
654
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
+
655
887
  var SameDeviceRequestCredentialsErrorMessage;
656
888
 
657
889
  (function(SameDeviceRequestCredentialsErrorMessage) {
@@ -659,110 +891,136 @@ var SameDeviceRequestCredentialsErrorMessage;
659
891
  SameDeviceRequestCredentialsErrorMessage["FailedToCreateSession"] = "Failed to create session";
660
892
  })(SameDeviceRequestCredentialsErrorMessage || (SameDeviceRequestCredentialsErrorMessage = {}));
661
893
 
662
- const requestCredentialsDigitalCredentialsApi = async options => {
663
- const {challenge: challenge, credentialQuery: credentialQuery, initialiseOptions: initialiseOptions} = options;
664
- 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);
665
901
  window.localStorage.setItem(LocalStorageKey.challenge, challenge);
666
- const storedChallenge = window.localStorage.getItem(LocalStorageKey.challenge);
667
- if (!storedChallenge) {
668
- return neverthrow.err({
669
- type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
670
- 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
671
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);
672
949
  }
673
- 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({
674
956
  credentialQuery: credentialQuery,
675
- 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,
676
960
  apiBaseUrl: apiBaseUrl,
677
- protocol: digitalCredentialsApiProtocol
961
+ applicationId: applicationId,
962
+ dcApiSupported: dcApiSupported
678
963
  });
679
964
  if (createSessionResult.isErr()) {
680
965
  return neverthrow.err({
681
966
  type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
682
- message: SameDeviceRequestCredentialsErrorMessage.FailedToCreateSession,
967
+ message: RequestCredentialsErrorMessage.FailedToCreateSession,
683
968
  cause: createSessionResult.error
684
969
  });
685
970
  }
686
- const {request: request, sessionId: sessionId} = createSessionResult.value;
687
- window.localStorage.setItem(LocalStorageKey.sessionId, sessionId);
688
- let rawResponse;
689
- try {
690
- rawResponse = await navigator.identity.get(request);
691
- } 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) {
692
985
  return neverthrow.err({
693
986
  type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
694
- message: "Failed call to digital credentials api"
987
+ message: RequestCredentialsErrorMessage.MissingOpenId4vpConfig
695
988
  });
696
989
  }
697
- let response;
698
- try {
699
- response = JSON.parse(rawResponse.data);
700
- } catch (_b) {
701
- 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
+ });
702
1000
  }
703
- const result = await getDigitalCredentialsApiSessionResult({
1001
+ return await requestCredentialsWithCrossDevice({
704
1002
  challenge: challenge,
705
- sessionId: sessionId,
706
- response: response,
707
1003
  apiBaseUrl: apiBaseUrl,
708
- protocol: digitalCredentialsApiProtocol !== null && digitalCredentialsApiProtocol !== void 0 ? digitalCredentialsApiProtocol : "preview"
709
- });
710
- if (result.isOk()) {
711
- return neverthrow.ok({
712
- sessionId: sessionId,
713
- result: result.value
714
- });
715
- }
716
- return neverthrow.err({
717
- type: exports.RequestCredentialsErrorType.RequestCredentialsFailed,
718
- message: "Invalid response from digital credentials api"
1004
+ sessionUrl: sessionUrl,
1005
+ sessionKey: sessionKey,
1006
+ sessionId: sessionId
719
1007
  });
720
1008
  };
721
1009
 
722
- const requestCredentials = async options => {
723
- var _a;
724
- const initialiseOptions = getInitialiseOptions();
725
- if (!initialiseOptions) {
726
- throw new Exception(InitialiseErrorMessage.SdkNotInitialised);
1010
+ const deriveOpenId4vpRedirectUri = openid4vpConfiguration => {
1011
+ if (!openid4vpConfiguration) {
1012
+ return undefined;
727
1013
  }
728
- assertType(RequestCredentialsOptionsValidator, "Invalid request credential options")(options);
729
- const {challenge: challenge = generateChallenge()} = options;
730
- const mode = (_a = options.mode) !== null && _a !== void 0 ? _a : isMobileDetect(navigator.userAgent) ? exports.Mode.sameDevice : exports.Mode.crossDevice;
731
- if (initialiseOptions.enableDigitalCredentialsApiCrossDeviceFlow && isDigitalCredentialsApiSupported() && mode === exports.Mode.crossDevice) {
732
- console.log("Digital Credentials API support found, proceeding with request using API in cross device flow");
733
- return await requestCredentialsDigitalCredentialsApi(Object.assign(Object.assign({}, options), {
734
- initialiseOptions: initialiseOptions,
735
- challenge: challenge
736
- }));
737
- } else if (initialiseOptions.enableDigitalCredentialsApiCrossDeviceFlow) {
738
- console.log("Digital Credentials API support not found, falling back to OpenID4VP");
739
- }
740
- if (initialiseOptions.enableDigitalCredentialsApiSameDeviceFlow && isDigitalCredentialsApiSupported() && mode === exports.Mode.sameDevice) {
741
- console.log("Digital Credentials API support found, proceeding with request using API in same device flow");
742
- return await requestCredentialsDigitalCredentialsApi(Object.assign(Object.assign({}, options), {
743
- initialiseOptions: initialiseOptions,
744
- challenge: challenge
745
- }));
746
- } else if (initialiseOptions.enableDigitalCredentialsApiSameDeviceFlow) {
747
- 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;
748
1019
  }
749
- if (mode === exports.Mode.sameDevice && "redirectUri" in options) {
750
- return await requestCredentialsSameDevice(Object.assign(Object.assign({}, options), {
751
- initialiseOptions: initialiseOptions,
752
- challenge: challenge,
753
- mode: mode
754
- }));
1020
+ if (detectedMode === exports.Mode.SameDevice && !isType(OpenId4vpConfigCrossDeviceOptionsValidator)(openid4vpConfiguration) && openid4vpConfiguration.redirectUri) {
1021
+ return openid4vpConfiguration.redirectUri.trim();
755
1022
  }
756
- if (mode === exports.Mode.crossDevice && "crossDeviceCallback" in options) {
757
- return await requestCredentialsCrossDevice(Object.assign(Object.assign({}, options), {
758
- initialiseOptions: initialiseOptions,
759
- challenge: challenge,
760
- mode: mode
761
- }));
762
- }
763
- throw new Exception("Invalid request credential options", {
764
- data: options
765
- });
1023
+ return undefined;
766
1024
  };
767
1025
 
768
1026
  exports.HandleRedirectCallbackErrorType = void 0;
@@ -776,16 +1034,16 @@ var HandleRedirectCallbackErrorMessage;
776
1034
  (function(HandleRedirectCallbackErrorMessage) {
777
1035
  HandleRedirectCallbackErrorMessage["FailedToFindResponseCode"] = "Failed to find response code";
778
1036
  HandleRedirectCallbackErrorMessage["FailedToFindChallenge"] = "Failed to find challenge";
779
- HandleRedirectCallbackErrorMessage["FailedToFindSessionId"] = "Failed to find sessionId";
1037
+ HandleRedirectCallbackErrorMessage["FailedToFindActiveSession"] = "Failed to find active session";
780
1038
  HandleRedirectCallbackErrorMessage["FailedToGetSessionResult"] = "Failed to get session result";
781
1039
  })(HandleRedirectCallbackErrorMessage || (HandleRedirectCallbackErrorMessage = {}));
782
1040
 
783
1041
  const handleRedirectCallback = async () => {
784
- const initialiseOptions = getInitialiseOptions();
785
- if (!initialiseOptions) {
786
- throw new Exception(InitialiseErrorMessage.SdkNotInitialised);
1042
+ const initializeOptions = getInitializeOptions();
1043
+ if (!initializeOptions) {
1044
+ throw new Exception(InitializeErrorMessage.SdkNotInitialized);
787
1045
  }
788
- const {apiBaseUrl: apiBaseUrl} = initialiseOptions;
1046
+ const {apiBaseUrl: apiBaseUrl} = initializeOptions;
789
1047
  const responseCode = getHashParamValue(window.location.hash, "response_code");
790
1048
  if (!responseCode) {
791
1049
  return neverthrow.err({
@@ -793,18 +1051,12 @@ const handleRedirectCallback = async () => {
793
1051
  message: HandleRedirectCallbackErrorMessage.FailedToFindResponseCode
794
1052
  });
795
1053
  }
796
- const challenge = window.localStorage.getItem(LocalStorageKey.challenge);
797
- if (!challenge) {
798
- return neverthrow.err({
799
- type: exports.HandleRedirectCallbackErrorType.HandleRedirectCallbackFailed,
800
- message: HandleRedirectCallbackErrorMessage.FailedToFindChallenge
801
- });
802
- }
803
1054
  const sessionId = window.localStorage.getItem(LocalStorageKey.sessionId);
804
- if (!sessionId) {
1055
+ const challenge = window.localStorage.getItem(LocalStorageKey.challenge);
1056
+ if (!sessionId || !challenge) {
805
1057
  return neverthrow.err({
806
1058
  type: exports.HandleRedirectCallbackErrorType.HandleRedirectCallbackFailed,
807
- message: HandleRedirectCallbackErrorMessage.FailedToFindSessionId
1059
+ message: HandleRedirectCallbackErrorMessage.FailedToFindActiveSession
808
1060
  });
809
1061
  }
810
1062
  const result = await exchangeSessionResult({
@@ -821,20 +1073,24 @@ const handleRedirectCallback = async () => {
821
1073
  });
822
1074
  }
823
1075
  return neverthrow.ok({
824
- result: result.value,
1076
+ result: "challenge" in result.value ? result.value : undefined,
825
1077
  sessionId: result.value.sessionId
826
1078
  });
827
1079
  };
828
1080
 
829
1081
  const utils = {
830
1082
  generateChallenge: generateChallenge,
831
- unwrap: unwrap,
832
- isDigitalCredentialsApiSupported: isDigitalCredentialsApiSupported
1083
+ getVersion: getVersion,
1084
+ unwrap: unwrap
833
1085
  };
834
1086
 
1087
+ exports.abortCredentialRequest = abortCredentialRequest;
1088
+
835
1089
  exports.handleRedirectCallback = handleRedirectCallback;
836
1090
 
837
- exports.initialise = initialise;
1091
+ exports.initialize = initialize;
1092
+
1093
+ exports.isDigitalCredentialsApiSupported = isDigitalCredentialsApiSupported;
838
1094
 
839
1095
  exports.requestCredentials = requestCredentials;
840
1096