@thatopen/services 0.0.1 → 0.0.3

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 (79) hide show
  1. package/AGENTS.md +86 -0
  2. package/CONTEXT.md +4 -4
  3. package/README.md +4 -4
  4. package/dist/cli.js +17 -6
  5. package/dist/core/client.d.ts +1 -1
  6. package/docs/access-backend-data.md +19 -0
  7. package/docs/app-architecture.md +94 -0
  8. package/docs/app-layout.md +139 -0
  9. package/docs/app-wiring.md +123 -0
  10. package/docs/bim-components/coding-conventions.md +128 -0
  11. package/docs/bim-components/element-collections.md +69 -0
  12. package/docs/bim-components/expose-events.md +84 -0
  13. package/docs/bim-components/library-examples.md +28 -0
  14. package/docs/bim-components/observable-collections.md +83 -0
  15. package/docs/bim-components/overview.md +160 -0
  16. package/docs/bim-components/per-frame-updates.md +20 -0
  17. package/docs/bim-components/save-and-restore-state.md +21 -0
  18. package/docs/bim-components/setup-and-cleanup.md +64 -0
  19. package/docs/bim-components/type-conventions.md +49 -0
  20. package/docs/bim-components/user-driven-object-creation.md +56 -0
  21. package/docs/cli-setup.md +54 -0
  22. package/docs/cloud-components.md +74 -0
  23. package/docs/connect-logic-to-ui.md +113 -0
  24. package/docs/previewing.md +45 -0
  25. package/docs/publishing.md +35 -0
  26. package/docs/scaffolding.md +71 -0
  27. package/docs/ui-components/async-actions.md +18 -0
  28. package/docs/ui-components/confirmation-dialog.md +39 -0
  29. package/docs/ui-components/data-table.md +185 -0
  30. package/docs/ui-components/display-text.md +39 -0
  31. package/docs/ui-components/inline-form.md +44 -0
  32. package/docs/ui-components/library-examples.md +24 -0
  33. package/docs/ui-components/overview.md +194 -0
  34. package/docs/ui-components/rendering-patterns.md +129 -0
  35. package/docs/ui-components/sections-layout.md +123 -0
  36. package/docs/update-grid-elements.md +46 -0
  37. package/docs/using-colors.md +32 -0
  38. package/docs/using-icons.md +37 -0
  39. package/package.json +4 -2
  40. package/src/cli/templates/bim/CONTEXT.md +4 -7
  41. package/src/cli/templates/bim/package.json +1 -2
  42. package/src/cli/templates/bim/src/app.ts +1 -1
  43. package/src/cli/templates/bim/src/bim-components/CloudRunner/index.ts +1 -1
  44. package/src/cli/templates/bim/src/main.ts +2 -3
  45. package/src/cli/templates/bim/src/setups/ui-manager.ts +1 -1
  46. package/src/cli/templates/bim/src/setups/viewports-manager.ts +1 -1
  47. package/src/cli/templates/bim-beta/CONTEXT.md +241 -0
  48. package/src/cli/templates/bim-beta/package.json +25 -0
  49. package/src/cli/templates/bim-beta/src/app.ts +16 -0
  50. package/src/cli/templates/bim-beta/src/bim-components/CloudRunner/index.ts +91 -0
  51. package/src/cli/templates/bim-beta/src/bim-components/CloudRunner/src/index.ts +1 -0
  52. package/src/cli/templates/bim-beta/src/bim-components/CloudRunner/src/types.ts +5 -0
  53. package/src/cli/templates/bim-beta/src/bim-components/index.ts +1 -0
  54. package/src/cli/templates/bim-beta/src/globals.ts +1 -0
  55. package/src/cli/templates/bim-beta/src/main.ts +89 -0
  56. package/src/cli/templates/bim-beta/src/setups/cloud-runner.ts +13 -0
  57. package/src/cli/templates/bim-beta/src/setups/index.ts +3 -0
  58. package/src/cli/templates/bim-beta/src/setups/ui-manager.ts +27 -0
  59. package/src/cli/templates/bim-beta/src/setups/viewports-manager.ts +22 -0
  60. package/src/cli/templates/bim-beta/src/ui-components/app-info-section/index.ts +26 -0
  61. package/src/cli/templates/bim-beta/src/ui-components/app-info-section/src/index.ts +1 -0
  62. package/src/cli/templates/bim-beta/src/ui-components/app-info-section/src/types.ts +15 -0
  63. package/src/cli/templates/bim-beta/src/ui-components/cloud-runner-section/index.ts +37 -0
  64. package/src/cli/templates/bim-beta/src/ui-components/cloud-runner-section/src/index.ts +1 -0
  65. package/src/cli/templates/bim-beta/src/ui-components/cloud-runner-section/src/types.ts +14 -0
  66. package/src/cli/templates/bim-beta/src/ui-components/index.ts +2 -0
  67. package/src/cli/templates/cloud/CONTEXT.md +205 -205
  68. package/src/cli/templates/cloud/package.json +1 -1
  69. package/src/cli/templates/cloud/src/main.ts +70 -70
  70. package/src/cli/templates/cloud-test/package.json +1 -1
  71. package/src/cli/templates/cloud-test/src/main.ts +1 -1
  72. package/src/cli/templates/default/CONTEXT.md +4 -4
  73. package/src/cli/templates/default/package.json +3 -0
  74. package/src/cli/templates/default/src/main.ts +3 -3
  75. package/src/cli/templates/shared/AGENTS.md +30 -0
  76. package/src/cli/templates/shared/CLAUDE.md +1 -0
  77. package/src/cli/templates/shared/cloud/vite.config.js +3 -3
  78. package/src/cli/templates/test/package.json +1 -1
  79. package/src/cli/templates/test/src/main.ts +2 -2
