@kozojs/cli 0.1.20 → 0.1.22

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.
@@ -1,43 +1,18 @@
1
- #!/usr/bin/env node
2
- "use strict";
3
- var __create = Object.create;
4
- var __defProp = Object.defineProperty;
5
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
- var __getOwnPropNames = Object.getOwnPropertyNames;
7
- var __getProtoOf = Object.getPrototypeOf;
8
- var __hasOwnProp = Object.prototype.hasOwnProperty;
9
- var __copyProps = (to, from, except, desc) => {
10
- if (from && typeof from === "object" || typeof from === "function") {
11
- for (let key of __getOwnPropNames(from))
12
- if (!__hasOwnProp.call(to, key) && key !== except)
13
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
- }
15
- return to;
16
- };
17
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
- // If the importer is in node compatibility mode or this is not an ESM
19
- // file that has been converted to a CommonJS file using a Babel-
20
- // compatible transform (i.e. "__esModule" has not been set), then set
21
- // "default" to the CommonJS "module.exports" for node compatibility.
22
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
- mod
24
- ));
25
-
26
1
  // src/index.ts
27
- var import_commander = require("commander");
2
+ import { Command } from "commander";
28
3
 
29
4
  // src/commands/new.ts
30
- var p = __toESM(require("@clack/prompts"));
31
- var import_picocolors2 = __toESM(require("picocolors"));
32
- var import_execa = require("execa");
5
+ import * as p from "@clack/prompts";
6
+ import pc2 from "picocolors";
7
+ import { execa } from "execa";
33
8
 
34
9
  // src/utils/scaffold.ts
35
- var import_fs_extra = __toESM(require("fs-extra"));
36
- var import_node_path = __toESM(require("path"));
10
+ import fs from "fs-extra";
11
+ import path from "path";
37
12
  async function scaffoldProject(options) {
38
13
  const { projectName, runtime, database, dbPort, auth, packageSource, template, frontend, extras } = options;
39
- const projectDir = import_node_path.default.resolve(process.cwd(), projectName);
40
- const kozoCoreDep = packageSource === "local" ? "workspace:*" : "^0.2.0";
14
+ const projectDir = path.resolve(process.cwd(), projectName);
15
+ const kozoCoreDep = packageSource === "local" ? "workspace:*" : "^0.3.1";
41
16
  if (frontend !== "none") {
42
17
  await scaffoldFullstackProject(projectDir, projectName, kozoCoreDep, runtime, database, dbPort, auth, frontend, extras, template);
43
18
  return;
@@ -55,9 +30,9 @@ async function scaffoldProject(options) {
55
30
  if (extras.includes("github-actions")) await createGitHubActions(projectDir);
56
31
  return;
57
32
  }
58
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "routes"));
59
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "db"));
60
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "services"));
33
+ await fs.ensureDir(path.join(projectDir, "src", "routes"));
34
+ await fs.ensureDir(path.join(projectDir, "src", "db"));
35
+ await fs.ensureDir(path.join(projectDir, "src", "services"));
61
36
  const packageJson = {
62
37
  name: projectName,
63
38
  version: "0.1.0",
@@ -72,6 +47,7 @@ async function scaffoldProject(options) {
72
47
  },
73
48
  dependencies: {
74
49
  "@kozojs/core": kozoCoreDep,
50
+ "uWebSockets.js": "github:uNetworking/uWebSockets.js#6609a88ffa9a16ac5158046761356ce03250a0df",
75
51
  hono: "^4.6.0",
76
52
  zod: "^3.23.0",
77
53
  "drizzle-orm": "^0.36.0",
@@ -87,7 +63,7 @@ async function scaffoldProject(options) {
87
63
  ...database === "sqlite" && { "@types/better-sqlite3": "^7.6.0" }
88
64
  }
89
65
  };
90
- await import_fs_extra.default.writeJSON(import_node_path.default.join(projectDir, "package.json"), packageJson, { spaces: 2 });
66
+ await fs.writeJSON(path.join(projectDir, "package.json"), packageJson, { spaces: 2 });
91
67
  const tsconfig = {
92
68
  compilerOptions: {
93
69
  target: "ES2022",
@@ -103,7 +79,7 @@ async function scaffoldProject(options) {
103
79
  include: ["src/**/*"],
104
80
  exclude: ["node_modules", "dist"]
105
81
  };
106
- await import_fs_extra.default.writeJSON(import_node_path.default.join(projectDir, "tsconfig.json"), tsconfig, { spaces: 2 });
82
+ await fs.writeJSON(path.join(projectDir, "tsconfig.json"), tsconfig, { spaces: 2 });
107
83
  const drizzleConfig = `import { defineConfig } from 'drizzle-kit';
108
84
 
109
85
  export default defineConfig({
@@ -115,21 +91,21 @@ export default defineConfig({
115
91
  }
116
92
  });
117
93
  `;
118
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "drizzle.config.ts"), drizzleConfig);
94
+ await fs.writeFile(path.join(projectDir, "drizzle.config.ts"), drizzleConfig);
119
95
  const envExample = `# Database
120
96
  ${database === "sqlite" ? "# SQLite uses local file, no URL needed" : "DATABASE_URL="}
121
97
 
122
98
  # Server
123
99
  PORT=3000
124
100
  `;
125
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".env.example"), envExample);
101
+ await fs.writeFile(path.join(projectDir, ".env.example"), envExample);
126
102
  const gitignore = `node_modules/
127
103
  dist/
128
104
  .env
129
105
  *.db
130
106
  .turbo/
131
107
  `;
132
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".gitignore"), gitignore);
108
+ await fs.writeFile(path.join(projectDir, ".gitignore"), gitignore);
133
109
  const indexTs = `import { createKozo } from '@kozojs/core';
134
110
  import { services } from './services/index.js';
135
111
 
@@ -151,9 +127,9 @@ const app = createKozo({
151
127
  }
152
128
  });
153
129
 
154
- app.listen();
130
+ await app.nativeListen();
155
131
  `;
156
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "index.ts"), indexTs);
132
+ await fs.writeFile(path.join(projectDir, "src", "index.ts"), indexTs);
157
133
  const servicesTs = `import { db } from '../db/index.js';
158
134
 
159
135
  export const services = {
@@ -167,14 +143,14 @@ declare module '@kozojs/core' {
167
143
  }
168
144
  }
169
145
  `;
170
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "services", "index.ts"), servicesTs);
146
+ await fs.writeFile(path.join(projectDir, "src", "services", "index.ts"), servicesTs);
171
147
  const schemaTs = getDatabaseSchema(database);
172
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "db", "schema.ts"), schemaTs);
148
+ await fs.writeFile(path.join(projectDir, "src", "db", "schema.ts"), schemaTs);
173
149
  const dbIndexTs = getDatabaseIndex(database);
174
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "db", "index.ts"), dbIndexTs);
150
+ await fs.writeFile(path.join(projectDir, "src", "db", "index.ts"), dbIndexTs);
175
151
  if (database === "sqlite") {
176
152
  const seedTs = getSQLiteSeed();
177
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "db", "seed.ts"), seedTs);
153
+ await fs.writeFile(path.join(projectDir, "src", "db", "seed.ts"), seedTs);
178
154
  }
179
155
  await createExampleRoutes(projectDir);
180
156
  const readme = `# ${projectName}
@@ -250,7 +226,7 @@ ${database === "sqlite" ? "## SQLite Notes\n\nThe database is automatically init
250
226
  - [Drizzle ORM](https://orm.drizzle.team)
251
227
  - [Hono](https://hono.dev)
252
228
  `;
253
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "README.md"), readme);
229
+ await fs.writeFile(path.join(projectDir, "README.md"), readme);
254
230
  if (database !== "none" && database !== "sqlite") await createDockerCompose(projectDir, projectName, database, dbPort);
255
231
  if (extras.includes("docker")) await createDockerfile(projectDir, runtime);
256
232
  if (extras.includes("github-actions")) await createGitHubActions(projectDir);
@@ -370,8 +346,8 @@ async function createExampleRoutes(projectDir) {
370
346
  };
371
347
  };
372
348
  `;
373
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "routes", "index.ts"), indexRoute);
374
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "routes", "users"));
349
+ await fs.writeFile(path.join(projectDir, "src", "routes", "index.ts"), indexRoute);
350
+ await fs.ensureDir(path.join(projectDir, "src", "routes", "users"));
375
351
  const getUsersRoute = `import type { HandlerContext } from '@kozojs/core';
376
352
  import { users } from '../../db/schema.js';
377
353
 
@@ -385,7 +361,7 @@ export default async ({ services: { db } }: HandlerContext) => {
385
361
  return { users: allUsers };
386
362
  };
387
363
  `;
388
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "routes", "users", "get.ts"), getUsersRoute);
364
+ await fs.writeFile(path.join(projectDir, "src", "routes", "users", "get.ts"), getUsersRoute);
389
365
  const postUsersRoute = `import { z } from 'zod';
390
366
  import type { HandlerContext } from '@kozojs/core';
391
367
  import { users } from '../../db/schema.js';
@@ -413,26 +389,26 @@ export default async ({ body, services: { db } }: HandlerContext<Body>) => {
413
389
  return { success: true, user };
414
390
  };
415
391
  `;
416
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "routes", "users", "post.ts"), postUsersRoute);
392
+ await fs.writeFile(path.join(projectDir, "src", "routes", "users", "post.ts"), postUsersRoute);
417
393
  }
418
394
  async function scaffoldCompleteTemplate(projectDir, projectName, kozoCoreDep, runtime, database = "none", dbPort, auth = true) {
419
- await import_fs_extra.default.ensureDir(projectDir);
420
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src"));
421
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "schemas"));
422
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "routes"));
423
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "routes", "auth"));
424
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "routes", "users"));
425
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "routes", "posts"));
426
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "middleware"));
427
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "utils"));
428
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "data"));
395
+ await fs.ensureDir(projectDir);
396
+ await fs.ensureDir(path.join(projectDir, "src"));
397
+ await fs.ensureDir(path.join(projectDir, "src", "schemas"));
398
+ await fs.ensureDir(path.join(projectDir, "src", "routes"));
399
+ await fs.ensureDir(path.join(projectDir, "src", "routes", "auth"));
400
+ await fs.ensureDir(path.join(projectDir, "src", "routes", "users"));
401
+ await fs.ensureDir(path.join(projectDir, "src", "routes", "posts"));
402
+ await fs.ensureDir(path.join(projectDir, "src", "middleware"));
403
+ await fs.ensureDir(path.join(projectDir, "src", "utils"));
404
+ await fs.ensureDir(path.join(projectDir, "src", "data"));
429
405
  const hasDb = database !== "none";
430
406
  if (hasDb) {
431
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src", "db"));
432
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "db", "schema.ts"), getDatabaseSchema(database));
433
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "db", "index.ts"), getDatabaseIndex(database));
407
+ await fs.ensureDir(path.join(projectDir, "src", "db"));
408
+ await fs.writeFile(path.join(projectDir, "src", "db", "schema.ts"), getDatabaseSchema(database));
409
+ await fs.writeFile(path.join(projectDir, "src", "db", "index.ts"), getDatabaseIndex(database));
434
410
  if (database === "sqlite") {
435
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "db", "seed.ts"), getSQLiteSeed());
411
+ await fs.writeFile(path.join(projectDir, "src", "db", "seed.ts"), getSQLiteSeed());
436
412
  }
437
413
  }
438
414
  const packageJson = {
@@ -454,6 +430,7 @@ async function scaffoldCompleteTemplate(projectDir, projectName, kozoCoreDep, ru
454
430
  "@kozojs/core": kozoCoreDep,
455
431
  ...auth && { "@kozojs/auth": kozoCoreDep === "workspace:*" ? "workspace:*" : "^0.1.0" },
456
432
  "@hono/node-server": "^1.13.0",
433
+ ...runtime === "node" && { "uWebSockets.js": "github:uNetworking/uWebSockets.js#6609a88ffa9a16ac5158046761356ce03250a0df" },
457
434
  hono: "^4.6.0",
458
435
  zod: "^3.23.0",
459
436
  dotenv: "^16.4.0",
@@ -470,7 +447,7 @@ async function scaffoldCompleteTemplate(projectDir, projectName, kozoCoreDep, ru
470
447
  ...database === "sqlite" && { "@types/better-sqlite3": "^7.6.0" }
471
448
  }
472
449
  };
473
- await import_fs_extra.default.writeJSON(import_node_path.default.join(projectDir, "package.json"), packageJson, { spaces: 2 });
450
+ await fs.writeJSON(path.join(projectDir, "package.json"), packageJson, { spaces: 2 });
474
451
  const tsconfig = {
475
452
  compilerOptions: {
476
453
  target: "ES2022",
@@ -488,14 +465,14 @@ async function scaffoldCompleteTemplate(projectDir, projectName, kozoCoreDep, ru
488
465
  include: ["src/**/*"],
489
466
  exclude: ["node_modules", "dist"]
490
467
  };
491
- await import_fs_extra.default.writeJSON(import_node_path.default.join(projectDir, "tsconfig.json"), tsconfig, { spaces: 2 });
468
+ await fs.writeJSON(path.join(projectDir, "tsconfig.json"), tsconfig, { spaces: 2 });
492
469
  const gitignore = `node_modules/
