@thatopen/services 0.7.0 → 0.9.0

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 (77) hide show
  1. package/README.md +62 -62
  2. package/dist/built-in/index.d.ts +66 -41
  3. package/dist/cli/lib/revit-addin.d.ts +8 -0
  4. package/dist/cli.js +154 -13
  5. package/dist/core/client.d.ts +6 -0
  6. package/dist/core/platform-client.d.ts +139 -0
  7. package/dist/core/platform-client.live.test.d.ts +1 -0
  8. package/dist/core/platform-client.notifications.test.d.ts +1 -0
  9. package/dist/index.cjs.js +2 -2
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.es.js +635 -445
  12. package/dist/types/notifications.d.ts +54 -0
  13. package/dist/vite-env.d.ts +1 -1
  14. package/docs/ai-quickstart.md +120 -1
  15. package/docs/cli/create.md +29 -29
  16. package/docs/cli/local-server.md +38 -38
  17. package/docs/cli/login.md +32 -32
  18. package/docs/cli/publish.md +31 -31
  19. package/docs/cli/run.md +26 -26
  20. package/docs/cli/serve.md +43 -43
  21. package/docs/cli/swap.md +30 -30
  22. package/docs/flow-plugin-guide.md +26 -0
  23. package/docs/revit-collab-quickstart.md +26 -17
  24. package/docs/rhino-interop-quickstart.md +74 -7
  25. package/package.json +1 -1
  26. package/resources/AGENTS.md +40 -40
  27. package/src/built-in/CDEManager/example.ts +214 -214
  28. package/src/built-in/CDEManager/examples/FileEditing/example.ts +226 -226
  29. package/src/built-in/CDEManager/examples/FileMoves/example.ts +186 -186
  30. package/src/built-in/CDEManager/examples/FileOperations/example.ts +295 -295
  31. package/src/built-in/CDEManager/examples/FileTransfers/example.ts +210 -210
  32. package/src/built-in/CDEManager/examples/FolderManagement/example.ts +230 -230
  33. package/src/built-in/CDEManager/examples/MetadataSchema/example.ts +230 -230
  34. package/src/built-in/CDEManager/examples/MetadataViews/example.ts +166 -166
  35. package/src/built-in/CDEManager/examples/ProjectConfig/example.ts +177 -177
  36. package/src/built-in/UIManager/src/app/example.ts +97 -97
  37. package/src/built-in/UIManager/src/app/examples/AppState/example.ts +140 -140
  38. package/src/built-in/UIManager/src/app/examples/Banner/example.ts +159 -159
  39. package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +123 -123
  40. package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +124 -124
  41. package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +90 -90
  42. package/src/built-in/UIManager/src/app/examples/Modal/example.ts +163 -163
  43. package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +133 -133
  44. package/src/built-in/UIManager/src/app/examples/ProjectFileStorage/example.ts +150 -150
  45. package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +102 -102
  46. package/src/built-in/UIManager/src/clashes-panel/example.ts +183 -183
  47. package/src/built-in/UIManager/src/git-history-panel/example.ts +70 -70
  48. package/src/built-in/UIManager/src/models-list/example.ts +122 -122
  49. package/src/built-in/UIManager/src/topics-panel/example.ts +170 -170
  50. package/src/built-in/index.ts +66 -41
  51. package/src/cli/templates/app/index.html +35 -35
  52. package/src/cli/templates/app/package.json +32 -32
  53. package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -95
  54. package/src/cli/templates/app/src/bim-components/CloudRunner/src/index.ts +1 -1
  55. package/src/cli/templates/app/src/bim-components/CloudRunner/src/types.ts +5 -5
  56. package/src/cli/templates/app/src/bim-components/index.ts +1 -1
  57. package/src/cli/templates/app/src/globals.ts +1 -1
  58. package/src/cli/templates/app/src/main.history.ts +191 -0
  59. package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -26
  60. package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -1
  61. package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -15
  62. package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -37
  63. package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -1
  64. package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -14
  65. package/src/cli/templates/app/src/ui-components/index.ts +2 -2
  66. package/src/cli/templates/app/tsconfig.json +16 -16
  67. package/src/cli/templates/app/vite.config.js +57 -57
  68. package/src/cli/templates/cloud-component/README.md +205 -205
  69. package/src/cli/templates/cloud-component/_thatopen +5 -5
  70. package/src/cli/templates/cloud-component/declarations.json +4 -4
  71. package/src/cli/templates/cloud-component/package.json +21 -21
  72. package/src/cli/templates/cloud-component/src/main.ts +70 -70
  73. package/src/cli/templates/cloud-component/tsconfig.json +16 -16
  74. package/src/cli/templates/cloud-component/vite.config.js +46 -46
  75. package/src/cli/templates/shared/AGENTS.md +8 -8
  76. package/src/cli/templates/shared/CLAUDE.md +1 -1
  77. package/src/cli/templates/shared/_gitignore +5 -5
