@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,510 @@
1
+ /**
2
+ * W4 shared contracts — authored at the **W4 kickoff**, read-only to Y6 and Y7.
3
+ *
4
+ * Stage 14's wave rule, fourth application. The three previous seams froze
5
+ * *types*; this one froze types and **behaviour**, and the reason is the W3 merge:
6
+ * `w3-contracts.ts` pinned every data type the two Y5 halves exchanged and none
7
+ * of the functions, so the stub and the real core agreed on every shape and
8
+ * disagreed on four behaviours — one of which (`V-224`) submitted a **wrong run**
9
+ * rather than failing to compile. A signature is not a seam. So where W4's two
10
+ * sessions would otherwise each write the same rule, **the rule is implemented
11
+ * here once, with tests**, and neither session owns a copy:
12
+ *
13
+ * {@link ngisWorkflowDataType} — the Pascal boundary spelling (F14.1)
14
+ * {@link promotableInputs} — which in-ports become slots / columns (F14.6)
15
+ * {@link recipeColumns} — a published recipe's batch columns (F14.21)
16
+ *
17
+ * Ownership:
18
+ *
19
+ * Y6 owns the recipe serializer, the `{graph,view}` mapping, the six-leg
20
+ * publish chain and the wizard: `recipe-model.ts`, `recipe-data.ts`,
21
+ * `RecipeWizard.tsx`, plus the `workflowApi` visibility leg.
22
+ * Y7 owns the batch table: `batch-model.ts`, `BatchTable.tsx`, and the
23
+ * `ModelSelect`-onto-`models.search` upgrade inherited from YD46.
24
+ *
25
+ * Nothing here imports React, a host, or `src/api/**`. That is what keeps the
26
+ * recipe layer **host-renderable from declarative data** — the property Stage 15's
27
+ * worker tier depends on, and the reason a recipe is data and not code.
28
+ *
29
+ * **Not re-exported from either barrel**, exactly as `w2-contracts.ts` and
30
+ * `w3-contracts.ts` are not: consumers import it by relative path. Public rows
31
+ * come through the owning session's model file, never through the seam.
32
+ *
33
+ * Contract: F14.1 (types), F14.4 (value forms), F14.5 (ports), F14.6 (recipe
34
+ * schema, the `{graph,view}` mapping, the publish sequence), F14.19 (review
35
+ * posture), F14.21 (batch). **Eleven kickoff corrections to that text are marked
36
+ * `KICKOFF CORRECTION` where they occur**; all eleven were verified against
37
+ * backend source, and each is recorded in the plan-of-record's Decisions table.
38
+ * None changes a clause's intent; every one is a place where following the frozen
39
+ * text literally produces something that does not publish, or publishes wrongly
40
+ * in silence.
41
+ */
42
+ import type { NgisDataType } from "../../sdk/facets/types";
43
+ import type { NgisFlowNode, NgisFlowNodeConfig, NgisFlowSnapshot, NgisInputBinding, NgisPortKind } from "./w3-contracts";
44
+ /** F14.6. A reader that does not know the version **refuses**; it never
45
+ * best-efforts, exactly as `ui_schema_version` does not (F14.2). */
46
+ export declare const NGIS_RECIPE_VERSION: 1;
47
+ /** F14.21, same rule. */
48
+ export declare const NGIS_BATCH_VERSION: 1;
49
+ /**
50
+ * W4's `data-slot` additions. The eight W2 names live in `w2-contracts.ts` and
51
+ * W3's two in `w3-contracts.ts`; these four extend the same table, and the same
52
+ * rule applies — a duplicate makes `verify-externals.mjs`'s plugin-ui
53
+ * fingerprint ambiguous.
54
+ */
55
+ export declare const NGIS_W4_DATA_SLOTS: {
56
+ readonly recipe: "ngis-recipe";
57
+ readonly recipeWizard: "ngis-recipe-wizard";
58
+ readonly batchTable: "ngis-batch-table";
59
+ readonly batchRow: "ngis-batch-row";
60
+ };
61
+ /**
62
+ * The canonical → **Pascal** spelling for `ToolInputSlot.dataType` /
63
+ * `ToolOutputSlot.dataType` and for a graph node's declared slot types.
64
+ *
65
+ * **KICKOFF CORRECTION 1 — F14.1 documents this column in prose and ships no
66
+ * map, and the failure is silent in both directions.**
67
+ * `WorkflowTypeCheckService.compatible` is
68
+ * `a.equals(b) || "File".equals(a) || "File".equals(b)`
69
+ * (`WorkflowTypeCheckService.java:103-105`) — case-sensitive `String.equals`, with
70
+ * Pascal `"File"` as the hardcoded wildcard. So writing `"raster"` into a slot
71
+ * does **not** raise "unknown type": it compares unequal to a builtin node's
72
+ * `"Raster"`, is not the wildcard either, and the edge is rejected as
73
+ * *incompatible* with a `400` at workflow save that names the wrong problem.
74
+ * Writing `"file"` is worse — it loses wildcard status and starts rejecting
75
+ * bindings that should warn.
76
+ *
77
+ * **`ToolInputSlot`'s own Java comment is wrong** and says lowercase
78
+ * (`ToolInputSlot.java:11`, `// raster | vector | table | file ...`). The
79
+ * ui-schema layer is immune because it squashes to lowercase on read
80
+ * (`ui_schema.py:41-48`) and the checked-in workflow fixture is Pascal
81
+ * (`tests/fixtures/ui_schema/us7-workflow.json:30`), so the two halves of the
82
+ * backend disagree about which spelling is canonical and only one of them is
83
+ * enforced. Pascal is the enforced one.
84
+ *
85
+ * Applied at, and **only** at, the `ngis-workflow` boundary (YD3) — never in a
86
+ * recipe's own `dataTypes`, which stay canonical lowercase.
87
+ */
88
+ export declare const NGIS_WORKFLOW_DATA_TYPES: Readonly<Record<NgisDataType, string>>;
89
+ /** The Pascal spelling for one canonical type. Total over `NgisDataType`. */
90
+ export declare function ngisWorkflowDataType(type: NgisDataType): string;
91
+ /**
92
+ * The slot spelling for a port that declares several types, or none.
93
+ *
94
+ * A slot carries **one** `dataType`, a port may declare many (F14.5's
95
+ * `dataTypes?: readonly NgisDataType[]`). F14.6 says "`dataTypes[0]` becomes
96
+ * `ToolInputSlot.dataType`", which is right for the single-type case and wrong
97
+ * for the rest: taking the first of `["table","raster"]` publishes a slot that
98
+ * type-checks against `Table` only and rejects the raster the author explicitly
99
+ * allowed. **A multi-type or absent declaration widens to `File`**, which is the
100
+ * wildcard on both sides of `compatible` and is therefore the only spelling that
101
+ * preserves the author's intent. The widening is lossy and deliberate; Y6
102
+ * surfaces it in the wizard rather than applying it silently.
103
+ */
104
+ export declare function ngisSlotDataType(dataTypes: readonly NgisDataType[] | undefined): string;
105
+ /**
106
+ * `NgisFlowNodeConfig` — the tool a node runs, and the version it was authored
107
+ * against. Declared in `w3-contracts.ts` because it is a member of
108
+ * `NgisFlowNode` and the alternative is a circular import; re-exported here so
109
+ * W4's two sessions read it from their own seam, like every other W4 name.
110
+ *
111
+ * **KICKOFF CORRECTION 2 — the W3 snapshot cannot express F14.6's recipe nodes,
112
+ * and this is the wave's load-bearing finding.** `NgisFlowNode` is
113
+ * `{id, slot, ports, inputs}` (`w3-contracts.ts:103-113`): there is **no
114
+ * `toolId` and no `toolVersion` anywhere in the snapshot graph**, while F14.6
115
+ * requires `nodes[].toolId` + `nodes[].toolVersion` and F14.21 requires the same
116
+ * two on a batch config. `flowSnapshot` is asserted *closed* against exactly this
117
+ * (`flow-model.test.ts:512-514` pins the absence of a `params` key;
118
+ * `flow-host.test.ts:801` pins the snapshot's key set), so Y6 and Y7 would each
119
+ * have had to reach around the snapshot for information W3 never put in it — and
120
+ * would each have invented a different way to do it.
121
+ *
122
+ * It is a *widening*, not a redesign, because the information is already in scope
123
+ * at the declaration sites and was simply never given a channel: `paramFormPorts`
124
+ * and `runButtonPorts` both take the full `NgisToolUiSchema`
125
+ * (`flow-ports.ts:178-182`, `:236-242`), which carries `tool_id` and
126
+ * `tool_version` (`src/types/analysis.ts:126-128`). The kickoff threads it
127
+ * through `NgisFlowPortDeclaration` → the registry → the snapshot, and populates
128
+ * it at `ParamForm.tsx` and `RunButton.tsx`. Optional, because nine of the eleven
129
+ * components run no tool.
130
+ *
131
+ * **`toolVersion` is what the author saw, not a guarantee about the run.** The
132
+ * server re-resolves and *overwrites* every node's version at publish —
133
+ * `pinToolVersions` (`WorkflowToolService.java:389-408`) calls `GetToolSchema`
134
+ * per node and does `((ObjectNode) n).put("toolVersion", resolvedVersion)` at
135
+ * `:406`. So the pin is authoritative in the recipe JSON and in the saved
136
+ * definition, and **advisory** on the published snapshot. A test asserting the
137
+ * pinned version survives into the published tool asserts the opposite of what
138
+ * the server does.
139
+ */
140
+ export type { NgisFlowNodeConfig } from "./w3-contracts";
141
+ /** A node's tool, or `null` for the nine components that run none. */
142
+ export declare function nodeConfigOf(node: NgisFlowNode): NgisFlowNodeConfig | null;
143
+ /**
144
+ * Build a node's `config` from whatever the component has to hand, or
145
+ * `undefined` when it has neither.
146
+ *
147
+ * One derivation in one place, because the two producers read the pair from two
148
+ * differently-spelled sources — `ParamForm` from its loaded
149
+ * `NgisToolUiSchema` (`tool_id` / `tool_version`, snake_case on the wire per
150
+ * YD6) and `RunButton` from the `NgisRunSubmission` it is about to submit
151
+ * (`toolId` / `toolVersion`, camelCase). Returning `undefined` rather than `null`
152
+ * is deliberate: `JSON.stringify` drops an `undefined` value, so a node with no
153
+ * tool stringifies in `useFlowPort`'s memo exactly as it did before W4 and does
154
+ * not re-register.
155
+ */
156
+ export declare function ngisNodeConfig(toolId: string | null | undefined, toolVersion: number | null | undefined): NgisFlowNodeConfig | undefined;
157
+ /**
158
+ * An in-port that becomes a recipe input, a published `ToolInputSlot`, and a
159
+ * batch column — the three names for one thing.
160
+ */
161
+ export interface NgisPromotableInput {
162
+ readonly nodeId: string;
163
+ /** The in-port member name. */
164
+ readonly portId: string;
165
+ /**
166
+ * `ToolInputSlot.bindInputKey` — always equal to {@link portId}, and carried
167
+ * as its own field anyway. **This is the field F14.6 omits** (CORRECTION 7),
168
+ * and omitting it cannot fail at compile time on the wire, so it is spelled
169
+ * once here where a publisher cannot miss it rather than left as a fact about
170
+ * `portId` that a reader has to know.
171
+ */
172
+ readonly bindInputKey: string;
173
+ /**
174
+ * `"<nodeId>.<portId>"` — `ToolInputSlot.slotKey`, and the key the caller
175
+ * supplies a file id under in `InvokeToolRequest.inputs`. The format is not a
176
+ * choice: `inferDraft` mints exactly `node.id + "." + key`
177
+ * (`WorkflowToolSchemaService.java:57`) and the checked-in workflow ui-schema
178
+ * fixture carries `clip.input` / `fill.dem`.
179
+ */
180
+ readonly slotKey: string;
181
+ /** F14.5's `label`, the generated-reason source. Never a message key. */
182
+ readonly label: string;
183
+ readonly kind: "resource" | "resources";
184
+ /** Canonical (F14.1). The Pascal spelling is applied only at publish. */
185
+ readonly dataTypes: readonly NgisDataType[];
186
+ readonly required: boolean;
187
+ }
188
+ /**
189
+ * Which of a flow graph's in-ports promote out of the recipe.
190
+ *
191
+ * **F14.6's rule, in one implementation.** *"Only file inputs promote"*, and a
192
+ * promoted input serializes as a **present but empty** `inputs.<key>` with no
193
+ * incoming edge — that absence of an edge is precisely what makes it a slot,
194
+ * because `inferDraft` derives one for *every unbound key of every node's
195
+ * `inputs` object* (`WorkflowToolSchemaService.java:43-71`). So "promotable"
196
+ * means exactly: a `resource`/`resources` in-port with **no upstream reference
197
+ * bound to it**.
198
+ *
199
+ * Three exclusions, each for a different reason:
200
+ *
201
+ * - **kind not `resource`/`resources`** — an option. `compileToolSchema` emits
202
+ * `x-role` of only `"input"` or `"output"` and **never `"option"`**
203
+ * (`WorkflowToolSchemaService.java:74-98`, verified verbatim), so a published
204
+ * workflow tool has no knobs at all; its whole invocable surface is
205
+ * `Map<String,String> inputs`. Option values therefore bake into node
206
+ * `params` at serialization or they are lost.
207
+ * - **bound to an `"@ref"`** — fed by an upstream node, so it is an edge, not a
208
+ * slot. `..."@ref"` spread directives are skipped for the same reason and are
209
+ * never ports at all (`isNgisFlowSpreadKey`).
210
+ * - **a `{$input}` binding** — already promoted; re-promoting it would mint a
211
+ * second slot for one input.
212
+ *
213
+ * A static (form 1) or `{$context}` (form 2) value on a *file* input is a real
214
+ * ambiguity that F14.6 does not address, and it is resolved in the safe
215
+ * direction: **it still promotes**, because a recipe's whole purpose is to run
216
+ * against fresh inputs and baking one authoring session's file id into a
217
+ * published tool would produce a tool that always reads the author's data. Y6
218
+ * surfaces the overridden value in the wizard as the slot's default.
219
+ *
220
+ * Order is declaration order — node order in the registry, then port order
221
+ * within a node — so the generated column order and the generated slot order are
222
+ * the same order the author wrote, and are stable across saves.
223
+ */
224
+ export declare function promotableInputs(snapshot: NgisFlowSnapshot): readonly NgisPromotableInput[];
225
+ /**
226
+ * Whether a promotable input carries an authored value that the wizard should
227
+ * offer as the slot's default. Kept next to {@link promotableInputs} because the
228
+ * two decisions are one rule read from opposite ends, and because
229
+ * `isNgisUnbound` is the single boundness predicate (the W2 `toWireParams`
230
+ * lesson: a satisfaction check that disagrees with a render check is a control
231
+ * that is enabled and then refuses).
232
+ */
233
+ export declare function promotedDefaultOf(node: NgisFlowNode, portId: string): string | null;
234
+ /**
235
+ * F14.6's promoted input, as it appears in recipe JSON.
236
+ *
237
+ * `kind` is `NgisPortKind` minus `task` and `record`, per F14.6 — but only
238
+ * `resource`/`resources` can actually arrive here, because the other three are
239
+ * options and options do not promote (see {@link promotableInputs}). The wider
240
+ * type is kept so a future clause can widen the *rule* without a schema change.
241
+ */
242
+ export interface NgisRecipeInput {
243
+ readonly id: string;
244
+ readonly label: string;
245
+ readonly kind: Exclude<NgisPortKind, "task" | "record">;
246
+ /** Canonical lowercase (F14.1). */
247
+ readonly dataTypes: readonly NgisDataType[];
248
+ readonly required: boolean;
249
+ readonly default: string | null;
250
+ }
251
+ /**
252
+ * A recipe node. `kind: "recipe"` is a nested recipe and is **IN for v1** — the
253
+ * whole substrate exists server-side and none of it is Y6's to build:
254
+ * `validateAtPublish` computes cross-tool depth against
255
+ * `workflow.nested.max-depth` (default **3**) and caps
256
+ * `max-nodes-per-dag` (default **10**), `checkAmbiguity` rejects a node carrying
257
+ * `workflowToolId` beside another discriminator, and `invokeNested` re-checks at
258
+ * runtime. **Y6 adds no client-side depth guard**; it surfaces the server's
259
+ * message, which is why nested recipes need `readApiErrorMessage`.
260
+ *
261
+ * **SCRIPT nodes are OUT of v1 recipes** — a recipe is the data tier and carries
262
+ * no code. (Independently, nothing in the workflow canvas emits them either.)
263
+ */
264
+ export interface NgisRecipeNode {
265
+ readonly id: string;
266
+ readonly kind: "tool" | "recipe";
267
+ /** An analysis tool id, or a published workflow tool id. */
268
+ readonly toolId: string;
269
+ /** See {@link NgisFlowNodeConfig} — advisory once published. */
270
+ readonly toolVersion: number;
271
+ /** Param name → one of F14.4's four value forms. */
272
+ readonly bindings: Readonly<Record<string, NgisInputBinding>>;
273
+ }
274
+ /**
275
+ * A recipe output.
276
+ *
277
+ * **KICKOFF CORRECTION 3 — `outputMode` and `targetResourceId` belong here, and
278
+ * F14.6's own JSON example puts them in the wrong place.** The clause's mapping
279
+ * table is right (*"each `outputs[]` entry → `{id, type:"OUTPUT", outputMode,
280
+ * targetResourceId?}`"*) and its JSON snippet contradicts it by hanging both
281
+ * fields off the **tool** node, where they are inert:
282
+ * `validateOutputNodes` only inspects nodes whose `type` is `OUTPUT`
283
+ * (`WorkflowTypeCheckService.java:166-186`), and no executor reads `outputMode`
284
+ * off a TASK node.
285
+ *
286
+ * **KICKOFF CORRECTION 4 — the recipe-level and invoke-level `outputMode` enums
287
+ * are different sets, and nothing in F14.6 says so.** An OUTPUT node accepts
288
+ * `ADD_LAYER` / `SCENE_LAYER` / `UPDATE_RESOURCE` / `SCENE_RESOURCE` and nothing
289
+ * else (`:174-180`); `LIBRARY` — perfectly legal in `InvokeToolRequest`
290
+ * (`InvokeToolRequest.java:8`) — is a **`400` at definition save**. And
291
+ * `UPDATE_RESOURCE` **requires** a non-null `targetResourceId` *at save time*
292
+ * (`:181-185`), not at run time, which is why it is a discriminated union here:
293
+ * the illegal combination should not be constructible.
294
+ */
295
+ export type NgisRecipeOutput = {
296
+ readonly id: string;
297
+ readonly label: string;
298
+ /** A reference form (F14.4) naming the producing node. */
299
+ readonly from: string;
300
+ readonly outputMode: "ADD_LAYER";
301
+ readonly targetResourceId?: never;
302
+ } | {
303
+ readonly id: string;
304
+ readonly label: string;
305
+ readonly from: string;
306
+ readonly outputMode: "UPDATE_RESOURCE";
307
+ /** Required at *save*, not at run. */
308
+ readonly targetResourceId: string;
309
+ };
310
+ /** F14.6's recipe JSON, exactly. */
311
+ export interface NgisRecipe {
312
+ readonly recipeVersion: typeof NGIS_RECIPE_VERSION;
313
+ /** Stable across saves. */
314
+ readonly id: string;
315
+ readonly name: string;
316
+ readonly description: string | null;
317
+ readonly inputs: readonly NgisRecipeInput[];
318
+ readonly nodes: readonly NgisRecipeNode[];
319
+ readonly outputs: readonly NgisRecipeOutput[];
320
+ }
321
+ /**
322
+ * The `type` values a recipe maps onto in the `{graph,view}` envelope, and the
323
+ * field that actually dispatches each one.
324
+ *
325
+ * **KICKOFF CORRECTION 5 — dispatch is unordered first-match, so a node carrying
326
+ * two discriminators is undefined behaviour rather than an error.**
327
+ * `WorkflowTaskRunner.java:61-65` takes `executors.stream().filter(supports).findFirst()`
328
+ * and **no executor carries `@Order`**. `NestedToolGuardService.checkAmbiguity`
329
+ * guards the `workflowToolId` combinations only, so `modelToolId` **+**
330
+ * `type:"OUTPUT"` is unguarded and dispatches by Spring's classpath-scan order.
331
+ * A serializer must therefore emit **exactly one** discriminator per node —
332
+ * which is a property of the mapping, not something the server will catch.
333
+ *
334
+ * `type` is display-only for TASK/WORKFLOW_TOOL (dispatch reads the *fields*),
335
+ * but Y6 emits it anyway so a persisted graph reads correctly, and it is
336
+ * matched case-insensitively for OUTPUT (`equalsIgnoreCase`).
337
+ */
338
+ export declare const NGIS_RECIPE_NODE_TYPES: {
339
+ readonly tool: {
340
+ readonly type: "TASK";
341
+ readonly discriminator: "modelToolId";
342
+ };
343
+ readonly recipe: {
344
+ readonly type: "WORKFLOW_TOOL";
345
+ readonly discriminator: "workflowToolId";
346
+ };
347
+ readonly output: {
348
+ readonly type: "OUTPUT";
349
+ readonly discriminator: "type";
350
+ };
351
+ };
352
+ /**
353
+ * **KICKOFF CORRECTION 6 — the fifteen keys that survive a save, and why the
354
+ * list is a contract rather than trivia.**
355
+ *
356
+ * `WorkflowGraphNormalizer.normalizeNode` (`:81-113`) rebuilds every node from
357
+ * scratch and copies exactly these fifteen keys. Everything else is dropped. The
358
+ * part that matters: the lossless presentation capture (`buildViewFromRaw`,
359
+ * `:136-151`, which stashes a whole original node under `view.nodes[id]`) runs
360
+ * **only when the payload is not already an envelope** (`:70-77`). Once a client
361
+ * sends `{graph, view}` — which Y6 does — any node key outside this list that is
362
+ * not *also* duplicated into `view` is **permanently lost on save**, with no
363
+ * error. A recipe's own fields (`recipeVersion`, promoted-input ids, labels) are
364
+ * not on this list, so **the recipe JSON must be persisted in `view`**, which the
365
+ * backend stores verbatim and never reads.
366
+ *
367
+ * Also: a blank string is dropped rather than stored as `null` (`putText`
368
+ * `:245-247`), a non-numeric `toolVersion` is silently discarded (`:99-102`), and
369
+ * an edge missing either endpoint is **silently discarded** (`normalizeEdge`
370
+ * returns `null`, consumed at `:66-68`) — so a mis-spelled node id in an edge is
371
+ * a missing dependency, not a refusal.
372
+ */
373
+ export declare const NGIS_GRAPH_NODE_KEYS: readonly ["id", "type", "params", "inputs", "outputs", "options", "modelToolId", "toolType", "workflowToolId", "toolVersion", "inputFileKey", "outputMode", "targetResourceId", "name", "script"];
374
+ /**
375
+ * An edge, after normalization. **Output keys are `from`/`to`/`fromOutput`/
376
+ * `toInput`/`fieldMap` and never `source`/`target`** — those are accepted as
377
+ * *input* aliases only, with `fromNodeId` beating `source` beating `from`
378
+ * (`normalizeEdge`, `:115-129`).
379
+ *
380
+ * **`fieldMap` is never emitted and never parsed** (F14.4). Despite the name it
381
+ * is a single flat *string*, not a map — a server-side path+pipeline expression
382
+ * over a task's output JSON, a shape the flow layer has no model of.
383
+ */
384
+ export declare const NGIS_GRAPH_EDGE_KEYS: readonly ["from", "to", "fromOutput", "toInput"];
385
+ /**
386
+ * `ToolInputSlot`, as the server actually declares it.
387
+ *
388
+ * **KICKOFF CORRECTION 7 — F14.6 omits `bindInputKey`, and the omission cannot
389
+ * fail at compile time. This is the single most expensive defect the kickoff
390
+ * found.** F14.6 freezes the input slot as
391
+ * `(slotKey, name, description, dataType, bindNodeId, optional)` — six
392
+ * components. `ToolInputSlot.java:8-15` is a **seven**-component record with
393
+ * `bindInputKey` between `bindNodeId` and `optional`. Because the record carries
394
+ * `@JsonIgnoreProperties(ignoreUnknown = true)`, posting the six-field shape
395
+ * raises **no** error: `bindInputKey` deserializes to `null`, publish proceeds
396
+ * as far as `validateSlots`, and dies at `WorkflowToolSchemaService.java:193-196`
397
+ * with `"input slot <slotKey> is missing bindInputKey"` — a `400` naming a field
398
+ * the frozen contract never mentions. A client built exactly to F14.6 cannot
399
+ * publish anything.
400
+ *
401
+ * It is not a cosmetic omission either: `bindInputKey` is the key the caller's
402
+ * file id is injected under at invoke time —
403
+ * `inputsNode.put(slot.bindInputKey(), fileId)`
404
+ * (`WorkflowToolService.java:421-423`) — so a wrong value would inject a real
405
+ * file under the wrong parameter.
406
+ *
407
+ * **Serialize by name, never positionally.** Both are Java records and their
408
+ * component orders are *transposed*: `dataType` is 4th on input and 5th on
409
+ * output, `bindNodeId` is 5th on input and 4th on output. `ToolOutputSlot`
410
+ * additionally keeps a 4-arg secondary constructor for pre-S11b rows
411
+ * (`ToolOutputSlot.java:15-17`), so a 4-tuple compiles and silently yields
412
+ * `dataType: null`.
413
+ */
414
+ export interface NgisToolInputSlot {
415
+ readonly slotKey: string;
416
+ readonly name: string;
417
+ readonly description: string | null;
418
+ /** **Pascal** (F14.1). See {@link ngisSlotDataType}. */
419
+ readonly dataType: string;
420
+ readonly bindNodeId: string;
421
+ /** The node-`inputs` key the file id is injected under. Never omit it. */
422
+ readonly bindInputKey: string;
423
+ readonly optional: boolean;
424
+ }
425
+ /**
426
+ * `ToolOutputSlot` (`ToolOutputSlot.java:8-18`).
427
+ *
428
+ * **KICKOFF CORRECTION 8 — publish `dataType` explicitly or the recipe's own
429
+ * generated dialog is wrong.** `inferDraft` builds output slots through the
430
+ * 4-arg constructor (`WorkflowToolSchemaService.java:67`), so every *inferred*
431
+ * slot has `dataType: null`; `compileToolSchema` then omits `x-data-type`
432
+ * entirely, and `ui_schema.py`'s `_resolve_data_type` falls back to
433
+ * `canonical_data_type(None) == "file"` (`:59-68`). An unenriched recipe
434
+ * therefore serves `data_type: "file"` for its outputs, and the generated dialog
435
+ * (F14.6's own exit criterion, backlog `V-12`) shows a file picker where the
436
+ * author declared a raster. Y6 publishes explicit `outputSlots` — which F14.6
437
+ * already requires for a different reason — and this is the second reason.
438
+ */
439
+ export interface NgisToolOutputSlot {
440
+ readonly slotKey: string;
441
+ readonly name: string;
442
+ readonly description: string | null;
443
+ readonly bindNodeId: string;
444
+ /** **Pascal** (F14.1), and never `null` from Y6. */
445
+ readonly dataType: string;
446
+ }
447
+ /**
448
+ * The hand-rolled refusals `POST /api/workflows/tools` raises, verbatim.
449
+ *
450
+ * **KICKOFF CORRECTION 9 — `PublishToolRequest` carries zero validation
451
+ * annotations and the controller does not `@Valid` it.** Every check is
452
+ * hand-written in `WorkflowToolService.publish` / `validateSlots`, so these
453
+ * messages *are* the contract, and they only reach a client at all because YB2
454
+ * set `include-message: always` for this service. Frozen here so Y6's tests
455
+ * assert the real strings and so the wizard can map them to a field.
456
+ */
457
+ export declare const NGIS_PUBLISH_REFUSALS: {
458
+ readonly missingDefinitionId: "definitionId is required";
459
+ readonly missingName: "name is required";
460
+ readonly noOutputSlot: "at least one output slot is required";
461
+ /** `+ " <slotKey> is missing bindInputKey"` — see the correction above. */
462
+ readonly missingBindInputKey: "is missing bindInputKey";
463
+ readonly unknownInputNode: "binds to unknown node";
464
+ };
465
+ /** F14.21's batch config, exactly. Saved and loaded as JSON. */
466
+ export interface NgisBatchConfig {
467
+ readonly batchVersion: typeof NGIS_BATCH_VERSION;
468
+ readonly toolId: string;
469
+ readonly toolVersion: number;
470
+ /** UI-schema param names, in display order. */
471
+ readonly columns: readonly string[];
472
+ /** One run per row. Values are the wire spelling — always strings. */
473
+ readonly rows: readonly Readonly<Record<string, string>>[];
474
+ readonly outputMode: "ADD_LAYER" | "UPDATE_RESOURCE";
475
+ readonly sceneId: string | null;
476
+ }
477
+ /**
478
+ * F14.21's concurrency cap. **Not a tuning knob.** The task fabric and the
479
+ * `UsageLimiter` windows are shared, and there is no global concurrency limit
480
+ * anywhere below this line — `analysis-task-runtime.ts`'s `taskControllers` map
481
+ * is keyed by task id and bounds nothing — so a 50-row batch fired at once is a
482
+ * self-inflicted outage.
483
+ */
484
+ export declare const NGIS_BATCH_CONCURRENCY = 3;
485
+ /**
486
+ * A batch cell's DOM/node id.
487
+ *
488
+ * **KICKOFF CORRECTION 10 — a batch table inside a `<Flow>` needs per-(row,param)
489
+ * ids or it silently loses cells.** Four of the twelve widgets delegate to
490
+ * components that are themselves flow nodes (`resource-select` and
491
+ * `resource-multi` → `ResourceSelect`, `field-select` → `FieldSelect`, `extent`
492
+ * → `ExtentPicker`), and each uses its `id` prop **as the flow node id**
493
+ * (`ResourceSelect.tsx:90-105`). The registry is **last-wins on id**
494
+ * (`w3-contracts.ts:99-102`), so N rows rendering the same param would collapse
495
+ * to one node — a `console.error` in development and, in production, N-1 cells
496
+ * bound to nothing. `ParamForm` already avoids this with
497
+ * `` `${scopeId}-${param.name}` `` (`ParamForm.tsx:493`); batch needs the row in
498
+ * the key too.
499
+ */
500
+ export declare function ngisBatchCellId(scopeId: string, rowIndex: number, paramName: string): string;
501
+ /**
502
+ * A published recipe's batch columns.
503
+ *
504
+ * F14.21: *"Batch works over a published recipe too: its promoted inputs are the
505
+ * columns."* This is the one function both sessions read — Y6 produces the
506
+ * recipe, Y7 consumes it — so it exists once. Column order is the recipe's own
507
+ * input order, which is {@link promotableInputs}' declaration order, which is
508
+ * the order the author wrote.
509
+ */
510
+ export declare function recipeColumns(recipe: NgisRecipe): readonly string[];
@@ -0,0 +1,12 @@
1
+ import * as React from "react";
2
+ import { type VariantProps } from "class-variance-authority";
3
+ declare const buttonVariants: (props?: ({
4
+ variant?: "default" | "destructive" | "outline" | "secondary" | "ghost" | "link" | null | undefined;
5
+ size?: "default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg" | null | undefined;
6
+ } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
+ type ButtonProps = React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
8
+ asChild?: boolean;
9
+ };
10
+ declare function Button({ className, variant, size, asChild, ...props }: ButtonProps): import("react/jsx-runtime").JSX.Element;
11
+ export { Button, buttonVariants };
12
+ export type { ButtonProps };
@@ -0,0 +1,4 @@
1
+ import * as React from "react";
2
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
3
+ declare function Checkbox({ className, ...props }: React.ComponentProps<typeof CheckboxPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
4
+ export { Checkbox };
@@ -0,0 +1,23 @@
1
+ import type { PointerEvent } from "react";
2
+ /**
3
+ * The draggable boundary at the trailing edge of a resizable column header.
4
+ *
5
+ * Sits absolutely inside a header cell marked `data-column-cell` (which
6
+ * {@link useColumnResize} measures at drag start), so the cell must be
7
+ * `relative` and must not clip its overflow — put `truncate` on an inner span,
8
+ * never on the cell itself. Straddles the boundary via `translate-x-1/2`: the
9
+ * grab target is wider than the hairline it paints, and lands in the gutter
10
+ * rather than eating the neighbour's padding.
11
+ */
12
+ export declare function ColumnResizeHandle({ label, active, onStart, onNudge, onReset, className, }: {
13
+ /** Accessible name — the column being sized, not the word "handle". */
14
+ label: string;
15
+ /** This column is the one currently being dragged. */
16
+ active?: boolean;
17
+ onStart: (event: PointerEvent<HTMLElement>) => void;
18
+ /** Keyboard resize by `delta` px, relative to the current rendered width. */
19
+ onNudge: (delta: number, from: HTMLElement) => void;
20
+ /** Restore the column's default width (double-click / Escape-free reset). */
21
+ onReset: () => void;
22
+ className?: string;
23
+ }): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,25 @@
1
+ import * as React from "react";
2
+ import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
3
+ declare function DropdownMenu({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
4
+ declare function DropdownMenuPortal({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Portal>): import("react/jsx-runtime").JSX.Element;
5
+ declare function DropdownMenuTrigger({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>): import("react/jsx-runtime").JSX.Element;
6
+ declare function DropdownMenuContent({ className, sideOffset, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Content>): import("react/jsx-runtime").JSX.Element;
7
+ declare function DropdownMenuGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Group>): import("react/jsx-runtime").JSX.Element;
8
+ declare function DropdownMenuItem({ className, inset, variant, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
9
+ inset?: boolean;
10
+ variant?: "default" | "destructive";
11
+ }): import("react/jsx-runtime").JSX.Element;
12
+ declare function DropdownMenuCheckboxItem({ className, children, checked, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>): import("react/jsx-runtime").JSX.Element;
13
+ declare function DropdownMenuRadioGroup({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>): import("react/jsx-runtime").JSX.Element;
14
+ declare function DropdownMenuRadioItem({ className, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>): import("react/jsx-runtime").JSX.Element;
15
+ declare function DropdownMenuLabel({ className, inset, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
16
+ inset?: boolean;
17
+ }): import("react/jsx-runtime").JSX.Element;
18
+ declare function DropdownMenuSeparator({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Separator>): import("react/jsx-runtime").JSX.Element;
19
+ declare function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<"span">): import("react/jsx-runtime").JSX.Element;
20
+ declare function DropdownMenuSub({ ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.Sub>): import("react/jsx-runtime").JSX.Element;
21
+ declare function DropdownMenuSubTrigger({ className, inset, children, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
22
+ inset?: boolean;
23
+ }): import("react/jsx-runtime").JSX.Element;
24
+ declare function DropdownMenuSubContent({ className, ...props }: React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>): import("react/jsx-runtime").JSX.Element;
25
+ export { DropdownMenu, DropdownMenuPortal, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuGroup, DropdownMenuLabel, DropdownMenuItem, DropdownMenuCheckboxItem, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubTrigger, DropdownMenuSubContent, };
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ declare function Input({ className, type, ...props }: React.ComponentProps<"input">): import("react/jsx-runtime").JSX.Element;
3
+ export { Input };
@@ -0,0 +1,4 @@
1
+ import * as React from "react";
2
+ import * as LabelPrimitive from "@radix-ui/react-label";
3
+ declare function Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
4
+ export { Label };
@@ -0,0 +1,10 @@
1
+ import * as React from "react";
2
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
3
+ declare function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
4
+ declare function PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>): import("react/jsx-runtime").JSX.Element;
5
+ declare function PopoverContent({ className, align, sideOffset, ...props }: React.ComponentProps<typeof PopoverPrimitive.Content>): import("react/jsx-runtime").JSX.Element;
6
+ declare function PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>): import("react/jsx-runtime").JSX.Element;
7
+ declare function PopoverHeader({ className, ...props }: React.ComponentProps<"div">): import("react/jsx-runtime").JSX.Element;
8
+ declare function PopoverTitle({ className, ...props }: React.ComponentProps<"h2">): import("react/jsx-runtime").JSX.Element;
9
+ declare function PopoverDescription({ className, ...props }: React.ComponentProps<"p">): import("react/jsx-runtime").JSX.Element;
10
+ export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor, PopoverHeader, PopoverTitle, PopoverDescription, };
@@ -0,0 +1,15 @@
1
+ import * as React from "react";
2
+ import * as SelectPrimitive from "@radix-ui/react-select";
3
+ declare function Select({ ...props }: React.ComponentProps<typeof SelectPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
4
+ declare function SelectGroup({ ...props }: React.ComponentProps<typeof SelectPrimitive.Group>): import("react/jsx-runtime").JSX.Element;
5
+ declare function SelectValue({ ...props }: React.ComponentProps<typeof SelectPrimitive.Value>): import("react/jsx-runtime").JSX.Element;
6
+ declare function SelectTrigger({ className, size, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Trigger> & {
7
+ size?: "sm" | "default";
8
+ }): import("react/jsx-runtime").JSX.Element;
9
+ declare function SelectContent({ className, children, position, align, ...props }: React.ComponentProps<typeof SelectPrimitive.Content>): import("react/jsx-runtime").JSX.Element;
10
+ declare function SelectLabel({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Label>): import("react/jsx-runtime").JSX.Element;
11
+ declare function SelectItem({ className, children, ...props }: React.ComponentProps<typeof SelectPrimitive.Item>): import("react/jsx-runtime").JSX.Element;
12
+ declare function SelectSeparator({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.Separator>): import("react/jsx-runtime").JSX.Element;
13
+ declare function SelectScrollUpButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollUpButton>): import("react/jsx-runtime").JSX.Element;
14
+ declare function SelectScrollDownButton({ className, ...props }: React.ComponentProps<typeof SelectPrimitive.ScrollDownButton>): import("react/jsx-runtime").JSX.Element;
15
+ export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, };
@@ -0,0 +1,6 @@
1
+ import * as React from "react";
2
+ import * as SwitchPrimitive from "@radix-ui/react-switch";
3
+ declare function Switch({ className, size, ...props }: React.ComponentProps<typeof SwitchPrimitive.Root> & {
4
+ size?: "sm" | "default";
5
+ }): import("react/jsx-runtime").JSX.Element;
6
+ export { Switch };