@thatopen/services 0.3.15 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +62 -62
  2. package/dist/built-in/index.d.ts +165 -2
  3. package/dist/cli.js +27 -13
  4. package/dist/core/client.d.ts +1 -0
  5. package/dist/core/platform-client.d.ts +7 -0
  6. package/dist/index.cjs.js +2 -2
  7. package/dist/index.es.js +396 -374
  8. package/dist/vite-env.d.ts +1 -1
  9. package/docs/builtin/paths.json +94 -86
  10. package/docs/cli/create.md +29 -29
  11. package/docs/cli/local-server.md +38 -38
  12. package/docs/cli/login.md +32 -32
  13. package/docs/cli/publish.md +31 -31
  14. package/docs/cli/run.md +26 -26
  15. package/docs/cli/serve.md +43 -43
  16. package/docs/cli/swap.md +30 -30
  17. package/package.json +4 -4
  18. package/resources/AGENTS.md +40 -40
  19. package/src/built-in/CDEManager/example.ts +214 -214
  20. package/src/built-in/CDEManager/examples/FileEditing/example.ts +226 -226
  21. package/src/built-in/CDEManager/examples/FileMoves/example.ts +186 -186
  22. package/src/built-in/CDEManager/examples/FileOperations/example.ts +295 -295
  23. package/src/built-in/CDEManager/examples/FileTransfers/example.ts +210 -210
  24. package/src/built-in/CDEManager/examples/FolderManagement/example.ts +230 -230
  25. package/src/built-in/CDEManager/examples/MetadataSchema/example.ts +230 -230
  26. package/src/built-in/CDEManager/examples/MetadataViews/example.ts +166 -166
  27. package/src/built-in/CDEManager/examples/ProjectConfig/example.ts +177 -177
  28. package/src/built-in/ClashesManager/example.ts +283 -283
  29. package/src/built-in/UIManager/src/app/example.ts +97 -97
  30. package/src/built-in/UIManager/src/app/examples/AppState/example.ts +140 -140
  31. package/src/built-in/UIManager/src/app/examples/Banner/example.ts +159 -159
  32. package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +123 -123
  33. package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +124 -124
  34. package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +90 -90
  35. package/src/built-in/UIManager/src/app/examples/Modal/example.ts +163 -163
  36. package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +133 -133
  37. package/src/built-in/UIManager/src/app/examples/ProjectFileStorage/example.ts +150 -0
  38. package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +102 -102
  39. package/src/built-in/UIManager/src/clashes-panel/example.ts +183 -160
  40. package/src/built-in/UIManager/src/models-list/example.ts +122 -122
  41. package/src/built-in/UIManager/src/topics-panel/example.ts +170 -0
  42. package/src/built-in/index.ts +1048 -881
  43. package/src/cli/templates/app/index.html +35 -35
  44. package/src/cli/templates/app/package.json +32 -32
  45. package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -95
  46. package/src/cli/templates/app/src/bim-components/CloudRunner/src/index.ts +1 -1
  47. package/src/cli/templates/app/src/bim-components/CloudRunner/src/types.ts +5 -5
  48. package/src/cli/templates/app/src/bim-components/index.ts +1 -1
  49. package/src/cli/templates/app/src/globals.ts +1 -1
  50. package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -26
  51. package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -1
  52. package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -15
  53. package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -37
  54. package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -1
  55. package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -14
  56. package/src/cli/templates/app/src/ui-components/index.ts +2 -2
  57. package/src/cli/templates/app/tsconfig.json +16 -16
  58. package/src/cli/templates/app/vite.config.js +57 -57
  59. package/src/cli/templates/cloud-component/README.md +205 -205
  60. package/src/cli/templates/cloud-component/_thatopen +5 -5
  61. package/src/cli/templates/cloud-component/declarations.json +4 -4
  62. package/src/cli/templates/cloud-component/package.json +21 -21
  63. package/src/cli/templates/cloud-component/src/main.ts +70 -70
  64. package/src/cli/templates/cloud-component/tsconfig.json +16 -16
  65. package/src/cli/templates/cloud-component/vite.config.js +46 -46
  66. package/src/cli/templates/shared/AGENTS.md +8 -8
  67. package/src/cli/templates/shared/CLAUDE.md +1 -1
  68. package/src/cli/templates/shared/_gitignore +5 -5
