@ifc-lite/viewer 1.14.2 → 1.14.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 (80) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/dist/assets/{Arrow.dom-CSgnLhN4.js → Arrow.dom-_vGzMMKs.js} +1 -1
  3. package/dist/assets/basketViewActivator-BZcoCL3V.js +1 -0
  4. package/dist/assets/{browser-qSKWrKQW.js → browser-Czmf34bo.js} +1 -1
  5. package/dist/assets/ifc-lite_bg-DyBKoGgk.wasm +0 -0
  6. package/dist/assets/index-CMQ_Dgkr.css +1 -0
  7. package/dist/assets/index-D7nEDctQ.js +229 -0
  8. package/dist/assets/{index-4Y4XaV8N.js → index-DX-Qf5fA.js} +72669 -61673
  9. package/dist/assets/{native-bridge-CSFDsEkg.js → native-bridge-DAOWftxE.js} +1 -1
  10. package/dist/assets/{wasm-bridge-Zf90ysEm.js → wasm-bridge-D7jYpn8a.js} +1 -1
  11. package/dist/index.html +2 -2
  12. package/package.json +21 -20
  13. package/src/App.tsx +17 -1
  14. package/src/components/viewer/BasketPresentationDock.tsx +8 -4
  15. package/src/components/viewer/ChatPanel.tsx +1402 -0
  16. package/src/components/viewer/CodeEditor.tsx +70 -4
  17. package/src/components/viewer/CommandPalette.tsx +1 -0
  18. package/src/components/viewer/HierarchyPanel.tsx +28 -13
  19. package/src/components/viewer/MainToolbar.tsx +113 -95
  20. package/src/components/viewer/ScriptPanel.tsx +351 -184
  21. package/src/components/viewer/UpgradePage.tsx +69 -0
  22. package/src/components/viewer/Viewport.tsx +23 -0
  23. package/src/components/viewer/chat/ChatMessage.tsx +144 -0
  24. package/src/components/viewer/chat/ExecutableCodeBlock.tsx +416 -0
  25. package/src/components/viewer/chat/ModelSelector.tsx +102 -0
  26. package/src/components/viewer/chat/renderTextContent.test.ts +23 -0
  27. package/src/components/viewer/chat/renderTextContent.ts +19 -0
  28. package/src/components/viewer/hierarchy/HierarchyNode.tsx +10 -3
  29. package/src/components/viewer/hierarchy/treeDataBuilder.test.ts +126 -0
  30. package/src/components/viewer/hierarchy/treeDataBuilder.ts +139 -38
  31. package/src/components/viewer/hierarchy/types.ts +6 -1
  32. package/src/components/viewer/hierarchy/useHierarchyTree.ts +27 -12
  33. package/src/hooks/useIfcCache.ts +1 -2
  34. package/src/hooks/useSandbox.ts +122 -6
  35. package/src/index.css +10 -0
  36. package/src/lib/attachments.ts +46 -0
  37. package/src/lib/llm/ClerkChatSync.tsx +74 -0
  38. package/src/lib/llm/clerk-auth.ts +62 -0
  39. package/src/lib/llm/code-extractor.ts +50 -0
  40. package/src/lib/llm/context-builder.test.ts +18 -0
  41. package/src/lib/llm/context-builder.ts +305 -0
  42. package/src/lib/llm/free-models.test.ts +118 -0
  43. package/src/lib/llm/message-capabilities.test.ts +131 -0
  44. package/src/lib/llm/message-capabilities.ts +94 -0
  45. package/src/lib/llm/models.ts +197 -0
  46. package/src/lib/llm/repair-loop.test.ts +91 -0
  47. package/src/lib/llm/repair-loop.ts +76 -0
  48. package/src/lib/llm/script-diagnostics.ts +445 -0
  49. package/src/lib/llm/script-edit-ops.test.ts +399 -0
  50. package/src/lib/llm/script-edit-ops.ts +954 -0
  51. package/src/lib/llm/script-preflight.test.ts +513 -0
  52. package/src/lib/llm/script-preflight.ts +990 -0
  53. package/src/lib/llm/script-preservation.test.ts +128 -0
  54. package/src/lib/llm/script-preservation.ts +152 -0
  55. package/src/lib/llm/stream-client.test.ts +97 -0
  56. package/src/lib/llm/stream-client.ts +410 -0
  57. package/src/lib/llm/system-prompt.test.ts +181 -0
  58. package/src/lib/llm/system-prompt.ts +665 -0
  59. package/src/lib/llm/types.ts +150 -0
  60. package/src/lib/scripts/templates/bim-globals.d.ts +226 -7
  61. package/src/lib/scripts/templates/create-building.ts +12 -12
  62. package/src/main.tsx +10 -1
  63. package/src/sdk/adapters/export-adapter.test.ts +24 -0
  64. package/src/sdk/adapters/export-adapter.ts +40 -16
  65. package/src/sdk/adapters/files-adapter.ts +39 -0
  66. package/src/sdk/adapters/model-compat.ts +1 -1
  67. package/src/sdk/adapters/mutate-adapter.ts +20 -6
  68. package/src/sdk/adapters/mutation-view.ts +112 -0
  69. package/src/sdk/adapters/query-adapter.ts +100 -4
  70. package/src/sdk/local-backend.ts +4 -0
  71. package/src/store/index.ts +15 -1
  72. package/src/store/slices/chatSlice.test.ts +325 -0
  73. package/src/store/slices/chatSlice.ts +468 -0
  74. package/src/store/slices/scriptSlice.test.ts +75 -0
  75. package/src/store/slices/scriptSlice.ts +256 -9
  76. package/src/vite-env.d.ts +10 -0
  77. package/vite.config.ts +21 -2
  78. package/dist/assets/ifc-lite_bg-BOvNXJA_.wasm +0 -0
  79. package/dist/assets/index-ByrFvN5A.css +0 -1
  80. package/dist/assets/index-CN7qDq7G.js +0 -216
