@voltx/cli 0.1.1 → 0.3.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 (47) hide show
  1. package/README.md +65 -0
  2. package/dist/build.d.mts +19 -0
  3. package/dist/build.d.ts +19 -0
  4. package/dist/build.js +145 -0
  5. package/dist/build.mjs +7 -0
  6. package/dist/chunk-AONHLE42.mjs +141 -0
  7. package/dist/chunk-BIE3F5AW.mjs +261 -0
  8. package/dist/chunk-BLBAHJXR.mjs +239 -0
  9. package/dist/chunk-H2SJO7GX.mjs +102 -0
  10. package/dist/chunk-IGBR4TFT.mjs +351 -0
  11. package/dist/chunk-IV352HZA.mjs +107 -0
  12. package/dist/chunk-KFHPTRKZ.mjs +405 -0
  13. package/dist/chunk-L3247M3A.mjs +81 -0
  14. package/dist/chunk-RN7BUALR.mjs +120 -0
  15. package/dist/chunk-SGL7RBD5.mjs +355 -0
  16. package/dist/chunk-TUZ3MHD4.mjs +355 -0
  17. package/dist/chunk-Y6FXYEAI.mjs +10 -0
  18. package/dist/chunk-YID3JCVU.mjs +131 -0
  19. package/dist/chunk-ZA7EJWJI.mjs +221 -0
  20. package/dist/chunk-ZB2F3WTS.mjs +121 -0
  21. package/dist/chunk-ZLIPYI22.mjs +350 -0
  22. package/dist/cli.js +971 -53
  23. package/dist/cli.mjs +123 -23
  24. package/dist/create.d.mts +1 -0
  25. package/dist/create.d.ts +1 -0
  26. package/dist/create.js +334 -30
  27. package/dist/create.mjs +3 -2
  28. package/dist/dev.d.mts +19 -0
  29. package/dist/dev.d.ts +19 -0
  30. package/dist/dev.js +144 -0
  31. package/dist/dev.mjs +7 -0
  32. package/dist/generate.d.mts +13 -0
  33. package/dist/generate.d.ts +13 -0
  34. package/dist/generate.js +165 -0
  35. package/dist/generate.mjs +7 -0
  36. package/dist/index.d.mts +5 -1
  37. package/dist/index.d.ts +5 -1
  38. package/dist/index.js +796 -33
  39. package/dist/index.mjs +21 -4
  40. package/dist/start.d.mts +16 -0
  41. package/dist/start.d.ts +16 -0
  42. package/dist/start.js +105 -0
  43. package/dist/start.mjs +7 -0
  44. package/dist/welcome.js +1 -1
  45. package/dist/welcome.mjs +2 -1
  46. package/package.json +24 -22
  47. package/LICENSE +0 -21
package/dist/cli.mjs CHANGED
@@ -3,53 +3,153 @@
3
3
  // src/cli.ts
4
4
  var args = process.argv.slice(2);
5
5
  var command = args[0];
