@thatopen/services 0.3.15 → 0.3.16
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/dist/built-in/index.d.ts +165 -2
- package/dist/cli.js +23 -12
- package/dist/index.cjs.js +2 -2
- package/dist/index.es.js +46 -36
- package/docs/ai-quickstart.md +130 -130
- package/docs/builtin/paths.json +94 -86
- package/docs/cloud/GaussianSplatConverter.md +43 -43
- package/docs/cloud/PointCloudConverter.md +53 -53
- package/docs/revit-collab-quickstart.md +256 -256
- package/package.json +95 -95
- package/src/built-in/UIManager/src/app/examples/ProjectFileStorage/example.ts +150 -0
- package/src/built-in/UIManager/src/clashes-panel/example.ts +183 -160
- package/src/built-in/UIManager/src/models-list/example.ts +122 -122
- package/src/built-in/UIManager/src/topics-panel/example.ts +170 -0
- package/src/built-in/index.ts +1048 -881
- package/src/cli/templates/app/README.md +217 -217
- package/src/cli/templates/app/src/app.ts +37 -37
- package/src/cli/templates/app/src/assets/tool-placeholder.ts +50 -50
- package/src/cli/templates/app/src/main.ts +199 -199
- package/src/cli/templates/app/src/setups/reality-capture/lib/hidden-tiles-plugin.ts +88 -88
- package/src/cli/templates/app/src/setups/reality-capture/lib/point-tile-plugin.ts +166 -166
- package/src/cli/templates/app/src/setups/reality-capture/lib/render-frame.ts +31 -31
- package/src/cli/templates/app/src/setups/reality-capture/lib/splat-tile-plugin.ts +51 -51
- package/src/cli/templates/app/src/setups/reality-capture-viewer.ts +1383 -1383
package/package.json
CHANGED
|
@@ -1,95 +1,95 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@thatopen/services",
|
|
3
|
-
"description": "Client library and CLI for building BIM apps and cloud components on the That Open Platform",
|
|
4
|
-
"author": "That Open Company",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"homepage": "https://github.com/ThatOpen/engine_services#readme",
|
|
7
|
-
"bugs": {
|
|
8
|
-
"url": "https://github.com/ThatOpen/engine_services/issues"
|
|
9
|
-
},
|
|
10
|
-
"repository": {
|
|
11
|
-
"type": "git",
|
|
12
|
-
"url": "git+https://github.com/ThatOpen/engine_services.git"
|
|
13
|
-
},
|
|
14
|
-
"publishConfig": {
|
|
15
|
-
"access": "public"
|
|
16
|
-
},
|
|
17
|
-
"private": false,
|
|
18
|
-
"version": "0.3.
|
|
19
|
-
"main": "dist/index.cjs.js",
|
|
20
|
-
"module": "dist/index.es.js",
|
|
21
|
-
"types": "dist/index.d.ts",
|
|
22
|
-
"bin": {
|
|
23
|
-
"thatopen": "dist/cli.js"
|
|
24
|
-
},
|
|
25
|
-
"files": [
|
|
26
|
-
"dist",
|
|
27
|
-
"src/cli/templates",
|
|
28
|
-
"src/built-in",
|
|
29
|
-
"docs",
|
|
30
|
-
"resources"
|
|
31
|
-
],
|
|
32
|
-
"scripts": {
|
|
33
|
-
"dev": "vite",
|
|
34
|
-
"lint": "eslint src/",
|
|
35
|
-
"build": "eslint src/ && tsc && vite build && vite build --config vite.config.cli.mts && node scripts/generate-cli-docs-paths.mjs && node scripts/generate-client-examples-paths.mjs",
|
|
36
|
-
"build:lib": "tsc && vite build",
|
|
37
|
-
"test": "vitest run",
|
|
38
|
-
"test:watch": "vitest",
|
|
39
|
-
"build:cli": "vite build --config vite.config.cli.mts",
|
|
40
|
-
"preview": "vite preview",
|
|
41
|
-
"test:ui": "vite --config test/vite.config.mts",
|
|
42
|
-
"template:app": "cd src/cli/templates/app && npm install && cd ../../../.. && node scripts/generate-template-tsconfig.mjs",
|
|
43
|
-
"template:app:dev": "cd src/cli/templates/app && npm run dev",
|
|
44
|
-
"changeset": "changeset",
|
|
45
|
-
"version": "changeset version",
|
|
46
|
-
"prepublishOnly": "npm run build"
|
|
47
|
-
},
|
|
48
|
-
"devDependencies": {
|
|
49
|
-
"@changesets/cli": "^2.27.7",
|
|
50
|
-
"@thatopen/components": "~3.4.0",
|
|
51
|
-
"@thatopen/components-front": "~3.4.0",
|
|
52
|
-
"@thatopen/fragments": "~3.4.0",
|
|
53
|
-
"@thatopen/ui": "~3.4.0",
|
|
54
|
-
"@thatopen/ui-obc": "~3.4.0",
|
|
55
|
-
"@types/node": "^20.12.12",
|
|
56
|
-
"@types/three": "^0.182.0",
|
|
57
|
-
"commander": "^14.0.3",
|
|
58
|
-
"esbuild": "^0.27.3",
|
|
59
|
-
"eslint": "9.x",
|
|
60
|
-
"eslint-config-prettier": "^9.1.0",
|
|
61
|
-
"eslint-plugin-prettier": "^5.1.3",
|
|
62
|
-
"globals": "^15.3.0",
|
|
63
|
-
"jszip": "^3.10.1",
|
|
64
|
-
"prettier": "^3.2.5",
|
|
65
|
-
"three": ">=0.182.0",
|
|
66
|
-
"tsx": "^4.16.2",
|
|
67
|
-
"typescript": "^5.2.2",
|
|
68
|
-
"typescript-eslint": "^7.10.0",
|
|
69
|
-
"vite": "^5.2.0",
|
|
70
|
-
"vite-plugin-dts": "^3.9.1",
|
|
71
|
-
"vite-plugin-eslint": "^1.8.1",
|
|
72
|
-
"vitest": "^4.1.4"
|
|
73
|
-
},
|
|
74
|
-
"dependencies": {
|
|
75
|
-
"dotenv": "^16.4.5",
|
|
76
|
-
"socket.io": "^4.8.0",
|
|
77
|
-
"socket.io-client": "^4.8.0"
|
|
78
|
-
},
|
|
79
|
-
"peerDependencies": {
|
|
80
|
-
"@thatopen/components": "~3.4.0",
|
|
81
|
-
"@thatopen/ui": "~3.4.0",
|
|
82
|
-
"three": ">=0.182.0"
|
|
83
|
-
},
|
|
84
|
-
"peerDependenciesMeta": {
|
|
85
|
-
"@thatopen/components": {
|
|
86
|
-
"optional": true
|
|
87
|
-
},
|
|
88
|
-
"@thatopen/ui": {
|
|
89
|
-
"optional": true
|
|
90
|
-
},
|
|
91
|
-
"three": {
|
|
92
|
-
"optional": true
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@thatopen/services",
|
|
3
|
+
"description": "Client library and CLI for building BIM apps and cloud components on the That Open Platform",
|
|
4
|
+
"author": "That Open Company",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/ThatOpen/engine_services#readme",
|
|
7
|
+
"bugs": {
|
|
8
|
+
"url": "https://github.com/ThatOpen/engine_services/issues"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/ThatOpen/engine_services.git"
|
|
13
|
+
},
|
|
14
|
+
"publishConfig": {
|
|
15
|
+
"access": "public"
|
|
16
|
+
},
|
|
17
|
+
"private": false,
|
|
18
|
+
"version": "0.3.16",
|
|
19
|
+
"main": "dist/index.cjs.js",
|
|
20
|
+
"module": "dist/index.es.js",
|
|
21
|
+
"types": "dist/index.d.ts",
|
|
22
|
+
"bin": {
|
|
23
|
+
"thatopen": "dist/cli.js"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src/cli/templates",
|
|
28
|
+
"src/built-in",
|
|
29
|
+
"docs",
|
|
30
|
+
"resources"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"dev": "vite",
|
|
34
|
+
"lint": "eslint src/",
|
|
35
|
+
"build": "eslint src/ && tsc && vite build && vite build --config vite.config.cli.mts && node scripts/generate-cli-docs-paths.mjs && node scripts/generate-client-examples-paths.mjs",
|
|
36
|
+
"build:lib": "tsc && vite build",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"test:watch": "vitest",
|
|
39
|
+
"build:cli": "vite build --config vite.config.cli.mts",
|
|
40
|
+
"preview": "vite preview",
|
|
41
|
+
"test:ui": "vite --config test/vite.config.mts",
|
|
42
|
+
"template:app": "cd src/cli/templates/app && npm install && cd ../../../.. && node scripts/generate-template-tsconfig.mjs",
|
|
43
|
+
"template:app:dev": "cd src/cli/templates/app && npm run dev",
|
|
44
|
+
"changeset": "changeset",
|
|
45
|
+
"version": "changeset version",
|
|
46
|
+
"prepublishOnly": "npm run build"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@changesets/cli": "^2.27.7",
|
|
50
|
+
"@thatopen/components": "~3.4.0",
|
|
51
|
+
"@thatopen/components-front": "~3.4.0",
|
|
52
|
+
"@thatopen/fragments": "~3.4.0",
|
|
53
|
+
"@thatopen/ui": "~3.4.0",
|
|
54
|
+
"@thatopen/ui-obc": "~3.4.0",
|
|
55
|
+
"@types/node": "^20.12.12",
|
|
56
|
+
"@types/three": "^0.182.0",
|
|
57
|
+
"commander": "^14.0.3",
|
|
58
|
+
"esbuild": "^0.27.3",
|
|
59
|
+
"eslint": "9.x",
|
|
60
|
+
"eslint-config-prettier": "^9.1.0",
|
|
61
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
62
|
+
"globals": "^15.3.0",
|
|
63
|
+
"jszip": "^3.10.1",
|
|
64
|
+
"prettier": "^3.2.5",
|
|
65
|
+
"three": ">=0.182.0",
|
|
66
|
+
"tsx": "^4.16.2",
|
|
67
|
+
"typescript": "^5.2.2",
|
|
68
|
+
"typescript-eslint": "^7.10.0",
|
|
69
|
+
"vite": "^5.2.0",
|
|
70
|
+
"vite-plugin-dts": "^3.9.1",
|
|
71
|
+
"vite-plugin-eslint": "^1.8.1",
|
|
72
|
+
"vitest": "^4.1.4"
|
|
73
|
+
},
|
|
74
|
+
"dependencies": {
|
|
75
|
+
"dotenv": "^16.4.5",
|
|
76
|
+
"socket.io": "^4.8.0",
|
|
77
|
+
"socket.io-client": "^4.8.0"
|
|
78
|
+
},
|
|
79
|
+
"peerDependencies": {
|
|
80
|
+
"@thatopen/components": "~3.4.0",
|
|
81
|
+
"@thatopen/ui": "~3.4.0",
|
|
82
|
+
"three": ">=0.182.0"
|
|
83
|
+
},
|
|
84
|
+
"peerDependenciesMeta": {
|
|
85
|
+
"@thatopen/components": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
88
|
+
"@thatopen/ui": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"three": {
|
|
92
|
+
"optional": true
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/* MD
|
|
2
|
+
## Persisting project-scoped data with projectStorageContext
|
|
3
|
+
---
|
|
4
|
+
Most non-trivial apps built on top-app eventually need to persist some of
|
|
5
|
+
their own data inside the project — user preferences, cached results,
|
|
6
|
+
domain state that isn't a 3D model or a regular CDE file. The naive
|
|
7
|
+
approach is for each panel/manager to talk to the CDE client directly:
|
|
8
|
+
resolve or create a folder under `__project_data`, resolve or create the
|
|
9
|
+
file, decide between uploading a new file and versioning an existing one.
|
|
10
|
+
That's the same handful of steps every single consumer ends up
|
|
11
|
+
re-implementing.
|
|
12
|
+
|
|
13
|
+
top-app centralizes exactly that plumbing behind `projectStorageContext`, a
|
|
14
|
+
`@lit/context` value any descendant can `@consume`. It provides a small,
|
|
15
|
+
stable service object — not reactive state, since `save`/`flush` are
|
|
16
|
+
actions, not values to observe:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
interface ProjectStorage {
|
|
20
|
+
save(path: string, blob: Blob): void; // debounced (~2s), per path
|
|
21
|
+
flush(): Promise<void>; // cancel debounces, save everything NOW, await it
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`path` is resolved under `__project_data/`. Calling `save` schedules a
|
|
26
|
+
debounced upload — top-app creates whichever folders in the path don't
|
|
27
|
+
exist yet, creates the file the first time, and versions it (no explicit
|
|
28
|
+
`versionTag` needed — the backend assigns the next one) every time after.
|
|
29
|
+
Saves are debounced *per path*, so unrelated consumers saving around the
|
|
30
|
+
same time don't reset each other's timers, and a small floating indicator
|
|
31
|
+
(bottom-right, so it doesn't rely on the sidebar, which is optional and can
|
|
32
|
+
be hidden) reflects both phases distinctly: just the icon, no background/
|
|
33
|
+
border, while a save is debouncing (nothing to tell the user yet — it's
|
|
34
|
+
still waiting to see if more changes come in), and the full "Saving..."
|
|
35
|
+
pill once an upload is actually in flight. Each consumer only ever decides
|
|
36
|
+
*what* to save and *where* — never the CDE mechanics, nor the indicator.
|
|
37
|
+
|
|
38
|
+
Use `flush()` whenever you're about to do something that would conflict
|
|
39
|
+
with a save still in flight — e.g. triggering a cloud job that reads the
|
|
40
|
+
same file you just edited. It cancels any pending debounce, starts the
|
|
41
|
+
upload right away, and its returned promise resolves only once that
|
|
42
|
+
upload has actually finished.
|
|
43
|
+
|
|
44
|
+
By the end, you'll have a tiny "project notes" panel that autosaves free
|
|
45
|
+
text to `__project_data/notes/notes.json`, plus a "Save now" button that
|
|
46
|
+
demonstrates `flush()`.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
import { html, LitElement } from "lit";
|
|
50
|
+
import { customElement, state } from "lit/decorators.js";
|
|
51
|
+
import { consume } from "@lit/context";
|
|
52
|
+
import * as THREE from "three";
|
|
53
|
+
import * as OBC from "@thatopen/components";
|
|
54
|
+
import * as OBF from "@thatopen/components-front";
|
|
55
|
+
import * as FRAGS from "@thatopen/fragments";
|
|
56
|
+
import * as BUI from "@thatopen/ui";
|
|
57
|
+
import { PlatformClient, UIManager } from "@thatopen/services";
|
|
58
|
+
import type { App } from "../../index";
|
|
59
|
+
import { projectStorageContext, type ProjectStorage } from "../../src/context";
|
|
60
|
+
|
|
61
|
+
// The path is always relative to `__project_data/` — top-app creates
|
|
62
|
+
// whichever folders in it don't exist yet.
|
|
63
|
+
const NOTES_PATH = "notes/notes.json";
|
|
64
|
+
|
|
65
|
+
function notesBlob(text: string): Blob {
|
|
66
|
+
return new Blob([JSON.stringify({ text, savedAt: new Date().toISOString() })], {
|
|
67
|
+
type: "application/json",
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
@customElement("notes-panel")
|
|
72
|
+
class NotesPanel extends LitElement {
|
|
73
|
+
@consume({ context: projectStorageContext })
|
|
74
|
+
private _storage?: ProjectStorage;
|
|
75
|
+
|
|
76
|
+
@state() private _text = "";
|
|
77
|
+
@state() private _flushing = false;
|
|
78
|
+
|
|
79
|
+
render() {
|
|
80
|
+
return html`
|
|
81
|
+
<bim-panel label="Project Notes">
|
|
82
|
+
<bim-panel-section label="Notes" icon="tabler:notes">
|
|
83
|
+
<bim-text-input
|
|
84
|
+
vertical
|
|
85
|
+
type="area"
|
|
86
|
+
label="Note"
|
|
87
|
+
placeholder="Type something — autosaves as you go"
|
|
88
|
+
.value=${this._text}
|
|
89
|
+
@input=${(e: Event) => {
|
|
90
|
+
this._text = (e.target as HTMLInputElement).value ?? "";
|
|
91
|
+
// Debounced — top-app coalesces rapid edits into one upload.
|
|
92
|
+
this._storage?.save(NOTES_PATH, notesBlob(this._text));
|
|
93
|
+
}}
|
|
94
|
+
></bim-text-input>
|
|
95
|
+
<bim-button
|
|
96
|
+
label="Save now"
|
|
97
|
+
icon="tabler:cloud-upload"
|
|
98
|
+
.loading=${this._flushing}
|
|
99
|
+
@click=${async () => {
|
|
100
|
+
// Same blob, but flush() cancels the debounce and waits for
|
|
101
|
+
// the upload to actually finish before this resolves.
|
|
102
|
+
this._storage?.save(NOTES_PATH, notesBlob(this._text));
|
|
103
|
+
this._flushing = true;
|
|
104
|
+
await this._storage?.flush();
|
|
105
|
+
this._flushing = false;
|
|
106
|
+
}}
|
|
107
|
+
></bim-button>
|
|
108
|
+
</bim-panel-section>
|
|
109
|
+
</bim-panel>
|
|
110
|
+
`;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// ---- app wiring ----
|
|
115
|
+
|
|
116
|
+
const client = PlatformClient.fromPlatformContext();
|
|
117
|
+
const { components } = (await client.setup(
|
|
118
|
+
{ OBC, OBF, BUI, THREE, FRAGS },
|
|
119
|
+
{ uuid: UIManager.uuid },
|
|
120
|
+
)) as { components: OBC.Components };
|
|
121
|
+
components.get(UIManager).init();
|
|
122
|
+
|
|
123
|
+
const app = document.createElement("top-app") as unknown as App;
|
|
124
|
+
|
|
125
|
+
app.setup = (waitUntil) => {
|
|
126
|
+
waitUntil(
|
|
127
|
+
(async () => {
|
|
128
|
+
const fragments = components.get(OBC.FragmentsManager);
|
|
129
|
+
const workerUrl = await FRAGS.FragmentsModels.getWorker();
|
|
130
|
+
fragments.init(await FRAGS.toClassicWorker(workerUrl), { classicWorker: true });
|
|
131
|
+
})(),
|
|
132
|
+
"Fragments Core",
|
|
133
|
+
);
|
|
134
|
+
return { components, client };
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
app.elements = {
|
|
138
|
+
viewer: () => html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
|
|
139
|
+
panel: () => html`<notes-panel></notes-panel>`,
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
app.base = "viewer";
|
|
143
|
+
app.layouts = {
|
|
144
|
+
main: { label: "Main", icon: "solar:home-bold", template: `"panel" 1fr / 22rem` },
|
|
145
|
+
};
|
|
146
|
+
app.layout = "main";
|
|
147
|
+
|
|
148
|
+
const container = document.getElementById("that-open-app") ?? document.body;
|
|
149
|
+
container.appendChild(app);
|
|
150
|
+
document.body.style.margin = "0";
|