@forinda/kickjs-cli 2.0.1 → 2.2.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 (118) hide show
  1. package/bin.js +8 -0
  2. package/dist/cli.mjs +6550 -0
  3. package/dist/index.d.mts +302 -0
  4. package/dist/index.d.mts.map +1 -0
  5. package/dist/index.mjs +3627 -0
  6. package/dist/index.mjs.map +1 -0
  7. package/dist/typegen-DCnJdqP1.mjs +886 -0
  8. package/dist/typegen-DCnJdqP1.mjs.map +1 -0
  9. package/package.json +31 -13
  10. package/dist/cli.d.ts +0 -2
  11. package/dist/cli.d.ts.map +0 -1
  12. package/dist/cli.js +0 -1552
  13. package/dist/commands/add.d.ts +0 -5
  14. package/dist/commands/add.d.ts.map +0 -1
  15. package/dist/commands/custom.d.ts +0 -56
  16. package/dist/commands/custom.d.ts.map +0 -1
  17. package/dist/commands/generate.d.ts +0 -3
  18. package/dist/commands/generate.d.ts.map +0 -1
  19. package/dist/commands/info.d.ts +0 -3
  20. package/dist/commands/info.d.ts.map +0 -1
  21. package/dist/commands/init.d.ts +0 -3
  22. package/dist/commands/init.d.ts.map +0 -1
  23. package/dist/commands/inspect.d.ts +0 -3
  24. package/dist/commands/inspect.d.ts.map +0 -1
  25. package/dist/commands/remove.d.ts +0 -3
  26. package/dist/commands/remove.d.ts.map +0 -1
  27. package/dist/commands/run.d.ts +0 -3
  28. package/dist/commands/run.d.ts.map +0 -1
  29. package/dist/commands/tinker.d.ts +0 -3
  30. package/dist/commands/tinker.d.ts.map +0 -1
  31. package/dist/config-D9faxBLQ.js +0 -3108
  32. package/dist/config.d.ts +0 -131
  33. package/dist/config.d.ts.map +0 -1
  34. package/dist/generators/adapter.d.ts +0 -7
  35. package/dist/generators/adapter.d.ts.map +0 -1
  36. package/dist/generators/config.d.ts +0 -9
  37. package/dist/generators/config.d.ts.map +0 -1
  38. package/dist/generators/controller.d.ts +0 -11
  39. package/dist/generators/controller.d.ts.map +0 -1
  40. package/dist/generators/dto.d.ts +0 -11
  41. package/dist/generators/dto.d.ts.map +0 -1
  42. package/dist/generators/guard.d.ts +0 -11
  43. package/dist/generators/guard.d.ts.map +0 -1
  44. package/dist/generators/job.d.ts +0 -8
  45. package/dist/generators/job.d.ts.map +0 -1
  46. package/dist/generators/middleware.d.ts +0 -11
  47. package/dist/generators/middleware.d.ts.map +0 -1
  48. package/dist/generators/module.d.ts +0 -33
  49. package/dist/generators/module.d.ts.map +0 -1
  50. package/dist/generators/patterns/cqrs.d.ts +0 -3
  51. package/dist/generators/patterns/cqrs.d.ts.map +0 -1
  52. package/dist/generators/patterns/ddd.d.ts +0 -3
  53. package/dist/generators/patterns/ddd.d.ts.map +0 -1
  54. package/dist/generators/patterns/index.d.ts +0 -6
  55. package/dist/generators/patterns/index.d.ts.map +0 -1
  56. package/dist/generators/patterns/minimal.d.ts +0 -3
  57. package/dist/generators/patterns/minimal.d.ts.map +0 -1
  58. package/dist/generators/patterns/rest.d.ts +0 -3
  59. package/dist/generators/patterns/rest.d.ts.map +0 -1
  60. package/dist/generators/patterns/types.d.ts +0 -15
  61. package/dist/generators/patterns/types.d.ts.map +0 -1
  62. package/dist/generators/project.d.ts +0 -14
  63. package/dist/generators/project.d.ts.map +0 -1
  64. package/dist/generators/remove-module.d.ts +0 -12
  65. package/dist/generators/remove-module.d.ts.map +0 -1
  66. package/dist/generators/resolver.d.ts +0 -7
  67. package/dist/generators/resolver.d.ts.map +0 -1
  68. package/dist/generators/scaffold.d.ts +0 -20
  69. package/dist/generators/scaffold.d.ts.map +0 -1
  70. package/dist/generators/service.d.ts +0 -11
  71. package/dist/generators/service.d.ts.map +0 -1
  72. package/dist/generators/templates/constants.d.ts +0 -3
  73. package/dist/generators/templates/constants.d.ts.map +0 -1
  74. package/dist/generators/templates/controller.d.ts +0 -6
  75. package/dist/generators/templates/controller.d.ts.map +0 -1
  76. package/dist/generators/templates/cqrs.d.ts +0 -23
  77. package/dist/generators/templates/cqrs.d.ts.map +0 -1
  78. package/dist/generators/templates/domain.d.ts +0 -5
  79. package/dist/generators/templates/domain.d.ts.map +0 -1
  80. package/dist/generators/templates/drizzle/index.d.ts +0 -4
  81. package/dist/generators/templates/drizzle/index.d.ts.map +0 -1
  82. package/dist/generators/templates/dtos.d.ts +0 -5
  83. package/dist/generators/templates/dtos.d.ts.map +0 -1
  84. package/dist/generators/templates/index.d.ts +0 -14
  85. package/dist/generators/templates/index.d.ts.map +0 -1
  86. package/dist/generators/templates/module-index.d.ts +0 -13
  87. package/dist/generators/templates/module-index.d.ts.map +0 -1
  88. package/dist/generators/templates/prisma/index.d.ts +0 -3
  89. package/dist/generators/templates/prisma/index.d.ts.map +0 -1
  90. package/dist/generators/templates/project-app.d.ts +0 -9
  91. package/dist/generators/templates/project-app.d.ts.map +0 -1
  92. package/dist/generators/templates/project-config.d.ts +0 -23
  93. package/dist/generators/templates/project-config.d.ts.map +0 -1
  94. package/dist/generators/templates/project-docs.d.ts +0 -9
  95. package/dist/generators/templates/project-docs.d.ts.map +0 -1
  96. package/dist/generators/templates/repository.d.ts +0 -5
  97. package/dist/generators/templates/repository.d.ts.map +0 -1
  98. package/dist/generators/templates/rest-service.d.ts +0 -6
  99. package/dist/generators/templates/rest-service.d.ts.map +0 -1
  100. package/dist/generators/templates/tests.d.ts +0 -4
  101. package/dist/generators/templates/tests.d.ts.map +0 -1
  102. package/dist/generators/templates/types.d.ts +0 -20
  103. package/dist/generators/templates/types.d.ts.map +0 -1
  104. package/dist/generators/templates/use-cases.d.ts +0 -6
  105. package/dist/generators/templates/use-cases.d.ts.map +0 -1
  106. package/dist/generators/test.d.ts +0 -9
  107. package/dist/generators/test.d.ts.map +0 -1
  108. package/dist/index.d.ts +0 -12
  109. package/dist/index.d.ts.map +0 -1
  110. package/dist/index.js +0 -17
  111. package/dist/utils/fs.d.ts +0 -11
  112. package/dist/utils/fs.d.ts.map +0 -1
  113. package/dist/utils/naming.d.ts +0 -18
  114. package/dist/utils/naming.d.ts.map +0 -1
  115. package/dist/utils/resolve-out-dir.d.ts +0 -25
  116. package/dist/utils/resolve-out-dir.d.ts.map +0 -1
  117. package/dist/utils/shell.d.ts +0 -3
  118. package/dist/utils/shell.d.ts.map +0 -1
