sentri 1.0.6 → 1.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.
Files changed (39) hide show
  1. package/README.md +107 -21
  2. package/dist/client.d.ts +51 -14
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +3 -1
  5. package/dist/client.js.map +1 -1
  6. package/dist/errors/AuthError.d.ts +82 -21
  7. package/dist/errors/AuthError.d.ts.map +1 -1
  8. package/dist/errors/AuthError.js +87 -17
  9. package/dist/errors/AuthError.js.map +1 -1
  10. package/dist/index.d.ts +3 -1
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +2 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/libs/token.d.ts +5 -4
  15. package/dist/libs/token.d.ts.map +1 -1
  16. package/dist/libs/token.js +3 -2
  17. package/dist/libs/token.js.map +1 -1
  18. package/dist/middleware/errorHandler.d.ts +73 -0
  19. package/dist/middleware/errorHandler.d.ts.map +1 -0
  20. package/dist/middleware/errorHandler.js +76 -0
  21. package/dist/middleware/errorHandler.js.map +1 -0
  22. package/dist/middleware/protect.d.ts +14 -4
  23. package/dist/middleware/protect.d.ts.map +1 -1
  24. package/dist/middleware/protect.js +24 -6
  25. package/dist/middleware/protect.js.map +1 -1
  26. package/dist/middleware/router.d.ts +5 -2
  27. package/dist/middleware/router.d.ts.map +1 -1
  28. package/dist/middleware/router.js +30 -8
  29. package/dist/middleware/router.js.map +1 -1
  30. package/dist/services/auth.d.ts +3 -1
  31. package/dist/services/auth.d.ts.map +1 -1
  32. package/dist/services/auth.js +7 -3
  33. package/dist/services/auth.js.map +1 -1
  34. package/dist/types/auth.d.ts +50 -8
  35. package/dist/types/auth.d.ts.map +1 -1
  36. package/dist/types/auth.js.map +1 -1
  37. package/package.json +5 -2
  38. package/templates/drizzle/auth.ts +37 -2
  39. package/templates/prisma/auth.ts +37 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # sentri
2
2
 
3
- Auth and authorization library for Express + PostgreSQL. Provides JWT-based authentication with refresh token rotation, role-based access control, fine-grained permission checks, and a pre-built Express router — all behind a single typed client.
3
+ Auth and authorization library for Express + PostgreSQL. Provides JWT-based authentication with session-bound access tokens, refresh token rotation, role-based access control, fine-grained permission checks, and a pre-built Express router — all behind a single typed client.
4
4
 
5
5
  ---
6
6
 
@@ -99,7 +99,7 @@ npx sentri generate drizzle
99
99
  import { createAuth } from 'sentri';
100
100
 
