@tula-tech/contract 0.0.0-stage → 0.1.0-alpha.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.
- package/LICENSE +202 -0
- package/README.md +38 -2
- package/dist/custom-claims.d.ts +161 -0
- package/dist/custom-claims.js +28 -0
- package/dist/device-binding.d.ts +217 -0
- package/dist/device-binding.js +24 -0
- package/dist/error-codes.d.ts +386 -0
- package/dist/error-codes.js +10 -0
- package/dist/event-types.d.ts +107 -0
- package/dist/event-types.js +10 -0
- package/dist/headers.d.ts +223 -0
- package/dist/headers.js +36 -0
- package/dist/index.d.ts +10384 -0
- package/dist/index.js +3912 -0
- package/dist/issuer.d.ts +31 -0
- package/dist/issuer.js +8 -0
- package/dist/password-rules.d.ts +452 -0
- package/dist/password-rules.js +10 -0
- package/dist/redirect-url.d.ts +223 -0
- package/dist/redirect-url.js +26 -0
- package/dist/shared/chunk-2xak18qy.js +56 -0
- package/dist/shared/chunk-4rb5jsfz.js +102 -0
- package/dist/shared/chunk-4stpmame.js +58 -0
- package/dist/shared/chunk-7yqzghgm.js +108 -0
- package/dist/shared/chunk-9pvdavrw.js +9 -0
- package/dist/shared/chunk-cce3bhet.js +251 -0
- package/dist/shared/chunk-pcn6ax54.js +195 -0
- package/dist/shared/chunk-q309e9bk.js +19 -0
- package/dist/shared/chunk-r202nxfw.js +438 -0
- package/dist/shared/chunk-sc6qg3d2.js +219 -0
- package/dist/theme.d.ts +227 -0
- package/dist/theme.js +16 -0
- package/dist/webhook-signature.d.ts +103 -0
- package/dist/webhook-signature.js +22 -0
- package/openapi.json +30076 -0
- package/package.json +79 -4
package/dist/issuer.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The issuer (`iss`) of an environment's access tokens: its URL under the API.
|
|
3
|
+
*
|
|
4
|
+
* Standard JWKS clients fetch keys from a URL with no custom headers, so the environment is part
|
|
5
|
+
* of the path, and the key set lives at {@link jwksUrl} of the issuer (OIDC-style discovery).
|
|
6
|
+
*
|
|
7
|
+
* @param apiUrl - The API's public base URL, e.g. `https://auth.example.com`.
|
|
8
|
+
* @param environmentId - The environment id.
|
|
9
|
+
* @returns The issuer URL, without a trailing slash.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* environmentIssuer('https://auth.example.com/', 'env_1')
|
|
14
|
+
* // 'https://auth.example.com/v1/environments/env_1'
|
|
15
|
+
* ```
|
|
16
|
+
*/
|
|
17
|
+
declare function environmentIssuer(apiUrl: string, environmentId: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Where an issuer publishes its public signing keys.
|
|
20
|
+
*
|
|
21
|
+
* @param issuer - The token's `iss` claim.
|
|
22
|
+
* @returns The JWKS URL.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* jwksUrl('https://auth.example.com/v1/environments/env_1')
|
|
27
|
+
* // 'https://auth.example.com/v1/environments/env_1/.well-known/jwks.json'
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
declare function jwksUrl(issuer: string): string;
|
|
31
|
+
export { environmentIssuer, jwksUrl };
|
package/dist/issuer.js
ADDED
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Every machine-readable error code the API can return, keyed `area.reason`.
|
|
3
|
+
*
|
|
4
|
+
* Codes are part of the public contract: SDKs switch on them and translate them, so they are
|
|
5
|
+
* append-only. Removing or renaming one is a breaking change.
|
|
6
|
+
*
|
|
7
|
+
* Sign-up deliberately has no "email already taken" code: an existing address still receives
|
|
8
|
+
* `needs_email_verification` (and a notice email) so sign-up can't be used to enumerate accounts.
|
|
9
|
+
*/
|
|
10
|
+
declare const ERROR_DEFINITIONS: {
|
|
11
|
+
readonly "auth.invalid_credentials": {
|
|
12
|
+
readonly status: 401;
|
|
13
|
+
readonly message: "The email or password is incorrect.";
|
|
14
|
+
};
|
|
15
|
+
readonly "auth.unauthenticated": {
|
|
16
|
+
readonly status: 401;
|
|
17
|
+
readonly message: "You need to sign in to do that.";
|
|
18
|
+
};
|
|
19
|
+
readonly "auth.invalid_key": {
|
|
20
|
+
readonly status: 401;
|
|
21
|
+
readonly message: "The API key is missing, invalid or revoked.";
|
|
22
|
+
};
|
|
23
|
+
readonly "auth.forbidden": {
|
|
24
|
+
readonly status: 403;
|
|
25
|
+
readonly message: "You do not have permission to do that.";
|
|
26
|
+
};
|
|
27
|
+
readonly "auth.user_banned": {
|
|
28
|
+
readonly status: 403;
|
|
29
|
+
readonly message: "This account has been disabled.";
|
|
30
|
+
};
|
|
31
|
+
readonly "auth.method_disabled": {
|
|
32
|
+
readonly status: 403;
|
|
33
|
+
readonly message: "This sign-in method is not available.";
|
|
34
|
+
};
|
|
35
|
+
readonly "auth.step_up_required": {
|
|
36
|
+
readonly status: 403;
|
|
37
|
+
readonly message: "Confirm it is you to continue.";
|
|
38
|
+
};
|
|
39
|
+
readonly "flow.not_found": {
|
|
40
|
+
readonly status: 404;
|
|
41
|
+
readonly message: "This attempt does not exist or has expired.";
|
|
42
|
+
};
|
|
43
|
+
readonly "flow.invalid_step": {
|
|
44
|
+
readonly status: 409;
|
|
45
|
+
readonly message: "That action is not valid at this step. Please start again.";
|
|
46
|
+
};
|
|
47
|
+
readonly "email.invalid": {
|
|
48
|
+
readonly status: 422;
|
|
49
|
+
readonly message: "Enter a valid email address.";
|
|
50
|
+
};
|
|
51
|
+
readonly "email.already_set": {
|
|
52
|
+
readonly status: 409;
|
|
53
|
+
readonly message: "This account already has an email address.";
|
|
54
|
+
};
|
|
55
|
+
readonly "password.too_short": {
|
|
56
|
+
readonly status: 422;
|
|
57
|
+
readonly message: "Password is too short.";
|
|
58
|
+
};
|
|
59
|
+
readonly "password.too_long": {
|
|
60
|
+
readonly status: 422;
|
|
61
|
+
readonly message: "Password is too long.";
|
|
62
|
+
};
|
|
63
|
+
readonly "password.missing_lowercase": {
|
|
64
|
+
readonly status: 422;
|
|
65
|
+
readonly message: "Add a lowercase letter.";
|
|
66
|
+
};
|
|
67
|
+
readonly "password.missing_uppercase": {
|
|
68
|
+
readonly status: 422;
|
|
69
|
+
readonly message: "Add an uppercase letter.";
|
|
70
|
+
};
|
|
71
|
+
readonly "password.missing_number": {
|
|
72
|
+
readonly status: 422;
|
|
73
|
+
readonly message: "Add a number.";
|
|
74
|
+
};
|
|
75
|
+
readonly "password.missing_special": {
|
|
76
|
+
readonly status: 422;
|
|
77
|
+
readonly message: "Add a special character.";
|
|
78
|
+
};
|
|
79
|
+
readonly "password.too_few_character_classes": {
|
|
80
|
+
readonly status: 422;
|
|
81
|
+
readonly message: "Use a wider mix of letters, numbers and symbols.";
|
|
82
|
+
};
|
|
83
|
+
readonly "password.contains_user_info": {
|
|
84
|
+
readonly status: 422;
|
|
85
|
+
readonly message: "Password must not contain your name or email.";
|
|
86
|
+
};
|
|
87
|
+
readonly "password.common": {
|
|
88
|
+
readonly status: 422;
|
|
89
|
+
readonly message: "This password is too common.";
|
|
90
|
+
};
|
|
91
|
+
readonly "password.breached": {
|
|
92
|
+
readonly status: 422;
|
|
93
|
+
readonly message: "This password appeared in a data breach. Choose a different one.";
|
|
94
|
+
};
|
|
95
|
+
readonly "password.repeated_characters": {
|
|
96
|
+
readonly status: 422;
|
|
97
|
+
readonly message: "Avoid repeating the same character.";
|
|
98
|
+
};
|
|
99
|
+
readonly "password.sequence": {
|
|
100
|
+
readonly status: 422;
|
|
101
|
+
readonly message: "Avoid sequences like \"abcd\" or \"1234\".";
|
|
102
|
+
};
|
|
103
|
+
readonly "password.reused": {
|
|
104
|
+
readonly status: 422;
|
|
105
|
+
readonly message: "You have used this password recently. Choose a different one.";
|
|
106
|
+
};
|
|
107
|
+
readonly "password.not_set": {
|
|
108
|
+
readonly status: 409;
|
|
109
|
+
readonly message: "This account has no password yet. Use \"forgot password\" to set one.";
|
|
110
|
+
};
|
|
111
|
+
readonly "verification.invalid_code": {
|
|
112
|
+
readonly status: 422;
|
|
113
|
+
readonly message: "That code is incorrect.";
|
|
114
|
+
};
|
|
115
|
+
readonly "verification.expired": {
|
|
116
|
+
readonly status: 410;
|
|
117
|
+
readonly message: "That code has expired. Request a new one.";
|
|
118
|
+
};
|
|
119
|
+
readonly "verification.too_many_attempts": {
|
|
120
|
+
readonly status: 429;
|
|
121
|
+
readonly message: "Too many incorrect codes. Request a new one.";
|
|
122
|
+
};
|
|
123
|
+
readonly "verification.different_browser": {
|
|
124
|
+
readonly status: 409;
|
|
125
|
+
readonly message: "Open this link in the browser where you started signing in, or enter the code from the email there.";
|
|
126
|
+
};
|
|
127
|
+
readonly "mfa.invalid_code": {
|
|
128
|
+
readonly status: 422;
|
|
129
|
+
readonly message: "That code is incorrect.";
|
|
130
|
+
};
|
|
131
|
+
readonly "mfa.already_enabled": {
|
|
132
|
+
readonly status: 409;
|
|
133
|
+
readonly message: "Two-step verification is already on for this account.";
|
|
134
|
+
};
|
|
135
|
+
readonly "mfa.not_enabled": {
|
|
136
|
+
readonly status: 409;
|
|
137
|
+
readonly message: "Two-step verification is not on for this account.";
|
|
138
|
+
};
|
|
139
|
+
readonly "mfa.enrolment_expired": {
|
|
140
|
+
readonly status: 410;
|
|
141
|
+
readonly message: "This setup has expired. Start again.";
|
|
142
|
+
};
|
|
143
|
+
readonly "mfa.not_available": {
|
|
144
|
+
readonly status: 403;
|
|
145
|
+
readonly message: "Two-step verification is not available for this app.";
|
|
146
|
+
};
|
|
147
|
+
readonly "mfa.enrolment_needs_other_sign_in": {
|
|
148
|
+
readonly status: 403;
|
|
149
|
+
readonly message: "Sign in another way to set up two-step verification.";
|
|
150
|
+
};
|
|
151
|
+
readonly "mfa.needs_other_sign_in": {
|
|
152
|
+
readonly status: 403;
|
|
153
|
+
readonly message: "Sign in another way. A texted code cannot be both steps.";
|
|
154
|
+
};
|
|
155
|
+
readonly "mfa.sms_not_allowed": {
|
|
156
|
+
readonly status: 409;
|
|
157
|
+
readonly message: "This account already has a stronger second step than a texted code.";
|
|
158
|
+
};
|
|
159
|
+
readonly "mfa.phone_number_required": {
|
|
160
|
+
readonly status: 409;
|
|
161
|
+
readonly message: "Add a phone number to your account first.";
|
|
162
|
+
};
|
|
163
|
+
readonly "mfa.required_by_policy": {
|
|
164
|
+
readonly status: 403;
|
|
165
|
+
readonly message: "This app requires two-step verification. It cannot be turned off.";
|
|
166
|
+
};
|
|
167
|
+
readonly "oauth.access_denied": {
|
|
168
|
+
readonly status: 403;
|
|
169
|
+
readonly message: "Sign-in was cancelled. Try again or choose another way to sign in.";
|
|
170
|
+
};
|
|
171
|
+
readonly "oauth.provider_error": {
|
|
172
|
+
readonly status: 502;
|
|
173
|
+
readonly message: "The sign-in provider could not complete the request. Try again.";
|
|
174
|
+
};
|
|
175
|
+
readonly "oauth.state_invalid": {
|
|
176
|
+
readonly status: 400;
|
|
177
|
+
readonly message: "This sign-in could not be completed. Start again.";
|
|
178
|
+
};
|
|
179
|
+
readonly "oauth.ticket_invalid": {
|
|
180
|
+
readonly status: 410;
|
|
181
|
+
readonly message: "This sign-in has expired. Start again.";
|
|
182
|
+
};
|
|
183
|
+
readonly "oauth.different_browser": {
|
|
184
|
+
readonly status: 409;
|
|
185
|
+
readonly message: "Finish signing in in the browser where you started, or start again here.";
|
|
186
|
+
};
|
|
187
|
+
readonly "oauth.email_missing": {
|
|
188
|
+
readonly status: 403;
|
|
189
|
+
readonly message: "This provider did not share an email address. Allow access to your email and try again.";
|
|
190
|
+
};
|
|
191
|
+
readonly "oauth.email_unverified": {
|
|
192
|
+
readonly status: 403;
|
|
193
|
+
readonly message: "Your email address is not verified with this provider. Verify it there and try again.";
|
|
194
|
+
};
|
|
195
|
+
readonly "oauth.account_exists": {
|
|
196
|
+
readonly status: 409;
|
|
197
|
+
readonly message: "An account with this email already exists. Sign in the way you usually do, then connect this provider from your account.";
|
|
198
|
+
};
|
|
199
|
+
readonly "oauth.identity_in_use": {
|
|
200
|
+
readonly status: 409;
|
|
201
|
+
readonly message: "This provider account is already connected to another user.";
|
|
202
|
+
};
|
|
203
|
+
readonly "oauth.already_linked": {
|
|
204
|
+
readonly status: 409;
|
|
205
|
+
readonly message: "An account of this provider is already connected. Disconnect it first.";
|
|
206
|
+
};
|
|
207
|
+
readonly "identity.last_sign_in_method": {
|
|
208
|
+
readonly status: 409;
|
|
209
|
+
readonly message: "This is your only way to sign in. Add a password or connect another account first.";
|
|
210
|
+
};
|
|
211
|
+
readonly "webhook.url_not_allowed": {
|
|
212
|
+
readonly status: 422;
|
|
213
|
+
readonly message: "The server cannot deliver to that address.";
|
|
214
|
+
};
|
|
215
|
+
readonly "webhook.cannot_redeliver": {
|
|
216
|
+
readonly status: 409;
|
|
217
|
+
readonly message: "This delivery cannot be sent again.";
|
|
218
|
+
};
|
|
219
|
+
readonly "webhook.rotation_refused": {
|
|
220
|
+
readonly status: 409;
|
|
221
|
+
readonly message: "The signing secret cannot be changed now.";
|
|
222
|
+
};
|
|
223
|
+
readonly "hook.denied": {
|
|
224
|
+
readonly status: 403;
|
|
225
|
+
readonly message: "This was not allowed.";
|
|
226
|
+
};
|
|
227
|
+
readonly "hook.unavailable": {
|
|
228
|
+
readonly status: 503;
|
|
229
|
+
readonly message: "This is unavailable right now. Try again later.";
|
|
230
|
+
};
|
|
231
|
+
readonly "hook.url_not_allowed": {
|
|
232
|
+
readonly status: 422;
|
|
233
|
+
readonly message: "The server cannot call that address.";
|
|
234
|
+
};
|
|
235
|
+
readonly "passkey.registration_failed": {
|
|
236
|
+
readonly status: 422;
|
|
237
|
+
readonly message: "That passkey could not be saved. Try again.";
|
|
238
|
+
};
|
|
239
|
+
readonly "passkey.already_registered": {
|
|
240
|
+
readonly status: 409;
|
|
241
|
+
readonly message: "This passkey is already saved to an account.";
|
|
242
|
+
};
|
|
243
|
+
readonly "passkey.limit_reached": {
|
|
244
|
+
readonly status: 409;
|
|
245
|
+
readonly message: "You have reached the number of passkeys an account can have. Remove one first.";
|
|
246
|
+
};
|
|
247
|
+
readonly "passkey.last_sign_in_method": {
|
|
248
|
+
readonly status: 409;
|
|
249
|
+
readonly message: "This is your only way to sign in. Add a password or connect an account first.";
|
|
250
|
+
};
|
|
251
|
+
readonly "phone.invalid": {
|
|
252
|
+
readonly status: 422;
|
|
253
|
+
readonly message: "Enter a phone number with its country code, such as +14155550100.";
|
|
254
|
+
};
|
|
255
|
+
readonly "sms.disabled": {
|
|
256
|
+
readonly status: 403;
|
|
257
|
+
readonly message: "Text messages are not available.";
|
|
258
|
+
};
|
|
259
|
+
readonly "sms.country_not_allowed": {
|
|
260
|
+
readonly status: 422;
|
|
261
|
+
readonly message: "Text messages cannot be sent to that country.";
|
|
262
|
+
};
|
|
263
|
+
readonly "sms.unavailable": {
|
|
264
|
+
readonly status: 503;
|
|
265
|
+
readonly message: "The text message could not be sent. Try again later.";
|
|
266
|
+
};
|
|
267
|
+
readonly "session.invalid_token": {
|
|
268
|
+
readonly status: 401;
|
|
269
|
+
readonly message: "Your session is invalid. Sign in again.";
|
|
270
|
+
};
|
|
271
|
+
readonly "session.expired": {
|
|
272
|
+
readonly status: 401;
|
|
273
|
+
readonly message: "Your session has expired. Sign in again.";
|
|
274
|
+
};
|
|
275
|
+
readonly "session.revoked": {
|
|
276
|
+
readonly status: 401;
|
|
277
|
+
readonly message: "Your session was signed out. Sign in again.";
|
|
278
|
+
};
|
|
279
|
+
readonly "session.reuse_detected": {
|
|
280
|
+
readonly status: 401;
|
|
281
|
+
readonly message: "For your security this session was signed out. Sign in again.";
|
|
282
|
+
};
|
|
283
|
+
readonly "session.limit_reached": {
|
|
284
|
+
readonly status: 403;
|
|
285
|
+
readonly message: "You are signed in on too many devices. Sign out on another device, or reset your password to sign out everywhere, then try again.";
|
|
286
|
+
};
|
|
287
|
+
readonly "device.proof_invalid": {
|
|
288
|
+
readonly status: 401;
|
|
289
|
+
readonly message: "This session is bound to a device key, and the request did not prove that key.";
|
|
290
|
+
};
|
|
291
|
+
readonly "device.nonce_required": {
|
|
292
|
+
readonly status: 400;
|
|
293
|
+
readonly message: "The proof needs a fresh nonce. Send the request again with the nonce provided.";
|
|
294
|
+
};
|
|
295
|
+
readonly "device.binding_not_supported": {
|
|
296
|
+
readonly status: 400;
|
|
297
|
+
readonly message: "A session of this kind of client cannot be bound to a device key.";
|
|
298
|
+
};
|
|
299
|
+
readonly "device.binding_required": {
|
|
300
|
+
readonly status: 400;
|
|
301
|
+
readonly message: "Signing in here needs a device key.";
|
|
302
|
+
};
|
|
303
|
+
readonly rate_limited: {
|
|
304
|
+
readonly status: 429;
|
|
305
|
+
readonly message: "Too many requests. Try again shortly.";
|
|
306
|
+
};
|
|
307
|
+
readonly "request.malformed": {
|
|
308
|
+
readonly status: 400;
|
|
309
|
+
readonly message: "The request could not be read.";
|
|
310
|
+
};
|
|
311
|
+
readonly "request.too_large": {
|
|
312
|
+
readonly status: 413;
|
|
313
|
+
readonly message: "The request body is too large.";
|
|
314
|
+
};
|
|
315
|
+
readonly "request.origin_not_allowed": {
|
|
316
|
+
readonly status: 403;
|
|
317
|
+
readonly message: "This origin is not allowed to sign in to this app.";
|
|
318
|
+
};
|
|
319
|
+
readonly "request.redirect_not_allowed": {
|
|
320
|
+
readonly status: 400;
|
|
321
|
+
readonly message: "This redirect URL is not allowed for this app.";
|
|
322
|
+
};
|
|
323
|
+
readonly "validation.failed": {
|
|
324
|
+
readonly status: 422;
|
|
325
|
+
readonly message: "Some fields are invalid.";
|
|
326
|
+
};
|
|
327
|
+
readonly "resource.not_found": {
|
|
328
|
+
readonly status: 404;
|
|
329
|
+
readonly message: "The requested resource does not exist.";
|
|
330
|
+
};
|
|
331
|
+
readonly "resource.conflict": {
|
|
332
|
+
readonly status: 409;
|
|
333
|
+
readonly message: "The resource conflicts with existing data.";
|
|
334
|
+
};
|
|
335
|
+
readonly "precondition.required": {
|
|
336
|
+
readonly status: 428;
|
|
337
|
+
readonly message: "Send the revision you are changing in an If-Match header.";
|
|
338
|
+
};
|
|
339
|
+
readonly "precondition.failed": {
|
|
340
|
+
readonly status: 412;
|
|
341
|
+
readonly message: "The resource changed since you read it. Read it again and retry.";
|
|
342
|
+
};
|
|
343
|
+
readonly not_implemented: {
|
|
344
|
+
readonly status: 501;
|
|
345
|
+
readonly message: "This capability is not available yet.";
|
|
346
|
+
};
|
|
347
|
+
readonly "service.unavailable": {
|
|
348
|
+
readonly status: 503;
|
|
349
|
+
readonly message: "The service is temporarily unavailable. Try again shortly.";
|
|
350
|
+
};
|
|
351
|
+
readonly internal: {
|
|
352
|
+
readonly status: 500;
|
|
353
|
+
readonly message: "Something went wrong on our side.";
|
|
354
|
+
};
|
|
355
|
+
};
|
|
356
|
+
/** A stable, machine-readable error code (e.g. `password.too_short`). */
|
|
357
|
+
type ErrorCode = keyof typeof ERROR_DEFINITIONS;
|
|
358
|
+
import { z } from "zod";
|
|
359
|
+
/**
|
|
360
|
+
* A project's password rules (business plan §4.7).
|
|
361
|
+
*
|
|
362
|
+
* The same object is enforced by the server and rendered as a live checklist by every SDK, so
|
|
363
|
+
* web, iOS and Android can never disagree about what's valid.
|
|
364
|
+
*/
|
|
365
|
+
declare const PasswordPolicySchema: z.ZodObject<{
|
|
366
|
+
preset: z.ZodEnum<{
|
|
367
|
+
custom: "custom";
|
|
368
|
+
legacy: "legacy";
|
|
369
|
+
recommended: "recommended";
|
|
370
|
+
strict: "strict";
|
|
371
|
+
}>;
|
|
372
|
+
minLength: z.ZodNumber;
|
|
373
|
+
maxLength: z.ZodNumber;
|
|
374
|
+
requireLowercase: z.ZodBoolean;
|
|
375
|
+
requireUppercase: z.ZodBoolean;
|
|
376
|
+
requireNumber: z.ZodBoolean;
|
|
377
|
+
requireSpecial: z.ZodBoolean;
|
|
378
|
+
minCharacterClasses: z.ZodNumber;
|
|
379
|
+
specialChars: z.ZodString;
|
|
380
|
+
disallowUserInfo: z.ZodBoolean;
|
|
381
|
+
disallowCommon: z.ZodBoolean;
|
|
382
|
+
breachCheck: z.ZodEnum<{
|
|
383
|
+
block: "block";
|
|
384
|
+
off: "off";
|
|
385
|
+
warn: "warn";
|
|
386
|
+
}>;
|
|
387
|
+
maxRepeatedChars: z.ZodNullable<z.ZodNumber>;
|
|
388
|
+
blockSequences: z.ZodBoolean;
|
|
389
|
+
history: z.ZodNumber;
|
|
390
|
+
expiryDays: z.ZodNullable<z.ZodNumber>;
|
|
391
|
+
}, z.core.$strip>;
|
|
392
|
+
/** Password policy. */
|
|
393
|
+
type PasswordPolicy = z.infer<typeof PasswordPolicySchema>;
|
|
394
|
+
/** ASCII punctuation counted as "special" by default. */
|
|
395
|
+
declare const DEFAULT_SPECIAL_CHARS = "!@#$%^&*()-_=+[]{};:,.?/\\|'\"`~<>";
|
|
396
|
+
/** Rule identifiers shown in the live checklist. */
|
|
397
|
+
type PasswordRule = "min_length" | "max_length" | "lowercase" | "uppercase" | "number" | "special" | "character_classes" | "user_info" | "common" | "repeated_characters" | "sequence";
|
|
398
|
+
/** The result of one rule. */
|
|
399
|
+
interface PasswordCheck {
|
|
400
|
+
/** Which rule this is. */
|
|
401
|
+
rule: PasswordRule;
|
|
402
|
+
/** The error code to report when the rule fails. */
|
|
403
|
+
code: ErrorCode;
|
|
404
|
+
/** Whether the password satisfies the rule. */
|
|
405
|
+
passed: boolean;
|
|
406
|
+
/** Rule parameters for rendering, e.g. `{ min: 10 }`. */
|
|
407
|
+
params?: Record<string, string | number | boolean>;
|
|
408
|
+
}
|
|
409
|
+
/** Result of evaluating a password against a policy (breach check excluded; it's async). */
|
|
410
|
+
interface PasswordEvaluation {
|
|
411
|
+
/** True when every rule passed. */
|
|
412
|
+
ok: boolean;
|
|
413
|
+
/** Every applicable rule, in checklist order. */
|
|
414
|
+
checks: PasswordCheck[];
|
|
415
|
+
}
|
|
416
|
+
/** Personal details a password must not contain when `disallowUserInfo` is on. */
|
|
417
|
+
interface PasswordUserInfo {
|
|
418
|
+
email?: string;
|
|
419
|
+
firstName?: string;
|
|
420
|
+
lastName?: string;
|
|
421
|
+
username?: string;
|
|
422
|
+
}
|
|
423
|
+
/**
|
|
424
|
+
* Normalize a password before measuring or hashing it.
|
|
425
|
+
*
|
|
426
|
+
* NFC keeps visually identical Unicode passphrases (e.g. composed vs decomposed "é") equal on
|
|
427
|
+
* every platform.
|
|
428
|
+
*
|
|
429
|
+
* @param password - The raw password.
|
|
430
|
+
* @returns The NFC-normalized password.
|
|
431
|
+
*/
|
|
432
|
+
declare function normalizePassword(password: string): string;
|
|
433
|
+
/**
|
|
434
|
+
* Evaluate a password against a policy and return every rule's result.
|
|
435
|
+
*
|
|
436
|
+
* Pure and synchronous so it runs identically on the server and inside SDKs (live checklist).
|
|
437
|
+
* Length is measured in Unicode code points after NFC normalization, so emoji and accented
|
|
438
|
+
* passphrases count the way users expect. The breached-password check is not included; the server
|
|
439
|
+
* runs it separately.
|
|
440
|
+
*
|
|
441
|
+
* @param policy - The active password policy.
|
|
442
|
+
* @param password - The candidate password.
|
|
443
|
+
* @param userInfo - Personal details the password must not contain.
|
|
444
|
+
* @returns `ok` plus the result of each applicable rule.
|
|
445
|
+
*
|
|
446
|
+
* @example
|
|
447
|
+
* ```ts
|
|
448
|
+
* const { ok, checks } = evaluatePassword(PASSWORD_POLICY_PRESETS.recommended, 'correct horse')
|
|
449
|
+
* ```
|
|
450
|
+
*/
|
|
451
|
+
declare function evaluatePassword(policy: PasswordPolicy, password: string, userInfo?: PasswordUserInfo): PasswordEvaluation;
|
|
452
|
+
export { DEFAULT_SPECIAL_CHARS, PasswordCheck, PasswordEvaluation, PasswordRule, PasswordUserInfo, evaluatePassword, normalizePassword };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_SPECIAL_CHARS2,
|
|
3
|
+
normalizePassword2,
|
|
4
|
+
evaluatePassword2
|
|
5
|
+
} from "./shared/chunk-sc6qg3d2.js";
|
|
6
|
+
export {
|
|
7
|
+
DEFAULT_SPECIAL_CHARS2 as DEFAULT_SPECIAL_CHARS,
|
|
8
|
+
evaluatePassword2 as evaluatePassword,
|
|
9
|
+
normalizePassword2 as normalizePassword
|
|
10
|
+
};
|