create-warlock 4.0.30 → 4.0.39

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 (121) hide show
  1. package/cjs/index.js +10 -5
  2. package/cjs/index.js.map +1 -1
  3. package/create-app.js +0 -0
  4. package/esm/index.js +10 -5
  5. package/esm/index.js.map +1 -1
  6. package/package.json +32 -38
  7. package/templates/warlock/docs/new-module.md +123 -61
  8. package/templates/warlock/package.json +60 -67
  9. package/templates/warlock/src/app/auth/controllers/forgot-password.controller.ts +3 -2
  10. package/templates/warlock/src/app/auth/controllers/login.controller.ts +1 -4
  11. package/templates/warlock/src/app/auth/main.ts +6 -3
  12. package/templates/warlock/src/app/auth/models/otp/migrations/22-12-2025_10-30-20.otp-migration.ts +13 -16
  13. package/templates/warlock/src/app/auth/models/otp/otp.model.ts +26 -31
  14. package/templates/warlock/src/app/auth/requests/login.request.ts +1 -1
  15. package/templates/warlock/src/app/auth/services/auth.service.ts +10 -5
  16. package/templates/warlock/src/app/auth/services/otp.service.ts +2 -12
  17. package/templates/warlock/src/app/auth/services/reset-password.service.ts +1 -1
  18. package/templates/warlock/src/app/posts/controllers/create-new-post.controller.ts +20 -0
  19. package/templates/warlock/src/app/posts/controllers/update-post.controller.ts +24 -0
  20. package/templates/warlock/src/app/posts/models/post/psot.model.ts +33 -0
  21. package/templates/warlock/src/app/posts/routes.ts +11 -0
  22. package/templates/warlock/src/app/shared/utils/global-columns-schema.ts +8 -0
  23. package/templates/warlock/src/app/shared/utils/locales.ts +4 -0
  24. package/templates/warlock/src/app/uploads/controllers/fetch-uploaded-file.controller.ts +32 -0
  25. package/templates/warlock/src/app/uploads/routes.ts +4 -0
  26. package/templates/warlock/src/app/users/controllers/create-new-user.controller.ts +28 -0
  27. package/templates/warlock/src/app/users/controllers/get-users.controller.ts +7 -2
  28. package/templates/warlock/src/app/users/events/inject-created-by-user.into-model.event.ts +32 -0
  29. package/templates/warlock/src/app/users/events/sync.ts +5 -0
  30. package/templates/warlock/src/app/users/main.ts +5 -0
  31. package/templates/warlock/src/app/users/models/user/migrations/11-12-2025_23-58-03-user.migration.ts +12 -12
  32. package/templates/warlock/src/app/users/models/user/user.model.ts +54 -27
  33. package/templates/warlock/src/app/users/repositories/users.repository.ts +16 -20
  34. package/templates/warlock/src/app/users/routes.ts +7 -1
  35. package/templates/warlock/src/app/users/seeds/users.seed.ts +21 -0
  36. package/templates/warlock/src/app/utils/cloud-upload.middleware.ts +14 -0
  37. package/templates/warlock/src/app/utils/router.ts +11 -1
  38. package/templates/warlock/src/config/auth.ts +2 -0
  39. package/templates/warlock/src/config/database.ts +24 -7
  40. package/templates/warlock/src/config/storage.ts +17 -8
  41. package/templates/warlock/tsconfig.json +6 -5
  42. package/templates/warlock/yarn.lock +4831 -0
  43. package/cjs/commands/create-new-app/get-app-path.d.ts +0 -2
  44. package/cjs/commands/create-new-app/get-app-path.d.ts.map +0 -1
  45. package/cjs/commands/create-new-app/get-app-path.js +0 -8
  46. package/cjs/commands/create-new-app/get-app-path.js.map +0 -1
  47. package/cjs/commands/create-new-app/index.d.ts +0 -2
  48. package/cjs/commands/create-new-app/index.d.ts.map +0 -1
  49. package/cjs/commands/create-new-app/index.js +0 -50
  50. package/cjs/commands/create-new-app/index.js.map +0 -1
  51. package/cjs/commands/create-new-app/select-app-type.d.ts +0 -2
  52. package/cjs/commands/create-new-app/select-app-type.d.ts.map +0 -1
  53. package/cjs/commands/create-new-app/types.d.ts +0 -9
  54. package/cjs/commands/create-new-app/types.d.ts.map +0 -1
  55. package/cjs/commands/create-warlock-app/index.d.ts +0 -3
  56. package/cjs/commands/create-warlock-app/index.d.ts.map +0 -1
  57. package/cjs/commands/create-warlock-app/index.js +0 -51
  58. package/cjs/commands/create-warlock-app/index.js.map +0 -1
  59. package/cjs/helpers/app.d.ts +0 -54
  60. package/cjs/helpers/app.d.ts.map +0 -1
  61. package/cjs/helpers/app.js +0 -126
  62. package/cjs/helpers/app.js.map +0 -1
  63. package/cjs/helpers/exec.d.ts +0 -10
  64. package/cjs/helpers/exec.d.ts.map +0 -1
  65. package/cjs/helpers/exec.js +0 -69
  66. package/cjs/helpers/exec.js.map +0 -1
  67. package/cjs/helpers/package-manager.d.ts +0 -6
  68. package/cjs/helpers/package-manager.d.ts.map +0 -1
  69. package/cjs/helpers/package-manager.js +0 -22
  70. package/cjs/helpers/package-manager.js.map +0 -1
  71. package/cjs/helpers/paths.d.ts +0 -4
  72. package/cjs/helpers/paths.d.ts.map +0 -1
  73. package/cjs/helpers/paths.js +0 -8
  74. package/cjs/helpers/paths.js.map +0 -1
  75. package/cjs/helpers/project-builder-helpers.d.ts +0 -6
  76. package/cjs/helpers/project-builder-helpers.d.ts.map +0 -1
  77. package/cjs/helpers/project-builder-helpers.js +0 -18
  78. package/cjs/helpers/project-builder-helpers.js.map +0 -1
  79. package/cjs/index.d.ts +0 -2
  80. package/cjs/index.d.ts.map +0 -1
  81. package/esm/commands/create-new-app/get-app-path.d.ts +0 -2
  82. package/esm/commands/create-new-app/get-app-path.d.ts.map +0 -1
  83. package/esm/commands/create-new-app/get-app-path.js +0 -8
  84. package/esm/commands/create-new-app/get-app-path.js.map +0 -1
  85. package/esm/commands/create-new-app/index.d.ts +0 -2
  86. package/esm/commands/create-new-app/index.d.ts.map +0 -1
  87. package/esm/commands/create-new-app/index.js +0 -50
  88. package/esm/commands/create-new-app/index.js.map +0 -1
  89. package/esm/commands/create-new-app/select-app-type.d.ts +0 -2
  90. package/esm/commands/create-new-app/select-app-type.d.ts.map +0 -1
  91. package/esm/commands/create-new-app/types.d.ts +0 -9
  92. package/esm/commands/create-new-app/types.d.ts.map +0 -1
  93. package/esm/commands/create-warlock-app/index.d.ts +0 -3
  94. package/esm/commands/create-warlock-app/index.d.ts.map +0 -1
  95. package/esm/commands/create-warlock-app/index.js +0 -51
  96. package/esm/commands/create-warlock-app/index.js.map +0 -1
  97. package/esm/helpers/app.d.ts +0 -54
  98. package/esm/helpers/app.d.ts.map +0 -1
  99. package/esm/helpers/app.js +0 -126
  100. package/esm/helpers/app.js.map +0 -1
  101. package/esm/helpers/exec.d.ts +0 -10
  102. package/esm/helpers/exec.d.ts.map +0 -1
  103. package/esm/helpers/exec.js +0 -69
  104. package/esm/helpers/exec.js.map +0 -1
  105. package/esm/helpers/package-manager.d.ts +0 -6
  106. package/esm/helpers/package-manager.d.ts.map +0 -1
  107. package/esm/helpers/package-manager.js +0 -22
  108. package/esm/helpers/package-manager.js.map +0 -1
  109. package/esm/helpers/paths.d.ts +0 -4
  110. package/esm/helpers/paths.d.ts.map +0 -1
  111. package/esm/helpers/paths.js +0 -8
  112. package/esm/helpers/paths.js.map +0 -1
  113. package/esm/helpers/project-builder-helpers.d.ts +0 -6
  114. package/esm/helpers/project-builder-helpers.d.ts.map +0 -1
  115. package/esm/helpers/project-builder-helpers.js +0 -18
  116. package/esm/helpers/project-builder-helpers.js.map +0 -1
  117. package/esm/index.d.ts +0 -2
  118. package/esm/index.d.ts.map +0 -1
  119. package/templates/warlock/src/app/users/repositories/users-repository.ts +0 -66
  120. package/templates/warlock/src/app/users/services/get-new-customers.ts +0 -5
  121. package/templates/warlock/src/app/utils/output.ts +0 -5
