create-nexwire 4.0.0 → 4.1.0

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 (175) hide show
  1. package/README.md +5 -4
  2. package/express/.env +1 -1
  3. package/express/README.md +13 -7
  4. package/express/package.json +2 -2
  5. package/express/src/config/session.ts +1 -1
  6. package/express/src/database/migrations/sqlite/meta/0000_snapshot.json +1 -1
  7. package/express/src/database/migrations/sqlite/meta/_journal.json +1 -1
  8. package/express/src/database/schema.ts +3 -3
  9. package/express/src/framework/cache/cache.ts +82 -81
  10. package/express/src/framework/database/seed.ts +1 -1
  11. package/express/src/framework/facade.ts +1 -24
  12. package/express/src/framework/http/app.ts +5 -5
  13. package/express/src/framework/http/openapi.ts +1 -1
  14. package/express/src/framework/http/router.ts +3 -18
  15. package/express/src/framework/http/types.ts +19 -0
  16. package/express/src/framework/http/validation.ts +18 -18
  17. package/express/src/framework/maker-cli/middleware/core.mjs +41 -47
  18. package/express/src/framework/maker-cli/module/core.mjs +920 -684
  19. package/express/src/framework/maker-cli/module/index.mjs +202 -140
  20. package/express/src/framework/maker-cli/runtime/core.mjs +1 -2
  21. package/express/src/framework/maker-cli/stubs/controller/openapi.ts.stub +40 -14
  22. package/express/src/framework/maker-cli/stubs/controller/openapi.with-model.ts.stub +40 -15
  23. package/express/src/framework/maker-cli/stubs/controller/plain.ts.stub +42 -16
  24. package/express/src/framework/maker-cli/stubs/controller/standalone.ts.stub +47 -0
  25. package/express/src/framework/maker-cli/stubs/facade/name.ts.stub +12 -0
  26. package/express/src/framework/maker-cli/stubs/helper/name.ts.stub +14 -0
  27. package/express/src/framework/maker-cli/stubs/middleware/name.local.ts.stub +15 -0
  28. package/express/src/framework/maker-cli/stubs/model/name.mysql.ts.stub +9 -8
  29. package/express/src/framework/maker-cli/stubs/model/name.postgresql.ts.stub +9 -8
  30. package/express/src/framework/maker-cli/stubs/model/name.sqlite.ts.stub +9 -8
  31. package/express/src/framework/maker-cli/stubs/notification/route.api.ts.stub +50 -50
  32. package/express/src/framework/maker-cli/stubs/notification/route.plain.ts.stub +11 -11
  33. package/express/src/framework/maker-cli/stubs/route/api.ts.stub +93 -79
  34. package/express/src/framework/maker-cli/stubs/route/plain.ts.stub +23 -10
  35. package/express/src/framework/maker-cli/stubs/route/standalone.api.ts.stub +113 -0
  36. package/express/src/framework/maker-cli/stubs/route/standalone.plain.ts.stub +37 -0
  37. package/express/src/framework/maker-cli/stubs/{controller/schema.plain.ts.stub → schema/name.plain.ts.stub} +13 -13
  38. package/express/src/framework/maker-cli/stubs/{controller/schema.ts.stub → schema/name.ts.stub} +32 -32
  39. package/express/src/framework/maker-cli/stubs/service/name.plain.ts.stub +67 -0
  40. package/express/src/framework/maker-cli/stubs/service/name.ts.stub +65 -0
  41. package/express/src/framework/maker-cli/stubs/type/name.ts.stub +22 -0
  42. package/express/src/framework/maker-cli/utils/naming.mjs +56 -13
  43. package/express/src/framework/modules/discover.ts +57 -54
  44. package/express/src/framework/notification/index.ts +1 -1
  45. package/express/src/framework/realtime/broadcast.ts +46 -46
  46. package/express/src/framework/server.ts +2 -1
  47. package/express/src/framework/session/session.ts +102 -98
  48. package/express/src/framework/support/mail.ts +48 -48
  49. package/express/src/framework/support/status-codes.ts +75 -0
  50. package/express/src/middlewares/auth-middleware.ts +1 -1
  51. package/express/src/modules/auth/__tests__/forgetpass.test.ts +200 -0
  52. package/express/src/modules/auth/__tests__/login.test.ts +171 -0
  53. package/express/src/modules/auth/__tests__/logout.test.ts +60 -0
  54. package/express/src/modules/auth/__tests__/logoutalldevices.test.ts +49 -0
  55. package/express/src/modules/auth/__tests__/me.test.ts +91 -0
  56. package/express/src/modules/auth/__tests__/refreshtoken.test.ts +305 -0
  57. package/express/src/modules/auth/__tests__/register.test.ts +291 -0
  58. package/express/src/modules/auth/__tests__/resetpass.test.ts +206 -0
  59. package/express/src/modules/auth/__tests__/verifyemail.test.ts +183 -0
  60. package/express/src/modules/auth/controllers/auth.ts +254 -0
  61. package/express/src/modules/auth/controllers/{role.controller.ts → role.ts} +25 -15
  62. package/{hono/src/modules/auth/database/models/notifications.ts → express/src/modules/auth/database/models/notification.ts} +1 -1
  63. package/express/src/modules/auth/database/models/role.ts +1 -1
  64. package/express/src/modules/auth/database/models/user.ts +1 -1
  65. package/express/src/modules/auth/facade.ts +12 -0
  66. package/express/src/modules/auth/{controllers/auth.helpers.ts → helpers/auth.ts} +3 -4
  67. package/express/src/modules/auth/jobs/registeruser.ts +23 -23
  68. package/express/src/modules/auth/routes/{api.ts → index.ts} +150 -150
  69. package/express/src/modules/auth/routes/role.ts +33 -33
  70. package/{hono/src/modules/auth/controllers/auth.schema.ts → express/src/modules/auth/schemas/auth.ts} +102 -102
  71. package/express/src/modules/auth/services/forgetpassword.ts +66 -0
  72. package/express/src/modules/auth/services/login.ts +63 -0
  73. package/express/src/modules/auth/services/logout.ts +25 -0
  74. package/express/src/modules/auth/services/logoutalldevices.ts +19 -0
  75. package/express/src/modules/auth/services/me.ts +31 -0
  76. package/express/src/modules/auth/services/refreshtoken.ts +110 -0
  77. package/express/src/modules/auth/services/register.ts +141 -0
  78. package/express/src/modules/auth/services/resetpassword.ts +69 -0
  79. package/express/src/modules/auth/services/verifyemail.ts +77 -0
  80. package/express/src/modules/auth/types/auth.ts +31 -0
  81. package/express/src/resources/src/assets/images/logo.png +0 -0
  82. package/express/src/resources/src/pages/auth/forgetPassword.vue +1 -0
  83. package/express/src/resources/src/pages/auth/login.vue +1 -1
  84. package/express/src/storage/database/nexwire.sqlite +0 -0
  85. package/hono/.env +1 -1
  86. package/hono/README.md +13 -7
  87. package/hono/package.json +1 -1
  88. package/hono/src/config/session.ts +1 -1
  89. package/hono/src/database/migrations/sqlite/meta/0000_snapshot.json +1 -1
  90. package/hono/src/database/migrations/sqlite/meta/_journal.json +1 -1
  91. package/hono/src/database/schema.ts +3 -3
  92. package/hono/src/framework/cache/cache.ts +82 -81
  93. package/hono/src/framework/database/seed.ts +1 -1
  94. package/hono/src/framework/http/app.ts +5 -5
  95. package/hono/src/framework/http/validation.ts +21 -21
  96. package/hono/src/framework/maker-cli/middleware/core.mjs +40 -46
  97. package/hono/src/framework/maker-cli/module/core.mjs +401 -168
  98. package/hono/src/framework/maker-cli/module/index.mjs +73 -11
  99. package/hono/src/framework/maker-cli/stubs/controller/openapi.ts.stub +28 -16
  100. package/hono/src/framework/maker-cli/stubs/controller/openapi.with-model.ts.stub +28 -17
  101. package/hono/src/framework/maker-cli/stubs/controller/plain.ts.stub +28 -16
  102. package/hono/src/framework/maker-cli/stubs/controller/standalone.ts.stub +56 -0
  103. package/hono/src/framework/maker-cli/stubs/facade/name.ts.stub +12 -0
  104. package/hono/src/framework/maker-cli/stubs/helper/name.ts.stub +14 -0
  105. package/hono/src/framework/maker-cli/stubs/middleware/name.local.ts.stub +15 -0
  106. package/hono/src/framework/maker-cli/stubs/model/name.mysql.ts.stub +9 -8
  107. package/hono/src/framework/maker-cli/stubs/model/name.postgresql.ts.stub +9 -8
  108. package/hono/src/framework/maker-cli/stubs/model/name.sqlite.ts.stub +9 -8
  109. package/hono/src/framework/maker-cli/stubs/notification/route.api.ts.stub +49 -49
  110. package/hono/src/framework/maker-cli/stubs/notification/route.plain.ts.stub +11 -11
  111. package/hono/src/framework/maker-cli/stubs/route/api.ts.stub +93 -79
  112. package/hono/src/framework/maker-cli/stubs/route/plain.ts.stub +23 -10
  113. package/hono/src/framework/maker-cli/stubs/route/standalone.api.ts.stub +112 -0
  114. package/hono/src/framework/maker-cli/stubs/route/standalone.plain.ts.stub +37 -0
  115. package/hono/src/framework/maker-cli/stubs/{controller/schema.plain.ts.stub → schema/name.plain.ts.stub} +13 -13
  116. package/hono/src/framework/maker-cli/stubs/{controller/schema.ts.stub → schema/name.ts.stub} +32 -32
  117. package/hono/src/framework/maker-cli/stubs/service/name.plain.ts.stub +67 -0
  118. package/hono/src/framework/maker-cli/stubs/service/name.ts.stub +65 -0
  119. package/hono/src/framework/maker-cli/stubs/type/name.ts.stub +22 -0
  120. package/hono/src/framework/maker-cli/utils/naming.mjs +56 -13
  121. package/hono/src/framework/modules/discover.ts +57 -54
  122. package/hono/src/framework/notification/index.ts +1 -1
  123. package/hono/src/framework/realtime/broadcast.ts +46 -46
  124. package/hono/src/framework/server.ts +1 -1
  125. package/hono/src/framework/session/session.ts +121 -116
  126. package/hono/src/middlewares/auth-middleware.ts +1 -1
  127. package/hono/src/modules/auth/__tests__/forgetpass.test.ts +170 -0
  128. package/hono/src/modules/auth/__tests__/login.test.ts +154 -0
  129. package/hono/src/modules/auth/__tests__/logout.test.ts +53 -0
  130. package/hono/src/modules/auth/__tests__/logoutalldevices.test.ts +34 -0
  131. package/hono/src/modules/auth/__tests__/me.test.ts +87 -0
  132. package/hono/src/modules/auth/__tests__/refreshtoken.test.ts +305 -0
  133. package/hono/src/modules/auth/__tests__/register.test.ts +258 -0
  134. package/hono/src/modules/auth/__tests__/resetpass.test.ts +214 -0
  135. package/hono/src/modules/auth/__tests__/verifyemail.test.ts +189 -0
  136. package/hono/src/modules/auth/controllers/auth.ts +238 -0
  137. package/hono/src/modules/auth/controllers/{role.controller.ts → role.ts} +25 -25
  138. package/{express/src/modules/auth/database/models/notifications.ts → hono/src/modules/auth/database/models/notification.ts} +1 -1
  139. package/hono/src/modules/auth/database/models/role.ts +1 -1
  140. package/hono/src/modules/auth/database/models/user.ts +1 -1
  141. package/hono/src/modules/auth/facade.ts +12 -0
  142. package/hono/src/modules/auth/{controllers/auth.helpers.ts → helpers/auth.ts} +5 -6
  143. package/hono/src/modules/auth/jobs/registeruser.ts +23 -23
  144. package/hono/src/modules/auth/routes/{api.ts → index.ts} +150 -150
  145. package/hono/src/modules/auth/routes/role.ts +33 -33
  146. package/{express/src/modules/auth/controllers/auth.schema.ts → hono/src/modules/auth/schemas/auth.ts} +102 -102
  147. package/hono/src/modules/auth/services/forgetpassword.ts +58 -0
  148. package/hono/src/modules/auth/services/login.ts +61 -0
  149. package/hono/src/modules/auth/services/logout.ts +24 -0
  150. package/hono/src/modules/auth/services/logoutalldevices.ts +19 -0
  151. package/hono/src/modules/auth/services/me.ts +31 -0
  152. package/hono/src/modules/auth/services/refreshtoken.ts +110 -0
  153. package/hono/src/modules/auth/services/register.ts +132 -0
  154. package/hono/src/modules/auth/services/resetpassword.ts +69 -0
  155. package/hono/src/modules/auth/services/verifyemail.ts +77 -0
  156. package/hono/src/modules/auth/types/auth.ts +31 -0
  157. package/hono/src/resources/src/assets/images/logo.png +0 -0
  158. package/hono/src/storage/database/nexwire.sqlite +0 -0
  159. package/package.json +1 -1
  160. package/express/src/framework/maker-cli/stubs/example/console.ts.stub +0 -34
  161. package/express/src/framework/maker-cli/stubs/example/controller.ts.stub +0 -418
  162. package/express/src/framework/maker-cli/stubs/example/job.ts.stub +0 -75
  163. package/express/src/framework/maker-cli/stubs/example/route.api.ts.stub +0 -207
  164. package/express/src/framework/maker-cli/stubs/example/route.plain.ts.stub +0 -18
  165. package/express/src/framework/maker-cli/stubs/example/schema.plain.ts.stub +0 -42
  166. package/express/src/framework/maker-cli/stubs/example/schema.ts.stub +0 -42
  167. package/express/src/modules/auth/controllers/auth.controller.ts +0 -358
  168. package/hono/src/framework/maker-cli/stubs/example/console.ts.stub +0 -34
  169. package/hono/src/framework/maker-cli/stubs/example/controller.ts.stub +0 -505
  170. package/hono/src/framework/maker-cli/stubs/example/job.ts.stub +0 -75
  171. package/hono/src/framework/maker-cli/stubs/example/route.api.ts.stub +0 -207
  172. package/hono/src/framework/maker-cli/stubs/example/route.plain.ts.stub +0 -18
  173. package/hono/src/framework/maker-cli/stubs/example/schema.plain.ts.stub +0 -42
  174. package/hono/src/framework/maker-cli/stubs/example/schema.ts.stub +0 -42
  175. package/hono/src/modules/auth/controllers/auth.controller.ts +0 -413
