@sohan_fahad/wilt 0.1.2

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 (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +250 -0
  3. package/bin/commands/add.ts +155 -0
  4. package/bin/commands/generate.ts +74 -0
  5. package/bin/commands/new.ts +457 -0
  6. package/bin/create-wilt-app.ts +3 -0
  7. package/bin/generators/module.generator.ts +266 -0
  8. package/bin/utils/config.ts +46 -0
  9. package/bin/utils/paths.ts +32 -0
  10. package/bin/utils/wrangler.ts +216 -0
  11. package/bin/wilt.ts +79 -0
  12. package/dist/lib/bin/create-wilt-app.js +413 -0
  13. package/dist/lib/bin/create-wilt-app.js.map +1 -0
  14. package/dist/lib/bin/wilt.js +1151 -0
  15. package/dist/lib/bin/wilt.js.map +1 -0
  16. package/dist/lib/chunk-EUXUH3YW.js +15 -0
  17. package/dist/lib/chunk-EUXUH3YW.js.map +1 -0
  18. package/dist/lib/chunk-FIEODUMV.js +234 -0
  19. package/dist/lib/chunk-FIEODUMV.js.map +1 -0
  20. package/dist/lib/chunk-MOVXD653.cjs +234 -0
  21. package/dist/lib/chunk-MOVXD653.cjs.map +1 -0
  22. package/dist/lib/chunk-ZBDE64SD.cjs +15 -0
  23. package/dist/lib/chunk-ZBDE64SD.cjs.map +1 -0
  24. package/dist/lib/config.cjs +10 -0
  25. package/dist/lib/config.cjs.map +1 -0
  26. package/dist/lib/config.d.cts +13 -0
  27. package/dist/lib/config.d.ts +13 -0
  28. package/dist/lib/config.js +10 -0
  29. package/dist/lib/config.js.map +1 -0
  30. package/dist/lib/index.cjs +974 -0
  31. package/dist/lib/index.cjs.map +1 -0
  32. package/dist/lib/index.d.cts +255 -0
  33. package/dist/lib/index.d.ts +255 -0
  34. package/dist/lib/index.js +974 -0
  35. package/dist/lib/index.js.map +1 -0
  36. package/dist/lib/middleware/index.cjs +10 -0
  37. package/dist/lib/middleware/index.cjs.map +1 -0
  38. package/dist/lib/middleware/index.d.cts +18 -0
  39. package/dist/lib/middleware/index.d.ts +18 -0
  40. package/dist/lib/middleware/index.js +10 -0
  41. package/dist/lib/middleware/index.js.map +1 -0
  42. package/package.json +78 -0
  43. package/src/wilt/README.md +285 -0
  44. package/src/wilt/config.ts +14 -0
  45. package/src/wilt/context/execution-context.ts +36 -0
  46. package/src/wilt/context/index.ts +1 -0
  47. package/src/wilt/decorators/core/exception-filters.decorator.ts +24 -0
  48. package/src/wilt/decorators/core/index.ts +6 -0
  49. package/src/wilt/decorators/core/injectable.decorator.ts +41 -0
  50. package/src/wilt/decorators/core/optional.decorator.ts +9 -0
  51. package/src/wilt/decorators/core/set-metadata.decorator.ts +20 -0
  52. package/src/wilt/decorators/core/use-guards.decorator.ts +14 -0
  53. package/src/wilt/decorators/core/use-interceptors.decorator.ts +16 -0
  54. package/src/wilt/decorators/http/controller.decorator.ts +230 -0
  55. package/src/wilt/decorators/http/header.decorator.ts +11 -0
  56. package/src/wilt/decorators/http/http-code.decorator.ts +8 -0
  57. package/src/wilt/decorators/http/index.ts +6 -0
  58. package/src/wilt/decorators/http/redirect.decorator.ts +13 -0
  59. package/src/wilt/decorators/http/route-mapping.decorator.ts +22 -0
  60. package/src/wilt/decorators/http/route-params.decorator.ts +60 -0
  61. package/src/wilt/decorators/index.ts +3 -0
  62. package/src/wilt/decorators/modules/global.decorator.ts +8 -0
  63. package/src/wilt/decorators/modules/index.ts +2 -0
  64. package/src/wilt/decorators/modules/module.decorator.ts +16 -0
  65. package/src/wilt/exceptions/http-exception.ts +17 -0
  66. package/src/wilt/exceptions/http-exceptions.ts +85 -0
  67. package/src/wilt/exceptions/index.ts +2 -0
  68. package/src/wilt/index.ts +11 -0
  69. package/src/wilt/injector/index.ts +1 -0
  70. package/src/wilt/injector/injector.ts +103 -0
  71. package/src/wilt/injector/module-compiler.ts +48 -0
  72. package/src/wilt/injector/module.factory.ts +74 -0
  73. package/src/wilt/interfaces/core/filter.interface.ts +5 -0
  74. package/src/wilt/interfaces/core/guard.interface.ts +5 -0
  75. package/src/wilt/interfaces/core/index.ts +5 -0
  76. package/src/wilt/interfaces/core/interceptor.interface.ts +9 -0
  77. package/src/wilt/interfaces/core/lifecycle.interface.ts +19 -0
  78. package/src/wilt/interfaces/core/pipe.interface.ts +9 -0
  79. package/src/wilt/interfaces/http/index.ts +1 -0
  80. package/src/wilt/interfaces/http/response.interface.ts +27 -0
  81. package/src/wilt/interfaces/index.ts +3 -0
  82. package/src/wilt/interfaces/modules/index.ts +1 -0
  83. package/src/wilt/interfaces/modules/module.interface.ts +17 -0
  84. package/src/wilt/middleware/error-handler.middleware.ts +63 -0
  85. package/src/wilt/middleware/index.ts +2 -0
  86. package/src/wilt/middleware/request-logger.middleware.ts +17 -0
  87. package/src/wilt/pipes/index.ts +3 -0
  88. package/src/wilt/pipes/validate.pipe.ts +79 -0
  89. package/src/wilt/pipes/zod-query.pipe.ts +42 -0
  90. package/src/wilt/pipes/zod-validate.pipe.ts +49 -0
  91. package/src/wilt/services/index.ts +1 -0
  92. package/src/wilt/services/reflector.service.ts +24 -0
  93. package/src/wilt/utils/apply-decorators.util.ts +17 -0
  94. package/src/wilt/utils/forward-ref.util.ts +14 -0
  95. package/src/wilt/utils/index.ts +22 -0
  96. package/src/wilt/utils/logger.util.ts +189 -0
  97. package/src/wilt/utils/response.util.ts +72 -0
@@ -0,0 +1,413 @@
1
+ #!/usr/bin/env node
2
+
3
+ // bin/commands/new.ts
4
+ import { mkdirSync, writeFileSync, existsSync } from "fs";
5
+ import { join, resolve } from "path";
6
+ import { execSync } from "child_process";
7
+ function pascal(name) {
8
+ return name.replace(/[-_](.)/g, (_, c) => c.toUpperCase()).replace(/^(.)/, (_, c) => c.toUpperCase());
9
+ }
10
+ function kebab(name) {
11
+ return name.replace(/([A-Z])/g, "-$1").replace(/^-/, "").replace(/_/g, "-").toLowerCase();
12
+ }
13
+ function packageJsonTemplate(name) {
14
+ return JSON.stringify(
15
+ {
16
+ name: kebab(name),
17
+ version: "0.0.1",
18
+ private: true,
19
+ type: "module",
20
+ scripts: {
21
+ dev: "vite dev --host --port 4001",
22
+ "dev:cf": "wrangler dev --port 4001",
23
+ build: "vite build",
24
+ deploy: "vite build && wrangler deploy",
25
+ "cf-typegen": "wrangler types --env-interface CloudflareBindings",
26
+ test: "vitest --run",
27
+ "test:watch": "vitest --watch",
28
+ "db:gen": "drizzle-kit generate",
29
+ "db:migrate": "wrangler d1 migrations apply DB --local",
30
+ "db:migrate:remote": "wrangler d1 migrations apply DB --remote",
31
+ check: "tsc --noEmit",
32
+ wilt: "wilt"
33
+ },
34
+ dependencies: {
35
+ hono: "^4.12.0",
36
+ wilt: "^0.1.0",
37
+ "reflect-metadata": "^0.2.2",
38
+ tsyringe: "^4.10.0",
39
+ zod: "^4.0.0",
40
+ "drizzle-orm": "^0.45.0",
41
+ ulid: "^3.0.0"
42
+ },
43
+ devDependencies: {
44
+ "@cloudflare/vite-plugin": "^1.36.0",
45
+ "@cloudflare/workers-types": "^4.0.0",
46
+ "@cloudflare/vitest-pool-workers": "^0.16.0",
47
+ "@sohan_fahad/wilt": "^0.1.0",
48
+ "@types/node": "^22.0.0",
49
+ "drizzle-kit": "^0.31.0",
50
+ typescript: "^5.0.0",
51
+ vite: "^6.0.0",
52
+ vitest: "^4.1.0",
53
+ tsx: "^4.0.0",
54
+ wrangler: "^4.0.0"
55
+ }
56
+ },
57
+ null,
58
+ 2
59
+ );
60
+ }
61
+ function wranglerTemplate(name) {
62
+ return `{
63
+ "$schema": "node_modules/wrangler/config-schema.json",
64
+ "name": "${kebab(name)}",
65
+ "main": "./src/index.ts",
66
+ "compatibility_date": "2025-06-17",
67
+ "compatibility_flags": ["nodejs_compat"],
68
+ "vars": {
69
+ "MODE": "development"
70
+ },
71
+ "observability": { "enabled": true },
72
+ "d1_databases": [
73
+ {
74
+ "binding": "DB",
75
+ "database_name": "REPLACE_WITH_YOUR_D1_NAME",
76
+ "database_id": "00000000-0000-0000-0000-000000000001",
77
+ "migrations_dir": "migrations",
78
+ "preview_database_id": "00000000-0000-0000-0000-000000000002"
79
+ }
80
+ ],
81
+ "dev": { "port": 4001 }
82
+ }
83
+ `;
84
+ }
85
+ function tsconfigTemplate() {
86
+ return `{
87
+ "compilerOptions": {
88
+ "target": "ESNext",
89
+ "module": "ESNext",
90
+ "moduleResolution": "Bundler",
91
+ "strict": true,
92
+ "skipLibCheck": true,
93
+ "experimentalDecorators": true,
94
+ "emitDecoratorMetadata": true,
95
+ "lib": ["ESNext", "DOM"],
96
+ "types": ["vite/client", "@cloudflare/workers-types"],
97
+ "baseUrl": ".",
98
+ "paths": {
99
+ "@app/*": ["src/*"]
100
+ }
101
+ },
102
+ "include": ["src/**/*", "worker-configuration.d.ts"],
103
+ "exclude": ["node_modules", "dist"]
104
+ }
105
+ `;
106
+ }
107
+ function viteConfigTemplate() {
108
+ return `import { defineConfig } from "vite";
109
+ import { cloudflare } from "@cloudflare/vite-plugin";
110
+ import { fileURLToPath, URL } from "node:url";
111
+
112
+ export default defineConfig({
113
+ plugins: [cloudflare()],
114
+ resolve: {
115
+ alias: {
116
+ "@app": fileURLToPath(new URL("./src", import.meta.url)),
117
+ },
118
+ },
119
+ });
120
+ `;
121
+ }
122
+ function workerTypesTemplate() {
123
+ return `// Generated by \`pnpm cf-typegen\`. Do not edit manually.
124
+ /// <reference types="@cloudflare/vitest-pool-workers/types" />
125
+ interface CloudflareBindings {
126
+ DB: D1Database;
127
+ MODE: string;
128
+ }
129
+
130
+ declare namespace Cloudflare {
131
+ interface Env extends CloudflareBindings {
132
+ TEST_MIGRATIONS: string;
133
+ }
134
+ }
135
+ `;
136
+ }
137
+ function vitestConfigTemplate() {
138
+ return `import path from "path";
139
+ import { defineConfig } from "vitest/config";
140
+ import { cloudflarePool, cloudflareTest, readD1Migrations } from "@cloudflare/vitest-pool-workers";
141
+
142
+ export default defineConfig(async () => {
143
+ const migrations = await readD1Migrations("./migrations");
144
+ const poolOptions = {
145
+ wrangler: { configPath: "./wrangler.jsonc" },
146
+ miniflare: {
147
+ bindings: { TEST_MIGRATIONS: JSON.stringify(migrations) },
148
+ },
149
+ };
150
+ return {
151
+ plugins: [cloudflareTest(poolOptions)],
152
+ resolve: {
153
+ alias: { "@app": path.resolve("./src") },
154
+ },
155
+ test: {
156
+ pool: cloudflarePool(poolOptions),
157
+ },
158
+ };
159
+ });
160
+ `;
161
+ }
162
+ function indexTemplate() {
163
+ return `import "reflect-metadata";
164
+ import { app } from "./app.module";
165
+
166
+ export default {
167
+ async fetch(request: Request, env: CloudflareBindings, ctx: ExecutionContext): Promise<Response> {
168
+ return app.fetch(request, env, ctx);
169
+ },
170
+ };
171
+ `;
172
+ }
173
+ function appModuleTemplate(name) {
174
+ const p = pascal(name);
175
+ return `import { cors } from "hono/cors";
176
+ import { secureHeaders } from "hono/secure-headers";
177
+
178
+ import { Module, createModule } from "wilt";
179
+ import { requestLogger } from "wilt/middleware";
180
+ import { HelloModule } from "./modules/app/hello/hello.module";
181
+
182
+ @Module({
183
+ imports: [HelloModule],
184
+ })
185
+ export class AppModule {}
186
+
187
+ const app = createModule(AppModule, {
188
+ middlewares: [cors(), secureHeaders(), requestLogger],
189
+ });
190
+
191
+ app.get("/", (c) => c.json({ success: true, status: "healthy", timestamp: new Date().toISOString() }));
192
+ app.get("/health", (c) => c.json({ success: true, status: "healthy", timestamp: new Date().toISOString() }));
193
+
194
+ export { app };
195
+ `;
196
+ }
197
+ function helloModuleTemplate() {
198
+ return `import { Module } from "wilt";
199
+ import { HelloController } from "./hello.controller";
200
+ import { HelloService } from "./hello.service";
201
+
202
+ @Module({
203
+ controllers: [HelloController],
204
+ providers: [HelloService],
205
+ })
206
+ export class HelloModule {}
207
+ `;
208
+ }
209
+ function helloControllerTemplate() {
210
+ return `import type { Context } from "hono";
211
+ import { Controller, Get, Inject } from "wilt";
212
+ import { ResponseUtil } from "wilt";
213
+ import { HelloService } from "./hello.service";
214
+
215
+ @Controller("/hello")
216
+ export class HelloController {
217
+ constructor(@Inject(HelloService) private helloService: HelloService) {}
218
+
219
+ @Get()
220
+ async greet(c: Context) {
221
+ const message = this.helloService.greet();
222
+ return ResponseUtil.success(c, { message });
223
+ }
224
+ }
225
+ `;
226
+ }
227
+ function helloServiceTemplate() {
228
+ return `import { Injectable } from "wilt";
229
+
230
+ @Injectable()
231
+ export class HelloService {
232
+ greet() {
233
+ return "Hello from Wilt!";
234
+ }
235
+ }
236
+ `;
237
+ }
238
+ function dbSchemaTemplate() {
239
+ return `// Register all your entity tables here so Drizzle can build relations and
240
+ // drizzle-kit can generate migrations from a single source of truth.
241
+ export const schema = {};
242
+ `;
243
+ }
244
+ function dbConnectionTemplate() {
245
+ return `import { drizzle } from "drizzle-orm/d1";
246
+ import type { Context } from "hono";
247
+ import { schema } from "./schema";
248
+ export function getDb(c: Context) {
249
+ return drizzle(c.env.DB, { schema: schema });
250
+ }
251
+ `;
252
+ }
253
+ function gitignoreTemplate() {
254
+ return `dist/
255
+ node_modules/
256
+ .wrangler
257
+ .env
258
+ .env.production
259
+ .dev.vars
260
+ .DS_Store
261
+ coverage/
262
+ *.log
263
+ `;
264
+ }
265
+ function wiltConfigTemplate() {
266
+ return `import { defineConfig } from "wilt/config";
267
+
268
+ export default defineConfig({
269
+ // Directory where generated modules are placed (relative to project root)
270
+ modulesDir: "src/modules/app",
271
+
272
+ // Default files scaffolded by \`wilt generate module <name>\`
273
+ // Remove "test" to skip test files, or pass --no-test at the CLI
274
+ generate: {
275
+ files: ["module", "controller", "service", "dto", "entity", "test"],
276
+ },
277
+ });
278
+ `;
279
+ }
280
+ function envExampleTemplate() {
281
+ return `CLOUDFLARE_ACCOUNT_ID=
282
+ CLOUDFLARE_TOKEN=
283
+
284
+ CLOUDFLARE_DATABASE_ID=
285
+ `;
286
+ }
287
+ function drizzleConfigTemplate() {
288
+ return `import { defineConfig } from "drizzle-kit";
289
+
290
+ export default defineConfig({
291
+ schema: "./src/database/schema.ts",
292
+ out: "./migrations",
293
+ dialect: "sqlite",
294
+ driver: "d1-http",
295
+ dbCredentials: {
296
+ accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,
297
+ databaseId: process.env.CLOUDFLARE_DATABASE_ID!,
298
+ token: process.env.CLOUDFLARE_TOKEN!,
299
+ },
300
+ verbose: true,
301
+ strict: true,
302
+ });
303
+ `;
304
+ }
305
+ function migrationTemplate() {
306
+ return `-- Initial migration
307
+ -- Add your tables here
308
+ `;
309
+ }
310
+ function migrationMetaTemplate(name) {
311
+ return JSON.stringify(
312
+ {
313
+ version: "5",
314
+ dialect: "sqlite",
315
+ entries: [
316
+ {
317
+ idx: 0,
318
+ version: "5",
319
+ when: Date.now(),
320
+ tag: "0000_initial",
321
+ breakpoints: true
322
+ }
323
+ ]
324
+ },
325
+ null,
326
+ 2
327
+ );
328
+ }
329
+ function write(path, content) {
330
+ writeFileSync(path, content, "utf-8");
331
+ console.log(` \u2714 ${path.replace(process.cwd() + "/", "")}`);
332
+ }
333
+ function dir(path) {
334
+ mkdirSync(path, { recursive: true });
335
+ }
336
+ function runNew(args) {
337
+ const [name] = args;
338
+ if (!name) {
339
+ console.error(" \u2717 Usage: wilt new <project-name>");
340
+ process.exit(1);
341
+ }
342
+ const projectDir = resolve(process.cwd(), name);
343
+ if (existsSync(projectDir)) {
344
+ console.error(` \u2717 Directory already exists: ${projectDir}`);
345
+ process.exit(1);
346
+ }
347
+ console.log(`
348
+ Creating Wilt app "${name}"...
349
+ `);
350
+ dir(join(projectDir, "src/modules/app/hello"));
351
+ dir(join(projectDir, "src/database"));
352
+ dir(join(projectDir, "migrations/meta"));
353
+ write(join(projectDir, "package.json"), packageJsonTemplate(name));
354
+ write(join(projectDir, "wrangler.jsonc"), wranglerTemplate(name));
355
+ write(join(projectDir, "tsconfig.json"), tsconfigTemplate());
356
+ write(join(projectDir, "vite.config.ts"), viteConfigTemplate());
357
+ write(join(projectDir, "vitest.config.ts"), vitestConfigTemplate());
358
+ write(join(projectDir, "worker-configuration.d.ts"), workerTypesTemplate());
359
+ write(join(projectDir, "wilt.config.ts"), wiltConfigTemplate());
360
+ write(join(projectDir, ".gitignore"), gitignoreTemplate());
361
+ write(join(projectDir, ".env.example"), envExampleTemplate());
362
+ write(join(projectDir, "drizzle.config.ts"), drizzleConfigTemplate());
363
+ write(join(projectDir, "src/index.ts"), indexTemplate());
364
+ write(join(projectDir, "src/app.module.ts"), appModuleTemplate(name));
365
+ write(join(projectDir, "src/modules/app/hello/hello.module.ts"), helloModuleTemplate());
366
+ write(join(projectDir, "src/modules/app/hello/hello.controller.ts"), helloControllerTemplate());
367
+ write(join(projectDir, "src/modules/app/hello/hello.service.ts"), helloServiceTemplate());
368
+ write(join(projectDir, "src/database/schema.ts"), dbSchemaTemplate());
369
+ write(join(projectDir, "src/database/connection.ts"), dbConnectionTemplate());
370
+ write(join(projectDir, "migrations/0000_initial.sql"), migrationTemplate());
371
+ write(join(projectDir, "migrations/meta/_journal.json"), migrationMetaTemplate(name));
372
+ console.log("\n Installing dependencies...\n");
373
+ try {
374
+ const pm = detectPackageManager();
375
+ execSync(`${pm} install`, { cwd: projectDir, stdio: "inherit" });
376
+ } catch {
377
+ console.log(" \u26A0 Could not auto-install. Run `pnpm install` manually.\n");
378
+ }
379
+ console.log(`
380
+ \u2714 Project created!
381
+
382
+ Next steps:
383
+ cd ${name}
384
+ cp .env.example .env # fill in Cloudflare credentials
385
+ # Edit wrangler.jsonc: set database_name + database_id
386
+ pnpm db:migrate # apply local D1 migrations
387
+ pnpm dev # http://localhost:4001
388
+
389
+ Try it:
390
+ curl http://localhost:4001/health
391
+ curl http://localhost:4001/hello
392
+
393
+ Generate a new module:
394
+ pnpm wilt generate module posts
395
+ `);
396
+ }
397
+ function detectPackageManager() {
398
+ try {
399
+ execSync("pnpm --version", { stdio: "ignore" });
400
+ return "pnpm";
401
+ } catch {
402
+ }
403
+ try {
404
+ execSync("bun --version", { stdio: "ignore" });
405
+ return "bun";
406
+ } catch {
407
+ }
408
+ return "npm";
409
+ }
410
+
411
+ // bin/create-wilt-app.ts
412
+ runNew(process.argv.slice(2));
413
+ //# sourceMappingURL=create-wilt-app.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../bin/commands/new.ts","../../../bin/create-wilt-app.ts"],"sourcesContent":["import { mkdirSync, writeFileSync, existsSync } from \"node:fs\";\nimport { join, resolve } from \"node:path\";\nimport { execSync } from \"node:child_process\";\n\nfunction pascal(name: string) {\n return name\n .replace(/[-_](.)/g, (_, c) => c.toUpperCase())\n .replace(/^(.)/, (_, c) => c.toUpperCase());\n}\n\nfunction kebab(name: string) {\n return name\n .replace(/([A-Z])/g, \"-$1\")\n .replace(/^-/, \"\")\n .replace(/_/g, \"-\")\n .toLowerCase();\n}\n\n// ─── File templates ───────────────────────────────────────────────────────────\n\nfunction packageJsonTemplate(name: string) {\n return JSON.stringify(\n {\n name: kebab(name),\n version: \"0.0.1\",\n private: true,\n type: \"module\",\n scripts: {\n dev: \"vite dev --host --port 4001\",\n \"dev:cf\": \"wrangler dev --port 4001\",\n build: \"vite build\",\n deploy: \"vite build && wrangler deploy\",\n \"cf-typegen\": \"wrangler types --env-interface CloudflareBindings\",\n test: \"vitest --run\",\n \"test:watch\": \"vitest --watch\",\n \"db:gen\": \"drizzle-kit generate\",\n \"db:migrate\": \"wrangler d1 migrations apply DB --local\",\n \"db:migrate:remote\": \"wrangler d1 migrations apply DB --remote\",\n check: \"tsc --noEmit\",\n wilt: \"wilt\",\n },\n dependencies: {\n hono: \"^4.12.0\",\n wilt: \"^0.1.0\",\n \"reflect-metadata\": \"^0.2.2\",\n tsyringe: \"^4.10.0\",\n zod: \"^4.0.0\",\n \"drizzle-orm\": \"^0.45.0\",\n ulid: \"^3.0.0\",\n },\n devDependencies: {\n \"@cloudflare/vite-plugin\": \"^1.36.0\",\n \"@cloudflare/workers-types\": \"^4.0.0\",\n \"@cloudflare/vitest-pool-workers\": \"^0.16.0\",\n \"@sohan_fahad/wilt\": \"^0.1.0\",\n \"@types/node\": \"^22.0.0\",\n \"drizzle-kit\": \"^0.31.0\",\n typescript: \"^5.0.0\",\n vite: \"^6.0.0\",\n vitest: \"^4.1.0\",\n tsx: \"^4.0.0\",\n wrangler: \"^4.0.0\",\n },\n },\n null,\n 2\n );\n}\n\nfunction wranglerTemplate(name: string) {\n return `{\n \"$schema\": \"node_modules/wrangler/config-schema.json\",\n \"name\": \"${kebab(name)}\",\n \"main\": \"./src/index.ts\",\n \"compatibility_date\": \"2025-06-17\",\n \"compatibility_flags\": [\"nodejs_compat\"],\n \"vars\": {\n \"MODE\": \"development\"\n },\n \"observability\": { \"enabled\": true },\n \"d1_databases\": [\n {\n \"binding\": \"DB\",\n \"database_name\": \"REPLACE_WITH_YOUR_D1_NAME\",\n \"database_id\": \"00000000-0000-0000-0000-000000000001\",\n \"migrations_dir\": \"migrations\",\n \"preview_database_id\": \"00000000-0000-0000-0000-000000000002\"\n }\n ],\n \"dev\": { \"port\": 4001 }\n}\n`;\n}\n\nfunction tsconfigTemplate() {\n return `{\n \"compilerOptions\": {\n \"target\": \"ESNext\",\n \"module\": \"ESNext\",\n \"moduleResolution\": \"Bundler\",\n \"strict\": true,\n \"skipLibCheck\": true,\n \"experimentalDecorators\": true,\n \"emitDecoratorMetadata\": true,\n \"lib\": [\"ESNext\", \"DOM\"],\n \"types\": [\"vite/client\", \"@cloudflare/workers-types\"],\n \"baseUrl\": \".\",\n \"paths\": {\n \"@app/*\": [\"src/*\"]\n }\n },\n \"include\": [\"src/**/*\", \"worker-configuration.d.ts\"],\n \"exclude\": [\"node_modules\", \"dist\"]\n}\n`;\n}\n\nfunction viteConfigTemplate() {\n return `import { defineConfig } from \"vite\";\nimport { cloudflare } from \"@cloudflare/vite-plugin\";\nimport { fileURLToPath, URL } from \"node:url\";\n\nexport default defineConfig({\n plugins: [cloudflare()],\n resolve: {\n alias: {\n \"@app\": fileURLToPath(new URL(\"./src\", import.meta.url)),\n },\n },\n});\n`;\n}\n\nfunction workerTypesTemplate() {\n return `// Generated by \\`pnpm cf-typegen\\`. Do not edit manually.\n/// <reference types=\"@cloudflare/vitest-pool-workers/types\" />\ninterface CloudflareBindings {\n DB: D1Database;\n MODE: string;\n}\n\ndeclare namespace Cloudflare {\n interface Env extends CloudflareBindings {\n TEST_MIGRATIONS: string;\n }\n}\n`;\n}\n\nfunction vitestConfigTemplate() {\n return `import path from \"path\";\nimport { defineConfig } from \"vitest/config\";\nimport { cloudflarePool, cloudflareTest, readD1Migrations } from \"@cloudflare/vitest-pool-workers\";\n\nexport default defineConfig(async () => {\n const migrations = await readD1Migrations(\"./migrations\");\n const poolOptions = {\n wrangler: { configPath: \"./wrangler.jsonc\" },\n miniflare: {\n bindings: { TEST_MIGRATIONS: JSON.stringify(migrations) },\n },\n };\n return {\n plugins: [cloudflareTest(poolOptions)],\n resolve: {\n alias: { \"@app\": path.resolve(\"./src\") },\n },\n test: {\n pool: cloudflarePool(poolOptions),\n },\n };\n});\n`;\n}\n\nfunction indexTemplate() {\n return `import \"reflect-metadata\";\nimport { app } from \"./app.module\";\n\nexport default {\n async fetch(request: Request, env: CloudflareBindings, ctx: ExecutionContext): Promise<Response> {\n return app.fetch(request, env, ctx);\n },\n};\n`;\n}\n\nfunction appModuleTemplate(name: string) {\n const p = pascal(name);\n return `import { cors } from \"hono/cors\";\nimport { secureHeaders } from \"hono/secure-headers\";\n\nimport { Module, createModule } from \"wilt\";\nimport { requestLogger } from \"wilt/middleware\";\nimport { HelloModule } from \"./modules/app/hello/hello.module\";\n\n@Module({\n imports: [HelloModule],\n})\nexport class AppModule {}\n\nconst app = createModule(AppModule, {\n middlewares: [cors(), secureHeaders(), requestLogger],\n});\n\napp.get(\"/\", (c) => c.json({ success: true, status: \"healthy\", timestamp: new Date().toISOString() }));\napp.get(\"/health\", (c) => c.json({ success: true, status: \"healthy\", timestamp: new Date().toISOString() }));\n\nexport { app };\n`;\n}\n\nfunction helloModuleTemplate() {\n return `import { Module } from \"wilt\";\nimport { HelloController } from \"./hello.controller\";\nimport { HelloService } from \"./hello.service\";\n\n@Module({\n controllers: [HelloController],\n providers: [HelloService],\n})\nexport class HelloModule {}\n`;\n}\n\nfunction helloControllerTemplate() {\n return `import type { Context } from \"hono\";\nimport { Controller, Get, Inject } from \"wilt\";\nimport { ResponseUtil } from \"wilt\";\nimport { HelloService } from \"./hello.service\";\n\n@Controller(\"/hello\")\nexport class HelloController {\n constructor(@Inject(HelloService) private helloService: HelloService) {}\n\n @Get()\n async greet(c: Context) {\n const message = this.helloService.greet();\n return ResponseUtil.success(c, { message });\n }\n}\n`;\n}\n\nfunction helloServiceTemplate() {\n return `import { Injectable } from \"wilt\";\n\n@Injectable()\nexport class HelloService {\n greet() {\n return \"Hello from Wilt!\";\n }\n}\n`;\n}\n\nfunction dbSchemaTemplate() {\n return `// Register all your entity tables here so Drizzle can build relations and\n// drizzle-kit can generate migrations from a single source of truth.\nexport const schema = {};\n`;\n}\n\nfunction dbConnectionTemplate() {\n return `import { drizzle } from \"drizzle-orm/d1\";\nimport type { Context } from \"hono\";\nimport { schema } from \"./schema\";\nexport function getDb(c: Context) {\n return drizzle(c.env.DB, { schema: schema });\n}\n`;\n}\n\nfunction gitignoreTemplate() {\n return `dist/\nnode_modules/\n.wrangler\n.env\n.env.production\n.dev.vars\n.DS_Store\ncoverage/\n*.log\n`;\n}\n\n\nfunction wiltConfigTemplate() {\n return `import { defineConfig } from \"wilt/config\";\n\nexport default defineConfig({\n // Directory where generated modules are placed (relative to project root)\n modulesDir: \"src/modules/app\",\n\n // Default files scaffolded by \\`wilt generate module <name>\\`\n // Remove \"test\" to skip test files, or pass --no-test at the CLI\n generate: {\n files: [\"module\", \"controller\", \"service\", \"dto\", \"entity\", \"test\"],\n },\n});\n`;\n}\n\nfunction envExampleTemplate() {\n return `CLOUDFLARE_ACCOUNT_ID=\nCLOUDFLARE_TOKEN=\n\nCLOUDFLARE_DATABASE_ID=\n`;\n}\n\nfunction drizzleConfigTemplate() {\n return `import { defineConfig } from \"drizzle-kit\";\n\nexport default defineConfig({\n schema: \"./src/database/schema.ts\",\n out: \"./migrations\",\n dialect: \"sqlite\",\n driver: \"d1-http\",\n dbCredentials: {\n accountId: process.env.CLOUDFLARE_ACCOUNT_ID!,\n databaseId: process.env.CLOUDFLARE_DATABASE_ID!,\n token: process.env.CLOUDFLARE_TOKEN!,\n },\n verbose: true,\n strict: true,\n});\n`;\n}\n\nfunction migrationTemplate() {\n return `-- Initial migration\n-- Add your tables here\n`;\n}\n\nfunction migrationMetaTemplate(name: string) {\n return JSON.stringify(\n {\n version: \"5\",\n dialect: \"sqlite\",\n entries: [\n {\n idx: 0,\n version: \"5\",\n when: Date.now(),\n tag: \"0000_initial\",\n breakpoints: true,\n },\n ],\n },\n null,\n 2\n );\n}\n\n// ─── Scaffold ─────────────────────────────────────────────────────────────────\n\nfunction write(path: string, content: string) {\n writeFileSync(path, content, \"utf-8\");\n console.log(` ✔ ${path.replace(process.cwd() + \"/\", \"\")}`);\n}\n\nfunction dir(path: string) {\n mkdirSync(path, { recursive: true });\n}\n\nexport function runNew(args: string[]): void {\n const [name] = args;\n\n if (!name) {\n console.error(\" ✗ Usage: wilt new <project-name>\");\n process.exit(1);\n }\n\n const projectDir = resolve(process.cwd(), name);\n\n if (existsSync(projectDir)) {\n console.error(` ✗ Directory already exists: ${projectDir}`);\n process.exit(1);\n }\n\n console.log(`\\n Creating Wilt app \"${name}\"...\\n`);\n\n // Directories\n dir(join(projectDir, \"src/modules/app/hello\"));\n dir(join(projectDir, \"src/database\"));\n dir(join(projectDir, \"migrations/meta\"));\n\n // Config files\n write(join(projectDir, \"package.json\"), packageJsonTemplate(name));\n write(join(projectDir, \"wrangler.jsonc\"), wranglerTemplate(name));\n write(join(projectDir, \"tsconfig.json\"), tsconfigTemplate());\n write(join(projectDir, \"vite.config.ts\"), viteConfigTemplate());\n write(join(projectDir, \"vitest.config.ts\"), vitestConfigTemplate());\n write(join(projectDir, \"worker-configuration.d.ts\"), workerTypesTemplate());\n write(join(projectDir, \"wilt.config.ts\"), wiltConfigTemplate());\n write(join(projectDir, \".gitignore\"), gitignoreTemplate());\n write(join(projectDir, \".env.example\"), envExampleTemplate());\n write(join(projectDir, \"drizzle.config.ts\"), drizzleConfigTemplate());\n\n // App entry\n write(join(projectDir, \"src/index.ts\"), indexTemplate());\n write(join(projectDir, \"src/app.module.ts\"), appModuleTemplate(name));\n\n // Hello module\n write(join(projectDir, \"src/modules/app/hello/hello.module.ts\"), helloModuleTemplate());\n write(join(projectDir, \"src/modules/app/hello/hello.controller.ts\"), helloControllerTemplate());\n write(join(projectDir, \"src/modules/app/hello/hello.service.ts\"), helloServiceTemplate());\n\n // Database\n write(join(projectDir, \"src/database/schema.ts\"), dbSchemaTemplate());\n write(join(projectDir, \"src/database/connection.ts\"), dbConnectionTemplate());\n\n // Migrations\n write(join(projectDir, \"migrations/0000_initial.sql\"), migrationTemplate());\n write(join(projectDir, \"migrations/meta/_journal.json\"), migrationMetaTemplate(name));\n\n // Try to install dependencies\n console.log(\"\\n Installing dependencies...\\n\");\n try {\n const pm = detectPackageManager();\n execSync(`${pm} install`, { cwd: projectDir, stdio: \"inherit\" });\n } catch {\n console.log(\" ⚠ Could not auto-install. Run `pnpm install` manually.\\n\");\n }\n\n console.log(`\n ✔ Project created!\n\n Next steps:\n cd ${name}\n cp .env.example .env # fill in Cloudflare credentials\n # Edit wrangler.jsonc: set database_name + database_id\n pnpm db:migrate # apply local D1 migrations\n pnpm dev # http://localhost:4001\n\n Try it:\n curl http://localhost:4001/health\n curl http://localhost:4001/hello\n\n Generate a new module:\n pnpm wilt generate module posts\n`);\n}\n\nfunction detectPackageManager(): string {\n try {\n execSync(\"pnpm --version\", { stdio: \"ignore\" });\n return \"pnpm\";\n } catch { }\n try {\n execSync(\"bun --version\", { stdio: \"ignore\" });\n return \"bun\";\n } catch { }\n return \"npm\";\n}\n","import { runNew } from \"./commands/new.js\";\n\nrunNew(process.argv.slice(2));\n"],"mappings":"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","names":[]}