@ifc-lite/sandbox 1.14.5 → 1.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bridge-create-schedule.d.ts +12 -0
- package/dist/bridge-create-schedule.d.ts.map +1 -0
- package/dist/bridge-create-schedule.js +150 -0
- package/dist/bridge-create-schedule.js.map +1 -0
- package/dist/bridge-create.d.ts +7 -0
- package/dist/bridge-create.d.ts.map +1 -0
- package/dist/bridge-create.js +503 -0
- package/dist/bridge-create.js.map +1 -0
- package/dist/bridge-export.d.ts +3 -0
- package/dist/bridge-export.d.ts.map +1 -0
- package/dist/bridge-export.js +60 -0
- package/dist/bridge-export.js.map +1 -0
- package/dist/bridge-files.d.ts +6 -0
- package/dist/bridge-files.d.ts.map +1 -0
- package/dist/bridge-files.js +56 -0
- package/dist/bridge-files.js.map +1 -0
- package/dist/bridge-helpers.d.ts +28 -0
- package/dist/bridge-helpers.d.ts.map +1 -0
- package/dist/bridge-helpers.js +45 -0
- package/dist/bridge-helpers.js.map +1 -0
- package/dist/bridge-model.d.ts +6 -0
- package/dist/bridge-model.d.ts.map +1 -0
- package/dist/bridge-model.js +45 -0
- package/dist/bridge-model.js.map +1 -0
- package/dist/bridge-mutate.d.ts +6 -0
- package/dist/bridge-mutate.d.ts.map +1 -0
- package/dist/bridge-mutate.js +79 -0
- package/dist/bridge-mutate.js.map +1 -0
- package/dist/bridge-query.d.ts +3 -0
- package/dist/bridge-query.d.ts.map +1 -0
- package/dist/bridge-query.js +421 -0
- package/dist/bridge-query.js.map +1 -0
- package/dist/bridge-schedule.d.ts +58 -0
- package/dist/bridge-schedule.d.ts.map +1 -0
- package/dist/bridge-schedule.js +207 -0
- package/dist/bridge-schedule.js.map +1 -0
- package/dist/bridge-schema.d.ts.map +1 -1
- package/dist/bridge-schema.js +21 -1294
- package/dist/bridge-schema.js.map +1 -1
- package/dist/bridge-store.d.ts +9 -0
- package/dist/bridge-store.d.ts.map +1 -0
- package/dist/bridge-store.js +426 -0
- package/dist/bridge-store.js.map +1 -0
- package/dist/bridge-viewer.d.ts +3 -0
- package/dist/bridge-viewer.d.ts.map +1 -0
- package/dist/bridge-viewer.js +110 -0
- package/dist/bridge-viewer.js.map +1 -0
- package/dist/creator-registry.d.ts +16 -0
- package/dist/creator-registry.d.ts.map +1 -0
- package/dist/creator-registry.js +45 -0
- package/dist/creator-registry.js.map +1 -0
- package/dist/sandbox.js.map +1 -1
- package/dist/transpile.d.ts.map +1 -1
- package/dist/transpile.js +4 -2
- package/dist/transpile.js.map +1 -1
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -0
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
package/dist/bridge-schema.js
CHANGED
|
@@ -1,1205 +1,30 @@
|
|
|
1
1
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
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
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (!sessionCreators) {
|
|
15
|
-
sessionCreators = new Map();
|
|
16
|
-
creatorsBySession.set(sessionId, sessionCreators);
|
|
17
|
-
}
|
|
18
|
-
return sessionCreators;
|
|
19
|
-
}
|
|
20
|
-
return {
|
|
21
|
-
registerForSession(sessionId, creator) {
|
|
22
|
-
const handle = nextHandleBySession.get(sessionId) ?? 1;
|
|
23
|
-
nextHandleBySession.set(sessionId, handle + 1);
|
|
24
|
-
getSessionCreators(sessionId).set(handle, creator);
|
|
25
|
-
return handle;
|
|
26
|
-
},
|
|
27
|
-
getForSession(sessionId, handle) {
|
|
28
|
-
const creator = creatorsBySession.get(sessionId)?.get(handle);
|
|
29
|
-
if (!creator)
|
|
30
|
-
throw new Error(`Invalid creator handle: ${handle}`);
|
|
31
|
-
return creator;
|
|
32
|
-
},
|
|
33
|
-
removeForSession(sessionId, handle) {
|
|
34
|
-
const sessionCreators = creatorsBySession.get(sessionId);
|
|
35
|
-
if (!sessionCreators)
|
|
36
|
-
return;
|
|
37
|
-
sessionCreators.delete(handle);
|
|
38
|
-
if (sessionCreators.size === 0) {
|
|
39
|
-
creatorsBySession.delete(sessionId);
|
|
40
|
-
nextHandleBySession.delete(sessionId);
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
|
-
removeSession(sessionId) {
|
|
44
|
-
creatorsBySession.delete(sessionId);
|
|
45
|
-
nextHandleBySession.delete(sessionId);
|
|
46
|
-
},
|
|
47
|
-
};
|
|
48
|
-
})();
|
|
49
|
-
// ============================================================================
|
|
50
|
-
// Helpers
|
|
51
|
-
// ============================================================================
|
|
52
|
-
/**
|
|
53
|
-
* Add PascalCase IFC aliases to entity data for script flexibility.
|
|
54
|
-
* Scripts can use either e.name or e.Name, e.type or e.Type, etc.
|
|
55
|
-
*/
|
|
56
|
-
function withAliases(entity) {
|
|
57
|
-
return {
|
|
58
|
-
ref: entity.ref,
|
|
59
|
-
globalId: entity.globalId, GlobalId: entity.globalId,
|
|
60
|
-
name: entity.name, Name: entity.name,
|
|
61
|
-
type: entity.type, Type: entity.type,
|
|
62
|
-
description: entity.description, Description: entity.description,
|
|
63
|
-
objectType: entity.objectType, ObjectType: entity.objectType,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* Extract an EntityRef from a dumped entity object.
|
|
68
|
-
* Accepts both { ref: { modelId, expressId } } and { modelId, expressId }.
|
|
69
|
-
*/
|
|
70
|
-
function toRef(raw) {
|
|
71
|
-
const obj = raw;
|
|
72
|
-
if (!obj)
|
|
73
|
-
return null;
|
|
74
|
-
if (obj.ref && typeof obj.ref === 'object') {
|
|
75
|
-
const ref = obj.ref;
|
|
76
|
-
if (typeof ref.modelId === 'string' && typeof ref.expressId === 'number') {
|
|
77
|
-
return ref;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (typeof obj.modelId === 'string' && typeof obj.expressId === 'number') {
|
|
81
|
-
return obj;
|
|
82
|
-
}
|
|
83
|
-
return null;
|
|
84
|
-
}
|
|
85
|
-
function mapNamedProperties(properties) {
|
|
86
|
-
return properties.map((property) => ({
|
|
87
|
-
name: property.name, Name: property.name,
|
|
88
|
-
value: property.value, Value: property.value,
|
|
89
|
-
NominalValue: property.value,
|
|
90
|
-
type: property.type, Type: property.type,
|
|
91
|
-
}));
|
|
92
|
-
}
|
|
93
|
-
/** Methods with non-standard signatures that need hand-written wiring */
|
|
94
|
-
const SPECIAL_METHODS = new Set([
|
|
95
|
-
'constructor', 'toIfc', 'setColor',
|
|
96
|
-
]);
|
|
97
|
-
/**
|
|
98
|
-
* Explicit allow-list of IfcCreator methods exposed in the sandbox.
|
|
99
|
-
* Only methods in this set (or in SPECIAL_METHODS/ELEMENT_METHODS/ZERO_ARG_METHODS)
|
|
100
|
-
* are wired. This prevents accidental exposure of private/internal helpers.
|
|
101
|
-
*/
|
|
102
|
-
const ALLOWED_METHODS = new Set([
|
|
103
|
-
// Spatial structure
|
|
104
|
-
'addIfcBuildingStorey',
|
|
105
|
-
// Building elements
|
|
106
|
-
'addIfcWall', 'addIfcSlab', 'addIfcColumn', 'addIfcBeam',
|
|
107
|
-
'addIfcStair', 'addIfcRoof', 'addIfcGableRoof', 'addIfcWallDoor', 'addIfcWallWindow', 'addIfcDoor', 'addIfcWindow',
|
|
108
|
-
'addIfcRamp', 'addIfcRailing', 'addIfcPlate', 'addIfcMember',
|
|
109
|
-
'addIfcFooting', 'addIfcPile', 'addIfcSpace', 'addIfcCurtainWall',
|
|
110
|
-
'addIfcFurnishingElement', 'addIfcBuildingElementProxy',
|
|
111
|
-
// Specialized profiles
|
|
112
|
-
'addIfcCircularColumn', 'addIfcIShapeBeam',
|
|
113
|
-
'addIfcLShapeMember', 'addIfcTShapeMember', 'addIfcUShapeMember',
|
|
114
|
-
'addIfcHollowCircularColumn', 'addIfcRectangleHollowBeam',
|
|
115
|
-
// Generic element creation
|
|
116
|
-
'addElement', 'addAxisElement', 'createProfile',
|
|
117
|
-
// Properties and materials
|
|
118
|
-
'addIfcPropertySet', 'addIfcElementQuantity', 'addIfcMaterial',
|
|
119
|
-
// Low-level geometry
|
|
120
|
-
'getWorldPlacementId',
|
|
121
|
-
]);
|
|
122
|
-
/** Methods that take (elementId, def) instead of (storeyId, params) */
|
|
123
|
-
const ELEMENT_METHODS = new Set([
|
|
124
|
-
'addIfcWallDoor', 'addIfcWallWindow',
|
|
125
|
-
'addIfcPropertySet', 'addIfcElementQuantity', 'addIfcMaterial',
|
|
126
|
-
]);
|
|
127
|
-
/** Methods that take a single params object after the handle */
|
|
128
|
-
const SINGLE_DUMP_METHODS = new Set([
|
|
129
|
-
'createProfile',
|
|
130
|
-
]);
|
|
131
|
-
/** Methods with zero args (just need the handle) */
|
|
132
|
-
const ZERO_ARG_METHODS = new Set([
|
|
133
|
-
'getWorldPlacementId',
|
|
134
|
-
]);
|
|
135
|
-
function classifyMethod(name, _fn) {
|
|
136
|
-
if (SPECIAL_METHODS.has(name))
|
|
137
|
-
return 'special';
|
|
138
|
-
if (ZERO_ARG_METHODS.has(name))
|
|
139
|
-
return 'no-args';
|
|
140
|
-
if (SINGLE_DUMP_METHODS.has(name))
|
|
141
|
-
return 'single-dump';
|
|
142
|
-
if (ELEMENT_METHODS.has(name))
|
|
143
|
-
return 'element-params';
|
|
144
|
-
return 'storey-params';
|
|
145
|
-
}
|
|
146
|
-
/** Humanize a method name for the doc string */
|
|
147
|
-
function methodDoc(name) {
|
|
148
|
-
// addIfcWall → 'Add an IfcWall'
|
|
149
|
-
// addElement → 'Add a generic element'
|
|
150
|
-
// createProfile → 'Create a profile from a ProfileDef'
|
|
151
|
-
if (name === 'addIfcBuildingStorey')
|
|
152
|
-
return 'Add a building storey. Returns storey expressId.';
|
|
153
|
-
if (name === 'addIfcGableRoof')
|
|
154
|
-
return 'Add a dual-pitch gable roof. `Slope` is in radians. Returns roof expressId.';
|
|
155
|
-
if (name === 'addIfcWallDoor')
|
|
156
|
-
return 'Add a door hosted in a wall opening. Position is wall-local [alongWall, 0, baseHeight]. Returns door expressId.';
|
|
157
|
-
if (name === 'addIfcWallWindow')
|
|
158
|
-
return 'Add a window hosted in a wall opening. Position is wall-local [alongWall, 0, sillHeight]. Returns window expressId.';
|
|
159
|
-
if (name === 'addElement')
|
|
160
|
-
return 'Create ANY IFC type with a profile at a placement. Returns expressId.';
|
|
161
|
-
if (name === 'addAxisElement')
|
|
162
|
-
return 'Create ANY IFC type extruded along a Start→End axis. Returns expressId.';
|
|
163
|
-
if (name === 'createProfile')
|
|
164
|
-
return 'Create a profile from a ProfileDef union. Returns profile ID.';
|
|
165
|
-
if (name === 'getWorldPlacementId')
|
|
166
|
-
return 'Get the world placement ID for use with addLocalPlacement.';
|
|
167
|
-
if (name.startsWith('addIfc')) {
|
|
168
|
-
const entity = name.slice(3); // remove 'add', keep 'IfcWall' etc.
|
|
169
|
-
return `Add ${entity}. Returns expressId.`;
|
|
170
|
-
}
|
|
171
|
-
if (name.startsWith('add')) {
|
|
172
|
-
const what = name.slice(3);
|
|
173
|
-
return `Add ${what}. Returns ID.`;
|
|
174
|
-
}
|
|
175
|
-
return `Call ${name} on the creator.`;
|
|
176
|
-
}
|
|
177
|
-
const CREATE_METHOD_SEMANTICS = {
|
|
178
|
-
project: {
|
|
179
|
-
taskTags: ['create', 'repair'],
|
|
180
|
-
useWhen: 'Start a new generated IFC model before creating storeys and elements.',
|
|
181
|
-
},
|
|
182
|
-
toIfc: {
|
|
183
|
-
taskTags: ['create', 'export'],
|
|
184
|
-
useWhen: 'Finalize the in-memory IFC model and produce STEP content for preview or download.',
|
|
185
|
-
},
|
|
186
|
-
setColor: {
|
|
187
|
-
taskTags: ['visualize', 'repair'],
|
|
188
|
-
useWhen: 'Assign a named RGB color to a created element using [r, g, b] values between 0 and 1.',
|
|
189
|
-
},
|
|
190
|
-
addIfcBuildingStorey: {
|
|
191
|
-
taskTags: ['create', 'repair'],
|
|
192
|
-
requiredKeys: ['Elevation'],
|
|
193
|
-
useWhen: 'Create a building storey container before adding level-based geometry.',
|
|
194
|
-
},
|
|
195
|
-
addIfcWall: {
|
|
196
|
-
taskTags: ['create', 'repair'],
|
|
197
|
-
placement: 'storey-relative',
|
|
198
|
-
requiredKeys: ['Start', 'End', 'Thickness', 'Height'],
|
|
199
|
-
positiveKeys: ['Thickness', 'Height'],
|
|
200
|
-
pointArity: { Start: 3, End: 3 },
|
|
201
|
-
axisPair: ['Start', 'End'],
|
|
202
|
-
useWhen: 'Create a wall from a start/end axis on the current storey.',
|
|
203
|
-
},
|
|
204
|
-
addIfcSlab: {
|
|
205
|
-
taskTags: ['create', 'repair'],
|
|
206
|
-
placement: 'storey-relative',
|
|
207
|
-
requiredKeys: ['Position', 'Thickness'],
|
|
208
|
-
anyOfKeys: [['Profile'], ['Width', 'Depth']],
|
|
209
|
-
positiveKeys: ['Thickness', 'Width', 'Depth'],
|
|
210
|
-
pointArity: { Position: 3 },
|
|
211
|
-
customValidationId: 'slab-shape',
|
|
212
|
-
useWhen: 'Create a slab from a rectangular footprint or a 2D point-array profile.',
|
|
213
|
-
},
|
|
214
|
-
addIfcColumn: {
|
|
215
|
-
taskTags: ['create', 'repair'],
|
|
216
|
-
placement: 'storey-relative',
|
|
217
|
-
requiredKeys: ['Position', 'Width', 'Depth', 'Height'],
|
|
218
|
-
positiveKeys: ['Width', 'Depth', 'Height'],
|
|
219
|
-
pointArity: { Position: 3 },
|
|
220
|
-
useWhen: 'Create a vertical column from a base position and dimensions.',
|
|
221
|
-
},
|
|
222
|
-
addIfcBeam: {
|
|
223
|
-
taskTags: ['create', 'repair'],
|
|
224
|
-
placement: 'storey-relative',
|
|
225
|
-
requiredKeys: ['Start', 'End', 'Width', 'Height'],
|
|
226
|
-
positiveKeys: ['Width', 'Height'],
|
|
227
|
-
pointArity: { Start: 3, End: 3 },
|
|
228
|
-
axisPair: ['Start', 'End'],
|
|
229
|
-
useWhen: 'Create a beam from an axis on the current storey.',
|
|
230
|
-
},
|
|
231
|
-
addIfcMember: {
|
|
232
|
-
taskTags: ['create', 'repair'],
|
|
233
|
-
placement: 'world',
|
|
234
|
-
requiredKeys: ['Start', 'End', 'Width', 'Height'],
|
|
235
|
-
positiveKeys: ['Width', 'Height'],
|
|
236
|
-
pointArity: { Start: 3, End: 3 },
|
|
237
|
-
axisPair: ['Start', 'End'],
|
|
238
|
-
useWhen: 'Create mullions, braces, or facade members with explicit world coordinates.',
|
|
239
|
-
cautions: [
|
|
240
|
-
'Inside storey loops, include the current storey elevation in Start/End Z for facade members.',
|
|
241
|
-
],
|
|
242
|
-
},
|
|
243
|
-
addIfcPlate: {
|
|
244
|
-
taskTags: ['create', 'repair'],
|
|
245
|
-
placement: 'world',
|
|
246
|
-
requiredKeys: ['Position', 'Width', 'Depth', 'Thickness'],
|
|
247
|
-
positiveKeys: ['Width', 'Depth', 'Thickness'],
|
|
248
|
-
pointArity: { Position: 3 },
|
|
249
|
-
forbiddenKeys: [
|
|
250
|
-
{ key: 'Height', message: '`bim.create.addIfcPlate(...)` uses `Depth` and `Thickness`, not `Height`.' },
|
|
251
|
-
{ key: 'Start', message: '`bim.create.addIfcPlate(...)` uses `Position`, not `Start`/`End`.' },
|
|
252
|
-
{ key: 'End', message: '`bim.create.addIfcPlate(...)` uses `Position`, not `Start`/`End`.' },
|
|
253
|
-
],
|
|
254
|
-
useWhen: 'Create thin world-placement panels or facade plates from a base point.',
|
|
255
|
-
cautions: [
|
|
256
|
-
'Facade plates repeated by storey usually need absolute Z = elevation + localOffset.',
|
|
257
|
-
],
|
|
258
|
-
},
|
|
259
|
-
addIfcCurtainWall: {
|
|
260
|
-
taskTags: ['create', 'repair'],
|
|
261
|
-
placement: 'world',
|
|
262
|
-
requiredKeys: ['Start', 'End', 'Height'],
|
|
263
|
-
positiveKeys: ['Height', 'Thickness'],
|
|
264
|
-
pointArity: { Start: 3, End: 3 },
|
|
265
|
-
axisPair: ['Start', 'End'],
|
|
266
|
-
useWhen: 'Create a world-placement curtain wall segment between two points.',
|
|
267
|
-
cautions: [
|
|
268
|
-
'Inside storey loops, include the current storey elevation in Start/End Z.',
|
|
269
|
-
],
|
|
270
|
-
},
|
|
271
|
-
addIfcRailing: {
|
|
272
|
-
taskTags: ['create', 'repair'],
|
|
273
|
-
placement: 'world',
|
|
274
|
-
requiredKeys: ['Start', 'End', 'Height'],
|
|
275
|
-
positiveKeys: ['Height', 'Width'],
|
|
276
|
-
pointArity: { Start: 3, End: 3 },
|
|
277
|
-
axisPair: ['Start', 'End'],
|
|
278
|
-
useWhen: 'Create a world-placement railing along an axis.',
|
|
279
|
-
},
|
|
280
|
-
addIfcStair: {
|
|
281
|
-
taskTags: ['create', 'repair'],
|
|
282
|
-
placement: 'storey-relative',
|
|
283
|
-
requiredKeys: ['Position', 'NumberOfRisers', 'RiserHeight', 'TreadLength', 'Width'],
|
|
284
|
-
positiveKeys: ['NumberOfRisers', 'RiserHeight', 'TreadLength', 'Width'],
|
|
285
|
-
pointArity: { Position: 3 },
|
|
286
|
-
useWhen: 'Create a stair from a base position and riser/tread definition.',
|
|
287
|
-
},
|
|
288
|
-
addIfcRoof: {
|
|
289
|
-
taskTags: ['create', 'repair'],
|
|
290
|
-
placement: 'storey-relative',
|
|
291
|
-
requiredKeys: ['Position', 'Width', 'Depth', 'Thickness'],
|
|
292
|
-
positiveKeys: ['Width', 'Depth', 'Thickness', 'Slope'],
|
|
293
|
-
pointArity: { Position: 3 },
|
|
294
|
-
forbiddenKeys: [
|
|
295
|
-
{ key: 'Profile', message: '`bim.create.addIfcRoof(...)` does not support `Profile`. Use `Position`, `Width`, `Depth`, `Thickness`, and optional `Slope`.' },
|
|
296
|
-
{ key: 'ExtrusionHeight', message: '`bim.create.addIfcRoof(...)` uses `Depth`, not `ExtrusionHeight`.' },
|
|
297
|
-
{ key: 'Height', message: '`bim.create.addIfcRoof(...)` uses `Thickness` and `Depth`, not `Height`.' },
|
|
298
|
-
{ key: 'Overhang', message: '`bim.create.addIfcRoof(...)` does not support `Overhang`. Use `addIfcGableRoof(...)` for a house-style roof with pitch and overhang.' },
|
|
299
|
-
],
|
|
300
|
-
customValidationId: 'roof-shape',
|
|
301
|
-
useWhen: 'Create flat or mono-pitch roof slabs only.',
|
|
302
|
-
cautions: [
|
|
303
|
-
'Slope is in radians.',
|
|
304
|
-
'Use addIfcGableRoof for house, pitched-roof, or gable-roof requests.',
|
|
305
|
-
],
|
|
306
|
-
},
|
|
307
|
-
addIfcGableRoof: {
|
|
308
|
-
taskTags: ['create', 'repair'],
|
|
309
|
-
placement: 'storey-relative',
|
|
310
|
-
requiredKeys: ['Position', 'Width', 'Depth', 'Thickness', 'Slope'],
|
|
311
|
-
positiveKeys: ['Width', 'Depth', 'Thickness', 'Slope'],
|
|
312
|
-
pointArity: { Position: 3 },
|
|
313
|
-
forbiddenKeys: [
|
|
314
|
-
{ key: 'Profile', message: '`bim.create.addIfcGableRoof(...)` does not support `Profile`. Use `Position`, `Width`, `Depth`, `Thickness`, `Slope`, and optional `Overhang`.' },
|
|
315
|
-
{ key: 'ExtrusionHeight', message: '`bim.create.addIfcGableRoof(...)` uses `Thickness`, not `ExtrusionHeight`.' },
|
|
316
|
-
{ key: 'Height', message: '`bim.create.addIfcGableRoof(...)` uses `Thickness` for roof thickness and derives ridge height from `Slope`.' },
|
|
317
|
-
],
|
|
318
|
-
customValidationId: 'roof-shape',
|
|
319
|
-
useWhen: 'Create standard dual-pitch house roofs.',
|
|
320
|
-
cautions: [
|
|
321
|
-
'Slope is in radians.',
|
|
322
|
-
],
|
|
323
|
-
},
|
|
324
|
-
addIfcWallDoor: {
|
|
325
|
-
taskTags: ['create', 'repair'],
|
|
326
|
-
placement: 'wall-local',
|
|
327
|
-
requiredKeys: ['Position', 'Width', 'Height'],
|
|
328
|
-
positiveKeys: ['Width', 'Height', 'Thickness'],
|
|
329
|
-
pointArity: { Position: 3 },
|
|
330
|
-
forbiddenKeys: [
|
|
331
|
-
{ key: 'Start', message: '`bim.create.addIfcWallDoor(...)` uses wall-local `Position`, not `Start`/`End`.' },
|
|
332
|
-
{ key: 'End', message: '`bim.create.addIfcWallDoor(...)` uses wall-local `Position`, not `Start`/`End`.' },
|
|
333
|
-
{ key: 'Rotation', message: '`bim.create.addIfcWallDoor(...)` auto-aligns to the host wall. Do not pass `Rotation`.' },
|
|
334
|
-
{ key: 'Direction', message: '`bim.create.addIfcWallDoor(...)` auto-aligns to the host wall. Do not pass `Direction`.' },
|
|
335
|
-
{ key: 'Axis', message: '`bim.create.addIfcWallDoor(...)` auto-aligns to the host wall. Do not pass `Axis`.' },
|
|
336
|
-
{ key: 'RefDirection', message: '`bim.create.addIfcWallDoor(...)` auto-aligns to the host wall. Do not pass `RefDirection`.' },
|
|
337
|
-
{ key: 'Placement', message: '`bim.create.addIfcWallDoor(...)` uses wall-local `Position`, not `Placement`.' },
|
|
338
|
-
],
|
|
339
|
-
useWhen: 'Create a wall-hosted door aligned to a host wall.',
|
|
340
|
-
},
|
|
341
|
-
addIfcWallWindow: {
|
|
342
|
-
taskTags: ['create', 'repair'],
|
|
343
|
-
placement: 'wall-local',
|
|
344
|
-
requiredKeys: ['Position', 'Width', 'Height'],
|
|
345
|
-
positiveKeys: ['Width', 'Height', 'Thickness'],
|
|
346
|
-
pointArity: { Position: 3 },
|
|
347
|
-
forbiddenKeys: [
|
|
348
|
-
{ key: 'Start', message: '`bim.create.addIfcWallWindow(...)` uses wall-local `Position`, not `Start`/`End`.' },
|
|
349
|
-
{ key: 'End', message: '`bim.create.addIfcWallWindow(...)` uses wall-local `Position`, not `Start`/`End`.' },
|
|
350
|
-
{ key: 'Rotation', message: '`bim.create.addIfcWallWindow(...)` auto-aligns to the host wall. Do not pass `Rotation`.' },
|
|
351
|
-
{ key: 'Direction', message: '`bim.create.addIfcWallWindow(...)` auto-aligns to the host wall. Do not pass `Direction`.' },
|
|
352
|
-
{ key: 'Axis', message: '`bim.create.addIfcWallWindow(...)` auto-aligns to the host wall. Do not pass `Axis`.' },
|
|
353
|
-
{ key: 'RefDirection', message: '`bim.create.addIfcWallWindow(...)` auto-aligns to the host wall. Do not pass `RefDirection`.' },
|
|
354
|
-
{ key: 'Placement', message: '`bim.create.addIfcWallWindow(...)` uses wall-local `Position`, not `Placement`.' },
|
|
355
|
-
],
|
|
356
|
-
useWhen: 'Create a wall-hosted window aligned to a host wall.',
|
|
357
|
-
},
|
|
358
|
-
addIfcDoor: {
|
|
359
|
-
taskTags: ['create', 'repair'],
|
|
360
|
-
placement: 'world',
|
|
361
|
-
requiredKeys: ['Position', 'Width', 'Height'],
|
|
362
|
-
positiveKeys: ['Width', 'Height', 'Thickness'],
|
|
363
|
-
pointArity: { Position: 3 },
|
|
364
|
-
forbiddenKeys: [
|
|
365
|
-
{ key: 'Start', message: '`bim.create.addIfcDoor(...)` uses `Position`, not `Start`/`End`.' },
|
|
366
|
-
{ key: 'End', message: '`bim.create.addIfcDoor(...)` uses `Position`, not `Start`/`End`.' },
|
|
367
|
-
{ key: 'Direction', message: '`bim.create.addIfcDoor(...)` does not support wall-axis rotation. It creates a world-aligned standalone door element.' },
|
|
368
|
-
{ key: 'Rotation', message: '`bim.create.addIfcDoor(...)` does not support rotation. For wall-hosted inserts, use `bim.create.addIfcWallDoor(...)` or wall `Openings`.' },
|
|
369
|
-
{ key: 'Axis', message: '`bim.create.addIfcDoor(...)` does not accept `Axis`. It is not a generic placement API.' },
|
|
370
|
-
{ key: 'RefDirection', message: '`bim.create.addIfcDoor(...)` does not accept `RefDirection`. It is not auto-aligned to wall direction.' },
|
|
371
|
-
{ key: 'Placement', message: '`bim.create.addIfcDoor(...)` uses `Position`, not `Placement`.' },
|
|
372
|
-
],
|
|
373
|
-
useWhen: 'Create a standalone world-aligned door element.',
|
|
374
|
-
cautions: [
|
|
375
|
-
'For wall-hosted inserts, use addIfcWallDoor or wall Openings instead.',
|
|
376
|
-
],
|
|
377
|
-
},
|
|
378
|
-
addIfcWindow: {
|
|
379
|
-
taskTags: ['create', 'repair'],
|
|
380
|
-
placement: 'world',
|
|
381
|
-
requiredKeys: ['Position', 'Width', 'Height'],
|
|
382
|
-
positiveKeys: ['Width', 'Height', 'Thickness'],
|
|
383
|
-
pointArity: { Position: 3 },
|
|
384
|
-
forbiddenKeys: [
|
|
385
|
-
{ key: 'Start', message: '`bim.create.addIfcWindow(...)` uses `Position`, not `Start`/`End`.' },
|
|
386
|
-
{ key: 'End', message: '`bim.create.addIfcWindow(...)` uses `Position`, not `Start`/`End`.' },
|
|
387
|
-
{ key: 'Direction', message: '`bim.create.addIfcWindow(...)` does not support wall-axis rotation. It creates a world-aligned standalone window element.' },
|
|
388
|
-
{ key: 'Rotation', message: '`bim.create.addIfcWindow(...)` does not support rotation. For wall-hosted inserts, use `bim.create.addIfcWallWindow(...)` or wall `Openings`.' },
|
|
389
|
-
{ key: 'Axis', message: '`bim.create.addIfcWindow(...)` does not accept `Axis`. It is not a generic placement API.' },
|
|
390
|
-
{ key: 'RefDirection', message: '`bim.create.addIfcWindow(...)` does not accept `RefDirection`. It is not auto-aligned to wall direction.' },
|
|
391
|
-
{ key: 'Placement', message: '`bim.create.addIfcWindow(...)` uses `Position`, not `Placement`.' },
|
|
392
|
-
],
|
|
393
|
-
useWhen: 'Create a standalone world-aligned window element.',
|
|
394
|
-
cautions: [
|
|
395
|
-
'For wall-hosted inserts, use addIfcWallWindow or wall Openings instead.',
|
|
396
|
-
],
|
|
397
|
-
},
|
|
398
|
-
addElement: {
|
|
399
|
-
taskTags: ['create', 'repair'],
|
|
400
|
-
placement: 'explicit-placement',
|
|
401
|
-
requiredKeys: ['IfcType', 'Placement', 'Profile', 'Depth'],
|
|
402
|
-
positiveKeys: ['Depth'],
|
|
403
|
-
customValidationId: 'generic-element',
|
|
404
|
-
useWhen: 'Create advanced IFC entities only when no dedicated helper exists.',
|
|
405
|
-
},
|
|
406
|
-
addAxisElement: {
|
|
407
|
-
taskTags: ['create', 'repair'],
|
|
408
|
-
placement: 'world',
|
|
409
|
-
requiredKeys: ['IfcType', 'Start', 'End', 'Profile'],
|
|
410
|
-
pointArity: { Start: 3, End: 3 },
|
|
411
|
-
axisPair: ['Start', 'End'],
|
|
412
|
-
customValidationId: 'axis-element',
|
|
413
|
-
useWhen: 'Create advanced axis-based IFC entities when no dedicated helper exists.',
|
|
414
|
-
},
|
|
415
|
-
};
|
|
416
|
-
/**
|
|
417
|
-
* Build all bim.create method schemas by discovering public methods
|
|
418
|
-
* on IfcCreator.prototype. New methods are automatically exposed.
|
|
419
|
-
*/
|
|
420
|
-
function buildCreateMethods() {
|
|
421
|
-
const methods = [];
|
|
422
|
-
// ── Special: project (creates IfcCreator, returns handle) ──
|
|
423
|
-
methods.push({
|
|
424
|
-
name: 'project',
|
|
425
|
-
doc: 'Create a new IFC project. Returns a creator handle (number).',
|
|
426
|
-
args: ['dump'],
|
|
427
|
-
paramNames: ['params'],
|
|
428
|
-
tsParamTypes: ['{ Name?: string; Description?: string; Schema?: string; LengthUnit?: string; Author?: string; Organization?: string }'],
|
|
429
|
-
tsReturn: 'number',
|
|
430
|
-
call: (_sdk, args, context) => {
|
|
431
|
-
const params = (args[0] ?? {});
|
|
432
|
-
const creator = new IfcCreator(params);
|
|
433
|
-
return creatorRegistry.registerForSession(context.sandboxSessionId, creator);
|
|
434
|
-
},
|
|
435
|
-
returns: 'value',
|
|
436
|
-
llmSemantics: CREATE_METHOD_SEMANTICS.project,
|
|
437
|
-
});
|
|
438
|
-
// ── Special: toIfc (finalizes + cleans up handle) ──
|
|
439
|
-
methods.push({
|
|
440
|
-
name: 'toIfc',
|
|
441
|
-
doc: 'Generate the IFC STEP file content. Returns { content, entities, stats }.',
|
|
442
|
-
args: ['number'],
|
|
443
|
-
paramNames: ['handle'],
|
|
444
|
-
tsReturn: '{ content: string; entities: Array<{ expressId: number; type: string; Name?: string }>; stats: { entityCount: number; fileSize: number } }',
|
|
445
|
-
call: (_sdk, args, context) => {
|
|
446
|
-
const handle = args[0];
|
|
447
|
-
try {
|
|
448
|
-
const creator = creatorRegistry.getForSession(context.sandboxSessionId, handle);
|
|
449
|
-
return creator.toIfc();
|
|
450
|
-
}
|
|
451
|
-
finally {
|
|
452
|
-
creatorRegistry.removeForSession(context.sandboxSessionId, handle);
|
|
453
|
-
}
|
|
454
|
-
},
|
|
455
|
-
returns: 'value',
|
|
456
|
-
llmSemantics: CREATE_METHOD_SEMANTICS.toIfc,
|
|
457
|
-
});
|
|
458
|
-
// ── Special: setColor (unique signature: handle, elementId, name, rgb) ──
|
|
459
|
-
methods.push({
|
|
460
|
-
name: 'setColor',
|
|
461
|
-
doc: 'Assign a named colour to an element. Call before toIfc().',
|
|
462
|
-
args: ['number', 'number', 'string', 'dump'],
|
|
463
|
-
paramNames: ['handle', 'elementId', 'name', 'rgb'],
|
|
464
|
-
tsReturn: 'void',
|
|
465
|
-
call: (_sdk, args, context) => {
|
|
466
|
-
const creator = creatorRegistry.getForSession(context.sandboxSessionId, args[0]);
|
|
467
|
-
creator.setColor(args[1], args[2], args[3]);
|
|
468
|
-
},
|
|
469
|
-
returns: 'void',
|
|
470
|
-
llmSemantics: CREATE_METHOD_SEMANTICS.setColor,
|
|
471
|
-
});
|
|
472
|
-
// ── Auto-discover all other public methods from IfcCreator.prototype ──
|
|
473
|
-
const proto = IfcCreator.prototype;
|
|
474
|
-
const methodNames = Object.getOwnPropertyNames(proto)
|
|
475
|
-
.filter(name => typeof proto[name] === 'function' && ALLOWED_METHODS.has(name))
|
|
476
|
-
.sort();
|
|
477
|
-
for (const name of methodNames) {
|
|
478
|
-
const pattern = classifyMethod(name, proto[name]);
|
|
479
|
-
if (pattern === 'special')
|
|
480
|
-
continue; // already handled above
|
|
481
|
-
switch (pattern) {
|
|
482
|
-
case 'storey-params':
|
|
483
|
-
// addIfcBuildingStorey takes (params) — 1 arg after handle
|
|
484
|
-
if (name === 'addIfcBuildingStorey') {
|
|
485
|
-
methods.push({
|
|
486
|
-
name,
|
|
487
|
-
doc: methodDoc(name),
|
|
488
|
-
args: ['number', 'dump'],
|
|
489
|
-
paramNames: ['handle', 'params'],
|
|
490
|
-
tsReturn: 'number',
|
|
491
|
-
call: (_sdk, args, context) => {
|
|
492
|
-
const creator = creatorRegistry.getForSession(context.sandboxSessionId, args[0]);
|
|
493
|
-
return creator[name](args[1]);
|
|
494
|
-
},
|
|
495
|
-
returns: 'value',
|
|
496
|
-
llmSemantics: CREATE_METHOD_SEMANTICS[name],
|
|
497
|
-
});
|
|
498
|
-
}
|
|
499
|
-
else {
|
|
500
|
-
// Standard: (storeyId, params) — 2 args after handle
|
|
501
|
-
methods.push({
|
|
502
|
-
name,
|
|
503
|
-
doc: methodDoc(name),
|
|
504
|
-
args: ['number', 'number', 'dump'],
|
|
505
|
-
paramNames: ['handle', 'storeyId', 'params'],
|
|
506
|
-
tsReturn: 'number',
|
|
507
|
-
call: (_sdk, args, context) => {
|
|
508
|
-
const creator = creatorRegistry.getForSession(context.sandboxSessionId, args[0]);
|
|
509
|
-
return creator[name](args[1], args[2]);
|
|
510
|
-
},
|
|
511
|
-
returns: 'value',
|
|
512
|
-
llmSemantics: CREATE_METHOD_SEMANTICS[name],
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
break;
|
|
516
|
-
case 'element-params':
|
|
517
|
-
// (elementId, def) — 2 args after handle, may return number or void
|
|
518
|
-
methods.push({
|
|
519
|
-
name,
|
|
520
|
-
doc: methodDoc(name),
|
|
521
|
-
args: ['number', 'number', 'dump'],
|
|
522
|
-
paramNames: ['handle', name === 'addIfcWallDoor' || name === 'addIfcWallWindow' ? 'wallId' : 'elementId', 'params'],
|
|
523
|
-
tsReturn: name === 'addIfcMaterial' ? 'void' : 'number',
|
|
524
|
-
call: (_sdk, args, context) => {
|
|
525
|
-
const creator = creatorRegistry.getForSession(context.sandboxSessionId, args[0]);
|
|
526
|
-
return creator[name](args[1], args[2]);
|
|
527
|
-
},
|
|
528
|
-
returns: name === 'addIfcMaterial' ? 'void' : 'value',
|
|
529
|
-
llmSemantics: CREATE_METHOD_SEMANTICS[name],
|
|
530
|
-
});
|
|
531
|
-
break;
|
|
532
|
-
case 'single-dump':
|
|
533
|
-
methods.push({
|
|
534
|
-
name,
|
|
535
|
-
doc: methodDoc(name),
|
|
536
|
-
args: ['number', 'dump'],
|
|
537
|
-
paramNames: ['handle', 'profile'],
|
|
538
|
-
tsReturn: 'number',
|
|
539
|
-
call: (_sdk, args, context) => {
|
|
540
|
-
const creator = creatorRegistry.getForSession(context.sandboxSessionId, args[0]);
|
|
541
|
-
return creator[name](args[1]);
|
|
542
|
-
},
|
|
543
|
-
returns: 'value',
|
|
544
|
-
llmSemantics: CREATE_METHOD_SEMANTICS[name],
|
|
545
|
-
});
|
|
546
|
-
break;
|
|
547
|
-
case 'no-args':
|
|
548
|
-
methods.push({
|
|
549
|
-
name,
|
|
550
|
-
doc: methodDoc(name),
|
|
551
|
-
args: ['number'],
|
|
552
|
-
paramNames: ['handle'],
|
|
553
|
-
tsReturn: 'number',
|
|
554
|
-
call: (_sdk, args, context) => {
|
|
555
|
-
const creator = creatorRegistry.getForSession(context.sandboxSessionId, args[0]);
|
|
556
|
-
return creator[name]();
|
|
557
|
-
},
|
|
558
|
-
returns: 'value',
|
|
559
|
-
llmSemantics: CREATE_METHOD_SEMANTICS[name],
|
|
560
|
-
});
|
|
561
|
-
break;
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
return methods;
|
|
565
|
-
}
|
|
4
|
+
import { creatorRegistry } from './creator-registry.js';
|
|
5
|
+
import { buildModelNamespace } from './bridge-model.js';
|
|
6
|
+
import { buildQueryNamespace } from './bridge-query.js';
|
|
7
|
+
import { buildViewerNamespace } from './bridge-viewer.js';
|
|
8
|
+
import { buildMutateNamespace } from './bridge-mutate.js';
|
|
9
|
+
import { buildStoreNamespace } from './bridge-store.js';
|
|
10
|
+
import { buildCreateMethods } from './bridge-create.js';
|
|
11
|
+
import { buildFilesNamespace } from './bridge-files.js';
|
|
12
|
+
import { buildExportNamespace } from './bridge-export.js';
|
|
13
|
+
import { buildScheduleNamespace } from './bridge-schedule.js';
|
|
566
14
|
// ============================================================================
|
|
567
15
|
// Schema Definitions
|
|
568
16
|
// ============================================================================
|
|
569
17
|
export const NAMESPACE_SCHEMAS = [
|
|
570
18
|
// ── bim.model ──────────────────────────────────────────────
|
|
571
|
-
|
|
572
|
-
name: 'model',
|
|
573
|
-
doc: 'Model operations',
|
|
574
|
-
permission: 'model',
|
|
575
|
-
methods: [
|
|
576
|
-
{
|
|
577
|
-
name: 'list',
|
|
578
|
-
doc: 'List loaded models',
|
|
579
|
-
args: [],
|
|
580
|
-
tsReturn: 'BimModelInfo[]',
|
|
581
|
-
call: (sdk) => sdk.model.list(),
|
|
582
|
-
returns: 'value',
|
|
583
|
-
},
|
|
584
|
-
{
|
|
585
|
-
name: 'active',
|
|
586
|
-
doc: 'Get active model',
|
|
587
|
-
args: [],
|
|
588
|
-
tsReturn: 'BimModelInfo | null',
|
|
589
|
-
call: (sdk) => sdk.model.active(),
|
|
590
|
-
returns: 'value',
|
|
591
|
-
},
|
|
592
|
-
{
|
|
593
|
-
name: 'activeId',
|
|
594
|
-
doc: 'Get active model ID',
|
|
595
|
-
args: [],
|
|
596
|
-
tsReturn: 'string | null',
|
|
597
|
-
call: (sdk) => sdk.model.activeId(),
|
|
598
|
-
returns: 'value',
|
|
599
|
-
},
|
|
600
|
-
{
|
|
601
|
-
name: 'loadIfc',
|
|
602
|
-
doc: 'Load IFC content into the 3D viewer for preview',
|
|
603
|
-
args: ['string', 'string'],
|
|
604
|
-
paramNames: ['content', 'filename'],
|
|
605
|
-
call: (sdk, args) => { sdk.model.loadIfc(args[0], args[1]); },
|
|
606
|
-
returns: 'void',
|
|
607
|
-
},
|
|
608
|
-
],
|
|
609
|
-
},
|
|
19
|
+
buildModelNamespace(),
|
|
610
20
|
// ── bim.query ─────────────────────────────────────────────
|
|
611
|
-
|
|
612
|
-
name: 'query',
|
|
613
|
-
doc: 'Query entities',
|
|
614
|
-
permission: 'query',
|
|
615
|
-
methods: [
|
|
616
|
-
{
|
|
617
|
-
name: 'all',
|
|
618
|
-
doc: 'Get all entities',
|
|
619
|
-
args: [],
|
|
620
|
-
tsReturn: 'BimEntity[]',
|
|
621
|
-
call: (sdk) => {
|
|
622
|
-
return sdk.query().toArray().map(withAliases);
|
|
623
|
-
},
|
|
624
|
-
returns: 'value',
|
|
625
|
-
},
|
|
626
|
-
{
|
|
627
|
-
name: 'byType',
|
|
628
|
-
doc: "Filter by IFC type e.g. 'IfcWall'",
|
|
629
|
-
args: ['...strings'],
|
|
630
|
-
paramNames: ['types'],
|
|
631
|
-
tsReturn: 'BimEntity[]',
|
|
632
|
-
call: (sdk, args) => {
|
|
633
|
-
const types = args[0];
|
|
634
|
-
const builder = sdk.query();
|
|
635
|
-
if (types.length > 0)
|
|
636
|
-
builder.byType(...types);
|
|
637
|
-
return builder.toArray().map(withAliases);
|
|
638
|
-
},
|
|
639
|
-
returns: 'value',
|
|
640
|
-
},
|
|
641
|
-
{
|
|
642
|
-
name: 'entity',
|
|
643
|
-
doc: 'Get entity by model ID and express ID',
|
|
644
|
-
args: ['string', 'number'],
|
|
645
|
-
paramNames: ['modelId', 'expressId'],
|
|
646
|
-
tsReturn: 'BimEntity | null',
|
|
647
|
-
call: (sdk, args) => {
|
|
648
|
-
const modelId = args[0];
|
|
649
|
-
const expressId = args[1];
|
|
650
|
-
const entity = sdk.entity({ modelId, expressId });
|
|
651
|
-
return entity ? withAliases(entity) : null;
|
|
652
|
-
},
|
|
653
|
-
returns: 'value',
|
|
654
|
-
},
|
|
655
|
-
{
|
|
656
|
-
name: 'attributes',
|
|
657
|
-
doc: 'Get all named string/enum attributes for an entity',
|
|
658
|
-
args: ['dump'],
|
|
659
|
-
paramNames: ['entity'],
|
|
660
|
-
tsParamTypes: ['BimEntity'],
|
|
661
|
-
tsReturn: 'BimAttribute[]',
|
|
662
|
-
call: (sdk, args) => {
|
|
663
|
-
const ref = toRef(args[0]);
|
|
664
|
-
if (!ref)
|
|
665
|
-
return [];
|
|
666
|
-
return sdk.attributes(ref);
|
|
667
|
-
},
|
|
668
|
-
returns: 'value',
|
|
669
|
-
llmSemantics: {
|
|
670
|
-
taskTags: ['inspect', 'repair'],
|
|
671
|
-
inspectFirst: true,
|
|
672
|
-
useWhen: 'Inspect raw IFC occurrence attributes before guessing metadata names.',
|
|
673
|
-
},
|
|
674
|
-
},
|
|
675
|
-
{
|
|
676
|
-
name: 'properties',
|
|
677
|
-
doc: 'Get all IfcPropertySet data for an entity',
|
|
678
|
-
args: ['dump'],
|
|
679
|
-
paramNames: ['entity'],
|
|
680
|
-
tsParamTypes: ['BimEntity'],
|
|
681
|
-
tsReturn: 'BimPropertySet[]',
|
|
682
|
-
call: (sdk, args) => {
|
|
683
|
-
const ref = toRef(args[0]);
|
|
684
|
-
if (!ref)
|
|
685
|
-
return [];
|
|
686
|
-
return sdk.properties(ref).map(pset => {
|
|
687
|
-
const mappedProperties = mapNamedProperties(pset.properties);
|
|
688
|
-
return {
|
|
689
|
-
name: pset.name, Name: pset.name,
|
|
690
|
-
globalId: pset.globalId, GlobalId: pset.globalId,
|
|
691
|
-
properties: mappedProperties,
|
|
692
|
-
Properties: mappedProperties,
|
|
693
|
-
};
|
|
694
|
-
});
|
|
695
|
-
},
|
|
696
|
-
returns: 'value',
|
|
697
|
-
llmSemantics: {
|
|
698
|
-
taskTags: ['inspect', 'repair'],
|
|
699
|
-
inspectFirst: true,
|
|
700
|
-
useWhen: 'Inspect all property sets on an occurrence before guessing individual property names.',
|
|
701
|
-
},
|
|
702
|
-
},
|
|
703
|
-
{
|
|
704
|
-
name: 'quantities',
|
|
705
|
-
doc: 'Get all IfcElementQuantity data for an entity',
|
|
706
|
-
args: ['dump'],
|
|
707
|
-
paramNames: ['entity'],
|
|
708
|
-
tsParamTypes: ['BimEntity'],
|
|
709
|
-
tsReturn: 'BimQuantitySet[]',
|
|
710
|
-
call: (sdk, args) => {
|
|
711
|
-
const ref = toRef(args[0]);
|
|
712
|
-
if (!ref)
|
|
713
|
-
return [];
|
|
714
|
-
return sdk.quantities(ref).map(qset => {
|
|
715
|
-
const mappedQuantities = mapNamedProperties(qset.quantities);
|
|
716
|
-
return {
|
|
717
|
-
name: qset.name, Name: qset.name,
|
|
718
|
-
quantities: mappedQuantities,
|
|
719
|
-
Quantities: mappedQuantities,
|
|
720
|
-
};
|
|
721
|
-
});
|
|
722
|
-
},
|
|
723
|
-
returns: 'value',
|
|
724
|
-
llmSemantics: {
|
|
725
|
-
taskTags: ['inspect', 'repair'],
|
|
726
|
-
inspectFirst: true,
|
|
727
|
-
useWhen: 'Inspect all quantity sets on an occurrence.',
|
|
728
|
-
},
|
|
729
|
-
},
|
|
730
|
-
{
|
|
731
|
-
name: 'property',
|
|
732
|
-
doc: 'Get a single property value from an entity',
|
|
733
|
-
args: ['dump', 'string', 'string'],
|
|
734
|
-
paramNames: ['entity', 'psetName', 'propName'],
|
|
735
|
-
tsParamTypes: ['BimEntity'],
|
|
736
|
-
tsReturn: 'string | number | boolean | null',
|
|
737
|
-
call: (sdk, args) => {
|
|
738
|
-
const ref = toRef(args[0]);
|
|
739
|
-
if (!ref)
|
|
740
|
-
return null;
|
|
741
|
-
return sdk.property(ref, args[1], args[2]);
|
|
742
|
-
},
|
|
743
|
-
returns: 'value',
|
|
744
|
-
llmSemantics: {
|
|
745
|
-
taskTags: ['inspect', 'repair'],
|
|
746
|
-
inspectFirst: true,
|
|
747
|
-
useWhen: 'Read one known property when you already know the exact property-set and property names.',
|
|
748
|
-
},
|
|
749
|
-
},
|
|
750
|
-
{
|
|
751
|
-
name: 'classifications',
|
|
752
|
-
doc: 'Get classification references for an entity',
|
|
753
|
-
args: ['dump'],
|
|
754
|
-
paramNames: ['entity'],
|
|
755
|
-
tsParamTypes: ['BimEntity'],
|
|
756
|
-
tsReturn: 'BimClassification[]',
|
|
757
|
-
call: (sdk, args) => {
|
|
758
|
-
const ref = toRef(args[0]);
|
|
759
|
-
if (!ref)
|
|
760
|
-
return [];
|
|
761
|
-
return sdk.classifications(ref);
|
|
762
|
-
},
|
|
763
|
-
returns: 'value',
|
|
764
|
-
llmSemantics: {
|
|
765
|
-
taskTags: ['inspect', 'repair'],
|
|
766
|
-
inspectFirst: true,
|
|
767
|
-
useWhen: 'Read relationship-based classification references.',
|
|
768
|
-
cautions: ['Prefer this over guessing ad-hoc classification property names.'],
|
|
769
|
-
},
|
|
770
|
-
},
|
|
771
|
-
{
|
|
772
|
-
name: 'materials',
|
|
773
|
-
doc: 'Get material assignment for an entity',
|
|
774
|
-
args: ['dump'],
|
|
775
|
-
paramNames: ['entity'],
|
|
776
|
-
tsParamTypes: ['BimEntity'],
|
|
777
|
-
tsReturn: 'BimMaterial | null',
|
|
778
|
-
call: (sdk, args) => {
|
|
779
|
-
const ref = toRef(args[0]);
|
|
780
|
-
if (!ref)
|
|
781
|
-
return null;
|
|
782
|
-
return sdk.materials(ref);
|
|
783
|
-
},
|
|
784
|
-
returns: 'value',
|
|
785
|
-
llmSemantics: {
|
|
786
|
-
taskTags: ['inspect', 'repair'],
|
|
787
|
-
inspectFirst: true,
|
|
788
|
-
useWhen: 'Read assigned material data for an entity.',
|
|
789
|
-
cautions: ['Prefer this over querying Pset_MaterialCommon or Material.Name as ordinary property sets.'],
|
|
790
|
-
},
|
|
791
|
-
},
|
|
792
|
-
{
|
|
793
|
-
name: 'typeProperties',
|
|
794
|
-
doc: 'Get type-level property sets for an entity',
|
|
795
|
-
args: ['dump'],
|
|
796
|
-
paramNames: ['entity'],
|
|
797
|
-
tsParamTypes: ['BimEntity'],
|
|
798
|
-
tsReturn: 'BimTypeProperties | null',
|
|
799
|
-
call: (sdk, args) => {
|
|
800
|
-
const ref = toRef(args[0]);
|
|
801
|
-
if (!ref)
|
|
802
|
-
return null;
|
|
803
|
-
return sdk.typeProperties(ref);
|
|
804
|
-
},
|
|
805
|
-
returns: 'value',
|
|
806
|
-
llmSemantics: {
|
|
807
|
-
taskTags: ['inspect', 'repair'],
|
|
808
|
-
inspectFirst: true,
|
|
809
|
-
useWhen: 'Inspect type-level properties when occurrence-level property sets are missing expected data.',
|
|
810
|
-
},
|
|
811
|
-
},
|
|
812
|
-
{
|
|
813
|
-
name: 'documents',
|
|
814
|
-
doc: 'Get linked document references for an entity',
|
|
815
|
-
args: ['dump'],
|
|
816
|
-
paramNames: ['entity'],
|
|
817
|
-
tsParamTypes: ['BimEntity'],
|
|
818
|
-
tsReturn: 'BimDocument[]',
|
|
819
|
-
call: (sdk, args) => {
|
|
820
|
-
const ref = toRef(args[0]);
|
|
821
|
-
if (!ref)
|
|
822
|
-
return [];
|
|
823
|
-
return sdk.documents(ref);
|
|
824
|
-
},
|
|
825
|
-
returns: 'value',
|
|
826
|
-
llmSemantics: {
|
|
827
|
-
taskTags: ['inspect', 'repair'],
|
|
828
|
-
inspectFirst: true,
|
|
829
|
-
useWhen: 'Inspect linked document references and external documentation.',
|
|
830
|
-
},
|
|
831
|
-
},
|
|
832
|
-
{
|
|
833
|
-
name: 'relationships',
|
|
834
|
-
doc: 'Get structural relationship summary for an entity',
|
|
835
|
-
args: ['dump'],
|
|
836
|
-
paramNames: ['entity'],
|
|
837
|
-
tsParamTypes: ['BimEntity'],
|
|
838
|
-
tsReturn: 'BimRelationships',
|
|
839
|
-
call: (sdk, args) => {
|
|
840
|
-
const ref = toRef(args[0]);
|
|
841
|
-
if (!ref)
|
|
842
|
-
return { voids: [], fills: [], groups: [], connections: [] };
|
|
843
|
-
return sdk.relationships(ref);
|
|
844
|
-
},
|
|
845
|
-
returns: 'value',
|
|
846
|
-
llmSemantics: {
|
|
847
|
-
taskTags: ['inspect', 'repair'],
|
|
848
|
-
inspectFirst: true,
|
|
849
|
-
useWhen: 'Inspect structural and semantic relationships such as voids, fills, groups, and connections.',
|
|
850
|
-
},
|
|
851
|
-
},
|
|
852
|
-
{
|
|
853
|
-
name: 'quantity',
|
|
854
|
-
doc: 'Get a single quantity value from an entity',
|
|
855
|
-
args: ['dump', 'string', 'string'],
|
|
856
|
-
paramNames: ['entity', 'qsetName', 'quantityName'],
|
|
857
|
-
tsParamTypes: ['BimEntity'],
|
|
858
|
-
tsReturn: 'number | null',
|
|
859
|
-
call: (sdk, args) => {
|
|
860
|
-
const ref = toRef(args[0]);
|
|
861
|
-
if (!ref)
|
|
862
|
-
return null;
|
|
863
|
-
return sdk.quantity(ref, args[1], args[2]);
|
|
864
|
-
},
|
|
865
|
-
returns: 'value',
|
|
866
|
-
},
|
|
867
|
-
{
|
|
868
|
-
name: 'related',
|
|
869
|
-
doc: 'Get related entities by IFC relationship type',
|
|
870
|
-
args: ['dump', 'string', 'string'],
|
|
871
|
-
paramNames: ['entity', 'relType', 'direction'],
|
|
872
|
-
tsParamTypes: ['BimEntity', undefined, "'forward' | 'inverse'"],
|
|
873
|
-
tsReturn: 'BimEntity[]',
|
|
874
|
-
call: (sdk, args) => {
|
|
875
|
-
const ref = toRef(args[0]);
|
|
876
|
-
if (!ref)
|
|
877
|
-
return [];
|
|
878
|
-
return sdk.related(ref, args[1], args[2]).map(withAliases);
|
|
879
|
-
},
|
|
880
|
-
returns: 'value',
|
|
881
|
-
llmSemantics: {
|
|
882
|
-
taskTags: ['inspect', 'repair'],
|
|
883
|
-
inspectFirst: true,
|
|
884
|
-
useWhen: 'Traverse a known IFC relationship type in forward or inverse direction.',
|
|
885
|
-
},
|
|
886
|
-
},
|
|
887
|
-
{
|
|
888
|
-
name: 'containedIn',
|
|
889
|
-
doc: 'Get the spatial container of an entity',
|
|
890
|
-
args: ['dump'],
|
|
891
|
-
paramNames: ['entity'],
|
|
892
|
-
tsParamTypes: ['BimEntity'],
|
|
893
|
-
tsReturn: 'BimEntity | null',
|
|
894
|
-
call: (sdk, args) => {
|
|
895
|
-
const ref = toRef(args[0]);
|
|
896
|
-
if (!ref)
|
|
897
|
-
return null;
|
|
898
|
-
const entity = sdk.containedIn(ref);
|
|
899
|
-
return entity ? withAliases(entity) : null;
|
|
900
|
-
},
|
|
901
|
-
returns: 'value',
|
|
902
|
-
},
|
|
903
|
-
{
|
|
904
|
-
name: 'contains',
|
|
905
|
-
doc: 'Get entities contained in a spatial container',
|
|
906
|
-
args: ['dump'],
|
|
907
|
-
paramNames: ['entity'],
|
|
908
|
-
tsParamTypes: ['BimEntity'],
|
|
909
|
-
tsReturn: 'BimEntity[]',
|
|
910
|
-
call: (sdk, args) => {
|
|
911
|
-
const ref = toRef(args[0]);
|
|
912
|
-
if (!ref)
|
|
913
|
-
return [];
|
|
914
|
-
return sdk.contains(ref).map(withAliases);
|
|
915
|
-
},
|
|
916
|
-
returns: 'value',
|
|
917
|
-
},
|
|
918
|
-
{
|
|
919
|
-
name: 'decomposedBy',
|
|
920
|
-
doc: 'Get the parent aggregate of an entity',
|
|
921
|
-
args: ['dump'],
|
|
922
|
-
paramNames: ['entity'],
|
|
923
|
-
tsParamTypes: ['BimEntity'],
|
|
924
|
-
tsReturn: 'BimEntity | null',
|
|
925
|
-
call: (sdk, args) => {
|
|
926
|
-
const ref = toRef(args[0]);
|
|
927
|
-
if (!ref)
|
|
928
|
-
return null;
|
|
929
|
-
const entity = sdk.decomposedBy(ref);
|
|
930
|
-
return entity ? withAliases(entity) : null;
|
|
931
|
-
},
|
|
932
|
-
returns: 'value',
|
|
933
|
-
},
|
|
934
|
-
{
|
|
935
|
-
name: 'decomposes',
|
|
936
|
-
doc: 'Get aggregated children of an entity',
|
|
937
|
-
args: ['dump'],
|
|
938
|
-
paramNames: ['entity'],
|
|
939
|
-
tsParamTypes: ['BimEntity'],
|
|
940
|
-
tsReturn: 'BimEntity[]',
|
|
941
|
-
call: (sdk, args) => {
|
|
942
|
-
const ref = toRef(args[0]);
|
|
943
|
-
if (!ref)
|
|
944
|
-
return [];
|
|
945
|
-
return sdk.decomposes(ref).map(withAliases);
|
|
946
|
-
},
|
|
947
|
-
returns: 'value',
|
|
948
|
-
},
|
|
949
|
-
{
|
|
950
|
-
name: 'storey',
|
|
951
|
-
doc: 'Get the containing building storey of an entity',
|
|
952
|
-
args: ['dump'],
|
|
953
|
-
paramNames: ['entity'],
|
|
954
|
-
tsParamTypes: ['BimEntity'],
|
|
955
|
-
tsReturn: 'BimEntity | null',
|
|
956
|
-
call: (sdk, args) => {
|
|
957
|
-
const ref = toRef(args[0]);
|
|
958
|
-
if (!ref)
|
|
959
|
-
return null;
|
|
960
|
-
const entity = sdk.storey(ref);
|
|
961
|
-
return entity ? withAliases(entity) : null;
|
|
962
|
-
},
|
|
963
|
-
returns: 'value',
|
|
964
|
-
llmSemantics: {
|
|
965
|
-
taskTags: ['inspect', 'repair'],
|
|
966
|
-
inspectFirst: true,
|
|
967
|
-
useWhen: 'Resolve which building storey currently contains an entity.',
|
|
968
|
-
},
|
|
969
|
-
},
|
|
970
|
-
{
|
|
971
|
-
name: 'path',
|
|
972
|
-
doc: 'Get the spatial/aggregation path from project to entity',
|
|
973
|
-
args: ['dump'],
|
|
974
|
-
paramNames: ['entity'],
|
|
975
|
-
tsParamTypes: ['BimEntity'],
|
|
976
|
-
tsReturn: 'BimEntity[]',
|
|
977
|
-
call: (sdk, args) => {
|
|
978
|
-
const ref = toRef(args[0]);
|
|
979
|
-
if (!ref)
|
|
980
|
-
return [];
|
|
981
|
-
return sdk.path(ref).map(withAliases);
|
|
982
|
-
},
|
|
983
|
-
returns: 'value',
|
|
984
|
-
llmSemantics: {
|
|
985
|
-
taskTags: ['inspect', 'repair'],
|
|
986
|
-
inspectFirst: true,
|
|
987
|
-
useWhen: 'Inspect the full project-to-entity spatial path before generating hierarchy-aware edits.',
|
|
988
|
-
},
|
|
989
|
-
},
|
|
990
|
-
{
|
|
991
|
-
name: 'storeys',
|
|
992
|
-
doc: 'List all building storeys',
|
|
993
|
-
args: [],
|
|
994
|
-
tsReturn: 'BimEntity[]',
|
|
995
|
-
call: (sdk) => {
|
|
996
|
-
return sdk.storeys().map(withAliases);
|
|
997
|
-
},
|
|
998
|
-
returns: 'value',
|
|
999
|
-
llmSemantics: {
|
|
1000
|
-
taskTags: ['inspect', 'repair'],
|
|
1001
|
-
inspectFirst: true,
|
|
1002
|
-
useWhen: 'List all building storeys and use their actual names/elevations as generation targets.',
|
|
1003
|
-
},
|
|
1004
|
-
},
|
|
1005
|
-
{
|
|
1006
|
-
name: 'selection',
|
|
1007
|
-
doc: 'Get the current viewer selection as entities',
|
|
1008
|
-
args: [],
|
|
1009
|
-
tsReturn: 'BimEntity[]',
|
|
1010
|
-
call: (sdk) => {
|
|
1011
|
-
return sdk.viewer.getSelection()
|
|
1012
|
-
.map((ref) => sdk.entity(ref))
|
|
1013
|
-
.filter((entity) => Boolean(entity))
|
|
1014
|
-
.map(withAliases);
|
|
1015
|
-
},
|
|
1016
|
-
returns: 'value',
|
|
1017
|
-
llmSemantics: {
|
|
1018
|
-
taskTags: ['inspect', 'repair'],
|
|
1019
|
-
inspectFirst: true,
|
|
1020
|
-
useWhen: 'Inspect what the user currently selected in the viewer before proposing targeted edits or analysis.',
|
|
1021
|
-
},
|
|
1022
|
-
},
|
|
1023
|
-
],
|
|
1024
|
-
},
|
|
21
|
+
buildQueryNamespace(),
|
|
1025
22
|
// ── bim.viewer ─────────────────────────────────────────────
|
|
1026
|
-
|
|
1027
|
-
name: 'viewer',
|
|
1028
|
-
doc: 'Viewer control',
|
|
1029
|
-
permission: 'viewer',
|
|
1030
|
-
methods: [
|
|
1031
|
-
{
|
|
1032
|
-
name: 'colorize',
|
|
1033
|
-
doc: "Colorize entities e.g. '#ff0000'",
|
|
1034
|
-
args: ['entityRefs', 'string'],
|
|
1035
|
-
paramNames: ['entities', 'color'],
|
|
1036
|
-
call: (sdk, args) => {
|
|
1037
|
-
sdk.viewer.colorize(args[0], args[1]);
|
|
1038
|
-
},
|
|
1039
|
-
returns: 'void',
|
|
1040
|
-
},
|
|
1041
|
-
{
|
|
1042
|
-
name: 'colorizeAll',
|
|
1043
|
-
doc: 'Batch colorize with [{entities, color}]',
|
|
1044
|
-
args: ['dump'],
|
|
1045
|
-
paramNames: ['batches'],
|
|
1046
|
-
tsParamTypes: ['Array<{ entities: BimEntity[]; color: string }>'],
|
|
1047
|
-
tsReturn: 'void',
|
|
1048
|
-
call: (sdk, args) => {
|
|
1049
|
-
// batches: Array<{ entities: EntityData[], color: string }>
|
|
1050
|
-
// Extract .ref from entity data objects and pass to SDK
|
|
1051
|
-
const raw = args[0];
|
|
1052
|
-
const batches = raw.map(b => ({
|
|
1053
|
-
refs: b.entities.map(e => e.ref ?? e),
|
|
1054
|
-
color: b.color,
|
|
1055
|
-
}));
|
|
1056
|
-
sdk.viewer.colorizeAll(batches);
|
|
1057
|
-
},
|
|
1058
|
-
returns: 'void',
|
|
1059
|
-
},
|
|
1060
|
-
{
|
|
1061
|
-
name: 'hide',
|
|
1062
|
-
doc: 'Hide entities',
|
|
1063
|
-
args: ['entityRefs'],
|
|
1064
|
-
paramNames: ['entities'],
|
|
1065
|
-
call: (sdk, args) => {
|
|
1066
|
-
sdk.viewer.hide(args[0]);
|
|
1067
|
-
},
|
|
1068
|
-
returns: 'void',
|
|
1069
|
-
},
|
|
1070
|
-
{
|
|
1071
|
-
name: 'show',
|
|
1072
|
-
doc: 'Show entities',
|
|
1073
|
-
args: ['entityRefs'],
|
|
1074
|
-
paramNames: ['entities'],
|
|
1075
|
-
call: (sdk, args) => {
|
|
1076
|
-
sdk.viewer.show(args[0]);
|
|
1077
|
-
},
|
|
1078
|
-
returns: 'void',
|
|
1079
|
-
},
|
|
1080
|
-
{
|
|
1081
|
-
name: 'isolate',
|
|
1082
|
-
doc: 'Isolate entities',
|
|
1083
|
-
args: ['entityRefs'],
|
|
1084
|
-
paramNames: ['entities'],
|
|
1085
|
-
call: (sdk, args) => {
|
|
1086
|
-
sdk.viewer.isolate(args[0]);
|
|
1087
|
-
},
|
|
1088
|
-
returns: 'void',
|
|
1089
|
-
},
|
|
1090
|
-
{
|
|
1091
|
-
name: 'select',
|
|
1092
|
-
doc: 'Select entities',
|
|
1093
|
-
args: ['entityRefs'],
|
|
1094
|
-
paramNames: ['entities'],
|
|
1095
|
-
call: (sdk, args) => {
|
|
1096
|
-
sdk.viewer.select(args[0]);
|
|
1097
|
-
},
|
|
1098
|
-
returns: 'void',
|
|
1099
|
-
},
|
|
1100
|
-
{
|
|
1101
|
-
name: 'flyTo',
|
|
1102
|
-
doc: 'Fly camera to entities',
|
|
1103
|
-
args: ['entityRefs'],
|
|
1104
|
-
paramNames: ['entities'],
|
|
1105
|
-
call: (sdk, args) => {
|
|
1106
|
-
sdk.viewer.flyTo(args[0]);
|
|
1107
|
-
},
|
|
1108
|
-
returns: 'void',
|
|
1109
|
-
},
|
|
1110
|
-
{
|
|
1111
|
-
name: 'resetColors',
|
|
1112
|
-
doc: 'Reset all colors',
|
|
1113
|
-
args: [],
|
|
1114
|
-
call: (sdk) => {
|
|
1115
|
-
sdk.viewer.resetColors();
|
|
1116
|
-
},
|
|
1117
|
-
returns: 'void',
|
|
1118
|
-
},
|
|
1119
|
-
{
|
|
1120
|
-
name: 'resetVisibility',
|
|
1121
|
-
doc: 'Reset all visibility',
|
|
1122
|
-
args: [],
|
|
1123
|
-
call: (sdk) => {
|
|
1124
|
-
sdk.viewer.resetVisibility();
|
|
1125
|
-
},
|
|
1126
|
-
returns: 'void',
|
|
1127
|
-
},
|
|
1128
|
-
],
|
|
1129
|
-
},
|
|
23
|
+
buildViewerNamespace(),
|
|
1130
24
|
// ── bim.mutate ─────────────────────────────────────────────
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
permission: 'mutate',
|
|
1135
|
-
methods: [
|
|
1136
|
-
{
|
|
1137
|
-
name: 'setProperty',
|
|
1138
|
-
doc: 'Set an IfcPropertySet or quantity value (not a root IFC attribute)',
|
|
1139
|
-
args: ['dump', 'string', 'string', 'dump'],
|
|
1140
|
-
paramNames: ['entity', 'psetName', 'propName', 'value'],
|
|
1141
|
-
call: (sdk, args) => {
|
|
1142
|
-
const ref = toRef(args[0]);
|
|
1143
|
-
if (!ref) {
|
|
1144
|
-
throw new Error('bim.mutate.setProperty: invalid entity reference');
|
|
1145
|
-
}
|
|
1146
|
-
sdk.mutate.setProperty(ref, args[1], args[2], args[3]);
|
|
1147
|
-
},
|
|
1148
|
-
returns: 'void',
|
|
1149
|
-
},
|
|
1150
|
-
{
|
|
1151
|
-
name: 'setAttribute',
|
|
1152
|
-
doc: 'Set a root IFC attribute such as Name, Description, ObjectType, or Tag',
|
|
1153
|
-
args: ['dump', 'string', 'string'],
|
|
1154
|
-
paramNames: ['entity', 'attrName', 'value'],
|
|
1155
|
-
call: (sdk, args) => {
|
|
1156
|
-
const ref = toRef(args[0]);
|
|
1157
|
-
if (!ref) {
|
|
1158
|
-
throw new Error('bim.mutate.setAttribute: invalid entity reference');
|
|
1159
|
-
}
|
|
1160
|
-
sdk.mutate.setAttribute(ref, args[1], args[2]);
|
|
1161
|
-
},
|
|
1162
|
-
returns: 'void',
|
|
1163
|
-
},
|
|
1164
|
-
{
|
|
1165
|
-
name: 'deleteProperty',
|
|
1166
|
-
doc: 'Delete a property',
|
|
1167
|
-
args: ['dump', 'string', 'string'],
|
|
1168
|
-
paramNames: ['entity', 'psetName', 'propName'],
|
|
1169
|
-
call: (sdk, args) => {
|
|
1170
|
-
const ref = toRef(args[0]);
|
|
1171
|
-
if (!ref) {
|
|
1172
|
-
throw new Error('bim.mutate.deleteProperty: invalid entity reference');
|
|
1173
|
-
}
|
|
1174
|
-
sdk.mutate.deleteProperty(ref, args[1], args[2]);
|
|
1175
|
-
},
|
|
1176
|
-
returns: 'void',
|
|
1177
|
-
},
|
|
1178
|
-
// Note: batch is intentionally omitted — it takes a callback in the SDK
|
|
1179
|
-
// but QuickJS cannot marshal functions through vm.dump(). Scripts should
|
|
1180
|
-
// use individual setProperty calls instead.
|
|
1181
|
-
{
|
|
1182
|
-
name: 'undo',
|
|
1183
|
-
doc: 'Undo last mutation',
|
|
1184
|
-
args: ['string'],
|
|
1185
|
-
paramNames: ['modelId'],
|
|
1186
|
-
call: (sdk, args) => {
|
|
1187
|
-
sdk.mutate.undo(args[0]);
|
|
1188
|
-
},
|
|
1189
|
-
returns: 'void',
|
|
1190
|
-
},
|
|
1191
|
-
{
|
|
1192
|
-
name: 'redo',
|
|
1193
|
-
doc: 'Redo undone mutation',
|
|
1194
|
-
args: ['string'],
|
|
1195
|
-
paramNames: ['modelId'],
|
|
1196
|
-
call: (sdk, args) => {
|
|
1197
|
-
sdk.mutate.redo(args[0]);
|
|
1198
|
-
},
|
|
1199
|
-
returns: 'void',
|
|
1200
|
-
},
|
|
1201
|
-
],
|
|
1202
|
-
},
|
|
25
|
+
buildMutateNamespace(),
|
|
26
|
+
// ── bim.store ──────────────────────────────────────────────
|
|
27
|
+
buildStoreNamespace(),
|
|
1203
28
|
// ── bim.lens ───────────────────────────────────────────────
|
|
1204
29
|
{
|
|
1205
30
|
name: 'lens',
|
|
@@ -1228,110 +53,12 @@ export const NAMESPACE_SCHEMAS = [
|
|
|
1228
53
|
permission: 'export', // reuses export permission — creation produces files
|
|
1229
54
|
methods: buildCreateMethods(),
|
|
1230
55
|
},
|
|
56
|
+
// ── bim.files ──────────────────────────────────────────────
|
|
57
|
+
buildFilesNamespace(),
|
|
58
|
+
// ── bim.schedule ───────────────────────────────────────────
|
|
59
|
+
buildScheduleNamespace(),
|
|
1231
60
|
// ── bim.export ─────────────────────────────────────────────
|
|
1232
|
-
|
|
1233
|
-
name: 'files',
|
|
1234
|
-
doc: 'Uploaded file attachments',
|
|
1235
|
-
permission: 'files',
|
|
1236
|
-
methods: [
|
|
1237
|
-
{
|
|
1238
|
-
name: 'list',
|
|
1239
|
-
doc: 'List uploaded file attachments available to scripts',
|
|
1240
|
-
args: [],
|
|
1241
|
-
tsReturn: 'BimFileAttachment[]',
|
|
1242
|
-
call: (sdk) => sdk.files.list(),
|
|
1243
|
-
returns: 'value',
|
|
1244
|
-
},
|
|
1245
|
-
{
|
|
1246
|
-
name: 'text',
|
|
1247
|
-
doc: 'Get raw text content for an uploaded attachment by file name',
|
|
1248
|
-
args: ['string'],
|
|
1249
|
-
paramNames: ['name'],
|
|
1250
|
-
tsReturn: 'string | null',
|
|
1251
|
-
call: (sdk, args) => sdk.files.text(args[0]),
|
|
1252
|
-
returns: 'value',
|
|
1253
|
-
llmSemantics: {
|
|
1254
|
-
taskTags: ['inspect', 'modify', 'repair', 'export'],
|
|
1255
|
-
useWhen: 'Read uploaded CSV, TSV, JSON, or text attachments without using fetch().',
|
|
1256
|
-
},
|
|
1257
|
-
},
|
|
1258
|
-
{
|
|
1259
|
-
name: 'csv',
|
|
1260
|
-
doc: 'Get parsed CSV/TSV rows for an uploaded attachment by file name',
|
|
1261
|
-
args: ['string'],
|
|
1262
|
-
paramNames: ['name'],
|
|
1263
|
-
tsReturn: 'Record<string, string>[] | null',
|
|
1264
|
-
call: (sdk, args) => sdk.files.csv(args[0]),
|
|
1265
|
-
returns: 'value',
|
|
1266
|
-
llmSemantics: {
|
|
1267
|
-
taskTags: ['inspect', 'modify', 'repair', 'export'],
|
|
1268
|
-
useWhen: 'Load uploaded CSV rows directly inside a script and join them against model entities.',
|
|
1269
|
-
},
|
|
1270
|
-
},
|
|
1271
|
-
{
|
|
1272
|
-
name: 'csvColumns',
|
|
1273
|
-
doc: 'Get parsed CSV column names for an uploaded attachment by file name',
|
|
1274
|
-
args: ['string'],
|
|
1275
|
-
paramNames: ['name'],
|
|
1276
|
-
tsReturn: 'string[]',
|
|
1277
|
-
call: (sdk, args) => sdk.files.csvColumns(args[0]),
|
|
1278
|
-
returns: 'value',
|
|
1279
|
-
},
|
|
1280
|
-
],
|
|
1281
|
-
},
|
|
1282
|
-
{
|
|
1283
|
-
name: 'export',
|
|
1284
|
-
doc: 'Data export',
|
|
1285
|
-
permission: 'export',
|
|
1286
|
-
methods: [
|
|
1287
|
-
{
|
|
1288
|
-
name: 'csv',
|
|
1289
|
-
doc: 'Export entities to CSV string',
|
|
1290
|
-
args: ['entityRefs', 'dump'],
|
|
1291
|
-
paramNames: ['entities', 'options'],
|
|
1292
|
-
tsParamTypes: [undefined, '{ columns: string[]; filename?: string; separator?: string }'],
|
|
1293
|
-
tsReturn: 'string',
|
|
1294
|
-
call: (sdk, args) => {
|
|
1295
|
-
return sdk.export.csv(args[0], args[1]);
|
|
1296
|
-
},
|
|
1297
|
-
returns: 'string',
|
|
1298
|
-
},
|
|
1299
|
-
{
|
|
1300
|
-
name: 'json',
|
|
1301
|
-
doc: 'Export entities to JSON array',
|
|
1302
|
-
args: ['entityRefs', 'dump'],
|
|
1303
|
-
paramNames: ['entities', 'columns'],
|
|
1304
|
-
tsParamTypes: [undefined, 'string[]'],
|
|
1305
|
-
tsReturn: 'Record<string, unknown>[]',
|
|
1306
|
-
call: (sdk, args) => {
|
|
1307
|
-
return sdk.export.json(args[0], args[1]);
|
|
1308
|
-
},
|
|
1309
|
-
returns: 'value',
|
|
1310
|
-
},
|
|
1311
|
-
{
|
|
1312
|
-
name: 'ifc',
|
|
1313
|
-
doc: 'Export entities to IFC STEP text. Pass filename to auto-download a valid .ifc file',
|
|
1314
|
-
args: ['entityRefs', 'dump'],
|
|
1315
|
-
paramNames: ['entities', 'options'],
|
|
1316
|
-
tsParamTypes: [undefined, '{ schema?: "IFC2X3" | "IFC4" | "IFC4X3"; filename?: string; includeMutations?: boolean; visibleOnly?: boolean }'],
|
|
1317
|
-
tsReturn: 'string | Uint8Array',
|
|
1318
|
-
call: (sdk, args) => {
|
|
1319
|
-
return sdk.export.ifc(args[0], args[1]);
|
|
1320
|
-
},
|
|
1321
|
-
returns: 'string',
|
|
1322
|
-
},
|
|
1323
|
-
{
|
|
1324
|
-
name: 'download',
|
|
1325
|
-
doc: 'Trigger a browser file download with the given content',
|
|
1326
|
-
args: ['string', 'string', 'string'],
|
|
1327
|
-
paramNames: ['content', 'filename', 'mimeType'],
|
|
1328
|
-
call: (sdk, args) => {
|
|
1329
|
-
sdk.export.download(args[0], args[1], args[2] || 'text/plain');
|
|
1330
|
-
},
|
|
1331
|
-
returns: 'void',
|
|
1332
|
-
},
|
|
1333
|
-
],
|
|
1334
|
-
},
|
|
61
|
+
buildExportNamespace(),
|
|
1335
62
|
];
|
|
1336
63
|
// ============================================================================
|
|
1337
64
|
// Generic Builder
|