@ifc-lite/codegen 1.15.3 → 1.15.5

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 (41) hide show
  1. package/README.md +17 -14
  2. package/dist/serialization-generator.d.ts +7 -2
  3. package/dist/serialization-generator.d.ts.map +1 -1
  4. package/dist/serialization-generator.js +30 -301
  5. package/dist/serialization-generator.js.map +1 -1
  6. package/package.json +18 -7
  7. package/.turbo/turbo-build.log +0 -4
  8. package/CHANGELOG.md +0 -117
  9. package/INTEGRATION.md +0 -354
  10. package/generated/ifc4/entities.ts +0 -7400
  11. package/generated/ifc4/enums.ts +0 -2467
  12. package/generated/ifc4/index.ts +0 -17
  13. package/generated/ifc4/schema-registry.ts +0 -63186
  14. package/generated/ifc4/selects.ts +0 -315
  15. package/generated/ifc4/serializers.ts +0 -322
  16. package/generated/ifc4/test-compile.ts +0 -49
  17. package/generated/ifc4/type-ids.ts +0 -1682
  18. package/generated/ifc4/types.ts +0 -401
  19. package/generated/ifc4x3/entities.ts +0 -8300
  20. package/generated/ifc4x3/enums.ts +0 -3096
  21. package/generated/ifc4x3/index.ts +0 -17
  22. package/generated/ifc4x3/schema-registry.ts +0 -71489
  23. package/generated/ifc4x3/selects.ts +0 -312
  24. package/generated/ifc4x3/serializers.ts +0 -322
  25. package/generated/ifc4x3/test-compile.ts +0 -49
  26. package/generated/ifc4x3/type-ids.ts +0 -1882
  27. package/generated/ifc4x3/types.ts +0 -407
  28. package/src/cli.ts +0 -72
  29. package/src/crc32.ts +0 -77
  30. package/src/express-parser.ts +0 -457
  31. package/src/generator.ts +0 -268
  32. package/src/index.ts +0 -57
  33. package/src/rust-generator.ts +0 -714
  34. package/src/serialization-generator.ts +0 -343
  35. package/src/type-ids-generator.ts +0 -166
  36. package/src/typescript-generator.ts +0 -631
  37. package/test/express-parser.test.ts +0 -363
  38. package/test/integration.test.ts +0 -246
  39. package/test/typescript-generator.test.ts +0 -348
  40. package/tsconfig.json +0 -21
  41. package/vitest.config.ts +0 -18
package/README.md CHANGED
@@ -14,19 +14,25 @@ npm install --save-dev @ifc-lite/codegen
14
14
 
15
15
  ```bash
16
16
  # IFC4 (776 entities)
17
- npx ifc-lite-codegen ./schemas/IFC4.exp --out ./src/generated
17
+ node dist/cli.js schemas/IFC4_ADD2_TC1.exp --output ./generated/ifc4
18
18
 
19
19
  # IFC4X3 (876 entities, includes infrastructure: roads, bridges, alignments)
20
- npx ifc-lite-codegen ./schemas/IFC4X3.exp --out ./src/generated
20
+ node dist/cli.js schemas/IFC4X3.exp --output ./generated/ifc4x3
21
21
  ```
22
22
 
23
- Generated files (one per output directory):
23
+ Pass `--rust` to also emit Rust type tables (consumed by the ifc-lite Rust core).
24
24
 
25
- ```
26
- src/generated/
25
+ Generated files (one per output directory, e.g. `./generated/ifc4`):
26
+
27
+ ```text
28
+ generated/ifc4/
27
29
  ├── entities.ts ← TypeScript interfaces for every entity
30
+ ├── types.ts ← defined-type aliases
31
+ ├── enums.ts ← enum definitions
32
+ ├── selects.ts ← SELECT union types
28
33
  ├── schema-registry.ts ← runtime metadata (parent, attributes, ...)
