@ifc-lite/geometry 3.4.0 → 3.6.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/dist/types.d.ts CHANGED
@@ -1,6 +1,19 @@
1
1
  /**
2
2
  * Geometry types for IFC-Lite
3
3
  */
4
+ /**
5
+ * An entity's world-space axis-aligned bounding box, in the renderer frame
6
+ * (WebGL Y-up, metres) and in ABSOLUTE world coordinates — the RTC offset and
7
+ * the per-element {@link MeshData.origin} are already folded in.
8
+ *
9
+ * Distinct from {@link MeshData.localBounds}, which is the pre-placement
10
+ * object-space box of one submesh, and from `origin`, which is a translation
11
+ * carried purely for f32 precision. Do not conflate the three.
12
+ */
13
+ export interface EntityWorldAabb {
14
+ min: [number, number, number];
15
+ max: [number, number, number];
16
+ }
4
17
  /**
5
18
  * Mesh data for a single geometric representation of an IFC element.
6
19
  *
@@ -60,6 +73,41 @@ export interface MeshData {
60
73
  * share the same value (it is the whole-entity hash). Consumed by the
61
74
  * model-diff / compare feature (issue #924); renderers ignore it. */
62
75
  geometryHash?: bigint;
76
+ /** Whole-entity world bounding box from the SAME hashing pass as
77
+ * {@link MeshData.geometryHash} (`MeshCollection.geometryAabbValues`),
78
+ * populated only when geometry hashing is enabled
79
+ * (`GeometryProcessor.enableGeometryHashes()`). Like the hash, all submeshes
80
+ * of one entity carry the same box — it spans the entity, not this submesh.
81
+ *
82
+ * ABSOLUTE world, unlike `positions`: the RTC offset and the per-element
83
+ * {@link MeshData.origin} are already folded in, so two revisions that chose
84
+ * different RTC offsets report the same box. Do NOT add `origin` to it.
85
+ *
86
+ * Absent when the pass produced no box for the entity (the wasm side writes
87
+ * six `NaN`s there; the extractor drops them rather than passing a
88
+ * NaN-bearing object on), when hashing is off, or on a wasm build predating
89
+ * the getter. Consumed by the model-diff / compare feature to tell a move
90
+ * from a reshape (#1891); renderers ignore it. */
91
+ geometryAabb?: EntityWorldAabb;
92
+ /** Whole-entity enclosed volume in CUBIC METRES, from the SAME hashing pass
93
+ * as {@link MeshData.geometryHash} (`MeshCollection.geometryVolumeValues`,
94
+ * #1993). Like the hash and the box, all submeshes of one entity carry the
95
+ * identical value — it is the volume of the entity, not of this submesh, so
96
+ * summing it across submeshes would multiply it.
97
+ *
98
+ * Present only when the meshed geometry was PROVABLY a single closed,
99
+ * orientable, single-component solid (measured coverage on a real corpus:
100
+ * 71.4%, 24,073 of 33,701 elements). Absent means the kernel could not prove
101
+ * a volume — an open shell, a material-layered wall, a multi-item assembly —
102
+ * and NEVER that the volume is zero or that it differs. The wasm side writes
103
+ * `NaN` there; the extractor drops it rather than passing a NaN-bearing
104
+ * number on.
105
+ *
106
+ * It is the volume of what was actually meshed, AFTER opening cuts, so it is
107
+ * not an IFC `BaseQuantities` `GrossVolume` and must not be compared with
108
+ * one. Consumed by the model-diff split/merge detector (#1891); renderers
109
+ * ignore it. */
110
+ geometryVolume?: number;
63
111
  /** Geometry provenance for rendering and the viewer's Model/Types view switch:
64
112
  * - 0 = occurrence (placed IfcProduct). RENDER THIS in normal/Model views.
65
113
  * - 1 = orphan type geometry (an IfcTypeProduct RepresentationMap with no
@@ -283,6 +331,25 @@ export interface GeometryResult {
283
331
  * geometry hashing is off or no entity was fully instanced.
284
332
  */
285
333
  instancedGeometryHashes?: Map<number, bigint>;