493
470
  dist/
494
471
  .env
495
472
  .turbo/
496
473
  *.log
497
474
  `;
498
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".gitignore"), gitignore);
475
+ await fs.writeFile(path.join(projectDir, ".gitignore"), gitignore);
499
476
  const pgPort = dbPort ?? 5436;
500
477
  const dbUrl = database === "postgresql" ? `postgresql://postgres:postgres@localhost:${pgPort}/${projectName}` : database === "mysql" ? `mysql://root:root@localhost:3306/${projectName}` : void 0;
501
478
  const envExample = `# Server
@@ -515,8 +492,8 @@ CORS_ORIGIN=http://localhost:5173
515
492
  RATE_LIMIT_MAX=100
516
493
  RATE_LIMIT_WINDOW=60000
517
494
  `;
518
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".env.example"), envExample);
519
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".env"), envExample);
495
+ await fs.writeFile(path.join(projectDir, ".env.example"), envExample);
496
+ await fs.writeFile(path.join(projectDir, ".env"), envExample);
520
497
  if (hasDb) {
521
498
  const dialect = database === "postgresql" ? "postgresql" : database === "mysql" ? "mysql" : "sqlite";
522
499
  const drizzleConfig = `import { defineConfig } from 'drizzle-kit';
@@ -531,7 +508,7 @@ export default defineConfig({
531
508
  },
532
509
  });
533
510
  `;
534
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "drizzle.config.ts"), drizzleConfig);
511
+ await fs.writeFile(path.join(projectDir, "drizzle.config.ts"), drizzleConfig);
535
512
  }
536
513
  const indexTs = `import { createKozo, cors, logger, rateLimit } from '@kozojs/core';
537
514
  ${auth ? "import { authenticateJWT } from '@kozojs/auth';" : ""}
@@ -576,7 +553,7 @@ console.log('');
576
553
  console.log('\u{1F525} Kozo server starting\u2026');
577
554
  console.log('');
578
555
 
579
- await app.listen(PORT);
556
+ await app.nativeListen(PORT);
580
557
  console.log('');
581
558
  console.log('\u{1F4DA} Endpoints:');
582
559
  console.log(' GET /health Health check');
@@ -594,7 +571,7 @@ console.log('');
594
571
  console.log('\u{1F512} Middleware: CORS \xB7 Rate limit \xB7 JWT \xB7 Logger');
595
572
  console.log('\u{1F6E1}\uFE0F Graceful shutdown enabled (SIGTERM / SIGINT)');
596
573
  `;
597
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "index.ts"), indexTs);
574
+ await fs.writeFile(path.join(projectDir, "src", "index.ts"), indexTs);
598
575
  await createCompleteSchemas(projectDir);
599
576
  await createCompleteUtils(projectDir);
600
577
  await createCompleteDataStore(projectDir);
@@ -759,7 +736,7 @@ Request \u2500\u2500\u25BA \u2502 uWebSockets \u2502 C++ HTTP parser + epoll/kq
759
736
 
760
737
  Built with \u2764\uFE0F using Kozo Framework
761
738
  `;
762
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "README.md"), readme);
739
+ await fs.writeFile(path.join(projectDir, "README.md"), readme);
763
740
  }
764
741
  async function createCompleteSchemas(projectDir) {
765
742
  const userSchemas = `import { z } from 'zod';
@@ -788,7 +765,7 @@ export type User = z.infer<typeof UserSchema>;
788
765
  export type CreateUser = z.infer<typeof CreateUserSchema>;
789
766
  export type UpdateUser = z.infer<typeof UpdateUserSchema>;
790
767
  `;
791
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "schemas", "user.ts"), userSchemas);
768
+ await fs.writeFile(path.join(projectDir, "src", "schemas", "user.ts"), userSchemas);
792
769
  const postSchemas = `import { z } from 'zod';
793
770
  import { UserSchema } from './user.js';
794
771
 
@@ -818,7 +795,7 @@ export type Post = z.infer<typeof PostSchema>;
818
795
  export type PostWithAuthor = z.infer<typeof PostWithAuthorSchema>;
819
796
  export type CreatePost = z.infer<typeof CreatePostSchema>;
820
797
  `;
821
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "schemas", "post.ts"), postSchemas);
798
+ await fs.writeFile(path.join(projectDir, "src", "schemas", "post.ts"), postSchemas);
822
799
  const commonSchemas = `import { z } from 'zod';
823
800
 
824
801
  export const PaginationSchema = z.object({
@@ -835,7 +812,7 @@ export const PostFiltersSchema = z.object({
835
812
  export type Pagination = z.infer<typeof PaginationSchema>;
836
813
  export type PostFilters = z.infer<typeof PostFiltersSchema>;
837
814
  `;
838
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "schemas", "common.ts"), commonSchemas);
815
+ await fs.writeFile(path.join(projectDir, "src", "schemas", "common.ts"), commonSchemas);
839
816
  }
840
817
  async function createCompleteUtils(projectDir) {
841
818
  const helpers = `export function generateUUID(): string {
@@ -858,7 +835,7 @@ export function paginate<T>(items: T[], page: number, limit: number) {
858
835
  };
859
836
  }
860
837
  `;
861
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "utils", "helpers.ts"), helpers);
838
+ await fs.writeFile(path.join(projectDir, "src", "utils", "helpers.ts"), helpers);
862
839
  }
863
840
  async function createCompleteDataStore(projectDir) {
864
841
  const store = `import type { User } from '../schemas/user.js';
@@ -896,7 +873,7 @@ export const posts: Post[] = [
896
873
  },
897
874
  ];
898
875
  `;
899
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "data", "store.ts"), store);
876
+ await fs.writeFile(path.join(projectDir, "src", "data", "store.ts"), store);
900
877
  }
901
878
  async function createCompleteRoutes(projectDir) {
902
879
  const healthRoute = `import type { Kozo } from '@kozojs/core';
@@ -912,7 +889,7 @@ export function registerHealthRoute(app: Kozo) {
912
889
  });
913
890
  }
914
891
  `;
915
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "routes", "health.ts"), healthRoute);
892
+ await fs.writeFile(path.join(projectDir, "src", "routes", "health.ts"), healthRoute);
916
893
  const statsRoute = `import { z } from 'zod';
917
894
  import type { Kozo } from '@kozojs/core';
918
895
  import { users } from '../data/store.js';
@@ -967,7 +944,7 @@ export function registerStatsRoute(app: Kozo) {
967
944
  });
968
945
  }
969
946
  `;
970
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "routes", "stats.ts"), statsRoute);
947
+ await fs.writeFile(path.join(projectDir, "src", "routes", "stats.ts"), statsRoute);
971
948
  const authRoutes = `import { z } from 'zod';
972
949
  import type { Kozo } from '@kozojs/core';
973
950
  import { createJWT } from '@kozojs/auth';
@@ -1013,7 +990,7 @@ export function registerAuthRoutes(app: Kozo) {
1013
990
  });
1014
991
  }
1015
992
  `;
1016
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "routes", "auth", "index.ts"), authRoutes);
993
+ await fs.writeFile(path.join(projectDir, "src", "routes", "auth", "index.ts"), authRoutes);
1017
994
  const userRoutes = `import { z } from 'zod';
1018
995
  import type { Kozo } from '@kozojs/core';
1019
996
  import { UserSchema, CreateUserSchema, UpdateUserSchema } from '../../schemas/user.js';
@@ -1098,7 +1075,7 @@ export function registerUserRoutes(app: Kozo) {
1098
1075
  });
1099
1076
  }
1100
1077
  `;
1101
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "routes", "users", "index.ts"), userRoutes);
1078
+ await fs.writeFile(path.join(projectDir, "src", "routes", "users", "index.ts"), userRoutes);
1102
1079
  const postRoutes = `import { z } from 'zod';
1103
1080
  import type { Kozo } from '@kozojs/core';
1104
1081
  import { PostSchema, PostWithAuthorSchema, CreatePostSchema } from '../../schemas/post.js';
@@ -1174,10 +1151,10 @@ export function registerPostRoutes(app: Kozo) {
1174
1151
  });
1175
1152
  }
1176
1153
  `;
1177
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "routes", "posts", "index.ts"), postRoutes);
1154
+ await fs.writeFile(path.join(projectDir, "src", "routes", "posts", "index.ts"), postRoutes);
1178
1155
  }
1179
1156
  async function scaffoldApiOnlyTemplate(projectDir, projectName, kozoCoreDep, runtime) {
1180
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "src"));
1157
+ await fs.ensureDir(path.join(projectDir, "src"));
1181
1158
  const packageJson = {
1182
1159
  name: projectName,
1183
1160
  version: "1.0.0",
@@ -1191,7 +1168,8 @@ async function scaffoldApiOnlyTemplate(projectDir, projectName, kozoCoreDep, run
1191
1168
  "@kozojs/core": kozoCoreDep,
1192
1169
  hono: "^4.6.0",
1193
1170
  zod: "^3.23.0",
1194
- ...runtime === "node" && { "@hono/node-server": "^1.13.0" }
1171
+ ...runtime === "node" && { "@hono/node-server": "^1.13.0" },
1172
+ ...runtime === "node" && { "uWebSockets.js": "github:uNetworking/uWebSockets.js#6609a88ffa9a16ac5158046761356ce03250a0df" }
1195
1173
  },
1196
1174
  devDependencies: {
1197
1175
  "@types/node": "^22.0.0",
@@ -1199,7 +1177,7 @@ async function scaffoldApiOnlyTemplate(projectDir, projectName, kozoCoreDep, run
1199
1177
  typescript: "^5.6.0"
1200
1178
  }
1201
1179
  };
1202
- await import_fs_extra.default.writeJSON(import_node_path.default.join(projectDir, "package.json"), packageJson, { spaces: 2 });
1180
+ await fs.writeJSON(path.join(projectDir, "package.json"), packageJson, { spaces: 2 });
1203
1181
  const tsconfig = {
1204
1182
  compilerOptions: {
1205
1183
  target: "ES2022",
@@ -1214,7 +1192,7 @@ async function scaffoldApiOnlyTemplate(projectDir, projectName, kozoCoreDep, run
1214
1192
  include: ["src/**/*"],
1215
1193
  exclude: ["node_modules", "dist"]
1216
1194
  };
1217
- await import_fs_extra.default.writeJSON(import_node_path.default.join(projectDir, "tsconfig.json"), tsconfig, { spaces: 2 });
1195
+ await fs.writeJSON(path.join(projectDir, "tsconfig.json"), tsconfig, { spaces: 2 });
1218
1196
  const indexTs = `import { createKozo } from '@kozojs/core';
