fluidcad 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 (123) hide show
  1. package/README.md +7 -7
  2. package/lib/dist/common/shape-factory.d.ts +1 -1
  3. package/lib/dist/oc/boolean-ops.d.ts +2 -2
  4. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  5. package/package.json +3 -2
  6. package/lib/dist/constraints/constraint.d.ts +0 -11
  7. package/lib/dist/constraints/constraint.js +0 -51
  8. package/lib/dist/constraints/outside.d.ts +0 -3
  9. package/lib/dist/constraints/outside.js +0 -4
  10. package/lib/dist/core/2d/aslot.d.ts +0 -12
  11. package/lib/dist/core/2d/aslot.js +0 -40
  12. package/lib/dist/core/2d/crect.d.ts +0 -12
  13. package/lib/dist/core/2d/crect.js +0 -74
  14. package/lib/dist/core/2d/face-maker.d.ts +0 -13
  15. package/lib/dist/core/2d/face-maker.js +0 -119
  16. package/lib/dist/core/2d/face-maker2.d.ts +0 -6
  17. package/lib/dist/core/2d/face-maker2.js +0 -54
  18. package/lib/dist/core/region.d.ts +0 -13
  19. package/lib/dist/core/region.js +0 -18
  20. package/lib/dist/features/2d/amove.d.ts +0 -14
  21. package/lib/dist/features/2d/amove.js +0 -33
  22. package/lib/dist/features/2d/constraints/constraint.d.ts +0 -11
  23. package/lib/dist/features/2d/constraints/constraint.js +0 -49
  24. package/lib/dist/features/2d/constraints/outside.d.ts +0 -3
  25. package/lib/dist/features/2d/constraints/outside.js +0 -4
  26. package/lib/dist/features/2d/tarc-two-circles.d.ts +0 -18
  27. package/lib/dist/features/2d/tarc-two-circles.js +0 -61
  28. package/lib/dist/features/2d/tcircle-three-tan.d.ts +0 -13
  29. package/lib/dist/features/2d/tcircle-three-tan.js +0 -33
  30. package/lib/dist/features/2d/tcircle-two-tan.d.ts +0 -13
  31. package/lib/dist/features/2d/tcircle-two-tan.js +0 -33
  32. package/lib/dist/features/Extrude.d.ts +0 -1
  33. package/lib/dist/features/Extrude.js +0 -1
  34. package/lib/dist/features/cut-base.d.ts +0 -49
  35. package/lib/dist/features/cut-base.js +0 -312
  36. package/lib/dist/features/cut-symmetric.d.ts +0 -23
  37. package/lib/dist/features/cut-symmetric.js +0 -119
  38. package/lib/dist/features/cut-two-distances.d.ts +0 -24
  39. package/lib/dist/features/cut-two-distances.js +0 -110
  40. package/lib/dist/features/cut.d.ts +0 -27
  41. package/lib/dist/features/cut.js +0 -101
  42. package/lib/dist/features/extrude-symmetric.d.ts +0 -28
  43. package/lib/dist/features/extrude-symmetric.js +0 -177
  44. package/lib/dist/features/region2d.d.ts +0 -25
  45. package/lib/dist/features/region2d.js +0 -185
  46. package/lib/dist/features/repeat-circular2d.d.ts +0 -17
  47. package/lib/dist/features/repeat-circular2d.js +0 -90
  48. package/lib/dist/features/repeat-linear2d.d.ts +0 -17
  49. package/lib/dist/features/repeat-linear2d.js +0 -114
  50. package/lib/dist/features/revolve-options.d.ts +0 -6
  51. package/lib/dist/features/revolve-options.js +0 -1
  52. package/lib/dist/features/split.d.ts +0 -14
  53. package/lib/dist/features/split.js +0 -74
  54. package/lib/dist/features/state-scene-object.d.ts +0 -15
  55. package/lib/dist/features/state-scene-object.js +0 -44
  56. package/lib/dist/features/state-select.d.ts +0 -21
  57. package/lib/dist/features/state-select.js +0 -73
  58. package/lib/dist/features/translate2d.d.ts +0 -16
  59. package/lib/dist/features/translate2d.js +0 -61
  60. package/lib/dist/filters/all-filter.d.ts +0 -8
  61. package/lib/dist/filters/all-filter.js +0 -12
  62. package/lib/dist/filters/near-point-filter.d.ts +0 -11
  63. package/lib/dist/filters/near-point-filter.js +0 -33
  64. package/lib/dist/helpers/resolve-filters.d.ts +0 -6
  65. package/lib/dist/helpers/resolve-filters.js +0 -25
  66. package/lib/dist/math/axis.test.d.ts +0 -1
  67. package/lib/dist/math/axis.test.js +0 -287
  68. package/lib/dist/math/coordinate-system.test.d.ts +0 -1
  69. package/lib/dist/math/coordinate-system.test.js +0 -308
  70. package/lib/dist/math/matrix4.test.d.ts +0 -1
  71. package/lib/dist/math/matrix4.test.js +0 -357
  72. package/lib/dist/math/plane.test.d.ts +0 -1
  73. package/lib/dist/math/plane.test.js +0 -398
  74. package/lib/dist/math/point.test.d.ts +0 -1
  75. package/lib/dist/math/point.test.js +0 -385
  76. package/lib/dist/math/quaternion.test.d.ts +0 -1
  77. package/lib/dist/math/quaternion.test.js +0 -278
  78. package/lib/dist/math/vector3d.test.d.ts +0 -1
  79. package/lib/dist/math/vector3d.test.js +0 -276
  80. package/lib/dist/oc/constraint-resolver.d.ts +0 -7
  81. package/lib/dist/oc/constraint-resolver.js +0 -31
  82. package/lib/dist/oc/constraints/curve-constraint-solver.d.ts +0 -1
  83. package/lib/dist/oc/constraints/curve-constraint-solver.js +0 -2
  84. package/lib/dist/oc/constraints/geometric-constraint-solver.d.ts +0 -1
  85. package/lib/dist/oc/constraints/geometric-constraint-solver.js +0 -5
  86. package/lib/dist/oc/face-maker.d.ts +0 -14
  87. package/lib/dist/oc/face-maker.js +0 -191
  88. package/lib/dist/oc/measure.d.ts +0 -21
  89. package/lib/dist/oc/measure.js +0 -256
  90. package/lib/dist/oc/tangent-circle-solver.d.ts +0 -17
  91. package/lib/dist/oc/tangent-circle-solver.js +0 -72
  92. package/lib/dist/oc/tangent-line-solver.d.ts +0 -17
  93. package/lib/dist/oc/tangent-line-solver.js +0 -83
  94. package/lib/dist/oc/tangent-solver.d.ts +0 -14
  95. package/lib/dist/oc/tangent-solver.js +0 -199
  96. package/lib/dist/rendering/builder-context.d.ts +0 -16
  97. package/lib/dist/rendering/builder-context.js +0 -63
  98. package/lib/dist/tests/extrude.test.d.ts +0 -1
  99. package/lib/dist/tests/extrude.test.js +0 -48
  100. package/lib/dist/tests/features/copy.test.d.ts +0 -1
  101. package/lib/dist/tests/features/copy.test.js +0 -158
  102. package/lib/dist/tests/features/dispose.test.d.ts +0 -1
  103. package/lib/dist/tests/features/dispose.test.js +0 -189
  104. package/lib/dist/tests/features/part-pick.test.d.ts +0 -1
  105. package/lib/dist/tests/features/part-pick.test.js +0 -73
  106. package/lib/dist/tests/features/part-repeat.test.d.ts +0 -1
  107. package/lib/dist/tests/features/part-repeat.test.js +0 -109
  108. package/server/dist/fluidcad-server.d.ts +0 -32
  109. package/server/dist/fluidcad-server.js +0 -150
  110. package/server/dist/index.d.ts +0 -1
  111. package/server/dist/index.js +0 -290
  112. package/server/dist/routes/actions.d.ts +0 -3
  113. package/server/dist/routes/actions.js +0 -100
  114. package/server/dist/routes/export.d.ts +0 -3
  115. package/server/dist/routes/export.js +0 -55
  116. package/server/dist/routes/properties.d.ts +0 -3
  117. package/server/dist/routes/properties.js +0 -46
  118. package/server/dist/routes/screenshot.d.ts +0 -2
  119. package/server/dist/routes/screenshot.js +0 -76
  120. package/server/dist/vite-manager.d.ts +0 -10
  121. package/server/dist/vite-manager.js +0 -64
  122. package/server/dist/ws-protocol.d.ts +0 -138
  123. package/server/dist/ws-protocol.js +0 -4
