@korajs/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/bin.cjs +2170 -0
  2. package/dist/bin.cjs.map +1 -0
  3. package/dist/bin.js +1640 -0
  4. package/dist/bin.js.map +1 -0
  5. package/dist/chunk-N36PFOSA.js +103 -0
  6. package/dist/chunk-N36PFOSA.js.map +1 -0
  7. package/dist/chunk-REOTYAM6.js +370 -0
  8. package/dist/chunk-REOTYAM6.js.map +1 -0
  9. package/dist/chunk-ZVB4HAB3.js +88 -0
  10. package/dist/chunk-ZVB4HAB3.js.map +1 -0
  11. package/dist/create.cjs +313 -0
  12. package/dist/create.cjs.map +1 -0
  13. package/dist/create.js +10 -0
  14. package/dist/create.js.map +1 -0
  15. package/dist/index.cjs +218 -0
  16. package/dist/index.cjs.map +1 -0
  17. package/dist/index.d.cts +72 -0
  18. package/dist/index.d.ts +72 -0
  19. package/dist/index.js +26 -0
  20. package/dist/index.js.map +1 -0
  21. package/package.json +48 -0
  22. package/templates/react-basic/index.html.hbs +12 -0
  23. package/templates/react-basic/kora.config.ts +13 -0
  24. package/templates/react-basic/package.json.hbs +26 -0
  25. package/templates/react-basic/src/App.tsx +48 -0
  26. package/templates/react-basic/src/main.tsx +16 -0
  27. package/templates/react-basic/src/schema.ts +15 -0
  28. package/templates/react-basic/tsconfig.json +14 -0
  29. package/templates/react-basic/vite.config.ts +6 -0
  30. package/templates/react-sync/index.html.hbs +12 -0
  31. package/templates/react-sync/kora.config.ts +17 -0
  32. package/templates/react-sync/package.json.hbs +28 -0
  33. package/templates/react-sync/server.ts +11 -0
  34. package/templates/react-sync/src/App.tsx +50 -0
  35. package/templates/react-sync/src/main.tsx +24 -0
  36. package/templates/react-sync/src/schema.ts +15 -0
  37. package/templates/react-sync/tsconfig.json +14 -0
  38. package/templates/react-sync/vite.config.ts +6 -0