29
- ├── types.ts ← enum unions and SELECT types
34
+ ├── type-ids.ts ← numeric type-id lookup tables
35
+ ├── serializers.ts ← STEP serializer bound to the schema registry
30
36
  └── index.ts ← barrel export
31
37
  ```
32
38
 
@@ -34,19 +40,16 @@ src/generated/
34
40
 
35
41
  ```typescript
36
42
  import { parseExpressSchema, generateTypeScript } from '@ifc-lite/codegen';
37
- import { writeFile } from 'node:fs/promises';
43
+ import { readFile, writeFile } from 'node:fs/promises';
38
44
 
39
- const schema = parseExpressSchema('./schemas/IFC4.exp');
45
+ const schema = parseExpressSchema(await readFile('./schemas/IFC4.exp', 'utf-8'));
40
46
 
41
47
  console.log(`Parsed ${schema.entities.length} entities, ${schema.types.length} types`);
42
48
 
43
- const generated = generateTypeScript(schema, {
44
- inheritanceChain: true,
45
- emitEnums: true,
46
- });
49
+ const generated = generateTypeScript(schema);
47
50
 
48
- await writeFile('./src/generated/entities.ts', generated.entities);
49
- await writeFile('./src/generated/schema-registry.ts', generated.schemaRegistry);
51
+ await writeFile('./generated/ifc4/entities.ts', generated.entities);
52
+ await writeFile('./generated/ifc4/schema-registry.ts', generated.schemaRegistry);
50
53
  ```
51
54
 
52
55
  ## What you get
@@ -1,11 +1,16 @@
1
1
  /**
2
2
  * Serialization Generator
3
3
  *
4
- * Generates TypeScript code for serializing IFC entities to STEP format.
4
+ * Emits the per-schema STEP serializer bundle file. The serialization LOGIC is
5
+ * schema-agnostic and lives once in `@ifc-lite/data`; this generator emits only
6
+ * a thin binding that re-exports those primitives and binds the bundle's
7
+ * `SCHEMA_REGISTRY` to the registry-coupled helpers. Keeping the logic in a
8
+ * single place means the generated copies can never drift from the runtime.
5
9
  */
6
10
  import type { ExpressSchema } from './express-parser.js';
7
11
  /**
8
- * Generate serialization support code
12
+ * Generate serialization support code — a thin re-export of the shared
13
+ * `@ifc-lite/data` STEP serializer with this schema's registry bound in.
9
14
  */
10
15
  export declare function generateSerializers(schema: ExpressSchema): string;
11
16
  //# sourceMappingURL=serialization-generator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"serialization-generator.d.ts","sourceRoot":"","sources":["../src/serialization-generator.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAyC,MAAM,qBAAqB,CAAC;AAGhG;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAsUjE"}
1
+ {"version":3,"file":"serialization-generator.d.ts","sourceRoot":"","sources":["../src/serialization-generator.ts"],"names":[],"mappings":"AAIA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,aAAa,GAAG,MAAM,CAqDjE"}
@@ -2,10 +2,11 @@
2
2
  * License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
4
  /**
5
- * Generate serialization support code
5
+ * Generate serialization support code — a thin re-export of the shared
6
+ * `@ifc-lite/data` STEP serializer with this schema's registry bound in.
6
7
  */
7
8
  export function generateSerializers(schema) {
8
- let code = `/* This Source Code Form is subject to the terms of the Mozilla Public
9
+ return `/* This Source Code Form is subject to the terms of the Mozilla Public
9
10
  * License, v. 2.0. If a copy of the MPL was not distributed with this
10
11
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
11
12
 
@@ -13,321 +14,49 @@ export function generateSerializers(schema) {
13
14
  * IFC Serialization Support
14
15
  * Generated from EXPRESS schema: ${schema.name}
15
16
  *
16
- * Utilities for serializing IFC entities to STEP format.
17
+ * Thin binding over the shared, schema-agnostic STEP serializer in
18
+ * \`@ifc-lite/data\`. All serialization logic lives there (single source of
19
+ * truth); only this bundle's \`SCHEMA_REGISTRY\` is bound to the registry-coupled
20
+ * helpers below.
17
21
  *
18
22
  * DO NOT EDIT - This file is auto-generated
19
23
  */
