@thatopen/services 0.1.3 → 0.3.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 (120) hide show
  1. package/README.md +59 -46
  2. package/dist/built-in/index.d.ts +486 -563
  3. package/dist/cli/lib/npmrc.d.ts +28 -0
  4. package/dist/cli/lib/npmrc.test.d.ts +1 -0
  5. package/dist/cli.js +91 -7
  6. package/dist/core/client.d.ts +10 -0
  7. package/dist/index.cjs.js +2 -2
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.es.js +42 -32
  10. package/dist/types/npm.d.ts +14 -0
  11. package/dist/vite-env.d.ts +1 -1
  12. package/docs/builtin/paths.json +74 -70
  13. package/docs/cli/create.md +28 -28
  14. package/docs/cli/local-server.md +38 -38
  15. package/docs/cli/login.md +32 -32
  16. package/docs/cli/publish.md +31 -31
  17. package/docs/cli/run.md +26 -26
  18. package/docs/cli/serve.md +43 -43
  19. package/docs/cli/swap.md +30 -30
  20. package/package.json +100 -100
  21. package/resources/AGENTS.md +40 -40
  22. package/src/built-in/CDEManager/example.ts +214 -214
  23. package/src/built-in/CDEManager/examples/FileEditing/example.ts +226 -226
  24. package/src/built-in/CDEManager/examples/FileMoves/example.ts +186 -186
  25. package/src/built-in/CDEManager/examples/FileOperations/example.ts +295 -295
  26. package/src/built-in/CDEManager/examples/FileTransfers/example.ts +210 -210
  27. package/src/built-in/CDEManager/examples/FolderManagement/example.ts +230 -230
  28. package/src/built-in/CDEManager/examples/MetadataSchema/example.ts +230 -230
  29. package/src/built-in/CDEManager/examples/MetadataViews/example.ts +166 -166
  30. package/src/built-in/CDEManager/examples/ProjectConfig/example.ts +177 -177
  31. package/src/built-in/UIManager/src/app/example.ts +99 -99
  32. package/src/built-in/UIManager/src/app/examples/AppState/example.ts +142 -142
  33. package/src/built-in/UIManager/src/app/examples/Banner/example.ts +161 -0
  34. package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +125 -125
  35. package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +126 -0
  36. package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +92 -92
  37. package/src/built-in/UIManager/src/app/examples/Modal/example.ts +165 -0
  38. package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +135 -161
  39. package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +104 -104
  40. package/src/built-in/index.ts +649 -755
  41. package/src/cli/templates/app/README.md +241 -241
  42. package/src/cli/templates/app/index.html +35 -27
  43. package/src/cli/templates/app/package.json +31 -27
  44. package/src/cli/templates/app/src/app.ts +37 -0
  45. package/src/cli/templates/app/src/assets/tool-placeholder.ts +50 -0
  46. package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -87
  47. package/src/cli/templates/app/src/bim-components/CloudRunner/src/index.ts +1 -1
  48. package/src/cli/templates/app/src/bim-components/CloudRunner/src/types.ts +5 -5
  49. package/src/cli/templates/app/src/bim-components/index.ts +1 -1
  50. package/src/cli/templates/app/src/globals.ts +1 -0
  51. package/src/cli/templates/app/src/main.ts +340 -56
  52. package/src/cli/templates/app/src/setups/active-tool-hud.ts +69 -0
  53. package/src/cli/templates/app/src/setups/camera-tools.ts +63 -0
  54. package/src/cli/templates/app/src/setups/camera-views.ts +201 -0
  55. package/src/cli/templates/app/src/setups/card-header.ts +35 -0
  56. package/src/cli/templates/app/src/setups/clipper-panel.ts +167 -0
  57. package/src/cli/templates/app/src/setups/clipper-tool.ts +754 -0
  58. package/src/cli/templates/app/src/setups/clipper.ts +75 -0
  59. package/src/cli/templates/app/src/setups/cloud-runner.ts +13 -9
  60. package/src/cli/templates/app/src/setups/commands-panel.ts +239 -0
  61. package/src/cli/templates/app/src/setups/data-table-panel.ts +2224 -0
  62. package/src/cli/templates/app/src/setups/exploded-view.ts +246 -0
  63. package/src/cli/templates/app/src/setups/file-format-icons.ts +95 -0
  64. package/src/cli/templates/app/src/setups/files-panel.ts +1503 -0
  65. package/src/cli/templates/app/src/setups/fps-indicator.ts +63 -0
  66. package/src/cli/templates/app/src/setups/graphics-panel.ts +490 -0
  67. package/src/cli/templates/app/src/setups/helper-panel.ts +88 -0
  68. package/src/cli/templates/app/src/setups/hider.ts +98 -0
  69. package/src/cli/templates/app/src/setups/index.ts +33 -3
  70. package/src/cli/templates/app/src/setups/inspection.ts +136 -0
  71. package/src/cli/templates/app/src/setups/measurement-panel.ts +188 -0
  72. package/src/cli/templates/app/src/setups/measurement-settings-panel.ts +161 -0
  73. package/src/cli/templates/app/src/setups/measurement-tool.ts +570 -0
  74. package/src/cli/templates/app/src/setups/measurements.ts +133 -0
  75. package/src/cli/templates/app/src/setups/model-tree.ts +797 -0
  76. package/src/cli/templates/app/src/setups/navigation-gizmo.ts +316 -0
  77. package/src/cli/templates/app/src/setups/objects-panel.ts +127 -0
  78. package/src/cli/templates/app/src/setups/plans-panel.ts +619 -0
  79. package/src/cli/templates/app/src/setups/properties-panel.ts +1048 -0
  80. package/src/cli/templates/app/src/setups/reality-capture/lib/hidden-tiles-plugin.ts +88 -0
  81. package/src/cli/templates/app/src/setups/reality-capture/lib/point-tile-plugin.ts +166 -0
  82. package/src/cli/templates/app/src/setups/reality-capture/lib/render-frame.ts +31 -0
  83. package/src/cli/templates/app/src/setups/reality-capture/lib/splat-tile-plugin.ts +51 -0
  84. package/src/cli/templates/app/src/setups/reality-capture-viewer.ts +1383 -0
  85. package/src/cli/templates/app/src/setups/right-sidebar.ts +178 -0
  86. package/src/cli/templates/app/src/setups/settings-panel.ts +94 -0
  87. package/src/cli/templates/app/src/setups/styles-panel.ts +110 -0
  88. package/src/cli/templates/app/src/setups/styles.ts +375 -0
  89. package/src/cli/templates/app/src/setups/tool-mode-manager.ts +150 -0
  90. package/src/cli/templates/app/src/setups/tool-mode.ts +23 -0
  91. package/src/cli/templates/app/src/setups/toolbar.ts +229 -0
  92. package/src/cli/templates/app/src/setups/ui-manager.ts +27 -0
  93. package/src/cli/templates/app/src/setups/visibility-toolbar.ts +498 -0
  94. package/src/cli/templates/app/src/setups/walkthrough.ts +528 -0
  95. package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -0
  96. package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -0
  97. package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -0
  98. package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -0
  99. package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -0
  100. package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -0
  101. package/src/cli/templates/app/src/ui-components/index.ts +2 -1
  102. package/src/cli/templates/app/tsconfig.json +16 -17
  103. package/src/cli/templates/app/vite.config.js +45 -42
  104. package/src/cli/templates/cloud-component/README.md +205 -205
  105. package/src/cli/templates/cloud-component/_thatopen +5 -5
  106. package/src/cli/templates/cloud-component/declarations.json +4 -4
  107. package/src/cli/templates/cloud-component/package.json +21 -21
  108. package/src/cli/templates/cloud-component/src/main.ts +70 -70
  109. package/src/cli/templates/cloud-component/tsconfig.json +16 -16
  110. package/src/cli/templates/cloud-component/vite.config.js +46 -46
  111. package/src/cli/templates/shared/AGENTS.md +8 -8
  112. package/src/cli/templates/shared/CLAUDE.md +1 -1
  113. package/src/cli/templates/shared/_gitignore +5 -4
  114. package/src/built-in/AppManager/example.ts +0 -86
  115. package/src/built-in/FileList/example.ts +0 -107
  116. package/src/built-in/TabbedNavigation/example.ts +0 -115
  117. package/src/built-in/ViewportsManager/example.ts +0 -106
  118. package/src/cli/templates/app/src/setups/fragments.ts +0 -18
  119. package/src/cli/templates/app/src/setups/ifc-loader.ts +0 -12
  120. package/src/cli/templates/app/src/ui-components/AppPanel/index.ts +0 -160
