@ifc-lite/viewer 1.29.0 → 1.30.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 (80) hide show
  1. package/.turbo/turbo-build.log +32 -31
  2. package/CHANGELOG.md +58 -0
  3. package/dist/assets/{basketViewActivator-BSRgF1Hw.js → basketViewActivator-BHNb23Vw.js} +6 -6
  4. package/dist/assets/{bcf-3uE1MvcT.js → bcf-C0XZ2DSl.js} +1 -1
  5. package/dist/assets/{deflate-BLlUfw9-.js → deflate-DvvFcUtV.js} +1 -1
  6. package/dist/assets/{exporters-BL6UmxRa.js → exporters-CvORJOLn.js} +1345 -1434
  7. package/dist/assets/geometry.worker-B7X9DQQY.js +1 -0
  8. package/dist/assets/{geotiff-BydcIud8.js → geotiff-fSD_sVw_.js} +10 -10
  9. package/dist/assets/{ids-DFl74rTt.js → ids-BUOe5QQl.js} +951 -713
  10. package/dist/assets/idsValidation.worker-DEodXb0f.js +190468 -0
  11. package/dist/assets/ifc-lite_bg-CmMuB1zf.wasm +0 -0
  12. package/dist/assets/{index-BNTlm2lP.js → index-B6T42T86.js} +35235 -32937
  13. package/dist/assets/index-D0tqJL0X.css +1 -0
  14. package/dist/assets/{index.es-Bk4nLsyS.js → index.es-YGMensDM.js} +7 -7
  15. package/dist/assets/{jpeg-BvMO8-Tc.js → jpeg-0Sla88_N.js} +1 -1
  16. package/dist/assets/{jspdf.es.min-BZ_ed66E.js → jspdf.es.min-mnbLNj-p.js} +4 -4
  17. package/dist/assets/{lerc-CNnDpLpV.js → lerc-C7xUDHpL.js} +1 -1
  18. package/dist/assets/{lzw-DBaPrGGZ.js → lzw-CK480t0_.js} +1 -1
  19. package/dist/assets/{native-bridge-DFOoBvTg.js → native-bridge-sLWRanza.js} +1 -1
  20. package/dist/assets/{packbits-C7uyD2Bi.js → packbits-DcL4imYS.js} +1 -1
  21. package/dist/assets/parser.worker-BsGV6ml7.js +182 -0
  22. package/dist/assets/{pdf-DlqdjX9e.js → pdf-BARGfLmx.js} +8 -8
  23. package/dist/assets/raw-BMWh6mDy.js +1 -0
  24. package/dist/assets/{sandbox-0Z2NzeOJ.js → sandbox-BSiO04m8.js} +2801 -2609
  25. package/dist/assets/server-client-AlpWMVq9.js +741 -0
  26. package/dist/assets/{webimage-zN-oCabb.js → webimage-uy5DjZLk.js} +1 -1
  27. package/dist/assets/{xlsx-N2LbIR1G.js → xlsx-D02ho69_.js} +6 -6
  28. package/dist/assets/{zstd-Jk3QKIeb.js → zstd-DcR1TBwT.js} +1 -1
  29. package/dist/index.html +7 -7
  30. package/package.json +27 -32
  31. package/src/components/viewer/CesiumOverlay.tsx +195 -8
  32. package/src/components/viewer/IDSPanel.tsx +23 -7
  33. package/src/components/viewer/MainToolbar.tsx +31 -0
  34. package/src/components/viewer/SunSkyPanel.tsx +363 -0
  35. package/src/components/viewer/Viewport.tsx +49 -1
  36. package/src/components/viewer/ViewportContainer.tsx +20 -1
  37. package/src/components/viewer/useAnimationLoop.ts +19 -1
  38. package/src/disable-react-dev-perf-track.ts +38 -0
  39. package/src/hooks/has-entity-type.ts +33 -0
  40. package/src/hooks/ids/idsWorkerClient.ts +136 -0
  41. package/src/hooks/ingest/federationAlign.ts +1 -1
  42. package/src/hooks/ingest/pointCloudIngest.ts +22 -98
  43. package/src/hooks/ingest/viewerModelIngest.ts +8 -13
  44. package/src/hooks/useAlignmentLines3D.ts +5 -0
  45. package/src/hooks/useGridLines3D.ts +4 -0
  46. package/src/hooks/useIDS.ts +77 -13
  47. package/src/hooks/useIfcCache.ts +1 -1
  48. package/src/hooks/useIfcFederation.ts +1 -1
  49. package/src/hooks/useIfcServer.ts +1 -1
  50. package/src/hooks/useModelSelection.ts +1 -1
  51. package/src/hooks/useSolarEnvironment.ts +114 -0
  52. package/src/hooks/useSolarSweep.ts +66 -0
  53. package/src/hooks/useSymbolicAnnotations.ts +10 -0
  54. package/src/hooks/useViewerSelectors.ts +1 -1
  55. package/src/lib/geo/cesium-sun.ts +277 -0
  56. package/src/lib/geo/solar-direction.test.ts +70 -0
  57. package/src/lib/geo/solar-direction.ts +94 -0
  58. package/src/lib/lighting-presets.ts +128 -0
  59. package/src/lib/recent-files.ts +4 -24
  60. package/src/lib/solar-time.ts +55 -0
  61. package/src/main.tsx +5 -0
  62. package/src/store/index.ts +8 -0
  63. package/src/store/slices/annotationsSlice.test.ts +0 -16
  64. package/src/store/slices/cesiumSlice.ts +3 -3
  65. package/src/store/slices/dataSlice.test.ts +0 -40
  66. package/src/store/slices/environmentSlice.ts +101 -0
  67. package/src/store/slices/idsSlice.ts +6 -1
  68. package/src/store/slices/selectionSlice.test.ts +0 -43
  69. package/src/store/slices/solarSlice.ts +121 -0
  70. package/src/store/slices/visibilitySlice.test.ts +15 -45
  71. package/src/utils/loadingUtils.ts +1 -1
  72. package/src/workers/idsValidation.worker.ts +98 -0
  73. package/dist/assets/geometry.worker-DVwFYHTq.js +0 -1
  74. package/dist/assets/ifc-lite_bg-FPffpFK_.wasm +0 -0
  75. package/dist/assets/index-DpoJvkdg.css +0 -1
  76. package/dist/assets/parser.worker-U_PVhLNi.js +0 -182
  77. package/dist/assets/raw-p_2cfl6T.js +0 -1
  78. package/dist/assets/server-client-DUMy2mXg.js +0 -719
  79. package/src/components/ui/context-menu.tsx +0 -174
  80. package/src/store.ts +0 -80
