@thatopen/services 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/AGENTS.md +86 -76
  2. package/dist/cli.js +10 -1
  3. package/docs/access-backend-data.md +19 -19
  4. package/docs/app-architecture.md +94 -94
  5. package/docs/app-layout.md +139 -139
  6. package/docs/app-wiring.md +123 -123
  7. package/docs/bim-components/coding-conventions.md +128 -128
  8. package/docs/bim-components/element-collections.md +69 -69
  9. package/docs/bim-components/expose-events.md +84 -84
  10. package/docs/bim-components/library-examples.md +28 -28
  11. package/docs/bim-components/observable-collections.md +83 -83
  12. package/docs/bim-components/overview.md +160 -160
  13. package/docs/bim-components/per-frame-updates.md +20 -20
  14. package/docs/bim-components/save-and-restore-state.md +21 -21
  15. package/docs/bim-components/setup-and-cleanup.md +64 -64
  16. package/docs/bim-components/type-conventions.md +49 -49
  17. package/docs/bim-components/user-driven-object-creation.md +56 -56
  18. package/docs/cli-setup.md +54 -54
  19. package/docs/cloud-components.md +74 -74
  20. package/docs/connect-logic-to-ui.md +113 -113
  21. package/docs/previewing.md +45 -45
  22. package/docs/publishing.md +35 -35
  23. package/docs/scaffolding.md +71 -54
  24. package/docs/ui-components/async-actions.md +18 -18
  25. package/docs/ui-components/confirmation-dialog.md +39 -39
  26. package/docs/ui-components/data-table.md +185 -185
  27. package/docs/ui-components/display-text.md +39 -39
  28. package/docs/ui-components/inline-form.md +44 -44
  29. package/docs/ui-components/library-examples.md +24 -24
  30. package/docs/ui-components/overview.md +194 -194
  31. package/docs/ui-components/rendering-patterns.md +129 -129
  32. package/docs/ui-components/sections-layout.md +123 -123
  33. package/docs/update-grid-elements.md +46 -46
  34. package/docs/using-colors.md +32 -32
  35. package/docs/using-icons.md +37 -37
  36. package/package.json +2 -2
  37. package/src/cli/templates/bim/CONTEXT.md +1 -4
  38. package/src/cli/templates/bim/package.json +0 -1
  39. package/src/cli/templates/bim/src/main.ts +1 -2
  40. package/src/cli/templates/bim-beta/CONTEXT.md +241 -0
  41. package/src/cli/templates/bim-beta/package.json +25 -0
  42. package/src/cli/templates/bim-beta/src/app.ts +16 -0
  43. package/src/cli/templates/bim-beta/src/bim-components/CloudRunner/index.ts +91 -0
  44. package/src/cli/templates/bim-beta/src/bim-components/CloudRunner/src/index.ts +1 -0
  45. package/src/cli/templates/bim-beta/src/bim-components/CloudRunner/src/types.ts +5 -0
  46. package/src/cli/templates/bim-beta/src/bim-components/index.ts +1 -0
  47. package/src/cli/templates/bim-beta/src/globals.ts +1 -0
  48. package/src/cli/templates/bim-beta/src/main.ts +93 -0
  49. package/src/cli/templates/bim-beta/src/setups/cloud-runner.ts +13 -0
  50. package/src/cli/templates/bim-beta/src/setups/index.ts +3 -0
  51. package/src/cli/templates/bim-beta/src/setups/ui-manager.ts +27 -0
  52. package/src/cli/templates/bim-beta/src/setups/viewports-manager.ts +22 -0
  53. package/src/cli/templates/bim-beta/src/ui-components/app-info-section/index.ts +26 -0
  54. package/src/cli/templates/bim-beta/src/ui-components/app-info-section/src/index.ts +1 -0
  55. package/src/cli/templates/bim-beta/src/ui-components/app-info-section/src/types.ts +15 -0
  56. package/src/cli/templates/bim-beta/src/ui-components/cloud-runner-section/index.ts +37 -0
  57. package/src/cli/templates/bim-beta/src/ui-components/cloud-runner-section/src/index.ts +1 -0
  58. package/src/cli/templates/bim-beta/src/ui-components/cloud-runner-section/src/types.ts +14 -0
  59. package/src/cli/templates/bim-beta/src/ui-components/index.ts +2 -0
  60. package/src/cli/templates/cloud/CONTEXT.md +205 -205
  61. package/src/cli/templates/cloud/src/main.ts +70 -70
  62. package/src/cli/templates/shared/AGENTS.md +30 -23
  63. package/src/cli/templates/shared/CLAUDE.md +1 -1