@@ -12,7 +12,7 @@ src/app/[module-name]/
12
12
  │ └── [module].restful.ts # RESTful resource controller (optional)
13
13
  ├── services/ # Business logic layer
14
14
  │ ├── *.service.ts
15
- │ └── mail/ # Email services (optional, can be separate folder or files)
15
+ ├── mail/ # Business logic layer
16
16
  │ └── *.ts
17
17
  ├── repositories/ # Data access layer
18
18
  │ └── [resource].repository.ts
@@ -22,11 +22,11 @@ src/app/[module-name]/
22
22
  │ ├── [model-name].model.ts
23
23
  │ └── migrations/
24
24
  │ └── [date]_[model-name].migration.ts
25
- ├── validation/ # Request validation schemas
25
+ ├── requests/ # Request validation schemas
26
26
  │ ├── index.ts # Simple validations (if all in one file)
27
- │ └── *.validation.ts # Individual validation files
28
- ├── output/ # Response output transformers
29
- │ └── *.output.ts
27
+ │ └── *.request.ts # Individual validation files
28
+ ├── resources/ # Response resource transformers
29
+ │ └── *.resource.ts
30
30
  ├── events/ # Event handlers/listeners (auto-imported by Warlock.js)
31
31
  │ └── *.ts
32
32
  ├── components/ # Reusable components for use within mails