@@ -10,8 +10,17 @@
10
10
  import type { StateCreator } from 'zustand';
11
11
  import type { SavedScript } from '../../lib/scripts/persistence.js';
12
12
  import { loadSavedScripts, saveScripts, validateScriptName, canCreateScript, isScriptWithinSizeLimit } from '../../lib/scripts/persistence.js';
13
+ import type { ScriptEditOperation, ScriptEditorSelection, ScriptEditorTextChange } from '../../lib/llm/types.js';
14
+ import { applyScriptEditOperations } from '../../lib/llm/script-edit-ops.js';
15
+ import type { ScriptDiagnostic } from '../../lib/llm/script-diagnostics.js';
16
+ import {
17
+ type ScriptMutationIntent,
18
+ type ScriptReplacementSource,
19
+ validateScriptReplacementCandidate,
20
+ } from '../../lib/llm/script-preservation.js';
13
21
 
14
22
  export type ScriptExecutionState = 'idle' | 'running' | 'error' | 'success';
23
+ const SCRIPT_PANEL_VISIBLE_STORAGE_KEY = 'ifc-lite-script-panel-visible';
15
24
 
16
25
  export interface LogEntry {
17
26
  level: 'log' | 'warn' | 'error' | 'info';
@@ -25,6 +34,42 @@ export interface ScriptResult {
25
34
  durationMs: number;
26
35
  }
27
36
 
37
+ export interface ScriptEditorApplyAdapter {
38
+ apply: (
39
+ nextContent: string,
40
+ selection: ScriptEditorSelection,
41
+ options?: { userEvent?: string; changes?: ScriptEditorTextChange[] },
42
+ ) => void;
43
+ undo: () => void;
44
+ redo: () => void;
45
+ }
46
+
47
+ export interface ScriptApplyResult {
48
+ ok: boolean;
49
+ error?: string;
50
+ appliedOpIds: string[];
51
+ status?: 'ok' | 'revision_conflict' | 'range_error' | 'semantic_error';
52
+ diagnostic?: ScriptDiagnostic;
53
+ }
54
+
55
+ export interface ScriptApplyOptions {
56
+ acceptedBaseRevision?: number;
57
+ baseContentSnapshot?: string;
58
+ priorAcceptedOps?: ScriptEditOperation[];
59
+ intent?: ScriptMutationIntent;
60
+ }
61
+
62
+ export interface ScriptFallbackOptions {
63
+ intent?: ScriptMutationIntent;
64
+ source?: ScriptReplacementSource;
65
+ }
66
+
67
+ export interface ScriptAssistantTurnSnapshot {
68
+ content: string;
69
+ selection: ScriptEditorSelection;
70
+ revision: number;
71
+ }
72
+
28
73
  export interface ScriptSlice {
29
74
  // State
30
75
  savedScripts: SavedScript[];
@@ -34,8 +79,16 @@ export interface ScriptSlice {
34
79
  scriptExecutionState: ScriptExecutionState;
35
80
  scriptLastResult: ScriptResult | null;
36
81
  scriptLastError: string | null;
82
+ scriptLastDiagnostics: ScriptDiagnostic[];
37
83
  scriptPanelVisible: boolean;
38
84
  scriptDeleteConfirmId: string | null;
85
+ scriptEditorRevision: number;
86
+ scriptEditorSelection: ScriptEditorSelection;
87
+ scriptAppliedOpIds: Set<string>;
88
+ scriptEditorApplyAdapter: ScriptEditorApplyAdapter | null;
89
+ scriptCanUndo: boolean;
90
+ scriptCanRedo: boolean;
91
+ scriptAssistantTurnSnapshot: ScriptAssistantTurnSnapshot | null;
39
92
 
40
93
  // Actions
41
94
  createScript: (name: string, code?: string) => string;
@@ -46,10 +99,22 @@ export interface ScriptSlice {
46
99
  setScriptEditorContent: (content: string) => void;
47
100
  setScriptExecutionState: (state: ScriptExecutionState) => void;
48
101
  setScriptResult: (result: ScriptResult | null) => void;
49
- setScriptError: (error: string | null) => void;
102
+ setScriptError: (error: string | null, diagnostics?: ScriptDiagnostic[]) => void;
103
+ setScriptDiagnostics: (diagnostics: ScriptDiagnostic[]) => void;
50
104
  setScriptPanelVisible: (visible: boolean) => void;
51
105
  toggleScriptPanel: () => void;
52
106
  setScriptDeleteConfirmId: (id: string | null) => void;
107
+ setScriptCursorContext: (selection: ScriptEditorSelection) => void;
108
+ registerScriptEditorApplyAdapter: (adapter: ScriptEditorApplyAdapter | null) => void;
109
+ applyScriptEditOps: (ops: ScriptEditOperation[], options?: ScriptApplyOptions) => ScriptApplyResult;
110
+ replaceScriptContentFallback: (content: string, options?: ScriptFallbackOptions) => ScriptApplyResult;
111
+ beginAssistantScriptTurn: () => void;
112
+ commitAssistantScriptTurn: () => void;
113
+ rollbackAssistantScriptTurn: () => void;
114
+ resetScriptEditorForNewChat: () => void;
115
+ setScriptHistoryState: (canUndo: boolean, canRedo: boolean) => void;
116
+ undoScriptEditor: () => void;
117
+ redoScriptEditor: () => void;
53
118
  }
54
119
 
55
120
  const DEFAULT_CODE = `// Write your BIM script here
@@ -71,6 +136,14 @@ for (const [type, count] of Object.entries(counts).sort((a, b) => b[1] - a[1]))
71
136
  }
72
137
  `;
73
138
 
139
+ function loadStoredScriptPanelVisible(): boolean {
140
+ try {
141
+ return localStorage.getItem(SCRIPT_PANEL_VISIBLE_STORAGE_KEY) === 'true';
142
+ } catch {
143
+ return false;
144
+ }
145
+ }
146
+
74
147
  export const createScriptSlice: StateCreator<ScriptSlice, [], [], ScriptSlice> = (set, get) => ({
75
148
  // Initial state
76
149
  savedScripts: loadSavedScripts(),
@@ -80,8 +153,16 @@ export const createScriptSlice: StateCreator<ScriptSlice, [], [], ScriptSlice> =
80
153
  scriptExecutionState: 'idle',
81
154
  scriptLastResult: null,
82
155
  scriptLastError: null,
83
- scriptPanelVisible: false,
156
+ scriptLastDiagnostics: [],
157
+ scriptPanelVisible: loadStoredScriptPanelVisible(),
84
158
  scriptDeleteConfirmId: null,
159
+ scriptEditorRevision: 0,
160
+ scriptEditorSelection: { from: 0, to: 0 },
161
+ scriptAppliedOpIds: new Set(),
162
+ scriptEditorApplyAdapter: null,
163
+ scriptCanUndo: false,
164
+ scriptCanRedo: false,
165
+ scriptAssistantTurnSnapshot: null,
85
166
 
86
167
  // Actions
87
168
  createScript: (name, code) => {
@@ -113,6 +194,9 @@ export const createScriptSlice: StateCreator<ScriptSlice, [], [], ScriptSlice> =
113
194
  activeScriptId: id,
114
195
  scriptEditorContent: script.code,
115
196
  scriptEditorDirty: false,
197
+ scriptEditorRevision: get().scriptEditorRevision + 1,
198
+ scriptEditorSelection: { from: script.code.length, to: script.code.length },
199
+ scriptAppliedOpIds: new Set(),
116
200
  });
117
201
  const result = saveScripts(updated);
118
202
  if (!result.ok) {
@@ -146,6 +230,9 @@ export const createScriptSlice: StateCreator<ScriptSlice, [], [], ScriptSlice> =
146
230
  scriptEditorContent,
147
231
  scriptEditorDirty: false,
148
232
  scriptDeleteConfirmId: null,
233
+ scriptEditorRevision: get().scriptEditorRevision + 1,
234
+ scriptEditorSelection: { from: scriptEditorContent.length, to: scriptEditorContent.length },
235
+ scriptAppliedOpIds: new Set(),
149
236
  });
150
237
  saveScripts(updated);
151
238
  },
@@ -176,7 +263,11 @@ export const createScriptSlice: StateCreator<ScriptSlice, [], [], ScriptSlice> =
176
263
  scriptEditorDirty: false,
177
264
  scriptLastResult: null,
178
265
  scriptLastError: null,
266
+ scriptLastDiagnostics: [],
179
267
  scriptExecutionState: 'idle',
268
+ scriptEditorRevision: get().scriptEditorRevision + 1,
269
+ scriptEditorSelection: { from: script.code.length, to: script.code.length },
270
+ scriptAppliedOpIds: new Set(),
180
271
  });
