sentri 1.1.1 → 1.1.2

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.
Files changed (44) hide show
  1. package/README.md +107 -43
  2. package/dist/client.d.ts +10 -10
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/errors/AuthError.d.ts +20 -22
  5. package/dist/errors/AuthError.d.ts.map +1 -1
  6. package/dist/errors/AuthError.js +17 -19
  7. package/dist/errors/AuthError.js.map +1 -1
  8. package/dist/index.d.ts +4 -3
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +2 -1
  11. package/dist/index.js.map +1 -1
  12. package/dist/libs/config.d.ts +2 -2
  13. package/dist/libs/config.js +8 -8
  14. package/dist/libs/config.js.map +1 -1
  15. package/dist/libs/token.d.ts +2 -2
  16. package/dist/libs/token.js +10 -10
  17. package/dist/libs/token.js.map +1 -1
  18. package/dist/middleware/authorize.d.ts +1 -1
  19. package/dist/middleware/authorize.js +4 -4
  20. package/dist/middleware/authorize.js.map +1 -1
  21. package/dist/middleware/errorHandler.d.ts +11 -13
  22. package/dist/middleware/errorHandler.d.ts.map +1 -1
  23. package/dist/middleware/errorHandler.js +11 -13
  24. package/dist/middleware/errorHandler.js.map +1 -1
  25. package/dist/middleware/permit.d.ts +1 -1
  26. package/dist/middleware/permit.js +4 -4
  27. package/dist/middleware/permit.js.map +1 -1
  28. package/dist/middleware/protect.d.ts +1 -1
  29. package/dist/middleware/protect.js +4 -4
  30. package/dist/middleware/protect.js.map +1 -1
  31. package/dist/middleware/router.d.ts.map +1 -1
  32. package/dist/middleware/router.js +10 -10
  33. package/dist/middleware/router.js.map +1 -1
  34. package/dist/services/auth.d.ts +5 -5
  35. package/dist/services/auth.d.ts.map +1 -1
  36. package/dist/services/auth.js +15 -15
  37. package/dist/services/auth.js.map +1 -1
  38. package/dist/types/auth.d.ts +21 -21
  39. package/dist/types/auth.d.ts.map +1 -1
  40. package/dist/types/auth.js +1 -1
  41. package/dist/types/auth.js.map +1 -1
  42. package/package.json +1 -1
  43. package/templates/drizzle/auth.ts +5 -5
  44. package/templates/prisma/auth.ts +5 -5
