@thatopen/services 0.0.4 → 0.0.5

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 (140) hide show
  1. package/README.md +24 -263
  2. package/dist/cli/commands/swap.d.ts +3 -0
  3. package/dist/cli/lib/beta.d.ts +2 -0
  4. package/dist/cli/lib/config.d.ts +2 -0
  5. package/dist/cli.js +85 -126
  6. package/dist/core/examples/apps.d.ts +1 -0
  7. package/dist/core/examples/components.d.ts +1 -0
  8. package/dist/core/examples/execution.d.ts +1 -0
  9. package/dist/core/examples/file-metadata.d.ts +1 -0
  10. package/dist/core/examples/files.d.ts +1 -0
  11. package/dist/core/examples/folders.d.ts +1 -0
  12. package/dist/core/examples/hidden-files.d.ts +1 -0
  13. package/dist/core/examples/icons.d.ts +1 -0
  14. package/dist/core/examples/permissions.d.ts +1 -0
  15. package/dist/types/items.d.ts +2 -0
  16. package/docs/builtin/paths.json +54 -0
  17. package/docs/cli/create.md +28 -0
  18. package/docs/cli/local-server.md +38 -0
  19. package/docs/cli/login.md +32 -0
  20. package/docs/cli/paths.json +30 -0
  21. package/docs/cli/publish.md +31 -0
  22. package/docs/cli/run.md +26 -0
  23. package/docs/cli/serve.md +43 -0
  24. package/docs/cli/swap.md +30 -0
  25. package/docs/client/paths.json +38 -0
  26. package/package.json +8 -10
  27. package/resources/AGENTS.md +39 -0
  28. package/src/built-in/AppManager/example.ts +86 -0
  29. package/src/built-in/CDEManager/example.ts +214 -0
  30. package/src/built-in/CDEManager/examples/FileEditing/example.ts +226 -0
  31. package/src/built-in/CDEManager/examples/FileMoves/example.ts +186 -0
  32. package/src/built-in/CDEManager/examples/FileOperations/example.ts +295 -0
  33. package/src/built-in/CDEManager/examples/FileTransfers/example.ts +210 -0
  34. package/src/built-in/CDEManager/examples/FolderManagement/example.ts +230 -0
  35. package/src/built-in/CDEManager/examples/MetadataSchema/example.ts +230 -0
  36. package/src/built-in/CDEManager/examples/MetadataViews/example.ts +166 -0
  37. package/src/built-in/CDEManager/examples/ProjectConfig/example.ts +177 -0
  38. package/src/built-in/FileList/example.ts +107 -0
  39. package/src/built-in/TabbedNavigation/example.ts +115 -0
  40. package/src/built-in/ViewportsManager/example.ts +106 -0
  41. package/src/cli/templates/{shared/app → app}/vite.config.js +42 -23
  42. package/src/cli/templates/{shared/cloud → cloud-component}/vite.config.js +46 -27
  43. package/src/cli/templates/shared/AGENTS.md +8 -30
  44. package/src/cli/templates/shared/CLAUDE.md +1 -1
  45. package/AGENTS.md +0 -86
  46. package/CONTEXT.md +0 -258
  47. package/dist/built-in/index.d.ts +0 -723
  48. package/dist/cli/commands/create-tests.d.ts +0 -3
  49. package/dist/cli/commands/serve-tests.d.ts +0 -3
  50. package/docs/access-backend-data.md +0 -19
  51. package/docs/app-architecture.md +0 -94
  52. package/docs/app-layout.md +0 -139
  53. package/docs/app-wiring.md +0 -123
  54. package/docs/bim-components/coding-conventions.md +0 -128
  55. package/docs/bim-components/element-collections.md +0 -69
  56. package/docs/bim-components/expose-events.md +0 -84
  57. package/docs/bim-components/library-examples.md +0 -28
  58. package/docs/bim-components/observable-collections.md +0 -83
  59. package/docs/bim-components/overview.md +0 -160
  60. package/docs/bim-components/per-frame-updates.md +0 -20
  61. package/docs/bim-components/save-and-restore-state.md +0 -21
  62. package/docs/bim-components/setup-and-cleanup.md +0 -64
  63. package/docs/bim-components/type-conventions.md +0 -49
  64. package/docs/bim-components/user-driven-object-creation.md +0 -56
  65. package/docs/cli-setup.md +0 -54
  66. package/docs/cloud-components.md +0 -74
  67. package/docs/connect-logic-to-ui.md +0 -113
  68. package/docs/previewing.md +0 -45
  69. package/docs/publishing.md +0 -35
  70. package/docs/scaffolding.md +0 -71
  71. package/docs/ui-components/async-actions.md +0 -18
  72. package/docs/ui-components/confirmation-dialog.md +0 -39
  73. package/docs/ui-components/data-table.md +0 -185
  74. package/docs/ui-components/display-text.md +0 -39
  75. package/docs/ui-components/inline-form.md +0 -44
  76. package/docs/ui-components/library-examples.md +0 -24
  77. package/docs/ui-components/overview.md +0 -194
  78. package/docs/ui-components/rendering-patterns.md +0 -129
  79. package/docs/ui-components/sections-layout.md +0 -123
  80. package/docs/update-grid-elements.md +0 -46
  81. package/docs/using-colors.md +0 -32
  82. package/docs/using-icons.md +0 -37
  83. package/src/cli/templates/bim/src/bim-components/CloudRunner/src/index.ts +0 -1
  84. package/src/cli/templates/bim/src/bim-components/CloudRunner/src/types.ts +0 -5
  85. package/src/cli/templates/bim/src/bim-components/index.ts +0 -1
  86. package/src/cli/templates/bim/src/globals.ts +0 -1
  87. package/src/cli/templates/bim/src/setups/index.ts +0 -3
  88. package/src/cli/templates/bim/src/ui-components/app-info-section/index.ts +0 -26
  89. package/src/cli/templates/bim/src/ui-components/app-info-section/src/index.ts +0 -1
  90. package/src/cli/templates/bim/src/ui-components/cloud-runner-section/index.ts +0 -37
  91. package/src/cli/templates/bim/src/ui-components/cloud-runner-section/src/index.ts +0 -1
  92. package/src/cli/templates/bim/src/ui-components/index.ts +0 -2
  93. package/src/cli/templates/bim-beta/CONTEXT.md +0 -241
  94. package/src/cli/templates/bim-beta/package.json +0 -25
  95. package/src/cli/templates/bim-beta/src/app.ts +0 -16
  96. package/src/cli/templates/bim-beta/src/bim-components/CloudRunner/index.ts +0 -91
  97. package/src/cli/templates/bim-beta/src/main.ts +0 -93
  98. package/src/cli/templates/bim-beta/src/setups/cloud-runner.ts +0 -13
  99. package/src/cli/templates/bim-beta/src/setups/ui-manager.ts +0 -27
  100. package/src/cli/templates/bim-beta/src/setups/viewports-manager.ts +0 -22
  101. package/src/cli/templates/bim-beta/src/ui-components/app-info-section/src/types.ts +0 -15
  102. package/src/cli/templates/bim-beta/src/ui-components/cloud-runner-section/src/types.ts +0 -14
  103. package/src/cli/templates/cloud/_thatopen +0 -5
  104. package/src/cli/templates/cloud/package.json +0 -22
  105. package/src/cli/templates/cloud-test/CONTEXT.md +0 -56
  106. package/src/cli/templates/cloud-test/src/main.ts +0 -565
  107. package/src/cli/templates/default/CONTEXT.md +0 -92
  108. package/src/cli/templates/default/package.json +0 -18
  109. package/src/cli/templates/default/src/main.ts +0 -62
  110. package/src/cli/templates/test/CONTEXT.md +0 -53
  111. package/src/cli/templates/test/package.json +0 -25
  112. package/src/cli/templates/test/src/main.ts +0 -955
  113. /package/src/cli/templates/{bim/CONTEXT.md → app/README.md} +0 -0
  114. /package/src/cli/templates/{shared/app → app}/index.html +0 -0
  115. /package/src/cli/templates/{bim → app}/package.json +0 -0
  116. /package/src/cli/templates/{bim → app}/src/app.ts +0 -0
  117. /package/src/cli/templates/{bim → app}/src/bim-components/CloudRunner/index.ts +0 -0
  118. /package/src/cli/templates/{bim-beta → app}/src/bim-components/CloudRunner/src/index.ts +0 -0
  119. /package/src/cli/templates/{bim-beta → app}/src/bim-components/CloudRunner/src/types.ts +0 -0
  120. /package/src/cli/templates/{bim-beta → app}/src/bim-components/index.ts +0 -0
  121. /package/src/cli/templates/{bim-beta → app}/src/globals.ts +0 -0
  122. /package/src/cli/templates/{bim → app}/src/main.ts +0 -0
  123. /package/src/cli/templates/{bim → app}/src/setups/cloud-runner.ts +0 -0
  124. /package/src/cli/templates/{bim-beta → app}/src/setups/index.ts +0 -0
  125. /package/src/cli/templates/{bim → app}/src/setups/ui-manager.ts +0 -0
  126. /package/src/cli/templates/{bim → app}/src/setups/viewports-manager.ts +0 -0
  127. /package/src/cli/templates/{bim-beta → app}/src/ui-components/app-info-section/index.ts +0 -0
  128. /package/src/cli/templates/{bim-beta → app}/src/ui-components/app-info-section/src/index.ts +0 -0
  129. /package/src/cli/templates/{bim → app}/src/ui-components/app-info-section/src/types.ts +0 -0
  130. /package/src/cli/templates/{bim-beta → app}/src/ui-components/cloud-runner-section/index.ts +0 -0
  131. /package/src/cli/templates/{bim-beta → app}/src/ui-components/cloud-runner-section/src/index.ts +0 -0
  132. /package/src/cli/templates/{bim → app}/src/ui-components/cloud-runner-section/src/types.ts +0 -0
  133. /package/src/cli/templates/{bim-beta → app}/src/ui-components/index.ts +0 -0
  134. /package/src/cli/templates/{shared/app → app}/tsconfig.json +0 -0
  135. /package/src/cli/templates/{cloud/CONTEXT.md → cloud-component/README.md} +0 -0
  136. /package/src/cli/templates/{cloud-test → cloud-component}/_thatopen +0 -0
  137. /package/src/cli/templates/{cloud → cloud-component}/declarations.json +0 -0
  138. /package/src/cli/templates/{cloud-test → cloud-component}/package.json +0 -0
  139. /package/src/cli/templates/{cloud → cloud-component}/src/main.ts +0 -0
  140. /package/src/cli/templates/{shared/cloud → cloud-component}/tsconfig.json +0 -0
