@ifc-lite/collab 0.2.6 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/dist/awareness/presence.d.ts +6 -0
  2. package/dist/awareness/presence.d.ts.map +1 -1
  3. package/dist/awareness/presence.js.map +1 -1
  4. package/dist/doc/annotation.d.ts +54 -0
  5. package/dist/doc/annotation.d.ts.map +1 -0
  6. package/dist/doc/annotation.js +84 -0
  7. package/dist/doc/annotation.js.map +1 -0
  8. package/dist/doc/entity.d.ts +18 -2
  9. package/dist/doc/entity.d.ts.map +1 -1
  10. package/dist/doc/entity.js +161 -11
  11. package/dist/doc/entity.js.map +1 -1
  12. package/dist/doc/geometry.d.ts +8 -0
  13. package/dist/doc/geometry.d.ts.map +1 -1
  14. package/dist/doc/geometry.js +12 -0
  15. package/dist/doc/geometry.js.map +1 -1
  16. package/dist/doc/placement.d.ts +102 -0
  17. package/dist/doc/placement.d.ts.map +1 -0
  18. package/dist/doc/placement.js +118 -0
  19. package/dist/doc/placement.js.map +1 -0
  20. package/dist/doc/schema.d.ts +14 -3
  21. package/dist/doc/schema.d.ts.map +1 -1
  22. package/dist/doc/schema.js +7 -0
  23. package/dist/doc/schema.js.map +1 -1
  24. package/dist/geometry/blob-store.d.ts.map +1 -1
  25. package/dist/geometry/blob-store.js +5 -1
  26. package/dist/geometry/blob-store.js.map +1 -1
  27. package/dist/geometry/gc.d.ts.map +1 -1
  28. package/dist/geometry/gc.js +12 -3
  29. package/dist/geometry/gc.js.map +1 -1
  30. package/dist/index.d.ts +2 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +2 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/providers/webrtc.d.ts.map +1 -1
  35. package/dist/providers/webrtc.js +9 -1
  36. package/dist/providers/webrtc.js.map +1 -1
  37. package/dist/snapshot/from-ifcx.d.ts.map +1 -1
  38. package/dist/snapshot/from-ifcx.js +34 -2
  39. package/dist/snapshot/from-ifcx.js.map +1 -1
  40. package/dist/snapshot/from-step.d.ts +76 -0
  41. package/dist/snapshot/from-step.d.ts.map +1 -0
  42. package/dist/snapshot/from-step.js +70 -0
  43. package/dist/snapshot/from-step.js.map +1 -0
  44. package/dist/snapshot/index.d.ts +3 -0
  45. package/dist/snapshot/index.d.ts.map +1 -1
  46. package/dist/snapshot/index.js +3 -0
  47. package/dist/snapshot/index.js.map +1 -1
  48. package/dist/snapshot/minimal-layer.d.ts +20 -4
  49. package/dist/snapshot/minimal-layer.d.ts.map +1 -1
  50. package/dist/snapshot/minimal-layer.js +113 -70
  51. package/dist/snapshot/minimal-layer.js.map +1 -1
  52. package/dist/snapshot/publish-layer.d.ts +60 -0
  53. package/dist/snapshot/publish-layer.d.ts.map +1 -0
  54. package/dist/snapshot/publish-layer.js +43 -0
  55. package/dist/snapshot/publish-layer.js.map +1 -0
  56. package/dist/snapshot/structured-attrs.d.ts +107 -0
  57. package/dist/snapshot/structured-attrs.d.ts.map +1 -0
  58. package/dist/snapshot/structured-attrs.js +250 -0
  59. package/dist/snapshot/structured-attrs.js.map +1 -0
  60. package/dist/snapshot/to-ifcx.d.ts +4 -0
  61. package/dist/snapshot/to-ifcx.d.ts.map +1 -1
  62. package/dist/snapshot/to-ifcx.js +5 -2
  63. package/dist/snapshot/to-ifcx.js.map +1 -1
  64. package/package.json +4 -4