@@ -41,9 +41,11 @@ src/app/[module-name]/
41
41
  ## Directory Structure Details
42
42
 
43
43
  ### 1. main.ts (Auto-imported)
44
+
44
45
  Entry point file that is automatically imported by Warlock.js when the module loads. Use this for module initialization, event listeners, or setup code that should run when the module is loaded.
45
46
 
46
47
  **Example:**
48
+
47
49
  ```typescript
48
50
  import { onceConnected } from "@warlock.js/cascade";
49
51
 
@@ -56,9 +58,11 @@ onceConnected(async () => {
56
58
  ```
57
59
 
58
60
  ### 2. routes.ts (Auto-imported)
61
+
59
62
  Main routing file that defines all module endpoints. This file is automatically imported by Warlock.js. Use router guards (`guarded`, `guardedAdmin`, `guardedGuest`, etc.) to protect routes.
60
63
 
61
64
  **Example:**
65
+
62
66
  ```typescript
63
67
  import { router } from "@warlock.js/core";
64
68
  import { guarded, guardedGuest } from "app/utils/router";
@@ -75,28 +79,28 @@ guarded(() => {
75
79
  ```
76
80
 
77
81
  ### 3. controllers/
82
+
78
83
  Request handlers that process HTTP requests. Organize controllers by feature (e.g., `auth/`, `profile/`).
79
84
 
80
85
  **Controller Structure:**
86
+
81
87
  ```typescript
82
88
  import type { Request, RequestHandler, Response } from "@warlock.js/core";
83
89
  import { someService } from "app/[module]/services/some.service";
84
- import { someSchema } from "app/[module]/validation/some.validation";
90
+ import { someRequestSchema, type SomeRequest } from "app/[module]/requests/some.request";
85
91
 
86
- export const someController: RequestHandler = async (
87
- request: Request,
88
- response: Response,
89
- ) => {
92
+ export const someController: RequestHandler = async (request: SomeRequest, response: Response) => {
90
93
  const data = await someService(request.validated());
91
94
  return response.success({ data });
92
95
  };
93
96
 
94
97
  someController.validation = {
95
- schema: someSchema,
98
+ schema: someRequestSchema,
96
99
  };
97
100
  ```
98
101
 
99
102
  **For RESTful Resources:**
103
+
100
104
  ```typescript
101
105
  import { Restful, type RouteResource, v } from "@warlock.js/core";
102
106
  import { SomeModel } from "../models/some";
@@ -104,7 +108,7 @@ import { someRepository } from "../repositories/some.repository";
104
108
 
105
109
  class RestfulSome extends Restful<SomeModel> implements RouteResource {
106
110
  protected repository = someRepository;
107
-
111
+
108
112
  public validation: RouteResource["validation"] = {
109
113
  create: {
110
114
  schema: v.object({
@@ -118,31 +122,33 @@ export const restfulSome = new RestfulSome();
118
122
  ```
119
123
 
120
124
  ### 4. services/
125
+
121
126
  Business logic layer. Services handle the core functionality and interact with repositories.
122
127
 
123
128
  **Service Structure:**
129
+
124
130
  ```typescript
125
131
  import type { SomeModel } from "app/[module]/models/some";
126
132
  import { someRepository } from "app/[module]/repositories/some.repository";
127
133
 
128
- export async function someService(
129
- data: Record<string, any>,
130
- ): Promise<SomeModel> {
134
+ export async function someService(data: Record<string, any>): Promise<SomeModel> {
131
135
  return await someRepository.create(data);
132
136
  }
133
137
  ```
