@proveanything/smartlinks 1.15.11 → 1.15.14

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.
@@ -1,20 +1,47 @@
1
- import type { AuthLoginResponse, AppleLoginOptions, RefreshResponse, LogoutResponse, PhoneSendCodeResponse, PhoneVerifyResponse, PasswordResetRequestResponse, VerifyResetTokenResponse, PasswordResetCompleteResponse, EmailVerificationActionResponse, EmailVerifyTokenResponse, AuthKitConfig, MagicLinkSendResponse, MagicLinkVerifyResponse, UserProfile, UpdateProfileResponse, ProfileUpdateData, SuccessResponse, SendWhatsAppRequest, SendWhatsAppResponse, ExchangeWhatsAppSessionResponse, VerifyWhatsAppResponse, WhatsAppStatusResponse, SendSmsVerifyRequest, SendSmsVerifyResponse, VerifySmsResponse, UpsertContactRequest, UpsertContactResponse } from "../types/authKit";
1
+ import type { AuthLoginResponse, AppleLoginOptions, RefreshResponse, LogoutResponse, PhoneSendCodeResponse, PhoneVerifyResponse, PasswordResetRequestResponse, VerifyResetTokenResponse, PasswordResetCompleteResponse, EmailVerificationActionResponse, EmailVerifyTokenResponse, AuthKitConfig, MagicLinkSendResponse, MagicLinkVerifyResponse, UserProfile, UpdateProfileResponse, ProfileUpdateData, SuccessResponse, SendWhatsAppRequest, SendWhatsAppResponse, ExchangeWhatsAppSessionResponse, VerifyWhatsAppResponse, WhatsAppStatusResponse, SendSmsVerifyRequest, SendSmsVerifyResponse, VerifySmsResponse, UpsertContactRequest, UpsertContactResponse, MfaChallengeSendResponse, MfaFinalizeResponse, MfaEnrollSendResponse, MfaEnrolledResponse, MfaFactorsResponse, TrustedDevice } from "../types/authKit";
2
2
  /**
3
3
  * Namespace containing helper functions for the new AuthKit API.
4
4
  * Legacy collection-based authKit helpers retained (marked as *Legacy*).
5
5
  */
6
6
  export declare namespace authKit {
7
- /** Login with email + password (public). */
8
- function login(clientId: string, email: string, password: string): Promise<AuthLoginResponse>;
9
- /** Register a new user (public). */
7
+ /**
8
+ * Login with email + password (public).
9
+ *
10
+ * When the client's MFA policy requires a step-up, the server returns **403
11
+ * `MFA_REQUIRED`** instead of a session — `login()` throws a `SmartlinksApiError` with
12
+ * `err.errorResponse?.errorCode === 'MFA_REQUIRED'` and the challenge details in
13
+ * `err.details` (see {@link MfaRequiredDetails}). Route the caller to
14
+ * {@link mfaChallengeSend} on that error; this method's return type is unchanged.
15
+ *
16
+ * @param trustedDeviceToken - Optional. If a previous MFA challenge on this device
17
+ * returned one (via {@link mfaChallengeVerify}/{@link mfaRecoveryCode} with
18
+ * `trustDevice: true`), pass it here to skip the challenge entirely as long as it's
19
+ * still valid. If it's revoked/expired, the server silently falls back to requiring a
20
+ * fresh challenge — `login()` just returns `MFA_REQUIRED` again, no special handling.
21
+ */
22
+ function login(clientId: string, email: string, password: string, trustedDeviceToken?: string): Promise<AuthLoginResponse>;
23
+ /**
24
+ * Register a new user (public).
25
+ *
26
+ * Not gated by step-up MFA — a brand-new user has no enrolled factors yet, so there's
27
+ * nothing to challenge against.
28
+ */
10
29
  function register(clientId: string, data: {
11
30
  email: string;
12
31
  password: string;
13
32
  displayName?: string;
14
33
  accountData?: Record<string, any>;
15
34
  }): Promise<AuthLoginResponse>;
16
- /** Google OAuth login via ID token (public). */
17
- function googleLogin(clientId: string, idToken: string): Promise<AuthLoginResponse>;
35
+ /**
36
+ * Google OAuth login via ID token (public).
37
+ *
38
+ * Gated by step-up MFA — see {@link login} for the `MFA_REQUIRED` error shape.
39
+ *
40
+ * @param trustedDeviceToken - Optional. Pass a token previously returned by
41
+ * {@link mfaChallengeVerify}/{@link mfaRecoveryCode} (with `trustDevice: true`) to skip
42
+ * the challenge on this device, same as {@link login}.
43
+ */
44
+ function googleLogin(clientId: string, idToken: string, trustedDeviceToken?: string): Promise<AuthLoginResponse>;
18
45
  /** Google OAuth login via server-side authorization code (public). */
19
46
  function googleCodeLogin(clientId: string, code: string, redirectUri: string): Promise<AuthLoginResponse>;
20
47
  /**
@@ -32,6 +59,9 @@ export declare namespace authKit {
32
59
  * then link Apple from settings. **The same 409 can now come back from
33
60
  * {@link googleLogin}** under the shared verified-to-verified linking policy.
34
61
  *
62
+ * Gated by step-up MFA — see {@link login} for the `MFA_REQUIRED` error shape. Pass
63
+ * `opts.trustedDeviceToken` to skip the challenge on a recognized device.
64
+ *
35
65
  * @see AppleLoginOptions
36
66
  */
37
67
  function appleLogin(clientId: string, identityToken: string, opts?: AppleLoginOptions): Promise<AuthLoginResponse>;
@@ -70,20 +100,46 @@ export declare namespace authKit {
70
100
  redirectUrl: string;
71
101
  accountData?: Record<string, any>;
72
102
  }): Promise<MagicLinkSendResponse>;
