sentri 1.0.5 → 1.0.6

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 (43) hide show
  1. package/README.md +87 -37
  2. package/dist/client.d.ts +34 -75
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +0 -7
  5. package/dist/client.js.map +1 -1
  6. package/dist/index.d.ts +1 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js.map +1 -1
  9. package/dist/libs/config.d.ts +45 -1
  10. package/dist/libs/config.d.ts.map +1 -1
  11. package/dist/libs/config.js +40 -2
  12. package/dist/libs/config.js.map +1 -1
  13. package/dist/libs/hash.d.ts +14 -0
  14. package/dist/libs/hash.d.ts.map +1 -1
  15. package/dist/libs/hash.js +14 -0
  16. package/dist/libs/hash.js.map +1 -1
  17. package/dist/libs/token.d.ts +37 -0
  18. package/dist/libs/token.d.ts.map +1 -1
  19. package/dist/libs/token.js +63 -0
  20. package/dist/libs/token.js.map +1 -1
  21. package/dist/middleware/authorize.d.ts +15 -0
  22. package/dist/middleware/authorize.d.ts.map +1 -1
  23. package/dist/middleware/authorize.js +15 -0
  24. package/dist/middleware/authorize.js.map +1 -1
  25. package/dist/middleware/protect.d.ts +17 -0
  26. package/dist/middleware/protect.d.ts.map +1 -1
  27. package/dist/middleware/protect.js +17 -0
  28. package/dist/middleware/protect.js.map +1 -1
  29. package/dist/middleware/router.d.ts +10 -6
  30. package/dist/middleware/router.d.ts.map +1 -1
  31. package/dist/middleware/router.js +24 -14
  32. package/dist/middleware/router.js.map +1 -1
  33. package/dist/services/auth.d.ts +75 -0
  34. package/dist/services/auth.d.ts.map +1 -1
  35. package/dist/services/auth.js +75 -0
  36. package/dist/services/auth.js.map +1 -1
  37. package/dist/types/auth.d.ts +144 -0
  38. package/dist/types/auth.d.ts.map +1 -1
  39. package/package.json +11 -3
  40. package/templates/drizzle/adapter.ts +3 -9
  41. package/templates/drizzle/auth.ts +20 -0
  42. package/templates/prisma/adapter.ts +3 -9
  43. package/templates/prisma/auth.ts +20 -0