1219
1197
  import { z } from 'zod';
1220
1198
 
@@ -1237,8 +1215,8 @@ app.get('/hello/:name', {
1237
1215
  console.log('\u{1F525} Kozo running on http://localhost:3000');
1238
1216
  await app.nativeListen();
1239
1217
  `;
1240
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "src", "index.ts"), indexTs);
1241
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".gitignore"), "node_modules/\ndist/\n.env\n");
1218
+ await fs.writeFile(path.join(projectDir, "src", "index.ts"), indexTs);
1219
+ await fs.writeFile(path.join(projectDir, ".gitignore"), "node_modules/\ndist/\n.env\n");
1242
1220
  }
1243
1221
  async function createDockerCompose(dir, projectName, database, dbPort, includeApiService = false, runtime = "node") {
1244
1222
  if (database === "none" || database === "sqlite") return;
@@ -1319,7 +1297,7 @@ async function createDockerCompose(dir, projectName, database, dbPort, includeAp
1319
1297
  const volumes = database === "postgresql" ? "\nvolumes:\n postgres_data:\n" : database === "mysql" ? "\nvolumes:\n mysql_data:\n" : "";
1320
1298
  const compose = `services:
1321
1299
  ${services}${volumes}`;
1322
- await import_fs_extra.default.writeFile(import_node_path.default.join(dir, "docker-compose.yml"), compose);
1300
+ await fs.writeFile(path.join(dir, "docker-compose.yml"), compose);
1323
1301
  }
1324
1302
  async function createDockerfile(projectDir, runtime) {
1325
1303
  const dockerfile = runtime === "bun" ? `FROM oven/bun:1 AS builder
@@ -1350,11 +1328,11 @@ RUN npm ci --omit=dev
1350
1328
  EXPOSE 3000
1351
1329
  CMD ["node", "dist/index.js"]
1352
1330
  `;
1353
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "Dockerfile"), dockerfile);
1354
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".dockerignore"), "node_modules\ndist\n.git\n.env\n");
1331
+ await fs.writeFile(path.join(projectDir, "Dockerfile"), dockerfile);
1332
+ await fs.writeFile(path.join(projectDir, ".dockerignore"), "node_modules\ndist\n.git\n.env\n");
1355
1333
  }
1356
1334
  async function createGitHubActions(projectDir) {
1357
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, ".github", "workflows"));
1335
+ await fs.ensureDir(path.join(projectDir, ".github", "workflows"));
1358
1336
  const workflow = `name: CI
1359
1337
 
1360
1338
  on:
@@ -1376,15 +1354,15 @@ jobs:
1376
1354
  - run: npm run build
1377
1355
  - run: npm test --if-present
1378
1356
  `;
1379
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".github", "workflows", "ci.yml"), workflow);
1357
+ await fs.writeFile(path.join(projectDir, ".github", "workflows", "ci.yml"), workflow);
1380
1358
  }
1381
1359
  async function scaffoldFullstackProject(projectDir, projectName, kozoCoreDep, runtime, database, dbPort, auth, frontend, extras, template) {
1382
1360
  const hasDb = database !== "none";
1383
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "apps", "api", "src", "routes"));
1384
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "apps", "api", "src", "data"));
1385
- if (hasDb) await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "apps", "api", "src", "db"));
1386
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, "apps", "web", "src", "lib"));
1387
- await import_fs_extra.default.ensureDir(import_node_path.default.join(projectDir, ".vscode"));
1361
+ await fs.ensureDir(path.join(projectDir, "apps", "api", "src", "routes"));
1362
+ await fs.ensureDir(path.join(projectDir, "apps", "api", "src", "data"));
1363
+ if (hasDb) await fs.ensureDir(path.join(projectDir, "apps", "api", "src", "db"));
1364
+ await fs.ensureDir(path.join(projectDir, "apps", "web", "src", "lib"));
1365
+ await fs.ensureDir(path.join(projectDir, ".vscode"));
1388
1366
  const rootPackageJson = {
1389
1367
  name: projectName,
1390
1368
  private: true,
@@ -1393,32 +1371,32 @@ async function scaffoldFullstackProject(projectDir, projectName, kozoCoreDep, ru
1393
1371
  build: "pnpm run --recursive build"
1394
1372
  }
1395
1373
  };
1396
- await import_fs_extra.default.writeJSON(import_node_path.default.join(projectDir, "package.json"), rootPackageJson, { spaces: 2 });
1397
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "pnpm-workspace.yaml"), `packages:
1374
+ await fs.writeJSON(path.join(projectDir, "package.json"), rootPackageJson, { spaces: 2 });
1375
+ await fs.writeFile(path.join(projectDir, "pnpm-workspace.yaml"), `packages:
1398
1376
  - 'apps/*'
1399
1377
  `);
1400
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, ".gitignore"), "node_modules/\ndist/\n.env\n*.log\n");
1378
+ await fs.writeFile(path.join(projectDir, ".gitignore"), "node_modules/\ndist/\n.env\n*.log\n");
1401
1379
  await scaffoldFullstackApi(projectDir, projectName, kozoCoreDep, runtime, database, dbPort, auth);
1402
1380
  await scaffoldFullstackWeb(projectDir, projectName, frontend, auth);
1403
1381
  await scaffoldFullstackReadme(projectDir, projectName);
1404
1382
  if (database !== "none" && database !== "sqlite") await createDockerCompose(projectDir, projectName, database, dbPort);
1405
- if (extras.includes("docker")) await createDockerfile(import_node_path.default.join(projectDir, "apps", "api"), runtime);
1383
+ if (extras.includes("docker")) await createDockerfile(path.join(projectDir, "apps", "api"), runtime);
1406
1384
  if (extras.includes("github-actions")) await createGitHubActions(projectDir);
1407
1385
  }
1408
1386
  async function scaffoldFullstackApi(projectDir, projectName, kozoCoreDep, runtime, database = "none", dbPort, auth = true) {
1409
- const apiDir = import_node_path.default.join(projectDir, "apps", "api");
1387
+ const apiDir = path.join(projectDir, "apps", "api");
1410
1388
  const hasDb = database !== "none";
1411
1389
  if (hasDb) {
1412
- await import_fs_extra.default.ensureDir(import_node_path.default.join(apiDir, "src", "db"));
1413
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "db", "schema.ts"), getDatabaseSchema(database));
1414
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "db", "index.ts"), getDatabaseIndex(database));
1390
+ await fs.ensureDir(path.join(apiDir, "src", "db"));
1391
+ await fs.writeFile(path.join(apiDir, "src", "db", "schema.ts"), getDatabaseSchema(database));
1392
+ await fs.writeFile(path.join(apiDir, "src", "db", "index.ts"), getDatabaseIndex(database));
1415
1393
  if (database === "sqlite") {
1416
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "db", "seed.ts"), getSQLiteSeed());
1394
+ await fs.writeFile(path.join(apiDir, "src", "db", "seed.ts"), getSQLiteSeed());
1417
1395
  }
1418
1396
  const dialect = database === "postgresql" ? "postgresql" : database === "mysql" ? "mysql" : "sqlite";
1419
1397
  const pgPort = dbPort ?? 5436;
1420
1398
  const dbUrl = database === "postgresql" ? `postgresql://postgres:postgres@localhost:${pgPort}/${projectName}` : database === "mysql" ? `mysql://root:root@localhost:3306/${projectName}` : void 0;
1421
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "drizzle.config.ts"), `import { defineConfig } from 'drizzle-kit';
1399
+ await fs.writeFile(path.join(apiDir, "drizzle.config.ts"), `import { defineConfig } from 'drizzle-kit';
1422
1400
  import 'dotenv/config';
1423
1401
 
