@warlock.js/auth 4.0.174 → 4.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 (164) hide show
  1. package/README.md +37 -0
  2. package/cjs/index.cjs +807 -0
  3. package/cjs/index.cjs.map +1 -0
  4. package/esm/commands/auth-cleanup-command.d.mts +13 -0
  5. package/esm/commands/auth-cleanup-command.d.mts.map +1 -0
  6. package/esm/commands/auth-cleanup-command.mjs +34 -0
  7. package/esm/commands/auth-cleanup-command.mjs.map +1 -0
  8. package/esm/commands/jwt-secret-generator-command.d.mts +5 -0
  9. package/esm/commands/jwt-secret-generator-command.d.mts.map +1 -0
  10. package/esm/commands/jwt-secret-generator-command.mjs +15 -0
  11. package/esm/commands/jwt-secret-generator-command.mjs.map +1 -0
  12. package/esm/contracts/auth-contract.d.mts +40 -0
  13. package/esm/contracts/auth-contract.d.mts.map +1 -0
  14. package/esm/contracts/index.d.mts +2 -0
  15. package/esm/contracts/types.d.mts +170 -0
  16. package/esm/contracts/types.d.mts.map +1 -0
  17. package/esm/contracts/types.mjs +25 -0
  18. package/esm/contracts/types.mjs.map +1 -0
  19. package/esm/index.d.mts +15 -0
  20. package/esm/index.mjs +17 -0
  21. package/esm/middleware/auth.middleware.d.mts +22 -0
  22. package/esm/middleware/auth.middleware.d.mts.map +1 -0
  23. package/esm/middleware/auth.middleware.mjs +72 -0
  24. package/esm/middleware/auth.middleware.mjs.map +1 -0
  25. package/esm/middleware/index.mjs +3 -0
  26. package/esm/models/access-token/access-token.model.d.mts +13 -0
  27. package/esm/models/access-token/access-token.model.d.mts.map +1 -0
  28. package/esm/models/access-token/access-token.model.mjs +23 -0
  29. package/esm/models/access-token/access-token.model.mjs.map +1 -0
  30. package/esm/models/access-token/index.d.mts +1 -0
  31. package/esm/models/access-token/index.mjs +3 -0
  32. package/esm/models/access-token/migration.mjs +24 -0
  33. package/esm/models/access-token/migration.mjs.map +1 -0
  34. package/esm/models/auth.model.d.mts +63 -0
  35. package/esm/models/auth.model.d.mts.map +1 -0
  36. package/esm/models/auth.model.mjs +77 -0
  37. package/esm/models/auth.model.mjs.map +1 -0
  38. package/esm/models/index.d.mts +8 -0
  39. package/esm/models/index.d.mts.map +1 -0
  40. package/esm/models/index.mjs +14 -0
  41. package/esm/models/index.mjs.map +1 -0
  42. package/esm/models/refresh-token/index.d.mts +1 -0
  43. package/esm/models/refresh-token/index.mjs +3 -0
  44. package/esm/models/refresh-token/migration.mjs +27 -0
  45. package/esm/models/refresh-token/migration.mjs.map +1 -0
  46. package/esm/models/refresh-token/refresh-token.model.d.mts +36 -0
  47. package/esm/models/refresh-token/refresh-token.model.d.mts.map +1 -0
  48. package/esm/models/refresh-token/refresh-token.model.mjs +58 -0
  49. package/esm/models/refresh-token/refresh-token.model.mjs.map +1 -0
  50. package/esm/services/auth-events.d.mts +89 -0
  51. package/esm/services/auth-events.d.mts.map +1 -0
  52. package/esm/services/auth-events.mjs +68 -0
  53. package/esm/services/auth-events.mjs.map +1 -0
  54. package/esm/services/auth.service.d.mts +95 -0
  55. package/esm/services/auth.service.d.mts.map +1 -0
  56. package/esm/services/auth.service.mjs +275 -0
  57. package/esm/services/auth.service.mjs.map +1 -0
  58. package/esm/services/generate-jwt-secret.d.mts +5 -0
  59. package/esm/services/generate-jwt-secret.d.mts.map +1 -0
  60. package/esm/services/generate-jwt-secret.mjs +48 -0
  61. package/esm/services/generate-jwt-secret.mjs.map +1 -0
  62. package/esm/services/index.d.mts +4 -0
  63. package/esm/services/index.mjs +6 -0
  64. package/esm/services/jwt.d.mts +52 -0
  65. package/esm/services/jwt.d.mts.map +1 -0
  66. package/esm/services/jwt.mjs +58 -0
  67. package/esm/services/jwt.mjs.map +1 -0
  68. package/esm/utils/auth-error-codes.d.mts +23 -0
  69. package/esm/utils/auth-error-codes.d.mts.map +1 -0
  70. package/esm/utils/auth-error-codes.mjs +23 -0
  71. package/esm/utils/auth-error-codes.mjs.map +1 -0
  72. package/llms-full.txt +1023 -0
  73. package/llms.txt +16 -0
  74. package/package.json +47 -36
  75. package/skills/auth-basics/SKILL.md +88 -0
  76. package/skills/customize-user-type/SKILL.md +137 -0
  77. package/skills/handle-login-and-logout/SKILL.md +160 -0
  78. package/skills/manage-tokens/SKILL.md +169 -0
  79. package/skills/overview/SKILL.md +66 -0
  80. package/skills/protect-routes/SKILL.md +105 -0
  81. package/skills/register-user/SKILL.md +135 -0
  82. package/skills/run-auth-commands/SKILL.md +125 -0
  83. package/esm/commands/auth-cleanup-command.d.ts +0 -10
  84. package/esm/commands/auth-cleanup-command.d.ts.map +0 -1
  85. package/esm/commands/auth-cleanup-command.js +0 -29
  86. package/esm/commands/auth-cleanup-command.js.map +0 -1
  87. package/esm/commands/jwt-secret-generator-command.d.ts +0 -2
  88. package/esm/commands/jwt-secret-generator-command.d.ts.map +0 -1
  89. package/esm/commands/jwt-secret-generator-command.js +0 -7
  90. package/esm/commands/jwt-secret-generator-command.js.map +0 -1
  91. package/esm/contracts/auth-contract.d.ts +0 -23
  92. package/esm/contracts/auth-contract.d.ts.map +0 -1
  93. package/esm/contracts/index.d.ts +0 -3
  94. package/esm/contracts/index.d.ts.map +0 -1
  95. package/esm/contracts/types.d.ts +0 -167
  96. package/esm/contracts/types.d.ts.map +0 -1
  97. package/esm/contracts/types.js +0 -20
  98. package/esm/contracts/types.js.map +0 -1
  99. package/esm/index.d.ts +0 -8
  100. package/esm/index.d.ts.map +0 -1
  101. package/esm/index.js +0 -1
  102. package/esm/index.js.map +0 -1
  103. package/esm/middleware/auth.middleware.d.ts +0 -2
  104. package/esm/middleware/auth.middleware.d.ts.map +0 -1
  105. package/esm/middleware/auth.middleware.js +0 -72
  106. package/esm/middleware/auth.middleware.js.map +0 -1
  107. package/esm/middleware/index.d.ts +0 -2
  108. package/esm/middleware/index.d.ts.map +0 -1
  109. package/esm/models/access-token/access-token.model.d.ts +0 -9
  110. package/esm/models/access-token/access-token.model.d.ts.map +0 -1
  111. package/esm/models/access-token/access-token.model.js +0 -14
  112. package/esm/models/access-token/access-token.model.js.map +0 -1
  113. package/esm/models/access-token/index.d.ts +0 -2
  114. package/esm/models/access-token/index.d.ts.map +0 -1
  115. package/esm/models/access-token/migration.d.ts +0 -2
  116. package/esm/models/access-token/migration.d.ts.map +0 -1
  117. package/esm/models/access-token/migration.js +0 -22
  118. package/esm/models/access-token/migration.js.map +0 -1
  119. package/esm/models/auth.model.d.ts +0 -58
  120. package/esm/models/auth.model.d.ts.map +0 -1
  121. package/esm/models/auth.model.js +0 -68
  122. package/esm/models/auth.model.js.map +0 -1
  123. package/esm/models/index.d.ts +0 -5
  124. package/esm/models/index.d.ts.map +0 -1
  125. package/esm/models/index.js +0 -1
  126. package/esm/models/index.js.map +0 -1
  127. package/esm/models/refresh-token/index.d.ts +0 -2
  128. package/esm/models/refresh-token/index.d.ts.map +0 -1
  129. package/esm/models/refresh-token/migration.d.ts +0 -2
  130. package/esm/models/refresh-token/migration.d.ts.map +0 -1
  131. package/esm/models/refresh-token/migration.js +0 -23
  132. package/esm/models/refresh-token/migration.js.map +0 -1
  133. package/esm/models/refresh-token/refresh-token.model.d.ts +0 -32
  134. package/esm/models/refresh-token/refresh-token.model.d.ts.map +0 -1
  135. package/esm/models/refresh-token/refresh-token.model.js +0 -53
  136. package/esm/models/refresh-token/refresh-token.model.js.map +0 -1
  137. package/esm/services/auth-events.d.ts +0 -85
  138. package/esm/services/auth-events.d.ts.map +0 -1
  139. package/esm/services/auth-events.js +0 -65
  140. package/esm/services/auth-events.js.map +0 -1
  141. package/esm/services/auth.service.d.ts +0 -92
  142. package/esm/services/auth.service.d.ts.map +0 -1
  143. package/esm/services/auth.service.js +0 -322
  144. package/esm/services/auth.service.js.map +0 -1
  145. package/esm/services/generate-jwt-secret.d.ts +0 -2
  146. package/esm/services/generate-jwt-secret.d.ts.map +0 -1
  147. package/esm/services/generate-jwt-secret.js +0 -47
  148. package/esm/services/generate-jwt-secret.js.map +0 -1
  149. package/esm/services/index.d.ts +0 -5
  150. package/esm/services/index.d.ts.map +0 -1
  151. package/esm/services/jwt.d.ts +0 -23
  152. package/esm/services/jwt.d.ts.map +0 -1
  153. package/esm/services/jwt.js +0 -40
  154. package/esm/services/jwt.js.map +0 -1
  155. package/esm/utils/auth-error-codes.d.ts +0 -18
  156. package/esm/utils/auth-error-codes.d.ts.map +0 -1
  157. package/esm/utils/auth-error-codes.js +0 -18
  158. package/esm/utils/auth-error-codes.js.map +0 -1
  159. package/esm/utils/duration.d.ts +0 -45
  160. package/esm/utils/duration.d.ts.map +0 -1
  161. package/esm/utils/duration.js +0 -93
  162. package/esm/utils/duration.js.map +0 -1
  163. package/esm/utils/index.d.ts +0 -3
  164. package/esm/utils/index.d.ts.map +0 -1
