@ngis/plugin-sdk 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +17 -1
- package/dist/index.mjs +1 -1
- package/dist/src/api/analysis.d.ts +38 -1
- package/dist/src/api/resources.d.ts +174 -10
- package/dist/src/api/scenes.d.ts +103 -4
- package/dist/src/domain/algorithms/flow-field-style.d.ts +68 -0
- package/dist/src/domain/algorithms/scene-layer-type.d.ts +12 -0
- package/dist/src/domain/map/rendered-layers.d.ts +1 -0
- package/dist/src/domain/map/types.d.ts +2 -0
- package/dist/src/domain/models/crs.d.ts +187 -0
- package/dist/src/domain/models/dataset-kind.d.ts +256 -0
- package/dist/src/domain/models/flow-field-style.d.ts +32 -0
- package/dist/src/domain/models/scene-layer-type.d.ts +28 -3
- package/dist/src/sdk/context/publishers.d.ts +37 -0
- package/dist/src/sdk/facets/types.d.ts +73 -2
- package/dist/src/sdk/map-api.d.ts +4 -1
- package/dist/src/sdk/plugin.d.ts +6 -0
- package/dist/src/sdk/scopes.d.ts +1 -0
- package/dist/src/systems/renderer/FlowFieldLayer.d.ts +9 -6
- package/dist/src/systems/renderer/flow-field/flow-field-resources.d.ts +3 -0
- package/dist/src/systems/renderer/flow-field/flow-field-shaders.d.ts +3 -3
- package/dist/src/types/analysis.d.ts +111 -7
- package/dist/src/types/extensions.d.ts +43 -0
- package/dist/src/types/gis.d.ts +1 -1
- package/package.json +3 -25
- package/LICENSE +0 -13
- package/README.md +0 -31
|
@@ -99,6 +99,8 @@ export interface SceneLayerHighlight {
|
|
|
99
99
|
allFeatures?: boolean;
|
|
100
100
|
/** Only meaningful with `allFeatures`; rows unchecked after select-all. */
|
|
101
101
|
excludedFeatureIds?: string[];
|
|
102
|
+
/** Optional MapLibre predicate narrowing an all-matching table selection. */
|
|
103
|
+
attributeFilter?: HighlightFilterExpression;
|
|
102
104
|
}
|
|
103
105
|
export type SceneLayerStyle = Record<string, unknown>;
|
|
104
106
|
export type SceneLayerRenderMode = "maplibre" | "custom-raster-color" | "custom-flow-field";
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage 25 (F25.1) — the frontend's CRS domain model.
|
|
3
|
+
*
|
|
4
|
+
* **Authored by the W1 kickoff: TYPES AND CONSTANTS ONLY. Read-only to every W1 session
|
|
5
|
+
* except S25-13, which owns this file and adds the function bodies below.**
|
|
6
|
+
*
|
|
7
|
+
* This is the TypeScript leg of the Stage 25 twin triple. The other two are `CrsDto`
|
|
8
|
+
* (ngis-file, `io.ngis.file.dto`) and `crs_ref.py` (ngis-geoanalysis). All three mirror
|
|
9
|
+
* `ngis-protos/crs.proto`'s `CrsRef` and the fixtures in `__fixtures__/crs/`, which are
|
|
10
|
+
* byte-identical across four copies (F25.14 — compare with `diff --strip-trailing-cr`,
|
|
11
|
+
* never an on-disk hash: the two repos normalise line endings differently).
|
|
12
|
+
*
|
|
13
|
+
* ## G-CRS lives here
|
|
14
|
+
*
|
|
15
|
+
* `key` is the identity and the only field a caller must round-trip. An absent CRS is
|
|
16
|
+
* `null` — never `key: ""`, never `epsg: 0`. Zero is not "unknown", it is absent. The whole
|
|
17
|
+
* stage exists because `crs.py:78` silently turned an undetectable vector CRS into 4326 and
|
|
18
|
+
* nothing downstream could tell the difference.
|
|
19
|
+
*
|
|
20
|
+
* @see docs/projection_management_stage/README.md — F25.1, F25.13 (frozen names)
|
|
21
|
+
*/
|
|
22
|
+
/** How a CRS came to be attached to a dataset. Never absent on a stored CRS (G-CRS). */
|
|
23
|
+
export type NgisCrsSource = "DETECTED" | "SPEC_DEFAULT" | "USER_ASSIGNED" | "DERIVED";
|
|
24
|
+
/**
|
|
25
|
+
* The display accessor over `NgisCrsRef.geographic`. The boolean is right on the wire, but
|
|
26
|
+
* `!ref.geographic` reads as a double negative at every UI call site (F25.13).
|
|
27
|
+
*/
|
|
28
|
+
export type NgisCrsKind = "geographic" | "projected";
|
|
29
|
+
/**
|
|
30
|
+
* What a tool requires of its inputs' CRS.
|
|
31
|
+
*
|
|
32
|
+
* `"uniform"` is **not** a member — D25-5 struck it. `"geographic"` is hand-authored only.
|
|
33
|
+
*/
|
|
34
|
+
export type NgisCrsRequirement = "any" | "projected" | "geographic";
|
|
35
|
+
/**
|
|
36
|
+
* Where a tool's `crsRequirement` came from. A `CLASSIFIER` requirement may only ever raise
|
|
37
|
+
* an **advisory** issue (R10 / D25-5 as amended): no classifier rule measured better than
|
|
38
|
+
* 0.800 precision, and a false `"projected"` refuses a run the user is entitled to make.
|
|
39
|
+
*/
|
|
40
|
+
export type NgisCrsRequirementSource = "HAND_AUTHORED" | "CLASSIFIER";
|
|
41
|
+
/** One coordinate reference system. `key` is `"EPSG:<code>"` or `"custom:<ulid>"`. */
|
|
42
|
+
export interface NgisCrsRef {
|
|
43
|
+
/** The identity, and the only field a caller must round-trip. */
|
|
44
|
+
readonly key: string;
|
|
45
|
+
/** Set iff `key` is an `EPSG:` ref. Never `0` — an absent CRS is a `null` ref. */
|
|
46
|
+
readonly epsg?: number;
|
|
47
|
+
/** Always on a resolved custom ref; on an EPSG ref only when asked. */
|
|
48
|
+
readonly wkt2?: string;
|
|
49
|
+
/** e.g. `"WGS 84 / UTM zone 50N"`. Present iff the oracle has resolved the ref. */
|
|
50
|
+
readonly name?: string;
|
|
51
|
+
readonly geographic?: boolean;
|
|
52
|
+
/** `"metre"` | `"degree"` | `"foot"` | `"us-foot"` | … */
|
|
53
|
+
readonly unit?: string;
|
|
54
|
+
readonly source?: NgisCrsSource;
|
|
55
|
+
}
|
|
56
|
+
/** Blocking refuses the submit with 400; advisory never gates Run (R9). */
|
|
57
|
+
export type NgisValidationIssueSeverity = "blocking" | "advisory";
|
|
58
|
+
/**
|
|
59
|
+
* Open by design — a later stage may add a code, and an unknown code must render as its
|
|
60
|
+
* `messageKey` rather than being dropped (the `ExtensionSettingsForm` rule, F14.9).
|
|
61
|
+
*/
|
|
62
|
+
export type NgisCrsIssueCode = "CRS_UNKNOWN" | "CRS_PROJECTED_REQUIRED" | "CRS_GEOGRAPHIC_REQUIRED" | "CRS_REPROJECT_NOTICE" | "CRS_UNSUPPORTED_BY_PROVIDER" | (string & {});
|
|
63
|
+
/** The one-click remedy attached to a blocking issue. Carries the `NgisPickerNotice.action`. */
|
|
64
|
+
export interface NgisValidationIssueFix {
|
|
65
|
+
/** The parameter the fix sets — e.g. `"ngis:outputCrs"`. */
|
|
66
|
+
readonly param: string;
|
|
67
|
+
readonly value: string;
|
|
68
|
+
/** Client-localised under `Crs.issues.fix.*`. */
|
|
69
|
+
readonly labelKey: string;
|
|
70
|
+
readonly params?: Readonly<Record<string, string | number>>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* A typed, per-parameter validation issue (F25.6). **Additive** to F14.9's string arrays:
|
|
74
|
+
* `missingParameters` / `parameterErrors` / `outputErrors` / `warnings` keep their meaning.
|
|
75
|
+
*
|
|
76
|
+
* `param` routes it to that field's `notices`; `port` routes it to that input port.
|
|
77
|
+
*/
|
|
78
|
+
export interface NgisValidationIssue {
|
|
79
|
+
readonly code: NgisCrsIssueCode;
|
|
80
|
+
readonly severity: NgisValidationIssueSeverity;
|
|
81
|
+
/** Client-localised under `Crs.issues.*`. */
|
|
82
|
+
readonly messageKey: string;
|
|
83
|
+
readonly params?: Readonly<Record<string, string | number>>;
|
|
84
|
+
readonly param?: string;
|
|
85
|
+
readonly port?: string;
|
|
86
|
+
readonly fix?: NgisValidationIssueFix;
|
|
87
|
+
readonly crs?: {
|
|
88
|
+
readonly input?: NgisCrsRef;
|
|
89
|
+
readonly suggested?: NgisCrsRef;
|
|
90
|
+
readonly compute?: NgisCrsRef;
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** One input as the compiled plan sees it. */
|
|
94
|
+
export interface NgisCrsPlanInput {
|
|
95
|
+
readonly port: string;
|
|
96
|
+
/** The CRS the stored dataset is in. */
|
|
97
|
+
readonly from: string;
|
|
98
|
+
/** The CRS it is staged into for this run. Equal to `from` when no staging is needed. */
|
|
99
|
+
readonly to: string;
|
|
100
|
+
/** Written back as a cached export variant above `STAGING_CACHE_MIN_BYTES` (20 MiB). */
|
|
101
|
+
readonly cacheable?: boolean;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The server-compiled CRS plan (F25.4). Every executor path executes **this** rather than
|
|
105
|
+
* re-deriving a CRS from dataset metadata or a fallback — that is G-U.
|
|
106
|
+
*
|
|
107
|
+
* `null` whenever a blocking issue was raised (R9).
|
|
108
|
+
*/
|
|
109
|
+
export interface NgisCrsPlan {
|
|
110
|
+
/** The CRS the run computes in. */
|
|
111
|
+
readonly computeCrs: string;
|
|
112
|
+
/**
|
|
113
|
+
* The integer that reaches the PostGIS SQL, the `-t_srs` of ogr2ogr/gdalwarp and the
|
|
114
|
+
* iObjects `inputSrids`: the EPSG code, or the registry's `spatial_ref_sys` srid
|
|
115
|
+
* (>= 900001) for a custom CRS. No executor re-derives it (R7).
|
|
116
|
+
*/
|
|
117
|
+
readonly pgSrid: number;
|
|
118
|
+
/** The CRS the result is registered in. */
|
|
119
|
+
readonly resultCrs: string;
|
|
120
|
+
/** Always `"DERIVED"` when present (R6). */
|
|
121
|
+
readonly resultCrsSource?: NgisCrsSource;
|
|
122
|
+
/** One entry per input that had to be reprojected for the run. Staging never mutates storage. */
|
|
123
|
+
readonly stage: readonly NgisCrsPlanInput[];
|
|
124
|
+
}
|
|
125
|
+
/** The one platform projection parameter, injected into every tool's UI schema (F25.4). */
|
|
126
|
+
export declare const NGIS_OUTPUT_CRS_PARAM = "ngis:outputCrs";
|
|
127
|
+
/** `x-role` of a synthetic platform parameter. `w2-fixture.test.ts:252` excludes these. */
|
|
128
|
+
export declare const NGIS_PLATFORM_ROLE = "platform";
|
|
129
|
+
/**
|
|
130
|
+
* The identifier half of the chip, alone — `"EPSG:32650"`, `"Custom"`, or the
|
|
131
|
+
* NEEDS_CRS text. It exists so the chip, the table cell and the picker footer
|
|
132
|
+
* cannot drift: `formatCrs` is this plus the name, never a second spelling.
|
|
133
|
+
*
|
|
134
|
+
* **G-CRS.** A bare integer is never returned. A key that *is* a bare integer —
|
|
135
|
+
* which is what a server still on the old numeric `srid` would send — is
|
|
136
|
+
* rendered `EPSG:<n>`, because the one thing the user must never see is a naked
|
|
137
|
+
* number they cannot tell from a feature count.
|
|
138
|
+
*/
|
|
139
|
+
export declare function formatCrsKey(key: string | null, needsCrsText?: string): string;
|
|
140
|
+
/**
|
|
141
|
+
* The full chip string — `"EPSG:32650 · WGS 84 / UTM zone 50N"`, `"Custom · <name>"`.
|
|
142
|
+
*
|
|
143
|
+
* **This is where G-CRS lives on the client.** It never prints a bare integer,
|
|
144
|
+
* and `formatCrs(null)` returns the NEEDS_CRS text — never `"-"`, and never
|
|
145
|
+
* `"EPSG:4326"`, which is the silent default the whole stage exists to remove.
|
|
146
|
+
* A ref whose oracle lookup has not happened yet has no `name`, and renders as
|
|
147
|
+
* its identifier alone rather than borrowing one.
|
|
148
|
+
*/
|
|
149
|
+
export declare function formatCrs(ref: NgisCrsRef | null, needsCrsText?: string): string;
|
|
150
|
+
/**
|
|
151
|
+
* `true` only for a ref the oracle has resolved *and* reported as projected.
|
|
152
|
+
*
|
|
153
|
+
* An **unresolved** ref (no `geographic`) is `false` here, exactly as
|
|
154
|
+
* `crs_ref.py`'s `.projected` is — but it is never `true`, so "we have not asked
|
|
155
|
+
* yet" can never read as "this is safe to measure distance in". That asymmetry
|
|
156
|
+
* is G-U, restated in one predicate.
|
|
157
|
+
*/
|
|
158
|
+
export declare function isProjectedCrs(ref: NgisCrsRef | null): boolean;
|
|
159
|
+
/**
|
|
160
|
+
* The display accessor over `NgisCrsRef.geographic` (F25.13). The boolean is
|
|
161
|
+
* right on the wire; `!ref.geographic` reads as a double negative at every UI
|
|
162
|
+
* call site, and a UI that has to negate to say "projected" eventually forgets to.
|
|
163
|
+
*
|
|
164
|
+
* Reports `"projected"` on exactly the refs {@link isProjectedCrs} accepts, so
|
|
165
|
+
* the two cannot drift. An unresolved ref reports `"geographic"` — the
|
|
166
|
+
* conservative half — and the chip draws it with the unknown sigil instead,
|
|
167
|
+
* because {@link crsUnitGlyph} has no unit to show.
|
|
168
|
+
*/
|
|
169
|
+
export declare function crsKind(ref: NgisCrsRef): NgisCrsKind;
|
|
170
|
+
/**
|
|
171
|
+
* The unit sigil's glyph: `°` · `m` · `ft` · `?`.
|
|
172
|
+
*
|
|
173
|
+
* Exported because the sigil is drawn in five places (full chip, compact chip,
|
|
174
|
+
* picker trigger, list row, "needs projection" filter) and an inlined map would
|
|
175
|
+
* drift between them. `"?"` is the honest answer for both an absent ref and a
|
|
176
|
+
* unit no client mapping knows — a guessed glyph on an unknown unit is exactly
|
|
177
|
+
* the silent default this stage removes.
|
|
178
|
+
*/
|
|
179
|
+
export declare function crsUnitGlyph(ref: NgisCrsRef | null): string;
|
|
180
|
+
/**
|
|
181
|
+
* The wire value — the ref's `key`, or `null`. This is what the `crs` widget
|
|
182
|
+
* puts in the params payload and what `PUT /api/datasets/{id}/crs` echoes.
|
|
183
|
+
*
|
|
184
|
+
* An empty-string key is `null`, not `""`: `key: ""` is not a CRS, and letting
|
|
185
|
+
* it through is how an absent CRS gets laundered into a present one.
|
|
186
|
+
*/
|
|
187
|
+
export declare function crsKeyOf(ref: NgisCrsRef | null): string | null;
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage 29 (F29.1 / F29.4 / F29.5 / F29.7 / F29.9) — the frontend's dataset-kind
|
|
3
|
+
* domain model.
|
|
4
|
+
*
|
|
5
|
+
* **This module is the one place in the client that names a dataset kind.** It is
|
|
6
|
+
* the F25.1 `crs.ts` precedent applied to the second vocabulary this platform
|
|
7
|
+
* spelled seven ways: a dataset's kind was spelled seven different ways, in three
|
|
8
|
+
* casings, derived from four different source fields, and no two of the seven had
|
|
9
|
+
* the same membership. After Stage 29 there is **one** derivation chain — the
|
|
10
|
+
* server's `datasetType` — and `G-KIND` is the rule that nothing outside a
|
|
11
|
+
* registry module branches on a kind id.
|
|
12
|
+
*
|
|
13
|
+
* Every shape below mirrors the frozen fixtures in
|
|
14
|
+
* `src/domain/models/__fixtures__/dataset-kind/`, which are byte-identical copies
|
|
15
|
+
* of `ngis-backend/stages/29-resource-plane/fixtures/` (F29.10 — compare with
|
|
16
|
+
* `diff --strip-trailing-cr`, never an on-disk hash: the two repos normalise line
|
|
17
|
+
* endings differently).
|
|
18
|
+
*
|
|
19
|
+
* ## The three-state rule lives here
|
|
20
|
+
*
|
|
21
|
+
* {@link NgisKindCapabilities} is a `Partial<>` and that is **load-bearing**
|
|
22
|
+
* (F29.4, inheriting F25.8). A flag **absent** from the block means *the server
|
|
23
|
+
* has not said*; `{supported: false, reasonKey}` means *this kind cannot*;
|
|
24
|
+
* `{supported: true, reasonKey: null}` means *it can*. A client that coalesces
|
|
25
|
+
* absent into `false` has re-introduced exactly the defect Stage 26 paid to
|
|
26
|
+
* learn — which is why {@link datasetKindCapability} is the only supported way to
|
|
27
|
+
* read a flag and why it returns `undefined` rather than fabricating a record.
|
|
28
|
+
*
|
|
29
|
+
* @see ngis-backend/stages/29-resource-plane/F29-contract.md — F29.1, F29.4,
|
|
30
|
+
* F29.5, F29.7, F29.9 (frozen names)
|
|
31
|
+
* @see docs/resource_plane_stage/README.md — the frontend plan of record
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* **The one client dataset-kind type (F29.1).** The wire field keeps its shipped
|
|
35
|
+
* name, `datasetType`, and its value is a registered kind id in UPPERCASE
|
|
36
|
+
* `SNAKE_CASE`.
|
|
37
|
+
*
|
|
38
|
+
* **The union is OPEN, and that is the whole point.** `D29-1` makes a kind
|
|
39
|
+
* *registered data*, so a client shipped today must render a kind registered
|
|
40
|
+
* tomorrow. The three named members exist for autocomplete and for the
|
|
41
|
+
* exhaustiveness of *today's* switch statements — they are **not** a membership
|
|
42
|
+
* assertion, and **no test may assert that the set of kinds equals those three**.
|
|
43
|
+
* (Stage 15's `Market.*` sub-namespace lesson, which cost a session on three
|
|
44
|
+
* consecutive waves: a closed-world assertion breaks on every sibling merge.)
|
|
45
|
+
*
|
|
46
|
+
* `null` — not a member of this union — keeps exactly one meaning after F29.3:
|
|
47
|
+
* *no kind resolved* (`status: "NEEDS_KIND"`). `"GENERIC"` is gone from the wire;
|
|
48
|
+
* a non-geo file reports `datasetType: null` with `status: "N/A"`.
|
|
49
|
+
*/
|
|
50
|
+
export type NgisDatasetKind = "VECTOR" | "RASTER" | "FLOW_FIELD" | (string & {});
|
|
51
|
+
/**
|
|
52
|
+
* **The six capability flags, frozen (F29.4).**
|
|
53
|
+
*
|
|
54
|
+
* `renderable` is deliberately **not** a member, and that is not an oversight:
|
|
55
|
+
* `renderable` is a server-computed property of a dataset *row*
|
|
56
|
+
* (`ready && geometryType != null && capabilities.tileable.supported === true`,
|
|
57
|
+
* F29.6), never a declared capability of a *kind*. Stage 28 ships a
|
|
58
|
+
* `capabilities.renderable` on a **symbol template**, an unrelated object that
|
|
59
|
+
* happens to share the field name; keeping `renderable` out of this union is what
|
|
60
|
+
* stops a symbol payload from satisfying a dataset capability block
|
|
61
|
+
* (`S29-V073`).
|
|
62
|
+
*/
|
|
63
|
+
export type NgisCapabilityFlag = "tileable" | "analyzable" | "shareable" | "copyable" | "quotaCountable" | "exportable";
|
|
64
|
+
/** The six flags in the F29.4 order. */
|
|
65
|
+
export declare const NGIS_CAPABILITY_FLAGS: readonly NgisCapabilityFlag[];
|
|
66
|
+
/**
|
|
67
|
+
* One declared capability of a kind (F29.4 / F29.5).
|
|
68
|
+
*
|
|
69
|
+
* **A boolean cannot say why a control is greyed**, which is why this is a record
|
|
70
|
+
* and never a bare boolean. `reasonKey` is an **i18n key the client localises** —
|
|
71
|
+
* the server never sends display text for a capability refusal — and `params`
|
|
72
|
+
* carries its interpolation values. The in-repo precedent is shipped:
|
|
73
|
+
* `ValidationIssue.message_key` / `params_json` and `IssueFix.label_key` /
|
|
74
|
+
* `params_json` (`ngis-protos/geoanalysis.proto:553-572`); `IssueFix.params_json`
|
|
75
|
+
* exists *because* a key without its interpolation values made the gRPC and REST
|
|
76
|
+
* twins of one fixture disagree.
|
|
77
|
+
*/
|
|
78
|
+
export interface NgisCapability {
|
|
79
|
+
supported: boolean;
|
|
80
|
+
/** Required when `supported === false`; **must** be `null` when `true`. */
|
|
81
|
+
reasonKey: string | null;
|
|
82
|
+
/** Interpolation values for `reasonKey`; `{}` when the key takes none. */
|
|
83
|
+
params: Record<string, unknown>;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A kind's declared capability block (F29.4).
|
|
87
|
+
*
|
|
88
|
+
* **`Partial<>` is load-bearing — there are three states, not two.** An absent
|
|
89
|
+
* flag means *the server has not said*, and it must never render as
|
|
90
|
+
* *this kind cannot*. Read a flag with {@link datasetKindCapability} and nothing
|
|
91
|
+
* else.
|
|
92
|
+
*
|
|
93
|
+
* `{}` is the **empty** block and differs from an absent block: it means *no kind
|
|
94
|
+
* resolved, therefore no declared capabilities* (`fx-ds-0003`, `status:
|
|
95
|
+
* "NEEDS_KIND"`). Every flag is then in its third state.
|
|
96
|
+
*
|
|
97
|
+
* The block describes the **kind**, not the row's readiness. A `NEEDS_CRS` vector
|
|
98
|
+
* is still `tileable: true`; it is `ready: false` that stops it rendering.
|
|
99
|
+
* Conflating the two is how `renderable` came to name three kinds.
|
|
100
|
+
*/
|
|
101
|
+
export type NgisKindCapabilities = Partial<Record<NgisCapabilityFlag, NgisCapability>>;
|
|
102
|
+
/**
|
|
103
|
+
* Read one declared capability — **the only supported way to read a flag.**
|
|
104
|
+
*
|
|
105
|
+
* Returns `undefined` for an absent flag and **never fabricates
|
|
106
|
+
* `{supported: false}`**. That is F29.4's three-state rule enforced in one
|
|
107
|
+
* function so no call site can get it wrong; a caller that wants a boolean must
|
|
108
|
+
* decide, explicitly and at its own site, what *"the server has not said"* means
|
|
109
|
+
* for the control it is drawing.
|
|
110
|
+
*
|
|
111
|
+
* The flag argument is typed {@link NgisCapabilityFlag}, so
|
|
112
|
+
* `datasetKindCapability(caps, "renderable")` is a **compile error**
|
|
113
|
+
* (`S29-V073`).
|
|
114
|
+
*/
|
|
115
|
+
export declare function datasetKindCapability(caps: NgisKindCapabilities | null | undefined, flag: NgisCapabilityFlag): NgisCapability | undefined;
|
|
116
|
+
/**
|
|
117
|
+
* Why a dataset's time axis is or is not known (F29.7, `D29-3` generalised from
|
|
118
|
+
* CRS).
|
|
119
|
+
*
|
|
120
|
+
* There are **four** states, and the fourth is the `temporalExtent` field itself
|
|
121
|
+
* being `null`, which means *the server has not said* (F25.8) — distinct from
|
|
122
|
+
* `NOT_APPLICABLE`, which means *this kind has no time axis*.
|
|
123
|
+
*/
|
|
124
|
+
export type NgisTemporalExtentState = "RESOLVED" | "UNRESOLVABLE" | "NOT_APPLICABLE";
|
|
125
|
+
/**
|
|
126
|
+
* A dataset's temporal extent (F29.7).
|
|
127
|
+
*
|
|
128
|
+
* **Never a bare range.** A defaulted range — epoch-to-now, the file's mtime,
|
|
129
|
+
* anything — is a contract violation, not a fallback (`D29-3`). `fx-ds-0005` is
|
|
130
|
+
* the fixture that proves it: `start` and `end` are `null` **and** `state` says
|
|
131
|
+
* why.
|
|
132
|
+
*
|
|
133
|
+
* What each state renders as (F29.7, frozen because `D29-3` forbids a default):
|
|
134
|
+
*
|
|
135
|
+
* | State | Renders as |
|
|
136
|
+
* |---|---|
|
|
137
|
+
* | the field is `null` | the temporal row is **not rendered at all** |
|
|
138
|
+
* | `NOT_APPLICABLE` | the temporal row is **not rendered at all** |
|
|
139
|
+
* | `UNRESOLVABLE` | the row renders, with the localised `reasonKey` where the range would be — never a dash, never an empty range |
|
|
140
|
+
* | `RESOLVED` | the range |
|
|
141
|
+
*
|
|
142
|
+
* `null` and `NOT_APPLICABLE` render identically **on purpose**: there is nothing
|
|
143
|
+
* useful to say to a user in either case. They stay distinct **on the wire**,
|
|
144
|
+
* because a test must be able to tell them apart and the array stage will need to.
|
|
145
|
+
*/
|
|
146
|
+
export interface NgisTemporalExtent {
|
|
147
|
+
state: NgisTemporalExtentState;
|
|
148
|
+
/** ISO 8601; non-null iff `state === "RESOLVED"`. */
|
|
149
|
+
start: string | null;
|
|
150
|
+
/** ISO 8601; non-null iff `state === "RESOLVED"`. */
|
|
151
|
+
end: string | null;
|
|
152
|
+
/** An i18n key; non-null iff `state === "UNRESOLVABLE"`. */
|
|
153
|
+
reasonKey: string | null;
|
|
154
|
+
params: Record<string, unknown>;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Where a dataset came from (F29.7, `D29-5`).
|
|
158
|
+
*
|
|
159
|
+
* `authority` is `AUTHORITY` or `DERIVED`, never both. A `DERIVED` dataset
|
|
160
|
+
* carries `rebuildableFrom`; an `AUTHORITY` one carries `null` there.
|
|
161
|
+
*
|
|
162
|
+
* `sourceFileId` is **not** unique across datasets: `fx-ds-0005` and `fx-ds-0006`
|
|
163
|
+
* share one. That is `D29-2` — one file, many datasets.
|
|
164
|
+
*/
|
|
165
|
+
export interface NgisDatasetLineage {
|
|
166
|
+
authority: "AUTHORITY" | "DERIVED";
|
|
167
|
+
sourceFileId: string | null;
|
|
168
|
+
derivedFromFileId: string | null;
|
|
169
|
+
producedByTaskId: string | null;
|
|
170
|
+
/** Non-null iff `authority === "DERIVED"`. */
|
|
171
|
+
rebuildableFrom: string | null;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* The array plane's placeholder (F29.7, `D29-S1`).
|
|
175
|
+
*
|
|
176
|
+
* **Deliberately typed `null` and nothing else.** `dimensions` is declared on the
|
|
177
|
+
* wire so the array stage needs no second migration and no second contract
|
|
178
|
+
* freeze, and it is `null` for every kind Stage 29 registers. Typing it as the
|
|
179
|
+
* `null` literal makes *"a session that builds a time slider off it is out of
|
|
180
|
+
* contract"* a compile error rather than a code-review note; widening this alias
|
|
181
|
+
* is the array stage's job and nobody else's.
|
|
182
|
+
*/
|
|
183
|
+
export type NgisDatasetDimensions = null;
|
|
184
|
+
/**
|
|
185
|
+
* **The dataset spine (F29.7), as one nominal shape.**
|
|
186
|
+
*
|
|
187
|
+
* *Recorded extra export, not in F29.9's table — see the S29-14 session note.*
|
|
188
|
+
* It exists for `S29-V073`: `renderable` and `ready` are members of a record that
|
|
189
|
+
* also requires `datasetType`, `status` and `lineage`, so a Stage 28 **symbol
|
|
190
|
+
* template** — which carries `capabilities.renderable` and none of those — cannot
|
|
191
|
+
* resolve against the client's **dataset** `renderable`. Two unrelated objects
|
|
192
|
+
* share one field name; this type and {@link NgisCapabilityFlag}'s exclusion of
|
|
193
|
+
* `renderable` are the two independent guards that keep them apart.
|
|
194
|
+
*
|
|
195
|
+
* `ready` and `renderable` are server-computed and keep their names (F29.6):
|
|
196
|
+
*
|
|
197
|
+
* ```
|
|
198
|
+
* ready = status ∈ kind.readyStates
|
|
199
|
+
* renderable = ready && geometryType != null && capabilities.tileable.supported === true
|
|
200
|
+
* ```
|
|
201
|
+
*
|
|
202
|
+
* Both are optional, and `undefined` ("the server has not said") must never render
|
|
203
|
+
* the same as `false` ("this kind cannot be tiled") — `SceneWorkspaceLayers.tsx`'s
|
|
204
|
+
* `resolveLayerCrs` is the in-repo precedent and its comment states the rule.
|
|
205
|
+
*/
|
|
206
|
+
export interface NgisDatasetSpine {
|
|
207
|
+
/** `null` means *no kind resolved* — the only meaning `null` carries (F29.3). */
|
|
208
|
+
datasetType: NgisDatasetKind | null;
|
|
209
|
+
/**
|
|
210
|
+
* **An OPEN vocabulary (F29.7 R2).** A consumer that does not recognise a
|
|
211
|
+
* status renders the **raw token**, never `UNKNOWN`. The measured hazard is
|
|
212
|
+
* live: `ngis-file`'s `FileService` normalises a status through a whitelist
|
|
213
|
+
* whose default arm is `UNKNOWN`, so a `NEEDS_CRS` dataset already reports as
|
|
214
|
+
* `UNKNOWN` on the library listing — *"we know exactly what is wrong with it"*
|
|
215
|
+
* collapsed into *"we do not know"*, which is the very thing `D29-3` forbids.
|
|
216
|
+
*/
|
|
217
|
+
status: string;
|
|
218
|
+
capabilities?: NgisKindCapabilities;
|
|
219
|
+
temporalExtent?: NgisTemporalExtent | null;
|
|
220
|
+
dimensions?: NgisDatasetDimensions;
|
|
221
|
+
lineage?: NgisDatasetLineage | null;
|
|
222
|
+
ready?: boolean;
|
|
223
|
+
renderable?: boolean;
|
|
224
|
+
}
|
|
225
|
+
/** The minimum an issue must carry for {@link isKindAdaptableIssue} to judge it. */
|
|
226
|
+
export interface NgisIssueCodeCarrier {
|
|
227
|
+
code?: string | null;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* F29.8's rule A1, in one place: is this the **kind** adaptation, or Stage 26's
|
|
231
|
+
* **CRS** one?
|
|
232
|
+
*
|
|
233
|
+
* `"ADAPTABLE"` is the same verdict token for both. **Only the issue code
|
|
234
|
+
* distinguishes them** — a test that asserts only `verdict === "ADAPTABLE"`
|
|
235
|
+
* passes on a CRS adaptation and proves Stage 26's code path, not this stage's.
|
|
236
|
+
*
|
|
237
|
+
* The client never re-classifies a server verdict or severity (`G-U`): this is a
|
|
238
|
+
* predicate over a code the server sent, and nothing more.
|
|
239
|
+
*/
|
|
240
|
+
export declare function isKindAdaptableIssue(issue: NgisIssueCodeCarrier | null | undefined): boolean;
|
|
241
|
+
/**
|
|
242
|
+
* The kind → scene-layer resource-kind projection.
|
|
243
|
+
*
|
|
244
|
+
* *Recorded extra export, not in F29.9's table — see the S29-14 session note.*
|
|
245
|
+
* It is what F29.1 row 6 means by *"S29-14 delegates it to `NgisDatasetKind`"*:
|
|
246
|
+
* `SceneLayerResourceKind` used to be reached by `geometry.includes("raster")`, a
|
|
247
|
+
* substring match on a geometry string, and that is a guess. The spine now
|
|
248
|
+
* carries the answer, and this is the one place the answer is projected onto the
|
|
249
|
+
* two-value vocabulary the scene-layer type table is written in.
|
|
250
|
+
*
|
|
251
|
+
* Returns `null` for a kind that is neither — including an unregistered kind the
|
|
252
|
+
* client has never seen, which is `NgisDatasetKind` being open — so a caller must
|
|
253
|
+
* decide what *"I cannot place this kind"* means rather than being handed
|
|
254
|
+
* `"vector"` by default.
|
|
255
|
+
*/
|
|
256
|
+
export declare function sceneLayerResourceKindOfDatasetKind(kind: NgisDatasetKind | null | undefined): "vector" | "raster" | null;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** Canonical, per-scene-layer presentation state for a FLOW_FIELD resource. */
|
|
2
|
+
export interface FlowFieldColorRamp {
|
|
3
|
+
/** A UI hint only. `colors` is the renderer authority. */
|
|
4
|
+
presetId: string;
|
|
5
|
+
/** Low-speed to high-speed colors. */
|
|
6
|
+
colors: string[];
|
|
7
|
+
}
|
|
8
|
+
export type FlowFieldSpeedRange = {
|
|
9
|
+
mode: "data";
|
|
10
|
+
} | {
|
|
11
|
+
mode: "manual";
|
|
12
|
+
min: number;
|
|
13
|
+
max: number;
|
|
14
|
+
};
|
|
15
|
+
export interface FlowFieldStyle {
|
|
16
|
+
renderer: "flow-field";
|
|
17
|
+
styleVersion: 1;
|
|
18
|
+
/** Compatibility-only identity for scenes created before SceneResource links. */
|
|
19
|
+
flowFieldId?: string;
|
|
20
|
+
opacity: number;
|
|
21
|
+
colorRamp: FlowFieldColorRamp;
|
|
22
|
+
speedRange: FlowFieldSpeedRange;
|
|
23
|
+
speedFactor: number;
|
|
24
|
+
particleCount: number;
|
|
25
|
+
lineWidth: number;
|
|
26
|
+
trailLength: number;
|
|
27
|
+
frameDurationMs: number;
|
|
28
|
+
paused: boolean;
|
|
29
|
+
maxParticleAge: number;
|
|
30
|
+
dropRate: number;
|
|
31
|
+
dropRateBump: number;
|
|
32
|
+
}
|
|
@@ -1,10 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
import type { sceneLayerResourceKindOfDatasetKind } from "./dataset-kind";
|
|
2
|
+
export declare const SCENE_LAYER_TYPE_IDS: readonly ["MAPLIBRE_FILL", "MAPLIBRE_LINE", "MAPLIBRE_CIRCLE", "MAPLIBRE_RASTER", "CUSTOM_FLOW_FIELD", "DECK_MVT_POLYGON", "DECK_MVT_EXTRUDED_POLYGON", "DECK_COLUMN", "DECK_HEATMAP", "DECK_HEXAGON", "DECK_MVT_LINE", "DECK_MVT_POINT", "SYMBOL_POINT", "SYMBOL_LINE", "SYMBOL_POLYGON", "PLOTTING_SYMBOL", "DYNAMIC_LINE"];
|
|
2
3
|
export type SceneLayerTypeId = (typeof SCENE_LAYER_TYPE_IDS)[number];
|
|
3
4
|
export type LegacySceneLayerTypeId = "VECTOR" | "RASTER";
|
|
4
5
|
export type SceneLayerRendererKind = "maplibre" | "deck" | "custom";
|
|
5
|
-
|
|
6
|
+
/**
|
|
7
|
+
* **RETIRED as an independent vocabulary (F29.1 row 6).**
|
|
8
|
+
*
|
|
9
|
+
* It was one of the seven spellings of a dataset's kind, and the worst-founded
|
|
10
|
+
* of them: nothing declared it, it was *reached* by `geometry.includes("raster")`
|
|
11
|
+
* — a substring match on a geometry string — so a resource whose geometry string
|
|
12
|
+
* was merely non-empty classified as `"vector"`. The spine now carries the
|
|
13
|
+
* answer, and the one projection from it lives in
|
|
14
|
+
* {@link sceneLayerResourceKindOfDatasetKind}.
|
|
15
|
+
*
|
|
16
|
+
* The **name and the two lowercase values stay**, because this is the vocabulary
|
|
17
|
+
* the layer-type table below is written in and renaming it is out of contract
|
|
18
|
+
* (F29.1's rule for row 1 applies equally here). What is retired is its
|
|
19
|
+
* *derivation*: it is now defined as the return of the one projection, so it can
|
|
20
|
+
* never again drift from {@link NgisDatasetKind} by being re-typed by hand, and
|
|
21
|
+
* widening it is a change to that function and nowhere else.
|
|
22
|
+
*
|
|
23
|
+
* It is a **layer-compatibility** vocabulary, not a kind: it answers *"which
|
|
24
|
+
* renderers can draw this"*, which is why it is deliberately narrower than the
|
|
25
|
+
* open kind union — a kind registered tomorrow projects to `null` here and the
|
|
26
|
+
* caller must decide what that means, rather than being handed `"vector"`.
|
|
27
|
+
*/
|
|
28
|
+
export type SceneLayerResourceKind = NonNullable<ReturnType<typeof sceneLayerResourceKindOfDatasetKind>>;
|
|
6
29
|
export type SceneLayerGeometryFamily = "point" | "line" | "polygon" | "raster";
|
|
7
|
-
export type SceneLayerStyleKind = "maplibre-fill" | "maplibre-line" | "maplibre-circle" | "maplibre-raster" | "custom-flow-field" | "deck-mvt-polygon" | "deck-mvt-extruded-polygon" | "deck-column" | "deck-heatmap" | "deck-hexagon" | "deck-mvt-line" | "deck-mvt-point" | "symbol"
|
|
30
|
+
export type SceneLayerStyleKind = "maplibre-fill" | "maplibre-line" | "maplibre-circle" | "maplibre-raster" | "custom-flow-field" | "deck-mvt-polygon" | "deck-mvt-extruded-polygon" | "deck-column" | "deck-heatmap" | "deck-hexagon" | "deck-mvt-line" | "deck-mvt-point" | "symbol"
|
|
31
|
+
/** S28: no-resource Canvas runtime, deliberately not a Stage 25 symbol style. */
|
|
32
|
+
| "plotting" | "dynamic-line";
|
|
8
33
|
export interface SceneLayerTypeDefinition {
|
|
9
34
|
id: SceneLayerTypeId;
|
|
10
35
|
label: string;
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
* unrelated store write (a loading flag, a style draft) costs one reference
|
|
18
18
|
* compare rather than a re-derivation and a notification.
|
|
19
19
|
*/
|
|
20
|
+
import { type NgisDatasetKind } from "../../domain/models/dataset-kind";
|
|
20
21
|
import type { NgisUnsubscribe } from "../map-api";
|
|
21
22
|
import { type NgisContextValue, type NgisResourceType } from "./keys";
|
|
22
23
|
import type { NgisContextStore } from "./store";
|
|
@@ -41,8 +42,23 @@ export interface SceneContextResource {
|
|
|
41
42
|
* `"Raster"` for a RASTER dataset, the vector geometry type for a VECTOR
|
|
42
43
|
* one, and `null` for everything else — which is the signal
|
|
43
44
|
* `classifySceneResourceType` reads.
|
|
45
|
+
*
|
|
46
|
+
* **Stage 29 (F29.1 row 6):** it is no longer the *first* signal. See
|
|
47
|
+
* {@link SceneContextResource.datasetType}.
|
|
44
48
|
*/
|
|
45
49
|
geometryType?: string | null;
|
|
50
|
+
/**
|
|
51
|
+
* `SceneResourceDto.datasetType` — the registered kind id, and **the answer
|
|
52
|
+
* this publisher should be reading** (F29.1 row 6).
|
|
53
|
+
*
|
|
54
|
+
* Optional because the producer is `createSceneStore()`
|
|
55
|
+
* (`src/store/scene-store.ts`), which `S29-15` owns and which does not carry it
|
|
56
|
+
* onto this slice yet. Until it does, {@link classifySceneResourceType} falls
|
|
57
|
+
* back to the geometry-string guess — absent is *"the store has not said"*, not
|
|
58
|
+
* *"this resource has no kind"*, so the fallback is a third state and not a
|
|
59
|
+
* default.
|
|
60
|
+
*/
|
|
61
|
+
datasetType?: NgisDatasetKind | null;
|
|
46
62
|
}
|
|
47
63
|
export interface SceneContextScene {
|
|
48
64
|
id: string;
|
|
@@ -79,6 +95,27 @@ export interface AuthContextSlice {
|
|
|
79
95
|
* → `"vector"`, absent → `"file"` (which covers `GENERIC` and a dataset whose
|
|
80
96
|
* metadata fetch failed). The authoritative join lives in X2's
|
|
81
97
|
* `host.resources` facet; wiring this publisher to it is backlog row **V-21**.
|
|
98
|
+
*
|
|
99
|
+
* ## Classifier disposition (F29.1 row 6): DELEGATES, with a fallback
|
|
100
|
+
*
|
|
101
|
+
* The `geometry.includes("raster")` line below is **the substring match F29.1
|
|
102
|
+
* retires** — a guess about a dataset's kind made from a geometry string, which
|
|
103
|
+
* answered `"vector"` for anything non-empty that did not contain the letters
|
|
104
|
+
* `raster`. The kind id now answers first, through
|
|
105
|
+
* {@link sceneLayerResourceKindOfDatasetKind}, which is the one place the
|
|
106
|
+
* projection lives.
|
|
107
|
+
*
|
|
108
|
+
* The guess survives **only** as the `datasetType`-absent arm, because the
|
|
109
|
+
* producer of this slice is `src/store/scene-store.ts` — `S29-15`'s file, not
|
|
110
|
+
* this session's — so the field cannot be populated here. When `S29-15` carries
|
|
111
|
+
* it onto the slice, every branch below the first becomes unreachable for an
|
|
112
|
+
* enriched scene and the guess can be deleted outright. Carried as `S29-V108`.
|
|
113
|
+
*
|
|
114
|
+
* A kind that projects to neither `vector` nor `raster` — including a kind
|
|
115
|
+
* registered after this client shipped — falls through to the geometry arm
|
|
116
|
+
* rather than to `"file"`, because an unregistered *kind* is not evidence that
|
|
117
|
+
* the resource has no *geometry*; that is the same absent-is-not-false rule
|
|
118
|
+
* F29.4 states for capability flags.
|
|
82
119
|
*/
|
|
83
120
|
export declare function classifySceneResourceType(resource: SceneContextResource): NgisResourceType;
|
|
84
121
|
/**
|