@@ -7,43 +7,52 @@ import {
7
7
  deleteNotificationModule,
8
8
  listModules,
9
9
  makeController,
10
- makeExampleModule,
10
+ makeHelper,
11
11
  makeJob,
12
+ makeLocalMiddleware,
12
13
  makeModel,
13
14
  makeModule,
15
+ makeModules,
14
16
  makeNotificationModule,
15
17
  makeRoute,
16
18
  makeSchedule,
19
+ makeSchema,
17
20
  makeSeeder,
21
+ makeService,
18
22
  makeTest,
23
+ makeType,
19
24
  runModuleMigrate
20
25
  } from "./core.mjs";
21
26
 
22
27
  /** Register module:* subcommands on the CLI program. */
23
28
  export function registerModuleCommands(program, rawArgs) {
24
29
  program
25
- .command("module:make <name>")
26
- .description("Create a module with controller, route, model, and seeder folders")
30
+ .command("module:make <names...>")
31
+ .description("Create one or more modules with facade, schema, service, controller, route, model, and seeder folders")
32
+ .option("--path <panel>", "Nest the module(s) under a panel folder (e.g. --path=admin)")
33
+ .option("--force", "Overwrite the files of modules that already exist")
27
34
  .allowUnknownOption(true)
28
- .action(async (name) => makeModule(name));
35
+ .action(async (names) => {
36
+ const result = await makeModules(names, rawArgs.slice(1 + names.length));
37
+ if (result.failed.length) process.exitCode = 1;
38
+ });
29
39
  program
30
40
  .command("module:make-notification [name]")
31
41
  .description("Generate notification backend module (controller, routes, job)")
42
+ .option("--path <panel>", "Nest the module under a panel folder (e.g. --path=admin)")
43
+ .option("--force", "Overwrite the files of a module that already exists")
32
44
  .allowUnknownOption(true)
33
45
  .action(async (name) => {
34
46
  const maybeModule = name && !name.startsWith("--") ? name : "";
35
- await makeNotificationModule(maybeModule || "notification");
47
+ const flagStart = maybeModule ? 2 : 1;
48
+ await makeNotificationModule(maybeModule || "notification", rawArgs.slice(flagStart));
36
49
  });
37
- program
38
- .command("module:example [name]")
39
- .description("Generate one-shot example module with queue/broadcast/scheduler cases")
40
- .allowUnknownOption(true)
41
- .action(async (name) => makeExampleModule(name || "example"));
42
50
  program
43
51
  .command("module:delete-notification [name]")
44
52
  .description("Remove notification module (moves to trash)")
45
53
  .option("--yes", "Confirm deletion without prompt")
46
54
  .option("--dry-run", "Print what would be deleted without executing")
55
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
47
56
  .allowUnknownOption(true)
48
57
  .action(async (name) => {
49
58
  const maybeModule = name && !name.startsWith("--") ? name : "";
@@ -55,6 +64,7 @@ export function registerModuleCommands(program, rawArgs) {
55
64
  .description("Move a module directory to storage trash (soft delete)")
56
65
  .option("--yes", "Confirm deletion without prompt")
57
66
  .option("--dry-run", "Print what would be deleted without executing")
67
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
58
68
  .allowUnknownOption(true)
59
69
  .action(async (name) => deleteModule(name, rawArgs.slice(2)));
60
70
  program
@@ -62,6 +72,7 @@ export function registerModuleCommands(program, rawArgs) {
62
72
  .description("Permanently remove entries from module trash storage")
63
73
  .option("--yes", "Confirm cleanup without prompt")
64
74
  .option("--dry-run", "Print what would be cleaned without executing")
75
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
65
76
  .allowUnknownOption(true)
66
77
  .action(async (name) => {
67
78
  const maybeModule = name && !name.startsWith("--") ? name : "";
@@ -73,20 +84,64 @@ export function registerModuleCommands(program, rawArgs) {
73
84
  .description("Generate a route file for an existing module")
74
85
  .option("--force", "Overwrite existing route file")
75
86
  .option("--dry-run", "Print what would be created without executing")
87
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
76
88
  .allowUnknownOption(true)
77
89
  .action(async (moduleName, controller) => makeRoute(moduleName, controller, rawArgs.slice(controller ? 3 : 2)));
78
90
  program
79
91
  .command("module:make-controller <module> [name]")
80
92
  .description("Generate a controller for an existing module")
81
- .option("--force", "Overwrite existing controller files")
93
+ .option("--force", "Overwrite existing controller file")
82
94
  .option("--dry-run", "Print what would be created without executing")
95
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
83
96
  .allowUnknownOption(true)
84
97
  .action(async (moduleName, name) => makeController(moduleName, name, rawArgs.slice(name ? 3 : 2)));
98
+ program
99
+ .command("module:make-schema <module> [name]")
100
+ .description("Generate a schema file for an existing module")
101
+ .option("--force", "Overwrite existing schema file")
102
+ .option("--dry-run", "Print what would be created without executing")
103
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
104
+ .allowUnknownOption(true)
105
+ .action(async (moduleName, name) => makeSchema(moduleName, name, rawArgs.slice(name ? 3 : 2)));
106
+ program
107
+ .command("module:make-service <module> [name]")
108
+ .description("Generate a service file for an existing module")
109
+ .option("--with-model", "Query database/models/<name>.ts instead of returning empty defaults")
110
+ .option("--force", "Overwrite existing service file")
111
+ .option("--dry-run", "Print what would be created without executing")
112
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
113
+ .allowUnknownOption(true)
114
+ .action(async (moduleName, name) => makeService(moduleName, name, rawArgs.slice(name ? 3 : 2)));
115
+ program
116
+ .command("module:make-helper <module> [name]")
117
+ .description("Generate a helper file in the module's helpers folder")
118
+ .option("--force", "Overwrite existing helper file")
119
+ .option("--dry-run", "Print what would be created without executing")
120
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
121
+ .allowUnknownOption(true)
122
+ .action(async (moduleName, name) => makeHelper(moduleName, name, rawArgs.slice(name ? 3 : 2)));
123
+ program
124
+ .command("module:make-middleware <module> [name]")
125
+ .description("Generate a module-local middleware file for an existing module")
126
+ .option("--force", "Overwrite existing middleware file")
127
+ .option("--dry-run", "Print what would be created without executing")
128
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
129
+ .allowUnknownOption(true)
130
+ .action(async (moduleName, name) => makeLocalMiddleware(moduleName, name, rawArgs.slice(name ? 3 : 2)));
131
+ program
132
+ .command("module:make-type <module> [name]")
133
+ .description("Generate a types file for an existing module")
134
+ .option("--force", "Overwrite existing types file")
135
+ .option("--dry-run", "Print what would be created without executing")
136
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
137
+ .allowUnknownOption(true)
138
+ .action(async (moduleName, name) => makeType(moduleName, name, rawArgs.slice(name ? 3 : 2)));
85
139
  program
86
140
  .command("module:make-model <module> [name]")
87
141
  .description("Generate a model file for an existing module")
88
142
  .option("--force", "Overwrite existing model file")
89
143
  .option("--dry-run", "Print what would be created without executing")
144
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
90
145
  .allowUnknownOption(true)
91
146
  .action(async (moduleName, name) => makeModel(moduleName, name, rawArgs.slice(name ? 3 : 2)));
92
147
  program
@@ -94,6 +149,7 @@ export function registerModuleCommands(program, rawArgs) {
94
149
  .description("Generate a seeder file for an existing module model")
95
150
  .option("--force", "Overwrite existing seeder file")
96
151
  .option("--dry-run", "Print what would be created without executing")
152
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
97
153
  .allowUnknownOption(true)
98
154
  .action(async (moduleName, name) => makeSeeder(moduleName, name, rawArgs.slice(name ? 3 : 2)));
99
155
  program
@@ -101,6 +157,7 @@ export function registerModuleCommands(program, rawArgs) {
101
157
  .description("Generate a job file for an existing module")
102
158
  .option("--force", "Overwrite existing job file")
103
159
  .option("--dry-run", "Print what would be created without executing")
160
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
104
161
  .allowUnknownOption(true)
105
162
  .action(async (moduleName, name) => makeJob(moduleName, name, rawArgs.slice(name ? 3 : 2)));
106
163
  program
@@ -108,16 +165,19 @@ export function registerModuleCommands(program, rawArgs) {
108
165
  .description("Generate a scheduler/console file for an existing module")
109
166
  .option("--force", "Overwrite existing console file")
110
167
  .option("--dry-run", "Print what would be created without executing")
168
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
111
169
  .allowUnknownOption(true)
112
170
  .action(async (moduleName, name) => makeSchedule(moduleName, name, rawArgs.slice(name ? 3 : 2)));
113
171
  program
114
172
  .command("module:list")
115
173
  .description("List all discovered modules")
174
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
116
175
  .allowUnknownOption(true)
117
176
  .action(async () => listModules());
118
177
  program
119
178
  .command("module:seed <module>")
120
179
  .description("Run seeders for one module")
180
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
121
181
  .allowUnknownOption(true)
122
182
  .action(async (moduleName) => {
123
183
  const normalized = assertName(moduleName, "Module name");
@@ -128,6 +188,7 @@ export function registerModuleCommands(program, rawArgs) {
128
188
  .command("module:migrate <module>")
129
189
  .description("Generate module-only schema, generate migration, then run migrate")
130
190
  .option("--keep-temp", "Keep temporary schema file after migration")
191
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
131
192
  .allowUnknownOption(true)
132
193
  .action(async (moduleName) => runModuleMigrate(moduleName, rawArgs));
133
194
  program
@@ -135,6 +196,7 @@ export function registerModuleCommands(program, rawArgs) {
135
196
  .description("Generate a unit test file for a module")
136
197
  .option("--force", "Overwrite existing test file")
137
198
  .option("--dry-run", "Print what would be created without executing")
199
+ .option("--path <panel>", "Address a module inside a panel folder (e.g. --path=admin)")
138
200
  .allowUnknownOption(true)
139
201
  .action(async (moduleName, name) => makeTest(moduleName, name, rawArgs.slice(name ? 3 : 2)));
140
202
  }
@@ -1,57 +1,69 @@
1
1
  import type { Handler } from "hono";
2
2
  import { HttpStatusCodes } from "@/framework/facade.js";
3
+ import { {{controller}}Service } from "@/modules/{{module}}/services/{{controller}}.js";
3
4
 
4
5
  /**
5
- * Why: Returns collection response shape for list pages.
6
+ * Why: Returns every {{controller}} row for list screens.
6
7
  * When: Used by GET list endpoint.
7
8
  * Where: GET /{{controller}} route.
8
9
  */
9
10
  export const index: Handler = async (c: any) => {
10
- return c.json({ message: "{{controller}} list fetched successfully", data: [] });
11
+ const data = await {{controller}}Service.list();
12
+
13
+ return c.json({ message: "{{controller}} list fetched successfully", data });
11
14
  };
12
15
 
13
16
  /**
14
- * Why: Returns one resource by validated route id.
17
+ * Why: Returns one {{controller}} row by validated route id.
15
18
  * When: Used by detail screens or fetch-by-id calls.
16
19
  * Where: GET /{{controller}}/{id} route.
17
20
  */
18
21
  export const show: Handler = async (c: any) => {
19
- const params = c.req.valid("param");
22
+ const { id } = c.req.valid("param");
23
+ const data = await {{controller}}Service.findOne(id);
24
+
25
+ if (!data) return c.json({ message: "{{controller}} not found" }, HttpStatusCodes.NOT_FOUND);
20
26
 
21
- return c.json({ message: "{{controller}} fetched successfully", data: { id: params.id, name: "" } });
27
+ return c.json({ message: "{{controller}} fetched successfully", data });
22
28
  };
23
29
 
24
30
  /**
25
- * Why: Creates a new resource from validated request body.
31
+ * Why: Creates a new {{controller}} row from a validated request body.
26
32
  * When: Used by create form submissions.
27
33
  * Where: POST /{{controller}} route.
28
34
  */
29
35
  export const store: Handler = async (c: any) => {
30
- c.req.valid("json");
36
+ const body = c.req.valid("json");
37
+ const data = await {{controller}}Service.create(body);
31
38
 
32
- return c.json({ message: "{{controller}} created successfully" }, HttpStatusCodes.CREATED);
39
+ return c.json({ message: "{{controller}} created successfully", data }, HttpStatusCodes.CREATED);
33
40
  };
34
41
 
35
42
  /**
36
- * Why: Updates an existing resource using id + body validation.
43
+ * Why: Updates an existing {{controller}} row using id + body validation.
37
44
  * When: Used by edit/update form submissions.
38
45
  * Where: PUT/PATCH /{{controller}}/{id} route.
39
46
  */
40
47
  export const update: Handler = async (c: any) => {
41
- c.req.valid("param");
42
- c.req.valid("json");
48
+ const { id } = c.req.valid("param");
49
+ const body = c.req.valid("json");
50
+ const data = await {{controller}}Service.update(id, body);
43
51
 
44
- return c.json({ message: "{{controller}} updated successfully" });
52
+ if (!data) return c.json({ message: "{{controller}} not found" }, HttpStatusCodes.NOT_FOUND);
53
+
54
+ return c.json({ message: "{{controller}} updated successfully", data });
45
55
  };
46
56
 
47
57
  /**
48
- * Why: Deletes one resource by validated route id.
58
+ * Why: Deletes one {{controller}} row by validated route id.
49
59
  * When: Used by delete actions.
50
60
  * Where: DELETE /{{controller}}/{id} route.
51
61
  */
52
62
  export const destroy: Handler = async (c: any) => {
53
- c.req.valid("param");
63
+ const { id } = c.req.valid("param");
64
+ const data = await {{controller}}Service.remove(id);
54
65
 
55
- return c.json({ message: "{{controller}} deleted successfully" });
56
- };
66
+ if (!data) return c.json({ message: "{{controller}} not found" }, HttpStatusCodes.NOT_FOUND);
57
67
 
68
+ return c.json({ message: "{{controller}} deleted successfully", data });
69
+ };
@@ -1,58 +1,69 @@
1
1
  import type { Handler } from "hono";
2
2
  import { HttpStatusCodes } from "@/framework/facade.js";
3
- import { {{tableVariable}} } from "@/modules/{{module}}/database/models/{{controller}}.js";
3
+ import { {{controller}}Service } from "@/modules/{{module}}/services/{{controller}}.js";
4
4
 
5
5
  /**
6
- * Why: Returns collection response shape for list pages.
6
+ * Why: Returns every {{controller}} row for list screens.
7
7
  * When: Used by GET list endpoint.
8
8
  * Where: GET /{{controller}} route.
9
9
  */
10
10
  export const index: Handler = async (c: any) => {
11
- return c.json({ message: "{{controller}} list fetched successfully", data: [] });
11
+ const data = await {{controller}}Service.list();
12
+
13
+ return c.json({ message: "{{controller}} list fetched successfully", data });
12
14
  };
13
15
 
14
16
  /**
15
- * Why: Returns one resource by validated route id.
17
+ * Why: Returns one {{controller}} row by validated route id.
16
18
  * When: Used by detail screens or fetch-by-id calls.
17
19
  * Where: GET /{{controller}}/{id} route.
18
20
  */
19
21
  export const show: Handler = async (c: any) => {
20
- const params = c.req.valid("param");
22
+ const { id } = c.req.valid("param");
23
+ const data = await {{controller}}Service.findOne(id);
24
+
25
+ if (!data) return c.json({ message: "{{controller}} not found" }, HttpStatusCodes.NOT_FOUND);
21
26
 
22
- return c.json({ message: "{{controller}} fetched successfully", data: { id: params.id, name: "" } });
27
+ return c.json({ message: "{{controller}} fetched successfully", data });
23
28
  };
24
29
 
25
30
  /**
26
- * Why: Creates a new resource from validated request body.
31
+ * Why: Creates a new {{controller}} row from a validated request body.
27
32
  * When: Used by create form submissions.
28
33
  * Where: POST /{{controller}} route.
29
34
  */
30
35
  export const store: Handler = async (c: any) => {
31
- c.req.valid("json");
36
+ const body = c.req.valid("json");
37
+ const data = await {{controller}}Service.create(body);
32
38
 
33
- return c.json({ message: "{{controller}} created successfully" }, HttpStatusCodes.CREATED);
39
+ return c.json({ message: "{{controller}} created successfully", data }, HttpStatusCodes.CREATED);
34
40
  };
35
41
 
36
42
  /**
37
- * Why: Updates an existing resource using id + body validation.
43
+ * Why: Updates an existing {{controller}} row using id + body validation.
38
44
  * When: Used by edit/update form submissions.
39
45
  * Where: PUT/PATCH /{{controller}}/{id} route.
40
46
  */
41
47
  export const update: Handler = async (c: any) => {
42
- c.req.valid("param");
43
- c.req.valid("json");
48
+ const { id } = c.req.valid("param");
49
+ const body = c.req.valid("json");
50
+ const data = await {{controller}}Service.update(id, body);
44
51
 
45
- return c.json({ message: "{{controller}} updated successfully" });
52
+ if (!data) return c.json({ message: "{{controller}} not found" }, HttpStatusCodes.NOT_FOUND);
53
+
54
+ return c.json({ message: "{{controller}} updated successfully", data });
46
55
  };
47
56
 
48
57
  /**
49
- * Why: Deletes one resource by validated route id.
58
+ * Why: Deletes one {{controller}} row by validated route id.
50
59
  * When: Used by delete actions.
51
60
  * Where: DELETE /{{controller}}/{id} route.
52
61
  */
53
62
  export const destroy: Handler = async (c: any) => {
54
- c.req.valid("param");
63
+ const { id } = c.req.valid("param");
64
+ const data = await {{controller}}Service.remove(id);
55
65
 
56
- return c.json({ message: "{{controller}} deleted successfully" });
57
- };
66
+ if (!data) return c.json({ message: "{{controller}} not found" }, HttpStatusCodes.NOT_FOUND);
58
67
 
68
+ return c.json({ message: "{{controller}} deleted successfully", data });
69
+ };
@@ -1,59 +1,71 @@
1
1
  import type { Handler } from "hono";
2
2
  import { HttpStatusCodes } from "@/framework/facade.js";
3
3
  import { validate } from "@/framework/facade.js";
4
- import { Create{{ClassName}}Schema, Update{{ClassName}}Schema, {{ClassName}}IdParamsSchema } from "@/modules/{{module}}/controllers/{{controller}}.schema.js";
4
+ import { Create{{ClassName}}Schema, Update{{ClassName}}Schema, {{ClassName}}IdParamsSchema } from "@/modules/{{module}}/schemas/{{controller}}.js";
5
+ import { {{controller}}Service } from "@/modules/{{module}}/services/{{controller}}.js";
5
6
 
6
7
  /**
7
- * Why: Returns collection response shape for list pages.
8
+ * Why: Returns every {{controller}} row for list screens.
8
9
  * When: Used by GET list endpoint.
9
10
  * Where: GET /{{controller}} route.
10
11
  */
11
12
  export const index: Handler = async (c: any) => {
12
- return c.json({ message: "{{controller}} list fetched successfully", data: [] });
13
+ const data = await {{controller}}Service.list();
14
+
15
+ return c.json({ message: "{{controller}} list fetched successfully", data });
13
16
  };
14
17
 
15
18
  /**
16
- * Why: Returns one resource by validated route id.
19
+ * Why: Returns one {{controller}} row by validated route id.
17
20
  * When: Used by detail screens or fetch-by-id calls.
18
21
  * Where: GET /{{controller}}/{id} route.
19
22
  */
20
23
  export const show: Handler = async (c: any) => {
21
24
  const params = await validate({{ClassName}}IdParamsSchema, c.req.param());
25
+ const data = await {{controller}}Service.findOne(params.id);
26
+
27
+ if (!data) return c.json({ message: "{{controller}} not found" }, HttpStatusCodes.NOT_FOUND);
22
28
 
23
- return c.json({ message: "{{controller}} fetched successfully", data: { id: params.id, name: "" } });
29
+ return c.json({ message: "{{controller}} fetched successfully", data });
24
30
  };
25
31
 
26
32
  /**
27
- * Why: Creates a new resource from validated request body.
33
+ * Why: Creates a new {{controller}} row from a validated request body.
28
34
  * When: Used by create form submissions.
29
35
  * Where: POST /{{controller}} route.
30
36
  */
31
37
  export const store: Handler = async (c: any) => {
32
- await validate(Create{{ClassName}}Schema, await c.req.json());
38
+ const body = await validate(Create{{ClassName}}Schema, await c.req.json());
39
+ const data = await {{controller}}Service.create(body);
33
40
 
34
- return c.json({ message: "{{controller}} created successfully" }, HttpStatusCodes.CREATED);
41
+ return c.json({ message: "{{controller}} created successfully", data }, HttpStatusCodes.CREATED);
35
42
  };
36
43
 
37
44
  /**
38
- * Why: Updates an existing resource using id + body validation.
45
+ * Why: Updates an existing {{controller}} row using id + body validation.
39
46
  * When: Used by edit/update form submissions.
40
47
  * Where: PUT/PATCH /{{controller}}/{id} route.
41
48
  */
42
49
  export const update: Handler = async (c: any) => {
43
- await validate({{ClassName}}IdParamsSchema, c.req.param());
44
- await validate(Update{{ClassName}}Schema, await c.req.json());
50
+ const params = await validate({{ClassName}}IdParamsSchema, c.req.param());
51
+ const body = await validate(Update{{ClassName}}Schema, await c.req.json());
52
+ const data = await {{controller}}Service.update(params.id, body);
45
53
 
46
- return c.json({ message: "{{controller}} updated successfully" });
54
+ if (!data) return c.json({ message: "{{controller}} not found" }, HttpStatusCodes.NOT_FOUND);
55
+
56
+ return c.json({ message: "{{controller}} updated successfully", data });
47
57
  };
48
58
 
49
59
  /**
50
- * Why: Deletes one resource by validated route id.
60
+ * Why: Deletes one {{controller}} row by validated route id.
51
61
  * When: Used by delete actions.
52
62
  * Where: DELETE /{{controller}}/{id} route.
53
63
  */
54
64
  export const destroy: Handler = async (c: any) => {
55
- await validate({{ClassName}}IdParamsSchema, c.req.param());
65
+ const params = await validate({{ClassName}}IdParamsSchema, c.req.param());
66
+ const data = await {{controller}}Service.remove(params.id);
56
67
 
57
- return c.json({ message: "{{controller}} deleted successfully" });
58
- };
68
+ if (!data) return c.json({ message: "{{controller}} not found" }, HttpStatusCodes.NOT_FOUND);
59
69
 
70
+ return c.json({ message: "{{controller}} deleted successfully", data });
71
+ };
@@ -0,0 +1,56 @@
1
+ import type { Handler } from "hono";
2
+ import { HttpStatusCodes } from "@/framework/facade.js";
3
+
4
+ /**
5
+ * Why: Returns collection response shape for list pages.
6
+ * When: Used by GET list endpoint.
7
+ * Where: GET /{{controller}} route.
8
+ */
9
+ export const index: Handler = async (c: any) => {
10
+ return c.json({ message: "{{controller}} list fetched successfully", data: [] });
11
+ };
12
+
13
+ /**
14
+ * Why: Returns one resource by validated route id.
15
+ * When: Used by detail screens or fetch-by-id calls.
16
+ * Where: GET /{{controller}}/{id} route.
17
+ */
18
+ export const show: Handler = async (c: any) => {
19
+ const params = c.req.valid("param");
20
+
21
+ return c.json({ message: "{{controller}} fetched successfully", data: { id: params.id, name: "" } });
22
+ };
23
+
24
+ /**
25
+ * Why: Creates a new resource from validated request body.
26
+ * When: Used by create form submissions.
27
+ * Where: POST /{{controller}} route.
28
+ */
29
+ export const store: Handler = async (c: any) => {
30
+ c.req.valid("json");
31
+
32
+ return c.json({ message: "{{controller}} created successfully" }, HttpStatusCodes.CREATED);
33
+ };
34
+
35
+ /**
36
+ * Why: Updates an existing resource using id + body validation.
37
+ * When: Used by edit/update form submissions.
38
+ * Where: PUT/PATCH /{{controller}}/{id} route.
39
+ */
40
+ export const update: Handler = async (c: any) => {
41
+ c.req.valid("param");
42
+ c.req.valid("json");
43
+
44
+ return c.json({ message: "{{controller}} updated successfully" });
45
+ };
46
+
47
+ /**
48
+ * Why: Deletes one resource by validated route id.
49
+ * When: Used by delete actions.
50
+ * Where: DELETE /{{controller}}/{id} route.
51
+ */
52
+ export const destroy: Handler = async (c: any) => {
53
+ c.req.valid("param");
54
+
55
+ return c.json({ message: "{{controller}} deleted successfully" });
56
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Public API for the {{module}} module.
3
+ *
4
+ * Other modules import from this file, never from controllers/ or services/ directly.
5
+ * Re-export the pieces they are allowed to depend on:
6
+ *
7
+ * export { list, findOne } from "./services/{{controller}}.js";
8
+ *
9
+ * Rule: a facade must never import another module's facade.
10
+ */
11
+
12
+ export {};
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Why: Reusable {{name}} logic that does not belong to a controller or service.
3
+ * When: Called by controllers, services, jobs, or other helpers.
4
+ * Where: src/modules/{{module}}/helpers/{{name}}.ts
5
+ */
6
+
7
+ /**
8
+ * Why: Placeholder shared helper.
9
+ * When: Replace this with real logic and rename it.
10
+ * Where: Anywhere inside the {{module}} module.
11
+ */
12
+ export function {{name}}Helper<T>(value: T): T {
13
+ return value;
14
+ }
@@ -0,0 +1,15 @@
1
+ import type { Context, Next } from "hono";
2
+
3
+ /**
4
+ * Why: Route-scoped middleware for the {{module}} module.
5
+ * When: Attach to a route or route group inside routes/*.ts.
6
+ * Where: src/modules/{{module}}/middlewares/{{name}}.ts
7
+ *
8
+ * Register it in a route file:
9
+ * import { {{camel}}Middleware } from "@/modules/{{module}}/middlewares/{{name}}.js";
10
+ * router.get("/path", {{camel}}Middleware, handler);
11
+ */
12
+ export async function {{camel}}Middleware(c: Context, next: Next) {
13
+ // Guard the route here, then continue the chain.
14
+ return await next();
15
+ }
@@ -1,9 +1,10 @@
1
- import { relations } from "drizzle-orm";
2
- import { int, mysqlTable, timestamp } from "drizzle-orm/mysql-core";
3
-
4
- export const {{tableVariable}} = mysqlTable("{{tableName}}", {
5
- id: int("id").autoincrement().primaryKey(),
6
- createdAt: timestamp("created_at").defaultNow().notNull(),
7
- updatedAt: timestamp("updated_at").defaultNow().notNull()
8
- });
1
+ import { relations } from "drizzle-orm";
2
+ import { int, mysqlTable, timestamp, varchar } from "drizzle-orm/mysql-core";
3
+
4
+ export const {{tableVariable}} = mysqlTable("{{tableName}}", {
5
+ id: int("id").autoincrement().primaryKey(),
6
+ name: varchar("name", { length: 255 }).notNull(),
7
+ createdAt: timestamp("created_at").defaultNow().notNull(),
8
+ updatedAt: timestamp("updated_at").defaultNow().notNull()
9
+ });
9
10
 
@@ -1,9 +1,10 @@
1
- import { relations } from "drizzle-orm";
2
- import { pgTable, serial, timestamp } from "drizzle-orm/pg-core";
3
-
4
- export const {{tableVariable}} = pgTable("{{tableName}}", {
5
- id: serial("id").primaryKey(),
6
- createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
7
- updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
8
- });
1
+ import { relations } from "drizzle-orm";
2
+ import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
3
+
4
+ export const {{tableVariable}} = pgTable("{{tableName}}", {
5
+ id: serial("id").primaryKey(),
6
+ name: text("name").notNull(),
7
+ createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
8
+ updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull()
9
+ });
9
10
 
@@ -1,9 +1,10 @@
1
- import { relations } from "drizzle-orm";
2
- import { integer, sqliteTable } from "drizzle-orm/sqlite-core";
3
-
4
- export const {{tableVariable}} = sqliteTable("{{tableName}}", {
5
- id: integer("id").primaryKey({ autoIncrement: true }),
6
- createdAt: integer("created_at", { mode: "timestamp" }).$defaultFn(() => new Date()).notNull(),
7
- updatedAt: integer("updated_at", { mode: "timestamp" }).$defaultFn(() => new Date()).notNull()
8
- });
1
+ import { relations } from "drizzle-orm";
2
+ import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";
3
+
4
+ export const {{tableVariable}} = sqliteTable("{{tableName}}", {
5
+ id: integer("id").primaryKey({ autoIncrement: true }),
6
+ name: text("name").notNull(),
7
+ createdAt: integer("created_at", { mode: "timestamp" }).$defaultFn(() => new Date()).notNull(),
8
+ updatedAt: integer("updated_at", { mode: "timestamp" }).$defaultFn(() => new Date()).notNull()
9
+ });
9
10