@@ -0,0 +1,43 @@
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
+ import { computeLayerId, createProvenanceManifest, setProvenance } from '@ifc-lite/ifcx';
5
+ import { extractMinimalLayer } from './minimal-layer.js';
6
+ /**
7
+ * Freeze a draft doc into a published layer. Pure with respect to the
8
+ * draft: the Y.Doc is read, never mutated — publishing again after more
9
+ * edits produces a new layer with a new id.
10
+ */
11
+ export function publishLayer(doc, options) {
12
+ const delta = extractMinimalLayer(doc, options.baseline, options.extract);
13
+ const manifest = createProvenanceManifest({
14
+ author: options.author,
15
+ intent: options.intent,
16
+ base: options.base ?? null,
17
+ created: options.created,
18
+ parents: options.parents ?? (options.base ? [options.base.id] : []),
19
+ scope_claim: options.scope_claim ?? [],
20
+ checks: options.checks ?? [],
21
+ instructions_digest: options.instructions_digest,
22
+ });
23
+ // Normalize the generated snapshot header to the publish event so the
24
+ // content address is a function of content + manifest, not of when the
25
+ // snapshot writer happened to run.
26
+ const normalized = {
27
+ ...delta,
28
+ header: {
29
+ ...delta.header,
30
+ author: options.author.principal,
31
+ timestamp: manifest.created,
32
+ },
33
+ };
34
+ const withManifest = setProvenance(normalized, manifest);
35
+ const layerId = computeLayerId(withManifest);
36
+ return {
37
+ file: { ...withManifest, header: { ...withManifest.header, id: layerId } },
38
+ layerId,
39
+ manifest,
40
+ opCount: delta.data.length,
41
+ };
42
+ }
43
+ //# sourceMappingURL=publish-layer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish-layer.js","sourceRoot":"","sources":["../../src/snapshot/publish-layer.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AA0B/D,OAAO,EAAE,cAAc,EAAE,wBAAwB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEzF,OAAO,EAAE,mBAAmB,EAAmC,MAAM,oBAAoB,CAAC;AAsC1F;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,GAAU,EAAE,OAA4B;IACnE,MAAM,KAAK,GAAG,mBAAmB,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAE1E,MAAM,QAAQ,GAAG,wBAAwB,CAAC;QACxC,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,IAAI;QAC1B,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACnE,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,EAAE;QACtC,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,EAAE;QAC5B,mBAAmB,EAAE,OAAO,CAAC,mBAAmB;KACjD,CAAC,CAAC;IAEH,sEAAsE;IACtE,uEAAuE;IACvE,mCAAmC;IACnC,MAAM,UAAU,GAAa;QAC3B,GAAG,KAAK;QACR,MAAM,EAAE;YACN,GAAG,KAAK,CAAC,MAAM;YACf,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS;YAChC,SAAS,EAAE,QAAQ,CAAC,OAAO;SAC5B;KACF,CAAC;IACF,MAAM,YAAY,GAAG,aAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACzD,MAAM,OAAO,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;IAE7C,OAAO;QACL,IAAI,EAAE,EAAE,GAAG,YAAY,EAAE,MAAM,EAAE,EAAE,GAAG,YAAY,CAAC,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE;QAC1E,OAAO;QACP,QAAQ;QACR,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,MAAM;KAC3B,CAAC;AACJ,CAAC"}
@@ -0,0 +1,107 @@
1
+ /**
2
+ * Structured-branch ↔ namespaced-attribute conversion (#1031).
3
+ *
4
+ * The Y.Doc keeps psets / quantities / classifications / materials /
5
+ * geometryRef as dedicated CRDT branches so concurrent edits to
6
+ * different branches never conflict, but the IFCX wire type only has
7
+ * `attributes` / `children` / `inherits`. At the snapshot boundary the
8
+ * structured branches fold into ordinary attributes; `seedFromIfcx`
9
+ * re-inflates them, so structured edits survive snapshot → seed
10
+ * round-trips.
11
+ *
12
+ * Representation (the convention the MCP draft tools, the merge
13
+ * engine's `pset:`/`qset:` component keys, scope verification, and the
14
+ * IFC4→5 migration already share):
15
+ * - pset property → `bsi::ifc::v5a::<Set>::<Prop>` with the full
16
+ * typed PropertyValue object as the attribute value;
17
+ * - quantity → `bsi::ifc::v5a::<Qto_Set>::<Name>` with the raw
18
+ * number as the attribute value;
19
+ * - classifications / materials / geometryRef → single attributes
20
+ * under the `ifclite::` extension namespace (whole-array values:
21
+ * the Y.Array is the unit users edit, and merge granularity at the
22
+ * array level matches that).
23
+ *
24
+ * Inflation is shape-gated so legacy flat attributes written by the
25
+ * IFC4→IFC5 migration (raw values under the same v5a keys) stay flat:
26
+ * only PropertyValue-shaped objects inflate into psets, and numbers
27
+ * inflate into quantities unless the set is `Pset_`-named — the
28
+ * migration only ever emits `Pset_*` set names, so that exclusion is
29
+ * exactly the legacy population, and custom quantity-set names still
30
+ * round-trip. Both directions are inverse to each other, so
31
+ * flatten(inflate(x)) == x and a doc holding the same key in both the
32
+ * flat and structured branch serializes deterministically (structured
33
+ * wins).
34
+ */
35
+ import { V5A_ATTR_PREFIX } from '@ifc-lite/ifcx';
36
+ import * as Y from 'yjs';
37
+ import { type ClassificationRef, type GeometryRefRecord, type MaterialAssignment, type PropertyValue } from '../doc/schema.js';
38
+ export { V5A_ATTR_PREFIX };
39
+ /**
40
+ * Shape test for the typed PropertyValue record — the canonical wire
41
+ * shape every writer and reader shares (`isTypedPropertyValue` in
42
+ * `@ifc-lite/ifcx`). Strict on purpose: legacy migrated attributes
43
+ * carry raw scalars, never `{type, value}` objects, so this is what
44
+ * disambiguates pset inflation from "leave it as a flat attribute".
45
+ */
46
+ export declare function isPropertyValueShaped(value: unknown): value is PropertyValue;
47
+ /** The structured branches `entityToJSON` exposes alongside attributes. */
48
+ export interface StructuredBranchesJSON {
49
+ psets: Record<string, Record<string, PropertyValue>>;
50
+ quantities: Record<string, Record<string, number>>;
51
+ classifications: ClassificationRef[];
52
+ materials: MaterialAssignment[];
53
+ geometryRefs: string[];
54
+ }
55
+ /**
56
+ * Wire form of a geometry reference whose target record is known at
57
+ * snapshot time: carrying the record (sans CRDT version vector) keeps
58
+ * the round-trip self-contained — a seed can recreate the geometry map
59
+ * entry instead of restoring a dangling ref. A bare `geomId` string is
60
+ * still valid for refs whose geometry hydrates out-of-band (blob sync).
61
+ */
62
+ export interface GeometryRefCarrier {
63
+ geomId: string;
64
+ type?: string;
65
+ source?: string;
66
+ blobHash?: string;
67
+ params?: Record<string, unknown>;
68
+ bbox?: number[];
69
+ }
70
+ export interface FlattenOptions {
71
+ /**
72
+ * Resolve a geometry record for a geomId (typically from the doc's
73
+ * top-level geometry map). When it returns one, the carrier embeds it;
74
+ * otherwise only the id travels.
75
+ */
76
+ geometryRecordFor?: (geomId: string) => Omit<GeometryRefCarrier, 'geomId'> | undefined;
77
+ }
78
+ /** Attribute key for one pset property / quantity. */
79
+ export declare function structuredAttributeKey(setName: string, name: string): string;
80
+ /**
81
+ * Fold an entity's structured branches into its flat attribute record.
82
+ * Structured values overwrite same-key flat attributes — the typed
83
+ * branch is the newer write path, so it wins deterministically.
84
+ */
85
+ export declare function flattenStructuredBranches(json: {
86
+ attributes: Record<string, unknown>;
87
+ } & StructuredBranchesJSON, options?: FlattenOptions): Record<string, unknown>;
88
+ export interface InflatedAttributes extends StructuredBranchesJSON {
89
+ /** Whatever didn't inflate — stays in the flat attributes branch. */
90
+ attributes: Record<string, unknown>;
91
+ geometryRefRecord?: GeometryRefRecord;
92
+ /** Embedded geometry records to recreate in the doc's geometry map, if carried. */
93
+ geometryCarriers: GeometryRefCarrier[];
94
+ }
95
+ /**
96
+ * Inverse of `flattenStructuredBranches`: split an IFCX attribute
97
+ * record into the flat remainder and the structured branches. Keys
98
+ * whose values don't pass the shape gates stay flat (legacy migrated
99
+ * raw values, foreign data under colliding namespaces).
100
+ */
101
+ export declare function inflateStructuredAttributes(attributes: Record<string, unknown>): InflatedAttributes;
102
+ /**
103
+ * `FlattenOptions.geometryRecordFor` backed by `doc`'s geometry map.
104
+ * The CRDT version vector is replica bookkeeping and never travels.
105
+ */
106
+ export declare function geometryRecordLookup(doc: Y.Doc): (geomId: string) => Omit<GeometryRefCarrier, 'geomId'> | undefined;
107
+ //# sourceMappingURL=structured-attrs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structured-attrs.d.ts","sourceRoot":"","sources":["../../src/snapshot/structured-attrs.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAgB,eAAe,EAAqC,MAAM,gBAAgB,CAAC;AAClG,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAGL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,aAAa,EACnB,MAAM,kBAAkB,CAAC;AAI1B,OAAO,EAAE,eAAe,EAAE,CAAC;AAa3B;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,aAAa,CAE5E;AAaD,2EAA2E;AAC3E,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAAC;IACrD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,eAAe,EAAE,iBAAiB,EAAE,CAAC;IACrC,SAAS,EAAE,kBAAkB,EAAE,CAAC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,GAAG,SAAS,CAAC;CACxF;AAED,sDAAsD;AACtD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5E;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,sBAAsB,EACtE,OAAO,GAAE,cAAmB,GAC3B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA+BzB;AAED,MAAM,WAAW,kBAAmB,SAAQ,sBAAsB;IAChE,qEAAqE;IACrE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACpC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,mFAAmF;IACnF,gBAAgB,EAAE,kBAAkB,EAAE,CAAC;CACxC;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CACzC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAClC,kBAAkB,CA+FpB;AAOD;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,CAAC,CAAC,GAAG,GACT,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC,kBAAkB,EAAE,QAAQ,CAAC,GAAG,SAAS,CAqBpE"}
@@ -0,0 +1,250 @@
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
+ * Structured-branch ↔ namespaced-attribute conversion (#1031).
6
+ *
7
+ * The Y.Doc keeps psets / quantities / classifications / materials /
8
+ * geometryRef as dedicated CRDT branches so concurrent edits to
9
+ * different branches never conflict, but the IFCX wire type only has
10
+ * `attributes` / `children` / `inherits`. At the snapshot boundary the
11
+ * structured branches fold into ordinary attributes; `seedFromIfcx`
12
+ * re-inflates them, so structured edits survive snapshot → seed
13
+ * round-trips.
14
+ *
15
+ * Representation (the convention the MCP draft tools, the merge
16
+ * engine's `pset:`/`qset:` component keys, scope verification, and the
17
+ * IFC4→5 migration already share):
18
+ * - pset property → `bsi::ifc::v5a::<Set>::<Prop>` with the full
19
+ * typed PropertyValue object as the attribute value;
20
+ * - quantity → `bsi::ifc::v5a::<Qto_Set>::<Name>` with the raw
21
+ * number as the attribute value;
22
+ * - classifications / materials / geometryRef → single attributes
23
+ * under the `ifclite::` extension namespace (whole-array values:
24
+ * the Y.Array is the unit users edit, and merge granularity at the
25
+ * array level matches that).
26
+ *
27
+ * Inflation is shape-gated so legacy flat attributes written by the
28
+ * IFC4→IFC5 migration (raw values under the same v5a keys) stay flat:
29
+ * only PropertyValue-shaped objects inflate into psets, and numbers
30
+ * inflate into quantities unless the set is `Pset_`-named — the
31
+ * migration only ever emits `Pset_*` set names, so that exclusion is
32
+ * exactly the legacy population, and custom quantity-set names still
33
+ * round-trip. Both directions are inverse to each other, so
34
+ * flatten(inflate(x)) == x and a doc holding the same key in both the
35
+ * flat and structured branch serializes deterministically (structured
36
+ * wins).
37
+ */
38
+ import { IFCLITE_ATTR, V5A_ATTR_PREFIX, isTypedPropertyValue, parseV5aKey } from '@ifc-lite/ifcx';
39
+ import * as Y from 'yjs';
40
+ import { GEOMETRY_KEY, geometryMap, } from '../doc/schema.js';
41
+ // Re-exported for existing consumers; the canonical definition lives in
42
+ // @ifc-lite/ifcx next to the routing rule that shares the dialect.
43
+ export { V5A_ATTR_PREFIX };
44
+ /**
45
+ * Numbers under `Pset_*` sets never inflate into quantities: the
46
+ * IFC4→IFC5 migration writes raw scalars under `Pset_*` keys only, so
47
+ * this exclusion keeps exactly that legacy population flat while any
48
+ * other set name (Qto_* or custom) round-trips as a quantity.
49
+ */
50
+ const PSET_SET_RE = /^Pset_/;
51
+ /** `Qto_*` members route to quantities even when wrapped in a typed record. */
52
+ const QTO_SET_RE = /^Qto_/;
53
+ /**
54
+ * Shape test for the typed PropertyValue record — the canonical wire
55
+ * shape every writer and reader shares (`isTypedPropertyValue` in
56
+ * `@ifc-lite/ifcx`). Strict on purpose: legacy migrated attributes
57
+ * carry raw scalars, never `{type, value}` objects, so this is what
58
+ * disambiguates pset inflation from "leave it as a flat attribute".
59
+ */
60
+ export function isPropertyValueShaped(value) {
61
+ return isTypedPropertyValue(value);
62
+ }
63
+ function isClassificationRefShaped(value) {
64
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
65
+ return false;
66
+ const record = value;
67
+ return typeof record.system === 'string' && typeof record.code === 'string';
68
+ }
69
+ function isMaterialAssignmentShaped(value) {
70
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
71
+ return false;
72
+ return typeof value.materialId === 'string';
73
+ }
74
+ /** Attribute key for one pset property / quantity. */
75
+ export function structuredAttributeKey(setName, name) {
76
+ return `${V5A_ATTR_PREFIX}${setName}::${name}`;
77
+ }
78
+ /**
79
+ * Fold an entity's structured branches into its flat attribute record.
80
+ * Structured values overwrite same-key flat attributes — the typed
81
+ * branch is the newer write path, so it wins deterministically.
82
+ */
83
+ export function flattenStructuredBranches(json, options = {}) {
84
+ const out = { ...json.attributes };
85
+ for (const [setName, props] of Object.entries(json.psets)) {
86
+ for (const [propName, value] of Object.entries(props)) {
87
+ out[structuredAttributeKey(setName, propName)] = { ...value };
88
+ }
89
+ }
90
+ for (const [setName, qtys] of Object.entries(json.quantities)) {
91
+ for (const [qtyName, value] of Object.entries(qtys)) {
92
+ out[structuredAttributeKey(setName, qtyName)] = value;
93
+ }
94
+ }
95
+ if (json.classifications.length > 0) {
96
+ out[IFCLITE_ATTR.CLASSIFICATIONS] = json.classifications.map((ref) => ({ ...ref }));
97
+ }
98
+ if (json.materials.length > 0) {
99
+ out[IFCLITE_ATTR.MATERIALS] = json.materials.map((mat) => ({ ...mat }));
100
+ }
101
+ if (json.geometryRefs.length > 0) {
102
+ // One ref keeps the legacy scalar wire shape (string or carrier) so
103
+ // single-geometry snapshots stay byte-identical; several refs ride as
104
+ // an ordered list of the same per-ref shapes.
105
+ const entries = json.geometryRefs.map((geomId) => {
106
+ const record = options.geometryRecordFor?.(geomId);
107
+ return record ? { geomId, ...record } : geomId;
108
+ });
109
+ out[IFCLITE_ATTR.GEOMETRY_REF] = entries.length === 1 ? entries[0] : entries;
110
+ }
111
+ return out;
112
+ }
113
+ /**
114
+ * Inverse of `flattenStructuredBranches`: split an IFCX attribute
115
+ * record into the flat remainder and the structured branches. Keys
116
+ * whose values don't pass the shape gates stay flat (legacy migrated
117
+ * raw values, foreign data under colliding namespaces).
118
+ */
119
+ export function inflateStructuredAttributes(attributes) {
120
+ const flat = {};
121
+ const psets = {};
122
+ const quantities = {};
123
+ let classifications = [];
124
+ let materials = [];
125
+ let geometryRefs = [];
126
+ const geometryCarriers = [];
127
+ for (const [key, value] of Object.entries(attributes)) {
128
+ if (key === IFCLITE_ATTR.CLASSIFICATIONS) {
129
+ if (Array.isArray(value) && value.every(isClassificationRefShaped)) {
130
+ classifications = value.map((ref) => ({ ...ref }));
131
+ continue;
132
+ }
133
+ flat[key] = value;
134
+ continue;
135
+ }
136
+ if (key === IFCLITE_ATTR.MATERIALS) {
137
+ if (Array.isArray(value) && value.every(isMaterialAssignmentShaped)) {
138
+ materials = value.map((mat) => ({ ...mat }));
139
+ continue;
140
+ }
141
+ flat[key] = value;
142
+ continue;
143
+ }
144
+ if (key === IFCLITE_ATTR.GEOMETRY_REF) {
145
+ // Scalar (string or carrier) is the single-ref wire shape; a list of
146
+ // the same per-ref shapes carries multi-geometry entities. Anything
147
+ // else stays flat.
148
+ const entries = Array.isArray(value) ? value : [value];
149
+ const ids = [];
150
+ const carriers = [];
151
+ let recognized = entries.length > 0;
152
+ for (const entry of entries) {
153
+ if (typeof entry === 'string') {
154
+ ids.push(entry);
155
+ }
156
+ else if (isGeometryRefCarrierShaped(entry)) {
157
+ ids.push(entry.geomId);
158
+ carriers.push({ ...entry });
159
+ }
160
+ else {
161
+ recognized = false;
162
+ break;
163
+ }
164
+ }
165
+ if (recognized) {
166
+ geometryRefs = ids;
167
+ geometryCarriers.push(...carriers);
168
+ continue;
169
+ }
170
+ flat[key] = value;
171
+ continue;
172
+ }
173
+ {
174
+ const v5a = parseV5aKey(key);
175
+ if (v5a) {
176
+ const { setName, name } = v5a;
177
+ // Qto_* members are quantities before anything else: a typed
178
+ // record under a quantity set (e.g. written by a draft
179
+ // set_property op) unwraps to its number — otherwise the value
180
+ // would land in psets and compete with later quantity edits on
181
+ // the same wire key. The quantities branch stores plain numbers,
182
+ // so the raw number is the canonical re-flattened shape.
183
+ if (QTO_SET_RE.test(setName)) {
184
+ const candidate = isPropertyValueShaped(value) ? value.value : value;
185
+ if (typeof candidate === 'number' && Number.isFinite(candidate)) {
186
+ (quantities[setName] ??= {})[name] = candidate;
187
+ continue;
188
+ }
189
+ }
190
+ if (isPropertyValueShaped(value)) {
191
+ (psets[setName] ??= {})[name] = { ...value };
192
+ continue;
193
+ }
194
+ if (typeof value === 'number' && Number.isFinite(value) && !PSET_SET_RE.test(setName)) {
195
+ (quantities[setName] ??= {})[name] = value;
196
+ continue;
197
+ }
198
+ }
199
+ }
200
+ flat[key] = value;
201
+ }
202
+ return {
203
+ attributes: flat,
204
+ psets,
205
+ quantities,
206
+ classifications,
207
+ materials,
208
+ geometryRefs,
209
+ geometryRefRecord: geometryRefs.length > 0 ? { geomIds: geometryRefs } : undefined,
210
+ geometryCarriers,
211
+ };
212
+ }
213
+ function isGeometryRefCarrierShaped(value) {
214
+ if (value === null || typeof value !== 'object' || Array.isArray(value))
215
+ return false;
216
+ return typeof value.geomId === 'string';
217
+ }
218
+ /**
219
+ * `FlattenOptions.geometryRecordFor` backed by `doc`'s geometry map.
220
+ * The CRDT version vector is replica bookkeeping and never travels.
221
+ */
222
+ export function geometryRecordLookup(doc) {
223
+ return (geomId) => {
224
+ const entry = geometryMap(doc).get(geomId);
225
+ if (!entry)
226
+ return undefined;
227
+ const record = {};
228
+ const type = entry.get(GEOMETRY_KEY.TYPE);
229
+ if (typeof type === 'string')
230
+ record.type = type;
231
+ const source = entry.get(GEOMETRY_KEY.SOURCE);
232
+ if (typeof source === 'string')
233
+ record.source = source;
234
+ const blobHash = entry.get(GEOMETRY_KEY.BLOB_HASH);
235
+ if (typeof blobHash === 'string')
236
+ record.blobHash = blobHash;
237
+ const params = entry.get(GEOMETRY_KEY.PARAMS);
238
+ if (params instanceof Y.Map && params.size > 0) {
239
+ const plain = {};
240
+ for (const [k, v] of params.entries())
241
+ plain[k] = v;
242
+ record.params = plain;
243
+ }
244
+ const bbox = entry.get(GEOMETRY_KEY.BBOX);
245
+ if (Array.isArray(bbox))
246
+ record.bbox = bbox;
247
+ return record;
248
+ };
249
+ }
250
+ //# sourceMappingURL=structured-attrs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structured-attrs.js","sourceRoot":"","sources":["../../src/snapshot/structured-attrs.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,10 @@
4
4
  * Round-trips with `seedFromIfcx`: seeding a doc, snapshotting, then
5
5
  * seeding a fresh doc from the snapshot must produce structurally equal
6
6
  * Y states (verified by tests).
7
+ *
8
+ * Structured branches (psets / quantities / classifications / materials
9
+ * / geometryRef) fold into namespaced attributes on the wire — see
10
+ * `structured-attrs.ts` for the representation contract (#1031).
7
11
  */
8
12
  import type { IfcxFile } from '@ifc-lite/ifcx';
9
13
  import * as Y from 'yjs';
@@ -1 +1 @@
1
- {"version":3,"file":"to-ifcx.d.ts","sourceRoot":"","sources":["../../src/snapshot/to-ifcx.ts"],"names":[],"mappings":"AAIA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAoC,MAAM,gBAAgB,CAAC;AACjF,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAIzB,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAiDlF;AAED,yCAAyC;AACzC,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,UAAO,GAAG,MAAM,CAEnE"}
1
+ {"version":3,"file":"to-ifcx.d.ts","sourceRoot":"","sources":["../../src/snapshot/to-ifcx.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAoC,MAAM,gBAAgB,CAAC;AACjF,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAKzB,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kDAAkD;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wCAAwC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4BAA4B;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAmDlF;AAED,yCAAyC;AACzC,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,MAAM,UAAO,GAAG,MAAM,CAEnE"}
@@ -3,6 +3,7 @@
3
3
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
4
  import { entityToJSON, iterEntities } from '../doc/entity.js';
5
5
  import { metaMap } from '../doc/schema.js';
6
+ import { flattenStructuredBranches, geometryRecordLookup } from './structured-attrs.js';
6
7
  export function snapshotToIfcx(doc, options = {}) {
7
8
  const meta = metaMap(doc);
8
9
  const seededHeader = meta.get('header') ?? undefined;
@@ -16,6 +17,7 @@ export function snapshotToIfcx(doc, options = {}) {
16
17
  timestamp: options.timestamp ?? new Date().toISOString(),
17
18
  };
18
19
  const data = [];
20
+ const geometryRecordFor = geometryRecordLookup(doc);
19
21
  for (const [path, entity] of iterEntities(doc)) {
20
22
  const json = entityToJSON(entity);
21
23
  const node = { path };
@@ -35,8 +37,9 @@ export function snapshotToIfcx(doc, options = {}) {
35
37
  for (const k of inheritsKeys)
36
38
  node.inherits[k] = json.inherits[k];
37
39
  }
38
- if (Object.keys(json.attributes).length > 0) {
39
- node.attributes = { ...json.attributes };
40
+ const attributes = flattenStructuredBranches(json, { geometryRecordFor });
41
+ if (Object.keys(attributes).length > 0) {
42
+ node.attributes = attributes;
40
43
  }
41
44
  data.push(node);
42
45
  }
@@ -1 +1 @@
1
- {"version":3,"file":"to-ifcx.js","sourceRoot":"","sources":["../../src/snapshot/to-ifcx.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"to-ifcx.js","sourceRoot":"","sources":["../../src/snapshot/to-ifcx.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ifc-lite/collab",
3
- "version": "0.2.6",
3
+ "version": "0.3.0",
4
4
  "description": "Real-time collaborative BIM via CRDT on IFCX",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -39,9 +39,9 @@
39
39
  "y-protocols": "^1.0.6",
40
40
  "y-websocket": "^3.0.0",
41
41
  "yjs": "^13.6.31",
42
- "@ifc-lite/ifcx": "^2.2.2",
43
- "@ifc-lite/mutations": "^1.18.1",
44
- "@ifc-lite/data": "^2.5.2"
42
+ "@ifc-lite/data": "^2.5.3",
43
+ "@ifc-lite/ifcx": "^2.3.0",
44
+ "@ifc-lite/mutations": "^1.19.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "typescript": "^6.0.3",