334
+ /**
335
+ * World bounding boxes for the SAME instanced-only entities as
336
+ * {@link GeometryResult.instancedGeometryHashes}, keyed the same way. A
337
+ * separate map rather than a field on the hash entry because an entity can
338
+ * have a hash and no box (the wasm side writes six `NaN`s there); a key
339
+ * missing here means exactly that. Absent when geometry hashing is off,
340
+ * nothing was fully instanced, or the wasm build predates the getter.
341
+ */
342
+ instancedGeometryAabbs?: Map<number, EntityWorldAabb>;
343
+ /**
344
+ * Enclosed volumes (m³) for the SAME instanced-only entities, keyed the same
345
+ * way (#1993). A third map for the same reason the boxes are a second one: an
346
+ * entity can be hashed and boxed with no PROVED volume, so a key missing here
347
+ * means exactly "not proved", and folding it into the hash entry would make
348
+ * absence indistinguishable from an entity that has no fingerprint at all.
349
+ * Absent when geometry hashing is off, nothing was fully instanced, or the
350
+ * wasm build predates the getter.
351
+ */
352
+ instancedGeometryVolumes?: Map<number, number>;
286
353
  }
287
354
  /**
288
355
  * Representation identifier types for symbolic representations
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -36,7 +36,8 @@ export interface InitWasmRetryOptions {
36
36
  /**
37
37
  * Run `init` once; on a transient-looking failure, wait and retry exactly once.
38
38
  * Non-transient failures propagate without a retry. The second failure (if any)
39
- * propagates to the caller.
39
+ * propagates to the caller — attributed to the engine binary when the browser's
40
+ * own wording identifies nothing (see {@link attributeEngineLoadFailure}).
40
41
  *
41
42
  * @param init Thunk that performs the actual `init(...)` call (so callers can
42
43
  * bind their own wasm URL / arguments).
@@ -1 +1 @@
1
- {"version":3,"file":"wasm-init-retry.d.ts","sourceRoot":"","sources":["../src/wasm-init-retry.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAOjE;AAED,MAAM,WAAW,oBAAoB;IACnC,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,oDAAoD;IACpD,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD;;;;;;;GAOG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC5B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAYf"}
1
+ {"version":3,"file":"wasm-init-retry.d.ts","sourceRoot":"","sources":["../src/wasm-init-retry.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAOjE;AA6CD,MAAM,WAAW,oBAAoB;IACnC,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uDAAuD;IACvD,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,oDAAoD;IACpD,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,sCAAsC;IACtC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAKD;;;;;;;;GAQG;AACH,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,EAC5B,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAgBf"}
@@ -33,11 +33,52 @@ export function isTransientWasmLoadError(message) {
33
33
  }
34
34
  return /HTTP status code is not ok|failed to fetch|network ?error|load failed/i.test(message);
35
35
  }
36
+ /**
37
+ * A message that already names the thing that failed to load, so re-throwing it
38
+ * with an attribution prefix would only add noise. Deliberately includes
39
+ * `WebAssembly` (the `'compile' on 'WebAssembly'` phrasings) — those are exactly
40
+ * the signatures `isWasmAssetUnavailableError` (wasm-asset-error.ts) matches to
41
+ * drive the #1363 stale-deploy reload, and they must reach it byte-for-byte.
42
+ */
43
+ const SELF_IDENTIFYING = /wasm|webassembly/i;
44
+ /**
45
+ * A failed *module* load already carries its own specifier. Prefixing one with
46
+ * `ifc-lite_bg.wasm` would make it look to that same #1363 matcher like a
47
+ * rotated ENGINE BINARY (`/\.wasm/` + "dynamically imported module") and
48
+ * trigger a spurious page reload, so those are passed through untouched.
49
+ */
50
+ const MODULE_LOAD_FAILURE = /dynamically imported module|module script/i;
51
+ /**
52
+ * Name the engine binary in a transport failure that names nothing (issue #1903).
53
+ *
54
+ * wasm-bindgen's generated loader `await`s the `fetch()` it starts, so a
55
+ * network-level rejection propagates RAW: WebKit words it `TypeError: Load
56
+ * failed`, Chromium `TypeError: Failed to fetch`, and because the rejection
57
+ * originates inside the fetch rather than in our frames it carries an EMPTY
58
+ * stack. Two words and no frames is unattributable by construction — the toast,
59
+ * `classifyLoadError` in the viewer, and error tracking all see a bare
60
+ * `TypeError` that could have come from anywhere in the load.
61
+ *
62
+ * So when the final failure identifies nothing, re-throw it naming the binary
63
+ * and the call site, preserving the original as `.cause`. Anything that already
64
+ * identifies itself is returned unchanged.
65
+ */
66
+ function attributeEngineLoadFailure(error, label) {
67
+ if (!(error instanceof Error))
68
+ return error;
69
+ const msg = error.message;
70
+ if (!isTransientWasmLoadError(msg))
71
+ return error;
72
+ if (SELF_IDENTIFYING.test(msg) || MODULE_LOAD_FAILURE.test(msg))
73
+ return error;
74
+ return new Error(`Failed to load the WASM engine binary (ifc-lite_bg.wasm) in ${label}: ${msg}`, { cause: error });
75
+ }
36
76
  const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
