@metamask-previews/kyc-controller 0.0.0-preview-abca9bcea → 0.0.0-preview-ec24abb79

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 (76) hide show
  1. package/CHANGELOG.md +0 -12
  2. package/dist/KycController-method-action-types.cjs.map +1 -1
  3. package/dist/KycController-method-action-types.d.cts +4 -6
  4. package/dist/KycController-method-action-types.d.cts.map +1 -1
  5. package/dist/KycController-method-action-types.d.mts +4 -6
  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 +300 -191
  9. package/dist/KycController.cjs.map +1 -1
  10. package/dist/KycController.d.cts +40 -46
  11. package/dist/KycController.d.cts.map +1 -1
  12. package/dist/KycController.d.mts +40 -46
  13. package/dist/KycController.d.mts.map +1 -1
  14. package/dist/KycController.mjs +299 -188
  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 +6 -23
  18. package/dist/KycService-method-action-types.d.cts.map +1 -1
  19. package/dist/KycService-method-action-types.d.mts +6 -23
  20. package/dist/KycService-method-action-types.d.mts.map +1 -1
  21. package/dist/KycService-method-action-types.mjs.map +1 -1
  22. package/dist/KycService.cjs +119 -100
  23. package/dist/KycService.cjs.map +1 -1
  24. package/dist/KycService.d.cts +12 -38
  25. package/dist/KycService.d.cts.map +1 -1
  26. package/dist/KycService.d.mts +12 -38
  27. package/dist/KycService.d.mts.map +1 -1
  28. package/dist/KycService.mjs +119 -100
  29. package/dist/KycService.mjs.map +1 -1
  30. package/dist/index.cjs +1 -3
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +4 -4
  33. package/dist/index.d.cts.map +1 -1
  34. package/dist/index.d.mts +4 -4
  35. package/dist/index.d.mts.map +1 -1
  36. package/dist/index.mjs +1 -1
  37. package/dist/index.mjs.map +1 -1
  38. package/dist/types.cjs.map +1 -1
  39. package/dist/types.d.cts +5 -53
  40. package/dist/types.d.cts.map +1 -1
  41. package/dist/types.d.mts +5 -53
  42. package/dist/types.d.mts.map +1 -1
  43. package/dist/types.mjs.map +1 -1
  44. package/dist/ukyc/wrapEncryptionKey.cjs +9 -4
  45. package/dist/ukyc/wrapEncryptionKey.cjs.map +1 -1
  46. package/dist/ukyc/wrapEncryptionKey.d.cts +10 -8
  47. package/dist/ukyc/wrapEncryptionKey.d.cts.map +1 -1
  48. package/dist/ukyc/wrapEncryptionKey.d.mts +10 -8
  49. package/dist/ukyc/wrapEncryptionKey.d.mts.map +1 -1
  50. package/dist/ukyc/wrapEncryptionKey.mjs +9 -4
  51. package/dist/ukyc/wrapEncryptionKey.mjs.map +1 -1
  52. package/package.json +2 -2
  53. package/dist/logger.cjs +0 -9
  54. package/dist/logger.cjs.map +0 -1
  55. package/dist/logger.d.cts +0 -6
  56. package/dist/logger.d.cts.map +0 -1
  57. package/dist/logger.d.mts +0 -6
  58. package/dist/logger.d.mts.map +0 -1
  59. package/dist/logger.mjs +0 -6
  60. package/dist/logger.mjs.map +0 -1
  61. package/dist/vendorDisclaimerAcceptance.cjs +0 -74
  62. package/dist/vendorDisclaimerAcceptance.cjs.map +0 -1
  63. package/dist/vendorDisclaimerAcceptance.d.cts +0 -39
  64. package/dist/vendorDisclaimerAcceptance.d.cts.map +0 -1
  65. package/dist/vendorDisclaimerAcceptance.d.mts +0 -39
  66. package/dist/vendorDisclaimerAcceptance.d.mts.map +0 -1
  67. package/dist/vendorDisclaimerAcceptance.mjs +0 -67
  68. package/dist/vendorDisclaimerAcceptance.mjs.map +0 -1
  69. package/dist/vendors/MoonPayFrameHandler.cjs +0 -235
  70. package/dist/vendors/MoonPayFrameHandler.cjs.map +0 -1
  71. package/dist/vendors/MoonPayFrameHandler.d.cts +0 -74
  72. package/dist/vendors/MoonPayFrameHandler.d.cts.map +0 -1
  73. package/dist/vendors/MoonPayFrameHandler.d.mts +0 -74
  74. package/dist/vendors/MoonPayFrameHandler.d.mts.map +0 -1
  75. package/dist/vendors/MoonPayFrameHandler.mjs +0 -230
  76. package/dist/vendors/MoonPayFrameHandler.mjs.map +0 -1
@@ -9,21 +9,23 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
9
9
  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");
10
10
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
11
  };
12
- var _KycController_instances, _KycController_sumsubLauncher, _KycController_moonPayFrames, _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_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;
12
+ 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
13
  import { BaseController } from "@metamask/base-controller";
14
14
  import { stringToBytes } from "@metamask/utils";
15
15
  import { x25519 } from "@noble/curves/ed25519";
16
+ import { decryptCredentials, generateKeyPair } from "./crypto.mjs";
16
17
  import { toBase64Url } from "./encoding.mjs";
17
- import { controllerLog } from "./logger.mjs";
18
18
  import { deriveClientMaterial } from "./ukyc/deriveClientMaterial.mjs";
19
19
  import { verifyJwtChain } from "./ukyc/jwtChain.mjs";
20
20
  import { getOrCreateLocalUserSecret } from "./ukyc/localUserSecret.mjs";
21
21
  import { encodeStorageAccessTokenForHeader, signStorageAccessToken } from "./ukyc/storageAccessToken.mjs";
22
22
  import { wrapEncryptionKey } from "./ukyc/wrapEncryptionKey.mjs";
23
- import { clearVendorDisclaimerAcceptance, hasVendorDisclaimerAcceptance, ironDisclaimerIds, recordVendorDisclaimerAcceptance } from "./vendorDisclaimerAcceptance.mjs";
24
- import { clearMoonPaySession, MoonPayFrameHandler } from "./vendors/MoonPayFrameHandler.mjs";
25
23
  // === GENERAL ===
26
24
  export const controllerName = 'KycController';
25
+ const FRAMES_BASE_URL = 'https://blocks.moonpay.com/platform/v1';
26
+ const CHANNEL_CHECK = 'ch_1';
27
+ const CHANNEL_AUTH = 'ch_2';
28
+ const CHANNEL_RESET = 'ch_reset';
27
29
  // Placeholder credentials for the SumSub sub-flow. These are demo values that
