@metamask-previews/kyc-controller 0.0.0-preview-e57e5c3dc → 0.0.0-preview-c34a16a37
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/CHANGELOG.md +14 -2
- package/README.md +1 -1
- package/dist/KycController-method-action-types.cjs.map +1 -1
- package/dist/KycController-method-action-types.d.cts +46 -1
- package/dist/KycController-method-action-types.d.cts.map +1 -1
- package/dist/KycController-method-action-types.d.mts +46 -1
- package/dist/KycController-method-action-types.d.mts.map +1 -1
- package/dist/KycController-method-action-types.mjs.map +1 -1
- package/dist/KycController.cjs +366 -10
- package/dist/KycController.cjs.map +1 -1
- package/dist/KycController.d.cts +85 -3
- package/dist/KycController.d.cts.map +1 -1
- package/dist/KycController.d.mts +85 -3
- package/dist/KycController.d.mts.map +1 -1
- package/dist/KycController.mjs +366 -10
- package/dist/KycController.mjs.map +1 -1
- package/dist/KycService-method-action-types.cjs.map +1 -1
- package/dist/KycService-method-action-types.d.cts +56 -1
- package/dist/KycService-method-action-types.d.cts.map +1 -1
- package/dist/KycService-method-action-types.d.mts +56 -1
- package/dist/KycService-method-action-types.d.mts.map +1 -1
- package/dist/KycService-method-action-types.mjs.map +1 -1
- package/dist/KycService.cjs +167 -10
- package/dist/KycService.cjs.map +1 -1
- package/dist/KycService.d.cts +75 -2
- package/dist/KycService.d.cts.map +1 -1
- package/dist/KycService.d.mts +75 -2
- package/dist/KycService.d.mts.map +1 -1
- package/dist/KycService.mjs +168 -11
- package/dist/KycService.mjs.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs.map +1 -1
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +48 -10
- package/dist/types.d.cts.map +1 -1
- package/dist/types.d.mts +48 -10
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs.map +1 -1
- package/dist/ukyc/deriveClientMaterial.cjs +1 -1
- package/dist/ukyc/deriveClientMaterial.cjs.map +1 -1
- package/dist/ukyc/deriveClientMaterial.mjs +1 -1
- package/dist/ukyc/deriveClientMaterial.mjs.map +1 -1
- package/dist/ukyc/storageAccessToken.cjs +1 -1
- package/dist/ukyc/storageAccessToken.cjs.map +1 -1
- package/dist/ukyc/storageAccessToken.d.cts.map +1 -1
- package/dist/ukyc/storageAccessToken.d.mts.map +1 -1
- package/dist/ukyc/storageAccessToken.mjs +1 -1
- package/dist/ukyc/storageAccessToken.mjs.map +1 -1
- package/dist/ukyc/wrappedRelayPayload.cjs.map +1 -1
- package/dist/ukyc/wrappedRelayPayload.d.cts.map +1 -1
- package/dist/ukyc/wrappedRelayPayload.d.mts.map +1 -1
- package/dist/ukyc/wrappedRelayPayload.mjs.map +1 -1
- package/package.json +1 -1
package/dist/KycController.cjs
CHANGED
|
@@ -10,14 +10,14 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
10
10
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
11
11
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
12
12
|
};
|
|
13
|
-
var _KycController_instances, _KycController_sumsubLauncher, _KycController_keypair, _KycController_authClientToken, _KycController_generation, _KycController_sessionStatusPollIntervalMs, _KycController_pollTimer, _KycController_pollToken, _KycController_localUserSecretStore, _KycController_createSession, _KycController_clearAcceptedTerms, _KycController_handleCheckOutcome, _KycController_handleAuthOutcome, _KycController_continueAfterAuthentication, _KycController_requireTermsReacceptance, _KycController_startSessionStatusPolling, _KycController_pollSessionStatusOnce, _KycController_stopPolling, _KycController_updateIfCurrent, _KycController_applyUpdate, _KycController_fail;
|
|
13
|
+
var _KycController_instances, _KycController_sumsubLauncher, _KycController_keypair, _KycController_authClientToken, _KycController_generation, _KycController_sessionStatusPollIntervalMs, _KycController_pollTimer, _KycController_pollToken, _KycController_userStatusPollIntervalMs, _KycController_userStatusPollTimer, _KycController_userStatusPollToken, _KycController_localUserSecretStore, _KycController_startIronSession, _KycController_createSession, _KycController_clearAcceptedTerms, _KycController_handleCheckOutcome, _KycController_handleAuthOutcome, _KycController_continueAfterAuthentication, _KycController_requireTermsReacceptance, _KycController_fetchAndApplyUserStatus, _KycController_applyUserStatus, _KycController_ensureUserStatusPolling, _KycController_stopUserStatusPolling, _KycController_startSessionStatusPolling, _KycController_pollSessionStatusOnce, _KycController_stopPolling, _KycController_updateIfCurrent, _KycController_applyUpdate, _KycController_fail;
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.KycController = exports.getDefaultKycControllerState = exports.controllerName = void 0;
|
|
16
16
|
const base_controller_1 = require("@metamask/base-controller");
|
|
17
17
|
const ed25519_1 = require("@noble/curves/ed25519");
|
|
18
18
|
const crypto_js_1 = require("./crypto.cjs");
|
|
19
|
-
const deriveClientMaterial_js_1 = require("./ukyc/deriveClientMaterial.cjs");
|
|
20
19
|
const encoding_js_1 = require("./encoding.cjs");
|
|
20
|
+
const deriveClientMaterial_js_1 = require("./ukyc/deriveClientMaterial.cjs");
|
|
21
21
|
const jwtChain_js_1 = require("./ukyc/jwtChain.cjs");
|
|
22
22
|
const localUserSecret_js_1 = require("./ukyc/localUserSecret.cjs");
|
|
23
23
|
const storageAccessToken_js_1 = require("./ukyc/storageAccessToken.cjs");
|
|
@@ -87,6 +87,12 @@ const SUCCESSFUL_SESSION_STATUSES = new Set([
|
|
|
87
87
|
// to do, so the sub-flow stops before launching the SDK and surfaces this
|
|
88
88
|
// message.
|
|
89
89
|
const VENDOR_PROCESSING_MESSAGE = 'Your KYC has been submitted and is being processed by the vendor.';
|
|
90
|
+
// UKYC / relay error indicating the applicant already finished KYC. Mapped to
|
|
91
|
+
// the simplified `completed` user status for the Money toast surface.
|
|
92
|
+
const SESSION_NOT_IN_VALID_STATE = 'session_not_in_valid_state';
|
|
93
|
+
// How often to refresh the user-keyed `GET /kyc/status` while the simplified
|
|
94
|
+
// status is still `pending`. Overridable via the constructor.
|
|
95
|
+
const DEFAULT_USER_STATUS_POLL_INTERVAL_MS = 15000;
|
|
90
96
|
const kycControllerMetadata = {
|
|
91
97
|
phase: {
|
|
92
98
|
includeInDebugSnapshot: true,
|
|
@@ -160,6 +166,12 @@ const kycControllerMetadata = {
|
|
|
160
166
|
persist: false,
|
|
161
167
|
usedInUi: false,
|
|
162
168
|
},
|
|
169
|
+
activeVendor: {
|
|
170
|
+
includeInDebugSnapshot: true,
|
|
171
|
+
includeInStateLogs: true,
|
|
172
|
+
persist: false,
|
|
173
|
+
usedInUi: true,
|
|
174
|
+
},
|
|
163
175
|
activeProduct: {
|
|
164
176
|
includeInDebugSnapshot: true,
|
|
165
177
|
includeInStateLogs: true,
|
|
@@ -178,6 +190,24 @@ const kycControllerMetadata = {
|
|
|
178
190
|
persist: true,
|
|
179
191
|
usedInUi: false,
|
|
180
192
|
},
|
|
193
|
+
userStatus: {
|
|
194
|
+
includeInDebugSnapshot: true,
|
|
195
|
+
includeInStateLogs: true,
|
|
196
|
+
persist: true,
|
|
197
|
+
usedInUi: true,
|
|
198
|
+
},
|
|
199
|
+
userStatusSumsubSessionId: {
|
|
200
|
+
includeInDebugSnapshot: false,
|
|
201
|
+
includeInStateLogs: false,
|
|
202
|
+
persist: true,
|
|
203
|
+
usedInUi: true,
|
|
204
|
+
},
|
|
205
|
+
userStatusErrorCode: {
|
|
206
|
+
includeInDebugSnapshot: true,
|
|
207
|
+
includeInStateLogs: true,
|
|
208
|
+
persist: true,
|
|
209
|
+
usedInUi: true,
|
|
210
|
+
},
|
|
181
211
|
sumsub: {
|
|
182
212
|
includeInDebugSnapshot: false,
|
|
183
213
|
includeInStateLogs: false,
|
|
@@ -204,9 +234,13 @@ function getDefaultKycControllerState() {
|
|
|
204
234
|
sessionToken: null,
|
|
205
235
|
accessToken: null,
|
|
206
236
|
moonpayCustomerId: null,
|
|
237
|
+
activeVendor: 'moonpay',
|
|
207
238
|
activeProduct: null,
|
|
208
239
|
kycRequiredByProduct: {},
|
|
209
240
|
lastCheckedAt: null,
|
|
241
|
+
userStatus: null,
|
|
242
|
+
userStatusSumsubSessionId: null,
|
|
243
|
+
userStatusErrorCode: null,
|
|
210
244
|
sumsub: {
|
|
211
245
|
status: 'idle',
|
|
212
246
|
result: null,
|
|
@@ -222,6 +256,7 @@ const MESSENGER_EXPOSED_METHODS = [
|
|
|
222
256
|
'initialize',
|
|
223
257
|
'loadDisclaimers',
|
|
224
258
|
'acceptTermsAndStartSession',
|
|
259
|
+
'createIronCustomer',
|
|
225
260
|
'clearSavedTerms',
|
|
226
261
|
'handleFrameMessage',
|
|
227
262
|
'buildCheckFrameUrl',
|
|
@@ -229,6 +264,8 @@ const MESSENGER_EXPOSED_METHODS = [
|
|
|
229
264
|
'buildResetFrameUrl',
|
|
230
265
|
'checkKycRequired',
|
|
231
266
|
'getKycStatus',
|
|
267
|
+
'getCustomerIdentity',
|
|
268
|
+
'refreshKycStatus',
|
|
232
269
|
'startSumSub',
|
|
233
270
|
'getSessionStatus',
|
|
234
271
|
'reset',
|
|
@@ -251,8 +288,10 @@ class KycController extends base_controller_1.BaseController {
|
|
|
251
288
|
* @param options.sumsubLauncher - The platform SumSub launcher adapter.
|
|
252
289
|
* @param options.sessionStatusPollIntervalMs - How often to poll the UKYC
|
|
253
290
|
* session status after the SumSub SDK completes.
|
|
291
|
+
* @param options.userStatusPollIntervalMs - How often to refresh the
|
|
292
|
+
* user-keyed KYC status while it is still `pending`.
|
|
254
293
|
*/
|
|
255
|
-
constructor({ messenger, state, sumsubLauncher, sessionStatusPollIntervalMs = DEFAULT_SESSION_STATUS_POLL_INTERVAL_MS, }) {
|
|
294
|
+
constructor({ messenger, state, sumsubLauncher, sessionStatusPollIntervalMs = DEFAULT_SESSION_STATUS_POLL_INTERVAL_MS, userStatusPollIntervalMs = DEFAULT_USER_STATUS_POLL_INTERVAL_MS, }) {
|
|
256
295
|
super({
|
|
257
296
|
messenger,
|
|
258
297
|
metadata: kycControllerMetadata,
|
|
@@ -283,8 +322,15 @@ class KycController extends base_controller_1.BaseController {
|
|
|
283
322
|
* let an already-awaiting request finish and reschedule.
|
|
284
323
|
*/
|
|
285
324
|
_KycController_pollToken.set(this, 0);
|
|
325
|
+
/** Interval, in milliseconds, between user-keyed status polls. */
|
|
326
|
+
_KycController_userStatusPollIntervalMs.set(this, void 0);
|
|
327
|
+
/** Handle for the scheduled next user-status poll, or `null`. */
|
|
328
|
+
_KycController_userStatusPollTimer.set(this, null);
|
|
329
|
+
/** Monotonic token for the user-status poll loop (see `#pollToken`). */
|
|
330
|
+
_KycController_userStatusPollToken.set(this, 0);
|
|
286
331
|
__classPrivateFieldSet(this, _KycController_sumsubLauncher, sumsubLauncher, "f");
|
|
287
332
|
__classPrivateFieldSet(this, _KycController_sessionStatusPollIntervalMs, sessionStatusPollIntervalMs, "f");
|
|
333
|
+
__classPrivateFieldSet(this, _KycController_userStatusPollIntervalMs, userStatusPollIntervalMs, "f");
|
|
288
334
|
__classPrivateFieldSet(this, _KycController_keypair, (0, crypto_js_1.generateKeyPair)(), "f");
|
|
289
335
|
this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
|
|
290
336
|
}
|
|
@@ -299,6 +345,8 @@ class KycController extends base_controller_1.BaseController {
|
|
|
299
345
|
* authentication completes (and chains into document verification when KYC
|
|
300
346
|
* is required). When omitted, the flow stops at `form` and the consumer must
|
|
301
347
|
* call `checkKycRequired` manually.
|
|
348
|
+
* @param params.vendor - Identity vendor for this flow. Pass `iron` for the
|
|
349
|
+
* Money/VBA path (no MoonPay Check/Auth frames). Defaults to `moonpay`.
|
|
302
350
|
*/
|
|
303
351
|
async initialize(params) {
|
|
304
352
|
// A repeat `initialize` while a session flow is already in progress must
|
|
@@ -309,6 +357,7 @@ class KycController extends base_controller_1.BaseController {
|
|
|
309
357
|
if (IN_PROGRESS_PHASES.includes(this.state.phase)) {
|
|
310
358
|
return;
|
|
311
359
|
}
|
|
360
|
+
const vendor = params?.vendor ?? 'moonpay';
|
|
312
361
|
// `initialize` starts a fresh flow, so `activeProduct` is always reset to
|
|
313
362
|
// this call's product (or `null`). Otherwise a prior run's product could
|
|
314
363
|
// linger and cause `#continueAfterAuthentication` to auto-run the check /
|
|
@@ -317,6 +366,13 @@ class KycController extends base_controller_1.BaseController {
|
|
|
317
366
|
if (params?.email) {
|
|
318
367
|
state.email = params.email;
|
|
319
368
|
}
|
|
369
|
+
state.activeVendor = vendor;
|
|
370
|
+
// `moonpayCustomerId` is only ever issued by the MoonPay Check / Auth
|
|
371
|
+
// frames. Leaving it set while the flow switches to another vendor would
|
|
372
|
+
// make `getCustomerIdentity` report a MoonPay id under the wrong vendor.
|
|
373
|
+
if (vendor !== 'moonpay') {
|
|
374
|
+
state.moonpayCustomerId = null;
|
|
375
|
+
}
|
|
320
376
|
state.activeProduct = params?.product ?? null;
|
|
321
377
|
});
|
|
322
378
|
// Capture the flow generation so a `reset()` landing while the async
|
|
@@ -333,10 +389,36 @@ class KycController extends base_controller_1.BaseController {
|
|
|
333
389
|
catch {
|
|
334
390
|
// Ignore; disclaimers loading will surface a country error if needed.
|
|
335
391
|
}
|
|
392
|
+
// Iron: create the empty-shell customer before T&C (offsite decision).
|
|
393
|
+
if (vendor === 'iron' && this.state.email) {
|
|
394
|
+
try {
|
|
395
|
+
await this.messenger.call('KycService:createIronCustomer', {
|
|
396
|
+
email: this.state.email,
|
|
397
|
+
});
|
|
398
|
+
if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
catch (error) {
|
|
403
|
+
if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, `Iron customer creation failed: ${String(error)}`);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
336
410
|
const hasTerms = Boolean(this.state.termsAcceptedAt) &&
|
|
337
411
|
this.state.acceptedDisclaimerIds.length > 0;
|
|
338
412
|
if (hasTerms && this.state.email) {
|
|
339
|
-
|
|
413
|
+
if (vendor === 'iron') {
|
|
414
|
+
await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_startIronSession).call(this, {
|
|
415
|
+
sumsubTncSigned: true,
|
|
416
|
+
idosTncSigned: true,
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_createSession).call(this);
|
|
421
|
+
}
|
|
340
422
|
return;
|
|
341
423
|
}
|
|
342
424
|
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
|
|
@@ -344,6 +426,35 @@ class KycController extends base_controller_1.BaseController {
|
|
|
344
426
|
});
|
|
345
427
|
await this.loadDisclaimers();
|
|
346
428
|
}
|
|
429
|
+
/**
|
|
430
|
+
* Creates (or resumes) an Iron empty-shell customer. Exposed so Money can
|
|
431
|
+
* ensure the customer exists before showing T&C screens independently of
|
|
432
|
+
* {@link initialize}.
|
|
433
|
+
*
|
|
434
|
+
* @param params - The parameters.
|
|
435
|
+
* @param params.email - Email for the Iron customer.
|
|
436
|
+
*/
|
|
437
|
+
async createIronCustomer(params) {
|
|
438
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
|
|
439
|
+
state.email = params.email;
|
|
440
|
+
state.activeVendor = 'iron';
|
|
441
|
+
// See `initialize`: a MoonPay-issued customer id must not survive a
|
|
442
|
+
// switch to Iron, or `getCustomerIdentity` reports the wrong vendor.
|
|
443
|
+
state.moonpayCustomerId = null;
|
|
444
|
+
});
|
|
445
|
+
const generation = __classPrivateFieldGet(this, _KycController_generation, "f");
|
|
446
|
+
try {
|
|
447
|
+
await this.messenger.call('KycService:createIronCustomer', {
|
|
448
|
+
email: params.email,
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
catch (error) {
|
|
452
|
+
if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, `Iron customer creation failed: ${String(error)}`);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
347
458
|
/**
|
|
348
459
|
* Loads the disclaimers for the resolved (or provided) country.
|
|
349
460
|
*
|
|
@@ -364,7 +475,13 @@ class KycController extends base_controller_1.BaseController {
|
|
|
364
475
|
state.geoCountry = country;
|
|
365
476
|
});
|
|
366
477
|
}
|
|
367
|
-
const disclaimers =
|
|
478
|
+
const disclaimers = this.state.activeVendor === 'iron'
|
|
479
|
+
? await this.messenger.call('KycService:fetchIronDisclaimers', {
|
|
480
|
+
country,
|
|
481
|
+
})
|
|
482
|
+
: await this.messenger.call('KycService:fetchDisclaimers', {
|
|
483
|
+
country,
|
|
484
|
+
});
|
|
368
485
|
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
|
|
369
486
|
state.disclaimers = disclaimers;
|
|
370
487
|
state.disclaimersError = null;
|
|
@@ -385,6 +502,10 @@ class KycController extends base_controller_1.BaseController {
|
|
|
385
502
|
* @param params.product - The consuming feature the flow runs for. See
|
|
386
503
|
* {@link initialize} for how the product drives the automatic post
|
|
387
504
|
* authentication continuation.
|
|
505
|
+
* @param params.sumsubTncSigned - Iron path: whether Sumsub T&C were
|
|
506
|
+
* accepted (T&C2). Defaults to `true` when omitted.
|
|
507
|
+
* @param params.idosTncSigned - Iron path: whether idOS T&C were accepted
|
|
508
|
+
* (T&C2). Defaults to `true` when omitted.
|
|
388
509
|
*/
|
|
389
510
|
async acceptTermsAndStartSession(params) {
|
|
390
511
|
const termsAcceptedAt = new Date().toISOString();
|
|
@@ -399,6 +520,13 @@ class KycController extends base_controller_1.BaseController {
|
|
|
399
520
|
state.termsAcceptedAt = termsAcceptedAt;
|
|
400
521
|
state.acceptedDisclaimerIds = disclaimerIds;
|
|
401
522
|
});
|
|
523
|
+
if (this.state.activeVendor === 'iron') {
|
|
524
|
+
await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_startIronSession).call(this, {
|
|
525
|
+
sumsubTncSigned: params?.sumsubTncSigned ?? true,
|
|
526
|
+
idosTncSigned: params?.idosTncSigned ?? true,
|
|
527
|
+
});
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
402
530
|
await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_createSession).call(this);
|
|
403
531
|
}
|
|
404
532
|
/**
|
|
@@ -580,6 +708,25 @@ class KycController extends base_controller_1.BaseController {
|
|
|
580
708
|
getKycStatus(params) {
|
|
581
709
|
return this.state.kycRequiredByProduct[params.product];
|
|
582
710
|
}
|
|
711
|
+
/**
|
|
712
|
+
* Returns the vendor-scoped identity for the currently authenticated
|
|
713
|
+
* customer, or `null` when the flow has not yet captured a vendor customer
|
|
714
|
+
* id (before authentication or after {@link reset}).
|
|
715
|
+
*
|
|
716
|
+
* Exposed so consumers (e.g. ramps autoramp creation) can attach the vendor
|
|
717
|
+
* customer id to downstream calls without reading the full KYC state, which
|
|
718
|
+
* also holds session/access tokens. The id is session-scoped and never
|
|
719
|
+
* persisted.
|
|
720
|
+
*
|
|
721
|
+
* @returns The current {@link KycCustomerIdentity}, or `null`.
|
|
722
|
+
*/
|
|
723
|
+
getCustomerIdentity() {
|
|
724
|
+
const { moonpayCustomerId, activeVendor } = this.state;
|
|
725
|
+
if (!moonpayCustomerId) {
|
|
726
|
+
return null;
|
|
727
|
+
}
|
|
728
|
+
return { vendor: activeVendor, id: moonpayCustomerId };
|
|
729
|
+
}
|
|
583
730
|
/**
|
|
584
731
|
* Runs the SumSub document-verification sub-flow end to end:
|
|
585
732
|
*
|
|
@@ -658,12 +805,18 @@ class KycController extends base_controller_1.BaseController {
|
|
|
658
805
|
operations: ['read'],
|
|
659
806
|
expiresAt: new Date(Date.now() + UKYC_CAPABILITY_TOKEN_TTL_MS),
|
|
660
807
|
});
|
|
808
|
+
const isIron = this.state.activeVendor === 'iron';
|
|
661
809
|
const { sessionId, kycStatus, finalStatus } = await this.messenger.call('KycService:createUkycSession', {
|
|
662
810
|
jwtToken,
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
811
|
+
vendorId: isIron ? 'iron' : 'moonpay',
|
|
812
|
+
...(isIron
|
|
813
|
+
? {}
|
|
814
|
+
: {
|
|
815
|
+
vendorMetadata: {
|
|
816
|
+
moonPayAccessToken: this.state.accessToken,
|
|
817
|
+
moonPayUserId: this.state.moonpayCustomerId,
|
|
818
|
+
},
|
|
819
|
+
}),
|
|
667
820
|
wrappedEncryptionKey,
|
|
668
821
|
ukycCapabilityToken,
|
|
669
822
|
});
|
|
@@ -753,6 +906,28 @@ class KycController extends base_controller_1.BaseController {
|
|
|
753
906
|
return result;
|
|
754
907
|
}
|
|
755
908
|
catch (error) {
|
|
909
|
+
// Applicant already finished KYC — treat as completed for Money toast.
|
|
910
|
+
if (String(error).includes(SESSION_NOT_IN_VALID_STATE)) {
|
|
911
|
+
// A reset() may have landed while `launch` was in flight; forcing
|
|
912
|
+
// `completed` (and publishing `statusChanged`) on an idle controller
|
|
913
|
+
// would resurrect a flow the consumer already tore down.
|
|
914
|
+
if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
|
|
915
|
+
return { alreadyCompleted: true };
|
|
916
|
+
}
|
|
917
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUserStatus).call(this, {
|
|
918
|
+
status: 'completed',
|
|
919
|
+
sumsubSessionId: null,
|
|
920
|
+
errorCode: null,
|
|
921
|
+
});
|
|
922
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
|
|
923
|
+
state.sumsub.status = 'complete';
|
|
924
|
+
state.sumsub.result = { alreadyCompleted: true };
|
|
925
|
+
state.statusMessage = 'KYC already completed.';
|
|
926
|
+
state.phase = 'done';
|
|
927
|
+
state.error = null;
|
|
928
|
+
});
|
|
929
|
+
return { alreadyCompleted: true };
|
|
930
|
+
}
|
|
756
931
|
const result = { error: String(error) };
|
|
757
932
|
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
|
|
758
933
|
state.sumsub.status = 'failed';
|
|
@@ -761,6 +936,23 @@ class KycController extends base_controller_1.BaseController {
|
|
|
761
936
|
return result;
|
|
762
937
|
}
|
|
763
938
|
}
|
|
939
|
+
/**
|
|
940
|
+
* Refreshes the user-keyed simplified KYC status from `GET /kyc/status`,
|
|
941
|
+
* stores it on state, publishes {@link KycControllerStatusChangedEvent}, and
|
|
942
|
+
* schedules short-interval polling while the status is `pending`.
|
|
943
|
+
*
|
|
944
|
+
* @returns The latest status payload.
|
|
945
|
+
*/
|
|
946
|
+
async refreshKycStatus() {
|
|
947
|
+
const payload = await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fetchAndApplyUserStatus).call(this);
|
|
948
|
+
if (payload.status === 'pending') {
|
|
949
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_ensureUserStatusPolling).call(this);
|
|
950
|
+
}
|
|
951
|
+
else {
|
|
952
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_stopUserStatusPolling).call(this);
|
|
953
|
+
}
|
|
954
|
+
return payload;
|
|
955
|
+
}
|
|
764
956
|
/**
|
|
765
957
|
* Fetches the current UKYC session status for the active sub-flow and records
|
|
766
958
|
* it on state. Useful for a one-off refresh outside the automatic polling
|
|
@@ -792,6 +984,7 @@ class KycController extends base_controller_1.BaseController {
|
|
|
792
984
|
// Stop any session-status polling so a late poll cannot write onto the
|
|
793
985
|
// now-idle controller.
|
|
794
986
|
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_stopPolling).call(this);
|
|
987
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_stopUserStatusPolling).call(this);
|
|
795
988
|
// Invalidate any in-flight async work started before this reset so its
|
|
796
989
|
// results are discarded rather than written onto the now-idle controller.
|
|
797
990
|
__classPrivateFieldSet(this, _KycController_generation, __classPrivateFieldGet(this, _KycController_generation, "f") + 1, "f");
|
|
@@ -804,6 +997,7 @@ class KycController extends base_controller_1.BaseController {
|
|
|
804
997
|
state.sessionToken = null;
|
|
805
998
|
state.accessToken = null;
|
|
806
999
|
state.moonpayCustomerId = null;
|
|
1000
|
+
state.activeVendor = 'moonpay';
|
|
807
1001
|
state.activeProduct = null;
|
|
808
1002
|
state.sumsub = {
|
|
809
1003
|
status: 'idle',
|
|
@@ -816,11 +1010,91 @@ class KycController extends base_controller_1.BaseController {
|
|
|
816
1010
|
}
|
|
817
1011
|
}
|
|
818
1012
|
exports.KycController = KycController;
|
|
819
|
-
_KycController_sumsubLauncher = new WeakMap(), _KycController_keypair = new WeakMap(), _KycController_authClientToken = new WeakMap(), _KycController_generation = new WeakMap(), _KycController_sessionStatusPollIntervalMs = new WeakMap(), _KycController_pollTimer = new WeakMap(), _KycController_pollToken = new WeakMap(), _KycController_instances = new WeakSet(), _KycController_localUserSecretStore = function _KycController_localUserSecretStore() {
|
|
1013
|
+
_KycController_sumsubLauncher = new WeakMap(), _KycController_keypair = new WeakMap(), _KycController_authClientToken = new WeakMap(), _KycController_generation = new WeakMap(), _KycController_sessionStatusPollIntervalMs = new WeakMap(), _KycController_pollTimer = new WeakMap(), _KycController_pollToken = new WeakMap(), _KycController_userStatusPollIntervalMs = new WeakMap(), _KycController_userStatusPollTimer = new WeakMap(), _KycController_userStatusPollToken = new WeakMap(), _KycController_instances = new WeakSet(), _KycController_localUserSecretStore = function _KycController_localUserSecretStore() {
|
|
820
1014
|
return {
|
|
821
1015
|
get: async (path, entropySourceId) => this.messenger.call('UserStorageController:performGetStorage', path, entropySourceId),
|
|
822
1016
|
set: async (path, value, entropySourceId) => this.messenger.call('UserStorageController:performSetStorage', path, value, entropySourceId),
|
|
823
1017
|
};
|
|
1018
|
+
}, _KycController_startIronSession =
|
|
1019
|
+
/**
|
|
1020
|
+
* Iron-only path: post consents (Iron signings + Sumsub/idOS ack), then
|
|
1021
|
+
* launch SumSub — skipping MoonPay Check/Auth frames.
|
|
1022
|
+
*
|
|
1023
|
+
* @param consents - T&C2 boolean flags.
|
|
1024
|
+
* @param consents.sumsubTncSigned - Whether Sumsub T&C were accepted.
|
|
1025
|
+
* @param consents.idosTncSigned - Whether idOS T&C were accepted.
|
|
1026
|
+
*/
|
|
1027
|
+
async function _KycController_startIronSession(consents) {
|
|
1028
|
+
const { email, acceptedDisclaimerIds } = this.state;
|
|
1029
|
+
if (!email) {
|
|
1030
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing email for Iron session.');
|
|
1031
|
+
return;
|
|
1032
|
+
}
|
|
1033
|
+
if (acceptedDisclaimerIds.length === 0) {
|
|
1034
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing Iron disclaimer acceptance.');
|
|
1035
|
+
return;
|
|
1036
|
+
}
|
|
1037
|
+
const generation = __classPrivateFieldGet(this, _KycController_generation, "f");
|
|
1038
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
|
|
1039
|
+
state.error = null;
|
|
1040
|
+
state.phase = 'session';
|
|
1041
|
+
state.statusMessage = 'Submitting consents...';
|
|
1042
|
+
// Iron has no MoonPay session/access tokens.
|
|
1043
|
+
state.sessionToken = null;
|
|
1044
|
+
state.accessToken = null;
|
|
1045
|
+
});
|
|
1046
|
+
try {
|
|
1047
|
+
await this.messenger.call('KycService:submitConsents', {
|
|
1048
|
+
ironDisclaimerIds: acceptedDisclaimerIds,
|
|
1049
|
+
sumsubTncSigned: consents.sumsubTncSigned,
|
|
1050
|
+
idosTncSigned: consents.idosTncSigned,
|
|
1051
|
+
});
|
|
1052
|
+
if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
|
|
1056
|
+
state.phase = 'submit';
|
|
1057
|
+
state.statusMessage = 'Starting document verification...';
|
|
1058
|
+
});
|
|
1059
|
+
const sumsubResult = await this.startSumSub();
|
|
1060
|
+
if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
|
|
1061
|
+
return;
|
|
1062
|
+
}
|
|
1063
|
+
const sumsubError = sumsubResult?.error;
|
|
1064
|
+
if (typeof sumsubError === 'string') {
|
|
1065
|
+
throw new Error(sumsubError);
|
|
1066
|
+
}
|
|
1067
|
+
// After SumSub, refresh user-keyed status for the Money toast and start
|
|
1068
|
+
// polling while still pending. Soft-fail: toast refresh must not rewind
|
|
1069
|
+
// the consent / SumSub outcome.
|
|
1070
|
+
try {
|
|
1071
|
+
await this.refreshKycStatus();
|
|
1072
|
+
}
|
|
1073
|
+
catch (statusError) {
|
|
1074
|
+
console.error('KYC status refresh failed:', statusError);
|
|
1075
|
+
}
|
|
1076
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
|
|
1077
|
+
if (state.phase !== 'error' && state.phase !== 'done') {
|
|
1078
|
+
state.phase = 'done';
|
|
1079
|
+
state.statusMessage = 'KYC submitted.';
|
|
1080
|
+
}
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
catch (error) {
|
|
1084
|
+
console.error('Iron session failed:', error);
|
|
1085
|
+
if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
|
|
1086
|
+
return;
|
|
1087
|
+
}
|
|
1088
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
|
|
1089
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearAcceptedTerms).call(this, state);
|
|
1090
|
+
state.activeProduct = null;
|
|
1091
|
+
state.error = `Iron session failed: ${String(error)}`;
|
|
1092
|
+
state.statusMessage =
|
|
1093
|
+
'Consent / verification failed — accept the terms to try again.';
|
|
1094
|
+
state.phase = 'terms';
|
|
1095
|
+
});
|
|
1096
|
+
await this.loadDisclaimers();
|
|
1097
|
+
}
|
|
824
1098
|
}, _KycController_createSession =
|
|
825
1099
|
/**
|
|
826
1100
|
* Creates a vendor session from the currently stored terms + email.
|
|
@@ -986,6 +1260,88 @@ async function _KycController_continueAfterAuthentication() {
|
|
|
986
1260
|
state.statusMessage =
|
|
987
1261
|
'The vendor updated its Terms of Use — please re-accept.';
|
|
988
1262
|
});
|
|
1263
|
+
}, _KycController_fetchAndApplyUserStatus =
|
|
1264
|
+
/**
|
|
1265
|
+
* Fetches `GET /kyc/status` and applies it to state without managing the
|
|
1266
|
+
* poll loop (used by both {@link refreshKycStatus} and the poll tick).
|
|
1267
|
+
*
|
|
1268
|
+
* @returns The latest status payload.
|
|
1269
|
+
*/
|
|
1270
|
+
async function _KycController_fetchAndApplyUserStatus() {
|
|
1271
|
+
const generation = __classPrivateFieldGet(this, _KycController_generation, "f");
|
|
1272
|
+
const response = await this.messenger.call('KycService:fetchKycStatus');
|
|
1273
|
+
if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
|
|
1274
|
+
return {
|
|
1275
|
+
status: this.state.userStatus ?? 'not-started',
|
|
1276
|
+
sumsubSessionId: this.state.userStatusSumsubSessionId,
|
|
1277
|
+
errorCode: this.state.userStatusErrorCode,
|
|
1278
|
+
};
|
|
1279
|
+
}
|
|
1280
|
+
const payload = {
|
|
1281
|
+
status: response.status,
|
|
1282
|
+
sumsubSessionId: response.sumsubSessionId ?? null,
|
|
1283
|
+
errorCode: response.errorCode ?? null,
|
|
1284
|
+
};
|
|
1285
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUserStatus).call(this, payload);
|
|
1286
|
+
return payload;
|
|
1287
|
+
}, _KycController_applyUserStatus = function _KycController_applyUserStatus(payload) {
|
|
1288
|
+
const previous = this.state.userStatus;
|
|
1289
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
|
|
1290
|
+
state.userStatus = payload.status;
|
|
1291
|
+
state.userStatusSumsubSessionId = payload.sumsubSessionId;
|
|
1292
|
+
state.userStatusErrorCode = payload.errorCode;
|
|
1293
|
+
});
|
|
1294
|
+
if (previous !== payload.status) {
|
|
1295
|
+
this.messenger.publish(`${exports.controllerName}:statusChanged`, payload);
|
|
1296
|
+
}
|
|
1297
|
+
}, _KycController_ensureUserStatusPolling = function _KycController_ensureUserStatusPolling() {
|
|
1298
|
+
if (__classPrivateFieldGet(this, _KycController_userStatusPollTimer, "f") !== null) {
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
const token = __classPrivateFieldGet(this, _KycController_userStatusPollToken, "f");
|
|
1302
|
+
const tick = async () => {
|
|
1303
|
+
try {
|
|
1304
|
+
const payload = await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fetchAndApplyUserStatus).call(this);
|
|
1305
|
+
// Race with `reset()` / `#stopUserStatusPolling` while the request was
|
|
1306
|
+
// in flight — do not reschedule onto an idle controller.
|
|
1307
|
+
/* istanbul ignore next */
|
|
1308
|
+
if (__classPrivateFieldGet(this, _KycController_userStatusPollToken, "f") !== token) {
|
|
1309
|
+
return;
|
|
1310
|
+
}
|
|
1311
|
+
if (payload.status !== 'pending') {
|
|
1312
|
+
__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_stopUserStatusPolling).call(this);
|
|
1313
|
+
return;
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
catch {
|
|
1317
|
+
// Keep polling on transient errors, unless the loop was superseded.
|
|
1318
|
+
/* istanbul ignore next */
|
|
1319
|
+
if (__classPrivateFieldGet(this, _KycController_userStatusPollToken, "f") !== token) {
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
__classPrivateFieldSet(this, _KycController_userStatusPollTimer, setTimeout(() => {
|
|
1324
|
+
__classPrivateFieldSet(this, _KycController_userStatusPollTimer, null, "f");
|
|
1325
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1326
|
+
tick();
|
|
1327
|
+
}, __classPrivateFieldGet(this, _KycController_userStatusPollIntervalMs, "f")), "f");
|
|
1328
|
+
// Allow the process to exit while a pending-status poll is scheduled.
|
|
1329
|
+
// React Native / browser timers are numbers with no `unref`, hence the
|
|
1330
|
+
// optional call.
|
|
1331
|
+
__classPrivateFieldGet(this, _KycController_userStatusPollTimer, "f").unref?.();
|
|
1332
|
+
};
|
|
1333
|
+
__classPrivateFieldSet(this, _KycController_userStatusPollTimer, setTimeout(() => {
|
|
1334
|
+
__classPrivateFieldSet(this, _KycController_userStatusPollTimer, null, "f");
|
|
1335
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1336
|
+
tick();
|
|
1337
|
+
}, __classPrivateFieldGet(this, _KycController_userStatusPollIntervalMs, "f")), "f");
|
|
1338
|
+
__classPrivateFieldGet(this, _KycController_userStatusPollTimer, "f").unref?.();
|
|
1339
|
+
}, _KycController_stopUserStatusPolling = function _KycController_stopUserStatusPolling() {
|
|
1340
|
+
__classPrivateFieldSet(this, _KycController_userStatusPollToken, __classPrivateFieldGet(this, _KycController_userStatusPollToken, "f") + 1, "f");
|
|
1341
|
+
if (__classPrivateFieldGet(this, _KycController_userStatusPollTimer, "f") !== null) {
|
|
1342
|
+
clearTimeout(__classPrivateFieldGet(this, _KycController_userStatusPollTimer, "f"));
|
|
1343
|
+
__classPrivateFieldSet(this, _KycController_userStatusPollTimer, null, "f");
|
|
1344
|
+
}
|
|
989
1345
|
}, _KycController_startSessionStatusPolling =
|
|
990
1346
|
/**
|
|
991
1347
|
* Begins polling the UKYC session status until a terminal decision is
|