@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,328 @@
1
+ /**
2
+ * W3 shared contracts — authored at the **W3 kickoff**, read-only to Y5a and Y5b.
3
+ *
4
+ * Stage 14's wave rule, third application: every surface read by more than one
5
+ * session is frozen here so neither agent coordinates live with a sibling. W3
6
+ * splits the flow engine at the seam the stage has used twice already — pure
7
+ * model versus React — so:
8
+ *
9
+ * Y5a owns `flow-model.ts`: the registry's data model, binding resolution,
10
+ * satisfaction, {@link ngisTypeVerdict}, reasons, disclosure, snapshot.
11
+ * Y5b owns `Flow.tsx` + the eleven components' port declarations + the
12
+ * inspector: everything that needs React, a DOM or a host.
13
+ *
14
+ * The seam is exactly four things, all frozen below:
15
+ *
16
+ * 1. what a node *is* ({@link NgisFlowNode})
17
+ * 2. how a bound input is spelled ({@link NgisInputBinding})
18
+ * 3. what a resolution *answers* ({@link NgisPortResolution})
19
+ * 4. what a disabled control renders ({@link NgisFlowReason})
20
+ *
21
+ * Nothing here is a component. Nothing here imports React. Nothing here reads a
22
+ * host. That is what lets Y5a assert every behaviour F14.10 pins without a DOM,
23
+ * and what keeps `<Flow>` **host-renderable from declarative data** — the
24
+ * property Stage 15's worker tier depends on and that a scope holding React
25
+ * state in its contract would quietly destroy.
26
+ *
27
+ * **This module is deliberately not re-exported from either barrel**, exactly as
28
+ * `w2-contracts.ts` is not: consumers import it by relative path. The public
29
+ * names on F14.14's frozen export table (`NgisPortSpec`, `NgisPortKind`,
30
+ * `NgisPortDirection`, `ngisTypeVerdict`, `NgisTypeVerdict`) are re-exported by
31
+ * Y5a's `flow-model.ts`, and the barrels take them from there — so the seam
32
+ * stays a wave artifact and the package surface stays one file's responsibility.
33
+ *
34
+ * Contract: F14.1 (type verdict), F14.4 (value forms, reference forms, reserved
35
+ * members), F14.5 (port model), F14.10 (enablement, reasons, disclosure), F14.11
36
+ * (the bare-key publication). Three kickoff corrections to that text are marked
37
+ * **KICKOFF CORRECTION** where they occur; each is recorded in the stage README's
38
+ * Decisions table and none changes an F14 clause's intent.
39
+ */
40
+ import type { NgisDataType, NgisTaskOutput } from "../../sdk/facets/types";
41
+ import type { NgisUiSchemaValueType } from "../../types/analysis";
42
+ import type { NgisParamValue } from "./w2-contracts";
43
+ export type NgisPortDirection = "in" | "out";
44
+ export type NgisPortKind = "resource" | "resources" | "field" | "extent" | "task" | "value" | "record";
45
+ /**
46
+ * F14.5's port spec, verbatim but for one clarification.
47
+ *
48
+ * **KICKOFF CORRECTION 1 — `id` is unique within its *node*, not its scope.**
49
+ * F14.5 says "unique within the enclosing `<Flow>` scope", but its own
50
+ * per-component table gives four different components an out port called
51
+ * `value` and four an in port called `taskId`, and F14.4 addresses a member as
52
+ * `"@<nodeId>.<member>"`. Scope-unique port ids would make F14.5 and F14.4
53
+ * contradict each other in the first two-picker flow anyone writes. The frozen
54
+ * model: a component's `id` prop is the **node** id and is scope-unique; a port
55
+ * id is a **member name** and is unique within its node; the scope-unique
56
+ * identity is the pair, spelled by {@link ngisPortRef}. `NGIS_W2_PORT_IDS`
57
+ * (`w2-contracts.ts`) is exactly the reserved member vocabulary, unchanged.
58
+ */
59
+ export interface NgisPortSpec {
60
+ /** Member name, unique within the node. See KICKOFF CORRECTION 1. */
61
+ readonly id: string;
62
+ readonly direction: NgisPortDirection;
63
+ readonly kind: NgisPortKind;
64
+ /** The generated-reason text source (F14.10). Never a message key — a literal
65
+ * string or the UI schema's `label`. Plugin strings are literal (F13.11). */
66
+ readonly label: string;
67
+ readonly required: boolean;
68
+ /** kinds "resource" | "resources" only. Empty or absent ⇒ any type. */
69
+ readonly dataTypes?: readonly NgisDataType[];
70
+ /** kind "value" only. */
71
+ readonly valueType?: NgisUiSchemaValueType;
72
+ /** kind "field" only — the id of the **sibling in-port on this same node**
73
+ * that carries the parent resource (QGIS `parentLayerParameterName`). For
74
+ * `FieldSelect` that is `"parent"`, per F14.5's own component table; the
75
+ * parent's *value* arrives through that in-port's binding, so there is one
76
+ * resolution path and not two. */
77
+ readonly parentPortId?: string;
78
+ }
79
+ /** The scope-unique spelling of a port: `<nodeId>.<portId>`. */
80
+ export declare function ngisPortRef(nodeId: string, portId: string): string;
81
+ /**
82
+ * A node in a flow scope: one smart component's declaration, as the registry
83
+ * holds it. Registration is **last-wins on `id` within a scope**, and a
84
+ * duplicate id is a development-mode error, never a silent overwrite (F14.5).
85
+ */
86
+ export interface NgisFlowNode {
87
+ readonly id: string;
88
+ /** The `data-slot` the component renders, from `NGIS_W2_DATA_SLOTS` or
89
+ * `NGIS_W3_DATA_SLOTS`. The registry's only knowledge of *what* a node is —
90
+ * the engine never branches on a component identity beyond this. */
91
+ readonly slot: string;
92
+ readonly ports: readonly NgisPortSpec[];
93
+ /** Bindings for this node's in-ports, keyed by in-port member name, plus any
94
+ * number of spread directives (see {@link ngisFlowSpread}). */
95
+ readonly inputs: Readonly<Record<string, NgisInputBinding>>;
96
+ /**
97
+ * **W4 KICKOFF ADDITION (YD49).** The tool this node runs, when it runs one.
98
+ * Absent for the nine components that run none.
99
+ *
100
+ * Added here rather than in `w4-contracts.ts` because it is a *member of this
101
+ * type* and the alternative is a circular import. **The engine still never
102
+ * reads it** — `resolveFlow` ignores it entirely, exactly as it ignores
103
+ * everything about a component beyond `slot`; it rides the snapshot for Y6 and
104
+ * Y7, which is the whole reason it exists. See `NgisFlowNodeConfig`.
105
+ */
106
+ readonly config?: NgisFlowNodeConfig;
107
+ }
108
+ /**
109
+ * **W4 KICKOFF ADDITION (YD49).** The tool a node runs, and the version it was
110
+ * authored against.
111
+ *
112
+ * The W3 snapshot could not express F14.6's recipe nodes or F14.21's batch
113
+ * config: neither `toolId` nor `toolVersion` appears anywhere in the snapshot
114
+ * graph, while both clauses require both fields. The information was already in
115
+ * scope at the declaration sites — `paramFormPorts` and `runButtonPorts` each
116
+ * take the full `NgisToolUiSchema`, which carries `tool_id` and `tool_version` —
117
+ * and simply had no channel into the node. This is that channel.
118
+ *
119
+ * Rationale, the correction it answers and the caveat on `toolVersion` (the
120
+ * server **re-pins** it at publish) are recorded in full at
121
+ * `w4-contracts.ts` → `NgisFlowNodeConfig`, which re-exports this type so W4's
122
+ * sessions read it from their own seam.
123
+ */
124
+ export interface NgisFlowNodeConfig {
125
+ readonly toolId: string;
126
+ /** `NgisToolUiSchema.tool_version` at authoring time. Advisory once published. */
127
+ readonly toolVersion: number;
128
+ }
129
+ /**
130
+ * A reference to another node's output (F14.4 form 4).
131
+ *
132
+ * The template literal buys a real check where the argument type is *only* a
133
+ * reference — {@link ngisFlowSpread} rejects `"opts"` at compile time. It buys
134
+ * **nothing** inside {@link NgisInputBinding}, and the honest reason is worth
135
+ * writing down rather than discovering: form 1 is any JSON literal, so `string`
136
+ * is already in that union and `` `@${string}` `` collapses into it. A bare
137
+ * `"dem"` where `"@dem"` was meant is a legal *static string*, not a type error,
138
+ * and no type can tell them apart. The `@` sigil is a runtime discrimination.
139
+ */
140
+ export type NgisFlowRef = `@${string}`;
141
+ /** F14.4's four value forms, and nothing else. */
142
+ export type NgisInputBinding = NgisParamValue | {
143
+ readonly $context: string;
144
+ } | {
145
+ readonly $input: string;
146
+ } | NgisFlowRef;
147
+ /**
148
+ * **KICKOFF CORRECTION 3 — a static string starting with `@` needs an escape.**
149
+ *
150
+ * F14.4 gives `@` no escape, so a legitimate static value like an email-shaped
151
+ * string or a `@`-prefixed layer name is indistinguishable from a reference and
152
+ * would resolve as a broken one. The frozen rule mirrors F14.8's `$$`, which is
153
+ * already the precedent in this package: **`"@@"` opens a literal**, and
154
+ * `parseNgisBinding` yields the string with one `@` removed. Only a value
155
+ * matching `/^@[^@]/` (or the bare `"@"`) is a reference. Additive; no existing
156
+ * spelling changes meaning.
157
+ */
158
+ export declare function isNgisFlowRef(value: NgisInputBinding): value is NgisFlowRef;
159
+ /** Unescapes a static string that opened with `"@@"`. Identity otherwise. */
160
+ export declare function unescapeNgisStatic(value: string): string;
161
+ /** The reserved key prefix {@link ngisFlowSpread} mints. No in-port member name
162
+ * may start with it — a UI-schema param name cannot contain `.` at all. */
163
+ export declare const NGIS_FLOW_SPREAD_PREFIX = "...";
164
+ /**
165
+ * **KICKOFF CORRECTION 2 — the record spread needs a spelling, and F14.4's is
166
+ * not valid JavaScript.**
167
+ *
168
+ * F14.4 and F14.22 write the spread as `inputs={{ ELEV: "@dem", ..."@opts" }}`.
169
+ * Spreading a *string* into an object literal is legal JS with a meaning nobody
170
+ * wants: it spreads the string's indices, so `{..."@opts"}` is
171
+ * `{"0":"@","1":"o","2":"p","3":"t","4":"s"}`. Worse, that typechecks against
172
+ * `Record<string, NgisInputBinding>` — every character is a `string` — so the
173
+ * form fails **silently**, at runtime, as five bogus inputs. It cannot ship as
174
+ * written and the resolver must not try to detect the character-indexed shape.
175
+ *
176
+ * The frozen spelling keeps the `...` at the call site and is a real object
177
+ * spread of a real object:
178
+ *
179
+ * ```tsx
180
+ * <RunButton id="run" toolId={FLOOD_TOOL_ID}
181
+ * inputs={{ ELEV: "@dem", RAIN: "@rain", ...ngisFlowSpread("@opts") }} />
182
+ * ```
183
+ *
184
+ * Distinct references produce distinct keys, so two spreads compose; the same
185
+ * reference twice collapses, which is idempotent rather than an error. F14.4's
186
+ * two spread rules are unchanged and are Y5a's to enforce at resolution: the
187
+ * source port's kind must be `record`, and **two spreads contributing the same
188
+ * record key is an error**, with later explicit keys winning over spread keys.
189
+ *
190
+ * F14.22's snippet still shows the old form; correcting it is a W5 input handed
191
+ * to Y8, not a silent edit here.
192
+ */
193
+ export declare function ngisFlowSpread(ref: NgisFlowRef): Readonly<Record<string, NgisInputBinding>>;
194
+ /** Whether an `inputs` key is a spread directive rather than an in-port name. */
195
+ export declare function isNgisFlowSpreadKey(key: string): boolean;
196
+ /**
197
+ * F14.4's reserved members of a `task` reference, which win over any output
198
+ * name. A tool whose output parameter collides is addressed as
199
+ * `"@run.outputs.<name>"`.
200
+ */
201
+ export declare const NGIS_TASK_REF_MEMBERS: readonly ["taskId", "status", "stage", "outputs"];
202
+ export type NgisTaskRefMember = (typeof NGIS_TASK_REF_MEMBERS)[number];
203
+ /**
204
+ * What binding resolution answers for one in-port. Three states and not two:
205
+ * "unsatisfied because the user has not chosen yet" and "unsatisfied because an
206
+ * upstream node has not produced yet" are the same *value* and different
207
+ * *renderings* (F14.10's `blocked` vs `pending`), so the resolver must
208
+ * distinguish them and a boolean cannot.
209
+ */
210
+ export type NgisPortResolution = {
211
+ readonly state: "satisfied";
212
+ readonly value: NgisResolvedValue;
213
+ } | {
214
+ readonly state: "unsatisfied";
215
+ readonly awaiting: "user" | "upstream";
216
+ } | {
217
+ readonly state: "invalid";
218
+ readonly reason: NgisFlowReason;
219
+ };
220
+ /**
221
+ * The value forms a port can carry, by kind. `record` is flat by F14.5 — a
222
+ * nested record is not expressible and must not be invented, because F14.6's
223
+ * recipe `params` are flat and a nested one would not serialize.
224
+ */
225
+ export type NgisResolvedValue = string | number | boolean | readonly string[] | readonly [number, number, number, number] | Readonly<Record<string, string | number | boolean>> | NgisTaskRefValue;
226
+ /** What a `task` port carries: F14.4's reserved members, resolved. */
227
+ export interface NgisTaskRefValue {
228
+ readonly taskId: string;
229
+ readonly status: string;
230
+ readonly stage: string | null;
231
+ readonly outputs: readonly NgisTaskOutput[];
232
+ }
233
+ /**
234
+ * **Unbound is one predicate, in one place.** F14.10: absent, `null`, `""` and
235
+ * `[]` are all unbound, never "bound to empty". Both sessions need this and a
236
+ * second copy would be the W2 `toWireParams` lesson repeated — a satisfaction
237
+ * check that disagrees with a render check is a control that is enabled and
238
+ * refuses.
239
+ */
240
+ export declare function isNgisUnbound(value: unknown): boolean;
241
+ export type NgisTypeVerdict = "pass" | "warn" | "fail";
242
+ /**
243
+ * F14.1's client-side binding check, mirroring `ValidateToolBindings` and
244
+ * `WorkflowTypeCheckService` together. `"warn"` never blocks a run; `"fail"`
245
+ * blocks it with a generated reason (F14.10).
246
+ *
247
+ * Frozen here rather than in `flow-model.ts` because Y5b's port declarations
248
+ * need the same verdict a resolution reports, and because the `file` wildcard
249
+ * is bidirectional — the asymmetric reading (only `expected === "file"` widens)
250
+ * is the plausible wrong implementation.
251
+ */
252
+ export declare function ngisTypeVerdict(expected: NgisDataType, actual: NgisDataType): NgisTypeVerdict;
253
+ /**
254
+ * F14.10's three disclosure states, frozen. `pending` is the only one that
255
+ * dims; `blocked` renders normally with the action disabled.
256
+ */
257
+ export type NgisDisclosureState = "ready" | "blocked" | "pending";
258
+ /**
259
+ * A generated reason, as **data**. Y5a produces it, Y5b renders it — which is
260
+ * why it carries a message key and its placeholders rather than a string: a
261
+ * pure model cannot hold a `useTranslations`, and F14.10 requires the reason to
262
+ * be generated, never authored. The three keys are F14.10's, spelled verbatim,
263
+ * and the kickoff seeds them in both locales so neither session invents a
264
+ * fourth.
265
+ */
266
+ export type NgisFlowReason = {
267
+ readonly key: "GIS.flow.reason.unsatisfied";
268
+ readonly label: string;
269
+ /** Count of *further* unsatisfied required ports; `0` ⇒ no `.more` suffix. */
270
+ readonly more: number;
271
+ } | {
272
+ readonly key: "GIS.flow.reason.typeMismatch";
273
+ readonly label: string;
274
+ readonly expected: NgisDataType;
275
+ readonly actual: NgisDataType;
276
+ };
277
+ export declare const NGIS_FLOW_REASON_KEYS: readonly ["GIS.flow.reason.unsatisfied", "GIS.flow.reason.more", "GIS.flow.reason.typeMismatch"];
278
+ /**
279
+ * A node's derived enablement — F14.10 in one shape. `enabled` is
280
+ * `disclosure === "ready"`; both are carried because the render needs the
281
+ * state and the control needs the boolean, and deriving one from the other at
282
+ * two call sites is how they drift.
283
+ */
284
+ export interface NgisNodeEnablement {
285
+ readonly nodeId: string;
286
+ readonly enabled: boolean;
287
+ readonly disclosure: NgisDisclosureState;
288
+ /** `null` iff `enabled`. The **first** unsatisfied required port in
289
+ * declaration order, per F14.10 — ordering is declaration order and is
290
+ * fully deterministic. */
291
+ readonly reason: NgisFlowReason | null;
292
+ }
293
+ /**
294
+ * What `<Flow>` hands Y6, and the whole of it. Deliberately the *graph as
295
+ * declared* and not a recipe: F14.6 owns the recipe schema, and a snapshot that
296
+ * pre-shaped itself into recipe fields would put half of Y6's mapping in W3
297
+ * where no clause authorizes it. Y6 derives promoted inputs, node `params` and
298
+ * the `{graph,view}` envelope from this; W3 promises only that everything
299
+ * needed to do so is present and that the shape is stable.
300
+ */
301
+ export interface NgisFlowSnapshot {
302
+ readonly nodes: readonly NgisFlowNode[];
303
+ /** Resolutions at snapshot time, keyed by {@link ngisPortRef}. A saved recipe
304
+ * keeps bindings, not values — but Y6 needs the resolved side to decide
305
+ * which inputs *can* promote, and Y7's batch table needs it per row. */
306
+ readonly resolved: Readonly<Record<string, NgisPortResolution>>;
307
+ }
308
+ /**
309
+ * W3's `data-slot` additions. The eight W2 names stay in `w2-contracts.ts`;
310
+ * these two extend the same table, and the same rule applies — a duplicate
311
+ * makes `first-party-plugins/scripts/verify-externals.mjs`'s plugin-ui
312
+ * fingerprint ambiguous.
313
+ */
314
+ export declare const NGIS_W3_DATA_SLOTS: {
315
+ readonly flow: "ngis-flow";
316
+ readonly flowInspector: "ngis-flow-inspector";
317
+ };
318
+ /**
319
+ * The DOM attributes a node's ports render, already in use by W2's three
320
+ * `data-port-*` sites (`RunButton`, `TaskStatus`, `TaskList`). Frozen because
321
+ * the inspector and the harness both read them, and because they are the only
322
+ * way an e2e spec can see a port at all.
323
+ */
324
+ export declare const NGIS_PORT_ATTRIBUTES: {
325
+ readonly in: "data-port-in";
326
+ readonly out: "data-port-out";
327
+ readonly node: "data-flow-node";
328
+ };