@snaptrude/plugin-core 0.9.14 → 0.9.16

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 (51) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/api-manifest.json +527 -26
  3. package/dist/api/core/camera/index.d.ts +418 -0
  4. package/dist/api/core/camera/index.d.ts.map +1 -1
  5. package/dist/api/core/index.d.ts +4 -4
  6. package/dist/api/core/index.d.ts.map +1 -1
  7. package/dist/api/core/layers.d.ts +377 -255
  8. package/dist/api/core/layers.d.ts.map +1 -1
  9. package/dist/api/core/proposals/index.d.ts +4 -3
  10. package/dist/api/core/proposals/index.d.ts.map +1 -1
  11. package/dist/api/core/storeys/index.d.ts +12 -0
  12. package/dist/api/core/storeys/index.d.ts.map +1 -1
  13. package/dist/api/core/storeys/layers.d.ts +408 -0
  14. package/dist/api/core/storeys/layers.d.ts.map +1 -0
  15. package/dist/api/core/tags.d.ts +3 -3
  16. package/dist/api/design/create/bulk-items.d.ts +44 -0
  17. package/dist/api/design/create/bulk-items.d.ts.map +1 -1
  18. package/dist/api/design/create/index.d.ts +31 -3
  19. package/dist/api/design/create/index.d.ts.map +1 -1
  20. package/dist/api/design/selection/index.d.ts +2 -2
  21. package/dist/api/design/update/index.d.ts +73 -0
  22. package/dist/api/design/update/index.d.ts.map +1 -1
  23. package/dist/api/presentation/aiInspiration.d.ts +13 -13
  24. package/dist/api/presentation/camera.d.ts +265 -0
  25. package/dist/api/presentation/camera.d.ts.map +1 -0
  26. package/dist/api/presentation/index.d.ts +14 -0
  27. package/dist/api/presentation/index.d.ts.map +1 -1
  28. package/dist/api/presentation/placedViews.d.ts +1 -1
  29. package/dist/api/presentation/views.d.ts +3 -1
  30. package/dist/api/presentation/views.d.ts.map +1 -1
  31. package/dist/api/presentation/walkthroughs.d.ts +1350 -0
  32. package/dist/api/presentation/walkthroughs.d.ts.map +1 -0
  33. package/dist/index.cjs +3162 -2553
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.js +3077 -2550
  36. package/dist/index.js.map +1 -1
  37. package/package.json +1 -1
  38. package/scripts/generate-manifest.test.mjs +14 -3
  39. package/src/api/core/camera/index.ts +400 -1
  40. package/src/api/core/index.ts +4 -4
  41. package/src/api/core/layers.ts +380 -173
  42. package/src/api/core/proposals/index.ts +4 -3
  43. package/src/api/core/storeys/index.ts +14 -0
  44. package/src/api/core/storeys/layers.ts +339 -0
  45. package/src/api/design/create/bulk-items.ts +68 -0
  46. package/src/api/design/create/index.ts +30 -4
  47. package/src/api/design/update/index.ts +80 -1
  48. package/src/api/presentation/camera.ts +289 -0
  49. package/src/api/presentation/index.ts +14 -0
  50. package/src/api/presentation/views.ts +3 -1
  51. package/src/api/presentation/walkthroughs.ts +1201 -0
@@ -1,24 +1,33 @@
1
1
  import * as z from "zod"
2
2
  import { PluginApiReturn } from "../../types"
3
+ import { ComponentHandle } from "../../handles"
3
4
 
4
5
  /**
5
- * Layers — read and toggle the drawing/reference layers of a storey.
6
+ * Layers — the layers in the **Layers panel** in the left sidebar (the panel
7
+ * with the "+" add-layer button and one row per layer, such as "Default" or
8
+ * "BIM layer"; the radio mark is the active layer).
6
9
  *
7
- * These are the **drawing/reference** layers shown in the storey's Layers panel —
8
- * the surfaces you sketch on and the imported underlays (CAD, PDF, images,
9
- * terrain). They are **not** wall/floor construction-assembly material layers,
10
- * which are a property of the built element, not this namespace.
10
+ * A layer is a named group of objects. Every object is on exactly one layer, and
11
+ * new objects land on the active layer. Each row can be renamed, locked, hidden
12
+ * and deleted, and objects can be moved between layers.
11
13
  *
12
- * Reads return plain records and never throw for a missing layer (`get` and
13
- * `getActive` return `null`, `list` returns `[]`).
14
+ * These are **not** each storey's sketch surfaces and imported underlays (ids
15
+ * like `ly_5`); those are {@linkcode PluginCoreStoreysLayersApi}
16
+ * (`core.storeys.layers`, formerly `core.layers`). They are also not wall/floor
17
+ * construction-assembly material layers.
14
18
  *
15
- * v1 exposes reads plus visibility edits and the active-layer switch.
16
- * Creating and deleting layers are intentionally not part of this contract yet.
19
+ * Each design option ({@linkcode PluginCoreProposalsApi}) owns a set of layers;
20
+ * `core.proposals` records refer to these ids as `bucketIds` and
21
+ * `defaultBucketId`. `list` and every write are scoped to the **active** design
22
+ * option, like the panel; on legacy projects without design options every layer
23
+ * is in scope. Reads never throw for a missing layer (`get` and `getActive`
24
+ * return `null`).
17
25
  *
18
- * Sub-namespace members typed as optional (`?`) are **authored ahead of the
19
- * host** — declared so plugins and codegen can see the shape, but kept out of the
20
- * discovery manifest until the host lands them (at which point they are promoted
21
- * to required `abstract` members).
26
+ * **Compatibility.** Before 0.9.15 this namespace was the storey sketch-surface
27
+ * API that is now {@linkcode PluginCoreStoreysLayersApi}. Calls in that shape
28
+ * keep working here and are routed to it: `list(storeyId)`, `getActive(storeyId)`,
29
+ * and `get` / `setActive` / `update(layerId, hidden)` with a storey-layer id
30
+ * (`ly_*`). They are deprecated: new code calls `core.storeys.layers` directly.
22
31
  *
23
32
  * Accessed via `snaptrude.core.layers`.
24
33
  */