73
- /** Verify a magic link token and authenticate/create the user (public). */
74
- function verifyMagicLink(clientId: string, token: string): Promise<MagicLinkVerifyResponse>;
103
+ /**
104
+ * Verify a magic link token and authenticate/create the user (public).
105
+ *
106
+ * Gated by step-up MFA — see {@link login} for the `MFA_REQUIRED` error shape.
107
+ *
108
+ * @param trustedDeviceToken - Optional. See {@link login}.
109
+ */
110
+ function verifyMagicLink(clientId: string, token: string, trustedDeviceToken?: string): Promise<MagicLinkVerifyResponse>;
75
111
  /** Send phone verification code (public). */
76
112
  function sendPhoneCode(clientId: string, phoneNumber: string): Promise<PhoneSendCodeResponse>;
77
- /** Verify phone verification code (public). */
78
- function verifyPhoneCode(clientId: string, phoneNumber: string, code: string): Promise<PhoneVerifyResponse>;
113
+ /**
114
+ * Verify phone verification code (public).
115
+ *
116
+ * Gated by step-up MFA — see {@link login} for the `MFA_REQUIRED` error shape.
117
+ *
118
+ * @param trustedDeviceToken - Optional. See {@link login}.
119
+ */
120
+ function verifyPhoneCode(clientId: string, phoneNumber: string, code: string, trustedDeviceToken?: string): Promise<PhoneVerifyResponse>;
79
121
  /** Send a WhatsApp verification deep-link (public). */
80
122
  function sendWhatsApp(clientId: string, body?: SendWhatsAppRequest): Promise<SendWhatsAppResponse>;
81
- /** Manually verify WhatsApp token if inbound webhook path is unavailable (legacy/public fallback). */
123
+ /**
124
+ * Manually verify WhatsApp token if inbound webhook path is unavailable (legacy/public fallback).
125
+ *
126
+ * Not gated by step-up MFA — this endpoint only confirms the code, it never issues a
127
+ * session/bearer token, so there is nothing to challenge. {@link exchangeWhatsAppSession}
128
+ * is the WhatsApp method that's gated.
129
+ */
82
130
  function verifyWhatsApp(clientId: string, token: string, phoneNumber: string): Promise<VerifyWhatsAppResponse>;
83
131
  /** Poll WhatsApp verification status for a token (public). */
84
132
  function getWhatsAppStatus(clientId: string, token: string): Promise<WhatsAppStatusResponse>;
