@mattrglobal/verifier-sdk-web 2.0.0-preview-digital-credential-api.2 → 2.0.0-preview-digital-credential-api.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -33
- package/dist/lib/verifier-js-no-deps.cjs.js +32 -18
- package/dist/lib/verifier-js-no-deps.cjs.js.map +1 -1
- package/dist/lib/verifier-js.cjs.js +130 -127
- package/dist/lib/verifier-js.cjs.js.map +1 -1
- package/dist/typings/verifier/types/credential-presentation.d.ts +46 -35
- package/dist/typings/verifier/types/verifier-web-sdk.d.ts +3 -0
- package/dist/typings/verifier/utils.d.ts +8 -7
- package/dist/verifier-js.development.js +121 -118
- package/dist/verifier-js.development.js.map +1 -1
- package/dist/verifier-js.production.esm.js +4 -4
- package/dist/verifier-js.production.esm.js.map +1 -1
- package/dist/verifier-js.production.js +4 -4
- package/dist/verifier-js.production.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -35,7 +35,7 @@ Request or download the
|
|
|
35
35
|
|
|
36
36
|
## Overview
|
|
37
37
|
|
|
38
|
-
The Verifier Web SDK is a powerful tool for integrating online credential verification capabilities into your web applications. It enables secure and efficient verification of [mDocs](https://learn.mattr.global/docs/
|
|
38
|
+
The Verifier Web SDK is a powerful tool for integrating online credential verification capabilities into your web applications. It enables secure and efficient verification of [mDocs](https://learn.mattr.global/docs/mdocs), supporting both [same-device](https://learn.mattr.global/docs/verification/online/mdocs/overview#same-device-verification-workflow) and [cross-device](https://learn.mattr.global/docs/verification/online/mdocs/overview#cross-device-verification-workflow) verification workflows. The SDK leverages the MATTR VII platform to handle credential presentation and verification processes.
|
|
39
39
|
|
|
40
40
|
## Features
|
|
41
41
|
|
|
@@ -50,7 +50,7 @@ The Verifier Web SDK is a powerful tool for integrating online credential verifi
|
|
|
50
50
|
|
|
51
51
|
## How to get access to the MATTR Pi Verifier Web SDK
|
|
52
52
|
|
|
53
|
-
Refer to our [SDK Docs landing page](https://learn.mattr.global/sdk-docs) for step-by-step instructions to gain access
|
|
53
|
+
Refer to our [SDK Docs landing page](https://learn.mattr.global/references#mattr-pi-sdk-docs) for step-by-step instructions to gain access
|
|
54
54
|
to any of our SDKs.
|
|
55
55
|
|
|
56
56
|
> Please [reach out](mailto:dev-support@mattr.global) if you need any assistance.
|
|
@@ -84,9 +84,9 @@ MATTRVerifierSDK.initialise(...);
|
|
|
84
84
|
2. Access SDK functions via global `MATTRVerifierSDK` object.
|
|
85
85
|
|
|
86
86
|
```javascript
|
|
87
|
-
<script>
|
|
87
|
+
<script>
|
|
88
88
|
MATTRVerifierSDK.initialise(...);
|
|
89
|
-
</script>
|
|
89
|
+
</script>
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
# Usage
|
|
@@ -101,46 +101,56 @@ The SDK can make a request to create a presentation session with a configured MA
|
|
|
101
101
|
|
|
102
102
|
## Support for Digital Credential API (Tech Preview)
|
|
103
103
|
|
|
104
|
-
This
|
|
104
|
+
This SDK supports the experimental Web Platform Digital Credential API and will automatically attempt to use the Digital Credential API (ahead of executing the request based on OpenID4VP as per ISO 18013-7) when the following conditions are met:
|
|
105
|
+
- The SDK detects the Digital Credential API is available in the current web browser.
|
|
106
|
+
- The feature has been enabled when the SDK was [initialised]((#initialise-the-sdk).
|
|
105
107
|
|
|
106
108
|
## Initialise the SDK
|
|
107
109
|
|
|
108
|
-
You must initialise the SDK before you can use any of its functions and methods
|
|
110
|
+
You must initialise the SDK before you can use any of its functions and methods:
|
|
109
111
|
|
|
110
112
|
```javascript
|
|
111
113
|
MATTRVerifierSDK.initialise({
|
|
112
|
-
apiBaseUrl: "{tenant_url}",
|
|
113
|
-
|
|
114
|
-
|
|
114
|
+
apiBaseUrl: "{tenant_url}",
|
|
115
|
+
applicationId: "{applicationId}",
|
|
116
|
+
/**
|
|
117
|
+
* Configurations when Digital Credential Api is available
|
|
115
118
|
**/
|
|
116
119
|
enableDigitalCredentialsApiSameDeviceFlow: true, // indicate if SDK will request credential via Digital Credential Api in a same device flow
|
|
117
120
|
enableDigitalCredentialsApiCrossDeviceFlow: false, // indicate if SDK request credential via Digital Credential Api in a cross device flow
|
|
118
121
|
});
|
|
119
122
|
```
|
|
120
123
|
|
|
124
|
+
- `apiBaseUrl` (required): URL of the MATTR VII verifier tenant.
|
|
125
|
+
- `applicationId` (optional): Unique identifier of the verifier application. This must match the [`name`](https://learn.mattr.global/api-reference/latest/tag/mDocs-verification#operation/postVerifierApplication!path=name&t=request) parameter defined as part of a Verifier application created on the MATTR VII verifier tenant.
|
|
126
|
+
|
|
121
127
|
## Prepare a credential query
|
|
122
128
|
|
|
123
|
-
The following example credential query will request the `birthdate` and `portrait` claims from a `mobile` credential `profile` with `org.iso.18013.5.1.mDL` as a `docType`:
|
|
129
|
+
The following example credential query will request the `birthdate` and `portrait` claims from a `mobile` credential `profile` with `org.iso.18013.5.1.mDL` as a `docType`:
|
|
124
130
|
|
|
125
131
|
```javascript
|
|
126
|
-
const credentialQuery =
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
"
|
|
131
|
-
"
|
|
132
|
-
"
|
|
132
|
+
const credentialQuery = [
|
|
133
|
+
{
|
|
134
|
+
"profile": "mobile",
|
|
135
|
+
"docType": "org.iso.18013.5.1.mDL",
|
|
136
|
+
"nameSpaces": {
|
|
137
|
+
"org.iso.18013.5.1": {
|
|
138
|
+
"birthdate": {
|
|
139
|
+
"intentToRetain": false
|
|
140
|
+
},
|
|
141
|
+
"portrait": {
|
|
142
|
+
"intentToRetain": false
|
|
143
|
+
},
|
|
144
|
+
"resident_postal_code": {
|
|
145
|
+
"intentToRetain": false
|
|
146
|
+
}
|
|
133
147
|
},
|
|
134
|
-
|
|
135
|
-
"resident_postal_code": {
|
|
136
|
-
"intentToRetain": false
|
|
137
|
-
}
|
|
138
|
-
},
|
|
148
|
+
}
|
|
139
149
|
}
|
|
140
|
-
|
|
150
|
+
];
|
|
141
151
|
```
|
|
142
152
|
|
|
143
|
-
> The API supports multiple
|
|
153
|
+
> The API supports including multiple query objects in the `credentialQuery` array in a single request. For simplicity, this example only includes a single query object.
|
|
144
154
|
|
|
145
155
|
## Generate challenge
|
|
146
156
|
|
|
@@ -154,7 +164,7 @@ When the challenge is generated by your backend, you should use it to validate t
|
|
|
154
164
|
|
|
155
165
|
The **same-device flow** involves the user completing all steps on a single device, such as their smartphone. They initiate the credential request on the verifier's web app, are redirected to their wallet app to consent and present credentials, and then return to the verifier's web app with the results.
|
|
156
166
|
|
|
157
|
-
In contrast, the **cross-device flow** starts on one device, like a laptop. When the user initiates the request, the web app responds by displaying a QR code. The user then scans this QR code with their smartphone, use their wallet app to present matching credentials, and the results are sent back to the verifier's web app.
|
|
167
|
+
In contrast, the **cross-device flow** starts on one device, like a laptop. When the user initiates the request, the web app responds by displaying a QR code. The user then scans this QR code with their smartphone, use their wallet app to present matching credentials, and the results are sent back to the verifier's web app.
|
|
158
168
|
|
|
159
169
|
The main difference is that the same-device flow uses only one device for the entire process, while the cross-device flow uses two devices for added flexibility.
|
|
160
170
|
|
|
@@ -182,8 +192,8 @@ When using the same-device presentation flow with OpenID4VP (ISO 18013-7) e.g in
|
|
|
182
192
|
## Request credentials with automatic flow selection
|
|
183
193
|
|
|
184
194
|
```javascript
|
|
185
|
-
MATTRVerifierSDK.initialise({ apiBaseUrl }); // Initialise the SDK
|
|
186
|
-
const
|
|
195
|
+
MATTRVerifierSDK.initialise({ apiBaseUrl, applicationId }); // Initialise the SDK
|
|
196
|
+
const result = await MATTRVerifierSDK.requestCredentials({
|
|
187
197
|
credentialQuery: [credentialQuery], // Define what credential query to use
|
|
188
198
|
challenge: MATTRVerifierSDK.utils.generateChallenge(), // Pass a unique challenge
|
|
189
199
|
walletProviderId, // Define the wallet identifier
|
|
@@ -199,7 +209,7 @@ const requestCredentialsResult = await MATTRVerifierSDK.requestCredentials({
|
|
|
199
209
|
});
|
|
200
210
|
|
|
201
211
|
// Check result when it's available in the return value
|
|
202
|
-
if (requestCredentialsResult.isOk() && "result" in requestCredentialsResult.value) {
|
|
212
|
+
if (requestCredentialsResult.isOk() && "result" in requestCredentialsResult.value) {
|
|
203
213
|
console.info("<<< MATTRVerifierSDK.requestCredentials result",result.value.result);
|
|
204
214
|
}
|
|
205
215
|
|
|
@@ -220,7 +230,7 @@ window.addEventListener("load", async () => {
|
|
|
220
230
|
## Request credentials with explicit same-device flow
|
|
221
231
|
|
|
222
232
|
```javascript
|
|
223
|
-
MATTRVerifierSDK.initialise({ apiBaseUrl });
|
|
233
|
+
MATTRVerifierSDK.initialise({ apiBaseUrl, applicationId });
|
|
224
234
|
const requestCredentialsResult = await MATTRVerifierSDK.requestCredentials({
|
|
225
235
|
credentialQuery: [credentialQuery],
|
|
226
236
|
challenge: MATTRVerifierSDK.utils.generateChallenge(),
|
|
@@ -230,13 +240,13 @@ const requestCredentialsResult = await MATTRVerifierSDK.requestCredentials({
|
|
|
230
240
|
});
|
|
231
241
|
|
|
232
242
|
// Check result when it's available in the return value
|
|
233
|
-
if (requestCredentialsResult.isOk() && "result" in requestCredentialsResult.value) {
|
|
243
|
+
if (requestCredentialsResult.isOk() && "result" in requestCredentialsResult.value) {
|
|
234
244
|
console.info("<<< MATTRVerifierSDK.requestCredentials result",result.value.result);
|
|
235
245
|
}
|
|
236
246
|
|
|
237
247
|
// Check result also in your page of redirect_uri
|
|
238
248
|
window.addEventListener("load", async () => {
|
|
239
|
-
MATTRVerifierSDK.initialise({ apiBaseUrl });
|
|
249
|
+
MATTRVerifierSDK.initialise({ apiBaseUrl, applicationId });
|
|
240
250
|
const result = await MATTRVerifierSDK.handleRedirectCallback();
|
|
241
251
|
});
|
|
242
252
|
```
|
|
@@ -248,7 +258,7 @@ window.addEventListener("load", async () => {
|
|
|
248
258
|
## Request credentials with explicit cross-device flow
|
|
249
259
|
|
|
250
260
|
```javascript
|
|
251
|
-
MATTRVerifierSDK.initialise({ apiBaseUrl });
|
|
261
|
+
MATTRVerifierSDK.initialise({ apiBaseUrl, applicationId });
|
|
252
262
|
const requestCredentialsResult = await MATTRVerifierSDK.requestCredentials({
|
|
253
263
|
credentialQuery: [credentialQuery],
|
|
254
264
|
challenge: MATTRVerifierSDK.utils.generateChallenge(),
|
|
@@ -265,7 +275,7 @@ const requestCredentialsResult = await MATTRVerifierSDK.requestCredentials({
|
|
|
265
275
|
});
|
|
266
276
|
|
|
267
277
|
// Check result when it's available in the return value
|
|
268
|
-
if (requestCredentialsResult.isOk() && "result" in requestCredentialsResult.value) {
|
|
278
|
+
if (requestCredentialsResult.isOk() && "result" in requestCredentialsResult.value) {
|
|
269
279
|
console.info("<<< MATTRVerifierSDK.requestCredentials result",result.value.result);
|
|
270
280
|
}
|
|
271
281
|
```
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Copyright
|
|
2
|
+
* Copyright 2025 - MATTR Limited
|
|
3
3
|
* All rights reserved
|
|
4
4
|
* Confidential and proprietary
|
|
5
5
|
*
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
* Do Not Translate or Localize
|
|
8
8
|
*
|
|
9
9
|
* Bundle of @mattrglobal/verifier-sdk-web
|
|
10
|
-
* Generated:
|
|
11
|
-
* Version: 2.0.0-preview-digital-credential-api.
|
|
10
|
+
* Generated: 2025-03-25
|
|
11
|
+
* Version: 2.0.0-preview-digital-credential-api.4
|
|
12
12
|
* Dependencies:
|
|
13
13
|
*/
|
|
14
14
|
|
|
@@ -127,6 +127,9 @@ exports.MobileCredentialVerificationReasonType = void 0;
|
|
|
127
127
|
(function(MobileCredentialVerificationReasonType) {
|
|
128
128
|
MobileCredentialVerificationReasonType["Expired"] = "expired";
|
|
129
129
|
MobileCredentialVerificationReasonType["Inactive"] = "inactive";
|
|
130
|
+
MobileCredentialVerificationReasonType["StatusRevoked"] = "invalid";
|
|
131
|
+
MobileCredentialVerificationReasonType["StatusSuspended"] = "suspended";
|
|
132
|
+
MobileCredentialVerificationReasonType["StatusUnknown"] = "unknown";
|
|
130
133
|
})(exports.MobileCredentialVerificationReasonType || (exports.MobileCredentialVerificationReasonType = {}));
|
|
131
134
|
|
|
132
135
|
exports.ClaimType = void 0;
|
|
@@ -268,6 +271,7 @@ exports.RequestCredentialsErrorType = void 0;
|
|
|
268
271
|
|
|
269
272
|
const InitialiseOptionsValidator = v__namespace.object({
|
|
270
273
|
apiBaseUrl: v__namespace.string(),
|
|
274
|
+
applicationId: v__namespace.optional(v__namespace.string()),
|
|
271
275
|
enableDigitalCredentialsApiSameDeviceFlow: v__namespace.optional(v__namespace.boolean()),
|
|
272
276
|
enableDigitalCredentialsApiCrossDeviceFlow: v__namespace.optional(v__namespace.boolean())
|
|
273
277
|
});
|
|
@@ -319,12 +323,14 @@ const getHashParamValue = (hash, param) => {
|
|
|
319
323
|
return urlParams.get(param);
|
|
320
324
|
};
|
|
321
325
|
|
|
322
|
-
const createSession = async ({credentialQuery: credentialQuery, challenge: challenge, redirectUri: redirectUri, apiBaseUrl: apiBaseUrl, walletProviderId: walletProviderId}) => {
|
|
323
|
-
const postData = Object.assign(Object.assign({
|
|
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({
|
|
324
328
|
credentialQuery: credentialQuery,
|
|
325
329
|
challenge: challenge
|
|
326
330
|
}, redirectUri ? {
|
|
327
331
|
redirectUri: redirectUri
|
|
332
|
+
} : {}), applicationId ? {
|
|
333
|
+
applicationId: applicationId
|
|
328
334
|
} : {}), walletProviderId ? {
|
|
329
335
|
walletProviderId: walletProviderId
|
|
330
336
|
} : {});
|
|
@@ -394,12 +400,14 @@ const isDigitalCredentialsApiSupported = () => {
|
|
|
394
400
|
}
|
|
395
401
|
};
|
|
396
402
|
|
|
397
|
-
const createDigitalCredentialsApiSession = async ({credentialQuery: credentialQuery, challenge: challenge, apiBaseUrl: apiBaseUrl}) => {
|
|
398
|
-
const postData = {
|
|
403
|
+
const createDigitalCredentialsApiSession = async ({credentialQuery: credentialQuery, challenge: challenge, apiBaseUrl: apiBaseUrl, protocol: protocol}) => {
|
|
404
|
+
const postData = Object.assign({
|
|
399
405
|
credentialQuery: credentialQuery,
|
|
400
406
|
challenge: challenge
|
|
401
|
-
}
|
|
402
|
-
|
|
407
|
+
}, protocol && {
|
|
408
|
+
protocol: protocol
|
|
409
|
+
});
|
|
410
|
+
const responseResult = await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/web/request`, {
|
|
403
411
|
method: "POST",
|
|
404
412
|
headers: {
|
|
405
413
|
"Content-Type": "application/json"
|
|
@@ -419,13 +427,14 @@ const createDigitalCredentialsApiSession = async ({credentialQuery: credentialQu
|
|
|
419
427
|
return neverthrow.ok(data);
|
|
420
428
|
};
|
|
421
429
|
|
|
422
|
-
const getDigitalCredentialsApiSessionResult = async ({challenge: challenge, sessionId: sessionId, response: response, apiBaseUrl: apiBaseUrl}) => {
|
|
430
|
+
const getDigitalCredentialsApiSessionResult = async ({challenge: challenge, sessionId: sessionId, response: response, apiBaseUrl: apiBaseUrl, protocol: protocol}) => {
|
|
423
431
|
const postData = {
|
|
424
432
|
challenge: challenge,
|
|
425
433
|
sessionId: sessionId,
|
|
426
|
-
response: response
|
|
434
|
+
response: response,
|
|
435
|
+
protocol: protocol
|
|
427
436
|
};
|
|
428
|
-
const fetchResultFn = async () => await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/
|
|
437
|
+
const fetchResultFn = async () => await safeFetch(`${apiBaseUrl}/v2/presentations/sessions/web/response`, {
|
|
429
438
|
method: "POST",
|
|
430
439
|
headers: {
|
|
431
440
|
"Content-Type": "application/json"
|
|
@@ -546,17 +555,19 @@ const openCrossDeviceModal = options => {
|
|
|
546
555
|
modalContainer.appendChild(style);
|
|
547
556
|
modalContainer.appendChild(iframe);
|
|
548
557
|
document.body.appendChild(modalContainer);
|
|
549
|
-
modalContainer.setAttribute("style", "background: rgba(0, 0, 0, 0.5) !important; position: fixed !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important;");
|
|
558
|
+
modalContainer.setAttribute("style", "background: rgba(0, 0, 0, 0.5) !important; position: fixed !important; top: 0 !important; left: 0 !important; width: 100% !important; height: 100% !important; z-index: 999;");
|
|
559
|
+
modalContainer.setAttribute("class", "mattr-verifier-modal-container");
|
|
550
560
|
return modalContainer;
|
|
551
561
|
};
|
|
552
562
|
|
|
553
563
|
const requestCredentialsCrossDevice = async options => {
|
|
554
564
|
const {challenge: challenge, walletProviderId: walletProviderId, credentialQuery: credentialQuery, crossDeviceCallback: crossDeviceCallback, initialiseOptions: initialiseOptions} = options;
|
|
555
|
-
const {apiBaseUrl: apiBaseUrl} = initialiseOptions;
|
|
565
|
+
const {apiBaseUrl: apiBaseUrl, applicationId: applicationId} = initialiseOptions;
|
|
556
566
|
const createSessionResult = await createSession({
|
|
557
567
|
credentialQuery: credentialQuery,
|
|
558
568
|
challenge: challenge,
|
|
559
569
|
apiBaseUrl: apiBaseUrl,
|
|
570
|
+
applicationId: applicationId,
|
|
560
571
|
walletProviderId: walletProviderId
|
|
561
572
|
});
|
|
562
573
|
if (createSessionResult.isErr()) {
|
|
@@ -593,7 +604,7 @@ var SameDeviceRequestCredentialsErrorMessage$1;
|
|
|
593
604
|
|
|
594
605
|
const requestCredentialsSameDevice = async options => {
|
|
595
606
|
const {challenge: challenge, credentialQuery: credentialQuery, redirectUri: redirectUri, walletProviderId: walletProviderId, initialiseOptions: initialiseOptions} = options;
|
|
596
|
-
const {apiBaseUrl: apiBaseUrl} = initialiseOptions;
|
|
607
|
+
const {apiBaseUrl: apiBaseUrl, applicationId: applicationId} = initialiseOptions;
|
|
597
608
|
window.localStorage.setItem(LocalStorageKey.challenge, challenge);
|
|
598
609
|
const storedChallenge = window.localStorage.getItem(LocalStorageKey.challenge);
|
|
599
610
|
if (!storedChallenge) {
|
|
@@ -607,6 +618,7 @@ const requestCredentialsSameDevice = async options => {
|
|
|
607
618
|
challenge: storedChallenge,
|
|
608
619
|
redirectUri: redirectUri,
|
|
609
620
|
apiBaseUrl: apiBaseUrl,
|
|
621
|
+
applicationId: applicationId,
|
|
610
622
|
walletProviderId: walletProviderId
|
|
611
623
|
});
|
|
612
624
|
if (createSessionResult.isErr()) {
|
|
@@ -633,7 +645,7 @@ var SameDeviceRequestCredentialsErrorMessage;
|
|
|
633
645
|
|
|
634
646
|
const requestCredentialsDigitalCredentialsApi = async options => {
|
|
635
647
|
const {challenge: challenge, credentialQuery: credentialQuery, initialiseOptions: initialiseOptions} = options;
|
|
636
|
-
const {apiBaseUrl: apiBaseUrl} = initialiseOptions;
|
|
648
|
+
const {apiBaseUrl: apiBaseUrl, digitalCredentialsApiProtocol: digitalCredentialsApiProtocol} = initialiseOptions;
|
|
637
649
|
window.localStorage.setItem(LocalStorageKey.challenge, challenge);
|
|
638
650
|
const storedChallenge = window.localStorage.getItem(LocalStorageKey.challenge);
|
|
639
651
|
if (!storedChallenge) {
|
|
@@ -645,7 +657,8 @@ const requestCredentialsDigitalCredentialsApi = async options => {
|
|
|
645
657
|
const createSessionResult = await createDigitalCredentialsApiSession({
|
|
646
658
|
credentialQuery: credentialQuery,
|
|
647
659
|
challenge: storedChallenge,
|
|
648
|
-
apiBaseUrl: apiBaseUrl
|
|
660
|
+
apiBaseUrl: apiBaseUrl,
|
|
661
|
+
protocol: digitalCredentialsApiProtocol
|
|
649
662
|
});
|
|
650
663
|
if (createSessionResult.isErr()) {
|
|
651
664
|
return neverthrow.err({
|
|
@@ -675,7 +688,8 @@ const requestCredentialsDigitalCredentialsApi = async options => {
|
|
|
675
688
|
challenge: challenge,
|
|
676
689
|
sessionId: sessionId,
|
|
677
690
|
response: response,
|
|
678
|
-
apiBaseUrl: apiBaseUrl
|
|
691
|
+
apiBaseUrl: apiBaseUrl,
|
|
692
|
+
protocol: digitalCredentialsApiProtocol !== null && digitalCredentialsApiProtocol !== void 0 ? digitalCredentialsApiProtocol : "preview"
|
|
679
693
|
});
|
|
680
694
|
if (result.isOk()) {
|
|
681
695
|
return neverthrow.ok({
|