@ngis/plugin-ui 0.4.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 (79) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +25 -0
  3. package/dist/index.cjs +71 -0
  4. package/dist/index.d.ts +114 -0
  5. package/dist/index.mjs +69 -0
  6. package/dist/src/api/analysis.d.ts +140 -0
  7. package/dist/src/api/resources.d.ts +530 -0
  8. package/dist/src/api/scenes.d.ts +251 -0
  9. package/dist/src/api/users.d.ts +22 -0
  10. package/dist/src/api/workflows.d.ts +191 -0
  11. package/dist/src/components/plugin-ui/AttributeTable.d.ts +26 -0
  12. package/dist/src/components/plugin-ui/BatchTable.d.ts +47 -0
  13. package/dist/src/components/plugin-ui/ChartCanvas.d.ts +14 -0
  14. package/dist/src/components/plugin-ui/ExtentPicker.d.ts +22 -0
  15. package/dist/src/components/plugin-ui/FieldSelect.d.ts +23 -0
  16. package/dist/src/components/plugin-ui/Flow.d.ts +256 -0
  17. package/dist/src/components/plugin-ui/ModelSelect.d.ts +36 -0
  18. package/dist/src/components/plugin-ui/ParamForm.d.ts +63 -0
  19. package/dist/src/components/plugin-ui/PickerField.d.ts +52 -0
  20. package/dist/src/components/plugin-ui/ResourceSelect.d.ts +37 -0
  21. package/dist/src/components/plugin-ui/ResultActions.d.ts +48 -0
  22. package/dist/src/components/plugin-ui/RunButton.d.ts +49 -0
  23. package/dist/src/components/plugin-ui/StatChart.d.ts +66 -0
  24. package/dist/src/components/plugin-ui/TaskChrome.d.ts +35 -0
  25. package/dist/src/components/plugin-ui/TaskList.d.ts +29 -0
  26. package/dist/src/components/plugin-ui/TaskStatus.d.ts +55 -0
  27. package/dist/src/components/plugin-ui/batch-model.d.ts +442 -0
  28. package/dist/src/components/plugin-ui/flow-inputs.d.ts +61 -0
  29. package/dist/src/components/plugin-ui/flow-model.d.ts +303 -0
  30. package/dist/src/components/plugin-ui/flow-ports.d.ts +155 -0
  31. package/dist/src/components/plugin-ui/param-form-data.d.ts +122 -0
  32. package/dist/src/components/plugin-ui/param-form-model.d.ts +187 -0
  33. package/dist/src/components/plugin-ui/param-widgets.d.ts +88 -0
  34. package/dist/src/components/plugin-ui/picker-data.d.ts +141 -0
  35. package/dist/src/components/plugin-ui/picker-model.d.ts +150 -0
  36. package/dist/src/components/plugin-ui/recipe-model.d.ts +320 -0
  37. package/dist/src/components/plugin-ui/result-data.d.ts +112 -0
  38. package/dist/src/components/plugin-ui/result-model.d.ts +96 -0
  39. package/dist/src/components/plugin-ui/run-data.d.ts +118 -0
  40. package/dist/src/components/plugin-ui/run-model.d.ts +179 -0
  41. package/dist/src/components/plugin-ui/stat-chart-model.d.ts +168 -0
  42. package/dist/src/components/plugin-ui/validation-messages.d.ts +18 -0
  43. package/dist/src/components/plugin-ui/w2-contracts.d.ts +151 -0
  44. package/dist/src/components/plugin-ui/w3-contracts.d.ts +328 -0
  45. package/dist/src/components/plugin-ui/w4-contracts.d.ts +510 -0
  46. package/dist/src/components/ui/button.d.ts +12 -0
  47. package/dist/src/components/ui/checkbox.d.ts +4 -0
  48. package/dist/src/components/ui/column-resize-handle.d.ts +23 -0
  49. package/dist/src/components/ui/dropdown-menu.d.ts +25 -0
  50. package/dist/src/components/ui/input.d.ts +3 -0
  51. package/dist/src/components/ui/label.d.ts +4 -0
  52. package/dist/src/components/ui/popover.d.ts +10 -0
  53. package/dist/src/components/ui/select.d.ts +15 -0
  54. package/dist/src/components/ui/switch.d.ts +6 -0
  55. package/dist/src/domain/map/types.d.ts +128 -0
  56. package/dist/src/features/gis/components/GisAttributeTable.d.ts +56 -0
  57. package/dist/src/features/gis/hooks/useDatasetFeatureWindow.d.ts +51 -0
  58. package/dist/src/lib/api-error.d.ts +81 -0
  59. package/dist/src/lib/api.d.ts +82 -0
  60. package/dist/src/lib/auth-session.d.ts +22 -0
  61. package/dist/src/lib/hooks/useColumnResize.d.ts +57 -0
  62. package/dist/src/lib/raster-color-layer/RasterColorLayer.d.ts +48 -0
  63. package/dist/src/lib/raster-color-layer/TileGrid.d.ts +31 -0
  64. package/dist/src/lib/raster-color-layer/colorRamp.d.ts +18 -0
  65. package/dist/src/lib/raster-color-layer/shaders/raster-color.frag.d.ts +2 -0
  66. package/dist/src/lib/raster-color-layer/shaders/raster-color.vert.d.ts +2 -0
  67. package/dist/src/lib/raster-color-layer/zoomInterpolate.d.ts +2 -0
  68. package/dist/src/lib/utils.d.ts +2 -0
  69. package/dist/src/sdk/facets/types.d.ts +370 -0
  70. package/dist/src/sdk/host-api.d.ts +256 -0
  71. package/dist/src/sdk/map-api.d.ts +288 -0
  72. package/dist/src/sdk/panels.d.ts +130 -0
  73. package/dist/src/types/analysis.d.ts +205 -0
  74. package/dist/src/types/common.d.ts +17 -0
  75. package/dist/src/types/extensions.d.ts +560 -0
  76. package/dist/src/types/gis.d.ts +242 -0
  77. package/dist/src/types/market-social.d.ts +378 -0
  78. package/dist/src/types/workflow.d.ts +83 -0
  79. package/package.json +59 -0