package/README.md CHANGED
@@ -17,6 +17,7 @@ Auth and authorization library for Express + PostgreSQL. Provides JWT-based auth
17
17
  - [Programmatic API](#programmatic-api)
18
18
  - [Types](#types)
19
19
  - [Error Handling](#error-handling)
20
+ - [Migration from 1.0.x](#migration-from-10x)
20
21
 
21
22
  ---
22
23
 
@@ -55,7 +56,7 @@ prisma/
55
56
  schema.prisma ← Prisma models (Prisma only, created or appended)
56
57
  ```
57
58
 
58
- ### 2. Mount the router
59
+ ### 2. Mount the router and error handler
59
60
 
60
61
  ```typescript
61
62
  import express from 'express';
@@ -64,6 +65,12 @@ import { auth } from './lib/sentri/auth.js';
64
65
  const app = express();
65
66
  app.use(express.json());
66
67
  app.use('/auth', auth.router());
68
+
69
+ // ... your routes ...
70
+
71
+ // Must be last — catches SentriError from sentri and your own subclasses
72
+ app.use(auth.errorHandler());
73
+ app.listen(3000);
67
74
  ```
68
75
 
69
76
  Done. All endpoints are available at `/auth/*`.
@@ -189,7 +196,7 @@ The `router` field in config lets you replace the built-in service logic for ind
189
196
  Each key is optional — only override what you need. Any key you omit falls back to the built-in behaviour.
190
197
 
191
198
  ```typescript
192
- import { createAuth, AuthError } from 'sentri';
199
+ import { createAuth, SentriError } from 'sentri';
193
200
  import type { AuthResult } from 'sentri';
194
201
 
195
202
  export const auth = createAuth({
@@ -202,7 +209,7 @@ export const auth = createAuth({
202
209
  login: async (input): Promise<AuthResult> => {
203
210
  const otpVerified = await redis.get(`otp:${input.identifier}`);
204
211
  if (!otpVerified) {
205
- return { success: false, error: new AuthError('INVALID_CREDENTIALS', 'OTP required') };
212
+ return { success: false, error: new SentriError('INVALID_CREDENTIALS', 'OTP required') };
206
213
  }
207
214
  return defaultLogin(input);
208
215
  },
@@ -232,7 +239,7 @@ export const auth = createAuth({
232
239
 
233
240
  | Key | Signature | Must return |
234
241
  |---|---|---|
235
- | `register` | `(input: SignupInput) => Promise<SignupResult>` | `SignupResult` |
242
+ | `register` | `(input: RegisterInput) => Promise<RegisterResult>` | `RegisterResult` |
236
243
  | `login` | `(input: LoginInput) => Promise<AuthResult>` | `AuthResult` |
237
244
  | `refresh` | `(refreshToken: string) => Promise<RefreshResult>` | `RefreshResult` |
238
245
  | `logout` | `(refreshToken: string \| undefined) => Promise<void>` | `void` |
@@ -287,7 +294,7 @@ import { createAdapter } from './adapter.js';
287
294
  export const adapter = createAdapter(db);
288
295
  ```
289
296
 
290
- `createAdapter` throws `AuthError` with code `CONFIGURATION_ERROR` at runtime if called without a `db` argument.
297
+ `createAdapter` throws `SentriError` with code `CONFIGURATION_ERROR` at runtime if called without a `db` argument.
291
298
 
292
299
  ---
293
300
 
@@ -473,8 +480,8 @@ Token and password utilities are available on the auth client for use outside th
473
480
  ```typescript
474
481
  // Token utilities
475
482
  const accessToken = auth.signAccessToken({ id, identifier, roles });
476
- const user = auth.verifyAccessToken(accessToken); // throws AuthError if invalid
477
- const { sessionId } = auth.verifyRefreshToken(token); // throws AuthError if invalid
483
+ const user = auth.verifyAccessToken(accessToken); // throws SentriError if invalid
484
+ const { sessionId } = auth.verifyRefreshToken(token); // throws SentriError if invalid
478
485
  const refreshToken = auth.signRefreshToken(sessionId);
479
486
 
480
487
  // Password utilities
@@ -482,7 +489,26 @@ const hash = await auth.hashPassword('secret123');
482
489
  const valid = await auth.verifyPassword('secret123', hash);
483
490
  ```
484
491
 
485
- `verifyAccessToken` and `verifyRefreshToken` throw `AuthError` with code `TOKEN_EXPIRED` or `TOKEN_INVALID` — wrap them in a try/catch or use the router which handles this automatically.
492
+ `verifyAccessToken` and `verifyRefreshToken` throw `SentriError` with code `TOKEN_EXPIRED` or `TOKEN_INVALID` — wrap them in a try/catch or use the router which handles this automatically.
493
+
494
+ ### `register` — standalone service function
495
+
496
+ The `register` function is also exported directly so you can call it outside the built-in router (e.g. in tests, scripts, or admin tools):
497
+
498
+ ```typescript
499
+ import { register } from 'sentri';
500
+
501
+ const result = await register(
502
+ { identifier: 'alice@example.com', password: 'hunter2', roles: ['user'] },
503
+ config,
504
+ );
505
+
506
+ if (result.success) {
507
+ console.log(result.user.id);
508
+ } else {
509
+ console.error(result.error.code); // 'USER_ALREADY_EXISTS' | 'INVALID_ROLE'
510
+ }
511
+ ```
486
512
 
487
513
  ---
488
514
 
@@ -495,11 +521,11 @@ import type {
495
521
  AuthAdapter,
496
522
  AuthUser,
497
523
  AuthResult,
498
- SignupResult,
524
+ RegisterResult,
499
525
  AssignRolesResult,
500
526
  RefreshResult,
501
527
  ApiResponse,
502
- SignupInput,
528
+ RegisterInput,
503
529
  LoginInput,
504
530
  RouterHandlers,
505
531
  UserRecord,
@@ -508,17 +534,17 @@ import type {
508
534
  CookieConfig,
509
535
  PermitCheck,
510
536
  PermitOptions,
511
- AuthErrorCode,
537
+ SentriErrorCode,
512
538
  } from 'sentri';
513
539
 
514
- import { AuthError, createAuth } from 'sentri';
540
+ import { SentriError, AUTH_ERROR_STATUS, createAuth, register } from 'sentri';
515
541
  ```
516
542
 
517
543
  ---
518
544
 
519
545
  ## Error Handling
520
546
 
521
- All errors thrown by the library are instances of `AuthError` with a machine-readable `code`:
547
+ All errors thrown by the library are instances of `SentriError` with a machine-readable `code` and an HTTP `statusCode`:
522
548
 
523
549
  | Code | HTTP | Meaning |
524
550
  |---|---|---|
@@ -533,44 +559,70 @@ All errors thrown by the library are instances of `AuthError` with a machine-rea
533
559
  | `VALIDATION_ERROR` | 400 | Missing or invalid input field |
534
560
  | `CONFIGURATION_ERROR` | 500 | Invalid `createAuth` configuration |
535
561
 
536
- The built-in router converts all `AuthError` instances to the standard envelope automatically. For custom routes:
562
+ ### `auth.errorHandler()`
563
+
564
+ Mount `auth.errorHandler()` **after all your routes** to automatically format every `SentriError` (and any subclass) into the standard envelope:
537
565
 
538
566
  ```typescript
539
- import { AuthError } from 'sentri';
540
-
541
- const AUTH_ERROR_STATUS: Record<string, number> = {
542
- UNAUTHORIZED: 401,
543
- TOKEN_EXPIRED: 401,
544
- TOKEN_INVALID: 401,
545
- INVALID_CREDENTIALS: 401,
546
- FORBIDDEN: 403,
547
- USER_NOT_FOUND: 404,
548
- USER_ALREADY_EXISTS: 409,
549
- INVALID_ROLE: 400,
550
- VALIDATION_ERROR: 400,
551
- CONFIGURATION_ERROR: 500,
552
- };
567
+ app.use('/auth', auth.router());
568
+ app.use('/api', apiRouter);
569
+
570
+ // Must be last
571
+ app.use(auth.errorHandler());
572
+ ```
573
+
574
+ Optional logger for unexpected errors:
575
+
576
+ ```typescript
577
+ app.use(auth.errorHandler({
578
+ onUnhandled: (err) => logger.error('Unexpected error', { err }),
579
+ }));
580
+ ```
581
+
582
+ ### Extending `SentriError`
583
+
584
+ Define application-specific errors by extending `SentriError`. They are caught automatically by `auth.errorHandler()` via `instanceof`:
585
+
586
+ ```typescript
587
+ import { SentriError } from 'sentri';
588
+
589
+ export class NotFoundError extends SentriError {
590
+ constructor(resource: string) {
591
+ super('NOT_FOUND', `${resource} not found`, 404);
592
+ }
593
+ }
553
594
 
554
- app.use((error, _request, response, next) => {
555
- if (error instanceof AuthError) {
556
- const statusCode = AUTH_ERROR_STATUS[error.code] ?? 500;
557
- return response.status(statusCode).json({
558
- error: true,
559
- statusCode,
560
- code: error.code,
561
- message: error.message,
562
- data: null,
563
- });
595
+ export class PaymentError extends SentriError {
596
+ constructor(message: string) {
597
+ super('PAYMENT_FAILED', message, 402);
564
598
  }
565
- next(error);
599
+ }
600
+
601
+ // Throw anywhere in your routes — auth.errorHandler() catches them all
602
+ app.get('/items/:id', auth.protect(), async (req, res) => {
603
+ const item = await db.items.findById(req.params['id']);
604
+ if (!item) throw new NotFoundError('Item');
605
+ res.json(item);
566
606
  });
567
607
  ```
568
608
 
609
+ Response shape for any `SentriError` (built-in or custom):
610
+
611
+ ```json
612
+ {
613
+ "error": true,
614
+ "statusCode": 404,
615
+ "code": "NOT_FOUND",
616
+ "message": "Item not found",
617
+ "data": null
618
+ }
619
+ ```
620
+
569
621
  ---
570
622
 
571
623
  ## Migration from 1.0.x
572
624
 
573
- ### Breaking changes
625
+ ### Breaking changes in 1.1.0
574
626
 
575
627
  | What changed | Action required |
576
628
  |---|---|
@@ -578,7 +630,19 @@ app.use((error, _request, response, next) => {
578
630
  | `RouterHandlers.signup` renamed to `RouterHandlers.register` | Update config if you used a custom signup handler |
579
631
  | `protect()` now performs one DB read per request | Ensure your adapter's `session.findById` is indexed on session ID |
580
632
 
581
- ### New features
633
+ ### Breaking changes in 1.2.0
582
634
 
583
- - **Session-bound tokens** access tokens are immediately invalidated after logout without waiting for expiry.
584
- - **`apiKey` config** — lock `POST /register` to trusted callers via `X-Api-Key` header.
635
+ | What changed | Action required |
636
+ |---|---|
637
+ | `AuthError` renamed to `SentriError` | Replace all `import { AuthError }` with `import { SentriError }` |
638
+ | `AuthErrorCode` renamed to `SentriErrorCode` | Replace all `AuthErrorCode` type references |
639
+ | `SignupResult` renamed to `RegisterResult` | Replace type references |
640
+ | `SignupInput` renamed to `RegisterInput` | Replace type references |
641
+ | `signup` service renamed to `register` | Replace `import { signup }` with `import { register }` |
642
+
643
+ ### New features in 1.2.0
644
+
645
+ - **`auth.errorHandler()`** — built-in Express error handler mounted like `auth.router()`.
646
+ - **`SentriError.statusCode`** — each error carries its own HTTP status; no need for a manual status map.
647
+ - **Extensible errors** — subclass `SentriError` with a custom `code` and `statusCode`; `auth.errorHandler()` catches all subclasses automatically.
648
+ - **`register` exported** — the registration service function is now a named export for use outside the built-in router.
package/dist/client.d.ts CHANGED
@@ -17,7 +17,7 @@ export interface AuthClient<TRole extends string = string> {
17
17
  *
18
18
  * Reads the `Authorization: Bearer <token>` header, verifies the access token,
19
19
  * confirms the session is still active in the database, and injects the decoded
20
- * payload as `request.user`. Calls `next(AuthError)` on any failure.
20
+ * payload as `request.user`. Calls `next(SentriError)` on any failure.
21
21
  *
22
22
  * @example
23
23
  * router.get('/me', auth.protect(), (request, response) => {
@@ -29,7 +29,7 @@ export interface AuthClient<TRole extends string = string> {
29
29
  * Express middleware factory that enforces role-based access.
30
30
  *
31
31
  * Must be used **after** `protect()`. Passes if the authenticated user has
32
- * at least one of the specified roles; otherwise calls `next(AuthError)` with
32
+ * at least one of the specified roles; otherwise calls `next(SentriError)` with
33
33
  * code `FORBIDDEN`.
34
34
  *
35
35
  * @example
@@ -40,7 +40,7 @@ export interface AuthClient<TRole extends string = string> {
40
40
  * Express middleware factory for resource-level permission checks.
41
41
  *
42
42
  * Must be used **after** `protect()`. Evaluates a check function against the
43
- * current request and calls `next(AuthError)` with `FORBIDDEN` if it returns `false`.
43
+ * current request and calls `next(SentriError)` with `FORBIDDEN` if it returns `false`.
44
44
  *
45
45
  * Accepts either a bare check function or an options object with an optional
46
46
  * `roles` list whose members bypass the check entirely.
@@ -77,9 +77,9 @@ export interface AuthClient<TRole extends string = string> {
77
77
  signAccessToken(payload: AuthUser<TRole>): string;
78
78
  /** Sign a refresh token bound to a session ID. */
79
79
  signRefreshToken(sessionId: string): string;
80
- /** Verify and decode an access token. Throws `AuthError` if invalid or expired. */
80
+ /** Verify and decode an access token. Throws `SentriError` if invalid or expired. */
81
81
  verifyAccessToken(token: string): AuthUser<TRole>;
82
- /** Verify and decode a refresh token. Throws `AuthError` if invalid or expired. */
82
+ /** Verify and decode a refresh token. Throws `SentriError` if invalid or expired. */
83
83
  verifyRefreshToken(token: string): {
84
84
  sessionId: string;
85
85
  };
@@ -103,7 +103,7 @@ export interface AuthClient<TRole extends string = string> {
103
103
  */
104
104
  router(): Router;
105
105
  /**
106
- * Returns an Express error-handling middleware that formats every `AuthError`
106
+ * Returns an Express error-handling middleware that formats every `SentriError`
107
107
  * (and any subclass) into the standard sentri response envelope:
108
108
  *
109
109
  * ```json
@@ -111,13 +111,13 @@ export interface AuthClient<TRole extends string = string> {
111
111
  * ```
112
112
  *
113
113
  * Mount it **after all your routes** so it acts as the global catch-all for
114
- * both sentri errors and your own `AuthError` subclasses.
114
+ * both sentri errors and your own `SentriError` subclasses.
115
115
  *
116
116
  * @example
117
- * import { AuthError } from 'sentri';
117
+ * import { SentriError } from 'sentri';
118
118
  *
119
- * // Define app-specific errors by extending AuthError
120
- * class NotFoundError extends AuthError {
119
+ * // Define app-specific errors by extending SentriError
120
+ * class NotFoundError extends SentriError {
121
121
  * constructor(resource: string) {
122
122
  * super('NOT_FOUND', `${resource} not found`, 404);
123
123
  * }
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE3E;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IACvD;;;;;;;;;;;OAWG;IACH,OAAO,IAAI,cAAc,CAAC;IAE1B;;;;;;;;;OASG;IACH,SAAS,CAAC,GAAG,KAAK,EAAE,KAAK,EAAE,GAAG,cAAc,CAAC;IAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,cAAc,CAAC;IAC3C,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,cAAc,CAAC;IAEtD,oEAAoE;IACpE,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7C,kEAAkE;IAClE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE9D,uDAAuD;IACvD,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;IAElD,kDAAkD;IAClD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAE5C,mFAAmF;IACnF,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAElD,mFAAmF;IACnF,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAEzD;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,IAAI,MAAM,CAAC;IAEjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,YAAY,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,CAAC;CAClE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EACtD,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,GACxB,UAAU,CAAC,KAAK,CAAC,CAiBnB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAE3E;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IACvD;;;;;;;;;;;OAWG;IACH,OAAO,IAAI,cAAc,CAAC;IAE1B;;;;;;;;;OASG;IACH,SAAS,CAAC,GAAG,KAAK,EAAE,KAAK,EAAE,GAAG,cAAc,CAAC;IAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,cAAc,CAAC;IAC3C,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,cAAc,CAAC;IAEtD,oEAAoE;IACpE,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7C,kEAAkE;IAClE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE9D,uDAAuD;IACvD,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;IAElD,kDAAkD;IAClD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAE5C,qFAAqF;IACrF,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAElD,qFAAqF;IACrF,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAEzD;;;;;;;;;;;;;;;;;OAiBG;IACH,MAAM,IAAI,MAAM,CAAC;IAEjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,YAAY,CAAC,OAAO,CAAC,EAAE,mBAAmB,GAAG,mBAAmB,CAAC;CAClE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EACtD,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,GACxB,UAAU,CAAC,KAAK,CAAC,CAiBnB"}
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Discriminant codes for built-in {@link AuthError} instances.
2
+ * Discriminant codes for built-in {@link SentriError} instances.
3
3
  *
4
4
  * - `INVALID_CREDENTIALS` — identifier or password did not match (intentionally vague to prevent user enumeration)
5
5
  * - `USER_NOT_FOUND` — an operation required a user that does not exist
@@ -12,10 +12,10 @@
12
12
  * - `VALIDATION_ERROR` — a required field was missing or had an invalid value
13
13
  * - `CONFIGURATION_ERROR` — `createAuth` was called with an invalid configuration
14
14
  *
15
- * When you extend {@link AuthError} for your own error types you can use any
15
+ * When you extend {@link SentriError} for your own error types you can use any
16
16
  * string as `code` — it does not need to be one of these built-in values.
17
17
  */
18
- export type AuthErrorCode = 'INVALID_CREDENTIALS' | 'USER_NOT_FOUND' | 'USER_ALREADY_EXISTS' | 'TOKEN_EXPIRED' | 'TOKEN_INVALID' | 'FORBIDDEN' | 'UNAUTHORIZED' | 'INVALID_ROLE' | 'VALIDATION_ERROR' | 'CONFIGURATION_ERROR';
18
+ export type SentriErrorCode = 'INVALID_CREDENTIALS' | 'USER_NOT_FOUND' | 'USER_ALREADY_EXISTS' | 'TOKEN_EXPIRED' | 'TOKEN_INVALID' | 'FORBIDDEN' | 'UNAUTHORIZED' | 'INVALID_ROLE' | 'VALIDATION_ERROR' | 'CONFIGURATION_ERROR';
19
19
  /**
20
20
  * Default HTTP status codes for built-in error codes.
21
21
  * Custom codes that are not in this map default to 500.
@@ -24,37 +24,37 @@ export type AuthErrorCode = 'INVALID_CREDENTIALS' | 'USER_NOT_FOUND' | 'USER_ALR
24
24
  */
25
25
  export declare const AUTH_ERROR_STATUS: Record<string, number>;
26
26
  /**
27
- * Base error class for all authentication and authorization failures.
27
+ * Base error class for all authentication and authorization failures in sentri.
28
28
  *
29
- * Every error thrown by sentri is an instance of `AuthError`. The `code`
29
+ * Every error thrown by sentri is an instance of `SentriError`. The `code`
30
30
  * property is a machine-readable string that lets you distinguish error
31
31
  * types without string-matching on the message. Built-in codes are listed
32
- * in {@link AuthErrorCode}; custom subclasses may use any string.
32
+ * in {@link SentriErrorCode}; custom subclasses may use any string.
33
33
  *
34
34
  * The `statusCode` property holds the HTTP status that the built-in router
35
- * and `createErrorHandler()` will use in the response. For built-in codes
35
+ * and `auth.errorHandler()` will use in the response. For built-in codes
36
36
  * it is derived automatically. Pass it explicitly when subclassing with a
37
37
  * custom code.
38
38
  *
39
39
  * ---
40
40
  *
41
- * **Extending AuthError**
41
+ * **Extending SentriError**
42
42
  *
43
- * You can create application-specific error classes by extending `AuthError`.
44
- * Any subclass will be caught automatically by `createErrorHandler()` because
45
- * `instanceof AuthError` is `true` for all subclasses.
43
+ * You can create application-specific error classes by extending `SentriError`.
44
+ * Any subclass will be caught automatically by `auth.errorHandler()` because
45
+ * `instanceof SentriError` is `true` for all subclasses.
46
46
  *
47
47
  * ```typescript
48
- * import { AuthError } from 'sentri';
48
+ * import { SentriError } from 'sentri';
49
49
  *
50
50
  * // Domain error with a custom code and explicit HTTP status
51
- * export class PaymentError extends AuthError {
51
+ * export class PaymentError extends SentriError {
52
52
  * constructor(message: string) {
53
53
  * super('PAYMENT_FAILED', message, 402);
54
54
  * }
55
55
  * }
56
56
  *
57
- * // Throw it anywhere in your routes — createErrorHandler() catches it
57
+ * // Throw it anywhere in your routes — auth.errorHandler() catches it
58
58
  * router.post('/checkout', auth.protect(), async (req, res) => {
59
59
  * const ok = await chargeCard(req.body.cardToken);
60
60
  * if (!ok) throw new PaymentError('Card declined');
@@ -67,19 +67,17 @@ export declare const AUTH_ERROR_STATUS: Record<string, number>;
67
67
  * **Error handling in custom routes**
68
68
  *
69
69
  * ```typescript
70
- * import { AuthError, createErrorHandler } from 'sentri';
71
- *
72
70
  * app.use('/auth', auth.router());
73
71
  * app.use('/api', apiRouter);
74
72
  *
75
- * // Mount after all routes — catches AuthError from sentri AND your subclasses
76
- * app.use(createErrorHandler());
73
+ * // Mount after all routes — catches SentriError from sentri AND your subclasses
74
+ * app.use(auth.errorHandler());
77
75
  * ```
78
76
  */
79
- export declare class AuthError extends Error {
77
+ export declare class SentriError extends Error {
80
78
  /**
81
79
  * Machine-readable error code.
82
- * Built-in codes are defined by {@link AuthErrorCode}.
80
+ * Built-in codes are defined by {@link SentriErrorCode}.
83
81
  * Custom subclasses may use any string.
84
82
  */
85
83
  readonly code: string;
@@ -90,12 +88,12 @@ export declare class AuthError extends Error {
90
88
  */
91
89
  readonly statusCode: number;
92
90
  /**
93
- * @param code - Machine-readable error code. Use a built-in {@link AuthErrorCode}
91
+ * @param code - Machine-readable error code. Use a built-in {@link SentriErrorCode}
94
92
  * or any string for custom subclasses.
95
93
  * @param message - Human-readable description of the error.
96
94
  * @param statusCode - HTTP status to use in the response. For built-in codes
97
95
  * this is derived automatically; for custom codes it defaults to `500`.
98
96
  */
99
- constructor(code: AuthErrorCode | (string & {}), message: string, statusCode?: number);
97
+ constructor(code: SentriErrorCode | (string & {}), message: string, statusCode?: number);
100
98
  }
101
99
  //# sourceMappingURL=AuthError.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AuthError.d.ts","sourceRoot":"","sources":["../../src/errors/AuthError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,aAAa,GACrB,qBAAqB,GACrB,gBAAgB,GAChB,qBAAqB,GACrB,eAAe,GACf,eAAe,GACf,WAAW,GACX,cAAc,GACd,cAAc,GACd,kBAAkB,GAClB,qBAAqB,CAAC;AAE1B;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAWpD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC;;;;OAIG;IACH,SAAgB,IAAI,EAAE,MAAM,CAAC;IAE7B;;;;OAIG;IACH,SAAgB,UAAU,EAAE,MAAM,CAAC;IAEnC;;;;;;OAMG;gBAED,IAAI,EAAE,aAAa,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EACnC,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM;CAOtB"}
1
+ {"version":3,"file":"AuthError.d.ts","sourceRoot":"","sources":["../../src/errors/AuthError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,MAAM,eAAe,GACvB,qBAAqB,GACrB,gBAAgB,GAChB,qBAAqB,GACrB,eAAe,GACf,eAAe,GACf,WAAW,GACX,cAAc,GACd,cAAc,GACd,kBAAkB,GAClB,qBAAqB,CAAC;AAE1B;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAWpD,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC;;;;OAIG;IACH,SAAgB,IAAI,EAAE,MAAM,CAAC;IAE7B;;;;OAIG;IACH,SAAgB,UAAU,EAAE,MAAM,CAAC;IAEnC;;;;;;OAMG;gBAED,IAAI,EAAE,eAAe,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,EACrC,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM;CAOtB"}
@@ -17,37 +17,37 @@ export const AUTH_ERROR_STATUS = {
17
17
  CONFIGURATION_ERROR: 500,
18
18
  };
19
19
  /**
20
- * Base error class for all authentication and authorization failures.
20
+ * Base error class for all authentication and authorization failures in sentri.
21
21
  *
22
- * Every error thrown by sentri is an instance of `AuthError`. The `code`
22
+ * Every error thrown by sentri is an instance of `SentriError`. The `code`
23
23
  * property is a machine-readable string that lets you distinguish error
24
24
  * types without string-matching on the message. Built-in codes are listed
25
- * in {@link AuthErrorCode}; custom subclasses may use any string.
25
+ * in {@link SentriErrorCode}; custom subclasses may use any string.
26
26
  *
27
27
  * The `statusCode` property holds the HTTP status that the built-in router
28
- * and `createErrorHandler()` will use in the response. For built-in codes
28
+ * and `auth.errorHandler()` will use in the response. For built-in codes
29
29
  * it is derived automatically. Pass it explicitly when subclassing with a
30
30
  * custom code.
31
31
  *
32
32
  * ---
33
33
  *
34
- * **Extending AuthError**
34
+ * **Extending SentriError**
35
35
  *
36
- * You can create application-specific error classes by extending `AuthError`.
37
- * Any subclass will be caught automatically by `createErrorHandler()` because
38
- * `instanceof AuthError` is `true` for all subclasses.
36
+ * You can create application-specific error classes by extending `SentriError`.
37
+ * Any subclass will be caught automatically by `auth.errorHandler()` because
38
+ * `instanceof SentriError` is `true` for all subclasses.
39
39
  *
40
40
  * ```typescript
41
- * import { AuthError } from 'sentri';
41
+ * import { SentriError } from 'sentri';
42
42
  *
43
43
  * // Domain error with a custom code and explicit HTTP status
44
- * export class PaymentError extends AuthError {
44
+ * export class PaymentError extends SentriError {
45
45
  * constructor(message: string) {
46
46
  * super('PAYMENT_FAILED', message, 402);
47
47
  * }
48
48
  * }
49
49
  *
50
- * // Throw it anywhere in your routes — createErrorHandler() catches it
50
+ * // Throw it anywhere in your routes — auth.errorHandler() catches it
51
51
  * router.post('/checkout', auth.protect(), async (req, res) => {
52
52
  * const ok = await chargeCard(req.body.cardToken);
53
53
  * if (!ok) throw new PaymentError('Card declined');
@@ -60,19 +60,17 @@ export const AUTH_ERROR_STATUS = {
60
60
  * **Error handling in custom routes**
61
61
  *
62
62
  * ```typescript
63
- * import { AuthError, createErrorHandler } from 'sentri';
64
- *
65
63
  * app.use('/auth', auth.router());
66
64
  * app.use('/api', apiRouter);
67
65
  *
68
- * // Mount after all routes — catches AuthError from sentri AND your subclasses
69
- * app.use(createErrorHandler());
66
+ * // Mount after all routes — catches SentriError from sentri AND your subclasses
67
+ * app.use(auth.errorHandler());
70
68
  * ```
71
69
  */
72
- export class AuthError extends Error {
70
+ export class SentriError extends Error {
73
71
  /**
74
72
  * Machine-readable error code.
75
- * Built-in codes are defined by {@link AuthErrorCode}.
73
+ * Built-in codes are defined by {@link SentriErrorCode}.
76
74
  * Custom subclasses may use any string.
77
75
  */
78
76
  code;
@@ -83,7 +81,7 @@ export class AuthError extends Error {
83
81
  */
84
82
  statusCode;
85
83
  /**
86
- * @param code - Machine-readable error code. Use a built-in {@link AuthErrorCode}
84
+ * @param code - Machine-readable error code. Use a built-in {@link SentriErrorCode}
87
85
  * or any string for custom subclasses.
88
86
  * @param message - Human-readable description of the error.
89
87
  * @param statusCode - HTTP status to use in the response. For built-in codes
@@ -91,7 +89,7 @@ export class AuthError extends Error {
91
89
  */
92
90
  constructor(code, message, statusCode) {
93
91
  super(message);
94
- this.name = 'AuthError';
92
+ this.name = 'SentriError';
95
93
  this.code = code;
96
94
  this.statusCode = statusCode ?? AUTH_ERROR_STATUS[code] ?? 500;
97
95
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AuthError.js","sourceRoot":"","sources":["../../src/errors/AuthError.ts"],"names":[],"mappings":"AA6BA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA2B;IACvD,YAAY,EAAE,GAAG;IACjB,aAAa,EAAE,GAAG;IAClB,aAAa,EAAE,GAAG;IAClB,mBAAmB,EAAE,GAAG;IACxB,SAAS,EAAE,GAAG;IACd,cAAc,EAAE,GAAG;IACnB,mBAAmB,EAAE,GAAG;IACxB,YAAY,EAAE,GAAG;IACjB,gBAAgB,EAAE,GAAG;IACrB,mBAAmB,EAAE,GAAG;CACzB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClC;;;;OAIG;IACa,IAAI,CAAS;IAE7B;;;;OAIG;IACa,UAAU,CAAS;IAEnC;;;;;;OAMG;IACH,YACE,IAAmC,EACnC,OAAe,EACf,UAAmB;QAEnB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;IACjE,CAAC;CACF"}
1
+ {"version":3,"file":"AuthError.js","sourceRoot":"","sources":["../../src/errors/AuthError.ts"],"names":[],"mappings":"AA6BA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA2B;IACvD,YAAY,EAAE,GAAG;IACjB,aAAa,EAAE,GAAG;IAClB,aAAa,EAAE,GAAG;IAClB,mBAAmB,EAAE,GAAG;IACxB,SAAS,EAAE,GAAG;IACd,cAAc,EAAE,GAAG;IACnB,mBAAmB,EAAE,GAAG;IACxB,YAAY,EAAE,GAAG;IACjB,gBAAgB,EAAE,GAAG;IACrB,mBAAmB,EAAE,GAAG;CACzB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC;;;;OAIG;IACa,IAAI,CAAS;IAE7B;;;;OAIG;IACa,UAAU,CAAS;IAEnC;;;;;;OAMG;IACH,YACE,IAAqC,EACrC,OAAe,EACf,UAAmB;QAEnB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;IACjE,CAAC;CACF"}
package/dist/index.d.ts CHANGED
@@ -6,12 +6,13 @@ declare global {
6
6
  }
7
7
  }
8
8
  }
9
- export type { AuthConfig, CookieConfig, AuthUser, ApiResponse, AuthAdapter, UserRecord, SessionRecord, CreateUserData, RouterHandlers, SignupInput, LoginInput, SignupResult, AuthResult, RefreshResult, AssignRolesResult, } from './types/auth.js';
10
- export type { AuthErrorCode } from './errors/AuthError.js';
9
+ export type { AuthConfig, CookieConfig, AuthUser, ApiResponse, AuthAdapter, UserRecord, SessionRecord, CreateUserData, RouterHandlers, RegisterInput, LoginInput, RegisterResult, AuthResult, RefreshResult, AssignRolesResult, } from './types/auth.js';
10
+ export type { SentriErrorCode } from './errors/AuthError.js';
11
11
  export type { AuthClient } from './client.js';
12
12
  export type { ErrorHandlerOptions } from './middleware/errorHandler.js';
13
- export { AuthError, AUTH_ERROR_STATUS } from './errors/AuthError.js';
13
+ export { SentriError, AUTH_ERROR_STATUS } from './errors/AuthError.js';
14
14
  export { createAuth } from './client.js';
15
15
  export { createErrorHandler } from './middleware/errorHandler.js';
16
+ export { register } from './services/auth.js';
16
17
  export type { PermitCheck, PermitOptions } from './middleware/permit.js';
17
18
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,IAAI,CAAC,EAAE,QAAQ,CAAC;SACjB;KACF;CACF;AAED,YAAY,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,WAAW,EACX,UAAU,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,WAAW,EACX,UAAU,EACV,YAAY,EACZ,UAAU,EACV,aAAa,EACb,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAGhD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,IAAI,CAAC,EAAE,QAAQ,CAAC;SACjB;KACF;CACF;AAED,YAAY,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,WAAW,EACX,UAAU,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,aAAa,EACb,UAAU,EACV,cAAc,EACd,UAAU,EACV,aAAa,EACb,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,YAAY,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAExE,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
- export { AuthError, AUTH_ERROR_STATUS } from './errors/AuthError.js';
1
+ export { SentriError, AUTH_ERROR_STATUS } from './errors/AuthError.js';
2
2
  export { createAuth } from './client.js';
3
3
  export { createErrorHandler } from './middleware/errorHandler.js';
4
+ export { register } from './services/auth.js';
4
5
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAiCA,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgCA,OAAO,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC"}
@@ -17,14 +17,14 @@ export interface ResolvedConfig {
17
17
  * Validate configuration at startup so misconfiguration is caught immediately,
18
18
  * not at the first login attempt.
19
19
  *
20
- * Throws {@link AuthError} with code `CONFIGURATION_ERROR` for any of:
20
+ * Throws {@link SentriError} with code `CONFIGURATION_ERROR` for any of:
21
21
  * - `secret` missing or shorter than 32 characters
22
22
  * - `saltRounds` outside the range 10–31
23
23
  * - `validRoles` is empty or missing
24
24
  * - `adapter` is missing
25
25
  *
26
26
  * @param config - The raw config passed to {@link createAuth}.
27
- * @throws {AuthError} With code `CONFIGURATION_ERROR` on any invalid field.
27
+ * @throws {SentriError} With code `CONFIGURATION_ERROR` on any invalid field.
28
28
  */
29
29
  export declare function validateConfig(config: AuthConfig): void;
30
30
  /**
@@ -1,4 +1,4 @@
1
- import { AuthError } from '../errors/AuthError.js';
1
+ import { SentriError } from '../errors/AuthError.js';
2
2
  const MIN_SECRET_LENGTH = 32;
3
3
  const MIN_SALT_ROUNDS = 10;
4
4
  const MAX_SALT_ROUNDS = 31;
@@ -6,31 +6,31 @@ const MAX_SALT_ROUNDS = 31;
6
6
  * Validate configuration at startup so misconfiguration is caught immediately,
7
7
  * not at the first login attempt.
8
8
  *
9
- * Throws {@link AuthError} with code `CONFIGURATION_ERROR` for any of:
9
+ * Throws {@link SentriError} with code `CONFIGURATION_ERROR` for any of:
10
10
  * - `secret` missing or shorter than 32 characters
11
11
  * - `saltRounds` outside the range 10–31
12
12
  * - `validRoles` is empty or missing
13
13
  * - `adapter` is missing
14
14
  *
15
15
  * @param config - The raw config passed to {@link createAuth}.
16
- * @throws {AuthError} With code `CONFIGURATION_ERROR` on any invalid field.
16
+ * @throws {SentriError} With code `CONFIGURATION_ERROR` on any invalid field.
17
17
  */
18
18
  export function validateConfig(config) {
19
19
  if (!config.secret || config.secret.trim().length === 0) {
20
- throw new AuthError('CONFIGURATION_ERROR', 'secret must not be empty');
20
+ throw new SentriError('CONFIGURATION_ERROR', 'secret must not be empty');
21
21
  }
22
22
  if (config.secret.length < MIN_SECRET_LENGTH) {
23
- throw new AuthError('CONFIGURATION_ERROR', `secret must be at least ${MIN_SECRET_LENGTH} characters to be cryptographically safe`);
23
+ throw new SentriError('CONFIGURATION_ERROR', `secret must be at least ${MIN_SECRET_LENGTH} characters to be cryptographically safe`);
24
24
  }
25
25
  const saltRounds = config.saltRounds ?? 12;
26
26
  if (!Number.isInteger(saltRounds) || saltRounds < MIN_SALT_ROUNDS || saltRounds > MAX_SALT_ROUNDS) {
27
- throw new AuthError('CONFIGURATION_ERROR', `saltRounds must be an integer between ${MIN_SALT_ROUNDS} and ${MAX_SALT_ROUNDS}`);
27
+ throw new SentriError('CONFIGURATION_ERROR', `saltRounds must be an integer between ${MIN_SALT_ROUNDS} and ${MAX_SALT_ROUNDS}`);
28
28
  }
29
29
  if (!config.validRoles || config.validRoles.length === 0) {
30
- throw new AuthError('CONFIGURATION_ERROR', 'validRoles must contain at least one role');
30
+ throw new SentriError('CONFIGURATION_ERROR', 'validRoles must contain at least one role');
31
31
  }
32
32
  if (!config.adapter) {
33
- throw new AuthError('CONFIGURATION_ERROR', 'adapter is required');
33
+ throw new SentriError('CONFIGURATION_ERROR', 'adapter is required');
34
34
  }
35
35
  }
36
36
  /**