@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/dist/index.es.js
CHANGED
|
@@ -3,8 +3,8 @@ var we = (n) => {
|
|
|
3
3
|
throw TypeError(n);
|
|
4
4
|
};
|
|
5
5
|
var Ve = (n, e, t) => e in n ? Me(n, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : n[e] = t;
|
|
6
|
-
var w = (n, e, t) => Ve(n, typeof e != "symbol" ? e + "" : e, t),
|
|
7
|
-
var Y = (n, e, t) => (
|
|
6
|
+
var w = (n, e, t) => Ve(n, typeof e != "symbol" ? e + "" : e, t), j = (n, e, t) => e.has(n) || we("Cannot " + t);
|
|
7
|
+
var Y = (n, e, t) => (j(n, e, "read from private field"), t ? t.call(n) : e.get(n)), K = (n, e, t) => e.has(n) ? we("Cannot add the same private member more than once") : e instanceof WeakSet ? e.add(n) : e.set(n, t), _e = (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 v = /* @__PURE__ */ Object.create(null);
|
|
9
9
|
v.open = "0";
|
|
10
10
|
v.close = "1";
|
|
@@ -47,7 +47,7 @@ const Ge = (n) => {
|
|
|
47
47
|
for (s = 0; s < t; s += 4)
|
|
48
48
|
i = P[n.charCodeAt(s)], o = P[n.charCodeAt(s + 1)], h = P[n.charCodeAt(s + 2)], l = P[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
|
-
},
|
|
50
|
+
}, Je = typeof ArrayBuffer == "function", fe = (n, e) => {
|
|
51
51
|
if (typeof n != "string")
|
|
52
52
|
return {
|
|
53
53
|
type: "message",
|
|
@@ -56,15 +56,15 @@ const Ge = (n) => {
|
|
|
56
56
|
const t = n.charAt(0);
|
|
57
57
|
return t === "b" ? {
|
|
58
58
|
type: "message",
|
|
59
|
-
data:
|
|
59
|
+
data: je(n.substring(1), e)
|
|
60
60
|
} : U[t] ? n.length > 1 ? {
|
|
61
61
|
type: U[t],
|
|
62
62
|
data: n.substring(1)
|
|
63
63
|
} : {
|
|
64
64
|
type: U[t]
|
|
65
65
|
} : te;
|
|
66
|
-
},
|
|
67
|
-
if (
|
|
66
|
+
}, je = (n, e) => {
|
|
67
|
+
if (Je) {
|
|
68
68
|
const t = Ge(n);
|
|
69
69
|
return $e(t, e);
|
|
70
70
|
} else
|
|
@@ -224,7 +224,7 @@ function xe(n, ...e) {
|
|
|
224
224
|
return e.reduce((t, s) => (n.hasOwnProperty(s) && (t[s] = n[s]), t), {});
|
|
225
225
|
}
|
|
226
226
|
const Ze = _.setTimeout, et = _.clearTimeout;
|
|
227
|
-
function
|
|
227
|
+
function J(n, e) {
|
|
228
228
|
e.useNativeTimers ? (n.setTimeoutFn = Ze.bind(_), n.clearTimeoutFn = et.bind(_)) : (n.setTimeoutFn = _.setTimeout.bind(_), n.clearTimeoutFn = _.clearTimeout.bind(_));
|
|
229
229
|
}
|
|
230
230
|
const tt = 1.33;
|
|
@@ -267,7 +267,7 @@ class pe extends g {
|
|
|
267
267
|
* @protected
|
|
268
268
|
*/
|
|
269
269
|
constructor(e) {
|
|
270
|
-
super(), this.writable = !1,
|
|
270
|
+
super(), this.writable = !1, J(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.
|
|
@@ -474,8 +474,8 @@ class ut extends at {
|
|
|
474
474
|
/**
|
|
475
475
|
* Sends data.
|
|
476
476
|
*
|
|
477
|
-
* @param {String} data
|
|
478
|
-
* @param {Function}
|
|
477
|
+
* @param {String} data to send.
|
|
478
|
+
* @param {Function} called upon flush.
|
|
479
479
|
* @private
|
|
480
480
|
*/
|
|
481
481
|
doWrite(e, t) {
|
|
@@ -507,7 +507,7 @@ class T extends g {
|
|
|
507
507
|
* @package
|
|
508
508
|
*/
|
|
509
509
|
constructor(e, t, s) {
|
|
510
|
-
super(), this.createRequest = e,
|
|
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();
|
|
511
511
|
}
|
|
512
512
|
/**
|
|
513
513
|
* Creates the XHR object and sends the request.
|
|
@@ -807,7 +807,7 @@ class R extends g {
|
|
|
807
807
|
const s = se(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 = se(t.host).host);
|
|
810
|
-
|
|
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) => {
|
|
811
811
|
const r = s.prototype.name;
|
|
812
812
|
this.transports.push(r), this._transportsByName[r] = s;
|
|
813
813
|
}), this.opts = Object.assign({
|
|
@@ -1008,7 +1008,7 @@ class R extends g {
|
|
|
1008
1008
|
/**
|
|
1009
1009
|
* Sends a packet.
|
|
1010
1010
|
*
|
|
1011
|
-
* @param {String} type
|
|
1011
|
+
* @param {String} type: packet type.
|
|
1012
1012
|
* @param {String} data.
|
|
1013
1013
|
* @param {Object} options.
|
|
1014
1014
|
* @param {Function} fn - callback function.
|
|
@@ -1140,8 +1140,8 @@ class Et extends R {
|
|
|
1140
1140
|
}
|
|
1141
1141
|
let Tt = class extends Et {
|
|
1142
1142
|
constructor(e, t = {}) {
|
|
1143
|
-
const s = typeof e == "object"
|
|
1144
|
-
(!
|
|
1143
|
+
const s = typeof e == "object" ? e : t;
|
|
1144
|
+
(!s.transports || s.transports && typeof s.transports[0] == "string") && (s.transports = (s.transports || ["polling", "websocket", "webtransport"]).map((r) => mt[r]).filter((r) => !!r)), super(e, s);
|
|
1145
1145
|
}
|
|
1146
1146
|
};
|
|
1147
1147
|
function vt(n, e = "", t) {
|
|
@@ -1274,12 +1274,11 @@ class Bt {
|
|
|
1274
1274
|
class ye extends g {
|
|
1275
1275
|
/**
|
|
1276
1276
|
* Decoder constructor
|
|
1277
|
+
*
|
|
1278
|
+
* @param {function} reviver - custom reviver to pass down to JSON.stringify
|
|
1277
1279
|
*/
|
|
1278
1280
|
constructor(e) {
|
|
1279
|
-
super(), this.
|
|
1280
|
-
reviver: void 0,
|
|
1281
|
-
maxAttachments: 10
|
|
1282
|
-
}, typeof e == "function" ? { reviver: e } : e);
|
|
1281
|
+
super(), this.reviver = e;
|
|
1283
1282
|
}
|
|
1284
1283
|
/**
|
|
1285
1284
|
* Decodes an encoded packet string into packet JSON.
|
|
@@ -1322,12 +1321,7 @@ class ye extends g {
|
|
|
1322
1321
|
const o = e.substring(i, t);
|
|
1323
1322
|
if (o != Number(o) || e.charAt(t) !== "-")
|
|
1324
1323
|
throw new Error("Illegal attachments");
|
|
1325
|
-
|
|
1326
|
-
if (!Nt(h) || h < 0)
|
|
1327
|
-
throw new Error("Illegal attachments");
|
|
1328
|
-
if (h > this.opts.maxAttachments)
|
|
1329
|
-
throw new Error("too many attachments");
|
|
1330
|
-
s.attachments = h;
|
|
1324
|
+
s.attachments = Number(o);
|
|
1331
1325
|
}
|
|
1332
1326
|
if (e.charAt(t + 1) === "/") {
|
|
1333
1327
|
const i = t + 1;
|
|
@@ -1361,7 +1355,7 @@ class ye extends g {
|
|
|
1361
1355
|
}
|
|
1362
1356
|
tryParse(e) {
|
|
1363
1357
|
try {
|
|
1364
|
-
return JSON.parse(e, this.
|
|
1358
|
+
return JSON.parse(e, this.reviver);
|
|
1365
1359
|
} catch {
|
|
1366
1360
|
return !1;
|
|
1367
1361
|
}
|
|
@@ -1415,13 +1409,10 @@ class xt {
|
|
|
1415
1409
|
this.reconPack = null, this.buffers = [];
|
|
1416
1410
|
}
|
|
1417
1411
|
}
|
|
1418
|
-
const Nt = Number.isInteger || function(n) {
|
|
1419
|
-
return typeof n == "number" && isFinite(n) && Math.floor(n) === n;
|
|
1420
|
-
};
|
|
1421
1412
|
function ke(n) {
|
|
1422
1413
|
return Object.prototype.toString.call(n) === "[object Object]";
|
|
1423
1414
|
}
|
|
1424
|
-
const
|
|
1415
|
+
const Nt = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1425
1416
|
__proto__: null,
|
|
1426
1417
|
Decoder: ye,
|
|
1427
1418
|
Encoder: Bt,
|
|
@@ -1434,7 +1425,7 @@ function b(n, e, t) {
|
|
|
1434
1425
|
n.off(e, t);
|
|
1435
1426
|
};
|
|
1436
1427
|
}
|
|
1437
|
-
const
|
|
1428
|
+
const Pt = Object.freeze({
|
|
1438
1429
|
connect: 1,
|
|
1439
1430
|
connect_error: 1,
|
|
1440
1431
|
disconnect: 1,
|
|
@@ -1559,7 +1550,7 @@ class Ue extends g {
|
|
|
1559
1550
|
*/
|
|
1560
1551
|
emit(e, ...t) {
|
|
1561
1552
|
var s, r, i;
|
|
1562
|
-
if (
|
|
1553
|
+
if (Pt.hasOwnProperty(e))
|
|
1563
1554
|
throw new Error('"' + e.toString() + '" is a reserved event name');
|
|
1564
1555
|
if (t.unshift(e), this._opts.retries && !this.flags.fromQueue && !this.flags.volatile)
|
|
1565
1556
|
return this._addToQueue(t), this;
|
|
@@ -2061,12 +2052,12 @@ x.prototype.setJitter = function(n) {
|
|
|
2061
2052
|
class oe extends g {
|
|
2062
2053
|
constructor(e, t) {
|
|
2063
2054
|
var s;
|
|
2064
|
-
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,
|
|
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 x({
|
|
2065
2056
|
min: this.reconnectionDelay(),
|
|
2066
2057
|
max: this.reconnectionDelayMax(),
|
|
2067
2058
|
jitter: this.randomizationFactor()
|
|
2068
2059
|
}), this.timeout(t.timeout == null ? 2e4 : t.timeout), this._readyState = "closed", this.uri = e;
|
|
2069
|
-
const r = t.parser ||
|
|
2060
|
+
const r = t.parser || Nt;
|
|
2070
2061
|
this.encoder = new r.Encoder(), this.decoder = new r.Decoder(), this._autoConnect = t.autoConnect !== !1, this._autoConnect && this.open();
|
|
2071
2062
|
}
|
|
2072
2063
|
reconnection(e) {
|
|
@@ -2309,7 +2300,7 @@ Object.assign(M, {
|
|
|
2309
2300
|
io: M,
|
|
2310
2301
|
connect: M
|
|
2311
2302
|
});
|
|
2312
|
-
function
|
|
2303
|
+
function Lt(n) {
|
|
2313
2304
|
try {
|
|
2314
2305
|
const e = JSON.parse(n);
|
|
2315
2306
|
if (e && typeof e == "object") {
|
|
@@ -2324,9 +2315,9 @@ function It(n) {
|
|
|
2324
2315
|
}
|
|
2325
2316
|
return {};
|
|
2326
2317
|
}
|
|
2327
|
-
class
|
|
2318
|
+
class It extends Error {
|
|
2328
2319
|
constructor(t, s, r) {
|
|
2329
|
-
const i =
|
|
2320
|
+
const i = Lt(r);
|
|
2330
2321
|
super(i.message ?? `${s || "Request failed"} (${t})`);
|
|
2331
2322
|
w(this, "status");
|
|
2332
2323
|
w(this, "code");
|
|
@@ -2335,7 +2326,7 @@ class qt extends Error {
|
|
|
2335
2326
|
this.name = "RequestError", this.status = t, this.code = i.code, this.details = i.details, this.body = r;
|
|
2336
2327
|
}
|
|
2337
2328
|
}
|
|
2338
|
-
const E = "item/folder", f = "item", S = "processor",
|
|
2329
|
+
const E = "item/folder", f = "item", S = "processor", qt = "npm-registry", C = "hidden", Q = "FILE", Z = "TOOL", ee = "APP";
|
|
2339
2330
|
var a, ce, u, $, V, H, he, ue, De;
|
|
2340
2331
|
const me = class me {
|
|
2341
2332
|
/**
|
|
@@ -2884,7 +2875,7 @@ return main;`)(...h), d = (y == null ? void 0 : y.componentDefinition) ?? y;
|
|
|
2884
2875
|
* @returns The registry, scope, read-only token, and assembled `.npmrc`.
|
|
2885
2876
|
*/
|
|
2886
2877
|
async getNpmCredentials() {
|
|
2887
|
-
return await c(this, a, u).call(this, "GET", `${
|
|
2878
|
+
return await c(this, a, u).call(this, "GET", `${qt}/credentials`);
|
|
2888
2879
|
}
|
|
2889
2880
|
// ─── Execution ───────────────────────────────────────────────────
|
|
2890
2881
|
/**
|
|
@@ -3198,7 +3189,7 @@ a = new WeakSet(), ce = function(e) {
|
|
|
3198
3189
|
);
|
|
3199
3190
|
if (!A.ok) {
|
|
3200
3191
|
const O = await A.text().then((Fe) => Fe).catch(() => "");
|
|
3201
|
-
throw new
|
|
3192
|
+
throw new It(
|
|
3202
3193
|
A.status,
|
|
3203
3194
|
A.statusText,
|
|
3204
3195
|
O
|
|
@@ -3360,21 +3351,21 @@ const ge = class ge extends ae {
|
|
|
3360
3351
|
};
|
|
3361
3352
|
B = new WeakMap();
|
|
3362
3353
|
let Ae = ge;
|
|
3363
|
-
const
|
|
3354
|
+
const Ft = {
|
|
3364
3355
|
MAX_FIELDS: 200,
|
|
3365
3356
|
MAX_KEY_LENGTH: 50,
|
|
3366
3357
|
MAX_VALUE_LENGTH: 50
|
|
3367
|
-
},
|
|
3358
|
+
}, Mt = { uuid: "a3f82c1d-5b74-4e9a-bc30-d7e12f894a61" }, Vt = { uuid: "2c9f4e8d-3a1b-4c5e-9d7f-0a2b6c8e1d3f" }, Ht = { uuid: "b0b5e2a2-0b3a-4a6b-8b1c-0b1c4a6b8b1c" }, Gt = { uuid: "3f9c1a7e-6b2d-4e18-9a5c-7d0e2f4b6c81" }, Jt = { uuid: "2c4ae432-fc24-43e9-9783-0c960c674e96" }, jt = { uuid: "69af63aa-19ba-4fc7-b17b-75647bac1d76" }, Yt = { uuid: "234f1416-528d-452a-9cc9-a16c5239b2eb" };
|
|
3368
3359
|
export {
|
|
3369
|
-
|
|
3370
|
-
|
|
3360
|
+
Mt as CDEManager,
|
|
3361
|
+
Vt as ClashesManager,
|
|
3371
3362
|
ae as EngineServicesClient,
|
|
3372
|
-
|
|
3373
|
-
|
|
3363
|
+
Ht as FileList,
|
|
3364
|
+
Gt as GitHistoryManager,
|
|
3374
3365
|
Jt as HelloWorld,
|
|
3375
|
-
|
|
3366
|
+
Ft as METADATA_LIMITS,
|
|
3376
3367
|
Ae as PlatformClient,
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3368
|
+
It as RequestError,
|
|
3369
|
+
jt as TopicsManager,
|
|
3370
|
+
Yt as UIManager
|
|
3380
3371
|
};
|
package/dist/vite-env.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
/// <reference types="vite/client" />
|
|
1
|
+
/// <reference types="vite/client" />
|
package/docs/ai-quickstart.md
CHANGED
|
@@ -12,7 +12,7 @@ on the [That Open Platform](https://platform.thatopen.com) from scratch, using
|
|
|
12
12
|
> **Not building anything — here to work in Revit?** If what the user actually wants is to share a
|
|
13
13
|
> Revit model with their team, join one a colleague uploaded, or review a change some other tool
|
|
14
14
|
> proposed to their model, this is the wrong guide and nothing below applies. Go to
|
|
15
|
-
> **[the Revit collaboration quickstart](
|
|
15
|
+
> **[the Revit collaboration quickstart](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/revit-collab-quickstart.md)** and follow that instead.
|
|
16
16
|
> It is the same shape as this one: ask first, then drive the CLI.
|
|
17
17
|
>
|
|
18
18
|
> Phrases that mean that guide, not this one: *"I want to collaborate on a Revit project"*, *"share
|
|
@@ -21,8 +21,8 @@ on the [That Open Platform](https://platform.thatopen.com) from scratch, using
|
|
|
21
21
|
|
|
22
22
|
> **Making another application talk to this one?** If the user wants their own tool — Rhino, Blender,
|
|
23
23
|
> a script, an in-house app — to send changes into somebody's model or to show a model it did not
|
|
24
|
-
> author, that is a third thing again: **[Writing a flow plugin](
|
|
25
|
-
> byte contract, and **[the architecture notes](
|
|
24
|
+
> author, that is a third thing again: **[Writing a flow plugin](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/flow-plugin-guide.md)** is the
|
|
25
|
+
> byte contract, and **[the architecture notes](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/flow-architecture.md)** say why it is shaped that
|
|
26
26
|
> way. Start at its section 0, which sorts the work into three sizes; most integrations are the
|
|
27
27
|
> smallest one and need no ownership, no history and no collaboration layer.
|
|
28
28
|
>
|
|
@@ -69,6 +69,11 @@ Get the token from the platform dashboard — **https://platform.thatopen.com/da
|
|
|
69
69
|
thatopen login --token <platform-token>
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
**[Logging in to That Open Platform](https://raw.githubusercontent.com/ThatOpen/platform_services/main/docs/platform-token.md)** is the short version of everything that
|
|
73
|
+
goes wrong here: production and dev are separate worlds, `login` does not say which one it saved,
|
|
74
|
+
and a machine that is already logged in is somebody's previous session rather than a decision. Read
|
|
75
|
+
it if the user is not on a fresh machine, or if anything comes back `Unauthorized` or `403`.
|
|
76
|
+
|
|
72
77
|
This validates the token and stores it in `~/.thatopen/config.json`. Login **must** come
|
|
73
78
|
first: the next step's install pulls the private `@thatopen-platform/*-beta` packages, and
|
|
74
79
|
`create` uses your logged-in token to write an authenticated `.npmrc` so that install can
|
|
@@ -82,6 +87,16 @@ thatopen create my-app --beta
|
|
|
82
87
|
cd my-app
|
|
83
88
|
```
|
|
84
89
|
|
|
90
|
+
**[app, showing a Revit model's commit history]** If what they asked for is a viewer of the
|
|
91
|
+
revit-flow history, scaffold it directly. Do not build it by hand: the wiring is four additions in
|
|
92
|
+
three places and the ORDER of them is load-bearing (see the boot order section below). This ships
|
|
93
|
+
it already correct, opening on the History layout.
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
thatopen create my-app --beta --history
|
|
97
|
+
cd my-app
|
|
98
|
+
```
|
|
99
|
+
|
|
85
100
|
**[component]**
|
|
86
101
|
```bash
|
|
87
102
|
thatopen create my-component -t cloud-component --beta
|
|
@@ -105,12 +120,128 @@ npm run dev
|
|
|
105
120
|
Serves the app and opens it inside the platform. **You now have a complete, working viewer** —
|
|
106
121
|
model loading, spatial tree, properties, measurement, sectioning, and more.
|
|
107
122
|
|
|
123
|
+
If it does not open by itself, or the user closes the tab, the app you are serving from this
|
|
124
|
+
machine lives at:
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
https://platform.thatopen.com/dashboard/projects/<PROJECT_ID>/apps/local-app
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Substitute the project id. That is the local app running inside the platform's own UI, against
|
|
131
|
+
the project's real data. Send the user there rather than to a bare localhost port, which is the
|
|
132
|
+
app without the platform around it.
|
|
133
|
+
|
|
134
|
+
> **`npx tsc --noEmit` reports errors in a fresh beta scaffold, and they are not real.** You will see
|
|
135
|
+
> a handful of `Cannot find module '@thatopen/components'` and friends. A beta project aliases those
|
|
136
|
+
> imports to the `@thatopen-platform/*-beta` packages in `vite.config.js`, which bare `tsc` does not
|
|
137
|
+
> read — so it is looking for packages this project deliberately does not install.
|
|
138
|
+
>
|
|
139
|
+
> **In this project, `tsc` is not a signal.** Do not try to fix those errors, do not report them as
|
|
140
|
+
> problems you found, and do not use a clean `tsc` as your definition of done. `npm run dev` and
|
|
141
|
+
> `npm run build` are the ones that tell you anything; to check that something you added really
|
|
142
|
+
> shipped, grep the built bundle for it.
|
|
143
|
+
|
|
108
144
|
**[component]**
|
|
109
145
|
```bash
|
|
110
146
|
npm run run # executes the component locally against the platform (no browser)
|
|
111
147
|
```
|
|
112
148
|
Runs `main()` in a local emulation of the cloud engine so you can iterate before publishing.
|
|
113
149
|
|
|
150
|
+
## THE BOOT ORDER. Read this before you write a line of an app.
|
|
151
|
+
|
|
152
|
+
**This is where apps break, and the error never names the real cause.** An app boots in four
|
|
153
|
+
stages, and a built-in that touches models or the 3D scene must be initialised in the LAST one.
|
|
154
|
+
Call it where it reads naturally, right after `client.setup`, and you get:
|
|
155
|
+
|
|
156
|
+
```
|
|
157
|
+
Error: FragmentsManager not initialized. Call init() first.
|
|
158
|
+
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'onHighlight')
|
|
159
|
+
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'onClear')
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
None of which says "you called this too early". The app renders, the panel mounts, and it sits
|
|
163
|
+
there inert.
|
|
164
|
+
|
|
165
|
+
**Why.** `FragmentsManager` is initialised inside `top-app`'s own `setup` callback, and the 3D
|
|
166
|
+
world does not exist until `<top-app>` has been added to the DOM and `top-viewer` has built it.
|
|
167
|
+
Both of those happen well after `client.setup` returns. Any manager that reads model files or
|
|
168
|
+
colours elements reaches for them the moment it starts.
|
|
169
|
+
|
|
170
|
+
**The order, and it is not negotiable:**
|
|
171
|
+
|
|
172
|
+
1. `client.setup(...)` with every built-in you need, then `components.get(UIManager).init()`
|
|
173
|
+
2. `app.setup = ...`, which is where `FragmentsManager.init` goes, and append `<top-app>`
|
|
174
|
+
3. `await firstWorld(...)`, so the world exists
|
|
175
|
+
4. **only now**, `init(client)` on the model-facing managers
|
|
176
|
+
|
|
177
|
+
Copy this skeleton. It is the boot of an app that works.
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
async function main() {
|
|
181
|
+
const client = PlatformClient.fromPlatformContext();
|
|
182
|
+
|
|
183
|
+
// 1 ── built-ins registered, UI shell up
|
|
184
|
+
const { components } = await client.setup<OBC.Components>(
|
|
185
|
+
{ OBC, OBF, BUI, THREE, FRAGS, MARKERJS },
|
|
186
|
+
{ uuid: UIManager.uuid },
|
|
187
|
+
{ uuid: GitHistoryManager.uuid }, // and any other built-in you use
|
|
188
|
+
);
|
|
189
|
+
components.get(UIManager).init();
|
|
190
|
+
|
|
191
|
+
const viewerEl = document.createElement("top-viewer");
|
|
192
|
+
const app = document.createElement("top-app") as any;
|
|
193
|
+
|
|
194
|
+
// 2 ── this callback is what initialises FragmentsManager. Nothing that needs
|
|
195
|
+
// fragments may run before it has resolved.
|
|
196
|
+
app.setup = (waitUntil: (p: Promise<void>, label?: string) => void) => {
|
|
197
|
+
waitUntil(
|
|
198
|
+
(async () => {
|
|
199
|
+
const fragments = components.get(OBC.FragmentsManager);
|
|
200
|
+
const workerUrl = await FRAGS.FragmentsModels.getWorker();
|
|
201
|
+
fragments.init(await FRAGS.toClassicWorker(workerUrl), { classicWorker: true });
|
|
202
|
+
})(),
|
|
203
|
+
"Fragments Core",
|
|
204
|
+
);
|
|
205
|
+
return { components, client };
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
app.elements = { viewer: () => BUI.html`${viewerEl}` };
|
|
209
|
+
app.layouts = { Main: { template: `"viewer" 1fr / 1fr` } };
|
|
210
|
+
app.layout = "Main";
|
|
211
|
+
(document.getElementById("that-open-app") ?? document.body).appendChild(app);
|
|
212
|
+
|
|
213
|
+
// 3 ── the world is created asynchronously by top-viewer. Wait for it.
|
|
214
|
+
await firstWorld(components.get(OBC.Worlds));
|
|
215
|
+
|
|
216
|
+
// 4 ── ONLY NOW. Everything above had to have happened first.
|
|
217
|
+
await components.get(GitHistoryManager).init(client);
|
|
218
|
+
|
|
219
|
+
// ...and from here, the real layouts, panels and elements.
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/** Resolves with the first world once it exists (top-viewer creates it async). */
|
|
223
|
+
function firstWorld(worlds: any): Promise<any> {
|
|
224
|
+
const existing = [...worlds.list.values()][0];
|
|
225
|
+
if (existing) return Promise.resolve(existing);
|
|
226
|
+
return new Promise((resolve) => {
|
|
227
|
+
const handler = ({ value }: any) => {
|
|
228
|
+
worlds.list.onItemSet.remove(handler);
|
|
229
|
+
resolve(value);
|
|
230
|
+
};
|
|
231
|
+
worlds.list.onItemSet.add(handler);
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**Two more traps in the same family:**
|
|
237
|
+
|
|
238
|
+
- **One stable `top-viewer` node, held in a variable and returned by reference** from every
|
|
239
|
+
`elements.viewer()` call. Creating a fresh element on each render disposes the world and
|
|
240
|
+
builds another one, and everything wired to the old one goes quiet.
|
|
241
|
+
- **Registering a built-in is not the same as initialising it.** `client.setup` makes
|
|
242
|
+
`<top-git-history>` resolvable; `init(client)` is what fills it. A panel that mounts and stays
|
|
243
|
+
empty is usually the second one missing, not the first.
|
|
244
|
+
|
|
114
245
|
## 5. Then build — read the in-project agent guide
|
|
115
246
|
|
|
116
247
|
The scaffold is real, working code — a complete viewer **[app]** or a runnable `main()`
|
|
@@ -148,5 +279,8 @@ component, once added to a project, is then triggered by an app or an automation
|
|
|
148
279
|
- **Platform token only.** Never introduce, request, or store an npm token.
|
|
149
280
|
- **Never echo or persist the user's token.** It belongs only in `~/.thatopen/config.json` /
|
|
150
281
|
`.npmrc`, both of which the CLI manages and git-ignores.
|
|
151
|
-
- **
|
|
282
|
+
- **Do the thing they asked for.** If the request already says what to build, build it. Proposing a
|
|
283
|
+
four-point plan and waiting for approval to do what was just requested costs the user a whole turn
|
|
284
|
+
and buys nothing. Stop and ask only when you are about to change files you did not create, when
|
|
285
|
+
the request can be read two ways that mean different work, or when the next step is destructive.
|
|
152
286
|
- The scaffold already works — **extend it, don't replace it.**
|
package/docs/cli/create.md
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
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 (handled automatically once you `thatopen login`).
|
|
21
|
-
|
|
22
|
-
> **`--beta` is currently required.** The templates depend on engine APIs that only exist in the beta libraries, so scaffolding without `--beta` errors out for now. Public (non-beta) support is coming with the October release.
|
|
23
|
-
|
|
24
|
-
**Examples:**
|
|
25
|
-
```bash
|
|
26
|
-
thatopen create my-app --beta
|
|
27
|
-
thatopen create my-app -t cloud-component --beta
|
|
28
|
-
thatopen create . --beta
|
|
29
|
-
```
|
|
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 (handled automatically once you `thatopen login`).
|
|
21
|
+
|
|
22
|
+
> **`--beta` is currently required.** The templates depend on engine APIs that only exist in the beta libraries, so scaffolding without `--beta` errors out for now. Public (non-beta) support is coming with the October release.
|
|
23
|
+
|
|
24
|
+
**Examples:**
|
|
25
|
+
```bash
|
|
26
|
+
thatopen create my-app --beta
|
|
27
|
+
thatopen create my-app -t cloud-component --beta
|
|
28
|
+
thatopen create . --beta
|
|
29
|
+
```
|
package/docs/cli/local-server.md
CHANGED
|
@@ -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://platform.thatopen.com](https://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://platform.thatopen.com` (production). Pass `https://dev.platform.thatopen.com` to target the dev environment.
|
|
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://platform.thatopen.com](https://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://platform.thatopen.com` (production). Pass `https://dev.platform.thatopen.com` to target the dev environment.
|
|
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
|
+
```
|