@thatopen/services 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTEXT.md +258 -0
- package/README.md +285 -0
- package/dist/built-in/index.d.ts +723 -0
- package/dist/cli/commands/create-tests.d.ts +3 -0
- package/dist/cli/commands/create.d.ts +3 -0
- package/dist/cli/commands/local-server.d.ts +3 -0
- package/dist/cli/commands/login.d.ts +3 -0
- package/dist/cli/commands/publish.d.ts +3 -0
- package/dist/cli/commands/run.d.ts +3 -0
- package/dist/cli/commands/serve-tests.d.ts +3 -0
- package/dist/cli/commands/serve.d.ts +3 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/lib/config.d.ts +25 -0
- package/dist/cli/lib/declarations.d.ts +19 -0
- package/dist/cli/lib/engine-script.d.ts +10 -0
- package/dist/cli/lib/execution-manager.d.ts +52 -0
- package/dist/cli/lib/zip.d.ts +6 -0
- package/dist/cli.js +11566 -0
- package/dist/core/client.d.ts +682 -0
- package/dist/core/client.test.d.ts +1 -0
- package/dist/core/platform-client.d.ts +106 -0
- package/dist/core/platform-client.test.d.ts +1 -0
- package/dist/core/request-error.d.ts +25 -0
- package/dist/core/request-error.test.d.ts +1 -0
- package/dist/index.cjs.js +2 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.es.js +3310 -0
- package/dist/types/base.d.ts +9 -0
- package/dist/types/context.d.ts +20 -0
- package/dist/types/execution.d.ts +19 -0
- package/dist/types/files.d.ts +19 -0
- package/dist/types/item.dto.d.ts +24 -0
- package/dist/types/items.d.ts +57 -0
- package/dist/types/projects.d.ts +59 -0
- package/dist/types/response.d.ts +10 -0
- package/dist/types/storage.d.ts +11 -0
- package/dist/vite-env.d.ts +1 -0
- package/package.json +100 -0
- package/src/built-in/index.ts +755 -0
- package/src/cli/templates/bim/CONTEXT.md +244 -0
- package/src/cli/templates/bim/package.json +26 -0
- package/src/cli/templates/bim/src/app.ts +16 -0
- package/src/cli/templates/bim/src/bim-components/CloudRunner/index.ts +91 -0
- package/src/cli/templates/bim/src/bim-components/CloudRunner/src/index.ts +1 -0
- package/src/cli/templates/bim/src/bim-components/CloudRunner/src/types.ts +5 -0
- package/src/cli/templates/bim/src/bim-components/index.ts +1 -0
- package/src/cli/templates/bim/src/globals.ts +1 -0
- package/src/cli/templates/bim/src/main.ts +90 -0
- package/src/cli/templates/bim/src/setups/cloud-runner.ts +13 -0
- package/src/cli/templates/bim/src/setups/index.ts +3 -0
- package/src/cli/templates/bim/src/setups/ui-manager.ts +27 -0
- package/src/cli/templates/bim/src/setups/viewports-manager.ts +22 -0
- package/src/cli/templates/bim/src/ui-components/app-info-section/index.ts +26 -0
- package/src/cli/templates/bim/src/ui-components/app-info-section/src/index.ts +1 -0
- package/src/cli/templates/bim/src/ui-components/app-info-section/src/types.ts +15 -0
- package/src/cli/templates/bim/src/ui-components/cloud-runner-section/index.ts +37 -0
- package/src/cli/templates/bim/src/ui-components/cloud-runner-section/src/index.ts +1 -0
- package/src/cli/templates/bim/src/ui-components/cloud-runner-section/src/types.ts +14 -0
- package/src/cli/templates/bim/src/ui-components/index.ts +2 -0
- package/src/cli/templates/cloud/CONTEXT.md +205 -0
- package/src/cli/templates/cloud/_thatopen +5 -0
- package/src/cli/templates/cloud/declarations.json +4 -0
- package/src/cli/templates/cloud/package.json +22 -0
- package/src/cli/templates/cloud/src/main.ts +70 -0
- package/src/cli/templates/cloud-test/CONTEXT.md +56 -0
- package/src/cli/templates/cloud-test/_thatopen +5 -0
- package/src/cli/templates/cloud-test/package.json +22 -0
- package/src/cli/templates/cloud-test/src/main.ts +565 -0
- package/src/cli/templates/default/CONTEXT.md +92 -0
- package/src/cli/templates/default/package.json +15 -0
- package/src/cli/templates/default/src/main.ts +62 -0
- package/src/cli/templates/shared/_gitignore +4 -0
- package/src/cli/templates/shared/app/index.html +27 -0
- package/src/cli/templates/shared/app/tsconfig.json +16 -0
- package/src/cli/templates/shared/app/vite.config.js +23 -0
- package/src/cli/templates/shared/cloud/tsconfig.json +16 -0
- package/src/cli/templates/shared/cloud/vite.config.js +27 -0
- package/src/cli/templates/test/CONTEXT.md +53 -0
- package/src/cli/templates/test/package.json +25 -0
- package/src/cli/templates/test/src/main.ts +955 -0
package/CONTEXT.md
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
# thatopen-services
|
|
2
|
+
|
|
3
|
+
Client library and CLI for the That Open Platform — a cloud platform for building BIM (Building Information Modeling) software.
|
|
4
|
+
|
|
5
|
+
## What this repo contains
|
|
6
|
+
|
|
7
|
+
1. **Library** (`src/core/client.ts`) — `EngineServicesClient`, a TypeScript API client for managing files, folders, apps, cloud components, and executions on the platform.
|
|
8
|
+
2. **CLI** (`src/cli/`) — The `thatopen` command-line tool for scaffolding and publishing apps and cloud components.
|
|
9
|
+
3. **Built-in components** (`src/built-in/`) — Type stubs for platform-provided UI components (AppManager, ViewportManager, etc.) that are fetched and evaluated at runtime.
|
|
10
|
+
|
|
11
|
+
## Project structure
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
src/
|
|
15
|
+
core/client.ts # EngineServicesClient — the main API class
|
|
16
|
+
cli/
|
|
17
|
+
commands/create.ts # thatopen create — scaffolds new projects
|
|
18
|
+
commands/serve.ts # thatopen serve — dev server (esbuild watch + serve)
|
|
19
|
+
commands/login.ts # thatopen login — authenticate with the platform
|
|
20
|
+
commands/publish.ts # thatopen publish — build and upload to the platform
|
|
21
|
+
commands/run.ts # thatopen run — test cloud components locally
|
|
22
|
+
commands/create-tests.ts # thatopen create-tests — scaffolds test app + test component
|
|
23
|
+
commands/serve-tests.ts # thatopen serve-tests — serves both test projects in parallel
|
|
24
|
+
templates/ # Template generators for scaffolded projects
|
|
25
|
+
lib/ # CLI helper utilities (config, certificates)
|
|
26
|
+
built-in/index.ts # Built-in component type stubs + runtime UUID constants
|
|
27
|
+
types/ # TypeScript type definitions (items, execution, etc.)
|
|
28
|
+
index.ts # Library entry point (re-exports everything)
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Build system
|
|
32
|
+
|
|
33
|
+
- **Library** builds to CommonJS (`dist/index.cjs.js`) + ESM (`dist/index.es.js`) + types (`dist/index.d.ts`) via Vite (`vite.config.mts`).
|
|
34
|
+
- **CLI** builds to a single `dist/cli.js` executable via Vite (`vite.config.cli.mts`). It bundles commander, jszip, and all library code.
|
|
35
|
+
- TypeScript strict mode is enabled.
|
|
36
|
+
|
|
37
|
+
### Commands
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm run build # Full build (library + CLI)
|
|
41
|
+
npm run build:lib # Library only
|
|
42
|
+
npm run build:cli # CLI only
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Testing
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm run test # Run vitest unit tests (HTTP client contract)
|
|
49
|
+
npm run test:watch # Vitest watch mode
|
|
50
|
+
npm run test:ui # Interactive browser test page
|
|
51
|
+
npm run test:cli-build-app # Scaffold + build a test app
|
|
52
|
+
npm run test:cli-build-component # Scaffold + build a test cloud component
|
|
53
|
+
npm run test:cli-run-component # Run the test cloud component locally
|
|
54
|
+
npm run test:cli-build-tests # Build CLI + scaffold test app & test component into temp/
|
|
55
|
+
npm run test:cli-serve-tests # Serve the test app and test component's local server in parallel
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Two clients — components vs apps/FE
|
|
59
|
+
|
|
60
|
+
This package ships two clients with overlapping but intentionally different
|
|
61
|
+
surfaces. Pick the one that matches who's calling.
|
|
62
|
+
|
|
63
|
+
### `EngineServicesClient`
|
|
64
|
+
**For cloud components running inside the platform.** Authenticates via
|
|
65
|
+
API token by default (`?accessToken=`). Supports local-server execution,
|
|
66
|
+
WebSocket execution progress, built-in component runtime helpers, and the
|
|
67
|
+
low-level HTTP surface. This is what you get via
|
|
68
|
+
`EngineServicesClient.fromPlatformContext()` inside a component bundle.
|
|
69
|
+
|
|
70
|
+
### `PlatformClient`
|
|
71
|
+
**For apps, frontends, and any caller using a user JWT.** Extends
|
|
72
|
+
`EngineServicesClient`; the API-token-compatible surface is inherited and
|
|
73
|
+
the constructor forces `useBearer: true`. On top, it owns the JWT-only
|
|
74
|
+
routes — `getProject`, `getProjectData`, `checkPermission`,
|
|
75
|
+
`checkPermissionBatch` — which hit `ProjectController` in the backend
|
|
76
|
+
(guarded by JWT) and are not reachable with an access token.
|
|
77
|
+
|
|
78
|
+
The constructor accepts either a static JWT or a provider function
|
|
79
|
+
(sync or async) that returns the current JWT. The provider is called on
|
|
80
|
+
every request, so Auth0's `getAccessTokenSilently()` and similar
|
|
81
|
+
refreshing sources Just Work:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { PlatformClient } from 'thatopen-services';
|
|
85
|
+
const client = new PlatformClient(
|
|
86
|
+
() => auth0.getAccessTokenSilently(),
|
|
87
|
+
'https://api.thatopen.com',
|
|
88
|
+
);
|
|
89
|
+
await client.getProjectData(projectId);
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
`PlatformClient.fromPlatformContext()` is available for apps running inside
|
|
93
|
+
the platform iframe — it pulls the JWT from
|
|
94
|
+
`window.__THATOPEN_CONTEXT__` and returns a ready-to-use client.
|
|
95
|
+
|
|
96
|
+
Choose by audience:
|
|
97
|
+
- Component code → `EngineServicesClient` (or `EngineServicesClient.fromPlatformContext()`).
|
|
98
|
+
- App / FE / integration with a user JWT → `PlatformClient`.
|
|
99
|
+
|
|
100
|
+
## Permissions contract (backend coupling)
|
|
101
|
+
|
|
102
|
+
The platform API enforces **project-scoped permission checks**: whenever a
|
|
103
|
+
request carries a `projectId` (URL param, query, or body), the backend
|
|
104
|
+
rejects the call if the resource does not belong to that project or the
|
|
105
|
+
caller lacks permission there — regardless of whether the caller has access
|
|
106
|
+
to the same resource in a different project.
|
|
107
|
+
|
|
108
|
+
Relevant client methods:
|
|
109
|
+
|
|
110
|
+
- `executeComponent(componentId, executionParams, versionTag?)`: include
|
|
111
|
+
`projectId` in `executionParams` to scope the execution. The backend
|
|
112
|
+
validates that the component is linked to that project. Without a
|
|
113
|
+
`projectId`, the execution runs in the user's personal/ownership scope.
|
|
114
|
+
- `listExecutions(componentId, projectId?)`: pass `projectId` to filter
|
|
115
|
+
executions to that project's context.
|
|
116
|
+
- `checkPermission({ resourceType, action, resourceId?, projectId? })`:
|
|
117
|
+
returns `{ hasPermission, scope }`. `scope` is `'global' | 'project' |
|
|
118
|
+
'entity' | 'none'` — `global` for admin/owner bypass, `project` for a
|
|
119
|
+
role broad grant, `entity` for a per-entity override, `none` for denied.
|
|
120
|
+
- `checkPermissionBatch(checks)`: evaluates a list of checks in one
|
|
121
|
+
round-trip. Useful for hydrating action visibility for many rows without
|
|
122
|
+
N+1 calls.
|
|
123
|
+
|
|
124
|
+
Per-entity permission overrides (`ResourcePermission.removePermission`,
|
|
125
|
+
`ResourcePermission.appliesToDescendants`) are applied automatically on the
|
|
126
|
+
server side when listing project files/folders — no client change needed.
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
### Publishing to npm
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
yarn create-version # Build → changeset → version → publish
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Key concepts
|
|
136
|
+
|
|
137
|
+
### Apps vs Cloud Components
|
|
138
|
+
|
|
139
|
+
| | Apps | Cloud Components |
|
|
140
|
+
|---|---|---|
|
|
141
|
+
| **Runs in** | Browser (iframe on the platform) | Server (Node.js child process) |
|
|
142
|
+
| **Item type** | `APP` | `TOOL` |
|
|
143
|
+
| **Entry point** | Side effects in `main.ts` (renders UI) | `export async function main()` |
|
|
144
|
+
| **Context** | `window.__THATOPEN_CONTEXT__` provides `{ appId, projectId, accessToken, apiUrl }` | Globals: `thatOpenServices`, `executionParams`, `executionContext` (`{ projectId?, executionId, toolId, toolVersion }`), `executionReporter` (`message/error/progress`). `OBC`, `THREE`, `web-ifc`, `fs` are NOT injected — import them and let the bundler include them. |
|
|
145
|
+
| **Build output** | IIFE `dist/bundle.js` (all deps bundled) | IIFE `dist/bundle.js` (only `thatopen-services` externalized) |
|
|
146
|
+
| **Template** | `bim`, `default`, or `test` | `cloud` or `cloud-test` |
|
|
147
|
+
|
|
148
|
+
### Authentication
|
|
149
|
+
|
|
150
|
+
Two modes, controlled by `useBearer` in the constructor:
|
|
151
|
+
- **Query parameter** (default): Sends `accessToken` as a URL query param. Used with platform API tokens.
|
|
152
|
+
- **Bearer header** (`useBearer: true`): Sends as `Authorization: Bearer <token>`. Used with Auth0 JWTs inside platform apps.
|
|
153
|
+
|
|
154
|
+
### Built-in components
|
|
155
|
+
|
|
156
|
+
Built-in components are platform-hosted UI modules fetched at runtime. Usage pattern:
|
|
157
|
+
|
|
158
|
+
```ts
|
|
159
|
+
import { AppManager, ViewportManager } from "thatopen-services";
|
|
160
|
+
|
|
161
|
+
// Register all library globals once
|
|
162
|
+
client.setBuiltInGlobals({ OBC, OBF, BUI, CUI, THREE, FRAGS });
|
|
163
|
+
|
|
164
|
+
// Fetch, evaluate, and register with OBC — globals are automatically applied
|
|
165
|
+
await client.initBuiltInComponent(AppManager, components);
|
|
166
|
+
await client.initBuiltInComponent(ViewportManager, components);
|
|
167
|
+
|
|
168
|
+
// Use via OBC component system
|
|
169
|
+
const app = components.get(AppManager);
|
|
170
|
+
const viewports = components.get(ViewportManager);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Available built-in components:
|
|
174
|
+
|
|
175
|
+
| Component | Purpose |
|
|
176
|
+
|-----------|---------|
|
|
177
|
+
| `AppManager` | App shell — CSS grid layout with sidebar for switching layouts |
|
|
178
|
+
| `ViewportManager` | Factory for 3D viewports with pre-configured world |
|
|
179
|
+
| `LoadModelButton` | Button + dropdown for loading IFC / Fragments files |
|
|
180
|
+
| `ViewerToolbar` | Toolbar with Show/Hide/Focus/Isolate and color palette |
|
|
181
|
+
| `ModelsPanel` | Panel listing loaded models with search and load button |
|
|
182
|
+
| `ModelsDropdown` | Dropdown selector listing loaded models |
|
|
183
|
+
| `ClassificationsList` | Hierarchical table of IFC classification data |
|
|
184
|
+
| `ClashesList` | Interactive clash detection results with highlighting |
|
|
185
|
+
| `ClippingsList` | Panel listing clipping planes with controls |
|
|
186
|
+
| `LengthMeasuringsList` | Panel listing length measurements with totals |
|
|
187
|
+
| `AreaMeasuringsList` | Panel listing area measurements with totals |
|
|
188
|
+
| `ColorsPalette` | Color picker with Highlighter style swatches |
|
|
189
|
+
| `HighlightersList` | Panel listing Highlighter styles with manage actions |
|
|
190
|
+
| `QtoComparisonList` | Side-by-side quantity comparison for two elements |
|
|
191
|
+
| `QueriesHierarchy` | Recursive multi-level query browser |
|
|
192
|
+
| `CustomViewLegend` | Color legend overlay |
|
|
193
|
+
| `ScreenshotAnnotator` | Modal for annotating screenshots via MarkerJS |
|
|
194
|
+
|
|
195
|
+
Full API reference with config interfaces, method signatures, and `@example` blocks: `src/built-in/index.ts`.
|
|
196
|
+
|
|
197
|
+
### Configuration files
|
|
198
|
+
|
|
199
|
+
- **Global**: `~/.thatopen/config.json` — `{ accessToken, apiUrl }`
|
|
200
|
+
- **Local** (per project): `.thatopen` — `{ accessToken, apiUrl, appId?, componentId?, itemType? }`
|
|
201
|
+
- Local config takes priority. Created by `thatopen login --local`.
|
|
202
|
+
|
|
203
|
+
## API surface (EngineServicesClient)
|
|
204
|
+
|
|
205
|
+
### Files
|
|
206
|
+
- `listFiles(filters?)` / `getFile(id, props?)` / `createFile(data)` / `updateFile(id, data)`
|
|
207
|
+
- `archiveFile(id)` / `recoverFile(id)` / `downloadFile(id, params?)` / `getFileMetadata(id, params?)`
|
|
208
|
+
|
|
209
|
+
### Folders
|
|
210
|
+
- `listFolders(params?)` / `getFolder(id)` / `createFolder(name, parentId?)`
|
|
211
|
+
- `updateFolder(id, params)` / `archiveFolder(id)` / `recoverFolder(id)` / `downloadFolder(id)`
|
|
212
|
+
|
|
213
|
+
### Components
|
|
214
|
+
- `listComponents(params?)` / `getComponent(id, props?)` / `createComponent(data)` / `updateComponent(id, data)`
|
|
215
|
+
- `archiveComponent(id)` / `recoverComponent(id)` / `downloadComponent(id, params?)` / `downloadComponentBundle(id, params?)`
|
|
216
|
+
|
|
217
|
+
### Apps
|
|
218
|
+
- `listApps(params?)` / `createApp(data)` / `archiveApp(id)`
|
|
219
|
+
- `downloadApp(id, params?)` / `downloadAppBundle(id, params?)`
|
|
220
|
+
|
|
221
|
+
### Execution (cloud components)
|
|
222
|
+
- `executeComponent(componentId, params, versionTag?)` — triggers server-side execution, returns `{ executionId }`
|
|
223
|
+
- `abortExecution(executionId)` / `listExecutions(componentId)` / `getExecution(executionId)`
|
|
224
|
+
- `onExecutionProgress(executionId, callback)` — real-time WebSocket subscription
|
|
225
|
+
|
|
226
|
+
### Built-in components
|
|
227
|
+
- `setBuiltInGlobals(globals)` — registers globals once; subsequent `initBuiltInComponent` calls use them automatically
|
|
228
|
+
- `getBuiltInComponent(name)` — fetches JS bundle by name
|
|
229
|
+
- `initBuiltInComponent(component, components, globals?)` — fetches, evaluates, and registers (uses stored globals if `globals` omitted)
|
|
230
|
+
|
|
231
|
+
### Hidden files
|
|
232
|
+
- `createHiddenFile(file, parentId)` / `deleteHiddenFile(id)` / `getHiddenFile(id)`
|
|
233
|
+
- `downloadHiddenFile(id)` / `getHiddenFilesByParent(parentId)` / `deleteHiddenFilesByParent(parentId)`
|
|
234
|
+
|
|
235
|
+
### General
|
|
236
|
+
- `updateItem(id, params)` / `createVersion(id, file, tag, extraProps?, metadata?)`
|
|
237
|
+
- `getProjectData(projectId)` / `checkPermission(params)`
|
|
238
|
+
|
|
239
|
+
## CLI commands
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
thatopen create <name> [--template bim|default|cloud|test|cloud-test]
|
|
243
|
+
# Scaffold project + auto npm install
|
|
244
|
+
# Use "." as name to scaffold in current directory
|
|
245
|
+
thatopen serve [--port N] # Dev server (esbuild watch + serve bundle)
|
|
246
|
+
thatopen login [--token T] [--api-url U] [--local] # Authenticate
|
|
247
|
+
thatopen publish [--name N] [--version-tag T] [--skip-build] [--app-id ID | --component-id ID]
|
|
248
|
+
thatopen run [--params '{}'] [--skip-build] # Test cloud component locally
|
|
249
|
+
thatopen local-server [--port N] [--skip-build] # Local execution server (API-compatible)
|
|
250
|
+
thatopen create-tests [directory] # Scaffold test app + test component (cleans directory first)
|
|
251
|
+
thatopen serve-tests [directory] # Serve test app + test component in parallel
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Dependencies
|
|
255
|
+
|
|
256
|
+
- **Runtime**: `dotenv`, `socket.io-client`
|
|
257
|
+
- **Peer** (optional): `@thatopen/components` ^3.3.1, `@thatopen/ui` ^3.3.3, `three` ^0.182.0
|
|
258
|
+
- **CLI bundled**: `commander`, `jszip`
|
package/README.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# thatopen-services
|
|
2
|
+
|
|
3
|
+
Client library and CLI for building BIM apps and cloud components on the [That Open Platform](https://platform.thatopen.com).
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
### Create a BIM app
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Install the services package globally
|
|
11
|
+
npm i thatopen-services -g
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Then, create a brand new app repository:
|
|
15
|
+
|
|
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
|
+
```
|
|
210
|
+
|
|
211
|
+
### Build commands
|
|
212
|
+
|
|
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
|
|
220
|
+
|
|
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
|
|
227
|
+
|
|
228
|
+
# Build and scaffold a test cloud component
|
|
229
|
+
npm run test:cli-build-component
|
|
230
|
+
|
|
231
|
+
# Run the test cloud component locally
|
|
232
|
+
npm run test:cli-run-component
|
|
233
|
+
```
|
|
234
|
+
|
|
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
|
+
```
|
|
247
|
+
|
|
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:
|
|
249
|
+
|
|
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)
|
|
254
|
+
|
|
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:".
|
|
256
|
+
|
|
257
|
+
### Publishing a new version
|
|
258
|
+
|
|
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
|
+
```
|
|
284
|
+
|
|
285
|
+
Keep in mind the importance of semver — don't release a major for non-breaking changes.
|