package/README.md CHANGED
@@ -10,6 +10,7 @@ Auth and authorization library for Express + PostgreSQL. Provides JWT-based auth
10
10
  - [Quick Start](#quick-start)
11
11
  - [CLI](#cli)
12
12
  - [Configuration](#configuration)
13
+ - [Custom Route Handlers](#custom-route-handlers)
13
14
  - [Adapter Interface](#adapter-interface)
14
15
  - [Pre-built Router](#pre-built-router)
15
16
  - [Middleware](#middleware)
@@ -115,6 +116,15 @@ export const auth = createAuth({
115
116
  // sameSite: 'strict', // default: 'strict'
116
117
  // path: '/', // default: '/'
117
118
  },
119
+
120
+ // router: { // optional — replace built-in service logic per route
121
+ // login: async (input) => { ... },
122
+ // signup: async (input) => { ... },
123
+ // refresh: async (refreshToken) => { ... },
124
+ // logout: async (refreshToken) => { ... },
125
+ // logoutAll: async (userId) => { ... },
126
+ // assignRoles: async (userId, roles) => { ... },
127
+ // },
118
128
  });
119
129
  ```
120
130
 
@@ -124,6 +134,67 @@ When `cookie` is configured, the refresh token is stored in an httpOnly cookie a
124
134
 
125
135
  ---
126
136
 
137
+ ## Custom Route Handlers
138
+
139
+ 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.
140
+
141
+ Each key is optional — only override what you need. Any key you omit falls back to the built-in behaviour.
142
+
143
+ ```typescript
144
+ import { createAuth, AuthError } from 'sentri';
145
+ import type { AuthResult } from 'sentri';
146
+
147
+ export const auth = createAuth({
148
+ secret: process.env.JWT_SECRET!,
149
+ validRoles: ['user', 'admin'] as const,
150
+ adapter: myAdapter,
151
+
152
+ router: {
153
+ // Add an OTP check before issuing tokens
154
+ login: async (input): Promise<AuthResult> => {
155
+ const otpVerified = await redis.get(`otp:${input.identifier}`);
156
+ if (!otpVerified) {
157
+ return { success: false, error: new AuthError('INVALID_CREDENTIALS', 'OTP required') };
158
+ }
159
+ return defaultLogin(input);
160
+ },
161
+
162
+ // Send a welcome email after signup
163
+ signup: async (input) => {
164
+ const result = await defaultSignup(input);
165
+ if (result.success) {
166
+ await emailService.sendWelcome(input.identifier);
167
+ }
168
+ return result;
169
+ },
170
+
171
+ // Audit-log every token rotation
172
+ refresh: async (refreshToken) => {
173
+ const result = await defaultRefresh(refreshToken);
174
+ if (result.success) {
175
+ await auditLog.record('token_rotated', result.user.id);
176
+ }
177
+ return result;
178
+ },
179
+ },
180
+ });
181
+ ```
182
+
183
+ ### Available handler signatures
184
+
185
+ | Key | Signature | Must return |
186
+ |---|---|---|
187
+ | `signup` | `(input: SignupInput) => Promise<SignupResult>` | `SignupResult` |
188
+ | `login` | `(input: LoginInput) => Promise<AuthResult>` | `AuthResult` |
189
+ | `refresh` | `(refreshToken: string) => Promise<RefreshResult>` | `RefreshResult` |
190
+ | `logout` | `(refreshToken: string \| undefined) => Promise<void>` | `void` |
191
+ | `logoutAll` | `(userId: string) => Promise<void>` | `void` |
192
+ | `assignRoles` | `(userId: string, roles: string[]) => Promise<AssignRolesResult>` | `AssignRolesResult` |
193
+
194
+ The router always validates the request body and URL parameters before calling any handler. Your function receives the already-validated, trimmed input.
195
+
196
+ ---
197
+
127
198
  ## Adapter Interface
128
199
 
129
200
  The adapter connects sentri to your database. Implement `AuthAdapter` for any ORM or data layer.
@@ -168,7 +239,7 @@ import { createAdapter } from './adapter.js';
168
239
  export const adapter = createAdapter(db);
169
240
  ```
170
241
 
171
- `createAdapter` throws an `AdapterConfigError` at runtime if called without a `db` argument.
242
+ `createAdapter` throws `AuthError` with code `CONFIGURATION_ERROR` at runtime if called without a `db` argument.
172
243
 
173
244
  ---
174
245
 
@@ -284,11 +355,11 @@ Status: 200
284
355
 
285
356
  ### `auth.protect()`
286
357
 
287
- Verifies the `Authorization: Bearer <token>` header and injects `req.user` into the request.
358
+ Verifies the `Authorization: Bearer <token>` header and injects `request.user` into the request.
288
359
 
289
360
  ```typescript
290
- router.get('/dashboard', auth.protect(), (req, res) => {
291
- res.json(req.user); // { id, identifier, roles }
361
+ router.get('/dashboard', auth.protect(), (request, response) => {
362
+ response.json(request.user); // { id, identifier, roles }
292
363
  });
293
364
  ```
294
365
 
@@ -341,43 +412,21 @@ router.delete(
341
412
 
342
413
  ## Programmatic API
343
414
 
344
- All methods are available on the auth client for use outside the built-in router.
415
+ Token and password utilities are available on the auth client for use outside the built-in router.
345
416
 
346
417
  ```typescript
347
- // Auth
348
- const result = await auth.signup({ identifier: 'user@example.com', password: 'secret123' });
349
- const result = await auth.login({ identifier: 'user@example.com', password: 'secret123' });
350
- const result = await auth.refresh(refreshToken);
351
- await auth.logout(refreshToken);
352
- await auth.logoutAll(userId);
353
-
354
- // Roles
355
- const result = await auth.assignRoles(userId, ['admin']);
356
- // Merges with existing roles — result.user.roles has the full updated list
357
-
358
418
  // Token utilities
359
419
  const accessToken = auth.signAccessToken({ id, identifier, roles });
360
420
  const user = auth.verifyAccessToken(accessToken); // throws AuthError if invalid
361
421
  const { sessionId } = auth.verifyRefreshToken(token); // throws AuthError if invalid
422
+ const refreshToken = auth.signRefreshToken(sessionId);
362
423
 
363
424
  // Password utilities
364
425
  const hash = await auth.hashPassword('secret123');
365
426
  const valid = await auth.verifyPassword('secret123', hash);
366
427
  ```
367
428
 
368
- All auth methods return a discriminated union check `result.success` before accessing data:
369
-
370
- ```typescript
371
- const result = await auth.login({ identifier, password });
372
-
373
- if (!result.success) {
374
- console.error(result.error.code); // 'INVALID_CREDENTIALS'
375
- console.error(result.error.message);
376
- return;
377
- }
378
-
379
- const { accessToken, refreshToken, user } = result;
380
- ```
429
+ `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.
381
430
 
382
431
  ---
383
432
 
@@ -396,6 +445,7 @@ import type {
396
445
  ApiResponse,
397
446
  SignupInput,
398
447
  LoginInput,
448
+ RouterHandlers,
399
449
  UserRecord,
400
450
  SessionRecord,
401
451
  CreateUserData,
@@ -432,17 +482,17 @@ The built-in router converts all `AuthError` instances to the standard envelope
432
482
  ```typescript
433
483
  import { AuthError } from 'sentri';
434
484
 
435
- app.use((err, req, res, next) => {
436
- if (err instanceof AuthError) {
485
+ app.use((error, _request, response, next) => {
486
+ if (error instanceof AuthError) {
437
487
  const status =
438
- err.code === 'UNAUTHORIZED' || err.code === 'TOKEN_EXPIRED' || err.code === 'TOKEN_INVALID' || err.code === 'INVALID_CREDENTIALS' ? 401
439
- : err.code === 'FORBIDDEN' ? 403
440
- : err.code === 'USER_NOT_FOUND' ? 404
441
- : err.code === 'USER_ALREADY_EXISTS' ? 409
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
442
492
  : 400;
443
493
 
444
- return res.status(status).json({ error: true, statusCode: status, message: err.message, data: null });
494
+ return response.status(status).json({ error: true, statusCode: status, message: error.message, data: null });
445
495
  }
446
- next(err);
496
+ next(error);
447
497
  });
448
498
  ```
package/dist/client.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { PermitCheck, PermitOptions } from './middleware/permit.js';
2
- import type { AssignRolesResult, AuthConfig, AuthResult, AuthUser, LoginInput, RefreshResult, SignupInput, SignupResult } from './types/auth.js';
2
+ import type { AuthConfig, AuthUser } from './types/auth.js';
3
3
  import type { RequestHandler, Router } from 'express';
4
4
  /**
5
5
  * The bound auth client returned by {@link createAuth}.
@@ -8,52 +8,9 @@ import type { RequestHandler, Router } from 'express';
8
8
  * you never need to pass config around yourself.
9
9
  *
10
10
  * `TRole` is inferred from `validRoles` and narrows role strings to your
11
- * application's exact union type everywhere (signup, authorize, req.user, etc.).
11
+ * application's exact union type everywhere (authorize, req.user, etc.).
12
12
  */
13
13
  export interface AuthClient<TRole extends string = string> {
14
- /**
15
- * Register a new user.
16
- *
17
- * Validates that every requested role is in `validRoles`, rejects duplicate
18
- * identifiers, hashes the password, creates the user record, and returns the
19
- * created user. No tokens are issued — call `login` after signup.
20
- */
21
- signup(input: SignupInput<TRole>): Promise<SignupResult<TRole>>;
22
- /**
23
- * Authenticate an existing user by email and password.
24
- *
25
- * On success, creates a new session and returns an access + refresh token pair.
26
- * Returns `{ success: false, error }` with code `INVALID_CREDENTIALS` on any
27
- * mismatch (intentionally vague to prevent user enumeration).
28
- */
29
- login(input: LoginInput): Promise<AuthResult<TRole>>;
30
- /**
31
- * Exchange a valid refresh token for a new access + refresh token pair.
32
- *
33
- * Verifies the JWT, looks up the session in the database, checks expiry,
34
- * then **rotates** the session: the old session is deleted and a new one is
35
- * created. Old refresh tokens are immediately invalidated.
36
- */
37
- refresh(refreshToken: string): Promise<RefreshResult<TRole>>;
38
- /**
39
- * Invalidate a single session identified by the refresh token.
40
- *
41
- * Safe to call even if the token is already expired — it will simply
42
- * attempt a DB delete and resolve.
43
- */
44
- logout(refreshToken: string): Promise<void>;
45
- /**
46
- * Delete all sessions for a user, effectively logging them out of every device.
47
- *
48
- * @param userId - The user's primary key as stored in the database.
49
- */
50
- logoutAll(userId: string): Promise<void>;
51
- /**
52
- * Add roles to another user. Merges the given roles with the user's existing
53
- * roles (no duplicates). The built-in router exposes this as
54
- * `POST /users/:userId/roles` and restricts it to users with the `admin` role.
55
- */
56
- assignRoles(userId: string, roles: string[]): Promise<AssignRolesResult<TRole>>;
57
14
  /**
58
15
  * Express middleware factory that enforces authentication.
59
16
  *
@@ -77,36 +34,6 @@ export interface AuthClient<TRole extends string = string> {
77
34
  * router.delete('/posts/:id', auth.protect(), auth.authorize('admin'), handler);
78
35
  */
79
36
  authorize(...roles: TRole[]): RequestHandler;
80
- /** Hash a plain-text password using the configured `saltRounds`. */
81
- hashPassword(plain: string): Promise<string>;
82
- /** Compare a plain-text password against a stored bcrypt hash. */
83
- verifyPassword(plain: string, hash: string): Promise<boolean>;
84
- /** Sign an access token for the given user payload. */
85
- signAccessToken(payload: AuthUser<TRole>): string;
86
- /** Sign a refresh token bound to a session ID. */
87
- signRefreshToken(sessionId: string): string;
88
- /** Verify and decode an access token. Throws `AuthError` if invalid or expired. */
89
- verifyAccessToken(token: string): AuthUser<TRole>;
90
- /** Verify and decode a refresh token. Throws `AuthError` if invalid or expired. */
91
- verifyRefreshToken(token: string): {
92
- sessionId: string;
93
- };
94
- /**
95
- * Returns a pre-built Express Router with all standard auth endpoints mounted:
96
- *
97
- * - `POST /signup` — register, returns `{ user }`
98
- * - `POST /login` — authenticate, sets refresh token cookie, returns `{ accessToken, user }`
99
- * - `POST /refresh` — reads refresh token from cookie, returns `{ accessToken }`
100
- * - `POST /logout` — invalidate current session
101
- * - `POST /logout-all` — invalidate all sessions (requires valid access token)
102
- *
103
- * Requires `express.json()` to be applied before the router.
104
- *
105
- * @example
106
- * app.use(express.json());
107
- * app.use('/auth', auth.router());
108
- */
109
- router(): Router;
110
37
  /**
111
38
  * Express middleware factory for resource-level permission checks.
112
39
  *
@@ -140,6 +67,38 @@ export interface AuthClient<TRole extends string = string> {
140
67
  */
141
68
  permit(check: PermitCheck): RequestHandler;
142
69
  permit(options: PermitOptions<TRole>): RequestHandler;
70
+ /** Hash a plain-text password using the configured `saltRounds`. */
71
+ hashPassword(plain: string): Promise<string>;
72
+ /** Compare a plain-text password against a stored bcrypt hash. */
73
+ verifyPassword(plain: string, hash: string): Promise<boolean>;
74
+ /** Sign an access token for the given user payload. */
75
+ signAccessToken(payload: AuthUser<TRole>): string;
76
+ /** Sign a refresh token bound to a session ID. */
77
+ signRefreshToken(sessionId: string): string;
78
+ /** Verify and decode an access token. Throws `AuthError` if invalid or expired. */
79
+ verifyAccessToken(token: string): AuthUser<TRole>;
80
+ /** Verify and decode a refresh token. Throws `AuthError` if invalid or expired. */
81
+ verifyRefreshToken(token: string): {
82
+ sessionId: string;
83
+ };
84
+ /**
85
+ * Returns a pre-built Express Router with all standard auth endpoints mounted:
86
+ *
87
+ * - `POST /signup` — register a user, returns `{ user }`
88
+ * - `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
+ * - `GET /me` — return the authenticated user
93
+ * - `POST /users/:userId/roles` — assign roles (requires admin)
94
+ *
95
+ * Requires `express.json()` to be applied before the router.
96
+ *
97
+ * @example
98
+ * app.use(express.json());
99
+ * app.use('/auth', auth.router());
100
+ */
101
+ router(): Router;
143
102
  }
144
103
  /**
145
104
  * 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":"AAQA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EACV,iBAAiB,EACjB,UAAU,EACV,UAAU,EACV,QAAQ,EACR,UAAU,EACV,aAAa,EACb,WAAW,EACX,YAAY,EACb,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtD;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IACvD;;;;;;OAMG;IACH,MAAM,CAAC,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAEhE;;;;;;OAMG;IACH,KAAK,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAErD;;;;;;OAMG;IACH,OAAO,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;IAE7D;;;;;OAKG;IACH,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5C;;;;OAIG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzC;;;;OAIG;IACH,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;IAEhF;;;;;;;;;;OAUG;IACH,OAAO,IAAI,cAAc,CAAC;IAE1B;;;;;;;;;OASG;IACH,SAAS,CAAC,GAAG,KAAK,EAAE,KAAK,EAAE,GAAG,cAAc,CAAC;IAE7C,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;;;;;;;;;;;;;;OAcG;IACH,MAAM,IAAI,MAAM,CAAC;IAEjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,cAAc,CAAC;IAC3C,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,cAAc,CAAC;CACvD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EACtD,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,GACxB,UAAU,CAAC,KAAK,CAAC,CAsBnB"}
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"}
package/dist/client.js CHANGED
@@ -1,7 +1,6 @@
1
1
  import { hashPassword, verifyPassword } from './libs/hash.js';
2
2
  import { signAccessToken, signRefreshToken, verifyAccessToken, verifyRefreshToken } from './libs/token.js';
3
3
  import { resolveConfig, validateConfig } from './libs/config.js';
4
- import { signup, login, refresh, logout, logoutAll, assignRoles } from './services/auth.js';
5
4
  import { protect } from './middleware/protect.js';
6
5
  import { authorize } from './middleware/authorize.js';
7
6
  import { permit } from './middleware/permit.js';
@@ -29,12 +28,6 @@ export function createAuth(config) {
29
28
  validateConfig(config);
30
29
  const resolved = resolveConfig(config);
31
30
  return {
32
- signup: (input) => signup(input, config),
33
- login: (input) => login(input, config),
34
- refresh: (refreshToken) => refresh(refreshToken, config),
35
- logout: (refreshToken) => logout(refreshToken, config),
36
- logoutAll: (userId) => logoutAll(userId, config),
37
- assignRoles: (userId, roles) => assignRoles(userId, roles, config),
38
31
  protect: () => protect(config),
39
32
  authorize: (...roles) => authorize(...roles),
40
33
  hashPassword: (plain) => hashPassword(plain, resolved.saltRounds),
@@ -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,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC5F,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;AAwK1D;;;;;;;;;;;;;;;;;;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,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,KAAoB,EAAE,MAAoB,CAAiC;QACrG,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,MAAoB,CAA+B;QAClF,OAAO,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,EAAE,MAAoB,CAAkC;QACvG,MAAM,EAAE,CAAC,YAAY,EAAE,EAAE,CAAC,MAAM,CAAC,YAAY,EAAE,MAAoB,CAAC;QACpE,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,MAAoB,CAAC;QAC9D,WAAW,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,KAAK,EAAE,MAAoB,CAAsC;QACrH,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;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"}
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ declare global {
6
6
  }
7
7
  }
8
8
  }
9
- export type { AuthConfig, CookieConfig, AuthUser, AuthResult, SignupResult, AssignRolesResult, RefreshResult, ApiResponse, SignupInput, LoginInput, AuthAdapter, UserRecord, SessionRecord, CreateUserData, } from './types/auth.js';
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
12
  export { AuthError } from './errors/AuthError.js';
@@ -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,UAAU,EACV,YAAY,EACZ,iBAAiB,EACjB,aAAa,EACb,WAAW,EACX,WAAW,EACX,UAAU,EACV,WAAW,EACX,UAAU,EACV,aAAa,EACb,cAAc,GACf,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;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"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgCA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
@@ -1,4 +1,9 @@
1
1
  import type { AuthAdapter, AuthConfig } from '../types/auth.js';
2
+ /**
3
+ * Fully-resolved configuration with all optional fields filled in by
4
+ * their defaults. Produced by {@link resolveConfig} and used internally
5
+ * wherever the library needs guaranteed values.
6
+ */
2
7
  export interface ResolvedConfig {
3
8
  secret: string;
4
9
  accessExpiresIn: string | number;
@@ -9,10 +14,49 @@ export interface ResolvedConfig {
9
14
  adapter: AuthAdapter;
10
15
  }
11
16
  /**
12
- * Validates config at startup so misconfiguration is caught immediately,
17
+ * Validate configuration at startup so misconfiguration is caught immediately,
13
18
  * not at the first login attempt.
19
+ *
20
+ * Throws {@link AuthError} with code `CONFIGURATION_ERROR` for any of:
21
+ * - `secret` missing or shorter than 32 characters
22
+ * - `saltRounds` outside the range 10–31
23
+ * - `validRoles` is empty or missing
24
+ * - `adapter` is missing
25
+ *
26
+ * @param config - The raw config passed to {@link createAuth}.
27
+ * @throws {AuthError} With code `CONFIGURATION_ERROR` on any invalid field.
14
28
  */
15
29
  export declare function validateConfig(config: AuthConfig): void;
30
+ /**
31
+ * Merge a partial {@link AuthConfig} with library defaults and return a
32
+ * fully-resolved configuration object.
33
+ *
34
+ * Does **not** validate the config — call {@link validateConfig} first.
35
+ *
36
+ * Defaults applied:
37
+ * - `accessExpiresIn` → `'15m'`
38
+ * - `refreshExpiresIn` → `'7d'`
39
+ * - `algorithm` → `'HS256'`
40
+ * - `saltRounds` → `12`
41
+ *
42
+ * @param partial - The raw config passed to {@link createAuth}.
43
+ * @returns A {@link ResolvedConfig} with every field guaranteed to be present.
44
+ */
16
45
  export declare function resolveConfig(partial: AuthConfig): ResolvedConfig;
46
+ /**
47
+ * Convert a duration string or a number of seconds into milliseconds.
48
+ *
49
+ * Supported unit suffixes: `s` (seconds), `m` (minutes), `h` (hours),
50
+ * `d` (days), `w` (weeks). Numeric inputs are treated as seconds.
51
+ *
52
+ * @example
53
+ * parseExpiry('15m') // 900_000
54
+ * parseExpiry('7d') // 604_800_000
55
+ * parseExpiry(60) // 60_000
56
+ *
57
+ * @param expiresIn - A duration string (e.g. `'15m'`, `'7d'`) or a number of seconds.
58
+ * @returns The equivalent duration in milliseconds.
59
+ * @throws {Error} If the string format is unrecognised.
60
+ */
17
61
  export declare function parseExpiry(expiresIn: string | number): number;
18
62
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/libs/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEhE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,WAAW,CAAC;CACtB;AAMD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CA0BvD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,cAAc,CAUjE;AAGD,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAkB9D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/libs/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEhE;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,WAAW,CAAC;CACtB;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CA0BvD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,cAAc,CAUjE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAkB9D"}
@@ -3,8 +3,17 @@ const MIN_SECRET_LENGTH = 32;
3
3
  const MIN_SALT_ROUNDS = 10;
4
4
  const MAX_SALT_ROUNDS = 31;
5
5
  /**
6
- * Validates config at startup so misconfiguration is caught immediately,
6
+ * Validate configuration at startup so misconfiguration is caught immediately,
7
7
  * not at the first login attempt.
8
+ *
9
+ * Throws {@link AuthError} with code `CONFIGURATION_ERROR` for any of:
10
+ * - `secret` missing or shorter than 32 characters
11
+ * - `saltRounds` outside the range 10–31
12
+ * - `validRoles` is empty or missing
13
+ * - `adapter` is missing
14
+ *
15
+ * @param config - The raw config passed to {@link createAuth}.
16
+ * @throws {AuthError} With code `CONFIGURATION_ERROR` on any invalid field.
8
17
  */
9
18
  export function validateConfig(config) {
10
19
  if (!config.secret || config.secret.trim().length === 0) {
@@ -24,6 +33,21 @@ export function validateConfig(config) {
24
33
  throw new AuthError('CONFIGURATION_ERROR', 'adapter is required');
25
34
  }
26
35
  }
36
+ /**
37
+ * Merge a partial {@link AuthConfig} with library defaults and return a
38
+ * fully-resolved configuration object.
39
+ *
40
+ * Does **not** validate the config — call {@link validateConfig} first.
41
+ *
42
+ * Defaults applied:
43
+ * - `accessExpiresIn` → `'15m'`
44
+ * - `refreshExpiresIn` → `'7d'`
45
+ * - `algorithm` → `'HS256'`
46
+ * - `saltRounds` → `12`
47
+ *
48
+ * @param partial - The raw config passed to {@link createAuth}.
49
+ * @returns A {@link ResolvedConfig} with every field guaranteed to be present.
50
+ */
27
51
  export function resolveConfig(partial) {
28
52
  return {
29
53
  secret: partial.secret,
@@ -35,7 +59,21 @@ export function resolveConfig(partial) {
35
59
  adapter: partial.adapter,
36
60
  };
37
61
  }
38
- // Parses '15m', '7d', '1h', '30s', '2w' → milliseconds
62
+ /**
63
+ * Convert a duration string or a number of seconds into milliseconds.
64
+ *
65
+ * Supported unit suffixes: `s` (seconds), `m` (minutes), `h` (hours),
66
+ * `d` (days), `w` (weeks). Numeric inputs are treated as seconds.
67
+ *
68
+ * @example
69
+ * parseExpiry('15m') // 900_000
70
+ * parseExpiry('7d') // 604_800_000
71
+ * parseExpiry(60) // 60_000
72
+ *
73
+ * @param expiresIn - A duration string (e.g. `'15m'`, `'7d'`) or a number of seconds.
74
+ * @returns The equivalent duration in milliseconds.
75
+ * @throws {Error} If the string format is unrecognised.
76
+ */
39
77
  export function parseExpiry(expiresIn) {
40
78
  if (typeof expiresIn === 'number')
41
79
  return expiresIn * 1000;
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/libs/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAanD,MAAM,iBAAiB,GAAG,EAAE,CAAC;AAC7B,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,MAAkB;IAC/C,IAAI,CAAC,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,SAAS,CAAC,qBAAqB,EAAE,0BAA0B,CAAC,CAAC;IACzE,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,iBAAiB,EAAE,CAAC;QAC7C,MAAM,IAAI,SAAS,CACjB,qBAAqB,EACrB,2BAA2B,iBAAiB,0CAA0C,CACvF,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;IAC3C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,eAAe,IAAI,UAAU,GAAG,eAAe,EAAE,CAAC;QAClG,MAAM,IAAI,SAAS,CACjB,qBAAqB,EACrB,yCAAyC,eAAe,QAAQ,eAAe,EAAE,CAClF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzD,MAAM,IAAI,SAAS,CAAC,qBAAqB,EAAE,2CAA2C,CAAC,CAAC;IAC1F,CAAC;IAED,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,SAAS,CAAC,qBAAqB,EAAE,qBAAqB,CAAC,CAAC;IACpE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAmB;IAC/C,OAAO;QACL,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,KAAK;QACjD,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,IAAI;QAClD,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,OAAO;QACvC,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,EAAE;QACpC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,OAAO,EAAE,OAAO,CAAC,OAAO;KACzB,CAAC;AACJ,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,WAAW,CAAC,SAA0B;IACpD,IAAI,OAAO,SAAS,KAAK,QAAQ;QAAE,OAAO,SAAS,GAAG,IAAI,CAAC;IAC3D,MAAM,WAAW,GAA2B;QAC1C,CAAC,EAAE,KAAK;QACR,CAAC,EAAE,MAAM;QACT,CAAC,EAAE,SAAS;QACZ,CAAC,EAAE,UAAU;QACb,CAAC,EAAE,WAAW;KACf,CAAC;IACF,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACjD,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,uBAAuB,SAAS,gCAAgC,CAAC,CAAC;IACpF,CAAC;IACD,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACnC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CAAC,uBAAuB,SAAS,gCAAgC,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC;AACvC,CAAC"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/libs/config.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,17 @@
1
+ /**
2
+ * Hash a plain-text password using bcrypt.
3
+ *
4
+ * @param plain - The raw password string supplied by the user.
5
+ * @param saltRounds - bcrypt cost factor; higher values increase security at the cost of speed.
6
+ * @returns The bcrypt hash string to persist in the database.
7
+ */
1
8
  export declare function hashPassword(plain: string, saltRounds?: number): Promise<string>;
9
+ /**
10
+ * Compare a plain-text password against a stored bcrypt hash.
11
+ *
12
+ * @param plain - The raw password string to verify.
13
+ * @param hash - The stored bcrypt hash from the database.
14
+ * @returns `true` if the password matches the hash, `false` otherwise.
15
+ */
2
16
  export declare function verifyPassword(plain: string, hash: string): Promise<boolean>;
3
17
  //# sourceMappingURL=hash.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/libs/hash.ts"],"names":[],"mappings":"AAEA,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAElF;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAElF"}
1
+ {"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/libs/hash.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAElF;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAElF"}
package/dist/libs/hash.js CHANGED
@@ -1,7 +1,21 @@
1
1
  import bcrypt from 'bcrypt';
2
+ /**
3
+ * Hash a plain-text password using bcrypt.
4
+ *
5
+ * @param plain - The raw password string supplied by the user.
6
+ * @param saltRounds - bcrypt cost factor; higher values increase security at the cost of speed.
7
+ * @returns The bcrypt hash string to persist in the database.
8
+ */
2
9
  export async function hashPassword(plain, saltRounds = 12) {
3
10
  return bcrypt.hash(plain, saltRounds);
4
11
  }
12
+ /**
13
+ * Compare a plain-text password against a stored bcrypt hash.
14
+ *
15
+ * @param plain - The raw password string to verify.
16
+ * @param hash - The stored bcrypt hash from the database.
17
+ * @returns `true` if the password matches the hash, `false` otherwise.
18
+ */
5
19
  export async function verifyPassword(plain, hash) {
6
20
  return bcrypt.compare(plain, hash);
7
21
  }
@@ -1 +1 @@
1
- {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/libs/hash.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAa,EAAE,UAAU,GAAG,EAAE;IAC/D,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAa,EAAE,IAAY;IAC9D,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC"}
1
+ {"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/libs/hash.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAa,EAAE,UAAU,GAAG,EAAE;IAC/D,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAa,EAAE,IAAY;IAC9D,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC"}
@@ -1,7 +1,44 @@
1
1
  import type { AuthConfig, AuthUser } from '../types/auth.js';
2
+ /**
3
+ * Sign a short-lived access token containing the user's identity and roles.
4
+ *
5
+ * Uses the access-specific secret derived from config and the configured
6
+ * `accessExpiresIn` duration and HMAC algorithm.
7
+ *
8
+ * @param payload - The {@link AuthUser} payload to embed (id, identifier, roles).
9
+ * @param config - Auth configuration used to derive the secret and options.
10
+ * @returns Compact JWT string.
11
+ */
2
12
  export declare function signAccessToken(payload: AuthUser, config: AuthConfig): string;
13
+ /**
14
+ * Sign a long-lived refresh token bound to a specific session ID.
15
+ *
16
+ * Uses the refresh-specific secret derived from config and the configured
17
+ * `refreshExpiresIn` duration. The session ID is embedded as the sole claim
18
+ * so the token can be used to look up and rotate the session.
19
+ *
20
+ * @param sessionId - The database session ID to bind to this token.
21
+ * @param config - Auth configuration used to derive the secret and options.
22
+ * @returns Compact JWT string.
23
+ */
3
24
  export declare function signRefreshToken(sessionId: string, config: AuthConfig): string;
25
+ /**
26
+ * Verify an access token and return its decoded {@link AuthUser} payload.
27
+ *
28
+ * @param token - Compact JWT access token string.
29
+ * @param config - Auth configuration used to derive the secret and algorithm.
30
+ * @returns Decoded `AuthUser` payload (id, identifier, roles).
31
+ * @throws {AuthError} With `TOKEN_EXPIRED` if expired, `TOKEN_INVALID` otherwise.
32
+ */
4
33
  export declare function verifyAccessToken(token: string, config: AuthConfig): AuthUser;
34
+ /**
35
+ * Verify a refresh token and return the embedded session ID.
36
+ *
37
+ * @param token - Compact JWT refresh token string.
38
+ * @param config - Auth configuration used to derive the secret and algorithm.
39
+ * @returns Object with `sessionId` matching the one passed to {@link signRefreshToken}.
40
+ * @throws {AuthError} With `TOKEN_EXPIRED` if expired, `TOKEN_INVALID` otherwise.
41
+ */
5
42
  export declare function verifyRefreshToken(token: string, config: AuthConfig): {
6
43
  sessionId: string;
7
44
  };
@@ -1 +1 @@
1
- {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/libs/token.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AA2C7D,wBAAgB,eAAe,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAI7E;AAED,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAI9E;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,QAAQ,CAI7E;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAI3F"}
1
+ {"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/libs/token.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAqE7D;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAI7E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAI9E;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,QAAQ,CAI7E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAI3F"}