@thatopen/services 0.6.0 → 0.8.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.
- package/README.md +62 -62
- package/dist/built-in/index.d.ts +485 -100
- package/dist/cli/lib/revit-addin.d.ts +8 -0
- package/dist/cli.js +135 -24
- package/dist/index.cjs.js +2 -2
- package/dist/index.es.js +41 -50
- package/dist/vite-env.d.ts +1 -1
- package/docs/ai-quickstart.md +138 -4
- package/docs/cli/create.md +29 -29
- package/docs/cli/local-server.md +38 -38
- package/docs/cli/login.md +32 -32
- package/docs/cli/publish.md +31 -31
- package/docs/cli/run.md +26 -26
- package/docs/cli/serve.md +43 -43
- package/docs/cli/swap.md +30 -30
- package/docs/flow-architecture.md +1 -1
- package/docs/flow-plugin-guide.md +27 -1
- package/docs/platform-token.md +81 -0
- package/docs/revit-collab-quickstart.md +115 -35
- package/docs/rhino-interop-quickstart.md +458 -0
- package/package.json +1 -1
- package/resources/AGENTS.md +1 -1
- package/src/built-in/CDEManager/example.ts +214 -214
- package/src/built-in/CDEManager/examples/FileEditing/example.ts +226 -226
- package/src/built-in/CDEManager/examples/FileMoves/example.ts +186 -186
- package/src/built-in/CDEManager/examples/FileOperations/example.ts +295 -295
- package/src/built-in/CDEManager/examples/FileTransfers/example.ts +210 -210
- package/src/built-in/CDEManager/examples/FolderManagement/example.ts +230 -230
- package/src/built-in/CDEManager/examples/MetadataSchema/example.ts +230 -230
- package/src/built-in/CDEManager/examples/MetadataViews/example.ts +166 -166
- package/src/built-in/CDEManager/examples/ProjectConfig/example.ts +177 -177
- package/src/built-in/UIManager/src/app/example.ts +97 -97
- package/src/built-in/UIManager/src/app/examples/AppState/example.ts +140 -140
- package/src/built-in/UIManager/src/app/examples/Banner/example.ts +159 -159
- package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +123 -123
- package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +124 -124
- package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +90 -90
- package/src/built-in/UIManager/src/app/examples/Modal/example.ts +163 -163
- package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +133 -133
- package/src/built-in/UIManager/src/app/examples/ProjectFileStorage/example.ts +150 -150
- package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +102 -102
- package/src/built-in/UIManager/src/clashes-panel/example.ts +183 -183
- package/src/built-in/UIManager/src/git-history-panel/example.ts +70 -70
- package/src/built-in/UIManager/src/models-list/example.ts +122 -122
- package/src/built-in/UIManager/src/topics-panel/example.ts +170 -170
- package/src/built-in/index.ts +485 -100
- package/src/cli/templates/app/index.html +35 -35
- package/src/cli/templates/app/package.json +32 -32
- package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -95
- package/src/cli/templates/app/src/bim-components/CloudRunner/src/index.ts +1 -1
- package/src/cli/templates/app/src/bim-components/CloudRunner/src/types.ts +5 -5
- package/src/cli/templates/app/src/bim-components/index.ts +1 -1
- package/src/cli/templates/app/src/globals.ts +1 -1
- package/src/cli/templates/app/src/main.history.ts +191 -0
- package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -26
- package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -1
- package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -15
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -37
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -1
- package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -14
- package/src/cli/templates/app/src/ui-components/index.ts +2 -2
- package/src/cli/templates/app/tsconfig.json +16 -16
- package/src/cli/templates/app/vite.config.js +57 -57
- package/src/cli/templates/cloud-component/README.md +205 -205
- package/src/cli/templates/cloud-component/_thatopen +5 -5
- package/src/cli/templates/cloud-component/declarations.json +4 -4
- package/src/cli/templates/cloud-component/package.json +21 -21
- package/src/cli/templates/cloud-component/src/main.ts +70 -70
- package/src/cli/templates/cloud-component/tsconfig.json +16 -16
- package/src/cli/templates/cloud-component/vite.config.js +46 -46
- package/src/cli/templates/shared/AGENTS.md +8 -8
- package/src/cli/templates/shared/CLAUDE.md +1 -1
- package/src/cli/templates/shared/_gitignore +5 -5
package/docs/cli/publish.md
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Build and upload the project to the platform. Automatically detects app vs cloud component from the local .thatopen config. On first publish, saves the assigned item ID back to .thatopen so subsequent runs update the same item instead of creating a new one."
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
## thatopen publish
|
|
6
|
-
|
|
7
|
-
Builds the project and uploads it to the platform. Works for both apps and cloud components — the project type is read from `.thatopen` (`itemType: APP | COMPONENT`).
|
|
8
|
-
|
|
9
|
-
First publish creates the item and auto-saves its ID to `.thatopen`. Subsequent publishes update that same item.
|
|
10
|
-
|
|
11
|
-
**Usage:**
|
|
12
|
-
```bash
|
|
13
|
-
thatopen publish [flags]
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
**Flags:**
|
|
17
|
-
|
|
18
|
-
- `--name <name>` — Item name on the platform. Defaults to `name` in `package.json`.
|
|
19
|
-
- `--version-tag <tag>` — Version tag. Defaults to `version` in `package.json`.
|
|
20
|
-
- `--app-id <id>` — Target an existing app by ID (overrides `.thatopen`).
|
|
21
|
-
- `--component-id <id>` — Target an existing cloud component by ID (overrides `.thatopen`).
|
|
22
|
-
- `--skip-build` — Skip the build step and upload the existing `dist/bundle.js`.
|
|
23
|
-
- `--icon <path>` — Path to an icon file (PNG, WebP, or ICO, max 512 KB). Saved to `.thatopen` for future publishes.
|
|
24
|
-
|
|
25
|
-
**Examples:**
|
|
26
|
-
```bash
|
|
27
|
-
thatopen publish
|
|
28
|
-
thatopen publish --version-tag 2.0.0
|
|
29
|
-
thatopen publish --skip-build
|
|
30
|
-
thatopen publish --icon assets/icon.png
|
|
31
|
-
```
|
|
1
|
+
---
|
|
2
|
+
description: "Build and upload the project to the platform. Automatically detects app vs cloud component from the local .thatopen config. On first publish, saves the assigned item ID back to .thatopen so subsequent runs update the same item instead of creating a new one."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## thatopen publish
|
|
6
|
+
|
|
7
|
+
Builds the project and uploads it to the platform. Works for both apps and cloud components — the project type is read from `.thatopen` (`itemType: APP | COMPONENT`).
|
|
8
|
+
|
|
9
|
+
First publish creates the item and auto-saves its ID to `.thatopen`. Subsequent publishes update that same item.
|
|
10
|
+
|
|
11
|
+
**Usage:**
|
|
12
|
+
```bash
|
|
13
|
+
thatopen publish [flags]
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Flags:**
|
|
17
|
+
|
|
18
|
+
- `--name <name>` — Item name on the platform. Defaults to `name` in `package.json`.
|
|
19
|
+
- `--version-tag <tag>` — Version tag. Defaults to `version` in `package.json`.
|
|
20
|
+
- `--app-id <id>` — Target an existing app by ID (overrides `.thatopen`).
|
|
21
|
+
- `--component-id <id>` — Target an existing cloud component by ID (overrides `.thatopen`).
|
|
22
|
+
- `--skip-build` — Skip the build step and upload the existing `dist/bundle.js`.
|
|
23
|
+
- `--icon <path>` — Path to an icon file (PNG, WebP, or ICO, max 512 KB). Saved to `.thatopen` for future publishes.
|
|
24
|
+
|
|
25
|
+
**Examples:**
|
|
26
|
+
```bash
|
|
27
|
+
thatopen publish
|
|
28
|
+
thatopen publish --version-tag 2.0.0
|
|
29
|
+
thatopen publish --skip-build
|
|
30
|
+
thatopen publish --icon assets/icon.png
|
|
31
|
+
```
|
package/docs/cli/run.md
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Build and run a cloud component locally as a child process, mirroring the backend execution environment. Accepts execution parameters as JSON via --params, validates them against declarations.json, and streams progress output to the terminal."
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
## thatopen run
|
|
6
|
-
|
|
7
|
-
Builds and executes a cloud component locally, replicating what the platform's cloud engine does. Useful for testing component logic and parameters before publishing.
|
|
8
|
-
|
|
9
|
-
Execution output (`MESSAGE`, `PROGRESS`, `SUCCESS`, `FAIL`) is streamed to the terminal with elapsed time.
|
|
10
|
-
|
|
11
|
-
**Usage:**
|
|
12
|
-
```bash
|
|
13
|
-
thatopen run [flags]
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
**Flags:**
|
|
17
|
-
|
|
18
|
-
- `--params <json>` — Execution parameters as a JSON string. Default: `'{}'`. Validated against `declarations.json` if present (warns, does not fail).
|
|
19
|
-
- `--skip-build` — Skip the build step and run the existing `dist/bundle.js`.
|
|
20
|
-
|
|
21
|
-
**Examples:**
|
|
22
|
-
```bash
|
|
23
|
-
thatopen run
|
|
24
|
-
thatopen run --params '{"fileId": "abc123"}'
|
|
25
|
-
thatopen run --skip-build
|
|
26
|
-
```
|
|
1
|
+
---
|
|
2
|
+
description: "Build and run a cloud component locally as a child process, mirroring the backend execution environment. Accepts execution parameters as JSON via --params, validates them against declarations.json, and streams progress output to the terminal."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## thatopen run
|
|
6
|
+
|
|
7
|
+
Builds and executes a cloud component locally, replicating what the platform's cloud engine does. Useful for testing component logic and parameters before publishing.
|
|
8
|
+
|
|
9
|
+
Execution output (`MESSAGE`, `PROGRESS`, `SUCCESS`, `FAIL`) is streamed to the terminal with elapsed time.
|
|
10
|
+
|
|
11
|
+
**Usage:**
|
|
12
|
+
```bash
|
|
13
|
+
thatopen run [flags]
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Flags:**
|
|
17
|
+
|
|
18
|
+
- `--params <json>` — Execution parameters as a JSON string. Default: `'{}'`. Validated against `declarations.json` if present (warns, does not fail).
|
|
19
|
+
- `--skip-build` — Skip the build step and run the existing `dist/bundle.js`.
|
|
20
|
+
|
|
21
|
+
**Examples:**
|
|
22
|
+
```bash
|
|
23
|
+
thatopen run
|
|
24
|
+
thatopen run --params '{"fileId": "abc123"}'
|
|
25
|
+
thatopen run --skip-build
|
|
26
|
+
```
|
package/docs/cli/serve.md
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Start a local dev server for a browser app. Uses esbuild in watch mode and serves the IIFE bundle on port 4000 with SSE live reload. To connect: open the project on platform.thatopen.com, click the Local App icon, then Get Started."
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
## thatopen serve
|
|
6
|
-
|
|
7
|
-
Builds the app in watch mode and serves the IIFE bundle locally. On every save, esbuild rebuilds and the platform reloads the bundle automatically via SSE.
|
|
8
|
-
|
|
9
|
-
Does **not** open a browser tab — the app runs inside the platform iframe. Open your project on the platform, then click the debug button to connect it to the local server.
|
|
10
|
-
|
|
11
|
-
**Usage:**
|
|
12
|
-
```bash
|
|
13
|
-
thatopen serve [flags]
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
**Flags:**
|
|
17
|
-
|
|
18
|
-
- `--port <port>` — Port to serve the bundle on. Default: `4000`.
|
|
19
|
-
|
|
20
|
-
**Endpoints served:**
|
|
21
|
-
|
|
22
|
-
- `GET /bundle.js` — The compiled IIFE bundle.
|
|
23
|
-
- `GET /bundle.js.map` — Source map.
|
|
24
|
-
- `GET /events` — SSE stream for live reload.
|
|
25
|
-
|
|
26
|
-
**Example:**
|
|
27
|
-
```bash
|
|
28
|
-
thatopen serve
|
|
29
|
-
thatopen serve --port 4321
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
**Connecting the platform to your local server:**
|
|
33
|
-
|
|
34
|
-
1. Go to [https://platform.thatopen.com](https://platform.thatopen.com) and open a project (create one first if needed).
|
|
35
|
-
2. In the top right corner, click the **Local App** icon.
|
|
36
|
-
3. Click **Get Started**.
|
|
37
|
-
|
|
38
|
-
The platform loads the bundle from port 4000 and renders the app inside the project context, with full access to its models, data, and users. The dev server must be running before opening this URL — if nothing is served on port 4000, the platform will fail to load the app.
|
|
39
|
-
|
|
40
|
-
The resulting URL follows this pattern:
|
|
41
|
-
```
|
|
42
|
-
https://platform.thatopen.com/dashboard/projects/{projectId}/apps/local-app
|
|
43
|
-
```
|
|
1
|
+
---
|
|
2
|
+
description: "Start a local dev server for a browser app. Uses esbuild in watch mode and serves the IIFE bundle on port 4000 with SSE live reload. To connect: open the project on platform.thatopen.com, click the Local App icon, then Get Started."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## thatopen serve
|
|
6
|
+
|
|
7
|
+
Builds the app in watch mode and serves the IIFE bundle locally. On every save, esbuild rebuilds and the platform reloads the bundle automatically via SSE.
|
|
8
|
+
|
|
9
|
+
Does **not** open a browser tab — the app runs inside the platform iframe. Open your project on the platform, then click the debug button to connect it to the local server.
|
|
10
|
+
|
|
11
|
+
**Usage:**
|
|
12
|
+
```bash
|
|
13
|
+
thatopen serve [flags]
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
**Flags:**
|
|
17
|
+
|
|
18
|
+
- `--port <port>` — Port to serve the bundle on. Default: `4000`.
|
|
19
|
+
|
|
20
|
+
**Endpoints served:**
|
|
21
|
+
|
|
22
|
+
- `GET /bundle.js` — The compiled IIFE bundle.
|
|
23
|
+
- `GET /bundle.js.map` — Source map.
|
|
24
|
+
- `GET /events` — SSE stream for live reload.
|
|
25
|
+
|
|
26
|
+
**Example:**
|
|
27
|
+
```bash
|
|
28
|
+
thatopen serve
|
|
29
|
+
thatopen serve --port 4321
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Connecting the platform to your local server:**
|
|
33
|
+
|
|
34
|
+
1. Go to [https://platform.thatopen.com](https://platform.thatopen.com) and open a project (create one first if needed).
|
|
35
|
+
2. In the top right corner, click the **Local App** icon.
|
|
36
|
+
3. Click **Get Started**.
|
|
37
|
+
|
|
38
|
+
The platform loads the bundle from port 4000 and renders the app inside the project context, with full access to its models, data, and users. The dev server must be running before opening this URL — if nothing is served on port 4000, the platform will fail to load the app.
|
|
39
|
+
|
|
40
|
+
The resulting URL follows this pattern:
|
|
41
|
+
```
|
|
42
|
+
https://platform.thatopen.com/dashboard/projects/{projectId}/apps/local-app
|
|
43
|
+
```
|
package/docs/cli/swap.md
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
---
|
|
2
|
-
description: "Toggle or explicitly set the engine library mode between stable public packages (@thatopen/*) and private beta packages (@thatopen-platform/*-beta). Updates package.json and .thatopen, then runs npm install. Source code never changes — aliases handle resolution."
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
## thatopen swap
|
|
6
|
-
|
|
7
|
-
Switches the project between stable and beta engine libraries. Without flags, it toggles from the current state. Updates `package.json` dependencies and sets `beta` in `.thatopen` so `thatopen serve`, `thatopen local-server`, and `vite build` all pick up the change automatically.
|
|
8
|
-
|
|
9
|
-
Source code stays unchanged — `@thatopen/components` imports resolve to the correct package via esbuild/vite aliases based on the `beta` flag in `.thatopen`.
|
|
10
|
-
|
|
11
|
-
**Usage:**
|
|
12
|
-
```bash
|
|
13
|
-
thatopen swap # toggle: stable → beta or beta → stable
|
|
14
|
-
thatopen swap --beta # force beta
|
|
15
|
-
thatopen swap --stable # force stable
|
|
16
|
-
```
|
|
17
|
-
|
|
18
|
-
**Flags:**
|
|
19
|
-
|
|
20
|
-
- `--beta` — Switch to beta libraries (`@thatopen-platform/*-beta`).
|
|
21
|
-
- `--stable` — Switch back to stable public libraries (`@thatopen/*`).
|
|
22
|
-
|
|
23
|
-
**Examples:**
|
|
24
|
-
```bash
|
|
25
|
-
thatopen swap
|
|
26
|
-
thatopen swap --beta
|
|
27
|
-
thatopen swap --stable
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
> Beta packages are private and the access must be explicitly granted by That Open Company.
|
|
1
|
+
---
|
|
2
|
+
description: "Toggle or explicitly set the engine library mode between stable public packages (@thatopen/*) and private beta packages (@thatopen-platform/*-beta). Updates package.json and .thatopen, then runs npm install. Source code never changes — aliases handle resolution."
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
## thatopen swap
|
|
6
|
+
|
|
7
|
+
Switches the project between stable and beta engine libraries. Without flags, it toggles from the current state. Updates `package.json` dependencies and sets `beta` in `.thatopen` so `thatopen serve`, `thatopen local-server`, and `vite build` all pick up the change automatically.
|
|
8
|
+
|
|
9
|
+
Source code stays unchanged — `@thatopen/components` imports resolve to the correct package via esbuild/vite aliases based on the `beta` flag in `.thatopen`.
|
|
10
|
+
|
|
11
|
+
**Usage:**
|
|
12
|
+
```bash
|
|
13
|
+
thatopen swap # toggle: stable → beta or beta → stable
|
|
14
|
+
thatopen swap --beta # force beta
|
|
15
|
+
thatopen swap --stable # force stable
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**Flags:**
|
|
19
|
+
|
|
20
|
+
- `--beta` — Switch to beta libraries (`@thatopen-platform/*-beta`).
|
|
21
|
+
- `--stable` — Switch back to stable public libraries (`@thatopen/*`).
|
|
22
|
+
|
|
23
|
+
**Examples:**
|
|
24
|
+
```bash
|
|
25
|
+
thatopen swap
|
|
26
|
+
thatopen swap --beta
|
|
27
|
+
thatopen swap --stable
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
> Beta packages are private and the access must be explicitly granted by That Open Company.
|
|
@@ -386,4 +386,4 @@ Rhino kernel, so a converter can run server-side while real modelling operations
|
|
|
386
386
|
|
|
387
387
|
The concrete wire formats — where each file lives on the platform, what the proposal envelope
|
|
388
388
|
contains, how the queue and the ownership registry work — are in
|
|
389
|
-
[the plugin guide](
|
|
389
|
+
[the plugin guide](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/flow-plugin-guide.md), which is what to read if you are writing a plugin.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Writing a flow plugin
|
|
2
2
|
|
|
3
|
-
The concrete contract. [The architecture notes](
|
|
3
|
+
The concrete contract. [The architecture notes](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/flow-architecture.md) say why any of this is
|
|
4
4
|
shaped the way it is; this says what the bytes look like.
|
|
5
5
|
|
|
6
6
|
Nothing here is aspirational. Every rule below is what the Revit and Rhino plugins already do, and
|
|
@@ -152,6 +152,32 @@ made every proposal declare its units, which looked careful and was a bug waitin
|
|
|
152
152
|
an author state a unit while writing coordinates in an axis convention the target does not use, a
|
|
153
153
|
mistake no declared unit can catch.
|
|
154
154
|
|
|
155
|
+
### Who wrote it
|
|
156
|
+
|
|
157
|
+
`author` is free text for a timeline to print. `userId` is the one that has to be right: it is what
|
|
158
|
+
the platform's own member component resolves into a real name and face. Get it wrong and the
|
|
159
|
+
proposal shows up under somebody else's avatar, which is worse than showing none.
|
|
160
|
+
|
|
161
|
+
**In a browser app, take it from `getProjectData`.** It answers with `currentUser` already resolved
|
|
162
|
+
server-side, and the members it lists are keyed by exactly the id the history panel indexes:
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
const { currentUser } = await client.getProjectData(projectId);
|
|
166
|
+
const userId = currentUser?.user._id; // what the avatar resolves against
|
|
167
|
+
const author = currentUser?.user.fullName; // what the timeline prints
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Do not look for it on the client's context.** `client.context` is the four fields the platform
|
|
171
|
+
injects into the iframe: `appId`, `projectId`, `accessToken`, `apiUrl`. Reading `context.userId` or
|
|
172
|
+
`context.user.name` yields `undefined`, and both failures are silent: the envelope simply ships
|
|
173
|
+
without a `userId`, and the panel falls back to passing `author` as the email, so the member
|
|
174
|
+
component renders whatever it makes of a string that names nobody. A converter did exactly this, and
|
|
175
|
+
it looked fine until somebody noticed the proposal was wearing another person's face.
|
|
176
|
+
|
|
177
|
+
**In a native plug-in there is no such call**, so read the `u` claim out of the API key's JWT payload
|
|
178
|
+
(base64url, no signature check, since this only decides which name to display). That is what the
|
|
179
|
+
Revit add-in does.
|
|
180
|
+
|
|
155
181
|
### The verbs
|
|
156
182
|
|
|
157
183
|
One per item, in the attribute `flow:op`:
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Logging in to That Open Platform
|
|
2
|
+
|
|
3
|
+
Everything else in these guides needs this, and it is the same three lines every time, so it lives
|
|
4
|
+
here rather than in each of them.
|
|
5
|
+
|
|
6
|
+
## Get the token
|
|
7
|
+
|
|
8
|
+
Say this to the user, and wait:
|
|
9
|
+
|
|
10
|
+
> "To log in I need a That Open Platform **access token**. You create it yourself:
|
|
11
|
+
> **https://platform.thatopen.com/dashboard/data → API Tokens → create → copy**, then paste it
|
|
12
|
+
> here."
|
|
13
|
+
|
|
14
|
+
**Never print it back, never write it into a file, never commit it.** Not into a script, not into a
|
|
15
|
+
`.env` you are about to show, not into a chat message quoting the command you ran.
|
|
16
|
+
|
|
17
|
+
## Log in
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
thatopen login --token <TOKEN>
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Credentials go to `~/.thatopen/config.json`, as `accessToken` and `apiUrl`. `--local` writes them to
|
|
24
|
+
a `.thatopen` file in the project instead, which is what a scaffolded project uses.
|
|
25
|
+
|
|
26
|
+
You do not need an npm account or an npm token for the private packages. The CLI derives access to
|
|
27
|
+
them from this one.
|
|
28
|
+
|
|
29
|
+
## Everyone is on production
|
|
30
|
+
|
|
31
|
+
**Do not ask the user which environment they want.** Production is the answer, it is the default,
|
|
32
|
+
and the plain command above is already correct. Asking turns a decision nobody has into a question
|
|
33
|
+
they cannot answer, at the worst possible moment — the first thing you say to them.
|
|
34
|
+
|
|
35
|
+
There is a `dev` platform, and it exists for the people building That Open Platform itself. If the
|
|
36
|
+
user is one of them they already know, and they will tell you without being asked.
|
|
37
|
+
|
|
38
|
+
Everything below this line is for that case only. If nothing has mentioned dev, skip it.
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary>Dev, for the platform team</summary>
|
|
42
|
+
|
|
43
|
+
Two platforms, not two views of one. Separate accounts, separate tokens, separate projects. A token
|
|
44
|
+
from one is refused by the other, and a model published to the wrong one lands somewhere the user's
|
|
45
|
+
team cannot see — while every command reports success.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
thatopen login --token <TOKEN> --api-url https://dev.platform.thatopen.com
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Its dashboard is the same page on that host: `https://dev.platform.thatopen.com/dashboard/data`.
|
|
52
|
+
|
|
53
|
+
</details>
|
|
54
|
+
|
|
55
|
+
## Check, do not ask
|
|
56
|
+
|
|
57
|
+
**`login` prints "Logged in successfully" and does not name the environment**, so nothing on screen
|
|
58
|
+
would contradict a wrong assumption. Read `apiUrl` from `~/.thatopen/config.json` yourself.
|
|
59
|
+
|
|
60
|
+
If it says production — which it will — say nothing about it and carry on. There is no decision to
|
|
61
|
+
report.
|
|
62
|
+
|
|
63
|
+
**Only if it says dev**, and the user has not told you they work there, is there anything to say:
|
|
64
|
+
|
|
65
|
+
> "This machine is pointed at the dev platform, which is the one the That Open team builds on. I'll
|
|
66
|
+
> move it to production — that will need a token from **https://platform.thatopen.com/dashboard/data**,
|
|
67
|
+
> since dev tokens are not accepted there."
|
|
68
|
+
|
|
69
|
+
Check this **even when the machine is already logged in**, and especially then. A saved login is
|
|
70
|
+
whoever used this machine last, not an answer to a question you have asked.
|
|
71
|
+
|
|
72
|
+
## When it fails
|
|
73
|
+
|
|
74
|
+
- **`Unauthorized`** — the token is invalid, expired, or from the other environment. Production
|
|
75
|
+
tokens use no `--api-url`; dev tokens need it. Ask for a fresh one from the same environment as
|
|
76
|
+
the URL you are using.
|
|
77
|
+
- **HTTP 403 on `item/folder?projectId=…`** — login worked. The account simply has no access to that
|
|
78
|
+
project, or the project is in the other environment. Confirm the project id with the user before
|
|
79
|
+
assuming anything is broken.
|
|
80
|
+
- **A private package fails to install** — you are not logged in, or logged in to the environment
|
|
81
|
+
that does not have it. Log in again and retry; there is no separate npm login to do.
|
|
@@ -37,11 +37,21 @@ the point.
|
|
|
37
37
|
run, briefly, before you run it.
|
|
38
38
|
- After each command, **check the output** before moving on. A command that answered is not the
|
|
39
39
|
same as a command that did what you wanted.
|
|
40
|
+
- **Whatever you find already set up on this machine is somebody's previous session, not this
|
|
41
|
+
user's choice.** A saved login, an environment, a joined project, a model already open in Revit:
|
|
42
|
+
none of it is an answer to a question you have not asked. Report what you found and ask. This is
|
|
43
|
+
the single most likely way to get the whole thing wrong while every command succeeds.
|
|
40
44
|
|
|
41
45
|
---
|
|
42
46
|
|
|
43
47
|
## Step 0 — Ask what the user wants to do
|
|
44
48
|
|
|
49
|
+
**Only if they have not already told you.** "I want to start a new collaborative project in Revit
|
|
50
|
+
and here is my file" is (A), said plainly. Reading it back as a four-way menu costs the user a
|
|
51
|
+
whole turn to answer something they just said, and that is the single most common way this guide
|
|
52
|
+
wastes somebody's time. Work out which one it is, say which one you took it to be in one line, and
|
|
53
|
+
carry on. Ask only for what is genuinely missing.
|
|
54
|
+
|
|
45
55
|
> "What would you like to do?
|
|
46
56
|
> (A) **Share** a Revit model with my team for the first time.
|
|
47
57
|
> (B) **Connect** to a shared central a teammate already uploaded.
|
|
@@ -51,9 +61,24 @@ the point.
|
|
|
51
61
|
Then collect what that choice needs. Ask now; you will need it below.
|
|
52
62
|
|
|
53
63
|
- **(A) Share:** the **absolute path** to the `.rvt`, a short lowercase **name** for the shared
|
|
54
|
-
central (e.g. `tower-central`), and the platform **Project ID
|
|
55
|
-
|
|
56
|
-
|
|
64
|
+
central (e.g. `tower-central`), and the platform **Project ID**. The file may or may not already
|
|
65
|
+
be a workshared central — Step 3 checks. Either way **the user's original file is never
|
|
66
|
+
modified**; a copy is uploaded.
|
|
67
|
+
|
|
68
|
+
**Sharing a new central means a new project. Always send them to make one, every time:**
|
|
69
|
+
|
|
70
|
+
> "A shared central lives inside a platform project, so let's make one for it. Open
|
|
71
|
+
> **https://platform.thatopen.com/dashboard/projects**, create a project, then paste me either its
|
|
72
|
+
> id or just the URL of the page you land on — I can take the id out of the URL."
|
|
73
|
+
|
|
74
|
+
Take the **URL** if that is easier for them; the id is the segment after `/projects/`. Asking
|
|
75
|
+
somebody to copy a hex string off a settings page is a worse experience than asking for the
|
|
76
|
+
address bar, and it is the same information.
|
|
77
|
+
|
|
78
|
+
**You cannot do this part for them.** The CLI has no command to list projects and none to create
|
|
79
|
+
one, so there is no menu to offer and nothing to pick from — which also means: do not guess an id,
|
|
80
|
+
and do not reuse one you saw in `status`. Every command after this needs it, and a wrong one fails
|
|
81
|
+
with a 403 that reads like a permissions problem rather than a typo.
|
|
57
82
|
|
|
58
83
|
- **(B) Connect:** identify the existing central by **one** of:
|
|
59
84
|
- the **project folder id** of the central — the `revit-<name>` folder inside the project's
|
|
@@ -77,16 +102,24 @@ Do **not** ask for the access token yet. That is Step 1.
|
|
|
77
102
|
|
|
78
103
|
2. **Token.** Ask for it, and say exactly where to get it:
|
|
79
104
|
|
|
80
|
-
> "To log in I need
|
|
81
|
-
>
|
|
82
|
-
>
|
|
83
|
-
> 2. Go to **Data → API Tokens**.
|
|
84
|
-
> 3. **Create a new token**, copy it, and paste it here."
|
|
105
|
+
> "To log in I need a That Open Platform **access token**. You create it yourself:
|
|
106
|
+
> **https://platform.thatopen.com/dashboard/data → API Tokens → create → copy**, then paste it
|
|
107
|
+
> here."
|
|
85
108
|
|
|
86
109
|
```
|
|
87
110
|
thatopen login --token <TOKEN>
|
|
88
111
|
```
|
|
89
|
-
|
|
112
|
+
|
|
113
|
+
That command is already right: **it logs in to production, which is where everybody is.** Do not
|
|
114
|
+
ask the user to choose an environment — there is a dev platform, it is for the people building
|
|
115
|
+
That Open Platform, and they will say so without being asked.
|
|
116
|
+
|
|
117
|
+
**Log in even if the machine is already logged in.** A saved login is whoever used this machine
|
|
118
|
+
last. Never print the token back.
|
|
119
|
+
|
|
120
|
+
[Logging in to That Open Platform](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/platform-token.md) is the short page for when this does not
|
|
121
|
+
go smoothly: what to do if the machine turns out to be pointed at dev, and why `Unauthorized` and
|
|
122
|
+
`403` mean different things.
|
|
90
123
|
|
|
91
124
|
**Log in before Step 2**, not after: installing the add-in downloads a private package and needs
|
|
92
125
|
these credentials.
|
|
@@ -101,6 +134,16 @@ thatopen revit status
|
|
|
101
134
|
|
|
102
135
|
- Prints `"loaded": true` → the add-in is running. Check `addinVersion` is **1.2.17 or later**; if
|
|
103
136
|
not, update it with the same command as below. Then go to Step 3.
|
|
137
|
+
|
|
138
|
+
> **`status` also reports a `project`, a `doc` and a `central`. Do not use any of them.** They are
|
|
139
|
+
> whatever this machine did last, which on a colleague's laptop or a shared machine is somebody
|
|
140
|
+
> else's work. Say what you found and ask:
|
|
141
|
+
>
|
|
142
|
+
> > "This machine is still connected to project `<id>`, document `<doc>`. Do you want to keep
|
|
143
|
+
> > working on that one, connect to a different project, or share a new model?"
|
|
144
|
+
>
|
|
145
|
+
> Publishing into the wrong project succeeds, looks completely normal, and puts somebody's model
|
|
146
|
+
> somewhere their team cannot see it.
|
|
104
147
|
- Errors *"The That Open Revit add-in is not running"* → work through (a), then (b).
|
|
105
148
|
|
|
106
149
|
**(a) Is Revit 2026 open?** If not, launch it:
|
|
@@ -127,27 +170,30 @@ Re-run `thatopen revit status` every ten seconds or so until `"loaded": true`.
|
|
|
127
170
|
|
|
128
171
|
## Step 3 — Do the action
|
|
129
172
|
|
|
130
|
-
### (A) Share a model —
|
|
173
|
+
### (A) Share a model — one command
|
|
131
174
|
|
|
132
175
|
```
|
|
133
|
-
thatopen revit
|
|
176
|
+
thatopen revit share --file "<FILE>" --project <PROJECT>
|
|
134
177
|
```
|
|
135
178
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
179
|
+
That is the whole of it. `share` installs the add-in if nothing is listening, starts Revit and
|
|
180
|
+
waits for it, checks whether the file is already a central, publishes it, and opens the user's own
|
|
181
|
+
local. It prints each of the five steps as it reaches them, so a long silence is always a step you
|
|
182
|
+
can name.
|
|
183
|
+
|
|
184
|
+
- **`--doc <name>`** is optional. Left out, it comes from the file name, kebab-cased.
|
|
185
|
+
- **`--project`** takes the dashboard URL as happily as the id.
|
|
186
|
+
- **The original file is never modified.** Everything happens on a copy, which is why `share` does
|
|
187
|
+
not need to ask before converting: there is nothing to lose. Say so rather than asking.
|
|
188
|
+
- **It joins at the end on purpose.** Sharing a model and then carrying on in the original file is
|
|
189
|
+
the one reliable way to end up outside your own team.
|
|
190
|
+
|
|
191
|
+
Steps 1 and 2 (CLI, login, add-in) still have to have happened: `share` installs the add-in but it
|
|
192
|
+
cannot log in for somebody.
|
|
193
|
+
|
|
194
|
+
If you need the pieces separately — a central that already exists, a different convert decision,
|
|
195
|
+
scripting around it — they are still there: `thatopen revit inspect --file`, then
|
|
196
|
+
`thatopen revit publish-central --project --doc --file [--convert]`, then `thatopen revit join`.
|
|
151
197
|
|
|
152
198
|
### (B) Connect to a central — `join`
|
|
153
199
|
|
|
@@ -224,11 +270,16 @@ anything that can produce the format can queue one. This package's job starts wh
|
|
|
224
270
|
which is why nothing below asks where it came from.
|
|
225
271
|
|
|
226
272
|
If the user asks how to send changes *from* their own tool — or you are being asked to write that
|
|
227
|
-
tool — the format is documented: **[Writing a flow plugin](
|
|
228
|
-
contract, and **[the architecture notes](
|
|
273
|
+
tool — the format is documented: **[Writing a flow plugin](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/flow-plugin-guide.md)** is the byte
|
|
274
|
+
contract, and **[the architecture notes](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/flow-architecture.md)** say why it is shaped that way.
|
|
229
275
|
Publishing a proposal is the smallest of the three jobs described there: it needs no ownership, no
|
|
230
276
|
history, and no collaboration layer.
|
|
231
277
|
|
|
278
|
+
If the tool is **Rhino**, the whole path is already written and worked through end to end:
|
|
279
|
+
**[Rhino → Revit, start to finish](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/rhino-interop-quickstart.md)**. Read that
|
|
280
|
+
instead of assembling it from the two documents above — it covers installing the plug-in, driving
|
|
281
|
+
Rhino without a keyboard, and the traps that cost a night.
|
|
282
|
+
|
|
232
283
|
**This is where you use the add-in's local API** — the CLI has no proposal commands yet.
|
|
233
284
|
|
|
234
285
|
**List what is waiting:**
|
|
@@ -279,18 +330,47 @@ in a status field and differently in a model.
|
|
|
279
330
|
|
|
280
331
|
## Step 7 — Offer them a viewer that shows the progress
|
|
281
332
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
333
|
+
**Offer this as soon as the central exists — right after Step 3, before they start working.** Not
|
|
334
|
+
at the end. Every sync from that moment on becomes a commit they can watch arrive, and setting it up
|
|
335
|
+
costs the same on day one as on day thirty. Left to the end it sounds like an extra; offered at the
|
|
336
|
+
start it is the thing that makes the rest visible.
|
|
285
337
|
|
|
286
|
-
|
|
338
|
+
Every sync is a commit, and the platform keeps the lot: who changed what, when, and the geometry as
|
|
339
|
+
it was at each version. Nothing in Revit shows that back, and it is the first thing people ask —
|
|
340
|
+
*what has changed since Friday?*
|
|
287
341
|
|
|
288
|
-
|
|
342
|
+
Say it plainly and wait:
|
|
343
|
+
|
|
344
|
+
> "Everything you sync is stored as a history. Would you like a viewer that shows it — pick any
|
|
289
345
|
> version and see what was created, modified and deleted, coloured in 3D?"
|
|
290
346
|
|
|
291
347
|
If they say yes, that is an **app**, and building one is
|
|
292
|
-
**[the platform AI quick start](
|
|
293
|
-
it.
|
|
348
|
+
**[the platform AI quick start](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/ai-quickstart.md)** — scaffold with the `app` template and follow
|
|
349
|
+
it.
|
|
350
|
+
|
|
351
|
+
**Do not ask them how to add the panel.** Add a **new layout** called `History`, and leave the
|
|
352
|
+
scaffold's own layouts alone. It is a two-line change, it keeps the app they were given intact, and
|
|
353
|
+
it is the answer every time — asking hands somebody a UI decision about a screen they have not seen
|
|
354
|
+
yet.
|
|
355
|
+
|
|
356
|
+
```ts
|
|
357
|
+
app.elements = {
|
|
358
|
+
...app.elements,
|
|
359
|
+
history: () => html`<top-git-history></top-git-history>`,
|
|
360
|
+
};
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
**For the layout, copy one of the scaffold's own panel layouts and swap its panel for `history`** —
|
|
364
|
+
same side, same width, same shape. Do not choose a side and do not pick a width: the app already
|
|
365
|
+
answered both, and the answer is written in `app.layouts` right there in `main.ts`.
|
|
366
|
+
|
|
367
|
+
A panel that opens on the opposite side from every other one, at a different size, is the first
|
|
368
|
+
thing anybody notices, and it reads as bolted on however good the contents are.
|
|
369
|
+
|
|
370
|
+
For the layout's `icon`, use **`at-icons:git-branch`** — That Open's own icon set, and the branch
|
|
371
|
+
mark is what the panel actually shows.
|
|
372
|
+
|
|
373
|
+
What makes it a history viewer rather than an empty viewer is a built-in component that already
|
|
294
374
|
exists, so nobody writes this part:
|
|
295
375
|
|
|
296
376
|
- **`GitHistoryManager`** — the headless half. It reads `revitflow_history.json` and the per-commit
|