37
77
  /**
38
78
  * Run `init` once; on a transient-looking failure, wait and retry exactly once.
39
79
  * Non-transient failures propagate without a retry. The second failure (if any)
40
- * propagates to the caller.
80
+ * propagates to the caller — attributed to the engine binary when the browser's
81
+ * own wording identifies nothing (see {@link attributeEngineLoadFailure}).
41
82
  *
42
83
  * @param init Thunk that performs the actual `init(...)` call (so callers can
43
84
  * bind their own wasm URL / arguments).
@@ -54,7 +95,12 @@ export async function initWasmWithRetry(init, options = {}) {
54
95
  throw err;
55
96
  warn(`[${label}] WASM engine load failed (${msg}); retrying once`);
56
97
  await sleep(retryDelayMs);
57
- await init();
98
+ try {
99
+ await init();
100
+ }
101
+ catch (retryErr) {
102
+ throw attributeEngineLoadFailure(retryErr, label);
103
+ }
58
104
  }
59
105
  }
60
106
  //# sourceMappingURL=wasm-init-retry.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"wasm-init-retry.js","sourceRoot":"","sources":["../src/wasm-init-retry.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAe;IACtD,6EAA6E;IAC7E,kCAAkC;IAClC,IAAI,8EAA8E,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACjG,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,wEAAwE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAChG,CAAC;AAaD,MAAM,YAAY,GAAG,CAAC,EAAU,EAAiB,EAAE,CACjD,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAEpD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAA4B,EAC5B,UAAgC,EAAE;IAElC,MAAM,EAAE,YAAY,GAAG,GAAG,EAAE,KAAK,GAAG,YAAY,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;IAClG,IAAI,CAAC;QACH,MAAM,IAAI,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC;YAAE,MAAM,GAAG,CAAC;QAC9C,IAAI,CAAC,IAAI,KAAK,8BAA8B,GAAG,kBAAkB,CAAC,CAAC;QACnE,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;QAC1B,MAAM,IAAI,EAAE,CAAC;IACf,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"wasm-init-retry.js","sourceRoot":"","sources":["../src/wasm-init-retry.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;GAWG;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,wBAAwB,CAAC,OAAe;IACtD,6EAA6E;IAC7E,kCAAkC;IAClC,IAAI,8EAA8E,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACjG,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,wEAAwE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AAChG,CAAC;AAED;;;;;;GAMG;AACH,MAAM,gBAAgB,GAAG,mBAAmB,CAAC;AAE7C;;;;;GAKG;AACH,MAAM,mBAAmB,GAAG,4CAA4C,CAAC;AAEzE;;;;;;;;;;;;;;GAcG;AACH,SAAS,0BAA0B,CAAC,KAAc,EAAE,KAAa;IAC/D,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC;IAC1B,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACjD,IAAI,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,mBAAmB,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9E,OAAO,IAAI,KAAK,CACd,+DAA+D,KAAK,KAAK,GAAG,EAAE,EAC9E,EAAE,KAAK,EAAE,KAAK,EAAE,CACjB,CAAC;AACJ,CAAC;AAaD,MAAM,YAAY,GAAG,CAAC,EAAU,EAAiB,EAAE,CACjD,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAEpD;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAA4B,EAC5B,UAAgC,EAAE;IAElC,MAAM,EAAE,YAAY,GAAG,GAAG,EAAE,KAAK,GAAG,YAAY,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,KAAK,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;IAClG,IAAI,CAAC;QACH,MAAM,IAAI,EAAE,CAAC;QACb,OAAO;IACT,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7D,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC;YAAE,MAAM,GAAG,CAAC;QAC9C,IAAI,CAAC,IAAI,KAAK,8BAA8B,GAAG,kBAAkB,CAAC,CAAC;QACnE,MAAM,KAAK,CAAC,YAAY,CAAC,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,IAAI,EAAE,CAAC;QACf,CAAC;QAAC,OAAO,QAAQ,EAAE,CAAC;YAClB,MAAM,0BAA0B,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Classify WebAssembly runtime traps and, for the one case that genuinely
3
+ * cannot be recovered in-document, broadcast it so the host can offer a reload
4
+ * (#1898).
5
+ *
6
+ * A trap is what reaches JS when the engine executes `unreachable`: with
7
+ * `panic = "abort"` (rust/Cargo.toml) a Rust panic, a failed `assert!` and an
8
+ * allocator abort are ALL indistinguishable from here — see the same caveat in
9
+ * `huge-file-error.ts`. What a trap can damage is bounded: the wasm instance's
10
+ * linear memory keeps whatever the aborted call leaked, and any Rust state the
11
+ * call was mutating is left mid-flight. It does NOT invalidate the module, and
12
+ * it says nothing about other engine handles in the realm, let alone about
13
+ * other realms (each Worker instantiates its own `@ifc-lite/wasm`).
14
+ *
15
+ * So the recovery contract is:
16
+ *
17
+ * - a trap taken inside an *operation* is the caller's failure. The bridge
18
+ * that took it drops (and frees) its `IfcAPI` handle — that is where the
19
+ * wedgeable per-load caches live — and the original trap propagates
20
+ * unchanged. A later `init()`, on that bridge or any other, builds a fresh
21
+ * handle and works.
22
+ * - a trap taken while *initializing* means this realm could not produce a
23
+ * working engine at all, and neither half of that is retryable in practice:
24
+ * if the trap came from `new IfcAPI()` the module singleton is already built
25
+ * and wasm-bindgen's `init()` will keep returning it, and if it came from
26
+ * instantiation itself it is a deterministic module-level failure that
27
+ * recurs. That is the only case that earns
28
+ * {@link WASM_RUNTIME_UNRECOVERABLE_EVENT} — the user is told to reload,
29
+ * which is the one thing that really does get a new instance.
30
+ *
31
+ * Even then nothing is latched: a later `init()` still tries, so the
32
+ * "unrecoverable" verdict is a diagnosis for the user, never a lock that could
33
+ * disable an unrelated consumer. Recovery is lazy — it happens on the next
34
+ * `init()` a consumer asks for — so there is no retry loop to bound either.
35
+ *
36
+ * Detection lives here as a pure, unit-testable predicate; the host app owns
37
+ * the reload policy and subscribes to the event. This library never reloads
38
+ * the page on its own — same division of labour as `wasm-asset-error.ts`.
39
+ */
40
+ /**
41
+ * Stable marker in the message of the error thrown when the engine cannot be
42
+ * initialized after a trap. Kept in the message (not only in a field) so it
43
+ * survives the string-only round trip through error tracking, and so the host
44
+ * app can classify it without importing this package.
45
+ */
46
+ export declare const WASM_RUNTIME_UNRECOVERABLE_CODE = "WASM_RUNTIME_UNRECOVERABLE";
47
+ /**
48
+ * Dispatched on `globalThis` when the WebAssembly geometry engine trapped
49
+ * while initializing and therefore cannot be rebuilt in this document.
50
+ * `detail.message` carries the originating trap text. Hosts that opt in tell
51
+ * the user to reload; unlike the version-skew event this must NOT trigger an
52
+ * automatic reload — a crash mid-session would discard the user's work.
53
+ */
54
+ export declare const WASM_RUNTIME_UNRECOVERABLE_EVENT = "ifclite:wasm-runtime-unrecoverable";
55
+ /**
56
+ * True when `err` is a WebAssembly runtime trap.
57
+ *
58
+ * `instanceof WebAssembly.RuntimeError` alone is not enough: an error thrown
59
+ * inside a Worker/iframe realm and re-raised here fails the identity check
60
+ * because each realm has its own `WebAssembly.RuntimeError` constructor. The
61
+ * `.name` fallback is the cross-realm-safe half — `RuntimeError` is the class
62
+ * name the spec fixes for wasm traps, and structured-cloned errors keep it.
63
+ */
64
+ export declare function isWasmRuntimeTrap(err: unknown): boolean;
65
+ /**
66
+ * True for the typed error {@link wasmRuntimeUnrecoverableError} produces —
67
+ * matched on the message marker so it also works on an error that only
68
+ * survived as text (an analytics payload, a `postMessage` hop).
69
+ */
70
+ export declare function isWasmRuntimeUnrecoverableError(err: unknown): boolean;
71
+ /**
72
+ * Build the error thrown when the engine trapped while initializing.
73
+ *
74
+ * Constructed FRESH at every throw site on purpose. The bug this replaces
75
+ * stored one Error object in a module global and rethrew it forever, so the
76
+ * stack shipped to error tracking pointed at whichever call first trapped —
77
+ * the production report for #1898 showed a `exportGlb` stack captured under a
78
+ * model-load context, which made it undiagnosable. The underlying trap is kept
79
+ * verbatim in the message tail (for triage from text alone) and as `.cause`
80
+ * (for programmatic inspection), mirroring `largeFilePrepassError`.
81
+ */
82
+ export declare function wasmRuntimeUnrecoverableError(cause: unknown, operation: string): Error;
83
+ /**
84
+ * Broadcast {@link WASM_RUNTIME_UNRECOVERABLE_EVENT} on `globalThis` so an
85
+ * opted-in host can tell the user the engine is gone and offer a reload.
86
+ * No-op in non-DOM hosts such as Node (CLI/MCP), where the thrown error is the
87
+ * whole story.
88
+ */
89
+ export declare function notifyWasmRuntimeUnrecoverable(err: unknown): void;
90
+ //# sourceMappingURL=wasm-runtime-trap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasm-runtime-trap.d.ts","sourceRoot":"","sources":["../src/wasm-runtime-trap.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,+BAA+B,CAAC;AAE5E;;;;;;GAMG;AACH,eAAO,MAAM,gCAAgC,uCAAuC,CAAC;AAYrF;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAIvD;AAED;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAErE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,KAAK,CAQtF;AAaD;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAUjE"}
@@ -0,0 +1,134 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ /**
5
+ * Classify WebAssembly runtime traps and, for the one case that genuinely
6
+ * cannot be recovered in-document, broadcast it so the host can offer a reload
7
+ * (#1898).
8
+ *
9
+ * A trap is what reaches JS when the engine executes `unreachable`: with
10
+ * `panic = "abort"` (rust/Cargo.toml) a Rust panic, a failed `assert!` and an
11
+ * allocator abort are ALL indistinguishable from here — see the same caveat in
12
+ * `huge-file-error.ts`. What a trap can damage is bounded: the wasm instance's
13
+ * linear memory keeps whatever the aborted call leaked, and any Rust state the
14
+ * call was mutating is left mid-flight. It does NOT invalidate the module, and
15
+ * it says nothing about other engine handles in the realm, let alone about
16
+ * other realms (each Worker instantiates its own `@ifc-lite/wasm`).
17
+ *
18
+ * So the recovery contract is:
19
+ *
20
+ * - a trap taken inside an *operation* is the caller's failure. The bridge
21
+ * that took it drops (and frees) its `IfcAPI` handle — that is where the
22
+ * wedgeable per-load caches live — and the original trap propagates
23
+ * unchanged. A later `init()`, on that bridge or any other, builds a fresh
24
+ * handle and works.
25
+ * - a trap taken while *initializing* means this realm could not produce a
26
+ * working engine at all, and neither half of that is retryable in practice:
27
+ * if the trap came from `new IfcAPI()` the module singleton is already built
28
+ * and wasm-bindgen's `init()` will keep returning it, and if it came from
29
+ * instantiation itself it is a deterministic module-level failure that
30
+ * recurs. That is the only case that earns
31
+ * {@link WASM_RUNTIME_UNRECOVERABLE_EVENT} — the user is told to reload,
32
+ * which is the one thing that really does get a new instance.
33
+ *
34
+ * Even then nothing is latched: a later `init()` still tries, so the
35
+ * "unrecoverable" verdict is a diagnosis for the user, never a lock that could
36
+ * disable an unrelated consumer. Recovery is lazy — it happens on the next
37
+ * `init()` a consumer asks for — so there is no retry loop to bound either.
38
+ *
39
+ * Detection lives here as a pure, unit-testable predicate; the host app owns
40
+ * the reload policy and subscribes to the event. This library never reloads
41
+ * the page on its own — same division of labour as `wasm-asset-error.ts`.
42
+ */
43
+ /**
44
+ * Stable marker in the message of the error thrown when the engine cannot be
45
+ * initialized after a trap. Kept in the message (not only in a field) so it
46
+ * survives the string-only round trip through error tracking, and so the host
47
+ * app can classify it without importing this package.
48
+ */
49
+ export const WASM_RUNTIME_UNRECOVERABLE_CODE = 'WASM_RUNTIME_UNRECOVERABLE';
50
+ /**
51
+ * Dispatched on `globalThis` when the WebAssembly geometry engine trapped
52
+ * while initializing and therefore cannot be rebuilt in this document.
53
+ * `detail.message` carries the originating trap text. Hosts that opt in tell
54
+ * the user to reload; unlike the version-skew event this must NOT trigger an
55
+ * automatic reload — a crash mid-session would discard the user's work.
56
+ */
57
+ export const WASM_RUNTIME_UNRECOVERABLE_EVENT = 'ifclite:wasm-runtime-unrecoverable';
58
+ function messageOf(err) {
59
+ if (err == null)
60
+ return '';
61
+ if (typeof err === 'string')
62
+ return err;
63
+ if (typeof err === 'object' && 'message' in err) {
64
+ const m = err.message;
65
+ if (typeof m === 'string')
66
+ return m;
67
+ }
68
+ return String(err);
69
+ }
70
+ /**
71
+ * True when `err` is a WebAssembly runtime trap.
72
+ *
73
+ * `instanceof WebAssembly.RuntimeError` alone is not enough: an error thrown
74
+ * inside a Worker/iframe realm and re-raised here fails the identity check
75
+ * because each realm has its own `WebAssembly.RuntimeError` constructor. The
76
+ * `.name` fallback is the cross-realm-safe half — `RuntimeError` is the class
77
+ * name the spec fixes for wasm traps, and structured-cloned errors keep it.
78
+ */
79
+ export function isWasmRuntimeTrap(err) {
80
+ if (typeof WebAssembly !== 'undefined' && err instanceof WebAssembly.RuntimeError)
81
+ return true;
82
+ if (typeof err !== 'object' || err === null)
83
+ return false;
84
+ return err.name === 'RuntimeError';
85
+ }
86
+ /**
87
+ * True for the typed error {@link wasmRuntimeUnrecoverableError} produces —
88
+ * matched on the message marker so it also works on an error that only
89
+ * survived as text (an analytics payload, a `postMessage` hop).
90
+ */
91
+ export function isWasmRuntimeUnrecoverableError(err) {
92
+ return messageOf(err).includes(WASM_RUNTIME_UNRECOVERABLE_CODE);
93
+ }
94
+ /**
95
+ * Build the error thrown when the engine trapped while initializing.
96
+ *
97
+ * Constructed FRESH at every throw site on purpose. The bug this replaces
98
+ * stored one Error object in a module global and rethrew it forever, so the
99
+ * stack shipped to error tracking pointed at whichever call first trapped —
100
+ * the production report for #1898 showed a `exportGlb` stack captured under a
101
+ * model-load context, which made it undiagnosable. The underlying trap is kept
102
+ * verbatim in the message tail (for triage from text alone) and as `.cause`
103
+ * (for programmatic inspection), mirroring `largeFilePrepassError`.
104
+ */
105
+ export function wasmRuntimeUnrecoverableError(cause, operation) {
106
+ const raw = messageOf(cause) || String(cause);
107
+ return new Error(`${WASM_RUNTIME_UNRECOVERABLE_CODE}: the IFC-Lite WebAssembly geometry engine trapped during ` +
108
+ `${operation}, so this document has no working engine instance. Reload the page to get a ` +
109
+ `fresh one. (underlying wasm trap: ${raw})`, { cause });
110
+ }
111
+ function domDispatcher() {
112
+ const g = globalThis;
113
+ return typeof g.dispatchEvent === 'function' && typeof g.CustomEvent === 'function'
114
+ ? g
115
+ : null;
116
+ }
117
+ /**
118
+ * Broadcast {@link WASM_RUNTIME_UNRECOVERABLE_EVENT} on `globalThis` so an
119
+ * opted-in host can tell the user the engine is gone and offer a reload.
120
+ * No-op in non-DOM hosts such as Node (CLI/MCP), where the thrown error is the
121
+ * whole story.
122
+ */
123
+ export function notifyWasmRuntimeUnrecoverable(err) {
124
+ const target = domDispatcher();
125
+ if (!target)
126
+ return;
127
+ try {
128
+ target.dispatchEvent(new CustomEvent(WASM_RUNTIME_UNRECOVERABLE_EVENT, { detail: { message: messageOf(err) } }));
129
+ }
130
+ catch {
131
+ /* CustomEvent unavailable — best effort, nothing more to do */
132
+ }
133
+ }
134
+ //# sourceMappingURL=wasm-runtime-trap.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasm-runtime-trap.js","sourceRoot":"","sources":["../src/wasm-runtime-trap.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;;;;GAKG;AACH,MAAM,CAAC,MAAM,+BAA+B,GAAG,4BAA4B,CAAC;AAE5E;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,gCAAgC,GAAG,oCAAoC,CAAC;AAErF,SAAS,SAAS,CAAC,GAAY;IAC7B,IAAI,GAAG,IAAI,IAAI;QAAE,OAAO,EAAE,CAAC;IAC3B,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxC,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,SAAS,IAAI,GAAG,EAAE,CAAC;QAChD,MAAM,CAAC,GAAI,GAA6B,CAAC,OAAO,CAAC;QACjD,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;AACrB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAY;IAC5C,IAAI,OAAO,WAAW,KAAK,WAAW,IAAI,GAAG,YAAY,WAAW,CAAC,YAAY;QAAE,OAAO,IAAI,CAAC;IAC/F,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC1D,OAAQ,GAA0B,CAAC,IAAI,KAAK,cAAc,CAAC;AAC7D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAAC,GAAY;IAC1D,OAAO,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,+BAA+B,CAAC,CAAC;AAClE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,6BAA6B,CAAC,KAAc,EAAE,SAAiB;IAC7E,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC;IAC9C,OAAO,IAAI,KAAK,CACd,GAAG,+BAA+B,4DAA4D;QAC5F,GAAG,SAAS,8EAA8E;QAC1F,qCAAqC,GAAG,GAAG,EAC7C,EAAE,KAAK,EAAE,CACV,CAAC;AACJ,CAAC;AAMD,SAAS,aAAa;IACpB,MAAM,CAAC,GAAG,UAA2E,CAAC;IACtF,OAAO,OAAO,CAAC,CAAC,aAAa,KAAK,UAAU,IAAI,OAAO,CAAC,CAAC,WAAW,KAAK,UAAU;QACjF,CAAC,CAAE,CAAmB;QACtB,CAAC,CAAC,IAAI,CAAC;AACX,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,8BAA8B,CAAC,GAAY;IACzD,MAAM,MAAM,GAAG,aAAa,EAAE,CAAC;IAC/B,IAAI,CAAC,MAAM;QAAE,OAAO;IACpB,IAAI,CAAC;QACH,MAAM,CAAC,aAAa,CAClB,IAAI,WAAW,CAAC,gCAAgC,EAAE,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAC3F,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;IACjE,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ifc-lite/geometry",
3
- "version": "3.4.0",
3
+ "version": "3.6.0",
4
4
  "description": "Geometry processing bridge for IFC-Lite - exact-arithmetic CSG, streamed across workers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -13,8 +13,8 @@
13
13
  }
14
14
  },
15
15
  "dependencies": {
16
- "@ifc-lite/data": "^2.8.0",
17
- "@ifc-lite/wasm": "^4.1.4"
16
+ "@ifc-lite/data": "^3.2.0",
17
+ "@ifc-lite/wasm": "^4.3.0"
18
18
  },
19
19
  "optionalDependencies": {
20
20
  "@tauri-apps/api": "^2.11.1"