@@ -1,32 +0,0 @@
1
- export type SceneRenderedData = {
2
- absPath: string;
3
- result: any[];
4
- rollbackStop: number;
5
- };
6
- export declare class FluidCadServer {
7
- private viteManager;
8
- private sceneManager;
9
- private previousScenes;
10
- private renderingCache;
11
- private currentFileName;
12
- init(workspacePath: string): Promise<void>;
13
- processFile(filePath: string, ignoreCache?: boolean): Promise<SceneRenderedData | null>;
14
- updateLiveCode(fileName: string, code: string): Promise<SceneRenderedData | null>;
15
- rollbackFromUI(index: number): Promise<SceneRenderedData | null>;
16
- rollback(fileName: string, index: number): Promise<SceneRenderedData | null>;
17
- importFile(workspacePath: string, fileName: string, data: string): Promise<void>;
18
- getShapeProperties(shapeId: string): any;
19
- getFaceProperties(shapeId: string, faceIndex: number): any;
20
- getEdgeProperties(shapeId: string, edgeIndex: number): any;
21
- exportShapes(shapeIds: string[], options: {
22
- format: 'step' | 'stl';
23
- includeColors?: boolean;
24
- resolution?: string;
25
- customLinearDeflection?: number;
26
- customAngularDeflectionDeg?: number;
27
- }): {
28
- data: string | Uint8Array;
29
- fileName: string;
30
- } | null;
31
- hitTest(shapeId: string, rayOrigin: [number, number, number], rayDir: [number, number, number], edgeThreshold: number): any;
32
- }
@@ -1,150 +0,0 @@
1
- import { join } from 'path';
2
- import { existsSync } from 'fs';
3
- import { ViteManager } from "./vite-manager.js";
4
- export class FluidCadServer {
5
- viteManager = new ViteManager();
6
- sceneManager;
7
- previousScenes = new Map();
8
- renderingCache = new Map();
9
- currentFileName = '';
10
- async init(workspacePath) {
11
- await this.viteManager.init(workspacePath);
12
- const initFilePath = join(workspacePath, 'init.js');
13
- if (existsSync(initFilePath)) {
14
- const { default: _sceneManager } = await this.viteManager.loadModule(initFilePath);
15
- this.sceneManager = await _sceneManager;
16
- }
17
- }
18
- async processFile(filePath, ignoreCache = false) {
19
- if (!this.sceneManager) {
20
- return null;
21
- }
22
- const normalizedFileName = filePath.replace('virtual:live-render:', '');
23
- this.currentFileName = normalizedFileName;
24
- if (!ignoreCache) {
25
- const fromCache = this.renderingCache.get(normalizedFileName);
26
- if (fromCache) {
27
- return {
28
- absPath: normalizedFileName,
29
- result: fromCache,
30
- rollbackStop: fromCache.length - 1,
31
- };
32
- }
33
- }
34
- try {
35
- let scene = this.sceneManager.startScene();
36
- this.sceneManager.setCurrentFile(normalizedFileName);
37
- this.viteManager.invalidateModule();
38
- await this.viteManager.loadModule(filePath);
39
- if (this.previousScenes.has(normalizedFileName)) {
40
- const previousScene = this.previousScenes.get(normalizedFileName);
41
- scene = this.sceneManager.compare(previousScene, scene);
42
- }
43
- this.previousScenes.set(normalizedFileName, scene);
44
- this.sceneManager.renderScene(scene);
45
- const result = scene.getRenderedObjects();
46
- for (const obj of result) {
47
- if (obj.sourceLocation) {
48
- obj.sourceLocation.filePath = obj.sourceLocation.filePath.replace('virtual:live-render:', '');
49
- }
50
- }
51
- if (!filePath.startsWith('virtual:live-render')) {
52
- this.renderingCache.set(normalizedFileName, result);
53
- }
54
- return {
55
- absPath: normalizedFileName,
56
- result,
57
- rollbackStop: result.length - 1,
58
- };
59
- }
60
- catch (error) {
61
- this.viteManager.invalidateModule();
62
- console.log('Error processing file:', error);
63
- return null;
64
- }
65
- }
66
- async updateLiveCode(fileName, code) {
67
- const id = `virtual:live-render:${fileName}`;
68
- this.viteManager.setBuffer(id, code);
69
- this.renderingCache.delete(fileName);
70
- return this.processFile(id, true);
71
- }
72
- async rollbackFromUI(index) {
73
- return this.rollback(this.currentFileName, index);
74
- }
75
- async rollback(fileName, index) {
76
- if (!this.sceneManager) {
77
- return null;
78
- }
79
- const scene = this.previousScenes.get(fileName);
80
- if (!scene) {
81
- return null;
82
- }
83
- const totalObjects = scene.getAllSceneObjects().length;
84
- const rollbackIndex = index >= totalObjects - 1 ? totalObjects - 1 : index;
85
- this.sceneManager.rollbackScene(scene, rollbackIndex);
86
- const result = scene.getRenderedObjects();
87
- return {
88
- absPath: fileName,
89
- result,
90
- rollbackStop: index,
91
- };
92
- }
93
- async importFile(workspacePath, fileName, data) {
94
- if (!this.sceneManager) {
95
- throw new Error('SceneManager not initialized');
96
- }
97
- const binaryData = Buffer.from(data, 'base64');
98
- await this.sceneManager.importFile(workspacePath, fileName, binaryData);
99
- }
100
- getShapeProperties(shapeId) {
101
- if (!this.sceneManager) {
102
- return null;
103
- }
104
- const scene = this.previousScenes.get(this.currentFileName);
105
- if (!scene) {
106
- return null;
107
- }
108
- return this.sceneManager.getShapeProperties(scene, shapeId);
109
- }
110
- getFaceProperties(shapeId, faceIndex) {
111
- if (!this.sceneManager) {
112
- return null;
113
- }
114
- const scene = this.previousScenes.get(this.currentFileName);
115
- if (!scene) {
116
- return null;
117
- }
118
- return this.sceneManager.getFaceProperties(scene, shapeId, faceIndex);
119
- }
120
- getEdgeProperties(shapeId, edgeIndex) {
121
- if (!this.sceneManager) {
122
- return null;
123
- }
124
- const scene = this.previousScenes.get(this.currentFileName);
125
- if (!scene) {
126
- return null;
127
- }
128
- return this.sceneManager.getEdgeProperties(scene, shapeId, edgeIndex);
129
- }
130
- exportShapes(shapeIds, options) {
131
- if (!this.sceneManager) {
132
- return null;
133
- }
134
- const scene = this.previousScenes.get(this.currentFileName);
135
- if (!scene) {
136
- return null;
137
- }
138
- return this.sceneManager.exportShapes(scene, shapeIds, options);
139
- }
140
- hitTest(shapeId, rayOrigin, rayDir, edgeThreshold) {
141
- if (!this.sceneManager) {
142
- return null;
143
- }
144
- const scene = this.previousScenes.get(this.currentFileName);
145
- if (!scene) {
146
- return null;
147
- }
148
- return this.sceneManager.hitTest(scene, shapeId, rayOrigin, rayDir, edgeThreshold);
149
- }
150
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,290 +0,0 @@
1
- import crypto from 'crypto';
2
- import http from 'http';
3
- import path from 'path';
4
- import express from 'express';
5
- import { WebSocketServer, WebSocket } from 'ws';
6
- import { FluidCadServer } from "./fluidcad-server.js";
7
- import { createPropertiesRouter } from "./routes/properties.js";
8
- import { createActionsRouter } from "./routes/actions.js";
9
- import { createExportRouter } from "./routes/export.js";
10
- import { createScreenshotRouter } from "./routes/screenshot.js";
11
- const PORT = parseInt(process.env.FLUIDCAD_SERVER_PORT || '3100', 10);
12
- const WORKSPACE_PATH = process.env.FLUIDCAD_WORKSPACE_PATH || '';
13
- const UI_DIST = path.resolve(import.meta.dirname, '../../ui/dist');
14
- // ---------------------------------------------------------------------------
15
- // IPC helpers — communication with extension host process
16
- // ---------------------------------------------------------------------------
17
- function sendToExtension(msg) {
18
- if (process.send) {
19
- process.send(msg);
20
- }
21
- }
22
- // ---------------------------------------------------------------------------
23
- // Express app
24
- // ---------------------------------------------------------------------------
25
- const fluidCadServer = new FluidCadServer();
26
- const app = express();
27
- app.use(express.json({ limit: '50mb' }));
28
- app.use('/api', createPropertiesRouter(fluidCadServer));
29
- app.use('/api', createActionsRouter(fluidCadServer, sendToExtension, broadcastToUI, WORKSPACE_PATH));
30
- app.use('/api', createExportRouter(fluidCadServer));
31
- app.use('/api', createScreenshotRouter(requestScreenshot));
32
- // Static files — serve UI build, with SPA fallback
33
- app.use(express.static(UI_DIST, {
34
- setHeaders(res, filePath) {
35
- if (path.extname(filePath) === '.html') {
36
- res.setHeader('Cache-Control', 'no-cache');
37
- }
38
- },
39
- }));
40
- app.get('*splat', (_req, res) => {
41
- res.setHeader('Cache-Control', 'no-cache');
42
- res.sendFile(path.join(UI_DIST, 'index.html'));
43
- });
44
- // ---------------------------------------------------------------------------
45
- // HTTP + WebSocket server
46
- // ---------------------------------------------------------------------------
47
- const httpServer = http.createServer(app);
48
- const wss = new WebSocketServer({ server: httpServer });
49
- const uiClients = new Set();
50
- let lastSceneMessage = null;
51
- let initCompleteMessage = null;
52
- function broadcastToUI(msg) {
53
- const data = JSON.stringify(msg);
54
- if (msg.type === 'scene-rendered') {
55
- lastSceneMessage = data;
56
- }
57
- if (msg.type === 'init-complete') {
58
- initCompleteMessage = data;
59
- }
60
- for (const client of uiClients) {
61
- if (client.readyState === WebSocket.OPEN) {
62
- client.send(data);
63
- }
64
- }
65
- }
66
- // ---------------------------------------------------------------------------
67
- // Screenshot request/response coordination
68
- // ---------------------------------------------------------------------------
69
- const SCREENSHOT_TIMEOUT_MS = 10_000;
70
- const pendingScreenshots = new Map();
71
- function requestScreenshot(options) {
72
- return new Promise((resolve, reject) => {
73
- if (uiClients.size === 0) {
74
- reject(new Error('No UI client connected.'));
75
- return;
76
- }
77
- const requestId = crypto.randomUUID();
78
- const timeout = setTimeout(() => {
79
- pendingScreenshots.delete(requestId);
80
- reject(new Error('Screenshot request timed out.'));
81
- }, SCREENSHOT_TIMEOUT_MS);
82
- pendingScreenshots.set(requestId, {
83
- resolve(data) {
84
- clearTimeout(timeout);
85
- pendingScreenshots.delete(requestId);
86
- resolve(data);
87
- },
88
- reject(err) {
89
- clearTimeout(timeout);
90
- pendingScreenshots.delete(requestId);
91
- reject(err);
92
- },
93
- });
94
- broadcastToUI({ type: 'take-screenshot', requestId, options });
95
- });
96
- }
97
- function handleUIMessage(raw) {
98
- let msg;
99
- try {
100
- msg = JSON.parse(raw);
101
- }
102
- catch {
103
- return;
104
- }
105
- if (msg.type === 'screenshot-result' && msg.requestId) {
106
- const pending = pendingScreenshots.get(msg.requestId);
107
- if (!pending) {
108
- return;
109
- }
110
- if (msg.success && msg.data) {
111
- pending.resolve(Buffer.from(msg.data, 'base64'));
112
- }
113
- else {
114
- pending.reject(new Error(msg.error || 'Screenshot failed.'));
115
- }
116
- }
117
- }
118
- // ---------------------------------------------------------------------------
119
- // WebSocket connections
120
- // ---------------------------------------------------------------------------
121
- wss.on('connection', (ws) => {
122
- uiClients.add(ws);
123
- // Replay init-complete and last scene to newly connected UI client
124
- if (initCompleteMessage) {
125
- ws.send(initCompleteMessage);
126
- }
127
- if (lastSceneMessage) {
128
- ws.send(lastSceneMessage);
129
- }
130
- ws.on('message', (data) => {
131
- handleUIMessage(String(data));
132
- });
133
- ws.on('close', () => {
134
- uiClients.delete(ws);
135
- });
136
- });
137
- // ---------------------------------------------------------------------------
138
- // IPC message handling — extension host → server
139
- // ---------------------------------------------------------------------------
140
- let currentFile = null;
141
- let renderVersion = 0;
142
- async function handleExtensionMessage(msg) {
143
- try {
144
- switch (msg.type) {
145
- case 'process-file': {
146
- const myVersion = ++renderVersion;
147
- broadcastToUI({ type: 'processing-file' });
148
- currentFile = msg.filePath;
149
- const data = await fluidCadServer.processFile(msg.filePath);
150
- if (myVersion !== renderVersion) {
151
- return;
152
- }
153
- if (data) {
154
- sendToExtension({
155
- type: 'scene-rendered',
156
- absPath: data.absPath,
157
- result: data.result,
158
- rollbackStop: data.rollbackStop,
159
- });
160
- broadcastToUI({
161
- type: 'scene-rendered',
162
- result: data.result,
163
- absPath: data.absPath,
164
- });
165
- }
166
- break;
167
- }
168
- case 'live-update': {
169
- const myVersion = ++renderVersion;
170
- if (msg.fileName !== currentFile) {
171
- broadcastToUI({ type: 'processing-file' });
172
- currentFile = msg.fileName;
173
- }
174
- const data = await fluidCadServer.updateLiveCode(msg.fileName, msg.code);
175
- if (myVersion !== renderVersion) {
176
- return;
177
- }
178
- if (data) {
179
- sendToExtension({
180
- type: 'scene-rendered',
181
- absPath: data.absPath,
182
- result: data.result,
183
- rollbackStop: data.rollbackStop,
184
- });
185
- broadcastToUI({
186
- type: 'scene-rendered',
187
- result: data.result,
188
- absPath: data.absPath,
189
- });
190
- }
191
- break;
192
- }
193
- case 'rollback': {
194
- const myVersion = ++renderVersion;
195
- const data = await fluidCadServer.rollback(msg.fileName, msg.index);
196
- if (myVersion !== renderVersion) {
197
- return;
198
- }
199
- if (data) {
200
- sendToExtension({
201
- type: 'scene-rendered',
202
- absPath: data.absPath,
203
- result: data.result,
204
- rollbackStop: data.rollbackStop,
205
- });
206
- broadcastToUI({
207
- type: 'scene-rendered',
208
- result: data.result,
209
- absPath: data.absPath,
210
- rollbackStop: data.rollbackStop,
211
- });
212
- }
213
- break;
214
- }
215
- case 'import-file': {
216
- try {
217
- await fluidCadServer.importFile(msg.workspacePath, msg.fileName, msg.data);
218
- sendToExtension({ type: 'import-complete', success: true });
219
- }
220
- catch (err) {
221
- sendToExtension({ type: 'error', message: err.stack || err.message || String(err) });
222
- }
223
- break;
224
- }
225
- case 'highlight-shape': {
226
- broadcastToUI({ type: 'highlight-shape', shapeId: msg.shapeId });
227
- break;
228
- }
229
- case 'clear-highlight': {
230
- broadcastToUI({ type: 'clear-highlight' });
231
- break;
232
- }
233
- case 'show-shape-properties': {
234
- broadcastToUI({ type: 'show-shape-properties', shapeId: msg.shapeId });
235
- break;
236
- }
237
- case 'export-scene': {
238
- try {
239
- const result = fluidCadServer.exportShapes(msg.shapeIds, msg.options);
240
- if (result) {
241
- const data = typeof result.data === 'string'
242
- ? Buffer.from(result.data, 'utf-8').toString('base64')
243
- : Buffer.from(result.data).toString('base64');
244
- sendToExtension({
245
- type: 'export-complete',
246
- success: true,
247
- data,
248
- fileName: result.fileName,
249
- });
250
- }
251
- else {
252
- sendToExtension({ type: 'export-complete', success: false, error: 'No active scene to export.' });
253
- }
254
- }
255
- catch (err) {
256
- sendToExtension({ type: 'export-complete', success: false, error: err.message || String(err) });
257
- }
258
- break;
259
- }
260
- }
261
- }
262
- catch (err) {
263
- sendToExtension({
264
- type: 'error',
265
- message: err.stack || err.message || String(err),
266
- });
267
- }
268
- }
269
- // Listen for IPC messages from extension host
270
- process.on('message', (msg) => {
271
- handleExtensionMessage(msg);
272
- });
273
- // ---------------------------------------------------------------------------
274
- // Start
275
- // ---------------------------------------------------------------------------
276
- httpServer.listen(PORT, () => {
277
- const url = `http://localhost:${PORT}`;
278
- console.log(`FluidCAD server listening on ${url}`);
279
- // Signal ready immediately so extension can show the webview
280
- sendToExtension({ type: 'ready', port: PORT, url });
281
- // Initialize FluidCAD server in the background
282
- fluidCadServer.init(WORKSPACE_PATH).then(() => {
283
- sendToExtension({ type: 'init-complete', success: true });
284
- broadcastToUI({ type: 'init-complete', success: true });
285
- }).catch((err) => {
286
- const error = err.stack || err.message || String(err);
287
- sendToExtension({ type: 'init-complete', success: false, error });
288
- broadcastToUI({ type: 'init-complete', success: false, error });
289
- });
290
- });
@@ -1,3 +0,0 @@
1
- import { Router } from 'express';
2
- import type { FluidCadServer } from '../fluidcad-server.ts';
3
- export declare function createActionsRouter(fluidCadServer: FluidCadServer, sendToExtension: (msg: any) => void, broadcastToUI: (msg: any) => void, workspacePath: string): Router;
@@ -1,100 +0,0 @@
1
- import { Router } from 'express';
2
- export function createActionsRouter(fluidCadServer, sendToExtension, broadcastToUI, workspacePath) {
3
- const router = Router();
4
- router.post('/hit-test', (req, res) => {
5
- const { shapeId, rayOrigin, rayDir, edgeThreshold } = req.body;
6
- if (typeof shapeId !== 'string' ||
7
- !Array.isArray(rayOrigin) || rayOrigin.length !== 3 ||
8
- !Array.isArray(rayDir) || rayDir.length !== 3 ||
9
- typeof edgeThreshold !== 'number') {
10
- res.status(400).json({ error: 'Invalid request body' });
11
- return;
12
- }
13
- const result = fluidCadServer.hitTest(shapeId, rayOrigin, rayDir, edgeThreshold);
14
- res.json(result);
15
- });
16
- router.post('/insert-point', (req, res) => {
17
- const { point, sourceLocation } = req.body;
18
- if (!Array.isArray(point) || point.length !== 2 ||
19
- !sourceLocation || typeof sourceLocation.line !== 'number' || typeof sourceLocation.column !== 'number') {
20
- res.status(400).json({ error: 'Invalid request body' });
21
- return;
22
- }
23
- sendToExtension({
24
- type: 'insert-point',
25
- point: point,
26
- sourceLocation,
27
- });
28
- res.json({ success: true });
29
- });
30
- router.post('/remove-point', (req, res) => {
31
- const { point, sourceLocation } = req.body;
32
- if (!Array.isArray(point) || point.length !== 2 ||
33
- !sourceLocation || typeof sourceLocation.line !== 'number' || typeof sourceLocation.column !== 'number') {
34
- res.status(400).json({ error: 'Invalid request body' });
35
- return;
36
- }
37
- sendToExtension({
38
- type: 'remove-point',
39
- point: point,
40
- sourceLocation,
41
- });
42
- res.json({ success: true });
43
- });
44
- router.post('/rollback', async (req, res) => {
45
- const { index } = req.body;
46
- if (typeof index !== 'number' || index < 0) {
47
- res.status(400).json({ error: 'Invalid index' });
48
- return;
49
- }
50
- const data = await fluidCadServer.rollbackFromUI(index);
51
- if (!data) {
52
- res.status(404).json({ error: 'No active scene' });
53
- return;
54
- }
55
- sendToExtension({
56
- type: 'scene-rendered',
57
- absPath: data.absPath,
58
- result: data.result,
59
- rollbackStop: data.rollbackStop,
60
- });
61
- broadcastToUI({
62
- type: 'scene-rendered',
63
- result: data.result,
64
- absPath: data.absPath,
65
- rollbackStop: data.rollbackStop,
66
- });
67
- res.json({ success: true });
68
- });
69
- router.post('/set-pick-points', (req, res) => {
70
- const { points, sourceLocation } = req.body;
71
- if (!Array.isArray(points) ||
72
- !sourceLocation || typeof sourceLocation.line !== 'number' || typeof sourceLocation.column !== 'number') {
73
- res.status(400).json({ error: 'Invalid request body' });
74
- return;
75
- }
76
- sendToExtension({
77
- type: 'set-pick-points',
78
- points: points,
79
- sourceLocation,
80
- });
81
- res.json({ success: true });
82
- });
83
- router.post('/import-file', async (req, res) => {
84
- const { fileName, data } = req.body;
85
- if (typeof fileName !== 'string' || typeof data !== 'string') {
86
- res.status(400).json({ error: 'Invalid request body' });
87
- return;
88
- }
89
- try {
90
- await fluidCadServer.importFile(workspacePath, fileName, data);
91
- }
92
- catch (err) {
93
- res.status(500).json({ error: err.message || String(err) });
94
- return;
95
- }
96
- const loadName = fileName.replace(/\.(step|stp)$/i, '');
97
- res.json({ success: true, fileName: loadName });
98
- });
99
- return router;
100
- }
@@ -1,3 +0,0 @@
1
- import { Router } from 'express';
2
- import type { FluidCadServer } from '../fluidcad-server.ts';
3
- export declare function createExportRouter(fluidCadServer: FluidCadServer): Router;
@@ -1,55 +0,0 @@
1
- import { Router } from 'express';
2
- export function createExportRouter(fluidCadServer) {
3
- const router = Router();
4
- router.post('/export', (req, res) => {
5
- const { format, shapeIds, includeColors, resolution, customAngularDeflectionDeg, customLinearDeflection } = req.body;
6
- if (format !== 'step' && format !== 'stl') {
7
- res.status(400).json({ error: 'Invalid format. Must be "step" or "stl".' });
8
- return;
9
- }
10
- if (!Array.isArray(shapeIds) || shapeIds.length === 0) {
11
- res.status(400).json({ error: 'shapeIds must be a non-empty array.' });
12
- return;
13
- }
14
- if (format === 'stl') {
15
- const validResolutions = ['coarse', 'medium', 'fine', 'custom'];
16
- if (resolution && !validResolutions.includes(resolution)) {
17
- res.status(400).json({ error: 'Invalid resolution.' });
18
- return;
19
- }
20
- if (resolution === 'custom') {
21
- if (typeof customLinearDeflection !== 'number' || typeof customAngularDeflectionDeg !== 'number') {
22
- res.status(400).json({ error: 'Custom resolution requires customLinearDeflection and customAngularDeflectionDeg.' });
23
- return;
24
- }
25
- }
26
- }
27
- try {
28
- const result = fluidCadServer.exportShapes(shapeIds, {
29
- format,
30
- includeColors,
31
- resolution: resolution || 'medium',
32
- customLinearDeflection,
33
- customAngularDeflectionDeg,
34
- });
35
- if (!result) {
36
- res.status(404).json({ error: 'No active scene to export.' });
37
- return;
38
- }
39
- const ext = format === 'step' ? '.step' : '.stl';
40
- const mimeType = format === 'step' ? 'application/step' : 'application/sla';
41
- res.setHeader('Content-Type', mimeType);
42
- res.setHeader('Content-Disposition', `attachment; filename="export${ext}"`);
43
- if (typeof result.data === 'string') {
44
- res.send(Buffer.from(result.data, 'utf-8'));
45
- }
46
- else {
47
- res.send(Buffer.from(result.data));
48
- }
49
- }
50
- catch (err) {
51
- res.status(500).json({ error: err.message || String(err) });
52
- }
53
- });
54
- return router;
55
- }
@@ -1,3 +0,0 @@
1
- import { Router } from 'express';
2
- import type { FluidCadServer } from '../fluidcad-server.ts';
3
- export declare function createPropertiesRouter(fluidCadServer: FluidCadServer): Router;