134
138
 
135
139
  ### 5. repositories/
140
+
136
141
  Data access layer that extends `RepositoryManager`. Handles database queries and filtering.
137
142
 
138
143
  **Repository Structure:**
144
+
139
145
  ```typescript
140
146
  import type { FilterByOptions, RepositoryOptions } from "@warlock.js/core";
141
147
  import { RepositoryManager } from "@warlock.js/core";
142
148
  import { SomeModel } from "../models/some";
143
149
 
144
150
  export class SomeRepository extends RepositoryManager<SomeModel> {
145
- public model = SomeModel;
151
+ public source = SomeModel;
146
152
 
147
153
  protected defaultOptions: RepositoryOptions = this.withDefaultOptions({});
148
154
 
@@ -156,46 +162,69 @@ export const someRepository = new SomeRepository();
156
162
  ```
157
163
 
158
164
  ### 6. models/
165
+
159
166
  Database models that extend base model classes (e.g., `Model`, `Auth`). Include migrations in the `migrations/` subdirectory.
160
167
 
161
168
  **Model Structure:**
169
+
162
170
  ```typescript
163
171
  import { Model } from "@warlock.js/core";
164
- import type { Casts, Document } from "@warlock.js/core";
165
- import { SomeOutput } from "../../output/some.output";
172
+ import type { StrictMode } from "@warlock.js/cascade";
173
+ import { SomeResource } from "../../resources/some.resource";
174
+ import { v, type Infer } from "@warlock.js/seal";
166
175
 
167
- export class SomeModel extends Model {
168
- public static collection = "somes";
169
- public static output = SomeOutput;
170
-
171
- public syncWith = [];
176
+ const someModelSchema = v.object({
177
+ name: v.string().required(),
178
+ email: v.email().required(),
179
+ });
172
180
 
173
- public defaultValue: Document = {
174
- isActive: true,
175
- };
181
+ type SomeModelType = Infer<typeof someModelSchema>;
176
182
 
177
- protected casts: Casts = {
178
- name: "string",
179
- isActive: "boolean",
180
- };
183
+ export class SomeModel extends Model<SomeModelType> {
184
+ public static table = "somes";
185
+ public static strictMode: StrictMode = "fail";
186
+ public static resource = SomeResource;
187
+
188
+ public static schema = someModelSchema;
181
189
 
182
- public embedded = ["id", "name"];
190
+ public embed = ["id", "name"];
183
191
  }
184
192
  ```
185
193
 
186
- ### 7. validation/
187
- Validation schemas using the `@warlock.js/core` validation system. **All validation schemas must be in the validation folder** to be used with `request.validated()` and TypeScript type inference.
194
+ ### 7. requests/
195
+
196
+ Request handlers that process HTTP requests. Organize controllers by feature (e.g., `auth/`, `profile/`).
197
+
198
+ **Request Structure:**
199
+
200
+ ```typescript
201
+ import type { Request, RequestHandler, Response } from "@warlock.js/core";
202
+ import { someService } from "app/[module]/services/some.service";
203
+ import { someRequestSchema, type SomeRequest } from "app/[module]/requests/some.request";
204
+
205
+ export const someController: RequestHandler = async (request: SomeRequest, response: Response) => {
206
+ const data = await someService(request.validated());
207
+ return response.success({ data });
208
+ };
209
+
210
+ someController.validation = {
211
+ schema: someRequestSchema,
212
+ };
213
+ ```
188
214
 
189
215
  **Important Rules:**
216
+
190
217
  - If a module has simple validations, use `index.ts` to export all schemas
191
- - If validations are complex or numerous, use separate `.validation.ts` files
218
+ - If requests are complex or numerous, use separate `.request.ts` files
192
219
  - Always export the schema and its inferred type
193
- - Pass the inferred type as generic to `Request<Model, ValidationType>`
194
220
  - Use `Infer<typeof schema>` (similar to Zod) to generate TypeScript types
195
221
 
196
222
  **Simple Validation (index.ts):**
223
+
197
224
  ```typescript
198
- import { v, type Infer } from "@warlock.js/core";
225
+ import { v, type Infer } from "@warlock.js/seal";
226
+ import { type Request } from "@warlock.js/core";
227
+ import { type User } from "app/users/models/user";
199
228
 
200
229
  export const createSchema = v.object({
201
230
  name: v.string().minLength(2).required(),
@@ -207,30 +236,41 @@ export const updateSchema = v.object({
207
236
 
208
237
  export type CreateData = Infer<typeof createSchema>;
209
238
  export type UpdateData = Infer<typeof updateSchema>;
239
+
240
+ export type CreatePostRequest<User, CreateData>;
241
+ export type UpdatePostRequest<User, UpdateData>;
210
242
  ```