1424
1402
  export default defineConfig({
@@ -1434,14 +1412,14 @@ export default defineConfig({
1434
1412
  NODE_ENV=development
1435
1413
  ${dbUrl ? `DATABASE_URL=${dbUrl}
1436
1414
  ` : ""}${auth ? "JWT_SECRET=change-me-to-a-random-secret-at-least-32-chars\n" : ""}`;
1437
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, ".env"), envContent);
1438
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, ".env.example"), envContent);
1415
+ await fs.writeFile(path.join(apiDir, ".env"), envContent);
1416
+ await fs.writeFile(path.join(apiDir, ".env.example"), envContent);
1439
1417
  } else {
1440
1418
  const envContent = `PORT=3000
1441
1419
  NODE_ENV=development
1442
1420
  ${auth ? "JWT_SECRET=change-me-to-a-random-secret-at-least-32-chars\n" : ""}`;
1443
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, ".env"), envContent);
1444
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, ".env.example"), envContent);
1421
+ await fs.writeFile(path.join(apiDir, ".env"), envContent);
1422
+ await fs.writeFile(path.join(apiDir, ".env.example"), envContent);
1445
1423
  }
1446
1424
  const apiPackageJson = {
1447
1425
  name: `@${projectName}/api`,
@@ -1463,6 +1441,7 @@ ${auth ? "JWT_SECRET=change-me-to-a-random-secret-at-least-32-chars\n" : ""}`;
1463
1441
  zod: "^3.23.0",
1464
1442
  dotenv: "^16.4.0",
1465
1443
  ...runtime === "node" && { "@hono/node-server": "^1.13.0" },
1444
+ ...runtime === "node" && { "uWebSockets.js": "github:uNetworking/uWebSockets.js#6609a88ffa9a16ac5158046761356ce03250a0df" },
1466
1445
  ...hasDb && { "drizzle-orm": "^0.36.0" },
1467
1446
  ...database === "postgresql" && { postgres: "^3.4.0" },
1468
1447
  ...database === "mysql" && { mysql2: "^3.11.0" },
@@ -1476,7 +1455,7 @@ ${auth ? "JWT_SECRET=change-me-to-a-random-secret-at-least-32-chars\n" : ""}`;
1476
1455
  ...database === "sqlite" && { "@types/better-sqlite3": "^7.6.0" }
1477
1456
  }
1478
1457
  };
1479
- await import_fs_extra.default.writeJSON(import_node_path.default.join(apiDir, "package.json"), apiPackageJson, { spaces: 2 });
1458
+ await fs.writeJSON(path.join(apiDir, "package.json"), apiPackageJson, { spaces: 2 });
1480
1459
  const tsconfig = {
1481
1460
  compilerOptions: {
1482
1461
  target: "ES2022",
@@ -1491,10 +1470,9 @@ ${auth ? "JWT_SECRET=change-me-to-a-random-secret-at-least-32-chars\n" : ""}`;
1491
1470
  include: ["src/**/*"],
1492
1471
  exclude: ["node_modules", "dist"]
1493
1472
  };
1494
- await import_fs_extra.default.writeJSON(import_node_path.default.join(apiDir, "tsconfig.json"), tsconfig, { spaces: 2 });
1473
+ await fs.writeJSON(path.join(apiDir, "tsconfig.json"), tsconfig, { spaces: 2 });
1495
1474
  const authImport = auth ? `import { authenticateJWT } from '@kozojs/auth';
1496
1475
  ` : "";
1497
- const servicesSetup = "\nconst services = {};\n";
1498
1476
  const authMiddleware = auth ? `
1499
1477
  // JWT protects all /api/* routes except public ones
1500
1478
  const JWT_SECRET = process.env.JWT_SECRET || 'change-me';
@@ -1505,21 +1483,22 @@ app.getApp().use('/api/*', (c, next) => {
1505
1483
  return _jwt(c, next);
1506
1484
  });
1507
1485
  ` : "";
1508
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "index.ts"), `import 'dotenv/config';
1486
+ await fs.outputFile(path.join(apiDir, "src", "index.ts"), `import 'dotenv/config';
1509
1487
  import { createKozo } from '@kozojs/core';
1510
- ${authImport}import { registerRoutes } from './routes/index.js';
1511
- ${servicesSetup}
1512
- const app = createKozo({ port: 3000, services });
1513
- ${authMiddleware}
1514
- registerRoutes(app);
1488
+ ${authImport}import { fileURLToPath } from 'node:url';
1489
+ import { dirname, join } from 'node:path';
1490
+
1491
+ const __dirname = dirname(fileURLToPath(import.meta.url));
1492
+ const PORT = Number(process.env.PORT) || 3000;
1493
+ const app = createKozo({ port: PORT });
1494
+ ${authMiddleware}await app.loadRoutes(join(__dirname, 'routes'));
1515
1495
 
1516
1496
  export type AppType = typeof app;
1517
1497
 
1518
- console.log('\u{1F525} ${projectName} API starting on http://localhost:3000');
1519
- console.log('\u{1F4DA} Endpoints: /api/health, /api/users, /api/posts, /api/tasks, /api/stats');
1520
- await app.listen();
1498
+ console.log(\`\u{1F525} ${projectName} API on http://localhost:\${PORT}\`);
1499
+ ${runtime === "node" ? "await app.nativeListen();" : "await app.listen();"}
1521
1500
  `);
1522
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "data", "index.ts"), `import { z } from 'zod';
1501
+ await fs.outputFile(path.join(apiDir, "src", "schemas", "index.ts"), `import { z } from 'zod';
1523
1502
 
1524
1503
  export const UserSchema = z.object({
1525
1504
  id: z.string(),
@@ -1529,6 +1508,18 @@ export const UserSchema = z.object({
1529
1508
  createdAt: z.string().optional(),
1530
1509
  });
1531
1510
 
1511
+ export const CreateUserBody = z.object({
1512
+ name: z.string().min(1),
1513
+ email: z.string().email(),
1514
+ role: z.enum(['admin', 'user']).optional(),
1515
+ });
1516
+
1517
+ export const UpdateUserBody = z.object({
1518
+ name: z.string().optional(),
1519
+ email: z.string().email().optional(),
1520
+ role: z.enum(['admin', 'user']).optional(),
1521
+ });
1522
+
1532
1523
  export const PostSchema = z.object({
1533
1524
  id: z.string(),
1534
1525
  title: z.string(),
@@ -1538,6 +1529,19 @@ export const PostSchema = z.object({
1538
1529
  createdAt: z.string().optional(),
1539
1530
  });
1540
1531
 
1532
+ export const CreatePostBody = z.object({
1533
+ title: z.string().min(1),
1534
+ content: z.string().optional(),
1535
+ authorId: z.string().optional(),
1536
+ published: z.boolean().optional(),
1537
+ });
1538
+
1539
+ export const UpdatePostBody = z.object({
1540
+ title: z.string().optional(),
1541
+ content: z.string().optional(),
1542
+ published: z.boolean().optional(),
1543
+ });
1544
+
1541
1545
  export const TaskSchema = z.object({
1542
1546
  id: z.string(),
1543
1547
  title: z.string(),
@@ -1546,302 +1550,415 @@ export const TaskSchema = z.object({
1546
1550
  createdAt: z.string(),
1547
1551
  });
1548
1552
 
1549
- export const users: z.infer<typeof UserSchema>[] = [
1550
- { id: '1', name: 'Alice', email: 'alice@example.com', role: 'admin', createdAt: new Date().toISOString() },
1551
- { id: '2', name: 'Bob', email: 'bob@example.com', role: 'user', createdAt: new Date().toISOString() },
1553
+ export const CreateTaskBody = z.object({
1554
+ title: z.string().min(1),
1555
+ priority: z.enum(['low', 'medium', 'high']).optional(),
1556
+ });
1557
+
1558
+ export const UpdateTaskBody = z.object({
1559
+ title: z.string().optional(),
1560
+ completed: z.boolean().optional(),
1561
+ priority: z.enum(['low', 'medium', 'high']).optional(),
1562
+ });
1563
+ `);
1564
+ await fs.outputFile(path.join(apiDir, "src", "data", "index.ts"), `export const users = [
1565
+ { id: '1', name: 'Alice', email: 'alice@example.com', role: 'admin' as const, createdAt: new Date().toISOString() },
1566
+ { id: '2', name: 'Bob', email: 'bob@example.com', role: 'user' as const, createdAt: new Date().toISOString() },
1552
1567
  ];
1553
1568
 
1554
- export const posts: z.infer<typeof PostSchema>[] = [
1569
+ export const posts = [
1555
1570
  { id: '1', title: 'Hello World', content: 'First post!', authorId: '1', published: true, createdAt: new Date().toISOString() },
1556
1571
  { id: '2', title: 'Draft', content: 'Work in progress', authorId: '2', published: false, createdAt: new Date().toISOString() },
1557
1572
  ];
1558
1573
 
1559
- export const tasks: z.infer<typeof TaskSchema>[] = [
1560
- { id: '1', title: 'Setup project', completed: true, priority: 'high', createdAt: new Date().toISOString() },
1561
- { id: '2', title: 'Write tests', completed: false, priority: 'medium', createdAt: new Date().toISOString() },
1562
- { id: '3', title: 'Deploy', completed: false, priority: 'low', createdAt: new Date().toISOString() },
1574
+ export const tasks = [
1575
+ { id: '1', title: 'Setup project', completed: true, priority: 'high' as const, createdAt: new Date().toISOString() },
1576
+ { id: '2', title: 'Write tests', completed: false, priority: 'medium' as const, createdAt: new Date().toISOString() },
1577
+ { id: '3', title: 'Deploy', completed: false, priority: 'low' as const, createdAt: new Date().toISOString() },
1563
1578
  ];
1564
1579
  `);
1565
- const authRoutesImport = auth ? `import { registerAuthRoutes } from './auth';
1566
- ` : "";
1567
- const authRoutesCall = auth ? ` registerAuthRoutes(app); // Public auth endpoint must register before JWT middleware
1568
- ` : "";
1569
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "routes", "index.ts"), `import type { Kozo } from '@kozojs/core';
1570
- import { registerHealthRoutes } from './health';
1571
- import { registerUserRoutes } from './users';
1572
- import { registerPostRoutes } from './posts';
1573
- import { registerTaskRoutes } from './tasks';
1574
- import { registerToolRoutes } from './tools';
1575
- ${authRoutesImport}
1576
- export function registerRoutes(app: Kozo) {
1577
- ${authRoutesCall} registerHealthRoutes(app);
1578
- registerUserRoutes(app);
1579
- registerPostRoutes(app);
1580
- registerTaskRoutes(app);
1581
- registerToolRoutes(app);
1582
- }
1580
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "health", "get.ts"), `import { z } from 'zod';
1581
+
1582
+ export const schema = {
1583
+ response: z.object({
1584
+ status: z.string(),
1585
+ timestamp: z.string(),
1586
+ version: z.string(),
1587
+ uptime: z.number(),
1588
+ }),
1589
+ };
1590
+
1591
+ export default async () => ({
1592
+ status: 'ok',
1593
+ timestamp: new Date().toISOString(),
1594
+ version: '1.0.0',
1595
+ uptime: process.uptime(),
1596
+ });
1583
1597
  `);
1584
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "routes", "health.ts"), `import type { Kozo } from '@kozojs/core';
1585
- import { users, posts, tasks } from '../data';
1598
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "stats", "get.ts"), `import { z } from 'zod';
1599
+ import { users, posts, tasks } from '../../../data/index.js';
1586
1600
 
1587
- export function registerHealthRoutes(app: Kozo) {
1588
- app.get('/api/health', {}, () => ({
1589
- status: 'ok',
1590
- timestamp: new Date().toISOString(),
1591
- version: '1.0.0',
1592
- uptime: process.uptime(),
1593
- }));
1601
+ export const schema = {
1602
+ response: z.object({
1603
+ users: z.number(),
1604
+ posts: z.number(),
1605
+ tasks: z.number(),
1606
+ publishedPosts: z.number(),
1607
+ completedTasks: z.number(),
1608
+ }),
1609
+ };
1594
1610
 
1595
- app.get('/api/stats', {}, () => ({
1596
- users: users.length,
1597
- posts: posts.length,
1598
- tasks: tasks.length,
1599
- publishedPosts: posts.filter(p => p.published).length,
1600
- completedTasks: tasks.filter(t => t.completed).length,
1601
- }));
1602
- }
1611
+ export default async () => ({
1612
+ users: users.length,
1613
+ posts: posts.length,
1614
+ tasks: tasks.length,
1615
+ publishedPosts: posts.filter(p => p.published).length,
1616
+ completedTasks: tasks.filter(t => t.completed).length,
1617
+ });
1603
1618
  `);
1604
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "routes", "users.ts"), `import type { Kozo } from '@kozojs/core';
1605
- import { z } from 'zod';
1606
- import { users, UserSchema } from '../data';
1619
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "echo", "get.ts"), `import { z } from 'zod';
1607
1620
 
1608
- export function registerUserRoutes(app: Kozo) {
1609
- app.get('/api/users', {
1610
- response: z.array(UserSchema),
1611
- }, () => users);
1621
+ export const schema = {
1622
+ query: z.object({ message: z.string() }),
1623
+ response: z.object({
1624
+ echo: z.string(),
1625
+ timestamp: z.string(),
1626
+ }),
1627
+ };
1612
1628
 
1613
- app.get('/api/users/:id', {
1614
- params: z.object({ id: z.string() }),
1615
- response: UserSchema,
1616
- }, (c) => {
1617
- const user = users.find(u => u.id === c.params.id);
1618
- if (!user) throw new Error('User not found');
1619
- return user;
1620
- });
1629
+ export default async ({ query }: { query: { message: string } }) => ({
1630
+ echo: query.message,
1631
+ timestamp: new Date().toISOString(),
1632
+ });
1633
+ `);
1634
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "validate", "post.ts"), `import { z } from 'zod';
1621
1635
 
1622
- app.post('/api/users', {
1623
- body: z.object({
1624
- name: z.string().min(1),
1625
- email: z.string().email(),
1626
- role: z.enum(['admin', 'user']).optional(),
1627
- }),
1628
- response: UserSchema,
1629
- }, (c) => {
1630
- const newUser = {
1631
- id: String(Date.now()),
1632
- name: c.body.name,
1633
- email: c.body.email,
1634
- role: c.body.role || 'user' as const,
1635
- createdAt: new Date().toISOString(),
1636
- };
1637
- users.push(newUser);
1638
- return newUser;
1639
- });
1636
+ export const schema = {
1637
+ body: z.object({
1638
+ email: z.string().email(),
1639
+ age: z.number().min(0).max(150),
1640
+ }),
1641
+ response: z.object({
1642
+ valid: z.boolean(),
1643
+ data: z.object({ email: z.string(), age: z.number() }),
1644
+ }),
1645
+ };
1640
1646
 
1641
- app.put('/api/users/:id', {
1642
- params: z.object({ id: z.string() }),
1643
- body: z.object({
1644
- name: z.string().min(1).optional(),
1645
- email: z.string().email().optional(),
1646
- role: z.enum(['admin', 'user']).optional(),
1647
- }),
1648
- response: UserSchema,
1649
- }, (c) => {
1650
- const idx = users.findIndex(u => u.id === c.params.id);
1651
- if (idx === -1) throw new Error('User not found');
1652
- users[idx] = { ...users[idx], ...c.body };
1653
- return users[idx];
1654
- });
1647
+ export default async ({ body }: { body: { email: string; age: number } }) => ({
1648
+ valid: true,
1649
+ data: body,
1650
+ });
1651
+ `);
1652
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "users", "get.ts"), `import { z } from 'zod';
1653
+ import { users } from '../../../data/index.js';
1654
+ import { UserSchema } from '../../../schemas/index.js';
1655
1655
 
1656
- app.delete('/api/users/:id', {
1657
- params: z.object({ id: z.string() }),
1658
- }, (c) => {
1659
- const idx = users.findIndex(u => u.id === c.params.id);
1660
- if (idx === -1) throw new Error('User not found');
1661
- users.splice(idx, 1);
1662
- return { success: true, message: 'User deleted' };
1663
- });
1664
- }
1656
+ export const schema = {
1657
+ response: z.array(UserSchema),
1658
+ };
1659
+
1660
+ export default async () => users;
1665
1661
  `);
1666
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "routes", "posts.ts"), `import type { Kozo } from '@kozojs/core';
1667
- import { z } from 'zod';
1668
- import { posts, PostSchema } from '../data';
1662
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "users", "post.ts"), `import { users } from '../../../data/index.js';
1663
+ import { UserSchema, CreateUserBody } from '../../../schemas/index.js';
1669
1664
 
