@absolutejs/auth 0.57.9 → 0.58.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.
package/dist/index.d.ts CHANGED
@@ -1015,7 +1015,7 @@ export declare const createAuthApplications: <UserType>(configuration: AuthConfi
1015
1015
  query: unknown;
1016
1016
  headers: unknown;
1017
1017
  response: {
1018
- 400: "Phone must be in E.164 format";
1018
+ 400: string;
1019
1019
  401: "Authentication required";
1020
1020
  501: "SMS MFA is not configured";
1021
1021
  200: {
@@ -1030,6 +1030,8 @@ export declare const createAuthApplications: <UserType>(configuration: AuthConfi
1030
1030
  property?: string;
1031
1031
  expected?: string;
1032
1032
  };
1033
+ 429: string;
1034
+ 503: string;
1033
1035
  };
1034
1036
  };
1035
1037
  };
@@ -1043,7 +1045,7 @@ export declare const createAuthApplications: <UserType>(configuration: AuthConfi
1043
1045
  query: unknown;
1044
1046
  headers: unknown;
1045
1047
  response: {
1046
- 400: "No SMS enrollment in progress" | "SMS code expired" | "Invalid SMS code";
1048
+ 400: string;
1047
1049
  401: "Authentication required";
1048
1050
  200: {
1049
1051
  readonly status: "enrolled";
@@ -1057,7 +1059,8 @@ export declare const createAuthApplications: <UserType>(configuration: AuthConfi
1057
1059
  property?: string;
1058
1060
  expected?: string;
1059
1061
  };
1060
- 429: "Too many attempts";
1062
+ 429: string;
1063
+ 503: string;
1061
1064
  };
1062
1065
  };
1063
1066
  };
@@ -1073,7 +1076,7 @@ export declare const createAuthApplications: <UserType>(configuration: AuthConfi
1073
1076
  query: unknown;
1074
1077
  headers: unknown;
1075
1078
  response: {
1076
- 400: "SMS code required" | "No SMS code in progress";
1079
+ 400: string;
1077
1080
  401: "SMS code expired" | "Too many attempts" | "No MFA challenge in progress" | "Invalid MFA code";
1078
1081
  200: {
1079
1082
  readonly status: "sent";
@@ -1089,6 +1092,8 @@ export declare const createAuthApplications: <UserType>(configuration: AuthConfi
1089
1092
  property?: string;
1090
1093
  expected?: string;
1091
1094
  };
1095
+ 429: string;
1096
+ 503: string;
1092
1097
  };
1093
1098
  };
1094
1099
  };
@@ -3486,6 +3491,7 @@ export { createNeonDatabase } from './stores/postgres';
3486
3491
  export type { AnyPgDatabase } from './stores/postgres';
3487
3492
  export * from './mfa/config';
3488
3493
  export * from './mfa/types';
3494
+ export * from './verification/types';
3489
3495
  export { consumeBackupCode, generateBackupCodes } from './mfa/backupCodes';
3490
3496
  export { createMfaGate } from './mfa/gate';
3491
3497
  export { mfaChallenge } from './mfa/challenge';
package/dist/index.js CHANGED
@@ -5853,6 +5853,7 @@ var DEFAULT_SMS_CODE_LENGTH = 6;
5853
5853
  var SMS_CODE_TTL_MINUTES = 5;
5854
5854
  var DEFAULT_SMS_CODE_TTL_MS = SMS_CODE_TTL_MINUTES * SECONDS_IN_A_MINUTE * MILLISECONDS_IN_A_SECOND;
5855
5855
  var DEFAULT_SMS_MAX_ATTEMPTS = 3;
5856
+ var DEFAULT_SMS_RESEND_COOLDOWN_MS = 30 * MILLISECONDS_IN_A_SECOND;
5856
5857
  var DEFAULT_TOTP_MAX_ATTEMPTS = 5;
5857
5858
 
5858
5859
  // src/mfa/secret.ts
@@ -5863,6 +5864,20 @@ var encryptTotpSecret = (secret, encryptionKey) => encryptionKey ? encryptSecret
5863
5864
  // src/mfa/sms.ts
5864
5865
  init_crypto();
5865
5866
  import { Elysia as Elysia17, t as t11 } from "elysia";