@@ -0,0 +1,370 @@
1
+ /**
2
+ * Stage 13 (capability contract) — the frozen type text for the four **core**
3
+ * 0.4 facets: `scene`, `resources`, `models`, `tasks`.
4
+ *
5
+ * Every interface below is **F13.2 verbatim**
6
+ * (`docs/capability_contract_stage/README.md` → "Frozen contracts (X0)").
7
+ * Signature text is the contract; the JSDoc here is richer than the frozen
8
+ * text, never narrower. A session that needs a change here stops and raises
9
+ * it — it does not diverge locally, because XB1's validator tests and X4's
10
+ * parser tests must round-trip the *same* fixtures.
11
+ *
12
+ * **Worker-readiness (L6, binding on every signature).** Every method is
13
+ * `async` and takes/returns JSON-serializable values; every observation is a
14
+ * subscription returning the existing synchronous `NgisUnsubscribe`. The one
15
+ * handle-returning method here (`tasks.watch`) returns an object whose members
16
+ * are themselves async — proxyable as an RPC handle. No facet ever returns a
17
+ * DOM node, a React element, a class instance, or a function other than
18
+ * `NgisUnsubscribe`.
19
+ *
20
+ * No runtime *imports*, so a worker/RPC tier can consume the contract without
21
+ * pulling the host's implementation in with it. Stage 14's W1 kickoff adds two
22
+ * runtime *exports* — `NGIS_DATA_TYPES` and `NGIS_DATA_TYPE_TO_RESOURCE_TYPES`
23
+ * (F14.1 puts them in this file by name) — which are self-contained frozen data
24
+ * and preserve that property.
25
+ *
26
+ * ## Stage 14 (F14.1, F14.3) — kickoff-authored, read-only to W1 sessions
27
+ *
28
+ * The canonical `NgisDataType` vocabulary and the three additive `models` legs
29
+ * plus `viz.chart` were authored at the **W1 kickoff**
30
+ * (`docs/components_flow_stage/README.md` → F14.24). **No F13.2 member
31
+ * changes.** A session that needs a change here stops and raises it.
32
+ */
33
+ import type { AnalysisToolSchema } from "../../api/analysis";
34
+ import type { SceneType } from "../../api/scenes";
35
+ import type { NgisExecutionValidation, NgisToolUiSchema } from "../../types/analysis";
36
+ import type { NgisBounds, NgisUnsubscribe } from "../map-api";
37
+ export interface NgisSceneInfo {
38
+ id: string;
39
+ name: string;
40
+ /** `"MAP" | "ANALYSIS" | "GIS"` — `SceneType` from `src/api/scenes.ts`. */
41
+ type: SceneType;
42
+ ownerId: string | null;
43
+ /** Drives `storage.scene` writability and the `scene.isOwner` context key. */
44
+ isOwner: boolean;
45
+ resourceCount: number;
46
+ layerCount: number;
47
+ }
48
+ export interface NgisSceneFacet {
49
+ /** `null` on an unsaved scratch workspace — boot-payload plugins still run there. */
50
+ get(): Promise<NgisSceneInfo | null>;
51
+ onChange(listener: (scene: NgisSceneInfo | null) => void): NgisUnsubscribe;
52
+ }
53
+ /**
54
+ * XD7. `"table"` is in the union for forward compatibility and is **never
55
+ * emitted in v1** — see F13.6.
56
+ *
57
+ * Classification is `DatasetInfo.datasetType`: `VECTOR`→`vector`,
58
+ * `RASTER`→`raster`, everything else **including `GENERIC`**→`file`. Producing
59
+ * `"table"` would need `NgisFile.fileType`, i.e. a second
60
+ * `GET /api/files/{fileId}` per resource — an N+1 fan-out for a distinction no
61
+ * v1 consumer needs.
62
+ */
63
+ export type NgisResourceType = "vector" | "raster" | "table" | "file";
64
+ /**
65
+ * **The one wire vocabulary for port and parameter data types (F14.1).**
66
+ *
67
+ * Six vocabularies existed; this one is canonical from here on, and it is
68
+ * **lowercase** — which makes {@link NgisResourceType} a strict subset, so no
69
+ * shipped plugin, no shipped `when` expression and no shipped fixture changes.
70
+ * {@link NgisResourceType} is **not** widened: it classifies *scene resources*,
71
+ * and `DatasetInfo.datasetType` produces only `VECTOR`/`RASTER`/everything-else.
72
+ *
73
+ * Canonicalization is **case- and separator-insensitive**: lowercase, strip
74
+ * `_`, `-` and spaces, then match. `"Point Cloud"`, `"point_cloud"` and
75
+ * `"POINTCLOUD"` all canonicalize to `pointcloud`; `null`/absent → `file`.
76
+ *
77
+ * | canonical | BE `x-data-type` | binding-validation | classified as | workflow slot `dataType` |
78
+ * |---|---|---|---|---|
79
+ * | `raster` | `Raster` | `RASTER` | `raster` | `Raster` |
80
+ * | `vector` | `Vector` | `VECTOR` | `vector` | `Vector` |
81
+ * | `table` | `Table` | `TABLE` | `file` | `Table` |
82
+ * | `pointcloud` | `PointCloud` | `POINTCLOUD` | `file` | `PointCloud` |
83
+ * | `raster3d` | `Raster3D` | `RASTER` | `raster` \| `file` | `Raster3D` |
84
+ * | `file` | `File` (or absent) | `FILE` | any | `File` |
85
+ *
86
+ * **The last column is Pascal and that is not cosmetic.**
87
+ * `WorkflowTypeCheckService.compatible` is case-sensitive `String.equals`, so
88
+ * writing `"raster"` into a `ToolInputSlot.dataType` silently fails type-check
89
+ * against a builtin node's `"Raster"` and `400`s at workflow save. Y6 applies
90
+ * that column at, and **only** at, the `ngis-workflow` boundary. Nowhere else
91
+ * in either repo is Pascal correct.
92
+ */
93
+ export type NgisDataType = "raster" | "vector" | "table" | "pointcloud" | "raster3d" | "file";
94
+ export declare const NGIS_DATA_TYPES: readonly ["raster", "vector", "table", "pointcloud", "raster3d", "file"];
95
+ /**
96
+ * **Frozen (F14.1).** How a requested data type resolves to the resource types
97
+ * v1 can actually classify.
98
+ *
99
+ * `table` stays reserved and **unemitted** in `resources.types` and in
100
+ * `NgisResourceSummary.type` through Stage 14 (XD7 unchanged) — producing it
101
+ * needs `NgisFile.fileType`, an N+1 `GET /api/files/{fileId}`, and the
102
+ * server-side alternative lives in `ngis-scene`/`ngis-file`, which no Stage 14
103
+ * backend session owns. So `'table' in resources.types` is permanently false
104
+ * and stays on the grep-proof list.
105
+ *
106
+ * **But `table` is legal in a `types={…}` prop**, because that prop speaks
107
+ * `NgisDataType`, not `NgisResourceType`. A widened request (`table`,
108
+ * `pointcloud`, `raster3d`) must be **surfaced, never silent**: `ResourceSelect`
109
+ * renders `GIS.pluginUi.pick.widened` naming the requested type and the types
110
+ * actually listed. Refusals and approximations are surfaced, not masked.
111
+ */
112
+ export declare const NGIS_DATA_TYPE_TO_RESOURCE_TYPES: Readonly<Record<NgisDataType, readonly NgisResourceType[]>>;
113
+ export interface NgisResourceSummary {
114
+ /** Scene-resource id (`SceneResourceDto.id`), not a file id. */
115
+ id: string;
116
+ sceneId: string;
117
+ name: string;
118
+ /** `SceneResourceDto.effectiveFileId` — the id every dataset API takes. */
119
+ fileId: string;
120
+ type: NgisResourceType;
121
+ /** `DatasetInfo.status` verbatim (`PENDING|PROCESSING|DONE|FAILED|NOT_REGISTERED|N/A`).
122
+ * Passed through, never collapsed: a plugin must be able to tell "not ready"
123
+ * from "failed". */
124
+ datasetStatus: string;
125
+ /**
126
+ * Whether the scene service could resolve the cached Dataset summary. A
127
+ * resource whose metadata is unavailable or missing is not type-matchable.
128
+ */
129
+ metadataState: NgisResourceMetadataState;
130
+ geometryType: string | null;
131
+ layerCount: number;
132
+ rendered: boolean;
133
+ /**
134
+ * Scene layers that render this resource, when the host can supply them.
135
+ *
136
+ * A resource is still the data identity and {@link fileId} is still the
137
+ * value tools submit. These are deliberately a display projection so a
138
+ * picker can let a person choose the layer they recognise without leaking a
139
+ * layer id into a file-typed tool parameter. `undefined` preserves the
140
+ * v0.4 source contract for hosts that cannot enumerate scene layers yet.
141
+ */
142
+ layers?: readonly NgisResourceLayer[];
143
+ }
144
+ /** A data-backed scene layer, projected for resource-picking UI. */
145
+ export interface NgisResourceLayer {
146
+ /** `NgisSceneLayer.id`; unique even when several layers share one file. */
147
+ id: string;
148
+ name: string;
149
+ /** Scene render-layer type (for example `MAPLIBRE_FILL`), if known. */
150
+ layerType: string | null;
151
+ /** A hidden layer remains selectable, but is labelled honestly in the UI. */
152
+ visible: boolean;
153
+ /** Parent group names from root to leaf, when the host exposes groups. */
154
+ groupPath?: string | null;
155
+ }
156
+ /** Scene-resource summary freshness from `GET /api/scenes/{sceneId}/resources`. */
157
+ export type NgisResourceMetadataState = "AVAILABLE" | "MISSING" | "UNAVAILABLE" | "UNKNOWN";
158
+ export interface NgisResourceField {
159
+ name: string;
160
+ type: string;
161
+ }
162
+ export interface NgisResourceDetail extends NgisResourceSummary {
163
+ srid: number | null;
164
+ /** Vector only; `null` otherwise. */
165
+ featureCount: number | null;
166
+ /** Vector only; `[]` otherwise. */
167
+ fields: readonly NgisResourceField[];
168
+ /** Raster only; `null` otherwise. */
169
+ bandCount: number | null;
170
+ bbox: NgisBounds | null;
171
+ }
172
+ export interface NgisResourceValueCount {
173
+ value: string | number | boolean | null;
174
+ count: number;
175
+ }
176
+ /** A field's most frequent values, projected as plain worker-safe data. */
177
+ export interface NgisResourceFieldValues {
178
+ field: string;
179
+ type: string;
180
+ totalCount: number;
181
+ uniqueCount: number;
182
+ truncated: boolean;
183
+ values: readonly NgisResourceValueCount[];
184
+ }
185
+ export interface NgisResourcesFacet {
186
+ list(filter?: {
187
+ types?: readonly NgisResourceType[];
188
+ /** Refresh the scene service's persisted, bounded resource summaries. */
189
+ refresh?: boolean;
190
+ }): Promise<NgisResourceSummary[]>;
191
+ get(resourceId: string): Promise<NgisResourceDetail | null>;
192
+ /** Read field frequencies for a dataset file. `resources:read`. */
193
+ fieldValues?(fileId: string, field: string, limit?: number): Promise<NgisResourceFieldValues>;
194
+ onChange(listener: () => void): NgisUnsubscribe;
195
+ }
196
+ export interface NgisModelSummary {
197
+ id: string;
198
+ name: string;
199
+ /** `"workflow"` selects the WORKFLOW branch inside `tasks.run`; anything else
200
+ * (including `null`) is DIRECT. */
201
+ provider: string | null;
202
+ category: string | null;
203
+ description: string | null;
204
+ enabled: boolean;
205
+ modelboxId: string | null;
206
+ /** Stage 16. **Never** project id, revision id or any other runtime provenance —
207
+ * the shared-consumer detail endpoint deliberately withholds those. */
208
+ compatibilityStatus: string | null;
209
+ }
210
+ export interface NgisModelboxNode {
211
+ id: string;
212
+ name: string;
213
+ provider: string | null;
214
+ parentId: string | null;
215
+ children: readonly NgisModelboxNode[];
216
+ }
217
+ /**
218
+ * `AnalysisToolSchema` passed through unmodified — including `x-role`,
219
+ * `x-data-type` and every other `x-` key. v1 does **not** normalize it;
220
+ * one normalized UI schema is Stage 14 Y1 (design-v2 §8 item 4).
221
+ *
222
+ * XD19 makes normalizing `tool_schema` a **prohibition** for this stage, not a
223
+ * deferral: the object handed to a plugin is the response body itself.
224
+ */
225
+ export type NgisModelSchema = AnalysisToolSchema;
226
+ /**
227
+ * `host.models.validate` request. Camel-cased at the facet boundary like every
228
+ * other F13.2 request type; the facade snake-cases it onto
229
+ * `POST /api/analysis/tools/{toolId}/validate-execution`.
230
+ *
231
+ * `ownerId` is deliberately absent: it comes from the authenticated caller and
232
+ * is **never** read from a body.
233
+ */
234
+ export interface NgisModelValidateRequest {
235
+ toolId: string;
236
+ expectedToolVersion?: number;
237
+ bindings?: readonly {
238
+ portName: string;
239
+ fileIds: readonly string[];
240
+ }[];
241
+ params?: Readonly<Record<string, string>>;
242
+ sceneId?: string;
243
+ /** Lab-scene optimistic fence. Omitted for ordinary scenes. */
244
+ expectedSceneGeneration?: number;
245
+ outputMode?: "ADD_LAYER" | "UPDATE_RESOURCE";
246
+ targetResourceId?: string;
247
+ targetSrid?: number;
248
+ }
249
+ export interface NgisModelSearchRequest {
250
+ query?: string;
251
+ /** Server default 10, server maximum 50. */
252
+ limit?: number;
253
+ providers?: readonly string[];
254
+ kinds?: readonly string[];
255
+ inputTypes?: readonly NgisDataType[];
256
+ outputTypes?: readonly NgisDataType[];
257
+ }
258
+ /**
259
+ * One hit from `host.models.search` — the camel-cased facet projection of
260
+ * `ToolSearchResult`.
261
+ *
262
+ * **Note the deliberate asymmetry with `validate`,** which returns
263
+ * `NgisExecutionValidation` — the snake_case response DTO **verbatim**, because
264
+ * F14.3 says so: its field names are the client's contract with the proto and
265
+ * re-spelling them would be a second normalization of the very thing YB2 is
266
+ * projecting. `search` has no such constraint, so it follows F13.2's
267
+ * `NgisModelSummary` shape instead and stays a *summary*, not a wire echo.
268
+ *
269
+ * `inputTypes`/`outputTypes` are canonicalized to {@link NgisDataType} by the
270
+ * facade; the wire carries the search-meta strings.
271
+ */
272
+ export interface NgisModelSearchResult {
273
+ toolId: string;
274
+ version: number;
275
+ kind: string;
276
+ name: string;
277
+ provider: string | null;
278
+ summary: string | null;
279
+ domains: readonly string[];
280
+ operationTypes: readonly string[];
281
+ inputTypes: readonly NgisDataType[];
282
+ outputTypes: readonly NgisDataType[];
283
+ modelboxPath: string | null;
284
+ score: number;
285
+ }
286
+ export interface NgisModelsFacet {
287
+ /** F13.2, unchanged. `query` filters the list responses client-side on
288
+ * name/description; the facet-level {@link NgisModelsFacet.search} leg is
289
+ * the server-side facet query and is what `ModelSelect` and Flow use, because
290
+ * client-side filtering cannot express `inputTypes`/`outputTypes`. */
291
+ list(filter?: {
292
+ provider?: string;
293
+ category?: string;
294
+ modelboxId?: string;
295
+ query?: string;
296
+ }): Promise<NgisModelSummary[]>;
297
+ tree(): Promise<NgisModelboxNode[]>;
298
+ get(toolId: string): Promise<NgisModelSummary | null>;
299
+ schema(toolId: string): Promise<NgisModelSchema | null>;
300
+ /** The one normalized UI schema (F14.2). `null` when the tool or its schema
301
+ * is absent. Scope `models:read`. */
302
+ uiSchema(toolId: string): Promise<NgisToolUiSchema | null>;
303
+ /** REST projection of `ValidateToolExecution`. Returns the response DTO
304
+ * **verbatim**. Scope `models:read`, **not** `models:run` — it runs nothing,
305
+ * and returns only registry facts plus dataset metadata the caller can
306
+ * already read through `host.resources`. */
307
+ validate(request: NgisModelValidateRequest): Promise<NgisExecutionValidation>;
308
+ /** REST projection of `SearchTools`. Scope `models:read`. */
309
+ search(request: NgisModelSearchRequest): Promise<NgisModelSearchResult[]>;
310
+ }
311
+ export type NgisTaskStatus = "submitting" | "QUEUED" | "RUNNING" | "SUCCESS" | "FAILED" | "CANCELLED";
312
+ /**
313
+ * Mirrors `AnalysisTaskLifecycleStage` (`src/store/analysis-scene.ts:52-61`) —
314
+ * the reason a plugin can tell **complete from integrated**. `status: "SUCCESS"`
315
+ * with `stage: "waiting_scene_integration"` is a real, common state.
316
+ */
317
+ export type NgisTaskStage = "submitting" | "queued" | "running" | "waiting_output_datasets" | "waiting_scene_integration" | "refreshing_scene" | "success" | "failed" | "cancelled";
318
+ export interface NgisTaskRunRequest {
319
+ toolId: string;
320
+ /** The analysis API takes string-valued params; the facade does not coerce. */
321
+ params: Record<string, string>;
322
+ sceneId?: string;
323
+ /** Lab-scene optimistic fence. Omitted for ordinary scenes. */
324
+ expectedSceneGeneration?: number;
325
+ outputMode?: "ADD_LAYER" | "UPDATE_RESOURCE";
326
+ targetResourceId?: string;
327
+ }
328
+ export interface NgisTaskHandle {
329
+ /** DIRECT: the analysis task id. WORKFLOW: the workflow instance id. */
330
+ id: string;
331
+ kind: "direct" | "workflow";
332
+ }
333
+ export interface NgisTaskOutput {
334
+ name: string | null;
335
+ fileId: string | null;
336
+ primary: boolean;
337
+ }
338
+ export interface NgisTaskState {
339
+ id: string;
340
+ kind: "direct" | "workflow";
341
+ toolId: string;
342
+ status: NgisTaskStatus;
343
+ stage: NgisTaskStage;
344
+ /** DIRECT only. Workflow tools have no log stream, so this is always `[]`
345
+ * for `kind: "workflow"` — the facade does not fabricate one. */
346
+ logs: readonly string[];
347
+ error: string | null;
348
+ outputs: readonly NgisTaskOutput[];
349
+ startedAt: number;
350
+ updatedAt: number;
351
+ completedAt: number | null;
352
+ }
353
+ export interface NgisTaskWatcher {
354
+ close(): Promise<void>;
355
+ }
356
+ export interface NgisTasksFacet {
357
+ /** Branches on `NgisModelSummary.provider` inside the facade. The plugin sees
358
+ * one API and must not branch itself. */
359
+ run(request: NgisTaskRunRequest): Promise<NgisTaskHandle>;
360
+ get(taskId: string): Promise<NgisTaskState | null>;
361
+ list(filter?: {
362
+ active?: boolean;
363
+ }): Promise<NgisTaskState[]>;
364
+ /** DIRECT → the existing `analysisApi.streamTask` fetch-reader SSE transport,
365
+ * then `integration_status` polling. WORKFLOW → instance polling; **there is
366
+ * no workflow SSE** and the facade must not pretend otherwise. */
367
+ watch(taskId: string, listener: (state: NgisTaskState) => void): NgisTaskWatcher;
368
+ cancel(taskId: string): Promise<void>;
369
+ outputs(taskId: string): Promise<NgisTaskOutput[]>;
370
+ }
@@ -0,0 +1,256 @@
1
+ /**
2
+ * `NgisHostAPI` — the 0.4 host facade (Stage 13, session X2).
3
+ *
4
+ * The 0.3 map facade **keeps its name and its position**: it stays at
5
+ * `host.api`, holding exactly today's `NgisMapAPI`, and is *not* re-exported
6
+ * facet-by-facet onto the root. `host.api.layers` remains the only spelling, so
7
+ * no shipped call site moves.
8
+ *
9
+ * **XD1, amendment on record.** design-v2 §4's table spells the map leg
10
+ * `host.map`. Renaming `api` → `map` would touch every first-party plugin, the
11
+ * E7 command executor and `useRemoteExtensionPlugins`, for zero capability.
12
+ * `host.api` is the locked spelling; design-v2 §4 is amended, not implemented
13
+ * as written.
14
+ *
15
+ * **Worker-readiness (L6).** Every facet method is `async` and
16
+ * takes/returns JSON-serializable values; every observation is a subscription
17
+ * returning the synchronous `NgisUnsubscribe`. The two handle-returning methods
18
+ * (`ui.progress`, `tasks.watch`) return objects whose members are themselves
19
+ * async — proxyable as RPC handles. No facet returns a DOM node, a React
20
+ * element, a class instance, or a function other than `NgisUnsubscribe`.
21
+ *
22
+ * ## What this file owns, and what it deliberately does not
23
+ *
24
+ * X2 (W1) implements `scene` / `resources` / `models` / `tasks`. The remaining
25
+ * five slots are typed here — verbatim from F13.2, so the facade is
26
+ * type-complete from W1 — and implemented by later sessions:
27
+ *
28
+ * | slot | implementer |
29
+ * |---|---|
30
+ * | `context` | X1 (W1), `src/sdk/context/**` |
31
+ * | `viz` · `storage` · `ui` | X3 (W2), `src/sdk/facets/{viz,storage,ui}.ts` |
32
+ * | `commands` | X4 (W2), over the E7 `gisCommandRegistry` seam |
33
+ *
34
+ * Those sessions should **import** these interfaces rather than redeclare them.
35
+ * Anything omitted at construction is filled with a facet whose every member
36
+ * rejects loudly (`pendingFacet`) — never with fake empty data, which per F13.5
37
+ * is indistinguishable from a real empty scene.
38
+ */
39
+ import { type NgisMapAPI } from "./map-api";
40
+ import type { NgisBounds, NgisUnsubscribe } from "./map-api";
41
+ import type { NgisModelsFacet, NgisResourcesFacet, NgisSceneFacet, NgisTasksFacet } from "./facets/types";
42
+ export type { NgisModelSchema, NgisModelSummary, NgisModelboxNode, NgisModelsFacet, NgisResourceDetail, NgisResourceField, NgisResourceFieldValues, NgisResourceSummary, NgisResourceValueCount, NgisResourceType, NgisResourcesFacet, NgisSceneFacet, NgisSceneInfo, NgisTaskHandle, NgisTaskOutput, NgisTaskRunRequest, NgisTaskStage, NgisTaskState, NgisTaskStatus, NgisTaskWatcher, NgisTasksFacet, } from "./facets/types";
43
+ export type NgisChartKind = "bar" | "line" | "pie" | "scatter" | "histogram";
44
+ export interface NgisChartSeries {
45
+ name: string;
46
+ values: readonly number[];
47
+ }
48
+ /**
49
+ * **Declarative only (F14.3).** No DOM, no React element, no function — L6's
50
+ * worker-readiness rule (F13.1) binds every member added here, and the host is
51
+ * what renders it. A spec that carried a formatter callback or an ECharts
52
+ * option object would not survive Stage 15's worker tier.
53
+ */
54
+ export interface NgisChartSpec {
55
+ kind: NgisChartKind;
56
+ title?: string;
57
+ categories?: readonly string[];
58
+ series: readonly NgisChartSeries[];
59
+ xLabel?: string;
60
+ yLabel?: string;
61
+ }
62
+ /** F13.2 verbatim, plus F14.3's additive `chart` leg. Implemented by X3 (W2) in
63
+ * `src/sdk/facets/viz.ts`; `chart` is Y4's (W2). */
64
+ export interface NgisVizFacet {
65
+ /** Post-hoc add: registers a scene resource for `fileId` if absent, then adds a
66
+ * layer. Submit-time integration is the better path and is reached by passing
67
+ * `sceneId`/`outputMode` to `tasks.run` — this is for outputs produced without it. */
68
+ addResultLayer(options: {
69
+ fileId: string;
70
+ name?: string;
71
+ }): Promise<{
72
+ resourceId: string;
73
+ layerId: string;
74
+ }>;
75
+ /** Opens the existing attribute panel over the resource. */
76
+ openTable(resourceId: string): Promise<void>;
77
+ fit(target: {
78
+ resourceId: string;
79
+ } | {
80
+ bounds: NgisBounds;
81
+ }): Promise<void>;
82
+ /** F14.3, additive. **Ungated**, for the same reason `openTable`/`fit` are —
83
+ * it mutates nothing. Y4 (W2) implements it over `StatChart`'s renderer. */
84
+ chart(spec: NgisChartSpec): Promise<void>;
85
+ }
86
+ /** F13.2 verbatim. Implemented by X3 (W2) in `src/sdk/facets/storage.ts`;
87
+ * `NgisStorageError` is runtime code and ships with that session. */
88
+ export type NgisStorageWriteFailure = "read-only" | "too-large" | "conflict";
89
+ export interface NgisStorageLeg {
90
+ get(): Promise<unknown | null>;
91
+ /** Rejects with `NgisStorageError` (`read-only` · `too-large` · `conflict`) or
92
+ * `NgisScopeError`. Never silently no-ops. */
93
+ set(value: unknown): Promise<void>;
94
+ /** Scene leg: `false` for a non-owner viewer. User leg: always `true` while
95
+ * installed. Surfaced, never masked — a settings form must render read-only
96
+ * rather than fail on submit. */
97
+ canWrite(): Promise<boolean>;
98
+ onChange(listener: (value: unknown | null) => void): NgisUnsubscribe;
99
+ }
100
+ export interface NgisStorageFacet {
101
+ /** Per (user, extension). XB2's install-row column. */
102
+ user: NgisStorageLeg;
103
+ /** Per (scene, extension) — `extension_config.plugins[].settings`, owner-write-only. */
104
+ scene: NgisStorageLeg;
105
+ }
106
+ /**
107
+ * F13.2's `NgisContextFacet`, declared here under an `NgisHost`-prefixed name.
108
+ *
109
+ * X1 is building `src/sdk/context/**` **concurrently** in this same wave and
110
+ * owns the canonical `NgisContextFacet` / `NgisContextValue` spelling. Naming
111
+ * the slot type differently is what lets X1 and X2 merge without touching the
112
+ * same declaration; the two are structurally identical by construction (both
113
+ * are F13.2 verbatim), so X1's facet satisfies this slot as-is.
114
+ *
115
+ * At the X1→X2 rebase these two lines may collapse to
116
+ * `export type NgisHostContextFacet = NgisContextFacet;` — a mechanical change
117
+ * with no behavioural effect.
118
+ */
119
+ export type NgisHostContextValue = string | number | boolean | null | readonly (string | number)[];
120
+ export interface NgisHostContextFacet {
121
+ get(key: string): Promise<NgisHostContextValue | undefined>;
122
+ getAll(): Promise<Readonly<Record<string, NgisHostContextValue>>>;
123
+ /** Auto-namespaced to `plugin:<pluginId>:<key>` — **F14.11, as amended by
124
+ * F15.14**: the deprecated dotted `plugin.<pluginId>.<key>` spelling was
125
+ * removed in Stage 15 (W1, Z10) and is now written by nothing, so an
126
+ * expression against it names a key no publisher produces. A caller-supplied
127
+ * namespace prefix is rejected, not silently re-prefixed. */
128
+ set(key: string, value: NgisHostContextValue): Promise<void>;
129
+ /** Compiles and evaluates a when-grammar v1 expression once. */
130
+ evaluate(expression: string): Promise<boolean>;
131
+ /** Fires when any listed key changes, batched per microtask. */
132
+ onChange(keys: readonly string[], listener: (changed: Readonly<Record<string, NgisHostContextValue>>) => void): NgisUnsubscribe;
133
+ }
134
+ /** F13.2 verbatim. Implemented by X3 (W2) in `src/sdk/facets/ui.ts`. */
135
+ export interface NgisQuickPickItem {
136
+ id: string;
137
+ label: string;
138
+ description?: string;
139
+ }
140
+ export interface NgisProgressHandle {
141
+ update(patch: {
142
+ percent?: number;
143
+ message?: string;
144
+ }): Promise<void>;
145
+ done(): Promise<void>;
146
+ }
147
+ export interface NgisUiFacet {
148
+ toast(options: {
149
+ message: string;
150
+ kind?: "info" | "success" | "warning" | "error";
151
+ description?: string;
152
+ }): Promise<void>;
153
+ confirm(options: {
154
+ title: string;
155
+ description?: string;
156
+ confirmLabel?: string;
157
+ cancelLabel?: string;
158
+ destructive?: boolean;
159
+ }): Promise<boolean>;
160
+ /** Resolves to the chosen item's `id`, or `null` if dismissed. */
161
+ quickPick(options: {
162
+ title?: string;
163
+ items: readonly NgisQuickPickItem[];
164
+ }): Promise<string | null>;
165
+ progress(options: {
166
+ title: string;
167
+ }): Promise<NgisProgressHandle>;
168
+ }
169
+ /** F13.2 verbatim. Implemented by X4 (W2) over the E7 `gisCommandRegistry`. */
170
+ export interface NgisCommandSummary {
171
+ id: string;
172
+ title: string;
173
+ /** The declaring plugin — a plugin can see that a command is not its own. */
174
+ pluginId: string;
175
+ }
176
+ export interface NgisCommandsFacet {
177
+ list(): Promise<NgisCommandSummary[]>;
178
+ /** The E7 `gisCommandRegistry` seam. Cross-plugin invocation is allowed in v1
179
+ * and is **not** ordered — `pluginDependencies` activation ordering is Stage 15
180
+ * (XD15). A command whose plugin has not activated rejects. */
181
+ invoke(commandId: string, params?: Record<string, unknown>): Promise<unknown>;
182
+ }
183
+ export interface NgisHostAPI {
184
+ /** `NGIS_MAP_API_VERSION` — "0.4.0". */
185
+ readonly version: string;
186
+ /** The plugin this facade is bound to. Every facade is per-plugin: it is what
187
+ * namespaces `storage`/`context.set` and what attributes audit events. */
188
+ readonly pluginId: string;
189
+ /** **FROZEN 0.3.0 surface, ungated.** `layers` · `camera` · `selection` ·
190
+ * `draw` · `measure` · `panels` · `events` · `getMap()`. Not re-exported
191
+ * facet-by-facet onto the root: `host.api.layers` stays the only spelling,
192
+ * so no shipped call site moves. */
193
+ api: NgisMapAPI;
194
+ scene: NgisSceneFacet;
195
+ resources: NgisResourcesFacet;
196
+ models: NgisModelsFacet;
197
+ tasks: NgisTasksFacet;
198
+ viz: NgisVizFacet;
199
+ storage: NgisStorageFacet;
200
+ context: NgisHostContextFacet;
201
+ ui: NgisUiFacet;
202
+ commands: NgisCommandsFacet;
203
+ }
204
+ /**
205
+ * Back-compat alias — `activate(host: NgisPluginHost)` signatures do not change,
206
+ * and a 0.3-era plugin reading only `host.api` still type-checks and still runs.
207
+ *
208
+ * **Not yet re-exported from `@/sdk`.** `src/sdk/plugin.ts` still exports the
209
+ * 0.3 `NgisPluginHost = { api }`, and that is the name `@/sdk` re-exports today.
210
+ * Widening it is X4's atomic `NGIS_MAP_API_VERSION` → 0.4.0 flip in W2 (ED19):
211
+ * `plugin.ts`, `plugin-runtime.ts` and every host call site
212
+ * (`GisWorkspace.tsx:182` builds `{ api }`) are X4's files, and widening the
213
+ * type without them would break `tsc` across four modules X2 does not own.
214
+ */
215
+ export type NgisPluginHost = NgisHostAPI;
216
+ /**
217
+ * Thrown by every member of a facet slot that has not been wired yet. Loud on
218
+ * purpose: F13.5's refusal rule is "a typed error, never empty data", because a
219
+ * silent empty list is indistinguishable from a real empty scene.
220
+ */
221
+ export declare class NgisFacetUnavailableError extends Error {
222
+ readonly facet: string;
223
+ readonly member: string;
224
+ constructor(facet: string, member: string, owner: string);
225
+ }
226
+ export interface NgisHostAPIOptions {
227
+ pluginId: string;
228
+ /** The 0.3 facade from `createNgisMapAPI(...).api` — kept at `host.api`. */
229
+ api: NgisMapAPI;
230
+ scene: NgisSceneFacet;
231
+ resources: NgisResourcesFacet;
232
+ models: NgisModelsFacet;
233
+ tasks: NgisTasksFacet;
234
+ /** X1 (W1). Omitted until the context store is wired. */
235
+ context?: NgisHostContextFacet;
236
+ /** X3 (W2). */
237
+ viz?: NgisVizFacet;
238
+ /** X3 (W2). */
239
+ storage?: NgisStorageFacet;
240
+ /** X3 (W2). */
241
+ ui?: NgisUiFacet;
242
+ /** X4 (W2). */
243
+ commands?: NgisCommandsFacet;
244
+ /** Defaults to `NGIS_MAP_API_VERSION`. F13.13 bumps that constant to
245
+ * `"0.4.0"` in X4, atomically with its consumers (ED19) — this facade reads
246
+ * it rather than hard-coding a version that would then disagree with the
247
+ * runtime's negotiation. */
248
+ version?: string;
249
+ }
250
+ /**
251
+ * Assembles the 0.4 facade. Every facet is injected: `src/sdk/` sits below
252
+ * `src/store/`, `src/api/` and `src/features/`, so the wiring lives at the host
253
+ * call site — which is also what makes the facade worker-ready (a worker tier
254
+ * injects RPC-backed facets against the same interfaces).
255
+ */
256
+ export declare function createNgisHostAPI(options: NgisHostAPIOptions): NgisHostAPI;