85
- /** Exchange a verified WhatsApp token for an Auth Kit session (public). */
86
- function exchangeWhatsAppSession(clientId: string, token: string, sessionKey: string): Promise<ExchangeWhatsAppSessionResponse>;
133
+ /**
134
+ * Exchange a verified WhatsApp token for an Auth Kit session (public).
135
+ *
136
+ * Gated by step-up MFA — see {@link login} for the `MFA_REQUIRED` error shape. This is
137
+ * the WhatsApp method that needs `trustedDeviceToken`, not {@link verifyWhatsApp} (which
138
+ * never issues a session).
139
+ *
140
+ * @param trustedDeviceToken - Optional. See {@link login}.
141
+ */
142
+ function exchangeWhatsAppSession(clientId: string, token: string, sessionKey: string, trustedDeviceToken?: string): Promise<ExchangeWhatsAppSessionResponse>;
87
143
  /** Send an SMS click-to-verify link (public). */
88
144
  function sendSmsVerify(clientId: string, body: SendSmsVerifyRequest): Promise<SendSmsVerifyResponse>;
89
145
  /** Verify an SMS click-to-verify token via API (public). */
@@ -124,6 +180,47 @@ export declare namespace authKit {
124
180
  function verifyEmailChange(clientId: string, token: string): Promise<SuccessResponse>;
125
181
  function updatePhone(clientId: string, phoneNumber: string, verificationCode: string): Promise<SuccessResponse>;
126
182
  function deleteAccount(clientId: string, password: string, confirmText: string): Promise<SuccessResponse>;
183
+ /** Send (or resend) an MFA challenge code to the given factor (public). */
184
+ function mfaChallengeSend(clientId: string, mfaSessionToken: string, factor: 'email' | 'sms'): Promise<MfaChallengeSendResponse>;
185
+ /**
186
+ * Verify an MFA challenge code and finalize the login (public). On success this behaves
187
+ * like {@link login} — the bearer token is adopted and the cache invalidated.
188
+ *
189
+ * @param trustDevice - When `true`, the response includes `trustedDeviceToken` — persist
190
+ * it and pass it to future {@link login} calls to skip the challenge on this device.
191
+ */
192
+ function mfaChallengeVerify(clientId: string, mfaSessionToken: string, code: string, trustDevice?: boolean, deviceLabel?: string): Promise<MfaFinalizeResponse>;
193
+ /**
194
+ * Finalize a challenged login using a single-use recovery code instead of a sent code
195
+ * (public). Same finalize-session behaviour as {@link mfaChallengeVerify}.
196
+ */
197
+ function mfaRecoveryCode(clientId: string, mfaSessionToken: string, code: string, trustDevice?: boolean, deviceLabel?: string): Promise<MfaFinalizeResponse>;
198
+ /** List enrolled factors and recovery-code count for the current user (authenticated). */
199
+ function getMfaFactors(clientId: string): Promise<MfaFactorsResponse>;
200
+ /** Begin email-factor enrollment; sends a code to the account's existing email (authenticated). */
201
+ function enrollEmailMfa(clientId: string): Promise<MfaEnrollSendResponse>;
202
+ /** Confirm email-factor enrollment with the code sent by {@link enrollEmailMfa} (authenticated). */
203
+ function confirmEmailMfa(clientId: string, mfaSessionToken: string, code: string): Promise<MfaEnrolledResponse>;
204
+ /** Begin SMS-factor enrollment; sends a code to the given phone number (authenticated). */
205
+ function enrollSmsMfa(clientId: string, phoneNumber: string): Promise<MfaEnrollSendResponse>;
206
+ /** Confirm SMS-factor enrollment with the code sent by {@link enrollSmsMfa} (authenticated). */
207
+ function confirmSmsMfa(clientId: string, mfaSessionToken: string, code: string): Promise<MfaEnrolledResponse>;
208
+ /**
209
+ * Generate a fresh set of recovery codes, invalidating any previous set (authenticated).
210
+ * Returned **in plaintext, exactly once** — nothing else in the API ever returns them
211
+ * again, so the caller must display/export them immediately.
212
+ */
213
+ function generateMfaRecoveryCodes(clientId: string, password: string): Promise<{
214
+ recoveryCodes: string[];
215
+ }>;
216
+ /** Remove an enrolled MFA factor (authenticated). Server route is DELETE with a body. */
217
+ function removeMfaFactor(clientId: string, factor: 'email' | 'sms', password: string): Promise<SuccessResponse>;
218
+ /** List devices trusted to skip MFA challenges for the current user (authenticated). */
219
+ function listTrustedDevices(clientId: string): Promise<{
220
+ devices: TrustedDevice[];
221
+ }>;
222
+ /** Revoke a single trusted device by id (authenticated). */
223
+ function revokeTrustedDevice(clientId: string, id: string): Promise<SuccessResponse>;
127
224
  function load(authKitId: string): Promise<AuthKitConfig>;
128
225
  function get(collectionId: string, authKitId: string): Promise<AuthKitConfig>;
129
226
  function list(collectionId: string, admin?: boolean): Promise<AuthKitConfig[]>;
@@ -1,4 +1,4 @@
1
- import { request, post, put, del, setBearerToken, invalidateCache } from "../http";
1
+ import { request, post, put, del, requestWithOptions, setBearerToken, invalidateCache } from "../http";
2
2
  /**
3
3
  * Namespace containing helper functions for the new AuthKit API.
4
4
  * Legacy collection-based authKit helpers retained (marked as *Legacy*).
@@ -8,9 +8,26 @@ export var authKit;
8
8
  /* ===================================
9
9
  * Authentication (Per client)
10
10
  * =================================== */
11
- /** Login with email + password (public). */
12
- async function login(clientId, email, password) {
13
- const res = await post(`/authkit/${encodeURIComponent(clientId)}/auth/login`, { email, password });
11
+ /**
12
+ * Login with email + password (public).
13
+ *
14
+ * When the client's MFA policy requires a step-up, the server returns **403
15
+ * `MFA_REQUIRED`** instead of a session — `login()` throws a `SmartlinksApiError` with
16
+ * `err.errorResponse?.errorCode === 'MFA_REQUIRED'` and the challenge details in
17
+ * `err.details` (see {@link MfaRequiredDetails}). Route the caller to
18
+ * {@link mfaChallengeSend} on that error; this method's return type is unchanged.
19
+ *
20
+ * @param trustedDeviceToken - Optional. If a previous MFA challenge on this device
21
+ * returned one (via {@link mfaChallengeVerify}/{@link mfaRecoveryCode} with
22
+ * `trustDevice: true`), pass it here to skip the challenge entirely as long as it's
23
+ * still valid. If it's revoked/expired, the server silently falls back to requiring a
24
+ * fresh challenge — `login()` just returns `MFA_REQUIRED` again, no special handling.
25
+ */
26
+ async function login(clientId, email, password, trustedDeviceToken) {
27
+ const body = { email, password };
28
+ if (trustedDeviceToken)
29
+ body.trustedDeviceToken = trustedDeviceToken;
30
+ const res = await post(`/authkit/${encodeURIComponent(clientId)}/auth/login`, body);
14
31
  if (res.token) {
15
32
  setBearerToken(res.token);
16
33
  invalidateCache();
@@ -18,14 +35,27 @@ export var authKit;
18
35
  return res;
19
36
  }
20
37
  authKit.login = login;
21
- /** Register a new user (public). */
38
+ /**
39
+ * Register a new user (public).
40
+ *
41
+ * Not gated by step-up MFA — a brand-new user has no enrolled factors yet, so there's
42
+ * nothing to challenge against.
43
+ */
22
44
  async function register(clientId, data) {
23
45
  return post(`/authkit/${encodeURIComponent(clientId)}/auth/register`, data);
24
46
  }
25
47
  authKit.register = register;
26
- /** Google OAuth login via ID token (public). */
27
- async function googleLogin(clientId, idToken) {
28
- const res = await post(`/authkit/${encodeURIComponent(clientId)}/auth/google`, { idToken });
48
+ /**
49
+ * Google OAuth login via ID token (public).
50
+ *
51
+ * Gated by step-up MFA — see {@link login} for the `MFA_REQUIRED` error shape.
52
+ *
53
+ * @param trustedDeviceToken - Optional. Pass a token previously returned by
54
+ * {@link mfaChallengeVerify}/{@link mfaRecoveryCode} (with `trustDevice: true`) to skip
55
+ * the challenge on this device, same as {@link login}.
56
+ */
57
+ async function googleLogin(clientId, idToken, trustedDeviceToken) {
58
+ const res = await post(`/authkit/${encodeURIComponent(clientId)}/auth/google`, { idToken, trustedDeviceToken });
29
59
  if (res.token) {
30
60
  setBearerToken(res.token);
31
61
  invalidateCache();
@@ -58,6 +88,9 @@ export var authKit;
58
88
  * then link Apple from settings. **The same 409 can now come back from
59
89
  * {@link googleLogin}** under the shared verified-to-verified linking policy.
60
90
  *
91
+ * Gated by step-up MFA — see {@link login} for the `MFA_REQUIRED` error shape. Pass
92
+ * `opts.trustedDeviceToken` to skip the challenge on a recognized device.
93
+ *
61
94
  * @see AppleLoginOptions
62
95
  */
63
96
  async function appleLogin(clientId, identityToken, opts) {
@@ -121,9 +154,15 @@ export var authKit;
121
154
  return post(`/authkit/${encodeURIComponent(clientId)}/auth/magic-link/send`, data);
122
155
  }
123
156
  authKit.sendMagicLink = sendMagicLink;
124
- /** Verify a magic link token and authenticate/create the user (public). */
125
- async function verifyMagicLink(clientId, token) {
126
- const res = await post(`/authkit/${encodeURIComponent(clientId)}/auth/magic-link/verify`, { token });
157
+ /**
158
+ * Verify a magic link token and authenticate/create the user (public).
159
+ *
160
+ * Gated by step-up MFA — see {@link login} for the `MFA_REQUIRED` error shape.
161
+ *
162
+ * @param trustedDeviceToken - Optional. See {@link login}.
163
+ */
164
+ async function verifyMagicLink(clientId, token, trustedDeviceToken) {
165
+ const res = await post(`/authkit/${encodeURIComponent(clientId)}/auth/magic-link/verify`, { token, trustedDeviceToken });
127
166
  if (res.token) {
128
167
  setBearerToken(res.token);
129
168
  invalidateCache();
@@ -136,9 +175,15 @@ export var authKit;
136
175
  return post(`/authkit/${encodeURIComponent(clientId)}/auth/phone/send-code`, { phoneNumber });
137
176
  }
138
177
  authKit.sendPhoneCode = sendPhoneCode;
139
- /** Verify phone verification code (public). */
140
- async function verifyPhoneCode(clientId, phoneNumber, code) {
141
- const res = await post(`/authkit/${encodeURIComponent(clientId)}/auth/phone/verify`, { phoneNumber, code });
178
+ /**
179
+ * Verify phone verification code (public).
180
+ *
181
+ * Gated by step-up MFA — see {@link login} for the `MFA_REQUIRED` error shape.
182
+ *
183
+ * @param trustedDeviceToken - Optional. See {@link login}.
184
+ */
185
+ async function verifyPhoneCode(clientId, phoneNumber, code, trustedDeviceToken) {
186
+ const res = await post(`/authkit/${encodeURIComponent(clientId)}/auth/phone/verify`, { phoneNumber, code, trustedDeviceToken });
142
187
  setBearerToken(res.token);
143
188
  invalidateCache();
144
189
  return res;
@@ -149,7 +194,13 @@ export var authKit;
149
194
  return post(`/authkit/${encodeURIComponent(clientId)}/auth/whatsapp/send`, body);
150
195
  }
151
196
  authKit.sendWhatsApp = sendWhatsApp;
152
- /** Manually verify WhatsApp token if inbound webhook path is unavailable (legacy/public fallback). */
197
+ /**
198
+ * Manually verify WhatsApp token if inbound webhook path is unavailable (legacy/public fallback).
199
+ *
200
+ * Not gated by step-up MFA — this endpoint only confirms the code, it never issues a
201
+ * session/bearer token, so there is nothing to challenge. {@link exchangeWhatsAppSession}
202
+ * is the WhatsApp method that's gated.
203
+ */
153
204
  async function verifyWhatsApp(clientId, token, phoneNumber) {
154
205
  return post(`/authkit/${encodeURIComponent(clientId)}/auth/whatsapp/verify`, { token, phoneNumber });
155
206
  }
@@ -160,9 +211,17 @@ export var authKit;
160
211
  return request(`/authkit/${encodeURIComponent(clientId)}/auth/whatsapp/status?token=${encodedToken}`);
161
212
  }
162
213
  authKit.getWhatsAppStatus = getWhatsAppStatus;
163
- /** Exchange a verified WhatsApp token for an Auth Kit session (public). */
164
- async function exchangeWhatsAppSession(clientId, token, sessionKey) {
165
- const res = await post(`/authkit/${encodeURIComponent(clientId)}/auth/whatsapp/exchange-session`, { token, sessionKey });
214
+ /**
215
+ * Exchange a verified WhatsApp token for an Auth Kit session (public).
216
+ *
217
+ * Gated by step-up MFA — see {@link login} for the `MFA_REQUIRED` error shape. This is
218
+ * the WhatsApp method that needs `trustedDeviceToken`, not {@link verifyWhatsApp} (which
219
+ * never issues a session).
220
+ *
221
+ * @param trustedDeviceToken - Optional. See {@link login}.
222
+ */
223
+ async function exchangeWhatsAppSession(clientId, token, sessionKey, trustedDeviceToken) {
224
+ const res = await post(`/authkit/${encodeURIComponent(clientId)}/auth/whatsapp/exchange-session`, { token, sessionKey, trustedDeviceToken });
166
225
  setBearerToken(res.token);
167
226
  invalidateCache();
168
227
  return res;
@@ -277,6 +336,101 @@ export var authKit;
277
336
  return res;
278
337
  }
279
338
  authKit.deleteAccount = deleteAccount;
339
+ /* ===================================
340
+ * Step-up MFA — completing a challenged login (public)
341
+ *
342
+ * Called after login() throws MFA_REQUIRED. mfaSessionToken is short-lived (10 min) and
343
+ * single-use — burned on 5 failed attempts (MFA_TOO_MANY_ATTEMPTS) or on success.
344
+ * challenge/send can be called again on the same token (while unexpired/unburned) to
345
+ * switch factors or resend.
346
+ * =================================== */
347
+ /** Send (or resend) an MFA challenge code to the given factor (public). */
348
+ async function mfaChallengeSend(clientId, mfaSessionToken, factor) {
349
+ return post(`/authkit/${encodeURIComponent(clientId)}/mfa/challenge/send`, { mfaSessionToken, factor });
350
+ }
351
+ authKit.mfaChallengeSend = mfaChallengeSend;
352
+ /**
353
+ * Verify an MFA challenge code and finalize the login (public). On success this behaves
354
+ * like {@link login} — the bearer token is adopted and the cache invalidated.
355
+ *
356
+ * @param trustDevice - When `true`, the response includes `trustedDeviceToken` — persist
357
+ * it and pass it to future {@link login} calls to skip the challenge on this device.
358
+ */
359
+ async function mfaChallengeVerify(clientId, mfaSessionToken, code, trustDevice, deviceLabel) {
360
+ const res = await post(`/authkit/${encodeURIComponent(clientId)}/mfa/challenge/verify`, { mfaSessionToken, code, trustDevice, deviceLabel });
361
+ if (res.token) {
362
+ setBearerToken(res.token);
363
+ invalidateCache();
364
+ }
365
+ return res;
366
+ }
367
+ authKit.mfaChallengeVerify = mfaChallengeVerify;
368
+ /**
369
+ * Finalize a challenged login using a single-use recovery code instead of a sent code
370
+ * (public). Same finalize-session behaviour as {@link mfaChallengeVerify}.
371
+ */
372
+ async function mfaRecoveryCode(clientId, mfaSessionToken, code, trustDevice, deviceLabel) {
373
+ const res = await post(`/authkit/${encodeURIComponent(clientId)}/mfa/challenge/recovery-code`, { mfaSessionToken, code, trustDevice, deviceLabel });
374
+ if (res.token) {
375
+ setBearerToken(res.token);
376
+ invalidateCache();
377
+ }
378
+ return res;
379
+ }
380
+ authKit.mfaRecoveryCode = mfaRecoveryCode;
381
+ /* ===================================
382
+ * Step-up MFA — factor management (Authenticated)
383
+ * =================================== */
384
+ /** List enrolled factors and recovery-code count for the current user (authenticated). */
385
+ async function getMfaFactors(clientId) {
386
+ return request(`/authkit/${encodeURIComponent(clientId)}/mfa/factors`);
387
+ }
388
+ authKit.getMfaFactors = getMfaFactors;
389
+ /** Begin email-factor enrollment; sends a code to the account's existing email (authenticated). */
390
+ async function enrollEmailMfa(clientId) {
391
+ return post(`/authkit/${encodeURIComponent(clientId)}/mfa/factors/email/enroll`, {});
392
+ }
393
+ authKit.enrollEmailMfa = enrollEmailMfa;
394
+ /** Confirm email-factor enrollment with the code sent by {@link enrollEmailMfa} (authenticated). */
395
+ async function confirmEmailMfa(clientId, mfaSessionToken, code) {
396
+ return post(`/authkit/${encodeURIComponent(clientId)}/mfa/factors/email/confirm`, { mfaSessionToken, code });
397
+ }
398
+ authKit.confirmEmailMfa = confirmEmailMfa;
399
+ /** Begin SMS-factor enrollment; sends a code to the given phone number (authenticated). */
400
+ async function enrollSmsMfa(clientId, phoneNumber) {
401
+ return post(`/authkit/${encodeURIComponent(clientId)}/mfa/factors/sms/enroll`, { phoneNumber });
402
+ }
403
+ authKit.enrollSmsMfa = enrollSmsMfa;
404
+ /** Confirm SMS-factor enrollment with the code sent by {@link enrollSmsMfa} (authenticated). */
405
+ async function confirmSmsMfa(clientId, mfaSessionToken, code) {
406
+ return post(`/authkit/${encodeURIComponent(clientId)}/mfa/factors/sms/confirm`, { mfaSessionToken, code });
407
+ }
408
+ authKit.confirmSmsMfa = confirmSmsMfa;
409
+ /**
410
+ * Generate a fresh set of recovery codes, invalidating any previous set (authenticated).
411
+ * Returned **in plaintext, exactly once** — nothing else in the API ever returns them
412
+ * again, so the caller must display/export them immediately.
413
+ */
414
+ async function generateMfaRecoveryCodes(clientId, password) {
415
+ return post(`/authkit/${encodeURIComponent(clientId)}/mfa/recovery-codes/generate`, { password });
416
+ }
417
+ authKit.generateMfaRecoveryCodes = generateMfaRecoveryCodes;
418
+ /** Remove an enrolled MFA factor (authenticated). Server route is DELETE with a body. */
419
+ async function removeMfaFactor(clientId, factor, password) {
420
+ const path = `/authkit/${encodeURIComponent(clientId)}/mfa/factors/${factor}`;
421
+ return requestWithOptions(path, { method: 'DELETE', body: JSON.stringify({ password }) });
422
+ }
423
+ authKit.removeMfaFactor = removeMfaFactor;
424
+ /** List devices trusted to skip MFA challenges for the current user (authenticated). */
425
+ async function listTrustedDevices(clientId) {
426
+ return request(`/authkit/${encodeURIComponent(clientId)}/mfa/trusted-devices`);
427
+ }
428
+ authKit.listTrustedDevices = listTrustedDevices;
429
+ /** Revoke a single trusted device by id (authenticated). */
430
+ async function revokeTrustedDevice(clientId, id) {
431
+ return del(`/authkit/${encodeURIComponent(clientId)}/mfa/trusted-devices/${encodeURIComponent(id)}`);
432
+ }
433
+ authKit.revokeTrustedDevice = revokeTrustedDevice;
280
434
  /* ===================================
281
435
  * Collection-based AuthKit
282
436
  * =================================== */