package/dist/index.es.js CHANGED
@@ -3,8 +3,8 @@ var ge = (n) => {
3
3
  throw TypeError(n);
4
4
  };
5
5
  var Ve = (n, e, t) => e in n ? Fe(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t;
6
- var _ = (n, e, t) => Ve(n, typeof e != "symbol" ? e + "" : e, t), j = (n, e, t) => e.has(n) || ge("Cannot " + t);
7
- var G = (n, e, t) => (j(n, e, "read from private field"), t ? t.call(n) : e.get(n)), K = (n, e, t) => e.has(n) ? ge("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(n) : e.set(n, t), we = (n, e, t, s) => (j(n, e, "write to private field"), s ? s.call(n, t) : e.set(n, t), t), c = (n, e, t) => (j(n, e, "access private method"), t);
6
+ var _ = (n, e, t) => Ve(n, typeof e != "symbol" ? e + "" : e, t), J = (n, e, t) => e.has(n) || ge("Cannot " + t);
7
+ var j = (n, e, t) => (J(n, e, "read from private field"), t ? t.call(n) : e.get(n)), Y = (n, e, t) => e.has(n) ? ge("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(n) : e.set(n, t), we = (n, e, t, s) => (J(n, e, "write to private field"), s ? s.call(n, t) : e.set(n, t), t), c = (n, e, t) => (J(n, e, "access private method"), t);
8
8
  const k = /* @__PURE__ */ Object.create(null);
9
9
  k.open = "0";
10
10
  k.close = "1";
@@ -27,14 +27,14 @@ const ee = { type: "error", data: "parser error" }, Ae = typeof Blob == "functio
27
27
  function be(n) {
28
28
  return n instanceof Uint8Array ? n : n instanceof ArrayBuffer ? new Uint8Array(n) : new Uint8Array(n.buffer, n.byteOffset, n.byteLength);
29
29
  }
30
- let Y;
30
+ let K;
31
31
  function Me(n, e) {
32
32
  if (Ae && n.data instanceof Blob)
33
33
  return n.data.arrayBuffer().then(be).then(e);
34
34
  if (Oe && (n.data instanceof ArrayBuffer || Se(n.data)))
35
35
  return e(be(n.data));
36
36
  ue(n, !1, (t) => {
37
- Y || (Y = new TextEncoder()), e(Y.encode(t));
37
+ K || (K = new TextEncoder()), e(K.encode(t));
38
38
  });
39
39
  }
40
40
  const Ee = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", N = typeof Uint8Array > "u" ? [] : new Uint8Array(256);
@@ -47,7 +47,7 @@ const He = (n) => {
47
47
  for (s = 0; s < t; s += 4)
48
48
  i = N[n.charCodeAt(s)], o = N[n.charCodeAt(s + 1)], h = N[n.charCodeAt(s + 2)], l = N[n.charCodeAt(s + 3)], d[r++] = i << 2 | o >> 4, d[r++] = (o & 15) << 4 | h >> 2, d[r++] = (h & 3) << 6 | l & 63;
49
49
  return y;
50
- }, Je = typeof ArrayBuffer == "function", le = (n, e) => {
50
+ }, Ge = typeof ArrayBuffer == "function", le = (n, e) => {
51
51
  if (typeof n != "string")
52
52
  return {
53
53
  type: "message",
@@ -56,15 +56,15 @@ const He = (n) => {
56
56
  const t = n.charAt(0);
57
57
  return t === "b" ? {
58
58
  type: "message",
59
- data: je(n.substring(1), e)
59
+ data: Je(n.substring(1), e)
60
60
  } : q[t] ? n.length > 1 ? {
61
61
  type: q[t],
62
62
  data: n.substring(1)
63
63
  } : {
64
64
  type: q[t]
65
65
  } : ee;
66
- }, je = (n, e) => {
67
- if (Je) {
66
+ }, Je = (n, e) => {
67
+ if (Ge) {
68
68
  const t = He(n);
69
69
  return Ce(t, e);
70
70
  } else
@@ -77,7 +77,7 @@ const He = (n) => {
77
77
  default:
78
78
  return n instanceof ArrayBuffer ? n : n.buffer;
79
79
  }
80
- }, Re = "", Ge = (n, e) => {
80
+ }, Re = "", je = (n, e) => {
81
81
  const t = n.length, s = new Array(t);
82
82
  let r = 0;
83
83
  n.forEach((i, o) => {
@@ -85,7 +85,7 @@ const He = (n) => {
85
85
  s[o] = h, ++r === t && e(s.join(Re));
86
86
  });
87
87
  });
88
- }, Ke = (n, e) => {
88
+ }, Ye = (n, e) => {
89
89
  const t = n.split(Re), s = [];
90
90
  for (let r = 0; r < t.length; r++) {
91
91
  const i = le(t[r], e);
@@ -94,7 +94,7 @@ const He = (n) => {
94
94
  }
95
95
  return s;
96
96
  };
97
- function Ye() {
97
+ function Ke() {
98
98
  return new TransformStream({
99
99
  transform(n, e) {
100
100
  Me(n, (t) => {
@@ -224,7 +224,7 @@ function Be(n, ...e) {
224
224
  return e.reduce((t, s) => (n.hasOwnProperty(s) && (t[s] = n[s]), t), {});
225
225
  }
226
226
  const Qe = b.setTimeout, Ze = b.clearTimeout;
227
- function J(n, e) {
227
+ function G(n, e) {
228
228
  e.useNativeTimers ? (n.setTimeoutFn = Qe.bind(b), n.clearTimeoutFn = Ze.bind(b)) : (n.setTimeoutFn = b.setTimeout.bind(b), n.clearTimeoutFn = b.clearTimeout.bind(b));
229
229
  }
230
230
  const et = 1.33;
@@ -267,7 +267,7 @@ class fe extends g {
267
267
  * @protected
268
268
  */
269
269
  constructor(e) {
270
- super(), this.writable = !1, J(this, e), this.opts = e, this.query = e.query, this.socket = e.socket, this.supportsBinary = !e.forceBase64;
270
+ super(), this.writable = !1, G(this, e), this.opts = e, this.query = e.query, this.socket = e.socket, this.supportsBinary = !e.forceBase64;
271
271
  }
272
272
  /**
273
273
  * Emits an error.
@@ -413,7 +413,7 @@ class ot extends fe {
413
413
  return this.onClose({ description: "transport closed by the server" }), !1;
414
414
  this.onPacket(s);
415
415
  };
416
- Ke(e, this.socket.binaryType).forEach(t), this.readyState !== "closed" && (this._polling = !1, this.emitReserved("pollComplete"), this.readyState === "open" && this._poll());
416
+ Ye(e, this.socket.binaryType).forEach(t), this.readyState !== "closed" && (this._polling = !1, this.emitReserved("pollComplete"), this.readyState === "open" && this._poll());
417
417
  }
418
418
  /**
419
419
  * For polling, send a close packet.
@@ -433,7 +433,7 @@ class ot extends fe {
433
433
  * @protected
434
434
  */
435
435
  write(e) {
436
- this.writable = !1, Ge(e, (t) => {
436
+ this.writable = !1, je(e, (t) => {
437
437
  this.doWrite(t, () => {
438
438
  this.writable = !0, this.emitReserved("drain");
439
439
  });
@@ -507,7 +507,7 @@ class v extends g {
507
507
  * @package
508
508
  */
509
509
  constructor(e, t, s) {
510
- super(), this.createRequest = e, J(this, s), this._opts = s, this._method = s.method || "GET", this._uri = t, this._data = s.data !== void 0 ? s.data : null, this._create();
510
+ super(), this.createRequest = e, G(this, s), this._opts = s, this._method = s.method || "GET", this._uri = t, this._data = s.data !== void 0 ? s.data : null, this._create();
511
511
  }
512
512
  /**
513
513
  * Creates the XHR object and sends the request.
@@ -721,7 +721,7 @@ class dt extends fe {
721
721
  this.onError("webtransport error", e);
722
722
  }), this._transport.ready.then(() => {
723
723
  this._transport.createBidirectionalStream().then((e) => {
724
- const t = We(Number.MAX_SAFE_INTEGER, this.socket.binaryType), s = e.readable.pipeThrough(t).getReader(), r = Ye();
724
+ const t = We(Number.MAX_SAFE_INTEGER, this.socket.binaryType), s = e.readable.pipeThrough(t).getReader(), r = Ke();
725
725
  r.readable.pipeTo(e.writable), this._writer = r.writable.getWriter();
726
726
  const i = () => {
727
727
  s.read().then(({ done: h, value: l }) => {
@@ -807,7 +807,7 @@ class C extends g {
807
807
  const s = te(e);
808
808
  t.hostname = s.host, t.secure = s.protocol === "https" || s.protocol === "wss", t.port = s.port, s.query && (t.query = s.query);
809
809
  } else t.host && (t.hostname = te(t.host).host);
810
- J(this, t), this.secure = t.secure != null ? t.secure : typeof location < "u" && location.protocol === "https:", t.hostname && !t.port && (t.port = this.secure ? "443" : "80"), this.hostname = t.hostname || (typeof location < "u" ? location.hostname : "localhost"), this.port = t.port || (typeof location < "u" && location.port ? location.port : this.secure ? "443" : "80"), this.transports = [], this._transportsByName = {}, t.transports.forEach((s) => {
810
+ G(this, t), this.secure = t.secure != null ? t.secure : typeof location < "u" && location.protocol === "https:", t.hostname && !t.port && (t.port = this.secure ? "443" : "80"), this.hostname = t.hostname || (typeof location < "u" ? location.hostname : "localhost"), this.port = t.port || (typeof location < "u" && location.port ? location.port : this.secure ? "443" : "80"), this.transports = [], this._transportsByName = {}, t.transports.forEach((s) => {
811
811
  const r = s.prototype.name;
812
812
  this.transports.push(r), this._transportsByName[r] = s;
813
813
  }), this.opts = Object.assign({
@@ -2052,7 +2052,7 @@ B.prototype.setJitter = function(n) {
2052
2052
  class ie extends g {
2053
2053
  constructor(e, t) {
2054
2054
  var s;
2055
- super(), this.nsps = {}, this.subs = [], e && typeof e == "object" && (t = e, e = void 0), t = t || {}, t.path = t.path || "/socket.io", this.opts = t, J(this, t), this.reconnection(t.reconnection !== !1), this.reconnectionAttempts(t.reconnectionAttempts || 1 / 0), this.reconnectionDelay(t.reconnectionDelay || 1e3), this.reconnectionDelayMax(t.reconnectionDelayMax || 5e3), this.randomizationFactor((s = t.randomizationFactor) !== null && s !== void 0 ? s : 0.5), this.backoff = new B({
2055
+ super(), this.nsps = {}, this.subs = [], e && typeof e == "object" && (t = e, e = void 0), t = t || {}, t.path = t.path || "/socket.io", this.opts = t, G(this, t), this.reconnection(t.reconnection !== !1), this.reconnectionAttempts(t.reconnectionAttempts || 1 / 0), this.reconnectionDelay(t.reconnectionDelay || 1e3), this.reconnectionDelayMax(t.reconnectionDelayMax || 5e3), this.randomizationFactor((s = t.randomizationFactor) !== null && s !== void 0 ? s : 0.5), this.backoff = new B({
2056
2056
  min: this.reconnectionDelay(),
2057
2057
  max: this.reconnectionDelayMax(),
2058
2058
  jitter: this.randomizationFactor()
@@ -2326,7 +2326,7 @@ class Lt extends Error {
2326
2326
  this.name = "RequestError", this.status = t, this.code = i.code, this.details = i.details, this.body = r;
2327
2327
  }
2328
2328
  }
2329
- const T = "item/folder", p = "item", O = "processor", R = "hidden", X = "FILE", Q = "TOOL", Z = "APP";
2329
+ const T = "item/folder", p = "item", O = "processor", It = "npm-registry", R = "hidden", X = "FILE", Q = "TOOL", Z = "APP";
2330
2330
  var a, ae, u, S, V, M, ce, he, Ue;
2331
2331
  const ye = class ye {
2332
2332
  /**
@@ -2337,7 +2337,7 @@ const ye = class ye {
2337
2337
  * @param props - Optional configuration (retry count, auth mode, etc.).
2338
2338
  */
2339
2339
  constructor(e, t, s) {
2340
- K(this, a);
2340
+ Y(this, a);
2341
2341
  _(this, "apiUrl");
2342
2342
  _(this, "accessToken");
2343
2343
  _(this, "wsUrl");
@@ -2865,6 +2865,18 @@ return main;`)(...h), d = (y == null ? void 0 : y.componentDefinition) ?? y;
2865
2865
  async archiveApp(e) {
2866
2866
  return await c(this, a, u).call(this, "DELETE", `${p}/${e}`);
2867
2867
  }
2868
+ // ─── NPM Registry ────────────────────────────────────────────────
2869
+ /**
2870
+ * Fetches read-only npm credentials for the private `@thatopen` Founders
2871
+ * beta packages. Gated server-side on the token owner's membership tier:
2872
+ * FOUNDING members (and admins) get the token; everyone else gets a 403
2873
+ * (`RequestError` with `status === 403`). The returned `npmrc` is a
2874
+ * ready-to-write `.npmrc` body the CLI drops into a scaffolded project.
2875
+ * @returns The registry, scope, read-only token, and assembled `.npmrc`.
2876
+ */
2877
+ async getNpmCredentials() {
2878
+ return await c(this, a, u).call(this, "GET", `${It}/credentials`);
2879
+ }
2868
2880
  // ─── Execution ───────────────────────────────────────────────────
2869
2881
  /**
2870
2882
  * Triggers server-side execution of a cloud component.
@@ -3246,11 +3258,11 @@ const me = class me extends oe {
3246
3258
  */
3247
3259
  constructor(t, s, r) {
3248
3260
  super(typeof t == "string" ? t : "", s, { ...r, useBearer: !0 });
3249
- K(this, $);
3261
+ Y(this, $);
3250
3262
  typeof t == "function" && we(this, $, t);
3251
3263
  }
3252
3264
  async resolveAccessToken() {
3253
- return G(this, $) ? await G(this, $).call(this) : super.resolveAccessToken();
3265
+ return j(this, $) ? await j(this, $).call(this) : super.resolveAccessToken();
3254
3266
  }
3255
3267
  /**
3256
3268
  * Creates a client from the platform context injected into
@@ -3307,20 +3319,18 @@ const me = class me extends oe {
3307
3319
  };
3308
3320
  $ = new WeakMap();
3309
3321
  let ke = me;
3310
- const Ut = {
3322
+ const Dt = {
3311
3323
  MAX_FIELDS: 200,
3312
3324
  MAX_KEY_LENGTH: 50,
3313
3325
  MAX_VALUE_LENGTH: 50
3314
- }, Dt = { uuid: "2e32d873-02c9-421c-8743-d8a5ca6ad38a" }, Ft = { uuid: "b0b5e2a2-0b3a-4a6b-8b1c-0b1c4a6b8b1c" }, Vt = { uuid: "2c4ae432-fc24-43e9-9783-0c960c674e96" }, Mt = { uuid: "3c2a9f34-8b6c-4d1b-8f7a-1e4a5b2c9f08" }, Ht = { uuid: "234f1416-528d-452a-9cc9-a16c5239b2eb" }, Jt = { uuid: "def81d43-6b44-4f4a-9c08-7649486112a4" };
3326
+ }, Ft = { uuid: "a3f82c1d-5b74-4e9a-bc30-d7e12f894a61" }, Vt = { uuid: "b0b5e2a2-0b3a-4a6b-8b1c-0b1c4a6b8b1c" }, Mt = { uuid: "2c4ae432-fc24-43e9-9783-0c960c674e96" }, Ht = { uuid: "234f1416-528d-452a-9cc9-a16c5239b2eb" };
3315
3327
  export {
3316
- Dt as AppManager,
3328
+ Ft as CDEManager,
3317
3329
  oe as EngineServicesClient,
3318
- Ft as FileList,
3319
- Vt as HelloWorld,
3320
- Ut as METADATA_LIMITS,
3330
+ Vt as FileList,
3331
+ Mt as HelloWorld,
3332
+ Dt as METADATA_LIMITS,
3321
3333
  ke as PlatformClient,
3322
3334
  Lt as RequestError,
3323
- Mt as TabbedNavigation,
3324
- Ht as UIManager,
3325
- Jt as ViewportsManager
3335
+ Ht as UIManager
3326
3336
  };
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Read-only npm credentials for the private `@thatopen` Founders beta packages.
3
+ * Returned by `GET /api/npm-registry/credentials` to FOUNDING members only.
4
+ */
5
+ export interface NpmCredentials {
6
+ /** Registry the scope is pinned to (e.g. `https://registry.npmjs.org/`). */
7
+ registry: string;
8
+ /** Package scope the token grants read access to (e.g. `@thatopen`). */
9
+ scope: string;
10
+ /** The read-only npm token. */
11
+ token: string;
12
+ /** Ready-to-write `.npmrc` file body (scope pin + auth line). */
13
+ npmrc: string;
14
+ }
@@ -1 +1 @@
1
- /// <reference types="vite/client" />
1
+ /// <reference types="vite/client" />
@@ -1,70 +1,74 @@
1
- [
2
- {
3
- "path": "src/built-in/CDEManager/example.ts",
4
- "description": "CDEManager — CDEManager is the central state machine for a Common Data Environment. It holds files, folders, metadata schemas, viewer groups, and user permissions, and exposes a typed state machine that all file operations — selecting, editing, uploading, viewing — route through. It has no DOM or Three.js dependencies and can run in Node, a browser, or a server-side worker wherever `@thatopen/components` is available."
5
- },
6
- {
7
- "path": "src/built-in/CDEManager/examples/FileEditing/example.ts",
8
- "description": "Bulk file editing — stage, preview, revert, and commit — A project manager preparing a deliverable handoff needs to update discipline tags across fifteen IFC files after a scope change, rename each to match the new naming convention, and archive three superseded models — all before anything is sent to the backend. Doing the changes one file at a time risks leaving the file list in a half-updated state if the session is interrupted, and there is no way to review exactly what will change before committing."
9
- },
10
- {
11
- "path": "src/built-in/CDEManager/examples/FileMoves/example.ts",
12
- "description": "Drag-and-drop file and folder moves — A coordinator restructures the project after a scope change: structural files move from the root into a dedicated discipline folder, a MEP sub-folder needs to be promoted to the top level, and a few documents need to come back to root to appear in the general view. Drag-and-drop is the natural gesture for all of this, but each drag session has intermediate stages — the file is \"in the air\", hovering over a candidate target — and every panel watching the file table should see the right state without coordinating directly with the drag component."
13
- },
14
- {
15
- "path": "src/built-in/CDEManager/examples/FileOperations/example.ts",
16
- "description": "File operations — inline edit, rename, view, download, archive — BIM coordinators reviewing a model drop repeat the same small actions throughout their session: correcting a discipline tag that changed after a scope revision, renaming a file to match the agreed convention, opening it alongside the structural model to check for clashes, handing it off to a sub-consultant, or removing a superseded version from the live set. If every panel in the platform handles these separately, two panels looking at the same file at the same time can show contradictory states — one says \"uploading\", another still shows the old name."
17
- },
18
- {
19
- "path": "src/built-in/CDEManager/examples/FileTransfers/example.ts",
20
- "description": "File uploads, versioning, and the download cache — A site coordinator drops a batch of files onto the CDE every Monday after the weekend review: some are entirely new models, some are revised versions of files already in the project, and sometimes the metadata group they upload into should be stamped automatically onto the new files. If the platform makes the coordinator sort this out manually, it slows the handoff and introduces naming errors. And if an upload fails halfway through a batch, the file table should land in a safe state rather than freeze at a loading spinner."
21
- },
22
- {
23
- "path": "src/built-in/CDEManager/examples/FolderManagement/example.ts",
24
- "description": "Folder management — create, rename, archive, and commit — A project reaches the construction phase and the coordination team needs to restructure the folder hierarchy: add a \"Facades\" discipline folder, rename \"Structural\" to its official abbreviation, and archive two superseded folders that have been merged. Doing these one at a time through separate API calls means the folder tree flickers between invalid states as each change lands — a freshly created folder appears before its sibling is renamed, and the archived folders briefly disappear before the new one is visible."
25
- },
26
- {
27
- "path": "src/built-in/CDEManager/examples/MetadataSchema/example.ts",
28
- "description": "Metadata schema — define, stage, and publish field definitions — Every project has its own vocabulary for describing files: discipline codes, revision phases, area zones, review statuses. A metadata schema defines which fields exist, what values they accept, and whether they are mandatory. Without a structured schema, each user invents their own labels and the file list becomes impossible to filter or report on consistently."
29
- },
30
- {
31
- "path": "src/built-in/CDEManager/examples/MetadataViews/example.ts",
32
- "description": "Metadata views — organize fields into named table layouts — A structural engineer and an MEP coordinator look at the same file list but care about completely different metadata. Showing every field to everyone produces a wide table that is hard to navigate. Metadata views let each role define which fields appear in which order — saving the layout so the table opens correctly next time without requiring a manual setup every session."
33
- },
34
- {
35
- "path": "src/built-in/CDEManager/examples/ProjectConfig/example.ts",
36
- "description": "Project configuration — read, write, and reload persistent data — A CDE application needs to store two kinds of configuration: project-wide settings that all team members share (the metadata schema, custom naming rules) and personal settings that belong to one user (which columns are visible, which metadata views are pinned). Both live inside the project's file storage under a reserved system folder, so they travel with the project and don't rely on a separate configuration service."
37
- },
38
- {
39
- "path": "src/built-in/FileList/example.ts",
40
- "description": ""
41
- },
42
- {
43
- "path": "src/built-in/TabbedNavigation/example.ts",
44
- "description": ""
45
- },
46
- {
47
- "path": "src/built-in/UIManager/src/app/example.ts",
48
- "description": "top-app — Front-end developers building BIM web apps need to coordinate several async initialization steps before the UI can be shown — loading the engine, preparing fragment workers, registering loaders — and users need visible feedback on what is happening during that wait, rather than a blank screen."
49
- },
50
- {
51
- "path": "src/built-in/UIManager/src/app/examples/AppState/example.ts",
52
- "description": "Shared reactive state with AppState — Developers building interactive BIM panels often need sibling components — a filter selector and a results table, for example — to stay in sync without a shared parent. Lifting state to a common ancestor and threading it down as props works for shallow trees but becomes unwieldy as the component tree grows."
53
- },
54
- {
55
- "path": "src/built-in/UIManager/src/app/examples/Contexts/example.ts",
56
- "description": "Consuming platform contexts in child components — Developers building custom BIM panels need access to the 3D engine, the platform API, and the current project's metadata — but threading these objects down through props across multiple component layers forces every intermediate element to know about data it doesn't use, making trees brittle and hard to refactor."
57
- },
58
- {
59
- "path": "src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts",
60
- "description": "Floating layout — Developers building BIM coordination tools often want the 3D model to fill the entire window while control panels float above it — but standard grid layouts give every area equal standing, shrinking the viewer into one cell and leaving visible seams between it and the panels."
61
- },
62
- {
63
- "path": "src/built-in/UIManager/src/app/examples/Notifications/example.ts",
64
- "description": "Toasts, file drop, and cross-component notifications — Developers building BIM processing UIs need to surface status updates, errors, and file-drop feedback to users from different points in the component tree — but reaching back to the app root to trigger a notification from a deeply nested component requires threading a reference through every layer in between."
65
- },
66
- {
67
- "path": "src/built-in/UIManager/src/app/examples/Sidebar/example.ts",
68
- "description": "Sidebar navigation — Product teams building BIM apps often need multiple distinct views — a 3D model viewer, a data browser, a settings screen — but wiring a custom nav bar and managing view transitions from scratch adds complexity before any real feature work begins."
69
- }
70
- ]
1
+ [
2
+ {
3
+ "path": "src/built-in/CDEManager/example.ts",
4
+ "description": "CDEManager — CDEManager is the central state machine for a Common Data Environment. It holds files, folders, metadata schemas, viewer groups, and user permissions, and exposes a typed state machine that all file operations — selecting, editing, uploading, viewing — route through. It has no DOM or Three.js dependencies and can run in Node, a browser, or a server-side worker wherever `@thatopen/components` is available."
5
+ },
6
+ {
7
+ "path": "src/built-in/CDEManager/examples/FileEditing/example.ts",
8
+ "description": "Bulk file editing — stage, preview, revert, and commit — A project manager preparing a deliverable handoff needs to update discipline tags across fifteen IFC files after a scope change, rename each to match the new naming convention, and archive three superseded models — all before anything is sent to the backend. Doing the changes one file at a time risks leaving the file list in a half-updated state if the session is interrupted, and there is no way to review exactly what will change before committing."
9
+ },
10
+ {
11
+ "path": "src/built-in/CDEManager/examples/FileMoves/example.ts",
12
+ "description": "Drag-and-drop file and folder moves — A coordinator restructures the project after a scope change: structural files move from the root into a dedicated discipline folder, a MEP sub-folder needs to be promoted to the top level, and a few documents need to come back to root to appear in the general view. Drag-and-drop is the natural gesture for all of this, but each drag session has intermediate stages — the file is \"in the air\", hovering over a candidate target — and every panel watching the file table should see the right state without coordinating directly with the drag component."
13
+ },
14
+ {
15
+ "path": "src/built-in/CDEManager/examples/FileOperations/example.ts",
16
+ "description": "File operations — inline edit, rename, view, download, archive — BIM coordinators reviewing a model drop repeat the same small actions throughout their session: correcting a discipline tag that changed after a scope revision, renaming a file to match the agreed convention, opening it alongside the structural model to check for clashes, handing it off to a sub-consultant, or removing a superseded version from the live set. If every panel in the platform handles these separately, two panels looking at the same file at the same time can show contradictory states — one says \"uploading\", another still shows the old name."
17
+ },
18
+ {
19
+ "path": "src/built-in/CDEManager/examples/FileTransfers/example.ts",
20
+ "description": "File uploads, versioning, and the download cache — A site coordinator drops a batch of files onto the CDE every Monday after the weekend review: some are entirely new models, some are revised versions of files already in the project, and sometimes the metadata group they upload into should be stamped automatically onto the new files. If the platform makes the coordinator sort this out manually, it slows the handoff and introduces naming errors. And if an upload fails halfway through a batch, the file table should land in a safe state rather than freeze at a loading spinner."
21
+ },
22
+ {
23
+ "path": "src/built-in/CDEManager/examples/FolderManagement/example.ts",
24
+ "description": "Folder management — create, rename, archive, and commit — A project reaches the construction phase and the coordination team needs to restructure the folder hierarchy: add a \"Facades\" discipline folder, rename \"Structural\" to its official abbreviation, and archive two superseded folders that have been merged. Doing these one at a time through separate API calls means the folder tree flickers between invalid states as each change lands — a freshly created folder appears before its sibling is renamed, and the archived folders briefly disappear before the new one is visible."
25
+ },
26
+ {
27
+ "path": "src/built-in/CDEManager/examples/MetadataSchema/example.ts",
28
+ "description": "Metadata schema — define, stage, and publish field definitions — Every project has its own vocabulary for describing files: discipline codes, revision phases, area zones, review statuses. A metadata schema defines which fields exist, what values they accept, and whether they are mandatory. Without a structured schema, each user invents their own labels and the file list becomes impossible to filter or report on consistently."
29
+ },
30
+ {
31
+ "path": "src/built-in/CDEManager/examples/MetadataViews/example.ts",
32
+ "description": "Metadata views — organize fields into named table layouts — A structural engineer and an MEP coordinator look at the same file list but care about completely different metadata. Showing every field to everyone produces a wide table that is hard to navigate. Metadata views let each role define which fields appear in which order — saving the layout so the table opens correctly next time without requiring a manual setup every session."
33
+ },
34
+ {
35
+ "path": "src/built-in/CDEManager/examples/ProjectConfig/example.ts",
36
+ "description": "Project configuration — read, write, and reload persistent data — A CDE application needs to store two kinds of configuration: project-wide settings that all team members share (the metadata schema, custom naming rules) and personal settings that belong to one user (which columns are visible, which metadata views are pinned). Both live inside the project's file storage under a reserved system folder, so they travel with the project and don't rely on a separate configuration service."
37
+ },
38
+ {
39
+ "path": "src/built-in/UIManager/src/app/example.ts",
40
+ "description": "top-app — Front-end developers building BIM web apps need to coordinate several async initialization steps before the UI can be shown — loading the engine, preparing fragment workers, registering loaders — and users need visible feedback on what is happening during that wait, rather than a blank screen."
41
+ },
42
+ {
43
+ "path": "src/built-in/UIManager/src/app/examples/AppState/example.ts",
44
+ "description": "Shared reactive state with AppState — Developers building interactive BIM panels often need sibling components — a filter selector and a results table, for example — to stay in sync without a shared parent. Lifting state to a common ancestor and threading it down as props works for shallow trees but becomes unwieldy as the component tree grows."
45
+ },
46
+ {
47
+ "path": "src/built-in/UIManager/src/app/examples/Banner/example.ts",
48
+ "description": "Persistent banners with top:banner — Some application states need a persistent, visible indicator that stays on screen until the state is explicitly cleared — an archived-files mode, a read-only permission warning, a degraded-connectivity notice. A toast auto-dismisses after a few seconds, which is wrong for these cases. A modal blocks interaction entirely, which is too heavy."
49
+ },
50
+ {
51
+ "path": "src/built-in/UIManager/src/app/examples/Contexts/example.ts",
52
+ "description": "Consuming platform contexts in child components — Developers building custom BIM panels need access to the 3D engine, the platform API, and the current project's metadata — but threading these objects down through props across multiple component layers forces every intermediate element to know about data it doesn't use, making trees brittle and hard to refactor."
53
+ },
54
+ {
55
+ "path": "src/built-in/UIManager/src/app/examples/FileDrop/example.ts",
56
+ "description": "File drag-and-drop with top:files-dropped — Desktop BIM workflows often rely on dragging files straight from the OS file manager onto the browser window — but wiring a document-level dragenter, dragover, dragleave, and drop handler that correctly tracks nested enter/leave counts, shows a visual overlay, and forwards the files to the right component is tedious boilerplate to repeat for every app."
57
+ },
58
+ {
59
+ "path": "src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts",
60
+ "description": "Floating layout — Developers building BIM coordination tools often want the 3D model to fill the entire window while control panels float above it — but standard grid layouts give every area equal standing, shrinking the viewer into one cell and leaving visible seams between it and the panels."
61
+ },
62
+ {
63
+ "path": "src/built-in/UIManager/src/app/examples/Modal/example.ts",
64
+ "description": "Confirmation modals with top:modal — Destructive or irreversible actions — deleting records, overwriting files, leaving unsaved changes — should ask the user to confirm before proceeding. Opening a custom dialog element from a deeply nested component means threading a reference to a controller up through every layer of the tree."
65
+ },
66
+ {
67
+ "path": "src/built-in/UIManager/src/app/examples/Notifications/example.ts",
68
+ "description": "Toasts and cross-component notifications — Developers building BIM processing UIs need to surface status updates, errors, and async feedback to users from different points in the component tree — but reaching back to the app root to trigger a notification from a deeply nested component requires threading a reference through every layer in between."
69
+ },
70
+ {
71
+ "path": "src/built-in/UIManager/src/app/examples/Sidebar/example.ts",
72
+ "description": "Sidebar navigation — Product teams building BIM apps often need multiple distinct views — a 3D model viewer, a data browser, a settings screen — but wiring a custom nav bar and managing view transitions from scratch adds complexity before any real feature work begins."
73
+ }
74
+ ]
@@ -1,28 +1,28 @@
1
- ---
2
- description: "Scaffold a new app or cloud component project from a template. Covers --template (app for browser BIM apps, cloud-component for server-side components), --beta for switching to private beta engine libraries at scaffold time, and using '.' as the project name to scaffold into the current directory."
3
- ---
4
-
5
- ## thatopen create
6
-
7
- Scaffolds a new ThatOpen project and runs `npm install` automatically.
8
-
9
- **Usage:**
10
- ```bash
11
- thatopen create <project-name> [flags]
12
- thatopen create . # scaffold into the current directory
13
- ```
14
-
15
- **Flags:**
16
-
17
- - `--template <template>`, `-t` — Template to use. Default: `app`.
18
- - `app` — Browser BIM app running inside the platform iframe.
19
- - `cloud-component` — Server-side component executed by the platform's cloud engine and consumed in apps and/or automations.
20
- - `--beta` — Use private beta engine libraries (`@thatopen-platform/*-beta`) instead of the public ones. Sets `beta: true` in `.thatopen` so `serve`, `local-server`, and `vite build` all resolve to beta packages automatically. Requires beta npm access configured.
21
-
22
- **Examples:**
23
- ```bash
24
- thatopen create my-app
25
- thatopen create my-app -t cloud-component
26
- thatopen create my-app --beta
27
- thatopen create . --beta
28
- ```
1
+ ---
2
+ description: "Scaffold a new app or cloud component project from a template. Covers --template (app for browser BIM apps, cloud-component for server-side components), --beta for switching to private beta engine libraries at scaffold time, and using '.' as the project name to scaffold into the current directory."
3
+ ---
4
+
5
+ ## thatopen create
6
+
7
+ Scaffolds a new ThatOpen project and runs `npm install` automatically.
8
+
9
+ **Usage:**
10
+ ```bash
11
+ thatopen create <project-name> [flags]
12
+ thatopen create . # scaffold into the current directory
13
+ ```
14
+
15
+ **Flags:**
16
+
17
+ - `--template <template>`, `-t` — Template to use. Default: `app`.
18
+ - `app` — Browser BIM app running inside the platform iframe.
19
+ - `cloud-component` — Server-side component executed by the platform's cloud engine and consumed in apps and/or automations.
20
+ - `--beta` — Use private beta engine libraries (`@thatopen-platform/*-beta`) instead of the public ones. Sets `beta: true` in `.thatopen` so `serve`, `local-server`, and `vite build` all resolve to beta packages automatically. Requires beta npm access configured.
21
+
22
+ **Examples:**
23
+ ```bash
24
+ thatopen create my-app
25
+ thatopen create my-app -t cloud-component
26
+ thatopen create my-app --beta
27
+ thatopen create . --beta
28
+ ```
@@ -1,38 +1,38 @@
1
- ---
2
- description: "Start a local HTTP + Socket.IO server that replicates the platform's cloud execution API on port 4001, with esbuild watch mode. Connect an app to it via EngineServicesClient's localServerUrl option to execute and monitor a local cloud component without publishing."
3
- ---
4
-
5
- ## thatopen local-server
6
-
7
- Starts a local server that mimics the platform's cloud execution API. Runs esbuild in watch mode and rebuilds the component on every save.
8
-
9
- Connect an app to it by passing `localServerUrl` to `EngineServicesClient`:
10
-
11
- ```ts
12
- const client = new EngineServicesClient(token, apiUrl, {
13
- localServerUrl: 'http://localhost:4001'
14
- });
15
- ```
16
-
17
- **Usage:**
18
- ```bash
19
- thatopen local-server [flags]
20
- ```
21
-
22
- **Flags:**
23
-
24
- - `--port <port>` — Port to run the server on. Default: `4001`.
25
- - `--skip-build` — Skip the initial build and use the existing `dist/bundle.js`.
26
-
27
- **Endpoints:**
28
-
29
- - `POST /api/processor/:componentId/execute`
30
- - `GET /api/processor/progress/:executionId`
31
- - `POST /api/processor/progress/:executionId/abort`
32
- - `GET /api/processor/:componentId/progress`
33
-
34
- **Example:**
35
- ```bash
36
- thatopen local-server
37
- thatopen local-server --port 5000
38
- ```
1
+ ---
2
+ description: "Start a local HTTP + Socket.IO server that replicates the platform's cloud execution API on port 4001, with esbuild watch mode. Connect an app to it via EngineServicesClient's localServerUrl option to execute and monitor a local cloud component without publishing."
3
+ ---
4
+
5
+ ## thatopen local-server
6
+
7
+ Starts a local server that mimics the platform's cloud execution API. Runs esbuild in watch mode and rebuilds the component on every save.
8
+
9
+ Connect an app to it by passing `localServerUrl` to `EngineServicesClient`:
10
+
11
+ ```ts
12
+ const client = new EngineServicesClient(token, apiUrl, {
13
+ localServerUrl: 'http://localhost:4001'
14
+ });
15
+ ```
16
+
17
+ **Usage:**
18
+ ```bash
19
+ thatopen local-server [flags]
20
+ ```
21
+
22
+ **Flags:**
23
+
24
+ - `--port <port>` — Port to run the server on. Default: `4001`.
25
+ - `--skip-build` — Skip the initial build and use the existing `dist/bundle.js`.
26
+
27
+ **Endpoints:**
28
+
29
+ - `POST /api/processor/:componentId/execute`
30
+ - `GET /api/processor/progress/:executionId`
31
+ - `POST /api/processor/progress/:executionId/abort`
32
+ - `GET /api/processor/:componentId/progress`
33
+
34
+ **Example:**
35
+ ```bash
36
+ thatopen local-server
37
+ thatopen local-server --port 5000
38
+ ```
package/docs/cli/login.md CHANGED
@@ -1,32 +1,32 @@
1
- ---
2
- description: "Authenticate with the ThatOpen platform by validating an access token against the API. Saves credentials globally (~/.thatopen/config.json) by default, or locally to the project's .thatopen file with --local. Local config takes priority over global."
3
- ---
4
-
5
- ## thatopen login
6
-
7
- Validates an access token against the platform API and saves the credentials. Run this once globally before using any other command, or per-project with `--local`.
8
-
9
- To get a token:
10
- 1. Go to [https://dev.platform.thatopen.com](https://dev.platform.thatopen.com)
11
- 2. In the header, click **Data**
12
- 3. Find the **Tokens** card and create a new token
13
- 4. Enable the permissions: **Apps**, **Components**, and **Storage**
14
- 5. Copy the token
15
-
16
- **Usage:**
17
- ```bash
18
- thatopen login --token <token> [flags]
19
- ```
20
-
21
- **Flags:**
22
-
23
- - `--token <token>` — Access token from the dashboard. Required.
24
- - `--api-url <url>` — Platform API URL. Default: `https://dev.platform.thatopen.com`.
25
- - `--local` — Save credentials to `.thatopen` in the current directory instead of the global config. Use this inside a project to override the global token for that project only.
26
-
27
- **Examples:**
28
- ```bash
29
- thatopen login --token my-token
30
- thatopen login --token my-token --local
31
- npm run login -- --token my-token # from inside a scaffolded project
32
- ```
1
+ ---
2
+ description: "Authenticate with the ThatOpen platform by validating an access token against the API. Saves credentials globally (~/.thatopen/config.json) by default, or locally to the project's .thatopen file with --local. Local config takes priority over global."
3
+ ---
4
+
5
+ ## thatopen login
6
+
7
+ Validates an access token against the platform API and saves the credentials. Run this once globally before using any other command, or per-project with `--local`.
8
+
9
+ To get a token:
10
+ 1. Go to [https://dev.platform.thatopen.com](https://dev.platform.thatopen.com)
11
+ 2. In the header, click **Data**
12
+ 3. Find the **Tokens** card and create a new token
13
+ 4. Enable the permissions: **Apps**, **Components**, and **Storage**
14
+ 5. Copy the token
15
+
16
+ **Usage:**
17
+ ```bash
18
+ thatopen login --token <token> [flags]
19
+ ```
20
+
21
+ **Flags:**
22
+
23
+ - `--token <token>` — Access token from the dashboard. Required.
24
+ - `--api-url <url>` — Platform API URL. Default: `https://dev.platform.thatopen.com`.
25
+ - `--local` — Save credentials to `.thatopen` in the current directory instead of the global config. Use this inside a project to override the global token for that project only.
26
+
27
+ **Examples:**
28
+ ```bash
29
+ thatopen login --token my-token
30
+ thatopen login --token my-token --local
31
+ npm run login -- --token my-token # from inside a scaffolded project
32
+ ```