@metamask-previews/kyc-controller 0.0.0-preview-ea6a28c61 → 0.0.0-preview-e12b5ece6

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 (50) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/dist/KycController-method-action-types.cjs.map +1 -1
  3. package/dist/KycController-method-action-types.d.cts +6 -4
  4. package/dist/KycController-method-action-types.d.cts.map +1 -1
  5. package/dist/KycController-method-action-types.d.mts +6 -4
  6. package/dist/KycController-method-action-types.d.mts.map +1 -1
  7. package/dist/KycController-method-action-types.mjs.map +1 -1
  8. package/dist/KycController.cjs +180 -145
  9. package/dist/KycController.cjs.map +1 -1
  10. package/dist/KycController.d.cts +40 -34
  11. package/dist/KycController.d.cts.map +1 -1
  12. package/dist/KycController.d.mts +40 -34
  13. package/dist/KycController.d.mts.map +1 -1
  14. package/dist/KycController.mjs +177 -144
  15. package/dist/KycController.mjs.map +1 -1
  16. package/dist/KycService-method-action-types.cjs.map +1 -1
  17. package/dist/KycService-method-action-types.d.cts +4 -4
  18. package/dist/KycService-method-action-types.d.mts +4 -4
  19. package/dist/KycService-method-action-types.mjs.map +1 -1
  20. package/dist/KycService.cjs +21 -13
  21. package/dist/KycService.cjs.map +1 -1
  22. package/dist/KycService.d.cts +4 -4
  23. package/dist/KycService.d.cts.map +1 -1
  24. package/dist/KycService.d.mts +4 -4
  25. package/dist/KycService.d.mts.map +1 -1
  26. package/dist/KycService.mjs +21 -13
  27. package/dist/KycService.mjs.map +1 -1
  28. package/dist/index.cjs +3 -1
  29. package/dist/index.cjs.map +1 -1
  30. package/dist/index.d.cts +2 -2
  31. package/dist/index.d.cts.map +1 -1
  32. package/dist/index.d.mts +2 -2
  33. package/dist/index.d.mts.map +1 -1
  34. package/dist/index.mjs +1 -1
  35. package/dist/index.mjs.map +1 -1
  36. package/dist/types.cjs.map +1 -1
  37. package/dist/types.d.cts +50 -11
  38. package/dist/types.d.cts.map +1 -1
  39. package/dist/types.d.mts +50 -11
  40. package/dist/types.d.mts.map +1 -1
  41. package/dist/types.mjs.map +1 -1
  42. package/dist/vendorDisclaimerAcceptance.cjs +74 -0
  43. package/dist/vendorDisclaimerAcceptance.cjs.map +1 -0
  44. package/dist/vendorDisclaimerAcceptance.d.cts +39 -0
  45. package/dist/vendorDisclaimerAcceptance.d.cts.map +1 -0
  46. package/dist/vendorDisclaimerAcceptance.d.mts +39 -0
  47. package/dist/vendorDisclaimerAcceptance.d.mts.map +1 -0
  48. package/dist/vendorDisclaimerAcceptance.mjs +67 -0
  49. package/dist/vendorDisclaimerAcceptance.mjs.map +1 -0
  50. package/package.json +2 -2
@@ -10,9 +10,9 @@ 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_userStatusPollIntervalMs, _KycController_userStatusPollTimer, _KycController_userStatusPolling, _KycController_userStatusPollToken, _KycController_localUserSecretStore, _KycController_startConsentsSession, _KycController_recordSessionDisclaimers, _KycController_createSession, _KycController_clearAcceptedTerms, _KycController_clearMoonPaySession, _KycController_dropTermsUnlessForVendor, _KycController_hasTermsForVendor, _KycController_handleCheckOutcome, _KycController_handleAuthOutcome, _KycController_continueAfterAuthentication, _KycController_requireTermsReacceptance, _KycController_buildUkycSessionVendorFields, _KycController_createUkycSession, _KycController_fetchAndApplyUserStatus, _KycController_applyUserStatus, _KycController_ensureUserStatusPolling, _KycController_stopUserStatusPolling, _KycController_startSessionStatusPolling, _KycController_pollSessionStatusOnce, _KycController_stopPolling, _KycController_cancelPendingSession, _KycController_updateIfCurrent, _KycController_applyUpdate, _KycController_assertAttestedServerPublicKey, _KycController_fail;
13
+ var _KycController_instances, _KycController_sumsubLauncher, _KycController_moonpayFrameKeypair, _KycController_authClientToken, _KycController_generation, _KycController_sessionStatusPollIntervalMs, _KycController_pollTimer, _KycController_pollToken, _KycController_userStatusPollIntervalMs, _KycController_userStatusPollTimer, _KycController_userStatusPolling, _KycController_userStatusPollToken, _KycController_localUserSecretStore, _KycController_startConsentsSession, _KycController_recordSessionDisclaimers, _KycController_createSession, _KycController_clearAcceptedTerms, _KycController_clearMoonPaySession, _KycController_handleCheckOutcome, _KycController_handleAuthOutcome, _KycController_continueAfterAuthentication, _KycController_requireTermsReacceptance, _KycController_buildUkycSessionVendorFields, _KycController_createUkycSession, _KycController_fetchAndApplyUserStatus, _KycController_applyUserStatus, _KycController_ensureUserStatusPolling, _KycController_stopUserStatusPolling, _KycController_startSessionStatusPolling, _KycController_pollSessionStatusOnce, _KycController_stopPolling, _KycController_cancelPendingSession, _KycController_updateIfCurrent, _KycController_applyUpdate, _KycController_assertAttestedServerPublicKey, _KycController_fail;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.KycController = exports.getDefaultKycControllerState = exports.controllerName = void 0;
15
+ exports.KycController = exports.getDefaultKycControllerState = exports.getDefaultKycProviderDisclaimersAccepted = exports.getDefaultKycVendorDisclaimersAccepted = exports.controllerName = void 0;
16
16
  const base_controller_1 = require("@metamask/base-controller");