@@ -26,45 +35,42 @@ export abstract class PluginCoreLayersApi {
26
35
  constructor() {}
27
36
 
28
37
  /**
29
- * List the drawing layers of a storey.
38
+ * List the layers in the Layers panel: the active design option's layers,
39
+ * default layer first, then in creation order.
30
40
  *
31
- * Optionally filter to a single {@linkcode PluginCoreLayerType}.
41
+ * @returns A {@linkcode PluginCoreLayersListResult} with a `layers` array.
32
42
  *
33
- * @param storeyId - The storey whose layers to read.
34
- * @param layerType - Optional {@linkcode PluginCoreLayerType} filter.
35
- * @returns A {@linkcode PluginCoreLayersListResult} with a `layers` array
36
- * (empty when the storey is missing or has no matching layers).
37
- *
38
- * @examplePrompt List the drawing layers on this storey
39
- * @examplePrompt Show all the PDF underlays on storey st_2
40
- * @examplePrompt What CAD layers are on the ground floor?
43
+ * @examplePrompt List all the layers in the Layers panel
44
+ * @examplePrompt Show me the layers in the left sidebar
45
+ * @examplePrompt What layers does this project have?
46
+ * @examplePrompt Show every layer with whether it is locked or hidden
47
+ * @examplePrompt Which layer is the default layer?
48
+ * @examplePrompt Which layers are empty?
41
49
  *
42
50
  * # Example
43
51
  * ```ts
44
- * const { layers } = await snaptrude.core.layers.list("st_2")
45
- * for (const l of layers) console.log(l.name, l.layerType, l.hidden)
52
+ * const { layers } = await snaptrude.core.layers.list()
53
+ * for (const l of layers) console.log(l.name, l.objectCount, l.locked, l.hidden)
46
54
  * ```
47
55
  */
48
- public abstract list(
49
- storeyId: string,
50
- layerType?: PluginCoreLayerType,
51
- ): PluginApiReturn<PluginCoreLayersListResult>
56
+ public abstract list(): PluginApiReturn<PluginCoreLayersListResult>
52
57
 
53
58
  /**
54
- * Get a single drawing layer by id.
59
+ * Get one Layers-panel layer by id, including layers owned by other design
60
+ * options.
55
61
  *
56
62
  * @param layerId - The id of the layer to read.
57
63
  * @returns The matching {@linkcode PluginCoreLayer}, or `null` if no layer has
58
64
  * that id.
59
65
  *
60
- * @examplePrompt Get the drawing layer with id ly_5
61
- * @examplePrompt Is layer ly_5 hidden or locked?
62
- * @examplePrompt Look up a single drawing layer by its id
66
+ * @examplePrompt Get the Layers-panel layer with id 3f2a…
67
+ * @examplePrompt Is the Furniture layer locked or hidden?
68
+ * @examplePrompt How many objects are on layer 3f2a…?
63
69
  *
64
70
  * # Example
65
71
  * ```ts
66
- * const layer = await snaptrude.core.layers.get("ly_5")
67
- * if (layer) console.log(layer.name, layer.hidden, layer.locked)
72
+ * const layer = await snaptrude.core.layers.get(layerId)
73
+ * if (layer) console.log(layer.name, layer.objectCount)
68
74
  * ```
69
75
  */
70
76
  public abstract get(
@@ -72,160 +78,265 @@ export abstract class PluginCoreLayersApi {
72
78
  ): PluginApiReturn<PluginCoreLayersGetResult>
73
79
 
74
80
  /**
75
- * Get the active drawing layer of a storey.
76
- *
77
- * The active layer is the one new sketch geometry is drawn onto. Paired with
78
- * {@linkcode PluginCoreLayersApi.setActive}.
81
+ * Get the active Layers-panel layer: the one new objects land on.
79
82
  *
80
- * @param storeyId - The storey whose active layer to read.
81
- * @returns The active {@linkcode PluginCoreLayer}, or `null` if the storey is
82
- * missing or has no active layer.
83
+ * @returns The active {@linkcode PluginCoreLayer}, or `null` if none is set.
83
84
  *
84
- * @examplePrompt Which drawing layer is active on this storey?
85
- * @examplePrompt Get the current layer on storey st_2
86
- * @examplePrompt What layer am I drawing on?
85
+ * @examplePrompt Which layer is active?
86
+ * @examplePrompt Which layer in the Layers panel is active?
87
+ * @examplePrompt What layer will new objects go on?
88
+ * @examplePrompt Which layer are new walls and masses being added to?
87
89
  *
88
90
  * # Example
89
91
  * ```ts
90
- * const active = await snaptrude.core.layers.getActive("st_2")
92
+ * const active = await snaptrude.core.layers.getActive()
91
93
  * if (active) console.log(active.name)
92
94
  * ```
93
95
  */
94
- public abstract getActive(
95
- storeyId: string,
96
- ): PluginApiReturn<PluginCoreLayersGetActiveResult>
96
+ public abstract getActive(): PluginApiReturn<PluginCoreLayersGetActiveResult>
97
97
 
98
98
  /**
99
- * Make a drawing layer the active layer of its storey.
99
+ * Create a new layer in the Layers panel (the panel's "Add new layer" button
100
+ * followed by naming it).
100
101
  *
101
- * Paired with {@linkcode PluginCoreLayersApi.getActive}.
102
+ * The layer is added to the active design option and is **not** made active;
103
+ * call {@linkcode PluginCoreLayersApi.setActive} to put new objects on it.
104
+ * Names are trimmed, 1-40 characters, and must be unique across all layers
105
+ * (case-insensitive). **Undoable.**
102
106
  *
103
- * @param layerId - The id of the layer to activate.
104
- * @returns The id of the now-active layer.
105
- * @throws If no layer has the given id.
107
+ * @param name - The new layer's name.
108
+ * @returns The created {@linkcode PluginCoreLayer}.
109
+ * @throws `VALIDATION` for an empty name or one longer than 40 characters;
110
+ * `PRECONDITION_FAILED` if a layer with that name already exists.
106
111
  *
107
- * @examplePrompt Draw on layer ly_5
108
- * @examplePrompt Make this the active layer
109
- * @examplePrompt Switch the active layer to the CAD underlay
112
+ * @examplePrompt Create a new layer called Furniture
113
+ * @examplePrompt Add a layer called Landscape
114
+ * @examplePrompt Add a layer named Landscape to the Layers panel
115
+ * @examplePrompt Make a new layer for the facade elements
116
+ * @examplePrompt Create layers named Structure and Services
110
117
  *
111
118
  * # Example
112
119
  * ```ts
113
- * await snaptrude.core.layers.setActive("ly_5")
120
+ * const layer = await snaptrude.core.layers.create("Furniture")
121
+ * await snaptrude.core.layers.setActive(layer.id)
114
122
  * ```
115
123
  */
116
- public abstract setActive(
124
+ public abstract create(
125
+ name: string,
126
+ ): PluginApiReturn<PluginCoreLayersCreateResult>
127
+
128
+ /**
129
+ * Rename a layer (the panel row's "Rename layer").
130
+ *
131
+ * Names are trimmed, 1-40 characters, and must be unique across all layers
132
+ * (case-insensitive; changing only the case of the layer's own name is
133
+ * allowed). The default layer cannot be renamed. **Not undoable.**
134
+ *
135
+ * @param layerId - The id of the layer to rename.
136
+ * @param name - The new name.
137
+ * @returns The updated {@linkcode PluginCoreLayer}.
138
+ * @throws `VALIDATION` for a bad name; `HANDLE_INVALID` for an unknown
139
+ * `layerId`; `PRECONDITION_FAILED` if the layer is the default layer, is
140
+ * outside the active design option, or the name is already used;
141
+ * `OPERATION_FAILED` if the app refuses the rename.
142
+ *
143
+ * @examplePrompt Rename the Furniture layer to Loose furniture
144
+ * @examplePrompt Rename layer 3f2a… to Existing building
145
+ * @examplePrompt Change the name of the Landscape layer
146
+ *
147
+ * # Example
148
+ * ```ts
149
+ * await snaptrude.core.layers.rename(layerId, "Loose furniture")
150
+ * ```
151
+ */
152
+ public abstract rename(
117
153
  layerId: string,
118
- ): PluginApiReturn<PluginCoreLayersSetActiveResult>
154
+ name: string,
155
+ ): PluginApiReturn<PluginCoreLayersRenameResult>
119
156
 
120
157
  /**
121
- * Update a drawing layer's visibility.
158
+ * Lock/unlock or show/hide a layer (the panel row's padlock and eye).
122
159
  *
123
- * A **sparse** update: omit `hidden` to leave it unchanged. This edit is **not
124
- * undoable**. Locking and renaming are not exposed — layer `locked` is a
125
- * read-only status here (setting it at runtime does not lock the live meshes or
126
- * flip the panel padlock until a reload), and a rename cascades to every member
127
- * mesh's `layerName`, a corruption hazard.
160
+ * A **sparse** update: omitted fields are unchanged. `hidden` is **per-user**:
161
+ * it hides the layer for you, not for collaborators. Locking and hiding block
162
+ * interactive drawing in the app; plugin creates are not blocked (see
163
+ * {@linkcode PluginCoreLayersApi.setActive}). **Undoable**, one undo step per
164
+ * changed field.
128
165
  *
129
166
  * @param layerId - The id of the layer to update.
130
- * @param hidden - New hidden state (unchanged if omitted).
167
+ * @param options - `{ locked?, hidden? }`; omitted fields are unchanged.
131
168
  * @returns The updated {@linkcode PluginCoreLayer}.
132
- * @throws If no layer has the given id.
169
+ * @throws `VALIDATION` for any option other than `locked` / `hidden` (to
170
+ * rename, use {@linkcode PluginCoreLayersApi.rename}); `HANDLE_INVALID` for
171
+ * an unknown `layerId`; `PRECONDITION_FAILED` if the layer is outside the
172
+ * active design option, or `hidden` is changed with no signed-in user.
133
173
  *
134
- * @examplePrompt Hide the PDF underlay layer
135
- * @examplePrompt Show the CAD layer again
136
- * @examplePrompt Hide layer ly_5
174
+ * @examplePrompt Lock the Default layer
175
+ * @examplePrompt Lock the Structure layer
176
+ * @examplePrompt Hide the Landscape layer in the Layers panel
177
+ * @examplePrompt Unlock layer 3f2a… and show it again
137
178
  *
138
179
  * # Example
139
180
  * ```ts
140
- * const layer = await snaptrude.core.layers.update("ly_5", true)
181
+ * await snaptrude.core.layers.update(layerId, { locked: true, hidden: false })
141
182
  * ```
142
183
  */
143
184
  public abstract update(
144
185
  layerId: string,
145
- hidden?: boolean,
186
+ options?: { locked?: boolean; hidden?: boolean },
146
187
  ): PluginApiReturn<PluginCoreLayersUpdateResult>
147
- }
148
188
 
149
- /**
150
- * The kind of a drawing layer.
151
- *
152
- * Author-drawable kinds (`floor`, `wall`, `ceiling`, `rough`, `default`) plus
153
- * read-only imported underlays (`image`, `cad`, `pdf`, `terrain`, `buildings`).
154
- */
155
- export const PluginCoreLayerType = z.enum([
156
- "floor",
157
- "wall",
158
- "ceiling",
159
- "rough",
160
- "default",
161
- "image",
162
- "cad",
163
- "pdf",
164
- "terrain",
165
- "buildings",
166
- ])
167
- export type PluginCoreLayerType = z.infer<typeof PluginCoreLayerType>
189
+ /**
190
+ * Make a layer the active layer (clicking its row in the Layers panel).
191
+ *
192
+ * New objects, whether drawn in the app or created by plugins with
193
+ * `design.create.*`, land on the active layer. When the active layer is locked
194
+ * or hidden the app blocks interactive drawing, but plugin creates still land
195
+ * on it: objects created on a hidden layer are invisible, and objects on a
196
+ * locked layer cannot be edited. Unlock or show the layer first
197
+ * ({@linkcode PluginCoreLayersApi.update}). **Not undoable.**
198
+ *
199
+ * @param layerId - The id of the layer to activate.
200
+ * @returns The id of the now-active layer.
201
+ * @throws `HANDLE_INVALID` for an unknown `layerId`; `PRECONDITION_FAILED` if
202
+ * the layer is outside the active design option.
203
+ *
204
+ * @examplePrompt Put new objects on the Furniture layer
205
+ * @examplePrompt Make the Structure layer the active layer in the Layers panel
206
+ * @examplePrompt Switch the active layer to Landscape
207
+ *
208
+ * # Example
209
+ * ```ts
210
+ * await snaptrude.core.layers.setActive(layerId)
211
+ * ```
212
+ */
213
+ public abstract setActive(
214
+ layerId: string,
215
+ ): PluginApiReturn<PluginCoreLayersSetActiveResult>
216
+
217
+ /**
218
+ * Delete a layer (the panel row's "Delete layer").
219
+ *
220
+ * Choose **exactly one** disposition, mirroring the delete dialog:
221
+ *
222
+ * - `{ deleteObjects: true }` destroys the objects on the layer.
223
+ * - `{ targetLayerId }` moves them to another layer of the active design
224
+ * option first, then deletes the emptied layer.
225
+ *
226
+ * A bare `delete(layerId)` is **rejected**: the engine would drop the layer
227
+ * and leave its objects on a missing layer. Refused for the default layer, the
228
+ * last layer, a locked layer, a layer shared with other design options
229
+ * (`proposalIds.length > 1`; unshare it in the app first), and, with
230
+ * `deleteObjects`, when any object on it is locked. The server checks that no
231
+ * collaborator is using the layer (needs a live connection; times out after
232
+ * ~10 s). If the layer was active, the active design option's default layer
233
+ * becomes active.
234
+ *
235
+ * **Treat as permanent.** `core.history.undo` restores the layer in this
236
+ * session only; the server does not re-link it to its design option, so after
237
+ * a reload it is missing from the panel.
238
+ *
239
+ * @param layerId - The id of the layer to delete.
240
+ * @param options - Exactly one disposition: `{ deleteObjects: true }` or
241
+ * `{ targetLayerId }`.
242
+ * @returns Confirmation that the layer was deleted.
243
+ * @throws `VALIDATION` for no disposition, both, or `targetLayerId` equal to
244
+ * `layerId`; `HANDLE_INVALID` for an unknown `layerId` or
245
+ * `targetLayerId`; `PRECONDITION_FAILED` for the refusals above or a layer
246
+ * or target outside the active design option; `OPERATION_FAILED` if the
247
+ * server refuses (a collaborator is using it), the connection is down, or
248
+ * the check times out.
249
+ *
250
+ * @examplePrompt Delete the Furniture layer and everything on it
251
+ * @examplePrompt Delete the Furniture layer and move its objects to Default
252
+ * @examplePrompt Remove layer 3f2a… and move its objects to the default layer
253
+ * @examplePrompt Merge the Services layer into Structure and delete it
254
+ * @examplePrompt Delete every empty layer
255
+ *
256
+ * # Example
257
+ * ```ts
258
+ * await snaptrude.core.layers.delete(layerId, { deleteObjects: true })
259
+ * const { layers } = await snaptrude.core.layers.list()
260
+ * const def = layers.find((l) => l.isDefault)!
261
+ * await snaptrude.core.layers.delete(otherId, { targetLayerId: def.id })
262
+ * ```
263
+ */
264
+ public abstract delete(
265
+ layerId: string,
266
+ options:
267
+ | { deleteObjects: true; targetLayerId?: never }
268
+ | { deleteObjects?: false; targetLayerId: string },
269
+ ): PluginApiReturn<PluginCoreLayersDeleteResult>
270
+
271
+ /**
272
+ * Move objects onto a layer (picking a layer in the object properties panel).
273
+ *
274
+ * Doors, windows and voids hosted by a moved wall (and a terrain's
275
+ * neighbourhood buildings) move with it; if any of those is locked, the parent
276
+ * is skipped as `locked`. Locked objects, unknown ids and objects outside the
277
+ * active design option are returned in `skipped`, never silently dropped. The target layer's own lock
278
+ * does not block the move. An object is always on exactly one layer, so there
279
+ * is no `unassign`: assign to another layer instead. **Undoable** (one step).
280
+ *
281
+ * @param componentIds - The objects to move.
282
+ * @param layerId - The target layer.
283
+ * @returns A {@linkcode PluginCoreLayersAssignResult} splitting `assigned`
284
+ * from `skipped`.
285
+ * @throws `VALIDATION` for an empty `componentIds`; `HANDLE_INVALID` for an
286
+ * unknown `layerId`; `PRECONDITION_FAILED` if the target is outside the
287
+ * active design option.
288
+ *
289
+ * @examplePrompt Move the selected objects to the BIM layer
290
+ * @examplePrompt Move the selected objects to the Furniture layer
291
+ * @examplePrompt Assign the generated walls to the Structure layer
292
+ * @examplePrompt Put these masses on layer 3f2a…
293
+ *
294
+ * # Example
295
+ * ```ts
296
+ * const { assigned, skipped } = await snaptrude.core.layers.assign(ids, layerId)
297
+ * ```
298
+ */
299
+ public abstract assign(
300
+ componentIds: ComponentHandle[],
301
+ layerId: string,
302
+ ): PluginApiReturn<PluginCoreLayersAssignResult>
303
+ }
168
304
 
