@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
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import * as z from "zod"
|
|
2
|
+
import { PluginApiReturn } from "../../../../types"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Serialization format for {@link PluginCoreIoExportApi.model}.
|
|
6
|
+
*
|
|
7
|
+
* `glb` / `obj` serialize in the browser; `fbx` / `3ds` run the same server
|
|
8
|
+
* conversion the app's Export dialog uses and return a **zip** containing the
|
|
9
|
+
* converted file.
|
|
10
|
+
*/
|
|
11
|
+
export const ExportModelFormat = z.enum(["glb", "obj", "fbx", "3ds"])
|
|
12
|
+
export type ExportModelFormat = z.infer<typeof ExportModelFormat>
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* What to export: the whole model (`"scene"`, default) or only the current
|
|
16
|
+
* selection (`"selection"`).
|
|
17
|
+
*/
|
|
18
|
+
export const ExportScope = z.enum(["scene", "selection"])
|
|
19
|
+
export type ExportScope = z.infer<typeof ExportScope>
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A serialized model file returned by {@link PluginCoreIoExportApi.model}.
|
|
23
|
+
*
|
|
24
|
+
* | Property | Type | Description |
|
|
25
|
+
* |---|---|---|
|
|
26
|
+
* | `fileName` | `string` | Suggested file name incl. extension (e.g. `"model.glb"`) |
|
|
27
|
+
* | `mimeType` | `string` | MIME type (`"model/gltf-binary"` for glb, `"text/plain"` for obj) |
|
|
28
|
+
* | `dataBase64` | `string` | The file's bytes, base64-encoded (decode to save/download) |
|
|
29
|
+
*/
|
|
30
|
+
export const ExportedFile = z.object({
|
|
31
|
+
fileName: z.string(),
|
|
32
|
+
mimeType: z.string(),
|
|
33
|
+
dataBase64: z.string(),
|
|
34
|
+
})
|
|
35
|
+
export type ExportedFile = z.infer<typeof ExportedFile>
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Model export — serialize the scene (or selection) to a downloadable 3D file.
|
|
39
|
+
*
|
|
40
|
+
* `core.io.export.model` hands you the file bytes as base64 — no download
|
|
41
|
+
* dialog opens; the plugin decides what to do with the result (save it, POST
|
|
42
|
+
* it, diff it). Four formats:
|
|
43
|
+
*
|
|
44
|
+
* - `"glb"` — binary glTF (`model/gltf-binary`); geometry + materials,
|
|
45
|
+
* serialized in the browser (nothing is uploaded).
|
|
46
|
+
* - `"obj"` — Wavefront OBJ text (`text/plain`); geometry only, serialized in
|
|
47
|
+
* the browser.
|
|
48
|
+
* - `"fbx"` / `"3ds"` — Autodesk FBX / 3D Studio; the scene is uploaded to the
|
|
49
|
+
* same `/exportmodel/` conversion service the app's Export dialog uses, and
|
|
50
|
+
* the call resolves once the converted artifact is fetched back — a **zip**
|
|
51
|
+
* (`application/zip`) containing the `.fbx`/`.3ds` file. Whole-scene only
|
|
52
|
+
* (`scope: "selection"` is rejected). Conversion runs on the server and is
|
|
53
|
+
* bounded by the per-call plugin timeout (60 s) — very large models may
|
|
54
|
+
* exceed it and reject with `TIMEOUT`.
|
|
55
|
+
*
|
|
56
|
+
* For the browser formats, only real model geometry is exported (walls, slabs,
|
|
57
|
+
* roofs, floors, doors, windows, furniture, staircases, masses, ceilings,
|
|
58
|
+
* mullions, beams, columns, terrain); UI helpers, hidden objects, and
|
|
59
|
+
* hidden-bucket objects are excluded — matching the app's GLB export. The
|
|
60
|
+
* server formats convert the full serialized scene (hidden-bucket objects
|
|
61
|
+
* excluded), exactly like the Export dialog. This is a **read**: it never
|
|
62
|
+
* mutates the model.
|
|
63
|
+
*
|
|
64
|
+
* > Server-backed BIM exports (RVT / IFC / DWG) are **not** exposed here — those
|
|
65
|
+
* > run as fire-and-forget Forge jobs that stream a browser download and return
|
|
66
|
+
* > no retrievable bytes. Use the app's Export menu for those.
|
|
67
|
+
*
|
|
68
|
+
* Accessed via `snaptrude.core.io.export`.
|
|
69
|
+
*/
|
|
70
|
+
export abstract class PluginCoreIoExportApi {
|
|
71
|
+
constructor() {}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Export the model to a 3D file and return its bytes as base64.
|
|
75
|
+
*
|
|
76
|
+
* @param format - `"glb"` (binary glTF, geometry + materials), `"obj"`
|
|
77
|
+
* (Wavefront OBJ text, geometry only) — both serialized in the browser —
|
|
78
|
+
* or `"fbx"` / `"3ds"`, converted by the app's export service and returned
|
|
79
|
+
* as a zip containing the converted file.
|
|
80
|
+
* @param scope - `"scene"` (default) for the whole model, or `"selection"` for
|
|
81
|
+
* only the currently selected objects (browser formats only — `"fbx"`/`"3ds"`
|
|
82
|
+
* reject it). An empty selection yields an empty file.
|
|
83
|
+
* @returns an {@linkcode ExportedFile} — `{ fileName, mimeType, dataBase64 }`.
|
|
84
|
+
* @throws if the format is unsupported, `scope: "selection"` is combined with a
|
|
85
|
+
* server format, or the serialization/conversion fails.
|
|
86
|
+
*
|
|
87
|
+
* @examplePrompt Export the model as a GLB
|
|
88
|
+
* @examplePrompt Give me the whole scene as an OBJ file
|
|
89
|
+
* @examplePrompt Export just my selection to GLB
|
|
90
|
+
* @examplePrompt Download the model as an FBX file
|
|
91
|
+
* @examplePrompt Export the scene to 3DS for 3ds Max
|
|
92
|
+
*
|
|
93
|
+
* # Example
|
|
94
|
+
* ```ts
|
|
95
|
+
* const file = await snaptrude.core.io.export.model("glb")
|
|
96
|
+
* // decode base64 → bytes and save/download in the plugin UI
|
|
97
|
+
* const bytes = Uint8Array.from(atob(file.dataBase64), (c) => c.charCodeAt(0))
|
|
98
|
+
* const blob = new Blob([bytes], { type: file.mimeType })
|
|
99
|
+
* // ...offer blob for download as file.fileName
|
|
100
|
+
*
|
|
101
|
+
* // Only the current selection, as OBJ text:
|
|
102
|
+
* const obj = await snaptrude.core.io.export.model("obj", "selection")
|
|
103
|
+
* const text = atob(obj.dataBase64)
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
public abstract model(
|
|
107
|
+
format: ExportModelFormat,
|
|
108
|
+
scope?: ExportScope,
|
|
109
|
+
): PluginApiReturn<ExportedFile>
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Arguments for {@link PluginCoreIoExportApi.model}.
|
|
114
|
+
*
|
|
115
|
+
* | Property | Type | Description |
|
|
116
|
+
* |---|---|---|
|
|
117
|
+
* | `format` | {@link ExportModelFormat} | `"glb"`, `"obj"`, `"fbx"`, or `"3ds"` |
|
|
118
|
+
* | `scope` | {@link ExportScope} | `"scene"` (default) or `"selection"` (browser formats only) |
|
|
119
|
+
*/
|
|
120
|
+
export const PluginExportModelArgs = z.object({
|
|
121
|
+
format: ExportModelFormat,
|
|
122
|
+
scope: ExportScope.optional(),
|
|
123
|
+
})
|
|
124
|
+
export type PluginExportModelArgs = z.infer<typeof PluginExportModelArgs>
|
package/src/api/core/io/index.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { PluginCoreIoJobApi } from "./job"
|
|
|
3
3
|
import { PluginCoreIoUnderlayApi } from "./underlay"
|
|
4
4
|
import { PluginCoreIoTerrainApi } from "./terrain"
|
|
5
5
|
import { PluginCoreIoQueryApi } from "./query"
|
|
6
|
+
import { PluginCoreIoExportApi } from "./export"
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* I/O — bring external files into the project and manage what was imported.
|
|
@@ -12,6 +13,7 @@ import { PluginCoreIoQueryApi } from "./query"
|
|
|
12
13
|
* - {@linkcode PluginCoreIoApi.job} — poll long-running async imports (e.g. DWG)
|
|
13
14
|
* - {@linkcode PluginCoreIoApi.underlay} — inspect/scale/opacity/delete placed underlays
|
|
14
15
|
* - {@linkcode PluginCoreIoApi.terrain} — inspect/edit the site terrain (datum, layers, delete)
|
|
16
|
+
* - {@linkcode PluginCoreIoApi.export} — serialize the model to glb/obj (base64 bytes)
|
|
15
17
|
*
|
|
16
18
|
* Accessed via `snaptrude.core.io`.
|
|
17
19
|
*/
|
|
@@ -26,6 +28,8 @@ export abstract class PluginCoreIoApi {
|
|
|
26
28
|
public abstract underlay: PluginCoreIoUnderlayApi
|
|
27
29
|
/** Inspect and manage the site terrain. See {@linkcode PluginCoreIoTerrainApi}. */
|
|
28
30
|
public abstract terrain: PluginCoreIoTerrainApi
|
|
31
|
+
/** Serialize the model to a downloadable 3D file. See {@linkcode PluginCoreIoExportApi}. */
|
|
32
|
+
public abstract export: PluginCoreIoExportApi
|
|
29
33
|
|
|
30
34
|
constructor() {}
|
|
31
35
|
}
|
|
@@ -35,3 +39,4 @@ export * from "./job"
|
|
|
35
39
|
export * from "./underlay"
|
|
36
40
|
export * from "./terrain"
|
|
37
41
|
export * from "./query"
|
|
42
|
+
export * from "./export"
|
|
@@ -136,30 +136,70 @@ export abstract class PluginCoreProposalsApi {
|
|
|
136
136
|
public abstract isActive(proposalId: string): PluginApiReturn<boolean>
|
|
137
137
|
|
|
138
138
|
/**
|
|
139
|
-
* Create a new design option (proposal)
|
|
139
|
+
* Create a new design option (proposal) — blank, or configured from a base
|
|
140
|
+
* proposal (the New Proposal modal's two paths).
|
|
140
141
|
*
|
|
141
142
|
* **Pro-gated** (creating proposals requires a Pro plan, matching the UI) and
|
|
142
|
-
* **not undoable**.
|
|
143
|
-
*
|
|
144
|
-
*
|
|
143
|
+
* **not undoable**. The name is capped at 24 characters.
|
|
144
|
+
*
|
|
145
|
+
* **Blank** (no `options`) — creates a bare proposal with a single empty
|
|
146
|
+
* default bucket; it does **not** carry forward the current proposal's
|
|
147
|
+
* layers, views, or targets, and the active proposal does **not** change.
|
|
148
|
+
*
|
|
149
|
+
* **Configured** (`options.baseProposalId`) — the modal's Configure path:
|
|
150
|
+
* carries the base proposal's buckets (layers) forward per `options.layers`,
|
|
151
|
+
* where each entry names a bucket of the base proposal and an action —
|
|
152
|
+
* `"share"` (the new proposal references the same live bucket) or
|
|
153
|
+
* `"duplicate"` (an independent copy of the bucket and its contents).
|
|
154
|
+
* Buckets not listed are left behind. Omitting `layers` carries **every**
|
|
155
|
+
* base bucket forward as a `"duplicate"` (the modal's default). The base
|
|
156
|
+
* proposal's views and area targets are copied either way, and the new
|
|
157
|
+
* proposal becomes the **active** one (implicit switch — blocked with
|
|
158
|
+
* `PROPOSAL_SWITCH_BLOCKED` while an in-canvas agent run is in flight, like
|
|
159
|
+
* {@linkcode PluginCoreProposalsApi.setActive}).
|
|
145
160
|
*
|
|
146
161
|
* @param name - Display name of the new proposal (capped at 24 chars).
|
|
162
|
+
* @param options - Optional configure path: `baseProposalId` (the proposal to
|
|
163
|
+
* carry forward from) and `layers` (per-bucket `"share"` / `"duplicate"`
|
|
164
|
+
* actions; omitted buckets are excluded, omitted `layers` duplicates all).
|
|
147
165
|
* @returns The new proposal's id (read the full record back with
|
|
148
166
|
* {@linkcode PluginCoreProposalsApi.get}).
|
|
149
|
-
* @throws If the caller is not on a Pro plan,
|
|
150
|
-
*
|
|
167
|
+
* @throws If the caller is not on a Pro plan, the name is empty/duplicate,
|
|
168
|
+
* `layers` is passed without `baseProposalId`, the base proposal or a
|
|
169
|
+
* listed bucket does not exist / does not belong to the base proposal, or
|
|
170
|
+
* (configured only) `PROPOSAL_SWITCH_BLOCKED` while a canvas-agent run is
|
|
171
|
+
* in flight.
|
|
151
172
|
*
|
|
152
173
|
* @examplePrompt Create a design option called Scheme B
|
|
153
174
|
* @examplePrompt Add a new proposal named Option 2
|
|
154
|
-
* @examplePrompt
|
|
175
|
+
* @examplePrompt Duplicate the current proposal as Scheme C
|
|
176
|
+
* @examplePrompt Create a design option based on Proposal 1 that shares its site layer
|
|
155
177
|
*
|
|
156
178
|
* # Example
|
|
157
179
|
* ```ts
|
|
180
|
+
* // blank design option
|
|
158
181
|
* const { id } = await snaptrude.core.proposals.create("Scheme B")
|
|
182
|
+
*
|
|
183
|
+
* // configured from the active proposal: duplicate every layer
|
|
184
|
+
* const base = await snaptrude.core.proposals.getActive()
|
|
185
|
+
* if (base) {
|
|
186
|
+
* const { id: dup } = await snaptrude.core.proposals.create("Scheme C", {
|
|
187
|
+
* baseProposalId: base.id,
|
|
188
|
+
* })
|
|
189
|
+
* // …or share one layer and leave the rest behind
|
|
190
|
+
* const { id: shared } = await snaptrude.core.proposals.create("Scheme D", {
|
|
191
|
+
* baseProposalId: base.id,
|
|
192
|
+
* layers: [{ bucketId: base.defaultBucketId, action: "share" }],
|
|
193
|
+
* })
|
|
194
|
+
* }
|
|
159
195
|
* ```
|
|
160
196
|
*/
|
|
161
197
|
public abstract create(
|
|
162
198
|
name: string,
|
|
199
|
+
options?: {
|
|
200
|
+
baseProposalId: string
|
|
201
|
+
layers?: { bucketId: string; action: "share" | "duplicate" }[]
|
|
202
|
+
},
|
|
163
203
|
): PluginApiReturn<PluginCoreProposalsCreateResult>
|
|
164
204
|
|
|
165
205
|
/**
|
|
@@ -383,15 +423,35 @@ export type PluginCoreProposalsIsActiveArgs = z.infer<
|
|
|
383
423
|
>
|
|
384
424
|
|
|
385
425
|
/**
|
|
386
|
-
* Arguments for {@linkcode PluginCoreProposalsApi.create}.
|
|
426
|
+
* Arguments for {@linkcode PluginCoreProposalsApi.create}. A bare `name` makes
|
|
427
|
+
* a blank proposal; `baseProposalId` switches to the configured (carry-forward)
|
|
428
|
+
* path. `layers` requires `baseProposalId` — each entry names a bucket of the
|
|
429
|
+
* base proposal; omitted buckets are excluded, and omitting `layers` entirely
|
|
430
|
+
* duplicates every base bucket.
|
|
387
431
|
*
|
|
388
432
|
* | Property | Type | Description |
|
|
389
433
|
* |---|---|---|
|
|
390
434
|
* | `name` | `string` | Display name of the new proposal (capped at 24 chars) |
|
|
435
|
+
* | `baseProposalId` | `string \| undefined` | Proposal to carry forward from (configured path) |
|
|
436
|
+
* | `layers` | `{ bucketId: string; action: "share" \| "duplicate" }[] \| undefined` | Per-bucket carry-forward actions (requires `baseProposalId`) |
|
|
391
437
|
*/
|
|
392
|
-
export const PluginCoreProposalsCreateArgs = z
|
|
393
|
-
|
|
394
|
-
|
|
438
|
+
export const PluginCoreProposalsCreateArgs = z
|
|
439
|
+
.object({
|
|
440
|
+
name: z.string(),
|
|
441
|
+
baseProposalId: z.string().optional(),
|
|
442
|
+
layers: z
|
|
443
|
+
.array(
|
|
444
|
+
z.object({
|
|
445
|
+
bucketId: z.string(),
|
|
446
|
+
action: z.enum(["share", "duplicate"]),
|
|
447
|
+
}),
|
|
448
|
+
)
|
|
449
|
+
.optional(),
|
|
450
|
+
})
|
|
451
|
+
.refine((v) => v.layers === undefined || v.baseProposalId !== undefined, {
|
|
452
|
+
message:
|
|
453
|
+
"layers requires baseProposalId — the layers describe how to carry the base proposal's buckets forward",
|
|
454
|
+
})
|
|
395
455
|
export type PluginCoreProposalsCreateArgs = z.infer<
|
|
396
456
|
typeof PluginCoreProposalsCreateArgs
|
|
397
457
|
>
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as z from "zod"
|
|
2
|
+
import { PluginApiReturn } from "../../types"
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* User locale.
|
|
6
|
+
*
|
|
7
|
+
* Read the viewer's timezone and language — for date/number formatting and
|
|
8
|
+
* localized labels. This is locale only: NO precise geolocation, no IP, no
|
|
9
|
+
* account identity. Accessed via `snaptrude.core.user`.
|
|
10
|
+
*/
|
|
11
|
+
export abstract class PluginUserApi {
|
|
12
|
+
constructor() {}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get the viewer's locale: IANA timezone and BCP-47 language tag, resolved
|
|
16
|
+
* from the browser (`Intl.DateTimeFormat().resolvedOptions().timeZone` and
|
|
17
|
+
* `navigator.language`). Locale only — no precise location.
|
|
18
|
+
*
|
|
19
|
+
* @returns `{ timezone, language }` — e.g. `{ timezone: "Asia/Kolkata", language: "en-US" }`.
|
|
20
|
+
*
|
|
21
|
+
* @examplePrompt What timezone is the user in?
|
|
22
|
+
* @examplePrompt Get the viewer's language for localized labels
|
|
23
|
+
* @examplePrompt Format the report date in the user's local timezone
|
|
24
|
+
* @examplePrompt Which locale should I use for this plugin's UI?
|
|
25
|
+
*
|
|
26
|
+
* # Example
|
|
27
|
+
* ```ts
|
|
28
|
+
* const { timezone, language } = await snaptrude.core.user.getLocale()
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
public abstract getLocale(): PluginApiReturn<PluginUserLocale>
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The viewer's locale.
|
|
36
|
+
*
|
|
37
|
+
* | Property | Type | Description |
|
|
38
|
+
* |---|---|---|
|
|
39
|
+
* | `timezone` | `string` | IANA timezone id (e.g. `"Asia/Kolkata"`) |
|
|
40
|
+
* | `language` | `string` | BCP-47 language tag (e.g. `"en-US"`) |
|
|
41
|
+
*/
|
|
42
|
+
export const PluginUserLocale = z.object({
|
|
43
|
+
timezone: z.string(),
|
|
44
|
+
language: z.string(),
|
|
45
|
+
})
|
|
46
|
+
export type PluginUserLocale = z.infer<typeof PluginUserLocale>
|