@@ -1,64 +1,64 @@
1
- # Setup and Cleanup
2
-
3
- Two interfaces govern a component's lifecycle: `OBC.Configurable` for one-time initialization before use, and `OBC.Disposable` for cleanup when the component is destroyed.
4
-
5
- ---
6
-
7
- ## `OBC.Configurable<TManager, TConfig>`
8
-
9
- Implement when the component requires one-time initialization. This separates construction (cheap, no side effects) from setup (resolves dependencies, applies config, registers event listeners).
10
-
11
- ```ts
12
- export interface ActivityTrackerConfig {
13
- color: THREE.Color;
14
- autoColorize: boolean;
15
- }
16
-
17
- export class ActivityTracker extends OBC.Component
18
- implements OBC.Configurable<ActivityTrackerConfigManager, ActivityTrackerConfig> {
19
-
20
- isSetup = false;
21
- readonly onSetup = new OBC.Event<undefined>();
22
-
23
- protected _defaultConfig: ActivityTrackerConfig = {
24
- color: new THREE.Color("#6528d7"),
25
- autoColorize: false,
26
- };
27
-
28
- setup(config?: Partial<ActivityTrackerConfig>) {
29
- if (this.isSetup) return;
30
- const fullConfig = { ...this._defaultConfig, ...config };
31
- // apply config, resolve dependencies...
32
- this.isSetup = true;
33
- this.onSetup.trigger(undefined);
34
- }
35
- }
36
- ```
37
-
38
- The `if (this.isSetup) return` guard ensures setup only runs once. The constructor must never call other components — that belongs in `setup()`.
39
-
40
- ---
41
-
42
- ## `OBC.Disposable`
43
-
44
- Implement when the component holds resources that must be explicitly released — Three.js geometries and materials, event subscriptions to external components, workers.
45
-
46
- ```ts
47
- export class ActivityTracker extends OBC.Component implements OBC.Disposable {
48
- readonly onDisposed = new OBC.Event<undefined>();
49
-
50
- dispose() {
51
- // 1. Release Three.js resources
52
- this._mesh?.geometry.dispose();
53
- this._material.dispose();
54
-
55
- // 2. Reset all events (if OBC.Eventable is also implemented)
56
- this.events.reset();
57
-
58
- // 3. Signal disposal — always last
59
- this.onDisposed.trigger(undefined);
60
- }
61
- }
62
- ```
63
-
64
- `onDisposed` must be triggered at the end of `dispose()`, after all cleanup is done.
1
+ # Setup and Cleanup
2
+
3
+ Two interfaces govern a component's lifecycle: `OBC.Configurable` for one-time initialization before use, and `OBC.Disposable` for cleanup when the component is destroyed.
4
+
5
+ ---
6
+
7
+ ## `OBC.Configurable<TManager, TConfig>`
8
+
9
+ Implement when the component requires one-time initialization. This separates construction (cheap, no side effects) from setup (resolves dependencies, applies config, registers event listeners).
10
+
11
+ ```ts
12
+ export interface ActivityTrackerConfig {
13
+ color: THREE.Color;
14
+ autoColorize: boolean;
15
+ }
16
+
17
+ export class ActivityTracker extends OBC.Component
18
+ implements OBC.Configurable<ActivityTrackerConfigManager, ActivityTrackerConfig> {
19
+
20
+ isSetup = false;
21
+ readonly onSetup = new OBC.Event<undefined>();
22
+
23
+ protected _defaultConfig: ActivityTrackerConfig = {
24
+ color: new THREE.Color("#6528d7"),
25
+ autoColorize: false,
26
+ };
27
+
28
+ setup(config?: Partial<ActivityTrackerConfig>) {
29
+ if (this.isSetup) return;
30
+ const fullConfig = { ...this._defaultConfig, ...config };
31
+ // apply config, resolve dependencies...
32
+ this.isSetup = true;
33
+ this.onSetup.trigger(undefined);
34
+ }
35
+ }
36
+ ```
37
+
38
+ The `if (this.isSetup) return` guard ensures setup only runs once. The constructor must never call other components — that belongs in `setup()`.
39
+
40
+ ---
41
+
42
+ ## `OBC.Disposable`
43
+
44
+ Implement when the component holds resources that must be explicitly released — Three.js geometries and materials, event subscriptions to external components, workers.
45
+
46
+ ```ts
47
+ export class ActivityTracker extends OBC.Component implements OBC.Disposable {
48
+ readonly onDisposed = new OBC.Event<undefined>();
49
+
50
+ dispose() {
51
+ // 1. Release Three.js resources
52
+ this._mesh?.geometry.dispose();
53
+ this._material.dispose();
54
+
55
+ // 2. Reset all events (if OBC.Eventable is also implemented)
56
+ this.events.reset();
57
+
58
+ // 3. Signal disposal — always last
59
+ this.onDisposed.trigger(undefined);
60
+ }
61
+ }
62
+ ```
63
+
64
+ `onDisposed` must be triggered at the end of `dispose()`, after all cleanup is done.
@@ -1,49 +1,49 @@
1
- # Type Conventions
2
-
3
- All types for a component live in `src/types.ts` — domain interfaces, event payloads, serialized equivalents — so there is a single place to look.
4
-
5
- ---
6
-
7
- ## Runtime vs serialized
8
-
9
- Components that implement `OBC.Serializable` need two versions of their data types: a runtime version that uses rich TypeScript types, and a serialized version that is JSON-safe.
10
-
11
- The serialized type is named `Serialized{TypeName}`:
12
-
13
- ```ts
14
- // Runtime — uses Map, Set, Date, THREE.Color
15
- export interface Activity {
16
- index: number;
17
- name: string;
18
- color: THREE.Color;
19
- items: OBC.ModelIdMap;
20
- dates: Set<string>;
21
- }
22
-
23
- // Serialized — JSON-safe equivalent
24
- export interface SerializedActivity {
25
- index: number;
26
- name: string;
27
- color: string; // THREE.Color → hex string
28
- items: [string, number[]][]; // ModelIdMap → tuple array
29
- dates: string[]; // Set → array
30
- }
31
- ```
32
-
33
- Conversion happens inside `export()` and `import()` (see [`./save-and-restore-state.md`](./save-and-restore-state.md)).
34
-
35
- ---
36
-
37
- ## Generics that require `type`, not `interface`
38
-
39
- Some OBC and FRAGS generics enforce that their type parameter is a `type` alias. Passing an `interface` causes a TypeScript error. When in doubt, prefer `type` for types used as generic parameters:
40
-
41
- ```ts
42
- // ✗ Fails — interface not assignable to the generic constraint
43
- export interface ActivityData { name: string; value: number }
44
- const list = new FRAGS.DataMap<string, ActivityData>(); // error
45
-
46
- // ✓ Correct
47
- export type ActivityData = { name: string; value: number }
48
- const list = new FRAGS.DataMap<string, ActivityData>();
49
- ```
1
+ # Type Conventions
2
+
3
+ All types for a component live in `src/types.ts` — domain interfaces, event payloads, serialized equivalents — so there is a single place to look.
4
+
5
+ ---
6
+
7
+ ## Runtime vs serialized
8
+
9
+ Components that implement `OBC.Serializable` need two versions of their data types: a runtime version that uses rich TypeScript types, and a serialized version that is JSON-safe.
10
+
11
+ The serialized type is named `Serialized{TypeName}`:
12
+
13
+ ```ts
14
+ // Runtime — uses Map, Set, Date, THREE.Color
15
+ export interface Activity {
16
+ index: number;
17
+ name: string;
18
+ color: THREE.Color;
19
+ items: OBC.ModelIdMap;
20
+ dates: Set<string>;
21
+ }
22
+
23
+ // Serialized — JSON-safe equivalent
24
+ export interface SerializedActivity {
25
+ index: number;
26
+ name: string;
27
+ color: string; // THREE.Color → hex string
28
+ items: [string, number[]][]; // ModelIdMap → tuple array
29
+ dates: string[]; // Set → array
30
+ }
31
+ ```
32
+
33
+ Conversion happens inside `export()` and `import()` (see [`./save-and-restore-state.md`](./save-and-restore-state.md)).
34
+
35
+ ---
36
+
37
+ ## Generics that require `type`, not `interface`
38
+
39
+ Some OBC and FRAGS generics enforce that their type parameter is a `type` alias. Passing an `interface` causes a TypeScript error. When in doubt, prefer `type` for types used as generic parameters:
40
+
41
+ ```ts
42
+ // ✗ Fails — interface not assignable to the generic constraint
43
+ export interface ActivityData { name: string; value: number }
44
+ const list = new FRAGS.DataMap<string, ActivityData>(); // error
45
+
46
+ // ✓ Correct
47
+ export type ActivityData = { name: string; value: number }
48
+ const list = new FRAGS.DataMap<string, ActivityData>();
49
+ ```
@@ -1,56 +1,56 @@
1
- # User-Driven Object Creation
2
-
3
- ## `OBC.Createable`
4
-
5
- Implement when the component lets the user create objects in the scene through a multi-step interaction — click to start, click to confirm, Escape to cancel, click existing to delete.
6
-
7
- The key characteristic is **statefulness between clicks**: `create()` is called on every user click, but the first click initiates the workflow and the second confirms it by calling `endCreation()` internally.
8
-
9
- ```ts
10
- export class ActivityTracker extends OBC.Component implements OBC.Createable {
11
- private _temp: { isDragging: boolean; preview?: SomeObject } = {
12
- isDragging: false,
13
- };
14
-
15
- create = () => {
16
- if (!this.enabled) return;
17
- if (!this._temp.isDragging) {
18
- this._temp.isDragging = true;
19
- this._temp.preview = new SomeObject();
20
- return;
21
- }
22
- this.endCreation();
23
- };
24
-
25
- endCreation = () => {
26
- if (!this._temp.preview) return;
27
- this.list.add(this._temp.preview);
28
- this._temp.isDragging = false;
29
- this._temp.preview = undefined;
30
- };
31
-
32
- cancelCreation = () => {
33
- this._temp.isDragging = false;
34
- this._temp.preview?.dispose();
35
- this._temp.preview = undefined;
36
- };
37
-
38
- delete = () => {
39
- if (!this.world) return;
40
- const casters = this.components.get(OBC.Raycasters);
41
- const caster = casters.get(this.world);
42
- const intersect = caster.castRayToObjects([...this._boundingBoxes]);
43
- if (!intersect) return;
44
- // identify and remove the hit object from list
45
- };
46
- }
47
- ```
48
-
49
- Wire up the Escape key in the component's `enabled` setter so `cancelCreation()` fires automatically when the component is disabled mid-flow:
50
-
51
- ```ts
52
- set enabled(value: boolean) {
53
- this._enabled = value;
54
- if (!value) this.cancelCreation();
55
- }
56
- ```
1
+ # User-Driven Object Creation
2
+
3
+ ## `OBC.Createable`
4
+
5
+ Implement when the component lets the user create objects in the scene through a multi-step interaction — click to start, click to confirm, Escape to cancel, click existing to delete.
6
+
7
+ The key characteristic is **statefulness between clicks**: `create()` is called on every user click, but the first click initiates the workflow and the second confirms it by calling `endCreation()` internally.
8
+
9
+ ```ts
10
+ export class ActivityTracker extends OBC.Component implements OBC.Createable {
11
+ private _temp: { isDragging: boolean; preview?: SomeObject } = {
12
+ isDragging: false,
13
+ };
14
+
15
+ create = () => {
16
+ if (!this.enabled) return;
17
+ if (!this._temp.isDragging) {
18
+ this._temp.isDragging = true;
19
+ this._temp.preview = new SomeObject();
20
+ return;
21
+ }
22
+ this.endCreation();
23
+ };
24
+
25
+ endCreation = () => {
26
+ if (!this._temp.preview) return;
27
+ this.list.add(this._temp.preview);
28
+ this._temp.isDragging = false;
29
+ this._temp.preview = undefined;
30
+ };
31
+
32
+ cancelCreation = () => {
33
+ this._temp.isDragging = false;
34
+ this._temp.preview?.dispose();
35
+ this._temp.preview = undefined;
36
+ };
37
+
38
+ delete = () => {
39
+ if (!this.world) return;
40
+ const casters = this.components.get(OBC.Raycasters);
41
+ const caster = casters.get(this.world);
42
+ const intersect = caster.castRayToObjects([...this._boundingBoxes]);
43
+ if (!intersect) return;
44
+ // identify and remove the hit object from list
45
+ };
46
+ }
47
+ ```
48
+
49
+ Wire up the Escape key in the component's `enabled` setter so `cancelCreation()` fires automatically when the component is disabled mid-flow:
50
+
51
+ ```ts
52
+ set enabled(value: boolean) {
53
+ this._enabled = value;
54
+ if (!value) this.cancelCreation();
55
+ }
56
+ ```
package/docs/cli-setup.md CHANGED
@@ -1,54 +1,54 @@
1
- # CLI Setup and Authentication
2
-
3
- Before you can scaffold or publish a That Open Platform app, two things must be in place: the `@thatopen/services` CLI installed globally, and a valid platform token for authentication.
4
-
5
- ---
6
-
7
- ## Step 1: Install or update the CLI
8
-
9
- Run the following command in the terminal. This installs the CLI if it isn't present, or updates it to the latest version if it already is:
10
-
11
- ```bash
12
- npm i @thatopen/services@latest -g
13
- ```
14
-
15
- Once done, verify it works:
16
-
17
- ```bash
18
- thatopen --version
19
- ```
20
-
21
- If this returns a version number, the CLI is ready. If `npm` is not found, install Node.js first — download the LTS version from [https://nodejs.org](https://nodejs.org), then retry.
22
-
23
- ---
24
-
25
- ## Step 2: Get a platform token
26
-
27
- Generate an access token from the platform:
28
-
29
- 1. Go to [https://dev.platform.thatopen.com](https://dev.platform.thatopen.com)
30
- 2. In the header, click **Data**
31
- 3. Find the **Tokens** card and create a new token
32
- 4. Enable the permissions: **Apps**, **Components** and **Storage**
33
- 5. Copy the token
34
-
35
- ---
36
-
37
- ## Step 3: Authenticate
38
-
39
- Once you have the token, run:
40
-
41
- ```bash
42
- npm run login -- --token <TOKEN>
43
- ```
44
-
45
- where `<TOKEN>` is the token you copied. This stores credentials globally at `~/.thatopen/config.json` and persists across sessions — you only need to do this once per machine.
46
-
47
- ---
48
-
49
- ## When to use this guide
50
-
51
- Read this guide when:
52
- - You are starting a new app and haven't confirmed the CLI is installed
53
- - A `thatopen` command fails with a "command not found" or "not authenticated" error
54
- - You have never built a platform app before on this machine
1
+ # CLI Setup and Authentication
2
+
3
+ Before you can scaffold or publish a That Open Platform app, two things must be in place: the `@thatopen/services` CLI installed globally, and a valid platform token for authentication.
4
+
5
+ ---
6
+
7
+ ## Step 1: Install or update the CLI
8
+
9
+ Run the following command in the terminal. This installs the CLI if it isn't present, or updates it to the latest version if it already is:
10
+
11
+ ```bash
12
+ npm i @thatopen/services@latest -g
13
+ ```
14
+
15
+ Once done, verify it works:
16
+
17
+ ```bash
18
+ thatopen --version
19
+ ```
20
+
21
+ If this returns a version number, the CLI is ready. If `npm` is not found, install Node.js first — download the LTS version from [https://nodejs.org](https://nodejs.org), then retry.
22
+
23
+ ---
24
+
25
+ ## Step 2: Get a platform token
26
+
27
+ Generate an access token from the platform:
28
+
29
+ 1. Go to [https://dev.platform.thatopen.com](https://dev.platform.thatopen.com)
30
+ 2. In the header, click **Data**
31
+ 3. Find the **Tokens** card and create a new token
32
+ 4. Enable the permissions: **Apps**, **Components** and **Storage**
33
+ 5. Copy the token
34
+
35
+ ---
36
+
37
+ ## Step 3: Authenticate
38
+
39
+ Once you have the token, run:
40
+
41
+ ```bash
42
+ npm run login -- --token <TOKEN>
43
+ ```
44
+
45
+ where `<TOKEN>` is the token you copied. This stores credentials globally at `~/.thatopen/config.json` and persists across sessions — you only need to do this once per machine.
46
+
47
+ ---
48
+
49
+ ## When to use this guide
50
+
51
+ Read this guide when:
52
+ - You are starting a new app and haven't confirmed the CLI is installed
53
+ - A `thatopen` command fails with a "command not found" or "not authenticated" error
54
+ - You have never built a platform app before on this machine
@@ -1,74 +1,74 @@
1
- # Cloud components & automations
2
-
3
- A **cloud component** is a piece of logic that runs **server-side** (Node.js) on the platform,
4
- on the shared project context, via the API. Use them to automate real operations — clash checks,
5
- validations, document generation — and to let apps offload heavy work.
6
-
7
- ## Apps vs cloud components
8
-
9
- | | Apps | Cloud components |
10
- |---|---|---|
11
- | **Runs in** | Browser (iframe on the platform) | Server (Node.js child process) |
12
- | **Item type** | `APP` | `TOOL` |
13
- | **Entry point** | Side effects in `main.ts` (renders UI) | `export async function main()` |
14
- | **Build output** | IIFE `dist/bundle.js` (all deps bundled) | IIFE `dist/bundle.js` (only `@thatopen/services` externalized) |
15
- | **Template** | `bim`, `default`, `test` | `cloud`, `cloud-test` |
16
-
17
- ## Scaffold
18
-
19
- ```bash
20
- thatopen create my-component --template cloud
21
- cd my-component
22
- ```
23
-
24
- The component is an `export async function main()` that runs on the server. The execution engine
25
- injects these globals (do **not** import them; for `OBC`/`THREE`/`web-ifc` import them so the
26
- bundler includes them):
27
-
28
- | Global | Purpose |
29
- |--------|---------|
30
- | `thatOpenServices` | Authenticated `EngineServicesClient` |
31
- | `executionParams` | Parameters passed by the caller |
32
- | `executionContext` | `{ projectId?, executionId, toolId, toolVersion }` |
33
- | `executionReporter` | `{ message(msg), error(msg), progress(pct) }` for live feedback |
34
- | `OBC` | `@thatopen/components` — BIM engine (import it) |
35
- | `THREE` | `three` — 3D math/geometry (import it) |
36
- | `fs` | Node.js filesystem (import it) |
37
-
38
- ## Run locally
39
-
40
- ```bash
41
- npm run run # build + test locally
42
- npx thatopen run --params '{"inputFile":"model.ifc"}' # pass parameters
43
- ```
44
-
45
- `thatopen local-server` starts an API-compatible local execution server (default `:4001`) so an
46
- app can call the component before it's deployed (set `client.localServerUrl`).
47
-
48
- ## Authenticate & publish
49
-
50
- ```bash
51
- npm run login -- --token <your-token>
52
- npm run publish
53
- ```
54
-
55
- ## Calling a component from an app
56
-
57
- ```ts
58
- const { executionId } = await client.executeComponent(componentId, { param: "value" }, versionTag?);
59
- client.onExecutionProgress(executionId, (data) => {
60
- // data.progressUpdate — percentage
61
- // data.messageUpdate — status messages
62
- });
63
- ```
64
-
65
- Include `projectId` in the execution params to scope the run to a project (the backend validates
66
- the component is linked to that project). See [CONTEXT.md](../CONTEXT.md) for the permissions contract.
67
-
68
- ## Automations (event-triggered components)
69
-
70
- An **automation** is a cloud component that runs automatically in response to a platform **event**
71
- (rather than being invoked by hand) — e.g. "run the clash check whenever a model is updated."
72
- The component is the same; what differs is the trigger. Add it to a project, choose the event(s)
73
- that fire it, and the platform executes it on the shared project context, reporting progress and
74
- logs through `executionReporter`. Build and publish it exactly like any other cloud component above.
1
+ # Cloud components & automations
2
+
3
+ A **cloud component** is a piece of logic that runs **server-side** (Node.js) on the platform,
4
+ on the shared project context, via the API. Use them to automate real operations — clash checks,
5
+ validations, document generation — and to let apps offload heavy work.
6
+
7
+ ## Apps vs cloud components
8
+
9
+ | | Apps | Cloud components |
10
+ |---|---|---|
11
+ | **Runs in** | Browser (iframe on the platform) | Server (Node.js child process) |
12
+ | **Item type** | `APP` | `TOOL` |
13
+ | **Entry point** | Side effects in `main.ts` (renders UI) | `export async function main()` |
14
+ | **Build output** | IIFE `dist/bundle.js` (all deps bundled) | IIFE `dist/bundle.js` (only `@thatopen/services` externalized) |
15
+ | **Template** | `bim`, `default`, `test` | `cloud`, `cloud-test` |
16
+
17
+ ## Scaffold
18
+
19
+ ```bash
20
+ thatopen create my-component --template cloud
21
+ cd my-component
22
+ ```
23
+
24
+ The component is an `export async function main()` that runs on the server. The execution engine
25
+ injects these globals (do **not** import them; for `OBC`/`THREE`/`web-ifc` import them so the
26
+ bundler includes them):
27
+
28
+ | Global | Purpose |
29
+ |--------|---------|
30
+ | `thatOpenServices` | Authenticated `EngineServicesClient` |
31
+ | `executionParams` | Parameters passed by the caller |
32
+ | `executionContext` | `{ projectId?, executionId, toolId, toolVersion }` |
33
+ | `executionReporter` | `{ message(msg), error(msg), progress(pct) }` for live feedback |
34
+ | `OBC` | `@thatopen/components` — BIM engine (import it) |
35
+ | `THREE` | `three` — 3D math/geometry (import it) |
36
+ | `fs` | Node.js filesystem (import it) |
37
+
38
+ ## Run locally
39
+
40
+ ```bash
41
+ npm run run # build + test locally
42
+ npx thatopen run --params '{"inputFile":"model.ifc"}' # pass parameters
43
+ ```
44
+
45
+ `thatopen local-server` starts an API-compatible local execution server (default `:4001`) so an
46
+ app can call the component before it's deployed (set `client.localServerUrl`).
47
+
48
+ ## Authenticate & publish
49
+
50
+ ```bash
51
+ npm run login -- --token <your-token>
52
+ npm run publish
53
+ ```
54
+
55
+ ## Calling a component from an app
56
+
57
+ ```ts
58
+ const { executionId } = await client.executeComponent(componentId, { param: "value" }, versionTag?);
59
+ client.onExecutionProgress(executionId, (data) => {
60
+ // data.progressUpdate — percentage
61
+ // data.messageUpdate — status messages
62
+ });
63
+ ```
64
+
65
+ Include `projectId` in the execution params to scope the run to a project (the backend validates
66
+ the component is linked to that project). See [CONTEXT.md](../CONTEXT.md) for the permissions contract.
67
+
68
+ ## Automations (event-triggered components)
69
+
70
+ An **automation** is a cloud component that runs automatically in response to a platform **event**
71
+ (rather than being invoked by hand) — e.g. "run the clash check whenever a model is updated."
72
+ The component is the same; what differs is the trigger. Add it to a project, choose the event(s)
73
+ that fire it, and the platform executes it on the shared project context, reporting progress and
74
+ logs through `executionReporter`. Build and publish it exactly like any other cloud component above.