@warlock.js/auth 5.2.4 → 5.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/llms-full.txt CHANGED
@@ -20,7 +20,7 @@ JWT-based authentication for Warlock. `Auth` base model + `authMiddleware` gate
20
20
  ## Install
21
21
 
22
22
  ```bash
23
- yarn add @warlock.js/auth
23
+ pnpm add @warlock.js/auth
24
24
  ```
25
25
 
26
26
  ## Foundations
@@ -399,9 +399,10 @@ description: 'Run the full login flow via authService.login(Model, credentials,
399
399
 
400
400
  ```ts
401
401
  import { authService } from "@warlock.js/auth";
402
+ import { type RequestHandler } from "@warlock.js/core";
402
403
  import { User } from "@/app/users/models/user.model";
403
404
 
404
- async function loginController(request: Request, response: Response) {
405
+ export const loginController: RequestHandler = async ({ request, response }) => {
405
406
  const result = await authService.login(User, {
406
407
  email: request.input("email"),
407
408
  password: request.input("password"),
@@ -418,7 +419,7 @@ async function loginController(request: Request, response: Response) {
418
419
  user: result.user,
419
420
  tokens: result.tokens,
420
421
  });
421
- }
422
+ };
422
423
  ```
423
424
 
424
425
  The returned shape:
@@ -470,7 +471,9 @@ Useful for "show active sessions" UIs — see `authService.getActiveSessions(use
470
471
  ## Logout — `authService.logout(user, accessToken?, refreshToken?)`
471
472
 
472
473
  ```ts
473
- async function logoutController(request: Request, response: Response) {
474
+ import { type RequestHandler } from "@warlock.js/core";
475
+
476
+ export const logoutController: RequestHandler = async ({ request, response }) => {
474
477
  await authService.logout(
475
478
  request.user!,
476
479
  request.authorizationValue, // access token from the Authorization header
@@ -478,7 +481,7 @@ async function logoutController(request: Request, response: Response) {
478
481
  );
479
482
 
480
483
  return response.success({ message: "Logged out" });
481
- }
484
+ };
482
485
  ```
483
486
 
484
487
  The contract:
@@ -502,7 +505,9 @@ Useful for "logout from all devices" buttons. Fires `token.revoked` per token +
502
505
  ## Refresh tokens — `authService.refreshTokens(refreshTokenString, deviceInfo?)`
503
506
 
504
507
  ```ts
505
- async function refreshController(request: Request, response: Response) {
508
+ import { type RequestHandler } from "@warlock.js/core";
509
+
510
+ export const refreshController: RequestHandler = async ({ request, response }) => {
506
511
  const tokens = await authService.refreshTokens(
507
512
  request.input("refreshToken"),
508
513
  { userAgent: request.header("user-agent"), ip: request.ip },
@@ -513,7 +518,7 @@ async function refreshController(request: Request, response: Response) {
513
518
  }
514
519
 
515
520
  return response.success({ tokens });
516
- }
521
+ };
517
522
  ```
518
523
 
519
524
  Returns a new token pair or `null` (token expired, revoked, or replay-detected). With rotation enabled (default), the old refresh token is consumed; the new pair stays in the same "family." Replay → revoke the whole family. See [`@warlock.js/auth/manage-tokens/SKILL.md`](@warlock.js/auth/manage-tokens/SKILL.md).
@@ -872,13 +877,15 @@ On failure, the middleware returns one of these 401 responses:
872
877
  ## Reading the user in a controller
873
878
 
874
879
  ```ts
875
- async function accountController(request: Request, response: Response) {
880
+ import { type RequestHandler } from "@warlock.js/core";
881
+
882
+ export const accountController: RequestHandler = async ({ request, response }) => {
876
883
  const user = request.user!; // typed via your Auth subclass
877
884
  return response.success({
878
885
  id: user.id,
879
886
  email: user.get("email"),
880
887
  });
881
- }
888
+ };
882
889
  ```
883
890
 
884
891
  Because the middleware always requires a valid token, `request.user` is guaranteed present inside any gated controller (the middleware would have responded 401 otherwise). The `!` is safe here.
@@ -899,10 +906,12 @@ Every route inside the group is gated — the group's `middleware` array applies
899
906
  There is no "hydrate `request.user` if a token is present, otherwise continue" mode. `authMiddleware` always requires a valid token. If a route should be reachable anonymously, leave the middleware off — and read the token yourself in the controller if you want soft personalization:
900
907
 
901
908
  ```ts
902
- async function feedController(request: Request, response: Response) {
909
+ import { type RequestHandler } from "@warlock.js/core";
910
+
911
+ export const feedController: RequestHandler = async ({ request, response }) => {
903
912
  const token = request.authorizationValue;
904
913
  // optionally decode/hydrate manually when a token is present
905
- }
914
+ };
906
915
  ```
907
916
 
908
917
  ## Custom error responses
@@ -975,10 +984,10 @@ Two-step on the server: create the user (with hashed password), then issue token
975
984
 
976
985
  ```ts
977
986
  import { authService } from "@warlock.js/auth";
978
- import { hashPassword } from "@warlock.js/core";
987
+ import { hashPassword, type RequestHandler } from "@warlock.js/core";
979
988
  import { User } from "@/app/users/models/user.model";
980
989
 
981
- async function registerController(request: Request, response: Response) {
990
+ export const registerController: RequestHandler = async ({ request, response }) => {
982
991
  const { email, password, name } = request.all();
983
992
 
984
993
  // 1. Check duplicates
@@ -1005,7 +1014,7 @@ async function registerController(request: Request, response: Response) {
1005
1014
  user, // shape via static toJsonColumns / static resource
1006
1015
  tokens,
1007
1016
  });
1008
- }
1017
+ };
1009
1018
  ```
1010
1019
 
1011
1020
  That's the whole flow. `User.create({...})` runs the schema validation (including `.email()`, `.min()`, etc. on each field), so you don't need a separate validation pass — see [`@warlock.js/seal/handle-seal-errors/SKILL.md`](@warlock.js/seal/handle-seal-errors/SKILL.md) for catching validation failures.
@@ -1134,7 +1143,7 @@ export default defineConfig({
1134
1143
  ## `warlock jwt.generate` — JWT secret bootstrap
1135
1144
 
1136
1145
  ```bash
1137
- yarn warlock jwt.generate
1146
+ pnpm warlock jwt.generate
1138
1147
  ```
1139
1148
 
1140
1149
  Generates a cryptographically strong secret string and writes it to your `.env` as `JWT_SECRET=...` (and `JWT_REFRESH_SECRET=...` if refresh tokens are enabled).
@@ -1146,7 +1155,7 @@ Run it once when setting up a new project. Each developer typically runs it loca
1146
1155
  ## `warlock auth.cleanup` — expired token sweep
1147
1156
 
1148
1157
  ```bash
1149
- yarn warlock auth.cleanup
1158
+ pnpm warlock auth.cleanup
1150
1159
  ```
1151
1160
 
1152
1161
  Runs `authService.cleanupExpiredTokens()` — deletes every refresh token whose `expires_at` has passed, then sweeps expired access-token rows too. Fires `token.expired` per refresh token and `cleanup.completed` once.
@@ -1174,7 +1183,7 @@ In-process — no shell call. See [`@warlock.js/scheduler/scheduler-basics/SKILL
1174
1183
  ### Via system cron
1175
1184
 
1176
1185
  ```cron
1177
- 0 3 * * * cd /path/to/app && /usr/local/bin/yarn warlock auth.cleanup
1186
+ 0 3 * * * cd /path/to/app && /usr/local/bin/pnpm warlock auth.cleanup
1178
1187
  ```
1179
1188
 
1180
1189
  Out-of-process — works when you don't want the scheduler subsystem running in this service.
@@ -1188,8 +1197,8 @@ If you have very-short-lived refresh tokens (1h expiry) and a million-user scale
1188
1197
  ## `warlock auth.purge-never-expiring` — one-off remediation
1189
1198
 
1190
1199
  ```bash
1191
- yarn warlock auth.purge-never-expiring --dry-run # report only
1192
- yarn warlock auth.purge-never-expiring # report, then revoke
1200
+ pnpm warlock auth.purge-never-expiring --dry-run # report only
1201
+ pnpm warlock auth.purge-never-expiring # report, then revoke
1193
1202
  ```
1194
1203
 
1195
1204
  Register with `registerAuthPurgeNeverExpiringCommand()`.
package/package.json CHANGED
@@ -12,12 +12,12 @@
12
12
  "ms": "^2.1.3"
13
13
  },