181
272
  return;
182
273
  }
@@ -187,32 +278,188 @@ export const createScriptSlice: StateCreator<ScriptSlice, [], [], ScriptSlice> =
187
278
  scriptEditorDirty: false,
188
279
  scriptLastResult: null,
189
280
  scriptLastError: null,
281
+ scriptLastDiagnostics: [],
190
282
  scriptExecutionState: 'idle',
283
+ scriptEditorRevision: get().scriptEditorRevision + 1,
284
+ scriptEditorSelection: { from: DEFAULT_CODE.length, to: DEFAULT_CODE.length },
285
+ scriptAppliedOpIds: new Set(),
191
286
  });
192
287
  },
193
288
 
194
289
  setScriptEditorContent: (scriptEditorContent) => {
195
- set({ scriptEditorContent, scriptEditorDirty: true });
290
+ set({
291
+ scriptEditorContent,
292
+ scriptEditorDirty: true,
293
+ scriptEditorRevision: get().scriptEditorRevision + 1,
294
+ scriptEditorSelection: { from: scriptEditorContent.length, to: scriptEditorContent.length },
295
+ scriptAppliedOpIds: new Set(),
296
+ });
196
297
  },
197
298
 
198
299
  setScriptExecutionState: (scriptExecutionState) => set({ scriptExecutionState }),