1670
- export function registerPostRoutes(app: Kozo) {
1671
- app.get('/api/posts', {
1672
- query: z.object({ published: z.coerce.boolean().optional() }),
1673
- response: z.array(PostSchema),
1674
- }, (c) => {
1675
- if (c.query.published !== undefined) {
1676
- return posts.filter(p => p.published === c.query.published);
1677
- }
1678
- return posts;
1679
- });
1665
+ export const schema = {
1666
+ body: CreateUserBody,
1667
+ response: UserSchema,
1668
+ };
1680
1669
 
1681
- app.get('/api/posts/:id', {
1682
- params: z.object({ id: z.string() }),
1683
- response: PostSchema,
1684
- }, (c) => {
1685
- const post = posts.find(p => p.id === c.params.id);
1686
- if (!post) throw new Error('Post not found');
1687
- return post;
1688
- });
1670
+ export default async ({ body }: { body: { name: string; email: string; role?: 'admin' | 'user' } }) => {
1671
+ const newUser = {
1672
+ id: String(Date.now()),
1673
+ name: body.name,
1674
+ email: body.email,
1675
+ role: body.role ?? ('user' as const),
1676
+ createdAt: new Date().toISOString(),
1677
+ };
1678
+ users.push(newUser);
1679
+ return newUser;
1680
+ };
1681
+ `);
1682
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "users", "[id]", "get.ts"), `import { z } from 'zod';
1683
+ import { KozoError } from '@kozojs/core';
1684
+ import { users } from '../../../../data/index.js';
1685
+ import { UserSchema } from '../../../../schemas/index.js';
1689
1686
 
1690
- app.post('/api/posts', {
1691
- body: z.object({
1692
- title: z.string().min(1),
1693
- content: z.string(),
1694
- authorId: z.string(),
1695
- published: z.boolean().optional(),
1696
- }),
1697
- response: PostSchema,
1698
- }, (c) => {
1699
- const newPost = {
1700
- id: String(Date.now()),
1701
- title: c.body.title,
1702
- content: c.body.content,
1703
- authorId: c.body.authorId,
1704
- published: c.body.published ?? false,
1705
- createdAt: new Date().toISOString(),
1706
- };
1707
- posts.push(newPost);
1708
- return newPost;
1709
- });
1687
+ export const schema = {
1688
+ params: z.object({ id: z.string() }),
1689
+ response: UserSchema,
1690
+ };
1710
1691
 
1711
- app.put('/api/posts/:id', {
1712
- params: z.object({ id: z.string() }),
1713
- body: z.object({
1714
- title: z.string().min(1).optional(),
1715
- content: z.string().optional(),
1716
- published: z.boolean().optional(),
1717
- }),
1718
- response: PostSchema,
1719
- }, (c) => {
1720
- const idx = posts.findIndex(p => p.id === c.params.id);
1721
- if (idx === -1) throw new Error('Post not found');
1722
- posts[idx] = { ...posts[idx], ...c.body };
1723
- return posts[idx];
1724
- });
1692
+ export default async ({ params }: { params: { id: string } }) => {
1693
+ const user = users.find(u => u.id === params.id);
1694
+ if (!user) throw new KozoError('User not found', 404, 'NOT_FOUND');
1695
+ return user;
1696
+ };
1697
+ `);
1698
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "users", "[id]", "put.ts"), `import { z } from 'zod';
1699
+ import { KozoError } from '@kozojs/core';
1700
+ import { users } from '../../../../data/index.js';
1701
+ import { UserSchema, UpdateUserBody } from '../../../../schemas/index.js';
1725
1702
 
1726
- app.delete('/api/posts/:id', {
1727
- params: z.object({ id: z.string() }),
1728
- }, (c) => {
1729
- const idx = posts.findIndex(p => p.id === c.params.id);
1730
- if (idx === -1) throw new Error('Post not found');
1731
- posts.splice(idx, 1);
1732
- return { success: true, message: 'Post deleted' };
1733
- });
1734
- }
1703
+ export const schema = {
1704
+ params: z.object({ id: z.string() }),
1705
+ body: UpdateUserBody,
1706
+ response: UserSchema,
1707
+ };
1708
+
1709
+ export default async ({
1710
+ params,
1711
+ body,
1712
+ }: {
1713
+ params: { id: string };
1714
+ body: { name?: string; email?: string; role?: 'admin' | 'user' };
1715
+ }) => {
1716
+ const idx = users.findIndex(u => u.id === params.id);
1717
+ if (idx === -1) throw new KozoError('User not found', 404, 'NOT_FOUND');
1718
+ users[idx] = { ...users[idx], ...body };
1719
+ return users[idx];
1720
+ };
1735
1721
  `);
1736
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "routes", "tasks.ts"), `import type { Kozo } from '@kozojs/core';
1737
- import { z } from 'zod';
1738
- import { tasks, TaskSchema } from '../data';
1722
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "users", "[id]", "delete.ts"), `import { z } from 'zod';
1723
+ import { KozoError } from '@kozojs/core';
1724
+ import { users } from '../../../../data/index.js';
1739
1725
 
1740
- export function registerTaskRoutes(app: Kozo) {
1741
- app.get('/api/tasks', {
1742
- query: z.object({
1743
- completed: z.coerce.boolean().optional(),
1744
- priority: z.enum(['low', 'medium', 'high']).optional(),
1745
- }),
1746
- response: z.array(TaskSchema),
1747
- }, (c) => {
1748
- let result = [...tasks];
1749
- if (c.query.completed !== undefined) {
1750
- result = result.filter(t => t.completed === c.query.completed);
1751
- }
1752
- if (c.query.priority) {
1753
- result = result.filter(t => t.priority === c.query.priority);
1754
- }
1755
- return result;
1756
- });
1726
+ export const schema = {
1727
+ params: z.object({ id: z.string() }),
1728
+ response: z.object({ success: z.boolean(), message: z.string() }),
1729
+ };
1757
1730
 
1758
- app.get('/api/tasks/:id', {
1759
- params: z.object({ id: z.string() }),
1760
- response: TaskSchema,
1761
- }, (c) => {
1762
- const task = tasks.find(t => t.id === c.params.id);
1763
- if (!task) throw new Error('Task not found');
1764
- return task;
1765
- });
1731
+ export default async ({ params }: { params: { id: string } }) => {
1732
+ const idx = users.findIndex(u => u.id === params.id);
1733
+ if (idx === -1) throw new KozoError('User not found', 404, 'NOT_FOUND');
1734
+ users.splice(idx, 1);
1735
+ return { success: true, message: 'User deleted' };
1736
+ };
1737
+ `);
1738
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "posts", "get.ts"), `import { z } from 'zod';
1739
+ import { posts } from '../../../data/index.js';
1740
+ import { PostSchema } from '../../../schemas/index.js';
1766
1741
 
1767
- app.post('/api/tasks', {
1768
- body: z.object({
1769
- title: z.string().min(1),
1770
- priority: z.enum(['low', 'medium', 'high']).optional(),
1771
- }),
1772
- response: TaskSchema,
1773
- }, (c) => {
1774
- const newTask = {
1775
- id: String(Date.now()),
1776
- title: c.body.title,
1777
- completed: false,
1778
- priority: c.body.priority || 'medium' as const,
1779
- createdAt: new Date().toISOString(),
1780
- };
1781
- tasks.push(newTask);
1782
- return newTask;
1783
- });
1742
+ export const schema = {
1743
+ query: z.object({ published: z.coerce.boolean().optional() }),
1744
+ response: z.array(PostSchema),
1745
+ };
1784
1746
 
1785
- app.put('/api/tasks/:id', {
1786
- params: z.object({ id: z.string() }),
1787
- body: z.object({
1788
- title: z.string().min(1).optional(),
1789
- completed: z.boolean().optional(),
1790
- priority: z.enum(['low', 'medium', 'high']).optional(),
1791
- }),
1792
- response: TaskSchema,
1793
- }, (c) => {
1794
- const idx = tasks.findIndex(t => t.id === c.params.id);
1795
- if (idx === -1) throw new Error('Task not found');
1796
- tasks[idx] = { ...tasks[idx], ...c.body };
1797
- return tasks[idx];
1798
- });
1747
+ export default async ({ query }: { query: { published?: boolean } }) => {
1748
+ if (query.published !== undefined) {
1749
+ return posts.filter(p => p.published === query.published);
1750
+ }
1751
+ return posts;
1752
+ };
1753
+ `);
1754
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "posts", "post.ts"), `import { posts, users } from '../../../data/index.js';
1755
+ import { PostSchema, CreatePostBody } from '../../../schemas/index.js';
1799
1756
 
1800
- app.patch('/api/tasks/:id/toggle', {
1801
- params: z.object({ id: z.string() }),
1802
- response: TaskSchema,
1803
- }, (c) => {
1804
- const idx = tasks.findIndex(t => t.id === c.params.id);
1805
- if (idx === -1) throw new Error('Task not found');
1806
- tasks[idx].completed = !tasks[idx].completed;
1807
- return tasks[idx];
1808
- });
1757
+ export const schema = {
1758
+ body: CreatePostBody,
1759
+ response: PostSchema,
1760
+ };
1809
1761
 
1810
- app.delete('/api/tasks/:id', {
1811
- params: z.object({ id: z.string() }),
1812
- }, (c) => {
1813
- const idx = tasks.findIndex(t => t.id === c.params.id);
1814
- if (idx === -1) throw new Error('Task not found');
1815
- tasks.splice(idx, 1);
1816
- return { success: true, message: 'Task deleted' };
1817
- });
1818
- }
1762
+ export default async ({
1763
+ body,
1764
+ }: {
1765
+ body: { title: string; content?: string; authorId?: string; published?: boolean };
1766
+ }) => {
1767
+ const authorId = body.authorId ?? users[0]?.id ?? 'unknown';
1768
+ const newPost = {
1769
+ id: String(Date.now()),
1770
+ title: body.title,
1771
+ content: body.content ?? '',
1772
+ authorId,
1773
+ published: body.published ?? false,
1774
+ createdAt: new Date().toISOString(),
1775
+ };
1776
+ posts.push(newPost);
1777
+ return newPost;
1778
+ };
1819
1779
  `);
1820
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "routes", "tools.ts"), `import type { Kozo } from '@kozojs/core';
1821
- import { z } from 'zod';
1780
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "posts", "[id]", "get.ts"), `import { z } from 'zod';
1781
+ import { KozoError } from '@kozojs/core';
1782
+ import { posts } from '../../../../data/index.js';
1783
+ import { PostSchema } from '../../../../schemas/index.js';
1822
1784
 