169
305
  /**
170
- * A drawing/reference layer on a storey.
171
- *
172
- * | Property | Type | Description |
173
- * |---|---|---|
174
- * | `id` | `string` | Stable public layer id (e.g. `"ly_5"`) |
175
- * | `name` | `string` | Display name |
176
- * | `layerType` | {@linkcode PluginCoreLayerType} | The layer's kind |
177
- * | `storeyId` | `string` | The stable id of the storey this layer belongs to |
178
- * | `buildingId` | `string` | The stable id of the building this layer belongs to |
179
- * | `hidden` | `boolean` | Whether the layer is hidden |
180
- * | `locked` | `boolean` | Whether the layer is locked against edits |
181
- * | `contentSummary` | `object` | A summary of what the layer holds (see below) |
182
- *
183
- * `contentSummary`:
306
+ * A layer in the Layers panel.
184
307
  *
185
308
  * | Property | Type | Description |
186
309
  * |---|---|---|
187
- * | `hasFloorplan` | `boolean` | Whether the layer holds drawn floorplan geometry |
188
- * | `pdfCount` | `number` | Number of PDF underlays on the layer |
189
- * | `hasTerrain` | `boolean` | Whether the layer holds terrain |
310
+ * | `id` | `string` | Layer id (the ids `core.proposals` records list) |
311
+ * | `name` | `string` | Display name (1-40 characters, unique case-insensitively) |
312
+ * | `isDefault` | `boolean` | The design option's default layer: cannot be renamed or deleted |
313
+ * | `isActive` | `boolean` | Whether new objects land on this layer |
314
+ * | `locked` | `boolean` | Whether the layer is locked (its objects cannot be edited) |
315
+ * | `hidden` | `boolean` | Whether the layer is hidden **for the current user** |
316
+ * | `proposalIds` | `string[]` | Design options that own the layer (more than one = shared) |
317
+ * | `objectCount` | `number` | Objects currently on the layer (0 = empty) |
190
318
  */
