@snaptrude/plugin-core 0.7.1 → 0.8.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/CHANGELOG.md +14 -0
- package/api-manifest.full.json +6442 -0
- package/api-manifest.json +2029 -128
- package/dist/api/core/camera/index.d.ts +208 -0
- package/dist/api/core/camera/index.d.ts.map +1 -0
- package/dist/api/core/comment/index.d.ts +105 -2
- package/dist/api/core/comment/index.d.ts.map +1 -1
- package/dist/api/core/geom/create/index.d.ts +13 -13
- package/dist/api/core/geom/delete/index.d.ts +8 -2
- package/dist/api/core/geom/delete/index.d.ts.map +1 -1
- package/dist/api/core/geom/query/arc.d.ts +5 -5
- package/dist/api/core/geom/query/brep.d.ts +18 -18
- package/dist/api/core/geom/query/circle.d.ts +18 -18
- package/dist/api/core/geom/query/contour.d.ts +20 -20
- package/dist/api/core/geom/query/curve.d.ts +49 -49
- package/dist/api/core/geom/query/edge.d.ts +5 -5
- package/dist/api/core/geom/query/face.d.ts +16 -16
- package/dist/api/core/geom/query/halfedge.d.ts +8 -8
- package/dist/api/core/geom/query/profile.d.ts +19 -19
- package/dist/api/core/geom/query/vertex.d.ts +8 -8
- package/dist/api/core/geom/update/contour.d.ts +14 -14
- package/dist/api/core/geom/update/curve.d.ts +7 -7
- package/dist/api/core/geom/update/profile.d.ts +16 -16
- package/dist/api/core/handles/index.d.ts +210 -0
- package/dist/api/core/handles/index.d.ts.map +1 -0
- package/dist/api/core/index.d.ts +15 -0
- package/dist/api/core/index.d.ts.map +1 -1
- package/dist/api/core/io/export/index.d.ts +132 -0
- package/dist/api/core/io/export/index.d.ts.map +1 -0
- package/dist/api/core/io/import/index.d.ts +1 -1
- package/dist/api/core/io/index.d.ts +5 -0
- package/dist/api/core/io/index.d.ts.map +1 -1
- package/dist/api/core/layers.d.ts +7 -7
- package/dist/api/core/proposals/index.d.ts +65 -9
- package/dist/api/core/proposals/index.d.ts.map +1 -1
- package/dist/api/core/user.d.ts +44 -0
- package/dist/api/core/user.d.ts.map +1 -0
- package/dist/api/design/boolean/index.d.ts +4 -4
- package/dist/api/design/create/index.d.ts +139 -44
- package/dist/api/design/create/index.d.ts.map +1 -1
- package/dist/api/design/doors/index.d.ts +36 -0
- package/dist/api/design/doors/index.d.ts.map +1 -1
- package/dist/api/design/edit/index.d.ts +1 -1
- package/dist/api/design/erase/index.d.ts +2 -2
- package/dist/api/design/furniture/index.d.ts +114 -3
- package/dist/api/design/furniture/index.d.ts.map +1 -1
- package/dist/api/design/index.d.ts +10 -0
- package/dist/api/design/index.d.ts.map +1 -1
- package/dist/api/design/materials/index.d.ts +111 -14
- package/dist/api/design/materials/index.d.ts.map +1 -1
- package/dist/api/design/query/index.d.ts +31 -1
- package/dist/api/design/query/index.d.ts.map +1 -1
- package/dist/api/design/query/spaces.d.ts +5 -5
- package/dist/api/design/transform/index.d.ts +83 -14
- package/dist/api/design/transform/index.d.ts.map +1 -1
- package/dist/api/design/types/index.d.ts +181 -0
- package/dist/api/design/types/index.d.ts.map +1 -0
- package/dist/api/design/update/index.d.ts +335 -2
- package/dist/api/design/update/index.d.ts.map +1 -1
- package/dist/api/design/visibility.d.ts +98 -0
- package/dist/api/design/visibility.d.ts.map +1 -0
- package/dist/api/entity/referenceLine.d.ts +2 -2
- package/dist/api/entity/space.d.ts +19 -19
- package/dist/api/entity/story.d.ts +128 -15
- package/dist/api/entity/story.d.ts.map +1 -1
- package/dist/api/presentation/annotate.d.ts +448 -0
- package/dist/api/presentation/annotate.d.ts.map +1 -0
- package/dist/api/presentation/diagrams.d.ts +49 -8
- package/dist/api/presentation/diagrams.d.ts.map +1 -1
- package/dist/api/presentation/export.d.ts +104 -0
- package/dist/api/presentation/export.d.ts.map +1 -0
- package/dist/api/presentation/index.d.ts +38 -0
- package/dist/api/presentation/index.d.ts.map +1 -1
- package/dist/api/presentation/sheets.d.ts +410 -13
- package/dist/api/presentation/sheets.d.ts.map +1 -1
- package/dist/api/presentation/views.d.ts +165 -10
- package/dist/api/presentation/views.d.ts.map +1 -1
- package/dist/api/program/areas.d.ts +63 -3
- package/dist/api/program/areas.d.ts.map +1 -1
- package/dist/api/program/cores.d.ts +3 -99
- package/dist/api/program/cores.d.ts.map +1 -1
- package/dist/api/program/index.d.ts +2 -2
- package/dist/api/program/index.d.ts.map +1 -1
- package/dist/api/program/layout.d.ts +172 -12
- package/dist/api/program/layout.d.ts.map +1 -1
- package/dist/api/program/site.d.ts +11 -8
- package/dist/api/program/site.d.ts.map +1 -1
- package/dist/api/program/spreadsheet.d.ts +105 -13
- package/dist/api/program/spreadsheet.d.ts.map +1 -1
- package/dist/handles.d.ts +64 -25
- package/dist/handles.d.ts.map +1 -1
- package/dist/index.cjs +2316 -1644
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2224 -1639
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/api/core/camera/index.ts +212 -0
- package/src/api/core/comment/index.ts +120 -2
- package/src/api/core/geom/delete/index.ts +6 -0
- package/src/api/core/handles/index.ts +233 -0
- package/src/api/core/index.ts +15 -0
- package/src/api/core/io/export/index.ts +124 -0
- package/src/api/core/io/index.ts +5 -0
- package/src/api/core/proposals/index.ts +71 -11
- package/src/api/core/user.ts +46 -0
- package/src/api/design/create/index.ts +166 -36
- package/src/api/design/doors/index.ts +40 -0
- package/src/api/design/furniture/index.ts +127 -3
- package/src/api/design/index.ts +10 -0
- package/src/api/design/materials/index.ts +157 -30
- package/src/api/design/query/index.ts +33 -7
- package/src/api/design/transform/index.ts +89 -12
- package/src/api/design/types/index.ts +156 -0
- package/src/api/design/update/index.ts +402 -6
- package/src/api/design/visibility.ts +109 -0
- package/src/api/entity/story.ts +141 -15
- package/src/api/presentation/annotate.ts +360 -0
- package/src/api/presentation/diagrams.ts +53 -8
- package/src/api/presentation/export.ts +104 -0
- package/src/api/presentation/index.ts +46 -0
- package/src/api/presentation/sheets.ts +346 -13
- package/src/api/presentation/views.ts +164 -12
- package/src/api/program/areas.ts +57 -6
- package/src/api/program/cores.ts +3 -91
- package/src/api/program/index.ts +2 -2
- package/src/api/program/layout.ts +182 -12
- package/src/api/program/site.ts +11 -8
- package/src/api/program/spreadsheet.ts +125 -29
- package/src/handles.ts +77 -13
- package/tsconfig.json +7 -2
package/package.json
CHANGED
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import * as z from "zod"
|
|
2
|
+
import { PluginApiReturn } from "../../../types"
|
|
3
|
+
import { Vec3Handle } from "../../../handles"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Camera controls.
|
|
7
|
+
*
|
|
8
|
+
* Position the viewport camera, snap it to a standard orthographic/isometric
|
|
9
|
+
* view, and toggle between the 2D (plan) and 3D modelling modes — mirrors the
|
|
10
|
+
* canvas view menu and the 2D/3D toggle. Like {@linkcode PluginZoomApi}, these
|
|
11
|
+
* are transient VIEW-STATE changes: they are not model edits, so they are not
|
|
12
|
+
* write-gated and are not undoable. Accessed via `snaptrude.core.camera`.
|
|
13
|
+
*/
|
|
14
|
+
export abstract class PluginCameraApi {
|
|
15
|
+
constructor() {}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Point the camera: place its eye at `eye` looking toward `target` (world
|
|
19
|
+
* coordinates, internal `babylon` units). View-state only — not undoable.
|
|
20
|
+
*
|
|
21
|
+
* @param eye - Camera position as a {@linkcode Vec3Handle}
|
|
22
|
+
* @param target - Point the camera looks at as a {@linkcode Vec3Handle}
|
|
23
|
+
* @returns `true` once the camera has been positioned.
|
|
24
|
+
*
|
|
25
|
+
* @examplePrompt Look at the model from above the north-east corner
|
|
26
|
+
* @examplePrompt Position the camera at (50, 30, 50) looking at the origin
|
|
27
|
+
* @examplePrompt Point the camera at the centre of the building from the side
|
|
28
|
+
* @examplePrompt Set the eye to this point and aim it at that point
|
|
29
|
+
*
|
|
30
|
+
* # Example
|
|
31
|
+
* ```ts
|
|
32
|
+
* const { vec3 } = snaptrude.core.math
|
|
33
|
+
* await snaptrude.core.camera.lookFrom(vec3.new(50, 30, 50), vec3.new(0, 0, 0))
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
public abstract lookFrom(
|
|
37
|
+
eye: Vec3Handle,
|
|
38
|
+
target: Vec3Handle,
|
|
39
|
+
): PluginApiReturn<boolean>
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Snap the camera to a standard view — the five orthographic elevations
|
|
43
|
+
* (`top` / `front` / `back` / `left` / `right`) or the 3D `iso` (isometric
|
|
44
|
+
* perspective) view. Mirrors the canvas view menu. View-state only — not
|
|
45
|
+
* undoable. The orthographic presets exit 2D mode first if needed.
|
|
46
|
+
*
|
|
47
|
+
* @param view - The standard view to snap to ({@linkcode PluginStandardView})
|
|
48
|
+
* @returns `true` once the view has been applied.
|
|
49
|
+
*
|
|
50
|
+
* @examplePrompt Switch to the top view
|
|
51
|
+
* @examplePrompt Show me the front elevation
|
|
52
|
+
* @examplePrompt Go to the isometric view
|
|
53
|
+
* @examplePrompt Look at the model from the left
|
|
54
|
+
* @examplePrompt Give me a plan view from the top
|
|
55
|
+
*
|
|
56
|
+
* # Example
|
|
57
|
+
* ```ts
|
|
58
|
+
* await snaptrude.core.camera.setStandardView("top")
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
public abstract setStandardView(
|
|
62
|
+
view: PluginStandardView,
|
|
63
|
+
): PluginApiReturn<boolean>
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Toggle the modelling mode between `2d` (plan) and `3d`. Mirrors the canvas
|
|
67
|
+
* 2D/3D toggle: `3d` enters the isometric perspective view, `2d` drops to the
|
|
68
|
+
* orthographic plan of the active storey. View-state only — not undoable.
|
|
69
|
+
*
|
|
70
|
+
* @param mode - `"2d"` or `"3d"` ({@linkcode PluginCameraMode})
|
|
71
|
+
* @returns `true` once the mode switch has been requested.
|
|
72
|
+
*
|
|
73
|
+
* @examplePrompt Switch to 3D view
|
|
74
|
+
* @examplePrompt Drop into 2D plan mode
|
|
75
|
+
* @examplePrompt Go back to 3D
|
|
76
|
+
* @examplePrompt Show the floor plan in 2D
|
|
77
|
+
*
|
|
78
|
+
* # Example
|
|
79
|
+
* ```ts
|
|
80
|
+
* await snaptrude.core.camera.setMode("3d")
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
public abstract setMode(mode: PluginCameraMode): PluginApiReturn<boolean>
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Read the camera's current projection: `"perspective"` (the default 3D
|
|
87
|
+
* view) or `"orthographic"`. In 2D (plan) mode this always reports
|
|
88
|
+
* `"orthographic"` — a plan is an orthographic projection.
|
|
89
|
+
*
|
|
90
|
+
* @returns The current {@linkcode PluginCameraProjection}.
|
|
91
|
+
*
|
|
92
|
+
* @examplePrompt Is the camera in perspective or orthographic?
|
|
93
|
+
* @examplePrompt What projection is the 3D view using?
|
|
94
|
+
* @examplePrompt Check whether perspective is on
|
|
95
|
+
*
|
|
96
|
+
* # Example
|
|
97
|
+
* ```ts
|
|
98
|
+
* const projection = await snaptrude.core.camera.getProjection()
|
|
99
|
+
* console.log(projection) // "perspective" | "orthographic"
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
public abstract getProjection(): PluginApiReturn<PluginCameraProjection>
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Switch the 3D camera between `"perspective"` and `"orthographic"`
|
|
106
|
+
* projection — the Perspective/Orthographic control in the Design tab's
|
|
107
|
+
* View Settings panel. Like {@linkcode PluginCameraApi.setMode}, this is a
|
|
108
|
+
* transient view-state change: not write-gated, not undoable.
|
|
109
|
+
*
|
|
110
|
+
* In 2D (plan) mode the canvas is always an orthographic plan:
|
|
111
|
+
* `"orthographic"` is accepted as a no-op, while `"perspective"` is
|
|
112
|
+
* rejected — switch to 3D first via `setMode("3d")`.
|
|
113
|
+
*
|
|
114
|
+
* @param projection - `"perspective"` or `"orthographic"` ({@linkcode PluginCameraProjection})
|
|
115
|
+
* @returns `true` once the projection has been applied.
|
|
116
|
+
*
|
|
117
|
+
* @examplePrompt Switch the camera to orthographic
|
|
118
|
+
* @examplePrompt Turn perspective off
|
|
119
|
+
* @examplePrompt Give me a perspective view of the model
|
|
120
|
+
* @examplePrompt Make the 3D view orthographic like an axonometric drawing
|
|
121
|
+
*
|
|
122
|
+
* # Example
|
|
123
|
+
* ```ts
|
|
124
|
+
* await snaptrude.core.camera.setProjection("orthographic")
|
|
125
|
+
* const projection = await snaptrude.core.camera.getProjection() // "orthographic"
|
|
126
|
+
* ```
|
|
127
|
+
*/
|
|
128
|
+
public abstract setProjection(
|
|
129
|
+
projection: PluginCameraProjection,
|
|
130
|
+
): PluginApiReturn<boolean>
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* A standard camera view: the five orthographic elevations (`top`/`front`/
|
|
135
|
+
* `back`/`left`/`right`) or the 3D isometric perspective (`iso`).
|
|
136
|
+
*/
|
|
137
|
+
export const PluginStandardView = z.enum([
|
|
138
|
+
"top",
|
|
139
|
+
"front",
|
|
140
|
+
"back",
|
|
141
|
+
"left",
|
|
142
|
+
"right",
|
|
143
|
+
"iso",
|
|
144
|
+
])
|
|
145
|
+
export type PluginStandardView = z.infer<typeof PluginStandardView>
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* The modelling mode: `2d` (orthographic plan) or `3d` (isometric perspective).
|
|
149
|
+
*/
|
|
150
|
+
export const PluginCameraMode = z.enum(["2d", "3d"])
|
|
151
|
+
export type PluginCameraMode = z.infer<typeof PluginCameraMode>
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* The 3D camera projection: `perspective` (the default) or `orthographic` —
|
|
155
|
+
* the Perspective/Orthographic control in the Design tab's View Settings panel.
|
|
156
|
+
*/
|
|
157
|
+
export const PluginCameraProjection = z.enum(["perspective", "orthographic"])
|
|
158
|
+
export type PluginCameraProjection = z.infer<typeof PluginCameraProjection>
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Arguments for {@linkcode PluginCameraApi.lookFrom}.
|
|
162
|
+
*
|
|
163
|
+
* | Property | Type | Description |
|
|
164
|
+
* |---|---|---|
|
|
165
|
+
* | `eye` | {@linkcode Vec3Handle} | Camera position (world, `babylon` units) |
|
|
166
|
+
* | `target` | {@linkcode Vec3Handle} | Point the camera looks at |
|
|
167
|
+
*/
|
|
168
|
+
export const PluginCameraLookFromArgs = z.object({
|
|
169
|
+
eye: Vec3Handle,
|
|
170
|
+
target: Vec3Handle,
|
|
171
|
+
})
|
|
172
|
+
export type PluginCameraLookFromArgs = z.infer<typeof PluginCameraLookFromArgs>
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Arguments for {@linkcode PluginCameraApi.setStandardView}.
|
|
176
|
+
*
|
|
177
|
+
* | Property | Type | Description |
|
|
178
|
+
* |---|---|---|
|
|
179
|
+
* | `view` | {@linkcode PluginStandardView} | The standard view to snap to |
|
|
180
|
+
*/
|
|
181
|
+
export const PluginCameraSetStandardViewArgs = z.object({
|
|
182
|
+
view: PluginStandardView,
|
|
183
|
+
})
|
|
184
|
+
export type PluginCameraSetStandardViewArgs = z.infer<
|
|
185
|
+
typeof PluginCameraSetStandardViewArgs
|
|
186
|
+
>
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Arguments for {@linkcode PluginCameraApi.setMode}.
|
|
190
|
+
*
|
|
191
|
+
* | Property | Type | Description |
|
|
192
|
+
* |---|---|---|
|
|
193
|
+
* | `mode` | {@linkcode PluginCameraMode} | `"2d"` or `"3d"` |
|
|
194
|
+
*/
|
|
195
|
+
export const PluginCameraSetModeArgs = z.object({
|
|
196
|
+
mode: PluginCameraMode,
|
|
197
|
+
})
|
|
198
|
+
export type PluginCameraSetModeArgs = z.infer<typeof PluginCameraSetModeArgs>
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Arguments for {@linkcode PluginCameraApi.setProjection}.
|
|
202
|
+
*
|
|
203
|
+
* | Property | Type | Description |
|
|
204
|
+
* |---|---|---|
|
|
205
|
+
* | `projection` | {@linkcode PluginCameraProjection} | `"perspective"` or `"orthographic"` |
|
|
206
|
+
*/
|
|
207
|
+
export const PluginCameraSetProjectionArgs = z.object({
|
|
208
|
+
projection: PluginCameraProjection,
|
|
209
|
+
})
|
|
210
|
+
export type PluginCameraSetProjectionArgs = z.infer<
|
|
211
|
+
typeof PluginCameraSetProjectionArgs
|
|
212
|
+
>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as z from "zod"
|
|
2
2
|
import { PluginApiReturn } from "../../../types"
|
|
3
|
-
import { Vec3Handle, ComponentHandle } from "../../../handles"
|
|
3
|
+
import { Vec3Handle, ComponentHandle, Vec3Components } from "../../../handles"
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Comments — create, edit, resolve, tag, and list scene/project comments.
|
|
@@ -140,7 +140,10 @@ export abstract class PluginCommentApi {
|
|
|
140
140
|
* await snaptrude.core.comment.tag(comment, "alex@acme.com")
|
|
141
141
|
* ```
|
|
142
142
|
*/
|
|
143
|
-
public abstract tag(
|
|
143
|
+
public abstract tag(
|
|
144
|
+
comment: CommentHandle,
|
|
145
|
+
email: string,
|
|
146
|
+
): PluginApiReturn<boolean>
|
|
144
147
|
|
|
145
148
|
/**
|
|
146
149
|
* Permanently remove a comment from the project.
|
|
@@ -176,6 +179,57 @@ export abstract class PluginCommentApi {
|
|
|
176
179
|
* ```
|
|
177
180
|
*/
|
|
178
181
|
public abstract list(): PluginApiReturn<CommentHandle[]>
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Read a comment's full detail — its text, author, pin location, resolved
|
|
185
|
+
* state, and reply thread. Comments are otherwise write-only; this is the read
|
|
186
|
+
* side. Pass a top-level comment handle or a reply handle (a reply has an empty
|
|
187
|
+
* `thread`). Returns `null` if the handle doesn't match a live comment.
|
|
188
|
+
*
|
|
189
|
+
* @param comment - The comment (or reply) to read.
|
|
190
|
+
* @returns the {@link PluginCommentDetails}, or `null` if not found.
|
|
191
|
+
*
|
|
192
|
+
* @examplePrompt Read the comment on this wall and tell me what it says
|
|
193
|
+
* @examplePrompt Who left this comment and where is it pinned?
|
|
194
|
+
* @examplePrompt Show me the full thread for this comment
|
|
195
|
+
* @examplePrompt Get the text and author of the selected comment
|
|
196
|
+
*
|
|
197
|
+
* # Example
|
|
198
|
+
* ```ts
|
|
199
|
+
* const [first] = await snaptrude.core.comment.list()
|
|
200
|
+
* const details = await snaptrude.core.comment.get(first)
|
|
201
|
+
* console.log(details?.content, "by", details?.author?.name)
|
|
202
|
+
* console.log(`${details?.thread.length ?? 0} replies`)
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
public abstract get(
|
|
206
|
+
comment: CommentHandle,
|
|
207
|
+
): PluginApiReturn<PluginCommentDetails | null>
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Reply to a comment — posts a new comment threaded under `comment` (which must
|
|
211
|
+
* be a top-level comment, not itself a reply). Notifies the thread's
|
|
212
|
+
* participants, mirroring the sidebar Reply action.
|
|
213
|
+
*
|
|
214
|
+
* @param comment - The top-level comment to reply to.
|
|
215
|
+
* @param text - The reply text (emojis = plain unicode).
|
|
216
|
+
* @returns the new reply's {@link CommentHandle}.
|
|
217
|
+
*
|
|
218
|
+
* @examplePrompt Reply to this comment saying I fixed the wall height
|
|
219
|
+
* @examplePrompt Add a reply to the review note confirming it's done
|
|
220
|
+
* @examplePrompt Respond to the comment about the door with "looks good now"
|
|
221
|
+
* @examplePrompt Post a follow-up on the selected comment thread
|
|
222
|
+
*
|
|
223
|
+
* # Example
|
|
224
|
+
* ```ts
|
|
225
|
+
* const [thread] = await snaptrude.core.comment.list()
|
|
226
|
+
* const reply = await snaptrude.core.comment.reply(thread, "Fixed 👍")
|
|
227
|
+
* ```
|
|
228
|
+
*/
|
|
229
|
+
public abstract reply(
|
|
230
|
+
comment: CommentHandle,
|
|
231
|
+
text: string,
|
|
232
|
+
): PluginApiReturn<CommentHandle>
|
|
179
233
|
}
|
|
180
234
|
|
|
181
235
|
/**
|
|
@@ -256,3 +310,67 @@ export const PluginCommentTagArgs = z.object({
|
|
|
256
310
|
})
|
|
257
311
|
|
|
258
312
|
export type PluginCommentTagArgs = z.infer<typeof PluginCommentTagArgs>
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Arguments for {@link PluginCommentApi.reply}.
|
|
316
|
+
*
|
|
317
|
+
* | Property | Type | Description |
|
|
318
|
+
* |---|---|---|
|
|
319
|
+
* | `comment` | {@link CommentHandle} | The top-level comment to reply to |
|
|
320
|
+
* | `text` | `string` | The reply text (emojis = unicode) |
|
|
321
|
+
*/
|
|
322
|
+
export const PluginCommentReplyArgs = z.object({
|
|
323
|
+
comment: CommentHandle,
|
|
324
|
+
text: z.string(),
|
|
325
|
+
})
|
|
326
|
+
|
|
327
|
+
export type PluginCommentReplyArgs = z.infer<typeof PluginCommentReplyArgs>
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* The author of a comment or reply — the display name and email of the teammate
|
|
331
|
+
* who posted it. `null` on the rare comment with no recorded author.
|
|
332
|
+
*/
|
|
333
|
+
export interface PluginCommentAuthor {
|
|
334
|
+
/** The author's display name (falls back to their email). */
|
|
335
|
+
name: string
|
|
336
|
+
/** The author's email. */
|
|
337
|
+
email: string
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* One reply in a comment's thread (returned by {@link PluginCommentApi.get}).
|
|
342
|
+
*/
|
|
343
|
+
export interface PluginCommentReply {
|
|
344
|
+
/** The reply's own {@link CommentHandle}. */
|
|
345
|
+
id: CommentHandle
|
|
346
|
+
/** The reply text. */
|
|
347
|
+
content: string
|
|
348
|
+
/** Who posted the reply. */
|
|
349
|
+
author: PluginCommentAuthor | null
|
|
350
|
+
/** ISO-8601 timestamp of when the reply was posted (empty if unknown). */
|
|
351
|
+
createdAt: string
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
/**
|
|
355
|
+
* The read model of a comment — returned by {@link PluginCommentApi.get}. The
|
|
356
|
+
* inverse of {@link PluginCommentApi.create}: `content`/`component`/`position`
|
|
357
|
+
* echo what was posted, plus the resolved state and reply `thread`.
|
|
358
|
+
*/
|
|
359
|
+
export interface PluginCommentDetails {
|
|
360
|
+
/** The comment's {@link CommentHandle}. */
|
|
361
|
+
id: CommentHandle
|
|
362
|
+
/** The comment text. */
|
|
363
|
+
content: string
|
|
364
|
+
/** Who posted the comment. */
|
|
365
|
+
author: PluginCommentAuthor | null
|
|
366
|
+
/** The pin point (engine world coordinates), or `null` if un-anchored. */
|
|
367
|
+
position: Vec3Components | null
|
|
368
|
+
/** The component the comment is anchored to, or `null` if un-anchored. */
|
|
369
|
+
component: ComponentHandle | null
|
|
370
|
+
/** Whether the comment has been marked resolved. */
|
|
371
|
+
isResolved: boolean
|
|
372
|
+
/** ISO-8601 timestamp of when the comment was posted (empty if unknown). */
|
|
373
|
+
createdAt: string
|
|
374
|
+
/** The reply thread, oldest first. Empty for a comment with no replies. */
|
|
375
|
+
thread: PluginCommentReply[]
|
|
376
|
+
}
|
|
@@ -20,6 +20,9 @@ export abstract class PluginGeomDeleteApi {
|
|
|
20
20
|
* reclaims its share of the plugin's resource quota. This is a handle-lifecycle
|
|
21
21
|
* operation only and does NOT tear down any engine-side geometry.
|
|
22
22
|
*
|
|
23
|
+
* @deprecated Use `core.handles.release([profile])` — the universal, batched
|
|
24
|
+
* release API for every arena handle kind.
|
|
25
|
+
*
|
|
23
26
|
* @param profile The transient profile handle to release
|
|
24
27
|
* @returns Nothing
|
|
25
28
|
*
|
|
@@ -37,6 +40,9 @@ export abstract class PluginGeomDeleteApi {
|
|
|
37
40
|
* reclaims its share of the plugin's resource quota. Handle-lifecycle only; does
|
|
38
41
|
* NOT tear down engine-side geometry, nor the contour's child profile handles.
|
|
39
42
|
*
|
|
43
|
+
* @deprecated Use `core.handles.release([contour])` — the universal, batched
|
|
44
|
+
* release API for every arena handle kind.
|
|
45
|
+
*
|
|
40
46
|
* @param contour The transient contour handle to release
|
|
41
47
|
* @returns Nothing
|
|
42
48
|
*
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
import * as z from "zod"
|
|
2
|
+
import { PluginApiReturn } from "../../../types"
|
|
3
|
+
// Type-only: src/handles.ts type-only-imports ArenaKind from this file, so the
|
|
4
|
+
// cycle stays purely type-level and is erased at emit.
|
|
5
|
+
import type { AnyArenaHandle } from "../../../handles"
|
|
6
|
+
import { Handle } from "../../../handles"
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The 12 registry-arena handle kinds — the releasable families. Entity-style
|
|
10
|
+
* handles (component / material / underlay / terrain / importJob / comment) are
|
|
11
|
+
* raw engine ids with no arena entry and therefore no lifecycle: passing one to
|
|
12
|
+
* `release` is a silent no-op like any other unknown id.
|
|
13
|
+
*/
|
|
14
|
+
export const ArenaKind = z.enum([
|
|
15
|
+
"vec3",
|
|
16
|
+
"quat",
|
|
17
|
+
"line",
|
|
18
|
+
"arc",
|
|
19
|
+
"circle",
|
|
20
|
+
"profile",
|
|
21
|
+
"contour",
|
|
22
|
+
"brep",
|
|
23
|
+
"face",
|
|
24
|
+
"edge",
|
|
25
|
+
"halfedge",
|
|
26
|
+
"vertex",
|
|
27
|
+
])
|
|
28
|
+
export type ArenaKind = z.infer<typeof ArenaKind>
|
|
29
|
+
|
|
30
|
+
/** Max handles accepted by a single `release` / `endScope(retain)` call. */
|
|
31
|
+
export const RELEASE_BATCH_MAX = 10_000
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* An opaque token identifying a handle scope opened by
|
|
35
|
+
* {@linkcode PluginCoreHandlesApi.beginScope}. It is NOT an arena handle —
|
|
36
|
+
* it pins no memory, and `release(token)` is a silent no-op; only
|
|
37
|
+
* {@linkcode PluginCoreHandlesApi.endScope} consumes it.
|
|
38
|
+
*/
|
|
39
|
+
export type ScopeToken = string
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Handle lifecycle — free host-side handle registry entries the plugin no
|
|
43
|
+
* longer needs, individually ({@linkcode release}), by kind
|
|
44
|
+
* ({@linkcode releaseAll}), or as a mint-recording region
|
|
45
|
+
* ({@linkcode beginScope} / {@linkcode endScope}).
|
|
46
|
+
*
|
|
47
|
+
* Releasing is a handle-lifecycle operation only: it frees the registry entry
|
|
48
|
+
* (host memory + quota room) and makes the handle unresolvable. It never
|
|
49
|
+
* deletes engine-side geometry or scene entities.
|
|
50
|
+
*
|
|
51
|
+
* Accessed via `snaptrude.core.handles`.
|
|
52
|
+
*/
|
|
53
|
+
export abstract class PluginCoreHandlesApi {
|
|
54
|
+
constructor() {}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Free arena handles in bulk. Unknown, foreign, or already-released ids are
|
|
58
|
+
* silent no-ops — there is no per-id result and no count, so responses can
|
|
59
|
+
* never be used as an existence oracle.
|
|
60
|
+
*
|
|
61
|
+
* @param handles The handles to release (max {@linkcode RELEASE_BATCH_MAX} per call)
|
|
62
|
+
* @returns Nothing
|
|
63
|
+
*
|
|
64
|
+
* # Example
|
|
65
|
+
* ```ts
|
|
66
|
+
* const faces = await snaptrude.core.geom.query.brep.listFaces(brep)
|
|
67
|
+
* // ... read what you need ...
|
|
68
|
+
* await snaptrude.core.handles.release(faces)
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
public abstract release(handles: ReadonlyArray<AnyArenaHandle>): PluginApiReturn<void>
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Free every live arena handle of one kind, or ALL arena handles when the
|
|
75
|
+
* kind is omitted. Useful at batch boundaries — e.g. a poll loop that mints
|
|
76
|
+
* a fresh footprint contour per tick.
|
|
77
|
+
*
|
|
78
|
+
* @param kind Optional arena kind to restrict the sweep to
|
|
79
|
+
* @returns Nothing
|
|
80
|
+
*
|
|
81
|
+
* # Example
|
|
82
|
+
* ```ts
|
|
83
|
+
* const footprint = await snaptrude.design.query.spaces.getFootprint(space)
|
|
84
|
+
* // ... measure ...
|
|
85
|
+
* await snaptrude.core.handles.releaseAll("contour")
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
public abstract releaseAll(kind?: ArenaKind): PluginApiReturn<void>
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Open a mint-recording scope: every arena handle MINTED after this call
|
|
92
|
+
* (fresh mints only — identity-deduped re-registrations of pre-existing
|
|
93
|
+
* objects are not captured) is freed when the matching
|
|
94
|
+
* {@linkcode endScope} runs. Scopes nest, up to 64 deep — always pair
|
|
95
|
+
* begin/end in try/finally.
|
|
96
|
+
*
|
|
97
|
+
* @returns The scope token to pass to {@linkcode endScope}
|
|
98
|
+
*
|
|
99
|
+
* # Example
|
|
100
|
+
* ```ts
|
|
101
|
+
* for (const space of spaces) {
|
|
102
|
+
* const scope = await snaptrude.core.handles.beginScope()
|
|
103
|
+
* try {
|
|
104
|
+
* const footprint = await snaptrude.design.query.spaces.getFootprint(space)
|
|
105
|
+
* const area = await snaptrude.core.geom.query.contour.getArea(footprint)
|
|
106
|
+
* } finally {
|
|
107
|
+
* await snaptrude.core.handles.endScope(scope) // footprint (and intermediates) freed
|
|
108
|
+
* }
|
|
109
|
+
* }
|
|
110
|
+
* ```
|
|
111
|
+
*/
|
|
112
|
+
public abstract beginScope(): PluginApiReturn<ScopeToken>
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Close a scope by its token and free every handle it recorded, except those
|
|
116
|
+
* listed in `retain`. Retained handles are promoted to the enclosing scope
|
|
117
|
+
* (if any), so nesting composes like block scopes. Closing is
|
|
118
|
+
* token-addressed: an out-of-order close (interleaved async tasks) frees
|
|
119
|
+
* only that scope's mints and leaves other open scopes intact. Always pair
|
|
120
|
+
* begin/end in try/finally so a thrown body cannot leak the scope.
|
|
121
|
+
*
|
|
122
|
+
* @param scope The token returned by the matching {@linkcode beginScope}
|
|
123
|
+
* @param retain Handles minted inside the scope that must survive it
|
|
124
|
+
* @returns Nothing
|
|
125
|
+
*
|
|
126
|
+
* # Example
|
|
127
|
+
* ```ts
|
|
128
|
+
* const scope = await snaptrude.core.handles.beginScope()
|
|
129
|
+
* const outline = await snaptrude.design.query.spaces.getFootprint(space)
|
|
130
|
+
* const outer = await snaptrude.core.geom.query.contour.getOuterProfile(outline)
|
|
131
|
+
* await snaptrude.core.handles.endScope(scope, [outer]) // outline freed, outer survives
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
public abstract endScope(
|
|
135
|
+
scope: ScopeToken,
|
|
136
|
+
retain?: ReadonlyArray<AnyArenaHandle>
|
|
137
|
+
): PluginApiReturn<void>
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Live handle-registry statistics for the calling plugin, plus the host
|
|
141
|
+
* page's JS heap usage (when the browser exposes it). Diagnostic surface for
|
|
142
|
+
* verifying that releases actually shrink host memory.
|
|
143
|
+
*
|
|
144
|
+
* @returns Arena entry counts, open scope depth, and host heap bytes
|
|
145
|
+
*
|
|
146
|
+
* # Example
|
|
147
|
+
* ```ts
|
|
148
|
+
* const before = await snaptrude.core.handles.stats()
|
|
149
|
+
* await snaptrude.core.handles.releaseAll("vec3")
|
|
150
|
+
* const after = await snaptrude.core.handles.stats()
|
|
151
|
+
* console.log(`freed ${before.values - after.values} value entries`)
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
public abstract stats(): PluginApiReturn<PluginHandlesStatsResult>
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Wire-normalize one handle argument: a raw id string passes through; a live
|
|
159
|
+
* `Handle` instance (direct host callers — console harness, host-internal) or a
|
|
160
|
+
* structured-clone-stripped `{id}` / tagged `{__h}` shape collapses to its id.
|
|
161
|
+
* Deliberately shape-lax beyond that (non-empty string) — a malformed id is
|
|
162
|
+
* just an id that resolves nowhere (anti-oracle).
|
|
163
|
+
*/
|
|
164
|
+
const handleIdWire = z.preprocess((v) => {
|
|
165
|
+
if (typeof v === "string") return v
|
|
166
|
+
if (v instanceof Handle) return v.id
|
|
167
|
+
if (v && typeof v === "object") {
|
|
168
|
+
const o = v as Record<string, unknown>
|
|
169
|
+
if (typeof o.__h === "string") return o.__h
|
|
170
|
+
if (typeof o.id === "string") return o.id
|
|
171
|
+
}
|
|
172
|
+
return v
|
|
173
|
+
}, z.string().min(1))
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Arguments for {@linkcode PluginCoreHandlesApi.release}.
|
|
177
|
+
*
|
|
178
|
+
* | Property | Type | Description |
|
|
179
|
+
* |---|---|---|
|
|
180
|
+
* | `handles` | `string[]` | Handles to release (≤ {@linkcode RELEASE_BATCH_MAX}) |
|
|
181
|
+
*/
|
|
182
|
+
export const PluginHandlesReleaseArgs = z.object({
|
|
183
|
+
handles: z.array(handleIdWire).max(RELEASE_BATCH_MAX),
|
|
184
|
+
})
|
|
185
|
+
export type PluginHandlesReleaseArgs = z.infer<typeof PluginHandlesReleaseArgs>
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Arguments for {@linkcode PluginCoreHandlesApi.releaseAll}.
|
|
189
|
+
*
|
|
190
|
+
* | Property | Type | Description |
|
|
191
|
+
* |---|---|---|
|
|
192
|
+
* | `kind` | {@linkcode ArenaKind} (optional) | Restrict the sweep to one kind |
|
|
193
|
+
*/
|
|
194
|
+
export const PluginHandlesReleaseAllArgs = z.object({
|
|
195
|
+
kind: ArenaKind.optional(),
|
|
196
|
+
})
|
|
197
|
+
export type PluginHandlesReleaseAllArgs = z.infer<typeof PluginHandlesReleaseAllArgs>
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* Arguments for {@linkcode PluginCoreHandlesApi.endScope}.
|
|
201
|
+
*
|
|
202
|
+
* | Property | Type | Description |
|
|
203
|
+
* |---|---|---|
|
|
204
|
+
* | `scope` | {@linkcode ScopeToken} | Token from the matching `beginScope` |
|
|
205
|
+
* | `retain` | `string[]` (optional) | Scope-minted handles that must survive |
|
|
206
|
+
*/
|
|
207
|
+
export const PluginHandlesEndScopeArgs = z.object({
|
|
208
|
+
scope: z.string().regex(/^scope_[A-Za-z0-9_-]+$/, 'expected a "scope" token'),
|
|
209
|
+
retain: z.array(handleIdWire).max(RELEASE_BATCH_MAX).optional(),
|
|
210
|
+
})
|
|
211
|
+
export type PluginHandlesEndScopeArgs = z.infer<typeof PluginHandlesEndScopeArgs>
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Result of {@linkcode PluginCoreHandlesApi.stats}.
|
|
215
|
+
*
|
|
216
|
+
* | Property | Type | Description |
|
|
217
|
+
* |---|---|---|
|
|
218
|
+
* | `resources` | `number` | Live resource-arena entries (profile/contour) |
|
|
219
|
+
* | `values` | `number` | Live value-arena entries (vec3/quat/line/arc/circle) |
|
|
220
|
+
* | `topology` | `number` | Live topology-arena entries (brep/face/edge/halfedge/vertex) |
|
|
221
|
+
* | `scopes` | `number` | Currently open handle scopes |
|
|
222
|
+
* | `hostHeapUsedBytes` | `number \| null` | Host page `usedJSHeapSize` (null where unsupported) |
|
|
223
|
+
* | `hostHeapTotalBytes` | `number \| null` | Host page `totalJSHeapSize` (null where unsupported) |
|
|
224
|
+
*/
|
|
225
|
+
export const PluginHandlesStatsResult = z.object({
|
|
226
|
+
resources: z.number().int().nonnegative(),
|
|
227
|
+
values: z.number().int().nonnegative(),
|
|
228
|
+
topology: z.number().int().nonnegative(),
|
|
229
|
+
scopes: z.number().int().nonnegative(),
|
|
230
|
+
hostHeapUsedBytes: z.number().nullable(),
|
|
231
|
+
hostHeapTotalBytes: z.number().nullable(),
|
|
232
|
+
})
|
|
233
|
+
export type PluginHandlesStatsResult = z.infer<typeof PluginHandlesStatsResult>
|
package/src/api/core/index.ts
CHANGED
|
@@ -10,7 +10,10 @@ import { PluginCoreBuildingsApi } from "./buildings"
|
|
|
10
10
|
import { PluginCoreLayersApi } from "./layers"
|
|
11
11
|
import { PluginCoreTagsApi } from "./tags"
|
|
12
12
|
import { PluginCoreIoApi } from "./io"
|
|
13
|
+
import { PluginCoreHandlesApi } from "./handles"
|
|
13
14
|
import { PluginCoreProposalsApi } from "./proposals"
|
|
15
|
+
import { PluginCameraApi } from "./camera"
|
|
16
|
+
import { PluginUserApi } from "./user"
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
19
|
* Core primitives and infrastructure used across the plugin API.
|
|
@@ -20,6 +23,8 @@ import { PluginCoreProposalsApi } from "./proposals"
|
|
|
20
23
|
* - {@linkcode PluginCoreApi.history} — Undo / redo of committed history entries
|
|
21
24
|
* - {@linkcode PluginCoreApi.units} — Unit-type queries and conversion
|
|
22
25
|
* - {@linkcode PluginCoreApi.zoom} — Camera zoom controls (extents / selection)
|
|
26
|
+
* - {@linkcode PluginCoreApi.camera} — Camera controls — position, standard views, 2D/3D mode
|
|
27
|
+
* - {@linkcode PluginCoreApi.user} — User locale — timezone & language
|
|
23
28
|
* - {@linkcode PluginCoreApi.project} — Project-level settings and info
|
|
24
29
|
* - {@linkcode PluginCoreApi.comment} — Comments: create, edit, resolve, tag, list
|
|
25
30
|
* - {@linkcode PluginCoreApi.groups} — Read & edit the group hierarchy
|
|
@@ -27,6 +32,7 @@ import { PluginCoreProposalsApi } from "./proposals"
|
|
|
27
32
|
* - {@linkcode PluginCoreApi.layers} — Read & toggle storey drawing/reference layers
|
|
28
33
|
* - {@linkcode PluginCoreApi.tags} — Tag catalog + assignment
|
|
29
34
|
* - {@linkcode PluginCoreApi.io} — Import files (image/pdf/cad/model/terrain), poll jobs, manage underlays
|
|
35
|
+
* - {@linkcode PluginCoreApi.handles} — Handle lifecycle: release, releaseAll, scopes
|
|
30
36
|
* - {@linkcode PluginCoreApi.proposals} — Design options: read, create, rename, switch, delete
|
|
31
37
|
*/
|
|
32
38
|
export abstract class PluginCoreApi {
|
|
@@ -40,6 +46,10 @@ export abstract class PluginCoreApi {
|
|
|
40
46
|
public abstract units: PluginUnitsApi
|
|
41
47
|
/** Camera zoom controls. See {@linkcode PluginZoomApi}. */
|
|
42
48
|
public abstract zoom: PluginZoomApi
|
|
49
|
+
/** Camera controls — position, standard views, 2D/3D mode. See {@linkcode PluginCameraApi}. */
|
|
50
|
+
public abstract camera: PluginCameraApi
|
|
51
|
+
/** User locale — timezone & language. See {@linkcode PluginUserApi}. */
|
|
52
|
+
public abstract user: PluginUserApi
|
|
43
53
|
/** Project-level settings and info. See {@linkcode PluginProjectApi}. */
|
|
44
54
|
public abstract project: PluginProjectApi
|
|
45
55
|
/** Comments — create, edit, resolve, tag, list. See {@linkcode PluginCommentApi}. */
|
|
@@ -54,6 +64,8 @@ export abstract class PluginCoreApi {
|
|
|
54
64
|
public abstract tags: PluginCoreTagsApi
|
|
55
65
|
/** I/O — file import, import jobs, and underlay management. See {@linkcode PluginCoreIoApi}. */
|
|
56
66
|
public abstract io: PluginCoreIoApi
|
|
67
|
+
/** Handle lifecycle — release, releaseAll, and mint-recording scopes. See {@linkcode PluginCoreHandlesApi}. */
|
|
68
|
+
public abstract handles: PluginCoreHandlesApi
|
|
57
69
|
/** Proposals — design options: read, create, rename, switch, delete. See {@linkcode PluginCoreProposalsApi}. */
|
|
58
70
|
public abstract proposals: PluginCoreProposalsApi
|
|
59
71
|
|
|
@@ -65,6 +77,8 @@ export * from "./geom"
|
|
|
65
77
|
export * from "./history"
|
|
66
78
|
export * from "./units"
|
|
67
79
|
export * from "./zoom"
|
|
80
|
+
export * from "./camera"
|
|
81
|
+
export * from "./user"
|
|
68
82
|
export * from "./project"
|
|
69
83
|
export * from "./comment"
|
|
70
84
|
export * from "./groups"
|
|
@@ -72,4 +86,5 @@ export * from "./buildings"
|
|
|
72
86
|
export * from "./layers"
|
|
73
87
|
export * from "./tags"
|
|
74
88
|
export * from "./io"
|
|
89
|
+
export * from "./handles"
|
|
75
90
|
export * from "./proposals"
|