@zap-js/client 0.0.2 → 0.0.4

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 (115) hide show
  1. package/README.md +310 -24
  2. package/bin/zap +0 -0
  3. package/bin/zap-codegen +0 -0
  4. package/dist/cli/commands/build.d.ts +11 -0
  5. package/dist/cli/commands/build.js +282 -0
  6. package/dist/cli/commands/codegen.d.ts +8 -0
  7. package/dist/cli/commands/codegen.js +95 -0
  8. package/dist/cli/commands/dev.d.ts +20 -0
  9. package/dist/cli/commands/dev.js +78 -0
  10. package/dist/cli/commands/new.d.ts +9 -0
  11. package/dist/cli/commands/new.js +307 -0
  12. package/dist/cli/commands/routes-old.d.ts +9 -0
  13. package/dist/cli/commands/routes-old.js +106 -0
  14. package/dist/cli/commands/routes.d.ts +11 -0
  15. package/dist/cli/commands/routes.js +280 -0
  16. package/dist/cli/commands/serve.d.ts +17 -0
  17. package/dist/cli/commands/serve.js +386 -0
  18. package/dist/cli/index.d.ts +2 -0
  19. package/dist/cli/index.js +76 -0
  20. package/dist/cli/utils/index.d.ts +2 -0
  21. package/dist/cli/utils/index.js +2 -0
  22. package/dist/cli/utils/logger.d.ts +84 -0
  23. package/dist/cli/utils/logger.js +181 -0
  24. package/dist/cli/utils/port-finder.d.ts +8 -0
  25. package/dist/cli/utils/port-finder.js +48 -0
  26. package/dist/dev-server/codegen-runner.d.ts +41 -0
  27. package/dist/dev-server/codegen-runner.js +172 -0
  28. package/dist/dev-server/hot-reload.d.ts +72 -0
  29. package/dist/dev-server/hot-reload.js +280 -0
  30. package/dist/dev-server/index.d.ts +8 -0
  31. package/dist/dev-server/index.js +8 -0
  32. package/dist/dev-server/route-scanner.d.ts +71 -0
  33. package/dist/dev-server/route-scanner.js +114 -0
  34. package/dist/dev-server/rust-builder.d.ts +66 -0
  35. package/dist/dev-server/rust-builder.js +286 -0
  36. package/dist/dev-server/server.d.ts +147 -0
  37. package/dist/dev-server/server.js +658 -0
  38. package/dist/dev-server/vite-proxy.d.ts +56 -0
  39. package/dist/dev-server/vite-proxy.js +212 -0
  40. package/dist/dev-server/watcher.d.ts +48 -0
  41. package/dist/dev-server/watcher.js +127 -0
  42. package/dist/router/codegen-enhanced.d.ts +5 -0
  43. package/dist/router/codegen-enhanced.js +275 -0
  44. package/dist/router/codegen.d.ts +17 -0
  45. package/dist/router/codegen.js +654 -0
  46. package/dist/router/index.d.ts +16 -0
  47. package/dist/router/index.js +19 -0
  48. package/dist/router/scanner.d.ts +86 -0
  49. package/dist/router/scanner.js +689 -0
  50. package/dist/router/ssg.d.ts +115 -0
  51. package/dist/router/ssg.js +202 -0
  52. package/dist/router/types.d.ts +124 -0
  53. package/dist/router/types.js +9 -0
  54. package/dist/router/watch.d.ts +38 -0
  55. package/dist/router/watch.js +135 -0
  56. package/dist/runtime/csrf.d.ts +146 -0
  57. package/dist/runtime/csrf.js +166 -0
  58. package/dist/runtime/error-boundary.d.ts +129 -0
  59. package/dist/runtime/error-boundary.js +287 -0
  60. package/dist/runtime/hooks.d.ts +83 -0
  61. package/dist/runtime/hooks.js +96 -0
  62. package/dist/runtime/index.d.ts +229 -0
  63. package/dist/runtime/index.js +449 -0
  64. package/dist/runtime/ipc-client.d.ts +144 -0
  65. package/dist/runtime/ipc-client.js +621 -0
  66. package/dist/runtime/logger.d.ts +71 -0
  67. package/dist/runtime/logger.js +164 -0
  68. package/dist/runtime/middleware.d.ts +66 -0
  69. package/dist/runtime/middleware.js +114 -0
  70. package/dist/runtime/process-manager.d.ts +51 -0
  71. package/dist/runtime/process-manager.js +207 -0
  72. package/dist/runtime/router-simple.d.ts +98 -0
  73. package/dist/runtime/router-simple.js +330 -0
  74. package/dist/runtime/router.d.ts +103 -0
  75. package/dist/runtime/router.js +435 -0
  76. package/dist/runtime/rpc-client.d.ts +35 -0
  77. package/dist/runtime/rpc-client.js +140 -0
  78. package/dist/runtime/streaming-utils.d.ts +86 -0
  79. package/dist/runtime/streaming-utils.js +150 -0
  80. package/dist/runtime/types.d.ts +465 -0
  81. package/dist/runtime/types.js +60 -0
  82. package/dist/runtime/websockets-utils.d.ts +50 -0
  83. package/dist/runtime/websockets-utils.js +92 -0
  84. package/package.json +30 -20
  85. package/index.js +0 -29
  86. package/internal/cli/package.json +0 -46
  87. package/internal/cli/tsconfig.tsbuildinfo +0 -1
  88. package/internal/dev-server/node_modules/ora/index.d.ts +0 -332
  89. package/internal/dev-server/node_modules/ora/index.js +0 -416
  90. package/internal/dev-server/node_modules/ora/license +0 -9
  91. package/internal/dev-server/node_modules/ora/node_modules/string-width/index.d.ts +0 -36
  92. package/internal/dev-server/node_modules/ora/node_modules/string-width/index.js +0 -65
  93. package/internal/dev-server/node_modules/ora/node_modules/string-width/license +0 -9
  94. package/internal/dev-server/node_modules/ora/node_modules/string-width/node_modules/emoji-regex/LICENSE-MIT.txt +0 -20
  95. package/internal/dev-server/node_modules/ora/node_modules/string-width/node_modules/emoji-regex/README.md +0 -107
  96. package/internal/dev-server/node_modules/ora/node_modules/string-width/node_modules/emoji-regex/index.d.ts +0 -3
  97. package/internal/dev-server/node_modules/ora/node_modules/string-width/node_modules/emoji-regex/index.js +0 -4
  98. package/internal/dev-server/node_modules/ora/node_modules/string-width/node_modules/emoji-regex/index.mjs +0 -4
  99. package/internal/dev-server/node_modules/ora/node_modules/string-width/node_modules/emoji-regex/package.json +0 -46
  100. package/internal/dev-server/node_modules/ora/node_modules/string-width/package.json +0 -60
  101. package/internal/dev-server/node_modules/ora/node_modules/string-width/readme.md +0 -62
  102. package/internal/dev-server/node_modules/ora/package.json +0 -66
  103. package/internal/dev-server/node_modules/ora/readme.md +0 -325
  104. package/internal/dev-server/package.json +0 -41
  105. package/internal/router/package.json +0 -28
  106. package/internal/runtime/package.json +0 -41
  107. package/internal/runtime/src/error-boundary.tsx +0 -476
  108. package/internal/runtime/src/router-simple.tsx +0 -640
  109. package/internal/runtime/src/router.tsx +0 -771
  110. package/internal/runtime/tsconfig.tsbuildinfo +0 -1
  111. package/src/errors.js +0 -33
  112. package/src/logger.js +0 -10
  113. package/src/middleware.js +0 -32
  114. package/src/router.js +0 -41
  115. package/src/types.js +0 -39
