@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
package/README.md CHANGED
@@ -1,44 +1,330 @@
1
- # @zap-js/client
1
+ # @zapjs/client
2
2
 
3
- Client-side package for the ZapJS fullstack React framework.
3
+ Official CLI and development tools for ZapJS - the fullstack Rust + React framework.
4
4
 
5
5
  ## Installation
6
6
 
7
+ ### Global Installation (Recommended)
8
+
9
+ Install the ZapJS CLI globally to use the `zap` command anywhere:
10
+
11
+ ```bash
12
+ npm install -g @zapjs/client
13
+ ```
14
+
15
+ After installation, verify it works:
16
+
7
17
  ```bash
8
- npm install @zap-js/client
18
+ zap --version
19
+ zap --help
9
20
  ```
10
21
 
11
- ## Usage
22
+ ### Local Project Installation
12
23
 
13
- ```javascript
14
- import { router, middleware, errors, logger } from '@zap-js/client'
24
+ For project-specific installation:
15
25
 
16
- // Router components and hooks
17
- const { Link, useRouter, useParams } = router
26
+ ```bash
27
+ npm install --save-dev @zapjs/client
28
+ ```
29
+
30
+ Then use via npm scripts in your `package.json`:
18
31
 
19
- // Middleware functions
20
- const { requireAuth, preloadData } = middleware
32
+ ```json
33
+ {
34
+ "scripts": {
35
+ "dev": "zap dev",
36
+ "build": "zap build",
37
+ "serve": "zap serve"
38
+ }
39
+ }
40
+ ```
41
+
42
+ ### Local Development (Contributors)
21
43
 
22
- // Error handling
23
- const { ErrorBoundary } = errors
44
+ If you're contributing to ZapJS:
24
45
 
25
- // Logging
26
- const log = logger.create('MyApp')
46
+ ```bash
47
+ cd packages/client
48
+ npm install
49
+ npm run build
50
+ npm link
27
51
  ```
28
52
 
29
- ## Features
53
+ This creates a global symlink for local testing. The `zap` command will now use your local development version.
54
+
55
+ ## Available Commands
56
+
57
+ ### `zap new <name>`
58
+
59
+ Create a new ZapJS project with the specified template.
60
+
61
+ ```bash
62
+ zap new my-app
63
+ zap new my-app --template fullstack
64
+ zap new my-app --no-install --no-git
65
+ ```
66
+
67
+ **Options:**
68
+ - `-t, --template <template>` - Template to use: `basic` or `fullstack` (default: `basic`)
69
+ - `--no-install` - Skip npm install
70
+ - `--no-git` - Skip git initialization
71
+
72
+ ### `zap dev`
73
+
74
+ Start the development server with hot reload for both Rust and TypeScript.
75
+
76
+ ```bash
77
+ zap dev
78
+ zap dev --port 3000 --vite-port 5173
79
+ zap dev --release --skip-build
80
+ ```
81
+
82
+ **Options:**
83
+ - `-p, --port <port>` - API server port (default: `3000`)
84
+ - `--vite-port <port>` - Vite dev server port (default: `5173`)
85
+ - `--no-open` - Don't open browser automatically
86
+ - `-l, --log-level <level>` - Log level: `debug`, `info`, `warn`, `error` (default: `info`)
87
+ - `--release` - Build Rust in release mode (slower build, faster runtime)
88
+ - `--skip-build` - Skip initial Rust build (use existing binary)
89
+ - `--binary-path <path>` - Path to pre-built zap binary
90
+ - `--codegen-binary-path <path>` - Path to pre-built zap-codegen binary
91
+
92
+ **Keyboard Shortcuts (during dev):**
93
+ - `r` - Manually trigger Rust rebuild
94
+ - `c` - Regenerate TypeScript bindings
95
+ - `q` - Quit dev server
96
+ - `Ctrl+C` - Stop server
97
+
98
+ ### `zap build`
99
+
100
+ Build your application for production.
101
+
102
+ ```bash
103
+ zap build
104
+ zap build --output ./dist --target x86_64-unknown-linux-gnu
105
+ zap build --skip-frontend
106
+ ```
107
+
108
+ **Options:**
109
+ - `--release` - Build optimized release (default: `true`)
110
+ - `-o, --output <dir>` - Output directory (default: `./dist`)
111
+ - `--target <target>` - Cross-compile target (e.g., `x86_64-unknown-linux-gnu`)
112
+ - `--skip-frontend` - Skip Vite frontend build
113
+ - `--skip-codegen` - Skip TypeScript binding generation
114
+
115
+ **Output Structure:**
116
+ ```
117
+ dist/
118
+ ├── bin/
119
+ │ └── zap # Rust binary
120
+ ├── static/ # Frontend assets (if built)
121
+ ├── config.json # Production config
122
+ └── manifest.json # Build metadata
123
+ ```
124
+
125
+ ### `zap serve`
126
+
127
+ Run the production server.
128
+
129
+ ```bash
130
+ zap serve
131
+ zap serve --port 8080 --host 0.0.0.0
132
+ zap serve --config ./custom-config.json
133
+ ```
134
+
135
+ **Options:**
136
+ - `-p, --port <port>` - Server port
137
+ - `--host <host>` - Host to bind to (default: `0.0.0.0`)
138
+ - `-c, --config <path>` - Path to config file
139
+ - `-w, --workers <count>` - Number of worker threads
140
+
141
+ ### `zap codegen`
142
+
143
+ Generate TypeScript bindings from Rust exports.
144
+
145
+ ```bash
146
+ zap codegen
147
+ zap codegen --output ./src/api
148
+ zap codegen --input ./metadata.json
149
+ ```
150
+
151
+ **Options:**
152
+ - `-i, --input <file>` - Input metadata JSON file
153
+ - `-o, --output <dir>` - Output directory (default: `./src/api`)
154
+
155
+ ### `zap routes`
156
+
157
+ Scan routes directory and display/generate route tree.
158
+
159
+ ```bash
160
+ zap routes
161
+ zap routes --routes-dir ./routes --output ./src/generated
162
+ zap routes --json
163
+ zap routes --verbose
164
+ ```
165
+
166
+ **Options:**
167
+ - `-d, --routes-dir <dir>` - Routes directory path
168
+ - `-o, --output <dir>` - Output directory for generated files
169
+ - `--json` - Output routes as JSON
170
+ - `--verbose` - Show full handler code
171
+
172
+ ## Project Structure
173
+
174
+ A typical ZapJS project structure:
175
+
176
+ ```
177
+ my-app/
178
+ ├── routes/ # File-based routing
179
+ │ ├── __root.tsx # Root layout
180
+ │ ├── index.tsx # Home page (/)
181
+ │ ├── about.tsx # About page (/about)
182
+ │ ├── posts/
183
+ │ │ ├── [id].tsx # Dynamic route (/posts/:id)
184
+ │ │ └── index.tsx # Posts index (/posts)
185
+ │ └── api/
186
+ │ ├── hello.ts # API route (/api/hello)
187
+ │ └── users.$id.ts # Dynamic API route (/api/users/:id)
188
+ ├── server/
189
+ │ ├── src/
190
+ │ │ └── main.rs # Rust server entry point
191
+ │ └── Cargo.toml # Rust dependencies
192
+ ├── src/
193
+ │ └── generated/ # Auto-generated files
194
+ │ ├── routes.tsx # Generated route tree
195
+ │ └── routeManifest.json
196
+ ├── package.json
197
+ ├── Cargo.toml # Workspace Cargo.toml
198
+ ├── tsconfig.json
199
+ └── zap.config.ts # Optional config
200
+ ```
201
+
202
+ ## Configuration
203
+
204
+ ### `zap.config.ts` (Optional)
205
+
206
+ ```typescript
207
+ import { defineConfig } from 'zap';
208
+
209
+ export default defineConfig({
210
+ server: {
211
+ port: 3000,
212
+ hostname: '127.0.0.1',
213
+ },
214
+ dev: {
215
+ apiPort: 3000,
216
+ clientPort: 5173,
217
+ watchRust: true,
218
+ watchTypeScript: true,
219
+ open: true,
220
+ },
221
+ });
222
+ ```
223
+
224
+ ## Routing Conventions
225
+
226
+ ### File-Based Routing
227
+
228
+ ZapJS uses Next.js-style file-based routing:
229
+
230
+ - `routes/index.tsx` → `/`
231
+ - `routes/about.tsx` → `/about`
232
+ - `routes/posts/[id].tsx` → `/posts/:id`
233
+ - `routes/posts/[...slug].tsx` → `/posts/*` (catch-all)
234
+ - `routes/__root.tsx` → Root layout wrapper
235
+ - `routes/_layout.tsx` → Layout wrapper
236
+
237
+ ### API Routes
238
+
239
+ TypeScript files in `routes/api/` become API endpoints:
240
+
241
+ ```typescript
242
+ // routes/api/users.ts
243
+ export const GET = async () => {
244
+ return { users: [] };
245
+ };
246
+
247
+ export const POST = async ({ request }: { request: Request }) => {
248
+ const body = await request.json();
249
+ return { created: body };
250
+ };
251
+ ```
252
+
253
+ **Supported Methods:** `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS`
254
+
255
+ ### Dynamic Routes
256
+
257
+ Use `[param]` or `$param` syntax for dynamic segments:
258
+
259
+ ```typescript
260
+ // routes/api/users.$id.ts or routes/api/users/[id].ts
261
+ export const GET = async ({ params }: { params: { id: string } }) => {
262
+ return { id: params.id };
263
+ };
264
+ ```
265
+
266
+ ## Troubleshooting
267
+
268
+ ### `zap` command not found
269
+
270
+ After installing globally, if `zap` is not found:
271
+
272
+ 1. Check npm global bin directory is in PATH:
273
+ ```bash
274
+ npm config get prefix
275
+ ```
276
+
277
+ 2. Add npm global bin to your PATH:
278
+ ```bash
279
+ # Add to ~/.bashrc or ~/.zshrc
280
+ export PATH="$(npm config get prefix)/bin:$PATH"
281
+ ```
282
+
283
+ 3. Verify installation:
284
+ ```bash
285
+ which zap
286
+ zap --version
287
+ ```
288
+
289
+ ### Development server won't start
290
+
291
+ 1. Ensure Rust is installed:
292
+ ```bash
293
+ rustc --version
294
+ cargo --version
295
+ ```
296
+
297
+ 2. Clean and rebuild:
298
+ ```bash
299
+ cargo clean
300
+ npm run build
301
+ zap dev
302
+ ```
303
+
304
+ 3. Check port availability:
305
+ ```bash
306
+ lsof -i :3000 # Check if port 3000 is in use
307
+ ```
308
+
309
+ ### TypeScript bindings not generating
310
+
311
+ 1. Ensure `zap-codegen` binary exists:
312
+ ```bash
313
+ cargo build --release --bin zap-codegen
314
+ ```
30
315
 
31
- - **File-based routing** with automatic route generation
32
- - **Nested layouts** with `_layout.tsx` files
33
- - **Route-level middleware** for auth and data preloading
34
- - **Zero-config development** with hot module reload
35
- - **TypeScript support** out of the box
36
- - **Production optimizations** built-in
316
+ 2. Manually run codegen:
317
+ ```bash
318
+ zap codegen
319
+ ```
37
320
 
38
- ## Documentation
321
+ ## Links
39
322
 
40
- Full documentation available at [https://github.com/saint0x/zapjs](https://github.com/saint0x/zapjs)
323
+ - [Documentation](https://github.com/yourusername/zapjs)
324
+ - [Examples](https://github.com/yourusername/zapjs/tree/main/examples)
325
+ - [Discord Community](https://discord.gg/zapjs)
326
+ - [GitHub Issues](https://github.com/yourusername/zapjs/issues)
41
327
 
42
328
  ## License
43
329
 
44
- MIT
330
+ MIT
package/bin/zap ADDED
Binary file
Binary file
@@ -0,0 +1,11 @@
1
+ export interface BuildOptions {
2
+ release?: boolean;
3
+ output?: string;
4
+ target?: string;
5
+ skipFrontend?: boolean;
6
+ skipCodegen?: boolean;
7
+ }
8
+ /**
9
+ * Build for production
10
+ */
11
+ export declare function buildCommand(options: BuildOptions): Promise<void>;
@@ -0,0 +1,282 @@
1
+ import { execSync } from 'child_process';
2
+ import { join, resolve } from 'path';
3
+ import { existsSync, mkdirSync, copyFileSync, readdirSync, statSync, rmSync, writeFileSync } from 'fs';
4
+ import { cliLogger } from '../utils/logger.js';
5
+ /**
6
+ * Build for production
7
+ */
8
+ export async function buildCommand(options) {
9
+ const outputDir = resolve(options.output || './dist');
10
+ const startTime = Date.now();
11
+ try {
12
+ cliLogger.header('ZapJS Production Build');
13
+ // Step 1: Generate TypeScript bindings first (needed for type checking)
14
+ if (!options.skipCodegen) {
15
+ await runCodegen();
16
+ }
17
+ // Step 2: TypeScript type checking (optional but recommended)
18
+ await typeCheck();
19
+ // Clean output directory
20
+ if (existsSync(outputDir)) {
21
+ cliLogger.spinner('clean', 'Cleaning output directory...');
22
+ rmSync(outputDir, { recursive: true, force: true });
23
+ cliLogger.succeedSpinner('clean', 'Output directory cleaned');
24
+ }
25
+ // Step 3: Build frontend first (if not skipped)
26
+ // Vite will create the dist/ directory and populate it
27
+ let staticDir = null;
28
+ if (!options.skipFrontend) {
29
+ staticDir = await buildFrontend(outputDir);
30
+ }
31
+ // Step 4: Create bin directory and build Rust binary
32
+ // This happens AFTER frontend build so Vite doesn't overwrite it
33
+ mkdirSync(join(outputDir, 'bin'), { recursive: true });
34
+ await buildRust(outputDir, options);
35
+ // Step 5: Create production config
36
+ await createProductionConfig(outputDir, staticDir);
37
+ // Step 6: Create build manifest
38
+ const manifest = createBuildManifest(outputDir, staticDir);
39
+ writeFileSync(join(outputDir, 'manifest.json'), JSON.stringify(manifest, null, 2));
40
+ // Summary
41
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
42
+ const binSize = getBinarySize(join(outputDir, 'bin', 'zap'));
43
+ cliLogger.newline();
44
+ cliLogger.success(`Build complete in ${elapsed}s`);
45
+ cliLogger.newline();
46
+ cliLogger.keyValue('Directory', outputDir);
47
+ cliLogger.keyValue('Binary', binSize);
48
+ if (staticDir) {
49
+ cliLogger.keyValue('Static', join(outputDir, 'static'));
50
+ }
51
+ cliLogger.newline();
52
+ cliLogger.command(`cd ${outputDir} && ./bin/zap`, 'Run in production');
53
+ cliLogger.newline();
54
+ }
55
+ catch (error) {
56
+ if (error instanceof Error) {
57
+ cliLogger.error('Build failed', error);
58
+ }
59
+ process.exit(1);
60
+ }
61
+ }
62
+ async function buildRust(outputDir, options) {
63
+ cliLogger.spinner('rust', 'Building Rust backend (release mode)...');
64
+ const args = ['build', '--release', '--bin', 'zap'];
65
+ if (options.target) {
66
+ args.push('--target', options.target);
67
+ }
68
+ try {
69
+ execSync(`cargo ${args.join(' ')}`, {
70
+ cwd: process.cwd(),
71
+ stdio: 'inherit', // Show cargo output
72
+ });
73
+ const targetDir = options.target
74
+ ? join('target', options.target, 'release')
75
+ : join('target', 'release');
76
+ // Get the default Rust target for this platform
77
+ let defaultTarget = '';
78
+ try {
79
+ defaultTarget = execSync('rustc -vV | grep host | cut -d: -f2', {
80
+ stdio: 'pipe',
81
+ encoding: 'utf-8'
82
+ }).trim();
83
+ }
84
+ catch {
85
+ // Fallback targets based on platform
86
+ if (process.platform === 'darwin' && process.arch === 'arm64') {
87
+ defaultTarget = 'aarch64-apple-darwin';
88
+ }
89
+ else if (process.platform === 'darwin') {
90
+ defaultTarget = 'x86_64-apple-darwin';
91
+ }
92
+ else if (process.platform === 'linux') {
93
+ defaultTarget = 'x86_64-unknown-linux-gnu';
94
+ }
95
+ }
96
+ const platformTargetDir = defaultTarget
97
+ ? join('target', defaultTarget, 'release')
98
+ : targetDir;
99
+ // Try multiple locations for the binary (workspace vs local)
100
+ const possibleBinaryPaths = [
101
+ // Workspace target with platform-specific dir
102
+ join(process.cwd(), '..', platformTargetDir, 'zap'),
103
+ join(process.cwd(), '..', '..', platformTargetDir, 'zap'),
104
+ // Workspace target standard
105
+ join(process.cwd(), '..', targetDir, 'zap'),
106
+ join(process.cwd(), '..', '..', targetDir, 'zap'),
107
+ // Local target with platform-specific dir
108
+ join(process.cwd(), platformTargetDir, 'zap'),
109
+ // Local target standard
110
+ join(process.cwd(), targetDir, 'zap'),
111
+ ];
112
+ let srcBinary = null;
113
+ for (const path of possibleBinaryPaths) {
114
+ if (existsSync(path)) {
115
+ srcBinary = path;
116
+ break;
117
+ }
118
+ }
119
+ if (!srcBinary) {
120
+ throw new Error(`Binary not found. Checked:\n${possibleBinaryPaths.join('\n')}`);
121
+ }
122
+ const destBinary = join(outputDir, 'bin', 'zap');
123
+ copyFileSync(srcBinary, destBinary);
124
+ execSync(`chmod +x "${destBinary}"`, { stdio: 'pipe' });
125
+ cliLogger.succeedSpinner('rust', 'Rust backend built (release + LTO)');
126
+ }
127
+ catch (error) {
128
+ cliLogger.failSpinner('rust', 'Rust build failed');
129
+ throw error;
130
+ }
131
+ }
132
+ async function buildFrontend(outputDir) {
133
+ const viteConfig = ['vite.config.ts', 'vite.config.js', 'vite.config.mjs']
134
+ .find(f => existsSync(join(process.cwd(), f)));
135
+ if (!viteConfig) {
136
+ cliLogger.info('No Vite config found, skipping frontend build');
137
+ return null;
138
+ }
139
+ cliLogger.spinner('vite', 'Building frontend (Vite)...');
140
+ try {
141
+ // Build to a temporary directory to avoid conflicts
142
+ const tempDist = join(process.cwd(), '.dist-temp');
143
+ // Clean temp directory if it exists
144
+ if (existsSync(tempDist)) {
145
+ rmSync(tempDist, { recursive: true, force: true });
146
+ }
147
+ execSync(`npx vite build --outDir ${tempDist}`, {
148
+ cwd: process.cwd(),
149
+ stdio: 'pipe',
150
+ });
151
+ const staticDir = join(outputDir, 'static');
152
+ if (existsSync(tempDist)) {
153
+ copyDirectory(tempDist, staticDir);
154
+ // Clean up temp directory
155
+ rmSync(tempDist, { recursive: true, force: true });
156
+ cliLogger.succeedSpinner('vite', 'Frontend built and bundled');
157
+ return staticDir;
158
+ }
159
+ else {
160
+ cliLogger.warn('Vite build completed but no output found');
161
+ return null;
162
+ }
163
+ }
164
+ catch (error) {
165
+ cliLogger.failSpinner('vite', 'Frontend build failed');
166
+ cliLogger.warn('Continuing without frontend');
167
+ return null;
168
+ }
169
+ }
170
+ async function typeCheck() {
171
+ // Check if tsconfig exists
172
+ const tsconfigPath = join(process.cwd(), 'tsconfig.json');
173
+ if (!existsSync(tsconfigPath)) {
174
+ return; // Skip if no tsconfig
175
+ }
176
+ cliLogger.spinner('typecheck', 'Type checking TypeScript...');
177
+ try {
178
+ execSync('npx tsc --noEmit', {
179
+ cwd: process.cwd(),
180
+ stdio: 'pipe',
181
+ });
182
+ cliLogger.succeedSpinner('typecheck', 'TypeScript types OK');
183
+ }
184
+ catch (error) {
185
+ cliLogger.warn('TypeScript type check failed (continuing build)');
186
+ // Don't fail the build, just warn
187
+ }
188
+ }
189
+ async function runCodegen() {
190
+ const projectDir = process.cwd();
191
+ // Find codegen binary using same logic as codegen command
192
+ const possiblePaths = [
193
+ join(projectDir, 'bin', 'zap-codegen'),
194
+ join(projectDir, '../../target/release/zap-codegen'),
195
+ join(projectDir, '../../target/aarch64-apple-darwin/release/zap-codegen'),
196
+ join(projectDir, '../../target/x86_64-unknown-linux-gnu/release/zap-codegen'),
197
+ join(projectDir, 'target/release/zap-codegen'),
198
+ ];
199
+ let codegenBinary = null;
200
+ for (const path of possiblePaths) {
201
+ if (existsSync(path)) {
202
+ codegenBinary = path;
203
+ break;
204
+ }
205
+ }
206
+ // Try global zap-codegen as fallback
207
+ if (!codegenBinary) {
208
+ try {
209
+ execSync('which zap-codegen', { stdio: 'pipe' });
210
+ codegenBinary = 'zap-codegen';
211
+ }
212
+ catch {
213
+ cliLogger.info('Codegen skipped (binary not found)');
214
+ return;
215
+ }
216
+ }
217
+ cliLogger.spinner('codegen', 'Generating TypeScript bindings...');
218
+ try {
219
+ execSync(`"${codegenBinary}" --output-dir ./src/api`, {
220
+ cwd: process.cwd(),
221
+ stdio: 'pipe',
222
+ });
223
+ cliLogger.succeedSpinner('codegen', 'TypeScript bindings generated');
224
+ }
225
+ catch (error) {
226
+ cliLogger.warn('Codegen failed (continuing build)');
227
+ }
228
+ }
229
+ async function createProductionConfig(outputDir, staticDir) {
230
+ const config = {
231
+ server: {
232
+ host: '0.0.0.0',
233
+ port: 3000,
234
+ },
235
+ static: staticDir ? {
236
+ prefix: '/',
237
+ directory: './static',
238
+ } : null,
239
+ logging: {
240
+ level: 'info',
241
+ format: 'json',
242
+ },
243
+ };
244
+ writeFileSync(join(outputDir, 'config.json'), JSON.stringify(config, null, 2));
245
+ }
246
+ function createBuildManifest(outputDir, staticDir) {
247
+ return {
248
+ version: '1.0.0',
249
+ buildTime: new Date().toISOString(),
250
+ rustBinary: './bin/zap',
251
+ staticDir: staticDir ? './static' : null,
252
+ env: 'production',
253
+ };
254
+ }
255
+ function copyDirectory(src, dest) {
256
+ mkdirSync(dest, { recursive: true });
257
+ const entries = readdirSync(src, { withFileTypes: true });
258
+ for (const entry of entries) {
259
+ const srcPath = join(src, entry.name);
260
+ const destPath = join(dest, entry.name);
261
+ if (entry.isDirectory()) {
262
+ copyDirectory(srcPath, destPath);
263
+ }
264
+ else {
265
+ copyFileSync(srcPath, destPath);
266
+ }
267
+ }
268
+ }
269
+ function getBinarySize(path) {
270
+ try {
271
+ const stats = statSync(path);
272
+ const bytes = stats.size;
273
+ if (bytes < 1024)
274
+ return `${bytes} B`;
275
+ if (bytes < 1024 * 1024)
276
+ return `${(bytes / 1024).toFixed(1)} KB`;
277
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
278
+ }
279
+ catch {
280
+ return 'unknown';
281
+ }
282
+ }
@@ -0,0 +1,8 @@
1
+ export interface CodegenOptions {
2
+ input?: string;
3
+ output?: string;
4
+ }
5
+ /**
6
+ * Generate TypeScript bindings from Rust exports
7
+ */
8
+ export declare function codegenCommand(options: CodegenOptions): Promise<void>;