6
+ function parseFlag(flag) {
7
+ const idx = args.indexOf(flag);
8
+ return idx !== -1 && args[idx + 1] ? args[idx + 1] : void 0;
9
+ }
10
+ function hasFlag(flag) {
11
+ return args.includes(flag);
12
+ }
13
+ function parsePort() {
14
+ const portStr = parseFlag("--port") ?? parseFlag("-p");
15
+ return portStr ? Number(portStr) : void 0;
16
+ }
6
17
  async function main() {
7
18
  switch (command) {
19
+ // ─── voltx create ──────────────────────────────────────────────────
8
20
  case "create": {
9
21
  const projectName = args[1];
10
- if (!projectName) {
11
- console.error("[voltx] Usage: voltx create <project-name> [--template chatbot|rag-app|agent-app]");
22
+ if (!projectName || projectName.startsWith("-")) {
23
+ console.error("[voltx] Usage: voltx create <project-name> [--template chatbot|rag-app|agent-app] [--auth better-auth|jwt|none]");
12
24
  process.exit(1);
13
25
  }
14
- const templateFlag = args.indexOf("--template");
15
- const template = templateFlag !== -1 ? args[templateFlag + 1] : "blank";
26
+ const template = parseFlag("--template");
27
+ const auth = parseFlag("--auth");
16
28
  const { createProject } = await import("./create.mjs");
17
- await createProject({ name: projectName, template });
29
+ await createProject({ name: projectName, template: template ?? "blank", auth: auth ?? "none" });
18
30
  break;
19
31
  }
32
+ // ─── voltx dev ─────────────────────────────────────────────────────
20
33
  case "dev": {
21
- console.log("[voltx] Starting dev server...");
22
- console.log("[voltx] Dev server not yet implemented \u2014 coming in Phase 2");
34
+ const { runDev } = await import("./dev.mjs");
35
+ await runDev({
36
+ port: parsePort(),
37
+ entry: parseFlag("--entry"),
38
+ clearScreen: !hasFlag("--no-clear")
39
+ });
23
40
  break;
24
41
  }
42
+ // ─── voltx build ───────────────────────────────────────────────────
25
43
  case "build": {
26
- console.log("[voltx] Building for production...");
27
- console.log("[voltx] Build not yet implemented \u2014 coming in Phase 2");
44
+ const { runBuild } = await import("./build.mjs");
45
+ await runBuild({
46
+ entry: parseFlag("--entry"),
47
+ outDir: parseFlag("--out-dir") ?? parseFlag("-o"),
48
+ minify: !hasFlag("--no-minify"),
49
+ sourcemap: hasFlag("--sourcemap")
50
+ });
28
51
  break;
29
52
  }
53
+ // ─── voltx start ──────────────────────────────────────────────────
30
54
  case "start": {
31
- console.log("[voltx] Starting production server...");
32
- console.log("[voltx] Start not yet implemented \u2014 coming in Phase 2");
55
+ const { runStart } = await import("./start.mjs");
56
+ await runStart({
57
+ port: parsePort(),
58
+ outDir: parseFlag("--out-dir") ?? parseFlag("-o"),
59
+ entry: parseFlag("--entry")
60
+ });
61
+ break;
62
+ }
63
+ // ─── voltx generate ───────────────────────────────────────────────
64
+ case "generate":
65
+ case "g": {
66
+ const type = args[1];
67
+ const name = args[2];
68
+ if (!type || !name) {
69
+ console.error("[voltx] Usage: voltx generate <type> <name>");
70
+ console.error("");
71
+ console.error(" Types:");
72
+ console.error(" route <path> Generate a new API route (e.g., api/users)");
73
+ console.error(" agent <name> Generate a new agent (e.g., assistant)");
74
+ console.error(" tool <name> Generate a new tool (e.g., search)");
75
+ console.error(" job <name> Generate a new background job (e.g., cleanup)");
76
+ console.error("");
77
+ console.error(" Options:");
78
+ console.error(" --method <GET|POST|PUT|DELETE> HTTP method for routes (default: POST)");
79
+ process.exit(1);
80
+ }
81
+ const { runGenerate } = await import("./generate.mjs");
82
+ await runGenerate({
83
+ type,
84
+ name,
85
+ method: parseFlag("--method")
86
+ });
33
87
  break;
34
88
  }
89
+ // ─── voltx --version ──────────────────────────────────────────────
90
+ case "--version":
91
+ case "-v": {
92
+ const { CLI_VERSION } = await import("./index.mjs");
93
+ console.log(`voltx v${CLI_VERSION}`);
94
+ break;
95
+ }
96
+ // ─── voltx help / default ─────────────────────────────────────────
97
+ case "help":
98
+ case "--help":
99
+ case "-h":
35
100
  default: {
36
- console.log(`
101
+ printHelp();
102
+ }
103
+ }
104
+ }
105
+ function printHelp() {
106
+ console.log(`
37
107
  \u26A1 voltx \u2014 The AI-first full-stack framework
38
108
 
39
109
  Usage:
40
- voltx create <name> Create a new VoltX project
41
- voltx dev Start the development server
42
- voltx build Build for production
43
- voltx start Start the production server
110
+ voltx <command> [options]
44
111
 
45
- Options:
46
- --template <type> Template: chatbot, rag-app, agent-app, blank (default)
112
+ Commands:
113
+ create <name> Create a new VoltX project
114
+ dev Start the development server (hot reload)
115
+ build Build for production
116
+ start Start the production server
117
+ generate <type> <name> Generate routes, agents, tools, or jobs
47
118
 
48
- Example:
49
- voltx create my-app --template chatbot
50
- `);
51
- }
52
- }
119
+ Create Options:
120
+ --template <type> Template: chatbot, rag-app, agent-app, blank (default)
121
+ --auth <provider> Auth: better-auth, jwt, none (default)
122
+
123
+ Dev Options:
124
+ --port, -p <number> Port override
125
+ --entry <file> Custom entry file (default: src/index.ts)
126
+ --no-clear Don't clear screen on restart
127
+
128
+ Build Options:
129
+ --entry <file> Custom entry file
130
+ --out-dir, -o <dir> Output directory (default: dist)
131
+ --no-minify Skip minification
132
+ --sourcemap Generate source maps
133
+
134
+ Start Options:
135
+ --port, -p <number> Port override
136
+ --out-dir, -o <dir> Build output directory (default: dist)
137
+ --entry <file> Entry file within output dir
138
+
139
+ Generate Types:
140
+ route <path> API route (e.g., voltx generate route api/users)
141
+ agent <name> Agent (e.g., voltx generate agent assistant)
142
+ tool <name> Tool (e.g., voltx generate tool search)
143
+ job <name> Background job (e.g., voltx generate job cleanup)
144
+
145
+ Examples:
146
+ voltx create my-app --template chatbot --auth jwt
147
+ voltx dev --port 4000
148
+ voltx build --sourcemap
149
+ voltx start
150
+ voltx generate route api/users --method GET
151
+ voltx generate agent assistant
152
+ `);
53
153
  }
54
154
  main().catch((err) => {
55
155
  console.error("[voltx] Fatal error:", err);
package/dist/create.d.mts CHANGED
@@ -2,6 +2,7 @@
2
2
  interface CreateProjectOptions {
3
3
  name: string;
4
4
  template?: "chatbot" | "rag-app" | "agent-app" | "blank";
5
+ auth?: "better-auth" | "jwt" | "none";
5
6
  }
6
7
  declare function createProject(options: CreateProjectOptions): Promise<void>;
7
8
 
package/dist/create.d.ts CHANGED
@@ -2,6 +2,7 @@
2
2
  interface CreateProjectOptions {
3
3
  name: string;
4
4
  template?: "chatbot" | "rag-app" | "agent-app" | "blank";
5
+ auth?: "better-auth" | "jwt" | "none";
5
6
  }
6
7
  declare function createProject(options: CreateProjectOptions): Promise<void>;
7
8
 
package/dist/create.js CHANGED
@@ -118,7 +118,7 @@ function printWelcomeBanner(projectName) {
118
118
  console.log(` ${rgb(100, 180, 255, "Next steps:")}`);
119
119
  console.log(` ${rgb(200, 200, 220, ` cd ${projectName}`)}`);
120
120
  console.log(` ${rgb(200, 200, 220, " pnpm install")}`);
121
- console.log(` ${rgb(200, 200, 220, " pnpm dev")}`);
121
+ console.log(` ${rgb(200, 200, 220, " pnpm dev # or: npx voltx dev")}`);
122
122
  console.log("");
123
123
  console.log(dimRule());
124
124
  console.log("");
@@ -143,7 +143,7 @@ function printWelcomeBanner(projectName) {
143
143
 
144
144
  // src/create.ts
145
145
  async function createProject(options) {
146
- const { name, template = "blank" } = options;
146
+ const { name, template = "blank", auth = "none" } = options;
147
147
  const targetDir = path.resolve(process.cwd(), name);
148
148
  if (fs.existsSync(targetDir)) {
149
149
  console.error(`[voltx] Directory "${name}" already exists.`);
@@ -151,26 +151,29 @@ async function createProject(options) {
151
151
  }
152
152
  fs.mkdirSync(targetDir, { recursive: true });
153
153
  const templateDeps = {
154
- blank: { "@voltx/core": "^0.1.0" },
154
+ blank: {
155
+ "@voltx/core": "^0.3.0",
156
+ "@voltx/server": "^0.3.0"
157
+ },
155
158
  chatbot: {
156
- "@voltx/core": "^0.1.0",
157
- "@voltx/agents": "^0.1.0",
158
- "@voltx/memory": "^0.1.0",
159
- "@voltx/ui": "^0.1.0"
159
+ "@voltx/core": "^0.3.0",
160
+ "@voltx/ai": "^0.3.0",
161
+ "@voltx/server": "^0.3.0",
162
+ "@voltx/memory": "^0.3.0"
160
163
  },
161
164
  "rag-app": {
162
- "@voltx/core": "^0.1.0",
163
- "@voltx/rag": "^0.1.0",
164
- "@voltx/db": "^0.1.0",
165
- "@voltx/ui": "^0.1.0"
165
+ "@voltx/core": "^0.3.0",
166
+ "@voltx/ai": "^0.3.0",
167
+ "@voltx/server": "^0.3.0",
168
+ "@voltx/rag": "^0.3.0",
169
+ "@voltx/db": "^0.3.0"
166
170
  },
167
171
  "agent-app": {
168
- "@voltx/core": "^0.1.0",
169
- "@voltx/agents": "^0.1.0",
170
- "@voltx/memory": "^0.1.0",
171
- "@voltx/rag": "^0.1.0",
172
- "@voltx/db": "^0.1.0",
173
- "@voltx/ui": "^0.1.0"
172
+ "@voltx/core": "^0.3.0",
173
+ "@voltx/ai": "^0.3.0",
174
+ "@voltx/server": "^0.3.0",
175
+ "@voltx/agents": "^0.3.0",
176
+ "@voltx/memory": "^0.3.0"
174
177
  }
175
178
  };
176
179
  const packageJson = {
@@ -182,36 +185,335 @@ async function createProject(options) {
182
185
  build: "voltx build",
183
186
  start: "voltx start"
184
187
  },
185
- dependencies: templateDeps[template] ?? templateDeps["blank"]
188
+ dependencies: {
189
+ ...templateDeps[template] ?? templateDeps["blank"],
190
+ "@voltx/cli": "^0.3.0",
191
+ ...auth === "better-auth" ? { "@voltx/auth": "^0.3.0", "better-auth": "^1.5.0" } : {},
192
+ ...auth === "jwt" ? { "@voltx/auth": "^0.3.0", "jose": "^6.0.0" } : {}
193
+ },
194
+ devDependencies: {
195
+ typescript: "^5.7.0",
196
+ tsx: "^4.21.0",
197
+ tsup: "^8.0.0",
198
+ "@types/node": "^22.0.0"
199
+ }
186
200
  };
187
201
  fs.writeFileSync(
188
202
  path.join(targetDir, "package.json"),
189
203
  JSON.stringify(packageJson, null, 2)
190
204
  );
191
- const configContent = `import { defineConfig } from "@voltx/core";
205
+ const hasDb = template === "rag-app" || template === "agent-app" || auth === "better-auth";
206
+ const provider = template === "rag-app" ? "openai" : "cerebras";
207
+ const model = template === "rag-app" ? "gpt-4o" : "llama-4-scout-17b-16e";
208
+ let configContent = `import { defineConfig } from "@voltx/core";
192
209
 
193
210
  export default defineConfig({
194
211
  name: "${name}",
195
212
  port: 3000,
196
213
  ai: {
197
- provider: "openai",
198
- model: "gpt-4o",
214
+ provider: "${provider}",
215
+ model: "${model}",
216
+ },`;
217
+ if (hasDb) {
218
+ configContent += `
219
+ db: {
220
+ url: process.env.DATABASE_URL,
221
+ },`;
222
+ }
223
+ if (auth !== "none") {
224
+ configContent += `
225
+ auth: {
226
+ provider: "${auth}",
227
+ },`;
228
+ }
229
+ configContent += `
230
+ server: {
231
+ routesDir: "src/routes",
232
+ staticDir: "public",
233
+ cors: true,
199
234
  },
200
235
  });
201
236
  `;
202
237
  fs.writeFileSync(path.join(targetDir, "voltx.config.ts"), configContent);
203
- fs.mkdirSync(path.join(targetDir, "src", "routes"), { recursive: true });
204
- fs.mkdirSync(path.join(targetDir, "src", "agents"), { recursive: true });
205
- const indexContent = `import { createApp } from "@voltx/core";
238
+ fs.mkdirSync(path.join(targetDir, "src", "routes", "api"), { recursive: true });
239
+ fs.mkdirSync(path.join(targetDir, "public"), { recursive: true });
240
+ fs.writeFileSync(
241
+ path.join(targetDir, "src", "index.ts"),
242
+ `import { createApp } from "@voltx/core";
206
243
  import config from "../voltx.config";
207
244
 
208
245
  const app = createApp(config);
209
246
  app.start();
210
- `;
211
- fs.writeFileSync(path.join(targetDir, "src", "index.ts"), indexContent);
247
+ `
248
+ );
249
+ fs.writeFileSync(
250
+ path.join(targetDir, "src", "routes", "index.ts"),
251
+ `// GET / \u2014 Health check
252
+ import type { Context } from "@voltx/server";
253
+
254
+ export function GET(c: Context) {
255
+ return c.json({ name: "${name}", status: "ok" });
256
+ }
257
+ `
258
+ );
259
+ if (template === "chatbot" || template === "agent-app") {
260
+ fs.writeFileSync(
261
+ path.join(targetDir, "src", "routes", "api", "chat.ts"),
262
+ `// POST /api/chat \u2014 Streaming chat with conversation memory
263
+ import type { Context } from "@voltx/server";
264
+ import { streamText } from "@voltx/ai";
265
+ import { createMemory } from "@voltx/memory";
266
+
267
+ // In-memory for dev; swap to createMemory("postgres", { url }) for production
268
+ const memory = createMemory({ maxMessages: 50 });
269
+
270
+ export async function POST(c: Context) {
271
+ const { messages, conversationId = "default" } = await c.req.json();
272
+
273
+ // Store the latest user message
274
+ const lastMessage = messages[messages.length - 1];
275
+ if (lastMessage?.role === "user") {
276
+ await memory.add(conversationId, { role: "user", content: lastMessage.content });
277
+ }
278
+
279
+ // Get conversation history from memory
280
+ const history = await memory.get(conversationId);
281
+
282
+ const result = await streamText({
283
+ model: "${provider}:${model}",
284
+ system: "You are a helpful AI assistant.",
285
+ messages: history.map((m) => ({ role: m.role, content: m.content })),
286
+ });
287
+
288
+ // Store assistant response after stream completes
289
+ result.text.then(async (text) => {
290
+ await memory.add(conversationId, { role: "assistant", content: text });
291
+ });
292
+
293
+ return result.toSSEResponse();
294
+ }
295
+ `
296
+ );
297
+ }
298
+ if (template === "agent-app") {
299
+ fs.mkdirSync(path.join(targetDir, "src", "agents"), { recursive: true });
300
+ fs.mkdirSync(path.join(targetDir, "src", "tools"), { recursive: true });
301
+ fs.writeFileSync(
302
+ path.join(targetDir, "src", "agents", "assistant.ts"),
303
+ `import { createAgent } from "@voltx/agents";
304
+ import { searchTool } from "../tools/search";
305
+
306
+ export const assistant = createAgent({
307
+ name: "assistant",
308
+ model: "${provider}:${model}",
309
+ instructions: "You are a helpful AI assistant. Use your tools when needed.",
310
+ tools: [searchTool],
311
+ maxIterations: 5,
312
+ });
313
+ `
314
+ );
315
+ fs.writeFileSync(
316
+ path.join(targetDir, "src", "tools", "search.ts"),
317
+ `import type { Tool } from "@voltx/agents";
318
+
319
+ export const searchTool: Tool = {
320
+ name: "search",
321
+ description: "Search for information on a topic.",
322
+ parameters: {
323
+ type: "object",
324
+ properties: { query: { type: "string", description: "The search query" } },
325
+ required: ["query"],
326
+ },
327
+ async execute(args: { query: string }) {
328
+ return \`Search results for "\${args.query}": Placeholder \u2014 connect a real search API.\`;
329
+ },
330
+ };
331
+ `
332
+ );
333
+ fs.writeFileSync(
334
+ path.join(targetDir, "src", "routes", "api", "agent.ts"),
335
+ `import type { Context } from "@voltx/server";
336
+ import { assistant } from "../../agents/assistant";
337
+
338
+ export async function POST(c: Context) {
339
+ const { input } = await c.req.json();
340
+ if (!input) return c.json({ error: "Missing 'input' field" }, 400);
341
+ const result = await assistant.run(input);
342
+ return c.json({ content: result.content, steps: result.steps });
343
+ }
344
+ `
345
+ );
346
+ }
347
+ if (template === "rag-app") {
348
+ const embedModel = "openai:text-embedding-3-small";
349
+ fs.mkdirSync(path.join(targetDir, "src", "routes", "api", "rag"), { recursive: true });
350
+ fs.writeFileSync(
351
+ path.join(targetDir, "src", "routes", "api", "rag", "query.ts"),
352
+ `// POST /api/rag/query \u2014 Query documents with RAG
353
+ import type { Context } from "@voltx/server";
354
+ import { streamText } from "@voltx/ai";
355
+ import { createRAGPipeline, createEmbedder } from "@voltx/rag";
356
+ import { createVectorStore } from "@voltx/db";
357
+
358
+ const vectorStore = createVectorStore(); // swap to "pinecone" or "pgvector" for production
359
+ const embedder = createEmbedder({ model: "${embedModel}" });
360
+ const rag = createRAGPipeline({ embedder, vectorStore });
361
+
362
+ export async function POST(c: Context) {
363
+ const { question } = await c.req.json();
364
+
365
+ const context = await rag.getContext(question, { topK: 5 });
366
+
367
+ const result = await streamText({
368
+ model: "${provider}:${model}",
369
+ system: \`Answer the user's question based on the following context. If the context doesn't contain relevant information, say so.\\n\\nContext:\\n\${context}\`,
370
+ messages: [{ role: "user", content: question }],
371
+ });
372
+
373
+ return result.toSSEResponse();
374
+ }
375
+ `
376
+ );
377
+ fs.writeFileSync(
378
+ path.join(targetDir, "src", "routes", "api", "rag", "ingest.ts"),
379
+ `// POST /api/rag/ingest \u2014 Ingest documents into the vector store
380
+ import type { Context } from "@voltx/server";
381
+ import { createRAGPipeline, createEmbedder } from "@voltx/rag";
382
+ import { createVectorStore } from "@voltx/db";
383
+
384
+ const vectorStore = createVectorStore();
385
+ const embedder = createEmbedder({ model: "${embedModel}" });
386
+ const rag = createRAGPipeline({ embedder, vectorStore });
387
+
388
+ export async function POST(c: Context) {
389
+ const { text, idPrefix } = await c.req.json();
390
+
391
+ if (!text || typeof text !== "string") {
392
+ return c.json({ error: "Missing 'text' field" }, 400);
393
+ }
394
+
395
+ const result = await rag.ingest(text, idPrefix ?? "doc");
396
+ return c.json({ status: "ok", chunks: result.chunks, ids: result.ids });
397
+ }
398
+ `
399
+ );
400
+ }
401
+ if (auth === "better-auth") {
402
+ fs.mkdirSync(path.join(targetDir, "src", "routes", "api", "auth"), { recursive: true });
403
+ fs.writeFileSync(
404
+ path.join(targetDir, "src", "routes", "api", "auth", "[...path].ts"),
405
+ `// ALL /api/auth/* \u2014 Better Auth handler
406
+ import type { Context } from "@voltx/server";
407
+ import { auth } from "../../../lib/auth";
408
+ import { createAuthHandler } from "@voltx/auth";
409
+
410
+ const handler = createAuthHandler(auth);
411
+
412
+ export const GET = (c: Context) => handler(c);
413
+ export const POST = (c: Context) => handler(c);
414
+ `
415
+ );
416
+ fs.mkdirSync(path.join(targetDir, "src", "lib"), { recursive: true });
417
+ fs.writeFileSync(
418
+ path.join(targetDir, "src", "lib", "auth.ts"),
419
+ `// Auth configuration \u2014 Better Auth with DB-backed sessions
420
+ import { createAuth, createAuthMiddleware } from "@voltx/auth";
421
+
422
+ export const auth = createAuth("better-auth", {
423
+ database: process.env.DATABASE_URL!,
424
+ emailAndPassword: true,
425
+ });
426
+
427
+ export const authMiddleware = createAuthMiddleware({
428
+ provider: auth,
429
+ publicPaths: ["/api/auth", "/api/health", "/"],
430
+ });
431
+ `
432
+ );
433
+ } else if (auth === "jwt") {
434
+ fs.mkdirSync(path.join(targetDir, "src", "lib"), { recursive: true });
435
+ fs.writeFileSync(
436
+ path.join(targetDir, "src", "lib", "auth.ts"),
437
+ `// Auth configuration \u2014 JWT (stateless)
438
+ import { createAuth, createAuthMiddleware } from "@voltx/auth";
439
+
440
+ export const jwt = createAuth("jwt", {
441
+ secret: process.env.JWT_SECRET!,
442
+ expiresIn: "7d",
443
+ });
444
+
445
+ export const authMiddleware = createAuthMiddleware({
446
+ provider: jwt,
447
+ publicPaths: ["/api/auth", "/api/health", "/"],
448
+ });
449
+ `
450
+ );
451
+ fs.writeFileSync(
452
+ path.join(targetDir, "src", "routes", "api", "auth.ts"),
453
+ `// POST /api/auth/login \u2014 Example JWT login route
454
+ import type { Context } from "@voltx/server";
455
+ import { jwt } from "../../lib/auth";
456
+
457
+ export async function POST(c: Context) {
458
+ const { email, password } = await c.req.json();
459
+
460
+ if (!email || !password) {
461
+ return c.json({ error: "Email and password are required" }, 400);
462
+ }
463
+
464
+ const token = await jwt.sign({ sub: email, email });
465
+ return c.json({ token });
466
+ }
467
+ `
468
+ );
469
+ }
470
+ let envContent = "";
471
+ if (template === "rag-app") {
472
+ envContent += "# \u2500\u2500\u2500 LLM Provider \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nOPENAI_API_KEY=sk-...\n\n";
473
+ envContent += "# \u2500\u2500\u2500 Database (Neon Postgres) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nDATABASE_URL=postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/dbname?sslmode=require\n\n";
474
+ envContent += "# \u2500\u2500\u2500 Vector Database (Pinecone) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nPINECONE_API_KEY=pc-...\nPINECONE_INDEX=voltx-embeddings\n\n";
475
+ } else if (template === "chatbot" || template === "agent-app") {
476
+ envContent += "# \u2500\u2500\u2500 LLM Provider \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nCEREBRAS_API_KEY=csk-...\n\n";
477
+ if (template === "agent-app") {
478
+ envContent += "# \u2500\u2500\u2500 Database (Neon Postgres \u2014 optional) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nDATABASE_URL=\n\n";
479
+ }
480
+ } else {
481
+ envContent += "# \u2500\u2500\u2500 LLM Provider (add your key) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n# OPENAI_API_KEY=sk-...\n# CEREBRAS_API_KEY=csk-...\n\n";
482
+ }
483
+ if (auth === "better-auth") {
484
+ envContent += "# \u2500\u2500\u2500 Auth (Better Auth) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nBETTER_AUTH_SECRET=your-secret-key-min-32-chars-here\nBETTER_AUTH_URL=http://localhost:3000\n";
485
+ if (template !== "rag-app" && template !== "agent-app") {
486
+ envContent += "DATABASE_URL=postgresql://user:pass@ep-xxx.us-east-2.aws.neon.tech/dbname?sslmode=require\n";
487
+ }
488
+ envContent += "# GITHUB_CLIENT_ID=\n# GITHUB_CLIENT_SECRET=\n\n";
489
+ } else if (auth === "jwt") {
490
+ envContent += "# \u2500\u2500\u2500 Auth (JWT) \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nJWT_SECRET=your-jwt-secret-key\n\n";
491
+ }
492
+ envContent += "# \u2500\u2500\u2500 App \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nPORT=3000\nNODE_ENV=development\n";
493
+ fs.writeFileSync(path.join(targetDir, ".env.example"), envContent);
494
+ fs.writeFileSync(
495
+ path.join(targetDir, ".gitignore"),
496
+ "node_modules\ndist\n.env\n"
497
+ );
212
498
  fs.writeFileSync(
213
- path.join(targetDir, ".env.example"),
214
- "OPENAI_API_KEY=your-key-here\nDATABASE_URL=\n"
499
+ path.join(targetDir, "tsconfig.json"),
500
+ JSON.stringify(
501
+ {
502
+ compilerOptions: {
503
+ target: "ES2022",
504
+ module: "ESNext",
505
+ moduleResolution: "bundler",
506
+ strict: true,
507
+ esModuleInterop: true,
508
+ skipLibCheck: true,
509
+ outDir: "dist",
510
+ rootDir: "src"
511
+ },
512
+ include: ["src"]
513
+ },
514
+ null,
515
+ 2
516
+ )
215
517
  );
216
518
  printWelcomeBanner(name);
217
519
  }
@@ -219,12 +521,14 @@ var isDirectRun = typeof require !== "undefined" && require.main === module && p
219
521
  if (isDirectRun) {
220
522
  const projectName = process.argv[2];
221
523
  if (!projectName) {
222
- console.log("Usage: create-voltx-app <project-name> [--template chatbot]");
524
+ console.log("Usage: create-voltx-app <project-name> [--template chatbot] [--auth jwt]");
223
525
  process.exit(1);
224
526
  }
225
527
  const templateFlag = process.argv.indexOf("--template");
226
528
  const template = templateFlag !== -1 ? process.argv[templateFlag + 1] : "blank";
227
- createProject({ name: projectName, template }).catch((err) => {
529
+ const authFlag = process.argv.indexOf("--auth");
530
+ const auth = authFlag !== -1 ? process.argv[authFlag + 1] : "none";
531
+ createProject({ name: projectName, template, auth }).catch((err) => {
228
532
  console.error("[voltx] Error:", err);
229
533
  process.exit(1);
230
534
  });
package/dist/create.mjs CHANGED
@@ -1,8 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  createProject
4
- } from "./chunk-H4YMCUJC.mjs";
5
- import "./chunk-RH5Q7I3S.mjs";
4
+ } from "./chunk-KFHPTRKZ.mjs";
5
+ import "./chunk-IV352HZA.mjs";
6
+ import "./chunk-Y6FXYEAI.mjs";
6
7
  export {
7
8
  createProject
8
9
  };
package/dist/dev.d.mts ADDED
@@ -0,0 +1,19 @@
1
+ interface DevOptions {
2
+ /** Port override (reads from voltx.config.ts or env if not set) */
3
+ port?: number;
4
+ /** Entry file (default: src/index.ts) */
5
+ entry?: string;
6
+ /** Extra directories to watch */
7
+ watch?: string[];
8
+ /** Clear console on restart */
9
+ clearScreen?: boolean;
10
+ }
11
+ /**
12
+ * Start the VoltX dev server with hot reload.
13
+ *
14
+ * Spawns `tsx watch` on the app entry point. tsx handles TypeScript
15
+ * compilation and automatic restarts when files change.
16
+ */
17
+ declare function runDev(options?: DevOptions): Promise<void>;
18
+
19
+ export { type DevOptions, runDev };
package/dist/dev.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ interface DevOptions {
2
+ /** Port override (reads from voltx.config.ts or env if not set) */
3
+ port?: number;
4
+ /** Entry file (default: src/index.ts) */
5
+ entry?: string;
6
+ /** Extra directories to watch */
7
+ watch?: string[];
8
+ /** Clear console on restart */
9
+ clearScreen?: boolean;
10
+ }
11
+ /**
12
+ * Start the VoltX dev server with hot reload.
13
+ *
14
+ * Spawns `tsx watch` on the app entry point. tsx handles TypeScript
15
+ * compilation and automatic restarts when files change.
16
+ */
17
+ declare function runDev(options?: DevOptions): Promise<void>;
18
+
19
+ export { type DevOptions, runDev };