@@ -0,0 +1,95 @@
1
+ import { execSync } from 'child_process';
2
+ import { existsSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { cliLogger } from '../utils/logger.js';
5
+ /**
6
+ * Find the zap-codegen binary in known locations
7
+ */
8
+ function findCodegenBinary() {
9
+ const projectDir = process.cwd();
10
+ // Check multiple possible locations
11
+ const possiblePaths = [
12
+ // Project bin directory
13
+ join(projectDir, 'bin', 'zap-codegen'),
14
+ join(projectDir, 'bin', 'zap-codegen.exe'),
15
+ // Workspace target (for monorepo development)
16
+ join(projectDir, '../../target/release/zap-codegen'),
17
+ join(projectDir, '../../target/aarch64-apple-darwin/release/zap-codegen'),
18
+ join(projectDir, '../../target/x86_64-unknown-linux-gnu/release/zap-codegen'),
19
+ join(projectDir, '../../target/debug/zap-codegen'),
20
+ // Local target directory
21
+ join(projectDir, 'target/release/zap-codegen'),
22
+ join(projectDir, 'target/debug/zap-codegen'),
23
+ ];
24
+ for (const path of possiblePaths) {
25
+ if (existsSync(path)) {
26
+ return path;
27
+ }
28
+ }
29
+ // Try global zap-codegen as fallback
30
+ try {
31
+ execSync('which zap-codegen', { stdio: 'pipe' });
32
+ return 'zap-codegen';
33
+ }
34
+ catch {
35
+ // Not in PATH
36
+ }
37
+ return null;
38
+ }
39
+ /**
40
+ * Generate TypeScript bindings from Rust exports
41
+ */
42
+ export async function codegenCommand(options) {
43
+ const outputDir = options.output || './src/api';
44
+ try {
45
+ cliLogger.header('Generating TypeScript Bindings');
46
+ // Find the codegen binary
47
+ const codegenBinary = findCodegenBinary();
48
+ if (!codegenBinary) {
49
+ cliLogger.error('zap-codegen binary not found');
50
+ cliLogger.newline();
51
+ cliLogger.info('Please build the codegen binary first:');
52
+ cliLogger.command('cargo build --release --bin zap-codegen');
53
+ cliLogger.newline();
54
+ cliLogger.info('Or install globally:');
55
+ cliLogger.command('npm install -g @zapjs/codegen');
56
+ cliLogger.newline();
57
+ process.exit(1);
58
+ }
59
+ cliLogger.spinner('codegen', `Generating bindings to ${outputDir}...`);
60
+ try {
61
+ let cmd = `"${codegenBinary}"`;
62
+ if (options.output) {
63
+ cmd += ` --output-dir ${options.output}`;
64
+ }
65
+ else {
66
+ cmd += ` --output-dir ${outputDir}`;
67
+ }
68
+ if (options.input) {
69
+ cmd += ` --input ${options.input}`;
70
+ }
71
+ execSync(cmd, {
72
+ stdio: 'pipe',
73
+ });
74
+ cliLogger.succeedSpinner('codegen', 'TypeScript bindings generated');
75
+ }
76
+ catch (error) {
77
+ cliLogger.failSpinner('codegen', 'Codegen failed');
78
+ if (error instanceof Error) {
79
+ cliLogger.error('Error details', error.message);
80
+ }
81
+ process.exit(1);
82
+ }
83
+ cliLogger.newline();
84
+ cliLogger.success('Codegen complete!');
85
+ cliLogger.keyValue('Generated files in', outputDir);
86
+ cliLogger.newline();
87
+ }
88
+ catch (error) {
89
+ cliLogger.error('Codegen failed');
90
+ if (error instanceof Error) {
91
+ cliLogger.error('Error details', error.message);
92
+ }
93
+ process.exit(1);
94
+ }
95
+ }
@@ -0,0 +1,20 @@
1
+ export interface DevOptions {
2
+ port?: string;
3
+ vitePort?: string;
4
+ open?: boolean;
5
+ logLevel?: string;
6
+ release?: boolean;
7
+ skipBuild?: boolean;
8
+ binaryPath?: string;
9
+ codegenBinaryPath?: string;
10
+ }
11
+ /**
12
+ * Start development server with hot reload
13
+ *
14
+ * Orchestrates:
15
+ * - Rust backend compilation with file watching
16
+ * - Vite frontend dev server
17
+ * - Automatic TypeScript binding generation
18
+ * - Hot reload signaling
19
+ */
20
+ export declare function devCommand(options: DevOptions): Promise<void>;
@@ -0,0 +1,78 @@
1
+ import path from 'path';
2
+ import { existsSync } from 'fs';
3
+ import { DevServer } from '../../dev-server/index.js';
4
+ import { cliLogger } from '../utils/logger.js';
5
+ /**
6
+ * Auto-detect pre-built binaries in bin/ directory
7
+ */
8
+ function detectBinaries(projectDir) {
9
+ const binDir = path.join(projectDir, 'bin');
10
+ const result = {};
11
+ // Check for zap binary
12
+ const zapBinary = path.join(binDir, 'zap');
13
+ const zapBinaryExe = path.join(binDir, 'zap.exe');
14
+ if (existsSync(zapBinary)) {
15
+ result.binaryPath = zapBinary;
16
+ }
17
+ else if (existsSync(zapBinaryExe)) {
18
+ result.binaryPath = zapBinaryExe;
19
+ }
20
+ // Check for zap-codegen binary
21
+ const codegenBinary = path.join(binDir, 'zap-codegen');
22
+ const codegenBinaryExe = path.join(binDir, 'zap-codegen.exe');
23
+ if (existsSync(codegenBinary)) {
24
+ result.codegenBinaryPath = codegenBinary;
25
+ }
26
+ else if (existsSync(codegenBinaryExe)) {
27
+ result.codegenBinaryPath = codegenBinaryExe;
28
+ }
29
+ return result;
30
+ }
31
+ /**
32
+ * Start development server with hot reload
33
+ *
34
+ * Orchestrates:
35
+ * - Rust backend compilation with file watching
36
+ * - Vite frontend dev server
37
+ * - Automatic TypeScript binding generation
38
+ * - Hot reload signaling
39
+ */
40
+ export async function devCommand(options) {
41
+ const projectDir = process.cwd();
42
+ // Auto-detect pre-built binaries if not explicitly provided
43
+ const detectedBinaries = detectBinaries(projectDir);
44
+ const config = {
45
+ projectDir,
46
+ rustPort: options.port ? parseInt(options.port, 10) : 3000,
47
+ vitePort: options.vitePort ? parseInt(options.vitePort, 10) : 5173,
48
+ logLevel: options.logLevel || 'info',
49
+ release: options.release || false,
50
+ skipInitialBuild: options.skipBuild || false,
51
+ openBrowser: options.open !== false,
52
+ binaryPath: options.binaryPath || detectedBinaries.binaryPath,
53
+ codegenBinaryPath: options.codegenBinaryPath || detectedBinaries.codegenBinaryPath,
54
+ };
55
+ // Log if using pre-built binaries
56
+ if (config.binaryPath) {
57
+ cliLogger.info('Using pre-built binary', config.binaryPath);
58
+ }
59
+ const server = new DevServer(config);
60
+ // Handle graceful shutdown
61
+ const shutdown = async () => {
62
+ await server.stop();
63
+ process.exit(0);
64
+ };
65
+ process.on('SIGINT', shutdown);
66
+ process.on('SIGTERM', shutdown);
67
+ try {
68
+ await server.start();
69
+ // Keep the process running
70
+ await new Promise(() => { });
71
+ }
72
+ catch (error) {
73
+ if (error instanceof Error) {
74
+ cliLogger.error('Development server failed', error);
75
+ }
76
+ process.exit(1);
77
+ }
78
+ }
@@ -0,0 +1,9 @@
1
+ export interface NewOptions {
2
+ template: string;
3
+ install?: boolean;
4
+ git?: boolean;
5
+ }
6
+ /**
7
+ * Create a new ZapJS project
8
+ */
9
+ export declare function newCommand(name: string, options: NewOptions): Promise<void>;
@@ -0,0 +1,307 @@
1
+ import { execSync } from 'child_process';
2
+ import inquirer from 'inquirer';
3
+ import fsExtra from 'fs-extra';
4
+ import { join, resolve } from 'path';
5
+ import { cliLogger } from '../utils/logger.js';
6
+ const { ensureDirSync, writeFileSync } = fsExtra;
7
+ /**
8
+ * Create a new ZapJS project
9
+ */
10
+ export async function newCommand(name, options) {
11
+ if (!name || name.trim() === '') {
12
+ cliLogger.error('Project name is required');
13
+ process.exit(1);
14
+ }
15
+ const projectDir = resolve(process.cwd(), name);
16
+ try {
17
+ // Check if directory already exists
18
+ try {
19
+ const fs = await import('fs');
20
+ if (fs.existsSync(projectDir)) {
21
+ cliLogger.error(`Directory "${name}" already exists`);
22
+ process.exit(1);
23
+ }
24
+ }
25
+ catch (error) {
26
+ // Directory doesn't exist, which is good
27
+ }
28
+ cliLogger.header(`Create New ZapJS Project: ${name}`);
29
+ // Prompt for template if not specified
30
+ let template = options.template;
31
+ const templates = ['basic', 'fullstack'];
32
+ if (!templates.includes(template)) {
33
+ const answers = await inquirer.prompt([
34
+ {
35
+ type: 'list',
36
+ name: 'template',
37
+ message: 'Choose a template:',
38
+ choices: templates.map((t) => ({
39
+ name: t.charAt(0).toUpperCase() + t.slice(1),
40
+ value: t,
41
+ })),
42
+ default: 'basic',
43
+ },
44
+ ]);
45
+ template = answers.template;
46
+ }
47
+ // Create project directory
48
+ cliLogger.spinner('dir', 'Creating project directory...');
49
+ ensureDirSync(projectDir);
50
+ cliLogger.succeedSpinner('dir', 'Project directory created');
51
+ // Create project files
52
+ cliLogger.spinner('files', `Creating ${template} project...`);
53
+ createMinimalProject(projectDir, name, template);
54
+ cliLogger.succeedSpinner('files', 'Project files created');
55
+ // Install dependencies
56
+ if (options.install !== false) {
57
+ cliLogger.spinner('deps', 'Installing dependencies...');
58
+ try {
59
+ execSync('npm install', { cwd: projectDir, stdio: 'pipe' });
60
+ cliLogger.succeedSpinner('deps', 'Dependencies installed');
61
+ }
62
+ catch (error) {
63
+ cliLogger.warn('npm install skipped. Run "npm install" manually.');
64
+ }
65
+ }
66
+ // Initialize git
67
+ if (options.git !== false) {
68
+ cliLogger.spinner('git', 'Initializing git repository...');
69
+ try {
70
+ execSync('git init', { cwd: projectDir, stdio: 'pipe' });
71
+ execSync('git add .', { cwd: projectDir, stdio: 'pipe' });
72
+ execSync('git commit -m "Initial commit"', {
73
+ cwd: projectDir,
74
+ stdio: 'pipe',
75
+ });
76
+ cliLogger.succeedSpinner('git', 'Git repository initialized');
77
+ }
78
+ catch (error) {
79
+ cliLogger.warn('Git initialization skipped');
80
+ }
81
+ }
82
+ // Success message
83
+ cliLogger.newline();
84
+ cliLogger.success(`Project ${name} created successfully!`);
85
+ cliLogger.newline();
86
+ // Next steps
87
+ cliLogger.info('Next steps:');
88
+ cliLogger.command(`cd ${name}`);
89
+ cliLogger.command('cargo build --release');
90
+ cliLogger.command('zap dev');
91
+ cliLogger.newline();
92
+ cliLogger.info('Happy coding! 🚀');
93
+ cliLogger.newline();
94
+ }
95
+ catch (error) {
96
+ cliLogger.error('Project creation failed');
97
+ if (error instanceof Error) {
98
+ cliLogger.error('Error details', error.message);
99
+ }
100
+ process.exit(1);
101
+ }
102
+ }
103
+ /**
104
+ * Create a minimal project structure
105
+ */
106
+ function createMinimalProject(projectDir, projectName, template) {
107
+ // Create directory structure
108
+ const dirs = [
109
+ 'server/src',
110
+ 'routes',
111
+ 'routes/api',
112
+ 'src',
113
+ 'src/generated',
114
+ ];
115
+ for (const dir of dirs) {
116
+ ensureDirSync(join(projectDir, dir));
117
+ }
118
+ // Create server/src/main.rs
119
+ const mainRs = `use zap::Zap;
120
+
121
+ #[tokio::main]
122
+ async fn main() {
123
+ let mut app = Zap::new()
124
+ .port(3000)
125
+ .hostname("127.0.0.1")
126
+ .cors()
127
+ .logging();
128
+
129
+ // Register your routes here
130
+ app.get("/api/health", || {
131
+ serde_json::json!({ "status": "ok" })
132
+ });
133
+
134
+ if let Err(e) = app.listen().await {
135
+ eprintln!("Server error: {}", e);
136
+ std::process::exit(1);
137
+ }
138
+ }
139
+ `;
140
+ // Create routes/__root.tsx
141
+ const rootTsx = `import React from 'react';
142
+
143
+ export default function RootLayout({ children }: { children: React.ReactNode }) {
144
+ return (
145
+ <html lang="en">
146
+ <head>
147
+ <meta charSet="UTF-8" />
148
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
149
+ <title>ZapJS App</title>
150
+ </head>
151
+ <body>
152
+ {children}
153
+ </body>
154
+ </html>
155
+ );
156
+ }
157
+ `;
158
+ // Create routes/index.tsx
159
+ const indexRoute = `export default function HomePage() {
160
+ return (
161
+ <div style={{ fontFamily: 'system-ui, sans-serif', padding: '2rem' }}>
162
+ <h1>Welcome to ZapJS</h1>
163
+ <p>Fullstack Rust + React Framework</p>
164
+ <p>
165
+ Edit <code>routes/index.tsx</code> to get started.
166
+ </p>
167
+ </div>
168
+ );
169
+ }
170
+ `;
171
+ // Create routes/api/hello.ts
172
+ const helloApi = `import { server } from '../../src/generated/server';
173
+
174
+ export const GET = async () => {
175
+ return {
176
+ message: 'Hello from ZapJS!',
177
+ timestamp: new Date().toISOString(),
178
+ };
179
+ };
180
+
181
+ export const POST = async ({ request }: { request: Request }) => {
182
+ const body = await request.json();
183
+ return {
184
+ received: body,
185
+ message: 'Data received successfully',
186
+ };
187
+ };
188
+ `;
189
+ // Create routes/api/users.$id.ts
190
+ const usersApi = `export const GET = async ({ params }: { params: { id: string } }) => {
191
+ return {
192
+ id: params.id,
193
+ name: \`User \${params.id}\`,
194
+ email: \`user\${params.id}@example.com\`,
195
+ };
196
+ };
197
+ `;
198
+ // Create package.json
199
+ const packageJson = {
200
+ name: projectName,
201
+ version: '0.1.0',
202
+ type: 'module',
203
+ scripts: {
204
+ 'dev': 'zap dev',
205
+ 'build': 'zap build',
206
+ 'serve': 'zap serve',
207
+ 'routes': 'zap routes',
208
+ },
209
+ dependencies: {
210
+ 'react': '^18.0.0',
211
+ 'react-dom': '^18.0.0',
212
+ '@zapjs/runtime': '^0.1.0',
213
+ '@zapjs/router': '^0.1.0',
214
+ },
215
+ devDependencies: {
216
+ '@types/react': '^18.0.0',
217
+ '@types/react-dom': '^18.0.0',
218
+ '@zapjs/cli': '^0.1.0',
219
+ 'typescript': '^5.0.0',
220
+ 'vite': '^5.0.0',
221
+ },
222
+ };
223
+ // Create Cargo.toml
224
+ const cargoToml = `[package]
225
+ name = "${projectName}"
226
+ version = "0.1.0"
227
+ edition = "2021"
228
+
229
+ [dependencies]
230
+ zap = { path = "../../packages/server" }
231
+ tokio = { version = "1.0", features = ["full"] }
232
+ serde_json = "1.0"
233
+ `;
234
+ // Create zap.config.ts
235
+ const zapConfig = `import { defineConfig } from 'zap';
236
+
237
+ export default defineConfig({
238
+ server: {
239
+ port: 3000,
240
+ hostname: '127.0.0.1',
241
+ },
242
+ dev: {
243
+ apiPort: 3000,
244
+ clientPort: 5173,
245
+ watchRust: true,
246
+ watchTypeScript: true,
247
+ open: true,
248
+ },
249
+ });
250
+ `;
251
+ // Create tsconfig.json
252
+ const tsconfig = {
253
+ compilerOptions: {
254
+ target: 'ES2020',
255
+ useDefineForClassFields: true,
256
+ lib: ['ES2020', 'DOM', 'DOM.Iterable'],
257
+ module: 'ESNext',
258
+ skipLibCheck: true,
259
+ esModuleInterop: true,
260
+ allowSyntheticDefaultImports: true,
261
+ strict: true,
262
+ noEmit: true,
263
+ jsx: 'react-jsx',
264
+ moduleResolution: 'bundler',
265
+ allowImportingTsExtensions: true,
266
+ },
267
+ include: ['client/src'],
268
+ references: [{ path: './tsconfig.node.json' }],
269
+ };
270
+ // Write files
271
+ writeFileSync(join(projectDir, 'server/src/main.rs'), mainRs);
272
+ writeFileSync(join(projectDir, 'routes/__root.tsx'), rootTsx);
273
+ writeFileSync(join(projectDir, 'routes/index.tsx'), indexRoute);
274
+ writeFileSync(join(projectDir, 'routes/api/hello.ts'), helloApi);
275
+ writeFileSync(join(projectDir, 'routes/api/users.$id.ts'), usersApi);
276
+ writeFileSync(join(projectDir, 'package.json'), JSON.stringify(packageJson, null, 2));
277
+ writeFileSync(join(projectDir, 'Cargo.toml'), cargoToml);
278
+ writeFileSync(join(projectDir, 'zap.config.ts'), zapConfig);
279
+ writeFileSync(join(projectDir, 'tsconfig.json'), JSON.stringify(tsconfig, null, 2));
280
+ // Create .gitignore
281
+ const gitignore = `# Dependencies
282
+ node_modules/
283
+ package-lock.json
284
+
285
+ # Build output
286
+ /dist
287
+ /target
288
+ /server/target
289
+
290
+ # Rust
291
+ Cargo.lock
292
+
293
+ # IDE
294
+ .vscode/
295
+ .idea/
296
+ *.swp
297
+ *.swo
298
+
299
+ # Environment
300
+ .env
301
+ .env.local
302
+
303
+ # Logs
304
+ *.log
305
+ `;
306
+ writeFileSync(join(projectDir, '.gitignore'), gitignore);
307
+ }
@@ -0,0 +1,9 @@
1
+ export interface RoutesOptions {
2
+ routesDir?: string;
3
+ output?: string;
4
+ json?: boolean;
5
+ }
6
+ /**
7
+ * Scan routes and generate route tree
8
+ */
9
+ export declare function routesCommand(options: RoutesOptions): Promise<void>;
@@ -0,0 +1,106 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { existsSync, mkdirSync } from 'fs';
4
+ import { join, resolve } from 'path';
5
+ /**
6
+ * Scan routes and generate route tree
7
+ */
8
+ export async function routesCommand(options) {
9
+ const spinner = ora();
10
+ try {
11
+ const projectDir = process.cwd();
12
+ const routesDir = resolve(options.routesDir || join(projectDir, 'routes'));
13
+ const outputDir = resolve(options.output || join(projectDir, 'src', 'generated'));
14
+ console.log(chalk.cyan('\n⚡ ZapJS Route Scanner\n'));
15
+ // Check if routes directory exists
16
+ if (!existsSync(routesDir)) {
17
+ console.log(chalk.yellow('No routes directory found.'));
18
+ console.log(chalk.gray(`Expected: ${routesDir}`));
19
+ console.log(chalk.gray('\nCreate a routes/ directory with your route files to get started.'));
20
+ console.log(chalk.gray('\nTanStack-style conventions:'));
21
+ console.log(chalk.gray(' routes/index.tsx → /'));
22
+ console.log(chalk.gray(' routes/about.tsx → /about'));
23
+ console.log(chalk.gray(' routes/$postId.tsx → /:postId'));
24
+ console.log(chalk.gray(' routes/posts.$id.tsx → /posts/:id'));
25
+ console.log(chalk.gray(' routes/api/users.ts → /api/users'));
26
+ console.log(chalk.gray(' routes/_layout.tsx → Layout wrapper'));
27
+ console.log(chalk.gray(' routes/__root.tsx → Root layout\n'));
28
+ return;
29
+ }
30
+ // Try to load the router package
31
+ spinner.start('Loading route scanner...');
32
+ let router;
33
+ try {
34
+ // Dynamic import using variable to prevent TypeScript from resolving
35
+ const moduleName = '@zapjs/router';
36
+ router = await (Function('moduleName', 'return import(moduleName)')(moduleName));
37
+ }
38
+ catch {
39
+ spinner.fail('@zapjs/router not found');
40
+ console.log(chalk.yellow('\nInstall the router package:'));
41
+ console.log(chalk.cyan(' npm install @zapjs/router\n'));
42
+ return;
43
+ }
44
+ spinner.succeed('Route scanner loaded');
45
+ // Scan routes
46
+ spinner.start(`Scanning ${routesDir}...`);
47
+ const tree = router.scanRoutes(routesDir);
48
+ spinner.succeed('Routes scanned');
49
+ // Output JSON if requested
50
+ if (options.json) {
51
+ console.log(JSON.stringify(tree, null, 2));
52
+ return;
53
+ }
54
+ // Print route summary
55
+ console.log(chalk.white('\n Page Routes:'));
56
+ if (tree.routes.length === 0) {
57
+ console.log(chalk.gray(' (none)'));
58
+ }
59
+ else {
60
+ for (const route of tree.routes) {
61
+ const params = route.params.length > 0
62
+ ? chalk.gray(` [${route.params.map(p => p.name).join(', ')}]`)
63
+ : '';
64
+ const index = route.isIndex ? chalk.gray(' (index)') : '';
65
+ console.log(chalk.cyan(` ${route.urlPath}`) + params + index);
66
+ console.log(chalk.gray(` → ${route.relativePath}`));
67
+ }
68
+ }
69
+ console.log(chalk.white('\n API Routes:'));
70
+ if (tree.apiRoutes.length === 0) {
71
+ console.log(chalk.gray(' (none)'));
72
+ }
73
+ else {
74
+ for (const route of tree.apiRoutes) {
75
+ const params = route.params.length > 0
76
+ ? chalk.gray(` [${route.params.map(p => p.name).join(', ')}]`)
77
+ : '';
78
+ const methods = route.methods
79
+ ? chalk.gray(` (${route.methods.join(', ')})`)
80
+ : '';
81
+ console.log(chalk.green(` ${route.urlPath}`) + params + methods);
82
+ console.log(chalk.gray(` → ${route.relativePath}`));
83
+ }
84
+ }
85
+ // Generate route tree files
86
+ spinner.start('Generating route tree...');
87
+ if (!existsSync(outputDir)) {
88
+ mkdirSync(outputDir, { recursive: true });
89
+ }
90
+ router.generateRouteTree({
91
+ outputDir,
92
+ routeTree: tree,
93
+ });
94
+ spinner.succeed('Route tree generated');
95
+ // Summary
96
+ console.log(chalk.green(`\n✓ Found ${tree.routes.length} page routes, ${tree.apiRoutes.length} API routes`));
97
+ console.log(chalk.gray(` Output: ${outputDir}\n`));
98
+ }
99
+ catch (error) {
100
+ spinner.fail('Route scanning failed');
101
+ if (error instanceof Error) {
102
+ console.error(chalk.red(`\nError: ${error.message}\n`));
103
+ }
104
+ process.exit(1);
105
+ }
106
+ }
@@ -0,0 +1,11 @@
1
+ export interface RoutesOptions {
2
+ routesDir?: string;
3
+ output?: string;
4
+ json?: boolean;
5
+ showCode?: boolean;
6
+ verbose?: boolean;
7
+ }
8
+ /**
9
+ * Enhanced route scanner that shows handler logic
10
+ */
11
+ export declare function routesCommand(options: RoutesOptions): Promise<void>;