package/cjs/index.cjs ADDED
@@ -0,0 +1,807 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) {
14
+ __defProp(to, key, {
15
+ get: ((k) => from[k]).bind(null, key),
16
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
17
+ });
18
+ }
19
+ }
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
24
+ value: mod,
25
+ enumerable: true
26
+ }) : target, mod));
27
+
28
+ //#endregion
29
+ let _mongez_copper = require("@mongez/copper");
30
+ let _warlock_js_core = require("@warlock.js/core");
31
+ let _mongez_reinforcements = require("@mongez/reinforcements");
32
+ let ms = require("ms");
33
+ ms = __toESM(ms, 1);
34
+ let _warlock_js_cascade = require("@warlock.js/cascade");
35
+ let _warlock_js_seal = require("@warlock.js/seal");
36
+ let _mongez_events = require("@mongez/events");
37
+ _mongez_events = __toESM(_mongez_events, 1);
38
+ let fast_jwt = require("fast-jwt");
39
+ let _warlock_js_fs = require("@warlock.js/fs");
40
+ let _warlock_js_logger = require("@warlock.js/logger");
41
+
42
+ //#region ../../@warlock.js/auth/src/models/access-token/access-token.model.ts
43
+ const accessTokenSchema = _warlock_js_seal.v.object({
44
+ token: _warlock_js_seal.v.string().required(),
45
+ last_access: _warlock_js_seal.v.date().defaultNow().optional(),
46
+ user_id: _warlock_js_seal.v.scalar().required(),
47
+ user_type: _warlock_js_seal.v.string().required(),
48
+ is_active: _warlock_js_seal.v.boolean().default(true)
49
+ });
50
+ var AccessToken = class extends _warlock_js_cascade.Model {
51
+ static {
52
+ this.table = "access_tokens";
53
+ }
54
+ static {
55
+ this.schema = accessTokenSchema;
56
+ }
57
+ };
58
+
59
+ //#endregion
60
+ //#region ../../@warlock.js/auth/src/models/refresh-token/refresh-token.model.ts
61
+ const refreshTokenSchema = _warlock_js_seal.v.object({
62
+ token: _warlock_js_seal.v.string().required(),
63
+ user_id: _warlock_js_seal.v.scalar().required(),
64
+ user_type: _warlock_js_seal.v.string().required(),
65
+ family_id: _warlock_js_seal.v.string().required(),
66
+ expires_at: _warlock_js_seal.v.date().required(),
67
+ last_used_at: _warlock_js_seal.v.date().default(() => /* @__PURE__ */ new Date()),
68
+ revoked_at: _warlock_js_seal.v.date().optional(),
69
+ device_info: _warlock_js_seal.v.record(_warlock_js_seal.v.any()).optional()
70
+ });
71
+ var RefreshToken = class extends _warlock_js_cascade.Model {
72
+ static {
73
+ this.table = "refresh_tokens";
74
+ }
75
+ static {
76
+ this.schema = refreshTokenSchema;
77
+ }
78
+ /**
79
+ * Check if token is expired
80
+ */
81
+ get isExpired() {
82
+ const expiresAt = this.get("expires_at");
83
+ if (!expiresAt) return false;
84
+ return /* @__PURE__ */ new Date() > new Date(expiresAt);
85
+ }
86
+ /**
87
+ * Check if token is revoked
88
+ */
89
+ get isRevoked() {
90
+ return !!this.get("revoked_at");
91
+ }
92
+ /**
93
+ * Check if token is valid (not expired and not revoked)
94
+ */
95
+ get isValid() {
96
+ return !this.isExpired && !this.isRevoked;
97
+ }
98
+ /**
99
+ * Revoke this token
100
+ */
101
+ async revoke() {
102
+ return this.merge({ revoked_at: /* @__PURE__ */ new Date() }).save();
103
+ }
104
+ /**
105
+ * Mark token as used (update last_used_at)
106
+ */
107
+ async markAsUsed() {
108
+ await this.merge({ last_used_at: /* @__PURE__ */ new Date() }).save();
109
+ }
110
+ };
111
+
112
+ //#endregion
113
+ //#region ../../@warlock.js/auth/src/services/auth-events.ts
114
+ /**
115
+ * Event namespace prefix for auth events
116
+ */
117
+ const AUTH_EVENT_PREFIX = "auth.";
118
+ /**
119
+ * Type-safe auth events manager
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * // Subscribe to events with full autocomplete
124
+ * authEvents.on("login.success", (user, tokenPair, deviceInfo) => {
125
+ * console.log(`User ${user.id} logged in`);
126
+ * });
127
+ *
128
+ * authEvents.on("token.refreshed", (user, newPair, oldToken) => {
129
+ * console.log(`Token refreshed for user ${user.id}`);
130
+ * });
131
+ *
132
+ * // Trigger events
133
+ * authEvents.emit("login.success", user, tokenPair, deviceInfo);
134
+ * ```
135
+ */
136
+ const authEvents = {
137
+ /**
138
+ * Subscribe to an auth event
139
+ */
140
+ on(event, callback) {
141
+ return _mongez_events.default.subscribe(AUTH_EVENT_PREFIX + event, callback);
142
+ },
143
+ /**
144
+ * Subscribe to an auth event (alias for `on`)
145
+ */
146
+ subscribe(event, callback) {
147
+ return this.on(event, callback);
148
+ },
149
+ /**
150
+ * Emit an auth event
151
+ */
152
+ emit(event, ...args) {
153
+ _mongez_events.default.trigger(AUTH_EVENT_PREFIX + event, ...args);
154
+ },
155
+ /**
156
+ * Emit an auth event (alias for `emit`)
157
+ */
158
+ trigger(event, ...args) {
159
+ this.emit(event, ...args);
160
+ },
161
+ /**
162
+ * Unsubscribe from all auth events
163
+ */
164
+ unsubscribeAll() {
165
+ _mongez_events.default.unsubscribeNamespace(AUTH_EVENT_PREFIX.slice(0, -1));
166
+ },
167
+ /**
168
+ * Unsubscribe from a specific auth event
169
+ */
170
+ off(event) {
171
+ if (event) _mongez_events.default.unsubscribe(AUTH_EVENT_PREFIX + event);
172
+ else this.unsubscribeAll();
173
+ }
174
+ };
175
+
176
+ //#endregion
177
+ //#region ../../@warlock.js/auth/src/services/jwt.ts
178
+ const getSecretKey = () => _warlock_js_core.config.key("auth.jwt.secret");
179
+ const getAlgorithm = () => _warlock_js_core.config.key("auth.jwt.algorithm", "HS256");
180
+ const getRefreshSecretKey = () => _warlock_js_core.config.key("auth.jwt.refresh.secret") || getSecretKey();
181
+ const jwt = {
182
+ /**
183
+ * Generate a new JWT token for the user.
184
+ * @param payload The payload to encode in the JWT token.
185
+ */
186
+ async generate(payload, { key = getSecretKey(), algorithm = getAlgorithm(), ...options } = {}) {
187
+ return await (0, fast_jwt.createSigner)({
188
+ key,
189
+ ...options,
190
+ algorithm
191
+ })({ ...payload });
192
+ },
193
+ /**
194
+ * Verify the given token.
195
+ * @param token The JWT token to verify.
196
+ * @returns The decoded token payload if verification is successful.
197
+ */
198
+ async verify(token, { key = getSecretKey(), algorithms = getAlgorithm() ? [getAlgorithm()] : void 0, ...options } = {}) {
199
+ return await (0, fast_jwt.createVerifier)({
200
+ key,
201
+ ...options,
202
+ algorithms
203
+ })(token);
204
+ },
205
+ /**
206
+ * Generate a new refresh token for the user.
207
+ */
208
+ async generateRefreshToken(payload, { key = getRefreshSecretKey(), expiresIn, algorithm = getAlgorithm(), ...options } = {}) {
209
+ return (0, fast_jwt.createSigner)({
210
+ key,
211
+ expiresIn,
212
+ algorithm,
213
+ ...options
214
+ })({ ...payload });
215
+ },
216
+ /**
217
+ * Verify the given refresh token.
218
+ */
219
+ async verifyRefreshToken(token, { key = getRefreshSecretKey(), algorithms = [getAlgorithm()], ...options } = {}) {
220
+ return await (0, fast_jwt.createVerifier)({
221
+ key,
222
+ algorithms,
223
+ ...options
224
+ })(token);
225
+ }
226
+ };
227
+
228
+ //#endregion
229
+ //#region ../../@warlock.js/auth/src/services/auth.service.ts
230
+ var AuthService = class {
231
+ /**
232
+ * Build access token payload from user
233
+ */
234
+ buildAccessTokenPayload(user) {
235
+ return {
236
+ id: user.id,
237
+ userType: user.userType,
238
+ created_at: Date.now()
239
+ };
240
+ }
241
+ /**
242
+ * Generate access token for user
243
+ */
244
+ async generateAccessToken(user, payload) {
245
+ const data = payload || this.buildAccessTokenPayload(user);
246
+ const expiresInConfig = _warlock_js_core.config.key("auth.jwt.expiresIn");
247
+ const expiresIn = expiresInConfig ? (0, ms.default)(expiresInConfig) : 3600;
248
+ const token = await jwt.generate(data, { expiresIn });
249
+ const decoed = await jwt.verify(token);
250
+ await AccessToken.create({
251
+ token,
252
+ user_id: user.id,
253
+ user_type: user.userType
254
+ });
255
+ return {
256
+ token,
257
+ expiresAt: (/* @__PURE__ */ new Date(decoed.exp * 1e3)).toISOString()
258
+ };
259
+ }
260
+ /**
261
+ * Create refresh token for user
262
+ */
263
+ async createRefreshToken(user, deviceInfo) {
264
+ if (_warlock_js_core.config.get("auth.jwt.refresh.enabled") === false) return;
265
+ const familyId = deviceInfo?.familyId || _mongez_reinforcements.Random.string(32);
266
+ const payload = {
267
+ userId: user.id,
268
+ userType: user.userType,
269
+ familyId
270
+ };
271
+ const expiresIn = (0, ms.default)(_warlock_js_core.config.get("auth.jwt.refresh.expiresIn", "7d"));
272
+ const token = await jwt.generateRefreshToken(payload, { expiresIn });
273
+ const expiresAt = new Date(Date.now() + expiresIn).toISOString();
274
+ await this.enforceMaxRefreshTokens(user);
275
+ return RefreshToken.create({
276
+ token,
277
+ user_id: user.id,
278
+ user_type: user.userType,
279
+ family_id: familyId,
280
+ expires_at: expiresAt,
281
+ device_info: deviceInfo ? {
282
+ userAgent: deviceInfo.userAgent,
283
+ ip: deviceInfo.ip,
284
+ deviceId: deviceInfo.deviceId
285
+ } : void 0
286
+ });
287
+ }
288
+ /**
289
+ * Create both access and refresh tokens
290
+ */
291
+ async createTokenPair(user, deviceInfo) {
292
+ const accessToken = await this.generateAccessToken(user, deviceInfo?.payload);
293
+ const refreshToken = await this.createRefreshToken(user, deviceInfo);
294
+ const tokenPair = {
295
+ accessToken,
296
+ refreshToken: refreshToken ? {
297
+ token: refreshToken.get("token"),
298
+ expiresAt: refreshToken.get("expires_at")
299
+ } : void 0
300
+ };
301
+ authEvents.emit("token.created", user, tokenPair);
302
+ if (refreshToken) authEvents.emit("session.created", user, refreshToken, deviceInfo);
303
+ return tokenPair;
304
+ }
305
+ /**
306
+ * Refresh tokens using a refresh token
307
+ */
308
+ async refreshTokens(refreshTokenString, deviceInfo) {
309
+ try {
310
+ const decoded = await jwt.verifyRefreshToken(refreshTokenString);
311
+ if (!decoded) return null;
312
+ const refreshToken = await RefreshToken.first({ token: refreshTokenString });
313
+ if (!refreshToken?.isValid) {
314
+ if (refreshToken) await this.revokeTokenFamily(refreshToken.get("family_id"));
315
+ return null;
316
+ }
317
+ const UserModel = _warlock_js_core.config.key(`auth.userType.${decoded.userType}`);
318
+ if (!UserModel) return null;
319
+ const user = await UserModel.find(decoded.userId);
320
+ if (!user) return null;
321
+ if (_warlock_js_core.config.key("auth.jwt.refresh.rotation", true)) await refreshToken.revoke();
322
+ else await refreshToken.markAsUsed();
323
+ const newTokenPair = await this.createTokenPair(user, {
324
+ ...deviceInfo,
325
+ familyId: refreshToken.get("family_id")
326
+ });
327
+ authEvents.emit("token.refreshed", user, newTokenPair, refreshToken);
328
+ return newTokenPair;
329
+ } catch {
330
+ return null;
331
+ }
332
+ }
333
+ /**
334
+ * Verify password
335
+ */
336
+ async verifyPassword(plainPassword, hashedPassword) {
337
+ return (0, _warlock_js_core.verifyPassword)(plainPassword, hashedPassword);
338
+ }
339
+ /**
340
+ * Hash password
341
+ */
342
+ async hashPassword(password) {
343
+ return (0, _warlock_js_core.hashPassword)(password);
344
+ }
345
+ /**
346
+ * Attempt to login user with given credentials
347
+ */
348
+ async attemptLogin(Model, data) {
349
+ const { password, ...otherData } = data;
350
+ authEvents.emit("login.attempt", otherData);
351
+ const user = await Model.first(otherData);
352
+ if (!user) {
353
+ authEvents.emit("login.failed", otherData, "User not found");
354
+ return null;
355
+ }
356
+ if (!await this.verifyPassword(password, user.string("password"))) {
357
+ authEvents.emit("login.failed", otherData, "Invalid password");
358
+ return null;
359
+ }
360
+ return user;
361
+ }
362
+ /**
363
+ * Full login flow: validate credentials, create tokens, emit events
364
+ * Returns token pair on success, null on failure
365
+ */
366
+ async login(Model, credentials, deviceInfo) {
367
+ const user = await this.attemptLogin(Model, credentials);
368
+ if (!user) return null;
369
+ if (!_warlock_js_core.config.key("auth.jwt.refresh.enabled", true)) return {
370
+ user,
371
+ tokens: { accessToken: await this.generateAccessToken(user, deviceInfo?.payload) }
372
+ };
373
+ const tokens = await this.createTokenPair(user, deviceInfo);
374
+ authEvents.emit("login.success", user, tokens, deviceInfo);
375
+ return {
376
+ user,
377
+ tokens
378
+ };
379
+ }
380
+ /**
381
+ * Logout user
382
+ * @param user - The authenticated user
383
+ * @param accessToken - Optional access token string to revoke
384
+ * @param refreshToken - Optional refresh token string to revoke
385
+ * If refresh token is not provided, behavior is determined by config:
386
+ * - "revoke-all" (default): Revoke ALL refresh tokens for security
387
+ * - "error": Throw error requiring refresh token
388
+ */
389
+ async logout(user, accessToken, refreshToken) {
390
+ if (accessToken) await this.removeAccessToken(user, accessToken);
391
+ if (refreshToken) {
392
+ const token = await RefreshToken.first({
393
+ token: refreshToken,
394
+ userId: user.id
395
+ });
396
+ if (token) {
397
+ await token.revoke();
398
+ authEvents.emit("session.destroyed", user, token);
399
+ }
400
+ } else {
401
+ if (_warlock_js_core.config.key("auth.jwt.refresh.logoutWithoutToken", "revoke-all") === "error") throw new Error("Refresh token required for logout");
402
+ await this.revokeAllTokens(user);
403
+ authEvents.emit("logout.failsafe", user);
404
+ }
405
+ authEvents.emit("logout", user);
406
+ }
407
+ /**
408
+ * Remove specific access token
409
+ */
410
+ async removeAccessToken(user, token) {
411
+ AccessToken.delete({
412
+ token,
413
+ userId: user.id
414
+ });
415
+ }
416
+ /**
417
+ * Remove all access tokens for a user
418
+ */
419
+ async removeAllAccessTokens(user) {
420
+ AccessToken.delete({ user_id: user.id });
421
+ }
422
+ /**
423
+ * Remove specific refresh token
424
+ */
425
+ async removeRefreshToken(user, token) {
426
+ RefreshToken.delete({
427
+ token,
428
+ userId: user.id
429
+ });
430
+ }
431
+ /**
432
+ * Revoke all tokens for a user
433
+ */
434
+ async revokeAllTokens(user) {
435
+ const refreshTokens = await RefreshToken.query().where("user_id", user.id).where("user_type", user.userType).where("revoked_at", null).get();
436
+ for (const token of refreshTokens) {
437
+ await token.revoke();
438
+ authEvents.emit("token.revoked", user, token);
439
+ }
440
+ await this.removeAllAccessTokens(user);
441
+ authEvents.emit("logout.all", user);
442
+ }
443
+ /**
444
+ * Revoke entire token family (for rotation breach detection)
445
+ */
446
+ async revokeTokenFamily(familyId) {
447
+ const tokens = await RefreshToken.query().where("family_id", familyId).where("revoked_at", null).get();
448
+ for (const token of tokens) await token.revoke();
449
+ authEvents.emit("token.familyRevoked", familyId, tokens);
450
+ }
451
+ /**
452
+ * Cleanup expired tokens
453
+ */
454
+ async cleanupExpiredTokens() {
455
+ const expiredTokens = await RefreshToken.query().where("expires_at", "<", /* @__PURE__ */ new Date()).get();
456
+ for (const token of expiredTokens) {
457
+ authEvents.emit("token.expired", token);
458
+ await token.destroy();
459
+ }
460
+ authEvents.emit("cleanup.completed", expiredTokens.length);
461
+ return expiredTokens.length;
462
+ }
463
+ /**
464
+ * Enforce max refresh tokens per user
465
+ */
466
+ async enforceMaxRefreshTokens(user) {
467
+ const maxPerUser = _warlock_js_core.config.key("auth.jwt.refresh.maxPerUser", 5);
468
+ const activeTokens = await RefreshToken.query().where({
469
+ user_id: user.id,
470
+ user_type: user.userType,
471
+ revoked_at: null
472
+ }).orderBy("created_at", "asc").get();
473
+ if (activeTokens.length >= maxPerUser) {
474
+ const tokensToRevoke = activeTokens.slice(0, activeTokens.length - maxPerUser + 1);
475
+ for (const token of tokensToRevoke) await token.revoke();
476
+ }
477
+ }
478
+ /**
479
+ * Get active sessions for user
480
+ */
481
+ async getActiveSessions(user) {
482
+ return RefreshToken.query().where({
483
+ user_id: user.id,
484
+ user_type: user.userType,
485
+ revoked_at: null
486
+ }).where("expires_at", ">", /* @__PURE__ */ new Date()).orderBy("created_at", "desc").get();
487
+ }
488
+ };
489
+ const authService = new AuthService();
490
+
491
+ //#endregion
492
+ //#region ../../@warlock.js/auth/src/commands/auth-cleanup-command.ts
493
+ /**
494
+ * Register the auth:cleanup CLI command
495
+ *
496
+ * @example
497
+ * ```bash
498
+ * warlock auth:cleanup
499
+ * ```
500
+ */
501
+ function registerAuthCleanupCommand() {
502
+ return (0, _warlock_js_core.command)({
503
+ name: "auth.cleanup",
504
+ description: "Remove expired refresh tokens from the database",
505
+ preload: {
506
+ env: true,
507
+ config: ["auth", "database"],
508
+ connectors: ["database"]
509
+ },
510
+ action: async () => {
511
+ console.log(_mongez_copper.colors.cyan("🧹 Cleaning up expired tokens..."));
512
+ const count = await authService.cleanupExpiredTokens();
513
+ if (count === 0) console.log(_mongez_copper.colors.green("✅ No expired tokens found."));
514
+ else console.log(_mongez_copper.colors.green(`✅ Removed ${count} expired token(s).`));
515
+ }
516
+ });
517
+ }
518
+
519
+ //#endregion
520
+ //#region ../../@warlock.js/auth/src/services/generate-jwt-secret.ts
521
+ async function generateJWTSecret() {
522
+ let envFile = (0, _warlock_js_core.rootPath)(".env");
523
+ _warlock_js_logger.log.info("jwt", "generating", "Generating JWT secrets");
524
+ const environmentMode = (0, _warlock_js_core.environment)();
525
+ if (!await (0, _warlock_js_fs.fileExistsAsync)(envFile)) envFile = (0, _warlock_js_core.rootPath)(environmentMode === "production" ? ".env.production" : ".env.development");
526
+ if (!await (0, _warlock_js_fs.fileExistsAsync)(envFile)) {
527
+ _warlock_js_logger.log.error("jwt", "error", ".env file not found");
528
+ return;
529
+ }
530
+ let contents = await (0, _warlock_js_fs.getFileAsync)(envFile);
531
+ const hasJwtSecret = contents.includes("JWT_SECRET");
532
+ const hasJwtRefreshSecret = contents.includes("JWT_REFRESH_SECRET");
533
+ if (hasJwtSecret && hasJwtRefreshSecret) {
534
+ _warlock_js_logger.log.warn("jwt", "exists", "JWT secrets already exist in the .env file.");
535
+ return;
536
+ }
537
+ let secretsToAdd = "";
538
+ if (!hasJwtSecret) {
539
+ const jwtSecret = _mongez_reinforcements.Random.string(32);
540
+ secretsToAdd += `
541
+ # JWT Secret
542
+ JWT_SECRET=${jwtSecret}
543
+ `;
544
+ _warlock_js_logger.log.success("jwt", "generated", "JWT_SECRET generated and added to the .env file.");
545
+ } else _warlock_js_logger.log.info("jwt", "exists", "JWT_SECRET already exists in the .env file.");
546
+ if (!hasJwtRefreshSecret) {
547
+ const jwtRefreshSecret = _mongez_reinforcements.Random.string(32);
548
+ secretsToAdd += `
549
+ # JWT Refresh Secret
550
+ JWT_REFRESH_SECRET=${jwtRefreshSecret}
551
+ `;
552
+ _warlock_js_logger.log.success("jwt", "generated", "JWT_REFRESH_SECRET generated and added to the .env file.");
553
+ } else _warlock_js_logger.log.info("jwt", "exists", "JWT_REFRESH_SECRET already exists in the .env file.");
554
+ if (secretsToAdd) {
555
+ contents += secretsToAdd;
556
+ await (0, _warlock_js_fs.putFileAsync)(envFile, contents);
557
+ }
558
+ }
559
+
560
+ //#endregion
561
+ //#region ../../@warlock.js/auth/src/commands/jwt-secret-generator-command.ts
562
+ function registerJWTSecretGeneratorCommand() {
563
+ return (0, _warlock_js_core.command)({
564
+ name: "jwt.generate",
565
+ description: "Generate JWT Secret key in .env file",
566
+ action: generateJWTSecret
567
+ });
568
+ }
569
+
570
+ //#endregion
571
+ //#region ../../@warlock.js/auth/src/contracts/types.ts
572
+ /**
573
+ * Symbol to indicate no expiration for tokens
574
+ * Use this when you explicitly want tokens to never expire
575
+ *
576
+ * @example
577
+ * ```typescript
578
+ * // src/config/auth.ts
579
+ * import { NO_EXPIRATION, type AuthConfigurations } from "@warlock.js/auth";
580
+ *
581
+ * const authConfigurations: AuthConfigurations = {
582
+ * jwt: {
583
+ * secret: env("JWT_SECRET"),
584
+ * expiresIn: NO_EXPIRATION, // Token expires within 100 years
585
+ * },
586
+ * };
587
+ *
588
+ * export default authConfigurations;
589
+ * ```
590
+ */
591
+ const NO_EXPIRATION = "100y";
592
+
593
+ //#endregion
594
+ //#region ../../@warlock.js/auth/src/utils/auth-error-codes.ts
595
+ let AuthErrorCodes = /* @__PURE__ */ function(AuthErrorCodes) {
596
+ /**
597
+ * Missing Access Token Error Code EC001
598
+ * EC001 = Missing Access Token
599
+ */
600
+ AuthErrorCodes["MissingAccessToken"] = "EC001";
601
+ /**
602
+ * Invalid Access Token Error Code EC002
603
+ * EC002 = Invalid Access Token
604
+ */
605
+ AuthErrorCodes["InvalidAccessToken"] = "EC002";
606
+ /**
607
+ * Unauthorized Error Code EC003
608
+ * EC003 = Unauthorized
609
+ */
610
+ AuthErrorCodes["Unauthorized"] = "EC003";
611
+ return AuthErrorCodes;
612
+ }({});
613
+
614
+ //#endregion
615
+ //#region ../../@warlock.js/auth/src/middleware/auth.middleware.ts
616
+ /**
617
+ * Build a route gate that always requires an authenticated request.
618
+ *
619
+ * The argument is mandatory and selects which user types may pass:
620
+ * - `[]` — any authenticated user (token required, type not checked).
621
+ * - `"admin"` / `["admin", "staff"]` — token required AND the user's
622
+ * `userType` must be one of the listed types.
623
+ *
624
+ * There is no anonymous/optional mode: a request without a valid access
625
+ * token is always rejected with `401`. Routes that should be public
626
+ * simply omit the middleware.
627
+ *
628
+ * @example
629
+ * router.get("/account", authMiddleware([]), accountController);
630
+ * router.get("/admin", authMiddleware("admin"), adminController);
631
+ * router.get("/back-office", authMiddleware(["admin", "staff"]), backOfficeController);
632
+ */
633
+ function authMiddleware(allowedUserType) {
634
+ const allowedTypes = Array.isArray(allowedUserType) ? allowedUserType : [allowedUserType];
635
+ const auth = async (request, response) => {
636
+ try {
637
+ const authorizationValue = request.authorizationValue;
638
+ if (!authorizationValue) return response.unauthorized({
639
+ error: (0, _warlock_js_core.t)("auth.errors.missingAccessToken"),
640
+ errorCode: "EC001"
641
+ });
642
+ const user = await jwt.verify(authorizationValue);
643
+ request.decodedAccessToken = user;
644
+ const accessToken = await AccessToken.first({ token: authorizationValue });
645
+ if (!accessToken) return response.unauthorized({
646
+ error: (0, _warlock_js_core.t)("auth.errors.invalidAccessToken"),
647
+ errorCode: "EC002"
648
+ });
649
+ const userType = user.userType || accessToken.get("userType");
650
+ if (allowedTypes.length && !allowedTypes.includes(userType)) return response.unauthorized({
651
+ error: (0, _warlock_js_core.t)("auth.errors.unauthorized"),
652
+ errorCode: "EC003"
653
+ });
654
+ const UserModel = _warlock_js_core.config.key(`auth.userType.${userType}`);
655
+ if (!UserModel) throw new Error(`User type ${userType} is unknown type.`);
656
+ const currentUser = await UserModel.find(user.id);
657
+ if (!currentUser) {
658
+ accessToken.destroy();
659
+ return response.unauthorized({
660
+ error: (0, _warlock_js_core.t)("auth.errors.invalidAccessToken"),
661
+ errorCode: "EC002"
662
+ });
663
+ }
664
+ request.user = currentUser;
665
+ } catch (err) {
666
+ _warlock_js_logger.log.error("http", "auth", err);
667
+ request.clearCurrentUser();
668
+ return response.unauthorized({
669
+ error: (0, _warlock_js_core.t)("auth.errors.invalidAccessToken"),
670
+ errorCode: "EC002"
671
+ });
672
+ }
673
+ };
674
+ return auth;
675
+ }
676
+
677
+ //#endregion
678
+ //#region ../../@warlock.js/auth/src/models/access-token/migration.ts
679
+ const AccessTokenMigration = (0, _warlock_js_cascade.migrate)(AccessToken, {
680
+ name: "accessToken",
681
+ up() {
682
+ this.createTableIfNotExists();
683
+ this.primaryUuid();
684
+ this.text("token").unique();
685
+ this.timestamp("last_access").nullable();
686
+ this.uuid("user_id").index();
687
+ this.string("user_type", 50).nullable();
688
+ this.boolean("is_active").nullable();
689
+ this.timestamps();
690
+ },
691
+ down() {
692
+ this.dropTableIfExists();
693
+ }
694
+ });
695
+
696
+ //#endregion
697
+ //#region ../../@warlock.js/auth/src/models/refresh-token/migration.ts
698
+ const RefreshTokenMigration = (0, _warlock_js_cascade.migrate)(RefreshToken, {
699
+ name: "refreshToken",
700
+ up() {
701
+ this.createTableIfNotExists();
702
+ this.primaryUuid();
703
+ this.text("token").unique();
704
+ this.uuid("user_id").index();
705
+ this.string("user_type", 50).nullable();
706
+ this.text("family_id").index().nullable();
707
+ this.timestamp("expires_at").index().nullable();
708
+ this.timestamp("last_used_at").nullable();
709
+ this.timestamp("revoked_at").nullable();
710
+ this.json("device_info").nullable();
711
+ this.timestamps();
712
+ },
713
+ down() {
714
+ this.dropTableIfExists();
715
+ }
716
+ });
717
+
718
+ //#endregion
719
+ //#region ../../@warlock.js/auth/src/models/auth.model.ts
720
+ var Auth = class extends _warlock_js_cascade.Model {
721
+ /**
722
+ * Get access token payload
723
+ */
724
+ accessTokenPayload() {
725
+ return authService.buildAccessTokenPayload(this);
726
+ }
727
+ /**
728
+ * Create both access and refresh tokens
729
+ */
730
+ async createTokenPair(deviceInfo) {
731
+ return authService.createTokenPair(this, deviceInfo);
732
+ }
733
+ /**
734
+ * Generate access token
735
+ */
736
+ async generateAccessToken(data) {
737
+ return authService.generateAccessToken(this, data);
738
+ }
739
+ /**
740
+ * Generate refresh token
741
+ */
742
+ async generateRefreshToken(deviceInfo) {
743
+ return authService.createRefreshToken(this, deviceInfo);
744
+ }
745
+ /**
746
+ * Remove current access token
747
+ */
748
+ async removeAccessToken(token) {
749
+ return authService.removeAccessToken(this, token);
750
+ }
751
+ /**
752
+ * Remove refresh token
753
+ */
754
+ async removeRefreshToken(token) {
755
+ return authService.removeRefreshToken(this, token);
756
+ }
757
+ /**
758
+ * Remove all access tokens
759
+ */
760
+ async removeAllAccessTokens() {
761
+ return authService.removeAllAccessTokens(this);
762
+ }
763
+ /**
764
+ * Revoke all tokens (logout from all devices)
765
+ */
766
+ async revokeAllTokens() {
767
+ return authService.revokeAllTokens(this);
768
+ }
769
+ /**
770
+ * Get active sessions
771
+ */
772
+ async activeSessions() {
773
+ return authService.getActiveSessions(this);
774
+ }
775
+ /**
776
+ * Attempt to login the user
777
+ */
778
+ static async attempt(data) {
779
+ return authService.attemptLogin(this, data);
780
+ }
781
+ /**
782
+ * Confirm password
783
+ */
784
+ async confirmPassword(password) {
785
+ return authService.verifyPassword(password, this.string("password"));
786
+ }
787
+ };
788
+
789
+ //#endregion
790
+ //#region ../../@warlock.js/auth/src/models/index.ts
791
+ const authMigrations = [AccessTokenMigration, RefreshTokenMigration];
792
+
793
+ //#endregion
794
+ exports.AccessToken = AccessToken;
795
+ exports.Auth = Auth;
796
+ exports.AuthErrorCodes = AuthErrorCodes;
797
+ exports.NO_EXPIRATION = NO_EXPIRATION;
798
+ exports.RefreshToken = RefreshToken;
799
+ exports.authEvents = authEvents;
800
+ exports.authMiddleware = authMiddleware;
801
+ exports.authMigrations = authMigrations;
802
+ exports.authService = authService;
803
+ exports.generateJWTSecret = generateJWTSecret;
804
+ exports.jwt = jwt;
805
+ exports.registerAuthCleanupCommand = registerAuthCleanupCommand;
806
+ exports.registerJWTSecretGeneratorCommand = registerJWTSecretGeneratorCommand;
807
+ //# sourceMappingURL=index.cjs.map