@snaptrude/plugin-core 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/api-manifest.full.json +7703 -0
  3. package/api-manifest.json +2946 -259
  4. package/dist/api/analysis/daylight.d.ts +603 -0
  5. package/dist/api/analysis/daylight.d.ts.map +1 -0
  6. package/dist/api/analysis/heatmaps.d.ts +438 -14
  7. package/dist/api/analysis/heatmaps.d.ts.map +1 -1
  8. package/dist/api/analysis/index.d.ts +15 -0
  9. package/dist/api/analysis/index.d.ts.map +1 -1
  10. package/dist/api/analysis/solar.d.ts +249 -0
  11. package/dist/api/analysis/solar.d.ts.map +1 -0
  12. package/dist/api/analysis/weather.d.ts +193 -0
  13. package/dist/api/analysis/weather.d.ts.map +1 -0
  14. package/dist/api/core/camera/index.d.ts +245 -0
  15. package/dist/api/core/camera/index.d.ts.map +1 -0
  16. package/dist/api/core/comment/index.d.ts +105 -2
  17. package/dist/api/core/comment/index.d.ts.map +1 -1
  18. package/dist/api/core/geom/create/index.d.ts +331 -14
  19. package/dist/api/core/geom/create/index.d.ts.map +1 -1
  20. package/dist/api/core/geom/delete/index.d.ts +8 -2
  21. package/dist/api/core/geom/delete/index.d.ts.map +1 -1
  22. package/dist/api/core/geom/query/arc.d.ts +5 -5
  23. package/dist/api/core/geom/query/brep.d.ts +18 -18
  24. package/dist/api/core/geom/query/circle.d.ts +18 -18
  25. package/dist/api/core/geom/query/contour.d.ts +20 -20
  26. package/dist/api/core/geom/query/curve.d.ts +49 -49
  27. package/dist/api/core/geom/query/edge.d.ts +5 -5
  28. package/dist/api/core/geom/query/face.d.ts +16 -16
  29. package/dist/api/core/geom/query/halfedge.d.ts +8 -8
  30. package/dist/api/core/geom/query/profile.d.ts +19 -19
  31. package/dist/api/core/geom/query/vertex.d.ts +8 -8
  32. package/dist/api/core/geom/update/contour.d.ts +14 -14
  33. package/dist/api/core/geom/update/curve.d.ts +7 -7
  34. package/dist/api/core/geom/update/profile.d.ts +16 -16
  35. package/dist/api/core/handles/index.d.ts +210 -0
  36. package/dist/api/core/handles/index.d.ts.map +1 -0
  37. package/dist/api/core/index.d.ts +24 -0
  38. package/dist/api/core/index.d.ts.map +1 -1
  39. package/dist/api/core/io/export/index.d.ts +134 -0
  40. package/dist/api/core/io/export/index.d.ts.map +1 -0
  41. package/dist/api/core/io/import/index.d.ts +62 -1
  42. package/dist/api/core/io/import/index.d.ts.map +1 -1
  43. package/dist/api/core/io/index.d.ts +5 -0
  44. package/dist/api/core/io/index.d.ts.map +1 -1
  45. package/dist/api/core/layers.d.ts +7 -7
  46. package/dist/api/core/mode/index.d.ts +99 -0
  47. package/dist/api/core/mode/index.d.ts.map +1 -0
  48. package/dist/api/core/proposals/index.d.ts +65 -9
  49. package/dist/api/core/proposals/index.d.ts.map +1 -1
  50. package/dist/api/core/storeys/index.d.ts +251 -0
  51. package/dist/api/core/storeys/index.d.ts.map +1 -0
  52. package/dist/api/core/tags.d.ts +24 -0
  53. package/dist/api/core/tags.d.ts.map +1 -1
  54. package/dist/api/core/user.d.ts +44 -0
  55. package/dist/api/core/user.d.ts.map +1 -0
  56. package/dist/api/core/zoom/index.d.ts +4 -0
  57. package/dist/api/core/zoom/index.d.ts.map +1 -1
  58. package/dist/api/design/boolean/index.d.ts +4 -4
  59. package/dist/api/design/create/index.d.ts +253 -47
  60. package/dist/api/design/create/index.d.ts.map +1 -1
  61. package/dist/api/design/delete/index.d.ts +3 -0
  62. package/dist/api/design/delete/index.d.ts.map +1 -1
  63. package/dist/api/design/doors/index.d.ts +36 -0
  64. package/dist/api/design/doors/index.d.ts.map +1 -1
  65. package/dist/api/design/edit/index.d.ts +1 -1
  66. package/dist/api/design/erase/index.d.ts +2 -2
  67. package/dist/api/design/furniture/index.d.ts +114 -3
  68. package/dist/api/design/furniture/index.d.ts.map +1 -1
  69. package/dist/api/design/index.d.ts +10 -0
  70. package/dist/api/design/index.d.ts.map +1 -1
  71. package/dist/api/design/materials/index.d.ts +111 -14
  72. package/dist/api/design/materials/index.d.ts.map +1 -1
  73. package/dist/api/design/query/geometry/index.d.ts +112 -0
  74. package/dist/api/design/query/geometry/index.d.ts.map +1 -1
  75. package/dist/api/design/query/index.d.ts +35 -1
  76. package/dist/api/design/query/index.d.ts.map +1 -1
  77. package/dist/api/design/query/referenceLines.d.ts +45 -0
  78. package/dist/api/design/query/referenceLines.d.ts.map +1 -0
  79. package/dist/api/design/query/spaces.d.ts +178 -5
  80. package/dist/api/design/query/spaces.d.ts.map +1 -1
  81. package/dist/api/design/transform/index.d.ts +95 -14
  82. package/dist/api/design/transform/index.d.ts.map +1 -1
  83. package/dist/api/design/types/index.d.ts +181 -0
  84. package/dist/api/design/types/index.d.ts.map +1 -0
  85. package/dist/api/design/update/index.d.ts +385 -2
  86. package/dist/api/design/update/index.d.ts.map +1 -1
  87. package/dist/api/design/visibility.d.ts +98 -0
  88. package/dist/api/design/visibility.d.ts.map +1 -0
  89. package/dist/api/entity/buildableEnvelope.d.ts +4 -0
  90. package/dist/api/entity/buildableEnvelope.d.ts.map +1 -1
  91. package/dist/api/entity/referenceLine.d.ts +10 -2
  92. package/dist/api/entity/referenceLine.d.ts.map +1 -1
  93. package/dist/api/entity/space.d.ts +19 -19
  94. package/dist/api/entity/story.d.ts +148 -15
  95. package/dist/api/entity/story.d.ts.map +1 -1
  96. package/dist/api/index.d.ts +5 -0
  97. package/dist/api/index.d.ts.map +1 -1
  98. package/dist/api/presentation/annotate.d.ts +448 -0
  99. package/dist/api/presentation/annotate.d.ts.map +1 -0
  100. package/dist/api/presentation/diagrams.d.ts +49 -8
  101. package/dist/api/presentation/diagrams.d.ts.map +1 -1
  102. package/dist/api/presentation/export.d.ts +108 -0
  103. package/dist/api/presentation/export.d.ts.map +1 -0
  104. package/dist/api/presentation/import.d.ts +6 -0
  105. package/dist/api/presentation/import.d.ts.map +1 -1
  106. package/dist/api/presentation/index.d.ts +47 -0
  107. package/dist/api/presentation/index.d.ts.map +1 -1
  108. package/dist/api/presentation/placedViews.d.ts +370 -0
  109. package/dist/api/presentation/placedViews.d.ts.map +1 -0
  110. package/dist/api/presentation/shapes.d.ts +481 -0
  111. package/dist/api/presentation/shapes.d.ts.map +1 -0
  112. package/dist/api/presentation/sheets.d.ts +410 -13
  113. package/dist/api/presentation/sheets.d.ts.map +1 -1
  114. package/dist/api/presentation/views.d.ts +165 -10
  115. package/dist/api/presentation/views.d.ts.map +1 -1
  116. package/dist/api/program/areas.d.ts +63 -3
  117. package/dist/api/program/areas.d.ts.map +1 -1
  118. package/dist/api/program/cores.d.ts +3 -99
  119. package/dist/api/program/cores.d.ts.map +1 -1
  120. package/dist/api/program/index.d.ts +2 -2
  121. package/dist/api/program/index.d.ts.map +1 -1
  122. package/dist/api/program/layout.d.ts +172 -12
  123. package/dist/api/program/layout.d.ts.map +1 -1
  124. package/dist/api/program/site.d.ts +105 -8
  125. package/dist/api/program/site.d.ts.map +1 -1
  126. package/dist/api/program/spreadsheet.d.ts +365 -41
  127. package/dist/api/program/spreadsheet.d.ts.map +1 -1
  128. package/dist/api/workspace/index.d.ts +460 -0
  129. package/dist/api/workspace/index.d.ts.map +1 -0
  130. package/dist/handles.d.ts +64 -25
  131. package/dist/handles.d.ts.map +1 -1
  132. package/dist/index.cjs +3210 -1671
  133. package/dist/index.cjs.map +1 -1
  134. package/dist/index.js +3008 -1666
  135. package/dist/index.js.map +1 -1
  136. package/package.json +3 -2
  137. package/scripts/generate-manifest.mjs +45 -0
  138. package/src/api/analysis/daylight.ts +470 -0
  139. package/src/api/analysis/heatmaps.ts +444 -17
  140. package/src/api/analysis/index.ts +15 -0
  141. package/src/api/analysis/solar.ts +237 -0
  142. package/src/api/analysis/weather.ts +179 -0
  143. package/src/api/core/camera/index.ts +251 -0
  144. package/src/api/core/comment/index.ts +120 -2
  145. package/src/api/core/geom/create/index.ts +344 -1
  146. package/src/api/core/geom/delete/index.ts +6 -0
  147. package/src/api/core/handles/index.ts +233 -0
  148. package/src/api/core/index.ts +24 -0
  149. package/src/api/core/io/export/index.ts +126 -0
  150. package/src/api/core/io/import/index.ts +64 -0
  151. package/src/api/core/io/index.ts +5 -0
  152. package/src/api/core/mode/index.ts +96 -0
  153. package/src/api/core/proposals/index.ts +71 -11
  154. package/src/api/core/storeys/index.ts +279 -0
  155. package/src/api/core/tags.ts +27 -0
  156. package/src/api/core/user.ts +46 -0
  157. package/src/api/core/zoom/index.ts +4 -0
  158. package/src/api/design/create/index.ts +303 -36
  159. package/src/api/design/delete/index.ts +3 -0
  160. package/src/api/design/doors/index.ts +40 -0
  161. package/src/api/design/furniture/index.ts +127 -3
  162. package/src/api/design/index.ts +10 -0
  163. package/src/api/design/materials/index.ts +157 -30
  164. package/src/api/design/query/geometry/index.ts +125 -3
  165. package/src/api/design/query/index.ts +37 -7
  166. package/src/api/design/query/referenceLines.ts +52 -0
  167. package/src/api/design/query/spaces.ts +143 -0
  168. package/src/api/design/transform/index.ts +101 -12
  169. package/src/api/design/types/index.ts +156 -0
  170. package/src/api/design/update/index.ts +467 -6
  171. package/src/api/design/visibility.ts +109 -0
  172. package/src/api/entity/buildableEnvelope.ts +4 -0
  173. package/src/api/entity/referenceLine.ts +8 -0
  174. package/src/api/entity/story.ts +161 -15
  175. package/src/api/index.ts +5 -0
  176. package/src/api/presentation/annotate.ts +360 -0
  177. package/src/api/presentation/diagrams.ts +53 -8
  178. package/src/api/presentation/export.ts +108 -0
  179. package/src/api/presentation/import.ts +6 -0
  180. package/src/api/presentation/index.ts +55 -0
  181. package/src/api/presentation/placedViews.ts +363 -0
  182. package/src/api/presentation/shapes.ts +274 -0
  183. package/src/api/presentation/sheets.ts +346 -13
  184. package/src/api/presentation/views.ts +164 -12
  185. package/src/api/program/areas.ts +57 -6
  186. package/src/api/program/cores.ts +3 -91
  187. package/src/api/program/index.ts +2 -2
  188. package/src/api/program/layout.ts +182 -12
  189. package/src/api/program/site.ts +106 -8
  190. package/src/api/program/spreadsheet.ts +376 -35
  191. package/src/api/workspace/index.ts +516 -0
  192. package/src/handles.ts +77 -13
  193. package/tsconfig.json +7 -2