package/README.md CHANGED
@@ -1,285 +1,46 @@
1
1
  # @thatopen/services
2
2
 
3
- Client library and CLI for building BIM apps and cloud components on the [That Open Platform](https://platform.thatopen.com).
3
+ Client library and CLI for building BIM apps and cloud components on [That Open Platform](https://platform.thatopen.com). Apps run inside the platform's browser environment; cloud components run server-side and can be triggered from any app.
4
4
 
5
5
  ## Quick Start
6
6
 
7
- ### Create a BIM app
7
+ ### 1. Install the CLI
8
8
 
9
9
  ```bash
10
- # Install the services package globally
11
- npm i @thatopen/services -g
10
+ npm install -g @thatopen/services@latest
12
11
  ```
13
12
 
14
- Then, create a brand new app repository:
13
+ ### 2. Choose a project type
15
14
 
16
- ```bash
17
- npx thatopen create my-app
18
- cd my-app
19
- npm run dev
20
-
21
- # Open your project on platform.thatopen.com and click the debug button
22
- ```
23
-
24
- You can also scaffold in the current directory:
25
-
26
- ```bash
27
- mkdir my-app && cd my-app
28
- npx thatopen create .
29
- npm run dev
30
- ```
31
-
32
- ### Create a cloud component
33
-
34
- ```bash
35
- npx thatopen create my-component --template cloud
36
- cd my-component
37
- npm run run # Build and test locally
38
- ```
39
-
40
- ### Templates
41
-
42
- | Template | Command | What you get |
43
- |----------|---------|--------------|
44
- | `bim` (default) | `npx thatopen create my-app` | Three.js + BIM viewer + platform UI components |
45
- | `default` | `npx thatopen create my-app --template default` | Minimal app showing platform context |
46
- | `cloud` | `npx thatopen create my-component --template cloud` | Server-side Node.js component |
47
- | `test` | `npx thatopen create my-tests --template test` | Browser test app that exercises every API endpoint |
48
- | `cloud-test` | `npx thatopen create my-tests --template cloud-test` | Cloud component test suite for server-side API testing |
49
-
50
- Use `npx thatopen create .` to scaffold in the current directory instead of creating a new one.
51
-
52
- ## What's in this package
53
-
54
- - **Library** — `EngineServicesClient` for interacting with the That Open API (files, folders, apps, cloud components, executions, permissions)
55
- - **CLI** — `thatopen` command for scaffolding and publishing
56
- - **Built-in component types** — TypeScript stubs for platform-hosted UI components (AppManager, ViewportManager, etc.)
57
-
58
- ## Library usage
59
-
60
- ```typescript
61
- import { EngineServicesClient } from '@thatopen/services';
62
-
63
- const client = new EngineServicesClient(accessToken, apiUrl);
64
-
65
- // Files
66
- const files = await client.listFiles();
67
- await client.createFile({ file: blob, name: "model.ifc", versionTag: "v1" });
68
- const response = await client.downloadFile(fileId);
69
-
70
- // Folders
71
- const folders = await client.listFolders();
72
- await client.createFolder("My Folder");
73
-
74
- // Cloud component execution
75
- const { executionId } = await client.executeComponent(componentId, { param: "value" });
76
- client.onExecutionProgress(executionId, (data) => {
77
- console.log(data.progressUpdate, data.messageUpdate);
78
- });
79
- ```
80
-
81
- Inside platform apps, use the Auth0 JWT from the platform context:
82
-
83
- ```typescript
84
- const ctx = window.__THATOPEN_CONTEXT__; // { appId, projectId, accessToken, apiUrl }
85
- const client = new EngineServicesClient(ctx.accessToken, ctx.apiUrl, { useBearer: true });
86
- ```
87
-
88
- ## CLI commands
89
-
90
- | Command | Description |
91
- |---------|-------------|
92
- | `thatopen create <name> [--template bim\|default\|cloud\|test\|cloud-test]` | Scaffold a new project (use `.` for current directory) |
93
- | `thatopen serve [--port N]` | Dev server (esbuild watch + serve bundle) |
94
- | `thatopen login [--token T] [--local]` | Authenticate with the platform |
95
- | `thatopen publish` | Build and publish to the platform |
96
- | `thatopen run [--params '{}']` | Build and test a cloud component locally |
97
- | `thatopen create-tests [directory]` | Scaffold both a test app and test cloud component |
98
- | `thatopen serve-tests [directory]` | Serve both the test app and test component in parallel |
99
-
100
- ## App workflow
101
-
102
- Apps run inside the That Open Platform (platform.thatopen.com) within a project. They are served inside the platform's iframe — not as standalone websites.
103
-
104
- ```bash
105
- # 1. Create project (dependencies are installed automatically)
106
- npx thatopen create my-app
107
- cd my-app
108
-
109
- # 2. Develop locally
110
- npm run dev
111
- # Open your project on the platform and click the debug button.
112
- # Live reload is enabled — save a file to rebuild.
113
-
114
- # 3. Authenticate
115
- npm run login -- --token <your-token>
116
-
117
- # 4. Publish
118
- npm run publish
119
- ```
120
-
121
- ## Cloud component workflow
122
-
123
- ```bash
124
- # 1. Create project (dependencies are installed automatically)
125
- npx thatopen create my-component --template cloud
126
- cd my-component
127
-
128
- # 2. Run locally
129
- npm run run
130
-
131
- # 3. Pass parameters
132
- npx thatopen run --params '{"inputFile": "model.ifc"}'
133
-
134
- # 4. Authenticate and publish
135
- npm run login -- --token <your-token>
136
- npm run publish
137
- ```
138
-
139
- Cloud components export an `async function main()` that runs on the server. The execution engine provides globals:
140
-
141
- | Global | Purpose |
142
- |--------|---------|
143
- | `thatOpenServices` | Authenticated `EngineServicesClient` |
144
- | `executionParams` | Parameters passed by the caller |
145
- | `executionReporter` | `{ message(msg), progress(pct) }` for live feedback |
146
- | `OBC` | `@thatopen/components` — BIM engine |
147
- | `THREE` | `three` — 3D math and geometry |
148
- | `fs` | Node.js filesystem |
149
-
150
- ## Built-in components
151
-
152
- Platform-hosted UI components loaded at runtime:
153
-
154
- ```typescript
155
- import { AppManager, ViewportManager } from "@thatopen/services";
156
-
157
- // Register all library globals once
158
- client.setBuiltInGlobals({ OBC, OBF, BUI, CUI, THREE, FRAGS });
159
-
160
- // Load built-in components — globals are automatically applied
161
- await client.initBuiltInComponent(AppManager, components);
162
- await client.initBuiltInComponent(ViewportManager, components);
163
-
164
- const app = components.get(AppManager);
165
- const viewports = components.get(ViewportManager);
166
- const { element, world } = await viewports.create();
167
- ```
168
-
169
- | Component | Purpose |
170
- |-----------|---------|
171
- | `AppManager` | App shell — CSS grid layout with sidebar for switching layouts |
172
- | `ViewportManager` | Factory for 3D viewports with pre-configured world |
173
- | `LoadModelButton` | Button + dropdown for loading IFC / Fragments files |
174
- | `ViewerToolbar` | Toolbar with Show/Hide/Focus/Isolate and color palette |
175
- | `ModelsPanel` | Panel listing loaded models with search and load button |
176
- | `ModelsDropdown` | Dropdown selector listing loaded models |
177
- | `ClassificationsList` | Hierarchical table of IFC classification data |
178
- | `ClashesList` | Interactive clash detection results with highlighting |
179
- | `ClippingsList` | Panel listing clipping planes with controls |
180
- | `LengthMeasuringsList` | Panel listing length measurements with totals |
181
- | `AreaMeasuringsList` | Panel listing area measurements with totals |
182
- | `ColorsPalette` | Color picker with Highlighter style swatches |
183
- | `HighlightersList` | Panel listing Highlighter styles with manage actions |
184
- | `QtoComparisonList` | Side-by-side quantity comparison for two elements |
185
- | `QueriesHierarchy` | Recursive multi-level query browser |
186
- | `CustomViewLegend` | Color legend overlay |
187
- | `ScreenshotAnnotator` | Modal for annotating screenshots via MarkerJS |
188
-
189
- See `src/built-in/index.ts` for full API reference with config interfaces and `@example` blocks.
190
-
191
- ## Config files
192
-
193
- | File | Scope | Contains |
194
- |------|-------|----------|
195
- | `~/.thatopen/config.json` | Global | `accessToken`, `apiUrl` |
196
- | `.thatopen` (project root) | Per-project (gitignored) | `accessToken`, `apiUrl`, `appId` or `componentId` |
197
-
198
- The CLI checks the local `.thatopen` first, then falls back to the global config.
199
-
200
- ---
201
-
202
- ## Development (working on this repo)
203
-
204
- ### Setup
205
-
206
- ```bash
207
- npm install
208
- npm run build # Builds both library and CLI
209
- ```
15
+ | Type | Template | Use when |
16
+ |------|----------|----------|
17
+ | **App** | `app` | You're building a BIM app that runs in the platform's browser UI |
18
+ | **Cloud component** | `cloud-component` | You're building server-side logic triggered by an app |
210
19
 
211
- ### Build commands
20
+ ### 3. Scaffold
212
21
 
213
- ```bash
214
- npm run build # Full build (library + CLI)
215
- npm run build:lib # Library only
216
- npm run build:cli # CLI only
217
- ```
218
-
219
- ### Testing the CLI locally
22
+ See the full command reference here:
23
+ → [`docs/cli/create.md`](https://raw.githubusercontent.com/ThatOpen/engine_services/main/docs/cli/create.md)
220
24
 
221
- ```bash
222
- # Link the CLI globally so `thatopen` points to this repo
223
- npm link
224
-
225
- # Build CLI and scaffold a test app
226
- npm run test:cli-build-app
25
+ To use beta engine libraries instead of the stable ones, see:
26
+ → [`docs/cli/swap.md`](https://raw.githubusercontent.com/ThatOpen/engine_services/main/docs/cli/swap.md)
227
27
 
228
- # Build and scaffold a test cloud component
229
- npm run test:cli-build-component
28
+ ### 4. Next steps
230
29
 
231
- # Run the test cloud component locally
232
- npm run test:cli-run-component
233
- ```
30
+ Once scaffolded, open `AGENTS.md` in the scaffolded project root — it has everything needed to start building.
234
31
 
235
- ### Running the platform API test suite
236
-
237
- The test suite consists of two projects scaffolded together: a **test app** (browser-based, template `test`) and a **test cloud component** (server-side, template `cloud-test`). Both exercise every `EngineServicesClient` endpoint.
238
-
239
- ```bash
240
- # 1. Build the CLI and scaffold both test projects into a temp/ directory
241
- # (deletes temp/ first if it already exists)
242
- yarn test:cli-build-tests
243
-
244
- # 2. Serve both the test app and the test component's local server
245
- yarn test:cli-serve-tests
246
- ```
32
+ ## What's in this repository
247
33
 
248
- Then open your project on [platform.thatopen.com](https://platform.thatopen.com) and click the debug button. The test app will show a panel with:
34
+ - **Library** — `EngineServicesClient` and `PlatformClient` for interacting with the That Open API (files, folders, apps, cloud components, executions, permissions).
35
+ - **CLI** — `thatopen` command for scaffolding and publishing.
36
+ - **Built-in component types** — TypeScript stubs for platform-hosted components.
249
37
 
250
- - **Context** — current app/project/API info
251
- - **Execution Config** — input fields for a deployed Component ID and the local server URL (defaults to `http://localhost:4001`)
252
- - **Controls** — "Run All Tests" button
253
- - **Results** — test results grouped by API area (Context & Auth, Folders, Files, Hidden Files, Icons, Components, Apps, Execution, Built-in Components)
38
+ ## Docs
254
39
 
255
- When execution tests run, the cloud component's output appears in the same Results section as additional groups prefixed with "Local Component:" or "Deployed Component:".
40
+ Full reference for all CLI commands and flags:
41
+ → [`docs/cli/paths.json`](https://raw.githubusercontent.com/ThatOpen/engine_services/main/docs/cli/paths.json)
256
42
 
257
- ### Publishing a new version
43
+ ## Contributing
258
44
 
259
- Publishing is handled automatically by CI when a PR with changesets is merged to `main`.
260
-
261
- **1. Create a changeset (developer does this with their changes):**
262
-
263
- ```bash
264
- yarn changeset
265
- # Pick the bump type (patch / minor / major) and write a summary
266
- # This creates a .changeset/<random-name>.md file — commit it with your PR
267
- ```
268
-
269
- **2. Merge the PR to `main`:**
270
-
271
- CI will automatically:
272
- - Consume the changeset files
273
- - Bump `package.json` version and update `CHANGELOG.md`
274
- - Commit the version bump back to `main`
275
- - Build and publish to npm
276
-
277
- **Manual publishing (if CI is not available):**
278
-
279
- ```bash
280
- yarn version # Consume changesets, bump version
281
- yarn build
282
- yarn changeset publish
283
- ```
45
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup, build commands, and publishing workflow.
284
46
 
285
- Keep in mind the importance of semver — don't release a major for non-breaking changes.
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+
3
+ export declare const swapCommand: Command;
@@ -0,0 +1,2 @@
1
+ /** Public → beta package name mapping. Source of truth for all beta-related logic. */
2
+ export declare const BETA_ALIASES: Record<string, string>;
@@ -15,6 +15,8 @@ export interface ThatOpenLocalConfig {
15
15
  itemType?: ProjectType;
16
16
  /** Path to an icon file (PNG, WebP, or ICO) uploaded on publish. */
17
17
  iconPath?: string;
18
+ /** Whether this project uses beta engine libraries (@thatopen-platform/*-beta). */
19
+ beta?: boolean;
18
20
  }
19
21
  export declare function readLocalConfig(cwd?: string): ThatOpenLocalConfig | null;
20
22
  export declare function writeLocalConfig(config: ThatOpenLocalConfig, cwd?: string): void;
package/dist/cli.js CHANGED
@@ -7980,7 +7980,12 @@ const loginCommand = new Command2("login").description("Authenticate with the Th
7980
7980
  );
7981
7981
  }
7982
7982
  });
7983
- const TEMPLATES = ["default", "bim", "bim-beta", "cloud", "test", "cloud-test"];
7983
+ const BETA_ALIASES = {
7984
+ "@thatopen/components": "@thatopen-platform/components-beta",
7985
+ "@thatopen/components-front": "@thatopen-platform/components-front-beta",
7986
+ "@thatopen/fragments": "@thatopen-platform/fragments-beta"
7987
+ };
7988
+ const TEMPLATES = ["app", "cloud-component"];
7984
7989
  const libVersion = (() => {
7985
7990
  try {
7986
7991
  const pkg2 = JSON.parse(require$$3.readFileSync(require$$2.join(__dirname, "..", "package.json"), "utf-8"));
@@ -7990,13 +7995,13 @@ const libVersion = (() => {
7990
7995
  }
7991
7996
  })();
7992
7997
  const templatesDir = require$$2.join(__dirname, "..", "src", "cli", "templates");
7993
- const createCommand = new Command2("create").argument("<project-name>", 'Name of the project to create (use "." for current directory)').option("-t, --template <template>", `Template (${TEMPLATES.join(", ")})`, "bim").description("Scaffold a new ThatOpen app or cloud component project").action(async (projectName, opts) => {
7998
+ const createCommand = new Command2("create").argument("<project-name>", 'Name of the project to create (use "." for current directory)').option("-t, --template <template>", `Template (${TEMPLATES.join(", ")})`, "app").option("--beta", "Use beta engine libraries (@thatopen-platform/*-beta)").description("Scaffold a new ThatOpen app or cloud component project").action(async (projectName, opts) => {
7994
7999
  const template = opts.template;
7995
8000
  if (!TEMPLATES.includes(template)) {
7996
8001
  console.error(`Unknown template "${opts.template}". Available: ${TEMPLATES.join(", ")}`);
7997
8002
  process.exit(1);
7998
8003
  }
7999
- const isCloud = template === "cloud" || template === "cloud-test";
8004
+ const isCloud = template === "cloud-component";
8000
8005
  const projectKind = isCloud ? "cloud component" : "app";
8001
8006
  const useCurrentDir = projectName === ".";
8002
8007
  const targetDir = useCurrentDir ? process.cwd() : require$$2.resolve(process.cwd(), projectName);
@@ -8005,44 +8010,43 @@ const createCommand = new Command2("create").argument("<project-name>", 'Name of
8005
8010
  console.error(`Directory "${projectName}" already exists.`);
8006
8011
  process.exit(1);
8007
8012
  }
8008
- console.log(`Creating ThatOpen ${projectKind} "${packageName}" (template: ${template})...`);
8013
+ console.log(`Creating ThatOpen ${projectKind} "${packageName}" (template: ${template}${opts.beta ? ", beta" : ""})...`);
8009
8014
  if (!useCurrentDir) {
8010
8015
  require$$3.mkdirSync(targetDir, { recursive: true });
8011
8016
  }
8012
8017
  require$$3.mkdirSync(require$$2.join(targetDir, "src"), { recursive: true });
8013
8018
  const sharedDir = require$$2.join(templatesDir, "shared");
8014
- const sharedVariantDir = require$$2.join(sharedDir, isCloud ? "cloud" : "app");
8015
8019
  require$$3.copyFileSync(require$$2.join(sharedDir, "_gitignore"), require$$2.join(targetDir, ".gitignore"));
8016
8020
  require$$3.copyFileSync(require$$2.join(sharedDir, "AGENTS.md"), require$$2.join(targetDir, "AGENTS.md"));
8017
8021
  require$$3.copyFileSync(require$$2.join(sharedDir, "CLAUDE.md"), require$$2.join(targetDir, "CLAUDE.md"));
8018
- require$$3.copyFileSync(require$$2.join(sharedVariantDir, "tsconfig.json"), require$$2.join(targetDir, "tsconfig.json"));
8019
- require$$3.copyFileSync(require$$2.join(sharedVariantDir, "vite.config.js"), require$$2.join(targetDir, "vite.config.js"));
8020
- if (!isCloud) {
8021
- require$$3.copyFileSync(require$$2.join(sharedVariantDir, "index.html"), require$$2.join(targetDir, "index.html"));
8022
- }
8023
8022
  const templateDir = require$$2.join(templatesDir, template);
8024
8023
  require$$3.cpSync(templateDir, targetDir, { recursive: true });
8025
8024
  if (isCloud) {
8026
8025
  require$$3.renameSync(require$$2.join(targetDir, "_thatopen"), require$$2.join(targetDir, ".thatopen"));
8027
8026
  }
8028
8027
  const pkgPath = require$$2.join(targetDir, "package.json");
8029
- const pkg2 = require$$3.readFileSync(pkgPath, "utf-8").replace(/\{\{PROJECT_NAME\}\}/g, packageName).replace(/\{\{VERSION\}\}/g, libVersion).replace(/"@thatopen\/services": "file:[^"]*"/, `"@thatopen/services": "^${libVersion}"`);
8030
- require$$3.writeFileSync(pkgPath, pkg2);
8031
- const isBeta = template === "bim-beta";
8032
- if (isBeta) {
8033
- console.log("");
8034
- console.log("This template uses the private BETA engine libraries (@thatopen-platform/*-beta).");
8035
- console.log("If install fails with a 401/403, configure your beta access token in npm first.");
8028
+ const pkgContent = require$$3.readFileSync(pkgPath, "utf-8").replace(/\{\{PROJECT_NAME\}\}/g, packageName).replace(/\{\{VERSION\}\}/g, libVersion).replace(/"@thatopen\/services": "file:[^"]*"/, `"@thatopen/services": "^${libVersion}"`);
8029
+ require$$3.writeFileSync(pkgPath, pkgContent);
8030
+ if (opts.beta) {
8031
+ const pkg2 = JSON.parse(require$$3.readFileSync(pkgPath, "utf-8"));
8032
+ for (const [stable, beta] of Object.entries(BETA_ALIASES)) {
8033
+ if (pkg2.dependencies?.[stable] !== void 0) {
8034
+ delete pkg2.dependencies[stable];
8035
+ pkg2.dependencies[beta] = "latest";
8036
+ }
8037
+ }
8038
+ require$$3.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2));
8039
+ updateLocalConfig({ beta: true }, targetDir);
8036
8040
  }
8037
8041
  console.log("");
8038
8042
  console.log("Installing dependencies...");
8043
+ if (opts.beta) {
8044
+ console.log("(Beta packages are private — if this fails with 401/403, configure your beta npm token.)");
8045
+ }
8039
8046
  try {
8040
8047
  require$$1.execSync("npm install", { cwd: targetDir, stdio: "inherit" });
8041
8048
  } catch {
8042
8049
  console.error("Failed to install dependencies. Run `npm install` manually.");
8043
- if (isBeta) {
8044
- console.error("Beta packages are private — if this is an auth error, your beta token may not be configured.");
8045
- }
8046
8050
  }
8047
8051
  console.log("");
8048
8052
  console.log(useCurrentDir ? " Project ready!" : ` Created ./${projectName}`);
@@ -10719,6 +10723,7 @@ const serveCommand = new Command2("serve").description(
10719
10723
  );
10720
10724
  process.exit(1);
10721
10725
  }
10726
+ const isBeta = readLocalConfig(cwd)?.beta === true;
10722
10727
  const globalName = detectGlobalName(cwd);
10723
10728
  const bundlePath = require$$2.join(cwd, "dist", "bundle.js");
10724
10729
  const mapPath = require$$2.join(cwd, "dist", "bundle.js.map");
@@ -10746,6 +10751,7 @@ const serveCommand = new Command2("serve").description(
10746
10751
  outfile: bundlePath,
10747
10752
  sourcemap: true,
10748
10753
  logLevel: "info",
10754
+ alias: isBeta ? BETA_ALIASES : void 0,
10749
10755
  logOverride: {
10750
10756
  // IIFE format leaves import.meta empty. The only consumer of import.meta
10751
10757
  // in our ecosystem today is @thatopen/fragments' worker URL fallback,
@@ -10836,7 +10842,7 @@ const serveCommand = new Command2("serve").description(
10836
10842
  res.end("Not found");
10837
10843
  });
10838
10844
  server.listen(port, () => {
10839
- console.log(`Bundle server running at http://localhost:${port}`);
10845
+ console.log(`Bundle server running at http://localhost:${port}${isBeta ? " (beta mode)" : ""}`);
10840
10846
  console.log("");
10841
10847
  console.log(
10842
10848
  "Open your project on the platform and click the debug button."
@@ -11254,8 +11260,11 @@ const localServerCommand = new Command2("local-server").description(
11254
11260
  ).option("--port <port>", "Port for the local server", "4001").option("--skip-build", "Skip the initial build step").action(async (opts) => {
11255
11261
  const cwd = process.cwd();
11256
11262
  const config = requireResolvedConfig(cwd);
11263
+ const isBeta = readLocalConfig(cwd)?.beta === true;
11257
11264
  const port = parseInt(opts.port);
11258
11265
  const bundlePath = require$$2.join(cwd, "dist", "bundle.js");
11266
+ const stableExternals = ["@thatopen/components", "@thatopen/fragments"];
11267
+ const externalPackages = isBeta ? stableExternals.map((p) => BETA_ALIASES[p] ?? p) : stableExternals;
11259
11268
  let esbuild;
11260
11269
  try {
11261
11270
  esbuild = await import("esbuild");
@@ -11275,6 +11284,7 @@ const localServerCommand = new Command2("local-server").description(
11275
11284
  footer: { js: "var main = ThatOpenComponent.main;" },
11276
11285
  outfile: bundlePath,
11277
11286
  logLevel: "info",
11287
+ alias: isBeta ? BETA_ALIASES : void 0,
11278
11288
  logOverride: {
11279
11289
  // Same upstream @nodable/entities duplicate `euro:` key noise
11280
11290
  // silenced in the `serve` command. Cosmetic, no runtime impact.
@@ -11292,7 +11302,7 @@ const localServerCommand = new Command2("local-server").description(
11292
11302
  },
11293
11303
  external: [
11294
11304
  "@thatopen/services",
11295
- "@thatopen/components",
11305
+ ...externalPackages,
11296
11306
  "three",
11297
11307
  "web-ifc",
11298
11308
  "fs",
@@ -11417,7 +11427,7 @@ const localServerCommand = new Command2("local-server").description(
11417
11427
  });
11418
11428
  server.listen(port, () => {
11419
11429
  console.log("");
11420
- console.log(`[local-server] Running at http://localhost:${port}`);
11430
+ console.log(`[local-server] Running at http://localhost:${port}${isBeta ? " (beta mode)" : ""}`);
11421
11431
  console.log("");
11422
11432
  console.log("Usage with EngineServicesClient:");
11423
11433
  console.log("");
@@ -11438,114 +11448,64 @@ const localServerCommand = new Command2("local-server").description(
11438
11448
  process.exit(0);
11439
11449
  });
11440
11450
  });
11441
- const createTestsCommand = new Command2("create-tests").argument(
11442
- "<directory>",
11443
- "Parent directory for both projects (required to prevent accidental deletion)"
11444
- ).option("--app-name <name>", "Name of the test app project", "test-app").option(
11445
- "--component-name <name>",
11446
- "Name of the test component project",
11447
- "test-component"
11448
- ).description(
11449
- "Scaffold both a test app (--template test) and a test cloud component (--template cloud-test)"
11450
- ).action(
11451
- async (directory, opts) => {
11452
- const parentDir = require$$2.resolve(process.cwd(), directory);
11453
- const bin = process.argv[1];
11454
- if (require$$3.existsSync(parentDir)) {
11455
- console.log(`Removing existing directory "${directory}"...`);
11456
- require$$3.rmSync(parentDir, { recursive: true, force: true });
11457
- }
11458
- require$$3.mkdirSync(parentDir, { recursive: true });
11459
- console.log("Creating test suite...");
11460
- console.log("");
11461
- console.log(`── Creating test app "${opts.appName}" ──`);
11462
- const appResult = require$$1.spawnSync(
11463
- process.execPath,
11464
- [bin, "create", opts.appName, "-t", "test"],
11465
- { cwd: parentDir, stdio: "inherit" }
11466
- );
11467
- if (appResult.status !== 0) {
11468
- process.exit(appResult.status ?? 1);
11451
+ const swapCommand = new Command2("swap").description("Toggle between stable public and beta engine libraries").option("--beta", "Switch to beta libraries").option("--stable", "Switch to stable public libraries").action(async (opts) => {
11452
+ const cwd = process.cwd();
11453
+ const pkgPath = require$$2.join(cwd, "package.json");
11454
+ if (!require$$3.existsSync(pkgPath)) {
11455
+ console.error("No package.json found. Run this from a ThatOpen project.");
11456
+ process.exit(1);
11457
+ }
11458
+ const currentlyBeta = readLocalConfig(cwd)?.beta === true;
11459
+ let targetBeta;
11460
+ if (opts.beta && opts.stable) {
11461
+ console.error("Cannot use --beta and --stable together.");
11462
+ process.exit(1);
11463
+ } else if (opts.beta) {
11464
+ targetBeta = true;
11465
+ } else if (opts.stable) {
11466
+ targetBeta = false;
11467
+ } else {
11468
+ targetBeta = !currentlyBeta;
11469
+ }
11470
+ if (targetBeta === currentlyBeta) {
11471
+ console.log(`Already using ${currentlyBeta ? "beta" : "stable"} libraries. Nothing to do.`);
11472
+ return;
11473
+ }
11474
+ const pkg2 = JSON.parse(require$$3.readFileSync(pkgPath, "utf-8"));
11475
+ if (targetBeta) {
11476
+ for (const [stable, beta] of Object.entries(BETA_ALIASES)) {
11477
+ if (pkg2.dependencies?.[stable] !== void 0) {
11478
+ delete pkg2.dependencies[stable];
11479
+ pkg2.dependencies[beta] = "latest";
11480
+ }
11469
11481
  }
11470
- console.log("");
11471
- console.log(`── Creating test component "${opts.componentName}" ──`);
11472
- const compResult = require$$1.spawnSync(
11473
- process.execPath,
11474
- [bin, "create", opts.componentName, "-t", "cloud-test"],
11475
- { cwd: parentDir, stdio: "inherit" }
11482
+ } else {
11483
+ const cliPkg = JSON.parse(
11484
+ require$$3.readFileSync(require$$2.join(__dirname, "..", "package.json"), "utf-8")
11476
11485
  );
11477
- if (compResult.status !== 0) {
11478
- process.exit(compResult.status ?? 1);
11486
+ for (const [stable, beta] of Object.entries(BETA_ALIASES)) {
11487
+ if (pkg2.dependencies?.[beta] !== void 0) {
11488
+ delete pkg2.dependencies[beta];
11489
+ pkg2.dependencies[stable] = cliPkg.devDependencies?.[stable] ?? "latest";
11490
+ }
11479
11491
  }
11480
- console.log("");
11481
- console.log("Test suite ready!");
11482
- console.log("");
11483
- console.log("Quick start:");
11484
- console.log(
11485
- ` 1. cd ${opts.componentName} && npm run run # Run the test component locally`
11486
- );
11492
+ }
11493
+ require$$3.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2));
11494
+ updateLocalConfig({ beta: targetBeta }, cwd);
11495
+ console.log(`Switched to ${targetBeta ? "beta" : "stable"} libraries.`);
11496
+ if (targetBeta) {
11487
11497
  console.log(
11488
- ` 2. cd ${opts.appName} && npm run dev # Start the test app`
11498
+ "Beta packages are private — make sure your beta npm token is configured."
11489
11499
  );
11490
- console.log("");
11491
11500
  }
11492
- );
11493
- const serveTestsCommand = new Command2("serve-tests").argument(
11494
- "<directory>",
11495
- "Parent directory containing both projects"
11496
- ).option("--app-name <name>", "Name of the test app project", "test-app").option(
11497
- "--component-name <name>",
11498
- "Name of the test component project",
11499
- "test-component"
11500
- ).option("--app-port <port>", "Port for the app bundle server", "4000").option("--component-port <port>", "Port for the component local server", "4001").description(
11501
- "Serve both the test app (thatopen serve) and the test component (thatopen local-server) in parallel"
11502
- ).action(
11503
- async (directory, opts) => {
11504
- const parentDir = require$$2.resolve(process.cwd(), directory);
11505
- const bin = process.argv[1];
11506
- const appDir = require$$2.resolve(parentDir, opts.appName);
11507
- const componentDir = require$$2.resolve(parentDir, opts.componentName);
11508
- console.log("Starting test suite servers...");
11509
- console.log("");
11510
- const children = [];
11511
- function startProcess(label, cwd, args) {
11512
- const child = require$$1.spawn(process.execPath, [bin, ...args], {
11513
- cwd,
11514
- stdio: ["ignore", "pipe", "pipe"]
11515
- });
11516
- const prefix = `[${label}]`;
11517
- child.stdout.on("data", (data) => {
11518
- for (const line of data.toString().split("\n")) {
11519
- if (line) console.log(`${prefix} ${line}`);
11520
- }
11521
- });
11522
- child.stderr.on("data", (data) => {
11523
- for (const line of data.toString().split("\n")) {
11524
- if (line) console.error(`${prefix} ${line}`);
11525
- }
11526
- });
11527
- child.on("exit", (code) => {
11528
- console.log(`${prefix} exited with code ${code}`);
11529
- });
11530
- children.push(child);
11531
- }
11532
- startProcess("component", componentDir, [
11533
- "local-server",
11534
- "--port",
11535
- opts.componentPort
11536
- ]);
11537
- startProcess("app", appDir, ["serve", "--port", opts.appPort]);
11538
- console.log(`[component] ${componentDir} → http://localhost:${opts.componentPort}`);
11539
- console.log(`[app] ${appDir} → http://localhost:${opts.appPort}`);
11540
- console.log("");
11541
- process.on("SIGINT", () => {
11542
- for (const child of children) {
11543
- child.kill("SIGINT");
11544
- }
11545
- setTimeout(() => process.exit(0), 500);
11546
- });
11501
+ console.log("");
11502
+ console.log("Installing dependencies...");
11503
+ try {
11504
+ require$$1.execSync("npm install", { cwd, stdio: "inherit" });
11505
+ } catch {
11506
+ console.error("Failed to install dependencies. Run `npm install` manually.");
11547
11507
  }
11548
- );
11508
+ });
11549
11509
  const pkg = JSON.parse(
11550
11510
  require$$3.readFileSync(require$$2.join(__dirname, "..", "package.json"), "utf-8")
11551
11511
  );
@@ -11572,6 +11532,5 @@ program.addCommand(publishCommand);
11572
11532
  program.addCommand(serveCommand);
11573
11533
  program.addCommand(runCommand);
11574
11534
  program.addCommand(localServerCommand);
11575
- program.addCommand(createTestsCommand);
11576
- program.addCommand(serveTestsCommand);
11535
+ program.addCommand(swapCommand);
11577
11536
  program.parse(process.argv);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};