14
14
  "peerDependencies": {
15
- "@warlock.js/fs": "5.2.4",
16
- "@warlock.js/cache": "5.2.4",
17
- "@warlock.js/cascade": "5.2.4",
18
- "@warlock.js/core": "5.2.4",
19
- "@warlock.js/logger": "5.2.4",
20
- "@warlock.js/seal": "5.2.4"
15
+ "@warlock.js/fs": "5.3.1",
16
+ "@warlock.js/cache": "5.3.1",
17
+ "@warlock.js/cascade": "5.3.1",
18
+ "@warlock.js/core": "5.3.1",
19
+ "@warlock.js/logger": "5.3.1",
20
+ "@warlock.js/seal": "5.3.1"
21
21
  },
22
22
  "repository": {
23
23
  "type": "git",
@@ -33,7 +33,7 @@
33
33
  ],
34
34
  "author": "hassanzohdy",
35
35
  "license": "MIT",
36
- "version": "5.2.4",
36
+ "version": "5.3.1",
37
37
  "type": "module",
38
38
  "main": "./esm/index.mjs",
39
39
  "module": "./esm/index.mjs",
@@ -11,9 +11,10 @@ description: 'Run the full login flow via authService.login(Model, credentials,
11
11
 
12
12
  ```ts
13
13
  import { authService } from "@warlock.js/auth";
14
+ import { type RequestHandler } from "@warlock.js/core";
14
15
  import { User } from "@/app/users/models/user.model";
15
16
 
16
- async function loginController(request: Request, response: Response) {
17
+ export const loginController: RequestHandler = async ({ request, response }) => {
17
18
  const result = await authService.login(User, {
18
19
  email: request.input("email"),
19
20
  password: request.input("password"),
@@ -30,7 +31,7 @@ async function loginController(request: Request, response: Response) {
30
31
  user: result.user,
31
32
  tokens: result.tokens,
32
33
  });
33
- }
34
+ };
34
35
  ```