20
24
 
21
25
  import { SCHEMA_REGISTRY } from './schema-registry.js';
22
-
23
- /**
24
- * STEP value types
25
- */
26
- export type StepValue =
27
- | string
28
- | number
29
- | boolean
30
- | null
31
- | undefined
32
- | StepValue[]
33
- | EntityRef
34
- | EnumValue;
35
-
36
- /**
37
- * Entity reference (#123)
38
- */
39
- export interface EntityRef {
40
- ref: number;
41
- }
42
-
43
- /**
44
- * Enum value (.VALUE.)
45
- */
46
- export interface EnumValue {
47
- enum: string;
48
- }
49
-
50
- /**
51
- * Check if value is an entity reference
52
- */
53
- export function isEntityRef(value: unknown): value is EntityRef {
54
- return typeof value === 'object' && value !== null && 'ref' in value;
55
- }
56
-
57
- /**
58
- * Check if value is an enum value
59
- */
60
- export function isEnumValue(value: unknown): value is EnumValue {
61
- return typeof value === 'object' && value !== null && 'enum' in value;
62
- }
63
-
64
- /**
65
- * Create an entity reference
66
- */
67
- export function ref(id: number): EntityRef {
68
- return { ref: id };
69
- }
70
-
71
- /**
72
- * Create an enum value
73
- */
74
- export function enumVal(value: string): EnumValue {
75
- return { enum: value };
76
- }
77
-
78
- /**
79
- * Base interface for serializable entities
80
- */
81
- export interface StepEntity {
82
- /** Express ID (#123) */
83
- expressId: number;
84
- /** IFC type name */
85
- type: string;
86
- /** Attribute values */
87
- [key: string]: unknown;
88
- }
89
-
90
- /**
91
- * Serialize a single value to STEP format
92
- */
93
- export function serializeValue(value: StepValue): string {
94
- // Null/undefined -> $
95
- if (value === null || value === undefined) {
96
- return '$';
97
- }
98
-
99
- // Derived value -> *
100
- if (value === '*') {
101
- return '*';
102
- }
103
-
104
- // Boolean
105
- if (typeof value === 'boolean') {
106
- return value ? '.T.' : '.F.';
107
- }
108
-
109
- // Number
110
- if (typeof value === 'number') {
111
- if (!Number.isFinite(value)) {
112
- return '$';
113
- }
114
- // Use exponential notation for large/small numbers
115
- if (Math.abs(value) > 1e10 || (Math.abs(value) < 1e-10 && value !== 0)) {
116
- return value.toExponential(10).toUpperCase().replace('E+', 'E');
117
- }
118
- // Otherwise use fixed notation
119
- const str = value.toString();
120
- // Ensure there's a decimal point for REAL values
121
- return str.includes('.') ? str : str + '.';
122
- }
123
-
124
- // String
125
- if (typeof value === 'string') {
126
- return "'" + escapeStepString(value) + "'";
127
- }
128
-
129
- // Entity reference
130
- if (isEntityRef(value)) {
131
- return '#' + value.ref;
132
- }
133
-
134
- // Enum value
135
- if (isEnumValue(value)) {
136
- return '.' + value.enum + '.';
137
- }
138
-
139
- // Array/List
140
- if (Array.isArray(value)) {
141
- if (value.length === 0) {
142
- return '()';
143
- }
144
- return '(' + value.map(v => serializeValue(v as StepValue)).join(',') + ')';
145
- }
146
-
147
- // Object (shouldn't happen for valid STEP values)
148
- return '$';
149
- }
150
-
151
- /**
152
- * Escape a string for STEP format
153
- */
154
- function escapeStepString(str: string): string {
155
- return str
156
- .replace(/\\\\/g, '\\\\\\\\') // Backslash
157
- .replace(/'/g, "''"); // Single quote
158
- }
159
-
160
- /**
161
- * Serialize an entity to a STEP line
26
+ import {
27
+ generateHeader,
28
+ generateStepFileWithRegistry,
29
+ toStepLineWithRegistry,
30
+ type StepEntity,
31
+ } from '@ifc-lite/data';
32
+
33
+ export {
34
+ isEntityRef,
35
+ isEnumValue,
36
+ ref,
37
+ enumVal,
38
+ serializeValue,
39
+ generateHeader,
40
+ parseStepValue,
41
+ } from '@ifc-lite/data';
42
+ export type { StepValue, EntityRef, EnumValue, StepEntity } from '@ifc-lite/data';
43
+
44
+ /**
45
+ * Serialize an entity to a STEP line (bound to this bundle's schema).
162
46
  */
163
47
  export function toStepLine(entity: StepEntity): string {
164
- const schema = SCHEMA_REGISTRY.entities[entity.type];
165
- if (!schema) {
166
- throw new Error(\`Unknown entity type: \${entity.type}\`);
167
- }
168
-
169
- // Get all attributes in order
170
- const values: string[] = [];
171
- for (const attr of schema.allAttributes) {
172
- const value = entity[attr.name];
173
- values.push(serializeValue(value as StepValue));
174
- }
175
-
176
- return \`#\${entity.expressId}=\${entity.type.toUpperCase()}(\${values.join(',')});\`;
48
+ return toStepLineWithRegistry(SCHEMA_REGISTRY, entity);
177
49
  }
178
50
 
179
51
  /**
180
- * Generate STEP file header
181
- */
182
- export function generateHeader(options: {
183
- description?: string;
184
- author?: string;
185
- organization?: string;
186
- application?: string;
187
- schema: 'IFC2X3' | 'IFC4' | 'IFC4X3' | 'IFC5';
188
- filename?: string;
189
- }): string {
190
- const now = new Date().toISOString().replace(/[-:]/g, '').split('.')[0];
191
- const desc = options.description || 'ViewDefinition [CoordinationView]';
192
- const author = options.author || '';
193
- const org = options.organization || '';
194
- const app = options.application || 'ifc-lite';
195
- const filename = options.filename || 'output.ifc';
196
-
197
- return \`ISO-10303-21;
198
- HEADER;
199
- FILE_DESCRIPTION('\${desc}','2;1');
200
- FILE_NAME('\${filename}','\${now}',('\${author}'),('\${org}'),'\${app}','\${app}','');
201
- FILE_SCHEMA(('\${options.schema}'));
202
- ENDSEC;
203
- \`;
204
- }
205
-
206
- /**
207
- * Generate complete STEP file content
52
+ * Generate complete STEP file content (bound to this bundle's schema).
208
53
  */
209
54
  export function generateStepFile(
210
55
  entities: StepEntity[],
211
56
  options: Parameters<typeof generateHeader>[0]
212
57
  ): string {
213
- const header = generateHeader(options);
214
-
215
- // Sort entities by ID for deterministic output
216
- const sorted = [...entities].sort((a, b) => a.expressId - b.expressId);
217
-
218
- const data = sorted.map(e => toStepLine(e)).join('\\n');
219
-
220
- return \`\${header}DATA;
221
- \${data}
222
- ENDSEC;
223
- END-ISO-10303-21;
224
- \`;
225
- }
226
-
227
- /**
228
- * Parse a STEP value from string
229
- */
230
- export function parseStepValue(str: string): StepValue {
231
- str = str.trim();
232
-
233
- // Null
234
- if (str === '$') {
235
- return null;
236
- }
237
-
238
- // Derived
239
- if (str === '*') {
240
- return '*' as unknown as StepValue;
241
- }
242
-
243
- // Boolean
244
- if (str === '.T.') {
245
- return true;
246
- }
247
- if (str === '.F.') {
248
- return false;
249
- }
250
- if (str === '.U.') {
251
- return null; // Unknown/indeterminate
252
- }
253
-
254
- // Entity reference
255
- if (str.startsWith('#')) {
256
- return { ref: parseInt(str.substring(1), 10) };
257
- }
258
-
259
- // Enum
260
- if (str.startsWith('.') && str.endsWith('.')) {
261
- return { enum: str.substring(1, str.length - 1) };
262
- }
263
-
264
- // String
265
- if (str.startsWith("'") && str.endsWith("'")) {
266
- return unescapeStepString(str.substring(1, str.length - 1));
267
- }
268
-
269
- // List
270
- if (str.startsWith('(') && str.endsWith(')')) {
271
- return parseStepList(str);
272
- }
273
-
274
- // Number
275
- const num = parseFloat(str);
276
- if (!isNaN(num)) {
277
- return num;
278
- }
279
-
280
- // Unknown
281
- return str;
282
- }
283
-
284
- /**
285
- * Parse a STEP list
286
- */
287
- function parseStepList(str: string): StepValue[] {
288
- // Remove outer parentheses
289
- const inner = str.substring(1, str.length - 1).trim();
290
- if (inner === '') {
291
- return [];
292
- }
293
-
294
- const values: StepValue[] = [];
295
- let depth = 0;
296
- let current = '';
297
-
298
- for (let i = 0; i < inner.length; i++) {
299
- const char = inner[i];
300
-
301
- if (char === '(' || char === '[') {
302
- depth++;
303
- current += char;
304
- } else if (char === ')' || char === ']') {
305
- depth--;
306
- current += char;
307
- } else if (char === ',' && depth === 0) {
308
- values.push(parseStepValue(current));
309
- current = '';
310
- } else {
311
- current += char;
312
- }
313
- }
314
-
315
- if (current.trim()) {
316
- values.push(parseStepValue(current));
317
- }
318
-
319
- return values;
320
- }
321
-
322
- /**
323
- * Unescape a STEP string
324
- */
325
- function unescapeStepString(str: string): string {
326
- return str
327
- .replace(/''/g, "'")
328
- .replace(/\\\\\\\\/g, '\\\\');
58
+ return generateStepFileWithRegistry(SCHEMA_REGISTRY, entities, options);
329
59
  }
330
60
  `;
331
- return code;
332
61
  }
333
62
  //# sourceMappingURL=serialization-generator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"serialization-generator.js","sourceRoot":"","sources":["../src/serialization-generator.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAW/D;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAqB;IACvD,IAAI,IAAI,GAAG;;;;;;oCAMuB,MAAM,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4T9C,CAAC;IAEA,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"serialization-generator.js","sourceRoot":"","sources":["../src/serialization-generator.ts"],"names":[],"mappings":"AAAA;;+DAE+D;AAc/D;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CAAC,MAAqB;IACvD,OAAO;;;;;;oCAM2B,MAAM,CAAC,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6C9C,CAAC;AACF,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ifc-lite/codegen",
3
- "version": "1.15.3",
3
+ "version": "1.15.5",
4
4
  "description": "TypeScript code generator from IFC EXPRESS schemas",
5
5
  "type": "module",
6
6
  "repository": {
@@ -16,22 +16,33 @@
16
16
  "codegen",
17
17
  "typescript"
18
18
  ],
19
- "author": "",
20
- "license": "MIT",
19
+ "author": "Louis True",
20
+ "license": "MPL-2.0",
21
21
  "dependencies": {
22
- "commander": "^15.0.0"
22
+ "commander": "^15.0.0",
23
+ "@ifc-lite/data": "^2.5.1"
23
24
  },
24
25
  "devDependencies": {
25
- "@types/node": "^25.9.1",
26
+ "@types/node": "^26.1.0",
26
27
  "typescript": "^6.0.3",
27
- "vitest": "^4.1.0"
28
+ "vitest": "^4.1.9"
28
29
  },
30
+ "publishConfig": {
31
+ "access": "public"
32
+ },
33
+ "homepage": "https://ltplus-ag.github.io/ifc-lite/",
34
+ "bugs": "https://github.com/LTplus-AG/ifc-lite/issues",
35
+ "files": [
36
+ "dist",
37
+ "schemas",
38
+ "README.md"
39
+ ],
29
40
  "scripts": {
30
41
  "build": "pnpm exec tsc",
31
42
  "dev": "pnpm exec tsc --watch",
32
43
  "test": "vitest run",
33
44
  "generate": "node dist/cli.js",
34
- "generate:ifc4": "node dist/cli.js schemas/IFC4.exp -o generated/ifc4",
45
+ "generate:ifc4": "node dist/cli.js schemas/IFC4_ADD2_TC1.exp -o generated/ifc4",
35
46
  "generate:ifc4x3": "node dist/cli.js schemas/IFC4X3.exp -o generated/ifc4x3"
36
47
  }
37
48
  }
@@ -1,4 +0,0 @@
1
-
2
- > @ifc-lite/codegen@1.15.3 build /home/runner/work/ifc-lite/ifc-lite/packages/codegen
3
- > pnpm exec tsc
4
-
package/CHANGELOG.md DELETED
@@ -1,117 +0,0 @@
1
- # @ifc-lite/codegen
2
-
3
- ## 1.15.3
4
-
5
- ### Patch Changes
6
-
7
- - [#946](https://github.com/LTplus-AG/ifc-lite/pull/946) [`6378998`](https://github.com/LTplus-AG/ifc-lite/commit/6378998ec146f7f9297ef5fcc5953b155fd6b5e0) Thanks [@louistrue](https://github.com/louistrue)! - Fix a batch of verified findings from a full-codebase review (security, correctness,
8
- data-loss, and resource/memory leaks). Highlights:
9
-
10
- **Security**
11
-
12
- - collab-server: a malformed WebSocket frame no longer crashes the whole process
13
- (decode is wrapped; a bad frame is rejected/audited instead of throwing).
14
- - mcp: the local HTTP transport now validates `Host`/`Origin` and no longer sends a
15
- wildcard `Access-Control-Allow-Origin`, closing a DNS-rebinding/CSRF hole; the
16
- `AuthScope.modelIds` allowlist is now enforced at model resolution.
17
- - server-bin: `extractZip` uses `execFileSync` (argv, no shell), removing command
18
- injection via archive/destination paths.
19
- - export / sdk / cli / mcp / lists / viewer CSV exporters now neutralize spreadsheet
20
- formula injection (CWE-1236) consistently.
21
- - create-ifc-lite: validates the project name (no path traversal) and drops the
22
- unused `execSync`-based downloader.
23
- - embed-sdk: inbound `postMessage` now validates `event.origin`.
24
-
25
- **Correctness / data-loss**
26
-
27
- - parser: `lengthUnitScale` survives the worker transport; the nested STEP list
28
- parser is string-aware (commas/parens inside quoted values no longer mis-split).
29
- - mutations: deleting a property from a session-created pset and replaying
30
- `UPDATE_ATTRIBUTE` / `CREATE_PROPERTY_SET` mutations now work.
31
- - export: merged-export ID remapping no longer rewrites `#N` inside quoted strings.
32
- - drawing-2d: GPU section cutter triangle upload/readback use correct WGSL std-layout
33
- offsets and strides.
34
- - ifcx: cyclic children no longer abort the parse; spatial children round-trip; the
35
- mesh transform guards a zero/non-finite homogeneous `w`.
36
- - data / cache: a `NULL` string property value stays `null` instead of becoming `""`.
37
- - pointcloud, bcf, server-client, query, viewer-core, viewer store/federation: assorted
38
- decoding, federation-id, and selection-state fixes.
39
-
40
- **Resource / memory leaks**
41
-
42
- - geometry, query (DuckDB), renderer (GPU buffers), collab (federation presence),
43
- sandbox (host log capture + runtime), mcp (clash mesh cache), server-bin (signal
44
- listeners), and the viewer renderer on unmount now release resources deterministically.
45
-
46
- **Hardening (apps, not published)**
47
-
48
- - server: a dedicated `server-release` Cargo profile (`panic = "unwind"`) plus a
49
- `CatchPanicLayer` contain a malformed-IFC parse panic to the offending request
50
- instead of aborting the whole server.
51
- - desktop (Tauri): a Content-Security-Policy is set, and unused `shell:*` /
52
- `fs:allow-write|mkdir|remove` capabilities (and the unused shell plugin) are removed.
53
-
54
- **Second pass** (additional verified findings)
55
-
56
- - collab-server: S3 log load now follows `ListObjectsV2` pagination (no dropped frames);
57
- awareness frames are size-capped + rate-limited; path-lock verify runs after role/rate-limit;
58
- the blob route requires auth and `/metrics` can be token-gated.
59
- - server-bin: downloaded binaries are SHA-256 verified against a release sidecar (fail-closed on
60
- mismatch, warn-if-absent for older releases).
61
- - extensions: inner-ring capability check fails _closed_ for unknown namespaces; signing
62
- canonicalization is now injective (length-prefixed).
63
- - correctness/leaks: mutations quantity type+unit preserved on replay; `findByProperty` boolean
64
- comparisons; Parquet REAL columns kept as Float64; blob GC fail-safe on missing `uploadedAt`;
65
- spatial-hierarchy + codegen cycle guards; BVH NaN edge; bSDD/playground caches bounded;
66
- point-cloud GPU asset freed on federation error; mcp `parseColor` rejects non-hex; bcf/SVG/STEP
67
- output escaping; and more.
68
-
69
- ## 1.15.2
70
-
71
- ### Patch Changes
72
-
73
- - [#494](https://github.com/louistrue/ifc-lite/pull/494) [`ec0d3a0`](https://github.com/louistrue/ifc-lite/commit/ec0d3a0e4c7f9eaeb26ab0a724fd76d955e52ac5) Thanks [@louistrue](https://github.com/louistrue)! - Remove recursive package `prebuild` hooks and run TypeScript via `pnpm exec` so workspace builds resolve correctly on Windows.
74
-
75
- ## 1.15.1
76
-
77
- ### Patch Changes
78
-
79
- - [#461](https://github.com/louistrue/ifc-lite/pull/461) [`6ce40dd`](https://github.com/louistrue/ifc-lite/commit/6ce40ddb0cace5f83c2438d2d4c4bd47703468f7) Thanks [@louistrue](https://github.com/louistrue)! - Clean up package build health for georeferencing work by fixing parser generation issues, making export tests resolve workspace packages reliably, removing build scripts that masked TypeScript failures, tightening workspace test/build scripts, productizing CLI LOD generation, centralizing IFC GUID utilities in encoding, and adding mutation test coverage for property editing flows.
80
-
81
- ## 1.15.0
82
-
83
- ### Minor Changes
84
-
85
- - [#354](https://github.com/louistrue/ifc-lite/pull/354) [`3f212f1`](https://github.com/louistrue/ifc-lite/commit/3f212f1e24b896cbc6ff63444c02635a1128ba3f) Thanks [@louistrue](https://github.com/louistrue)! - Replace hardcoded IFC schema with codegen from EXPRESS schema, adding full type entity support (776 entities)
86
-
87
- ## 1.14.3
88
-
89
- ## 1.14.2
90
-
91
- ## 1.14.1
92
-
93
- ## 1.14.0
94
-
95
- ## 1.13.0
96
-
97
- ## 1.12.0
98
-
99
- ## 1.11.3
100
-
101
- ## 1.11.1
102
-
103
- ## 1.11.0
104
-
105
- ## 1.10.0
106
-
107
- ## 1.9.0
108
-
109
- ## 1.8.0
110
-
111
- ## 1.7.0
112
-
113
- ## 1.2.1
114
-
115
- ### Patch Changes
116
-
117
- - Version sync with @ifc-lite packages