@ifc-lite/collab 0.2.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 (219) hide show
  1. package/LICENSE +373 -0
  2. package/README.md +92 -0
  3. package/dist/awareness/agent.d.ts +36 -0
  4. package/dist/awareness/agent.d.ts.map +1 -0
  5. package/dist/awareness/agent.js +39 -0
  6. package/dist/awareness/agent.js.map +1 -0
  7. package/dist/awareness/color.d.ts +31 -0
  8. package/dist/awareness/color.d.ts.map +1 -0
  9. package/dist/awareness/color.js +61 -0
  10. package/dist/awareness/color.js.map +1 -0
  11. package/dist/awareness/index.d.ts +6 -0
  12. package/dist/awareness/index.d.ts.map +1 -0
  13. package/dist/awareness/index.js +9 -0
  14. package/dist/awareness/index.js.map +1 -0
  15. package/dist/awareness/overlay.d.ts +59 -0
  16. package/dist/awareness/overlay.d.ts.map +1 -0
  17. package/dist/awareness/overlay.js +110 -0
  18. package/dist/awareness/overlay.js.map +1 -0
  19. package/dist/awareness/presence.d.ts +95 -0
  20. package/dist/awareness/presence.d.ts.map +1 -0
  21. package/dist/awareness/presence.js +114 -0
  22. package/dist/awareness/presence.js.map +1 -0
  23. package/dist/awareness/render.d.ts +58 -0
  24. package/dist/awareness/render.d.ts.map +1 -0
  25. package/dist/awareness/render.js +66 -0
  26. package/dist/awareness/render.js.map +1 -0
  27. package/dist/branch/branch-tree.d.ts +40 -0
  28. package/dist/branch/branch-tree.d.ts.map +1 -0
  29. package/dist/branch/branch-tree.js +66 -0
  30. package/dist/branch/branch-tree.js.map +1 -0
  31. package/dist/branch/branch.d.ts +44 -0
  32. package/dist/branch/branch.d.ts.map +1 -0
  33. package/dist/branch/branch.js +109 -0
  34. package/dist/branch/branch.js.map +1 -0
  35. package/dist/branch/history-automerge.d.ts +31 -0
  36. package/dist/branch/history-automerge.d.ts.map +1 -0
  37. package/dist/branch/history-automerge.js +237 -0
  38. package/dist/branch/history-automerge.js.map +1 -0
  39. package/dist/branch/history.d.ts +147 -0
  40. package/dist/branch/history.d.ts.map +1 -0
  41. package/dist/branch/history.js +223 -0
  42. package/dist/branch/history.js.map +1 -0
  43. package/dist/branch/index.d.ts +5 -0
  44. package/dist/branch/index.d.ts.map +1 -0
  45. package/dist/branch/index.js +8 -0
  46. package/dist/branch/index.js.map +1 -0
  47. package/dist/conflicts/detector.d.ts +52 -0
  48. package/dist/conflicts/detector.d.ts.map +1 -0
  49. package/dist/conflicts/detector.js +226 -0
  50. package/dist/conflicts/detector.js.map +1 -0
  51. package/dist/conflicts/index.d.ts +3 -0
  52. package/dist/conflicts/index.d.ts.map +1 -0
  53. package/dist/conflicts/index.js +6 -0
  54. package/dist/conflicts/index.js.map +1 -0
  55. package/dist/conflicts/ui-bridge.d.ts +80 -0
  56. package/dist/conflicts/ui-bridge.d.ts.map +1 -0
  57. package/dist/conflicts/ui-bridge.js +126 -0
  58. package/dist/conflicts/ui-bridge.js.map +1 -0
  59. package/dist/doc/entity.d.ts +84 -0
  60. package/dist/doc/entity.d.ts.map +1 -0
  61. package/dist/doc/entity.js +345 -0
  62. package/dist/doc/entity.js.map +1 -0
  63. package/dist/doc/geometry.d.ts +39 -0
  64. package/dist/doc/geometry.d.ts.map +1 -0
  65. package/dist/doc/geometry.js +99 -0
  66. package/dist/doc/geometry.js.map +1 -0
  67. package/dist/doc/index.d.ts +8 -0
  68. package/dist/doc/index.d.ts.map +1 -0
  69. package/dist/doc/index.js +11 -0
  70. package/dist/doc/index.js.map +1 -0
  71. package/dist/doc/migration-ifc4-to-ifc4x3.d.ts +21 -0
  72. package/dist/doc/migration-ifc4-to-ifc4x3.d.ts.map +1 -0
  73. package/dist/doc/migration-ifc4-to-ifc4x3.js +55 -0
  74. package/dist/doc/migration-ifc4-to-ifc4x3.js.map +1 -0
  75. package/dist/doc/relationship.d.ts +27 -0
  76. package/dist/doc/relationship.d.ts.map +1 -0
  77. package/dist/doc/relationship.js +110 -0
  78. package/dist/doc/relationship.js.map +1 -0
  79. package/dist/doc/schema-version.d.ts +47 -0
  80. package/dist/doc/schema-version.d.ts.map +1 -0
  81. package/dist/doc/schema-version.js +41 -0
  82. package/dist/doc/schema-version.js.map +1 -0
  83. package/dist/doc/schema.d.ts +131 -0
  84. package/dist/doc/schema.d.ts.map +1 -0
  85. package/dist/doc/schema.js +117 -0
  86. package/dist/doc/schema.js.map +1 -0
  87. package/dist/doc/units.d.ts +45 -0
  88. package/dist/doc/units.d.ts.map +1 -0
  89. package/dist/doc/units.js +120 -0
  90. package/dist/doc/units.js.map +1 -0
  91. package/dist/federation/bridge.d.ts +34 -0
  92. package/dist/federation/bridge.d.ts.map +1 -0
  93. package/dist/federation/bridge.js +52 -0
  94. package/dist/federation/bridge.js.map +1 -0
  95. package/dist/federation/index.d.ts +4 -0
  96. package/dist/federation/index.d.ts.map +1 -0
  97. package/dist/federation/index.js +7 -0
  98. package/dist/federation/index.js.map +1 -0
  99. package/dist/federation/resolver.d.ts +58 -0
  100. package/dist/federation/resolver.d.ts.map +1 -0
  101. package/dist/federation/resolver.js +43 -0
  102. package/dist/federation/resolver.js.map +1 -0
  103. package/dist/federation/session.d.ts +79 -0
  104. package/dist/federation/session.d.ts.map +1 -0
  105. package/dist/federation/session.js +126 -0
  106. package/dist/federation/session.js.map +1 -0
  107. package/dist/geometry/blob-store.d.ts +106 -0
  108. package/dist/geometry/blob-store.d.ts.map +1 -0
  109. package/dist/geometry/blob-store.js +266 -0
  110. package/dist/geometry/blob-store.js.map +1 -0
  111. package/dist/geometry/csg.d.ts +63 -0
  112. package/dist/geometry/csg.d.ts.map +1 -0
  113. package/dist/geometry/csg.js +101 -0
  114. package/dist/geometry/csg.js.map +1 -0
  115. package/dist/geometry/determinism.d.ts +45 -0
  116. package/dist/geometry/determinism.d.ts.map +1 -0
  117. package/dist/geometry/determinism.js +92 -0
  118. package/dist/geometry/determinism.js.map +1 -0
  119. package/dist/geometry/gc.d.ts +63 -0
  120. package/dist/geometry/gc.d.ts.map +1 -0
  121. package/dist/geometry/gc.js +109 -0
  122. package/dist/geometry/gc.js.map +1 -0
  123. package/dist/geometry/index.d.ts +6 -0
  124. package/dist/geometry/index.d.ts.map +1 -0
  125. package/dist/geometry/index.js +9 -0
  126. package/dist/geometry/index.js.map +1 -0
  127. package/dist/geometry/parametric.d.ts +92 -0
  128. package/dist/geometry/parametric.d.ts.map +1 -0
  129. package/dist/geometry/parametric.js +200 -0
  130. package/dist/geometry/parametric.js.map +1 -0
  131. package/dist/index.d.ts +27 -0
  132. package/dist/index.d.ts.map +1 -0
  133. package/dist/index.js +46 -0
  134. package/dist/index.js.map +1 -0
  135. package/dist/mutations/bind.d.ts +56 -0
  136. package/dist/mutations/bind.d.ts.map +1 -0
  137. package/dist/mutations/bind.js +68 -0
  138. package/dist/mutations/bind.js.map +1 -0
  139. package/dist/mutations/index.d.ts +2 -0
  140. package/dist/mutations/index.d.ts.map +1 -0
  141. package/dist/mutations/index.js +5 -0
  142. package/dist/mutations/index.js.map +1 -0
  143. package/dist/perf/benchmark.d.ts +25 -0
  144. package/dist/perf/benchmark.d.ts.map +1 -0
  145. package/dist/perf/benchmark.js +97 -0
  146. package/dist/perf/benchmark.js.map +1 -0
  147. package/dist/perf/index.d.ts +3 -0
  148. package/dist/perf/index.d.ts.map +1 -0
  149. package/dist/perf/index.js +6 -0
  150. package/dist/perf/index.js.map +1 -0
  151. package/dist/perf/latency.d.ts +39 -0
  152. package/dist/perf/latency.d.ts.map +1 -0
  153. package/dist/perf/latency.js +79 -0
  154. package/dist/perf/latency.js.map +1 -0
  155. package/dist/privacy.d.ts +45 -0
  156. package/dist/privacy.d.ts.map +1 -0
  157. package/dist/privacy.js +66 -0
  158. package/dist/privacy.js.map +1 -0
  159. package/dist/providers/indexeddb.d.ts +37 -0
  160. package/dist/providers/indexeddb.d.ts.map +1 -0
  161. package/dist/providers/indexeddb.js +45 -0
  162. package/dist/providers/indexeddb.js.map +1 -0
  163. package/dist/providers/webrtc.d.ts +40 -0
  164. package/dist/providers/webrtc.d.ts.map +1 -0
  165. package/dist/providers/webrtc.js +81 -0
  166. package/dist/providers/webrtc.js.map +1 -0
  167. package/dist/providers/websocket.d.ts +45 -0
  168. package/dist/providers/websocket.d.ts.map +1 -0
  169. package/dist/providers/websocket.js +56 -0
  170. package/dist/providers/websocket.js.map +1 -0
  171. package/dist/security/e2e.d.ts +54 -0
  172. package/dist/security/e2e.d.ts.map +1 -0
  173. package/dist/security/e2e.js +147 -0
  174. package/dist/security/e2e.js.map +1 -0
  175. package/dist/security/index.d.ts +2 -0
  176. package/dist/security/index.d.ts.map +1 -0
  177. package/dist/security/index.js +5 -0
  178. package/dist/security/index.js.map +1 -0
  179. package/dist/session.d.ts +79 -0
  180. package/dist/session.d.ts.map +1 -0
  181. package/dist/session.js +112 -0
  182. package/dist/session.js.map +1 -0
  183. package/dist/snapshot/from-ifcx.d.ts +24 -0
  184. package/dist/snapshot/from-ifcx.d.ts.map +1 -0
  185. package/dist/snapshot/from-ifcx.js +93 -0
  186. package/dist/snapshot/from-ifcx.js.map +1 -0
  187. package/dist/snapshot/index.d.ts +6 -0
  188. package/dist/snapshot/index.d.ts.map +1 -0
  189. package/dist/snapshot/index.js +9 -0
  190. package/dist/snapshot/index.js.map +1 -0
  191. package/dist/snapshot/layers.d.ts +56 -0
  192. package/dist/snapshot/layers.d.ts.map +1 -0
  193. package/dist/snapshot/layers.js +82 -0
  194. package/dist/snapshot/layers.js.map +1 -0
  195. package/dist/snapshot/minimal-layer.d.ts +40 -0
  196. package/dist/snapshot/minimal-layer.d.ts.map +1 -0
  197. package/dist/snapshot/minimal-layer.js +123 -0
  198. package/dist/snapshot/minimal-layer.js.map +1 -0
  199. package/dist/snapshot/to-ifcx.d.ts +26 -0
  200. package/dist/snapshot/to-ifcx.d.ts.map +1 -0
  201. package/dist/snapshot/to-ifcx.js +54 -0
  202. package/dist/snapshot/to-ifcx.js.map +1 -0
  203. package/dist/snapshot/worker.d.ts +45 -0
  204. package/dist/snapshot/worker.d.ts.map +1 -0
  205. package/dist/snapshot/worker.js +73 -0
  206. package/dist/snapshot/worker.js.map +1 -0
  207. package/dist/sync/room.d.ts +15 -0
  208. package/dist/sync/room.d.ts.map +1 -0
  209. package/dist/sync/room.js +20 -0
  210. package/dist/sync/room.js.map +1 -0
  211. package/dist/undo.d.ts +25 -0
  212. package/dist/undo.d.ts.map +1 -0
  213. package/dist/undo.js +37 -0
  214. package/dist/undo.js.map +1 -0
  215. package/dist/viewer-bridge.d.ts +27 -0
  216. package/dist/viewer-bridge.d.ts.map +1 -0
  217. package/dist/viewer-bridge.js +82 -0
  218. package/dist/viewer-bridge.js.map +1 -0
  219. package/package.json +83 -0