211
243
 
212
244
  **Individual Validation Files:**
245
+
213
246
  ```typescript
214
- // validation/create-account.validation.ts
215
- import { v, type Infer } from "@warlock.js/core";
247
+ // requests/create-account.request.ts
248
+ import { v, type Infer } from "@warlock.js/seal";
249
+ import { type Request } from "@warlock.js/core";
216
250
 
217
251
  export const createAccountSchema = v.object({
218
252
  name: v.string().minLength(2).required(),
219
- email: v.string().email().required(),
220
- password: v.string().minLength(8).required().strongPassword(),
253
+ email: vemail().required(),
254
+ password: v.string().required().strongPassword(),
221
255
  });
222
256
 
223
257
  export type CreateAccountData = Infer<typeof createAccountSchema>;
258
+
259
+ export type CreateAccountRequest<undefined, CreateAccountData>;
224
260
  ```
225
261
 
226
262
  **Usage in Controller:**
263
+
227
264
  ```typescript
228
265
  import type { Request, RequestHandler, Response } from "@warlock.js/core";
229
266
  import type { User } from "app/[module]/models/user";
230
- import { createAccountSchema, type CreateAccountData } from "app/[module]/validation/create-account.validation";
267
+ import {
268
+ createAccountSchema,
269
+ type CreateAccountRequest,
270
+ } from "app/[module]/requests/create-account.request";
231
271
 
232
272
  export const createAccountController: RequestHandler = async (
233
- request: Request<User, CreateAccountData>,
273
+ request: CreateAccountRequest,
234
274
  response: Response,
235
275
  ) => {
236
276
  // request.validated() is now typed as CreateAccountData
@@ -243,26 +283,34 @@ createAccountController.validation = {
243
283
  };
244
284
  ```
245
285
 
246
- ### 8. output/
247
- Response output transformers that define what data is returned to clients.
286
+ ### 8. resources/
287
+
288
+ Resources define how data is transformed before being sent to clients.
289
+
290
+ **Resource Structure:**
248
291
 
249
- **Output Structure:**
250
292
  ```typescript
251
- import { Output, type FinalOutput } from "@warlock.js/core";
252
- import { withBaseOutputDetails } from "app/utils/output";
293
+ import { Resource } from "@warlock.js/core";
294
+ import {} from "app/utils/output";
253
295
 
254
- export class SomeOutput extends Output {
255
- protected output: FinalOutput = withBaseOutputDetails({
296
+ export class SomeResource extends Resource {
297
+ public schema = {
256
298
  name: "string",
257
- email: "string",
258
- });
299
+ id: "int",
300
+ type: () => "user", // custom output value
301
+ image: (value) => (value.startsWith("/") ? value : "/" + value),
302
+ };
259
303
  }
260
304
  ```
261
305
 
262
306
  ### 9. events/ (Auto-imported)
307
+
263
308
  Event handlers and listeners for model events or application events. **All files in this folder are automatically imported by Warlock.js** - no need to manually import them elsewhere.
264
309
 
310
+ > During development server, It's very important to use export const cleanup for events unbinding to prevent duplicate events registery on hmr.
311
+
265
312
  **Event Structure:**
313
+
266
314
  ```typescript
267
315
  import { Response } from "@warlock.js/core";
268
316
 
@@ -270,21 +318,28 @@ export function someEventHandler(response: Response) {
270
318
  // Event handling logic
271
319
  }
272
320
 
273
- Response.on("sending", someEventHandler);
321
+ const event = Response.on("sending", someEventHandler);
322
+
323
+ export const cleanup = [event];
324
+ // or use a callback if the event is not an unsubscribe function
325
+ export const cleanup = () => event.unsbcribe();
274
326
  ```
275
327
 
276
328
  **Note:** Files in the `events/` folder are auto-imported, similar to `routes.ts`, `main.ts`, and `utils/locales.ts`. Just create the file and it will be loaded automatically.
277
329
 
278
330
  ### 10. services/mail/ (or separate mail/ folder)
331
+
279
332
  Email service functions for sending notifications. **Mail files should be suffixed with `.mail.ts`** (e.g., `welcome.mail.ts`, `reset-password.mail.ts`).
280
333
 
281
334
  You can organize mail services either as:
335
+
282
336
  - Files in `services/mail/` folder (if you have multiple mail-related services) - **Recommended**
283
337
  - Individual files in `services/` folder (if you have few mail services)
284
338
  - A separate `mail/` folder at module root (legacy pattern, still supported)
285
339
 
286
340
  **Mail Structure:**
287
- ```typescript
341
+
342
+ ```tsx
288
343
  // services/mail/welcome.mail.ts
289
344
  import { sendMail } from "@warlock.js/core";
290
345
  import type { SomeModel } from "../models/some";
@@ -294,7 +349,7 @@ export default async function sendWelcomeEmail(model: SomeModel) {
294
349
  await sendMail({
295
350
  to: model.get("email"),
296
351
  subject: "Subject",
297
- html: SomeEmailComponent({ name: model.get("name") }),
352
+ component: <SomeEmailComponent name={model.get("name")} />,
298
353
  });
299
354
  }
300
355
  ```
@@ -302,10 +357,12 @@ export default async function sendWelcomeEmail(model: SomeModel) {
302
357
  **Recommendation:** Use `services/mail/` folder for better organization when you have multiple mail templates, and always suffix mail files with `.mail.ts`.
303
358
 
304
359
  ### 11. components/
360
+
305
361
  Reusable components for use within email templates. These are typically functions that return HTML strings or React-like components that can be used in mail services.
306
362
 
307
363
  **Component Structure:**
308
- ```typescript
364
+
365
+ ```tsx
309
366
  export function WelcomeEmailComponent(data: { name: string; email: string }) {
310
367
  return `
311
368
  <div>