@@ -0,0 +1,313 @@
1
+ "use strict";
2
+
3
+ // src/create.ts
4
+ var import_citty2 = require("citty");
5
+
6
+ // src/commands/create/create-command.ts
7
+ var import_node_child_process2 = require("child_process");
8
+ var import_node_fs = require("fs");
9
+ var import_node_path3 = require("path");
10
+ var import_node_url2 = require("url");
11
+ var import_citty = require("citty");
12
+
13
+ // src/errors.ts
14
+ var import_core = require("@korajs/core");
15
+ var ProjectExistsError = class extends import_core.KoraError {
16
+ constructor(directory) {
17
+ super(
18
+ `Directory "${directory}" already exists. Choose a different name or remove the existing directory.`,
19
+ "PROJECT_EXISTS",
20
+ { directory }
21
+ );
22
+ this.directory = directory;
23
+ this.name = "ProjectExistsError";
24
+ }
25
+ directory;
26
+ };
27
+
28
+ // src/types.ts
29
+ var PACKAGE_MANAGERS = ["pnpm", "npm", "yarn", "bun"];
30
+ var TEMPLATES = ["react-basic", "react-sync"];
31
+ var TEMPLATE_INFO = [
32
+ {
33
+ name: "react-basic",
34
+ label: "React (basic)",
35
+ description: "Local-only React app with Kora \u2014 no sync server"
36
+ },
37
+ {
38
+ name: "react-sync",
39
+ label: "React (with sync)",
40
+ description: "React app with Kora sync server included"
41
+ }
42
+ ];
43
+
44
+ // src/utils/fs-helpers.ts
45
+ var import_promises = require("fs/promises");
46
+ var import_node_path = require("path");
47
+ async function directoryExists(path) {
48
+ try {
49
+ await (0, import_promises.access)(path);
50
+ return true;
51
+ } catch {
52
+ return false;
53
+ }
54
+ }
55
+
56
+ // src/utils/logger.ts
57
+ var RESET = "\x1B[0m";
58
+ var BOLD = "\x1B[1m";
59
+ var DIM = "\x1B[2m";
60
+ var GREEN = "\x1B[32m";
61
+ var YELLOW = "\x1B[33m";
62
+ var RED = "\x1B[31m";
63
+ var CYAN = "\x1B[36m";
64
+ function createLogger(options) {
65
+ const colorDisabled = options?.noColor === true || process.env.NO_COLOR !== void 0 || !process.stdout.isTTY;
66
+ function color(code, text) {
67
+ return colorDisabled ? text : `${code}${text}${RESET}`;
68
+ }
69
+ return {
70
+ info(message) {
71
+ console.log(color(CYAN, message));
72
+ },
73
+ success(message) {
74
+ console.log(color(GREEN, ` \u2713 ${message}`));
75
+ },
76
+ warn(message) {
77
+ console.warn(color(YELLOW, ` \u26A0 ${message}`));
78
+ },
79
+ error(message) {
80
+ console.error(color(RED, ` \u2717 ${message}`));
81
+ },
82
+ step(message) {
83
+ console.log(color(DIM, ` ${message}`));
84
+ },
85
+ blank() {
86
+ console.log();
87
+ },
88
+ banner() {
89
+ console.log();
90
+ console.log(
91
+ color(BOLD + CYAN, " Kora.js") + color(DIM, " \u2014 Offline-first application framework")
92
+ );
93
+ console.log();
94
+ }
95
+ };
96
+ }
97
+
98
+ // src/utils/package-manager.ts
99
+ var import_node_child_process = require("child_process");
100
+ function detectPackageManager() {
101
+ const userAgent = process.env.npm_config_user_agent;
102
+ if (!userAgent) return "npm";
103
+ if (userAgent.startsWith("pnpm/")) return "pnpm";
104
+ if (userAgent.startsWith("yarn/")) return "yarn";
105
+ if (userAgent.startsWith("bun/")) return "bun";
106
+ return "npm";
107
+ }
108
+ function getInstallCommand(pm) {
109
+ return pm === "yarn" ? "yarn" : `${pm} install`;
110
+ }
111
+ function getRunDevCommand(pm) {
112
+ if (pm === "npm") return "npm run dev";
113
+ return `${pm} dev`;
114
+ }
115
+
116
+ // src/utils/prompt.ts
117
+ var import_node_readline = require("readline");
118
+ function promptText(message, defaultValue, options) {
119
+ return new Promise((resolve4) => {
120
+ const rl = createReadline(options);
121
+ const suffix = defaultValue !== void 0 ? ` (${defaultValue})` : "";
122
+ rl.question(` ? ${message}${suffix}: `, (answer) => {
123
+ rl.close();
124
+ const trimmed = answer.trim();
125
+ resolve4(trimmed || defaultValue || "");
126
+ });
127
+ });
128
+ }
129
+ function promptSelect(message, choices, options) {
130
+ return new Promise((resolve4) => {
131
+ const rl = createReadline(options);
132
+ const out = options?.output ?? process.stdout;
133
+ out.write(` ? ${message}
134
+ `);
135
+ for (let i = 0; i < choices.length; i++) {
136
+ const choice = choices[i];
137
+ if (choice) {
138
+ out.write(` ${i + 1}) ${choice.label}
139
+ `);
140
+ }
141
+ }
142
+ const ask = () => {
143
+ rl.question(" > ", (answer) => {
144
+ const index = Number.parseInt(answer.trim(), 10) - 1;
145
+ const selected = choices[index];
146
+ if (selected) {
147
+ rl.close();
148
+ resolve4(selected.value);
149
+ } else {
150
+ out.write(` Please enter a number between 1 and ${choices.length}
151
+ `);
152
+ ask();
153
+ }
154
+ });
155
+ };
156
+ ask();
157
+ });
158
+ }
159
+ function createReadline(options) {
160
+ return (0, import_node_readline.createInterface)({
161
+ input: options?.input ?? process.stdin,
162
+ output: options?.output ?? process.stdout
163
+ });
164
+ }
165
+
166
+ // src/commands/create/template-engine.ts
167
+ var import_promises2 = require("fs/promises");
168
+ var import_node_path2 = require("path");
169
+ var import_node_url = require("url");
170
+ var import_meta = {};
171
+ function substituteVariables(template, context) {
172
+ return template.replace(/\{\{(\w+)\}\}/g, (_match, key) => {
173
+ const value = context[key];
174
+ return value !== void 0 ? value : `{{${key}}}`;
175
+ });
176
+ }
177
+ function getTemplatePath(templateName) {
178
+ const currentDir = (0, import_node_path2.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
179
+ return (0, import_node_path2.resolve)(currentDir, "..", "..", "..", "templates", templateName);
180
+ }
181
+ async function scaffoldTemplate(templateName, targetDir, context) {
182
+ const templateDir = getTemplatePath(templateName);
183
+ const vars = {
184
+ projectName: context.projectName,
185
+ packageManager: context.packageManager,
186
+ koraVersion: context.koraVersion
187
+ };
188
+ await copyDirectory(templateDir, targetDir, vars);
189
+ }
190
+ async function copyDirectory(src, dest, vars) {
191
+ await (0, import_promises2.mkdir)(dest, { recursive: true });
192
+ const entries = await (0, import_promises2.readdir)(src);
193
+ for (const entry of entries) {
194
+ const srcPath = (0, import_node_path2.join)(src, entry);
195
+ const srcStat = await (0, import_promises2.stat)(srcPath);
196
+ if (srcStat.isDirectory()) {
197
+ await copyDirectory(srcPath, (0, import_node_path2.join)(dest, entry), vars);
198
+ } else if (entry.endsWith(".hbs")) {
199
+ const content = await (0, import_promises2.readFile)(srcPath, "utf-8");
200
+ const outputName = entry.slice(0, -4);
201
+ await (0, import_promises2.writeFile)((0, import_node_path2.join)(dest, outputName), substituteVariables(content, vars), "utf-8");
202
+ } else {
203
+ await (0, import_promises2.copyFile)(srcPath, (0, import_node_path2.join)(dest, entry));
204
+ }
205
+ }
206
+ }
207
+
208
+ // src/commands/create/create-command.ts
209
+ var import_meta2 = {};
210
+ var createCommand = (0, import_citty.defineCommand)({
211
+ meta: {
212
+ name: "create",
213
+ description: "Create a new Kora application"
214
+ },
215
+ args: {
216
+ name: {
217
+ type: "positional",
218
+ description: "Project directory name",
219
+ required: false
220
+ },
221
+ template: {
222
+ type: "string",
223
+ description: "Project template (react-basic, react-sync)"
224
+ },
225
+ pm: {
226
+ type: "string",
227
+ description: "Package manager (pnpm, npm, yarn, bun)"
228
+ },
229
+ "skip-install": {
230
+ type: "boolean",
231
+ description: "Skip installing dependencies",
232
+ default: false
233
+ }
234
+ },
235
+ async run({ args }) {
236
+ const logger = createLogger();
237
+ logger.banner();
238
+ const projectName = args.name || await promptText("Project name", "my-kora-app");
239
+ if (!projectName) {
240
+ logger.error("Project name is required");
241
+ process.exitCode = 1;
242
+ return;
243
+ }
244
+ let template;
245
+ if (args.template && isValidTemplate(args.template)) {
246
+ template = args.template;
247
+ } else {
248
+ template = await promptSelect(
249
+ "Select a template:",
250
+ TEMPLATE_INFO.map((t) => ({ label: `${t.label} \u2014 ${t.description}`, value: t.name }))
251
+ );
252
+ }
253
+ let pm;
254
+ if (args.pm && isValidPackageManager(args.pm)) {
255
+ pm = args.pm;
256
+ } else {
257
+ const detected = detectPackageManager();
258
+ pm = await promptSelect(
259
+ "Package manager:",
260
+ PACKAGE_MANAGERS.map((p) => ({
261
+ label: p === detected ? `${p} (detected)` : p,
262
+ value: p
263
+ }))
264
+ );
265
+ }
266
+ const targetDir = (0, import_node_path3.resolve)(process.cwd(), projectName);
267
+ if (await directoryExists(targetDir)) {
268
+ throw new ProjectExistsError(projectName);
269
+ }
270
+ const koraVersion = resolveKoraVersion();
271
+ logger.step(`Creating ${projectName} with ${template} template...`);
272
+ await scaffoldTemplate(template, targetDir, {
273
+ projectName,
274
+ packageManager: pm,
275
+ koraVersion
276
+ });
277
+ logger.success("Project scaffolded");
278
+ if (!args["skip-install"]) {
279
+ logger.step("Installing dependencies...");
280
+ try {
281
+ (0, import_node_child_process2.execSync)(getInstallCommand(pm), { cwd: targetDir, stdio: "inherit" });
282
+ logger.success("Dependencies installed");
283
+ } catch {
284
+ logger.warn("Failed to install dependencies. Run install manually.");
285
+ }
286
+ }
287
+ logger.blank();
288
+ logger.info("Done! Next steps:");
289
+ logger.blank();
290
+ logger.step(` cd ${projectName}`);
291
+ logger.step(` ${getRunDevCommand(pm)}`);
292
+ logger.blank();
293
+ }
294
+ });
295
+ function isValidTemplate(value) {
296
+ return TEMPLATES.includes(value);
297
+ }
298
+ function isValidPackageManager(value) {
299
+ return PACKAGE_MANAGERS.includes(value);
300
+ }
301
+ function resolveKoraVersion() {
302
+ try {
303
+ const cliDir = (0, import_node_path3.resolve)((0, import_node_path3.dirname)((0, import_node_url2.fileURLToPath)(import_meta2.url)), "..", "..", "..");
304
+ const pkg = JSON.parse((0, import_node_fs.readFileSync)((0, import_node_path3.resolve)(cliDir, "package.json"), "utf-8"));
305
+ return pkg.version === "0.0.0" ? "latest" : `^${pkg.version}`;
306
+ } catch {
307
+ return "latest";
308
+ }
309
+ }
310
+
311
+ // src/create.ts
312
+ (0, import_citty2.runMain)(createCommand);
313
+ //# sourceMappingURL=create.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/create.ts","../src/commands/create/create-command.ts","../src/errors.ts","../src/types.ts","../src/utils/fs-helpers.ts","../src/utils/logger.ts","../src/utils/package-manager.ts","../src/utils/prompt.ts","../src/commands/create/template-engine.ts"],"sourcesContent":["import { runMain } from 'citty'\nimport { createCommand } from './commands/create/create-command'\n\nrunMain(createCommand)\n","import { execSync } from 'node:child_process'\nimport { readFileSync } from 'node:fs'\nimport { dirname, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { defineCommand } from 'citty'\nimport { ProjectExistsError } from '../../errors'\nimport { PACKAGE_MANAGERS, TEMPLATES, TEMPLATE_INFO } from '../../types'\nimport type { PackageManager, TemplateName } from '../../types'\nimport { directoryExists } from '../../utils/fs-helpers'\nimport { createLogger } from '../../utils/logger'\nimport {\n\tdetectPackageManager,\n\tgetInstallCommand,\n\tgetRunDevCommand,\n} from '../../utils/package-manager'\nimport { promptSelect, promptText } from '../../utils/prompt'\nimport { scaffoldTemplate } from './template-engine'\n\n/**\n * The `create` command — scaffolds a new Kora project.\n * Used as `kora create <name>` or `create-kora-app <name>`.\n */\nexport const createCommand = defineCommand({\n\tmeta: {\n\t\tname: 'create',\n\t\tdescription: 'Create a new Kora application',\n\t},\n\targs: {\n\t\tname: {\n\t\t\ttype: 'positional',\n\t\t\tdescription: 'Project directory name',\n\t\t\trequired: false,\n\t\t},\n\t\ttemplate: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Project template (react-basic, react-sync)',\n\t\t},\n\t\tpm: {\n\t\t\ttype: 'string',\n\t\t\tdescription: 'Package manager (pnpm, npm, yarn, bun)',\n\t\t},\n\t\t'skip-install': {\n\t\t\ttype: 'boolean',\n\t\t\tdescription: 'Skip installing dependencies',\n\t\t\tdefault: false,\n\t\t},\n\t},\n\tasync run({ args }) {\n\t\tconst logger = createLogger()\n\t\tlogger.banner()\n\n\t\t// Resolve project name\n\t\tconst projectName = args.name || (await promptText('Project name', 'my-kora-app'))\n\t\tif (!projectName) {\n\t\t\tlogger.error('Project name is required')\n\t\t\tprocess.exitCode = 1\n\t\t\treturn\n\t\t}\n\n\t\t// Resolve template\n\t\tlet template: TemplateName\n\t\tif (args.template && isValidTemplate(args.template)) {\n\t\t\ttemplate = args.template\n\t\t} else {\n\t\t\ttemplate = await promptSelect(\n\t\t\t\t'Select a template:',\n\t\t\t\tTEMPLATE_INFO.map((t) => ({ label: `${t.label} — ${t.description}`, value: t.name })),\n\t\t\t)\n\t\t}\n\n\t\t// Resolve package manager\n\t\tlet pm: PackageManager\n\t\tif (args.pm && isValidPackageManager(args.pm)) {\n\t\t\tpm = args.pm\n\t\t} else {\n\t\t\tconst detected = detectPackageManager()\n\t\t\tpm = await promptSelect(\n\t\t\t\t'Package manager:',\n\t\t\t\tPACKAGE_MANAGERS.map((p) => ({\n\t\t\t\t\tlabel: p === detected ? `${p} (detected)` : p,\n\t\t\t\t\tvalue: p,\n\t\t\t\t})),\n\t\t\t)\n\t\t}\n\n\t\t// Validate target directory\n\t\tconst targetDir = resolve(process.cwd(), projectName)\n\t\tif (await directoryExists(targetDir)) {\n\t\t\tthrow new ProjectExistsError(projectName)\n\t\t}\n\n\t\t// Resolve kora version from this package's own package.json\n\t\tconst koraVersion = resolveKoraVersion()\n\n\t\t// Scaffold\n\t\tlogger.step(`Creating ${projectName} with ${template} template...`)\n\t\tawait scaffoldTemplate(template, targetDir, {\n\t\t\tprojectName,\n\t\t\tpackageManager: pm,\n\t\t\tkoraVersion,\n\t\t})\n\t\tlogger.success('Project scaffolded')\n\n\t\t// Install dependencies\n\t\tif (!args['skip-install']) {\n\t\t\tlogger.step('Installing dependencies...')\n\t\t\ttry {\n\t\t\t\texecSync(getInstallCommand(pm), { cwd: targetDir, stdio: 'inherit' })\n\t\t\t\tlogger.success('Dependencies installed')\n\t\t\t} catch {\n\t\t\t\tlogger.warn('Failed to install dependencies. Run install manually.')\n\t\t\t}\n\t\t}\n\n\t\t// Print next steps\n\t\tlogger.blank()\n\t\tlogger.info('Done! Next steps:')\n\t\tlogger.blank()\n\t\tlogger.step(` cd ${projectName}`)\n\t\tlogger.step(` ${getRunDevCommand(pm)}`)\n\t\tlogger.blank()\n\t},\n})\n\nfunction isValidTemplate(value: string): value is TemplateName {\n\treturn (TEMPLATES as readonly string[]).includes(value)\n}\n\nfunction isValidPackageManager(value: string): value is PackageManager {\n\treturn (PACKAGE_MANAGERS as readonly string[]).includes(value)\n}\n\n/**\n * Reads the version from @korajs/cli's own package.json.\n * Scaffolded projects pin their kora dependencies to this version.\n */\nfunction resolveKoraVersion(): string {\n\ttry {\n\t\tconst cliDir = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', '..')\n\t\tconst pkg = JSON.parse(readFileSync(resolve(cliDir, 'package.json'), 'utf-8')) as { version: string }\n\t\treturn pkg.version === '0.0.0' ? 'latest' : `^${pkg.version}`\n\t} catch {\n\t\treturn 'latest'\n\t}\n}\n","import { KoraError } from '@korajs/core'\n\n/**\n * Base error class for all CLI errors.\n */\nexport class CliError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'CLI_ERROR', context)\n\t\tthis.name = 'CliError'\n\t}\n}\n\n/**\n * Thrown when the target project directory already exists.\n */\nexport class ProjectExistsError extends KoraError {\n\tconstructor(public readonly directory: string) {\n\t\tsuper(\n\t\t\t`Directory \"${directory}\" already exists. Choose a different name or remove the existing directory.`,\n\t\t\t'PROJECT_EXISTS',\n\t\t\t{ directory },\n\t\t)\n\t\tthis.name = 'ProjectExistsError'\n\t}\n}\n\n/**\n * Thrown when a schema file cannot be found in the project.\n */\nexport class SchemaNotFoundError extends KoraError {\n\tconstructor(public readonly searchedPaths: string[]) {\n\t\tsuper(\n\t\t\t`Could not find a schema file. Searched: ${searchedPaths.join(', ')}. Create a schema file using defineSchema() from @korajs/core.`,\n\t\t\t'SCHEMA_NOT_FOUND',\n\t\t\t{ searchedPaths },\n\t\t)\n\t\tthis.name = 'SchemaNotFoundError'\n\t}\n}\n\n/**\n * Thrown when a command is run outside a valid Kora project.\n */\nexport class InvalidProjectError extends KoraError {\n\tconstructor(public readonly directory: string) {\n\t\tsuper(\n\t\t\t`\"${directory}\" is not a valid Kora project. No package.json with a kora dependency found. Run this command from inside a Kora project.`,\n\t\t\t'INVALID_PROJECT',\n\t\t\t{ directory },\n\t\t)\n\t\tthis.name = 'InvalidProjectError'\n\t}\n}\n\n/**\n * Thrown when a required local dev server binary cannot be found.\n */\nexport class DevServerError extends KoraError {\n\tconstructor(\n\t\tpublic readonly binary: string,\n\t\tpublic readonly searchPath: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not find required binary \"${binary}\" at ${searchPath}. Install project dependencies and try again.`,\n\t\t\t'DEV_SERVER_ERROR',\n\t\t\t{ binary, searchPath },\n\t\t)\n\t\tthis.name = 'DevServerError'\n\t}\n}\n","/** Supported package managers */\nexport const PACKAGE_MANAGERS = ['pnpm', 'npm', 'yarn', 'bun'] as const\nexport type PackageManager = (typeof PACKAGE_MANAGERS)[number]\n\n/** Available project templates */\nexport const TEMPLATES = ['react-basic', 'react-sync'] as const\nexport type TemplateName = (typeof TEMPLATES)[number]\n\n/** Metadata for a project template */\nexport interface TemplateInfo {\n\tname: TemplateName\n\tlabel: string\n\tdescription: string\n}\n\n/** Available templates with their descriptions */\nexport const TEMPLATE_INFO: readonly TemplateInfo[] = [\n\t{\n\t\tname: 'react-basic',\n\t\tlabel: 'React (basic)',\n\t\tdescription: 'Local-only React app with Kora — no sync server',\n\t},\n\t{\n\t\tname: 'react-sync',\n\t\tlabel: 'React (with sync)',\n\t\tdescription: 'React app with Kora sync server included',\n\t},\n] as const\n\n/** Variables available for template substitution */\nexport interface TemplateContext {\n\tprojectName: string\n\tpackageManager: PackageManager\n\tkoraVersion: string\n}\n","import { access, readFile } from 'node:fs/promises'\nimport { dirname, join, resolve } from 'node:path'\n\n/** Checks if a directory exists at the given path */\nexport async function directoryExists(path: string): Promise<boolean> {\n\ttry {\n\t\tawait access(path)\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/**\n * Walks up the directory tree from startDir looking for a package.json\n * that contains a kora or @korajs/* dependency.\n *\n * @param startDir - Directory to start searching from (defaults to cwd)\n * @returns Absolute path to the project root, or null if not found\n */\nexport async function findProjectRoot(startDir?: string): Promise<string | null> {\n\tlet current = resolve(startDir ?? process.cwd())\n\n\t// Walk up until the filesystem root (where dirname(x) === x)\n\tfor (;;) {\n\t\tconst pkgPath = join(current, 'package.json')\n\t\ttry {\n\t\t\tconst content = await readFile(pkgPath, 'utf-8')\n\t\t\tconst pkg: unknown = JSON.parse(content)\n\t\t\tif (isKoraProject(pkg)) {\n\t\t\t\treturn current\n\t\t\t}\n\t\t} catch {\n\t\t\t// No package.json at this level, keep walking up\n\t\t}\n\t\tconst parent = dirname(current)\n\t\tif (parent === current) break\n\t\tcurrent = parent\n\t}\n\n\treturn null\n}\n\n/**\n * Searches for a schema file in common locations within a project.\n *\n * @param projectRoot - The project root directory\n * @returns Absolute path to the schema file, or null if not found\n */\nexport async function findSchemaFile(projectRoot: string): Promise<string | null> {\n\tconst candidates = [\n\t\tjoin(projectRoot, 'src', 'schema.ts'),\n\t\tjoin(projectRoot, 'schema.ts'),\n\t\tjoin(projectRoot, 'src', 'schema.js'),\n\t\tjoin(projectRoot, 'schema.js'),\n\t]\n\n\tfor (const candidate of candidates) {\n\t\ttry {\n\t\t\tawait access(candidate)\n\t\t\treturn candidate\n\t\t} catch {\n\t\t\t// Not found, try next\n\t\t}\n\t}\n\n\treturn null\n}\n\n/**\n * Resolves a binary from a project's local node_modules/.bin directory.\n *\n * @param projectRoot - The project root directory\n * @param binaryName - Binary filename (for example: vite, tsx, kora)\n * @returns Absolute path to the binary, or null if not found\n */\nexport async function resolveProjectBinary(\n\tprojectRoot: string,\n\tbinaryName: string,\n): Promise<string | null> {\n\tconst binaryPath = join(projectRoot, 'node_modules', '.bin', binaryName)\n\n\ttry {\n\t\tawait access(binaryPath)\n\t\treturn binaryPath\n\t} catch {\n\t\treturn null\n\t}\n}\n\nfunction isKoraProject(pkg: unknown): boolean {\n\tif (typeof pkg !== 'object' || pkg === null) return false\n\tconst record = pkg as Record<string, unknown>\n\treturn hasKoraDep(record.dependencies) || hasKoraDep(record.devDependencies)\n}\n\nfunction hasKoraDep(deps: unknown): boolean {\n\tif (typeof deps !== 'object' || deps === null) return false\n\treturn Object.keys(deps).some((key) => key === 'kora' || key.startsWith('@korajs/'))\n}\n","/** ANSI escape codes for terminal colors */\nconst RESET = '\\x1b[0m'\nconst BOLD = '\\x1b[1m'\nconst DIM = '\\x1b[2m'\nconst GREEN = '\\x1b[32m'\nconst YELLOW = '\\x1b[33m'\nconst RED = '\\x1b[31m'\nconst CYAN = '\\x1b[36m'\n\nexport interface LoggerOptions {\n\t/** Disable ANSI colors */\n\tnoColor?: boolean\n}\n\nexport interface Logger {\n\tinfo(message: string): void\n\tsuccess(message: string): void\n\twarn(message: string): void\n\terror(message: string): void\n\tstep(message: string): void\n\tblank(): void\n\tbanner(): void\n}\n\n/**\n * Creates a logger with optional ANSI color support.\n * Respects the NO_COLOR environment variable and TTY detection.\n */\nexport function createLogger(options?: LoggerOptions): Logger {\n\tconst colorDisabled =\n\t\toptions?.noColor === true || process.env.NO_COLOR !== undefined || !process.stdout.isTTY\n\n\tfunction color(code: string, text: string): string {\n\t\treturn colorDisabled ? text : `${code}${text}${RESET}`\n\t}\n\n\treturn {\n\t\tinfo(message: string): void {\n\t\t\tconsole.log(color(CYAN, message))\n\t\t},\n\t\tsuccess(message: string): void {\n\t\t\tconsole.log(color(GREEN, ` ✓ ${message}`))\n\t\t},\n\t\twarn(message: string): void {\n\t\t\tconsole.warn(color(YELLOW, ` ⚠ ${message}`))\n\t\t},\n\t\terror(message: string): void {\n\t\t\tconsole.error(color(RED, ` ✗ ${message}`))\n\t\t},\n\t\tstep(message: string): void {\n\t\t\tconsole.log(color(DIM, ` ${message}`))\n\t\t},\n\t\tblank(): void {\n\t\t\tconsole.log()\n\t\t},\n\t\tbanner(): void {\n\t\t\tconsole.log()\n\t\t\tconsole.log(\n\t\t\t\tcolor(BOLD + CYAN, ' Kora.js') + color(DIM, ' — Offline-first application framework'),\n\t\t\t)\n\t\t\tconsole.log()\n\t\t},\n\t}\n}\n","import { execSync } from 'node:child_process'\nimport type { PackageManager } from '../types'\n\n/**\n * Detects the package manager used to invoke the current process\n * by reading the npm_config_user_agent environment variable.\n * Falls back to 'npm' if detection fails.\n */\nexport function detectPackageManager(): PackageManager {\n\tconst userAgent = process.env.npm_config_user_agent\n\tif (!userAgent) return 'npm'\n\n\tif (userAgent.startsWith('pnpm/')) return 'pnpm'\n\tif (userAgent.startsWith('yarn/')) return 'yarn'\n\tif (userAgent.startsWith('bun/')) return 'bun'\n\treturn 'npm'\n}\n\n/** Returns the install command for the given package manager */\nexport function getInstallCommand(pm: PackageManager): string {\n\treturn pm === 'yarn' ? 'yarn' : `${pm} install`\n}\n\n/** Returns the dev server run command for the given package manager */\nexport function getRunDevCommand(pm: PackageManager): string {\n\tif (pm === 'npm') return 'npm run dev'\n\treturn `${pm} dev`\n}\n\n/** Checks if a package manager is available on PATH */\nexport function isPackageManagerAvailable(pm: PackageManager): boolean {\n\ttry {\n\t\texecSync(`${pm} --version`, { stdio: 'ignore' })\n\t\treturn true\n\t} catch {\n\t\treturn false\n\t}\n}\n","import { type Interface as ReadlineInterface, createInterface } from 'node:readline'\n\nexport interface PromptOptions {\n\t/** Input stream (defaults to process.stdin) */\n\tinput?: NodeJS.ReadableStream\n\t/** Output stream (defaults to process.stdout) */\n\toutput?: NodeJS.WritableStream\n}\n\n/**\n * Prompts the user for text input.\n *\n * @param message - The prompt message to display\n * @param defaultValue - Optional default value shown in brackets\n * @param options - Optional input/output streams for testing\n */\nexport function promptText(\n\tmessage: string,\n\tdefaultValue?: string,\n\toptions?: PromptOptions,\n): Promise<string> {\n\treturn new Promise((resolve) => {\n\t\tconst rl = createReadline(options)\n\t\tconst suffix = defaultValue !== undefined ? ` (${defaultValue})` : ''\n\t\trl.question(` ? ${message}${suffix}: `, (answer) => {\n\t\t\trl.close()\n\t\t\tconst trimmed = answer.trim()\n\t\t\tresolve(trimmed || defaultValue || '')\n\t\t})\n\t})\n}\n\n/**\n * Prompts the user to select from a numbered list of options.\n *\n * @param message - The prompt message to display\n * @param choices - Array of { label, value } options\n * @param options - Optional input/output streams for testing\n */\nexport function promptSelect<T extends string>(\n\tmessage: string,\n\tchoices: readonly { label: string; value: T }[],\n\toptions?: PromptOptions,\n): Promise<T> {\n\treturn new Promise((resolve) => {\n\t\tconst rl = createReadline(options)\n\t\tconst out = options?.output ?? process.stdout\n\n\t\tout.write(` ? ${message}\\n`)\n\t\tfor (let i = 0; i < choices.length; i++) {\n\t\t\tconst choice = choices[i]\n\t\t\tif (choice) {\n\t\t\t\tout.write(` ${i + 1}) ${choice.label}\\n`)\n\t\t\t}\n\t\t}\n\n\t\tconst ask = (): void => {\n\t\t\trl.question(' > ', (answer) => {\n\t\t\t\tconst index = Number.parseInt(answer.trim(), 10) - 1\n\t\t\t\tconst selected = choices[index]\n\t\t\t\tif (selected) {\n\t\t\t\t\trl.close()\n\t\t\t\t\tresolve(selected.value)\n\t\t\t\t} else {\n\t\t\t\t\tout.write(` Please enter a number between 1 and ${choices.length}\\n`)\n\t\t\t\t\task()\n\t\t\t\t}\n\t\t\t})\n\t\t}\n\n\t\task()\n\t})\n}\n\n/**\n * Prompts the user with a yes/no confirmation.\n *\n * @param message - The prompt message to display\n * @param defaultValue - Default when input is empty (true => yes)\n * @param options - Optional input/output streams for testing\n */\nexport function promptConfirm(\n\tmessage: string,\n\tdefaultValue = false,\n\toptions?: PromptOptions,\n): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst rl = createReadline(options)\n\t\tconst suffix = defaultValue ? 'Y/n' : 'y/N'\n\n\t\tconst ask = (): void => {\n\t\t\trl.question(` ? ${message} (${suffix}): `, (answer) => {\n\t\t\t\tconst normalized = answer.trim().toLowerCase()\n\t\t\t\tif (normalized.length === 0) {\n\t\t\t\t\trl.close()\n\t\t\t\t\tresolve(defaultValue)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif (normalized === 'y' || normalized === 'yes') {\n\t\t\t\t\trl.close()\n\t\t\t\t\tresolve(true)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\tif (normalized === 'n' || normalized === 'no') {\n\t\t\t\t\trl.close()\n\t\t\t\t\tresolve(false)\n\t\t\t\t\treturn\n\t\t\t\t}\n\n\t\t\t\t(options?.output ?? process.stdout).write(' Please answer with y or n\\n')\n\t\t\t\task()\n\t\t\t})\n\t\t}\n\n\t\task()\n\t})\n}\n\nfunction createReadline(options?: PromptOptions): ReadlineInterface {\n\treturn createInterface({\n\t\tinput: options?.input ?? process.stdin,\n\t\toutput: options?.output ?? process.stdout,\n\t})\n}\n","import { copyFile, mkdir, readFile, readdir, stat, writeFile } from 'node:fs/promises'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport type { TemplateContext, TemplateName } from '../../types'\n\n/**\n * Replaces {{variable}} placeholders in a template string with context values.\n *\n * @param template - The template string containing {{variable}} placeholders\n * @param context - Key-value pairs to substitute\n * @returns The template with all placeholders replaced\n */\nexport function substituteVariables(template: string, context: Record<string, string>): string {\n\treturn template.replace(/\\{\\{(\\w+)\\}\\}/g, (_match, key: string) => {\n\t\tconst value = context[key]\n\t\treturn value !== undefined ? value : `{{${key}}}`\n\t})\n}\n\n/**\n * Resolves the absolute path to a bundled template directory.\n *\n * @param templateName - Name of the template (e.g. 'react-basic')\n * @returns Absolute path to the template directory\n */\nexport function getTemplatePath(templateName: TemplateName): string {\n\t// Navigate from src/commands/create/ up to package root, then into templates/\n\tconst currentDir = dirname(fileURLToPath(import.meta.url))\n\treturn resolve(currentDir, '..', '..', '..', 'templates', templateName)\n}\n\n/**\n * Scaffolds a project from a bundled template.\n * Copies all files from the template directory to the target, applying\n * variable substitution to .hbs files and stripping the .hbs extension.\n *\n * @param templateName - Which template to use\n * @param targetDir - Destination directory (must not exist yet)\n * @param context - Variables for template substitution\n */\nexport async function scaffoldTemplate(\n\ttemplateName: TemplateName,\n\ttargetDir: string,\n\tcontext: TemplateContext,\n): Promise<void> {\n\tconst templateDir = getTemplatePath(templateName)\n\tconst vars: Record<string, string> = {\n\t\tprojectName: context.projectName,\n\t\tpackageManager: context.packageManager,\n\t\tkoraVersion: context.koraVersion,\n\t}\n\tawait copyDirectory(templateDir, targetDir, vars)\n}\n\nasync function copyDirectory(\n\tsrc: string,\n\tdest: string,\n\tvars: Record<string, string>,\n): Promise<void> {\n\tawait mkdir(dest, { recursive: true })\n\tconst entries = await readdir(src)\n\n\tfor (const entry of entries) {\n\t\tconst srcPath = join(src, entry)\n\t\tconst srcStat = await stat(srcPath)\n\n\t\tif (srcStat.isDirectory()) {\n\t\t\tawait copyDirectory(srcPath, join(dest, entry), vars)\n\t\t} else if (entry.endsWith('.hbs')) {\n\t\t\t// Template file: substitute variables and strip .hbs extension\n\t\t\tconst content = await readFile(srcPath, 'utf-8')\n\t\t\tconst outputName = entry.slice(0, -4) // Remove .hbs\n\t\t\tawait writeFile(join(dest, outputName), substituteVariables(content, vars), 'utf-8')\n\t\t} else {\n\t\t\t// Regular file: copy as-is\n\t\t\tawait copyFile(srcPath, join(dest, entry))\n\t\t}\n\t}\n}\n"],"mappings":"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","names":["import_citty","import_node_child_process","import_node_path","import_node_url","resolve","import_promises","import_node_path","import_meta"]}
package/dist/create.js ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ createCommand
4
+ } from "./chunk-REOTYAM6.js";
5
+ import "./chunk-ZVB4HAB3.js";
6
+
7
+ // src/create.ts
8
+ import { runMain } from "citty";
9
+ runMain(createCommand);
10
+ //# sourceMappingURL=create.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/create.ts"],"sourcesContent":["import { runMain } from 'citty'\nimport { createCommand } from './commands/create/create-command'\n\nrunMain(createCommand)\n"],"mappings":";;;;;;;AAAA,SAAS,eAAe;AAGxB,QAAQ,aAAa;","names":[]}
package/dist/index.cjs ADDED
@@ -0,0 +1,218 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ CliError: () => CliError,
24
+ DevServerError: () => DevServerError,
25
+ InvalidProjectError: () => InvalidProjectError,
26
+ PACKAGE_MANAGERS: () => PACKAGE_MANAGERS,
27
+ ProjectExistsError: () => ProjectExistsError,
28
+ SchemaNotFoundError: () => SchemaNotFoundError,
29
+ TEMPLATES: () => TEMPLATES,
30
+ TEMPLATE_INFO: () => TEMPLATE_INFO,
31
+ generateTypes: () => generateTypes
32
+ });
33
+ module.exports = __toCommonJS(index_exports);
34
+
35
+ // src/types.ts
36
+ var PACKAGE_MANAGERS = ["pnpm", "npm", "yarn", "bun"];
37
+ var TEMPLATES = ["react-basic", "react-sync"];
38
+ var TEMPLATE_INFO = [
39
+ {
40
+ name: "react-basic",
41
+ label: "React (basic)",
42
+ description: "Local-only React app with Kora \u2014 no sync server"
43
+ },
44
+ {
45
+ name: "react-sync",
46
+ label: "React (with sync)",
47
+ description: "React app with Kora sync server included"
48
+ }
49
+ ];
50
+
51
+ // src/errors.ts
52
+ var import_core = require("@korajs/core");
53
+ var CliError = class extends import_core.KoraError {
54
+ constructor(message, context) {
55
+ super(message, "CLI_ERROR", context);
56
+ this.name = "CliError";
57
+ }
58
+ };
59
+ var ProjectExistsError = class extends import_core.KoraError {
60
+ constructor(directory) {
61
+ super(
62
+ `Directory "${directory}" already exists. Choose a different name or remove the existing directory.`,
63
+ "PROJECT_EXISTS",
64
+ { directory }
65
+ );
66
+ this.directory = directory;
67
+ this.name = "ProjectExistsError";
68
+ }
69
+ directory;
70
+ };
71
+ var SchemaNotFoundError = class extends import_core.KoraError {
72
+ constructor(searchedPaths) {
73
+ super(
74
+ `Could not find a schema file. Searched: ${searchedPaths.join(", ")}. Create a schema file using defineSchema() from @korajs/core.`,
75
+ "SCHEMA_NOT_FOUND",
76
+ { searchedPaths }
77
+ );
78
+ this.searchedPaths = searchedPaths;
79
+ this.name = "SchemaNotFoundError";
80
+ }
81
+ searchedPaths;
82
+ };
83
+ var InvalidProjectError = class extends import_core.KoraError {
84
+ constructor(directory) {
85
+ super(
86
+ `"${directory}" is not a valid Kora project. No package.json with a kora dependency found. Run this command from inside a Kora project.`,
87
+ "INVALID_PROJECT",
88
+ { directory }
89
+ );
90
+ this.directory = directory;
91
+ this.name = "InvalidProjectError";
92
+ }
93
+ directory;
94
+ };
95
+ var DevServerError = class extends import_core.KoraError {
96
+ constructor(binary, searchPath) {
97
+ super(
98
+ `Could not find required binary "${binary}" at ${searchPath}. Install project dependencies and try again.`,
99
+ "DEV_SERVER_ERROR",
100
+ { binary, searchPath }
101
+ );
102
+ this.binary = binary;
103
+ this.searchPath = searchPath;
104
+ this.name = "DevServerError";
105
+ }
106
+ binary;
107
+ searchPath;
108
+ };
109
+
110
+ // src/commands/generate/type-generator.ts
111
+ function generateTypes(schema) {
112
+ const lines = [
113
+ "// Auto-generated by @korajs/cli \u2014 do not edit manually",
114
+ `// Generated from schema version ${String(schema.version)}`,
115
+ ""
116
+ ];
117
+ const collectionNames = Object.keys(schema.collections);
118
+ if (collectionNames.length === 0) {
119
+ return lines.join("\n");
120
+ }
121
+ for (const [name, collection] of Object.entries(schema.collections)) {
122
+ const pascal = toPascalCase(name);
123
+ const fields = collection.fields;
124
+ lines.push(`export interface ${pascal}Record {`);
125
+ lines.push(" readonly id: string");
126
+ for (const [fieldName, descriptor] of Object.entries(fields)) {
127
+ const tsType = fieldKindToTypeScript(descriptor);
128
+ const optional = !descriptor.required && !descriptor.auto ? "?" : "";
129
+ lines.push(` readonly ${fieldName}${optional}: ${tsType}`);
130
+ }
131
+ lines.push("}");
132
+ lines.push("");
133
+ lines.push(`export interface ${pascal}InsertInput {`);
134
+ for (const [fieldName, descriptor] of Object.entries(fields)) {
135
+ if (descriptor.auto) continue;
136
+ const tsType = fieldKindToTypeScript(descriptor);
137
+ const optional = !descriptor.required || descriptor.defaultValue !== void 0 ? "?" : "";
138
+ lines.push(` ${fieldName}${optional}: ${tsType}`);
139
+ }
140
+ lines.push("}");
141
+ lines.push("");
142
+ lines.push(`export interface ${pascal}UpdateInput {`);
143
+ for (const [fieldName, descriptor] of Object.entries(fields)) {
144
+ if (descriptor.auto) continue;
145
+ const tsType = fieldKindToTypeScript(descriptor);
146
+ lines.push(` ${fieldName}?: ${tsType}`);
147
+ }
148
+ lines.push("}");
149
+ lines.push("");
150
+ }
151
+ return lines.join("\n");
152
+ }
153
+ function fieldKindToTypeScript(descriptor) {
154
+ switch (descriptor.kind) {
155
+ case "string":
156
+ return "string";
157
+ case "number":
158
+ return "number";
159
+ case "boolean":
160
+ return "boolean";
161
+ case "timestamp":
162
+ return "number";
163
+ case "richtext":
164
+ return "string";
165
+ case "enum": {
166
+ if (descriptor.enumValues && descriptor.enumValues.length > 0) {
167
+ return descriptor.enumValues.map((v) => `'${v}'`).join(" | ");
168
+ }
169
+ return "string";
170
+ }
171
+ case "array": {
172
+ const itemType = itemKindToTypeScript(descriptor.itemKind);
173
+ return `Array<${itemType}>`;
174
+ }
175
+ default:
176
+ return "unknown";
177
+ }
178
+ }
179
+ function itemKindToTypeScript(kind) {
180
+ switch (kind) {
181
+ case "string":
182
+ return "string";
183
+ case "number":
184
+ return "number";
185
+ case "boolean":
186
+ return "boolean";
187
+ case "timestamp":
188
+ return "number";
189
+ case "richtext":
190
+ return "string";
191
+ case "enum":
192
+ return "string";
193
+ case "array":
194
+ return "unknown[]";
195
+ default:
196
+ return "unknown";
197
+ }
198
+ }
199
+ function toPascalCase(name) {
200
+ return name.split(/[_-]/).map((part) => {
201
+ if (part.length === 0) return "";
202
+ const first = part[0];
203
+ return first ? first.toUpperCase() + part.slice(1) : "";
204
+ }).join("");
205
+ }
206
+ // Annotate the CommonJS export names for ESM import in node:
207
+ 0 && (module.exports = {
208
+ CliError,
209
+ DevServerError,
210
+ InvalidProjectError,
211
+ PACKAGE_MANAGERS,
212
+ ProjectExistsError,
213
+ SchemaNotFoundError,
214
+ TEMPLATES,
215
+ TEMPLATE_INFO,
216
+ generateTypes
217
+ });
218
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/errors.ts","../src/commands/generate/type-generator.ts"],"sourcesContent":["// @korajs/cli — public API\n// Every export here is a public API commitment. Be explicit.\n\n// === Types ===\nexport type { PackageManager, TemplateName, TemplateContext, TemplateInfo } from './types'\nexport { PACKAGE_MANAGERS, TEMPLATES, TEMPLATE_INFO } from './types'\n\n// === Errors ===\nexport {\n\tCliError,\n\tDevServerError,\n\tInvalidProjectError,\n\tProjectExistsError,\n\tSchemaNotFoundError,\n} from './errors'\n\n// === Type Generation (programmatic use) ===\nexport { generateTypes } from './commands/generate/type-generator'\n","/** Supported package managers */\nexport const PACKAGE_MANAGERS = ['pnpm', 'npm', 'yarn', 'bun'] as const\nexport type PackageManager = (typeof PACKAGE_MANAGERS)[number]\n\n/** Available project templates */\nexport const TEMPLATES = ['react-basic', 'react-sync'] as const\nexport type TemplateName = (typeof TEMPLATES)[number]\n\n/** Metadata for a project template */\nexport interface TemplateInfo {\n\tname: TemplateName\n\tlabel: string\n\tdescription: string\n}\n\n/** Available templates with their descriptions */\nexport const TEMPLATE_INFO: readonly TemplateInfo[] = [\n\t{\n\t\tname: 'react-basic',\n\t\tlabel: 'React (basic)',\n\t\tdescription: 'Local-only React app with Kora — no sync server',\n\t},\n\t{\n\t\tname: 'react-sync',\n\t\tlabel: 'React (with sync)',\n\t\tdescription: 'React app with Kora sync server included',\n\t},\n] as const\n\n/** Variables available for template substitution */\nexport interface TemplateContext {\n\tprojectName: string\n\tpackageManager: PackageManager\n\tkoraVersion: string\n}\n","import { KoraError } from '@korajs/core'\n\n/**\n * Base error class for all CLI errors.\n */\nexport class CliError extends KoraError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'CLI_ERROR', context)\n\t\tthis.name = 'CliError'\n\t}\n}\n\n/**\n * Thrown when the target project directory already exists.\n */\nexport class ProjectExistsError extends KoraError {\n\tconstructor(public readonly directory: string) {\n\t\tsuper(\n\t\t\t`Directory \"${directory}\" already exists. Choose a different name or remove the existing directory.`,\n\t\t\t'PROJECT_EXISTS',\n\t\t\t{ directory },\n\t\t)\n\t\tthis.name = 'ProjectExistsError'\n\t}\n}\n\n/**\n * Thrown when a schema file cannot be found in the project.\n */\nexport class SchemaNotFoundError extends KoraError {\n\tconstructor(public readonly searchedPaths: string[]) {\n\t\tsuper(\n\t\t\t`Could not find a schema file. Searched: ${searchedPaths.join(', ')}. Create a schema file using defineSchema() from @korajs/core.`,\n\t\t\t'SCHEMA_NOT_FOUND',\n\t\t\t{ searchedPaths },\n\t\t)\n\t\tthis.name = 'SchemaNotFoundError'\n\t}\n}\n\n/**\n * Thrown when a command is run outside a valid Kora project.\n */\nexport class InvalidProjectError extends KoraError {\n\tconstructor(public readonly directory: string) {\n\t\tsuper(\n\t\t\t`\"${directory}\" is not a valid Kora project. No package.json with a kora dependency found. Run this command from inside a Kora project.`,\n\t\t\t'INVALID_PROJECT',\n\t\t\t{ directory },\n\t\t)\n\t\tthis.name = 'InvalidProjectError'\n\t}\n}\n\n/**\n * Thrown when a required local dev server binary cannot be found.\n */\nexport class DevServerError extends KoraError {\n\tconstructor(\n\t\tpublic readonly binary: string,\n\t\tpublic readonly searchPath: string,\n\t) {\n\t\tsuper(\n\t\t\t`Could not find required binary \"${binary}\" at ${searchPath}. Install project dependencies and try again.`,\n\t\t\t'DEV_SERVER_ERROR',\n\t\t\t{ binary, searchPath },\n\t\t)\n\t\tthis.name = 'DevServerError'\n\t}\n}\n","import type { FieldDescriptor, FieldKind, SchemaDefinition } from '@korajs/core'\n\n/**\n * Generates TypeScript interfaces from a SchemaDefinition.\n * For each collection, produces three interfaces:\n * - {Name}Record: full record type (all fields + id)\n * - {Name}InsertInput: insert input (omit auto fields, optional for fields with defaults)\n * - {Name}UpdateInput: update input (all non-auto fields optional)\n *\n * @param schema - A validated SchemaDefinition from defineSchema()\n * @returns A complete TypeScript file as a string\n */\nexport function generateTypes(schema: SchemaDefinition): string {\n\tconst lines: string[] = [\n\t\t'// Auto-generated by @korajs/cli — do not edit manually',\n\t\t`// Generated from schema version ${String(schema.version)}`,\n\t\t'',\n\t]\n\n\tconst collectionNames = Object.keys(schema.collections)\n\tif (collectionNames.length === 0) {\n\t\treturn lines.join('\\n')\n\t}\n\n\tfor (const [name, collection] of Object.entries(schema.collections)) {\n\t\tconst pascal = toPascalCase(name)\n\t\tconst fields = collection.fields\n\n\t\t// Record type: all fields + id\n\t\tlines.push(`export interface ${pascal}Record {`)\n\t\tlines.push('\\treadonly id: string')\n\t\tfor (const [fieldName, descriptor] of Object.entries(fields)) {\n\t\t\tconst tsType = fieldKindToTypeScript(descriptor)\n\t\t\tconst optional = !descriptor.required && !descriptor.auto ? '?' : ''\n\t\t\tlines.push(`\\treadonly ${fieldName}${optional}: ${tsType}`)\n\t\t}\n\t\tlines.push('}')\n\t\tlines.push('')\n\n\t\t// Insert input: omit auto fields, optional for fields with defaults\n\t\tlines.push(`export interface ${pascal}InsertInput {`)\n\t\tfor (const [fieldName, descriptor] of Object.entries(fields)) {\n\t\t\tif (descriptor.auto) continue\n\t\t\tconst tsType = fieldKindToTypeScript(descriptor)\n\t\t\tconst optional = !descriptor.required || descriptor.defaultValue !== undefined ? '?' : ''\n\t\t\tlines.push(`\\t${fieldName}${optional}: ${tsType}`)\n\t\t}\n\t\tlines.push('}')\n\t\tlines.push('')\n\n\t\t// Update input: all non-auto fields optional\n\t\tlines.push(`export interface ${pascal}UpdateInput {`)\n\t\tfor (const [fieldName, descriptor] of Object.entries(fields)) {\n\t\t\tif (descriptor.auto) continue\n\t\t\tconst tsType = fieldKindToTypeScript(descriptor)\n\t\t\tlines.push(`\\t${fieldName}?: ${tsType}`)\n\t\t}\n\t\tlines.push('}')\n\t\tlines.push('')\n\t}\n\n\treturn lines.join('\\n')\n}\n\n/** Maps a FieldDescriptor to its TypeScript type string */\nfunction fieldKindToTypeScript(descriptor: FieldDescriptor): string {\n\tswitch (descriptor.kind) {\n\t\tcase 'string':\n\t\t\treturn 'string'\n\t\tcase 'number':\n\t\t\treturn 'number'\n\t\tcase 'boolean':\n\t\t\treturn 'boolean'\n\t\tcase 'timestamp':\n\t\t\treturn 'number'\n\t\tcase 'richtext':\n\t\t\treturn 'string'\n\t\tcase 'enum': {\n\t\t\tif (descriptor.enumValues && descriptor.enumValues.length > 0) {\n\t\t\t\treturn descriptor.enumValues.map((v) => `'${v}'`).join(' | ')\n\t\t\t}\n\t\t\treturn 'string'\n\t\t}\n\t\tcase 'array': {\n\t\t\tconst itemType = itemKindToTypeScript(descriptor.itemKind)\n\t\t\treturn `Array<${itemType}>`\n\t\t}\n\t\tdefault:\n\t\t\treturn 'unknown'\n\t}\n}\n\n/** Maps an item FieldKind to its TypeScript type string */\nfunction itemKindToTypeScript(kind: FieldKind | null): string {\n\tswitch (kind) {\n\t\tcase 'string':\n\t\t\treturn 'string'\n\t\tcase 'number':\n\t\t\treturn 'number'\n\t\tcase 'boolean':\n\t\t\treturn 'boolean'\n\t\tcase 'timestamp':\n\t\t\treturn 'number'\n\t\tcase 'richtext':\n\t\t\treturn 'string'\n\t\tcase 'enum':\n\t\t\treturn 'string'\n\t\tcase 'array':\n\t\t\treturn 'unknown[]'\n\t\tdefault:\n\t\t\treturn 'unknown'\n\t}\n}\n\n/** Converts a snake_case or kebab-case name to PascalCase */\nfunction toPascalCase(name: string): string {\n\treturn name\n\t\t.split(/[_-]/)\n\t\t.map((part) => {\n\t\t\tif (part.length === 0) return ''\n\t\t\tconst first = part[0]\n\t\t\treturn first ? first.toUpperCase() + part.slice(1) : ''\n\t\t})\n\t\t.join('')\n}\n"],"mappings":"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","names":[]}