@@ -1,186 +1,186 @@
1
- /* MD
2
- ## Drag-and-drop file and folder moves
3
- ---
4
- A coordinator restructures the project after a scope change: structural files move
5
- from the root into a dedicated discipline folder, a MEP sub-folder needs to be
6
- promoted to the top level, and a few documents need to come back to root to appear
7
- in the general view. Drag-and-drop is the natural gesture for all of this, but
8
- each drag session has intermediate stages — the file is "in the air", hovering over
9
- a candidate target — and every panel watching the file table should see the right
10
- state without coordinating directly with the drag component.
11
-
12
- CDEManager models drag-and-drop as a sequence of typed state transitions. Picking
13
- up files moves the machine to a dragging state that carries the files being dragged
14
- and where they came from. Dropping onto a target kicks off the API call and advances
15
- to a moving state. Releasing outside any drop zone cancels the drag and returns the
16
- machine to exactly the state it was in before the drag started — idle or a selection.
17
- Folder drags work the same way, with their own separate completion event.
18
-
19
- This tutorial covers starting a file drag from idle and from an active selection;
20
- cancelling the drag and confirming which state the machine returns to; committing
21
- a drop onto a folder and reading the moved files from the completion event; moving
22
- files back to the project root by passing a null target folder; and starting,
23
- cancelling, and committing a folder drag.
24
-
25
- By the end, you'll have a working demonstration of the full drag-and-drop cycle for
26
- both files and folders — start, cancel, and commit — with all state transitions and
27
- completion events verified against mock data.
28
- */
29
-
30
- import * as OBC from "@thatopen/components";
31
- // In production platform apps, CDEManager is loaded through the platform client:
32
- // const cde = await client.initBuiltInComponent(CDEManager.uuid, components);
33
- // Here we import directly from source for local testing.
34
- import { CDEManager } from "../../index";
35
- import type { CDEFile } from "../../src/types";
36
-
37
- /* MD
38
- ### 🛠️ Setting up
39
- File and folder moves are permission-gated, so we simulate the platform startup step
40
- that loads user permissions. The mock client also provides `updateItem` for file
41
- moves and `resolveAccessToken` for folder moves, which use different backend paths.
42
- */
43
-
44
- const components = new OBC.Components();
45
- const cde = components.get(CDEManager);
46
-
47
- const output = document.getElementById("output") as HTMLPreElement;
48
- const log = (msg: string) => { console.log(msg); output.textContent += msg + "\n"; };
49
-
50
- const mockClient = {
51
- checkPermissionBatch: async () => Array(5).fill({ hasPermission: true }),
52
- getProjectData: async () => ({ project: { title: "" }, users: [] }),
53
- listFolders: async () => [],
54
- updateItem: async (_id: string, _updates: any) => ({}),
55
- resolveAccessToken: async () => "mock-token",
56
- context: { apiUrl: "https://mock.api" },
57
- };
58
-
59
- cde.ctx = { client: mockClient as any, projectId: "mock" };
60
- await cde.loadFolders();
61
-
62
- const folders = [
63
- { _id: "folder-str", name: "Structural", parentId: null },
64
- { _id: "folder-arch", name: "Architecture", parentId: null },
65
- { _id: "folder-mep", name: "MEP", parentId: "folder-arch" },
66
- ];
67
- cde.folders = folders as any;
68
-
69
- const now = new Date();
70
- const mockFiles: CDEFile[] = [
71
- { _id: "f1", name: "column.ifc", folderId: null, createdBy: "alice", createdAt: now, metadata: {} } as CDEFile,
72
- { _id: "f2", name: "foundations.ifc", folderId: null, createdBy: "alice", createdAt: now, metadata: {} } as CDEFile,
73
- { _id: "f3", name: "duct.ifc", folderId: "folder-arch", createdBy: "bob", createdAt: now, metadata: {} } as CDEFile,
74
- ];
75
- cde.files = mockFiles;
76
-
77
- cde.onMachineStateChanged.add((s) => log(` → ${s.kind}`));
78
- cde.onFilesMovedCompleted.add(({ files, targetFolderName }) =>
79
- log(` [onFilesMovedCompleted] ${files.length} file(s) → "${targetFolderName ?? "root"}"`)
80
- );
81
- cde.onFolderMovedCompleted.add(({ folderName, targetFolderName }) =>
82
- log(` [onFolderMovedCompleted] "${folderName}" → "${targetFolderName ?? "root"}"`)
83
- );
84
-
85
- /* MD
86
- ### 🖱️ File drag — cancel
87
- Starting a drag records the dragged files and the folder they came from. Cancelling
88
- — for example when the user releases the mouse outside any drop target — returns the
89
- machine to the state it was in when the drag started. If the drag started from idle,
90
- it returns to idle. If it started from a selection, the same selection is restored.
91
- */
92
-
93
- log("\n--- file drag: cancel from idle ---");
94
- cde.sendMachineEvent({ type: "START_DRAG", files: [mockFiles[0]], sourceFolderId: null });
95
-
96
- if (cde.machineState.kind === "dragging") {
97
- log(` dragging: ${cde.machineState.files.length} file(s) from "${cde.machineState.sourceFolderId ?? "root"}"`);
98
- }
99
-
100
- cde.sendMachineEvent({ type: "END_DRAG" });
101
- log(` state after cancel: ${cde.machineState.kind}`);
102
-
103
- log("\n--- file drag: cancel from selection ---");
104
- cde.sendMachineEvent({ type: "SELECT", files: [mockFiles[0], mockFiles[1]] });
105
- // Drag starts from "selected" — previousState carries the selection.
106
- cde.sendMachineEvent({ type: "START_DRAG", files: [mockFiles[0]], sourceFolderId: null });
107
- cde.sendMachineEvent({ type: "END_DRAG" });
108
- log(` state after cancel: ${cde.machineState.kind}`);
109
- if (cde.machineState.kind === "selected") {
110
- log(` selection preserved: ${cde.machineState.files.length} file(s)`);
111
- }
112
-
113
- /* MD
114
- ### 📁 File drag — drop onto a folder
115
- When the user drops files onto a valid folder target, the machine moves to a moving
116
- state and the API call runs. On completion, the moved files reflect their new folder
117
- and the machine returns to idle. The completion event carries both the updated files
118
- and the target folder name, so the UI can show a confirmation without reading the
119
- whole file list.
120
- */
121
-
122
- log("\n--- file drag: drop onto folder ---");
123
- cde.sendMachineEvent({ type: "DESELECT" });
124
- cde.sendMachineEvent({ type: "START_DRAG", files: [mockFiles[0], mockFiles[1]], sourceFolderId: null });
125
-
126
- await new Promise<void>(resolve => {
127
- cde.onFilesMovedCompleted.add(() => resolve());
128
- cde.sendMachineEvent({ type: "DROP_FILES", targetFolderId: "folder-str" });
129
- });
130
-
131
- log(` state after move: ${cde.machineState.kind}`);
132
- const f1Updated = cde.files.find(f => f._id === "f1")!;
133
- log(` f1 folderId: ${(f1Updated as any).folderId}`);
134
-
135
- /* MD
136
- ### 🏠 File drag — drop at root
137
- Dropping files without specifying a target folder moves them to the project root.
138
- The completion event's `targetFolderName` is null for root drops, which the UI can
139
- use to display "Moved to root" instead of a folder name.
140
- */
141
-
142
- log("\n--- file drag: drop at root ---");
143
- cde.sendMachineEvent({ type: "START_DRAG", files: [mockFiles[2]], sourceFolderId: "folder-arch" });
144
-
145
- await new Promise<void>(resolve => {
146
- cde.onFilesMovedCompleted.add(() => resolve());
147
- cde.sendMachineEvent({ type: "DROP_FILES", targetFolderId: null });
148
- });
149
-
150
- log(` state after move: ${cde.machineState.kind}`);
151
- const f3Updated = cde.files.find(f => f._id === "f3")!;
152
- log(` f3 folderId: ${(f3Updated as any).folderId ?? "root"}`);
153
-
154
- /* MD
155
- ### 📂 Folder drag — cancel and commit
156
- Folder drags follow the same state sequence as file drags. Cancelling a folder drag
157
- returns to the previous state unchanged. Committing calls a dedicated backend
158
- endpoint and fires a separate completion event with the folder names involved, which
159
- the UI uses for confirmation messages.
160
- */
161
-
162
- log("\n--- folder drag: cancel ---");
163
- cde.sendMachineEvent({ type: "START_FOLDER_DRAG", folderId: "folder-mep", parentFolderId: "folder-arch" });
164
-
165
- if (cde.machineState.kind === "draggingFolder") {
166
- log(` draggingFolder: "${cde.machineState.folderId}"`);
167
- }
168
-
169
- cde.sendMachineEvent({ type: "END_FOLDER_DRAG" });
170
- log(` state after cancel: ${cde.machineState.kind}`);
171
-
172
- log("\n--- folder drag: commit ---");
173
- // _moveFolder calls fetch directly; intercept it for the mock.
174
- const realFetch = globalThis.fetch;
175
- globalThis.fetch = async () => new Response("{}", { status: 200 });
176
-
177
- cde.sendMachineEvent({ type: "START_FOLDER_DRAG", folderId: "folder-mep", parentFolderId: "folder-arch" });
178
-
179
- await new Promise<void>(resolve => {
180
- cde.onFolderMovedCompleted.add(() => resolve());
181
- // Move MEP out of Architecture and into Structural.
182
- cde.sendMachineEvent({ type: "DROP_FOLDER", targetFolderId: "folder-str" });
183
- });
184
-
185
- globalThis.fetch = realFetch;
186
- log(` state after commit: ${cde.machineState.kind}`);
1
+ /* MD
2
+ ## Drag-and-drop file and folder moves
3
+ ---
4
+ A coordinator restructures the project after a scope change: structural files move
5
+ from the root into a dedicated discipline folder, a MEP sub-folder needs to be
6
+ promoted to the top level, and a few documents need to come back to root to appear
7
+ in the general view. Drag-and-drop is the natural gesture for all of this, but
8
+ each drag session has intermediate stages — the file is "in the air", hovering over
9
+ a candidate target — and every panel watching the file table should see the right
10
+ state without coordinating directly with the drag component.
11
+
12
+ CDEManager models drag-and-drop as a sequence of typed state transitions. Picking
13
+ up files moves the machine to a dragging state that carries the files being dragged
14
+ and where they came from. Dropping onto a target kicks off the API call and advances
15
+ to a moving state. Releasing outside any drop zone cancels the drag and returns the
16
+ machine to exactly the state it was in before the drag started — idle or a selection.
17
+ Folder drags work the same way, with their own separate completion event.
18
+
19
+ This tutorial covers starting a file drag from idle and from an active selection;
20
+ cancelling the drag and confirming which state the machine returns to; committing
21
+ a drop onto a folder and reading the moved files from the completion event; moving
22
+ files back to the project root by passing a null target folder; and starting,
23
+ cancelling, and committing a folder drag.
24
+
25
+ By the end, you'll have a working demonstration of the full drag-and-drop cycle for
26
+ both files and folders — start, cancel, and commit — with all state transitions and
27
+ completion events verified against mock data.
28
+ */
29
+
30
+ import * as OBC from "@thatopen/components";
31
+ // In production platform apps, CDEManager is loaded through the platform client:
32
+ // const cde = await client.initBuiltInComponent(CDEManager.uuid, components);
33
+ // Here we import directly from source for local testing.
34
+ import { CDEManager } from "../../index";
35
+ import type { CDEFile } from "../../src/types";
36
+
37
+ /* MD
38
+ ### 🛠️ Setting up
39
+ File and folder moves are permission-gated, so we simulate the platform startup step
40
+ that loads user permissions. The mock client also provides `updateItem` for file
41
+ moves and `resolveAccessToken` for folder moves, which use different backend paths.
42
+ */
43
+
44
+ const components = new OBC.Components();
45
+ const cde = components.get(CDEManager);
46
+
47
+ const output = document.getElementById("output") as HTMLPreElement;
48
+ const log = (msg: string) => { console.log(msg); output.textContent += msg + "\n"; };
49
+
50
+ const mockClient = {
51
+ checkPermissionBatch: async () => Array(5).fill({ hasPermission: true }),
52
+ getProjectData: async () => ({ project: { title: "" }, users: [] }),
53
+ listFolders: async () => [],
54
+ updateItem: async (_id: string, _updates: any) => ({}),
55
+ resolveAccessToken: async () => "mock-token",
56
+ context: { apiUrl: "https://mock.api" },
57
+ };
58
+
59
+ cde.ctx = { client: mockClient as any, projectId: "mock" };
60
+ await cde.loadFolders();
61
+
62
+ const folders = [
63
+ { _id: "folder-str", name: "Structural", parentId: null },
64
+ { _id: "folder-arch", name: "Architecture", parentId: null },
65
+ { _id: "folder-mep", name: "MEP", parentId: "folder-arch" },
66
+ ];
67
+ cde.folders = folders as any;
68
+
69
+ const now = new Date();
70
+ const mockFiles: CDEFile[] = [
71
+ { _id: "f1", name: "column.ifc", folderId: null, createdBy: "alice", createdAt: now, metadata: {} } as CDEFile,
72
+ { _id: "f2", name: "foundations.ifc", folderId: null, createdBy: "alice", createdAt: now, metadata: {} } as CDEFile,
73
+ { _id: "f3", name: "duct.ifc", folderId: "folder-arch", createdBy: "bob", createdAt: now, metadata: {} } as CDEFile,
74
+ ];
75
+ cde.files = mockFiles;
76
+
77
+ cde.onMachineStateChanged.add((s) => log(` → ${s.kind}`));
78
+ cde.onFilesMovedCompleted.add(({ files, targetFolderName }) =>
79
+ log(` [onFilesMovedCompleted] ${files.length} file(s) → "${targetFolderName ?? "root"}"`)
80
+ );
81
+ cde.onFolderMovedCompleted.add(({ folderName, targetFolderName }) =>
82
+ log(` [onFolderMovedCompleted] "${folderName}" → "${targetFolderName ?? "root"}"`)
83
+ );
84
+
85
+ /* MD
86
+ ### 🖱️ File drag — cancel
87
+ Starting a drag records the dragged files and the folder they came from. Cancelling
88
+ — for example when the user releases the mouse outside any drop target — returns the
89
+ machine to the state it was in when the drag started. If the drag started from idle,
90
+ it returns to idle. If it started from a selection, the same selection is restored.
91
+ */
92
+
93
+ log("\n--- file drag: cancel from idle ---");
94
+ cde.sendMachineEvent({ type: "START_DRAG", files: [mockFiles[0]], sourceFolderId: null });
95
+
96
+ if (cde.machineState.kind === "dragging") {
97
+ log(` dragging: ${cde.machineState.files.length} file(s) from "${cde.machineState.sourceFolderId ?? "root"}"`);
98
+ }
99
+
100
+ cde.sendMachineEvent({ type: "END_DRAG" });
101
+ log(` state after cancel: ${cde.machineState.kind}`);
102
+
103
+ log("\n--- file drag: cancel from selection ---");
104
+ cde.sendMachineEvent({ type: "SELECT", files: [mockFiles[0], mockFiles[1]] });
105
+ // Drag starts from "selected" — previousState carries the selection.
106
+ cde.sendMachineEvent({ type: "START_DRAG", files: [mockFiles[0]], sourceFolderId: null });
107
+ cde.sendMachineEvent({ type: "END_DRAG" });
108
+ log(` state after cancel: ${cde.machineState.kind}`);
109
+ if (cde.machineState.kind === "selected") {
110
+ log(` selection preserved: ${cde.machineState.files.length} file(s)`);
111
+ }
112
+
113
+ /* MD
114
+ ### 📁 File drag — drop onto a folder
115
+ When the user drops files onto a valid folder target, the machine moves to a moving
116
+ state and the API call runs. On completion, the moved files reflect their new folder
117
+ and the machine returns to idle. The completion event carries both the updated files
118
+ and the target folder name, so the UI can show a confirmation without reading the
119
+ whole file list.
120
+ */
121
+
122
+ log("\n--- file drag: drop onto folder ---");
123
+ cde.sendMachineEvent({ type: "DESELECT" });
124
+ cde.sendMachineEvent({ type: "START_DRAG", files: [mockFiles[0], mockFiles[1]], sourceFolderId: null });
125
+
126
+ await new Promise<void>(resolve => {
127
+ cde.onFilesMovedCompleted.add(() => resolve());
128
+ cde.sendMachineEvent({ type: "DROP_FILES", targetFolderId: "folder-str" });
129
+ });
130
+
131
+ log(` state after move: ${cde.machineState.kind}`);
132
+ const f1Updated = cde.files.find(f => f._id === "f1")!;
133
+ log(` f1 folderId: ${(f1Updated as any).folderId}`);
134
+
135
+ /* MD
136
+ ### 🏠 File drag — drop at root
137
+ Dropping files without specifying a target folder moves them to the project root.
138
+ The completion event's `targetFolderName` is null for root drops, which the UI can
139
+ use to display "Moved to root" instead of a folder name.
140
+ */
141
+
142
+ log("\n--- file drag: drop at root ---");
143
+ cde.sendMachineEvent({ type: "START_DRAG", files: [mockFiles[2]], sourceFolderId: "folder-arch" });
144
+
145
+ await new Promise<void>(resolve => {
146
+ cde.onFilesMovedCompleted.add(() => resolve());
147
+ cde.sendMachineEvent({ type: "DROP_FILES", targetFolderId: null });
148
+ });
149
+
150
+ log(` state after move: ${cde.machineState.kind}`);
151
+ const f3Updated = cde.files.find(f => f._id === "f3")!;
152
+ log(` f3 folderId: ${(f3Updated as any).folderId ?? "root"}`);
153
+
154
+ /* MD
155
+ ### 📂 Folder drag — cancel and commit
156
+ Folder drags follow the same state sequence as file drags. Cancelling a folder drag
157
+ returns to the previous state unchanged. Committing calls a dedicated backend
158
+ endpoint and fires a separate completion event with the folder names involved, which
159
+ the UI uses for confirmation messages.
160
+ */
161
+
162
+ log("\n--- folder drag: cancel ---");
163
+ cde.sendMachineEvent({ type: "START_FOLDER_DRAG", folderId: "folder-mep", parentFolderId: "folder-arch" });
164
+
165
+ if (cde.machineState.kind === "draggingFolder") {
166
+ log(` draggingFolder: "${cde.machineState.folderId}"`);
167
+ }
168
+
169
+ cde.sendMachineEvent({ type: "END_FOLDER_DRAG" });
170
+ log(` state after cancel: ${cde.machineState.kind}`);
171
+
172
+ log("\n--- folder drag: commit ---");
173
+ // _moveFolder calls fetch directly; intercept it for the mock.
174
+ const realFetch = globalThis.fetch;
175
+ globalThis.fetch = async () => new Response("{}", { status: 200 });
176
+
177
+ cde.sendMachineEvent({ type: "START_FOLDER_DRAG", folderId: "folder-mep", parentFolderId: "folder-arch" });
178
+
179
+ await new Promise<void>(resolve => {
180
+ cde.onFolderMovedCompleted.add(() => resolve());
181
+ // Move MEP out of Architecture and into Structural.
182
+ cde.sendMachineEvent({ type: "DROP_FOLDER", targetFolderId: "folder-str" });
183
+ });
184
+
185
+ globalThis.fetch = realFetch;
186
+ log(` state after commit: ${cde.machineState.kind}`);