@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,286 @@
1
+ import { spawn } from 'child_process';
2
+ import { EventEmitter } from 'events';
3
+ import path from 'path';
4
+ import stripAnsi from 'strip-ansi';
5
+ /**
6
+ * RustBuilder - Manages Rust compilation with incremental builds
7
+ *
8
+ * Features:
9
+ * - Incremental compilation using cargo's built-in caching
10
+ * - Error parsing and structured output
11
+ * - Build queueing to prevent concurrent builds
12
+ * - Automatic binary detection
13
+ */
14
+ export class RustBuilder extends EventEmitter {
15
+ constructor(config) {
16
+ super();
17
+ this.currentBuild = null;
18
+ this.buildQueued = false;
19
+ this.status = 'idle';
20
+ this.lastBuildResult = null;
21
+ this.config = {
22
+ release: false,
23
+ ...config,
24
+ };
25
+ }
26
+ /**
27
+ * Get current build status
28
+ */
29
+ getStatus() {
30
+ return this.status;
31
+ }
32
+ /**
33
+ * Get last build result
34
+ */
35
+ getLastBuildResult() {
36
+ return this.lastBuildResult;
37
+ }
38
+ /**
39
+ * Trigger a build, queuing if one is in progress
40
+ */
41
+ async build() {
42
+ // If using pre-built binary, skip compilation
43
+ if (this.config.binaryPath) {
44
+ const { existsSync } = await import('fs');
45
+ if (existsSync(this.config.binaryPath)) {
46
+ this.status = 'success';
47
+ const result = {
48
+ success: true,
49
+ duration: 0,
50
+ errors: [],
51
+ warnings: [],
52
+ };
53
+ this.lastBuildResult = result;
54
+ this.emit('build-complete', result);
55
+ return result;
56
+ }
57
+ }
58
+ // If already building, queue another build
59
+ if (this.status === 'building') {
60
+ this.buildQueued = true;
61
+ return new Promise((resolve) => {
62
+ this.once('build-complete', resolve);
63
+ });
64
+ }
65
+ return this.runBuild();
66
+ }
67
+ /**
68
+ * Run the actual cargo build
69
+ */
70
+ async runBuild() {
71
+ const startTime = Date.now();
72
+ this.status = 'building';
73
+ this.emit('build-start');
74
+ const args = ['build'];
75
+ if (this.config.release) {
76
+ args.push('--release');
77
+ }
78
+ if (this.config.bin) {
79
+ args.push('--bin', this.config.bin);
80
+ }
81
+ if (this.config.target) {
82
+ args.push('--target', this.config.target);
83
+ }
84
+ if (this.config.features && this.config.features.length > 0) {
85
+ args.push('--features', this.config.features.join(','));
86
+ }
87
+ // Add message format for structured output
88
+ args.push('--message-format=json');
89
+ return new Promise((resolve) => {
90
+ const errors = [];
91
+ const warnings = [];
92
+ let stderr = '';
93
+ this.currentBuild = spawn('cargo', args, {
94
+ cwd: this.config.projectDir,
95
+ env: {
96
+ ...process.env,
97
+ CARGO_TERM_COLOR: 'always',
98
+ },
99
+ stdio: ['ignore', 'pipe', 'pipe'],
100
+ });
101
+ this.currentBuild.stdout?.on('data', (data) => {
102
+ const lines = data.toString().split('\n').filter(Boolean);
103
+ for (const line of lines) {
104
+ try {
105
+ const msg = JSON.parse(line);
106
+ if (msg.reason === 'compiler-message') {
107
+ const message = msg.message;
108
+ if (message.level === 'error') {
109
+ const formatted = this.formatCompilerMessage(message);
110
+ errors.push(formatted);
111
+ this.emit('error', formatted);
112
+ }
113
+ else if (message.level === 'warning') {
114
+ const formatted = this.formatCompilerMessage(message);
115
+ warnings.push(formatted);
116
+ this.emit('warning', formatted);
117
+ }
118
+ }
119
+ else if (msg.reason === 'build-finished') {
120
+ // Build finished message
121
+ }
122
+ else if (msg.reason === 'compiler-artifact') {
123
+ this.emit('artifact', msg.target?.name);
124
+ }
125
+ }
126
+ catch {
127
+ // Not JSON, might be regular output
128
+ this.emit('output', line);
129
+ }
130
+ }
131
+ });
132
+ this.currentBuild.stderr?.on('data', (data) => {
133
+ stderr += data.toString();
134
+ const clean = stripAnsi(data.toString()).trim();
135
+ if (clean) {
136
+ this.emit('stderr', clean);
137
+ }
138
+ });
139
+ this.currentBuild.on('close', (code) => {
140
+ const duration = Date.now() - startTime;
141
+ const success = code === 0;
142
+ this.status = success ? 'success' : 'failed';
143
+ this.currentBuild = null;
144
+ const result = {
145
+ success,
146
+ duration,
147
+ errors,
148
+ warnings,
149
+ };
150
+ this.lastBuildResult = result;
151
+ this.emit('build-complete', result);
152
+ // Process queued build if any
153
+ if (this.buildQueued) {
154
+ this.buildQueued = false;
155
+ setImmediate(() => this.runBuild());
156
+ }
157
+ resolve(result);
158
+ });
159
+ this.currentBuild.on('error', (err) => {
160
+ const duration = Date.now() - startTime;
161
+ this.status = 'failed';
162
+ this.currentBuild = null;
163
+ const result = {
164
+ success: false,
165
+ duration,
166
+ errors: [`Build process error: ${err.message}`],
167
+ warnings,
168
+ };
169
+ this.lastBuildResult = result;
170
+ this.emit('build-complete', result);
171
+ resolve(result);
172
+ });
173
+ });
174
+ }
175
+ /**
176
+ * Format a compiler message for display
177
+ */
178
+ formatCompilerMessage(message) {
179
+ const parts = [];
180
+ if (message.rendered) {
181
+ return stripAnsi(message.rendered);
182
+ }
183
+ // Fallback formatting
184
+ if (message.message) {
185
+ parts.push(message.message);
186
+ }
187
+ if (message.spans && message.spans.length > 0) {
188
+ const span = message.spans[0];
189
+ if (span.file_name && span.line_start) {
190
+ parts.push(` --> ${span.file_name}:${span.line_start}:${span.column_start}`);
191
+ }
192
+ }
193
+ return parts.join('\n');
194
+ }
195
+ /**
196
+ * Cancel current build if running
197
+ */
198
+ cancel() {
199
+ if (this.currentBuild && !this.currentBuild.killed) {
200
+ this.currentBuild.kill('SIGTERM');
201
+ this.status = 'idle';
202
+ }
203
+ this.buildQueued = false;
204
+ }
205
+ /**
206
+ * Check the project without building (faster)
207
+ */
208
+ async check() {
209
+ const startTime = Date.now();
210
+ this.status = 'building';
211
+ const args = ['check', '--message-format=json'];
212
+ if (this.config.bin) {
213
+ args.push('--bin', this.config.bin);
214
+ }
215
+ return new Promise((resolve) => {
216
+ const errors = [];
217
+ const warnings = [];
218
+ const proc = spawn('cargo', args, {
219
+ cwd: this.config.projectDir,
220
+ stdio: ['ignore', 'pipe', 'pipe'],
221
+ });
222
+ proc.stdout?.on('data', (data) => {
223
+ const lines = data.toString().split('\n').filter(Boolean);
224
+ for (const line of lines) {
225
+ try {
226
+ const msg = JSON.parse(line);
227
+ if (msg.reason === 'compiler-message') {
228
+ const message = msg.message;
229
+ if (message.level === 'error') {
230
+ errors.push(this.formatCompilerMessage(message));
231
+ }
232
+ else if (message.level === 'warning') {
233
+ warnings.push(this.formatCompilerMessage(message));
234
+ }
235
+ }
236
+ }
237
+ catch {
238
+ // Ignore non-JSON lines
239
+ }
240
+ }
241
+ });
242
+ proc.on('close', (code) => {
243
+ const duration = Date.now() - startTime;
244
+ this.status = code === 0 ? 'success' : 'failed';
245
+ resolve({
246
+ success: code === 0,
247
+ duration,
248
+ errors,
249
+ warnings,
250
+ });
251
+ });
252
+ });
253
+ }
254
+ /**
255
+ * Get the path to the built binary
256
+ */
257
+ getBinaryPath() {
258
+ // Return pre-built binary path if configured
259
+ if (this.config.binaryPath) {
260
+ return this.config.binaryPath;
261
+ }
262
+ const { existsSync } = require('fs');
263
+ const binName = this.config.bin || 'zap';
264
+ // Determine architecture-specific target directory
265
+ const arch = process.arch === 'arm64' ? 'aarch64-apple-darwin' : `${process.arch}-${process.platform}`;
266
+ // Check multiple candidate paths in order of preference
267
+ const candidates = [];
268
+ // If target is explicitly configured, try it first
269
+ if (this.config.target) {
270
+ candidates.push(path.join(this.config.projectDir, 'target', this.config.target, 'release', binName), path.join(this.config.projectDir, 'target', this.config.target, 'debug', binName));
271
+ }
272
+ // Try architecture-specific paths
273
+ candidates.push(path.join(this.config.projectDir, 'target', arch, 'release', binName), path.join(this.config.projectDir, 'target', arch, 'debug', binName));
274
+ // Try standard release/debug paths
275
+ candidates.push(path.join(this.config.projectDir, 'target', 'release', binName), path.join(this.config.projectDir, 'target', 'debug', binName));
276
+ // Return first existing binary
277
+ for (const candidate of candidates) {
278
+ if (existsSync(candidate)) {
279
+ return candidate;
280
+ }
281
+ }
282
+ // Fallback to expected path based on config (will fail if doesn't exist)
283
+ const targetDir = this.config.release ? 'release' : 'debug';
284
+ return path.join(this.config.projectDir, 'target', targetDir, binName);
285
+ }
286
+ }
@@ -0,0 +1,147 @@
1
+ import { EventEmitter } from 'events';
2
+ export interface DevServerConfig {
3
+ projectDir: string;
4
+ rustPort?: number;
5
+ vitePort?: number;
6
+ hotReloadPort?: number;
7
+ logLevel?: 'debug' | 'info' | 'warn' | 'error';
8
+ release?: boolean;
9
+ skipInitialBuild?: boolean;
10
+ openBrowser?: boolean;
11
+ /** Path to pre-built zap binary (skips Rust compilation) */
12
+ binaryPath?: string;
13
+ /** Path to pre-built zap-codegen binary */
14
+ codegenBinaryPath?: string;
15
+ }
16
+ interface ServerState {
17
+ phase: 'starting' | 'building' | 'ready' | 'rebuilding' | 'error' | 'stopped';
18
+ rustReady: boolean;
19
+ viteReady: boolean;
20
+ lastError: string | null;
21
+ }
22
+ /**
23
+ * DevServer - Unified development server orchestrator
24
+ *
25
+ * Coordinates all development components:
26
+ * - Rust backend compilation with file watching
27
+ * - Vite frontend dev server
28
+ * - Automatic TypeScript binding generation
29
+ * - Hot reload signaling
30
+ *
31
+ * Workflow:
32
+ * 1. Initial build of Rust backend
33
+ * 2. Generate TypeScript bindings
34
+ * 3. Start Vite dev server
35
+ * 4. Start hot reload WebSocket server
36
+ * 5. Watch for file changes and orchestrate rebuilds
37
+ */
38
+ export declare class DevServer extends EventEmitter {
39
+ private config;
40
+ private state;
41
+ private watcher;
42
+ private rustBuilder;
43
+ private viteProxy;
44
+ private codegenRunner;
45
+ private hotReloadServer;
46
+ private routeScanner;
47
+ private processManager;
48
+ private ipcServer;
49
+ private socketPath;
50
+ private currentRouteTree;
51
+ private registeredHandlers;
52
+ private startTime;
53
+ constructor(config: DevServerConfig);
54
+ /**
55
+ * Set up event handlers for all components
56
+ */
57
+ private setupEventHandlers;
58
+ /**
59
+ * Start the development server
60
+ */
61
+ start(): Promise<void>;
62
+ /**
63
+ * Stop all servers immediately
64
+ */
65
+ stop(): Promise<void>;
66
+ /**
67
+ * Build Rust backend
68
+ */
69
+ private buildRust;
70
+ /**
71
+ * Run codegen to generate TypeScript bindings
72
+ */
73
+ private runCodegen;
74
+ /**
75
+ * Scan routes directory and generate route tree
76
+ */
77
+ private scanRoutes;
78
+ /**
79
+ * Start the Rust HTTP server with IPC for TypeScript handlers
80
+ */
81
+ private startRustServer;
82
+ /**
83
+ * Load TypeScript route handlers and register them with IPC server
84
+ */
85
+ private loadRouteHandlers;
86
+ /**
87
+ * Format handler result into IPC response
88
+ */
89
+ private formatHandlerResponse;
90
+ /**
91
+ * Build Rust server configuration from routes
92
+ */
93
+ private buildRustConfig;
94
+ /**
95
+ * Restart Rust server (called when routes change)
96
+ */
97
+ private restartRustServer;
98
+ /**
99
+ * Start the route file watcher
100
+ */
101
+ private startRouteWatcher;
102
+ /**
103
+ * Start the hot reload WebSocket server
104
+ */
105
+ private startHotReloadServer;
106
+ /**
107
+ * Start the Vite dev server
108
+ */
109
+ private startViteServer;
110
+ /**
111
+ * Start the file watcher
112
+ */
113
+ private startWatcher;
114
+ /**
115
+ * Handle Rust file changes
116
+ */
117
+ private handleRustChange;
118
+ /**
119
+ * Handle TypeScript file changes
120
+ */
121
+ private handleTypeScriptChange;
122
+ /**
123
+ * Handle config file changes
124
+ */
125
+ private handleConfigChange;
126
+ /**
127
+ * Print the ready message
128
+ */
129
+ private printReadyMessage;
130
+ /**
131
+ * Set up keyboard input handling
132
+ */
133
+ private setupKeyboardInput;
134
+ /**
135
+ * Open the browser
136
+ */
137
+ private openBrowser;
138
+ /**
139
+ * Log a message with the appropriate level
140
+ */
141
+ private log;
142
+ /**
143
+ * Get current server state
144
+ */
145
+ getState(): ServerState;
146
+ }
147
+ export {};