@aooth/user 0.1.1

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.
@@ -0,0 +1,233 @@
1
+ import { C as UserStoreUpdate, S as UserServiceConfig, _ as TotpConfig, a as LockoutConfig, b as UserAuthErrorType, c as MfaMethod, d as PasswordData, f as PasswordPolicyContext, g as PolicyCheckResult, h as PasswordPolicyInstance, i as LockStatus, l as MfaMethodInfo, m as PasswordPolicyEvalFn, n as AccountData, o as LoginResult, p as PasswordPolicyDef, r as DeepPartial, s as MfaData, t as UserStore, u as PasswordConfig, v as TransferablePolicy, x as UserCredentials, y as TrustedDeviceRecord } from "./user-store-VJPWNgdp.cjs";
2
+
3
+ //#region src/errors.d.ts
4
+ declare class UserAuthError extends Error {
5
+ readonly type: UserAuthErrorType;
6
+ readonly details?: Record<string, unknown> | undefined;
7
+ readonly name = "UserAuthError";
8
+ constructor(type: UserAuthErrorType, message?: string, details?: Record<string, unknown> | undefined);
9
+ }
10
+ //#endregion
11
+ //#region src/password/hasher.d.ts
12
+ declare class PasswordHasher {
13
+ private readonly pepper;
14
+ private readonly N;
15
+ private readonly r;
16
+ private readonly p;
17
+ private readonly keyLength;
18
+ constructor(config?: PasswordConfig);
19
+ hash(password: string): Promise<string>;
20
+ verify(password: string, encoded: string): Promise<boolean>;
21
+ generatePassword(length?: number): string;
22
+ }
23
+ //#endregion
24
+ //#region src/password/policy.d.ts
25
+ declare function normalizePolicies(policies?: (PasswordPolicyDef | PasswordPolicyInstance)[]): PasswordPolicy[];
26
+ declare class PasswordPolicy implements PasswordPolicyInstance {
27
+ readonly rule: string | PasswordPolicyEvalFn;
28
+ readonly description: string;
29
+ readonly errorMessage: string;
30
+ constructor(config: PasswordPolicyDef);
31
+ protected _evalFn: PasswordPolicyEvalFn;
32
+ evaluate(password: string, context?: PasswordPolicyContext): boolean | Promise<boolean>;
33
+ get transferable(): boolean;
34
+ }
35
+ //#endregion
36
+ //#region src/user-service.d.ts
37
+ interface ResolvedConfig {
38
+ password: Required<Omit<PasswordConfig, "policies">> & {
39
+ policies: PasswordPolicy[];
40
+ };
41
+ lockout: Required<LockoutConfig>;
42
+ clock: () => number;
43
+ deviceTrust?: {
44
+ secret: string;
45
+ };
46
+ }
47
+ declare class UserService<T extends object = object> {
48
+ protected readonly store: UserStore<T>;
49
+ protected readonly config: ResolvedConfig;
50
+ protected readonly hasher: PasswordHasher;
51
+ constructor(store: UserStore<T>, config?: UserServiceConfig);
52
+ /**
53
+ * @param extras Optional partial user fields merged AFTER the base
54
+ * `UserCredentials` shape, so callers can populate consumer-specific
55
+ * required fields (e.g. `tenantId`) without subclassing the store.
56
+ * Because the merge is shallow and extras win, overlapping top-level
57
+ * keys (`id`, `account`, `mfa`, ...) replace the defaults entirely —
58
+ * pass nested objects with all required sub-fields if you intend to
59
+ * override them.
60
+ */
61
+ createUser(username: string, password?: string, extras?: Partial<T>): Promise<UserCredentials & T>;
62
+ getUser(username: string): Promise<UserCredentials & T>;
63
+ login(username: string, password: string): Promise<LoginResult<T>>;
64
+ verifyPassword(username: string, password: string): Promise<boolean>;
65
+ changePassword(username: string, currentPassword: string, newPassword: string, repeatPassword?: string): Promise<void>;
66
+ setPassword(username: string, newPassword: string): Promise<void>;
67
+ /**
68
+ * Hard-delete the user row. Returns nothing on success. Throws
69
+ * `UserAuthError("NOT_FOUND")` when no row matches `username`. Used by the
70
+ * invite workflow's `auth.cancelInvite` to revoke a pending invitation.
71
+ */
72
+ deleteUser(username: string): Promise<void>;
73
+ /**
74
+ * Deep-merge `patch` into the user record (top-level fields are shallow-
75
+ * merged; `account` / `mfa` / `password` are merged per their
76
+ * `@db.patch.strategy 'merge'` declaration). Returns the patched record.
77
+ * Used by the invite workflow's `applyProfile` default fallback.
78
+ */
79
+ update(username: string, patch: Partial<UserCredentials & T>): Promise<UserCredentials & T>;
80
+ activateAccount(username: string): Promise<void>;
81
+ deactivateAccount(username: string): Promise<void>;
82
+ lockAccount(username: string, reason: string, duration?: number): Promise<void>;
83
+ unlockAccount(username: string): Promise<void>;
84
+ getLockStatus(account: UserCredentials["account"]): LockStatus;
85
+ checkPolicies(password: string, passwordData?: PasswordData): Promise<PolicyCheckResult>;
86
+ getTransferablePolicies(): TransferablePolicy[];
87
+ addMfaMethod(username: string, method: MfaMethod): Promise<void>;
88
+ confirmMfaMethod(username: string, name: string): Promise<void>;
89
+ removeMfaMethod(username: string, name: string): Promise<void>;
90
+ setDefaultMfaMethod(username: string, name: string): Promise<void>;
91
+ setMfaAutoSend(username: string, value: boolean): Promise<void>;
92
+ getAvailableMfaMethods(mfa: MfaData): MfaMethodInfo[];
93
+ /**
94
+ * Generate `count` plaintext backup codes (default 10), persist their
95
+ * hashes (replacing any existing batch), and return the plaintext codes
96
+ * once for the caller to deliver to the user. Plaintext is never
97
+ * recoverable after this call returns.
98
+ *
99
+ * Throws `UserAuthError("NOT_FOUND")` if the user does not exist.
100
+ */
101
+ generateBackupCodes(username: string, count?: number): Promise<string[]>;
102
+ /**
103
+ * Consume a backup code: returns `true` and removes the matching hash
104
+ * from storage if `code` matches a stored backup code; returns `false`
105
+ * if no match (without modifying storage).
106
+ *
107
+ * Read-then-write is not atomic at this layer: two concurrent consumes
108
+ * of the same code may both succeed, with the last write winning. The
109
+ * underlying store API does not expose an atomic match-and-remove, so
110
+ * this is acceptable at the intended scale (backup codes are a fallback
111
+ * path, not a hot one). Wrap in your store's transaction primitive if a
112
+ * stricter guarantee is required.
113
+ *
114
+ * Throws `UserAuthError("NOT_FOUND")` if the user does not exist.
115
+ */
116
+ consumeBackupCode(username: string, code: string): Promise<boolean>;
117
+ /**
118
+ * Verify a TOTP code against the user's confirmed `totp` MFA method.
119
+ * Failures bump the same `failedLoginAttempts` counter as `login` so an
120
+ * attacker who knows the password but not the TOTP gets `lockout.threshold`
121
+ * total tries across BOTH factors, not `2 * threshold`.
122
+ */
123
+ verifyMfa(username: string, code: string, config?: TotpConfig): Promise<void>;
124
+ getPasswordHasher(): PasswordHasher;
125
+ getConfig(): Readonly<ResolvedConfig>;
126
+ /**
127
+ * Mint a freshly-signed trust record (does NOT persist — pair with
128
+ * `addTrustedDevice`). Throws when `deviceTrust.secret` is unset.
129
+ */
130
+ issueTrustedDevice(userId: string, opts: {
131
+ ip?: string;
132
+ ttlMs: number;
133
+ name?: string;
134
+ }): TrustedDeviceRecord;
135
+ /**
136
+ * Append a trust record to the user's `trustedDevices` list. Read-modify-
137
+ * write — the array shape is preserved end-to-end so DB adapters with a
138
+ * merge strategy replace the whole array.
139
+ */
140
+ addTrustedDevice(username: string, record: TrustedDeviceRecord): Promise<void>;
141
+ /**
142
+ * Returns true when the supplied token (a) signs against the user+ip with
143
+ * the configured secret, AND (b) matches a persisted record that is still
144
+ * within its expiry window and whose bound IP (if any) matches.
145
+ */
146
+ verifyTrustedDevice(username: string, token: string, ip?: string): Promise<boolean>;
147
+ /**
148
+ * Remove a specific trust record from the user. No-op when the record is
149
+ * absent — mirrors the legacy `DeviceTrustStore.revoke` semantics.
150
+ */
151
+ revokeTrustedDevice(username: string, token: string): Promise<void>;
152
+ listTrustedDevices(username: string): Promise<TrustedDeviceRecord[]>;
153
+ private requireDeviceTrustSecret;
154
+ private applyPasswordChange;
155
+ private hasConfirmedMfaMethods;
156
+ /**
157
+ * If `account.locked`: auto-unlock when the lock has expired (mutating
158
+ * `account` in place), or throw `LOCKED` otherwise.
159
+ */
160
+ private ensureNotLockedOrThrow;
161
+ /**
162
+ * Bump `failedLoginAttempts`, locking the account when threshold is hit,
163
+ * and always throw `errorCode` (with `details.lockEnds` when the lockout
164
+ * just tripped). Used by both `login` and `verifyMfa` so the two factors
165
+ * share one counter.
166
+ */
167
+ private incrementAndMaybeLock;
168
+ }
169
+ //#endregion
170
+ //#region src/store/memory.d.ts
171
+ declare class UserStoreMemory<T extends object = object> extends UserStore<T> {
172
+ private store;
173
+ constructor(seed?: Record<string, UserCredentials & T>);
174
+ exists(username: string): Promise<boolean>;
175
+ findByUsername(username: string): Promise<(UserCredentials & T) | null>;
176
+ create(data: UserCredentials & T): Promise<void>;
177
+ update(username: string, update: UserStoreUpdate): Promise<boolean>;
178
+ delete(username: string): Promise<boolean>;
179
+ }
180
+ //#endregion
181
+ //#region src/password/policies.d.ts
182
+ declare const ppHasMinLength: (min?: number) => PasswordPolicyDef;
183
+ declare const ppHasUpperCase: (n?: number) => PasswordPolicyDef;
184
+ declare const ppHasLowerCase: (n?: number) => PasswordPolicyDef;
185
+ declare const ppHasNumber: (n?: number) => PasswordPolicyDef;
186
+ declare const ppHasSpecialChar: (n?: number) => PasswordPolicyDef;
187
+ declare const ppMaxRepeatedChars: (maxRepeated?: number) => PasswordPolicyDef;
188
+ //#endregion
189
+ //#region src/mfa/totp.d.ts
190
+ declare function generateTotpSecret(bytes?: number): string;
191
+ declare function generateTotpUri(secret: string, issuer: string, account: string, config?: Pick<TotpConfig, "period" | "digits">): string;
192
+ declare function generateTotpCode(secret: string, config?: TotpConfig): string;
193
+ declare function verifyTotpCode(secret: string, code: string, config?: TotpConfig): boolean;
194
+ declare function generateMfaCode(length?: number): string;
195
+ //#endregion
196
+ //#region src/mfa/codes.d.ts
197
+ /**
198
+ * SHA-256 hash of an MFA code (e.g. one-time email/SMS code or backup code).
199
+ *
200
+ * Hex-encoded for stable, comparable output regardless of input case/format.
201
+ * Use {@link verifyMfaCode} to compare a submitted plaintext code against the
202
+ * stored hash in constant time.
203
+ */
204
+ declare function hashMfaCode(code: string): string;
205
+ /**
206
+ * Constant-time comparison of a submitted plaintext code against an
207
+ * expected SHA-256 hex hash (as produced by {@link hashMfaCode}).
208
+ *
209
+ * Returns false for malformed/empty expected hashes (timingSafeEqual
210
+ * requires equal-length, non-empty buffers).
211
+ */
212
+ declare function verifyMfaCode(submitted: string, expectedHash: string): boolean;
213
+ //#endregion
214
+ //#region src/mfa/backup-codes.d.ts
215
+ /**
216
+ * Generate `count` cryptographically-random backup codes (default 10).
217
+ *
218
+ * Format: 10 characters from the 31-char safe alphabet (uppercase letters +
219
+ * digits, omitting I/O/L/0/1), grouped as `XXXX-XXXX-XX`.
220
+ *
221
+ * Returns plaintext codes for the caller to deliver to the user — these
222
+ * should be hashed via {@link hashMfaCode} before persistence and never
223
+ * shown to the user again.
224
+ */
225
+ declare function generateBackupCodePlaintext(count?: number): string[];
226
+ //#endregion
227
+ //#region src/utils.d.ts
228
+ declare function maskEmail(email: string): string;
229
+ declare function maskPhone(phone: string): string;
230
+ declare function maskMfaValue(method: MfaMethod): string;
231
+ declare function setAtPath(obj: object, path: string, value: unknown): void;
232
+ //#endregion
233
+ export { type AccountData, type DeepPartial, type LockStatus, type LockoutConfig, type LoginResult, type MfaData, type MfaMethod, type MfaMethodInfo, type PasswordConfig, type PasswordData, PasswordHasher, PasswordPolicy, type PasswordPolicyContext, type PasswordPolicyDef, type PasswordPolicyEvalFn, type PasswordPolicyInstance, type PolicyCheckResult, type TotpConfig, type TransferablePolicy, type TrustedDeviceRecord, UserAuthError, type UserAuthErrorType, type UserCredentials, UserService, type UserServiceConfig, UserStore, UserStoreMemory, type UserStoreUpdate, generateBackupCodePlaintext, generateMfaCode, generateTotpCode, generateTotpSecret, generateTotpUri, hashMfaCode, maskEmail, maskMfaValue, maskPhone, normalizePolicies, ppHasLowerCase, ppHasMinLength, ppHasNumber, ppHasSpecialChar, ppHasUpperCase, ppMaxRepeatedChars, setAtPath, verifyMfaCode, verifyTotpCode };
@@ -0,0 +1,233 @@
1
+ import { C as UserStoreUpdate, S as UserServiceConfig, _ as TotpConfig, a as LockoutConfig, b as UserAuthErrorType, c as MfaMethod, d as PasswordData, f as PasswordPolicyContext, g as PolicyCheckResult, h as PasswordPolicyInstance, i as LockStatus, l as MfaMethodInfo, m as PasswordPolicyEvalFn, n as AccountData, o as LoginResult, p as PasswordPolicyDef, r as DeepPartial, s as MfaData, t as UserStore, u as PasswordConfig, v as TransferablePolicy, x as UserCredentials, y as TrustedDeviceRecord } from "./user-store-Dbc9unW3.mjs";
2
+
3
+ //#region src/errors.d.ts
4
+ declare class UserAuthError extends Error {
5
+ readonly type: UserAuthErrorType;
6
+ readonly details?: Record<string, unknown> | undefined;
7
+ readonly name = "UserAuthError";
8
+ constructor(type: UserAuthErrorType, message?: string, details?: Record<string, unknown> | undefined);
9
+ }
10
+ //#endregion
11
+ //#region src/password/hasher.d.ts
12
+ declare class PasswordHasher {
13
+ private readonly pepper;
14
+ private readonly N;
15
+ private readonly r;
16
+ private readonly p;
17
+ private readonly keyLength;
18
+ constructor(config?: PasswordConfig);
19
+ hash(password: string): Promise<string>;
20
+ verify(password: string, encoded: string): Promise<boolean>;
21
+ generatePassword(length?: number): string;
22
+ }
23
+ //#endregion
24
+ //#region src/password/policy.d.ts
25
+ declare function normalizePolicies(policies?: (PasswordPolicyDef | PasswordPolicyInstance)[]): PasswordPolicy[];
26
+ declare class PasswordPolicy implements PasswordPolicyInstance {
27
+ readonly rule: string | PasswordPolicyEvalFn;
28
+ readonly description: string;
29
+ readonly errorMessage: string;
30
+ constructor(config: PasswordPolicyDef);
31
+ protected _evalFn: PasswordPolicyEvalFn;
32
+ evaluate(password: string, context?: PasswordPolicyContext): boolean | Promise<boolean>;
33
+ get transferable(): boolean;
34
+ }
35
+ //#endregion
36
+ //#region src/user-service.d.ts
37
+ interface ResolvedConfig {
38
+ password: Required<Omit<PasswordConfig, "policies">> & {
39
+ policies: PasswordPolicy[];
40
+ };
41
+ lockout: Required<LockoutConfig>;
42
+ clock: () => number;
43
+ deviceTrust?: {
44
+ secret: string;
45
+ };
46
+ }
47
+ declare class UserService<T extends object = object> {
48
+ protected readonly store: UserStore<T>;
49
+ protected readonly config: ResolvedConfig;
50
+ protected readonly hasher: PasswordHasher;
51
+ constructor(store: UserStore<T>, config?: UserServiceConfig);
52
+ /**
53
+ * @param extras Optional partial user fields merged AFTER the base
54
+ * `UserCredentials` shape, so callers can populate consumer-specific
55
+ * required fields (e.g. `tenantId`) without subclassing the store.
56
+ * Because the merge is shallow and extras win, overlapping top-level
57
+ * keys (`id`, `account`, `mfa`, ...) replace the defaults entirely —
58
+ * pass nested objects with all required sub-fields if you intend to
59
+ * override them.
60
+ */
61
+ createUser(username: string, password?: string, extras?: Partial<T>): Promise<UserCredentials & T>;
62
+ getUser(username: string): Promise<UserCredentials & T>;
63
+ login(username: string, password: string): Promise<LoginResult<T>>;
64
+ verifyPassword(username: string, password: string): Promise<boolean>;
65
+ changePassword(username: string, currentPassword: string, newPassword: string, repeatPassword?: string): Promise<void>;
66
+ setPassword(username: string, newPassword: string): Promise<void>;
67
+ /**
68
+ * Hard-delete the user row. Returns nothing on success. Throws
69
+ * `UserAuthError("NOT_FOUND")` when no row matches `username`. Used by the
70
+ * invite workflow's `auth.cancelInvite` to revoke a pending invitation.
71
+ */
72
+ deleteUser(username: string): Promise<void>;
73
+ /**
74
+ * Deep-merge `patch` into the user record (top-level fields are shallow-
75
+ * merged; `account` / `mfa` / `password` are merged per their
76
+ * `@db.patch.strategy 'merge'` declaration). Returns the patched record.
77
+ * Used by the invite workflow's `applyProfile` default fallback.
78
+ */
79
+ update(username: string, patch: Partial<UserCredentials & T>): Promise<UserCredentials & T>;
80
+ activateAccount(username: string): Promise<void>;
81
+ deactivateAccount(username: string): Promise<void>;
82
+ lockAccount(username: string, reason: string, duration?: number): Promise<void>;
83
+ unlockAccount(username: string): Promise<void>;
84
+ getLockStatus(account: UserCredentials["account"]): LockStatus;
85
+ checkPolicies(password: string, passwordData?: PasswordData): Promise<PolicyCheckResult>;
86
+ getTransferablePolicies(): TransferablePolicy[];
87
+ addMfaMethod(username: string, method: MfaMethod): Promise<void>;
88
+ confirmMfaMethod(username: string, name: string): Promise<void>;
89
+ removeMfaMethod(username: string, name: string): Promise<void>;
90
+ setDefaultMfaMethod(username: string, name: string): Promise<void>;
91
+ setMfaAutoSend(username: string, value: boolean): Promise<void>;
92
+ getAvailableMfaMethods(mfa: MfaData): MfaMethodInfo[];
93
+ /**
94
+ * Generate `count` plaintext backup codes (default 10), persist their
95
+ * hashes (replacing any existing batch), and return the plaintext codes
96
+ * once for the caller to deliver to the user. Plaintext is never
97
+ * recoverable after this call returns.
98
+ *
99
+ * Throws `UserAuthError("NOT_FOUND")` if the user does not exist.
100
+ */
101
+ generateBackupCodes(username: string, count?: number): Promise<string[]>;
102
+ /**
103
+ * Consume a backup code: returns `true` and removes the matching hash
104
+ * from storage if `code` matches a stored backup code; returns `false`
105
+ * if no match (without modifying storage).
106
+ *
107
+ * Read-then-write is not atomic at this layer: two concurrent consumes
108
+ * of the same code may both succeed, with the last write winning. The
109
+ * underlying store API does not expose an atomic match-and-remove, so
110
+ * this is acceptable at the intended scale (backup codes are a fallback
111
+ * path, not a hot one). Wrap in your store's transaction primitive if a
112
+ * stricter guarantee is required.
113
+ *
114
+ * Throws `UserAuthError("NOT_FOUND")` if the user does not exist.
115
+ */
116
+ consumeBackupCode(username: string, code: string): Promise<boolean>;
117
+ /**
118
+ * Verify a TOTP code against the user's confirmed `totp` MFA method.
119
+ * Failures bump the same `failedLoginAttempts` counter as `login` so an
120
+ * attacker who knows the password but not the TOTP gets `lockout.threshold`
121
+ * total tries across BOTH factors, not `2 * threshold`.
122
+ */
123
+ verifyMfa(username: string, code: string, config?: TotpConfig): Promise<void>;
124
+ getPasswordHasher(): PasswordHasher;
125
+ getConfig(): Readonly<ResolvedConfig>;
126
+ /**
127
+ * Mint a freshly-signed trust record (does NOT persist — pair with
128
+ * `addTrustedDevice`). Throws when `deviceTrust.secret` is unset.
129
+ */
130
+ issueTrustedDevice(userId: string, opts: {
131
+ ip?: string;
132
+ ttlMs: number;
133
+ name?: string;
134
+ }): TrustedDeviceRecord;
135
+ /**
136
+ * Append a trust record to the user's `trustedDevices` list. Read-modify-
137
+ * write — the array shape is preserved end-to-end so DB adapters with a
138
+ * merge strategy replace the whole array.
139
+ */
140
+ addTrustedDevice(username: string, record: TrustedDeviceRecord): Promise<void>;
141
+ /**
142
+ * Returns true when the supplied token (a) signs against the user+ip with
143
+ * the configured secret, AND (b) matches a persisted record that is still
144
+ * within its expiry window and whose bound IP (if any) matches.
145
+ */
146
+ verifyTrustedDevice(username: string, token: string, ip?: string): Promise<boolean>;
147
+ /**
148
+ * Remove a specific trust record from the user. No-op when the record is
149
+ * absent — mirrors the legacy `DeviceTrustStore.revoke` semantics.
150
+ */
151
+ revokeTrustedDevice(username: string, token: string): Promise<void>;
152
+ listTrustedDevices(username: string): Promise<TrustedDeviceRecord[]>;
153
+ private requireDeviceTrustSecret;
154
+ private applyPasswordChange;
155
+ private hasConfirmedMfaMethods;
156
+ /**
157
+ * If `account.locked`: auto-unlock when the lock has expired (mutating
158
+ * `account` in place), or throw `LOCKED` otherwise.
159
+ */
160
+ private ensureNotLockedOrThrow;
161
+ /**
162
+ * Bump `failedLoginAttempts`, locking the account when threshold is hit,
163
+ * and always throw `errorCode` (with `details.lockEnds` when the lockout
164
+ * just tripped). Used by both `login` and `verifyMfa` so the two factors
165
+ * share one counter.
166
+ */
167
+ private incrementAndMaybeLock;
168
+ }
169
+ //#endregion
170
+ //#region src/store/memory.d.ts
171
+ declare class UserStoreMemory<T extends object = object> extends UserStore<T> {
172
+ private store;
173
+ constructor(seed?: Record<string, UserCredentials & T>);
174
+ exists(username: string): Promise<boolean>;
175
+ findByUsername(username: string): Promise<(UserCredentials & T) | null>;
176
+ create(data: UserCredentials & T): Promise<void>;
177
+ update(username: string, update: UserStoreUpdate): Promise<boolean>;
178
+ delete(username: string): Promise<boolean>;
179
+ }
180
+ //#endregion
181
+ //#region src/password/policies.d.ts
182
+ declare const ppHasMinLength: (min?: number) => PasswordPolicyDef;
183
+ declare const ppHasUpperCase: (n?: number) => PasswordPolicyDef;
184
+ declare const ppHasLowerCase: (n?: number) => PasswordPolicyDef;
185
+ declare const ppHasNumber: (n?: number) => PasswordPolicyDef;
186
+ declare const ppHasSpecialChar: (n?: number) => PasswordPolicyDef;
187
+ declare const ppMaxRepeatedChars: (maxRepeated?: number) => PasswordPolicyDef;
188
+ //#endregion
189
+ //#region src/mfa/totp.d.ts
190
+ declare function generateTotpSecret(bytes?: number): string;
191
+ declare function generateTotpUri(secret: string, issuer: string, account: string, config?: Pick<TotpConfig, "period" | "digits">): string;
192
+ declare function generateTotpCode(secret: string, config?: TotpConfig): string;
193
+ declare function verifyTotpCode(secret: string, code: string, config?: TotpConfig): boolean;
194
+ declare function generateMfaCode(length?: number): string;
195
+ //#endregion
196
+ //#region src/mfa/codes.d.ts
197
+ /**
198
+ * SHA-256 hash of an MFA code (e.g. one-time email/SMS code or backup code).
199
+ *
200
+ * Hex-encoded for stable, comparable output regardless of input case/format.
201
+ * Use {@link verifyMfaCode} to compare a submitted plaintext code against the
202
+ * stored hash in constant time.
203
+ */
204
+ declare function hashMfaCode(code: string): string;
205
+ /**
206
+ * Constant-time comparison of a submitted plaintext code against an
207
+ * expected SHA-256 hex hash (as produced by {@link hashMfaCode}).
208
+ *
209
+ * Returns false for malformed/empty expected hashes (timingSafeEqual
210
+ * requires equal-length, non-empty buffers).
211
+ */
212
+ declare function verifyMfaCode(submitted: string, expectedHash: string): boolean;
213
+ //#endregion
214
+ //#region src/mfa/backup-codes.d.ts
215
+ /**
216
+ * Generate `count` cryptographically-random backup codes (default 10).
217
+ *
218
+ * Format: 10 characters from the 31-char safe alphabet (uppercase letters +
219
+ * digits, omitting I/O/L/0/1), grouped as `XXXX-XXXX-XX`.
220
+ *
221
+ * Returns plaintext codes for the caller to deliver to the user — these
222
+ * should be hashed via {@link hashMfaCode} before persistence and never
223
+ * shown to the user again.
224
+ */
225
+ declare function generateBackupCodePlaintext(count?: number): string[];
226
+ //#endregion
227
+ //#region src/utils.d.ts
228
+ declare function maskEmail(email: string): string;
229
+ declare function maskPhone(phone: string): string;
230
+ declare function maskMfaValue(method: MfaMethod): string;
231
+ declare function setAtPath(obj: object, path: string, value: unknown): void;
232
+ //#endregion
233
+ export { type AccountData, type DeepPartial, type LockStatus, type LockoutConfig, type LoginResult, type MfaData, type MfaMethod, type MfaMethodInfo, type PasswordConfig, type PasswordData, PasswordHasher, PasswordPolicy, type PasswordPolicyContext, type PasswordPolicyDef, type PasswordPolicyEvalFn, type PasswordPolicyInstance, type PolicyCheckResult, type TotpConfig, type TransferablePolicy, type TrustedDeviceRecord, UserAuthError, type UserAuthErrorType, type UserCredentials, UserService, type UserServiceConfig, UserStore, UserStoreMemory, type UserStoreUpdate, generateBackupCodePlaintext, generateMfaCode, generateTotpCode, generateTotpSecret, generateTotpUri, hashMfaCode, maskEmail, maskMfaValue, maskPhone, normalizePolicies, ppHasLowerCase, ppHasMinLength, ppHasNumber, ppHasSpecialChar, ppHasUpperCase, ppMaxRepeatedChars, setAtPath, verifyMfaCode, verifyTotpCode };