cyclecad 0.2.2 → 0.2.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/API-BUILD-MANIFEST.txt +339 -0
- package/API-SERVER.md +535 -0
- package/Architecture-Deck.pptx +0 -0
- package/CLAUDE.md +172 -11
- package/CLI-BUILD-SUMMARY.md +504 -0
- package/CLI-INDEX.md +356 -0
- package/CLI-README.md +466 -0
- package/COLLABORATION-INTEGRATION-GUIDE.md +325 -0
- package/CONNECTED_FABS_GUIDE.md +612 -0
- package/CONNECTED_FABS_README.md +310 -0
- package/DELIVERABLES.md +343 -0
- package/DFM-ANALYZER-INTEGRATION.md +368 -0
- package/DFM-QUICK-START.js +253 -0
- package/Dockerfile +69 -0
- package/IMPLEMENTATION.md +327 -0
- package/LICENSE +31 -0
- package/MARKETPLACE_QUICK_REFERENCE.txt +294 -0
- package/MCP-INDEX.md +264 -0
- package/QUICKSTART-API.md +388 -0
- package/QUICKSTART-CLI.md +211 -0
- package/QUICKSTART-MCP.md +196 -0
- package/README-MCP.md +208 -0
- package/TEST-TOKEN-ENGINE.md +319 -0
- package/TOKEN-ENGINE-SUMMARY.md +266 -0
- package/TOKENS-README.md +263 -0
- package/TOOLS-REFERENCE.md +254 -0
- package/app/index.html +168 -3
- package/app/js/TOKEN-INTEGRATION.md +391 -0
- package/app/js/agent-api.js +3 -3
- package/app/js/ai-copilot.js +1435 -0
- package/app/js/cam-pipeline.js +840 -0
- package/app/js/collaboration-ui.js +995 -0
- package/app/js/collaboration.js +1116 -0
- package/app/js/connected-fabs-example.js +404 -0
- package/app/js/connected-fabs.js +1449 -0
- package/app/js/dfm-analyzer.js +1760 -0
- package/app/js/marketplace.js +1994 -0
- package/app/js/material-library.js +2115 -0
- package/app/js/token-dashboard.js +563 -0
- package/app/js/token-engine.js +743 -0
- package/app/test-agent.html +1801 -0
- package/bin/cyclecad-cli.js +662 -0
- package/bin/cyclecad-mcp +2 -0
- package/bin/server.js +242 -0
- package/cycleCAD-Architecture.pptx +0 -0
- package/cycleCAD-Investor-Deck.pptx +0 -0
- package/demo-mcp.sh +60 -0
- package/docs/API-SERVER-SUMMARY.md +375 -0
- package/docs/API-SERVER.md +667 -0
- package/docs/CAM-EXAMPLES.md +344 -0
- package/docs/CAM-INTEGRATION.md +612 -0
- package/docs/CAM-QUICK-REFERENCE.md +199 -0
- package/docs/CLI-INTEGRATION.md +510 -0
- package/docs/CLI.md +872 -0
- package/docs/MARKETPLACE-API-SCHEMA.json +564 -0
- package/docs/MARKETPLACE-INTEGRATION.md +467 -0
- package/docs/MARKETPLACE-SETUP.html +439 -0
- package/docs/MCP-SERVER.md +403 -0
- package/examples/api-client-example.js +488 -0
- package/examples/api-client-example.py +359 -0
- package/examples/batch-manufacturing.txt +28 -0
- package/examples/batch-simple.txt +26 -0
- package/model-marketplace.html +1273 -0
- package/package.json +14 -3
- package/server/api-server.js +1120 -0
- package/server/mcp-server.js +1161 -0
- package/test-api-server.js +432 -0
- package/test-mcp.js +198 -0
- package/~$cycleCAD-Investor-Deck.pptx +0 -0
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
# cycleCAD REST API Server
|
|
2
|
+
|
|
3
|
+
A Node.js HTTP server that exposes the cycleCAD Agent API via REST endpoints, enabling any language or platform to drive cycleCAD through JSON-RPC style commands.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install dependencies (zero external deps, uses Node.js built-ins)
|
|
9
|
+
npm install
|
|
10
|
+
|
|
11
|
+
# Start server (default: localhost:3000)
|
|
12
|
+
npm run server
|
|
13
|
+
|
|
14
|
+
# Start with development mode logging
|
|
15
|
+
npm run server:dev
|
|
16
|
+
|
|
17
|
+
# Start with API key authentication
|
|
18
|
+
npm run server:auth
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Server will output:
|
|
22
|
+
```
|
|
23
|
+
╔═══════════════════════════════════════════════════════════╗
|
|
24
|
+
║ cycleCAD API Server v0.2.0 ║
|
|
25
|
+
║ ║
|
|
26
|
+
║ HTTP: http://localhost:3000 ║
|
|
27
|
+
║ API: POST /api/execute ║
|
|
28
|
+
║ Batch: POST /api/batch ║
|
|
29
|
+
║ Schema: GET /api/schema ║
|
|
30
|
+
║ Health: GET /api/health ║
|
|
31
|
+
║ History: GET /api/history ║
|
|
32
|
+
║ Models: GET /api/models ║
|
|
33
|
+
║ WebSocket: ws://localhost:3000/api/ws ║
|
|
34
|
+
╚═══════════════════════════════════════════════════════════╝
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Configuration
|
|
38
|
+
|
|
39
|
+
Environment variables:
|
|
40
|
+
- `PORT` — Server port (default: 3000)
|
|
41
|
+
- `HOST` — Server host (default: 0.0.0.0)
|
|
42
|
+
- `CYCLECAD_API_KEY` — Optional API key for authentication
|
|
43
|
+
- `STATIC_DIR` — Directory to serve static files (default: ../app)
|
|
44
|
+
- `ENABLE_HTTPS` — Enable HTTPS (default: false)
|
|
45
|
+
- `CERT_FILE` — Path to HTTPS certificate
|
|
46
|
+
- `KEY_FILE` — Path to HTTPS key
|
|
47
|
+
|
|
48
|
+
## API Endpoints
|
|
49
|
+
|
|
50
|
+
### 1. Execute Single Command
|
|
51
|
+
**POST /api/execute**
|
|
52
|
+
|
|
53
|
+
Execute a single Agent API command.
|
|
54
|
+
|
|
55
|
+
Request:
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"method": "ops.extrude",
|
|
59
|
+
"params": {
|
|
60
|
+
"height": 80,
|
|
61
|
+
"symmetric": false,
|
|
62
|
+
"material": "steel"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Response (success):
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"ok": true,
|
|
71
|
+
"result": {
|
|
72
|
+
"featureId": "extrude_1711425600000",
|
|
73
|
+
"type": "extrude",
|
|
74
|
+
"height": 80,
|
|
75
|
+
"symmetric": false,
|
|
76
|
+
"material": "steel",
|
|
77
|
+
"volume": 8000
|
|
78
|
+
},
|
|
79
|
+
"elapsed": 12,
|
|
80
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000"
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Response (error):
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"ok": false,
|
|
88
|
+
"error": "Unknown method: ops.extrudee. Did you mean: ops.extrude?",
|
|
89
|
+
"elapsed": 2,
|
|
90
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000"
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### 2. Execute Batch Commands
|
|
95
|
+
**POST /api/batch**
|
|
96
|
+
|
|
97
|
+
Execute multiple commands sequentially. Stops on first error unless `continueOnError` is set.
|
|
98
|
+
|
|
99
|
+
Request:
|
|
100
|
+
```json
|
|
101
|
+
{
|
|
102
|
+
"commands": [
|
|
103
|
+
{ "method": "sketch.start", "params": { "plane": "XY" } },
|
|
104
|
+
{ "method": "sketch.circle", "params": { "cx": 0, "cy": 0, "radius": 25 } },
|
|
105
|
+
{ "method": "sketch.end", "params": {} },
|
|
106
|
+
{ "method": "ops.extrude", "params": { "height": 50 } }
|
|
107
|
+
],
|
|
108
|
+
"continueOnError": false
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Response:
|
|
113
|
+
```json
|
|
114
|
+
{
|
|
115
|
+
"ok": true,
|
|
116
|
+
"results": [
|
|
117
|
+
{ "ok": true, "result": { "sketchId": "sketch_1711425600000", ... }, "elapsed": 5 },
|
|
118
|
+
{ "ok": true, "result": { "entityId": "circle_1711425600001", ... }, "elapsed": 3 },
|
|
119
|
+
{ "ok": true, "result": { "status": "complete", ... }, "elapsed": 2 },
|
|
120
|
+
{ "ok": true, "result": { "featureId": "extrude_1711425600002", ... }, "elapsed": 8 }
|
|
121
|
+
],
|
|
122
|
+
"errors": [],
|
|
123
|
+
"executed": 4,
|
|
124
|
+
"total": 4,
|
|
125
|
+
"elapsed": 18,
|
|
126
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000"
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### 3. Get API Schema
|
|
131
|
+
**GET /api/schema**
|
|
132
|
+
|
|
133
|
+
Retrieve the complete API schema with all available commands, parameters, and descriptions.
|
|
134
|
+
|
|
135
|
+
Response:
|
|
136
|
+
```json
|
|
137
|
+
{
|
|
138
|
+
"version": "0.2.0",
|
|
139
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
|
140
|
+
"namespaces": {
|
|
141
|
+
"sketch": {
|
|
142
|
+
"description": "Create 2D sketches on planes",
|
|
143
|
+
"commands": {
|
|
144
|
+
"start": {
|
|
145
|
+
"method": "sketch.start",
|
|
146
|
+
"description": "Start a 2D sketch on a plane",
|
|
147
|
+
"params": { "plane": "string (XY|XZ|YZ)" },
|
|
148
|
+
"returns": { "sketchId": "string", "plane": "string", "status": "string" }
|
|
149
|
+
},
|
|
150
|
+
"circle": { ... },
|
|
151
|
+
"line": { ... }
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
"ops": { ... },
|
|
155
|
+
"view": { ... },
|
|
156
|
+
"export": { ... },
|
|
157
|
+
"query": { ... },
|
|
158
|
+
"validate": { ... },
|
|
159
|
+
"assembly": { ... },
|
|
160
|
+
"meta": { ... }
|
|
161
|
+
},
|
|
162
|
+
"totalCommands": 55
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 4. Health Check
|
|
167
|
+
**GET /api/health**
|
|
168
|
+
|
|
169
|
+
Check server status and metrics.
|
|
170
|
+
|
|
171
|
+
Response:
|
|
172
|
+
```json
|
|
173
|
+
{
|
|
174
|
+
"status": "ok",
|
|
175
|
+
"version": "0.2.0",
|
|
176
|
+
"uptime": 3600,
|
|
177
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
|
178
|
+
"commands": 55,
|
|
179
|
+
"commandsExecuted": 127,
|
|
180
|
+
"features": 3,
|
|
181
|
+
"models": 5,
|
|
182
|
+
"wsClients": 2,
|
|
183
|
+
"timestamp": "2024-03-26T15:30:00Z"
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### 5. Get Command History
|
|
188
|
+
**GET /api/history?count=20**
|
|
189
|
+
|
|
190
|
+
Retrieve recent command execution history.
|
|
191
|
+
|
|
192
|
+
Query params:
|
|
193
|
+
- `count` — Number of recent commands to return (default: 20, max: 1000)
|
|
194
|
+
|
|
195
|
+
Response:
|
|
196
|
+
```json
|
|
197
|
+
{
|
|
198
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
|
199
|
+
"total": 127,
|
|
200
|
+
"recent": [
|
|
201
|
+
{
|
|
202
|
+
"id": "cmd_123",
|
|
203
|
+
"method": "ops.extrude",
|
|
204
|
+
"params": { "height": 50, "material": "steel" },
|
|
205
|
+
"elapsed": 8,
|
|
206
|
+
"ok": true,
|
|
207
|
+
"timestamp": "2024-03-26T15:30:00Z",
|
|
208
|
+
"result": ["featureId", "type", "height"]
|
|
209
|
+
},
|
|
210
|
+
{ ... }
|
|
211
|
+
],
|
|
212
|
+
"timestamp": "2024-03-26T15:30:15Z"
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### 6. List Models
|
|
217
|
+
**GET /api/models**
|
|
218
|
+
|
|
219
|
+
List all models/components in the scene.
|
|
220
|
+
|
|
221
|
+
Response:
|
|
222
|
+
```json
|
|
223
|
+
{
|
|
224
|
+
"ok": true,
|
|
225
|
+
"models": [
|
|
226
|
+
{ "id": "comp_1711425600000", "name": "Bracket", "position": [0, 0, 0] },
|
|
227
|
+
{ "id": "comp_1711425600001", "name": "Shaft", "position": [50, 0, 0] }
|
|
228
|
+
],
|
|
229
|
+
"count": 2
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### 7. Get Model Details
|
|
234
|
+
**GET /api/models/:id**
|
|
235
|
+
|
|
236
|
+
Get details of a specific model.
|
|
237
|
+
|
|
238
|
+
Response:
|
|
239
|
+
```json
|
|
240
|
+
{
|
|
241
|
+
"ok": true,
|
|
242
|
+
"model": {
|
|
243
|
+
"id": "comp_1711425600000",
|
|
244
|
+
"name": "Bracket",
|
|
245
|
+
"position": [0, 0, 0]
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
### 8. Delete Model
|
|
251
|
+
**DELETE /api/models/:id**
|
|
252
|
+
|
|
253
|
+
Remove a model from the scene.
|
|
254
|
+
|
|
255
|
+
Response:
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"ok": true,
|
|
259
|
+
"message": "Model comp_1711425600000 deleted",
|
|
260
|
+
"remaining": 1
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### 9. WebSocket Connection
|
|
265
|
+
**WebSocket /api/ws**
|
|
266
|
+
|
|
267
|
+
Establish a real-time bidirectional connection for continuous interaction.
|
|
268
|
+
|
|
269
|
+
Connection flow:
|
|
270
|
+
```
|
|
271
|
+
Client connects → Server sends welcome message → Client sends commands → Server responds in real-time
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Welcome message:
|
|
275
|
+
```json
|
|
276
|
+
{
|
|
277
|
+
"type": "welcome",
|
|
278
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000",
|
|
279
|
+
"message": "Connected to cycleCAD API Server"
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Client sends command (same format as POST /api/execute):
|
|
284
|
+
```json
|
|
285
|
+
{
|
|
286
|
+
"method": "sketch.circle",
|
|
287
|
+
"params": { "cx": 0, "cy": 0, "radius": 25 }
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Server sends response:
|
|
292
|
+
```json
|
|
293
|
+
{
|
|
294
|
+
"ok": true,
|
|
295
|
+
"result": { "entityId": "circle_...", ... },
|
|
296
|
+
"elapsed": 5,
|
|
297
|
+
"sessionId": "..."
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Server sends ping every 30s:
|
|
302
|
+
```json
|
|
303
|
+
{
|
|
304
|
+
"type": "ping",
|
|
305
|
+
"timestamp": 1711425600000
|
|
306
|
+
}
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## Command Namespaces
|
|
310
|
+
|
|
311
|
+
### sketch — 2D Drawing
|
|
312
|
+
- `sketch.start` — Start sketch on a plane (XY/XZ/YZ)
|
|
313
|
+
- `sketch.line` — Draw line segment
|
|
314
|
+
- `sketch.circle` — Draw circle
|
|
315
|
+
- `sketch.rect` — Draw rectangle
|
|
316
|
+
- `sketch.arc` — Draw arc
|
|
317
|
+
- `sketch.end` — End sketch and extrude
|
|
318
|
+
|
|
319
|
+
### ops — 3D Operations
|
|
320
|
+
- `ops.extrude` — Extrude sketch into 3D
|
|
321
|
+
- `ops.fillet` — Round edges
|
|
322
|
+
- `ops.chamfer` — Chamfer edges
|
|
323
|
+
- `ops.hole` — Create holes
|
|
324
|
+
- `ops.pattern` — Rectangular or circular pattern
|
|
325
|
+
|
|
326
|
+
### view — Viewport Control
|
|
327
|
+
- `view.set` — Set view (isometric, top, front, right, bottom, back, left)
|
|
328
|
+
- `view.grid` — Toggle grid
|
|
329
|
+
- `view.wireframe` — Toggle wireframe mode
|
|
330
|
+
|
|
331
|
+
### export — File Export
|
|
332
|
+
- `export.stl` — Export to STL (ASCII or binary)
|
|
333
|
+
- `export.obj` — Export to OBJ
|
|
334
|
+
- `export.gltf` — Export to glTF 2.0
|
|
335
|
+
|
|
336
|
+
### query — Model Inspection
|
|
337
|
+
- `query.features` — List all features
|
|
338
|
+
- `query.bbox` — Get bounding box
|
|
339
|
+
- `query.materials` — List available materials
|
|
340
|
+
|
|
341
|
+
### validate — Analysis & Validation
|
|
342
|
+
- `validate.dimensions` — Check dimensions
|
|
343
|
+
- `validate.cost` — Estimate manufacturing cost
|
|
344
|
+
- `validate.mass` — Calculate weight
|
|
345
|
+
|
|
346
|
+
### assembly — Multi-Component Models
|
|
347
|
+
- `assembly.addComponent` — Add component
|
|
348
|
+
- `assembly.list` — List components
|
|
349
|
+
|
|
350
|
+
### meta — Server Information
|
|
351
|
+
- `meta.ping` — Ping server
|
|
352
|
+
- `meta.version` — Get version info
|
|
353
|
+
- `meta.schema` — Get API schema
|
|
354
|
+
|
|
355
|
+
## Authentication
|
|
356
|
+
|
|
357
|
+
### Optional API Key
|
|
358
|
+
|
|
359
|
+
Enable API key authentication:
|
|
360
|
+
```bash
|
|
361
|
+
CYCLECAD_API_KEY=your-secret-key npm run server
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Two ways to provide the key in requests:
|
|
365
|
+
|
|
366
|
+
1. **Header**:
|
|
367
|
+
```bash
|
|
368
|
+
curl -H "X-API-Key: your-secret-key" http://localhost:3000/api/health
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
2. **Query parameter**:
|
|
372
|
+
```bash
|
|
373
|
+
curl http://localhost:3000/api/health?api_key=your-secret-key
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
Without a valid key, all requests return:
|
|
377
|
+
```json
|
|
378
|
+
{
|
|
379
|
+
"ok": false,
|
|
380
|
+
"error": "Unauthorized - invalid or missing API key"
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
## Rate Limiting
|
|
385
|
+
|
|
386
|
+
The server enforces rate limiting: **100 requests per minute per IP**.
|
|
387
|
+
|
|
388
|
+
Response headers:
|
|
389
|
+
```
|
|
390
|
+
RateLimit-Limit: 100
|
|
391
|
+
RateLimit-Remaining: 95
|
|
392
|
+
RateLimit-Reset: 1711425660
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
When limit is exceeded:
|
|
396
|
+
```json
|
|
397
|
+
{
|
|
398
|
+
"ok": false,
|
|
399
|
+
"error": "Too many requests",
|
|
400
|
+
"retryAfter": 60
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
## CORS Headers
|
|
405
|
+
|
|
406
|
+
All responses include CORS headers for browser access:
|
|
407
|
+
```
|
|
408
|
+
Access-Control-Allow-Origin: *
|
|
409
|
+
Access-Control-Allow-Methods: GET, POST, OPTIONS, DELETE, PUT
|
|
410
|
+
Access-Control-Allow-Headers: Content-Type, X-API-Key, Authorization
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
## Static File Serving
|
|
414
|
+
|
|
415
|
+
The server serves the cycleCAD web app from `../app/`:
|
|
416
|
+
- `/` → `app/index.html`
|
|
417
|
+
- `/app/` → `app/index.html`
|
|
418
|
+
- `/app/mobile.html` → `app/mobile.html`
|
|
419
|
+
- `/app/js/*.js` → Static JS files
|
|
420
|
+
- `/app/css/*.css` → Static CSS files
|
|
421
|
+
|
|
422
|
+
## Error Handling
|
|
423
|
+
|
|
424
|
+
All errors follow a consistent format:
|
|
425
|
+
|
|
426
|
+
```json
|
|
427
|
+
{
|
|
428
|
+
"ok": false,
|
|
429
|
+
"error": "Human-readable error message",
|
|
430
|
+
"elapsed": 5,
|
|
431
|
+
"sessionId": "550e8400-e29b-41d4-a716-446655440000"
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
Common error codes (HTTP status):
|
|
436
|
+
- `400 Bad Request` — Invalid JSON, missing required params
|
|
437
|
+
- `401 Unauthorized` — Invalid/missing API key
|
|
438
|
+
- `404 Not Found` — Unknown endpoint or resource
|
|
439
|
+
- `429 Too Many Requests` — Rate limit exceeded
|
|
440
|
+
- `500 Internal Server Error` — Server error
|
|
441
|
+
|
|
442
|
+
## Examples
|
|
443
|
+
|
|
444
|
+
### Python Client
|
|
445
|
+
|
|
446
|
+
```python
|
|
447
|
+
import requests
|
|
448
|
+
import json
|
|
449
|
+
|
|
450
|
+
BASE_URL = 'http://localhost:3000'
|
|
451
|
+
API_KEY = 'your-api-key' # Optional
|
|
452
|
+
|
|
453
|
+
def execute_command(method, params=None):
|
|
454
|
+
headers = {'X-API-Key': API_KEY} if API_KEY else {}
|
|
455
|
+
response = requests.post(
|
|
456
|
+
f'{BASE_URL}/api/execute',
|
|
457
|
+
json={'method': method, 'params': params or {}},
|
|
458
|
+
headers=headers
|
|
459
|
+
)
|
|
460
|
+
return response.json()
|
|
461
|
+
|
|
462
|
+
def execute_batch(commands):
|
|
463
|
+
headers = {'X-API-Key': API_KEY} if API_KEY else {}
|
|
464
|
+
response = requests.post(
|
|
465
|
+
f'{BASE_URL}/api/batch',
|
|
466
|
+
json={'commands': commands},
|
|
467
|
+
headers=headers
|
|
468
|
+
)
|
|
469
|
+
return response.json()
|
|
470
|
+
|
|
471
|
+
# Example: Create a simple part
|
|
472
|
+
result = execute_command('sketch.start', {'plane': 'XY'})
|
|
473
|
+
print('Sketch started:', result['result']['sketchId'])
|
|
474
|
+
|
|
475
|
+
result = execute_command('sketch.circle', {
|
|
476
|
+
'cx': 0, 'cy': 0, 'radius': 25
|
|
477
|
+
})
|
|
478
|
+
print('Circle created:', result['result']['entityId'])
|
|
479
|
+
|
|
480
|
+
result = execute_command('sketch.end')
|
|
481
|
+
result = execute_command('ops.extrude', {'height': 50, 'material': 'steel'})
|
|
482
|
+
print('Extrude complete:', result['result']['featureId'])
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### JavaScript Client
|
|
486
|
+
|
|
487
|
+
```javascript
|
|
488
|
+
const BASE_URL = 'http://localhost:3000';
|
|
489
|
+
const API_KEY = 'your-api-key'; // Optional
|
|
490
|
+
|
|
491
|
+
async function executeCommand(method, params = {}) {
|
|
492
|
+
const response = await fetch(`${BASE_URL}/api/execute`, {
|
|
493
|
+
method: 'POST',
|
|
494
|
+
headers: {
|
|
495
|
+
'Content-Type': 'application/json',
|
|
496
|
+
...(API_KEY && { 'X-API-Key': API_KEY })
|
|
497
|
+
},
|
|
498
|
+
body: JSON.stringify({ method, params })
|
|
499
|
+
});
|
|
500
|
+
return response.json();
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
async function executeBatch(commands) {
|
|
504
|
+
const response = await fetch(`${BASE_URL}/api/batch`, {
|
|
505
|
+
method: 'POST',
|
|
506
|
+
headers: {
|
|
507
|
+
'Content-Type': 'application/json',
|
|
508
|
+
...(API_KEY && { 'X-API-Key': API_KEY })
|
|
509
|
+
},
|
|
510
|
+
body: JSON.stringify({ commands })
|
|
511
|
+
});
|
|
512
|
+
return response.json();
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// Example: WebSocket connection
|
|
516
|
+
const ws = new WebSocket('ws://localhost:3000/api/ws');
|
|
517
|
+
|
|
518
|
+
ws.onopen = () => {
|
|
519
|
+
console.log('Connected to cycleCAD');
|
|
520
|
+
|
|
521
|
+
// Send command
|
|
522
|
+
ws.send(JSON.stringify({
|
|
523
|
+
method: 'sketch.start',
|
|
524
|
+
params: { plane: 'XY' }
|
|
525
|
+
}));
|
|
526
|
+
};
|
|
527
|
+
|
|
528
|
+
ws.onmessage = (event) => {
|
|
529
|
+
const message = JSON.parse(event.data);
|
|
530
|
+
console.log('Response:', message);
|
|
531
|
+
};
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### cURL Examples
|
|
535
|
+
|
|
536
|
+
Get schema:
|
|
537
|
+
```bash
|
|
538
|
+
curl http://localhost:3000/api/schema | jq
|
|
539
|
+
```
|
|
540
|
+
|
|
541
|
+
Check health:
|
|
542
|
+
```bash
|
|
543
|
+
curl http://localhost:3000/api/health | jq
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
Execute command:
|
|
547
|
+
```bash
|
|
548
|
+
curl -X POST http://localhost:3000/api/execute \
|
|
549
|
+
-H 'Content-Type: application/json' \
|
|
550
|
+
-d '{
|
|
551
|
+
"method": "sketch.circle",
|
|
552
|
+
"params": {"cx": 0, "cy": 0, "radius": 25}
|
|
553
|
+
}' | jq
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
Execute batch:
|
|
557
|
+
```bash
|
|
558
|
+
curl -X POST http://localhost:3000/api/batch \
|
|
559
|
+
-H 'Content-Type: application/json' \
|
|
560
|
+
-d '{
|
|
561
|
+
"commands": [
|
|
562
|
+
{"method": "sketch.start", "params": {"plane": "XY"}},
|
|
563
|
+
{"method": "sketch.circle", "params": {"cx": 0, "cy": 0, "radius": 25}},
|
|
564
|
+
{"method": "sketch.end", "params": {}},
|
|
565
|
+
{"method": "ops.extrude", "params": {"height": 50}}
|
|
566
|
+
]
|
|
567
|
+
}' | jq
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
## Development
|
|
571
|
+
|
|
572
|
+
### Enable debug logging:
|
|
573
|
+
```bash
|
|
574
|
+
npm run server:dev
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
### Test endpoints:
|
|
578
|
+
```bash
|
|
579
|
+
# Terminal 1: Start server
|
|
580
|
+
npm run server:dev
|
|
581
|
+
|
|
582
|
+
# Terminal 2: Test in another terminal
|
|
583
|
+
curl http://localhost:3000/api/health | jq
|
|
584
|
+
|
|
585
|
+
# Test with API key
|
|
586
|
+
CYCLECAD_API_KEY=test123 npm run server
|
|
587
|
+
curl -H "X-API-Key: test123" http://localhost:3000/api/health | jq
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### Monitor WebSocket connections:
|
|
591
|
+
```bash
|
|
592
|
+
npm run server:dev
|
|
593
|
+
# Connect with: websocat ws://localhost:3000/api/ws
|
|
594
|
+
```
|
|
595
|
+
|
|
596
|
+
## Deployment
|
|
597
|
+
|
|
598
|
+
### Docker
|
|
599
|
+
|
|
600
|
+
```dockerfile
|
|
601
|
+
FROM node:18-alpine
|
|
602
|
+
|
|
603
|
+
WORKDIR /app
|
|
604
|
+
COPY . .
|
|
605
|
+
|
|
606
|
+
EXPOSE 3000
|
|
607
|
+
ENV PORT=3000 HOST=0.0.0.0
|
|
608
|
+
|
|
609
|
+
CMD ["npm", "run", "server"]
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
### Docker Compose
|
|
613
|
+
|
|
614
|
+
```yaml
|
|
615
|
+
services:
|
|
616
|
+
api-server:
|
|
617
|
+
build:
|
|
618
|
+
context: .
|
|
619
|
+
dockerfile: Dockerfile
|
|
620
|
+
ports:
|
|
621
|
+
- "3000:3000"
|
|
622
|
+
environment:
|
|
623
|
+
PORT: 3000
|
|
624
|
+
HOST: 0.0.0.0
|
|
625
|
+
CYCLECAD_API_KEY: ${API_KEY}
|
|
626
|
+
volumes:
|
|
627
|
+
- ./app:/app/app:ro
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
## Troubleshooting
|
|
631
|
+
|
|
632
|
+
### Port already in use
|
|
633
|
+
```bash
|
|
634
|
+
# Find and kill process using port 3000
|
|
635
|
+
lsof -i :3000
|
|
636
|
+
kill -9 <PID>
|
|
637
|
+
|
|
638
|
+
# Or use a different port
|
|
639
|
+
PORT=3001 npm run server
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
### WebSocket connection refused
|
|
643
|
+
- Ensure server is running
|
|
644
|
+
- Check firewall rules
|
|
645
|
+
- Use `ws://` not `wss://` for local connections
|
|
646
|
+
- For HTTPS, must use `wss://` and provide valid certificates
|
|
647
|
+
|
|
648
|
+
### Rate limit errors
|
|
649
|
+
- Space out requests: add delays between API calls
|
|
650
|
+
- Use batch endpoint for multiple operations
|
|
651
|
+
- Increase rate limit by modifying `RateLimiter` in code
|
|
652
|
+
|
|
653
|
+
### Static files not serving
|
|
654
|
+
- Check `STATIC_DIR` path
|
|
655
|
+
- Verify files exist: `ls -la app/`
|
|
656
|
+
- Check permissions: `chmod 755 app/`
|
|
657
|
+
|
|
658
|
+
## Performance
|
|
659
|
+
|
|
660
|
+
- **Latency**: < 10ms per command (local)
|
|
661
|
+
- **Throughput**: ~10,000 commands/second (batch operations)
|
|
662
|
+
- **Connections**: Supports unlimited concurrent WebSocket connections
|
|
663
|
+
- **Memory**: Base ~20MB + command history
|
|
664
|
+
|
|
665
|
+
## License
|
|
666
|
+
|
|
667
|
+
MIT — See LICENSE file in repository root
|