199
300
 
200
301
  setScriptResult: (scriptLastResult) =>
201
- set({ scriptLastResult, scriptLastError: null, scriptExecutionState: 'success' }),
302
+ set({ scriptLastResult, scriptLastError: null, scriptLastDiagnostics: [], scriptExecutionState: 'success' }),
202
303
 
203
304
  // Error and execution state are set independently — clearing an error
204
305
  // does NOT change execution state unless explicitly transitioned
205
- setScriptError: (scriptLastError) => {
306
+ setScriptError: (scriptLastError, scriptLastDiagnostics = []) => {
206
307
  if (scriptLastError) {
207
- set({ scriptLastError, scriptExecutionState: 'error' });
308
+ set({ scriptLastError, scriptLastDiagnostics, scriptExecutionState: 'error' });
208
309
  } else {
209
- set({ scriptLastError: null });
310
+ set({ scriptLastError: null, scriptLastDiagnostics: [] });
210
311
  }
211
312
  },
212
313
 
213
- setScriptPanelVisible: (scriptPanelVisible) => set({ scriptPanelVisible }),
314
+ setScriptDiagnostics: (scriptLastDiagnostics) => set({ scriptLastDiagnostics }),
214
315
 
215
- toggleScriptPanel: () => set((state) => ({ scriptPanelVisible: !state.scriptPanelVisible })),
316
+ setScriptPanelVisible: (scriptPanelVisible) => {
317
+ try { localStorage.setItem(SCRIPT_PANEL_VISIBLE_STORAGE_KEY, String(scriptPanelVisible)); } catch { /* ignore */ }
318
+ set({ scriptPanelVisible });
319
+ },
320
+
321
+ toggleScriptPanel: () => {
322
+ const next = !get().scriptPanelVisible;
323
+ try { localStorage.setItem(SCRIPT_PANEL_VISIBLE_STORAGE_KEY, String(next)); } catch { /* ignore */ }
324
+ set({ scriptPanelVisible: next });
325
+ },
216
326
 
217
327
  setScriptDeleteConfirmId: (scriptDeleteConfirmId) => set({ scriptDeleteConfirmId }),
328
+
329
+ setScriptCursorContext: (scriptEditorSelection) => set({ scriptEditorSelection }),
330
+
331
+ registerScriptEditorApplyAdapter: (scriptEditorApplyAdapter) => set({ scriptEditorApplyAdapter }),
332
+
333
+ applyScriptEditOps: (ops, options) => {
334
+ const state = get();
335
+ const result = applyScriptEditOperations({
336
+ content: state.scriptEditorContent,
337
+ selection: state.scriptEditorSelection,
338
+ revision: state.scriptEditorRevision,
339
+ operations: ops,
340
+ priorAcceptedOps: options?.priorAcceptedOps,
341
+ acceptedBaseRevision: options?.acceptedBaseRevision,
342
+ baseContentSnapshot: options?.baseContentSnapshot,
343
+ intent: options?.intent,
344
+ });
345
+
346
+ if (!result.ok) {
347
+ return {
348
+ ok: false,
349
+ error: result.error,
350
+ appliedOpIds: [],
351
+ status: result.status,
352
+ diagnostic: result.diagnostic,
353
+ };
354
+ }
355
+
356
+ const appliedSet = new Set(state.scriptAppliedOpIds);
357
+ result.appliedOpIds.forEach((id) => appliedSet.add(id));
358
+ state.scriptEditorApplyAdapter?.apply(result.content, result.selection, {
359
+ userEvent: 'assistant-turn',
360
+ changes: result.changes,
361
+ });
362
+ set({
363
+ scriptEditorContent: result.content,
364
+ scriptEditorSelection: result.selection,
365
+ scriptEditorRevision: result.revision,
366
+ scriptEditorDirty: true,
367
+ scriptAppliedOpIds: appliedSet,
368
+ });
369
+ return { ok: true, appliedOpIds: result.appliedOpIds, status: result.status };
370
+ },
371
+
372
+ replaceScriptContentFallback: (scriptEditorContent, options) => {
373
+ const state = get();
374
+ const replacementCheck = validateScriptReplacementCandidate({
375
+ previousContent: state.scriptEditorContent,
376
+ candidateContent: scriptEditorContent,
377
+ intent: options?.intent ?? 'create',
378
+ source: options?.source ?? 'code_block_fallback',
379
+ });
380
+ if (!replacementCheck.ok) {
381
+ return {
382
+ ok: false,
383
+ error: replacementCheck.diagnostic?.message,
384
+ appliedOpIds: [],
385
+ status: 'semantic_error',
386
+ diagnostic: replacementCheck.diagnostic,
387
+ };
388
+ }
389
+
390
+ const nextRevision = state.scriptEditorRevision + 1;
391
+ const selection = { from: scriptEditorContent.length, to: scriptEditorContent.length };
392
+ state.scriptEditorApplyAdapter?.apply(scriptEditorContent, selection, { userEvent: 'assistant-turn' });
393
+ set({
394
+ scriptEditorContent,
395
+ scriptEditorDirty: true,
396
+ scriptEditorRevision: nextRevision,
397
+ scriptEditorSelection: selection,
398
+ scriptAppliedOpIds: new Set(),
399
+ });
400
+ return { ok: true, appliedOpIds: [], status: 'ok' };
401
+ },
402
+
403
+ beginAssistantScriptTurn: () => {
404
+ const state = get();
405
+ set({
406
+ scriptAssistantTurnSnapshot: {
407
+ content: state.scriptEditorContent,
408
+ selection: state.scriptEditorSelection,
409
+ revision: state.scriptEditorRevision,
410
+ },
411
+ });
412
+ },
413
+
414
+ commitAssistantScriptTurn: () => {
415
+ set({ scriptAssistantTurnSnapshot: null });
416
+ },
417
+
418
+ rollbackAssistantScriptTurn: () => {
419
+ const state = get();
420
+ const snapshot = state.scriptAssistantTurnSnapshot;
421
+ if (!snapshot) return;
422
+ state.scriptEditorApplyAdapter?.apply(snapshot.content, snapshot.selection, { userEvent: 'assistant-turn' });
423
+ set({
424
+ scriptEditorContent: snapshot.content,
425
+ scriptEditorSelection: snapshot.selection,
426
+ scriptEditorRevision: snapshot.revision,
427
+ scriptEditorDirty: true,
428
+ scriptAppliedOpIds: new Set(),
429
+ scriptAssistantTurnSnapshot: null,
430
+ });
431
+ },
432
+
433
+ resetScriptEditorForNewChat: () => {
434
+ const state = get();
435
+ const scriptEditorContent = '';
436
+ const scriptEditorSelection = { from: 0, to: 0 };
437
+ state.scriptEditorApplyAdapter?.apply(scriptEditorContent, scriptEditorSelection, {
438
+ userEvent: 'new-chat-reset',
439
+ });
440
+ set({
441
+ activeScriptId: null,
442
+ scriptEditorContent,
443
+ scriptEditorDirty: false,
444
+ scriptExecutionState: 'idle',
445
+ scriptLastResult: null,
446
+ scriptLastError: null,
447
+ scriptLastDiagnostics: [],
448
+ scriptDeleteConfirmId: null,
449
+ scriptEditorRevision: state.scriptEditorRevision + 1,
450
+ scriptEditorSelection,
451
+ scriptAppliedOpIds: new Set(),
452
+ scriptAssistantTurnSnapshot: null,
453
+ });
454
+ },
455
+
456
+ setScriptHistoryState: (scriptCanUndo, scriptCanRedo) => set({ scriptCanUndo, scriptCanRedo }),
457
+
458
+ undoScriptEditor: () => {
459
+ get().scriptEditorApplyAdapter?.undo();
460
+ },
461
+
462
+ redoScriptEditor: () => {
463
+ get().scriptEditorApplyAdapter?.redo();
464
+ },
218
465
  });