191
319
  export const PluginCoreLayer = z.object({
192
320
  id: z.string(),
193
321
  name: z.string(),
194
- layerType: PluginCoreLayerType,
195
- storeyId: z.string(),
196
- buildingId: z.string(),
197
- hidden: z.boolean(),
322
+ isDefault: z.boolean(),
323
+ isActive: z.boolean(),
198
324
  locked: z.boolean(),
199
- contentSummary: z.object({
200
- hasFloorplan: z.boolean(),
201
- pdfCount: z.number().int(),
202
- hasTerrain: z.boolean(),
203
- }),
325
+ hidden: z.boolean(),
326
+ proposalIds: z.array(z.string()),
327
+ objectCount: z.number().int(),
204
328
  })
205
329
  export type PluginCoreLayer = z.infer<typeof PluginCoreLayer>
206
330
 
207
- /**
208
- * Arguments for {@linkcode PluginCoreLayersApi.list}.
209
- *
210
- * | Property | Type | Description |
211
- * |---|---|---|
212
- * | `storeyId` | `string` | The storey whose layers to read |
213
- * | `layerType` | {@linkcode PluginCoreLayerType}` \| undefined` | Optional layer-type filter |
214
- */
215
- export const PluginCoreLayersListArgs = z.object({
216
- storeyId: z.string(),
217
- layerType: PluginCoreLayerType.optional(),
218
- })
219
- export type PluginCoreLayersListArgs = z.infer<
220
- typeof PluginCoreLayersListArgs
221
- >
331
+ /** A layer name: trimmed, 1-40 characters (the panel input's limit). */
332
+ export const PluginCoreLayerName = z.string().trim().min(1).max(40)
222
333
 