@@ -0,0 +1,741 @@
1
+ import { _ as we, __tla as __tla_0 } from "./sandbox-BSiO04m8.js";
2
+ let tt, rt;
3
+ let __tla = Promise.all([
4
+ (()=>{
5
+ try {
6
+ return __tla_0;
7
+ } catch {}
8
+ })()
9
+ ]).then(async ()=>{
10
+ let Pe = !1, be = null;
11
+ async function Se() {
12
+ if (Pe && be) return be;
13
+ console.log("[parquet-decoder] Starting WASM initialization...");
14
+ let s;
15
+ try {
16
+ if (s = await we(()=>import("./parquet-CEXmQNRO.js").then((e)=>e.a), []), console.log("[parquet-decoder] Imported ESM build"), typeof s.default == "function") {
17
+ console.log("[parquet-decoder] Calling ESM init to load WASM...");
18
+ const o = (await we(()=>import("./parquet-CEXmQNRO.js").then((r)=>r.b), [])).default;
19
+ console.log("[parquet-decoder] Loading WASM from:", o), await s.default(o), console.log("[parquet-decoder] ESM WASM initialized");
20
+ }
21
+ if (typeof s.readParquet == "function") return be = s, Pe = !0, console.log("[parquet-decoder] ESM build ready with readParquet"), s;
22
+ console.warn("[parquet-decoder] ESM build initialized but readParquet not found");
23
+ } catch (e) {
24
+ console.warn("[parquet-decoder] ESM import failed:", e);
25
+ }
26
+ try {
27
+ if (s = await we(()=>import("./parquet-CEXmQNRO.js").then((e)=>e.a), []), typeof s.default == "function") {
28
+ console.log("[parquet-decoder] Trying web init with node_modules path...");
29
+ const e = [
30
+ "/node_modules/parquet-wasm/esm/arrow2_bg.wasm",
31
+ "./node_modules/parquet-wasm/esm/arrow2_bg.wasm"
32
+ ];
33
+ for (const o of e)try {
34
+ const r = await fetch(o);
35
+ if (r.ok && (console.log("[parquet-decoder] Found WASM at:", o), await s.default(r), typeof s.readParquet == "function")) return be = s, Pe = !0, console.log("[parquet-decoder] Web init successful"), s;
36
+ } catch {}
37
+ }
38
+ } catch (e) {
39
+ console.warn("[parquet-decoder] Web init failed:", e);
40
+ }
41
+ throw new Error("parquet-wasm: Could not load WASM module. Ensure parquet-wasm is installed and WASM files are accessible.");
42
+ }
43
+ async function De(s) {
44
+ const e = await Se(), o = new DataView(s);
45
+ let r = 0;
46
+ const a = o.getUint32(r, !0);
47
+ r += 4;
48
+ const t = new Uint8Array(s, r, a);
49
+ r += a;
50
+ const i = o.getUint32(r, !0);
51
+ r += 4;
52
+ const h = new Uint8Array(s, r, i);
53
+ r += i;
54
+ const c = o.getUint32(r, !0);
55
+ r += 4;
56
+ const l = new Uint8Array(s, r, c), q = e.readParquet(t), g = e.readParquet(h), P = e.readParquet(l), p = await we(()=>import("./arrow-fie-E7fe.js").then((A)=>A.A), []), d = p.tableFromIPC(q.intoIPCStream()), w = p.tableFromIPC(g.intoIPCStream()), E = p.tableFromIPC(P.intoIPCStream()), D = d.getChild("express_id")?.toArray(), L = d.getChild("ifc_type"), V = d.getChild("vertex_start")?.toArray(), B = d.getChild("vertex_count")?.toArray(), W = d.getChild("index_start")?.toArray(), x = d.getChild("index_count")?.toArray(), U = d.getChild("color_r")?.toArray(), f = d.getChild("color_g")?.toArray(), I = d.getChild("color_b")?.toArray(), $ = d.getChild("color_a")?.toArray(), v = w.getChild("x")?.toArray(), Q = w.getChild("y")?.toArray(), _ = w.getChild("z")?.toArray(), Y = w.getChild("nx")?.toArray(), ne = w.getChild("ny")?.toArray(), Z = w.getChild("nz")?.toArray(), F = E.getChild("i0")?.toArray(), j = E.getChild("i1")?.toArray(), ee = E.getChild("i2")?.toArray();
57
+ if (!v || !Q || !_ || !Y || !ne || !Z || !F || !j || !ee) throw new Error("Malformed Parquet geometry: missing required vertex/index column");
58
+ if (v.length !== Q.length || v.length !== _.length || Y.length !== ne.length || Y.length !== Z.length || F.length !== j.length || F.length !== ee.length) throw new Error("Malformed Parquet geometry: inconsistent parallel column lengths");
59
+ const K = D.length, G = new Array(K);
60
+ for(let A = 0; A < K; A++){
61
+ const k = V[A], z = B[A], C = W[A], X = x[A];
62
+ if (k + z > v.length || k + z > Y.length || C % 3 !== 0 || X % 3 !== 0 || (C + X) / 3 > F.length) throw new Error(`Malformed Parquet geometry: mesh ${A} range out of bounds (vertexStart=${k}, vertexCount=${z}, vertices=${v.length}; indexStart=${C}, indexCount=${X}, triangles=${F.length})`);
63
+ const te = new Float32Array(z * 3);
64
+ for(let m = 0; m < z; m++){
65
+ const T = k + m;
66
+ te[m * 3] = v[T], te[m * 3 + 1] = Q[T], te[m * 3 + 2] = _[T];
67
+ }
68
+ const O = new Float32Array(z * 3);
69
+ for(let m = 0; m < z; m++){
70
+ const T = k + m;
71
+ O[m * 3] = Y[T], O[m * 3 + 1] = ne[T], O[m * 3 + 2] = Z[T];
72
+ }
73
+ const le = X / 3, de = C / 3, J = new Uint32Array(X);
74
+ for(let m = 0; m < le; m++){
75
+ const T = de + m;
76
+ J[m * 3] = F[T], J[m * 3 + 1] = j[T], J[m * 3 + 2] = ee[T];
77
+ }
78
+ G[A] = {
79
+ express_id: D[A],
80
+ ifc_type: L?.get(A) ?? "Unknown",
81
+ positions: te,
82
+ normals: O,
83
+ indices: J,
84
+ color: [
85
+ U[A],
86
+ f[A],
87
+ I[A],
88
+ $[A]
89
+ ]
90
+ };
91
+ }
92
+ return G;
93
+ }
94
+ async function Ce() {
95
+ try {
96
+ return await Se(), !0;
97
+ } catch (s) {
98
+ return console.warn("[parquet-decoder] Parquet WASM initialization failed:", s), !1;
99
+ }
100
+ }
101
+ async function Ze(s, e = 1e4) {
102
+ const o = await Se(), r = await we(()=>import("./arrow-fie-E7fe.js").then((N)=>N.A), []), a = new DataView(s);
103
+ let t = 0;
104
+ const i = a.getUint8(t);
105
+ if (t += 1, i !== 2) throw new Error(`Unsupported optimized Parquet version: ${i}`);
106
+ const h = a.getUint8(t);
107
+ t += 1;
108
+ const c = (h & 1) !== 0, l = a.getUint32(t, !0);
109
+ t += 4;
110
+ const q = a.getUint32(t, !0);
111
+ t += 4;
112
+ const g = a.getUint32(t, !0);
113
+ t += 4;
114
+ const P = a.getUint32(t, !0);
115
+ t += 4;
116
+ const p = a.getUint32(t, !0);
117
+ t += 4;
118
+ const d = new Uint8Array(s, t, l);
119
+ t += l;
120
+ const w = new Uint8Array(s, t, q);
121
+ t += q;
122
+ const E = new Uint8Array(s, t, g);
123
+ t += g;
124
+ const D = new Uint8Array(s, t, P);
125
+ t += P;
126
+ const L = new Uint8Array(s, t, p), V = o.readParquet(d), B = o.readParquet(w), W = o.readParquet(E), x = o.readParquet(D), U = o.readParquet(L), f = r.tableFromIPC(V.intoIPCStream()), I = r.tableFromIPC(B.intoIPCStream()), $ = r.tableFromIPC(W.intoIPCStream()), v = r.tableFromIPC(x.intoIPCStream()), Q = r.tableFromIPC(U.intoIPCStream()), _ = f.getChild("entity_id")?.toArray(), Y = f.getChild("ifc_type"), ne = f.getChild("mesh_index")?.toArray(), Z = f.getChild("material_index")?.toArray(), F = I.getChild("vertex_offset")?.toArray(), j = I.getChild("vertex_count")?.toArray(), ee = I.getChild("index_offset")?.toArray(), K = I.getChild("index_count")?.toArray(), G = $.getChild("r")?.toArray(), A = $.getChild("g")?.toArray(), k = $.getChild("b")?.toArray(), z = $.getChild("a")?.toArray(), C = v.getChild("x")?.toArray(), X = v.getChild("y")?.toArray(), te = v.getChild("z")?.toArray(), O = c ? v.getChild("nx")?.toArray() : null, le = c ? v.getChild("ny")?.toArray() : null, de = c ? v.getChild("nz")?.toArray() : null, J = Q.getChild("i")?.toArray();
127
+ if (!C || !X || !te || !J || !G || !A || !k || !z) throw new Error("Malformed optimized Parquet geometry: missing required column");
128
+ if (C.length !== X.length || C.length !== te.length || G.length !== A.length || G.length !== k.length || G.length !== z.length || c && (!O || !le || !de || O.length !== C.length || le.length !== C.length || de.length !== C.length)) throw new Error("Malformed optimized Parquet geometry: inconsistent parallel column lengths");
129
+ const m = _.length, T = new Array(m), ue = 1 / e;
130
+ for(let N = 0; N < m; N++){
131
+ const re = ne[N], R = Z[N];
132
+ if (re >= F.length || R >= G.length) throw new Error(`Malformed optimized Parquet geometry: instance ${N} references mesh ${re} (of ${F.length}) / material ${R} (of ${G.length})`);
133
+ const u = F[re], oe = j[re], pe = ee[re], he = K[re];
134
+ if (u + oe > C.length || O && u + oe > O.length || pe + he > J.length) throw new Error(`Malformed optimized Parquet geometry: instance ${N} range out of bounds (meshIdx=${re}, vertexOffset=${u}, vertexCount=${oe}, vertices=${C.length}; indexOffset=${pe}, indexCount=${he}, indices=${J.length})`);
135
+ const ye = new Float32Array(oe * 3);
136
+ for(let S = 0; S < oe; S++){
137
+ const se = u + S;
138
+ ye[S * 3] = C[se] * ue, ye[S * 3 + 1] = X[se] * ue, ye[S * 3 + 2] = te[se] * ue;
139
+ }
140
+ let ae;
141
+ if (c && O && le && de) {
142
+ ae = new Float32Array(oe * 3);
143
+ for(let S = 0; S < oe; S++){
144
+ const se = u + S;
145
+ ae[S * 3] = O[se], ae[S * 3 + 1] = le[se], ae[S * 3 + 2] = de[se];
146
+ }
147
+ } else ae = Ke(ye, J.slice(pe, pe + he));
148
+ const _e = new Uint32Array(he);
149
+ for(let S = 0; S < he; S++)_e[S] = J[pe + S];
150
+ T[N] = {
151
+ express_id: _[N],
152
+ ifc_type: Y?.get(N) ?? "Unknown",
153
+ positions: ye,
154
+ normals: ae,
155
+ indices: _e,
156
+ color: [
157
+ G[R] / 255,
158
+ A[R] / 255,
159
+ k[R] / 255,
160
+ z[R] / 255
161
+ ]
162
+ };
163
+ }
164
+ return T;
165
+ }
166
+ function Ke(s, e) {
167
+ const o = s.length / 3, r = new Float32Array(o * 3).fill(0), a = e.length / 3;
168
+ for(let t = 0; t < a; t++){
169
+ const i = e[t * 3], h = e[t * 3 + 1], c = e[t * 3 + 2], l = s[i * 3], q = s[i * 3 + 1], g = s[i * 3 + 2], P = s[h * 3], p = s[h * 3 + 1], d = s[h * 3 + 2], w = s[c * 3], E = s[c * 3 + 1], D = s[c * 3 + 2], L = P - l, V = p - q, B = d - g, W = w - l, x = E - q, U = D - g, f = V * U - B * x, I = B * W - L * U, $ = L * x - V * W;
170
+ r[i * 3] += f, r[i * 3 + 1] += I, r[i * 3 + 2] += $, r[h * 3] += f, r[h * 3 + 1] += I, r[h * 3 + 2] += $, r[c * 3] += f, r[c * 3 + 1] += I, r[c * 3 + 2] += $;
171
+ }
172
+ for(let t = 0; t < o; t++){
173
+ const i = r[t * 3], h = r[t * 3 + 1], c = r[t * 3 + 2], l = Math.sqrt(i * i + h * h + c * c);
174
+ l > 0 && (r[t * 3] /= l, r[t * 3 + 1] /= l, r[t * 3 + 2] /= l);
175
+ }
176
+ return r;
177
+ }
178
+ async function ve(s) {
179
+ const e = s instanceof File ? s.stream() : new Blob([
180
+ s
181
+ ]).stream(), o = new CompressionStream("gzip"), r = e.pipeThrough(o);
182
+ return new Response(r).blob();
183
+ }
184
+ async function Le(s) {
185
+ const e = s instanceof File ? await s.arrayBuffer() : s, o = await crypto.subtle.digest("SHA-256", e);
186
+ return Array.from(new Uint8Array(o)).map((r)=>r.toString(16).padStart(2, "0")).join("");
187
+ }
188
+ function fe(s) {
189
+ const e = new URLSearchParams;
190
+ s?.tessellationQuality && s.tessellationQuality !== "medium" && e.set("tessellation_quality", s.tessellationQuality);
191
+ const o = e.toString();
192
+ return o ? `?${o}` : "";
193
+ }
194
+ tt = class {
195
+ constructor(e){
196
+ this.baseUrl = e.baseUrl.replace(/\/$/, ""), this.timeout = e.timeout ?? 3e5, this.token = e.token;
197
+ }
198
+ authHeaders(e) {
199
+ return this.token ? {
200
+ Authorization: `Bearer ${this.token}`,
201
+ ...e
202
+ } : {
203
+ ...e ?? {}
204
+ };
205
+ }
206
+ async health() {
207
+ const e = await fetch(`${this.baseUrl}/api/v1/health`, {
208
+ signal: AbortSignal.timeout(this.timeout)
209
+ });
210
+ if (!e.ok) throw await this.handleError(e);
211
+ return e.json();
212
+ }
213
+ async parse(e, o) {
214
+ const r = await ve(e), a = e instanceof File ? e.name : "model.ifc", t = new FormData;
215
+ t.append("file", r, a);
216
+ const i = await fetch(`${this.baseUrl}/api/v1/parse${fe(o)}`, {
217
+ method: "POST",
218
+ headers: this.authHeaders(),
219
+ body: t,
220
+ signal: AbortSignal.timeout(this.timeout)
221
+ });
222
+ if (!i.ok) throw await this.handleError(i);
223
+ return i.json();
224
+ }
225
+ async parseParquet(e, o) {
226
+ if (!await Ce()) throw new Error("Parquet parsing requires parquet-wasm and apache-arrow. Install them with: npm install parquet-wasm apache-arrow");
227
+ const a = performance.now(), t = await Le(e), i = performance.now() - a;
228
+ console.log(`[client] Computed file hash in ${i.toFixed(0)}ms: ${t.substring(0, 16)}...`);
229
+ const h = performance.now(), c = await fetch(`${this.baseUrl}/api/v1/cache/check/${t}${fe(o)}`, {
230
+ method: "GET",
231
+ headers: this.authHeaders(),
232
+ signal: AbortSignal.timeout(5e3)
233
+ }), l = performance.now() - h;
234
+ return c.ok ? (console.log(`[client] Cache HIT (check: ${l.toFixed(0)}ms) - skipping upload`), this.fetchCachedGeometry(t, o)) : (console.log(`[client] Cache MISS (check: ${l.toFixed(0)}ms) - uploading file`), this.uploadAndProcessParquet(e, t, o));
235
+ }
236
+ async parseParquetStream(e, o, r) {
237
+ if (!await Ce()) throw new Error("Parquet streaming requires parquet-wasm and apache-arrow. Install them with: npm install parquet-wasm apache-arrow");
238
+ const t = e instanceof File ? e.size : e.byteLength, i = e instanceof File ? e.name : "model.ifc", h = performance.now(), c = await Le(e), l = performance.now() - h;
239
+ console.log(`[client] Stream: computed hash in ${l.toFixed(0)}ms: ${c.substring(0, 16)}...`);
240
+ const q = performance.now(), g = await fetch(`${this.baseUrl}/api/v1/cache/check/${c}`, {
241
+ method: "GET",
242
+ headers: this.authHeaders(),
243
+ signal: AbortSignal.timeout(5e3)
244
+ }), P = performance.now() - q;
245
+ if (g.ok) {
246
+ console.log(`[client] Stream: Cache HIT (check: ${P.toFixed(0)}ms) - fetching cached geometry`);
247
+ const f = await this.fetchCachedGeometry(c), I = performance.now();
248
+ o({
249
+ meshes: f.meshes,
250
+ batch_number: 1,
251
+ decode_time_ms: performance.now() - I
252
+ });
253
+ let $ = null;
254
+ try {
255
+ $ = await this.fetchSymbolic(f.cache_key);
256
+ } catch (v) {
257
+ console.warn("[client] Symbolic fetch failed on cache hit; continuing without symbols:", v);
258
+ }
259
+ return {
260
+ cache_key: f.cache_key,
261
+ total_meshes: f.meshes.length,
262
+ stats: f.stats,
263
+ metadata: f.metadata,
264
+ symbolic_data: $ ?? void 0
265
+ };
266
+ }
267
+ console.log(`[client] Stream: Cache MISS (check: ${P.toFixed(0)}ms) - starting stream for ${i} (${(t / 1024 / 1024).toFixed(1)}MB)`);
268
+ const p = new FormData;
269
+ p.append("file", e instanceof File ? e : new Blob([
270
+ e
271
+ ]), i);
272
+ const d = performance.now(), w = await fetch(`${this.baseUrl}/api/v1/parse/parquet-stream${fe(r)}`, {
273
+ method: "POST",
274
+ headers: this.authHeaders(),
275
+ body: p,
276
+ signal: AbortSignal.timeout(this.timeout)
277
+ });
278
+ if (!w.ok) throw await this.handleError(w);
279
+ if (!w.body) throw new Error("No response body for streaming");
280
+ const E = w.body.getReader(), D = new TextDecoder;
281
+ let L = "", V = "", B = 0, W = null, x = null, U;
282
+ for(;;){
283
+ const { done: f, value: I } = await E.read();
284
+ if (f) break;
285
+ L += D.decode(I, {
286
+ stream: !0
287
+ });
288
+ const $ = L.split(`
289
+ `);
290
+ L = $.pop() || "";
291
+ for (const v of $){
292
+ if (!v.startsWith("data:")) continue;
293
+ const Q = v.slice(5).trim();
294
+ if (Q) try {
295
+ const _ = JSON.parse(Q);
296
+ switch(_.type){
297
+ case "start":
298
+ V = _.cache_key, console.log(`[client] Stream started: ${_.total_estimate} entities, cache_key: ${V.substring(0, 16)}...`);
299
+ break;
300
+ case "progress":
301
+ break;
302
+ case "batch":
303
+ {
304
+ const ne = performance.now(), Z = atob(_.data), F = new Uint8Array(Z.length);
305
+ for(let K = 0; K < Z.length; K++)F[K] = Z.charCodeAt(K);
306
+ const j = await De(F.buffer), ee = performance.now() - ne;
307
+ B += j.length, console.log(`[client] Batch #${_.batch_number}: ${j.length} meshes, decode: ${ee.toFixed(0)}ms`), o({
308
+ meshes: j,
309
+ batch_number: _.batch_number,
310
+ decode_time_ms: ee
311
+ });
312
+ break;
313
+ }
314
+ case "complete":
315
+ W = _.stats, x = _.metadata, U = _.symbolic_data;
316
+ const Y = performance.now() - d;
317
+ console.log(`[client] Stream complete: ${B} meshes in ${Y.toFixed(0)}ms`);
318
+ break;
319
+ case "error":
320
+ throw new Error(`Stream error: ${_.message}`);
321
+ }
322
+ } catch (_) {
323
+ if (_ instanceof SyntaxError) console.warn("[client] Failed to parse SSE event:", Q);
324
+ else throw _;
325
+ }
326
+ }
327
+ }
328
+ if (!W || !x) throw new Error("Stream ended without complete event");
329
+ return {
330
+ cache_key: V,
331
+ total_meshes: B,
332
+ stats: W,
333
+ metadata: x,
334
+ symbolic_data: U
335
+ };
336
+ }
337
+ async fetchCachedGeometry(e, o) {
338
+ const r = performance.now(), a = await fetch(`${this.baseUrl}/api/v1/cache/geometry/${e}${fe(o)}`, {
339
+ method: "GET",
340
+ headers: this.authHeaders(),
341
+ signal: AbortSignal.timeout(this.timeout)
342
+ });
343
+ if (!a.ok) throw await this.handleError(a);
344
+ const t = performance.now() - r;
345
+ console.log(`[client] Fetched cached geometry in ${t.toFixed(0)}ms`);
346
+ const i = a.headers.get("X-IFC-Metadata");
347
+ if (!i) throw new Error("Missing X-IFC-Metadata header in cached geometry response");
348
+ const h = JSON.parse(i), c = await a.arrayBuffer(), l = c.byteLength;
349
+ return this.parseParquetResponse(c, h, l);
350
+ }
351
+ async uploadAndProcessParquet(e, o, r) {
352
+ const a = e instanceof File ? e.size : e.byteLength, t = e instanceof File ? e.name : "model.ifc", i = this.baseUrl.includes("localhost") || this.baseUrl.includes("127.0.0.1"), h = a > 50 * 1024 * 1024 || i;
353
+ let c;
354
+ if (h) console.log(`[client] Skipping compression (file: ${(a / 1024 / 1024).toFixed(1)}MB, localhost: ${i})`), c = e instanceof File ? e : new Blob([
355
+ e
356
+ ]);
357
+ else {
358
+ const D = performance.now();
359
+ c = await ve(e), console.log(`[client] Compressed in ${(performance.now() - D).toFixed(0)}ms: ${(a / 1024 / 1024).toFixed(1)}MB → ${(c.size / 1024 / 1024).toFixed(1)}MB`);
360
+ }
361
+ const l = new FormData;
362
+ l.append("file", c, t);
363
+ const q = performance.now(), g = await fetch(`${this.baseUrl}/api/v1/parse/parquet${fe(r)}`, {
364
+ method: "POST",
365
+ headers: this.authHeaders(),
366
+ body: l,
367
+ signal: AbortSignal.timeout(this.timeout)
368
+ }), P = performance.now() - q;
369
+ if (console.log(`[client] Upload and processing completed in ${P.toFixed(0)}ms`), !g.ok) throw await this.handleError(g);
370
+ const p = g.headers.get("X-IFC-Metadata");
371
+ if (!p) throw new Error("Missing X-IFC-Metadata header in Parquet response");
372
+ const d = JSON.parse(p);
373
+ d.cache_key.startsWith(o) || console.warn(`[client] Cache key mismatch: expected a key derived from ${o.substring(0, 16)}..., got ${d.cache_key.substring(0, 16)}...`);
374
+ const w = await g.arrayBuffer(), E = w.byteLength;
375
+ return this.parseParquetResponse(w, d, E);
376
+ }
377
+ async parseParquetResponse(e, o, r) {
378
+ const a = new DataView(e);
379
+ let t = 0;
380
+ const i = a.getUint32(0, !0), h = i > 0 && i < e.byteLength && i < e.byteLength - 4;
381
+ let c, l;
382
+ if (h) {
383
+ const p = i;
384
+ if (t += 4, p > e.byteLength || p === 0 || t + p > e.byteLength) throw new Error(`Invalid geometry length: ${p}, buffer size: ${e.byteLength}, offset: ${t}`);
385
+ if (c = e.slice(t, t + p), t += p, t + 4 <= e.byteLength) {
386
+ const d = a.getUint32(t, !0);
387
+ t += 4, d > 0 && t + d <= e.byteLength && (l = e.slice(t, t + d));
388
+ }
389
+ } else console.log("[client] Detected old format (no wrapper), using entire payload as geometry"), c = e, l = void 0;
390
+ const q = performance.now(), g = await De(c), P = performance.now() - q;
391
+ return {
392
+ cache_key: o.cache_key,
393
+ meshes: g,
394
+ mesh_coordinate_space: o.mesh_coordinate_space,
395
+ site_transform: o.site_transform,
396
+ building_transform: o.building_transform,
397
+ metadata: o.metadata,
398
+ stats: o.stats,
399
+ parquet_stats: {
400
+ payload_size: r,
401
+ decode_time_ms: Math.round(P)
402
+ },
403
+ data_model: l
404
+ };
405
+ }
406
+ async fetchDataModel(e, o = 10) {
407
+ let r = 100;
408
+ for(let a = 0; a < o; a++)try {
409
+ const t = await fetch(`${this.baseUrl}/api/v1/parse/data-model/${e}`, {
410
+ method: "GET",
411
+ signal: AbortSignal.timeout(3e4)
412
+ });
413
+ if (t.status === 200) {
414
+ const i = await t.arrayBuffer();
415
+ return console.log(`[client] Data model fetched: ${(i.byteLength / 1024 / 1024).toFixed(2)}MB`), i;
416
+ } else if (t.status === 202) console.log(`[client] Data model still processing (attempt ${a + 1}/${o}), waiting ${r}ms...`), await new Promise((i)=>setTimeout(i, r)), r = Math.min(r * 1.5, 2e3);
417
+ else {
418
+ if (t.status === 404) return console.warn(`[client] Data model not found for cache key: ${e}`), null;
419
+ throw new Error(`Unexpected response status: ${t.status}`);
420
+ }
421
+ } catch (t) {
422
+ if (a === o - 1) return console.error("[client] Failed to fetch data model:", t), null;
423
+ await new Promise((i)=>setTimeout(i, r)), r = Math.min(r * 1.5, 2e3);
424
+ }
425
+ return console.warn("[client] Data model fetch timed out after max retries"), null;
426
+ }
427
+ async fetchSymbolic(e, o = 10) {
428
+ let r = 100;
429
+ for(let a = 0; a < o; a++){
430
+ let t;
431
+ try {
432
+ t = await fetch(`${this.baseUrl}/api/v1/parse/symbolic/${e}`, {
433
+ method: "GET",
434
+ signal: AbortSignal.timeout(3e4)
435
+ });
436
+ } catch (i) {
437
+ if (a === o - 1) throw i;
438
+ console.warn("[client] Retrying symbolic data fetch after network error:", i), await new Promise((h)=>setTimeout(h, r)), r = Math.min(r * 1.5, 2e3);
439
+ continue;
440
+ }
441
+ if (t.status === 200) return await t.json();
442
+ if (t.status === 202) await new Promise((i)=>setTimeout(i, r)), r = Math.min(r * 1.5, 2e3);
443
+ else {
444
+ if (t.status === 404) return console.warn(`[client] Symbolic data not found for cache key: ${e}`), null;
445
+ throw await this.handleError(t);
446
+ }
447
+ }
448
+ return console.warn("[client] Symbolic data fetch timed out after max retries"), null;
449
+ }
450
+ async isParquetSupported() {
451
+ return Ce();
452
+ }
453
+ async parseParquetOptimized(e, o) {
454
+ if (!await Ce()) throw new Error("Parquet parsing requires parquet-wasm and apache-arrow. Install them with: npm install parquet-wasm apache-arrow");
455
+ const a = await ve(e), t = e instanceof File ? e.name : "model.ifc", i = new FormData;
456
+ i.append("file", a, t);
457
+ const h = await fetch(`${this.baseUrl}/api/v1/parse/parquet/optimized${fe(o)}`, {
458
+ method: "POST",
459
+ headers: this.authHeaders(),
460
+ body: i,
461
+ signal: AbortSignal.timeout(this.timeout)
462
+ });
463
+ if (!h.ok) throw await this.handleError(h);
464
+ const c = h.headers.get("X-IFC-Metadata");
465
+ if (!c) throw new Error("Missing X-IFC-Metadata header in optimized Parquet response");
466
+ const l = JSON.parse(c), q = await h.arrayBuffer(), g = q.byteLength, P = performance.now(), p = await Ze(q, l.vertex_multiplier), d = performance.now() - P;
467
+ return {
468
+ cache_key: l.cache_key,
469
+ meshes: p,
470
+ mesh_coordinate_space: l.mesh_coordinate_space,
471
+ site_transform: l.site_transform,
472
+ building_transform: l.building_transform,
473
+ metadata: l.metadata,
474
+ stats: l.stats,
475
+ optimization_stats: l.optimization_stats,
476
+ parquet_stats: {
477
+ payload_size: g,
478
+ decode_time_ms: Math.round(d)
479
+ }
480
+ };
481
+ }
482
+ async *parseStream(e, o) {
483
+ const r = new FormData, a = e instanceof File ? e : new Blob([
484
+ e
485
+ ], {
486
+ type: "application/octet-stream"
487
+ });
488
+ r.append("file", a, e instanceof File ? e.name : "model.ifc");
489
+ const t = await fetch(`${this.baseUrl}/api/v1/parse/stream${fe(o)}`, {
490
+ method: "POST",
491
+ body: r,
492
+ headers: this.authHeaders({
493
+ Accept: "text/event-stream"
494
+ }),
495
+ signal: AbortSignal.timeout(this.timeout)
496
+ });
497
+ if (!t.ok) throw await this.handleError(t);
498
+ if (!t.body) throw new Error("Response body is null");
499
+ const i = t.body.getReader(), h = new TextDecoder;
500
+ let c = "";
501
+ try {
502
+ for(;;){
503
+ const { done: l, value: q } = await i.read();
504
+ if (l) break;
505
+ c += h.decode(q, {
506
+ stream: !0
507
+ });
508
+ const g = c.split(`
509
+
510
+ `);
511
+ c = g.pop() || "";
512
+ for (const P of g)if (P.startsWith("data: ")) try {
513
+ yield JSON.parse(P.slice(6));
514
+ } catch {}
515
+ }
516
+ if (c.startsWith("data: ")) try {
517
+ yield JSON.parse(c.slice(6));
518
+ } catch {}
519
+ } finally{
520
+ i.releaseLock();
521
+ }
522
+ }
523
+ async getMetadata(e) {
524
+ const o = new FormData;
525
+ o.append("file", e instanceof File ? e : new Blob([
526
+ e
527
+ ]), e instanceof File ? e.name : "model.ifc");
528
+ const r = await fetch(`${this.baseUrl}/api/v1/parse/metadata`, {
529
+ method: "POST",
530
+ headers: this.authHeaders(),
531
+ body: o,
532
+ signal: AbortSignal.timeout(3e4)
533
+ });
534
+ if (!r.ok) throw await this.handleError(r);
535
+ return r.json();
536
+ }
537
+ async getCached(e) {
538
+ const o = await fetch(`${this.baseUrl}/api/v1/cache/${e}`, {
539
+ signal: AbortSignal.timeout(this.timeout)
540
+ });
541
+ if (o.status === 404) return null;
542
+ if (!o.ok) throw await this.handleError(o);
543
+ return o.json();
544
+ }
545
+ async handleError(e) {
546
+ try {
547
+ const o = await e.json();
548
+ return new Error(`Server error (${o.code}): ${o.error}`);
549
+ } catch {
550
+ return new Error(`Server error: ${e.status} ${e.statusText}`);
551
+ }
552
+ }
553
+ };
554
+ rt = async function(s) {
555
+ const e = await Se(), o = await we(()=>import("./arrow-fie-E7fe.js").then((n)=>n.A), []), r = new DataView(s);
556
+ let a = 0;
557
+ const t = r.getUint32(a, !0);
558
+ a += 4;
559
+ const i = new Uint8Array(s, a, t);
560
+ a += t;
561
+ const h = r.getUint32(a, !0);
562
+ a += 4;
563
+ const c = new Uint8Array(s, a, h);
564
+ a += h;
565
+ const l = r.getUint32(a, !0);
566
+ a += 4;
567
+ const q = new Uint8Array(s, a, l);
568
+ a += l;
569
+ const g = r.getUint32(a, !0);
570
+ a += 4;
571
+ const P = new Uint8Array(s, a, g);
572
+ a += g;
573
+ const p = r.getUint32(a, !0);
574
+ a += 4;
575
+ const d = new Uint8Array(s, a, p);
576
+ a += p;
577
+ const w = ()=>{
578
+ if (a + 4 > s.byteLength) return null;
579
+ const n = r.getUint32(a, !0);
580
+ if (a += 4, n === 0 || a + n > s.byteLength) throw new Error(`Malformed data model: truncated appended section (len=${n}, remaining=${s.byteLength - a})`);
581
+ const y = new Uint8Array(s, a, n);
582
+ return a += n, y;
583
+ }, E = w(), D = w(), L = w(), V = e.readParquet(i), B = e.readParquet(c), W = e.readParquet(P), x = o.tableFromIPC(V.intoIPCStream()), U = o.tableFromIPC(B.intoIPCStream()), f = o.tableFromIPC(W.intoIPCStream()), I = x.getChild("entity_id")?.toArray(), $ = x.getChild("has_geometry")?.toArray(), v = x.getChild("type_name")?.toArray(), Q = x.getChild("global_id")?.toArray(), _ = x.getChild("name")?.toArray(), Y = x.getChild("description")?.toArray(), ne = x.getChild("object_type")?.toArray(), Z = I.length, F = new Map;
584
+ for(let n = 0; n < Z; n++)F.set(I[n], {
585
+ entity_id: I[n],
586
+ type_name: v[n] ?? "",
587
+ global_id: Q[n] || void 0,
588
+ name: _[n] || void 0,
589
+ description: Y?.[n] || void 0,
590
+ object_type: ne?.[n] || void 0,
591
+ has_geometry: $[n] !== 0
592
+ });
593
+ const j = U.getChild("pset_id")?.toArray(), ee = U.getChild("pset_name")?.toArray(), K = U.getChild("property_name")?.toArray(), G = U.getChild("property_value")?.toArray(), A = U.getChild("property_type")?.toArray(), k = new Map;
594
+ for(let n = 0; n < j.length; n++){
595
+ const y = j[n];
596
+ k.has(y) || k.set(y, {
597
+ pset_id: y,
598
+ pset_name: ee[n] ?? "",
599
+ properties: []
600
+ }), k.get(y).properties.push({
601
+ property_name: K[n] ?? "",
602
+ property_value: G[n] ?? "",
603
+ property_type: A[n] ?? ""
604
+ });
605
+ }
606
+ const z = e.readParquet(q), C = o.tableFromIPC(z.intoIPCStream()), X = C.getChild("qset_id")?.toArray(), te = C.getChild("qset_name")?.toArray(), O = C.getChild("method_of_measurement")?.toArray(), le = C.getChild("quantity_name")?.toArray(), de = C.getChild("quantity_value")?.toArray(), J = C.getChild("quantity_type")?.toArray(), m = new Map;
607
+ for(let n = 0; n < X.length; n++){
608
+ const y = X[n];
609
+ m.has(y) || m.set(y, {
610
+ qset_id: y,
611
+ qset_name: te[n] ?? "",
612
+ method_of_measurement: O[n] || void 0,
613
+ quantities: []
614
+ }), m.get(y).quantities.push({
615
+ quantity_name: le[n] ?? "",
616
+ quantity_value: de[n] ?? 0,
617
+ quantity_type: J[n] ?? ""
618
+ });
619
+ }
620
+ const T = f.getChild("rel_type")?.toArray(), ue = f.getChild("relating_id")?.toArray(), N = f.getChild("related_id")?.toArray(), re = new Array(ue.length);
621
+ for(let n = 0; n < ue.length; n++)re[n] = {
622
+ rel_type: T[n] ?? "",
623
+ relating_id: ue[n],
624
+ related_id: N[n]
625
+ };
626
+ const R = new DataView(d.buffer, d.byteOffset, d.byteLength);
627
+ let u = 0;
628
+ const oe = R.getUint32(u, !0);
629
+ u += 4;
630
+ const pe = new Uint8Array(d.buffer, d.byteOffset + u, oe);
631
+ u += oe;
632
+ const he = R.getUint32(u, !0);
633
+ u += 4;
634
+ const ye = new Uint8Array(d.buffer, d.byteOffset + u, he);
635
+ u += he;
636
+ const ae = R.getUint32(u, !0);
637
+ u += 4;
638
+ const _e = new Uint8Array(d.buffer, d.byteOffset + u, ae);
639
+ u += ae;
640
+ const S = R.getUint32(u, !0);
641
+ u += 4;
642
+ const se = new Uint8Array(d.buffer, d.byteOffset + u, S);
643
+ u += S;
644
+ const xe = R.getUint32(u, !0);
645
+ u += 4;
646
+ const ze = new Uint8Array(d.buffer, d.byteOffset + u, xe);
647
+ u += xe;
648
+ const Oe = R.getUint32(u, !0), Ne = e.readParquet(pe), ie = o.tableFromIPC(Ne.intoIPCStream()), Ie = ie.getChild("entity_id")?.toArray(), Re = ie.getChild("parent_id")?.toArray(), He = ie.getChild("level")?.toArray(), Ve = ie.getChild("path")?.toArray(), Be = ie.getChild("type_name")?.toArray(), We = ie.getChild("name")?.toArray(), je = ie.getChild("elevation")?.toArray(), $e = ie.getChild("children_ids"), Fe = ie.getChild("element_ids"), Te = Ie.length, Ue = new Array(Te);
649
+ for(let n = 0; n < Te; n++){
650
+ let y = [], H = [];
651
+ if ($e) {
652
+ const M = $e.get(n);
653
+ M && (y = [
654
+ ...M.toArray()
655
+ ]);
656
+ }
657
+ if (Fe) {
658
+ const M = Fe.get(n);
659
+ M && (H = [
660
+ ...M.toArray()
661
+ ]);
662
+ }
663
+ Ue[n] = {
664
+ entity_id: Ie[n],
665
+ parent_id: Re[n] ?? 0,
666
+ level: He[n],
667
+ path: Ve[n] ?? "",
668
+ type_name: Be[n] ?? "",
669
+ name: We[n] || void 0,
670
+ elevation: je[n] ?? void 0,
671
+ children_ids: y,
672
+ element_ids: H
673
+ };
674
+ }
675
+ const Ae = (n)=>{
676
+ const y = e.readParquet(n), H = o.tableFromIPC(y.intoIPCStream()), M = H.getChild("element_id")?.toArray(), ge = H.getChild("spatial_id")?.toArray(), me = new Map;
677
+ for(let b = 0; b < M.length; b++)me.set(M[b], ge[b]);
678
+ return me;
679
+ }, [Ge, Xe, Je, Qe] = [
680
+ Ae(ye),
681
+ Ae(_e),
682
+ Ae(se),
683
+ Ae(ze)
684
+ ], Ee = [];
685
+ if (E) {
686
+ const n = o.tableFromIPC(e.readParquet(E).intoIPCStream()), y = n.getChild("element_id")?.toArray(), H = n.getChild("system_name")?.toArray(), M = n.getChild("identification")?.toArray(), ge = n.getChild("name")?.toArray(), me = n.getChild("location")?.toArray();
687
+ for(let b = 0; b < y.length; b++)Ee.push({
688
+ element_id: y[b],
689
+ system_name: H?.[b] || void 0,
690
+ identification: M?.[b] || void 0,
691
+ name: ge?.[b] || void 0,
692
+ location: me?.[b] || void 0
693
+ });
694
+ }
695
+ const ke = [];
696
+ if (D) {
697
+ const n = o.tableFromIPC(e.readParquet(D).intoIPCStream()), y = n.getChild("element_id")?.toArray(), H = n.getChild("set_name")?.toArray(), M = n.getChild("layer_index")?.toArray(), ge = n.getChild("material_name")?.toArray(), me = n.getChild("thickness")?.toArray(), b = n.getChild("is_ventilated"), Ye = n.getChild("category")?.toArray();
698
+ for(let ce = 0; ce < y.length; ce++){
699
+ const qe = b?.get(ce);
700
+ ke.push({
701
+ element_id: y[ce],
702
+ set_name: H?.[ce] || void 0,
703
+ layer_index: M[ce],
704
+ material_name: ge?.[ce] ?? "",
705
+ thickness: me?.[ce] ?? void 0,
706
+ is_ventilated: qe == null ? void 0 : !!qe,
707
+ category: Ye?.[ce] || void 0
708
+ });
709
+ }
710
+ }
711
+ const Me = [];
712
+ if (L) {
713
+ const n = o.tableFromIPC(e.readParquet(L).intoIPCStream()), y = n.getChild("element_id")?.toArray(), H = n.getChild("identification")?.toArray(), M = n.getChild("name")?.toArray(), ge = n.getChild("location")?.toArray(), me = n.getChild("description")?.toArray();
714
+ for(let b = 0; b < y.length; b++)Me.push({
715
+ element_id: y[b],
716
+ identification: H?.[b] || void 0,
717
+ name: M?.[b] || void 0,
718
+ location: ge?.[b] || void 0,
719
+ description: me?.[b] || void 0
720
+ });
721
+ }
722
+ return {
723
+ entities: F,
724
+ propertySets: k,
725
+ quantitySets: m,
726
+ relationships: re,
727
+ classifications: Ee,
728
+ materials: ke,
729
+ documents: Me,
730
+ spatialHierarchy: {
731
+ nodes: Ue,
732
+ project_id: Oe,
733
+ element_to_storey: Ge,
734
+ element_to_building: Xe,
735
+ element_to_site: Je,
736
+ element_to_space: Qe
737
+ }
738
+ };
739
+ };
740
+ });
741
+ export { tt as I, rt as d, __tla };