@@ -0,0 +1,91 @@
1
+ import * as OBC from "@thatopen-platform/components-beta";
2
+ import { AppManager } from "@thatopen/services";
3
+ import { CloudRunnerStatus } from "./src";
4
+
5
+ export class CloudRunner extends OBC.Component {
6
+ static readonly uuid = "7c4e5d3b-2a1f-4e8d-9b6c-0a3f7e2c5d1b" as const;
7
+
8
+ enabled = true;
9
+
10
+ readonly onExecutionUpdated = new OBC.Event<CloudRunnerStatus>();
11
+
12
+ // TODO: Replace with your actual component ID after publishing.
13
+ componentId = "your-component-id";
14
+ localServerUrl = "http://localhost:4001";
15
+
16
+ // Reactive state — read by the UI template on each render.
17
+ status = "Idle";
18
+ progress = 0;
19
+ messages: string[] = [];
20
+
21
+ constructor(components: OBC.Components) {
22
+ super(components);
23
+ components.add(CloudRunner.uuid, this);
24
+ }
25
+
26
+ async run(useLocal: boolean) {
27
+ // Resolve client at call time via AppManager — never store it as a field.
28
+ const app = this.components.get(AppManager);
29
+ const client = app.client;
30
+
31
+ client.localServerUrl = useLocal ? this.localServerUrl : null;
32
+
33
+ this.status = useLocal ? "Starting (local)..." : "Starting (deployed)...";
34
+ this.progress = 0;
35
+ this.messages = [];
36
+ this._trigger();
37
+
38
+ try {
39
+ const { executionId } = await client.executeComponent(this.componentId, {
40
+ greeting: "Hello from the BIM app!",
41
+ });
42
+
43
+ this.status = `Running (${executionId.slice(0, 8)}...)`;
44
+ this._trigger();
45
+
46
+ // Subscribe to real-time progress updates via WebSocket.
47
+ client.onExecutionProgress(executionId, (data) => {
48
+ if (data.progressUpdate) {
49
+ this.progress = data.progressUpdate.progress;
50
+ if (data.progressUpdate.result) {
51
+ this.status = `${data.progressUpdate.result}: ${data.progressUpdate.resultMessage ?? "Done"}`;
52
+ }
53
+ }
54
+ if (data.messageUpdate) {
55
+ this.messages.push(data.messageUpdate.content);
56
+ }
57
+ this._trigger();
58
+ });
59
+
60
+ // Poll once after a short delay to catch fast executions that complete
61
+ // before the WebSocket subscription is established.
62
+ setTimeout(async () => {
63
+ try {
64
+ const exec = await client.getExecution(executionId);
65
+ if (exec.result) {
66
+ this.progress = exec.progress;
67
+ this.status = `${exec.result}: ${exec.resultMessage ?? "Done"}`;
68
+ this._trigger();
69
+ }
70
+ } catch {
71
+ /* WebSocket handles it */
72
+ }
73
+ }, 2000);
74
+ } catch (err) {
75
+ this.status = `Error: ${err}`;
76
+ this._trigger();
77
+ } finally {
78
+ client.localServerUrl = null;
79
+ }
80
+ }
81
+
82
+ private _trigger() {
83
+ this.onExecutionUpdated.trigger({
84
+ status: this.status,
85
+ progress: this.progress,
86
+ messages: [...this.messages],
87
+ });
88
+ }
89
+ }
90
+
91
+ export * from "./src";
@@ -0,0 +1 @@
1
+ export * from "./types";
@@ -0,0 +1,5 @@
1
+ export interface CloudRunnerStatus {
2
+ status: string;
3
+ progress: number;
4
+ messages: string[];
5
+ }
@@ -0,0 +1 @@
1
+ export * from "./CloudRunner";
@@ -0,0 +1 @@
1
+ export const icons = {};
@@ -0,0 +1,89 @@
1
+ import * as THREE from "three";
2
+ import * as OBC from "@thatopen-platform/components-beta";
3
+ import * as OBF from "@thatopen-platform/components-front-beta";
4
+ import * as FRAGS from "@thatopen-platform/fragments-beta";
5
+ import * as BUI from "@thatopen/ui";
6
+ import * as MARKERJS from "@markerjs/markerjs3"
7
+ import {
8
+ PlatformClient,
9
+ AppManager,
10
+ ViewportsManager,
11
+ UIManager,
12
+ } from "@thatopen/services";
13
+
14
+ import { getAppManager } from "./app";
15
+ import { uiManager, cloudRunner, viewportsManager, getUIManager } from "./setups";
16
+
17
+ // Wrap in async function since IIFE format does not support top-level await.
18
+ async function main() {
19
+ // ─── Platform Client ──────────────────────────────────────────
20
+ // Reads auth context from window.__THATOPEN_CONTEXT__ (injected by the
21
+ // platform) and creates a client with Bearer auth.
22
+ const client = PlatformClient.fromPlatformContext();
23
+
24
+ // ─── Built-in Components ──────────────────────────────────────
25
+ // First argument: library globals used by the engine.
26
+ // Subsequent arguments: platform built-in components to initialise.
27
+ const { components } = await client.setup<OBC.Components>(
28
+ { OBC, OBF, BUI, THREE, FRAGS, MARKERJS },
29
+ { uuid: ViewportsManager.uuid },
30
+ { uuid: AppManager.uuid },
31
+ { uuid: UIManager.uuid },
32
+ );
33
+
34
+ // ─── Viewport ─────────────────────────────────────────────────
35
+ // Must run before app.init() so the element is ready for the grid.
36
+ const viewerElement = await viewportsManager(components);
37
+
38
+ // ─── App Init ─────────────────────────────────────────────────
39
+ const app = getAppManager(components);
40
+
41
+ await app.init({
42
+ client,
43
+ icons: [],
44
+ componentSetups: {
45
+ // core: runs in parallel before the grid mounts.
46
+ core: [uiManager, cloudRunner],
47
+ },
48
+ grid: (grid) => {
49
+ const uis = getUIManager(components);
50
+
51
+ grid.elements = {
52
+ viewer: viewerElement,
53
+ appInfoSection: {
54
+ template: uis.custom.get("appInfoSection").template,
55
+ initialState: { components },
56
+ label: "App Info",
57
+ icon: "solar:info-circle-bold",
58
+ },
59
+ cloudRunnerSection: {
60
+ template: uis.custom.get("cloudRunnerSection").template,
61
+ initialState: { components },
62
+ label: "Cloud Component",
63
+ icon: "solar:code-bold",
64
+ },
65
+ };
66
+
67
+ grid.layouts = {
68
+ Viewer: {
69
+ template: `"viewer" 1fr / 1fr`,
70
+ },
71
+ Split: {
72
+ template: `
73
+ "tabs:left(appInfoSection, cloudRunnerSection) viewer" 1fr
74
+ / 24rem 1fr
75
+ `,
76
+ icon: "solar:info-circle-bold",
77
+ },
78
+ };
79
+
80
+ grid.areaGroups = {
81
+ left: { switchersFull: true },
82
+ };
83
+
84
+ grid.layout = "Split";
85
+ },
86
+ });
87
+ }
88
+
89
+ main().catch(console.error);
@@ -0,0 +1,13 @@
1
+ import * as OBC from "@thatopen-platform/components-beta";
2
+ import { CloudRunner } from "../bim-components";
3
+ import { getUIManager } from "./ui-manager";
4
+
5
+ export const cloudRunner = (components: OBC.Components) => {
6
+ const runner = components.get(CloudRunner);
7
+ const uis = getUIManager(components);
8
+
9
+ // Re-render all appInfoSection instances whenever execution state changes.
10
+ runner.onExecutionUpdated.add(() => {
11
+ uis.custom.get("cloudRunnerSection").updateInstances();
12
+ });
13
+ };
@@ -0,0 +1,3 @@
1
+ export * from "./ui-manager";
2
+ export * from "./viewports-manager";
3
+ export * from "./cloud-runner";
@@ -0,0 +1,27 @@
1
+ import * as OBC from "@thatopen-platform/components-beta";
2
+ import * as BUI from "@thatopen/ui";
3
+ import { UIManager } from "@thatopen/services";
4
+ import {
5
+ appInfoSectionTemplate,
6
+ AppInfoSectionState,
7
+ cloudRunnerSectionTemplate,
8
+ CloudRunnerSectionState,
9
+ } from "../ui-components";
10
+
11
+ export type CustomUIs = {
12
+ appInfoSection: { type: BUI.PanelSection; state: AppInfoSectionState };
13
+ cloudRunnerSection: { type: BUI.PanelSection; state: CloudRunnerSectionState };
14
+ };
15
+
16
+ export const getUIManager = (components: OBC.Components) =>
17
+ components.get(UIManager<CustomUIs>);
18
+
19
+ export const uiManager = (components: OBC.Components) => {
20
+ const uis = getUIManager(components);
21
+ uis.registerTemplate("appInfoSection", {
22
+ template: appInfoSectionTemplate,
23
+ });
24
+ uis.registerTemplate("cloudRunnerSection", {
25
+ template: cloudRunnerSectionTemplate,
26
+ });
27
+ };
@@ -0,0 +1,22 @@
1
+ import * as OBC from "@thatopen-platform/components-beta";
2
+ import { ViewportsManager } from "@thatopen/services";
3
+
4
+ export const viewportsManager = async (components: OBC.Components) => {
5
+ const viewports = components.get(ViewportsManager);
6
+ const { element, world } = await viewports.create();
7
+
8
+ // Load a sample model. Replace with client.downloadFile(fileId) to load
9
+ // a model from the platform:
10
+ // const response = await client.downloadFile(fileId);
11
+ // const buffer = await response.arrayBuffer();
12
+ const fragments = components.get(OBC.FragmentsManager);
13
+ const file = await fetch(
14
+ "https://thatopen.github.io/engine_components/resources/frags/school_arq.frag",
15
+ );
16
+ const buffer = await file.arrayBuffer();
17
+ await fragments.core.load(buffer, { modelId: "school_arq" });
18
+ await world.camera.controls.setLookAt(68, 23, -8.5, 21.5, -5.5, 23);
19
+ await fragments.core.update(true);
20
+
21
+ return element;
22
+ };
@@ -0,0 +1,26 @@
1
+ import * as BUI from "@thatopen/ui";
2
+ import { AppInfoSectionComponent } from "./src";
3
+ import { getAppManager } from "../../app";
4
+
5
+ export const appInfoSectionTemplate: AppInfoSectionComponent = ({
6
+ components,
7
+ }) => {
8
+ const app = getAppManager(components);
9
+
10
+ const fileItems =
11
+ app.projectData?.files.map(
12
+ (f: { name: string }) => BUI.html`<bim-label>${f.name}</bim-label>`,
13
+ ) ?? [];
14
+
15
+ return BUI.html`
16
+ <bim-panel-section label="App Info" icon="solar:info-circle-bold">
17
+ <bim-label>App ID: ${app.client?.context.appId}</bim-label>
18
+ <bim-label>Project ID: ${app.client?.context.projectId}</bim-label>
19
+ <bim-label>API URL: ${app.client?.context.apiUrl}</bim-label>
20
+ <bim-label>Files: ${fileItems.length}</bim-label>
21
+ ${fileItems}
22
+ </bim-panel-section>
23
+ `;
24
+ };
25
+
26
+ export * from "./src";
@@ -0,0 +1,15 @@
1
+ import * as BUI from "@thatopen/ui";
2
+ import * as OBC from "@thatopen-platform/components-beta";
3
+
4
+ export interface AppInfoSectionState {
5
+ components: OBC.Components;
6
+ }
7
+
8
+ export type AppInfoSectionComponent =
9
+ BUI.StatefullComponent<AppInfoSectionState>;
10
+
11
+ // Used in App type (app.ts) to type this element slot in the grid.
12
+ export type AppInfoSectionGridElement = {
13
+ name: "appInfoSection";
14
+ state: AppInfoSectionState;
15
+ };
@@ -0,0 +1,37 @@
1
+ import * as BUI from "@thatopen/ui";
2
+ import { CloudRunner } from "../../bim-components";
3
+ import { CloudRunnerSectionComponent } from "./src";
4
+
5
+ export const cloudRunnerSectionTemplate: CloudRunnerSectionComponent = ({
6
+ components,
7
+ }) => {
8
+ const runner = components.get(CloudRunner);
9
+
10
+ const messageItems = runner.messages.map(
11
+ (m) => BUI.html`<bim-label>${m}</bim-label>`,
12
+ );
13
+
14
+ return BUI.html`
15
+ <bim-panel-section label="Cloud Component" icon="solar:code-bold">
16
+ <bim-label>Component ID: ${runner.componentId}</bim-label>
17
+ <bim-label>Local server: ${runner.localServerUrl}</bim-label>
18
+ <div style="display:flex;gap:0.5rem;">
19
+ <bim-button
20
+ label="Run Local"
21
+ icon="solar:play-bold"
22
+ @click=${() => runner.run(true)}
23
+ ></bim-button>
24
+ <bim-button
25
+ label="Run Deployed"
26
+ icon="solar:cloud-bold-duotone"
27
+ @click=${() => runner.run(false)}
28
+ ></bim-button>
29
+ </div>
30
+ <bim-label>${runner.status}</bim-label>
31
+ <bim-label>Progress: ${runner.progress}%</bim-label>
32
+ ${messageItems}
33
+ </bim-panel-section>
34
+ `;
35
+ };
36
+
37
+ export * from "./src";
@@ -0,0 +1,14 @@
1
+ import * as OBC from "@thatopen-platform/components-beta";
2
+ import * as BUI from "@thatopen/ui";
3
+
4
+ export interface CloudRunnerSectionState {
5
+ components: OBC.Components;
6
+ }
7
+
8
+ export type CloudRunnerSectionComponent =
9
+ BUI.StatefullComponent<CloudRunnerSectionState>;
10
+
11
+ export type CloudRunnerSectionGridElement = {
12
+ name: "cloudRunnerSection";
13
+ state: CloudRunnerSectionState;
14
+ };
@@ -0,0 +1,2 @@
1
+ export * from "./app-info-section";
2
+ export * from "./cloud-runner-section";