223
334
  /**
224
335
  * Result of {@linkcode PluginCoreLayersApi.list}.
225
336
  *
226
337
  * | Property | Type | Description |
227
338
  * |---|---|---|
228
- * | `layers` | {@linkcode PluginCoreLayer}`[]` | The storey's drawing layers (empty when missing or none match) |
339
+ * | `layers` | {@linkcode PluginCoreLayer}`[]` | The active design option's layers, default first |
229
340
  */
230
341
  export const PluginCoreLayersListResult = z.object({
231
342
  layers: z.array(PluginCoreLayer),
@@ -241,43 +352,86 @@ export type PluginCoreLayersListResult = z.infer<
241
352
  * |---|---|---|
242
353
  * | `layerId` | `string` | The id of the layer to read |
243
354
  */
244
- export const PluginCoreLayersGetArgs = z.object({
245
- layerId: z.string(),
246
- })
247
- export type PluginCoreLayersGetArgs = z.infer<
248
- typeof PluginCoreLayersGetArgs
249
- >
355
+ export const PluginCoreLayersGetArgs = z.object({ layerId: z.string() })
356
+ export type PluginCoreLayersGetArgs = z.infer<typeof PluginCoreLayersGetArgs>
250
357
 
251
- /**
252
- * Result of {@linkcode PluginCoreLayersApi.get} — the layer, or `null`
253
- * when no layer has the given id.
254
- */
358
+ /** Result of {@linkcode PluginCoreLayersApi.get}: the layer, or `null`. */
255
359
  export const PluginCoreLayersGetResult = PluginCoreLayer.nullable()
256
360
  export type PluginCoreLayersGetResult = z.infer<
257
361
  typeof PluginCoreLayersGetResult
258
362
  >
259
363
 
364
+ /** Result of {@linkcode PluginCoreLayersApi.getActive}: the active layer, or `null`. */
365
+ export const PluginCoreLayersGetActiveResult = PluginCoreLayer.nullable()
366
+ export type PluginCoreLayersGetActiveResult = z.infer<
367
+ typeof PluginCoreLayersGetActiveResult
368
+ >
369
+
260
370
  /**
261
- * Arguments for {@linkcode PluginCoreLayersApi.getActive}.
371
+ * Arguments for {@linkcode PluginCoreLayersApi.create}.
262
372
  *
263
373
  * | Property | Type | Description |
264
374
  * |---|---|---|
265
- * | `storeyId` | `string` | The storey whose active layer to read |
375
+ * | `name` | `string` | The new layer's name (trimmed, 1-40 characters) |
266
376
  */
267
- export const PluginCoreLayersGetActiveArgs = z.object({
268
- storeyId: z.string(),
377
+ export const PluginCoreLayersCreateArgs = z.object({
378
+ name: PluginCoreLayerName,
269
379
  })
270
- export type PluginCoreLayersGetActiveArgs = z.infer<
271
- typeof PluginCoreLayersGetActiveArgs
380
+ export type PluginCoreLayersCreateArgs = z.infer<
381
+ typeof PluginCoreLayersCreateArgs
382
+ >
383
+
384
+ /** Result of {@linkcode PluginCoreLayersApi.create}: the created layer. */
385
+ export const PluginCoreLayersCreateResult = PluginCoreLayer
386
+ export type PluginCoreLayersCreateResult = z.infer<
387
+ typeof PluginCoreLayersCreateResult
272
388
  >
273
389
 
274
390
  /**
275
- * Result of {@linkcode PluginCoreLayersApi.getActive} — the active layer,
276
- * or `null` when the storey is missing or has no active layer.
391
+ * Arguments for {@linkcode PluginCoreLayersApi.rename}.
392
+ *
393
+ * | Property | Type | Description |
394
+ * |---|---|---|
395
+ * | `layerId` | `string` | The id of the layer to rename |
396
+ * | `name` | `string` | The new name (trimmed, 1-40 characters) |
277
397
  */
278
- export const PluginCoreLayersGetActiveResult = PluginCoreLayer.nullable()
279
- export type PluginCoreLayersGetActiveResult = z.infer<
280
- typeof PluginCoreLayersGetActiveResult
398
+ export const PluginCoreLayersRenameArgs = z.object({
399
+ layerId: z.string(),
400
+ name: PluginCoreLayerName,
401
+ })
402
+ export type PluginCoreLayersRenameArgs = z.infer<
403
+ typeof PluginCoreLayersRenameArgs
404
+ >
405
+
406
+ /** Result of {@linkcode PluginCoreLayersApi.rename}: the updated layer. */
407
+ export const PluginCoreLayersRenameResult = PluginCoreLayer
408
+ export type PluginCoreLayersRenameResult = z.infer<
409
+ typeof PluginCoreLayersRenameResult
410
+ >
411
+
412
+ /**
413
+ * Arguments for {@linkcode PluginCoreLayersApi.update}. Sparse: only the
414
+ * provided fields are changed.
415
+ *
416
+ * | Property | Type | Description |
417
+ * |---|---|---|
418
+ * | `layerId` | `string` | The id of the layer to update |
419
+ * | `locked` | `boolean \| undefined` | New locked state (unchanged if omitted) |
420
+ * | `hidden` | `boolean \| undefined` | New hidden state for the current user (unchanged if omitted) |
421
+ */
422
+ export const PluginCoreLayersUpdateArgs = z.object({
423
+ layerId: z.string(),
424
+ locked: z.boolean().optional(),
425
+ hidden: z.boolean().optional(),
426
+ }).strict()
427
+ export type PluginCoreLayersUpdateArgs = z.infer<
428
+ typeof PluginCoreLayersUpdateArgs
429
+ >
430
+
431
+ /** Result of {@linkcode PluginCoreLayersApi.update}: the updated layer. */
432
+ export const PluginCoreLayersUpdateResult = PluginCoreLayer
433
+ export type PluginCoreLayersUpdateResult = z.infer<
434
+ typeof PluginCoreLayersUpdateResult
281
435
  >
282
436
 
283
437
  /**
@@ -287,16 +441,13 @@ export type PluginCoreLayersGetActiveResult = z.infer<
287
441
  * |---|---|---|
288
442
  * | `layerId` | `string` | The id of the layer to activate |
289
443
  */
290
- export const PluginCoreLayersSetActiveArgs = z.object({
291
- layerId: z.string(),
292
- })
444
+ export const PluginCoreLayersSetActiveArgs = z.object({ layerId: z.string() })
293
445
  export type PluginCoreLayersSetActiveArgs = z.infer<
294
446
  typeof PluginCoreLayersSetActiveArgs
295
447
  >
296
448
 
297
449
  /**
298
- * Result of {@linkcode PluginCoreLayersApi.setActive} — the now-active
299
- * layer's id.
450
+ * Result of {@linkcode PluginCoreLayersApi.setActive}.
300
451
  *
301
452
  * | Property | Type | Description |
302
453
  * |---|---|---|
@@ -310,24 +461,80 @@ export type PluginCoreLayersSetActiveResult = z.infer<
310
461
  >
311
462
 
312
463
  /**
313
- * Arguments for {@linkcode PluginCoreLayersApi.update}. Sparse — only the
314
- * provided fields are changed.
464
+ * Arguments for {@linkcode PluginCoreLayersApi.delete}. Exactly one
465
+ * disposition is required: `deleteObjects: true` XOR `targetLayerId` (a
466
+ * **different** layer).
315
467
  *
316
468
  * | Property | Type | Description |
317
469
  * |---|---|---|
318
- * | `layerId` | `string` | The id of the layer to update |
319
- * | `hidden` | `boolean \| undefined` | New hidden state (unchanged if omitted) |
470
+ * | `layerId` | `string` | The id of the layer to delete |
471
+ * | `deleteObjects` | `boolean \| undefined` | `true` destroys the layer's objects (exclusive with `targetLayerId`) |
472
+ * | `targetLayerId` | `string \| undefined` | Move the layer's objects to this layer, then delete (exclusive with `deleteObjects`) |
320
473
  */
321
- export const PluginCoreLayersUpdateArgs = z.object({
474
+ export const PluginCoreLayersDeleteArgs = z
475
+ .object({
476
+ layerId: z.string(),
477
+ deleteObjects: z.boolean().optional(),
478
+ targetLayerId: z.string().optional(),
479
+ })
480
+ .refine((v) => (v.deleteObjects === true) !== (v.targetLayerId != null), {
481
+ message:
482
+ "Provide exactly one disposition: deleteObjects: true (destroy the layer's objects) or targetLayerId (move them to that layer, then delete)",
483
+ })
484
+ .refine((v) => v.targetLayerId == null || v.targetLayerId !== v.layerId, {
485
+ message: "targetLayerId must be a different layer than layerId",
486
+ })
487
+ export type PluginCoreLayersDeleteArgs = z.infer<
488
+ typeof PluginCoreLayersDeleteArgs
489
+ >
490
+
491
+ /**
492
+ * Result of {@linkcode PluginCoreLayersApi.delete}.
493
+ *
494
+ * | Property | Type | Description |
495
+ * |---|---|---|
496
+ * | `deleted` | `true` | The layer was deleted |
497
+ */
498
+ export const PluginCoreLayersDeleteResult = z.object({
499
+ deleted: z.literal(true),
500
+ })
501
+ export type PluginCoreLayersDeleteResult = z.infer<
502
+ typeof PluginCoreLayersDeleteResult
503
+ >
504
+
505
+ /**
506
+ * Arguments for {@linkcode PluginCoreLayersApi.assign}.
507
+ *
508
+ * | Property | Type | Description |
509
+ * |---|---|---|
510
+ * | `componentIds` | `string[]` | The objects to move (at least one) |
511
+ * | `layerId` | `string` | The target layer |
512
+ */
513
+ export const PluginCoreLayersAssignArgs = z.object({
514
+ componentIds: z.array(ComponentHandle).min(1),
322
515
  layerId: z.string(),
323
- hidden: z.boolean().optional(),
324
516
  })
325
- export type PluginCoreLayersUpdateArgs = z.infer<
326
- typeof PluginCoreLayersUpdateArgs
517
+ export type PluginCoreLayersAssignArgs = z.infer<
518
+ typeof PluginCoreLayersAssignArgs
327
519
  >
328
520
 
329
- /** Result of {@linkcode PluginCoreLayersApi.update} — the updated layer. */
330
- export const PluginCoreLayersUpdateResult = PluginCoreLayer
331
- export type PluginCoreLayersUpdateResult = z.infer<
332
- typeof PluginCoreLayersUpdateResult
521
+ /**
522
+ * Result of {@linkcode PluginCoreLayersApi.assign}.
523
+ *
524
+ * | Property | Type | Description |
525
+ * |---|---|---|
526
+ * | `assigned` | `string[]` | Ids of the objects that were moved |
527
+ * | `skipped` | `{ id: string; reason: "not-found" \| "locked" \| "outside-proposal" }[]` | Objects that were not moved, each with a reason |
528
+ */
529
+ export const PluginCoreLayersAssignResult = z.object({
530
+ assigned: z.array(ComponentHandle),
531
+ skipped: z.array(
532
+ z.object({
533
+ id: ComponentHandle,
534
+ reason: z.enum(["not-found", "locked", "outside-proposal"]),
535
+ }),
536
+ ),
537
+ })
538
+ export type PluginCoreLayersAssignResult = z.infer<
539
+ typeof PluginCoreLayersAssignResult
333
540
  >