28
30
  // must be replaced with real UKYC-issued material before production use.
29
31
  const MOCK_JWT_TOKEN = 'mock-jwt-token';
@@ -114,19 +116,31 @@ const kycControllerMetadata = {
114
116
  persist: false,
115
117
  usedInUi: false,
116
118
  },
117
- vendorDisclaimersAccepted: {
119
+ termsAcceptedAt: {
118
120
  includeInDebugSnapshot: true,
119
121
  includeInStateLogs: true,
120
122
  persist: true,
121
123
  usedInUi: false,
122
124
  },
123
- providerDisclaimersAccepted: {
125
+ acceptedDisclaimerIds: {
124
126
  includeInDebugSnapshot: true,
125
127
  includeInStateLogs: true,
126
128
  persist: true,
127
129
  usedInUi: false,
128
130
  },
129
- idosDisclaimersAccepted: {
131
+ termsAcceptedVendor: {
132
+ includeInDebugSnapshot: true,
133
+ includeInStateLogs: true,
134
+ persist: true,
135
+ usedInUi: false,
136
+ },
137
+ sumsubTncAccepted: {
138
+ includeInDebugSnapshot: true,
139
+ includeInStateLogs: true,
140
+ persist: true,
141
+ usedInUi: false,
142
+ },
143
+ idosTncAccepted: {
130
144
  includeInDebugSnapshot: true,
131
145
  includeInStateLogs: true,
132
146
  persist: true,
@@ -138,13 +152,13 @@ const kycControllerMetadata = {
138
152
  persist: false,
139
153
  usedInUi: false,
140
154
  },
141
- vendorDisclaimers: {
155
+ disclaimers: {
142
156
  includeInDebugSnapshot: false,
143
157
  includeInStateLogs: false,
144
158
  persist: false,
145
159
  usedInUi: true,
146
160
  },
147
- vendorError: {
161
+ disclaimersError: {
148
162
  includeInDebugSnapshot: true,
149
163
  includeInStateLogs: true,
150
164
  persist: false,
@@ -162,13 +176,13 @@ const kycControllerMetadata = {
162
176
  persist: false,
163
177
  usedInUi: true,
164
178
  },
165
- moonpaySessionToken: {
179
+ sessionToken: {
166
180
  includeInDebugSnapshot: false,
167
181
  includeInStateLogs: false,
168
182
  persist: false,
169
183
  usedInUi: false,
170
184
  },
171
- moonpayAccessToken: {
185
+ accessToken: {
172
186
  includeInDebugSnapshot: false,
173
187
  includeInStateLogs: false,
174
188
  persist: false,
@@ -229,17 +243,6 @@ const kycControllerMetadata = {
229
243
  usedInUi: true,
230
244
  },
231
245
  };
232
- /**
233
- * Constructs the default {@link KycVendorDisclaimersAccepted} value.
234
- *
235
- * @returns The default vendor-disclaimer acceptance map.
236
- */
237
- export function getDefaultKycVendorDisclaimersAccepted() {
238
- return { moonpay: null, iron: null };
239
- }
240
- export function getDefaultKycProviderDisclaimersAccepted() {
241
- return { sumsub: null };
242
- }
243
246
  /**
244
247
  * Constructs the default {@link KycController} state.
245
248
  *
@@ -251,16 +254,18 @@ export function getDefaultKycControllerState() {
251
254
  statusMessage: '',
252
255
  error: null,
253
256
  email: null,
254
- vendorDisclaimersAccepted: getDefaultKycVendorDisclaimersAccepted(),
255
- providerDisclaimersAccepted: getDefaultKycProviderDisclaimersAccepted(),
256
- idosDisclaimersAccepted: null,
257
+ termsAcceptedAt: null,
258
+ acceptedDisclaimerIds: [],
259
+ termsAcceptedVendor: null,
260
+ sumsubTncAccepted: null,
261
+ idosTncAccepted: null,
257
262
  credentialReusabilityConsentGiven: null,
258
- vendorDisclaimers: [],
259
- vendorError: null,
263
+ disclaimers: [],
264
+ disclaimersError: null,
260
265
  sessionDisclaimers: null,
261
266
  geoCountry: null,
262
- moonpaySessionToken: null,
263
- moonpayAccessToken: null,
267
+ sessionToken: null,
268
+ accessToken: null,
264
269
  moonpayCustomerId: null,
265
270
  activeVendor: 'moonpay',
266
271
  activeProduct: null,
@@ -304,62 +309,45 @@ function isConsentConflictError(error) {
304
309
  error.httpStatus === 409);
305
310
  }
306
311
  /**
307
- *
308
- * @param value - The value to validate.
309
- * @returns `true` when `value` is a valid consent record list.
310
- */
311
- function isValidConsentRecordList(value) {
312
- return (Array.isArray(value) &&
313
- value.every((item) => typeof item === 'object' &&
314
- item !== null &&
315
- typeof item.key === 'string' &&
316
- typeof item.version === 'string'));
317
- }
318
- /**
319
- * Maps accepted disclaimer records onto unconsented catalog documents.
312
+ * Maps a session-disclaimer catalog into the `{ key, version }` records the
313
+ * record-consents API expects, or an empty list when the user declined that
314
+ * category.
320
315
  *
321
316
  * @param documents - Catalog documents for one consent category.
322
- * @param accepted - Accepted `{ key, version }` records from the caller.
323
- * @returns Consent records to POST, omitting already-consented documents.
317
+ * @param accepted - Whether the user accepted that category.
318
+ * @returns Consent records, or `[]` when not accepted.
324
319
  */
325
- function consentRecordsFromAcceptedList(documents, accepted) {
326
- if (accepted.length === 0) {
320
+ function consentRecordsFromCatalog(documents, accepted) {
321
+ if (!accepted) {
327
322
  return [];
328
323
  }
329
- const acceptedKeys = new Set(accepted.map((record) => `${record.key}:${record.version}`));
330
324
  return documents
331
- .filter((document) => !document.consented &&
332
- acceptedKeys.has(`${document.key}:${document.version}`))
325
+ .filter((document) => !document.consented)
333
326
  .map(({ key, version }) => ({ key, version }));
334
327
  }
335
328
  /**
336
- * Whether accepted disclaimers reference a missing catalog category.
329
+ * Whether an accepted T&C2 category has no catalog documents. An empty list
330
+ * would otherwise skip the POST and count as success.
337
331
  *
338
332
  * @param documents - Catalog documents for one consent category.
339
- * @param accepted - Accepted `{ key, version }` records from the caller.
340
- * @returns `true` when the caller accepted docs but the catalog is empty.
333
+ * @param accepted - Whether the user accepted that category.
334
+ * @returns `true` when the user accepted and the catalog is empty.
341
335
  */
342
336
  function isAcceptedCategoryEmpty(documents, accepted) {
343
- return accepted.length > 0 && documents.length === 0;
337
+ return accepted && documents.length === 0;
344
338
  }
345
339
  /**
346
- * Whether accepted disclaimers are still missing consent after a 409 re-GET:
347
- * empty catalog or any accepted document still unconsented.
340
+ * Whether an accepted category is still missing consent after a 409 re-GET:
341
+ * empty catalog or any document still unconsented.
348
342
  *
349
343
  * @param documents - Latest catalog documents for one consent category.
350
- * @param accepted - Accepted `{ key, version }` records from the caller.
344
+ * @param accepted - Whether the user accepted that category.
351
345
  * @returns `true` when accepted documents are not fully consented.
352
346
  */
353
347
  function acceptedCategoryStillMissing(documents, accepted) {
354
- if (accepted.length === 0) {
355
- return false;
356
- }
357
- if (documents.length === 0) {
358
- return true;
359
- }
360
- const acceptedKeys = new Set(accepted.map((record) => `${record.key}:${record.version}`));
361
- const relevant = documents.filter((document) => acceptedKeys.has(`${document.key}:${document.version}`));
362
- return (relevant.length === 0 || relevant.some((document) => !document.consented));
348
+ return (accepted &&
349
+ (documents.length === 0 ||
350
+ documents.some((document) => !document.consented)));
363
351
  }
364
352
  /**
365
353
  * Vendors other than MoonPay skip Check/Auth frames and use the empty-shell
@@ -395,9 +383,9 @@ const MESSENGER_EXPOSED_METHODS = [
395
383
  /**
396
384
  * `KycController` orchestrates the vendor-backed KYC / identity-verification
397
385
  * flow (MoonPay identity + SumSub documents) behind a vendor-neutral, per
398
- * product surface used by ramps and card. It owns all state and HTTP
399
- * orchestration (via `KycService`), while vendor protocol handling and
400
- * platform-specific presentation (WebView/iframe, SumSub SDK) are delegated.
386
+ * product surface used by ramps and card. It owns all state, HTTP
387
+ * orchestration (via `KycService`), crypto, and the frame message protocol;
388
+ * platform-specific presentation (WebView/iframe, SumSub SDK) is injected.
401
389
  */
402
390
  export class KycController extends BaseController {
403
391
  /**
@@ -421,8 +409,10 @@ export class KycController extends BaseController {
421
409
  });
422
410
  _KycController_instances.add(this);
423
411
  _KycController_sumsubLauncher.set(this, void 0);
424
- /** MoonPay-specific frame protocol and non-persisted credentials. */
425
- _KycController_moonPayFrames.set(this, void 0);
412
+ /** Ephemeral X25519 keypair for the frame key exchange (never persisted). */
413
+ _KycController_keypair.set(this, void 0);
414
+ /** Auth-frame client token, kept out of state. */
415
+ _KycController_authClientToken.set(this, null);
426
416
  /**
427
417
  * Monotonic flow generation. Incremented by {@link reset} and
428
418
  * {@link clearState} so in-flight async work (e.g. the KYC-required check)
@@ -459,13 +449,7 @@ export class KycController extends BaseController {
459
449
  __classPrivateFieldSet(this, _KycController_sumsubLauncher, sumsubLauncher, "f");
460
450
  __classPrivateFieldSet(this, _KycController_sessionStatusPollIntervalMs, sessionStatusPollIntervalMs, "f");
461
451
  __classPrivateFieldSet(this, _KycController_userStatusPollIntervalMs, userStatusPollIntervalMs, "f");
462
- __classPrivateFieldSet(this, _KycController_moonPayFrames, new MoonPayFrameHandler({
463
- getState: () => this.state,
464
- update: (updater) => __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, updater),
465
- fail: (message) => __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, message),
466
- onAuthenticated: async () => __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_continueAfterAuthentication).call(this),
467
- requireTermsReacceptance: () => __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_requireTermsReacceptance).call(this),
468
- }), "f");
452
+ __classPrivateFieldSet(this, _KycController_keypair, generateKeyPair(), "f");
469
453
  this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
470
454
  }
471
455
  /**
@@ -488,19 +472,10 @@ export class KycController extends BaseController {
488
472
  // forces `phase` back through `session`/`check`, breaking an in-flight
489
473
  // Check/Auth frame flow. Leave the active flow untouched and let the
490
474
  // consumer drive it (or call `reset` first to start over).
491
- const vendor = params?.vendor ?? 'moonpay';
492
475
  if (IN_PROGRESS_PHASES.includes(this.state.phase)) {
493
- if (vendor === 'moonpay') {
494
- __classPrivateFieldGet(this, _KycController_moonPayFrames, "f").ensureKeypair();
495
- }
496
476
  return;
497
477
  }
498
- if (vendor === 'moonpay') {
499
- __classPrivateFieldGet(this, _KycController_moonPayFrames, "f").startFlow();
500
- }
501
- else {
502
- __classPrivateFieldGet(this, _KycController_moonPayFrames, "f").clear();
503
- }
478
+ const vendor = params?.vendor ?? 'moonpay';
504
479
  // `initialize` starts a fresh flow, so `activeProduct` is always reset to
505
480
  // this call's product (or `null`). Otherwise a prior run's product could
506
481
  // linger and cause `#continueAfterAuthentication` to auto-run the check /
@@ -510,9 +485,14 @@ export class KycController extends BaseController {
510
485
  state.email = params.email;
511
486
  }
512
487
  state.activeVendor = vendor;
513
- // MoonPay Check/Auth artifacts must not survive a switch to another vendor
488
+ // MoonPay Check/Auth artifacts must not survive a switch to another
489
+ // vendor: leftover `sessionToken` would keep `buildCheckFrameUrl` alive,
490
+ // leftover `accessToken` / `#authClientToken` would keep Auth / KYC
491
+ // calls bound to MoonPay, and leftover `moonpayCustomerId` would make
492
+ // `getCustomerIdentity` report a MoonPay id under the wrong vendor.
514
493
  if (vendor !== 'moonpay') {
515
- clearMoonPaySession(state);
494
+ __classPrivateFieldSet(this, _KycController_authClientToken, null, "f");
495
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearMoonPaySession).call(this, state);
516
496
  }
517
497
  state.activeProduct = params?.product ?? null;
518
498
  });
@@ -560,14 +540,16 @@ export class KycController extends BaseController {
560
540
  if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
561
541
  return;
562
542
  }
563
- const hasTerms = hasVendorDisclaimerAcceptance(this.state.vendorDisclaimersAccepted, vendor);
543
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_dropTermsUnlessForVendor).call(this, vendor);
544
+ const hasTerms = Boolean(this.state.termsAcceptedAt) &&
545
+ this.state.acceptedDisclaimerIds.length > 0;
564
546
  if (hasTerms && this.state.email) {
565
547
  if (usesConsentsFlow(vendor)) {
566
548
  // Consents-path vendors require T&C2 flags; if they weren't persisted
567
549
  // (i.e. null from pre-migration state), require reacceptance.
568
- const { providerDisclaimersAccepted, idosDisclaimersAccepted } = this.state;
569
- if (providerDisclaimersAccepted.sumsub === null ||
570
- idosDisclaimersAccepted === null) {
550
+ const sumsubTncSigned = this.state.sumsubTncAccepted;
551
+ const idosTncSigned = this.state.idosTncAccepted;
552
+ if (sumsubTncSigned === null || idosTncSigned === null) {
571
553
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
572
554
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearAcceptedTerms).call(this, state);
573
555
  state.phase = 'terms';
@@ -576,19 +558,12 @@ export class KycController extends BaseController {
576
558
  return;
577
559
  }
578
560
  await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_startConsentsSession).call(this, {
579
- providerDisclaimersAccepted: providerDisclaimersAccepted.sumsub,
580
- idosDisclaimersAccepted,
561
+ sumsubTncSigned,
562
+ idosTncSigned,
581
563
  credentialReusabilityConsentGiven: this.state.credentialReusabilityConsentGiven ?? false,
582
564
  });
583
565
  }
584
566
  else {
585
- // TODO: should this be here? or should it exist at all?
586
- if (vendor === 'moonpay' && this.state.vendorDisclaimers.length === 0) {
587
- await this.loadDisclaimers();
588
- if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
589
- return;
590
- }
591
- }
592
567
  await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_createSession).call(this);
593
568
  }
594
569
  return;
@@ -622,8 +597,8 @@ export class KycController extends BaseController {
622
597
  // after this request succeeds.
623
598
  state.activeVendor = params.vendor;
624
599
  if (params.vendor !== 'moonpay') {
625
- __classPrivateFieldGet(this, _KycController_moonPayFrames, "f").clear();
626
- clearMoonPaySession(state);
600
+ __classPrivateFieldSet(this, _KycController_authClientToken, null, "f");
601
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearMoonPaySession).call(this, state);
627
602
  }
628
603
  });
629
604
  const generation = __classPrivateFieldGet(this, _KycController_generation, "f");
@@ -632,6 +607,10 @@ export class KycController extends BaseController {
632
607
  vendor: params.vendor,
633
608
  email: params.email,
634
609
  });
610
+ if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
611
+ return;
612
+ }
613
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_dropTermsUnlessForVendor).call(this, params.vendor);
635
614
  }
636
615
  catch (error) {
637
616
  if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
@@ -660,18 +639,18 @@ export class KycController extends BaseController {
660
639
  state.geoCountry = country;
661
640
  });
662
641
  }
663
- const disclaimers = await this.messenger.call('KycService:fetchVendorDisclaimers', {
642
+ const disclaimers = await this.messenger.call('KycService:fetchDisclaimers', {
664
643
  vendor: this.state.activeVendor,
665
644
  country,
666
645
  });
667
646
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
668
- state.vendorDisclaimers = disclaimers;
669
- state.vendorError = null;
647
+ state.disclaimers = disclaimers;
648
+ state.disclaimersError = null;
670
649
  });
671
650
  }
672
651
  catch (error) {
673
652
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
674
- state.vendorError = `Failed to load disclaimers: ${String(error)}`;
653
+ state.disclaimersError = `Failed to load disclaimers: ${String(error)}`;
675
654
  });
676
655
  }
677
656
  }
@@ -684,47 +663,44 @@ export class KycController extends BaseController {
684
663
  * @param params.product - The consuming feature the flow runs for. See
685
664
  * {@link initialize} for how the product drives the automatic post
686
665
  * authentication continuation.
687
- * @param params.providerDisclaimersAccepted - Sumsub disclaimer documents the
688
- * customer accepted (`{ key, version }` records). Required for every vendor
689
- * so callers explicitly declare acceptance.
690
- * @param params.idosDisclaimersAccepted - idOS disclaimer documents the
691
- * customer accepted (`{ key, version }` records). Required for every vendor
692
- * so callers explicitly declare acceptance.
666
+ * @param params.sumsubTncSigned - Whether Sumsub T&C were accepted (T&C2).
667
+ * Required for every vendor so callers explicitly declare acceptance.
668
+ * @param params.idosTncSigned - Whether idOS T&C were accepted (T&C2).
669
+ * Required for every vendor so callers explicitly declare acceptance.
693
670
  * @param params.credentialReusabilityConsentGiven - Whether the customer
694
671
  * consented to reuse existing idOS credentials. Used when recording
695
672
  * session-scoped disclaimers on the consents path. Defaults to `false`.
696
673
  */
697
674
  async acceptTermsAndStartSession(params) {
698
- const providerDisclaimersAccepted = params?.providerDisclaimersAccepted;
699
- const idosDisclaimersAccepted = params?.idosDisclaimersAccepted;
700
- if (!isValidConsentRecordList(providerDisclaimersAccepted) ||
701
- !isValidConsentRecordList(idosDisclaimersAccepted)) {
675
+ const sumsubTncSigned = params?.sumsubTncSigned;
676
+ const idosTncSigned = params?.idosTncSigned;
677
+ if (typeof sumsubTncSigned !== 'boolean' ||
678
+ typeof idosTncSigned !== 'boolean') {
702
679
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing T&C2 acceptance flags.');
703
680
  return;
704
681
  }
705
- const credentialReusabilityConsentGiven = params?.credentialReusabilityConsentGiven ?? false;
682
+ const credentialReusabilityConsentGiven = params.credentialReusabilityConsentGiven ?? false;
706
683
  const termsAcceptedAt = new Date().toISOString();
707
- const disclaimerIds = this.state.vendorDisclaimers.map((disclaimer) => disclaimer.id);
684
+ const disclaimerIds = this.state.disclaimers.map((disclaimer) => disclaimer.id);
708
685
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
709
- if (params?.email) {
686
+ if (params.email) {
710
687
  state.email = params.email;
711
688
  }
712
- if (params?.product) {
689
+ if (params.product) {
713
690
  state.activeProduct = params.product;
714
691
  }
715
- state.vendorDisclaimersAccepted = recordVendorDisclaimerAcceptance(state.vendorDisclaimersAccepted, state.activeVendor, { termsAcceptedAt, disclaimerIds });
716
- state.providerDisclaimersAccepted = {
717
- ...state.providerDisclaimersAccepted,
718
- sumsub: providerDisclaimersAccepted,
719
- };
720
- state.idosDisclaimersAccepted = idosDisclaimersAccepted;
692
+ state.termsAcceptedAt = termsAcceptedAt;
693
+ state.acceptedDisclaimerIds = disclaimerIds;
694
+ state.termsAcceptedVendor = state.activeVendor;
695
+ state.sumsubTncAccepted = sumsubTncSigned;
696
+ state.idosTncAccepted = idosTncSigned;
721
697
  state.credentialReusabilityConsentGiven =
722
698
  credentialReusabilityConsentGiven;
723
699
  });
724
700
  if (usesConsentsFlow(this.state.activeVendor)) {
725
701
  await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_startConsentsSession).call(this, {
726
- providerDisclaimersAccepted,
727
- idosDisclaimersAccepted,
702
+ sumsubTncSigned,
703
+ idosTncSigned,
728
704
  credentialReusabilityConsentGiven,
729
705
  });
730
706
  return;
@@ -736,12 +712,7 @@ export class KycController extends BaseController {
736
712
  */
737
713
  clearSavedTerms() {
738
714
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
739
- state.vendorDisclaimersAccepted =
740
- getDefaultKycVendorDisclaimersAccepted();
741
- state.providerDisclaimersAccepted =
742
- getDefaultKycProviderDisclaimersAccepted();
743
- state.idosDisclaimersAccepted = null;
744
- state.credentialReusabilityConsentGiven = null;
715
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearAcceptedTerms).call(this, state);
745
716
  });
746
717
  }
747
718
  /**
@@ -755,7 +726,68 @@ export class KycController extends BaseController {
755
726
  * @returns An object whose optional `reply` should be posted back.
756
727
  */
757
728
  async handleFrameMessage(params) {
758
- return await __classPrivateFieldGet(this, _KycController_moonPayFrames, "f").handleMessage(params.message);
729
+ const payload = params.message;
730
+ if (!payload) {
731
+ return {};
732
+ }
733
+ if (payload.kind === 'handshake') {
734
+ const channelId = payload.meta?.channelId;
735
+ return { reply: { version: 2, meta: { channelId }, kind: 'ack' } };
736
+ }
737
+ if (payload.kind !== 'complete') {
738
+ return {};
739
+ }
740
+ const channelId = payload.meta?.channelId;
741
+ // Only honor a Check/Auth `complete` for the MoonPay frame the flow is
742
+ // currently waiting on. This drops stale or duplicate messages — e.g. a
743
+ // late post after `reset()` (phase `idle`), after the flow already
744
+ // advanced past this frame, or after a vendor switch — so they cannot
745
+ // resurrect tokens, rewind `phase`, or recapture `moonpayCustomerId` on a
746
+ // controller that has moved on. Frame messages are external input and,
747
+ // unlike the async steps, are not covered by the `#generation` guard.
748
+ let expectedPhase = null;
749
+ if (channelId === CHANNEL_CHECK) {
750
+ expectedPhase = 'check';
751
+ }
752
+ else if (channelId === CHANNEL_AUTH) {
753
+ expectedPhase = 'auth';
754
+ }
755
+ if (!expectedPhase ||
756
+ this.state.phase !== expectedPhase ||
757
+ this.state.activeVendor !== 'moonpay') {
758
+ return {};
759
+ }
760
+ const status = payload.payload?.status;
761
+ const credsEnvelope = payload.payload?.credentials;
762
+ const customerId = payload.payload?.customer?.id ?? null;
763
+ if (customerId) {
764
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
765
+ state.moonpayCustomerId = customerId;
766
+ });
767
+ }
768
+ if (!status) {
769
+ return {};
770
+ }
771
+ let accessToken;
772
+ let clientToken;
773
+ if (credsEnvelope) {
774
+ try {
775
+ const { credentials } = decryptCredentials(credsEnvelope, __classPrivateFieldGet(this, _KycController_keypair, "f").privateKey);
776
+ accessToken = credentials.accessToken;
777
+ clientToken = credentials.clientToken;
778
+ }
779
+ catch (error) {
780
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, `Failed to decrypt frame credentials: ${String(error)}`);
781
+ return {};
782
+ }
783
+ }
784
+ if (channelId === CHANNEL_CHECK) {
785
+ await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_handleCheckOutcome).call(this, status, accessToken, clientToken);
786
+ return {};
787
+ }
788
+ // channelId === CHANNEL_AUTH, guaranteed by the expectedPhase guard above.
789
+ await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_handleAuthOutcome).call(this, status, accessToken);
790
+ return {};
759
791
  }
760
792
  /**
761
793
  * Builds the Check-frame URL, or `null` when no session exists yet.
@@ -763,7 +795,15 @@ export class KycController extends BaseController {
763
795
  * @returns The Check-frame URL or `null`.
764
796
  */
765
797
  buildCheckFrameUrl() {
766
- return __classPrivateFieldGet(this, _KycController_moonPayFrames, "f").buildCheckFrameUrl();
798
+ if (this.state.activeVendor !== 'moonpay' || !this.state.sessionToken) {
799
+ return null;
800
+ }
801
+ const url = new URL(`${FRAMES_BASE_URL}/check-connection`);
802
+ url.searchParams.set('sessionToken', this.state.sessionToken);
803
+ url.searchParams.set('publicKey', __classPrivateFieldGet(this, _KycController_keypair, "f").publicKeyHex);
804
+ url.searchParams.set('channelId', CHANNEL_CHECK);
805
+ url.searchParams.set('skipKyc', 'true');
806
+ return url.toString();
767
807
  }
768
808
  /**
769
809
  * Builds the Auth-frame URL, or `null` when no client token is available.
@@ -771,7 +811,14 @@ export class KycController extends BaseController {
771
811
  * @returns The Auth-frame URL or `null`.
772
812
  */
773
813
  buildAuthFrameUrl() {
774
- return __classPrivateFieldGet(this, _KycController_moonPayFrames, "f").buildAuthFrameUrl();
814
+ if (this.state.activeVendor !== 'moonpay' || !__classPrivateFieldGet(this, _KycController_authClientToken, "f")) {
815
+ return null;
816
+ }
817
+ const url = new URL(`${FRAMES_BASE_URL}/auth`);
818
+ url.searchParams.set('clientToken', __classPrivateFieldGet(this, _KycController_authClientToken, "f"));
819
+ url.searchParams.set('publicKey', __classPrivateFieldGet(this, _KycController_keypair, "f").publicKeyHex);
820
+ url.searchParams.set('channelId', CHANNEL_AUTH);
821
+ return url.toString();
775
822
  }
776
823
  /**
777
824
  * Builds the Reset-frame URL.
@@ -779,7 +826,9 @@ export class KycController extends BaseController {
779
826
  * @returns The Reset-frame URL.
780
827
  */
781
828
  buildResetFrameUrl() {
782
- return __classPrivateFieldGet(this, _KycController_moonPayFrames, "f").buildResetFrameUrl();
829
+ const url = new URL(`${FRAMES_BASE_URL}/reset`);
830
+ url.searchParams.set('channelId', CHANNEL_RESET);
831
+ return url.toString();
783
832
  }
784
833
  /**
785
834
  * Checks whether KYC is required for a product and caches the result.
@@ -790,9 +839,9 @@ export class KycController extends BaseController {
790
839
  * @returns Whether KYC is required.
791
840
  */
792
841
  async checkKycRequired(params) {
793
- const { moonpayAccessToken } = this.state;
794
- if (!moonpayAccessToken) {
795
- __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing moonpayAccessToken — repeat the authentication step.');
842
+ const { accessToken } = this.state;
843
+ if (!accessToken) {
844
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing accessToken — repeat the authentication step.');
796
845
  return false;
797
846
  }
798
847
  const country = params.country ?? this.state.geoCountry;
@@ -808,11 +857,7 @@ export class KycController extends BaseController {
808
857
  state.statusMessage = 'Checking KYC status...';
809
858
  });
810
859
  try {
811
- const { kycRequired } = await this.messenger.call('KycService:checkKycRequired', {
812
- accessToken: moonpayAccessToken,
813
- country,
814
- capabilities: [{ product: params.product }],
815
- });
860
+ const { kycRequired } = await this.messenger.call('KycService:checkKycRequired', { accessToken, country, capabilities: [{ product: params.product }] });
816
861
  // The flow was reset while the check was in flight; discard the result
817
862
  // rather than resurrecting a done/cached state on an idle controller.
818
863
  const applied = __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
@@ -1097,11 +1142,13 @@ export class KycController extends BaseController {
1097
1142
  state.phase = 'idle';
1098
1143
  state.statusMessage = '';
1099
1144
  state.error = null;
1100
- state.vendorDisclaimers = [];
1101
- state.vendorError = null;
1145
+ state.disclaimers = [];
1146
+ state.disclaimersError = null;
1102
1147
  state.sessionDisclaimers = null;
1103
1148
  state.credentialReusabilityConsentGiven = null;
1104
- clearMoonPaySession(state);
1149
+ state.sessionToken = null;
1150
+ state.accessToken = null;
1151
+ state.moonpayCustomerId = null;
1105
1152
  state.activeVendor = 'moonpay';
1106
1153
  state.activeProduct = null;
1107
1154
  state.sumsub = {
@@ -1128,7 +1175,7 @@ export class KycController extends BaseController {
1128
1175
  });
1129
1176
  }
1130
1177
  }
1131
- _KycController_sumsubLauncher = new WeakMap(), _KycController_moonPayFrames = 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() {
1178
+ _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() {
1132
1179
  return {
1133
1180
  get: async (path, entropySourceId) => this.messenger.call('UserStorageController:performGetStorage', path, entropySourceId),
1134
1181
  set: async (path, value, entropySourceId) => this.messenger.call('UserStorageController:performSetStorage', path, value, entropySourceId),
@@ -1140,14 +1187,13 @@ _KycController_sumsubLauncher = new WeakMap(), _KycController_moonPayFrames = ne
1140
1187
  * SumSub — skipping MoonPay Check/Auth frames.
1141
1188
  *
1142
1189
  * @param consents - T&C2 flags mapped onto the session disclaimer catalog.
1143
- * @param consents.providerDisclaimersAccepted - Accepted Sumsub disclaimer records.
1144
- * @param consents.idosDisclaimersAccepted - Accepted idOS disclaimer records.
1190
+ * @param consents.sumsubTncSigned - Whether Sumsub T&C were accepted.
1191
+ * @param consents.idosTncSigned - Whether idOS T&C were accepted.
1145
1192
  * @param consents.credentialReusabilityConsentGiven - Whether credential
1146
1193
  * reuse was accepted.
1147
1194
  */
1148
1195
  async function _KycController_startConsentsSession(consents) {
1149
- const { email } = this.state;
1150
- const acceptedDisclaimerIds = ironDisclaimerIds(this.state.vendorDisclaimersAccepted);
1196
+ const { email, acceptedDisclaimerIds } = this.state;
1151
1197
  if (!email) {
1152
1198
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing email for consents session.');
1153
1199
  return;
@@ -1165,7 +1211,7 @@ async function _KycController_startConsentsSession(consents) {
1165
1211
  state.sumsub.result = null;
1166
1212
  state.sumsub.sessionStatus = null;
1167
1213
  // Consents-path vendors have no MoonPay session/access tokens.
1168
- clearMoonPaySession(state);
1214
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearMoonPaySession).call(this, state);
1169
1215
  });
1170
1216
  try {
1171
1217
  await this.messenger.call('KycService:submitVendorDisclaimers', {
@@ -1191,7 +1237,7 @@ async function _KycController_startConsentsSession(consents) {
1191
1237
  await this.refreshKycStatus();
1192
1238
  }
1193
1239
  catch (statusError) {
1194
- controllerLog('KYC status refresh failed:', statusError);
1240
+ console.error('KYC status refresh failed:', statusError);
1195
1241
  }
1196
1242
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
1197
1243
  state.phase = 'done';
@@ -1227,7 +1273,7 @@ async function _KycController_startConsentsSession(consents) {
1227
1273
  await this.refreshKycStatus();
1228
1274
  }
1229
1275
  catch (statusError) {
1230
- controllerLog('KYC status refresh failed:', statusError);
1276
+ console.error('KYC status refresh failed:', statusError);
1231
1277
  }
1232
1278
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
1233
1279
  if (state.phase !== 'error' && state.phase !== 'done') {
@@ -1255,7 +1301,7 @@ async function _KycController_startConsentsSession(consents) {
1255
1301
  });
1256
1302
  return;
1257
1303
  }
1258
- controllerLog('Consents session failed:', error);
1304
+ console.error('Consents session failed:', error);
1259
1305
  if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
1260
1306
  return;
1261
1307
  }
@@ -1282,8 +1328,8 @@ async function _KycController_startConsentsSession(consents) {
1282
1328
  *
1283
1329
  * @param sessionId - The UKYC session id.
1284
1330
  * @param consents - T&C2 flags mapped onto catalog documents.
1285
- * @param consents.providerDisclaimersAccepted - Accepted Sumsub disclaimer records.
1286
- * @param consents.idosDisclaimersAccepted - Accepted idOS disclaimer records.
1331
+ * @param consents.sumsubTncSigned - Whether Sumsub T&C were accepted.
1332
+ * @param consents.idosTncSigned - Whether idOS T&C were accepted.
1287
1333
  * @param consents.credentialReusabilityConsentGiven - Whether credential
1288
1334
  * reuse was accepted.
1289
1335
  * @param generation - Flow generation captured by the caller.
@@ -1297,12 +1343,12 @@ async function _KycController_recordSessionDisclaimers(sessionId, consents, gene
1297
1343
  state.sessionDisclaimers = catalog;
1298
1344
  state.statusMessage = 'Submitting consents...';
1299
1345
  });
1300
- if (isAcceptedCategoryEmpty(catalog.idOS, consents.idosDisclaimersAccepted) ||
1301
- isAcceptedCategoryEmpty(catalog.kycProvider, consents.providerDisclaimersAccepted)) {
1346
+ if (isAcceptedCategoryEmpty(catalog.idOS, consents.idosTncSigned) ||
1347
+ isAcceptedCategoryEmpty(catalog.kycProvider, consents.sumsubTncSigned)) {
1302
1348
  throw new Error('Session disclaimer catalog is missing documents for an accepted category.');
1303
1349
  }
1304
- const idOS = consentRecordsFromAcceptedList(catalog.idOS, consents.idosDisclaimersAccepted);
1305
- const kycProvider = consentRecordsFromAcceptedList(catalog.kycProvider, consents.providerDisclaimersAccepted);
1350
+ const idOS = consentRecordsFromCatalog(catalog.idOS, consents.idosTncSigned);
1351
+ const kycProvider = consentRecordsFromCatalog(catalog.kycProvider, consents.sumsubTncSigned);
1306
1352
  const reuseUnchanged = catalog.credentialReusabilityConsentGiven ===
1307
1353
  consents.credentialReusabilityConsentGiven;
1308
1354
  if (idOS.length === 0 && kycProvider.length === 0 && reuseUnchanged) {
@@ -1333,9 +1379,8 @@ async function _KycController_recordSessionDisclaimers(sessionId, consents, gene
1333
1379
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1334
1380
  state.sessionDisclaimers = latest;
1335
1381
  });
1336
- // TODO: Should we really be doing client side validation of these?
1337
- const stillMissingIdos = acceptedCategoryStillMissing(latest.idOS, consents.idosDisclaimersAccepted);
1338
- const stillMissingProvider = acceptedCategoryStillMissing(latest.kycProvider, consents.providerDisclaimersAccepted);
1382
+ const stillMissingIdos = acceptedCategoryStillMissing(latest.idOS, consents.idosTncSigned);
1383
+ const stillMissingProvider = acceptedCategoryStillMissing(latest.kycProvider, consents.sumsubTncSigned);
1339
1384
  const stillMissingReuse = consents.credentialReusabilityConsentGiven &&
1340
1385
  !latest.credentialReusabilityConsentGiven;
1341
1386
  if (stillMissingIdos || stillMissingProvider || stillMissingReuse) {
@@ -1347,9 +1392,7 @@ async function _KycController_recordSessionDisclaimers(sessionId, consents, gene
1347
1392
  * Creates a vendor session from the currently stored terms + email.
1348
1393
  */
1349
1394
  async function _KycController_createSession() {
1350
- const { email } = this.state;
1351
- const termsAcceptedAt = this.state.vendorDisclaimersAccepted.moonpay?.termsAcceptedAt;
1352
- const acceptedDisclaimerIds = this.state.vendorDisclaimers.map((disclaimer) => disclaimer.id);
1395
+ const { email, termsAcceptedAt, acceptedDisclaimerIds } = this.state;
1353
1396
  if (!email) {
1354
1397
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, 'Missing email for session creation.');
1355
1398
  return;
@@ -1364,7 +1407,7 @@ async function _KycController_createSession() {
1364
1407
  // (or, on failure, invalid) session token, `buildAuthFrameUrl` cannot
1365
1408
  // return a URL tied to an old client token, and `checkKycRequired` cannot
1366
1409
  // run with an access token from an earlier authentication. The Check/Auth
1367
- // frames re-populate these for the new session. Because `moonpaySessionToken` is
1410
+ // frames re-populate these for the new session. Because `sessionToken` is
1368
1411
  // cleared here and only re-set on success, a failed creation leaves it
1369
1412
  // `null` rather than resurrecting the previous session.
1370
1413
  // Capture the flow generation so a `reset()` landing while the create
@@ -1372,24 +1415,24 @@ async function _KycController_createSession() {
1372
1415
  // the now-idle controller (failure). The synchronous update below runs
1373
1416
  // before any `await`, so it needs no guard.
1374
1417
  const generation = __classPrivateFieldGet(this, _KycController_generation, "f");
1375
- __classPrivateFieldGet(this, _KycController_moonPayFrames, "f").clearAuthentication();
1418
+ __classPrivateFieldSet(this, _KycController_authClientToken, null, "f");
1376
1419
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1377
1420
  state.error = null;
1378
1421
  state.phase = 'session';
1379
1422
  state.statusMessage = 'Creating session...';
1380
- state.moonpaySessionToken = null;
1381
- state.moonpayAccessToken = null;
1423
+ state.sessionToken = null;
1424
+ state.accessToken = null;
1382
1425
  });
1383
1426
  try {
1384
1427
  const { sessionToken } = await this.messenger.call('KycService:createSession', { email, termsAcceptedAt, disclaimerIds: acceptedDisclaimerIds });
1385
1428
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_updateIfCurrent).call(this, generation, (state) => {
1386
- state.moonpaySessionToken = sessionToken;
1429
+ state.sessionToken = sessionToken;
1387
1430
  state.phase = 'check';
1388
1431
  state.statusMessage = 'Authenticating via Check frame...';
1389
1432
  });
1390
1433
  }
1391
1434
  catch (error) {
1392
- controllerLog('Session creation failed:', error);
1435
+ console.error('Session creation failed:', error);
1393
1436
  // A reset() superseded this flow while the request was in flight; leave
1394
1437
  // the idle controller alone rather than forcing it back to `terms`.
1395
1438
  if (__classPrivateFieldGet(this, _KycController_generation, "f") !== generation) {
@@ -1409,13 +1452,82 @@ async function _KycController_createSession() {
1409
1452
  });
1410
1453
  await this.loadDisclaimers();
1411
1454
  }
1412
- }, _KycController_clearAcceptedTerms = function _KycController_clearAcceptedTerms(state, vendor) {
1413
- const targetVendor = vendor ?? state.activeVendor;
1414
- state.vendorDisclaimersAccepted = clearVendorDisclaimerAcceptance(state.vendorDisclaimersAccepted, targetVendor);
1415
- state.providerDisclaimersAccepted =
1416
- getDefaultKycProviderDisclaimersAccepted();
1417
- state.idosDisclaimersAccepted = null;
1455
+ }, _KycController_clearAcceptedTerms = function _KycController_clearAcceptedTerms(state) {
1456
+ state.termsAcceptedAt = null;
1457
+ state.acceptedDisclaimerIds = [];
1458
+ state.termsAcceptedVendor = null;
1459
+ state.sumsubTncAccepted = null;
1460
+ state.idosTncAccepted = null;
1418
1461
  state.credentialReusabilityConsentGiven = null;
1462
+ }, _KycController_clearMoonPaySession = function _KycController_clearMoonPaySession(state) {
1463
+ state.moonpayCustomerId = null;
1464
+ state.sessionToken = null;
1465
+ state.accessToken = null;
1466
+ }, _KycController_dropTermsUnlessForVendor = function _KycController_dropTermsUnlessForVendor(vendor) {
1467
+ if (__classPrivateFieldGet(this, _KycController_instances, "m", _KycController_hasTermsForVendor).call(this, vendor)) {
1468
+ return;
1469
+ }
1470
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1471
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_clearAcceptedTerms).call(this, state);
1472
+ });
1473
+ }, _KycController_hasTermsForVendor = function _KycController_hasTermsForVendor(vendor) {
1474
+ if (this.state.termsAcceptedVendor === null) {
1475
+ return false;
1476
+ }
1477
+ return this.state.termsAcceptedVendor === vendor;
1478
+ }, _KycController_handleCheckOutcome =
1479
+ /**
1480
+ * Applies a Check-frame outcome.
1481
+ *
1482
+ * @param status - The frame status.
1483
+ * @param accessToken - The decrypted access token, if any.
1484
+ * @param clientToken - The decrypted client token, if any.
1485
+ */
1486
+ async function _KycController_handleCheckOutcome(status, accessToken, clientToken) {
1487
+ if (status === 'active' && accessToken) {
1488
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1489
+ state.accessToken = accessToken;
1490
+ state.phase = 'form';
1491
+ state.statusMessage = 'Already authenticated. Review to submit.';
1492
+ });
1493
+ await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_continueAfterAuthentication).call(this);
1494
+ return;
1495
+ }
1496
+ if (status === 'connectionRequired' && clientToken) {
1497
+ __classPrivateFieldSet(this, _KycController_authClientToken, clientToken, "f");
1498
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1499
+ state.phase = 'auth';
1500
+ state.statusMessage = 'Verify your email via OTP in the Auth frame.';
1501
+ });
1502
+ return;
1503
+ }
1504
+ if (status === 'termsAcceptanceRequired') {
1505
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_requireTermsReacceptance).call(this);
1506
+ return;
1507
+ }
1508
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, `Check frame returned status: ${status}`);
1509
+ }, _KycController_handleAuthOutcome =
1510
+ /**
1511
+ * Applies an Auth-frame outcome.
1512
+ *
1513
+ * @param status - The frame status.
1514
+ * @param accessToken - The decrypted access token, if any.
1515
+ */
1516
+ async function _KycController_handleAuthOutcome(status, accessToken) {
1517
+ if (status === 'active' && accessToken) {
1518
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_applyUpdate).call(this, (state) => {
1519
+ state.accessToken = accessToken;
1520
+ state.phase = 'form';
1521
+ state.statusMessage = 'Authenticated. Review to submit.';
1522
+ });
1523
+ await __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_continueAfterAuthentication).call(this);
1524
+ return;
1525
+ }
1526
+ if (status === 'termsAcceptanceRequired') {
1527
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_requireTermsReacceptance).call(this);
1528
+ return;
1529
+ }
1530
+ __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_fail).call(this, `Auth frame returned status: ${status}`);
1419
1531
  }, _KycController_continueAfterAuthentication =