5867
+
5868
+ // src/verification/types.ts
5869
+ class VerificationProviderError extends Error {
5870
+ kind;
5871
+ provider;
5872
+ constructor(input) {
5873
+ super(input.message, { cause: input.cause });
5874
+ this.name = "VerificationProviderError";
5875
+ this.kind = input.kind;
5876
+ this.provider = input.provider;
5877
+ }
5878
+ }
5879
+
5880
+ // src/mfa/sms.ts
5866
5881
  var DECIMAL_RADIX2 = 10;
5867
5882
  var MASK_VISIBLE_DIGITS = 4;
5868
5883
  var E164_PATTERN = /^\+[1-9]\d{7,14}$/u;
@@ -5877,28 +5892,83 @@ var issueSmsCode = async (codeLength, ttlMs) => {
5877
5892
  const expiresAt = Date.now() + ttlMs;
5878
5893
  return { code, expiresAt, hash };
5879
5894
  };
5895
+ var checkWithVerificationProvider = async (provider, input) => {
5896
+ try {
5897
+ return { result: await provider.check(input) };
5898
+ } catch (error) {
5899
+ const mapped = mapVerificationProviderError(error);
5900
+ if (mapped === undefined)
5901
+ throw error;
5902
+ return { error: mapped };
5903
+ }
5904
+ };
5880
5905
  var isE164Phone = (phone) => E164_PATTERN.test(phone);
5881
5906
  var issueAndStoreSmsCode = async ({
5882
5907
  codeLength,
5883
5908
  enrollment,
5884
5909
  mfaStore,
5885
5910
  onSendSmsCode,
5886
- ttlMs
5911
+ purpose,
5912
+ verificationProvider,
5913
+ ttlMs,
5914
+ userId
5887
5915
  }) => {
5888
5916
  const phone = enrollment.smsPhone;
5889
5917
  if (phone === undefined)
5890
5918
  return;
5919
+ if (verificationProvider !== undefined) {
5920
+ const started = await verificationProvider.start({
5921
+ channel: "sms",
5922
+ purpose,
5923
+ subject: userId,
5924
+ to: phone
5925
+ });
5926
+ await mfaStore.saveEnrollment({
5927
+ ...enrollment,
5928
+ smsCodeSentAt: Date.now(),
5929
+ smsFailedAttempts: 0,
5930
+ smsPendingCodeExpiresAt: started.expiresAt,
5931
+ smsPendingCodeHash: undefined,
5932
+ smsPendingPurpose: purpose,
5933
+ smsProviderReference: started.reference,
5934
+ updatedAt: Date.now()
5935
+ });
5936
+ return started.expiresAt;
5937
+ }
5891
5938
  const { code, expiresAt, hash } = await issueSmsCode(codeLength, ttlMs);
5892
5939
  await mfaStore.saveEnrollment({
5893
5940
  ...enrollment,
5941
+ smsCodeSentAt: Date.now(),
5894
5942
  smsFailedAttempts: 0,
5895
5943
  smsPendingCodeExpiresAt: expiresAt,
5896
5944
  smsPendingCodeHash: hash,
5945
+ smsPendingPurpose: purpose,
5946
+ smsProviderReference: undefined,
5897
5947
  updatedAt: Date.now()
5898
5948
  });
5899
- await onSendSmsCode?.({ code, expiresAt, phone });
5949
+ await onSendSmsCode?.({ code, expiresAt, phone, purpose, userId });
5900
5950
  return expiresAt;
5901
5951
  };