@@ -1,57 +1,57 @@
1
- // Production build config — builds dist/bundle.js as IIFE.
2
- // For local development, use: npm run dev (runs thatopen serve with esbuild).
3
- // Do NOT run "vite" or "vite build --watch" directly for dev.
4
- import { defineConfig } from 'vite';
5
- import { resolve } from 'path';
6
- import { existsSync, readFileSync } from 'fs';
7
-
8
- // When `.thatopen` marks the project as beta, alias the public engine imports
9
- // to their `@thatopen-platform/*-beta` packages at build time, so the source
10
- // can use the stable import names in both stable and beta modes.
11
- function getBetaAliases() {
12
- if (!existsSync('.thatopen')) return {};
13
- try {
14
- const config = JSON.parse(readFileSync('.thatopen', 'utf-8'));
15
- if (!config.beta) return {};
16
- return {
17
- '@thatopen/components': '@thatopen-platform/components-beta',
18
- '@thatopen/components-front': '@thatopen-platform/components-front-beta',
19
- '@thatopen/fragments': '@thatopen-platform/fragments-beta',
20
- };
21
- } catch {
22
- return {};
23
- }
24
- }
25
-
26
- // Some three.js example loaders (e.g. TTFLoader) import their deps from a
27
- // jsdelivr `/+esm` CDN URL. A bundler can't put a URL import in an IIFE — it
28
- // degrades to a runtime `require("https://…")` that throws — so rewrite any such
29
- // URL back to the bare package name and let it resolve from node_modules.
30
- const CDN_ESM = /^https:\/\/cdn\.jsdelivr\.net\/npm\/((?:@[^/]+\/)?[^@/]+)(?:@[^/]+)?\/\+esm$/;
31
-
32
- export default defineConfig({
33
- resolve: {
34
- alias: [
35
- { find: CDN_ESM, replacement: '$1' },
36
- ...Object.entries(getBetaAliases()).map(([find, replacement]) => ({
37
- find,
38
- replacement,
39
- })),
40
- ],
41
- },
42
- build: {
43
- lib: {
44
- entry: resolve(__dirname, 'src/main.ts'),
45
- name: 'ThatOpenApp',
46
- formats: ['iife'],
47
- fileName: () => 'bundle.js',
48
- },
49
- outDir: 'dist',
50
- sourcemap: true,
51
- rollupOptions: {
52
- output: {
53
- entryFileNames: 'bundle.js',
54
- },
55
- },
56
- },
57
- });
1
+ // Production build config — builds dist/bundle.js as IIFE.
2
+ // For local development, use: npm run dev (runs thatopen serve with esbuild).
3
+ // Do NOT run "vite" or "vite build --watch" directly for dev.
4
+ import { defineConfig } from 'vite';
5
+ import { resolve } from 'path';
6
+ import { existsSync, readFileSync } from 'fs';
7
+
8
+ // When `.thatopen` marks the project as beta, alias the public engine imports
9
+ // to their `@thatopen-platform/*-beta` packages at build time, so the source
10
+ // can use the stable import names in both stable and beta modes.
11
+ function getBetaAliases() {
12
+ if (!existsSync('.thatopen')) return {};
13
+ try {
14
+ const config = JSON.parse(readFileSync('.thatopen', 'utf-8'));
15
+ if (!config.beta) return {};
16
+ return {
17
+ '@thatopen/components': '@thatopen-platform/components-beta',
18
+ '@thatopen/components-front': '@thatopen-platform/components-front-beta',
19
+ '@thatopen/fragments': '@thatopen-platform/fragments-beta',
20
+ };
21
+ } catch {
22
+ return {};
23
+ }
24
+ }
25
+
26
+ // Some three.js example loaders (e.g. TTFLoader) import their deps from a
27
+ // jsdelivr `/+esm` CDN URL. A bundler can't put a URL import in an IIFE — it
28
+ // degrades to a runtime `require("https://…")` that throws — so rewrite any such
29
+ // URL back to the bare package name and let it resolve from node_modules.
30
+ const CDN_ESM = /^https:\/\/cdn\.jsdelivr\.net\/npm\/((?:@[^/]+\/)?[^@/]+)(?:@[^/]+)?\/\+esm$/;
31
+
32
+ export default defineConfig({
33
+ resolve: {
34
+ alias: [
35
+ { find: CDN_ESM, replacement: '$1' },
36
+ ...Object.entries(getBetaAliases()).map(([find, replacement]) => ({
37
+ find,
38
+ replacement,
39
+ })),
40
+ ],
41
+ },
42
+ build: {
43
+ lib: {
44
+ entry: resolve(__dirname, 'src/main.ts'),
45
+ name: 'ThatOpenApp',
46
+ formats: ['iife'],
47
+ fileName: () => 'bundle.js',
48
+ },
49
+ outDir: 'dist',
50
+ sourcemap: true,
51
+ rollupOptions: {
52
+ output: {
53
+ entryFileNames: 'bundle.js',
54
+ },
55
+ },
56
+ },
57
+ });
@@ -1,205 +1,205 @@
1
- # ThatOpen Cloud Component
2
-
3
- This is a cloud component for the That Open Platform.
4
- It runs on the server as a Node.js process, triggered via the platform API.
5
-
6
- ## How this component works
7
-
8
- - **Entry point**: `src/main.ts` — must export an `async function main()`.
9
- - **Parameter schema**: `declarations.json` — the list of parameters this component accepts. Bundled next to the code so the platform, the UI, and `thatopen run` know what to pass in.
10
- - **Build output**: `dist/bundle.js` — an IIFE built by Vite with `@thatopen/services` externalized.
11
- - **Execution**: The platform (or `thatopen run` locally) wraps the bundle in an execution engine that provides globals and calls `main()`.
12
-
13
- ## Parameters (`declarations.json`)
14
-
15
- Every cloud component declares its runtime parameters in a root-level `declarations.json` file. The CLI includes this file in the zip at publish time, and the platform refuses to publish a component without it. It's a plain JSON array of `{ id, label, type }` entries:
16
-
17
- ```json
18
- [
19
- { "id": "projectName", "label": "Project Name", "type": "string" },
20
- { "id": "iterations", "label": "Number of Iterations", "type": "number" }
21
- ]
22
- ```
23
-
24
- - `id` — the key users read off `executionParams` inside `main()`.
25
- - `label` — human-readable name shown to the user on the platform's execution form.
26
- - `type` — `"string"` or `"number"` (the only supported types for now).
27
-
28
- **Rule:** `declarations.json` and `src/main.ts` must stay in sync. When you add, remove, or rename a parameter in one, update the other. `thatopen publish` fails if `declarations.json` is missing, and `thatopen run --params '{...}'` warns if the keys or types don't match the schema.
29
-
30
- ## Commands
31
-
32
- ```bash
33
- npm run build # Build dist/bundle.js
34
- npm run run # Build and run locally (one-shot execution via thatopen run)
35
- npm run local-server # Start local execution server (API-compatible with EngineServicesClient)
36
- npm run login # Authenticate with the platform (saves token locally)
37
- npm run publish # Publish to the platform
38
- ```
39
-
40
- To pass parameters when running locally:
41
-
42
- ```bash
43
- npx thatopen run --params '{"inputFile": "model.ifc", "threshold": 0.5}'
44
- ```
45
-
46
- ### Local execution server
47
-
48
- The local server (`npm run local-server`) starts an HTTP + WebSocket server that implements
49
- the same execution API as the cloud. This lets apps using `EngineServicesClient` test against
50
- local component code without publishing:
51
-
52
- ```bash
53
- npm run local-server # Start on default port 4001
54
- npx thatopen local-server --port 5000 # Custom port
55
- ```
56
-
57
- Then in your app or test script:
58
-
59
- ```ts
60
- import { EngineServicesClient } from "@thatopen/services";
61
-
62
- const client = new EngineServicesClient(token, apiUrl, {
63
- localServerUrl: "http://localhost:4001",
64
- });
65
-
66
- const { executionId } = await client.executeComponent("any-id", { param: "value" });
67
- client.onExecutionProgress(executionId, (data) => {
68
- console.log(data.progressUpdate?.progress);
69
- });
70
- ```
71
-
72
- The server watches source files and auto-rebuilds — changes are picked up on the next execution.
73
-
74
- ## Globals available at runtime
75
-
76
- The execution engine injects **exactly these four** into scope — do NOT import them, do NOT assume anything else is available:
77
-
78
- | Global | Type | Purpose |
79
- |--------|------|---------|
80
- | `thatOpenServices` | `EngineServicesClient` | Authenticated API client (files, folders, components, executions) |
81
- | `executionParams` | `Record<string, any>` | User-supplied parameters (shape defined in `declarations.json`) |
82
- | `executionContext` | `{ projectId?, executionId, toolId, toolVersion }` | Platform-supplied run context. Use `executionContext.projectId` to scope operations to the project the component was launched from. Undefined when run outside a project context. |
83
- | `executionReporter` | `{ message(msg), error(msg), progress(pct) }` | Send live status updates, error lines, and a numeric progress percentage to the execution UI |
84
-
85
- Libraries like `@thatopen/components`, `three`, `web-ifc`, or Node's `fs` are **not** available as globals. If you need them, `import` them the normal way and let the bundler include them in `dist/bundle.js`. The execution environment is a plain Node.js process with no special additions beyond the four globals above.
86
-
87
- ### TypeScript declarations
88
-
89
- Already declared in `src/main.ts`. Keep them there for type checking:
90
-
91
- ```ts
92
- declare const thatOpenServices: import("@thatopen/services").EngineServicesClient;
93
- declare const executionParams: Record<string, unknown>;
94
- declare const executionContext: {
95
- projectId?: string;
96
- executionId: string;
97
- toolId: string;
98
- toolVersion: string;
99
- };
100
- declare const executionReporter: {
101
- message(msg: string): void;
102
- error(msg: string): void;
103
- progress(pct: number): void;
104
- };
105
- ```
106
-
107
- ## Return value
108
-
109
- `main()` must return an object with `type` and `message`:
110
-
111
- ```ts
112
- return { type: "SUCCESS", message: "Processed 42 elements" };
113
- // type: "SUCCESS" | "FAIL" | "WARNING"
114
- ```
115
-
116
- ## Common patterns
117
-
118
- ### Scoping uploads to the launching project
119
-
120
- ```ts
121
- export async function main() {
122
- const projectId = executionContext?.projectId;
123
- if (!projectId) {
124
- return { type: "FAIL", message: "This component must be launched from a project" };
125
- }
126
-
127
- const blob = new Blob(["hello"], { type: "text/plain" });
128
- await thatOpenServices.createFile({
129
- file: blob,
130
- name: "hello.txt",
131
- versionTag: "v1",
132
- projectId,
133
- });
134
-
135
- return { type: "SUCCESS", message: "Uploaded into the project" };
136
- }
137
- ```
138
-
139
- ### Processing a file from platform storage
140
-
141
- ```ts
142
- export async function main() {
143
- const { fileId } = executionParams;
144
-
145
- executionReporter.message("Downloading file...");
146
- const response = await thatOpenServices.downloadFile(fileId as string);
147
- const buffer = await response.arrayBuffer();
148
-
149
- executionReporter.progress(50);
150
- // ... process the buffer ...
151
- executionReporter.progress(100);
152
-
153
- return { type: "SUCCESS", message: "Done" };
154
- }
155
- ```
156
-
157
- ### Triggering another cloud component
158
-
159
- ```ts
160
- const { executionId } = await thatOpenServices.executeComponent(otherComponentId, { param: "value" });
161
- const result = await thatOpenServices.getExecution(executionId);
162
- ```
163
-
164
- ### Listing resources inside a project
165
-
166
- Pass `projectId` to the list methods to enumerate a specific project's
167
- resources. The backend enforces project-scoped permissions — the token
168
- running your component must have `STORAGE:READ` (or the relevant role)
169
- on that project; otherwise the call is rejected with `403`. A missing
170
- `projectId` still works and lists items in the caller's personal scope.
171
-
172
- ```ts
173
- const projectId = executionContext?.projectId;
174
- if (projectId) {
175
- const files = await thatOpenServices.listFiles({ projectId });
176
- const folders = await thatOpenServices.listFolders({ projectId });
177
- // listApps / listComponents / listExecutions all accept projectId too
178
- }
179
- ```
180
-
181
- ### Gating an action with a permission check
182
-
183
- ```ts
184
- const { hasPermission, scope } = await thatOpenServices.checkPermission({
185
- resourceType: "STORAGE",
186
- action: "WRITE",
187
- projectId: executionContext?.projectId,
188
- });
189
- if (!hasPermission) {
190
- return { type: "FAIL", message: "Caller cannot write to this project" };
191
- }
192
- // scope is 'global' | 'project' | 'entity' | 'none' — useful when you
193
- // want the UI to know *why* a permission was granted. checkPermissionBatch
194
- // accepts a list of checks in a single round-trip.
195
- ```
196
-
197
- ## Build configuration
198
-
199
- - `vite.config.js` builds to IIFE format.
200
- - Only `@thatopen/services` is externalized — the wrapper provides it at runtime via `require()`. Everything else (including any third-party npm dependency you install) is bundled into `dist/bundle.js`.
201
- - The build output has a footer `var main = ThatOpenComponent.main;` so the engine can find the entry point as a top-level `main` variable.
202
-
203
- ## Configuration
204
-
205
- - `.thatopen` — local config (gitignored). Created by `npm run login`. Contains `accessToken`, `apiUrl`, `itemType: "COMPONENT"`, and `componentId` after first publish.
1
+ # ThatOpen Cloud Component
2
+
3
+ This is a cloud component for the That Open Platform.
4
+ It runs on the server as a Node.js process, triggered via the platform API.
5
+
6
+ ## How this component works
7
+
8
+ - **Entry point**: `src/main.ts` — must export an `async function main()`.
9
+ - **Parameter schema**: `declarations.json` — the list of parameters this component accepts. Bundled next to the code so the platform, the UI, and `thatopen run` know what to pass in.
10
+ - **Build output**: `dist/bundle.js` — an IIFE built by Vite with `@thatopen/services` externalized.
11
+ - **Execution**: The platform (or `thatopen run` locally) wraps the bundle in an execution engine that provides globals and calls `main()`.
12
+
13
+ ## Parameters (`declarations.json`)
14
+
15
+ Every cloud component declares its runtime parameters in a root-level `declarations.json` file. The CLI includes this file in the zip at publish time, and the platform refuses to publish a component without it. It's a plain JSON array of `{ id, label, type }` entries:
16
+
17
+ ```json
18
+ [
19
+ { "id": "projectName", "label": "Project Name", "type": "string" },
20
+ { "id": "iterations", "label": "Number of Iterations", "type": "number" }
21
+ ]
22
+ ```
23
+
24
+ - `id` — the key users read off `executionParams` inside `main()`.
25
+ - `label` — human-readable name shown to the user on the platform's execution form.
26
+ - `type` — `"string"` or `"number"` (the only supported types for now).
27
+
28
+ **Rule:** `declarations.json` and `src/main.ts` must stay in sync. When you add, remove, or rename a parameter in one, update the other. `thatopen publish` fails if `declarations.json` is missing, and `thatopen run --params '{...}'` warns if the keys or types don't match the schema.
29
+
30
+ ## Commands
31
+
32
+ ```bash
33
+ npm run build # Build dist/bundle.js
34
+ npm run run # Build and run locally (one-shot execution via thatopen run)
35
+ npm run local-server # Start local execution server (API-compatible with EngineServicesClient)
36
+ npm run login # Authenticate with the platform (saves token locally)
37
+ npm run publish # Publish to the platform
38
+ ```
39
+
40
+ To pass parameters when running locally:
41
+
42
+ ```bash
43
+ npx thatopen run --params '{"inputFile": "model.ifc", "threshold": 0.5}'
44
+ ```
45
+
46
+ ### Local execution server
47
+
48
+ The local server (`npm run local-server`) starts an HTTP + WebSocket server that implements
49
+ the same execution API as the cloud. This lets apps using `EngineServicesClient` test against
50
+ local component code without publishing:
51
+
52
+ ```bash
53
+ npm run local-server # Start on default port 4001
54
+ npx thatopen local-server --port 5000 # Custom port
55
+ ```
56
+
57
+ Then in your app or test script:
58
+
59
+ ```ts
60
+ import { EngineServicesClient } from "@thatopen/services";
61
+
62
+ const client = new EngineServicesClient(token, apiUrl, {
63
+ localServerUrl: "http://localhost:4001",
64
+ });
65
+
66
+ const { executionId } = await client.executeComponent("any-id", { param: "value" });
67
+ client.onExecutionProgress(executionId, (data) => {
68
+ console.log(data.progressUpdate?.progress);
69
+ });
70
+ ```
71
+
72
+ The server watches source files and auto-rebuilds — changes are picked up on the next execution.
73
+
74
+ ## Globals available at runtime
75
+
76
+ The execution engine injects **exactly these four** into scope — do NOT import them, do NOT assume anything else is available:
77
+
78
+ | Global | Type | Purpose |
79
+ |--------|------|---------|
80
+ | `thatOpenServices` | `EngineServicesClient` | Authenticated API client (files, folders, components, executions) |
81
+ | `executionParams` | `Record<string, any>` | User-supplied parameters (shape defined in `declarations.json`) |
82
+ | `executionContext` | `{ projectId?, executionId, toolId, toolVersion }` | Platform-supplied run context. Use `executionContext.projectId` to scope operations to the project the component was launched from. Undefined when run outside a project context. |
83
+ | `executionReporter` | `{ message(msg), error(msg), progress(pct) }` | Send live status updates, error lines, and a numeric progress percentage to the execution UI |
84
+
85
+ Libraries like `@thatopen/components`, `three`, `web-ifc`, or Node's `fs` are **not** available as globals. If you need them, `import` them the normal way and let the bundler include them in `dist/bundle.js`. The execution environment is a plain Node.js process with no special additions beyond the four globals above.
86
+
87
+ ### TypeScript declarations
88
+
89
+ Already declared in `src/main.ts`. Keep them there for type checking:
90
+
91
+ ```ts
92
+ declare const thatOpenServices: import("@thatopen/services").EngineServicesClient;
93
+ declare const executionParams: Record<string, unknown>;
94
+ declare const executionContext: {
95
+ projectId?: string;
96
+ executionId: string;
97
+ toolId: string;
98
+ toolVersion: string;
99
+ };
100
+ declare const executionReporter: {
101
+ message(msg: string): void;
102
+ error(msg: string): void;
103
+ progress(pct: number): void;
104
+ };
105
+ ```
106
+
107
+ ## Return value
108
+
109
+ `main()` must return an object with `type` and `message`:
110
+
111
+ ```ts
112
+ return { type: "SUCCESS", message: "Processed 42 elements" };
113
+ // type: "SUCCESS" | "FAIL" | "WARNING"
114
+ ```
115
+
116
+ ## Common patterns
117
+
118
+ ### Scoping uploads to the launching project
119
+
120
+ ```ts
121
+ export async function main() {
122
+ const projectId = executionContext?.projectId;
123
+ if (!projectId) {
124
+ return { type: "FAIL", message: "This component must be launched from a project" };
125
+ }
126
+
127
+ const blob = new Blob(["hello"], { type: "text/plain" });
128
+ await thatOpenServices.createFile({
129
+ file: blob,
130
+ name: "hello.txt",
131
+ versionTag: "v1",
132
+ projectId,
133
+ });
134
+
135
+ return { type: "SUCCESS", message: "Uploaded into the project" };
136
+ }
137
+ ```
138
+
139
+ ### Processing a file from platform storage
140
+
141
+ ```ts
142
+ export async function main() {
143
+ const { fileId } = executionParams;
144
+
145
+ executionReporter.message("Downloading file...");
146
+ const response = await thatOpenServices.downloadFile(fileId as string);
147
+ const buffer = await response.arrayBuffer();
148
+
149
+ executionReporter.progress(50);
150
+ // ... process the buffer ...
151
+ executionReporter.progress(100);
152
+
153
+ return { type: "SUCCESS", message: "Done" };
154
+ }
155
+ ```
156
+
157
+ ### Triggering another cloud component
158
+
159
+ ```ts
160
+ const { executionId } = await thatOpenServices.executeComponent(otherComponentId, { param: "value" });
161
+ const result = await thatOpenServices.getExecution(executionId);
162
+ ```
163
+
164
+ ### Listing resources inside a project
165
+
166
+ Pass `projectId` to the list methods to enumerate a specific project's
167
+ resources. The backend enforces project-scoped permissions — the token
168
+ running your component must have `STORAGE:READ` (or the relevant role)
169
+ on that project; otherwise the call is rejected with `403`. A missing
170
+ `projectId` still works and lists items in the caller's personal scope.
171
+
172
+ ```ts
173
+ const projectId = executionContext?.projectId;
174
+ if (projectId) {
175
+ const files = await thatOpenServices.listFiles({ projectId });
176
+ const folders = await thatOpenServices.listFolders({ projectId });
177
+ // listApps / listComponents / listExecutions all accept projectId too
178
+ }
179
+ ```
180
+
181
+ ### Gating an action with a permission check
182
+
183
+ ```ts
184
+ const { hasPermission, scope } = await thatOpenServices.checkPermission({
185
+ resourceType: "STORAGE",
186
+ action: "WRITE",
187
+ projectId: executionContext?.projectId,
188
+ });
189
+ if (!hasPermission) {
190
+ return { type: "FAIL", message: "Caller cannot write to this project" };
191
+ }
192
+ // scope is 'global' | 'project' | 'entity' | 'none' — useful when you
193
+ // want the UI to know *why* a permission was granted. checkPermissionBatch
194
+ // accepts a list of checks in a single round-trip.
195
+ ```
196
+
197
+ ## Build configuration
198
+
199
+ - `vite.config.js` builds to IIFE format.
200
+ - Only `@thatopen/services` is externalized — the wrapper provides it at runtime via `require()`. Everything else (including any third-party npm dependency you install) is bundled into `dist/bundle.js`.
201
+ - The build output has a footer `var main = ThatOpenComponent.main;` so the engine can find the entry point as a top-level `main` variable.
202
+
203
+ ## Configuration
204
+
205
+ - `.thatopen` — local config (gitignored). Created by `npm run login`. Contains `accessToken`, `apiUrl`, `itemType: "COMPONENT"`, and `componentId` after first publish.
@@ -1,5 +1,5 @@
1
- {
2
- "accessToken": "",
3
- "apiUrl": "",
4
- "itemType": "COMPONENT"
5
- }
1
+ {
2
+ "accessToken": "",
3
+ "apiUrl": "",
4
+ "itemType": "COMPONENT"
5
+ }
@@ -1,4 +1,4 @@
1
- [
2
- { "id": "projectName", "label": "Project Name", "type": "string" },
3
- { "id": "iterations", "label": "Number of Iterations", "type": "number" }
4
- ]
1
+ [
2
+ { "id": "projectName", "label": "Project Name", "type": "string" },
3
+ { "id": "iterations", "label": "Number of Iterations", "type": "number" }
4
+ ]
@@ -1,22 +1,22 @@
1
- {
2
- "name": "{{PROJECT_NAME}}",
3
- "version": "1.0.0",
4
- "private": true,
5
- "scripts": {
6
- "build": "vite build",
7
- "run": "thatopen run",
8
- "local-server": "thatopen local-server",
9
- "login": "thatopen login --local",
10
- "publish": "thatopen publish"
11
- },
12
- "dependencies": {
13
- "@thatopen/components": "~3.4.0",
14
- "@thatopen/services": "^{{VERSION}}",
15
- "three": "^0.182.0"
16
- },
17
- "devDependencies": {
18
- "@types/three": "^0.182.0",
19
- "typescript": "^5.2.0",
20
- "vite": "^5.2.0"
21
- }
1
+ {
2
+ "name": "{{PROJECT_NAME}}",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "build": "vite build",
7
+ "run": "thatopen run",
8
+ "local-server": "thatopen local-server",
9
+ "login": "thatopen login --local",
10
+ "publish": "thatopen publish"
11
+ },
12
+ "dependencies": {
13
+ "@thatopen/components": "~3.4.0",
14
+ "@thatopen/services": "^{{VERSION}}",
15
+ "three": "^0.182.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/three": "^0.182.0",
19
+ "typescript": "^5.2.0",
20
+ "vite": "^5.2.0"
21
+ }
22
22
  }