@@ -19,10 +19,21 @@ import { PluginApiReturn } from "../../types"
19
19
  * longer `"running"` — a run can take up to 20 minutes.
20
20
  * 3. {@linkcode PluginProgramLayoutApi.cancel} aborts an in-flight run.
21
21
  *
22
- * `arrange` produces several candidate layouts and **auto-commits the first
23
- * solution** as one undoable edit (there is no interactive solution-review
24
- * over the plugin boundary); `pack` re-shapes and applies its single result
25
- * directly. Both are **Pro-plan-gated**, matching the product UI.
22
+ * `arrange` produces several candidate layouts. By default it **auto-commits
23
+ * the first solution** as one undoable edit; pass `autoCommit: false` to hold
24
+ * the candidates for review instead `getState` then reports
25
+ * `status: "pendingReview"` with `totalSolutions`, and
26
+ * {@linkcode PluginProgramLayoutApi.applySolution} commits the one you pick
27
+ * (the headless counterpart of the product's "Solution N of M → Apply" bar).
28
+ * `pack` re-shapes and applies its single result directly. Both are
29
+ * **Pro-plan-gated**, matching the product UI.
30
+ *
31
+ * {@linkcode PluginProgramLayoutApi.stack} is the **cross-storey** action —
32
+ * the product's *Pack in envelope* / auto-stack. It splits the building
33
+ * envelope by storey and packs each storey's departments into its slice as one
34
+ * undoable edit. Unlike `arrange` / `pack`, it is **not** the async-job model:
35
+ * it resolves inline when the whole multi-storey pack is done (no `getState`
36
+ * polling) and returns the storeys it had to skip. It is Pro-gated too.
26
37
  *
27
38
  * Accessed via `snaptrude.program.layout`.
28
39
  */
@@ -35,9 +46,16 @@ export abstract class PluginProgramLayoutApi {
35
46
  * Starts the backend job and **returns immediately** — poll
36
47
  * {@linkcode PluginProgramLayoutApi.getState} until `status` leaves
37
48
  * `"running"` (a run can take up to 20 minutes). The solver produces
38
- * several candidate layouts; this **auto-commits the first solution** as one
39
- * undoable edit (no interactive review over the plugin boundary). Starting a
40
- * run while one is in flight replaces it.
49
+ * several candidate layouts; by default this **auto-commits the first
50
+ * solution** as one undoable edit. Pass `autoCommit: false` to review them
51
+ * instead: the run finishes with `status: "pendingReview"` and
52
+ * `totalSolutions` in `getState`, and
53
+ * {@linkcode PluginProgramLayoutApi.applySolution} commits the candidate you
54
+ * pick ({@linkcode PluginProgramLayoutApi.cancel} discards them). An
55
+ * arrange **without an envelope** applies directly (there is nothing to
56
+ * review) regardless of `autoCommit`. Starting a run while one is in flight
57
+ * replaces it; while solutions are pending review, new runs are refused —
58
+ * apply or cancel first.
41
59
  *
42
60
  * With no `options`, operates on the eligible Room/Department masses on the
43
61
  * active storey and auto-detects the single buildable envelope there.
@@ -53,11 +71,14 @@ export abstract class PluginProgramLayoutApi {
53
71
  * @throws When a `spaceId` / `departmentId` / `envelopeId` does not resolve.
54
72
  * @throws When more than one envelope is on the active storey and none was
55
73
  * given (ambiguous).
74
+ * @throws When arrange solutions are pending review (apply or cancel them
75
+ * first).
56
76
  * @throws When plugin writes are disabled.
57
77
  *
58
78
  * @examplePrompt Arrange the rooms in the envelope
59
79
  * @examplePrompt Lay out the departments inside the building envelope
60
80
  * @examplePrompt Auto-arrange the program spaces
81
+ * @examplePrompt Arrange the rooms but let me pick the solution
61
82
  *
62
83
  * # Example
63
84
  * ```ts
@@ -98,6 +119,8 @@ export abstract class PluginProgramLayoutApi {
98
119
  * @throws When a `spaceId` / `departmentId` / `envelopeId` does not resolve.
99
120
  * @throws When more than one envelope is on the active storey and none was
100
121
  * given (ambiguous).
122
+ * @throws When arrange solutions are pending review (apply or cancel them
123
+ * first).
101
124
  * @throws When plugin writes are disabled.
102
125
  *
103
126
  * @examplePrompt Pack the rooms into the envelope
@@ -118,6 +141,92 @@ export abstract class PluginProgramLayoutApi {
118
141
  options?: PluginProgramLayoutRunArgs,
119
142
  ): PluginApiReturn<PluginProgramLayoutRunResult>
120
143
 
144
+ /**
145
+ * Apply one of the pending arrange solutions.
146
+ *
147
+ * The headless counterpart of the product's **"Solution N of M → Apply"**
148
+ * review bar: after an {@linkcode PluginProgramLayoutApi.arrange} run
149
+ * started with `autoCommit: false` finishes with `status: "pendingReview"`,
150
+ * this commits the candidate at `index` (0-based,
151
+ * `0 ≤ index < totalSolutions` from
152
+ * {@linkcode PluginProgramLayoutApi.getState}) as **one undoable edit** and
153
+ * discards the other candidates. `getState` then reports
154
+ * `status: "active"`.
155
+ *
156
+ * @param index - 0-based index of the pending solution to apply.
157
+ * @returns A {@linkcode PluginProgramLayoutApplyResult} —
158
+ * `{ success: true }` when the solution was applied.
159
+ * @throws When no arrange solutions are pending review (no
160
+ * `arrange({ autoCommit: false })` run has finished, or its solutions were
161
+ * already applied / cancelled).
162
+ * @throws When `index` is out of range for the pending solutions.
163
+ * @throws When plugin writes are disabled.
164
+ *
165
+ * @examplePrompt Apply the second arrange solution
166
+ * @examplePrompt Pick layout solution 3 and commit it
167
+ * @examplePrompt Apply the arrange solution I chose
168
+ *
169
+ * # Example
170
+ * ```ts
171
+ * await snaptrude.program.layout.arrange({ autoCommit: false })
172
+ * let job = await snaptrude.program.layout.getState()
173
+ * while (job?.status === "running") {
174
+ * await new Promise((r) => setTimeout(r, 5000))
175
+ * job = await snaptrude.program.layout.getState()
176
+ * }
177
+ * if (job?.status === "pendingReview") {
178
+ * console.log(`${job.totalSolutions} candidate layouts`)
179
+ * await snaptrude.program.layout.applySolution(1) // commit the second one
180
+ * }
181
+ * ```
182
+ */
183
+ public abstract applySolution(
184
+ index: number,
185
+ ): PluginApiReturn<PluginProgramLayoutApplyResult>
186
+
187
+ /**
188
+ * Stack the program across **every storey** of the building — the product's
189
+ * *Pack in envelope* / auto-stack.
190
+ *
191
+ * Splits the building envelope massing into per-storey envelope slices, then
192
+ * packs each storey's departments into its slice, applying the whole
193
+ * multi-storey result as **one undoable edit**.
194
+ *
195
+ * Unlike {@linkcode PluginProgramLayoutApi.arrange} /
196
+ * {@linkcode PluginProgramLayoutApi.pack}, this **is not** the async-job
197
+ * model: `await` it and it resolves when the stack is done — there is no
198
+ * `getState` polling. It operates on the whole active model (no id / envelope
199
+ * arguments): it auto-discovers the departments and envelope on each storey.
200
+ *
201
+ * Storeys that have departments but **no envelope** are reported in
202
+ * `skippedStoreys` (nothing was packed there). A storey's departments must
203
+ * already be on that storey — `stack` does not move departments between
204
+ * floors, it lays out each floor's program into that floor's envelope.
205
+ *
206
+ * @returns A {@linkcode PluginProgramLayoutStackResult} — `success: true`
207
+ * with the (possibly empty) `skippedStoreys` when the stack was applied, or
208
+ * `success: false` with an `error` when the run failed (e.g. the adjacency
209
+ * service was unreachable).
210
+ * @throws When the project is not on a Pro plan.
211
+ * @throws When plugin writes are disabled.
212
+ * @throws When an `arrange` / `pack` run, or another `stack`, is already in
213
+ * flight, or arrange solutions are pending review (finish, apply, or
214
+ * `cancel` first).
215
+ *
216
+ * @examplePrompt Stack the program across all floors
217
+ * @examplePrompt Auto-stack the departments into the envelope on every storey
218
+ * @examplePrompt Pack the whole building's program into its envelope
219
+ *
220
+ * # Example
221
+ * ```ts
222
+ * const { success, skippedStoreys, error } = await snaptrude.program.layout.stack()
223
+ * if (!success) throw new Error(error)
224
+ * if (skippedStoreys.length)
225
+ * console.warn(`No envelope on storeys: ${skippedStoreys.join(", ")}`)
226
+ * ```
227
+ */
228
+ public abstract stack(): PluginApiReturn<PluginProgramLayoutStackResult>
229
+
121
230
  /**
122
231
  * Get the state of the layout run.
123
232
  *
@@ -130,6 +239,10 @@ export abstract class PluginProgramLayoutApi {
130
239
  * | `"running"` | A run is in flight — keep polling |
131
240
  * | `"active"` | The run finished and its layout is applied to the model |
132
241
  * | `"inactive"` | A run finished without applying a layout (the solver failed or found no solution) |
242
+ * | `"pendingReview"` | An `arrange({ autoCommit: false })` run finished and its candidates await {@linkcode PluginProgramLayoutApi.applySolution} / {@linkcode PluginProgramLayoutApi.cancel} |
243
+ *
244
+ * While `status` is `"pendingReview"` the state also carries
245
+ * `totalSolutions` — the number of candidate layouts to pick from.
133
246
  *
134
247
  * @returns A {@linkcode PluginProgramLayoutStateResult} with the run
135
248
  * `status`, or `null` when no run result is available (never ran or was
@@ -150,11 +263,13 @@ export abstract class PluginProgramLayoutApi {
150
263
  /**
151
264
  * Cancel the in-flight layout run.
152
265
  *
153
- * Aborts the backend job and discards any pending solution. A no-op
154
- * (returns `false`) when nothing is running.
266
+ * Aborts the backend job and discards any pending solution. Also discards
267
+ * a finished run's **pending-review** solutions (after
268
+ * `arrange({ autoCommit: false })`) without applying one. A no-op (returns
269
+ * `false`) when nothing is running and nothing is pending.
155
270
  *
156
- * @returns `true` when a run was cancelled, `false` when nothing was
157
- * running.
271
+ * @returns `true` when a run was cancelled or pending solutions were
272
+ * discarded, `false` when there was nothing to cancel.
158
273
  * @throws When plugin writes are disabled.
159
274
  *
160
275
  * @examplePrompt Cancel the arrange
@@ -180,11 +295,13 @@ export abstract class PluginProgramLayoutApi {
180
295
  * | `spaceIds` | `string[] \| undefined` | Component ids of the Room masses to lay out |
181
296
  * | `departmentIds` | `string[] \| undefined` | Component ids of the Department masses to lay out |
182
297
  * | `envelopeId` | `string \| undefined` | The envelope to fit into — a mass component id or a buildable-envelope handle (`be_…`); omit to auto-detect the single envelope on the active storey |
298
+ * | `autoCommit` | `boolean \| undefined` | `arrange` only — `true` / omitted (default) auto-commits the first candidate solution; `false` holds the candidates for review via {@linkcode PluginProgramLayoutApi.applySolution}. Ignored by `pack` (it applies its single result directly) |
183
299
  */
184
300
  export const PluginProgramLayoutRunArgs = z.object({
185
301
  spaceIds: z.array(z.string()).optional(),
186
302
  departmentIds: z.array(z.string()).optional(),
187
303
  envelopeId: z.string().optional(),
304
+ autoCommit: z.boolean().optional(),
188
305
  })
189
306
  export type PluginProgramLayoutRunArgs = z.infer<
190
307
  typeof PluginProgramLayoutRunArgs
@@ -217,11 +334,13 @@ export type PluginProgramLayoutRunResult = z.infer<
217
334
  * | `"running"` | A run is in flight — keep polling |
218
335
  * | `"active"` | The run finished and its layout is applied to the model |
219
336
  * | `"inactive"` | A run finished without applying a layout (the solver failed or found no solution) |
337
+ * | `"pendingReview"` | An `arrange({ autoCommit: false })` run finished and its candidate solutions await {@linkcode PluginProgramLayoutApi.applySolution} / {@linkcode PluginProgramLayoutApi.cancel} |
220
338
  */
221
339
  export const PluginProgramLayoutJobStatus = z.enum([
222
340
  "running",
223
341
  "active",
224
342
  "inactive",
343
+ "pendingReview",
225
344
  ])
226
345
  export type PluginProgramLayoutJobStatus = z.infer<
227
346
  typeof PluginProgramLayoutJobStatus
@@ -232,10 +351,12 @@ export type PluginProgramLayoutJobStatus = z.infer<
232
351
  *
233
352
  * | Property | Type | Description |
234
353
  * |---|---|---|
235
- * | `status` | {@linkcode PluginProgramLayoutJobStatus} | `"running"` \| `"active"` \| `"inactive"` |
354
+ * | `status` | {@linkcode PluginProgramLayoutJobStatus} | `"running"` \| `"active"` \| `"inactive"` \| `"pendingReview"` |
355
+ * | `totalSolutions` | `number \| undefined` | Number of candidate solutions awaiting review — present only while `status` is `"pendingReview"` |
236
356
  */
237
357
  export const PluginProgramLayoutJobState = z.object({
238
358
  status: PluginProgramLayoutJobStatus,
359
+ totalSolutions: z.number().int().optional(),
239
360
  })
240
361
  export type PluginProgramLayoutJobState = z.infer<
241
362
  typeof PluginProgramLayoutJobState
@@ -250,3 +371,52 @@ export const PluginProgramLayoutStateResult =
250
371
  export type PluginProgramLayoutStateResult = z.infer<
251
372
  typeof PluginProgramLayoutStateResult
252
373
  >
374
+
375
+ /**
376
+ * Arguments for {@linkcode PluginProgramLayoutApi.applySolution}.
377
+ *
378
+ * | Property | Type | Description |
379
+ * |---|---|---|
380
+ * | `index` | `number` | 0-based index of the pending solution to apply (`0 ≤ index < totalSolutions`) |
381
+ */
382
+ export const PluginProgramLayoutApplySolutionArgs = z.object({
383
+ index: z.number().int().min(0),
384
+ })
385
+ export type PluginProgramLayoutApplySolutionArgs = z.infer<
386
+ typeof PluginProgramLayoutApplySolutionArgs
387
+ >
388
+
389
+ /**
390
+ * Result of {@linkcode PluginProgramLayoutApi.applySolution}.
391
+ *
392
+ * | Property | Type | Description |
393
+ * |---|---|---|
394
+ * | `success` | `boolean` | Whether the chosen solution was applied |
395
+ * | `error` | `string \| undefined` | Failure reason when `success` is `false` |
396
+ */
397
+ export const PluginProgramLayoutApplyResult = z.object({
398
+ success: z.boolean(),
399
+ error: z.string().optional(),
400
+ })
401
+ export type PluginProgramLayoutApplyResult = z.infer<
402
+ typeof PluginProgramLayoutApplyResult
403
+ >
404
+
405
+ /**
406
+ * Result of {@linkcode PluginProgramLayoutApi.stack} — reports whether the
407
+ * cross-storey stack was applied and which storeys were skipped.
408
+ *
409
+ * | Property | Type | Description |
410
+ * |---|---|---|
411
+ * | `success` | `boolean` | Whether the stack was applied |
412
+ * | `skippedStoreys` | `number[]` | Storey values that had departments but no envelope, so nothing was packed there |
413
+ * | `error` | `string \| undefined` | Failure reason when `success` is `false` |
414
+ */
415
+ export const PluginProgramLayoutStackResult = z.object({
416
+ success: z.boolean(),
417
+ skippedStoreys: z.array(z.number()),
418
+ error: z.string().optional(),
419
+ })
420
+ export type PluginProgramLayoutStackResult = z.infer<
421
+ typeof PluginProgramLayoutStackResult
422
+ >
@@ -6,8 +6,9 @@ import { PluginAreaUnit } from "./metrics"
6
6
  * Program site — read the planning context of the project's site/plot.
7
7
  *
8
8
  * The **site** is the set of plot/parcel footprints the program is planned
9
- * against: their total area, per-parcel footprints (in scene XZ coordinates),
10
- * andwhen the project is geo-located on terrain their geographic
9
+ * against: their total area, per-parcel footprints (world XZ plan coordinates
10
+ * in Snaptrude units — the same plan space as a space's `planPoints`), and —
11
+ * when the project is geo-located on terrain — their geographic
11
12
  * (latitude/longitude) rings. This is the program-planning view of the site;
12
13
  * zoning numbers (setbacks, FAR/FSI, height limits) live in the site-analysis
13
14
  * sheet and are not read here.
@@ -64,7 +65,8 @@ export abstract class PluginProgramSiteApi {
64
65
  public abstract getArea(): PluginApiReturn<PluginProgramSiteAreaResult>
65
66
 
66
67
  /**
67
- * List the site parcels with their footprints (in scene coordinates).
68
+ * List the site parcels with their footprints (world XZ plan coordinates,
69
+ * Snaptrude units).
68
70
  *
69
71
  * @returns A {@linkcode PluginProgramSiteListPolygonsResult} with each parcel's
70
72
  * id, area, label, and 2D footprint (XZ ground-plane points). Empty when the
@@ -88,7 +90,7 @@ export abstract class PluginProgramSiteApi {
88
90
  *
89
91
  * Only available when the project is geo-located on terrain; returns `[]` (no
90
92
  * rings) otherwise. Use {@linkcode PluginProgramSiteApi.listPolygons} for the
91
- * scene-coordinate footprints that are always available.
93
+ * world-coordinate footprints that are always available.
92
94
  *
93
95
  * @returns A {@linkcode PluginProgramSiteListGeoPolygonsResult} with one ring
94
96
  * of `{ lat, lng, alt }` points per parcel.
@@ -184,16 +186,67 @@ export abstract class PluginProgramSiteApi {
184
186
  * ```
185
187
  */
186
188
  public abstract getNorthAngle(): PluginApiReturn<PluginProgramSiteNorthAngleResult>
189
+
190
+ /**
191
+ * Get the IANA timezone of the project's geographic location.
192
+ *
193
+ * The timezone identifier (e.g. `"America/New_York"`, `"Asia/Kolkata"`)
194
+ * looked up from the same geo-location
195
+ * {@linkcode PluginProgramSiteApi.getLocation} returns. Returns `null` when
196
+ * the project is not geo-located on terrain.
197
+ *
198
+ * @returns A {@linkcode PluginProgramSiteTimezoneResult} — the IANA timezone
199
+ * id string, or `null` when the project has no geo-located site.
200
+ *
201
+ * @examplePrompt What timezone is this project in?
202
+ * @examplePrompt Get the site's IANA timezone
203
+ * @examplePrompt What's the local time zone at the project location?
204
+ * @examplePrompt Which timezone should I use for the sun study schedule?
205
+ *
206
+ * # Example
207
+ * ```ts
208
+ * const timezone = await snaptrude.program.site.getTimezone()
209
+ * if (timezone) console.log(`Project timezone: ${timezone}`)
210
+ * ```
211
+ */
212
+ public abstract getTimezone(): PluginApiReturn<PluginProgramSiteTimezoneResult>
213
+
214
+ /**
215
+ * Get the weather file resolved for the project site.
216
+ *
217
+ * A lightweight read of the EPW weather file the `analysis.*` sun and
218
+ * daylight studies compute against — its catalog id, station name, content
219
+ * checksum, and how it was selected. This is the same file (same
220
+ * `weatherFileId`) that {@linkcode PluginAnalysisWeatherApi.getSeries} reads
221
+ * rows from and that a daylight run echoes in its provenance. Returns `null`
222
+ * when the project has no geo-located site (no weather file to resolve).
223
+ *
224
+ * @returns A {@linkcode PluginProgramSiteWeatherResult} —
225
+ * `{ weatherFileId, station, checksum, selectionMethod }`, or `null` when
226
+ * the project has no geo-located site.
227
+ *
228
+ * @examplePrompt Which weather file is my project using?
229
+ * @examplePrompt What EPW station was resolved for this site?
230
+ * @examplePrompt Get the weather file id for the daylight analysis
231
+ *
232
+ * # Example
233
+ * ```ts
234
+ * const weather = await snaptrude.program.site.getWeather()
235
+ * if (weather) console.log(weather.station, weather.selectionMethod)
236
+ * ```
237
+ */
238
+ public abstract getWeather(): PluginApiReturn<PluginProgramSiteWeatherResult>
187
239
  }
188
240
 
189
241
  /**
190
- * A 2D ground-plane point of a site parcel footprint, in scene coordinates
191
- * (metres on the project's XZ plane).
242
+ * A 2D ground-plane point of a site parcel footprint, in world XZ plan
243
+ * coordinates (Snaptrude units) the same plan space as a space's
244
+ * `planPoints`, so site parcels overlay space footprints directly.
192
245
  *
193
246
  * | Property | Type | Description |
194
247
  * |---|---|---|
195
- * | `x` | `number` | X coordinate (scene metres) |
196
- * | `z` | `number` | Z coordinate (scene metres) |
248
+ * | `x` | `number` | X coordinate (world, Snaptrude units) |
249
+ * | `z` | `number` | Z coordinate (world, Snaptrude units) |
197
250
  */
198
251
  export const PluginSiteFootprintPoint = z.object({
199
252
  x: z.number(),
@@ -417,3 +470,48 @@ export const PluginProgramSiteNorthAngleResult = z.number().nullable()
417
470
  export type PluginProgramSiteNorthAngleResult = z.infer<
418
471
  typeof PluginProgramSiteNorthAngleResult
419
472
  >
473
+
474
+ /**
475
+ * Result of {@linkcode PluginProgramSiteApi.getTimezone} — the IANA timezone
476
+ * id of the project's geo-location (e.g. `"Europe/London"`), or `null` when
477
+ * the project is not geo-located.
478
+ */
479
+ export const PluginProgramSiteTimezoneResult = z.string().nullable()
480
+ export type PluginProgramSiteTimezoneResult = z.infer<
481
+ typeof PluginProgramSiteTimezoneResult
482
+ >
483
+
484
+ /**
485
+ * A summary of the weather file resolved for the project site. Matches the
486
+ * relevant fields of `analysis.weather`'s `PluginWeatherSourceMeta`;
487
+ * `selectionMethod` is one of `"nearest-station"`, `"user-upload"`, or
488
+ * `"project-override"`.
489
+ *
490
+ * | Property | Type | Description |
491
+ * |---|---|---|
492
+ * | `weatherFileId` | `string` | Catalog id (same key as `core.io.import.epw`) |
493
+ * | `station` | `string` | Station/file name |
494
+ * | `checksum` | `string` | sha256 of the EPW file |
495
+ * | `selectionMethod` | `"nearest-station" \| "user-upload" \| "project-override"` | How the file was matched |
496
+ */
497
+ export const PluginProgramSiteWeather = z.object({
498
+ weatherFileId: z.string(),
499
+ station: z.string(),
500
+ checksum: z.string(),
501
+ selectionMethod: z.enum([
502
+ "nearest-station",
503
+ "user-upload",
504
+ "project-override",
505
+ ]),
506
+ })
507
+ export type PluginProgramSiteWeather = z.infer<typeof PluginProgramSiteWeather>
508
+
509
+ /**
510
+ * Result of {@linkcode PluginProgramSiteApi.getWeather} — the resolved weather
511
+ * file summary, or `null` when the project has no geo-located site.
512
+ */
513
+ export const PluginProgramSiteWeatherResult =
514
+ PluginProgramSiteWeather.nullable()
515
+ export type PluginProgramSiteWeatherResult = z.infer<
516
+ typeof PluginProgramSiteWeatherResult
517
+ >