5952
+ var mapVerificationProviderError = (error) => {
5953
+ if (!(error instanceof VerificationProviderError))
5954
+ return;
5955
+ if (error.kind === "rate_limited") {
5956
+ return {
5957
+ message: "Verification provider rate limit reached",
5958
+ status: "Too Many Requests"
5959
+ };
5960
+ }
5961
+ if (error.kind === "invalid_destination") {
5962
+ return {
5963
+ message: "Phone number cannot receive verification codes",
5964
+ status: "Bad Request"
5965
+ };
5966
+ }
5967
+ return {
5968
+ message: "Verification provider unavailable",
5969
+ status: "Service Unavailable"
5970
+ };
5971
+ };
5902
5972
  var maskPhone = (phone) => {
5903
5973
  const visible = phone.slice(-MASK_VISIBLE_DIGITS);
5904
5974
  const maskedLength = Math.max(phone.length - MASK_VISIBLE_DIGITS, 0);
@@ -5910,9 +5980,11 @@ var mfaSmsRoutes = ({
5910
5980
  mfaStore,
5911
5981
  onMfaEnrolled,
5912
5982
  onSendSmsCode,
5983
+ verificationProvider,
5913
5984
  smsCodeLength = DEFAULT_SMS_CODE_LENGTH,
5914
5985
  smsCodeTtlMs = DEFAULT_SMS_CODE_TTL_MS,
5915
5986
  smsMaxAttempts = DEFAULT_SMS_MAX_ATTEMPTS,
5987
+ smsResendCooldownMs = DEFAULT_SMS_RESEND_COOLDOWN_MS,
5916
5988
  smsSetupRoute = "/auth/mfa/sms/setup",
5917
5989
  smsVerifyRoute = "/auth/mfa/sms/verify"
5918
5990
  }) => new Elysia17().use(sessionStore()).post(smsSetupRoute, async ({
@@ -5921,7 +5993,7 @@ var mfaSmsRoutes = ({
5921
5993
  status,
5922
5994
  store: { session }
5923
5995
  }) => {
5924
- if (onSendSmsCode === undefined) {
5996
+ if (onSendSmsCode === undefined && verificationProvider === undefined) {
5925
5997
  return status("Not Implemented", "SMS MFA is not configured");
5926
5998
  }
5927
5999
  const userSession = await loadSessionFromSource({
@@ -5938,21 +6010,51 @@ var mfaSmsRoutes = ({
5938
6010
  const userId = getUserId(userSession.user);
5939
6011
  const existing = await mfaStore.getEnrollment(userId);
5940
6012
  const now = Date.now();
5941
- const { code, expiresAt, hash } = await issueSmsCode(smsCodeLength, smsCodeTtlMs);
6013
+ if (existing?.smsCodeSentAt !== undefined && now - existing.smsCodeSentAt < smsResendCooldownMs) {
6014
+ return status("Too Many Requests", "SMS resend cooldown active");
6015
+ }
6016
+ let started;
6017
+ try {
6018
+ started = verificationProvider ? await verificationProvider.start({
6019
+ channel: "sms",
6020
+ purpose: "mfa_enrollment",
6021
+ subject: userId,
6022
+ to: phone
6023
+ }) : undefined;
6024
+ } catch (error) {
6025
+ const mapped = mapVerificationProviderError(error);
6026
+ if (mapped === undefined)
6027
+ throw error;
6028
+ return status(mapped.status, mapped.message);
6029
+ }
6030
+ const local = started ? undefined : await issueSmsCode(smsCodeLength, smsCodeTtlMs);
5942
6031
  await mfaStore.saveEnrollment({
5943
6032
  backupCodeHashes: existing?.backupCodeHashes ?? [],
5944
6033
  createdAt: existing?.createdAt ?? now,
6034
+ lastUsedAt: existing?.lastUsedAt,
6035
+ smsCodeSentAt: now,
5945
6036
  smsFailedAttempts: 0,
5946
- smsPendingCodeExpiresAt: expiresAt,
5947
- smsPendingCodeHash: hash,
6037
+ smsPendingCodeExpiresAt: started?.expiresAt ?? local?.expiresAt,
6038
+ smsPendingCodeHash: local?.hash,
6039
+ smsPendingPurpose: "mfa_enrollment",
5948
6040
  smsPhone: phone,
6041
+ smsProviderReference: started?.reference,
5949
6042
  smsVerified: false,
6043
+ totpFailedAttempts: existing?.totpFailedAttempts ?? 0,
5950
6044
  totpSecretCiphertext: existing?.totpSecretCiphertext,
5951
6045
  totpVerified: existing?.totpVerified ?? false,
5952
6046
  updatedAt: now,
5953
6047
  userId
5954
6048
  });
5955
- await onSendSmsCode({ code, expiresAt, phone });
6049
+ if (local !== undefined && onSendSmsCode !== undefined) {
6050
+ await onSendSmsCode({
6051
+ code: local.code,
6052
+ expiresAt: local.expiresAt,
6053
+ phone,
6054
+ purpose: "mfa_enrollment",
6055
+ userId
6056
+ });
6057
+ }
5956
6058
  return status("OK", { phone: maskPhone(phone) });
5957
6059
  }, {
5958
6060
  body: t11.Object({ phone: t11.String() }),
@@ -5973,29 +6075,58 @@ var mfaSmsRoutes = ({
5973
6075
  }
5974
6076
  const userId = getUserId(userSession.user);
5975
6077
  const enrollment = await mfaStore.getEnrollment(userId);
5976
- if (!enrollment?.smsPendingCodeHash || enrollment.smsPendingCodeExpiresAt === undefined) {
6078
+ if (!enrollment?.smsPhone) {
6079
+ return status("Bad Request", "No SMS enrollment in progress");
6080
+ }
6081
+ const localCodeHash = enrollment.smsPendingCodeHash;
6082
+ const localCodeExpiresAt = enrollment.smsPendingCodeExpiresAt;
6083
+ const providerReference = enrollment.smsProviderReference;
6084
+ if (enrollment.smsPendingPurpose !== "mfa_enrollment" || localCodeExpiresAt === undefined) {
5977
6085
  return status("Bad Request", "No SMS enrollment in progress");
5978
6086
  }
5979
- if (Date.now() > enrollment.smsPendingCodeExpiresAt) {
6087
+ if (verificationProvider === undefined && localCodeHash === undefined) {
6088
+ return status("Bad Request", "No SMS enrollment in progress");
6089
+ }
6090
+ if (Date.now() > localCodeExpiresAt) {
5980
6091
  return status("Bad Request", "SMS code expired");
5981
6092
  }
5982
6093
  if ((enrollment.smsFailedAttempts ?? 0) >= smsMaxAttempts) {
5983
6094
  return status("Too Many Requests", "Too many attempts");
5984
6095
  }
5985
- const codeValid = await constantTimeEqual(await hashToken(code), enrollment.smsPendingCodeHash);
6096
+ let providerResult;
6097
+ if (verificationProvider !== undefined) {
6098
+ if (providerReference === undefined) {
6099
+ return status("Bad Request", "No SMS enrollment in progress");
6100
+ }
6101
+ const checked = await checkWithVerificationProvider(verificationProvider, {
6102
+ channel: "sms",
6103
+ code,
6104
+ purpose: "mfa_enrollment",
6105
+ reference: providerReference,
6106
+ subject: userId,
6107
+ to: enrollment.smsPhone
6108
+ });
6109
+ if (checked.error !== undefined) {
6110
+ return status(checked.error.status, checked.error.message);
6111
+ }
6112
+ providerResult = checked.result;
6113
+ }
6114
+ const codeValid = providerResult ? providerResult.status === "approved" : localCodeHash !== undefined && await constantTimeEqual(await hashToken(code), localCodeHash);
5986
6115
  if (!codeValid) {
5987
6116
  await mfaStore.saveEnrollment({
5988
6117
  ...enrollment,
5989
6118
  smsFailedAttempts: (enrollment.smsFailedAttempts ?? 0) + 1,
5990
6119
  updatedAt: Date.now()
5991
6120
  });
5992
- return status("Bad Request", "Invalid SMS code");
6121
+ return status(providerResult?.status === "max_attempts_reached" ? "Too Many Requests" : "Bad Request", providerResult?.status === "expired" ? "SMS code expired" : "Invalid SMS code");
5993
6122
  }
5994
6123
  await mfaStore.saveEnrollment({
5995
6124
  ...enrollment,
5996
6125
  smsFailedAttempts: 0,
5997
6126
  smsPendingCodeExpiresAt: undefined,
5998
6127
  smsPendingCodeHash: undefined,
6128
+ smsPendingPurpose: undefined,
6129
+ smsProviderReference: undefined,
5999
6130
  smsVerified: true,
6000
6131
  updatedAt: Date.now()
6001
6132
  });
@@ -6018,10 +6149,12 @@ var mfaChallenge = ({
6018
6149
  onMfaChallengeError,
6019
6150
  onMfaChallengeSuccess,
6020
6151
  onSendSmsCode,
6152
+ verificationProvider,
6021
6153
  sessionDurationMs = DEFAULT_MFA_SESSION_TTL_MS,
6022
6154
  smsCodeLength = DEFAULT_SMS_CODE_LENGTH,
6023
6155
  smsCodeTtlMs = DEFAULT_SMS_CODE_TTL_MS,
6024
6156
  smsMaxAttempts = DEFAULT_SMS_MAX_ATTEMPTS,
6157
+ smsResendCooldownMs = DEFAULT_SMS_RESEND_COOLDOWN_MS,
6025
6158
  totpMaxAttempts = DEFAULT_TOTP_MAX_ATTEMPTS
6026
6159
  }) => new Elysia18().use(sessionStore()).post(challengeRoute, async ({
6027
6160
  body: { action, code, factor },
@@ -6063,27 +6196,48 @@ var mfaChallenge = ({
6063
6196
  await onMfaChallengeSuccess?.({ user, userSessionId });
6064
6197
  return status("OK", { status: "authenticated" });
6065
6198
  };
6066
- const runSmsChallenge = async () => {
6067
- if (!enrollment.smsVerified || !enrollment.smsPhone) {
6068
- return status("Unauthorized", "No MFA challenge in progress");
6199
+ const sendSmsChallenge = async () => {
6200
+ if (enrollment.smsCodeSentAt !== undefined && Date.now() - enrollment.smsCodeSentAt < smsResendCooldownMs) {
6201
+ return status("Too Many Requests", "SMS resend cooldown active");
6069
6202
  }
6070
- if (action === "send") {
6203
+ try {
6071
6204
  await issueAndStoreSmsCode({
6072
6205
  codeLength: smsCodeLength,
6073
6206
  enrollment,
6074
6207
  mfaStore,
6075
6208
  onSendSmsCode,
6076
- ttlMs: smsCodeTtlMs
6209
+ purpose: "mfa_challenge",
6210
+ ttlMs: smsCodeTtlMs,
6211
+ userId: getUserId(user),
6212
+ verificationProvider
6077
6213
  });
6078
- return status("OK", { status: "sent" });
6214
+ } catch (error) {
6215
+ const mapped = mapVerificationProviderError(error);
6216
+ if (mapped === undefined)
6217
+ throw error;
6218
+ return status(mapped.status, mapped.message);
6079
6219
  }
6220
+ return status("OK", { status: "sent" });
6221
+ };
6222
+ const runSmsChallenge = async () => {
6223
+ if (!enrollment.smsVerified || !enrollment.smsPhone) {
6224
+ return status("Unauthorized", "No MFA challenge in progress");
6225
+ }
6226
+ if (action === "send")
6227
+ return sendSmsChallenge();
6080
6228
  if (code === undefined) {
6081
6229
  return status("Bad Request", "SMS code required");
6082
6230
  }
6083
- if (!enrollment.smsPendingCodeHash || enrollment.smsPendingCodeExpiresAt === undefined) {
6231
+ const localCodeHash = enrollment.smsPendingCodeHash;
6232
+ const localCodeExpiresAt = enrollment.smsPendingCodeExpiresAt;
6233
+ const providerReference = enrollment.smsProviderReference;
6234
+ if (enrollment.smsPendingPurpose !== "mfa_challenge" || localCodeExpiresAt === undefined) {
6084
6235
  return status("Bad Request", "No SMS code in progress");
6085
6236
  }
6086
- if (Date.now() > enrollment.smsPendingCodeExpiresAt) {
6237
+ if (verificationProvider === undefined && localCodeHash === undefined) {
6238
+ return status("Bad Request", "No SMS code in progress");
6239
+ }
6240
+ if (Date.now() > localCodeExpiresAt) {
6087
6241
  return status("Unauthorized", "SMS code expired");
6088
6242
  }
6089
6243
  if ((enrollment.smsFailedAttempts ?? 0) >= smsMaxAttempts) {
@@ -6093,7 +6247,25 @@ var mfaChallenge = ({
6093
6247
  });
6094
6248
  return status("Unauthorized", "Too many attempts");
6095
6249
  }
6096
- const smsValid = await constantTimeEqual(await hashToken(code), enrollment.smsPendingCodeHash);
6250
+ let providerResult;
6251
+ if (verificationProvider !== undefined) {
6252
+ if (providerReference === undefined) {
6253
+ return status("Bad Request", "No SMS code in progress");
6254
+ }
6255
+ const checked = await checkWithVerificationProvider(verificationProvider, {
6256
+ channel: "sms",
6257
+ code,
6258
+ purpose: "mfa_challenge",
6259
+ reference: providerReference,
6260
+ subject: getUserId(user),
6261
+ to: enrollment.smsPhone
6262
+ });
6263
+ if (checked.error !== undefined) {
6264
+ return status(checked.error.status, checked.error.message);
6265
+ }
6266
+ providerResult = checked.result;
6267
+ }
6268
+ const smsValid = providerResult ? providerResult.status === "approved" : localCodeHash !== undefined && await constantTimeEqual(await hashToken(code), localCodeHash);
6097
6269
  if (!smsValid) {
6098
6270
  await mfaStore.saveEnrollment({
6099
6271
  ...enrollment,
@@ -6104,7 +6276,7 @@ var mfaChallenge = ({
6104
6276
  error: new Error("invalid_mfa_code"),
6105
6277
  userId: getUserId(user)
6106
6278
  });
6107
- return status("Unauthorized", "Invalid MFA code");
6279
+ return status(providerResult?.status === "max_attempts_reached" ? "Too Many Requests" : "Unauthorized", providerResult?.status === "expired" ? "SMS code expired" : "Invalid MFA code");
6108
6280
  }
6109
6281
  await mfaStore.saveEnrollment({
6110
6282
  ...enrollment,
@@ -6112,6 +6284,8 @@ var mfaChallenge = ({
6112
6284
  smsFailedAttempts: 0,
6113
6285
  smsPendingCodeExpiresAt: undefined,
6114
6286
  smsPendingCodeHash: undefined,
6287
+ smsPendingPurpose: undefined,
6288
+ smsProviderReference: undefined,
6115
6289
  updatedAt: Date.now()
6116
6290
  });
6117
6291
  return promote();
@@ -31840,12 +32014,15 @@ var mfaEnrollmentsTable = pgTable("auth_mfa_enrollments", {
31840
32014
  backup_code_hashes: jsonb("backup_code_hashes").$type().notNull().default([]),
31841
32015
  created_at_ms: bigint("created_at_ms", { mode: "number" }).notNull(),
31842
32016
  last_used_at_ms: bigint("last_used_at_ms", { mode: "number" }),
32017
+ sms_code_sent_at_ms: bigint("sms_code_sent_at_ms", { mode: "number" }),
31843
32018
  sms_failed_attempts: smallint("sms_failed_attempts").notNull().default(0),
31844
32019
  sms_pending_code_expires_at_ms: bigint("sms_pending_code_expires_at_ms", {
31845
32020
  mode: "number"
31846
32021
  }),
31847
32022
  sms_pending_code_hash: text("sms_pending_code_hash"),
32023
+ sms_pending_purpose: text("sms_pending_purpose").$type(),
31848
32024
  sms_phone: varchar("sms_phone", { length: PHONE_LENGTH }),
32025
+ sms_provider_reference: text("sms_provider_reference"),
31849
32026
  sms_verified: boolean("sms_verified").notNull().default(false),
31850
32027
  totp_failed_attempts: smallint("totp_failed_attempts").notNull().default(0),
31851
32028
  totp_secret_ciphertext: text("totp_secret_ciphertext"),
@@ -31857,10 +32034,13 @@ var toEnrollment = (row) => ({
31857
32034
  backupCodeHashes: row.backup_code_hashes,
31858
32035
  createdAt: row.created_at_ms,
31859
32036
  lastUsedAt: row.last_used_at_ms ?? undefined,
32037
+ smsCodeSentAt: row.sms_code_sent_at_ms ?? undefined,
31860
32038
  smsFailedAttempts: row.sms_failed_attempts,
31861
32039
  smsPendingCodeExpiresAt: row.sms_pending_code_expires_at_ms ?? undefined,
31862
32040
  smsPendingCodeHash: row.sms_pending_code_hash ?? undefined,
32041
+ smsPendingPurpose: row.sms_pending_purpose ?? undefined,
31863
32042
  smsPhone: row.sms_phone ?? undefined,
32043
+ smsProviderReference: row.sms_provider_reference ?? undefined,
31864
32044
  smsVerified: row.sms_verified,
31865
32045
  totpFailedAttempts: row.totp_failed_attempts,
31866
32046
  totpSecretCiphertext: row.totp_secret_ciphertext ?? undefined,
@@ -31886,10 +32066,13 @@ var createPostgresMfaStore = (db) => ({
31886
32066
  backup_code_hashes: enrollment.backupCodeHashes,
31887
32067
  created_at_ms: enrollment.createdAt,
31888
32068
  last_used_at_ms: enrollment.lastUsedAt ?? null,
32069
+ sms_code_sent_at_ms: enrollment.smsCodeSentAt ?? null,
31889
32070
  sms_failed_attempts: enrollment.smsFailedAttempts ?? 0,
31890
32071
  sms_pending_code_expires_at_ms: enrollment.smsPendingCodeExpiresAt ?? null,
31891
32072
  sms_pending_code_hash: enrollment.smsPendingCodeHash ?? null,
32073
+ sms_pending_purpose: enrollment.smsPendingPurpose ?? null,
31892
32074
  sms_phone: enrollment.smsPhone ?? null,
32075
+ sms_provider_reference: enrollment.smsProviderReference ?? null,
31893
32076
  sms_verified: enrollment.smsVerified,
31894
32077
  totp_failed_attempts: enrollment.totpFailedAttempts ?? 0,
31895
32078
  totp_secret_ciphertext: enrollment.totpSecretCiphertext ?? null,
@@ -36238,6 +36421,15 @@ var mfaTotpLockoutMigration = {
36238
36421
  id: "0003_totp_lockout",
36239
36422
  sql: 'ALTER TABLE "auth_mfa_enrollments" ADD COLUMN IF NOT EXISTS "totp_failed_attempts" smallint NOT NULL DEFAULT 0;'
36240
36423
  };
36424
+ var mfaSmsDeliveryPolicyMigration = {
36425
+ id: "0004_sms_delivery_policy",
36426
+ sql: [
36427
+ 'ALTER TABLE "auth_mfa_enrollments" ADD COLUMN IF NOT EXISTS "sms_code_sent_at_ms" bigint;',
36428
+ 'ALTER TABLE "auth_mfa_enrollments" ADD COLUMN IF NOT EXISTS "sms_pending_purpose" text;',
36429
+ 'ALTER TABLE "auth_mfa_enrollments" ADD COLUMN IF NOT EXISTS "sms_provider_reference" text;'
36430
+ ].join(`
36431
+ `)
36432
+ };
36241
36433
  var oidcResourceAudienceMigration = {
36242
36434
  id: "0002_resource_audience",
36243
36435
  sql: [
@@ -36292,7 +36484,8 @@ var blockMigrations = {
36292
36484
  migrations: [
36293
36485
  ...initMigration("mfa", [mfaEnrollmentsTable]).migrations,
36294
36486
  mfaSmsColumnsMigration,
36295
- mfaTotpLockoutMigration
36487
+ mfaTotpLockoutMigration,
36488
+ mfaSmsDeliveryPolicyMigration
36296
36489
  ]
36297
36490
  },
36298
36491
  oidc: {
@@ -36805,6 +36998,7 @@ var buildAuthApplications = async (configuration) => {
36805
36998
  credentials,
36806
36999
  customProviders,
36807
37000
  mfa,
37001
+ verificationProvider,
36808
37002
  passwordless,
36809
37003
  lockout,
36810
37004
  sessions,
@@ -37037,7 +37231,8 @@ var buildAuthApplications = async (configuration) => {
37037
37231
  auditedMfa ? mfaRoutes({
37038
37232
  ...auditedMfa,
37039
37233
  authSessionStore,
37040
- cookieSecure: resolvedCookieSecure
37234
+ cookieSecure: resolvedCookieSecure,
37235
+ verificationProvider
37041
37236
  }) : new Elysia45,
37042
37237
  passwordless ? passwordlessRoutes({
37043
37238
  ...passwordless,
@@ -37564,6 +37759,7 @@ export {
37564
37759
  accessTokensTable,
37565
37760
  acceptInvitation,
37566
37761
  WEBAUTHN_CHALLENGE_COOKIE,
37762
+ VerificationProviderError,
37567
37763
  STATUS_LIST_TYP,
37568
37764
  STATUS_LIST_SUB_TYP,
37569
37765
  REQUEST_URI_PREFIX,
@@ -37581,6 +37777,7 @@ export {
37581
37777
  DEFAULT_STATUS_ROUTE,
37582
37778
  DEFAULT_SSO_SESSION_TTL_MS,
37583
37779
  DEFAULT_SSO_ROUTE,
37780
+ DEFAULT_SMS_RESEND_COOLDOWN_MS,
37584
37781
  DEFAULT_SMS_MAX_ATTEMPTS,
37585
37782
  DEFAULT_SMS_CODE_TTL_MS,
37586
37783
  DEFAULT_SMS_CODE_LENGTH,
@@ -37613,5 +37810,5 @@ export {
37613
37810
  AGENT_CLAIM_GRANT_TYPE
37614
37811
  };
37615
37812
 
37616
- //# debugId=0FBF734780C91B5D64756E2164756E21
37813
+ //# debugId=588FAC011547AB7964756E2164756E21
37617
37814
  //# sourceMappingURL=index.js.map