@@ -317,7 +374,8 @@ export function WelcomeEmailComponent(data: { name: string; email: string }) {
317
374
  ```
318
375
 
319
376
  **Usage in Mail:**
320
- ```typescript
377
+
378
+ ```tsx
321
379
  import { sendMail } from "@warlock.js/core";
322
380
  import { WelcomeEmailComponent } from "../components/welcome-email.component";
323
381
 
@@ -325,22 +383,22 @@ export default async function sendWelcomeEmail(user: User) {
325
383
  await sendMail({
326
384
  to: user.get("email"),
327
385
  subject: "Welcome",
328
- html: WelcomeEmailComponent({
329
- name: user.get("name"),
330
- email: user.get("email")
331
- }),
386
+ component: <WelcomeEmailComponent name={user.get("name")} email={user.get("email")} />,
332
387
  });
333
388
  }
334
389
  ```
335
390
 
336
391
  ### 12. types/
392
+
337
393
  TypeScript type definitions specific to the module. Use this folder for:
394
+
338
395
  - Request/response types
339
396
  - Service parameter types
340
397
  - Module-specific interfaces
341
398
  - Type utilities
342
399
 
343
400
  **Types Structure:**
401
+
344
402
  ```typescript
345
403
  // types/user.types.ts
346
404
  export interface UserPreferences {
@@ -352,9 +410,11 @@ export type UserRole = "admin" | "user" | "guest";
352
410
  ```
353
411
 
354
412
  ### 13. utils/
413
+
355
414
  Module-specific utility functions. **Must include `locales.ts`** which is automatically imported by Warlock.js.
356
415
 
357
416
  **utils/locales.ts (Auto-imported):**
417
+
358
418
  ```typescript
359
419
  import { groupedTranslations } from "@mongez/localization";
360
420
 
@@ -371,6 +431,7 @@ groupedTranslations("moduleName", {
371
431
  ```
372
432
 
373
433
  **utils/flags.ts (Constants):**
434
+
374
435
  ```typescript
375
436
  // Module-specific constants and flags
376
437
  export const USER_STATUS = {
@@ -387,6 +448,7 @@ export const USER_ROLES = {
387
448
  ```
388
449
 
389
450
  **Other Utilities:**
451
+
390
452
  ```typescript
391
453
  // utils/helpers.ts or similar
392
454
  export function formatUserName(user: User): string {
@@ -444,4 +506,4 @@ export function formatUserName(user: User): string {
444
506
  - Keep mail services organized: use `services/mail/` folder if multiple, or individual files in `services/` if few
445
507
  - Use `components/` folder for reusable email components
446
508
  - Define module-specific types in `types/` folder
447
- - Use `utils/flags.ts` for constants and configuration flags
509
+ - Use `utils/flags.ts` for constants and configuration flags
@@ -1,69 +1,62 @@
1
1
  {
2
- "name": "app-name",
3
- "version": "1.0.0",
4
- "private": true,
5
- "type": "module",
6
- "scripts": {
7
- "dev": "warlock dev",
8
- "build": "tsc && warlock build",
9
- "prod": "warlock start",
10
- "postman": "warlock postman",
11
- "migrate": "warlock migrate",
12
- "migrate.fresh": "warlock migrate --fresh",
13
- "migrate.list": "warlock migrate --list",
14
- "jwt": "warlock jwt.generate",
15
- "prod.start": "yarn build && yarn prod",
16
- "serve": "yarn build && nohup warlock start > /dev/null 2>&1",
17
- "lint": "npx eslint --fix ./src --max-warnings=0",
18
- "format": "npx prettier --write ./src/**/*.{js,jsx,ts,tsx,css,md,json} --config ./.prettierrc.json",
19
- "tsc": "npx tsc --noEmit",
20
- "prepare": "huskier-init && husky install",
21
- "lf": "find . -type d ( -name 'node_modules' -o -name '.git' ) -prune -o -type f -exec dos2unix {} ;"
22
- },
23
- "dependencies": {
24
- "@mongez/collection": "^1.2.0",
25
- "@mongez/encryption": "^1.0.4",
26
- "@mongez/fs": "^3.0.5",
27
- "@mongez/reinforcements": "^2.3.12",
28
- "@mongez/localization": "^3.2.1",
29
- "@mongez/supportive-is": "^2.0.4",
30
- "@warlock.js/auth": "4.0.30",
31
- "@warlock.js/cache": "4.0.30",
32
- "@warlock.js/cascade": "4.0.30",
33
- "@warlock.js/scheduler": "4.0.30",
34
- "@warlock.js/core": "4.0.30",
35
- "@warlock.js/logger": "4.0.30",
36
- "@warlock.js/seal": "4.0.30",
37
- "dayjs": "^1.11.13"
38
- },
39
- "devDependencies": {
40
- "@mongez/huskier": "^3.0.0",
41
- "@types/node": "^25.0.3",
42
- "@types/prettier": "^3.0.0",
43
- "@types/react": "^19.2.7",
44
- "@types/react-dom": "^19.2.3",
45
- "@typescript-eslint/eslint-plugin": "^8.50.0",
46
- "@typescript-eslint/parser": "^8.50.0",
47
- "esbuild-css-modules-plugin": "^3.1.5",
48
- "esbuild-plugin-css-modules": "^0.3.0",
49
- "esbuild-plugin-postcss": "^0.3.0",
50
- "esbuild-plugin-postcss2": "^0.1.2",
51
- "eslint": "^9.39.2",
52
- "eslint-config-prettier": "^10.1.8",
53
- "eslint-plugin-prettier": "^5.5.4",
54
- "eslint-plugin-unused-imports": "^4.3.0",
55
- "npm-check-updates": "^19.2.0",
56
- "prettier": "^3.7.4",
57
- "prettier-plugin-organize-imports": "^4.3.0",
58
- "typescript": "^5.9.3"
59
- },
60
- "huskier": {
61
- "hooks": {
62
- "pre-commit": [
63
- "yarn format",
64
- "yarn lint",
65
- "yarn tsc"
66
- ]
67
- }
2
+ "name": "app-name",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "warlock dev",
8
+ "build": "tsc && warlock build",
9
+ "start": "warlock start",
10
+ "seed": "warlock seed",
11
+ "migrate": "warlock migrate",
12
+ "migrate.fresh": "warlock migrate --fresh",
13
+ "migrate.list": "warlock migrate --list",
14
+ "jwt": "warlock jwt.generate",
15
+ "serve": "yarn build && nohup warlock start > /dev/null 2>&1",
16
+ "lint": "npx eslint --fix ./src --max-warnings=0",
17
+ "format": "npx prettier --write ./src/**/*.{js,jsx,ts,tsx,css,md,json} --config ./.prettierrc.json",
18
+ "tsc": "npx tsc --noEmit",
19
+ "prepare": "huskier-init && husky install",
20
+ "lf": "find . -type d ( -name 'node_modules' -o -name '.git' ) -prune -o -type f -exec dos2unix {} ;"
21
+ },
22
+ "dependencies": {
23
+ "@mongez/fs": "^3.0.5",
24
+ "@mongez/reinforcements": "^2.3.17",
25
+ "@mongez/localization": "^3.2.1",
26
+ "@mongez/supportive-is": "^2.0.4",
27
+ "@warlock.js/auth": "4.0.32",
28
+ "@warlock.js/cache": "4.0.32",
29
+ "@warlock.js/cascade": "4.0.32",
30
+ "@warlock.js/scheduler": "4.0.32",
31
+ "@warlock.js/core": "4.0.32",
32
+ "@warlock.js/logger": "4.0.32",
33
+ "@warlock.js/seal": "4.0.32",
34
+ "dayjs": "^1.11.19"
35
+ },
36
+ "devDependencies": {
37
+ "@mongez/huskier": "^3.0.0",
38
+ "@types/mime": "^3.0.4",
39
+ "@types/node": "^25.0.3",
40
+ "@types/prettier": "^3.0.0",
41
+ "@typescript-eslint/eslint-plugin": "^8.50.0",
42
+ "@typescript-eslint/parser": "^8.50.0",
43
+ "eslint": "^9.39.2",
44
+ "eslint-config-prettier": "^10.1.8",
45
+ "eslint-plugin-prettier": "^5.5.4",
46
+ "eslint-plugin-unused-imports": "^4.3.0",
47
+ "npm-check-updates": "^19.2.0",
48
+ "prettier": "^3.7.4",
49
+ "prettier-plugin-organize-imports": "^4.3.0",
50
+ "tsx": "^4.21.0",
51
+ "typescript": "^5.9.3"
52
+ },
53
+ "huskier": {
54
+ "hooks": {
55
+ "pre-commit": [
56
+ "yarn format",
57
+ "yarn lint",
58
+ "yarn tsc"
59
+ ]
68
60
  }
69
- }
61
+ }
62
+ }
@@ -13,8 +13,9 @@ export const forgotPassword: RequestHandler = async (request: Request, response:
13
13
  const user = await usersRepository.first({ email });
14
14
 
15
15
  if (!user) {
16
- return response.notFound({
17
- error: t("auth.userNotFound"),
16
+ // Silent success - don't reveal if email exists
17
+ return response.success({
18
+ message: t("auth.otpSent"),
18
19
  });
19
20
  }
20
21
 
@@ -18,10 +18,7 @@ export const login: RequestHandler = async (request: LoginRequest, response: Res
18
18
  });
19
19
  }
20
20
 
21
- return response.success({
22
- user: result.user,
23
- ...result.tokens,
24
- });
21
+ return response.success(result);
25
22
  };
26
23
 
27
24
  login.description = "User Login";
@@ -1,9 +1,12 @@
1
+ import { authService } from "@warlock.js/auth";
1
2
  import { onceConnected } from "@warlock.js/cascade";
2
- import { Job } from "@warlock.js/scheduler";
3
3
  import { scheduler } from "app/shared/services/scheduler.service";
4
4
  import { cleanupExpiredOtpsService } from "./services/otp.service";
5
5
 
6
6
  onceConnected(() => {
7
- const cleanupJob = new Job("cleanup-expired-otps", cleanupExpiredOtpsService).everyHour();
8
- scheduler.addJob(cleanupJob);
7
+ // Cleanup expired OTPs every hour
8
+ scheduler.newJob("cleanup-expired-otps", cleanupExpiredOtpsService).everyHour();
9
+
10
+ // Cleanup expired refresh tokens every hour
11
+ scheduler.newJob("cleanup-expired-tokens", () => authService.cleanupExpiredTokens()).everyHour();
9
12
  });
@@ -1,22 +1,19 @@
1
- import { migrationOffice } from "@warlock.js/cascade";
1
+ import { migrate } from "@warlock.js/cascade";
2
2
  import { OTP } from "../otp.model";
3
3
 
4
- const otpBlueprint = OTP.blueprint();
5
-
6
- export default migrationOffice.register({
4
+ export default migrate(OTP, {
7
5
  name: "otp",
8
- createdAt: "22-12-2025_10-30-20",
9
- blueprint: otpBlueprint,
10
- up: async () => {
11
- await otpBlueprint.index("code");
12
- await otpBlueprint.index(["target", "type"]);
13
- await otpBlueprint.index("expiresAt");
14
- await otpBlueprint.index("userId");
6
+ createdAt: "2025-12-22T10:30:20", // ISO Date
7
+ up() {
8
+ this.index("code");
9
+ this.index(["target", "type"]);
10
+ this.index("expiresAt");
11
+ this.index("userId");
15
12
  },
16
- down: async () => {
17
- await otpBlueprint.dropIndex("code");
18
- await otpBlueprint.dropIndex("target", "type");
19
- await otpBlueprint.dropIndex("expiresAt");
20
- await otpBlueprint.dropIndex("userId");
13
+ down() {
14
+ this.dropIndex("code");
15
+ this.dropIndex(["target", "type"]);
16
+ this.dropIndex("expiresAt");
17
+ this.dropIndex("userId");
21
18
  },
22
19
  });