1420
1532
  /**
1421
1533
  * Continues the flow once authentication has completed (phase `form`).
@@ -1467,7 +1579,7 @@ async function _KycController_continueAfterAuthentication() {
1467
1579
  return {
1468
1580
  vendor: 'moonpay',
1469
1581
  vendorMetadata: {
1470
- moonPayAccessToken: this.state.moonpayAccessToken,
1582
+ moonPayAccessToken: this.state.accessToken,
1471
1583
  moonPayUserId: this.state.moonpayCustomerId,
1472
1584
  },
1473
1585
  };
@@ -1535,8 +1647,7 @@ async function _KycController_createUkycSession(generation) {
1535
1647
  // authorizes later storage reads without granting write or delete access.
1536
1648
  const ukycCapabilityToken = signStorageAccessToken({
1537
1649
  material: clientMaterial,
1538
- // TODO: Confirm with idOS when this can be switched back to read and a separate token is sent for write
1539
- operations: ['read', 'write'],
1650
+ operations: ['read'],
1540
1651
  expiresAt: new Date(Date.now() + UKYC_CAPABILITY_TOKEN_TTL_MS),
1541
1652
  });
1542
1653
  const wrappedUkycCapabilityToken = wrapEncryptionKey(sessionClientPrivateKey, capabilityTokenSchema.serverPublicKey.x, stringToBytes(encodeStorageAccessTokenForHeader(ukycCapabilityToken)));
@@ -1723,7 +1834,7 @@ async function _KycController_pollSessionStatusOnce(sessionId, token) {
1723
1834
  __classPrivateFieldSet(this, _KycController_pollTimer, null, "f");
1724
1835
  }
1725
1836
  }, _KycController_cancelPendingSession = function _KycController_cancelPendingSession() {
1726
- __classPrivateFieldGet(this, _KycController_moonPayFrames, "f").clear();
1837
+ __classPrivateFieldSet(this, _KycController_authClientToken, null, "f");
1727
1838
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_stopPolling).call(this);
1728
1839
  __classPrivateFieldGet(this, _KycController_instances, "m", _KycController_stopUserStatusPolling).call(this);
1729
1840
  __classPrivateFieldSet(this, _KycController_generation, __classPrivateFieldGet(this, _KycController_generation, "f") + 1, "f");