@getpara/core-sdk 3.3.0 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -431,7 +431,7 @@ const _ParaCore = class _ParaCore {
431
431
  this.addCredential = (params) => __async(this, null, function* () {
432
432
  return yield __privateGet(this, _authService).addCredential(params);
433
433
  });
434
- var _a;
434
+ var _a, _b, _c;
435
435
  let env, apiKey;
436
436
  const actualArgs = Array.from(arguments).filter((arg) => arg !== void 0);
437
437
  const actualArgumentCount = actualArgs.length;
@@ -518,6 +518,7 @@ const _ParaCore = class _ParaCore {
518
518
  };
519
519
  const rawPlatform = (_a = opts.hostPlatform) != null ? _a : this.platformUtils.sdkType;
520
520
  this.clientType = (0, import_userManagementClient.normalizePlatform)(rawPlatform);
521
+ const requestAgents = (_c = (_b = this.platformUtils).getRequestAgents) == null ? void 0 : _c.call(_b);
521
522
  const client = (0, import_userManagementClient.initClient)({
522
523
  env,
523
524
  version: _ParaCore.version,
@@ -528,7 +529,9 @@ const _ParaCore = class _ParaCore {
528
529
  platform: rawPlatform,
529
530
  useFetchAdapter: !!opts.disableWorkers,
530
531
  retrieveSessionCookie: this.retrieveSessionCookie,
531
- persistSessionCookie: this.persistSessionCookie
532
+ persistSessionCookie: this.persistSessionCookie,
533
+ httpAgent: requestAgents == null ? void 0 : requestAgents.httpAgent,
534
+ httpsAgent: requestAgents == null ? void 0 : requestAgents.httpsAgent
532
535
  });
533
536
  const enclaveClient = new import_enclave.EnclaveClient({
534
537
  userManagementClient: client,
@@ -1822,6 +1825,37 @@ const _ParaCore = class _ParaCore {
1822
1825
  yield this.ctx.client.enable2FA(userId, verificationCode);
1823
1826
  });
1824
1827
  }
1828
+ /**
1829
+ * Login-time 2FA (ENG-6906): enroll a TOTP second factor for the current session.
1830
+ * Distinct from setup2fa/enable2fa, which configure the recovery-gating 2FA. This
1831
+ * is authenticated by the active session (no recovery config gate); the backend
1832
+ * 404s the surface when the login-MFA flag is off.
1833
+ *
1834
+ * @returns {Object} `{ uri, backupCodes }` — otpauth URI to render as a QR, plus
1835
+ * one-time backup codes to show the user exactly once.
1836
+ */
1837
+ enrollMfa() {
1838
+ return __async(this, null, function* () {
1839
+ yield __privateMethod(this, _ParaCore_instances, assertPartner_fn).call(this);
1840
+ return yield __privateGet(this, _authService).enrollMfa();
1841
+ });
1842
+ }
1843
+ /**
1844
+ * Login-time 2FA (ENG-6906): verify the second factor for the current login. On
1845
+ * success the backend stamps the session and this re-polls the login status so the
1846
+ * flow advances toward `done`; a wrong code resolves to `{ ok:false, attemptsRemaining }`
1847
+ * so the UI can re-prompt without treating it as a hard error.
1848
+ *
1849
+ * @param {Object} opts the options object.
1850
+ * @param {string} opts.code the TOTP or backup code entered by the user.
1851
+ * @returns {Object} `{ ok: true } | { ok: false; attemptsRemaining? }`
1852
+ */
1853
+ verifyMfa(_0) {
1854
+ return __async(this, arguments, function* ({ code }) {
1855
+ yield __privateMethod(this, _ParaCore_instances, assertPartner_fn).call(this);
1856
+ return yield __privateGet(this, _authService).verifyMfa({ code });
1857
+ });
1858
+ }
1825
1859
  /**
1826
1860
  * Resend a verification email for the current user.
1827
1861
  */
@@ -46,7 +46,7 @@ __export(constants_exports, {
46
46
  TRANSACTION_REVIEW_TIMEOUT_MS: () => TRANSACTION_REVIEW_TIMEOUT_MS
47
47
  });
48
48
  module.exports = __toCommonJS(constants_exports);
49
- const PARA_CORE_VERSION = "3.3.0";
49
+ const PARA_CORE_VERSION = "3.5.0";
50
50
  const PREFIX = "@CAPSULE/";
51
51
  const PARA_PREFIX = "@PARA/";
52
52
  const LOCAL_STORAGE_AUTH_INFO = `${PREFIX}authInfo`;
@@ -124,7 +124,9 @@ function initClient({
124
124
  useFetchAdapter = false,
125
125
  retrieveSessionCookie,
126
126
  persistSessionCookie,
127
- staticTraceContext
127
+ staticTraceContext,
128
+ httpAgent,
129
+ httpsAgent
128
130
  }) {
129
131
  return new import_user_management_client.default({
130
132
  userManagementHost: getBaseUrl(env),
@@ -135,7 +137,9 @@ function initClient({
135
137
  opts: { useFetchAdapter },
136
138
  retrieveSessionCookie,
137
139
  persistSessionCookie,
138
- staticTraceContext
140
+ staticTraceContext,
141
+ httpAgent,
142
+ httpsAgent
139
143
  });
140
144
  }
141
145
  // Annotate the CommonJS export names for ESM import in node:
@@ -238,6 +238,11 @@ class AuthService {
238
238
  JSON.stringify(isSLOPossible)
239
239
  );
240
240
  return serverAuthState;
241
+ // No preparation needed
242
+ case "mfa":
243
+ return serverAuthState;
244
+ default:
245
+ return serverAuthState;
241
246
  }
242
247
  });
243
248
  this.prepareLoginState = (_0, _1) => __async(this, [_0, _1], function* (loginState, { useShortUrls: shorten = false, portalTheme, sessionLookupId }) {
@@ -489,10 +494,46 @@ class AuthService {
489
494
  return yield (0, import_stateListener.waitForAuthStateChange)({
490
495
  stateManager: __privateGet(this, _stateManager),
491
496
  resolvePhases: [
492
- { phase: "awaiting_session_start", onPhase: (state) => state.authStateResult }
497
+ { phase: "awaiting_session_start", onPhase: (state) => state.authStateResult },
498
+ // Login-time 2FA (ENG-6906): the OAuth poll surfaced an mfa challenge instead
499
+ // of completing. Resolve here so the caller stops blocking; the challenge is
500
+ // read from the consumer auth state (AuthStateInfo.mfa) and satisfied via the
501
+ // enroll/verify hooks, which fire RESOLVE_2FA to continue the flow.
502
+ { phase: "awaiting_2fa", onPhase: (state) => state.authStateResult },
503
+ { phase: "awaiting_2fa_enrollment", onPhase: (state) => state.authStateResult }
493
504
  ]
494
505
  });
495
506
  });
507
+ /**
508
+ * Login-time 2FA (ENG-6906): after the second factor has been satisfied/enrolled
509
+ * server-side, re-poll the login status to advance the flow. Fires RESOLVE_2FA,
510
+ * which re-enters verify-oauth polling (now returning stage:'done') and routes
511
+ * onward to awaiting_session_start / authenticated.
512
+ */
513
+ this.resolveMfa = (pollingCallbacks) => __async(this, null, function* () {
514
+ __privateGet(this, _stateManager).send({ type: "RESOLVE_2FA", data: pollingCallbacks });
515
+ return yield (0, import_stateListener.waitForAuthStateChange)({
516
+ stateManager: __privateGet(this, _stateManager),
517
+ resolvePhases: [
518
+ { phase: "awaiting_session_start", onPhase: (state) => state.authStateResult },
519
+ { phase: "authenticated", onPhase: (state) => state.authStateResult }
520
+ ],
521
+ // If re-polling after the second factor lands in the auth error phase, reject fast
522
+ // with a clear message instead of stalling until the listener's default timeout. The
523
+ // caller stays parked at awaiting_2fa and can re-prompt/retry. (ENG-6906)
524
+ rejectPhases: [{ phase: "error", onPhase: () => new Error("Login 2FA resolution failed") }]
525
+ });
526
+ });
527
+ this.enrollMfa = () => __async(this, null, function* () {
528
+ return yield __privateGet(this, _paraCoreInterface).ctx.client.enrollMfa();
529
+ });
530
+ this.verifyMfa = (_0) => __async(this, [_0], function* ({ code }) {
531
+ const result = yield __privateGet(this, _paraCoreInterface).ctx.client.verifyMfa(code);
532
+ if (result.ok) {
533
+ yield this.resolveMfa();
534
+ }
535
+ return result;
536
+ });
496
537
  this.authenticateWithOAuth = (params) => __async(this, null, function* () {
497
538
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
498
539
  switch (params.method) {
@@ -115,7 +115,7 @@ const _CoreStateManager = class _CoreStateManager {
115
115
  * Extracts all data needed by UI consumers from authStateResult.
116
116
  */
117
117
  computeAuthStateInfo(authContext, walletContext) {
118
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L;
118
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q;
119
119
  const defaultAuthStateInfo = {
120
120
  userId: null,
121
121
  isPasskeySupported: false,
@@ -137,6 +137,7 @@ const _CoreStateManager = class _CoreStateManager {
137
137
  fallbackUsed: false,
138
138
  fallbackChannel: null,
139
139
  externalWalletVerification: null,
140
+ mfa: null,
140
141
  recoverySecret: null,
141
142
  isNewUser: false
142
143
  };
@@ -178,6 +179,7 @@ const _CoreStateManager = class _CoreStateManager {
178
179
  let deliveryChannel = null;
179
180
  let fallbackUsed = false;
180
181
  let fallbackChannel = null;
182
+ let mfa = null;
181
183
  if (stage === "login") {
182
184
  const loginState = authStateResult;
183
185
  const authMethods = (_j = loginState.loginAuthMethods) != null ? _j : [];
@@ -214,6 +216,17 @@ const _CoreStateManager = class _CoreStateManager {
214
216
  deliveryChannel = (_E = verifyState.deliveryChannel) != null ? _E : null;
215
217
  fallbackUsed = (_F = verifyState.fallbackUsed) != null ? _F : false;
216
218
  fallbackChannel = (_G = verifyState.fallbackChannel) != null ? _G : null;
219
+ } else if (stage === "mfa") {
220
+ const { mfa: challenge } = authStateResult;
221
+ mfa = {
222
+ mode: challenge.mode,
223
+ step: challenge.step,
224
+ methods: (_H = challenge.methods) != null ? _H : null,
225
+ attemptsRemaining: (_I = challenge.attemptsRemaining) != null ? _I : null,
226
+ lockedUntil: (_J = challenge.lockedUntil) != null ? _J : null,
227
+ secretUri: (_K = challenge.secretUri) != null ? _K : null,
228
+ backupCodes: (_L = challenge.backupCodes) != null ? _L : null
229
+ };
217
230
  }
218
231
  return {
219
232
  userId,
@@ -236,10 +249,11 @@ const _CoreStateManager = class _CoreStateManager {
236
249
  fallbackUsed,
237
250
  fallbackChannel,
238
251
  externalWalletVerification: externalWalletVerification ? {
239
- signatureVerificationMessage: (_H = externalWalletVerification.signatureVerificationMessage) != null ? _H : "",
240
- walletAddress: (_J = (_I = externalWalletVerification.externalWallet) == null ? void 0 : _I.address) != null ? _J : "",
241
- walletType: (_L = (_K = externalWalletVerification.externalWallet) == null ? void 0 : _K.type) != null ? _L : ""
252
+ signatureVerificationMessage: (_M = externalWalletVerification.signatureVerificationMessage) != null ? _M : "",
253
+ walletAddress: (_O = (_N = externalWalletVerification.externalWallet) == null ? void 0 : _N.address) != null ? _O : "",
254
+ walletType: (_Q = (_P = externalWalletVerification.externalWallet) == null ? void 0 : _P.type) != null ? _Q : ""
242
255
  } : null,
256
+ mfa,
243
257
  recoverySecret,
244
258
  isNewUser
245
259
  };
@@ -300,10 +314,19 @@ const _CoreStateManager = class _CoreStateManager {
300
314
  }
301
315
  authStateInfoEqual(a, b) {
302
316
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
303
- return a.userId === b.userId && a.isPasskeySupported === b.isPasskeySupported && a.hasPasskey === b.hasPasskey && a.hasPassword === b.hasPassword && a.hasPin === b.hasPin && a.passkeyUrl === b.passkeyUrl && a.passkeyFullUrl === b.passkeyFullUrl && a.passkeyKnownDeviceUrl === b.passkeyKnownDeviceUrl && a.passwordUrl === b.passwordUrl && a.passwordFullUrl === b.passwordFullUrl && a.pinUrl === b.pinUrl && a.pinFullUrl === b.pinFullUrl && a.passkeyId === b.passkeyId && a.verificationUrl === b.verificationUrl && a.verificationFullUrl === b.verificationFullUrl && a.deliveryChannel === b.deliveryChannel && a.fallbackUsed === b.fallbackUsed && a.fallbackChannel === b.fallbackChannel && a.recoverySecret === b.recoverySecret && a.isNewUser === b.isNewUser && ((_a = a.externalWalletVerification) == null ? void 0 : _a.signatureVerificationMessage) === ((_b = b.externalWalletVerification) == null ? void 0 : _b.signatureVerificationMessage) && ((_c = a.externalWalletVerification) == null ? void 0 : _c.walletAddress) === ((_d = b.externalWalletVerification) == null ? void 0 : _d.walletAddress) && ((_e = a.externalWalletVerification) == null ? void 0 : _e.walletType) === ((_f = b.externalWalletVerification) == null ? void 0 : _f.walletType) && ((_g = a.passkeyHints) == null ? void 0 : _g.length) === ((_h = b.passkeyHints) == null ? void 0 : _h.length) && ((_i = a.passkeyHints) != null ? _i : []).every(
317
+ return a.userId === b.userId && a.isPasskeySupported === b.isPasskeySupported && a.hasPasskey === b.hasPasskey && a.hasPassword === b.hasPassword && a.hasPin === b.hasPin && a.passkeyUrl === b.passkeyUrl && a.passkeyFullUrl === b.passkeyFullUrl && a.passkeyKnownDeviceUrl === b.passkeyKnownDeviceUrl && a.passwordUrl === b.passwordUrl && a.passwordFullUrl === b.passwordFullUrl && a.pinUrl === b.pinUrl && a.pinFullUrl === b.pinFullUrl && a.passkeyId === b.passkeyId && a.verificationUrl === b.verificationUrl && a.verificationFullUrl === b.verificationFullUrl && a.deliveryChannel === b.deliveryChannel && a.fallbackUsed === b.fallbackUsed && a.fallbackChannel === b.fallbackChannel && a.recoverySecret === b.recoverySecret && a.isNewUser === b.isNewUser && ((_a = a.externalWalletVerification) == null ? void 0 : _a.signatureVerificationMessage) === ((_b = b.externalWalletVerification) == null ? void 0 : _b.signatureVerificationMessage) && ((_c = a.externalWalletVerification) == null ? void 0 : _c.walletAddress) === ((_d = b.externalWalletVerification) == null ? void 0 : _d.walletAddress) && ((_e = a.externalWalletVerification) == null ? void 0 : _e.walletType) === ((_f = b.externalWalletVerification) == null ? void 0 : _f.walletType) && this.mfaEqual(a.mfa, b.mfa) && ((_g = a.passkeyHints) == null ? void 0 : _g.length) === ((_h = b.passkeyHints) == null ? void 0 : _h.length) && ((_i = a.passkeyHints) != null ? _i : []).every(
304
318
  (hint, i) => hint.useragent === b.passkeyHints[i].useragent && hint.aaguid === b.passkeyHints[i].aaguid
305
319
  );
306
320
  }
321
+ mfaEqual(a, b) {
322
+ if (a === b) return true;
323
+ if (!a || !b) return false;
324
+ const sameStringArray = (x, y) => {
325
+ var _a, _b;
326
+ return ((_a = x == null ? void 0 : x.length) != null ? _a : -1) === ((_b = y == null ? void 0 : y.length) != null ? _b : -1) && (x != null ? x : []).every((v, i) => v === y[i]);
327
+ };
328
+ return a.mode === b.mode && a.step === b.step && a.attemptsRemaining === b.attemptsRemaining && a.lockedUntil === b.lockedUntil && a.secretUri === b.secretUri && sameStringArray(a.methods, b.methods) && sameStringArray(a.backupCodes, b.backupCodes);
329
+ }
307
330
  };
308
331
  _CoreStateManager.CORE_LOADING_STATES = /* @__PURE__ */ new Set([
309
332
  "setting_up",
@@ -317,7 +340,11 @@ _CoreStateManager.AUTH_LOADING_STATES = /* @__PURE__ */ new Set([
317
340
  "authenticating_farcaster",
318
341
  "processing_authentication",
319
342
  "authenticating_telegram",
320
- "checking_state"
343
+ "checking_state",
344
+ // Re-polling the login status after the second factor is satisfied (ENG-6906).
345
+ // awaiting_2fa / awaiting_2fa_enrollment are deliberately NOT loading — they are
346
+ // user-input holds where the UI shows the MFA prompt.
347
+ "resolving_2fa"
321
348
  ]);
322
349
  _CoreStateManager.WALLET_LOADING_STATES = /* @__PURE__ */ new Set([
323
350
  "checking_wallet_state",
@@ -756,18 +756,18 @@ function createAuthStateMachine(paraCoreInterface) {
756
756
  guard: (0, import_xstate.and)([
757
757
  ({ event }) => {
758
758
  const output = event.output;
759
- return !!output.externalWallet;
759
+ return !!(output == null ? void 0 : output.externalWallet);
760
760
  },
761
761
  (0, import_xstate.or)([
762
762
  ({ event }) => {
763
763
  var _a;
764
764
  const output = event.output;
765
- return output.stage === "done" && !((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
765
+ return (output == null ? void 0 : output.stage) === "done" && !((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
766
766
  },
767
767
  ({ event }) => {
768
768
  var _a, _b;
769
769
  const output = event.output;
770
- return output.stage === "verify" && !((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth) && !((_b = output.externalWallet) == null ? void 0 : _b.withVerification);
770
+ return (output == null ? void 0 : output.stage) === "verify" && !((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth) && !((_b = output == null ? void 0 : output.externalWallet) == null ? void 0 : _b.withVerification);
771
771
  }
772
772
  ])
773
773
  ])
@@ -784,12 +784,12 @@ function createAuthStateMachine(paraCoreInterface) {
784
784
  guard: (0, import_xstate.and)([
785
785
  ({ event }) => {
786
786
  const output = event.output;
787
- return !!output.externalWallet;
787
+ return !!(output == null ? void 0 : output.externalWallet);
788
788
  },
789
789
  ({ event }) => {
790
790
  var _a, _b;
791
791
  const output = event.output;
792
- return output.stage === "verify" && !((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth) && ((_b = output.externalWallet) == null ? void 0 : _b.withVerification);
792
+ return (output == null ? void 0 : output.stage) === "verify" && !((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth) && ((_b = output == null ? void 0 : output.externalWallet) == null ? void 0 : _b.withVerification);
793
793
  }
794
794
  ])
795
795
  },
@@ -805,12 +805,12 @@ function createAuthStateMachine(paraCoreInterface) {
805
805
  guard: (0, import_xstate.and)([
806
806
  ({ event }) => {
807
807
  const output = event.output;
808
- return !!output.externalWallet;
808
+ return !!(output == null ? void 0 : output.externalWallet);
809
809
  },
810
810
  ({ event }) => {
811
811
  var _a;
812
812
  const output = event.output;
813
- return output.stage === "verify" && !!((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
813
+ return (output == null ? void 0 : output.stage) === "verify" && !!((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
814
814
  }
815
815
  ])
816
816
  },
@@ -824,11 +824,37 @@ function createAuthStateMachine(paraCoreInterface) {
824
824
  ({ event }) => {
825
825
  var _a;
826
826
  const output = event.output;
827
- return output.stage === "verify" && !((_a = output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
827
+ return (output == null ? void 0 : output.stage) === "verify" && !((_a = output == null ? void 0 : output.externalWallet) == null ? void 0 : _a.withFullParaAuth);
828
828
  },
829
829
  () => !paraCoreInterface.authService.isEnclaveUser
830
830
  ])
831
831
  },
832
+ // Login-time 2FA (ENG-6906): the server gated the login behind a second
833
+ // factor. Enrollment (no factor yet) and verification (existing factor)
834
+ // are surfaced as distinct phases so a custom UI can show the right step.
835
+ {
836
+ target: "awaiting_2fa_enrollment",
837
+ actions: [
838
+ "storeAuthStateResult",
839
+ { type: "logTransition", params: { to: "awaiting_2fa_enrollment", detail: "mfa enroll" } }
840
+ ],
841
+ guard: ({ event }) => {
842
+ var _a;
843
+ const output = event.output;
844
+ return (output == null ? void 0 : output.stage) === "mfa" && ((_a = output == null ? void 0 : output.mfa) == null ? void 0 : _a.mode) === "enroll";
845
+ }
846
+ },
847
+ {
848
+ target: "awaiting_2fa",
849
+ actions: [
850
+ "storeAuthStateResult",
851
+ { type: "logTransition", params: { to: "awaiting_2fa", detail: "mfa verify" } }
852
+ ],
853
+ guard: ({ event }) => {
854
+ const output = event.output;
855
+ return (output == null ? void 0 : output.stage) === "mfa";
856
+ }
857
+ },
832
858
  {
833
859
  target: "awaiting_session_start",
834
860
  actions: [
@@ -871,6 +897,77 @@ function createAuthStateMachine(paraCoreInterface) {
871
897
  CANCEL: { target: "unauthenticated", actions: ["resetState"] }
872
898
  }
873
899
  },
900
+ // Login-time 2FA hold states (ENG-6906). The SDK satisfies the second factor
901
+ // out-of-band (enrollMfa/verifyMfa against /internal/v1/auth/2fa/*); once the
902
+ // backend has stamped the session, a RESOLVE_2FA event re-polls the login
903
+ // status, which now returns stage:'done'.
904
+ awaiting_2fa: {
905
+ on: {
906
+ RESOLVE_2FA: { target: "resolving_2fa", actions: ["setPollingCallbacks", "resetError"] },
907
+ CANCEL: { target: "unauthenticated", actions: ["resetState"] }
908
+ }
909
+ },
910
+ awaiting_2fa_enrollment: {
911
+ on: {
912
+ RESOLVE_2FA: { target: "resolving_2fa", actions: ["setPollingCallbacks", "resetError"] },
913
+ CANCEL: { target: "unauthenticated", actions: ["resetState"] }
914
+ }
915
+ },
916
+ resolving_2fa: {
917
+ entry: [{ type: "logTransition", params: { to: "resolving_2fa" } }],
918
+ invoke: {
919
+ src: "polling",
920
+ input: ({ context }) => {
921
+ var _a;
922
+ let resolvedAuthState = null;
923
+ return {
924
+ checkCondition: () => __async(this, null, function* () {
925
+ try {
926
+ const result = yield paraCoreInterface.pollingService.waitForOAuth({
927
+ onSuccess: (serverAuthState) => {
928
+ resolvedAuthState = serverAuthState;
929
+ }
930
+ })();
931
+ return { finished: result.finished && !!resolvedAuthState, data: { authState: resolvedAuthState } };
932
+ } catch (error) {
933
+ throw new Error(`2FA resolution polling failed: ${(0, import_stateErrorHelpers.extractErrorMessage)(error, "Unknown error")}`);
934
+ }
935
+ }),
936
+ onPoll: () => {
937
+ var _a2, _b;
938
+ return (_b = (_a2 = context.pollingCallbacks) == null ? void 0 : _a2.onPoll) == null ? void 0 : _b.call(_a2);
939
+ },
940
+ onCancel: () => {
941
+ var _a2, _b;
942
+ return (_b = (_a2 = context.pollingCallbacks) == null ? void 0 : _a2.onCancel) == null ? void 0 : _b.call(_a2);
943
+ },
944
+ isCanceled: ((_a = context.pollingCallbacks) == null ? void 0 : _a.isCanceled) || (() => false),
945
+ id: "resolving2fa"
946
+ };
947
+ },
948
+ onError: {
949
+ target: "error",
950
+ actions: (0, import_authStateMachine_helpers.setAuthErrorAssign)("2FA resolution failed")
951
+ }
952
+ },
953
+ on: (0, import_authStateMachine_helpers.makePollingOnHandlers)("processing_authentication", "2FA resolution failed", [
954
+ (0, import_xstate.assign)({
955
+ serverAuthStateResult: ({ event }) => {
956
+ var _a;
957
+ const authState = ((_a = event.data) == null ? void 0 : _a.authState) || null;
958
+ return {
959
+ authState,
960
+ opts: import_authStateMachine_helpers.DEFAULT_AUTH_OPTS
961
+ };
962
+ },
963
+ isNewUser: ({ event }) => {
964
+ var _a;
965
+ const authState = (_a = event.data) == null ? void 0 : _a.authState;
966
+ return authState ? (0, import_authStateMachine_helpers.computeIsNewUser)(authState) : false;
967
+ }
968
+ })
969
+ ])
970
+ },
874
971
  awaiting_session_start: {
875
972
  on: {
876
973
  WAIT_FOR_SESSION: {
@@ -219,6 +219,14 @@ function createCoreStateMachine(paraCoreInterface) {
219
219
  "WAIT_FOR_WALLET_CREATION": {
220
220
  actions: ({ context, event }) => context.authMachineRef.send(event)
221
221
  },
222
+ // Login-time 2FA (ENG-6906): after the second factor is satisfied, verifyMfa
223
+ // fires RESOLVE_2FA so the auth machine re-polls verify-oauth and advances the
224
+ // login. Without forwarding it here the parent silently drops the event, the
225
+ // auth child stays parked at awaiting_2fa[_enrollment], and the user never gets
226
+ // a wallet.
227
+ "RESOLVE_2FA": {
228
+ actions: ({ context, event }) => context.authMachineRef.send(event)
229
+ },
222
230
  "INITIALIZE_GUEST_MODE": {
223
231
  actions: ({ context, event }) => context.authMachineRef.send(event)
224
232
  },
@@ -39,6 +39,8 @@ const PARA_CORE_METHODS = [
39
39
  "setup2fa",
40
40
  "enable2fa",
41
41
  "verify2fa",
42
+ "enrollMfa",
43
+ "verifyMfa",
42
44
  "logout",
43
45
  "clearStorage",
44
46
  "isSessionActive",
@@ -376,7 +376,7 @@ const _ParaCore = class _ParaCore {
376
376
  this.addCredential = (params) => __async(this, null, function* () {
377
377
  return yield __privateGet(this, _authService).addCredential(params);
378
378
  });
379
- var _a;
379
+ var _a, _b, _c;
380
380
  let env, apiKey;
381
381
  const actualArgs = Array.from(arguments).filter((arg) => arg !== void 0);
382
382
  const actualArgumentCount = actualArgs.length;
@@ -463,6 +463,7 @@ const _ParaCore = class _ParaCore {
463
463
  };
464
464
  const rawPlatform = (_a = opts.hostPlatform) != null ? _a : this.platformUtils.sdkType;
465
465
  this.clientType = normalizePlatform(rawPlatform);
466
+ const requestAgents = (_c = (_b = this.platformUtils).getRequestAgents) == null ? void 0 : _c.call(_b);
466
467
  const client = initClient({
467
468
  env,
468
469
  version: _ParaCore.version,
@@ -473,7 +474,9 @@ const _ParaCore = class _ParaCore {
473
474
  platform: rawPlatform,
474
475
  useFetchAdapter: !!opts.disableWorkers,
475
476
  retrieveSessionCookie: this.retrieveSessionCookie,
476
- persistSessionCookie: this.persistSessionCookie
477
+ persistSessionCookie: this.persistSessionCookie,
478
+ httpAgent: requestAgents == null ? void 0 : requestAgents.httpAgent,
479
+ httpsAgent: requestAgents == null ? void 0 : requestAgents.httpsAgent
477
480
  });
478
481
  const enclaveClient = new EnclaveClient({
479
482
  userManagementClient: client,
@@ -1767,6 +1770,37 @@ const _ParaCore = class _ParaCore {
1767
1770
  yield this.ctx.client.enable2FA(userId, verificationCode);
1768
1771
  });
1769
1772
  }
1773
+ /**
1774
+ * Login-time 2FA (ENG-6906): enroll a TOTP second factor for the current session.
1775
+ * Distinct from setup2fa/enable2fa, which configure the recovery-gating 2FA. This
1776
+ * is authenticated by the active session (no recovery config gate); the backend
1777
+ * 404s the surface when the login-MFA flag is off.
1778
+ *
1779
+ * @returns {Object} `{ uri, backupCodes }` — otpauth URI to render as a QR, plus
1780
+ * one-time backup codes to show the user exactly once.
1781
+ */
1782
+ enrollMfa() {
1783
+ return __async(this, null, function* () {
1784
+ yield __privateMethod(this, _ParaCore_instances, assertPartner_fn).call(this);
1785
+ return yield __privateGet(this, _authService).enrollMfa();
1786
+ });
1787
+ }
1788
+ /**
1789
+ * Login-time 2FA (ENG-6906): verify the second factor for the current login. On
1790
+ * success the backend stamps the session and this re-polls the login status so the
1791
+ * flow advances toward `done`; a wrong code resolves to `{ ok:false, attemptsRemaining }`
1792
+ * so the UI can re-prompt without treating it as a hard error.
1793
+ *
1794
+ * @param {Object} opts the options object.
1795
+ * @param {string} opts.code the TOTP or backup code entered by the user.
1796
+ * @returns {Object} `{ ok: true } | { ok: false; attemptsRemaining? }`
1797
+ */
1798
+ verifyMfa(_0) {
1799
+ return __async(this, arguments, function* ({ code }) {
1800
+ yield __privateMethod(this, _ParaCore_instances, assertPartner_fn).call(this);
1801
+ return yield __privateGet(this, _authService).verifyMfa({ code });
1802
+ });
1803
+ }
1770
1804
  /**
1771
1805
  * Resend a verification email for the current user.
1772
1806
  */
@@ -1,5 +1,5 @@
1
1
  import "./chunk-7B52C2XE.js";
2
- const PARA_CORE_VERSION = "3.3.0";
2
+ const PARA_CORE_VERSION = "3.5.0";
3
3
  const PREFIX = "@CAPSULE/";
4
4
  const PARA_PREFIX = "@PARA/";
5
5
  const LOCAL_STORAGE_AUTH_INFO = `${PREFIX}authInfo`;
@@ -89,7 +89,9 @@ function initClient({
89
89
  useFetchAdapter = false,
90
90
  retrieveSessionCookie,
91
91
  persistSessionCookie,
92
- staticTraceContext
92
+ staticTraceContext,
93
+ httpAgent,
94
+ httpsAgent
93
95
  }) {
94
96
  return new Client({
95
97
  userManagementHost: getBaseUrl(env),
@@ -100,7 +102,9 @@ function initClient({
100
102
  opts: { useFetchAdapter },
101
103
  retrieveSessionCookie,
102
104
  persistSessionCookie,
103
- staticTraceContext
105
+ staticTraceContext,
106
+ httpAgent,
107
+ httpsAgent
104
108
  });
105
109
  }
106
110
  export {
@@ -169,6 +169,11 @@ class AuthService {
169
169
  JSON.stringify(isSLOPossible)
170
170
  );
171
171
  return serverAuthState;
172
+ // No preparation needed
173
+ case "mfa":
174
+ return serverAuthState;
175
+ default:
176
+ return serverAuthState;
172
177
  }
173
178
  });
174
179
  this.prepareLoginState = (_0, _1) => __async(this, [_0, _1], function* (loginState, { useShortUrls: shorten = false, portalTheme, sessionLookupId }) {
@@ -420,10 +425,46 @@ class AuthService {
420
425
  return yield waitForAuthStateChange({
421
426
  stateManager: __privateGet(this, _stateManager),
422
427
  resolvePhases: [
423
- { phase: "awaiting_session_start", onPhase: (state) => state.authStateResult }
428
+ { phase: "awaiting_session_start", onPhase: (state) => state.authStateResult },
429
+ // Login-time 2FA (ENG-6906): the OAuth poll surfaced an mfa challenge instead
430
+ // of completing. Resolve here so the caller stops blocking; the challenge is
431
+ // read from the consumer auth state (AuthStateInfo.mfa) and satisfied via the
432
+ // enroll/verify hooks, which fire RESOLVE_2FA to continue the flow.
433
+ { phase: "awaiting_2fa", onPhase: (state) => state.authStateResult },
434
+ { phase: "awaiting_2fa_enrollment", onPhase: (state) => state.authStateResult }
424
435
  ]
425
436
  });
426
437
  });
438
+ /**
439
+ * Login-time 2FA (ENG-6906): after the second factor has been satisfied/enrolled
440
+ * server-side, re-poll the login status to advance the flow. Fires RESOLVE_2FA,
441
+ * which re-enters verify-oauth polling (now returning stage:'done') and routes
442
+ * onward to awaiting_session_start / authenticated.
443
+ */
444
+ this.resolveMfa = (pollingCallbacks) => __async(this, null, function* () {
445
+ __privateGet(this, _stateManager).send({ type: "RESOLVE_2FA", data: pollingCallbacks });
446
+ return yield waitForAuthStateChange({
447
+ stateManager: __privateGet(this, _stateManager),
448
+ resolvePhases: [
449
+ { phase: "awaiting_session_start", onPhase: (state) => state.authStateResult },
450
+ { phase: "authenticated", onPhase: (state) => state.authStateResult }
451
+ ],
452
+ // If re-polling after the second factor lands in the auth error phase, reject fast
453
+ // with a clear message instead of stalling until the listener's default timeout. The
454
+ // caller stays parked at awaiting_2fa and can re-prompt/retry. (ENG-6906)
455
+ rejectPhases: [{ phase: "error", onPhase: () => new Error("Login 2FA resolution failed") }]
456
+ });
457
+ });
458
+ this.enrollMfa = () => __async(this, null, function* () {
459
+ return yield __privateGet(this, _paraCoreInterface).ctx.client.enrollMfa();
460
+ });
461
+ this.verifyMfa = (_0) => __async(this, [_0], function* ({ code }) {
462
+ const result = yield __privateGet(this, _paraCoreInterface).ctx.client.verifyMfa(code);
463
+ if (result.ok) {
464
+ yield this.resolveMfa();
465
+ }
466
+ return result;
467
+ });
427
468
  this.authenticateWithOAuth = (params) => __async(this, null, function* () {
428
469
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
429
470
  switch (params.method) {