package/dist/cli.js DELETED
@@ -1,1552 +0,0 @@
1
- #!/usr/bin/env node
2
- import { _ as E, a as ee, b as P, c as te, d as oe, f as re, g as S, h as L, i as ne, l as ie, m as se, n as w, o as ae, p as _, r as R, s as ce, u as de, v as M, y as $ } from "./config-D9faxBLQ.js";
3
- import { basename as pe, dirname as le, join as g, resolve as m } from "node:path";
4
- import { createInterface as N } from "node:readline";
5
- import { readFile as B, rm as me, writeFile as W } from "node:fs/promises";
6
- import { execSync as q, fork as ue } from "node:child_process";
7
- import { cpSync as fe, existsSync as j, mkdirSync as ge, readFileSync as $e, readdirSync as ye, rmSync as he } from "node:fs";
8
- import { fileURLToPath as we, pathToFileURL as ke } from "node:url";
9
- import { Command as ve } from "commander";
10
- import { arch as De, platform as Re, release as xe } from "node:os";
11
- function U(e, t) {
12
- const r = N({
13
- input: process.stdin,
14
- output: process.stdout
15
- }), o = t ? ` (${t})` : "";
16
- return new Promise((n) => {
17
- r.question(` ${e}${o}: `, (i) => {
18
- r.close(), n(i.trim() || t || "");
19
- });
20
- });
21
- }
22
- async function A(e, t, r = 0) {
23
- console.log(` ${e}`);
24
- for (let n = 0; n < t.length; n++) console.log(` ${n === r ? ">" : " "} ${n + 1}. ${t[n]}`);
25
- const o = await U("Choose", String(r + 1));
26
- return t[parseInt(o, 10) - 1] ?? t[r];
27
- }
28
- async function z(e, t = !0) {
29
- const r = await U(`${e} (${t ? "Y/n" : "y/N"})`);
30
- return r ? r.toLowerCase().startsWith("y") : t;
31
- }
32
- function Ce(e) {
33
- e.command("new [name]").alias("init").description('Create a new KickJS project (use "." for current directory)').option("-d, --directory <dir>", "Target directory (defaults to project name)").option("--pm <manager>", "Package manager: pnpm | npm | yarn").option("--git", "Initialize git repository").option("--no-git", "Skip git initialization").option("--install", "Install dependencies after scaffolding").option("--no-install", "Skip dependency installation").option("-f, --force", "Remove existing files without prompting").option("-t, --template <type>", "Project template: rest | graphql | ddd | cqrs | minimal").option("-r, --repo <type>", "Default repository: prisma | drizzle | inmemory | custom").action(async (t, r) => {
34
- console.log(), t || (t = await U("Project name", "my-api"));
35
- let o;
36
- if (t === "." ? (o = m("."), t = pe(o)) : o = m(r.directory || t), j(o)) {
37
- const d = ye(o);
38
- if (d.length > 0) {
39
- if (r.force) console.log(` Clearing existing files in ${o}...
40
- `);
41
- else {
42
- console.log(` Directory "${t}" is not empty:`);
43
- const p = d.slice(0, 5);
44
- for (const l of p) console.log(` - ${l}`);
45
- if (d.length > 5 && console.log(` ... and ${d.length - 5} more`), console.log(), !await z("Remove all existing files and proceed?", !1)) {
46
- console.log(` Aborted.
47
- `);
48
- return;
49
- }
50
- }
51
- for (const p of d) he(m(o, p), {
52
- recursive: !0,
53
- force: !0
54
- });
55
- }
56
- }
57
- let n = r.template;
58
- n || (n = await A("Project template:", [
59
- "REST API (Express + Swagger)",
60
- "GraphQL API (GraphQL + GraphiQL)",
61
- "DDD (Domain-Driven Design modules)",
62
- "CQRS (Commands, Queries, Events + WS/Queue)",
63
- "Minimal (bare Express)"
64
- ], 0), n = {
65
- "REST API (Express + Swagger)": "rest",
66
- "GraphQL API (GraphQL + GraphiQL)": "graphql",
67
- "DDD (Domain-Driven Design modules)": "ddd",
68
- "CQRS (Commands, Queries, Events + WS/Queue)": "cqrs",
69
- "Minimal (bare Express)": "minimal"
70
- }[n] ?? "rest");
71
- let i = r.pm;
72
- i || (i = await A("Package manager:", [
73
- "pnpm",
74
- "npm",
75
- "yarn"
76
- ], 0));
77
- let s = r.repo;
78
- if (!s) {
79
- const d = await A("Default repository/ORM:", [
80
- "Prisma",
81
- "Drizzle",
82
- "In-Memory",
83
- "Custom (specify later)"
84
- ], 0);
85
- s = {
86
- Prisma: "prisma",
87
- Drizzle: "drizzle",
88
- "In-Memory": "inmemory",
89
- "Custom (specify later)": "custom"
90
- }[d] ?? "inmemory", s === "custom" && (s = await U("Custom repository name", "custom"));
91
- }
92
- let a;
93
- r.git === void 0 ? a = await z("Initialize git repository?", !0) : a = r.git;
94
- let c;
95
- r.install === void 0 ? c = await z("Install dependencies?", !0) : c = r.install, await ne({
96
- name: t,
97
- directory: o,
98
- packageManager: i,
99
- initGit: a,
100
- installDeps: c,
101
- template: n,
102
- defaultRepo: s
103
- });
104
- });
105
- }
106
- async function je(e) {
107
- const t = N({
108
- input: process.stdin,
109
- output: process.stdout
110
- });
111
- return new Promise((r) => {
112
- t.question(` ${e} (y/N) `, (o) => {
113
- t.close(), r(o.trim().toLowerCase() === "y");
114
- });
115
- });
116
- }
117
- async function Se(e) {
118
- const t = g(e.outDir, "kick.config.ts"), r = e.modulesDir ?? "src/modules", o = e.defaultRepo ?? "inmemory";
119
- return j(t) && !e.force && !await je("kick.config.ts already exists. Overwrite?") ? (console.log(`
120
- Skipped — existing kick.config.ts preserved.`), []) : (await P(t, `import { defineConfig } from '@forinda/kickjs-cli'
121
-
122
- export default defineConfig({
123
- modulesDir: '${r}',
124
- defaultRepo: '${o}',
125
-
126
- commands: [
127
- {
128
- name: 'test',
129
- description: 'Run tests with Vitest',
130
- steps: 'npx vitest run',
131
- },
132
- {
133
- name: 'format',
134
- description: 'Format code with Prettier',
135
- steps: 'npx prettier --write src/',
136
- },
137
- {
138
- name: 'format:check',
139
- description: 'Check formatting without writing',
140
- steps: 'npx prettier --check src/',
141
- },
142
- {
143
- name: 'check',
144
- description: 'Run typecheck + format check',
145
- steps: ['npx tsc --noEmit', 'npx prettier --check src/'],
146
- aliases: ['verify', 'ci'],
147
- },
148
- ],
149
- })
150
- `), [t]);
151
- }
152
- async function Pe(e) {
153
- const { name: t, outDir: r } = e, o = E(t), n = S(t), i = L(t), s = [], a = async (c, d) => {
154
- const p = g(r, c);
155
- await P(p, d), s.push(p);
156
- };
157
- return await a(`${n}.resolver.ts`, `import { Service } from '@forinda/kickjs'
158
- import { Resolver, Query, Mutation, Arg } from '@forinda/kickjs-graphql'
159
-
160
- /**
161
- * ${o} GraphQL Resolver
162
- *
163
- * Decorators:
164
- * @Resolver(typeName?) — marks this class as a GraphQL resolver
165
- * @Query(name?, { returnType?, description? }) — defines a query field
166
- * @Mutation(name?, { returnType?, description? }) — defines a mutation field
167
- * @Arg(name, type?) — marks a method parameter as a GraphQL argument
168
- */
169
- @Service()
170
- @Resolver('${o}')
171
- export class ${o}Resolver {
172
- private items: Array<{ id: string; name: string }> = []
173
-
174
- @Query('${i}s', { returnType: '[${o}]', description: 'List all ${i}s' })
175
- findAll() {
176
- return this.items
177
- }
178
-
179
- @Query('${i}', { returnType: '${o}', description: 'Get a ${i} by ID' })
180
- findById(@Arg('id', 'ID!') id: string) {
181
- return this.items.find((item) => item.id === id) ?? null
182
- }
183
-
184
- @Mutation('create${o}', { returnType: '${o}', description: 'Create a new ${i}' })
185
- create(@Arg('name', 'String!') name: string) {
186
- const item = { id: String(this.items.length + 1), name }
187
- this.items.push(item)
188
- return item
189
- }
190
-
191
- @Mutation('update${o}', { returnType: '${o}', description: 'Update a ${i}' })
192
- update(@Arg('id', 'ID!') id: string, @Arg('name', 'String!') name: string) {
193
- const item = this.items.find((i) => i.id === id)
194
- if (item) item.name = name
195
- return item
196
- }
197
-
198
- @Mutation('delete${o}', { returnType: 'Boolean', description: 'Delete a ${i}' })
199
- remove(@Arg('id', 'ID!') id: string) {
200
- const idx = this.items.findIndex((i) => i.id === id)
201
- if (idx === -1) return false
202
- this.items.splice(idx, 1)
203
- return true
204
- }
205
- }
206
- `), await a(`${n}.typedefs.ts`, `/**
207
- * ${o} GraphQL type definitions.
208
- * Pass to GraphQLAdapter's typeDefs option to register custom types.
209
- */
210
- export const ${i}TypeDefs = \`
211
- type ${o} {
212
- id: ID!
213
- name: String!
214
- }
215
- \`
216
- `), s;
217
- }
218
- async function Ie(e) {
219
- const { name: t, outDir: r } = e, o = E(t), n = S(t), i = L(t), s = e.queue ?? `${n}-queue`, a = [];
220
- return await (async (d, p) => {
221
- const l = g(r, d);
222
- await P(l, p), a.push(l);
223
- })(`${n}.job.ts`, `import { Inject } from '@forinda/kickjs'
224
- import { Job, Process, QUEUE_MANAGER, type QueueService } from '@forinda/kickjs-queue'
225
-
226
- /**
227
- * ${o} Job Processor
228
- *
229
- * Decorators:
230
- * @Job(queueName) — marks this class as a job processor for a queue
231
- * @Process(jobName?) — marks a method as the handler for a specific job type
232
- * - Without a name: handles all jobs in the queue
233
- * - With a name: handles only jobs matching that name
234
- *
235
- * To add jobs to this queue from a service or controller:
236
- * @Inject(QUEUE_MANAGER) private queue: QueueService
237
- * await this.queue.add('${s}', '${i}', { ... })
238
- */
239
- @Job('${s}')
240
- export class ${o}Job {
241
- @Process()
242
- async handle(job: { name: string; data: any; id?: string }) {
243
- console.log(\`Processing \${job.name} (id: \${job.id})\`, job.data)
244
-
245
- // TODO: Implement job logic here
246
- // Example:
247
- // await this.emailService.send(job.data.to, job.data.subject, job.data.body)
248
- }
249
-
250
- @Process('${i}.priority')
251
- async handlePriority(job: { name: string; data: any; id?: string }) {
252
- console.log(\`Priority job: \${job.name}\`, job.data)
253
- // Handle high-priority variant of this job
254
- }
255
- }
256
- `), a;
257
- }
258
- var F = {
259
- string: {
260
- ts: "string",
261
- zod: "z.string()"
262
- },
263
- text: {
264
- ts: "string",
265
- zod: "z.string()"
266
- },
267
- number: {
268
- ts: "number",
269
- zod: "z.number()"
270
- },
271
- int: {
272
- ts: "number",
273
- zod: "z.number().int()"
274
- },
275
- float: {
276
- ts: "number",
277
- zod: "z.number()"
278
- },
279
- boolean: {
280
- ts: "boolean",
281
- zod: "z.boolean()"
282
- },
283
- date: {
284
- ts: "string",
285
- zod: "z.string().datetime()"
286
- },
287
- email: {
288
- ts: "string",
289
- zod: "z.string().email()"
290
- },
291
- url: {
292
- ts: "string",
293
- zod: "z.string().url()"
294
- },
295
- uuid: {
296
- ts: "string",
297
- zod: "z.string().uuid()"
298
- },
299
- json: {
300
- ts: "any",
301
- zod: "z.any()"
302
- }
303
- };
304
- function Oe(e) {
305
- return e.map((t) => {
306
- const r = t.indexOf(":");
307
- if (r === -1) throw new Error(`Invalid field: "${t}". Use format: name:type (e.g. title:string)`);
308
- const o = t.slice(0, r), n = t.slice(r + 1);
309
- if (!o || !n) throw new Error(`Invalid field: "${t}". Use format: name:type (e.g. title:string)`);
310
- const i = n.endsWith("?"), s = i ? n.slice(0, -1) : n;
311
- if (s.startsWith("enum:")) {
312
- const c = s.slice(5).split(",");
313
- return {
314
- name: o,
315
- type: "enum",
316
- tsType: c.map((d) => `'${d}'`).join(" | "),
317
- zodType: `z.enum([${c.map((d) => `'${d}'`).join(", ")}])`,
318
- optional: i
319
- };
320
- }
321
- const a = F[s];
322
- if (!a) {
323
- const c = [...Object.keys(F), "enum:a,b,c"].join(", ");
324
- throw new Error(`Unknown field type: "${s}". Valid types: ${c}`);
325
- }
326
- return {
327
- name: o,
328
- type: s,
329
- tsType: a.ts,
330
- zodType: a.zod,
331
- optional: i
332
- };
333
- });
334
- }
335
- async function Te(e) {
336
- const { name: t, fields: r, modulesDir: o, noEntity: n, noTests: i, repo: s = "inmemory" } = e, a = e.pluralize !== !1, c = S(t), d = E(t);
337
- L(t);
338
- const p = a ? _(c) : c, l = a ? se(d) : d, f = g(o, p), v = [], u = async (b, X) => {
339
- const H = g(f, b);
340
- await P(H, X), v.push(H);
341
- };
342
- await u("index.ts", Ge(d, c, p, s)), await u("constants.ts", Ae(d, r)), await u(`presentation/${c}.controller.ts`, Qe(d, c, p, l)), await u(`application/dtos/create-${c}.dto.ts`, Ee(d, r)), await u(`application/dtos/update-${c}.dto.ts`, be(d, r)), await u(`application/dtos/${c}-response.dto.ts`, Ue(d, r));
343
- const I = Ne(d, c, p, l);
344
- for (const b of I) await u(`application/use-cases/${b.file}`, b.content);
345
- return await u(`domain/repositories/${c}.repository.ts`, Le(d, c)), await u(`domain/services/${c}-domain.service.ts`, _e(d, c)), s === "inmemory" && await u(`infrastructure/repositories/in-memory-${c}.repository.ts`, ze(d, c, r)), n || (await u(`domain/entities/${c}.entity.ts`, Me(d, c, r)), await u(`domain/value-objects/${c}-id.vo.ts`, qe(d))), await He(o, d, p), v;
346
- }
347
- function Ee(e, t) {
348
- return `import { z } from 'zod'
349
-
350
- export const create${e}Schema = z.object({
351
- ${t.map((r) => {
352
- const o = r.zodType;
353
- return ` ${r.name}: ${o}${r.optional ? ".optional()" : ""},`;
354
- }).join(`
355
- `)}
356
- })
357
-
358
- export type Create${e}DTO = z.infer<typeof create${e}Schema>
359
- `;
360
- }
361
- function be(e, t) {
362
- return `import { z } from 'zod'
363
-
364
- export const update${e}Schema = z.object({
365
- ${t.map((r) => ` ${r.name}: ${r.zodType}.optional(),`).join(`
366
- `)}
367
- })
368
-
369
- export type Update${e}DTO = z.infer<typeof update${e}Schema>
370
- `;
371
- }
372
- function Ue(e, t) {
373
- return `export interface ${e}ResponseDTO {
374
- id: string
375
- ${t.map((r) => ` ${r.name}${r.optional ? "?" : ""}: ${r.tsType}`).join(`
376
- `)}
377
- createdAt: string
378
- updatedAt: string
379
- }
380
- `;
381
- }
382
- function Ae(e, t) {
383
- const r = t.filter((a) => a.tsType === "string").map((a) => `'${a.name}'`);
384
- t.filter((a) => a.tsType === "number").map((a) => `'${a.name}'`);
385
- const o = t.map((a) => `'${a.name}'`), n = [...o].join(", "), i = [
386
- ...o,
387
- "'createdAt'",
388
- "'updatedAt'"
389
- ].join(", "), s = r.length > 0 ? r.join(", ") : "'name'";
390
- return `import type { ApiQueryParamsConfig } from '@forinda/kickjs'
391
-
392
- export const ${e.toUpperCase()}_QUERY_CONFIG: ApiQueryParamsConfig = {
393
- filterable: [${n}],
394
- sortable: [${i}],
395
- searchable: [${s}],
396
- }
397
- `;
398
- }
399
- function ze(e, t, r) {
400
- return `import { randomUUID } from 'node:crypto'
401
- import { Repository, HttpException } from '@forinda/kickjs'
402
- import type { ParsedQuery } from '@forinda/kickjs'
403
- import type { I${e}Repository } from '../../domain/repositories/${t}.repository'
404
- import type { ${e}ResponseDTO } from '../../application/dtos/${t}-response.dto'
405
- import type { Create${e}DTO } from '../../application/dtos/create-${t}.dto'
406
- import type { Update${e}DTO } from '../../application/dtos/update-${t}.dto'
407
-
408
- @Repository()
409
- export class InMemory${e}Repository implements I${e}Repository {
410
- private store = new Map<string, ${e}ResponseDTO>()
411
-
412
- async findById(id: string): Promise<${e}ResponseDTO | null> {
413
- return this.store.get(id) ?? null
414
- }
415
-
416
- async findAll(): Promise<${e}ResponseDTO[]> {
417
- return Array.from(this.store.values())
418
- }
419
-
420
- async findPaginated(parsed: ParsedQuery): Promise<{ data: ${e}ResponseDTO[]; total: number }> {
421
- const all = Array.from(this.store.values())
422
- const data = all.slice(parsed.pagination.offset, parsed.pagination.offset + parsed.pagination.limit)
423
- return { data, total: all.length }
424
- }
425
-
426
- async create(dto: Create${e}DTO): Promise<${e}ResponseDTO> {
427
- const now = new Date().toISOString()
428
- const entity: ${e}ResponseDTO = {
429
- id: randomUUID(),
430
- ${r.map((o) => ` ${o.name}: dto.${o.name},`).join(`
431
- `)}
432
- createdAt: now,
433
- updatedAt: now,
434
- }
435
- this.store.set(entity.id, entity)
436
- return entity
437
- }
438
-
439
- async update(id: string, dto: Update${e}DTO): Promise<${e}ResponseDTO> {
440
- const existing = this.store.get(id)
441
- if (!existing) throw HttpException.notFound('${e} not found')
442
- const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }
443
- this.store.set(id, updated)
444
- return updated
445
- }
446
-
447
- async delete(id: string): Promise<void> {
448
- if (!this.store.has(id)) throw HttpException.notFound('${e} not found')
449
- this.store.delete(id)
450
- }
451
- }
452
- `;
453
- }
454
- function Me(e, t, r) {
455
- return `import { ${e}Id } from '../value-objects/${t}-id.vo'
456
-
457
- interface ${e}Props {
458
- id: ${e}Id
459
- ${r.map((o) => ` ${o.name}${o.optional ? "?" : ""}: ${o.tsType}`).join(`
460
- `)}
461
- createdAt: Date
462
- updatedAt: Date
463
- }
464
-
465
- export class ${e} {
466
- private constructor(private props: ${e}Props) {}
467
-
468
- static create(params: { ${r.filter((o) => !o.optional).map((o) => `${o.name}: ${o.tsType}`).join("; ")} }): ${e} {
469
- const now = new Date()
470
- return new ${e}({
471
- id: ${e}Id.create(),
472
- ${r.filter((o) => !o.optional).map((o) => ` ${o.name}: params.${o.name},`).join(`
473
- `)}
474
- createdAt: now,
475
- updatedAt: now,
476
- })
477
- }
478
-
479
- static reconstitute(props: ${e}Props): ${e} {
480
- return new ${e}(props)
481
- }
482
-
483
- get id(): ${e}Id { return this.props.id }
484
- ${r.map((o) => ` get ${o.name}(): ${o.tsType}${o.optional ? " | undefined" : ""} {
485
- return this.props.${o.name}
486
- }`).join(`
487
- `)}
488
- get createdAt(): Date { return this.props.createdAt }
489
- get updatedAt(): Date { return this.props.updatedAt }
490
-
491
- toJSON() {
492
- return {
493
- id: this.props.id.toString(),
494
- ${r.map((o) => ` ${o.name}: this.props.${o.name},`).join(`
495
- `)}
496
- createdAt: this.props.createdAt.toISOString(),
497
- updatedAt: this.props.updatedAt.toISOString(),
498
- }
499
- }
500
- }
501
- `;
502
- }
503
- function qe(e) {
504
- return `import { randomUUID } from 'node:crypto'
505
-
506
- export class ${e}Id {
507
- private constructor(private readonly value: string) {}
508
-
509
- static create(): ${e}Id { return new ${e}Id(randomUUID()) }
510
-
511
- static from(id: string): ${e}Id {
512
- if (!id || id.trim().length === 0) throw new Error('${e}Id cannot be empty')
513
- return new ${e}Id(id)
514
- }
515
-
516
- toString(): string { return this.value }
517
- equals(other: ${e}Id): boolean { return this.value === other.value }
518
- }
519
- `;
520
- }
521
- function Ge(e, t, r, o) {
522
- return `import type { AppModule, AppModuleClass } from '@forinda/kickjs'
523
- import { ${e}Controller } from './presentation/${t}.controller'
524
- import { ${e}DomainService } from './domain/services/${t}-domain.service'
525
- import { ${e.toUpperCase()}_REPOSITORY } from './domain/repositories/${t}.repository'
526
- import { InMemory${e}Repository } from './infrastructure/repositories/in-memory-${t}.repository'
527
-
528
- export class ${e}Module implements AppModule {
529
- register(container: any): void {
530
- container.registerFactory(
531
- ${e.toUpperCase()}_REPOSITORY,
532
- () => container.resolve(InMemory${e}Repository),
533
- )
534
- }
535
-
536
- routes() {
537
- return { prefix: '/${r}', controllers: [${e}Controller] }
538
- }
539
- }
540
- `;
541
- }
542
- function Qe(e, t, r, o) {
543
- return `import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams } from '@forinda/kickjs'
544
- import type { RequestContext } from '@forinda/kickjs'
545
- import { ApiTags } from '@forinda/kickjs-swagger'
546
- import { Create${e}UseCase } from '../application/use-cases/create-${t}.use-case'
547
- import { Get${e}UseCase } from '../application/use-cases/get-${t}.use-case'
548
- import { List${o}UseCase } from '../application/use-cases/list-${r}.use-case'
549
- import { Update${e}UseCase } from '../application/use-cases/update-${t}.use-case'
550
- import { Delete${e}UseCase } from '../application/use-cases/delete-${t}.use-case'
551
- import { create${e}Schema } from '../application/dtos/create-${t}.dto'
552
- import { update${e}Schema } from '../application/dtos/update-${t}.dto'
553
- import { ${e.toUpperCase()}_QUERY_CONFIG } from '../constants'
554
-
555
- @Controller()
556
- export class ${e}Controller {
557
- @Autowired() private create${e}UseCase!: Create${e}UseCase
558
- @Autowired() private get${e}UseCase!: Get${e}UseCase
559
- @Autowired() private list${o}UseCase!: List${o}UseCase
560
- @Autowired() private update${e}UseCase!: Update${e}UseCase
561
- @Autowired() private delete${e}UseCase!: Delete${e}UseCase
562
-
563
- @Get('/')
564
- @ApiTags('${e}')
565
- @ApiQueryParams(${e.toUpperCase()}_QUERY_CONFIG)
566
- async list(ctx: RequestContext) {
567
- return ctx.paginate(
568
- (parsed) => this.list${o}UseCase.execute(parsed),
569
- ${e.toUpperCase()}_QUERY_CONFIG,
570
- )
571
- }
572
-
573
- @Get('/:id')
574
- @ApiTags('${e}')
575
- async getById(ctx: RequestContext) {
576
- const result = await this.get${e}UseCase.execute(ctx.params.id)
577
- if (!result) return ctx.notFound('${e} not found')
578
- ctx.json(result)
579
- }
580
-
581
- @Post('/', { body: create${e}Schema, name: 'Create${e}' })
582
- @ApiTags('${e}')
583
- async create(ctx: RequestContext) {
584
- const result = await this.create${e}UseCase.execute(ctx.body)
585
- ctx.created(result)
586
- }
587
-
588
- @Put('/:id', { body: update${e}Schema, name: 'Update${e}' })
589
- @ApiTags('${e}')
590
- async update(ctx: RequestContext) {
591
- const result = await this.update${e}UseCase.execute(ctx.params.id, ctx.body)
592
- ctx.json(result)
593
- }
594
-
595
- @Delete('/:id')
596
- @ApiTags('${e}')
597
- async remove(ctx: RequestContext) {
598
- await this.delete${e}UseCase.execute(ctx.params.id)
599
- ctx.noContent()
600
- }
601
- }
602
- `;
603
- }
604
- function Le(e, t) {
605
- return `import type { ${e}ResponseDTO } from '../../application/dtos/${t}-response.dto'
606
- import type { Create${e}DTO } from '../../application/dtos/create-${t}.dto'
607
- import type { Update${e}DTO } from '../../application/dtos/update-${t}.dto'
608
- import type { ParsedQuery } from '@forinda/kickjs'
609
-
610
- export interface I${e}Repository {
611
- findById(id: string): Promise<${e}ResponseDTO | null>
612
- findAll(): Promise<${e}ResponseDTO[]>
613
- findPaginated(parsed: ParsedQuery): Promise<{ data: ${e}ResponseDTO[]; total: number }>
614
- create(dto: Create${e}DTO): Promise<${e}ResponseDTO>
615
- update(id: string, dto: Update${e}DTO): Promise<${e}ResponseDTO>
616
- delete(id: string): Promise<void>
617
- }
618
-
619
- export const ${e.toUpperCase()}_REPOSITORY = Symbol('I${e}Repository')
620
- `;
621
- }
622
- function _e(e, t) {
623
- return `import { Service, Inject, HttpException } from '@forinda/kickjs'
624
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../repositories/${t}.repository'
625
-
626
- @Service()
627
- export class ${e}DomainService {
628
- constructor(
629
- @Inject(${e.toUpperCase()}_REPOSITORY) private readonly repo: I${e}Repository,
630
- ) {}
631
-
632
- async ensureExists(id: string): Promise<void> {
633
- const entity = await this.repo.findById(id)
634
- if (!entity) throw HttpException.notFound('${e} not found')
635
- }
636
- }
637
- `;
638
- }
639
- function Ne(e, t, r, o) {
640
- return [
641
- {
642
- file: `create-${t}.use-case.ts`,
643
- content: `import { Service, Inject } from '@forinda/kickjs'
644
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
645
- import type { Create${e}DTO } from '../dtos/create-${t}.dto'
646
-
647
- @Service()
648
- export class Create${e}UseCase {
649
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
650
- async execute(dto: Create${e}DTO) { return this.repo.create(dto) }
651
- }
652
- `
653
- },
654
- {
655
- file: `get-${t}.use-case.ts`,
656
- content: `import { Service, Inject } from '@forinda/kickjs'
657
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
658
-
659
- @Service()
660
- export class Get${e}UseCase {
661
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
662
- async execute(id: string) { return this.repo.findById(id) }
663
- }
664
- `
665
- },
666
- {
667
- file: `list-${r}.use-case.ts`,
668
- content: `import { Service, Inject } from '@forinda/kickjs'
669
- import type { ParsedQuery } from '@forinda/kickjs'
670
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
671
-
672
- @Service()
673
- export class List${o}UseCase {
674
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
675
- async execute(parsed: ParsedQuery) { return this.repo.findPaginated(parsed) }
676
- }
677
- `
678
- },
679
- {
680
- file: `update-${t}.use-case.ts`,
681
- content: `import { Service, Inject } from '@forinda/kickjs'
682
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
683
- import type { Update${e}DTO } from '../dtos/update-${t}.dto'
684
-
685
- @Service()
686
- export class Update${e}UseCase {
687
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
688
- async execute(id: string, dto: Update${e}DTO) { return this.repo.update(id, dto) }
689
- }
690
- `
691
- },
692
- {
693
- file: `delete-${t}.use-case.ts`,
694
- content: `import { Service, Inject } from '@forinda/kickjs'
695
- import { ${e.toUpperCase()}_REPOSITORY, type I${e}Repository } from '../../domain/repositories/${t}.repository'
696
-
697
- @Service()
698
- export class Delete${e}UseCase {
699
- constructor(@Inject(${e.toUpperCase()}_REPOSITORY) private repo: I${e}Repository) {}
700
- async execute(id: string) { return this.repo.delete(id) }
701
- }
702
- `
703
- }
704
- ];
705
- }
706
- async function He(e, t, r) {
707
- const o = g(e, "index.ts");
708
- if (!await M(o)) {
709
- await P(o, `import type { AppModuleClass } from '@forinda/kickjs'
710
- import { ${t}Module } from './${r}'
711
-
712
- export const modules: AppModuleClass[] = [${t}Module]
713
- `);
714
- return;
715
- }
716
- let n = await B(o, "utf-8");
717
- const i = `import { ${t}Module } from './${r}'`;
718
- if (!n.includes(`${t}Module`)) {
719
- const s = n.lastIndexOf("import ");
720
- if (s !== -1) {
721
- const a = n.indexOf(`
722
- `, s);
723
- n = n.slice(0, a + 1) + i + `
724
- ` + n.slice(a + 1);
725
- } else n = i + `
726
- ` + n;
727
- n = n.replace(/(=\s*\[)([\s\S]*?)(])/, (a, c, d, p) => {
728
- const l = d.trim();
729
- if (!l) return `${c}${t}Module${p}`;
730
- const f = l.endsWith(",") ? "" : ",";
731
- return `${c}${d.trimEnd()}${f} ${t}Module${p}`;
732
- });
733
- }
734
- await W(o, n, "utf-8");
735
- }
736
- async function Fe(e) {
737
- const { name: t, moduleName: r, modulesDir: o } = e, n = S(t), i = E(t), s = [];
738
- let a;
739
- if (e.outDir) a = m(e.outDir);
740
- else if (r) {
741
- const d = _(S(r));
742
- a = m(g(o ?? "src/modules", d, "__tests__"));
743
- } else a = m("src/__tests__");
744
- const c = g(a, `${n}.test.ts`);
745
- return await P(c, `import { describe, it, expect, beforeEach } from 'vitest'
746
- import { Container } from '@forinda/kickjs'
747
-
748
- describe('${i}', () => {
749
- beforeEach(() => {
750
- Container.reset()
751
- })
752
-
753
- it('should be defined', () => {
754
- // TODO: Import and test your class/function here
755
- expect(true).toBe(true)
756
- })
757
-
758
- it('should handle the happy path', async () => {
759
- // TODO: Set up test data and assertions
760
- expect(true).toBe(true)
761
- })
762
-
763
- it('should handle edge cases', async () => {
764
- // TODO: Test error handling, empty inputs, etc.
765
- expect(true).toBe(true)
766
- })
767
- })
768
- `), s.push(c), s;
769
- }
770
- function y(e) {
771
- return e.parent?.opts()?.dryRun ?? !1;
772
- }
773
- function h(e, t = !1) {
774
- const r = process.cwd();
775
- console.log(`
776
- ${t ? "Would generate" : "Generated"} ${e.length} file${e.length === 1 ? "" : "s"}:`);
777
- for (const o of e) console.log(` ${o.replace(r + "/", "")}`);
778
- t && console.log(`
779
- (dry run — no files were written)`), console.log();
780
- }
781
- var J = [
782
- {
783
- name: "module <name>",
784
- description: "Full DDD module (controller, DTOs, use-cases, repo)"
785
- },
786
- {
787
- name: "scaffold <name> <fields...>",
788
- description: "CRUD module from field definitions"
789
- },
790
- {
791
- name: "controller <name>",
792
- description: "@Controller() class [-m module]"
793
- },
794
- {
795
- name: "service <name>",
796
- description: "@Service() singleton [-m module]"
797
- },
798
- {
799
- name: "middleware <name>",
800
- description: "Express middleware function [-m module]"
801
- },
802
- {
803
- name: "guard <name>",
804
- description: "Route guard (auth, roles, etc.) [-m module]"
805
- },
806
- {
807
- name: "dto <name>",
808
- description: "Zod DTO schema [-m module]"
809
- },
810
- {
811
- name: "adapter <name>",
812
- description: "AppAdapter with lifecycle hooks (app-level only)"
813
- },
814
- {
815
- name: "test <name>",
816
- description: "Vitest test scaffold [-m module]"
817
- },
818
- {
819
- name: "resolver <name>",
820
- description: "GraphQL @Resolver class"
821
- },
822
- {
823
- name: "job <name>",
824
- description: "Queue @Job processor"
825
- },
826
- {
827
- name: "config",
828
- description: "Generate kick.config.ts"
829
- }
830
- ];
831
- function Je() {
832
- console.log(`
833
- Available generators:
834
- `);
835
- const e = Math.max(...J.map((t) => t.name.length));
836
- for (const t of J) console.log(` kick g ${t.name.padEnd(e + 2)} ${t.description}`);
837
- console.log();
838
- }
839
- function Ye(e) {
840
- const t = e.command("generate").alias("g").description("Generate code scaffolds").option("--list", "List all available generators").option("--dry-run", "Preview files that would be generated without writing them").action((r) => {
841
- r.list ? Je() : t.help();
842
- });
843
- t.command("module <names...>").description("Generate one or more modules (e.g. kick g module user task project)").option("--no-entity", "Skip entity and value object generation").option("--no-tests", "Skip test file generation").option("--repo <type>", "Repository implementation: inmemory | drizzle | prisma").option("--pattern <pattern>", "Override project pattern: rest | ddd | cqrs | minimal").option("--minimal", "Shorthand for --pattern minimal").option("--modules-dir <dir>", "Modules directory").option("--no-pluralize", "Use singular names (skip auto-pluralization)").option("-f, --force", "Overwrite existing files without prompting").action(async (r, o, n) => {
844
- const i = y(n);
845
- $(i);
846
- const s = await w(process.cwd()), a = R(s), c = o.modulesDir ?? a.dir ?? "src/modules", d = o.repo ?? re(a.repo), p = o.pattern ?? s?.pattern ?? "ddd", l = o.pluralize === !1 ? !1 : a.pluralize ?? !0, f = [];
847
- for (const v of r) {
848
- const u = await oe({
849
- name: v,
850
- modulesDir: m(c),
851
- noEntity: o.entity === !1,
852
- noTests: o.tests === !1,
853
- repo: d,
854
- minimal: o.minimal,
855
- force: o.force,
856
- pattern: p,
857
- dryRun: i,
858
- pluralize: l,
859
- prismaClientPath: a.prismaClientPath
860
- });
861
- f.push(...u);
862
- }
863
- h(f, i);
864
- }), t.command("adapter <name>").description("Generate an AppAdapter with lifecycle hooks and middleware support").option("-o, --out <dir>", "Output directory", "src/adapters").action(async (r, o, n) => {
865
- const i = y(n);
866
- $(i), h(await de({
867
- name: r,
868
- outDir: m(o.out)
869
- }), i);
870
- }), t.command("middleware <name>").description(`Generate an Express middleware function
871
- Use -m to scope it to a module: kick g middleware auth -m users`).option("-o, --out <dir>", "Output directory (overrides --module)").option("-m, --module <module>", "Place inside a module folder").action(async (r, o, n) => {
872
- const i = y(n);
873
- $(i);
874
- const s = await w(process.cwd()), a = R(s).dir ?? "src/modules";
875
- h(await ie({
876
- name: r,
877
- outDir: o.out,
878
- moduleName: o.module,
879
- modulesDir: a,
880
- pattern: s?.pattern
881
- }), i);
882
- }), t.command("guard <name>").description(`Generate a route guard (auth, roles, etc.)
883
- Use -m to scope it to a module: kick g guard admin -m users`).option("-o, --out <dir>", "Output directory (overrides --module)").option("-m, --module <module>", "Place inside a module folder").action(async (r, o, n) => {
884
- const i = y(n);
885
- $(i);
886
- const s = await w(process.cwd()), a = R(s).dir ?? "src/modules";
887
- h(await te({
888
- name: r,
889
- outDir: o.out,
890
- moduleName: o.module,
891
- modulesDir: a,
892
- pattern: s?.pattern
893
- }), i);
894
- }), t.command("service <name>").description(`Generate a @Service() class
895
- Use -m to scope it to a module: kick g service payment -m orders`).option("-o, --out <dir>", "Output directory (overrides --module)").option("-m, --module <module>", "Place inside a module folder").action(async (r, o, n) => {
896
- const i = y(n);
897
- $(i);
898
- const s = await w(process.cwd()), a = R(s).dir ?? "src/modules";
899
- h(await ce({
900
- name: r,
901
- outDir: o.out,
902
- moduleName: o.module,
903
- modulesDir: a,
904
- pattern: s?.pattern
905
- }), i);
906
- }), t.command("controller <name>").description(`Generate a @Controller() class with basic routes
907
- Use -m to scope it to a module: kick g controller auth -m users`).option("-o, --out <dir>", "Output directory (overrides --module)").option("-m, --module <module>", "Place inside a module folder").action(async (r, o, n) => {
908
- const i = y(n);
909
- $(i);
910
- const s = await w(process.cwd()), a = R(s).dir ?? "src/modules";
911
- h(await ae({
912
- name: r,
913
- outDir: o.out,
914
- moduleName: o.module,
915
- modulesDir: a,
916
- pattern: s?.pattern
917
- }), i);
918
- }), t.command("dto <name>").description(`Generate a Zod DTO schema
919
- Use -m to scope it to a module: kick g dto create-user -m users`).option("-o, --out <dir>", "Output directory (overrides --module)").option("-m, --module <module>", "Place inside a module folder").action(async (r, o, n) => {
920
- const i = y(n);
921
- $(i);
922
- const s = await w(process.cwd()), a = R(s).dir ?? "src/modules";
923
- h(await ee({
924
- name: r,
925
- outDir: o.out,
926
- moduleName: o.module,
927
- modulesDir: a,
928
- pattern: s?.pattern
929
- }), i);
930
- }), t.command("test <name>").description(`Generate a Vitest test scaffold
931
- Use -m to scope it to a module: kick g test user-service -m users`).option("-o, --out <dir>", "Output directory (overrides --module)").option("-m, --module <module>", "Place inside a module's __tests__/ folder").action(async (r, o, n) => {
932
- const i = y(n);
933
- $(i);
934
- const s = R(await w(process.cwd())).dir ?? "src/modules";
935
- h(await Fe({
936
- name: r,
937
- outDir: o.out,
938
- moduleName: o.module,
939
- modulesDir: s
940
- }), i);
941
- }), t.command("resolver <name>").description("Generate a GraphQL @Resolver class with @Query and @Mutation methods").option("-o, --out <dir>", "Output directory", "src/resolvers").action(async (r, o, n) => {
942
- const i = y(n);
943
- $(i), h(await Pe({
944
- name: r,
945
- outDir: m(o.out)
946
- }), i);
947
- }), t.command("job <name>").description("Generate a @Job queue processor with @Process handlers").option("-o, --out <dir>", "Output directory", "src/jobs").option("-q, --queue <name>", "Queue name (default: <name>-queue)").action(async (r, o, n) => {
948
- const i = y(n);
949
- $(i), h(await Ie({
950
- name: r,
951
- outDir: m(o.out),
952
- queue: o.queue
953
- }), i);
954
- }), t.command("scaffold <name> [fields...]").description(`Generate a full CRUD module from field definitions
955
- Example: kick g scaffold Post title:string body:text published:boolean?
956
- Types: string, text, number, int, float, boolean, date, email, url, uuid, json, enum:a,b,c
957
- Append ? for optional fields: description:text?`).option("--no-entity", "Skip entity and value object generation").option("--no-tests", "Skip test file generation").option("--no-pluralize", "Use singular names (skip auto-pluralization)").option("--modules-dir <dir>", "Modules directory").action(async (r, o, n, i) => {
958
- const s = y(i);
959
- $(s), o.length === 0 && (console.error(`
960
- Error: At least one field is required.
961
- Usage: kick g scaffold <name> <field:type> [field:type...]
962
- Example: kick g scaffold Post title:string body:text published:boolean
963
- `), process.exit(1));
964
- const a = R(await w(process.cwd())), c = n.modulesDir ?? a.dir ?? "src/modules", d = Oe(o), p = await Te({
965
- name: r,
966
- fields: d,
967
- modulesDir: m(c),
968
- noEntity: n.entity === !1,
969
- noTests: n.tests === !1,
970
- pluralize: n.pluralize === !1 ? !1 : a.pluralize ?? !0
971
- });
972
- console.log(`
973
- Scaffolded ${r} with ${d.length} field(s):`);
974
- for (const l of d) console.log(` ${l.name}: ${l.type}${l.optional ? " (optional)" : ""}`);
975
- h(p, s);
976
- }), t.command("config").description("Generate a kick.config.ts at the project root").option("--modules-dir <dir>", "Modules directory path", "src/modules").option("--repo <type>", "Default repository type: inmemory | drizzle | prisma", "inmemory").option("-f, --force", "Overwrite existing kick.config.ts without prompting").action(async (r, o) => {
977
- const n = y(o);
978
- $(n), h(await Se({
979
- outDir: m("."),
980
- modulesDir: r.modulesDir,
981
- defaultRepo: r.repo,
982
- force: r.force
983
- }), n);
984
- });
985
- }
986
- function K(e, t) {
987
- q(e, {
988
- cwd: t,
989
- stdio: "inherit"
990
- });
991
- }
992
- async function Y(e, t) {
993
- t && (process.env.PORT = t);
994
- const { createRequire: r } = await import("node:module"), o = r(m("package.json")), n = o.resolve("vite"), { createServer: i, isRunnableDevEnvironment: s } = await import(n), a = await i({
995
- configFile: m("vite.config.ts"),
996
- appType: "custom",
997
- server: {
998
- middlewareMode: !0,
999
- hmr: !0
1000
- },
1001
- environments: { ssr: {} },
1002
- customLogger: (() => {
1003
- const { createLogger: l } = o(n), f = l(), v = f.warn.bind(f);
1004
- return f.warn = (u, I) => {
1005
- u.includes("(client)") && u.includes("externalized") || v(u, I);
1006
- }, f;
1007
- })()
1008
- }), c = a.environments.ssr;
1009
- s(c) || (console.error(`
1010
- Error: Vite environment is not runnable.
1011
- Ensure vite.config.ts uses the default SSR environment.
1012
- `), process.exit(1)), console.log(`
1013
- KickJS dev server starting...`), console.log(` Entry: ${e}`), console.log(` HMR: enabled (Vite Environment Runner)
1014
- `), await c.runner.import(`/${e}`);
1015
- const d = [
1016
- "kick.config.ts",
1017
- "kick.config.js",
1018
- "kick.config.mjs"
1019
- ];
1020
- for (const l of d) {
1021
- const f = m(l);
1022
- a.watcher.add(f);
1023
- }
1024
- a.watcher.on("change", (l) => {
1025
- const f = l.split("/").pop() ?? "";
1026
- d.includes(f) && (console.log(`
1027
- kick.config changed, restarting...
1028
- `), a.restart());
1029
- });
1030
- const p = async () => {
1031
- await a.close(), process.exit(0);
1032
- };
1033
- process.on("SIGINT", p), process.on("SIGTERM", p);
1034
- }
1035
- function Be(e) {
1036
- e.command("dev").description("Start development server with Vite HMR (zero-downtime reload)").option("-e, --entry <file>", "Entry file", "src/index.ts").option("-p, --port <port>", "Port number").action(async (t) => {
1037
- try {
1038
- await Y(t.entry, t.port);
1039
- } catch (r) {
1040
- r.code === "ERR_MODULE_NOT_FOUND" && r.message?.includes("vite") ? console.error(`
1041
- Error: vite is not installed.
1042
- Run: pnpm add -D vite unplugin-swc
1043
- `) : console.error(`
1044
- Dev server failed:`, r.message ?? r), process.exit(1);
1045
- }
1046
- }), e.command("build").description("Build for production via Vite").action(async () => {
1047
- console.log(`
1048
- Building for production...
1049
- `);
1050
- const { createRequire: t } = await import("node:module"), { build: r } = await import(t(m("package.json")).resolve("vite"));
1051
- await r({ configFile: m("vite.config.ts") });
1052
- const o = (await w(process.cwd()))?.copyDirs ?? [];
1053
- if (o.length > 0) {
1054
- console.log(`
1055
- Copying directories to dist...`);
1056
- for (const n of o) {
1057
- const i = typeof n == "string" ? n : n.src, s = typeof n == "string" ? g("dist", n) : n.dest ?? g("dist", i), a = m(i), c = m(s);
1058
- if (!j(a)) {
1059
- console.log(` ⚠ Skipped ${i} (not found)`);
1060
- continue;
1061
- }
1062
- ge(c, { recursive: !0 }), fe(a, c, { recursive: !0 }), console.log(` ✓ ${i} → ${s}`);
1063
- }
1064
- }
1065
- console.log(`
1066
- Build complete.
1067
- `);
1068
- }), e.command("start").description("Start production server").option("-e, --entry <file>", "Entry file", "dist/index.js").option("-p, --port <port>", "Port number").action((t) => {
1069
- const r = ["NODE_ENV=production"];
1070
- t.port && r.push(`PORT=${t.port}`), K(`${r.join(" ")} node ${t.entry}`);
1071
- }), e.command("dev:debug").description("Start dev server with Node.js inspector attached").option("-e, --entry <file>", "Entry file", "src/index.ts").option("-p, --port <port>", "Port number").option("--inspect-port <port>", "Inspector port", "9229").action(async (t) => {
1072
- const r = t.inspectPort ?? "9229";
1073
- process.env.NODE_OPTIONS = `--inspect=0.0.0.0:${r}`, console.log(` Debugger: ws://0.0.0.0:${r}`);
1074
- try {
1075
- await Y(t.entry, t.port);
1076
- } catch (o) {
1077
- console.error(`
1078
- Dev server (debug) failed:`, o.message ?? o), process.exit(1);
1079
- }
1080
- });
1081
- }
1082
- function We(e) {
1083
- e.command("info").description("Print system and framework info").action(() => {
1084
- console.log(`
1085
- KickJS CLI
1086
-
1087
- System:
1088
- OS: ${Re()} ${xe()} (${De()})
1089
- Node: ${process.version}
1090
-
1091
- Packages:
1092
- @forinda/kickjs-core workspace
1093
- @forinda/kickjs-http workspace
1094
- @forinda/kickjs-config workspace
1095
- @forinda/kickjs-cli workspace
1096
- `);
1097
- });
1098
- }
1099
- function Ke(e, t) {
1100
- if (t?.commands?.length)
1101
- for (const r of t.commands) Ve(e, r);
1102
- }
1103
- function Ve(e, t) {
1104
- const r = e.command(t.name).description(t.description);
1105
- if (t.aliases) for (const o of t.aliases) r.alias(o);
1106
- r.allowUnknownOption(!0), r.argument("[args...]", "Additional arguments passed to the command"), r.action((o) => {
1107
- const n = o.join(" "), i = Array.isArray(t.steps) ? t.steps : [t.steps];
1108
- for (const s of i) {
1109
- const a = n ? `${s} ${n}` : s;
1110
- console.log(` $ ${a}`);
1111
- try {
1112
- K(a);
1113
- } catch {
1114
- console.error(` Command failed: ${t.name}`), process.exitCode = 1;
1115
- return;
1116
- }
1117
- }
1118
- });
1119
- }
1120
- var x = (e) => `\x1B[${e}m`, C = x("0"), D = (e) => `${x("1")}${e}${C}`, k = (e) => `${x("2")}${e}${C}`, G = (e) => `${x("32")}${e}${C}`, T = (e) => `${x("31")}${e}${C}`, V = (e) => `${x("33")}${e}${C}`, Ze = (e) => `${x("36")}${e}${C}`, Xe = (e) => `${x("35")}${e}${C}`, et = (e) => `${x("34")}${e}${C}`, tt = {
1121
- GET: G,
1122
- POST: Ze,
1123
- PUT: V,
1124
- PATCH: Xe,
1125
- DELETE: T
1126
- };
1127
- function ot(e) {
1128
- return (tt[e] ?? k)(e.padEnd(7));
1129
- }
1130
- function rt(e) {
1131
- const t = Math.floor(e / 86400), r = Math.floor(e % 86400 / 3600), o = Math.floor(e % 3600 / 60), n = e % 60, i = [];
1132
- return t && i.push(`${t}d`), r && i.push(`${r}h`), o && i.push(`${o}m`), i.push(`${n}s`), i.join(" ");
1133
- }
1134
- async function nt(e) {
1135
- const t = await fetch(e, { signal: AbortSignal.timeout(5e3) });
1136
- if (!t.ok) throw new Error(`${t.status} ${t.statusText}`);
1137
- return t.json();
1138
- }
1139
- async function O(e, t) {
1140
- try {
1141
- return await nt(`${e}${t}`);
1142
- } catch {
1143
- return null;
1144
- }
1145
- }
1146
- async function it(e) {
1147
- const [t, r, o, n, i] = await Promise.all([
1148
- O(e, "/health"),
1149
- O(e, "/metrics"),
1150
- O(e, "/routes"),
1151
- O(e, "/container"),
1152
- O(e, "/ws")
1153
- ]);
1154
- return {
1155
- health: t,
1156
- metrics: r,
1157
- routes: o,
1158
- container: n,
1159
- ws: i
1160
- };
1161
- }
1162
- function st(e, t) {
1163
- const { health: r, metrics: o, routes: n, container: i, ws: s } = t, a = k("─".repeat(60));
1164
- if (console.log(), console.log(D(" KickJS Inspector") + k(` → ${e}`)), console.log(a), r) {
1165
- const c = r.status === "healthy" ? G("● healthy") : T("● " + r.status);
1166
- console.log(` ${D("Health:")} ${c}`);
1167
- } else console.log(` ${D("Health:")} ${T("● unreachable")}`);
1168
- if (o) {
1169
- const c = ((o.errorRate ?? 0) * 100).toFixed(1), d = o.errorRate > 0.1 ? T : o.errorRate > 0 ? V : G;
1170
- console.log(` ${D("Uptime:")} ${rt(o.uptimeSeconds)}`), console.log(` ${D("Requests:")} ${o.requests}`), console.log(` ${D("Errors:")} ${o.serverErrors} server, ${o.clientErrors ?? 0} client ${k("(")}${d(c + "%")}${k(")")}`);
1171
- }
1172
- if (i && console.log(` ${D("DI:")} ${i.count} bindings`), s && s.enabled && console.log(` ${D("WS:")} ${s.connections ?? 0} connections, ${s.namespaces ?? 0} namespaces`), n?.routes?.length) {
1173
- console.log(), console.log(D(" Routes")), console.log(a), console.log(` ${k("METHOD")} ${k("PATH".padEnd(36))} ${k("CONTROLLER")}`);
1174
- for (const c of n.routes) {
1175
- const d = c.path.length > 36 ? c.path.slice(0, 33) + "..." : c.path.padEnd(36);
1176
- console.log(` ${ot(c.method)} ${d} ${et(c.controller)}.${k(c.handler)}`);
1177
- }
1178
- }
1179
- console.log(a), console.log();
1180
- }
1181
- function at(e) {
1182
- e.command("inspect [url]").description("Connect to a running KickJS app and display debug info").option("-p, --port <port>", "Override port").option("-w, --watch", "Poll every 5 seconds").option("-j, --json", "Output raw JSON").action(async (t, r) => {
1183
- let o = t ?? "http://localhost:3000";
1184
- if (r.port) try {
1185
- const s = new URL(o);
1186
- s.port = r.port, o = s.origin;
1187
- } catch {
1188
- o = `http://localhost:${r.port}`;
1189
- }
1190
- const n = `${o.replace(/\/$/, "")}/_debug`, i = async () => {
1191
- try {
1192
- const s = await it(n);
1193
- r.json ? console.log(JSON.stringify(s, null, 2)) : st(o, s);
1194
- } catch (s) {
1195
- r.json ? console.log(JSON.stringify({ error: String(s) })) : (console.error(T(` ✖ Could not connect to ${o}`)), console.error(k(` ${s instanceof Error ? s.message : String(s)}`))), r.watch || (process.exitCode = 1);
1196
- }
1197
- };
1198
- if (r.watch) {
1199
- const s = async () => {
1200
- process.stdout.write("\x1B[2J\x1B[H"), await i();
1201
- };
1202
- await s(), setInterval(s, 5e3);
1203
- } else await i();
1204
- });
1205
- }
1206
- var Q = {
1207
- core: {
1208
- pkg: "@forinda/kickjs-core",
1209
- peers: [],
1210
- description: "DI container, decorators, reactivity"
1211
- },
1212
- http: {
1213
- pkg: "@forinda/kickjs-http",
1214
- peers: ["express"],
1215
- description: "Express 5, routing, middleware"
1216
- },
1217
- config: {
1218
- pkg: "@forinda/kickjs-config",
1219
- peers: [],
1220
- description: "Zod-based env validation"
1221
- },
1222
- cli: {
1223
- pkg: "@forinda/kickjs-cli",
1224
- peers: [],
1225
- description: "CLI tool and code generators",
1226
- dev: !0
1227
- },
1228
- swagger: {
1229
- pkg: "@forinda/kickjs-swagger",
1230
- peers: [],
1231
- description: "OpenAPI spec + Swagger UI + ReDoc"
1232
- },
1233
- graphql: {
1234
- pkg: "@forinda/kickjs-graphql",
1235
- peers: ["graphql"],
1236
- description: "GraphQL resolvers + GraphiQL"
1237
- },
1238
- drizzle: {
1239
- pkg: "@forinda/kickjs-drizzle",
1240
- peers: ["drizzle-orm"],
1241
- description: "Drizzle ORM adapter + query builder"
1242
- },
1243
- prisma: {
1244
- pkg: "@forinda/kickjs-prisma",
1245
- peers: ["@prisma/client"],
1246
- description: "Prisma adapter + query builder"
1247
- },
1248
- ws: {
1249
- pkg: "@forinda/kickjs-ws",
1250
- peers: ["socket.io"],
1251
- description: "WebSocket with @WsController decorators"
1252
- },
1253
- otel: {
1254
- pkg: "@forinda/kickjs-otel",
1255
- peers: ["@opentelemetry/api"],
1256
- description: "OpenTelemetry tracing + metrics"
1257
- },
1258
- devtools: {
1259
- pkg: "@forinda/kickjs-devtools",
1260
- peers: [],
1261
- description: "Development dashboard — routes, DI, metrics, health",
1262
- dev: !0
1263
- },
1264
- auth: {
1265
- pkg: "@forinda/kickjs-auth",
1266
- peers: ["jsonwebtoken"],
1267
- description: "Authentication — JWT, API key, and custom strategies"
1268
- },
1269
- mailer: {
1270
- pkg: "@forinda/kickjs-mailer",
1271
- peers: ["nodemailer"],
1272
- description: "Email sending — SMTP, Resend, SES, or custom provider"
1273
- },
1274
- cron: {
1275
- pkg: "@forinda/kickjs-cron",
1276
- peers: ["croner"],
1277
- description: "Cron job scheduling (production-grade with croner)"
1278
- },
1279
- queue: {
1280
- pkg: "@forinda/kickjs-queue",
1281
- peers: [],
1282
- description: "Queue adapter (BullMQ/RabbitMQ/Kafka)"
1283
- },
1284
- "queue:bullmq": {
1285
- pkg: "@forinda/kickjs-queue",
1286
- peers: ["bullmq", "ioredis"],
1287
- description: "Queue with BullMQ + Redis"
1288
- },
1289
- "queue:rabbitmq": {
1290
- pkg: "@forinda/kickjs-queue",
1291
- peers: ["amqplib"],
1292
- description: "Queue with RabbitMQ"
1293
- },
1294
- "queue:kafka": {
1295
- pkg: "@forinda/kickjs-queue",
1296
- peers: ["kafkajs"],
1297
- description: "Queue with Kafka"
1298
- },
1299
- "multi-tenant": {
1300
- pkg: "@forinda/kickjs-multi-tenant",
1301
- peers: [],
1302
- description: "Tenant resolution middleware"
1303
- },
1304
- notifications: {
1305
- pkg: "@forinda/kickjs-notifications",
1306
- peers: [],
1307
- description: "Multi-channel notifications — email, Slack, Discord, webhook"
1308
- },
1309
- testing: {
1310
- pkg: "@forinda/kickjs-testing",
1311
- peers: [],
1312
- description: "Test utilities and TestModule builder",
1313
- dev: !0
1314
- }
1315
- };
1316
- function ct() {
1317
- return j(m("pnpm-lock.yaml")) ? "pnpm" : j(m("yarn.lock")) ? "yarn" : "npm";
1318
- }
1319
- function Z() {
1320
- console.log(`
1321
- Available KickJS packages:
1322
- `);
1323
- const e = Math.max(...Object.keys(Q).map((t) => t.length));
1324
- for (const [t, r] of Object.entries(Q)) {
1325
- const o = t.padEnd(e + 2), n = r.peers.length ? ` (+ ${r.peers.join(", ")})` : "";
1326
- console.log(` ${o} ${r.description}${n}`);
1327
- }
1328
- console.log(`
1329
- Usage: kick add graphql drizzle otel`), console.log(" kick add queue:bullmq"), console.log();
1330
- }
1331
- function dt(e) {
1332
- e.command("list").alias("ls").description("List all available KickJS packages").action(() => {
1333
- Z();
1334
- });
1335
- }
1336
- function pt(e) {
1337
- e.command("add [packages...]").description("Add KickJS packages with their required dependencies").option("--pm <manager>", "Package manager override").option("-D, --dev", "Install as dev dependency").option("--list", "List all available packages").action(async (t, r) => {
1338
- if (r.list || t.length === 0) {
1339
- Z();
1340
- return;
1341
- }
1342
- const o = r.pm ?? ct(), n = r.dev, i = /* @__PURE__ */ new Set(), s = /* @__PURE__ */ new Set(), a = [];
1343
- for (const c of t) {
1344
- const d = Q[c];
1345
- if (!d) {
1346
- a.push(c);
1347
- continue;
1348
- }
1349
- const p = n || d.dev ? s : i;
1350
- p.add(d.pkg);
1351
- for (const l of d.peers) p.add(l);
1352
- }
1353
- if (!(a.length > 0 && (console.log(`
1354
- Unknown packages: ${a.join(", ")}`), console.log(` Run "kick add --list" to see available packages.
1355
- `), i.size === 0 && s.size === 0))) {
1356
- if (i.size > 0) {
1357
- const c = Array.from(i), d = `${o} add ${c.join(" ")}`;
1358
- console.log(`
1359
- Installing ${c.length} dependency(ies):`);
1360
- for (const p of c) console.log(` + ${p}`);
1361
- console.log();
1362
- try {
1363
- q(d, { stdio: "inherit" });
1364
- } catch {
1365
- console.log(`
1366
- Installation failed. Run manually:
1367
- ${d}
1368
- `);
1369
- }
1370
- }
1371
- if (s.size > 0) {
1372
- const c = Array.from(s), d = `${o} add -D ${c.join(" ")}`;
1373
- console.log(`
1374
- Installing ${c.length} dev dependency(ies):`);
1375
- for (const p of c) console.log(` + ${p} (dev)`);
1376
- console.log();
1377
- try {
1378
- q(d, { stdio: "inherit" });
1379
- } catch {
1380
- console.log(`
1381
- Installation failed. Run manually:
1382
- ${d}
1383
- `);
1384
- }
1385
- }
1386
- console.log(` Done!
1387
- `);
1388
- }
1389
- });
1390
- }
1391
- function lt(e) {
1392
- e.command("tinker").description("Interactive REPL with DI container and services loaded").option("-e, --entry <file>", "Entry file to load", "src/index.ts").action(async (t) => {
1393
- const r = process.cwd(), o = m(r, t.entry);
1394
- j(o) || (console.error(`
1395
- Error: ${t.entry} not found.
1396
- `), process.exit(1));
1397
- const n = ut(r, "tsx");
1398
- n || (console.error(`
1399
- Error: tsx not found. Install it: pnpm add -D tsx
1400
- `), process.exit(1));
1401
- const i = mt(o, t.entry), s = g(r, ".kick-tinker.mjs"), { writeFileSync: a, unlinkSync: c } = await import("node:fs");
1402
- a(s, i, "utf-8");
1403
- try {
1404
- const d = ue(s, [], {
1405
- cwd: r,
1406
- execPath: n,
1407
- stdio: "inherit"
1408
- });
1409
- await new Promise((p) => {
1410
- d.on("exit", () => p());
1411
- });
1412
- } finally {
1413
- try {
1414
- c(s);
1415
- } catch {
1416
- }
1417
- }
1418
- });
1419
- }
1420
- function mt(e, t) {
1421
- return `
1422
- import 'reflect-metadata'
1423
-
1424
- // Prevent bootstrap() from starting the HTTP server
1425
- process.env.KICK_TINKER = '1'
1426
-
1427
- console.log('\\n 🔧 KickJS Tinker')
1428
- console.log(' Loading: ${t}\\n')
1429
-
1430
- // Load core
1431
- let Container, Logger, HttpException, HttpStatus
1432
- try {
1433
- const core = await import('@forinda/kickjs-core')
1434
- Container = core.Container
1435
- Logger = core.Logger
1436
- HttpException = core.HttpException
1437
- HttpStatus = core.HttpStatus
1438
- } catch {
1439
- console.error(' Error: @forinda/kickjs-core not found.')
1440
- console.error(' Install it: pnpm add @forinda/kickjs-core\\n')
1441
- process.exit(1)
1442
- }
1443
-
1444
- // Load entry to trigger decorator registration
1445
- try {
1446
- await import('${ke(e).href}')
1447
- } catch (err) {
1448
- console.warn(' Warning: ' + err.message)
1449
- console.warn(' Container may be partially initialized.\\n')
1450
- }
1451
-
1452
- const container = Container.getInstance()
1453
-
1454
- // Start REPL
1455
- const repl = await import('node:repl')
1456
- const server = repl.start({ prompt: 'kick> ', useGlobal: true })
1457
-
1458
- server.context.container = container
1459
- server.context.Container = Container
1460
- server.context.resolve = (token) => container.resolve(token)
1461
- server.context.Logger = Logger
1462
- server.context.HttpException = HttpException
1463
- server.context.HttpStatus = HttpStatus
1464
-
1465
- console.log(' Available globals:')
1466
- console.log(' container — DI container instance')
1467
- console.log(' resolve(T) — shorthand for container.resolve(T)')
1468
- console.log(' Container, Logger, HttpException, HttpStatus')
1469
- console.log()
1470
-
1471
- server.on('exit', () => {
1472
- console.log('\\n Goodbye!\\n')
1473
- process.exit(0)
1474
- })
1475
- `;
1476
- }
1477
- function ut(e, t) {
1478
- let r = e;
1479
- for (; ; ) {
1480
- const o = g(r, "node_modules", ".bin", t);
1481
- if (j(o)) return o;
1482
- const n = m(r, "..");
1483
- if (n === r) break;
1484
- r = n;
1485
- }
1486
- return null;
1487
- }
1488
- function ft(e) {
1489
- const t = N({
1490
- input: process.stdin,
1491
- output: process.stdout
1492
- });
1493
- return new Promise((r) => {
1494
- t.question(` ${e} (y/N) `, (o) => {
1495
- t.close(), r(o.trim().toLowerCase() === "y");
1496
- });
1497
- });
1498
- }
1499
- async function gt(e) {
1500
- const { name: t, modulesDir: r, force: o } = e, n = e.pluralize !== !1, i = S(t), s = E(t), a = n ? _(i) : i, c = g(r, a);
1501
- if (!await M(c)) {
1502
- console.log(`
1503
- Module not found: ${c}
1504
- `);
1505
- return;
1506
- }
1507
- if (!o && !await ft(`Delete module '${a}' at ${c}? This cannot be undone.`)) {
1508
- console.log(`
1509
- Cancelled.
1510
- `);
1511
- return;
1512
- }
1513
- await me(c, {
1514
- recursive: !0,
1515
- force: !0
1516
- }), console.log(` Deleted: ${c}`);
1517
- const d = g(r, "index.ts");
1518
- if (await M(d)) {
1519
- let p = await B(d, "utf-8");
1520
- const l = p, f = new RegExp(`^import\\s*\\{\\s*${s}Module\\s*\\}\\s*from\\s*['\\./${a}']+.*\\n?`, "gm");
1521
- p = p.replace(f, ""), p = p.replace(new RegExp(`\\s*,?\\s*${s}Module\\s*,?`, "g"), (v) => {
1522
- const u = v.trimStart().startsWith(","), I = v.trimEnd().endsWith(",");
1523
- return u && I ? "," : "";
1524
- }), p = p.replace(/,(\s*])/, "$1"), p = p.replace(/\n{3,}/g, `
1525
-
1526
- `), p !== l && (await W(d, p, "utf-8"), console.log(` Unregistered: ${s}Module from ${d}`));
1527
- }
1528
- console.log(`
1529
- Module '${a}' removed.
1530
- `);
1531
- }
1532
- function $t(e) {
1533
- e.command("remove").alias("rm").description("Remove generated code").command("module <names...>").description("Remove one or more modules (e.g. kick rm module user task)").option("--modules-dir <dir>", "Modules directory").option("--no-pluralize", "Use singular module name").option("-f, --force", "Skip confirmation prompt").action(async (t, r) => {
1534
- const o = R(await w(process.cwd())), n = r.modulesDir ?? o.dir ?? "src/modules", i = r.pluralize === !1 ? !1 : o.pluralize ?? !0;
1535
- for (const s of t) await gt({
1536
- name: s,
1537
- modulesDir: m(n),
1538
- force: r.force,
1539
- pluralize: i
1540
- });
1541
- });
1542
- }
1543
- var yt = le(we(import.meta.url)), ht = JSON.parse($e(g(yt, "..", "package.json"), "utf-8"));
1544
- async function wt() {
1545
- const e = new ve();
1546
- e.name("kick").description("KickJS — A production-grade, decorator-driven Node.js framework").version(ht.version);
1547
- const t = await w(process.cwd());
1548
- Ce(e), Ye(e), Be(e), We(e), at(e), pt(e), dt(e), lt(e), $t(e), Ke(e, t), e.showHelpAfterError(), await e.parseAsync(process.argv);
1549
- }
1550
- wt().catch((e) => {
1551
- console.error(e instanceof Error ? e.message : e), process.exitCode = 1;
1552
- });