17
17
  const utils_1 = require("@metamask/utils");
18
18
  const ed25519_1 = require("@noble/curves/ed25519");
@@ -24,6 +24,7 @@ const jwtChain_js_1 = require("./ukyc/jwtChain.cjs");
24
24
  const localUserSecret_js_1 = require("./ukyc/localUserSecret.cjs");
25
25
  const storageAccessToken_js_1 = require("./ukyc/storageAccessToken.cjs");
26
26
  const wrapEncryptionKey_js_1 = require("./ukyc/wrapEncryptionKey.cjs");
27
+ const vendorDisclaimerAcceptance_js_1 = require("./vendorDisclaimerAcceptance.cjs");
27
28
  // === GENERAL ===
28
29
  exports.controllerName = 'KycController';
29
30
  const FRAMES_BASE_URL = 'https://blocks.moonpay.com/platform/v1';
@@ -120,31 +121,19 @@ const kycControllerMetadata = {
120
121
  persist: false,
121
122
  usedInUi: false,
122
123
  },
123
- termsAcceptedAt: {
124
+ vendorDisclaimersAccepted: {
124
125
  includeInDebugSnapshot: true,
125
126
  includeInStateLogs: true,
126
127
  persist: true,
127
128
  usedInUi: false,
128
129
  },
129
- acceptedDisclaimerIds: {
130
+ providerDisclaimersAccepted: {
130
131
  includeInDebugSnapshot: true,
131
132
  includeInStateLogs: true,
132
133
  persist: true,
133
134
  usedInUi: false,
134
135
  },
135
- termsAcceptedVendor: {
136
- includeInDebugSnapshot: true,
137
- includeInStateLogs: true,
138
- persist: true,
139
- usedInUi: false,
140
- },
141
- sumsubTncAccepted: {
142
- includeInDebugSnapshot: true,
143
- includeInStateLogs: true,
144
- persist: true,
145
- usedInUi: false,
146
- },
147
- idosTncAccepted: {
136
+ idosDisclaimersAccepted: {
148
137
  includeInDebugSnapshot: true,
149
138
  includeInStateLogs: true,
150
139
  persist: true,
@@ -156,13 +145,13 @@ const kycControllerMetadata = {
156
145
  persist: false,
157
146
  usedInUi: false,
158
147
  },
159
- disclaimers: {
148
+ vendorDisclaimers: {
160
149
  includeInDebugSnapshot: false,
161
150
  includeInStateLogs: false,
162
151
  persist: false,
163
152
  usedInUi: true,
164
153
  },
165
- disclaimersError: {
154
+ vendorError: {
166
155
  includeInDebugSnapshot: true,
167
156
  includeInStateLogs: true,
168
157
  persist: false,
@@ -180,13 +169,13 @@ const kycControllerMetadata = {
180
169
  persist: false,
181
170
  usedInUi: true,
182
171
  },
183
- sessionToken: {
172
+ moonpaySessionToken: {
184
173
  includeInDebugSnapshot: false,
185
174
  includeInStateLogs: false,
186
175
  persist: false,
187
176
  usedInUi: false,
188
177
  },
189
- accessToken: {
178
+ moonpayAccessToken: {
190
179
  includeInDebugSnapshot: false,
191
180
  includeInStateLogs: false,
192
181
  persist: false,
@@ -247,6 +236,19 @@ const kycControllerMetadata = {
247
236
  usedInUi: true,
248
237
  },
249
238
  };
239
+ /**
240
+ * Constructs the default {@link KycVendorDisclaimersAccepted} value.
241
+ *
242
+ * @returns The default vendor-disclaimer acceptance map.
243
+ */
244
+ function getDefaultKycVendorDisclaimersAccepted() {
245
+ return { moonpay: null, iron: null };
246
+ }
247
+ exports.getDefaultKycVendorDisclaimersAccepted = getDefaultKycVendorDisclaimersAccepted;
248
+ function getDefaultKycProviderDisclaimersAccepted() {
249
+ return { sumsub: null };
250
+ }
251
+ exports.getDefaultKycProviderDisclaimersAccepted = getDefaultKycProviderDisclaimersAccepted;
250
252
  /**
251
253
  * Constructs the default {@link KycController} state.
252
254
  *
@@ -258,18 +260,16 @@ function getDefaultKycControllerState() {
258
260
  statusMessage: '',
259
261
  error: null,
260
262
  email: null,
261
- termsAcceptedAt: null,
262
- acceptedDisclaimerIds: [],
263
- termsAcceptedVendor: null,
264
- sumsubTncAccepted: null,
265
- idosTncAccepted: null,
263
+ vendorDisclaimersAccepted: getDefaultKycVendorDisclaimersAccepted(),
264
+ providerDisclaimersAccepted: getDefaultKycProviderDisclaimersAccepted(),
265
+ idosDisclaimersAccepted: null,
266
266
  credentialReusabilityConsentGiven: null,
267
- disclaimers: [],
268
- disclaimersError: null,
267
+ vendorDisclaimers: [],
268
+ vendorError: null,
269
269
  sessionDisclaimers: null,
270
270
  geoCountry: null,
271
- sessionToken: null,
272
- accessToken: null,
271
+ moonpaySessionToken: null,
272
+ moonpayAccessToken: null,
273
273
  moonpayCustomerId: null,
274
274
  activeVendor: 'moonpay',
275
275
  activeProduct: null,
@@ -314,45 +314,62 @@ function isConsentConflictError(error) {
314
314
  error.httpStatus === 409);
315
315
  }
316
316
  /**
317
- * Maps a session-disclaimer catalog into the `{ key, version }` records the
318
- * record-consents API expects, or an empty list when the user declined that
319
- * category.
317
+ *
318
+ * @param value - The value to validate.
319
+ * @returns `true` when `value` is a valid consent record list.
320
+ */
321
+ function isValidConsentRecordList(value) {
322
+ return (Array.isArray(value) &&
323
+ value.every((item) => typeof item === 'object' &&
324
+ item !== null &&
325
+ typeof item.key === 'string' &&
326
+ typeof item.version === 'string'));
327
+ }
328
+ /**
329
+ * Maps accepted disclaimer records onto unconsented catalog documents.
320
330
  *
321
331
  * @param documents - Catalog documents for one consent category.
322
- * @param accepted - Whether the user accepted that category.
323
- * @returns Consent records, or `[]` when not accepted.
332
+ * @param accepted - Accepted `{ key, version }` records from the caller.
333
+ * @returns Consent records to POST, omitting already-consented documents.
324
334
  */
325
- function consentRecordsFromCatalog(documents, accepted) {
326
- if (!accepted) {
335
+ function consentRecordsFromAcceptedList(documents, accepted) {
336
+ if (accepted.length === 0) {
327
337
  return [];
328
338
  }
339
+ const acceptedKeys = new Set(accepted.map((record) => `${record.key}:${record.version}`));
329
340
  return documents
330
- .filter((document) => !document.consented)
341
+ .filter((document) => !document.consented &&
342
+ acceptedKeys.has(`${document.key}:${document.version}`))
331
343
  .map(({ key, version }) => ({ key, version }));
332
344
  }
333
345
  /**
334
- * Whether an accepted T&C2 category has no catalog documents. An empty list
335
- * would otherwise skip the POST and count as success.
346
+ * Whether accepted disclaimers reference a missing catalog category.
336
347
  *
337
348
  * @param documents - Catalog documents for one consent category.
338
- * @param accepted - Whether the user accepted that category.
339
- * @returns `true` when the user accepted and the catalog is empty.
349
+ * @param accepted - Accepted `{ key, version }` records from the caller.
350
+ * @returns `true` when the caller accepted docs but the catalog is empty.
340
351
  */
341
352
  function isAcceptedCategoryEmpty(documents, accepted) {
342
- return accepted && documents.length === 0;
353
+ return accepted.length > 0 && documents.length === 0;
343
354
  }
344
355
  /**
345
- * Whether an accepted category is still missing consent after a 409 re-GET:
346
- * empty catalog or any document still unconsented.
356
+ * Whether accepted disclaimers are still missing consent after a 409 re-GET:
357
+ * empty catalog or any accepted document still unconsented.
347
358
  *
348
359
  * @param documents - Latest catalog documents for one consent category.
349
- * @param accepted - Whether the user accepted that category.
360
+ * @param accepted - Accepted `{ key, version }` records from the caller.
350
361
  * @returns `true` when accepted documents are not fully consented.
351
362
  */
352
363
  function acceptedCategoryStillMissing(documents, accepted) {
353
- return (accepted &&
354
- (documents.length === 0 ||
355
- documents.some((document) => !document.consented)));
364
+ if (accepted.length === 0) {
365
+ return false;
366
+ }
367
+ if (documents.length === 0) {
368
+ return true;
369
+ }
370
+ const acceptedKeys = new Set(accepted.map((record) => `${record.key}:${record.version}`));
371
+ const relevant = documents.filter((document) => acceptedKeys.has(`${document.key}:${document.version}`));
372
+ return (relevant.length === 0 || relevant.some((document) => !document.consented));
356
373
  }
357
374
  /**
358
375
  * Vendors other than MoonPay skip Check/Auth frames and use the empty-shell
@@ -414,8 +431,8 @@ class KycController extends base_controller_1.BaseController {
414
431
  });
415
432
  _KycController_instances.add(this);
416
433
  _KycController_sumsubLauncher.set(this, void 0);
417
- /** Ephemeral X25519 keypair for the frame key exchange (never persisted). */
418
- _KycController_keypair.set(this, void 0);
434
+ /** MoonPay Check/Auth frame X25519 keypair (never persisted). */
435
+ _KycController_moonpayFrameKeypair.set(this, null);
419
436
  /** Auth-frame client token, kept out of state. */
420
437
  _KycController_authClientToken.set(this, null);
421
438
  /**
@@ -454,7 +471,6 @@ class KycController extends base_controller_1.BaseController {
454
471
  __classPrivateFieldSet(this, _KycController_sumsubLauncher, sumsubLauncher, "f");
455
472
  __classPrivateFieldSet(this, _KycController_sessionStatusPollIntervalMs, sessionStatusPollIntervalMs, "f");
456
473
  __classPrivateFieldSet(this, _KycController_userStatusPollIntervalMs, userStatusPollIntervalMs, "f");
457
- __classPrivateFieldSet(this, _KycController_keypair, (0, crypto_js_1.generateKeyPair)(), "f");
458
474
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
459
475
  }
460
476
  /**
@@ -477,10 +493,19 @@ class KycController extends base_controller_1.BaseController {
477
493
  // forces `phase` back through `session`/`check`, breaking an in-flight
478
494
  // Check/Auth frame flow. Leave the active flow untouched and let the
479
495
  // consumer drive it (or call `reset` first to start over).
496
+ const vendor = params?.vendor ?? 'moonpay';
480
497
  if (IN_PROGRESS_PHASES.includes(this.state.phase)) {
498
+ if (vendor === 'moonpay' && !__classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f")) {
499
+ __classPrivateFieldSet(this, _KycController_moonpayFrameKeypair, (0, crypto_js_1.generateKeyPair)(), "f");
500
+ }
481
501
  return;
482
502
  }
483
- const vendor = params?.vendor ?? 'moonpay';
503
+ if (vendor === 'moonpay') {
504
+ __classPrivateFieldSet(this, _KycController_moonpayFrameKeypair, (0, crypto_js_1.generateKeyPair)(), "f");
505
+ }
506
+ else {
507
+ __classPrivateFieldSet(this, _KycController_moonpayFrameKeypair, null, "f");
508
+ }
484
509
  // `initialize` starts a fresh flow, so `activeProduct` is always reset to
485
510
  // this call's product (or `null`). Otherwise a prior run's product could
486
511
  // linger and cause `#continueAfterAuthentication` to auto-run the check /
@@ -491,8 +516,8 @@ class KycController extends base_controller_1.BaseController {
491
516
  }
492
517
  state.activeVendor = vendor;
493
518
  // MoonPay Check/Auth artifacts must not survive a switch to another
494
- // vendor: leftover `sessionToken` would keep `buildCheckFrameUrl` alive,
495
- // leftover `accessToken` / `#authClientToken` would keep Auth / KYC
519
+ // vendor: leftover `moonpaySessionToken` would keep `buildCheckFrameUrl` alive,
520
+ // leftover `moonpayAccessToken` / `#authClientToken` would keep Auth / KYC
496
521
  // calls bound to MoonPay, and leftover `moonpayCustomerId` would make
497
522
  // `getCustomerIdentity` report a MoonPay id under the wrong vendor.
498
523
  if (vendor !== 'moonpay') {
@@ -545,16 +570,14 @@ class KycController extends base_controller_1.BaseController {
545
570
  if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
546
571
  return;
547
572
  }
548
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_dropTermsUnlessForVendor).call(this, vendor);
549
- const hasTerms = Boolean(this.state.termsAcceptedAt) &&
550
- this.state.acceptedDisclaimerIds.length > 0;
573
+ const hasTerms = (0, vendorDisclaimerAcceptance_js_1.hasVendorDisclaimerAcceptance)(this.state.vendorDisclaimersAccepted, vendor);
551
574
  if (hasTerms && this.state.email) {
552
575
  if (usesConsentsFlow(vendor)) {
553
576
  // Consents-path vendors require T&C2 flags; if they weren't persisted
554
577
  // (i.e. null from pre-migration state), require reacceptance.
555
- const sumsubTncSigned = this.state.sumsubTncAccepted;
556
- const idosTncSigned = this.state.idosTncAccepted;
557
- if (sumsubTncSigned === null || idosTncSigned === null) {
578
+ const { providerDisclaimersAccepted, idosDisclaimersAccepted } = this.state;
579
+ if (providerDisclaimersAccepted.sumsub === null ||
580
+ idosDisclaimersAccepted === null) {
558
581
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
559
582
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearAcceptedTerms).call(this, state);
560
583
  state.phase = 'terms';
@@ -563,12 +586,19 @@ class KycController extends base_controller_1.BaseController {
563
586
  return;
564
587
  }
565
588
  await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_startConsentsSession).call(this, {
566
- sumsubTncSigned,
567
- idosTncSigned,
589
+ providerDisclaimersAccepted: providerDisclaimersAccepted.sumsub,
590
+ idosDisclaimersAccepted,
568
591
  credentialReusabilityConsentGiven: this.state.credentialReusabilityConsentGiven ?? false,
569
592
  });
570
593
  }
571
594
  else {
595
+ // TODO: should this be here? or should it exist at all?
596
+ if (vendor === 'moonpay' && this.state.vendorDisclaimers.length === 0) {
597
+ await this.loadDisclaimers();
598
+ if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
599
+ return;
600
+ }
601
+ }
572
602
  await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_createSession).call(this);
573
603
  }
574
604
  return;
@@ -603,6 +633,7 @@ class KycController extends base_controller_1.BaseController {
603
633
  state.activeVendor = params.vendor;
604
634
  if (params.vendor !== 'moonpay') {
605
635
  __classPrivateFieldSet(this, _KycController_authClientToken, null, "f");
636
+ __classPrivateFieldSet(this, _KycController_moonpayFrameKeypair, null, "f");
606
637
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearMoonPaySession).call(this, state);
607
638
  }
608
639
  });
@@ -612,10 +643,6 @@ class KycController extends base_controller_1.BaseController {
612
643
  vendor: params.vendor,
613
644
  email: params.email,
614
645
  });
615
- if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
616
- return;
617
- }
618
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_dropTermsUnlessForVendor).call(this, params.vendor);
619
646
  }
620
647
  catch (error) {
621
648
  if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
@@ -649,13 +676,13 @@ class KycController extends base_controller_1.BaseController {
649
676
  country,
650
677
  });
651
678
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
652
- state.disclaimers = disclaimers;
653
- state.disclaimersError = null;
679
+ state.vendorDisclaimers = disclaimers;
680
+ state.vendorError = null;
654
681
  });
655
682
  }
656
683
  catch (error) {
657
684
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
658
- state.disclaimersError = `Failed to load disclaimers: ${String(error)}`;
685
+ state.vendorError = `Failed to load disclaimers: ${String(error)}`;
659
686
  });
660
687
  }
661
688
  }
@@ -668,44 +695,47 @@ class KycController extends base_controller_1.BaseController {
668
695
  * @param params.product - The consuming feature the flow runs for. See
669
696
  * {@link initialize} for how the product drives the automatic post
670
697
  * authentication continuation.
671
- * @param params.sumsubTncSigned - Whether Sumsub T&C were accepted (T&C2).
672
- * Required for every vendor so callers explicitly declare acceptance.
673
- * @param params.idosTncSigned - Whether idOS T&C were accepted (T&C2).
674
- * Required for every vendor so callers explicitly declare acceptance.
698
+ * @param params.providerDisclaimersAccepted - Sumsub disclaimer documents the
699
+ * customer accepted (`{ key, version }` records). Required for every vendor
700
+ * so callers explicitly declare acceptance.
701
+ * @param params.idosDisclaimersAccepted - idOS disclaimer documents the
702
+ * customer accepted (`{ key, version }` records). Required for every vendor
703
+ * so callers explicitly declare acceptance.
675
704
  * @param params.credentialReusabilityConsentGiven - Whether the customer
676
705
  * consented to reuse existing idOS credentials. Used when recording
677
706
  * session-scoped disclaimers on the consents path. Defaults to `false`.
678
707
  */
679
708
  async acceptTermsAndStartSession(params) {
680
- const sumsubTncSigned = params?.sumsubTncSigned;
681
- const idosTncSigned = params?.idosTncSigned;
682
- if (typeof sumsubTncSigned !== 'boolean' ||
683
- typeof idosTncSigned !== 'boolean') {
709
+ const providerDisclaimersAccepted = params?.providerDisclaimersAccepted;
710
+ const idosDisclaimersAccepted = params?.idosDisclaimersAccepted;
711
+ if (!isValidConsentRecordList(providerDisclaimersAccepted) ||
712
+ !isValidConsentRecordList(idosDisclaimersAccepted)) {
684
713
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing T&C2 acceptance flags.');
685
714
  return;
686
715
  }
687
- const credentialReusabilityConsentGiven = params.credentialReusabilityConsentGiven ?? false;
716
+ const credentialReusabilityConsentGiven = params?.credentialReusabilityConsentGiven ?? false;
688
717
  const termsAcceptedAt = new Date().toISOString();
689
- const disclaimerIds = this.state.disclaimers.map((disclaimer) => disclaimer.id);
718
+ const disclaimerIds = this.state.vendorDisclaimers.map((disclaimer) => disclaimer.id);
690
719
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
691
- if (params.email) {
720
+ if (params?.email) {
692
721
  state.email = params.email;
693
722
  }
694
- if (params.product) {
723
+ if (params?.product) {
695
724
  state.activeProduct = params.product;
696
725
  }
697
- state.termsAcceptedAt = termsAcceptedAt;
698
- state.acceptedDisclaimerIds = disclaimerIds;
699
- state.termsAcceptedVendor = state.activeVendor;
700
- state.sumsubTncAccepted = sumsubTncSigned;
701
- state.idosTncAccepted = idosTncSigned;
726
+ state.vendorDisclaimersAccepted = (0, vendorDisclaimerAcceptance_js_1.recordVendorDisclaimerAcceptance)(state.vendorDisclaimersAccepted, state.activeVendor, { termsAcceptedAt, disclaimerIds });
727
+ state.providerDisclaimersAccepted = {
728
+ ...state.providerDisclaimersAccepted,
729
+ sumsub: providerDisclaimersAccepted,
730
+ };
731
+ state.idosDisclaimersAccepted = idosDisclaimersAccepted;
702
732
  state.credentialReusabilityConsentGiven =
703
733
  credentialReusabilityConsentGiven;
704
734
  });
705
735
  if (usesConsentsFlow(this.state.activeVendor)) {
706
736
  await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_startConsentsSession).call(this, {
707
- sumsubTncSigned,
708
- idosTncSigned,
737
+ providerDisclaimersAccepted,
738
+ idosDisclaimersAccepted,
709
739
  credentialReusabilityConsentGiven,
710
740
  });
711
741
  return;
@@ -717,7 +747,12 @@ class KycController extends base_controller_1.BaseController {
717
747
  */
718
748
  clearSavedTerms() {
719
749
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
720
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearAcceptedTerms).call(this, state);
750
+ state.vendorDisclaimersAccepted =
751
+ getDefaultKycVendorDisclaimersAccepted();
752
+ state.providerDisclaimersAccepted =
753
+ getDefaultKycProviderDisclaimersAccepted();
754
+ state.idosDisclaimersAccepted = null;
755
+ state.credentialReusabilityConsentGiven = null;
721
756
  });
722
757
  }
723
758
  /**
@@ -775,9 +810,9 @@ class KycController extends base_controller_1.BaseController {
775
810
  }
776
811
  let accessToken;
777
812
  let clientToken;
778
- if (credsEnvelope) {
813
+ if (credsEnvelope && __classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f")) {
779
814
  try {
780
- const { credentials } = (0, crypto_js_1.decryptCredentials)(credsEnvelope, __classPrivateFieldGet(this, _KycController_keypair, "f").privateKey);
815
+ const { credentials } = (0, crypto_js_1.decryptCredentials)(credsEnvelope, __classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f").privateKey);
781
816
  accessToken = credentials.accessToken;
782
817
  clientToken = credentials.clientToken;
783
818
  }
@@ -800,12 +835,14 @@ class KycController extends base_controller_1.BaseController {
800
835
  * @returns The Check-frame URL or `null`.
801
836
  */
802
837
  buildCheckFrameUrl() {
803
- if (this.state.activeVendor !== 'moonpay' || !this.state.sessionToken) {
838
+ if (this.state.activeVendor !== 'moonpay' ||
839
+ !this.state.moonpaySessionToken ||
840
+ !__classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f")) {
804
841
  return null;
805
842
  }
806
843
  const url = new URL(`${FRAMES_BASE_URL}/check-connection`);
807
- url.searchParams.set('sessionToken', this.state.sessionToken);
808
- url.searchParams.set('publicKey', __classPrivateFieldGet(this, _KycController_keypair, "f").publicKeyHex);
844
+ url.searchParams.set('sessionToken', this.state.moonpaySessionToken);
845
+ url.searchParams.set('publicKey', __classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f").publicKeyHex);
809
846
  url.searchParams.set('channelId', CHANNEL_CHECK);
810
847
  url.searchParams.set('skipKyc', 'true');
811
848
  return url.toString();
@@ -816,12 +853,14 @@ class KycController extends base_controller_1.BaseController {
816
853
  * @returns The Auth-frame URL or `null`.
817
854
  */
818
855
  buildAuthFrameUrl() {
819
- if (this.state.activeVendor !== 'moonpay' || !__classPrivateFieldGet(this, _KycController_authClientToken, "f")) {
856
+ if (this.state.activeVendor !== 'moonpay' ||
857
+ !__classPrivateFieldGet(this, _KycController_authClientToken, "f") ||
858
+ !__classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f")) {
820
859
  return null;
821
860
  }
822
861
  const url = new URL(`${FRAMES_BASE_URL}/auth`);
823
862
  url.searchParams.set('clientToken', __classPrivateFieldGet(this, _KycController_authClientToken, "f"));
824
- url.searchParams.set('publicKey', __classPrivateFieldGet(this, _KycController_keypair, "f").publicKeyHex);
863
+ url.searchParams.set('publicKey', __classPrivateFieldGet(this, _KycController_moonpayFrameKeypair, "f").publicKeyHex);
825
864
  url.searchParams.set('channelId', CHANNEL_AUTH);
826
865
  return url.toString();
827
866
  }
@@ -844,9 +883,9 @@ class KycController extends base_controller_1.BaseController {
844
883
  * @returns Whether KYC is required.
845
884
  */
846
885
  async checkKycRequired(params) {
847
- const { accessToken } = this.state;
848
- if (!accessToken) {
849
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing accessToken — repeat the authentication step.');
886
+ const { moonpayAccessToken } = this.state;
887
+ if (!moonpayAccessToken) {
888
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing moonpayAccessToken — repeat the authentication step.');
850
889
  return false;
851
890
  }
852
891
  const country = params.country ?? this.state.geoCountry;
@@ -862,7 +901,11 @@ class KycController extends base_controller_1.BaseController {
862
901
  state.statusMessage = 'Checking KYC status...';
863
902
  });
864
903
  try {
865
- const { kycRequired } = await this.messenger.call('KycService:checkKycRequired', { accessToken, country, capabilities: [{ product: params.product }] });
904
+ const { kycRequired } = await this.messenger.call('KycService:checkKycRequired', {
905
+ accessToken: moonpayAccessToken,
906
+ country,
907
+ capabilities: [{ product: params.product }],
908
+ });
866
909
  // The flow was reset while the check was in flight; discard the result
867
910
  // rather than resurrecting a done/cached state on an idle controller.
868
911
  const applied = __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
@@ -1147,12 +1190,12 @@ class KycController extends base_controller_1.BaseController {
1147
1190
  state.phase = 'idle';
1148
1191
  state.statusMessage = '';
1149
1192
  state.error = null;
1150
- state.disclaimers = [];
1151
- state.disclaimersError = null;
1193
+ state.vendorDisclaimers = [];
1194
+ state.vendorError = null;
1152
1195
  state.sessionDisclaimers = null;
1153
1196
  state.credentialReusabilityConsentGiven = null;
1154
- state.sessionToken = null;
1155
- state.accessToken = null;
1197
+ state.moonpaySessionToken = null;
1198
+ state.moonpayAccessToken = null;
1156
1199
  state.moonpayCustomerId = null;
1157
1200
  state.activeVendor = 'moonpay';
1158
1201
  state.activeProduct = null;
@@ -1181,7 +1224,7 @@ class KycController extends base_controller_1.BaseController {
1181
1224
  }
1182
1225
  }
1183
1226
  exports.KycController = KycController;
1184
- _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_userStatusPolling = new WeakMap(), _KycController_userStatusPollToken = new WeakMap(), _KycController_instances = new WeakSet(), _KycController_localUserSecretStore = function _KycController_localUserSecretStore() {
1227
+ _KycController_sumsubLauncher = new WeakMap(), _KycController_moonpayFrameKeypair = 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_userStatusPolling = new WeakMap(), _KycController_userStatusPollToken = new WeakMap(), _KycController_instances = new WeakSet(), _KycController_localUserSecretStore = function _KycController_localUserSecretStore() {
1185
1228
  return {
1186
1229
  get: async (path, entropySourceId) => this.messenger.call('UserStorageController:performGetStorage', path, entropySourceId),
1187
1230
  set: async (path, value, entropySourceId) => this.messenger.call('UserStorageController:performSetStorage', path, value, entropySourceId),
@@ -1193,13 +1236,14 @@ _KycController_sumsubLauncher = new WeakMap(), _KycController_keypair = new Weak
1193
1236
  * SumSub — skipping MoonPay Check/Auth frames.
1194
1237
  *
1195
1238
  * @param consents - T&C2 flags mapped onto the session disclaimer catalog.
1196
- * @param consents.sumsubTncSigned - Whether Sumsub T&C were accepted.
1197
- * @param consents.idosTncSigned - Whether idOS T&C were accepted.
1239
+ * @param consents.providerDisclaimersAccepted - Accepted Sumsub disclaimer records.
1240
+ * @param consents.idosDisclaimersAccepted - Accepted idOS disclaimer records.
1198
1241
  * @param consents.credentialReusabilityConsentGiven - Whether credential
1199
1242
  * reuse was accepted.
1200
1243
  */
1201
1244
  async function _KycController_startConsentsSession(consents) {
1202
- const { email, acceptedDisclaimerIds } = this.state;
1245
+ const { email } = this.state;
1246
+ const acceptedDisclaimerIds = (0, vendorDisclaimerAcceptance_js_1.ironDisclaimerIds)(this.state.vendorDisclaimersAccepted);
1203
1247
  if (!email) {
1204
1248
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing email for consents session.');
1205
1249
  return;
@@ -1334,8 +1378,8 @@ async function _KycController_startConsentsSession(consents) {
1334
1378
  *
1335
1379
  * @param sessionId - The UKYC session id.
1336
1380
  * @param consents - T&C2 flags mapped onto catalog documents.
1337
- * @param consents.sumsubTncSigned - Whether Sumsub T&C were accepted.
1338
- * @param consents.idosTncSigned - Whether idOS T&C were accepted.
1381
+ * @param consents.providerDisclaimersAccepted - Accepted Sumsub disclaimer records.
1382
+ * @param consents.idosDisclaimersAccepted - Accepted idOS disclaimer records.
1339
1383
  * @param consents.credentialReusabilityConsentGiven - Whether credential
1340
1384
  * reuse was accepted.
1341
1385
  * @param generation - Flow generation captured by the caller.
@@ -1349,12 +1393,12 @@ async function _KycController_recordSessionDisclaimers(sessionId, consents, gene
1349
1393
  state.sessionDisclaimers = catalog;
1350
1394
  state.statusMessage = 'Submitting consents...';
1351
1395
  });
1352
- if (isAcceptedCategoryEmpty(catalog.idOS, consents.idosTncSigned) ||
1353
- isAcceptedCategoryEmpty(catalog.kycProvider, consents.sumsubTncSigned)) {
1396
+ if (isAcceptedCategoryEmpty(catalog.idOS, consents.idosDisclaimersAccepted) ||
1397
+ isAcceptedCategoryEmpty(catalog.kycProvider, consents.providerDisclaimersAccepted)) {
1354
1398
  throw new Error('Session disclaimer catalog is missing documents for an accepted category.');
1355
1399
  }
1356
- const idOS = consentRecordsFromCatalog(catalog.idOS, consents.idosTncSigned);
1357
- const kycProvider = consentRecordsFromCatalog(catalog.kycProvider, consents.sumsubTncSigned);
1400
+ const idOS = consentRecordsFromAcceptedList(catalog.idOS, consents.idosDisclaimersAccepted);
1401
+ const kycProvider = consentRecordsFromAcceptedList(catalog.kycProvider, consents.providerDisclaimersAccepted);
1358
1402
  const reuseUnchanged = catalog.credentialReusabilityConsentGiven ===
1359
1403
  consents.credentialReusabilityConsentGiven;
1360
1404
  if (idOS.length === 0 && kycProvider.length === 0 && reuseUnchanged) {
@@ -1385,8 +1429,9 @@ async function _KycController_recordSessionDisclaimers(sessionId, consents, gene
1385
1429
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1386
1430
  state.sessionDisclaimers = latest;
1387
1431
  });
1388
- const stillMissingIdos = acceptedCategoryStillMissing(latest.idOS, consents.idosTncSigned);
1389
- const stillMissingProvider = acceptedCategoryStillMissing(latest.kycProvider, consents.sumsubTncSigned);
1432
+ // TODO: Should we really be doing client side validation of these?
1433
+ const stillMissingIdos = acceptedCategoryStillMissing(latest.idOS, consents.idosDisclaimersAccepted);
1434
+ const stillMissingProvider = acceptedCategoryStillMissing(latest.kycProvider, consents.providerDisclaimersAccepted);
1390
1435
  const stillMissingReuse = consents.credentialReusabilityConsentGiven &&
1391
1436
  !latest.credentialReusabilityConsentGiven;
1392
1437
  if (stillMissingIdos || stillMissingProvider || stillMissingReuse) {
@@ -1398,7 +1443,9 @@ async function _KycController_recordSessionDisclaimers(sessionId, consents, gene
1398
1443
  * Creates a vendor session from the currently stored terms + email.
1399
1444
  */
1400
1445
  async function _KycController_createSession() {
1401
- const { email, termsAcceptedAt, acceptedDisclaimerIds } = this.state;
1446
+ const { email } = this.state;
1447
+ const termsAcceptedAt = this.state.vendorDisclaimersAccepted.moonpay?.termsAcceptedAt;
1448
+ const acceptedDisclaimerIds = this.state.vendorDisclaimers.map((disclaimer) => disclaimer.id);
1402
1449
  if (!email) {
1403
1450
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing email for session creation.');
1404
1451
  return;
@@ -1413,7 +1460,7 @@ async function _KycController_createSession() {
1413
1460
  // (or, on failure, invalid) session token, `buildAuthFrameUrl` cannot
1414
1461
  // return a URL tied to an old client token, and `checkKycRequired` cannot
1415
1462
  // run with an access token from an earlier authentication. The Check/Auth
1416
- // frames re-populate these for the new session. Because `sessionToken` is
1463
+ // frames re-populate these for the new session. Because `moonpaySessionToken` is
1417
1464
  // cleared here and only re-set on success, a failed creation leaves it
1418
1465
  // `null` rather than resurrecting the previous session.
1419
1466
  // Capture the flow generation so a `reset()` landing while the create
@@ -1426,13 +1473,13 @@ async function _KycController_createSession() {
1426
1473
  state.error = null;
1427
1474
  state.phase = 'session';
1428
1475
  state.statusMessage = 'Creating session...';
1429
- state.sessionToken = null;
1430
- state.accessToken = null;
1476
+ state.moonpaySessionToken = null;
1477
+ state.moonpayAccessToken = null;
1431
1478
  });
1432
1479
  try {
1433
1480
  const { sessionToken } = await this.messenger.call('KycService:createSession', { email, termsAcceptedAt, disclaimerIds: acceptedDisclaimerIds });
1434
1481
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
1435
- state.sessionToken = sessionToken;
1482
+ state.moonpaySessionToken = sessionToken;
1436
1483
  state.phase = 'check';
1437
1484
  state.statusMessage = 'Authenticating via Check frame...';
1438
1485
  });
@@ -1458,29 +1505,17 @@ async function _KycController_createSession() {
1458
1505
  });
1459
1506
  await this.loadDisclaimers();
1460
1507
  }
1461
- }, _KycController_clearAcceptedTerms = function _KycController_clearAcceptedTerms(state) {
1462
- state.termsAcceptedAt = null;
1463
- state.acceptedDisclaimerIds = [];
1464
- state.termsAcceptedVendor = null;
1465
- state.sumsubTncAccepted = null;
1466
- state.idosTncAccepted = null;
1508
+ }, _KycController_clearAcceptedTerms = function _KycController_clearAcceptedTerms(state, vendor) {
1509
+ const targetVendor = vendor ?? state.activeVendor;
1510
+ state.vendorDisclaimersAccepted = (0, vendorDisclaimerAcceptance_js_1.clearVendorDisclaimerAcceptance)(state.vendorDisclaimersAccepted, targetVendor);
1511
+ state.providerDisclaimersAccepted =
1512
+ getDefaultKycProviderDisclaimersAccepted();
1513
+ state.idosDisclaimersAccepted = null;
1467
1514
  state.credentialReusabilityConsentGiven = null;
1468
1515
  }, _KycController_clearMoonPaySession = function _KycController_clearMoonPaySession(state) {
1469
1516
  state.moonpayCustomerId = null;
1470
- state.sessionToken = null;
1471
- state.accessToken = null;
1472
- }, _KycController_dropTermsUnlessForVendor = function _KycController_dropTermsUnlessForVendor(vendor) {
1473
- if (__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_hasTermsForVendor).call(this, vendor)) {
1474
- return;
1475
- }
1476
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1477
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearAcceptedTerms).call(this, state);
1478
- });
1479
- }, _KycController_hasTermsForVendor = function _KycController_hasTermsForVendor(vendor) {
1480
- if (this.state.termsAcceptedVendor === null) {
1481
- return false;
1482
- }
1483
- return this.state.termsAcceptedVendor === vendor;
1517
+ state.moonpaySessionToken = null;
1518
+ state.moonpayAccessToken = null;
1484
1519
  }, _KycController_handleCheckOutcome =
1485
1520
  /**
1486
1521
  * Applies a Check-frame outcome.
@@ -1492,7 +1527,7 @@ async function _KycController_createSession() {
1492
1527
  async function _KycController_handleCheckOutcome(status, accessToken, clientToken) {
1493
1528
  if (status === 'active' && accessToken) {
1494
1529
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1495
- state.accessToken = accessToken;
1530
+ state.moonpayAccessToken = accessToken;
1496
1531
  state.phase = 'form';
1497
1532
  state.statusMessage = 'Already authenticated. Review to submit.';
1498
1533
  });
@@ -1522,7 +1557,7 @@ async function _KycController_handleCheckOutcome(status, accessToken, clientToke
1522
1557
  async function _KycController_handleAuthOutcome(status, accessToken) {
1523
1558
  if (status === 'active' && accessToken) {
1524
1559
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1525
- state.accessToken = accessToken;
1560
+ state.moonpayAccessToken = accessToken;
1526
1561
  state.phase = 'form';
1527
1562
  state.statusMessage = 'Authenticated. Review to submit.';
1528
1563
  });
@@ -1585,7 +1620,7 @@ async function _KycController_continueAfterAuthentication() {
1585
1620
  return {
1586
1621
  vendor: 'moonpay',
1587
1622
  vendorMetadata: {
1588
- moonPayAccessToken: this.state.accessToken,
1623
+ moonPayAccessToken: this.state.moonpayAccessToken,
1589
1624
  moonPayUserId: this.state.moonpayCustomerId,
1590
1625
  },
1591
1626
  };