1823
- export function registerToolRoutes(app: Kozo) {
1824
- app.get('/api/echo', {
1825
- query: z.object({ message: z.string() }),
1826
- }, (c) => ({
1827
- echo: c.query.message,
1828
- timestamp: new Date().toISOString(),
1829
- }));
1785
+ export const schema = {
1786
+ params: z.object({ id: z.string() }),
1787
+ response: PostSchema,
1788
+ };
1830
1789
 
1831
- app.post('/api/validate', {
1832
- body: z.object({
1833
- email: z.string().email(),
1834
- age: z.number().min(0).max(150),
1835
- }),
1836
- }, (c) => ({
1837
- valid: true,
1838
- data: c.body,
1839
- }));
1840
- }
1790
+ export default async ({ params }: { params: { id: string } }) => {
1791
+ const post = posts.find(p => p.id === params.id);
1792
+ if (!post) throw new KozoError('Post not found', 404, 'NOT_FOUND');
1793
+ return post;
1794
+ };
1795
+ `);
1796
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "posts", "[id]", "put.ts"), `import { z } from 'zod';
1797
+ import { KozoError } from '@kozojs/core';
1798
+ import { posts } from '../../../../data/index.js';
1799
+ import { PostSchema, UpdatePostBody } from '../../../../schemas/index.js';
1800
+
1801
+ export const schema = {
1802
+ params: z.object({ id: z.string() }),
1803
+ body: UpdatePostBody,
1804
+ response: PostSchema,
1805
+ };
1806
+
1807
+ export default async ({
1808
+ params,
1809
+ body,
1810
+ }: {
1811
+ params: { id: string };
1812
+ body: { title?: string; content?: string; published?: boolean };
1813
+ }) => {
1814
+ const idx = posts.findIndex(p => p.id === params.id);
1815
+ if (idx === -1) throw new KozoError('Post not found', 404, 'NOT_FOUND');
1816
+ posts[idx] = { ...posts[idx], ...body };
1817
+ return posts[idx];
1818
+ };
1819
+ `);
1820
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "posts", "[id]", "delete.ts"), `import { z } from 'zod';
1821
+ import { KozoError } from '@kozojs/core';
1822
+ import { posts } from '../../../../data/index.js';
1823
+
1824
+ export const schema = {
1825
+ params: z.object({ id: z.string() }),
1826
+ response: z.object({ success: z.boolean(), message: z.string() }),
1827
+ };
1828
+
1829
+ export default async ({ params }: { params: { id: string } }) => {
1830
+ const idx = posts.findIndex(p => p.id === params.id);
1831
+ if (idx === -1) throw new KozoError('Post not found', 404, 'NOT_FOUND');
1832
+ posts.splice(idx, 1);
1833
+ return { success: true, message: 'Post deleted' };
1834
+ };
1835
+ `);
1836
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "tasks", "get.ts"), `import { z } from 'zod';
1837
+ import { tasks } from '../../../data/index.js';
1838
+ import { TaskSchema } from '../../../schemas/index.js';
1839
+
1840
+ export const schema = {
1841
+ query: z.object({
1842
+ completed: z.coerce.boolean().optional(),
1843
+ priority: z.enum(['low', 'medium', 'high']).optional(),
1844
+ }),
1845
+ response: z.array(TaskSchema),
1846
+ };
1847
+
1848
+ export default async ({
1849
+ query,
1850
+ }: {
1851
+ query: { completed?: boolean; priority?: 'low' | 'medium' | 'high' };
1852
+ }) => {
1853
+ let result = [...tasks];
1854
+ if (query.completed !== undefined) {
1855
+ result = result.filter(t => t.completed === query.completed);
1856
+ }
1857
+ if (query.priority) {
1858
+ result = result.filter(t => t.priority === query.priority);
1859
+ }
1860
+ return result;
1861
+ };
1862
+ `);
1863
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "tasks", "post.ts"), `import { tasks } from '../../../data/index.js';
1864
+ import { TaskSchema, CreateTaskBody } from '../../../schemas/index.js';
1865
+
1866
+ export const schema = {
1867
+ body: CreateTaskBody,
1868
+ response: TaskSchema,
1869
+ };
1870
+
1871
+ export default async ({
1872
+ body,
1873
+ }: {
1874
+ body: { title: string; priority?: 'low' | 'medium' | 'high' };
1875
+ }) => {
1876
+ const newTask = {
1877
+ id: String(Date.now()),
1878
+ title: body.title,
1879
+ completed: false,
1880
+ priority: body.priority ?? ('medium' as const),
1881
+ createdAt: new Date().toISOString(),
1882
+ };
1883
+ tasks.push(newTask);
1884
+ return newTask;
1885
+ };
1886
+ `);
1887
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "tasks", "[id]", "get.ts"), `import { z } from 'zod';
1888
+ import { KozoError } from '@kozojs/core';
1889
+ import { tasks } from '../../../../data/index.js';
1890
+ import { TaskSchema } from '../../../../schemas/index.js';
1891
+
1892
+ export const schema = {
1893
+ params: z.object({ id: z.string() }),
1894
+ response: TaskSchema,
1895
+ };
1896
+
1897
+ export default async ({ params }: { params: { id: string } }) => {
1898
+ const task = tasks.find(t => t.id === params.id);
1899
+ if (!task) throw new KozoError('Task not found', 404, 'NOT_FOUND');
1900
+ return task;
1901
+ };
1902
+ `);
1903
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "tasks", "[id]", "put.ts"), `import { z } from 'zod';
1904
+ import { KozoError } from '@kozojs/core';
1905
+ import { tasks } from '../../../../data/index.js';
1906
+ import { TaskSchema, UpdateTaskBody } from '../../../../schemas/index.js';
1907
+
1908
+ export const schema = {
1909
+ params: z.object({ id: z.string() }),
1910
+ body: UpdateTaskBody,
1911
+ response: TaskSchema,
1912
+ };
1913
+
1914
+ export default async ({
1915
+ params,
1916
+ body,
1917
+ }: {
1918
+ params: { id: string };
1919
+ body: { title?: string; completed?: boolean; priority?: 'low' | 'medium' | 'high' };
1920
+ }) => {
1921
+ const idx = tasks.findIndex(t => t.id === params.id);
1922
+ if (idx === -1) throw new KozoError('Task not found', 404, 'NOT_FOUND');
1923
+ tasks[idx] = { ...tasks[idx], ...body };
1924
+ return tasks[idx];
1925
+ };
1926
+ `);
1927
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "tasks", "[id]", "delete.ts"), `import { z } from 'zod';
1928
+ import { KozoError } from '@kozojs/core';
1929
+ import { tasks } from '../../../../data/index.js';
1930
+
1931
+ export const schema = {
1932
+ params: z.object({ id: z.string() }),
1933
+ response: z.object({ success: z.boolean(), message: z.string() }),
1934
+ };
1935
+
1936
+ export default async ({ params }: { params: { id: string } }) => {
1937
+ const idx = tasks.findIndex(t => t.id === params.id);
1938
+ if (idx === -1) throw new KozoError('Task not found', 404, 'NOT_FOUND');
1939
+ tasks.splice(idx, 1);
1940
+ return { success: true, message: 'Task deleted' };
1941
+ };
1942
+ `);
1943
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "tasks", "[id]", "toggle", "patch.ts"), `import { z } from 'zod';
1944
+ import { KozoError } from '@kozojs/core';
1945
+ import { tasks } from '../../../../../data/index.js';
1946
+ import { TaskSchema } from '../../../../../schemas/index.js';
1947
+
1948
+ export const schema = {
1949
+ params: z.object({ id: z.string() }),
1950
+ response: TaskSchema,
1951
+ };
1952
+
1953
+ export default async ({ params }: { params: { id: string } }) => {
1954
+ const idx = tasks.findIndex(t => t.id === params.id);
1955
+ if (idx === -1) throw new KozoError('Task not found', 404, 'NOT_FOUND');
1956
+ tasks[idx].completed = !tasks[idx].completed;
1957
+ return tasks[idx];
1958
+ };
1841
1959
  `);
1842
1960
  if (auth) {
1843
- await import_fs_extra.default.writeFile(import_node_path.default.join(apiDir, "src", "routes", "auth.ts"), `import type { Kozo } from '@kozojs/core';
1844
- import { z } from 'zod';
1961
+ await fs.outputFile(path.join(apiDir, "src", "routes", "api", "auth", "login", "post.ts"), `import { z } from 'zod';
1845
1962
  import { createJWT, UnauthorizedError } from '@kozojs/auth';
1846
1963
 
1847
1964
  const JWT_SECRET = process.env.JWT_SECRET || 'change-me';
@@ -1851,28 +1968,38 @@ const DEMO_USERS = [
1851
1968
  { email: 'user@demo.com', password: 'user123', role: 'user', name: 'User' },
1852
1969
  ];
1853
1970
 
1854
- export function registerAuthRoutes(app: Kozo) {
1855
- app.post('/api/auth/login', {
1856
- body: z.object({ email: z.string().email(), password: z.string() }),
1857
- }, async (c) => {
1858
- const { email, password } = c.body;
1859
- const user = DEMO_USERS.find(u => u.email === email && u.password === password);
1860
- if (!user) throw new UnauthorizedError('Invalid credentials');
1861
- const token = await createJWT(
1862
- { email: user.email, role: user.role, name: user.name },
1863
- JWT_SECRET,
1864
- { expiresIn: '24h' },
1865
- );
1866
- return { token, user: { email: user.email, role: user.role, name: user.name } };
1867
- });
1868
- }
1971
+ export const schema = {
1972
+ body: z.object({
1973
+ email: z.string().email(),
1974
+ password: z.string(),
1975
+ }),
1976
+ response: z.object({
1977
+ token: z.string(),
1978
+ user: z.object({
1979
+ email: z.string(),
1980
+ role: z.string(),
1981
+ name: z.string(),
1982
+ }),
1983
+ }),
1984
+ };
1985
+
1986
+ export default async ({ body }: { body: { email: string; password: string } }) => {
1987
+ const user = DEMO_USERS.find(u => u.email === body.email && u.password === body.password);
1988
+ if (!user) throw new UnauthorizedError('Invalid credentials');
1989
+ const token = await createJWT(
1990
+ { email: user.email, role: user.role, name: user.name },
1991
+ JWT_SECRET,
1992
+ { expiresIn: '24h' },
1993
+ );
1994
+ return { token, user: { email: user.email, role: user.role, name: user.name } };
1995
+ };
1869
1996
  `);
1870
1997
  }
1871
1998
  }