35
36
 
36
37
  The returned shape:
@@ -82,7 +83,9 @@ Useful for "show active sessions" UIs — see `authService.getActiveSessions(use
82
83
  ## Logout — `authService.logout(user, accessToken?, refreshToken?)`
83
84
 
84
85
  ```ts
85
- async function logoutController(request: Request, response: Response) {
86
+ import { type RequestHandler } from "@warlock.js/core";
87
+
88
+ export const logoutController: RequestHandler = async ({ request, response }) => {
86
89
  await authService.logout(
87
90
  request.user!,
88
91
  request.authorizationValue, // access token from the Authorization header
@@ -90,7 +93,7 @@ async function logoutController(request: Request, response: Response) {
90
93
  );
91
94
 
92
95
  return response.success({ message: "Logged out" });
93
- }
96
+ };
94
97
  ```
95
98
 
96
99
  The contract:
@@ -114,7 +117,9 @@ Useful for "logout from all devices" buttons. Fires `token.revoked` per token +
114
117
  ## Refresh tokens — `authService.refreshTokens(refreshTokenString, deviceInfo?)`
115
118
 
116
119
  ```ts
117
- async function refreshController(request: Request, response: Response) {
120
+ import { type RequestHandler } from "@warlock.js/core";
121
+
122
+ export const refreshController: RequestHandler = async ({ request, response }) => {
118
123
  const tokens = await authService.refreshTokens(
119
124
  request.input("refreshToken"),
120
125
  { userAgent: request.header("user-agent"), ip: request.ip },
@@ -125,7 +130,7 @@ async function refreshController(request: Request, response: Response) {
125
130
  }
126
131
 
127
132
  return response.success({ tokens });
128
- }
133
+ };
129
134
  ```
130
135
 
131
136
  Returns a new token pair or `null` (token expired, revoked, or replay-detected). With rotation enabled (default), the old refresh token is consumed; the new pair stays in the same "family." Replay → revoke the whole family. See [`@warlock.js/auth/manage-tokens/SKILL.md`](@warlock.js/auth/manage-tokens/SKILL.md).
@@ -61,13 +61,15 @@ On failure, the middleware returns one of these 401 responses:
61
61
  ## Reading the user in a controller
62
62
 
63
63
  ```ts
64
- async function accountController(request: Request, response: Response) {
64
+ import { type RequestHandler } from "@warlock.js/core";
65
+
66
+ export const accountController: RequestHandler = async ({ request, response }) => {
65
67
  const user = request.user!; // typed via your Auth subclass
66
68
  return response.success({
67
69
  id: user.id,
68
70
  email: user.get("email"),
69
71
  });
70
- }
72
+ };
71
73
  ```
72
74
 
73
75
  Because the middleware always requires a valid token, `request.user` is guaranteed present inside any gated controller (the middleware would have responded 401 otherwise). The `!` is safe here.
@@ -88,10 +90,12 @@ Every route inside the group is gated — the group's `middleware` array applies
88
90
  There is no "hydrate `request.user` if a token is present, otherwise continue" mode. `authMiddleware` always requires a valid token. If a route should be reachable anonymously, leave the middleware off — and read the token yourself in the controller if you want soft personalization:
89
91
 
90
92
  ```ts
91
- async function feedController(request: Request, response: Response) {
93
+ import { type RequestHandler } from "@warlock.js/core";
94
+
95
+ export const feedController: RequestHandler = async ({ request, response }) => {
92
96
  const token = request.authorizationValue;
93
97
  // optionally decode/hydrate manually when a token is present
94
- }
98
+ };
95
99
  ```
96
100
 
97
101
  ## Custom error responses
@@ -11,10 +11,10 @@ Two-step on the server: create the user (with hashed password), then issue token
11
11
 
12
12
  ```ts
13
13
  import { authService } from "@warlock.js/auth";
14
- import { hashPassword } from "@warlock.js/core";
14
+ import { hashPassword, type RequestHandler } from "@warlock.js/core";
15
15
  import { User } from "@/app/users/models/user.model";
16
16
 
17
- async function registerController(request: Request, response: Response) {
17
+ export const registerController: RequestHandler = async ({ request, response }) => {
18
18
  const { email, password, name } = request.all();
19
19
 
20
20
  // 1. Check duplicates
@@ -41,7 +41,7 @@ async function registerController(request: Request, response: Response) {
41
41
  user, // shape via static toJsonColumns / static resource
42
42
  tokens,
43
43
  });
44
- }
44
+ };
45
45
  ```
46
46
 
47
47
  That's the whole flow. `User.create({...})` runs the schema validation (including `.email()`, `.min()`, etc. on each field), so you don't need a separate validation pass — see [`@warlock.js/seal/handle-seal-errors/SKILL.md`](@warlock.js/seal/handle-seal-errors/SKILL.md) for catching validation failures.