@gcoredev/fastedge-test 0.0.1-beta.4 → 0.1.0-beta.3
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.
- package/README.md +6 -6
- package/dist/fastedge-cli/METADATA.json +1 -3
- package/dist/fastedge-cli/{fastedge-run-linux-x64-unkown → fastedge-run-darwin-arm64} +0 -0
- package/dist/fastedge-cli/fastedge-run-linux-x64 +0 -0
- package/dist/fastedge-cli/fastedge-run.exe +0 -0
- package/dist/frontend/assets/index-CEFjsU8e.js +35 -0
- package/dist/frontend/assets/index-DdlINQc_.css +1 -0
- package/dist/frontend/index.html +2 -2
- package/dist/lib/index.cjs +299 -107
- package/dist/lib/index.js +301 -110
- package/dist/lib/runner/HostFunctions.d.ts +8 -0
- package/dist/lib/runner/HttpWasmRunner.d.ts +34 -14
- package/dist/lib/runner/IStateManager.d.ts +3 -2
- package/dist/lib/runner/IWasmRunner.d.ts +16 -1
- package/dist/lib/runner/NullStateManager.d.ts +1 -0
- package/dist/lib/runner/PortManager.d.ts +17 -19
- package/dist/lib/runner/ProxyWasmRunner.d.ts +7 -0
- package/dist/lib/schemas/api.d.ts +8 -2
- package/dist/lib/schemas/config.d.ts +4 -1
- package/dist/lib/test-framework/index.cjs +301 -108
- package/dist/lib/test-framework/index.js +303 -111
- package/dist/lib/test-framework/suite-runner.d.ts +1 -1
- package/dist/server.js +30 -29
- package/docs/API.md +758 -360
- package/docs/DEBUGGER.md +151 -0
- package/docs/INDEX.md +111 -0
- package/docs/RUNNER.md +582 -0
- package/docs/TEST_CONFIG.md +242 -0
- package/docs/TEST_FRAMEWORK.md +384 -284
- package/docs/WEBSOCKET.md +499 -0
- package/docs/quickstart.md +171 -0
- package/llms.txt +72 -14
- package/package.json +15 -5
- package/schemas/api-config.schema.json +12 -5
- package/schemas/api-load.schema.json +11 -6
- package/schemas/{test-config.schema.json → fastedge-config.test.schema.json} +12 -5
- package/dist/fastedge-cli/.gitkeep +0 -0
- package/dist/frontend/assets/index-CnXStFTd.css +0 -1
- package/dist/frontend/assets/index-FR9Oqsow.js +0 -37
- package/docs/HYBRID_LOADING.md +0 -546
- package/docs/LOCAL_SERVER.md +0 -153
package/docs/HYBRID_LOADING.md
DELETED
|
@@ -1,546 +0,0 @@
|
|
|
1
|
-
# Hybrid WASM Loading: Path vs Buffer
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
FastEdge-debugger now supports **two modes** for loading WASM binaries:
|
|
6
|
-
|
|
7
|
-
1. **Path-based loading** (new, optimized) - Provide a file path
|
|
8
|
-
2. **Buffer-based loading** (legacy, backward compatible) - Provide binary data
|
|
9
|
-
|
|
10
|
-
This hybrid approach provides **significant performance improvements** for local development while maintaining compatibility with remote/browser scenarios.
|
|
11
|
-
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
## Performance Impact
|
|
15
|
-
|
|
16
|
-
### For 12MB WASM File
|
|
17
|
-
|
|
18
|
-
| Metric | Buffer Mode | Path Mode | Improvement |
|
|
19
|
-
|--------|-------------|-----------|-------------|
|
|
20
|
-
| **Startup Time** | 1.45-3.9s | <1ms | **70-95% faster** |
|
|
21
|
-
| **Network Transfer** | 16MB (base64) | ~100 bytes | **99.999% less** |
|
|
22
|
-
| **Memory Usage** | 48-60MB (4 copies) | 12MB (1 copy) | **75-80% less** |
|
|
23
|
-
|
|
24
|
-
### Why Path Mode is Faster
|
|
25
|
-
|
|
26
|
-
**Buffer Mode (Legacy)**:
|
|
27
|
-
```
|
|
28
|
-
File (12MB) → Read → ArrayBuffer → base64 encode (16MB) →
|
|
29
|
-
JSON POST → Network → base64 decode → Buffer →
|
|
30
|
-
Write temp file → Spawn process
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
**Path Mode (Optimized)**:
|
|
34
|
-
```
|
|
35
|
-
Path string (~50 bytes) → JSON POST →
|
|
36
|
-
Network → Validate path → Spawn process
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
**Result**: Eliminates ~72MB of data movement!
|
|
40
|
-
|
|
41
|
-
---
|
|
42
|
-
|
|
43
|
-
## API Changes
|
|
44
|
-
|
|
45
|
-
### POST /api/load
|
|
46
|
-
|
|
47
|
-
#### New Parameters
|
|
48
|
-
|
|
49
|
-
```typescript
|
|
50
|
-
interface LoadRequest {
|
|
51
|
-
// Option 1: Path-based (preferred)
|
|
52
|
-
wasmPath?: string;
|
|
53
|
-
|
|
54
|
-
// Option 2: Buffer-based (fallback)
|
|
55
|
-
wasmBase64?: string;
|
|
56
|
-
|
|
57
|
-
// Common options
|
|
58
|
-
dotenvEnabled?: boolean;
|
|
59
|
-
}
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
#### Example: Path-based Loading
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
curl -X POST http://localhost:5179/api/load \
|
|
66
|
-
-H "Content-Type: application/json" \
|
|
67
|
-
-d '{
|
|
68
|
-
"wasmPath": "/workspace/target/wasm32-wasi/release/app.wasm",
|
|
69
|
-
"dotenvEnabled": true
|
|
70
|
-
}'
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
#### Example: Buffer-based Loading (Legacy)
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
# Read WASM file and encode to base64
|
|
77
|
-
WASM_BASE64=$(base64 -w 0 app.wasm)
|
|
78
|
-
|
|
79
|
-
curl -X POST http://localhost:5179/api/load \
|
|
80
|
-
-H "Content-Type: application/json" \
|
|
81
|
-
-d "{
|
|
82
|
-
\"wasmBase64\": \"$WASM_BASE64\",
|
|
83
|
-
\"dotenvEnabled\": true
|
|
84
|
-
}"
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
#### Response (Same for Both)
|
|
88
|
-
|
|
89
|
-
```json
|
|
90
|
-
{
|
|
91
|
-
"ok": true,
|
|
92
|
-
"wasmType": "http-wasm"
|
|
93
|
-
}
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
---
|
|
97
|
-
|
|
98
|
-
## Runner Interface Changes
|
|
99
|
-
|
|
100
|
-
### IWasmRunner.load()
|
|
101
|
-
|
|
102
|
-
**Before**:
|
|
103
|
-
```typescript
|
|
104
|
-
load(buffer: Buffer, config?: RunnerConfig): Promise<void>
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
**After**:
|
|
108
|
-
```typescript
|
|
109
|
-
load(bufferOrPath: Buffer | string, config?: RunnerConfig): Promise<void>
|
|
110
|
-
```
|
|
111
|
-
|
|
112
|
-
### Usage Examples
|
|
113
|
-
|
|
114
|
-
#### HTTP WASM Runner
|
|
115
|
-
|
|
116
|
-
```typescript
|
|
117
|
-
import { HttpWasmRunner } from './runner/HttpWasmRunner';
|
|
118
|
-
import { PortManager } from './runner/PortManager';
|
|
119
|
-
|
|
120
|
-
const portManager = new PortManager();
|
|
121
|
-
const runner = new HttpWasmRunner(portManager, true);
|
|
122
|
-
|
|
123
|
-
// Path-based loading (optimized)
|
|
124
|
-
await runner.load('/path/to/app.wasm');
|
|
125
|
-
|
|
126
|
-
// OR Buffer-based loading (legacy)
|
|
127
|
-
const buffer = await fs.readFile('/path/to/app.wasm');
|
|
128
|
-
await runner.load(buffer);
|
|
129
|
-
|
|
130
|
-
// Execute request (same for both)
|
|
131
|
-
const response = await runner.execute({
|
|
132
|
-
path: '/',
|
|
133
|
-
method: 'GET',
|
|
134
|
-
headers: {},
|
|
135
|
-
body: '',
|
|
136
|
-
});
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
#### Proxy WASM Runner
|
|
140
|
-
|
|
141
|
-
```typescript
|
|
142
|
-
import { ProxyWasmRunner } from './runner/ProxyWasmRunner';
|
|
143
|
-
|
|
144
|
-
const runner = new ProxyWasmRunner();
|
|
145
|
-
|
|
146
|
-
// Path-based loading
|
|
147
|
-
await runner.load('/path/to/filter.wasm');
|
|
148
|
-
|
|
149
|
-
// OR Buffer-based loading
|
|
150
|
-
const buffer = await fs.readFile('/path/to/filter.wasm');
|
|
151
|
-
await runner.load(buffer);
|
|
152
|
-
|
|
153
|
-
// Call hook (same for both)
|
|
154
|
-
const result = await runner.callHook({
|
|
155
|
-
hook: 'onRequestHeaders',
|
|
156
|
-
request: { headers: {}, body: '' },
|
|
157
|
-
response: { headers: {}, body: '' },
|
|
158
|
-
properties: {},
|
|
159
|
-
});
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
---
|
|
163
|
-
|
|
164
|
-
## Security
|
|
165
|
-
|
|
166
|
-
### Path Validation
|
|
167
|
-
|
|
168
|
-
All file paths are validated for security:
|
|
169
|
-
|
|
170
|
-
```typescript
|
|
171
|
-
import { validatePath, isPathSafe } from './utils/pathValidator';
|
|
172
|
-
|
|
173
|
-
// Validate with options
|
|
174
|
-
const result = validatePath(inputPath, {
|
|
175
|
-
workspaceRoot: '/workspace', // Restrict to workspace
|
|
176
|
-
requireWasmExtension: true, // Must end in .wasm
|
|
177
|
-
checkExists: true, // File must exist
|
|
178
|
-
allowAbsolute: true, // Allow absolute paths
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
if (!result.valid) {
|
|
182
|
-
throw new Error(result.error);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
// Use normalized path
|
|
186
|
-
const safePath = result.normalizedPath;
|
|
187
|
-
```
|
|
188
|
-
|
|
189
|
-
### Blocked Paths
|
|
190
|
-
|
|
191
|
-
The following paths are automatically blocked:
|
|
192
|
-
|
|
193
|
-
- `/etc`, `/sys`, `/proc`, `/dev`, `/boot`, `/root` (Unix)
|
|
194
|
-
- `C:\Windows`, `C:\Program Files` (Windows)
|
|
195
|
-
- `.ssh`, `.aws`, `.kube` (credentials)
|
|
196
|
-
- `node_modules` (large directories)
|
|
197
|
-
|
|
198
|
-
### Path Traversal Prevention
|
|
199
|
-
|
|
200
|
-
```typescript
|
|
201
|
-
// These are BLOCKED
|
|
202
|
-
validatePath('../../../etc/passwd'); // Escapes workspace
|
|
203
|
-
validatePath('/etc/passwd'); // System path
|
|
204
|
-
validatePath('~/.ssh/id_rsa'); // Credentials
|
|
205
|
-
|
|
206
|
-
// These are ALLOWED (if file exists)
|
|
207
|
-
validatePath('/workspace/app.wasm'); // Within workspace
|
|
208
|
-
validatePath('./target/wasm32-wasi/app.wasm'); // Relative path
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
---
|
|
212
|
-
|
|
213
|
-
## Use Cases
|
|
214
|
-
|
|
215
|
-
### ✅ Best for Path-Based Loading
|
|
216
|
-
|
|
217
|
-
1. **VSCode Extension**
|
|
218
|
-
- Workspace files are locally accessible
|
|
219
|
-
- ~3s faster startup for 12MB WASM
|
|
220
|
-
- No memory overhead
|
|
221
|
-
|
|
222
|
-
2. **GitHub Codespaces**
|
|
223
|
-
- Files are local to container
|
|
224
|
-
- Same performance benefits
|
|
225
|
-
- Works seamlessly
|
|
226
|
-
|
|
227
|
-
3. **Local Development**
|
|
228
|
-
- Developer's machine
|
|
229
|
-
- Fast iteration cycles
|
|
230
|
-
- Minimal resource usage
|
|
231
|
-
|
|
232
|
-
4. **AI Agents (MCP/Claude)**
|
|
233
|
-
- AI knows file paths
|
|
234
|
-
- No need to read files
|
|
235
|
-
- Simple integration
|
|
236
|
-
|
|
237
|
-
5. **CLI Tools**
|
|
238
|
-
- Direct path passing
|
|
239
|
-
- Standard Unix convention
|
|
240
|
-
- Simple UX
|
|
241
|
-
|
|
242
|
-
### ❌ Requires Buffer-Based Loading
|
|
243
|
-
|
|
244
|
-
1. **Web UI (Browser Only)**
|
|
245
|
-
- No filesystem access
|
|
246
|
-
- Must use File API
|
|
247
|
-
- Falls back to buffer
|
|
248
|
-
|
|
249
|
-
2. **Remote Debugger**
|
|
250
|
-
- Frontend ≠ backend machine
|
|
251
|
-
- File doesn't exist remotely
|
|
252
|
-
- Must transfer content
|
|
253
|
-
|
|
254
|
-
3. **In-Memory WASM Generation**
|
|
255
|
-
- Compiler generates WASM
|
|
256
|
-
- No file on disk
|
|
257
|
-
- Must use buffer
|
|
258
|
-
|
|
259
|
-
---
|
|
260
|
-
|
|
261
|
-
## VSCode Extension Integration
|
|
262
|
-
|
|
263
|
-
### Detection Logic
|
|
264
|
-
|
|
265
|
-
```typescript
|
|
266
|
-
// Detect if running in VSCode
|
|
267
|
-
const isVSCodeExtension = window.vscodeApi !== undefined;
|
|
268
|
-
|
|
269
|
-
export async function uploadWasm(
|
|
270
|
-
file: File,
|
|
271
|
-
dotenvEnabled: boolean = true,
|
|
272
|
-
): Promise<{ path: string; wasmType: WasmType }> {
|
|
273
|
-
|
|
274
|
-
// Use path-based loading in VSCode
|
|
275
|
-
if (isVSCodeExtension && file.path) {
|
|
276
|
-
return await fetch(`${API_BASE}/load`, {
|
|
277
|
-
method: 'POST',
|
|
278
|
-
headers: { 'Content-Type': 'application/json' },
|
|
279
|
-
body: JSON.stringify({
|
|
280
|
-
wasmPath: file.path,
|
|
281
|
-
dotenvEnabled
|
|
282
|
-
}),
|
|
283
|
-
}).then(r => r.json());
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
// Fallback to buffer-based loading
|
|
287
|
-
const buffer = await file.arrayBuffer();
|
|
288
|
-
const base64 = btoa(
|
|
289
|
-
new Uint8Array(buffer).reduce(
|
|
290
|
-
(data, byte) => data + String.fromCharCode(byte),
|
|
291
|
-
'',
|
|
292
|
-
),
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
return await fetch(`${API_BASE}/load`, {
|
|
296
|
-
method: 'POST',
|
|
297
|
-
headers: { 'Content-Type': 'application/json' },
|
|
298
|
-
body: JSON.stringify({ wasmBase64: base64, dotenvEnabled }),
|
|
299
|
-
}).then(r => r.json());
|
|
300
|
-
}
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
### No File Access Limitations
|
|
304
|
-
|
|
305
|
-
- VSCode extension runs in Node.js environment
|
|
306
|
-
- Full filesystem access to workspace
|
|
307
|
-
- Cross-platform path handling (Windows/Unix)
|
|
308
|
-
- Symlinks handled automatically
|
|
309
|
-
|
|
310
|
-
---
|
|
311
|
-
|
|
312
|
-
## Implementation Details
|
|
313
|
-
|
|
314
|
-
### HTTP WASM Runner
|
|
315
|
-
|
|
316
|
-
**Key Optimization**: Skip temp file creation
|
|
317
|
-
|
|
318
|
-
```typescript
|
|
319
|
-
async load(bufferOrPath: Buffer | string, config?: RunnerConfig): Promise<void> {
|
|
320
|
-
let wasmPath: string;
|
|
321
|
-
|
|
322
|
-
if (typeof bufferOrPath === 'string') {
|
|
323
|
-
// Path provided - use directly (no temp file!)
|
|
324
|
-
wasmPath = bufferOrPath;
|
|
325
|
-
this.tempWasmPath = null; // Don't cleanup
|
|
326
|
-
} else {
|
|
327
|
-
// Buffer provided - write to temp file
|
|
328
|
-
wasmPath = await writeTempWasmFile(bufferOrPath);
|
|
329
|
-
this.tempWasmPath = wasmPath; // Cleanup later
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
// Spawn process with path
|
|
333
|
-
this.process = spawn(this.cliPath, [
|
|
334
|
-
'http',
|
|
335
|
-
'-p', this.port.toString(),
|
|
336
|
-
'-w', wasmPath,
|
|
337
|
-
'--wasi-http', 'true',
|
|
338
|
-
]);
|
|
339
|
-
}
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
### Proxy WASM Runner
|
|
343
|
-
|
|
344
|
-
**Key Optimization**: Read once, compile once
|
|
345
|
-
|
|
346
|
-
```typescript
|
|
347
|
-
async load(bufferOrPath: Buffer | string, config?: RunnerConfig): Promise<void> {
|
|
348
|
-
let buffer: Buffer;
|
|
349
|
-
|
|
350
|
-
if (typeof bufferOrPath === 'string') {
|
|
351
|
-
// Path provided - read file
|
|
352
|
-
buffer = await readFile(bufferOrPath);
|
|
353
|
-
} else {
|
|
354
|
-
// Buffer provided - use directly
|
|
355
|
-
buffer = bufferOrPath;
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
// Compile once and reuse
|
|
359
|
-
this.module = await WebAssembly.compile(new Uint8Array(buffer));
|
|
360
|
-
}
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
---
|
|
364
|
-
|
|
365
|
-
## Testing
|
|
366
|
-
|
|
367
|
-
### Running Tests
|
|
368
|
-
|
|
369
|
-
```bash
|
|
370
|
-
# Path validator tests (unit)
|
|
371
|
-
pnpm test pathValidator
|
|
372
|
-
|
|
373
|
-
# Hybrid loading tests (integration)
|
|
374
|
-
pnpm test hybrid-loading
|
|
375
|
-
|
|
376
|
-
# All tests
|
|
377
|
-
pnpm test
|
|
378
|
-
```
|
|
379
|
-
|
|
380
|
-
### Test Coverage
|
|
381
|
-
|
|
382
|
-
**Path Validator** (22 tests):
|
|
383
|
-
- ✅ Valid path validation
|
|
384
|
-
- ✅ Path normalization (../, ./)
|
|
385
|
-
- ✅ Workspace root restriction
|
|
386
|
-
- ✅ Path traversal prevention
|
|
387
|
-
- ✅ Dangerous path blocking
|
|
388
|
-
- ✅ Extension validation
|
|
389
|
-
- ✅ Existence checking
|
|
390
|
-
- ✅ Absolute/relative paths
|
|
391
|
-
|
|
392
|
-
**Hybrid Loading** (15 tests):
|
|
393
|
-
- ✅ HTTP WASM: buffer vs path modes
|
|
394
|
-
- ✅ Proxy WASM: buffer vs path modes
|
|
395
|
-
- ✅ Identical execution results
|
|
396
|
-
- ✅ Error handling
|
|
397
|
-
- ✅ Performance characteristics
|
|
398
|
-
- ✅ Memory management
|
|
399
|
-
|
|
400
|
-
---
|
|
401
|
-
|
|
402
|
-
## Migration Guide
|
|
403
|
-
|
|
404
|
-
### Frontend Changes
|
|
405
|
-
|
|
406
|
-
**Before**:
|
|
407
|
-
```typescript
|
|
408
|
-
const buffer = await file.arrayBuffer();
|
|
409
|
-
const base64 = btoa(/* ... */);
|
|
410
|
-
|
|
411
|
-
await fetch('/api/load', {
|
|
412
|
-
body: JSON.stringify({ wasmBase64: base64 })
|
|
413
|
-
});
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
**After (with path support)**:
|
|
417
|
-
```typescript
|
|
418
|
-
// Try path first (if available)
|
|
419
|
-
if (file.path) {
|
|
420
|
-
await fetch('/api/load', {
|
|
421
|
-
body: JSON.stringify({ wasmPath: file.path })
|
|
422
|
-
});
|
|
423
|
-
} else {
|
|
424
|
-
// Fallback to buffer
|
|
425
|
-
const buffer = await file.arrayBuffer();
|
|
426
|
-
const base64 = btoa(/* ... */);
|
|
427
|
-
await fetch('/api/load', {
|
|
428
|
-
body: JSON.stringify({ wasmBase64: base64 })
|
|
429
|
-
});
|
|
430
|
-
}
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
### Backend Changes
|
|
434
|
-
|
|
435
|
-
**No changes required!** Backward compatible.
|
|
436
|
-
|
|
437
|
-
Existing code using `runner.load(buffer)` continues to work.
|
|
438
|
-
|
|
439
|
-
---
|
|
440
|
-
|
|
441
|
-
## Troubleshooting
|
|
442
|
-
|
|
443
|
-
### "File not found" Error
|
|
444
|
-
|
|
445
|
-
```typescript
|
|
446
|
-
// Error: File not found: /path/to/app.wasm
|
|
447
|
-
|
|
448
|
-
// Fix: Ensure file exists
|
|
449
|
-
fs.existsSync('/path/to/app.wasm'); // Should be true
|
|
450
|
-
|
|
451
|
-
// Fix: Use absolute path
|
|
452
|
-
const absolutePath = path.resolve('./app.wasm');
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
### "Invalid path" Error
|
|
456
|
-
|
|
457
|
-
```typescript
|
|
458
|
-
// Error: Invalid path
|
|
459
|
-
|
|
460
|
-
// Fix: Ensure .wasm extension
|
|
461
|
-
'/path/to/app.wasm' // ✅ Good
|
|
462
|
-
'/path/to/app.wat' // ❌ Bad
|
|
463
|
-
|
|
464
|
-
// Fix: Stay within workspace
|
|
465
|
-
'/workspace/app.wasm' // ✅ Good
|
|
466
|
-
'/../../../etc/passwd' // ❌ Bad
|
|
467
|
-
```
|
|
468
|
-
|
|
469
|
-
### "Access to system path not allowed"
|
|
470
|
-
|
|
471
|
-
```typescript
|
|
472
|
-
// Error: Access to system path '/etc' is not allowed
|
|
473
|
-
|
|
474
|
-
// Fix: Don't access system paths
|
|
475
|
-
'/workspace/app.wasm' // ✅ Good
|
|
476
|
-
'/etc/passwd' // ❌ Bad
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
---
|
|
480
|
-
|
|
481
|
-
## Future Enhancements
|
|
482
|
-
|
|
483
|
-
### Phase 2: Frontend Path Detection
|
|
484
|
-
- [ ] Detect VSCode extension context
|
|
485
|
-
- [ ] Extract file path from File object
|
|
486
|
-
- [ ] Auto-select path vs buffer mode
|
|
487
|
-
- [ ] Update UI to show loading mode
|
|
488
|
-
|
|
489
|
-
### Phase 3: Monitoring
|
|
490
|
-
- [ ] Add telemetry for path vs buffer usage
|
|
491
|
-
- [ ] Track startup time metrics
|
|
492
|
-
- [ ] Measure memory usage
|
|
493
|
-
- [ ] Analyze error rates
|
|
494
|
-
|
|
495
|
-
### Phase 4: File Watching
|
|
496
|
-
- [ ] Watch WASM file for changes
|
|
497
|
-
- [ ] Auto-reload on file modification
|
|
498
|
-
- [ ] Hot-reload during development
|
|
499
|
-
- [ ] WebSocket notification to clients
|
|
500
|
-
|
|
501
|
-
---
|
|
502
|
-
|
|
503
|
-
## Changelog
|
|
504
|
-
|
|
505
|
-
### 2026-02-11 - Phase 1: Hybrid Loading (Backward Compatible)
|
|
506
|
-
|
|
507
|
-
**Added**:
|
|
508
|
-
- Path validation utility (`utils/pathValidator.ts`)
|
|
509
|
-
- `wasmPath` parameter to `/api/load` endpoint
|
|
510
|
-
- Support for `Buffer | string` in runner `load()` methods
|
|
511
|
-
- Security checks for path traversal and dangerous paths
|
|
512
|
-
- Comprehensive test suite (37 tests)
|
|
513
|
-
|
|
514
|
-
**Changed**:
|
|
515
|
-
- `IWasmRunner.load()` signature to accept `Buffer | string`
|
|
516
|
-
- HTTP WASM runner skips temp file when path provided
|
|
517
|
-
- Proxy WASM runner reads from path when provided
|
|
518
|
-
- WASM type detector accepts `Buffer | string`
|
|
519
|
-
|
|
520
|
-
**Performance**:
|
|
521
|
-
- 70-95% faster startup for large WASMs
|
|
522
|
-
- 75-80% less memory usage
|
|
523
|
-
- 99.999% less network bandwidth
|
|
524
|
-
|
|
525
|
-
**Backward Compatibility**:
|
|
526
|
-
- ✅ All existing code continues to work
|
|
527
|
-
- ✅ Buffer-based loading fully supported
|
|
528
|
-
- ✅ No breaking changes to API
|
|
529
|
-
|
|
530
|
-
---
|
|
531
|
-
|
|
532
|
-
## Summary
|
|
533
|
-
|
|
534
|
-
The hybrid loading approach provides:
|
|
535
|
-
|
|
536
|
-
✅ **Massive performance improvements** for local development
|
|
537
|
-
✅ **Full backward compatibility** with existing code
|
|
538
|
-
✅ **Robust security** with path validation
|
|
539
|
-
✅ **Flexibility** to choose the right mode for each scenario
|
|
540
|
-
✅ **Future-proof** architecture for enhancements
|
|
541
|
-
|
|
542
|
-
**When to use**:
|
|
543
|
-
- **Path mode**: VSCode, Codespaces, local dev, CLI tools (99% of cases)
|
|
544
|
-
- **Buffer mode**: Web UI, remote debugging, in-memory WASM (1% of cases)
|
|
545
|
-
|
|
546
|
-
**Result**: Faster, more efficient debugger that scales to large WASM binaries!
|
package/docs/LOCAL_SERVER.md
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
# Local Debugger Server
|
|
2
|
-
|
|
3
|
-
The `@gcoredev/fastedge-test` package includes a full visual debugger server — an Express-based HTTP server with a React UI, REST API, and WebSocket log streaming. This is the same server embedded in the [FastEdge VSCode extension](https://marketplace.visualstudio.com/items?itemName=Gcore.fastedge).
|
|
4
|
-
|
|
5
|
-
Use it when you want an interactive local environment to load WASM binaries and test them via a browser UI — without needing VSCode.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## Running the Server
|
|
10
|
-
|
|
11
|
-
### Via npx (no install required)
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npx @gcoredev/fastedge-test
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
Opens the debugger at `http://localhost:5179`.
|
|
18
|
-
|
|
19
|
-
### Global install
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npm install -g @gcoredev/fastedge-test
|
|
23
|
-
fastedge-debug
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Custom port
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
PORT=8080 npx @gcoredev/fastedge-test
|
|
30
|
-
# Opens at http://localhost:8080
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
---
|
|
34
|
-
|
|
35
|
-
## What You Get
|
|
36
|
-
|
|
37
|
-
Once running, open `http://localhost:5179` in your browser:
|
|
38
|
-
|
|
39
|
-
- **Load a WASM binary** — drag-and-drop or select from disk
|
|
40
|
-
- **Send test requests** — configure URL, method, headers, body
|
|
41
|
-
- **Inspect results** — view response, modified headers, hook return codes
|
|
42
|
-
- **Real-time logs** — streamed via WebSocket as your WASM executes
|
|
43
|
-
- **Save/load test config** — persist test cases to `test-config.json`
|
|
44
|
-
|
|
45
|
-
Both FastEdge binary types are supported and auto-detected:
|
|
46
|
-
- **CDN (proxy-wasm)** — request/response filter binaries
|
|
47
|
-
- **HTTP-WASM** — component model HTTP handler binaries
|
|
48
|
-
|
|
49
|
-
---
|
|
50
|
-
|
|
51
|
-
## Programmatic Usage
|
|
52
|
-
|
|
53
|
-
If you want to start the server from your own script or test setup:
|
|
54
|
-
|
|
55
|
-
```typescript
|
|
56
|
-
import { startServer } from '@gcoredev/fastedge-test/server';
|
|
57
|
-
|
|
58
|
-
// Start on default port (5179) or override via PORT env var
|
|
59
|
-
await startServer();
|
|
60
|
-
|
|
61
|
-
// Start on a custom port
|
|
62
|
-
await startServer(8080);
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
`startServer(port?)` returns a `Promise<void>` that resolves once the server is listening.
|
|
66
|
-
|
|
67
|
-
> **Note**: When using `startServer()` programmatically, the process stays alive until terminated. Use `SIGTERM` or `SIGINT` to shut it down gracefully — both are handled automatically.
|
|
68
|
-
|
|
69
|
-
### Example: Start server in a script, run tests, shut down
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
import { startServer } from '@gcoredev/fastedge-test/server';
|
|
73
|
-
import { defineTestSuite, runAndExit } from '@gcoredev/fastedge-test/test';
|
|
74
|
-
|
|
75
|
-
// Start the visual server alongside headless tests
|
|
76
|
-
await startServer(5179);
|
|
77
|
-
console.log('Debugger running at http://localhost:5179');
|
|
78
|
-
|
|
79
|
-
// Also run automated tests in the same process
|
|
80
|
-
await runAndExit(defineTestSuite({
|
|
81
|
-
wasmPath: './build/app.wasm',
|
|
82
|
-
tests: [ /* ... */ ],
|
|
83
|
-
}));
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
---
|
|
87
|
-
|
|
88
|
-
## REST API
|
|
89
|
-
|
|
90
|
-
The server exposes a REST API that the browser UI uses internally. You can also call it directly from scripts, agents, or other tools.
|
|
91
|
-
|
|
92
|
-
| Method | Endpoint | Description |
|
|
93
|
-
|--------|----------|-------------|
|
|
94
|
-
| `GET` | `/health` | Check server is running |
|
|
95
|
-
| `POST` | `/api/load` | Load a WASM binary (base64 or file path) |
|
|
96
|
-
| `POST` | `/api/execute` | Execute a request against the loaded WASM |
|
|
97
|
-
| `POST` | `/api/send` | Run a full CDN flow (proxy-wasm) |
|
|
98
|
-
| `POST` | `/api/call` | Invoke a specific proxy-wasm hook |
|
|
99
|
-
| `GET` | `/api/config` | Get current test configuration |
|
|
100
|
-
| `POST` | `/api/config` | Save test configuration |
|
|
101
|
-
| `GET` | `/api/schema/:name` | Fetch a JSON Schema for request validation |
|
|
102
|
-
|
|
103
|
-
See **[API.md](./API.md)** for full endpoint documentation, request/response shapes, and examples.
|
|
104
|
-
|
|
105
|
-
### Quick example — load and execute via curl
|
|
106
|
-
|
|
107
|
-
```bash
|
|
108
|
-
# Load a WASM binary by file path
|
|
109
|
-
curl -s -X POST http://localhost:5179/api/load \
|
|
110
|
-
-H "Content-Type: application/json" \
|
|
111
|
-
-d '{"wasmPath": "/path/to/app.wasm"}'
|
|
112
|
-
|
|
113
|
-
# Execute a request
|
|
114
|
-
curl -s -X POST http://localhost:5179/api/execute \
|
|
115
|
-
-H "Content-Type: application/json" \
|
|
116
|
-
-d '{
|
|
117
|
-
"url": "https://example.com/page",
|
|
118
|
-
"method": "GET",
|
|
119
|
-
"headers": { "user-agent": "curl/7.0" }
|
|
120
|
-
}'
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## WebSocket Log Streaming
|
|
126
|
-
|
|
127
|
-
Logs emitted by your WASM binary are streamed in real time over WebSocket:
|
|
128
|
-
|
|
129
|
-
```javascript
|
|
130
|
-
const ws = new WebSocket('ws://localhost:5179/ws');
|
|
131
|
-
ws.onmessage = (event) => {
|
|
132
|
-
const msg = JSON.parse(event.data);
|
|
133
|
-
console.log(msg); // { type: 'log', level: 'info', message: '...' }
|
|
134
|
-
};
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
The browser UI connects to this automatically — you only need this if building custom tooling.
|
|
138
|
-
|
|
139
|
-
---
|
|
140
|
-
|
|
141
|
-
## VSCode Extension
|
|
142
|
-
|
|
143
|
-
If you use VSCode, the debugger is already built into the [FastEdge extension](https://marketplace.visualstudio.com/items?itemName=Gcore.fastedge) — no separate install needed. The extension starts the server automatically when you open a FastEdge project.
|
|
144
|
-
|
|
145
|
-
The standalone server (this page) is for developers not using VSCode who want the same interactive debugging experience in a browser.
|
|
146
|
-
|
|
147
|
-
---
|
|
148
|
-
|
|
149
|
-
## Related
|
|
150
|
-
|
|
151
|
-
- **[REST API Reference](./API.md)** — Full endpoint documentation
|
|
152
|
-
- **[Test Framework Guide](./TEST_FRAMEWORK.md)** — Headless programmatic testing (no server needed)
|
|
153
|
-
- **[WASM Loading Guide](./HYBRID_LOADING.md)** — Path vs buffer loading tradeoffs
|