101
101
  export const auth = createAuth({
102
- secret: process.env.JWT_SECRET!, // required — keep in env
102
+ secret: process.env.JWT_SECRET!, // required — keep in env, min 32 chars
103
103
  validRoles: ['user', 'admin'] as const, // required — use `as const` for type safety
104
104
  adapter: myAdapter, // required — see Adapter Interface
105
105
 
@@ -109,6 +109,10 @@ export const auth = createAuth({
109
109
  algorithm: 'HS256', // default: 'HS256' — also 'HS384' | 'HS512'
110
110
  saltRounds: 12, // default: 12 (bcrypt rounds, min 10)
111
111
 
112
+ // Restrict POST /register to callers that supply X-Api-Key header.
113
+ // When set, only requests with this exact key can create new accounts.
114
+ apiKey: process.env.REGISTER_API_KEY, // optional
115
+
112
116
  cookie: { // optional — enables httpOnly cookie for refresh token
113
117
  secure: process.env.NODE_ENV === 'production',
114
118
  // name: 'refresh_token', // default: 'refresh_token'
@@ -119,7 +123,7 @@ export const auth = createAuth({
119
123
 
120
124
  // router: { // optional — replace built-in service logic per route
121
125
  // login: async (input) => { ... },
122
- // signup: async (input) => { ... },
126
+ // register: async (input) => { ... },
123
127
  // refresh: async (refreshToken) => { ... },
124
128
  // logout: async (refreshToken) => { ... },
125
129
  // logoutAll: async (userId) => { ... },
@@ -134,6 +138,50 @@ When `cookie` is configured, the refresh token is stored in an httpOnly cookie a
134
138
 
135
139
  ---
136
140
 
141
+ ## apiKey — Restricting Registration
142
+
143
+ By default `POST /register` is open to the public. This can be a security risk when your application allows role selection at registration time — any caller could register themselves as `admin`.
144
+
145
+ Set `apiKey` in your config to lock the endpoint:
146
+
147
+ ```typescript
148
+ export const auth = createAuth({
149
+ // ...
150
+ apiKey: process.env.REGISTER_API_KEY!,
151
+ });
152
+ ```
153
+
154
+ Requests to `POST /register` must then include the header:
155
+
156
+ ```
157
+ X-Api-Key: <value of REGISTER_API_KEY>
158
+ ```
159
+
160
+ Requests without the header, or with the wrong value, receive HTTP 401 `UNAUTHORIZED`. Keep the API key in an environment variable and share it only with trusted services (your back-office panel, CI scripts, etc.).
161
+
162
+ ---
163
+
164
+ ## Session-Bound Access Tokens
165
+
166
+ Since version 1.1.0, access tokens embed the `sessionId` of the session that was created at login. The `protect()` middleware validates this session against the database on every request.
167
+
168
+ **What this means in practice:**
169
+
170
+ - `POST /logout` deletes the session. Any access token issued during that login is immediately rejected — even if it has not expired yet.
171
+ - `POST /logout-all` deletes **all** sessions for the user. Every access token across all devices is immediately rejected.
172
+ - Tokens issued before 1.1.0 (without the `sessionId` claim) are still accepted but bypass session validation — plan a rolling upgrade if you need strict enforcement for existing tokens.
173
+
174
+ ```
175
+ Login → session created → access token embeds sessionId
176
+ Request → protect() verifies JWT → checks session exists → ✓ allowed
177
+ Logout → session deleted
178
+ Request → protect() verifies JWT → session not found → ✗ 401 UNAUTHORIZED
179
+ ```
180
+
181
+ > **Trade-off:** `protect()` now performs one additional database read per request. For most applications this is negligible. If you need to avoid any per-request DB access, keep `accessExpiresIn` short (e.g. `'5m'`) and rely on token expiry instead — but note that tokens will remain valid for up to `accessExpiresIn` after logout.
182
+
183
+ ---
184
+
137
185
  ## Custom Route Handlers
138
186
 
139
187
  The `router` field in config lets you replace the built-in service logic for individual routes while the router still handles request parsing, input validation, and response formatting.
@@ -159,9 +207,9 @@ export const auth = createAuth({
159
207
  return defaultLogin(input);
160
208
  },
161
209
 
162
- // Send a welcome email after signup
163
- signup: async (input) => {
164
- const result = await defaultSignup(input);
210
+ // Send a welcome email after registration
211
+ register: async (input) => {
212
+ const result = await defaultRegister(input);
165
213
  if (result.success) {
166
214
  await emailService.sendWelcome(input.identifier);
167
215
  }
@@ -184,7 +232,7 @@ export const auth = createAuth({
184
232
 
185
233
  | Key | Signature | Must return |
186
234
  |---|---|---|
187
- | `signup` | `(input: SignupInput) => Promise<SignupResult>` | `SignupResult` |
235
+ | `register` | `(input: SignupInput) => Promise<SignupResult>` | `SignupResult` |
188
236
  | `login` | `(input: LoginInput) => Promise<AuthResult>` | `AuthResult` |
189
237
  | `refresh` | `(refreshToken: string) => Promise<RefreshResult>` | `RefreshResult` |
190
238
  | `logout` | `(refreshToken: string \| undefined) => Promise<void>` | `void` |
@@ -258,11 +306,12 @@ export const adapter = createAdapter(db);
258
306
 
259
307
  ### Endpoints
260
308
 
261
- #### `POST /signup`
309
+ #### `POST /register`
262
310
 
263
- Register a new user. Does **not** issue tokens — call `/login` after signup.
311
+ Register a new user. Does **not** issue tokens — call `/login` after registration.
264
312
 
265
313
  ```
314
+ Headers: X-Api-Key: <key> (required when config.apiKey is set)
266
315
  Body: { identifier, password, roles?: string[] }
267
316
  Returns: { user: { id, identifier, roles } }
268
317
  Status: 201
@@ -310,7 +359,7 @@ Returns: null
310
359
  Status: 200
311
360
  ```
312
361
 
313
- Safe to call even if the cookie is missing or the token is already expired.
362
+ After logout, any access token bound to this session is immediately rejected by `protect()`. Safe to call even if the cookie is missing or the token is already expired.
314
363
 
315
364
  ---
316
365
 
@@ -324,6 +373,8 @@ Returns: null
324
373
  Status: 200
325
374
  ```
326
375
 
376
+ All access tokens across all devices are immediately rejected by `protect()` after this call.
377
+
327
378
  ---
328
379
 
329
380
  #### `GET /me`
@@ -355,7 +406,7 @@ Status: 200
355
406
 
356
407
  ### `auth.protect()`
357
408
 
358
- Verifies the `Authorization: Bearer <token>` header and injects `request.user` into the request.
409
+ Verifies the `Authorization: Bearer <token>` header, confirms the session is still active in the database, and injects `request.user` into the request.
359
410
 
360
411
  ```typescript
361
412
  router.get('/dashboard', auth.protect(), (request, response) => {
@@ -363,6 +414,11 @@ router.get('/dashboard', auth.protect(), (request, response) => {
363
414
  });
364
415
  ```
365
416
 
417
+ Returns HTTP 401 if:
418
+ - The `Authorization` header is missing or malformed
419
+ - The token signature is invalid or the token is expired
420
+ - The session embedded in the token has been revoked (logout)
421
+
366
422
  ---
367
423
 
368
424
  ### `auth.authorize(...roles)`
@@ -467,11 +523,11 @@ All errors thrown by the library are instances of `AuthError` with a machine-rea
467
523
  | Code | HTTP | Meaning |
468
524
  |---|---|---|
469
525
  | `INVALID_CREDENTIALS` | 401 | Wrong identifier or password |
470
- | `USER_ALREADY_EXISTS` | 409 | Signup with duplicate identifier |
526
+ | `USER_ALREADY_EXISTS` | 409 | Registration with duplicate identifier |
471
527
  | `USER_NOT_FOUND` | 404 | Operation on a non-existent user |
472
528
  | `TOKEN_EXPIRED` | 401 | JWT `exp` claim is in the past |
473
529
  | `TOKEN_INVALID` | 401 | JWT signature invalid or malformed |
474
- | `UNAUTHORIZED` | 401 | No valid access token on the request |
530
+ | `UNAUTHORIZED` | 401 | No valid access token, revoked session, or invalid API key |
475
531
  | `FORBIDDEN` | 403 | Authenticated but missing required role |
476
532
  | `INVALID_ROLE` | 400 | Role name not in `validRoles` |
477
533
  | `VALIDATION_ERROR` | 400 | Missing or invalid input field |
@@ -482,17 +538,47 @@ The built-in router converts all `AuthError` instances to the standard envelope
482
538
  ```typescript
483
539
  import { AuthError } from 'sentri';
484
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
+ };
553
+
485
554
  app.use((error, _request, response, next) => {
486
555
  if (error instanceof AuthError) {
487
- const status =
488
- error.code === 'UNAUTHORIZED' || error.code === 'TOKEN_EXPIRED' || error.code === 'TOKEN_INVALID' || error.code === 'INVALID_CREDENTIALS' ? 401
489
- : error.code === 'FORBIDDEN' ? 403
490
- : error.code === 'USER_NOT_FOUND' ? 404
491
- : error.code === 'USER_ALREADY_EXISTS' ? 409
492
- : 400;
493
-
494
- return response.status(status).json({ error: true, statusCode: status, message: error.message, data: null });
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
+ });
495
564
  }
496
565
  next(error);
497
566
  });
498
567
  ```
568
+
569
+ ---
570
+
571
+ ## Migration from 1.0.x
572
+
573
+ ### Breaking changes
574
+
575
+ | What changed | Action required |
576
+ |---|---|
577
+ | `POST /signup` renamed to `POST /register` | Update all client-side calls |
578
+ | `RouterHandlers.signup` renamed to `RouterHandlers.register` | Update config if you used a custom signup handler |
579
+ | `protect()` now performs one DB read per request | Ensure your adapter's `session.findById` is indexed on session ID |
580
+
581
+ ### New features
582
+
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.
package/dist/client.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { PermitCheck, PermitOptions } from './middleware/permit.js';
2
+ import type { ErrorHandlerOptions } from './middleware/errorHandler.js';
2
3
  import type { AuthConfig, AuthUser } from './types/auth.js';
3
- import type { RequestHandler, Router } from 'express';
4
+ import type { ErrorRequestHandler, RequestHandler, Router } from 'express';
4
5
  /**
5
6
  * The bound auth client returned by {@link createAuth}.
6
7
  *
@@ -15,11 +16,12 @@ export interface AuthClient<TRole extends string = string> {
15
16
  * Express middleware factory that enforces authentication.
16
17
  *
17
18
  * Reads the `Authorization: Bearer <token>` header, verifies the access token,
18
- * and injects the decoded payload as `req.user`. Calls `next(AuthError)` on failure.
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.
19
21
  *
20
22
  * @example
21
- * router.get('/me', auth.protect(), (req, res) => {
22
- * res.json(req.user);
23
+ * router.get('/me', auth.protect(), (request, response) => {
24
+ * response.json(request.user);
23
25
  * });
24
26
  */
25
27
  protect(): RequestHandler;
@@ -47,7 +49,7 @@ export interface AuthClient<TRole extends string = string> {
47
49
  * // User can only update their own profile
48
50
  * router.put('/users/:id',
49
51
  * auth.protect(),
50
- * auth.permit((req) => req.user!.id === req.params['id']),
52
+ * auth.permit((request) => request.user!.id === request.params['id']),
51
53
  * handler,
52
54
  * );
53
55
  *
@@ -57,9 +59,9 @@ export interface AuthClient<TRole extends string = string> {
57
59
  * auth.protect(),
58
60
  * auth.permit({
59
61
  * roles: ['admin'],
60
- * check: async (req) => {
61
- * const post = await db.post.findUnique({ where: { id: req.params['id'] } });
62
- * return post?.authorId === req.user!.id;
62
+ * check: async (request) => {
63
+ * const post = await db.post.findUnique({ where: { id: request.params['id'] } });
64
+ * return post?.authorId === request.user!.id;
63
65
  * },
64
66
  * }),
65
67
  * handler,
@@ -82,23 +84,58 @@ export interface AuthClient<TRole extends string = string> {
82
84
  sessionId: string;
83
85
  };
84
86
  /**
85
- * Returns a pre-built Express Router with all standard auth endpoints mounted:
87
+ * Returns a pre-built Express Router with all standard auth endpoints mounted.
86
88
  *
87
- * - `POST /signup` — register a user, returns `{ user }`
89
+ * Endpoints:
90
+ * - `POST /register` — register a new user. Requires `X-Api-Key` header when `config.apiKey` is set.
88
91
  * - `POST /login` — authenticate, sets refresh token cookie, returns `{ accessToken, user }`
89
- * - `POST /refresh` — reads refresh token from cookie, returns `{ accessToken }`
90
- * - `POST /logout` — invalidate current session
91
- * - `POST /logout-all` — invalidate all sessions (requires valid access token)
92
+ * - `POST /refresh` — rotate refresh token, returns new `{ accessToken }`
93
+ * - `POST /logout` — delete the current session; the bound access token is immediately rejected by `protect()`
94
+ * - `POST /logout-all` — delete all sessions for the user (requires valid access token)
92
95
  * - `GET /me` — return the authenticated user
93
96
  * - `POST /users/:userId/roles` — assign roles (requires admin)
94
97
  *
95
- * Requires `express.json()` to be applied before the router.
98
+ * Requires `express.json()` before the router.
96
99
  *
97
100
  * @example
98
101
  * app.use(express.json());
99
102
  * app.use('/auth', auth.router());
100
103
  */
101
104
  router(): Router;
105
+ /**
106
+ * Returns an Express error-handling middleware that formats every `AuthError`
107
+ * (and any subclass) into the standard sentri response envelope:
108
+ *
109
+ * ```json
110
+ * { "error": true, "statusCode": 401, "code": "UNAUTHORIZED", "message": "...", "data": null }
111
+ * ```
112
+ *
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.
115
+ *
116
+ * @example
117
+ * import { AuthError } from 'sentri';
118
+ *
119
+ * // Define app-specific errors by extending AuthError
120
+ * class NotFoundError extends AuthError {
121
+ * constructor(resource: string) {
122
+ * super('NOT_FOUND', `${resource} not found`, 404);
123
+ * }
124
+ * }
125
+ *
126
+ * app.use('/auth', auth.router());
127
+ * app.use('/api', apiRouter);
128
+ *
129
+ * // Catches errors from sentri AND your own subclasses
130
+ * app.use(auth.errorHandler());
131
+ *
132
+ * @example
133
+ * // With optional unhandled-error logger
134
+ * app.use(auth.errorHandler({
135
+ * onUnhandled: (err) => logger.error('Unexpected error', { err }),
136
+ * }));
137
+ */
138
+ errorHandler(options?: ErrorHandlerOptions): ErrorRequestHandler;
102
139
  }
103
140
  /**
104
141
  * Create a fully configured auth client for your application.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtD;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IACvD;;;;;;;;;;OAUG;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;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,IAAI,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EACtD,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,GACxB,UAAU,CAAC,KAAK,CAAC,CAgBnB"}
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"}
package/dist/client.js CHANGED
@@ -5,6 +5,7 @@ import { protect } from './middleware/protect.js';
5
5
  import { authorize } from './middleware/authorize.js';
6
6
  import { permit } from './middleware/permit.js';
7
7
  import { createAuthRouter } from './middleware/router.js';
8
+ import { createErrorHandler } from './middleware/errorHandler.js';
8
9
  /**
9
10
  * Create a fully configured auth client for your application.
10
11
  *
@@ -30,6 +31,7 @@ export function createAuth(config) {
30
31
  return {
31
32
  protect: () => protect(config),
32
33
  authorize: (...roles) => authorize(...roles),
34
+ permit: (optionsOrCheck) => permit(optionsOrCheck),
33
35
  hashPassword: (plain) => hashPassword(plain, resolved.saltRounds),
34
36
  verifyPassword: (plain, hash) => verifyPassword(plain, hash),
35
37
  signAccessToken: (payload) => signAccessToken(payload, config),
@@ -37,7 +39,7 @@ export function createAuth(config) {
37
39
  verifyAccessToken: (token) => verifyAccessToken(token, config),
38
40
  verifyRefreshToken: (token) => verifyRefreshToken(token, config),
39
41
  router: () => createAuthRouter(config),
40
- permit: (optionsOrCheck) => permit(optionsOrCheck),
42
+ errorHandler: (options) => createErrorHandler(options),
41
43
  };
42
44
  }
43
45
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAgH1D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,UAAU,CACxB,MAAyB;IAEzB,cAAc,CAAC,MAAoB,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAoB,CAAC,CAAC;IAErD,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAoB,CAAC;QAC5C,SAAS,EAAE,CAAC,GAAG,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC;QAC5C,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC;QACjE,cAAc,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC;QAC5D,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC,OAAmB,EAAE,MAAoB,CAAC;QACxF,gBAAgB,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAoB,CAAC;QAClF,iBAAiB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAoB,CAAoB;QAC/F,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAoB,CAAC;QAC9E,MAAM,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC;QACtC,MAAM,EAAE,CAAC,cAAkD,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;KACvF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAsJlE;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,UAAU,CACxB,MAAyB;IAEzB,cAAc,CAAC,MAAoB,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAoB,CAAC,CAAC;IAErD,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAoB,CAAC;QAC5C,SAAS,EAAE,CAAC,GAAG,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC;QAC5C,MAAM,EAAE,CAAC,cAAkD,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;QACtF,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC;QACjE,cAAc,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC;QAC5D,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC,OAAmB,EAAE,MAAoB,CAAC;QACxF,gBAAgB,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAoB,CAAC;QAClF,iBAAiB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAoB,CAAoB;QAC/F,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAoB,CAAC;QAC9E,MAAM,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC;QACtC,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,kBAAkB,CAAC,OAAO,CAAC;KACvD,CAAC;AACJ,CAAC"}
@@ -1,40 +1,101 @@
1
1
  /**
2
- * Discriminant codes for {@link AuthError}.
2
+ * Discriminant codes for built-in {@link AuthError} 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
6
- * - `USER_ALREADY_EXISTS` — signup was attempted with an identifier already in the database
6
+ * - `USER_ALREADY_EXISTS` — registration was attempted with an identifier already in the database
7
7
  * - `TOKEN_EXPIRED` — the JWT was valid but its `exp` claim is in the past
8
8
  * - `TOKEN_INVALID` — the JWT could not be verified (bad signature, malformed, wrong type)
9
9
  * - `FORBIDDEN` — the user is authenticated but lacks the required role
10
- * - `UNAUTHORIZED` — no valid access token was present on the request
10
+ * - `UNAUTHORIZED` — no valid access token was present on the request, or the session was revoked
11
11
  * - `INVALID_ROLE` — a role name was used that is not in `validRoles`
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
+ *
15
+ * When you extend {@link AuthError} for your own error types you can use any
16
+ * string as `code` — it does not need to be one of these built-in values.
14
17
  */
15
18
  export type AuthErrorCode = 'INVALID_CREDENTIALS' | 'USER_NOT_FOUND' | 'USER_ALREADY_EXISTS' | 'TOKEN_EXPIRED' | 'TOKEN_INVALID' | 'FORBIDDEN' | 'UNAUTHORIZED' | 'INVALID_ROLE' | 'VALIDATION_ERROR' | 'CONFIGURATION_ERROR';
16
19
  /**
17
- * Error class thrown by the library for all authentication and authorization failures.
18
- *
19
- * Carries a machine-readable `code` that lets you distinguish error types without
20
- * string-matching on the message:
21
- *
22
- * @example
23
- * import { AuthError } from 'rizzzdev-auth';
24
- *
25
- * app.use((err, req, res, next) => {
26
- * if (err instanceof AuthError) {
27
- * const status = err.code === 'UNAUTHORIZED' ? 401
28
- * : err.code === 'FORBIDDEN' ? 403
29
- * : 400;
30
- * res.status(status).json({ error: err.code, message: err.message });
31
- * } else {
32
- * next(err);
20
+ * Default HTTP status codes for built-in error codes.
21
+ * Custom codes that are not in this map default to 500.
22
+ *
23
+ * @internal
24
+ */
25
+ export declare const AUTH_ERROR_STATUS: Record<string, number>;
26
+ /**
27
+ * Base error class for all authentication and authorization failures.
28
+ *
29
+ * Every error thrown by sentri is an instance of `AuthError`. The `code`
30
+ * property is a machine-readable string that lets you distinguish error
31
+ * types without string-matching on the message. Built-in codes are listed
32
+ * in {@link AuthErrorCode}; custom subclasses may use any string.
33
+ *
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
36
+ * it is derived automatically. Pass it explicitly when subclassing with a
37
+ * custom code.
38
+ *
39
+ * ---
40
+ *
41
+ * **Extending AuthError**
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.
46
+ *
47
+ * ```typescript
48
+ * import { AuthError } from 'sentri';
49
+ *
50
+ * // Domain error with a custom code and explicit HTTP status
51
+ * export class PaymentError extends AuthError {
52
+ * constructor(message: string) {
53
+ * super('PAYMENT_FAILED', message, 402);
33
54
  * }
55
+ * }
56
+ *
57
+ * // Throw it anywhere in your routes — createErrorHandler() catches it
58
+ * router.post('/checkout', auth.protect(), async (req, res) => {
59
+ * const ok = await chargeCard(req.body.cardToken);
60
+ * if (!ok) throw new PaymentError('Card declined');
61
+ * res.json({ success: true });
34
62
  * });
63
+ * ```
64
+ *
65
+ * ---
66
+ *
67
+ * **Error handling in custom routes**
68
+ *
69
+ * ```typescript
70
+ * import { AuthError, createErrorHandler } from 'sentri';
71
+ *
72
+ * app.use('/auth', auth.router());
73
+ * app.use('/api', apiRouter);
74
+ *
75
+ * // Mount after all routes — catches AuthError from sentri AND your subclasses
76
+ * app.use(createErrorHandler());
77
+ * ```
35
78
  */
36
79
  export declare class AuthError extends Error {
37
- readonly code: AuthErrorCode;
38
- constructor(code: AuthErrorCode, message: string);
80
+ /**
81
+ * Machine-readable error code.
82
+ * Built-in codes are defined by {@link AuthErrorCode}.
83
+ * Custom subclasses may use any string.
84
+ */
85
+ readonly code: string;
86
+ /**
87
+ * HTTP status code associated with this error.
88
+ * Derived automatically for built-in codes; pass it explicitly when
89
+ * subclassing with a custom `code`.
90
+ */
91
+ readonly statusCode: number;
92
+ /**
93
+ * @param code - Machine-readable error code. Use a built-in {@link AuthErrorCode}
94
+ * or any string for custom subclasses.
95
+ * @param message - Human-readable description of the error.
96
+ * @param statusCode - HTTP status to use in the response. For built-in codes
97
+ * this is derived automatically; for custom codes it defaults to `500`.
98
+ */
99
+ constructor(code: AuthErrorCode | (string & {}), message: string, statusCode?: number);
39
100
  }
40
101
  //# sourceMappingURL=AuthError.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"AuthError.d.ts","sourceRoot":"","sources":["../../src/errors/AuthError.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;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;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAClC,SAAgB,IAAI,EAAE,aAAa,CAAC;gBAExB,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM;CAKjD"}
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,29 +1,99 @@
1
1
  /**
2
- * Error class thrown by the library for all authentication and authorization failures.
3
- *
4
- * Carries a machine-readable `code` that lets you distinguish error types without
5
- * string-matching on the message:
6
- *
7
- * @example
8
- * import { AuthError } from 'rizzzdev-auth';
9
- *
10
- * app.use((err, req, res, next) => {
11
- * if (err instanceof AuthError) {
12
- * const status = err.code === 'UNAUTHORIZED' ? 401
13
- * : err.code === 'FORBIDDEN' ? 403
14
- * : 400;
15
- * res.status(status).json({ error: err.code, message: err.message });
16
- * } else {
17
- * next(err);
2
+ * Default HTTP status codes for built-in error codes.
3
+ * Custom codes that are not in this map default to 500.
4
+ *
5
+ * @internal
6
+ */
7
+ export const AUTH_ERROR_STATUS = {
8
+ UNAUTHORIZED: 401,
9
+ TOKEN_EXPIRED: 401,
10
+ TOKEN_INVALID: 401,
11
+ INVALID_CREDENTIALS: 401,
12
+ FORBIDDEN: 403,
13
+ USER_NOT_FOUND: 404,
14
+ USER_ALREADY_EXISTS: 409,
15
+ INVALID_ROLE: 400,
16
+ VALIDATION_ERROR: 400,
17
+ CONFIGURATION_ERROR: 500,
18
+ };
19
+ /**
20
+ * Base error class for all authentication and authorization failures.
21
+ *
22
+ * Every error thrown by sentri is an instance of `AuthError`. The `code`
23
+ * property is a machine-readable string that lets you distinguish error
24
+ * types without string-matching on the message. Built-in codes are listed
25
+ * in {@link AuthErrorCode}; custom subclasses may use any string.
26
+ *
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
29
+ * it is derived automatically. Pass it explicitly when subclassing with a
30
+ * custom code.
31
+ *
32
+ * ---
33
+ *
34
+ * **Extending AuthError**
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.
39
+ *
40
+ * ```typescript
41
+ * import { AuthError } from 'sentri';
42
+ *
43
+ * // Domain error with a custom code and explicit HTTP status
44
+ * export class PaymentError extends AuthError {
45
+ * constructor(message: string) {
46
+ * super('PAYMENT_FAILED', message, 402);
18
47
  * }
48
+ * }
49
+ *
50
+ * // Throw it anywhere in your routes — createErrorHandler() catches it
51
+ * router.post('/checkout', auth.protect(), async (req, res) => {
52
+ * const ok = await chargeCard(req.body.cardToken);
53
+ * if (!ok) throw new PaymentError('Card declined');
54
+ * res.json({ success: true });
19
55
  * });
56
+ * ```
57
+ *
58
+ * ---
59
+ *
60
+ * **Error handling in custom routes**
61
+ *
62
+ * ```typescript
63
+ * import { AuthError, createErrorHandler } from 'sentri';
64
+ *
65
+ * app.use('/auth', auth.router());
66
+ * app.use('/api', apiRouter);
67
+ *
68
+ * // Mount after all routes — catches AuthError from sentri AND your subclasses
69
+ * app.use(createErrorHandler());
70
+ * ```
20
71
  */
21
72
  export class AuthError extends Error {
73
+ /**
74
+ * Machine-readable error code.
75
+ * Built-in codes are defined by {@link AuthErrorCode}.
76
+ * Custom subclasses may use any string.
77
+ */
22
78
  code;
23
- constructor(code, message) {
79
+ /**
80
+ * HTTP status code associated with this error.
81
+ * Derived automatically for built-in codes; pass it explicitly when
82
+ * subclassing with a custom `code`.
83
+ */
84
+ statusCode;
85
+ /**
86
+ * @param code - Machine-readable error code. Use a built-in {@link AuthErrorCode}
87
+ * or any string for custom subclasses.
88
+ * @param message - Human-readable description of the error.
89
+ * @param statusCode - HTTP status to use in the response. For built-in codes
90
+ * this is derived automatically; for custom codes it defaults to `500`.
91
+ */
92
+ constructor(code, message, statusCode) {
24
93
  super(message);
25
94
  this.name = 'AuthError';
26
95
  this.code = code;
96
+ this.statusCode = statusCode ?? AUTH_ERROR_STATUS[code] ?? 500;
27
97
  }
28
98
  }
29
99
  //# sourceMappingURL=AuthError.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AuthError.js","sourceRoot":"","sources":["../../src/errors/AuthError.ts"],"names":[],"mappings":"AA0BA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,OAAO,SAAU,SAAQ,KAAK;IAClB,IAAI,CAAgB;IAEpC,YAAY,IAAmB,EAAE,OAAe;QAC9C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,WAAW,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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"}
package/dist/index.d.ts CHANGED
@@ -9,7 +9,9 @@ declare global {
9
9
  export type { AuthConfig, CookieConfig, AuthUser, ApiResponse, AuthAdapter, UserRecord, SessionRecord, CreateUserData, RouterHandlers, SignupInput, LoginInput, SignupResult, AuthResult, RefreshResult, AssignRolesResult, } from './types/auth.js';
10
10
  export type { AuthErrorCode } from './errors/AuthError.js';
11
11
  export type { AuthClient } from './client.js';
12
- export { AuthError } from './errors/AuthError.js';
12
+ export type { ErrorHandlerOptions } from './middleware/errorHandler.js';
13
+ export { AuthError, AUTH_ERROR_STATUS } from './errors/AuthError.js';
13
14
  export { createAuth } from './client.js';
15
+ export { createErrorHandler } from './middleware/errorHandler.js';
14
16
  export type { PermitCheck, PermitOptions } from './middleware/permit.js';
15
17
  //# 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;AAE9C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,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;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"}