@@ -0,0 +1,117 @@
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
+ * Y.Doc schema for the collaborative BIM runtime.
6
+ *
7
+ * Mirrors the spec §5 data model, adapted to the actual IFCX wire shape
8
+ * (path + flat namespaced attributes + role→path children).
9
+ */
10
+ import * as Y from 'yjs';
11
+ /** Top-level shared-type names. */
12
+ export const TOP = {
13
+ ENTITIES: 'entities',
14
+ RELATIONSHIPS: 'relationships',
15
+ GEOMETRY: 'geometry',
16
+ META: 'meta',
17
+ };
18
+ /** Origin tag used for transactions originated by the local CollabSession. */
19
+ export const LOCAL_ORIGIN = Symbol.for('@ifc-lite/collab/local-origin');
20
+ /** Origin tag for transactions originated by snapshot seeding. */
21
+ export const SEED_ORIGIN = Symbol.for('@ifc-lite/collab/seed-origin');
22
+ /** Origin tag for transactions originated by undo/redo. */
23
+ export const UNDO_ORIGIN = Symbol.for('@ifc-lite/collab/undo-origin');
24
+ /**
25
+ * Per-entity Y.Map keys.
26
+ *
27
+ * Each entity is a Y.Map with these well-known sub-maps. Sub-maps are
28
+ * themselves Y.Maps so concurrent edits to different sub-maps never
29
+ * conflict.
30
+ */
31
+ export const ENTITY_KEY = {
32
+ /** IFCX `attributes` — flat record keyed by namespaced names. */
33
+ ATTRIBUTES: 'attributes',
34
+ /** IFCX `children` — role → path. */
35
+ CHILDREN: 'children',
36
+ /** IFCX `inherits` — role → path. */
37
+ INHERITS: 'inherits',
38
+ /** Property sets, grouped: psetName → propName → PropertyValue. */
39
+ PSETS: 'psets',
40
+ /** Quantity sets: qsetName → quantityName → number. */
41
+ QUANTITIES: 'quantities',
42
+ /** Classification refs (Y.Array). */
43
+ CLASSIFICATIONS: 'classifications',
44
+ /** Material assignments (Y.Array). */
45
+ MATERIALS: 'materials',
46
+ /** Reference into the `geometry` top-level map. */
47
+ GEOMETRY_REF: 'geometryRef',
48
+ /** Provenance metadata: createdBy, createdAt, lastEditedBy, etc. */
49
+ META: 'meta',
50
+ };
51
+ /** Per-relationship Y.Map keys. */
52
+ export const RELATIONSHIP_KEY = {
53
+ IFC_CLASS: 'ifcClass',
54
+ SOURCE: 'source',
55
+ TARGETS: 'targets',
56
+ ATTRIBUTES: 'attributes',
57
+ };
58
+ /** Per-geometry Y.Map keys. */
59
+ export const GEOMETRY_KEY = {
60
+ TYPE: 'type',
61
+ SOURCE: 'source',
62
+ PARAMS: 'params',
63
+ BLOB_HASH: 'blobHash',
64
+ BBOX: 'bbox',
65
+ VERSION_VECTOR: 'versionVector',
66
+ };
67
+ /**
68
+ * Create a fresh, empty Y.Doc with the spec's top-level shared types.
69
+ *
70
+ * Idempotent: calling `getMap` twice returns the same shared type, so this
71
+ * is safe to call on an already-populated doc as well.
72
+ */
73
+ export function createCollabDoc(opts = {}) {
74
+ const doc = new Y.Doc({ gc: opts.gc ?? true });
75
+ // Force the shared types into existence so observers attached early see
76
+ // them. Y.Map is created lazily by getMap, so this is a no-op if they
77
+ // already exist.
78
+ doc.getMap(TOP.ENTITIES);
79
+ doc.getMap(TOP.RELATIONSHIPS);
80
+ doc.getMap(TOP.GEOMETRY);
81
+ doc.getMap(TOP.META);
82
+ return doc;
83
+ }
84
+ /** Top-level accessors. Centralized so refactors stay safe. */
85
+ export function entitiesMap(doc) {
86
+ return doc.getMap(TOP.ENTITIES);
87
+ }
88
+ export function relationshipsMap(doc) {
89
+ return doc.getMap(TOP.RELATIONSHIPS);
90
+ }
91
+ export function geometryMap(doc) {
92
+ return doc.getMap(TOP.GEOMETRY);
93
+ }
94
+ export function metaMap(doc) {
95
+ return doc.getMap(TOP.META);
96
+ }
97
+ /**
98
+ * Runtime invariant check used by tests and seeding.
99
+ *
100
+ * Throws if the Y.Doc does not have the expected shape. We check structural
101
+ * presence and type shape, not content, so an empty fresh doc passes.
102
+ */
103
+ export function assertSchemaInvariants(doc) {
104
+ const ents = doc.share.get(TOP.ENTITIES);
105
+ const rels = doc.share.get(TOP.RELATIONSHIPS);
106
+ const geom = doc.share.get(TOP.GEOMETRY);
107
+ if (!ents || !(ents instanceof Y.Map)) {
108
+ throw new Error(`@ifc-lite/collab: missing top-level Y.Map "${TOP.ENTITIES}"`);
109
+ }
110
+ if (!rels || !(rels instanceof Y.Map)) {
111
+ throw new Error(`@ifc-lite/collab: missing top-level Y.Map "${TOP.RELATIONSHIPS}"`);
112
+ }
113
+ if (!geom || !(geom instanceof Y.Map)) {
114
+ throw new Error(`@ifc-lite/collab: missing top-level Y.Map "${TOP.GEOMETRY}"`);
115
+ }
116
+ }
117
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/doc/schema.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Property unit conversion (spec §20 open problem #3).
3
+ *
4
+ * When a model's length unit changes (e.g. `m` → `mm`), numeric
5
+ * properties carrying a unit must auto-convert. This module ships a
6
+ * small, dependency-free converter for the IFC unit families we see
7
+ * most often in `Pset_*::*` properties: length, area, volume, angle.
8
+ *
9
+ * Real IFC schemas have far more units (mass, time, currency,
10
+ * frequency, …). We deliberately ship a minimal-but-correct subset
11
+ * that handles 95% of architectural / structural property data and
12
+ * leave the long tail to v1.0 + a published unit registry.
13
+ */
14
+ import * as Y from 'yjs';
15
+ export type UnitFamily = 'length' | 'area' | 'volume' | 'angle';
16
+ /** Detect which family a unit string belongs to (case-insensitive). */
17
+ export declare function familyOf(unit: string): UnitFamily | null;
18
+ /**
19
+ * Convert `value` from `from` units to `to` units. Returns `null` if
20
+ * either unit is unknown or they belong to different families.
21
+ */
22
+ export declare function convertValue(value: number, from: string, to: string): number | null;
23
+ export interface ConvertEntityUnitsOptions {
24
+ /** Forwarded to the transaction. */
25
+ origin?: unknown;
26
+ /** Override which families to touch. Defaults to all four. */
27
+ families?: ReadonlyArray<UnitFamily>;
28
+ }
29
+ export interface ConvertEntityUnitsReport {
30
+ /** How many `PropertyValue`s were converted. */
31
+ converted: number;
32
+ /** How many `PropertyValue`s were skipped because their unit didn't match `from`. */
33
+ skipped: number;
34
+ }
35
+ /**
36
+ * Walk every entity's Psets and convert numeric `PropertyValue`s
37
+ * carrying `unit === from` to `to`. The value is updated and the
38
+ * `unit` field is rewritten.
39
+ *
40
+ * Note: only converts within a single family at a time — call once per
41
+ * family pair (e.g. `convertEntityUnits(doc, 'mm', 'm')` for length,
42
+ * separately for area).
43
+ */
44
+ export declare function convertEntityUnits(doc: Y.Doc, from: string, to: string, options?: ConvertEntityUnitsOptions): ConvertEntityUnitsReport;
45
+ //# sourceMappingURL=units.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"units.d.ts","sourceRoot":"","sources":["../../src/doc/units.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAiDzB,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAShE,uEAAuE;AACvE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAMxD;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAWnF;AAED,MAAM,WAAW,yBAAyB;IACxC,oCAAoC;IACpC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,wBAAwB;IACvC,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,CAAC,CAAC,GAAG,EACV,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,EACV,OAAO,GAAE,yBAA8B,GACtC,wBAAwB,CAiC1B"}
@@ -0,0 +1,120 @@
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 { ENTITY_KEY, entitiesMap } from './schema.js';
5
+ /** SI-relative scale factors. `to_si = scale * value`. */
6
+ const LENGTH_TO_M = {
7
+ m: 1,
8
+ meter: 1,
9
+ meters: 1,
10
+ cm: 0.01,
11
+ mm: 0.001,
12
+ in: 0.0254,
13
+ inch: 0.0254,
14
+ ft: 0.3048,
15
+ feet: 0.3048,
16
+ };
17
+ const AREA_TO_M2 = {
18
+ 'm^2': 1,
19
+ m2: 1,
20
+ 'cm^2': 1e-4,
21
+ cm2: 1e-4,
22
+ 'mm^2': 1e-6,
23
+ mm2: 1e-6,
24
+ 'ft^2': 0.092903,
25
+ 'in^2': 0.00064516,
26
+ };
27
+ const VOLUME_TO_M3 = {
28
+ 'm^3': 1,
29
+ m3: 1,
30
+ 'cm^3': 1e-6,
31
+ cm3: 1e-6,
32
+ 'mm^3': 1e-9,
33
+ mm3: 1e-9,
34
+ liter: 0.001,
35
+ litre: 0.001,
36
+ l: 0.001,
37
+ };
38
+ const ANGLE_TO_RAD = {
39
+ rad: 1,
40
+ radian: 1,
41
+ radians: 1,
42
+ deg: Math.PI / 180,
43
+ degree: Math.PI / 180,
44
+ degrees: Math.PI / 180,
45
+ };
46
+ const FAMILY_TABLES = {
47
+ length: LENGTH_TO_M,
48
+ area: AREA_TO_M2,
49
+ volume: VOLUME_TO_M3,
50
+ angle: ANGLE_TO_RAD,
51
+ };
52
+ /** Detect which family a unit string belongs to (case-insensitive). */
53
+ export function familyOf(unit) {
54
+ const u = unit.toLowerCase();
55
+ for (const [family, table] of Object.entries(FAMILY_TABLES)) {
56
+ if (u in table)
57
+ return family;
58
+ }
59
+ return null;
60
+ }
61
+ /**
62
+ * Convert `value` from `from` units to `to` units. Returns `null` if
63
+ * either unit is unknown or they belong to different families.
64
+ */
65
+ export function convertValue(value, from, to) {
66
+ const fromLc = from.toLowerCase();
67
+ const toLc = to.toLowerCase();
68
+ const family = familyOf(fromLc);
69
+ if (!family)
70
+ return null;
71
+ if (familyOf(toLc) !== family)
72
+ return null;
73
+ const table = FAMILY_TABLES[family];
74
+ const fromScale = table[fromLc];
75
+ const toScale = table[toLc];
76
+ if (fromScale == null || toScale == null)
77
+ return null;
78
+ return (value * fromScale) / toScale;
79
+ }
80
+ /**
81
+ * Walk every entity's Psets and convert numeric `PropertyValue`s
82
+ * carrying `unit === from` to `to`. The value is updated and the
83
+ * `unit` field is rewritten.
84
+ *
85
+ * Note: only converts within a single family at a time — call once per
86
+ * family pair (e.g. `convertEntityUnits(doc, 'mm', 'm')` for length,
87
+ * separately for area).
88
+ */
89
+ export function convertEntityUnits(doc, from, to, options = {}) {
90
+ let converted = 0;
91
+ let skipped = 0;
92
+ doc.transact(() => {
93
+ entitiesMap(doc).forEach((entUntyped) => {
94
+ const entity = entUntyped;
95
+ const psets = entity.get(ENTITY_KEY.PSETS);
96
+ if (!psets)
97
+ return;
98
+ psets.forEach((psetUntyped) => {
99
+ const pset = psetUntyped;
100
+ pset.forEach((prop, propName) => {
101
+ if (!prop || prop.unit == null || typeof prop.value !== 'number')
102
+ return;
103
+ if (prop.unit.toLowerCase() !== from.toLowerCase()) {
104
+ skipped += 1;
105
+ return;
106
+ }
107
+ const newValue = convertValue(prop.value, from, to);
108
+ if (newValue == null) {
109
+ skipped += 1;
110
+ return;
111
+ }
112
+ pset.set(propName, { ...prop, value: newValue, unit: to });
113
+ converted += 1;
114
+ });
115
+ });
116
+ });
117
+ }, options.origin);
118
+ return { converted, skipped };
119
+ }
120
+ //# sourceMappingURL=units.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"units.js","sourceRoot":"","sources":["../../src/doc/units.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Bridge from `@ifc-lite/collab`'s `FederationResolver` to a
3
+ * legacy-STEP-shaped registry that uses numeric `expressId`s and an
4
+ * offset-based scheme (e.g. the `FederationRegistry` in
5
+ * `@ifc-lite/renderer`).
6
+ *
7
+ * The bridge keeps `@ifc-lite/collab` decoupled from the renderer
8
+ * package — apps wrap whichever registry they have with this helper.
9
+ *
10
+ * Example wiring:
11
+ *
12
+ * import { federationRegistry } from '@ifc-lite/renderer';
13
+ * import { createNumericRegistryAdapter } from '@ifc-lite/collab';
14
+ *
15
+ * const resolver = createNumericRegistryAdapter(federationRegistry);
16
+ *
17
+ * const fed = await createFederationSession({
18
+ * projectId, user, models, // …
19
+ * });
20
+ * // Pass `resolver` to wherever cross-model identifiers need to
21
+ * // be turned into numeric global ids for the renderer.
22
+ */
23
+ import type { FederationResolver } from './resolver.js';
24
+ /** Shape that `@ifc-lite/renderer.FederationRegistry` already implements. */
25
+ export interface NumericFederationRegistry {
26
+ toGlobalId(modelId: string, expressId: number): number;
27
+ fromGlobalId(globalId: number): {
28
+ modelId: string;
29
+ expressId: number;
30
+ } | null;
31
+ getModelForGlobalId(globalId: number): string | null;
32
+ }
33
+ export declare function createNumericRegistryAdapter(registry: NumericFederationRegistry): FederationResolver;
34
+ //# sourceMappingURL=bridge.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/federation/bridge.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,6EAA6E;AAC7E,MAAM,WAAW,yBAAyB;IACxC,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IACvD,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAC9E,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACtD;AAyBD,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,yBAAyB,GAClC,kBAAkB,CAuBpB"}
@@ -0,0 +1,52 @@
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
+ * Wrap a numeric-offset registry in our typed `FederationResolver`
6
+ * interface. We carry the underlying numeric global id as a string so
7
+ * `FederationRecord.refs.globalId: string` round-trips losslessly.
8
+ */
9
+ /**
10
+ * Parse a STEP express-id string as a strict positive decimal integer.
11
+ * Rejects everything `Number()` quietly accepts but is wrong for STEP
12
+ * ids: blank/whitespace strings, hex (`0x42`), scientific notation
13
+ * (`1e3`), floats, signed values, leading-zero forms beyond a single
14
+ * zero. Returning `null` instead of throwing so callers can decide
15
+ * whether the bad id is fatal (toGlobalId) or just skippable
16
+ * (fromGlobalId / getModelForGlobalId).
17
+ */
18
+ function parseExpressId(value) {
19
+ if (typeof value !== 'string')
20
+ return null;
21
+ if (!/^[1-9][0-9]*$/.test(value))
22
+ return null;
23
+ // Within JS safe-integer range — STEP files rarely exceed millions
24
+ // of entities, but reject anything that would lose precision.
25
+ const n = Number(value);
26
+ return Number.isSafeInteger(n) && n > 0 ? n : null;
27
+ }
28
+ export function createNumericRegistryAdapter(registry) {
29
+ return {
30
+ toGlobalId(modelId, localId) {
31
+ const expressId = parseExpressId(localId);
32
+ if (expressId === null) {
33
+ throw new Error(`@ifc-lite/collab: numeric registry adapter requires numeric local ids (positive decimal integers), got "${localId}"`);
34
+ }
35
+ return String(registry.toGlobalId(modelId, expressId));
36
+ },
37
+ fromGlobalId(globalId) {
38
+ const n = parseExpressId(globalId);
39
+ if (n === null)
40
+ return null;
41
+ const r = registry.fromGlobalId(n);
42
+ return r ? { modelId: r.modelId, globalId: String(r.expressId) } : null;
43
+ },
44
+ getModelForGlobalId(globalId) {
45
+ const n = parseExpressId(globalId);
46
+ if (n === null)
47
+ return null;
48
+ return registry.getModelForGlobalId(n);
49
+ },
50
+ };
51
+ }
52
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/federation/bridge.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAkC/D;;;;GAIG;AACH;;;;;;;;GAQG;AACH,SAAS,cAAc,CAAC,KAAa;IACnC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAC3C,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,mEAAmE;IACnE,8DAA8D;IAC9D,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACxB,OAAO,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,QAAmC;IAEnC,OAAO;QACL,UAAU,CAAC,OAAO,EAAE,OAAO;YACzB,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;YAC1C,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;gBACvB,MAAM,IAAI,KAAK,CACb,2GAA2G,OAAO,GAAG,CACtH,CAAC;YACJ,CAAC;YACD,OAAO,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;QACzD,CAAC;QACD,YAAY,CAAC,QAAQ;YACnB,MAAM,CAAC,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;YACnC,IAAI,CAAC,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC;YAC5B,MAAM,CAAC,GAAG,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;YACnC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1E,CAAC;QACD,mBAAmB,CAAC,QAAQ;YAC1B,MAAM,CAAC,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;YACnC,IAAI,CAAC,KAAK,IAAI;gBAAE,OAAO,IAAI,CAAC;YAC5B,OAAO,QAAQ,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,4 @@
1
+ export * from './session.js';
2
+ export * from './resolver.js';
3
+ export * from './bridge.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/federation/index.ts"],"names":[],"mappings":"AAIA,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,7 @@
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
+ export * from './session.js';
5
+ export * from './resolver.js';
6
+ export * from './bridge.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/federation/index.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAE/D,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * `FederationResolver` (spec §10.1, AGENTS.md §4).
3
+ *
4
+ * The CRDT layer stores cross-model references as `{ modelId, globalId
5
+ * }` pairs (`FederationRecord.refs`) and asks a resolver to translate
6
+ * between local and global identifiers when needed. We deliberately
7
+ * do NOT pull in `@ifc-lite/renderer`'s `FederationRegistry` here —
8
+ * apps that need it can wrap that class with this interface, and apps
9
+ * that already use IFCX (where path UUIDs are globally unique) can
10
+ * use the pass-through resolver shipped below.
11
+ *
12
+ * Adapter for `@ifc-lite/renderer`'s legacy STEP `FederationRegistry`:
13
+ *
14
+ * import { federationRegistry } from '@ifc-lite/renderer';
15
+ * import { type FederationResolver } from '@ifc-lite/collab';
16
+ *
17
+ * const resolver: FederationResolver = {
18
+ * toGlobalId(modelId, expressId) {
19
+ * return String(federationRegistry.toGlobalId(modelId, Number(expressId)));
20
+ * },
21
+ * fromGlobalId(globalId) {
22
+ * const r = federationRegistry.fromGlobalId(Number(globalId));
23
+ * return r ? { modelId: r.modelId, globalId: String(r.expressId) } : null;
24
+ * },
25
+ * getModelForGlobalId(globalId) {
26
+ * return federationRegistry.getModelForGlobalId(Number(globalId));
27
+ * },
28
+ * };
29
+ */
30
+ export interface ResolvedReference {
31
+ modelId: string;
32
+ globalId: string;
33
+ }
34
+ export interface FederationResolver {
35
+ /** Compose a `(modelId, localId)` pair into a global identifier. */
36
+ toGlobalId(modelId: string, localId: string): string;
37
+ /** Decompose a global identifier back into `(modelId, localId)`. Null if unknown. */
38
+ fromGlobalId(globalId: string): ResolvedReference | null;
39
+ /** Convenience: just the modelId. */
40
+ getModelForGlobalId(globalId: string): string | null;
41
+ }
42
+ /**
43
+ * Pass-through resolver for IFCX path-based identifiers.
44
+ *
45
+ * IFCX paths are UUIDs and are globally unique by construction —
46
+ * `toGlobalId` returns `localId` unchanged, and `fromGlobalId` cannot
47
+ * recover the originating model without external state, so it returns
48
+ * null. Apps that need bidirectional resolution should plug in a
49
+ * registry-backed resolver instead.
50
+ */
51
+ export declare const passThroughResolver: FederationResolver;
52
+ /**
53
+ * Build a resolver backed by an explicit `(globalId → modelId, localId)`
54
+ * map. Useful when paths *aren't* globally unique (rare in IFCX) or
55
+ * when apps maintain their own registry.
56
+ */
57
+ export declare function createMapBackedResolver(table: Map<string, ResolvedReference>): FederationResolver;
58
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/federation/resolver.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACrD,qFAAqF;IACrF,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAAC;IACzD,qCAAqC;IACrC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;CACtD;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,EAAE,kBAUjC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,GACpC,kBAAkB,CAapB"}
@@ -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
+ /**
5
+ * Pass-through resolver for IFCX path-based identifiers.
6
+ *
7
+ * IFCX paths are UUIDs and are globally unique by construction —
8
+ * `toGlobalId` returns `localId` unchanged, and `fromGlobalId` cannot
9
+ * recover the originating model without external state, so it returns
10
+ * null. Apps that need bidirectional resolution should plug in a
11
+ * registry-backed resolver instead.
12
+ */
13
+ export const passThroughResolver = {
14
+ toGlobalId(_modelId, localId) {
15
+ return localId;
16
+ },
17
+ fromGlobalId() {
18
+ return null;
19
+ },
20
+ getModelForGlobalId() {
21
+ return null;
22
+ },
23
+ };
24
+ /**
25
+ * Build a resolver backed by an explicit `(globalId → modelId, localId)`
26
+ * map. Useful when paths *aren't* globally unique (rare in IFCX) or
27
+ * when apps maintain their own registry.
28
+ */
29
+ export function createMapBackedResolver(table) {
30
+ return {
31
+ toGlobalId(_modelId, localId) {
32
+ return localId;
33
+ },
34
+ fromGlobalId(globalId) {
35
+ const v = table.get(globalId);
36
+ return v ? { modelId: v.modelId, globalId: v.globalId } : null;
37
+ },
38
+ getModelForGlobalId(globalId) {
39
+ return table.get(globalId)?.modelId ?? null;
40
+ },
41
+ };
42
+ }
43
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/federation/resolver.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AA8C/D;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAuB;IACrD,UAAU,CAAC,QAAQ,EAAE,OAAO;QAC1B,OAAO,OAAO,CAAC;IACjB,CAAC;IACD,YAAY;QACV,OAAO,IAAI,CAAC;IACd,CAAC;IACD,mBAAmB;QACjB,OAAO,IAAI,CAAC;IACd,CAAC;CACF,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,KAAqC;IAErC,OAAO;QACL,UAAU,CAAC,QAAQ,EAAE,OAAO;YAC1B,OAAO,OAAO,CAAC;QACjB,CAAC;QACD,YAAY,CAAC,QAAQ;YACnB,MAAM,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC9B,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACjE,CAAC;QACD,mBAAmB,CAAC,QAAQ;YAC1B,OAAO,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,OAAO,IAAI,IAAI,CAAC;QAC9C,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * FederationSession (spec §10).
3
+ *
4
+ * A federated project is N model rooms (one Y.Doc each) plus one
5
+ * `_federation` Y.Doc that holds cross-model relationships, BCF topic
6
+ * refs, and federation-level views.
7
+ *
8
+ * This class composes existing per-model `CollabSession`s. Presence is
9
+ * project-scoped: a single awareness channel — backed by the
10
+ * `_federation` doc — broadcasts cursors and selections across every
11
+ * model. That's the §10.2 contract.
12
+ *
13
+ * The FederationSession does NOT reinvent the existing
14
+ * `FederationRegistry` (per `AGENTS.md` §4) — it stores cross-model
15
+ * references as `{ modelId, globalId }` pairs and asks the registry to
16
+ * resolve them upstream.
17
+ */
18
+ import * as Y from 'yjs';
19
+ import { type CollabSession, type CollabSessionOptions, type ProviderKind } from '../session.js';
20
+ import { type Presence, type UserIdentity } from '../awareness/presence.js';
21
+ export interface FederationSessionOptions {
22
+ projectId: string;
23
+ user: UserIdentity;
24
+ /** Initial set of models to load. More can be added later via `addModel`. */
25
+ models: string[];
26
+ provider?: ProviderKind;
27
+ serverUrl?: string;
28
+ token?: string;
29
+ WebSocketPolyfill?: unknown;
30
+ /** Forwarded to every per-model session. */
31
+ presence?: CollabSessionOptions['presence'];
32
+ }
33
+ /**
34
+ * A single cross-model record in `_federation`. Stored as plain JSON
35
+ * inside a Y.Map so concurrent edits to the same record's fields merge
36
+ * via LWW per field.
37
+ */
38
+ export interface FederationRecord {
39
+ /** Stable cross-model record ID. */
40
+ recordId: string;
41
+ /** 'clash', 'rfi', 'view', 'comment', custom… */
42
+ type: string;
43
+ refs: Array<{
44
+ modelId: string;
45
+ globalId: string;
46
+ }>;
47
+ /** Resolution status (free-form; common values: 'open' | 'discussed' | 'resolved'). */
48
+ resolution?: string;
49
+ /** BCF topic ID, if any. */
50
+ bcfTopicId?: string;
51
+ /** Free-form metadata. */
52
+ meta?: Record<string, unknown>;
53
+ }
54
+ export interface FederationSession {
55
+ readonly projectId: string;
56
+ readonly federationDoc: Y.Doc;
57
+ readonly federationRoomId: string;
58
+ readonly presence: Presence;
59
+ readonly user: UserIdentity;
60
+ /** Per-model sessions keyed by modelId. */
61
+ readonly models: ReadonlyMap<string, CollabSession>;
62
+ /** Add a model to the session. Idempotent. */
63
+ addModel(modelId: string): Promise<CollabSession>;
64
+ /** Remove a model from the session and dispose its resources. */
65
+ removeModel(modelId: string): Promise<void>;
66
+ /** All loaded model IDs. */
67
+ modelIds(): string[];
68
+ upsertRecord(record: FederationRecord): void;
69
+ getRecord(recordId: string): FederationRecord | undefined;
70
+ removeRecord(recordId: string): boolean;
71
+ listRecords(): FederationRecord[];
72
+ observeRecords(listener: (records: FederationRecord[]) => void): () => void;
73
+ /** Resolves once every loaded session has finished its initial sync. */
74
+ whenSynced(): Promise<void>;
75
+ dispose(): Promise<void>;
76
+ }
77
+ /** Build a federation session and pre-load `models`. */
78
+ export declare function createFederationSession(opts: FederationSessionOptions): Promise<FederationSession>;
79
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/federation/session.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,oBAAoB,EACzB,KAAK,YAAY,EAClB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAI5F,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,YAAY,CAAC;IACnB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,oBAAoB,CAAC,UAAU,CAAC,CAAC;CAC7C;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,oCAAoC;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACnD,uFAAuF;IACvF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC,GAAG,CAAC;IAC9B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAEpD,8CAA8C;IAC9C,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAClD,iEAAiE;IACjE,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5C,4BAA4B;IAC5B,QAAQ,IAAI,MAAM,EAAE,CAAC;IAGrB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC7C,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAAC;IAC1D,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IACxC,WAAW,IAAI,gBAAgB,EAAE,CAAC;IAClC,cAAc,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;IAE5E,wEAAwE;IACxE,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAID,wDAAwD;AACxD,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,iBAAiB,CAAC,CAiH5B"}