package/src/vite-env.d.ts CHANGED
@@ -11,6 +11,16 @@ interface ImportMetaEnv {
11
11
  readonly VITE_SERVER_URL?: string;
12
12
  /** Set to 'true' to route IFC loading through server instead of client-side WASM */
13
13
  readonly VITE_USE_SERVER?: string;
14
+ /** Comma-separated free-tier model IDs */
15
+ readonly VITE_LLM_FREE_MODELS?: string;
16
+ /** Comma-separated pro model IDs grouped by relative cost */
17
+ readonly VITE_LLM_PRO_MODELS_LOW?: string;
18
+ readonly VITE_LLM_PRO_MODELS_MEDIUM?: string;
19
+ readonly VITE_LLM_PRO_MODELS_HIGH?: string;
20
+ /** Comma-separated model IDs that support image inputs */
21
+ readonly VITE_LLM_IMAGE_MODELS?: string;
22
+ /** Comma-separated model IDs that support file attachment context */
23
+ readonly VITE_LLM_FILE_ATTACHMENT_MODELS?: string;
14
24
  }
15
25
 
16
26
  interface ImportMeta {
package/vite.config.ts CHANGED
@@ -183,6 +183,9 @@ export default defineConfig({
183
183
  '@ifc-lite/ifcx': path.resolve(__dirname, '../../packages/ifcx/src'),
184
184
  '@ifc-lite/wasm': path.resolve(__dirname, '../../packages/wasm/pkg/ifc-lite.js'),
185
185
  '@ifc-lite/sdk': path.resolve(__dirname, '../../packages/sdk/src'),
186
+ '@ifc-lite/create': path.resolve(__dirname, '../../packages/create/src'),
187
+ '@ifc-lite/sandbox/schema': path.resolve(__dirname, '../../packages/sandbox/src/bridge-schema.ts'),
188
+ '@ifc-lite/sandbox': path.resolve(__dirname, '../../packages/sandbox/src'),
186
189
  '@ifc-lite/lens': path.resolve(__dirname, '../../packages/lens/src'),
187
190
  '@ifc-lite/mutations': path.resolve(__dirname, '../../packages/mutations/src'),
188
191
  '@ifc-lite/bcf': path.resolve(__dirname, '../../packages/bcf/src'),
@@ -196,12 +199,20 @@ export default defineConfig({
196
199
  port: 3000,
197
200
  headers: {
198
201
  'Cross-Origin-Opener-Policy': 'same-origin',
199
- 'Cross-Origin-Embedder-Policy': 'require-corp',
202
+ // Allows third-party no-cors resources like Stripe.js while preserving
203
+ // cross-origin isolation in modern browsers.
204
+ 'Cross-Origin-Embedder-Policy': 'credentialless',
200
205
  },
201
206
  fs: {
202
207
  allow: ['../..'],
203
208
  },
204
209
  proxy: {
210
+ '/api/chat': {
211
+ // Single API source of truth lives at repo-root `api/chat.ts`.
212
+ // For local dev, run `pnpm dev:api` from repo root.
213
+ target: 'http://localhost:3001',
214
+ changeOrigin: true,
215
+ },
205
216
  '/api/bsdd': {
206
217
  target: 'https://api.bsdd.buildingsmart.org',
207
218
  changeOrigin: true,
@@ -211,9 +222,17 @@ export default defineConfig({
211
222
  },
212
223
  build: {
213
224
  target: 'esnext',
225
+ chunkSizeWarningLimit: 6000,
214
226
  },
215
227
  optimizeDeps: {
216
- exclude: ['@duckdb/duckdb-wasm', '@ifc-lite/wasm', 'parquet-wasm'],
228
+ exclude: [
229
+ '@duckdb/duckdb-wasm',
230
+ '@ifc-lite/wasm',
231
+ 'parquet-wasm',
232
+ 'quickjs-emscripten',
233
+ '@jitl/quickjs-wasmfile-release-asyncify',
234
+ 'esbuild-wasm',
235
+ ],
217
236
  },
218
237
  worker: {
219
238
  format: 'es',