1872
1999
  async function scaffoldFullstackWeb(projectDir, projectName, frontend, auth = false) {
1873
- const webDir = import_node_path.default.join(projectDir, "apps", "web");
1874
- await import_fs_extra.default.ensureDir(import_node_path.default.join(webDir, "src", "lib"));
1875
- await import_fs_extra.default.ensureDir(import_node_path.default.join(webDir, "src", "pages"));
2000
+ const webDir = path.join(projectDir, "apps", "web");
2001
+ await fs.ensureDir(path.join(webDir, "src", "lib"));
2002
+ await fs.ensureDir(path.join(webDir, "src", "pages"));
1876
2003
  const packageJson = {
1877
2004
  name: `@${projectName}/web`,
1878
2005
  version: "1.0.0",
@@ -1894,8 +2021,8 @@ async function scaffoldFullstackWeb(projectDir, projectName, frontend, auth = fa
1894
2021
  tailwindcss: "^4.0.0"
1895
2022
  }
1896
2023
  };
1897
- await import_fs_extra.default.writeJSON(import_node_path.default.join(webDir, "package.json"), packageJson, { spaces: 2 });
1898
- await import_fs_extra.default.writeJSON(import_node_path.default.join(webDir, "tsconfig.json"), {
2024
+ await fs.writeJSON(path.join(webDir, "package.json"), packageJson, { spaces: 2 });
2025
+ await fs.writeJSON(path.join(webDir, "tsconfig.json"), {
1899
2026
  compilerOptions: {
1900
2027
  target: "ES2020",
1901
2028
  lib: ["ES2020", "DOM", "DOM.Iterable"],
@@ -1913,7 +2040,7 @@ async function scaffoldFullstackWeb(projectDir, projectName, frontend, auth = fa
1913
2040
  },
1914
2041
  include: ["src"]
1915
2042
  }, { spaces: 2 });
1916
- await import_fs_extra.default.writeFile(import_node_path.default.join(webDir, "vite.config.ts"), `import { defineConfig } from 'vite';
2043
+ await fs.writeFile(path.join(webDir, "vite.config.ts"), `import { defineConfig } from 'vite';
1917
2044
  import react from '@vitejs/plugin-react';
1918
2045
  import tailwindcss from '@tailwindcss/vite';
1919
2046
 
@@ -1927,7 +2054,7 @@ export default defineConfig({
1927
2054
  },
1928
2055
  });
1929
2056
  `);
1930
- await import_fs_extra.default.writeFile(import_node_path.default.join(webDir, "index.html"), `<!DOCTYPE html>
2057
+ await fs.writeFile(path.join(webDir, "index.html"), `<!DOCTYPE html>
1931
2058
  <html lang="en">
1932
2059
  <head>
1933
2060
  <meta charset="UTF-8" />
@@ -1940,12 +2067,12 @@ export default defineConfig({
1940
2067
  </body>
1941
2068
  </html>
1942
2069
  `);
1943
- await import_fs_extra.default.writeFile(import_node_path.default.join(webDir, "src", "index.css"), `@import "tailwindcss";
2070
+ await fs.writeFile(path.join(webDir, "src", "index.css"), `@import "tailwindcss";
1944
2071
 
1945
2072
  body { background-color: rgb(15 23 42); color: rgb(241 245 249); font-family: ui-sans-serif, system-ui, sans-serif; }
1946
2073
  * { box-sizing: border-box; }
1947
2074
  `);
1948
- await import_fs_extra.default.writeFile(import_node_path.default.join(webDir, "src", "lib", "api.ts"), `const API_BASE = '';
2075
+ await fs.writeFile(path.join(webDir, "src", "lib", "api.ts"), `const API_BASE = '';
1949
2076
 
1950
2077
  ${auth ? `export function getToken(): string | null {
1951
2078
  return localStorage.getItem('kozo_token');
@@ -1982,7 +2109,7 @@ ${auth ? ` const token = getToken();
1982
2109
  return { data, status: res.status, ms: Math.round(performance.now() - start) };
1983
2110
  }
1984
2111
  `);
1985
- await import_fs_extra.default.writeFile(import_node_path.default.join(webDir, "src", "main.tsx"), `import React from 'react';
2112
+ await fs.writeFile(path.join(webDir, "src", "main.tsx"), `import React from 'react';
1986
2113
  import ReactDOM from 'react-dom/client';
1987
2114
  import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
1988
2115
  import App from './App';
@@ -2000,14 +2127,14 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
2000
2127
  </React.StrictMode>
2001
2128
  );
2002
2129
  `);
2003
- await import_fs_extra.default.writeFile(import_node_path.default.join(webDir, "src", "pages", "Dashboard.tsx"), generateDashboardPage());
2004
- await import_fs_extra.default.writeFile(import_node_path.default.join(webDir, "src", "pages", "Users.tsx"), generateUsersPage());
2005
- await import_fs_extra.default.writeFile(import_node_path.default.join(webDir, "src", "pages", "Posts.tsx"), generatePostsPage());
2006
- await import_fs_extra.default.writeFile(import_node_path.default.join(webDir, "src", "pages", "Tasks.tsx"), generateTasksPage());
2130
+ await fs.writeFile(path.join(webDir, "src", "pages", "Dashboard.tsx"), generateDashboardPage());
2131
+ await fs.writeFile(path.join(webDir, "src", "pages", "Users.tsx"), generateUsersPage());
2132
+ await fs.writeFile(path.join(webDir, "src", "pages", "Posts.tsx"), generatePostsPage());
2133
+ await fs.writeFile(path.join(webDir, "src", "pages", "Tasks.tsx"), generateTasksPage());
2007
2134
  if (auth) {
2008
- await import_fs_extra.default.writeFile(import_node_path.default.join(webDir, "src", "pages", "Login.tsx"), generateLoginPage());
2135
+ await fs.writeFile(path.join(webDir, "src", "pages", "Login.tsx"), generateLoginPage());
2009
2136
  }
2010
- await import_fs_extra.default.writeFile(import_node_path.default.join(webDir, "src", "App.tsx"), generateAppTsx(projectName, auth));
2137
+ await fs.writeFile(path.join(webDir, "src", "App.tsx"), generateAppTsx(projectName, auth));
2011
2138
  }
2012
2139
  function generateAppTsx(projectName, auth) {
2013
2140
  const authImports = auth ? `import { getToken, clearToken } from './lib/api';` : "";
@@ -2791,19 +2918,19 @@ const res = await client.api.users.$get();
2791
2918
  const users = await res.json(); // Fully typed!
2792
2919
  \`\`\`
2793
2920
  `;
2794
- await import_fs_extra.default.writeFile(import_node_path.default.join(projectDir, "README.md"), readme);
2921
+ await fs.writeFile(path.join(projectDir, "README.md"), readme);
2795
2922
  }
2796
2923
 
2797
2924
  // src/utils/ascii-art.ts
2798
- var import_picocolors = __toESM(require("picocolors"));
2925
+ import pc from "picocolors";
2799
2926
  var KOZO_LOGO = `
2800
- ${import_picocolors.default.red(" _ __")}${import_picocolors.default.yellow("___ ")}${import_picocolors.default.red("______")}${import_picocolors.default.yellow("___ ")}
2801
- ${import_picocolors.default.red("| |/ /")}${import_picocolors.default.yellow(" _ \\\\")}${import_picocolors.default.red("|_ /")}${import_picocolors.default.yellow(" _ \\\\")}
2802
- ${import_picocolors.default.red("| ' /")}${import_picocolors.default.yellow(" (_) |")}${import_picocolors.default.red("/ /")}${import_picocolors.default.yellow(" (_) |")}
2803
- ${import_picocolors.default.red("|_|\\_\\\\")}${import_picocolors.default.yellow("___/")}${import_picocolors.default.red("___|\\\\")}${import_picocolors.default.yellow("___/")}
2927
+ ${pc.red(" _ __")}${pc.yellow("___ ")}${pc.red("______")}${pc.yellow("___ ")}
2928
+ ${pc.red("| |/ /")}${pc.yellow(" _ \\\\")}${pc.red("|_ /")}${pc.yellow(" _ \\\\")}
2929
+ ${pc.red("| ' /")}${pc.yellow(" (_) |")}${pc.red("/ /")}${pc.yellow(" (_) |")}
2930
+ ${pc.red("|_|\\_\\\\")}${pc.yellow("___/")}${pc.red("___|\\\\")}${pc.yellow("___/")}
2804
2931
  `;
2805
2932
  var KOZO_BANNER = `
2806
- ${import_picocolors.default.bold(import_picocolors.default.red("\u{1F525} KOZO"))} ${import_picocolors.default.dim("- The Structure for the Edge")}
2933
+ ${pc.bold(pc.red("\u{1F525} KOZO"))} ${pc.dim("- The Structure for the Edge")}
2807
2934
  `;
2808
2935
  function printLogo() {
2809
2936
  console.log(KOZO_LOGO);
@@ -2812,7 +2939,7 @@ function printLogo() {
2812
2939
  // src/commands/new.ts
2813
2940
  async function newCommand(projectName) {
2814
2941
  printLogo();
2815
- p.intro(import_picocolors2.default.bold(import_picocolors2.default.red("\u{1F525} Create a new Kozo project")));
2942
+ p.intro(pc2.bold(pc2.red("\u{1F525} Create a new Kozo project")));
2816
2943
  const isLocalWorkspace = process.env.KOZO_LOCAL === "true";
2817
2944
  const project = await p.group(
2818
2945
  {
@@ -2930,14 +3057,14 @@ async function newCommand(projectName) {
2930
3057
  if (project.install) {
2931
3058
  s.start("Installing dependencies...");
2932
3059
  try {
2933
- await (0, import_execa.execa)("pnpm", ["install"], {
3060
+ await execa("pnpm", ["install"], {
2934
3061
  cwd: project.name,
2935
3062
  stdio: "pipe"
2936
3063
  });
2937
3064
  s.stop("Dependencies installed!");
2938
3065
  } catch {
2939
3066
  try {
2940
- await (0, import_execa.execa)("npm", ["install"], {
3067
+ await execa("npm", ["install"], {
2941
3068
  cwd: project.name,
2942
3069
  stdio: "pipe"
2943
3070
  });
@@ -2948,33 +3075,33 @@ async function newCommand(projectName) {
2948
3075
  }
2949
3076
  }
2950
3077
  }
2951
- p.outro(import_picocolors2.default.green("\u2728 Project ready!"));
3078
+ p.outro(pc2.green("\u2728 Project ready!"));
2952
3079
  console.log(`
2953
- ${import_picocolors2.default.bold("Next steps:")}
3080
+ ${pc2.bold("Next steps:")}
2954
3081
 
2955
- ${import_picocolors2.default.cyan(`cd ${project.name}`)}
2956
- ${!project.install ? import_picocolors2.default.cyan("pnpm install") + "\n " : ""}${import_picocolors2.default.cyan("pnpm dev")}
3082
+ ${pc2.cyan(`cd ${project.name}`)}
3083
+ ${!project.install ? pc2.cyan("pnpm install") + "\n " : ""}${pc2.cyan("pnpm dev")}
2957
3084
 
2958
- ${import_picocolors2.default.dim("Documentation:")} ${import_picocolors2.default.underline("https://kozo-docs.vercel.app")}
3085
+ ${pc2.dim("Documentation:")} ${pc2.underline("https://kozo-docs.vercel.app")}
2959
3086
  `);
2960
3087
  }
2961
3088
 
2962
3089
  // src/commands/build.ts
2963
- var import_execa2 = require("execa");
2964
- var import_picocolors3 = __toESM(require("picocolors"));
2965
- var import_fs_extra2 = __toESM(require("fs-extra"));
2966
- var import_node_path4 = __toESM(require("path"));
3090
+ import { execa as execa2 } from "execa";
3091
+ import pc3 from "picocolors";
3092
+ import fs2 from "fs-extra";
3093
+ import path2 from "path";
2967
3094
 
2968
3095
  // src/routing/manifest.ts
2969
- var import_node_crypto = require("crypto");
2970
- var import_node_fs2 = require("fs");
2971
- var import_node_path3 = require("path");
2972
- var import_glob2 = require("glob");
3096
+ import { createHash } from "crypto";
3097
+ import { readFileSync as readFileSync2, writeFileSync, existsSync, mkdirSync } from "fs";
3098
+ import { join as join2, dirname } from "path";
3099
+ import { glob as glob2 } from "glob";
2973
3100
 
2974
3101
  // src/routing/scan.ts
2975
- var import_glob = require("glob");
2976
- var import_node_path2 = require("path");
2977
- var import_node_fs = require("fs");
3102
+ import { glob } from "glob";
3103
+ import { join } from "path";
3104
+ import { readFileSync } from "fs";
2978
3105
  var HTTP_METHODS = ["get", "post", "put", "patch", "delete"];
2979
3106
  function fileToRoute(filePath) {
2980
3107
  const normalized = filePath.replace(/\\/g, "/");
@@ -3012,7 +3139,7 @@ function isRouteFile(file) {
3012
3139
  function detectSchemas(absolutePath) {
3013
3140
  let source = "";
3014
3141
  try {
3015
- source = (0, import_node_fs.readFileSync)(absolutePath, "utf8");
3142
+ source = readFileSync(absolutePath, "utf8");
3016
3143
  } catch {
3017
3144
  return { hasBodySchema: false, hasQuerySchema: false };
3018
3145
  }
@@ -3032,7 +3159,7 @@ function routeScore(urlPath) {
3032
3159
  }
3033
3160
  async function scanRoutes(options) {
3034
3161
  const { routesDir, verbose = false } = options;
3035
- const files = await (0, import_glob.glob)("**/*.{ts,js}", {
3162
+ const files = await glob("**/*.{ts,js}", {
3036
3163
  cwd: routesDir,
3037
3164
  nodir: true,
3038
3165
  ignore: ["**/_*.ts", "**/_*.js", "**/*.test.ts", "**/*.spec.ts", "**/*.test.js", "**/*.spec.js"]
@@ -3042,7 +3169,7 @@ async function scanRoutes(options) {
3042
3169
  if (!isRouteFile(file)) continue;
3043
3170
  const parsed = fileToRoute(file);
3044
3171
  if (!parsed) continue;
3045
- const absolutePath = (0, import_node_path2.join)(routesDir, file);
3172
+ const absolutePath = join(routesDir, file);
3046
3173
  const { hasBodySchema, hasQuerySchema } = detectSchemas(absolutePath);
3047
3174
  const params = extractParams(parsed.path);
3048
3175
  routes.push({
@@ -3067,17 +3194,17 @@ async function scanRoutes(options) {
3067
3194
 
3068
3195
  // src/routing/manifest.ts
3069
3196
  async function hashRouteFiles(routesDir) {
3070
- const files = await (0, import_glob2.glob)("**/*.{ts,js}", {
3197
+ const files = await glob2("**/*.{ts,js}", {
3071
3198
  cwd: routesDir,
3072
3199
  nodir: true,
3073
3200
  ignore: ["**/_*.ts", "**/_*.js", "**/*.test.ts", "**/*.spec.ts", "**/*.test.js", "**/*.spec.js"]
3074
3201
  });
3075
3202
  files.sort();
3076
- const hash = (0, import_node_crypto.createHash)("sha256");
3203
+ const hash = createHash("sha256");
3077
3204
  for (const file of files) {
3078
3205
  hash.update(file);
3079
3206
  try {
3080
- const content = (0, import_node_fs2.readFileSync)((0, import_node_path3.join)(routesDir, file));
3207
+ const content = readFileSync2(join2(routesDir, file));
3081
3208
  hash.update(content);
3082
3209
  } catch {
3083
3210
  }
@@ -3085,9 +3212,9 @@ async function hashRouteFiles(routesDir) {
3085
3212
  return hash.digest("hex");
3086
3213
  }
3087
3214
  function readExistingManifest(manifestPath) {
3088
- if (!(0, import_node_fs2.existsSync)(manifestPath)) return null;
3215
+ if (!existsSync(manifestPath)) return null;
3089
3216
  try {
3090
- const raw = (0, import_node_fs2.readFileSync)(manifestPath, "utf8");
3217
+ const raw = readFileSync2(manifestPath, "utf8");
3091
3218
  return JSON.parse(raw);
3092
3219
  } catch {
3093
3220
  return null;
@@ -3097,7 +3224,7 @@ async function generateManifest(options) {
3097
3224
  const {
3098
3225
  routesDir,
3099
3226
  projectRoot,
3100
- outputPath = (0, import_node_path3.join)(projectRoot, "routes-manifest.json"),
3227
+ outputPath = join2(projectRoot, "routes-manifest.json"),
3101
3228
  cache = true,
3102
3229
  verbose = false
3103
3230
  } = options;
@@ -3130,11 +3257,11 @@ async function generateManifest(options) {
3130
3257
  contentHash,
3131
3258
  routes: entries
3132
3259
  };
3133
- const dir = (0, import_node_path3.dirname)(outputPath);
3134
- if (!(0, import_node_fs2.existsSync)(dir)) {
3135
- (0, import_node_fs2.mkdirSync)(dir, { recursive: true });
3260
+ const dir = dirname(outputPath);
3261
+ if (!existsSync(dir)) {
3262
+ mkdirSync(dir, { recursive: true });
3136
3263
  }
3137
- (0, import_node_fs2.writeFileSync)(outputPath, JSON.stringify(manifest, null, 2) + "\n", "utf8");
3264
+ writeFileSync(outputPath, JSON.stringify(manifest, null, 2) + "\n", "utf8");
3138
3265
  if (verbose) {
3139
3266
  console.log(` \u2713 Generated routes-manifest.json (${entries.length} routes, hash: ${contentHash.slice(0, 8)}\u2026)`);
3140
3267
  }
@@ -3147,22 +3274,22 @@ function printBox(title) {
3147
3274
  const width = 50;
3148
3275
  const pad = Math.max(0, Math.floor((width - title.length) / 2));
3149
3276
  const line = "\u2500".repeat(width);
3150
- console.log(import_picocolors3.default.cyan(`\u250C${line}\u2510`));
3151
- console.log(import_picocolors3.default.cyan("\u2502") + " ".repeat(pad) + import_picocolors3.default.bold(title) + " ".repeat(width - pad - title.length) + import_picocolors3.default.cyan("\u2502"));
3152
- console.log(import_picocolors3.default.cyan(`\u2514${line}\u2518`));
3277
+ console.log(pc3.cyan(`\u250C${line}\u2510`));
3278
+ console.log(pc3.cyan("\u2502") + " ".repeat(pad) + pc3.bold(title) + " ".repeat(width - pad - title.length) + pc3.cyan("\u2502"));
3279
+ console.log(pc3.cyan(`\u2514${line}\u2518`));
3153
3280
  console.log();
3154
3281
  }
3155
3282
  function step(n, total, label) {
3156
- console.log(import_picocolors3.default.dim(`[${n}/${total}]`) + " " + import_picocolors3.default.cyan("\u2192") + " " + label);
3283
+ console.log(pc3.dim(`[${n}/${total}]`) + " " + pc3.cyan("\u2192") + " " + label);
3157
3284
  }
3158
3285
  function ok(label) {
3159
- console.log(import_picocolors3.default.green(" \u2713") + " " + label);
3286
+ console.log(pc3.green(" \u2713") + " " + label);
3160
3287
  }
3161
3288
  function fail(label, err) {
3162
- console.log(import_picocolors3.default.red(" \u2717") + " " + label);
3289
+ console.log(pc3.red(" \u2717") + " " + label);
3163
3290
  if (err) {
3164
3291
  const msg = err instanceof Error ? err.message : String(err);
3165
- console.log(import_picocolors3.default.dim(" " + msg));
3292
+ console.log(pc3.dim(" " + msg));
3166
3293
  }
3167
3294
  }
3168
3295
  async function buildCommand(options = {}) {
@@ -3173,11 +3300,11 @@ async function buildCommand(options = {}) {
3173
3300
  let currentStep = 0;
3174
3301
  currentStep++;
3175
3302
  step(currentStep, TOTAL_STEPS, "Checking project structure\u2026");
3176
- if (!import_fs_extra2.default.existsSync(import_node_path4.default.join(cwd, "package.json"))) {
3303
+ if (!fs2.existsSync(path2.join(cwd, "package.json"))) {
3177
3304
  fail("No package.json found. Run this command inside a Kozo project.");
3178
3305
  process.exit(1);
3179
3306
  }
3180
- if (!import_fs_extra2.default.existsSync(import_node_path4.default.join(cwd, "node_modules"))) {
3307
+ if (!fs2.existsSync(path2.join(cwd, "node_modules"))) {
3181
3308
  fail("Dependencies not installed. Run `npm install` first.");
3182
3309
  process.exit(1);
3183
3310
  }
@@ -3185,7 +3312,7 @@ async function buildCommand(options = {}) {
3185
3312
  currentStep++;
3186
3313
  step(currentStep, TOTAL_STEPS, "Cleaning previous build\u2026");
3187
3314
  try {
3188
- await import_fs_extra2.default.remove(import_node_path4.default.join(cwd, "dist"));
3315
+ await fs2.remove(path2.join(cwd, "dist"));
3189
3316
  ok("dist/ cleaned");
3190
3317
  } catch (err) {
3191
3318
  fail("Failed to clean dist/", err);
@@ -3195,12 +3322,12 @@ async function buildCommand(options = {}) {
3195
3322
  currentStep++;
3196
3323
  step(currentStep, TOTAL_STEPS, "Generating routes manifest\u2026");
3197
3324
  const routesDirRel = options.routesDir ?? "src/routes";
3198
- const routesDirAbs = import_node_path4.default.join(cwd, routesDirRel);
3199
- if (!import_fs_extra2.default.existsSync(routesDirAbs)) {
3200
- console.log(import_picocolors3.default.dim(` \u26A0 Routes directory not found (${routesDirRel}), skipping manifest.`));
3325
+ const routesDirAbs = path2.join(cwd, routesDirRel);
3326
+ if (!fs2.existsSync(routesDirAbs)) {
3327
+ console.log(pc3.dim(` \u26A0 Routes directory not found (${routesDirRel}), skipping manifest.`));
3201
3328
  } else {
3202
3329
  try {
3203
- const manifestOutAbs = options.manifestOut ? import_node_path4.default.join(cwd, options.manifestOut) : import_node_path4.default.join(cwd, "routes-manifest.json");
3330
+ const manifestOutAbs = options.manifestOut ? path2.join(cwd, options.manifestOut) : path2.join(cwd, "routes-manifest.json");
3204
3331
  const manifest = await generateManifest({
3205
3332
  routesDir: routesDirAbs,
3206
3333
  projectRoot: cwd,
@@ -3211,7 +3338,7 @@ async function buildCommand(options = {}) {
3211
3338
  ok(`Manifest ready \u2014 ${manifest.routes.length} route(s)`);
3212
3339
  } catch (err) {
3213
3340
  fail("Manifest generation failed", err);
3214
- console.log(import_picocolors3.default.dim(" Continuing build without manifest\u2026"));
3341
+ console.log(pc3.dim(" Continuing build without manifest\u2026"));
3215
3342
  }
3216
3343
  }
3217
3344
  }
@@ -3219,7 +3346,7 @@ async function buildCommand(options = {}) {
3219
3346
  step(currentStep, TOTAL_STEPS, "Compiling with tsup\u2026");
3220
3347
  try {
3221
3348
  const tsupArgs = ["tsup", ...options.tsupArgs ?? []];
3222
- await (0, import_execa2.execa)("npx", tsupArgs, {
3349
+ await execa2("npx", tsupArgs, {
3223
3350
  cwd,
3224
3351
  stdio: "inherit",
3225
3352
  env: { ...process.env, NODE_ENV: "production" }
@@ -3230,12 +3357,12 @@ async function buildCommand(options = {}) {
3230
3357
  process.exit(1);
3231
3358
  }
3232
3359
  console.log();
3233
- console.log(import_picocolors3.default.green("\u2705 Build successful"));
3360
+ console.log(pc3.green("\u2705 Build successful"));
3234
3361
  console.log();
3235
3362
  }
3236
3363
 
3237
3364
  // src/index.ts
3238
- var program = new import_commander.Command();
3365
+ var program = new Command();
3239
3366
  program.name("kozo").description("CLI to scaffold new Kozo Framework projects").version("0.2.6");
3240
3367
  program.argument("[project-name]", "Name of the project").action(async (projectName) => {
3241
3368
  await newCommand(projectName);