@ngis/plugin-sdk 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 (70) hide show
  1. package/LICENSE +13 -0
  2. package/README.md +31 -0
  3. package/dist/index.cjs +76 -0
  4. package/dist/index.d.ts +77 -0
  5. package/dist/index.mjs +102 -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/domain/algorithms/deck-layer-style.d.ts +34 -0
  11. package/dist/src/domain/algorithms/maplibre-style.d.ts +63 -0
  12. package/dist/src/domain/algorithms/raster-color-ramps.d.ts +37 -0
  13. package/dist/src/domain/algorithms/scene-layer-type.d.ts +25 -0
  14. package/dist/src/domain/algorithms/symbol-compile.d.ts +100 -0
  15. package/dist/src/domain/algorithms/symbol-params.d.ts +90 -0
  16. package/dist/src/domain/map/bounds.d.ts +8 -0
  17. package/dist/src/domain/map/constants.d.ts +40 -0
  18. package/dist/src/domain/map/layer-builders.d.ts +32 -0
  19. package/dist/src/domain/map/rendered-layers.d.ts +30 -0
  20. package/dist/src/domain/map/style-ready.d.ts +24 -0
  21. package/dist/src/domain/map/tile-url.d.ts +20 -0
  22. package/dist/src/domain/map/types.d.ts +128 -0
  23. package/dist/src/domain/models/deck-layer-style.d.ts +211 -0
  24. package/dist/src/domain/models/scene-layer-type.d.ts +23 -0
  25. package/dist/src/domain/models/symbol.d.ts +424 -0
  26. package/dist/src/lib/api.d.ts +82 -0
  27. package/dist/src/lib/auth-session.d.ts +22 -0
  28. package/dist/src/lib/raster-color-layer/RasterColorLayer.d.ts +48 -0
  29. package/dist/src/lib/raster-color-layer/TileGrid.d.ts +31 -0
  30. package/dist/src/lib/raster-color-layer/colorRamp.d.ts +18 -0
  31. package/dist/src/lib/raster-color-layer/shaders/raster-color.frag.d.ts +2 -0
  32. package/dist/src/lib/raster-color-layer/shaders/raster-color.vert.d.ts +2 -0
  33. package/dist/src/lib/raster-color-layer/zoomInterpolate.d.ts +2 -0
  34. package/dist/src/sdk/commands.d.ts +113 -0
  35. package/dist/src/sdk/context/keys.d.ts +148 -0
  36. package/dist/src/sdk/context/publishers.d.ts +198 -0
  37. package/dist/src/sdk/context/store.d.ts +78 -0
  38. package/dist/src/sdk/context/when.d.ts +69 -0
  39. package/dist/src/sdk/contributions/dispatch.d.ts +78 -0
  40. package/dist/src/sdk/contributions/panel-id.d.ts +25 -0
  41. package/dist/src/sdk/contributions/registry.d.ts +199 -0
  42. package/dist/src/sdk/contributions/symbol-renderers.d.ts +107 -0
  43. package/dist/src/sdk/contributions/types.d.ts +288 -0
  44. package/dist/src/sdk/contributions/views-bridge.d.ts +92 -0
  45. package/dist/src/sdk/define-plugin.d.ts +17 -0
  46. package/dist/src/sdk/facets/storage.d.ts +152 -0
  47. package/dist/src/sdk/facets/types.d.ts +370 -0
  48. package/dist/src/sdk/host-api.d.ts +256 -0
  49. package/dist/src/sdk/map-api.d.ts +288 -0
  50. package/dist/src/sdk/panels.d.ts +130 -0
  51. package/dist/src/sdk/plugin.d.ts +145 -0
  52. package/dist/src/sdk/rail-tools.d.ts +58 -0
  53. package/dist/src/sdk/scopes.d.ts +158 -0
  54. package/dist/src/systems/renderer/DeckSceneRenderer.d.ts +26 -0
  55. package/dist/src/systems/renderer/FlowFieldLayer.d.ts +68 -0
  56. package/dist/src/systems/renderer/LayerRendererRegistry.d.ts +132 -0
  57. package/dist/src/systems/renderer/authenticated-deck-load.d.ts +4 -0
  58. package/dist/src/systems/renderer/deck/deck-layer-builders.d.ts +29 -0
  59. package/dist/src/systems/renderer/deck/deck-layer-helpers.d.ts +21 -0
  60. package/dist/src/systems/renderer/deck/mvt-point-aggregation-layer.d.ts +107 -0
  61. package/dist/src/systems/renderer/flow-field/flow-field-resources.d.ts +84 -0
  62. package/dist/src/systems/renderer/flow-field/flow-field-shaders.d.ts +4 -0
  63. package/dist/src/systems/renderer/symbol/SpriteRegistry.d.ts +34 -0
  64. package/dist/src/systems/renderer/symbol/entries.d.ts +67 -0
  65. package/dist/src/types/analysis.d.ts +205 -0
  66. package/dist/src/types/common.d.ts +17 -0
  67. package/dist/src/types/extensions.d.ts +560 -0
  68. package/dist/src/types/gis.d.ts +242 -0
  69. package/dist/src/types/market-social.d.ts +378 -0
  70. package/package.json +47 -0
@@ -0,0 +1,78 @@
1
+ /**
2
+ * The command-dispatch seam for contributions (Stage 13 X4a).
3
+ *
4
+ * A `statusItems` entry, a menu item and a `tools` stanza all reference code by
5
+ * **id** and never carry it (XD3's split rule). Turning that id into a running
6
+ * command is the load path's job: F13.4 derives `onCommand:<id>` from exactly
7
+ * these references, so clicking one is precisely the moment the bundle may
8
+ * still be un-imported and must be activated first. That path — activation,
9
+ * `host.commands.invoke`, the runtime reopen — is **X4b's file ownership**, not
10
+ * this session's.
11
+ *
12
+ * So the mounts call `dispatchContributionCommand` and this module holds a
13
+ * single settable port. **The real one is installed by `GisWorkspace`** (X4c
14
+ * item I-1, `createContributionCommandPort` in
15
+ * `src/features/gis/lib/pluginActivationTriggers.ts`): it fires
16
+ * `onCommand:<id>`, awaits the activation, and only then invokes. The fallback
17
+ * below survives for the windows in which no port is installed — server
18
+ * rendering, a unit test, a tree that mounts a contribution outside the GIS
19
+ * workspace — where it runs a command that is *already* registered and
20
+ * otherwise refuses visibly rather than pretending the click worked.
21
+ *
22
+ * One setter, not several, on purpose: a second global would let the port and
23
+ * its map facade drift out of step.
24
+ */
25
+ import type { NgisMapAPI } from "../map-api";
26
+ import { type CommandHostResolver } from "../commands";
27
+ import type { NgisMenuSlot } from "./types";
28
+ /** What the menu was opened over — `undefined` for a status item or a tool. */
29
+ export interface NgisContributionCommandTarget {
30
+ slot: NgisMenuSlot;
31
+ /** Scene-layer id for `layer/context`, scene-resource id for `resource/context`. */
32
+ id: string;
33
+ name?: string;
34
+ }
35
+ export interface NgisContributionCommandRequest {
36
+ /** The plugin that declared the contribution — **not** necessarily the
37
+ * plugin that owns the command. Cross-plugin invocation is allowed in v1
38
+ * (F13.2's `commands` facet), so both are reported. */
39
+ pluginId: string;
40
+ commandId: string;
41
+ source: "statusItem" | "menu" | "tool";
42
+ target?: NgisContributionCommandTarget;
43
+ params?: Record<string, string>;
44
+ }
45
+ /**
46
+ * The injected invoker. Installed by the host once; `null` restores the
47
+ * fallback. Returning a promise is fine — nothing awaits it, because a
48
+ * contribution click is fire-and-forget from the UI's point of view and the
49
+ * plugin reports its own progress through `host.ui`.
50
+ */
51
+ export interface NgisContributionCommandPort {
52
+ /** The real, activation-aware invoker. When absent, the fallback below runs
53
+ * instead — a host may install `api` alone and get eager-only dispatch. */
54
+ invoke?(request: NgisContributionCommandRequest): void | Promise<void>;
55
+ /** The 0.3 map facade, for the fallback path's `CommandInvokeContext`. */
56
+ api?: NgisMapAPI | null;
57
+ /**
58
+ * The **command owner's** 0.4 facade, for the fallback path's `ctx.host`
59
+ * (`V-121`).
60
+ *
61
+ * Beside `api` and optional for the same reason: a host may install neither
62
+ * and get a 0.3-shaped ctx, which is exactly what a tree mounting a
63
+ * contribution outside the GIS workspace has. Never derived from
64
+ * `request.pluginId` — see {@link NgisContributionCommandRequest.pluginId}.
65
+ */
66
+ resolveHost?: CommandHostResolver | null;
67
+ }
68
+ export declare function setNgisContributionCommandPort(next: NgisContributionCommandPort | null): void;
69
+ /** Test/inspection seam — never used to make a decision in shipping code. */
70
+ export declare function getNgisContributionCommandPort(): NgisContributionCommandPort | null;
71
+ /**
72
+ * Dispatches one contribution's command.
73
+ *
74
+ * Returns `true` when something ran (or was handed to the port), `false` when
75
+ * the command could not be reached. Never throws: a plugin command that blows
76
+ * up must not take a context menu — or the top bar — down with it.
77
+ */
78
+ export declare function dispatchContributionCommand(request: NgisContributionCommandRequest): boolean;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The contributed-view panel id, in one dependency-free module.
3
+ *
4
+ * **Why it moved here at the W5 kickoff (Stage 14).** F14.12 makes the id a
5
+ * *contract*: `capabilities.panels` stops implying eager activation exactly
6
+ * when every declared panel id is `contributedViewPanelId(pluginId, viewId)`
7
+ * for a view the same plugin declares. So `activation.ts` — which runs over the
8
+ * boot payload before any bundle is fetched, and in Node tests — now has to
9
+ * build the id too. Importing it from `views-bridge.ts` would have dragged
10
+ * `../panels` and therefore `react-dom/client` into the activation path's
11
+ * module graph, which is the opposite of what a lazy-activation substrate is
12
+ * for.
13
+ *
14
+ * The alternative was a second two-line implementation, and that is the defect
15
+ * class this stage exists to remove (`V-127`, `V-262`). One declaration, two
16
+ * importers: `views-bridge.ts` re-exports both names, so every existing import
17
+ * path — including `@/sdk/contributions`' barrel and `@ngis/plugin-sdk`'s
18
+ * published value list (F14.13) — is unchanged.
19
+ */
20
+ /** Panel-id prefix for a contributed view. Namespaced so it can never collide
21
+ * with a first-party panel id (none of which contain a `:`). */
22
+ export declare const CONTRIBUTED_VIEW_PANEL_PREFIX = "contrib:";
23
+ /** `contrib:<pluginId>:<viewId>` — stable, so a re-register targets the same
24
+ * tab and a plugin's own panel can deliberately take it over. */
25
+ export declare function contributedViewPanelId(pluginId: string, viewId: string): string;
@@ -0,0 +1,199 @@
1
+ /**
2
+ * The contribution registry (Stage 13 X4a, F13.3 / F13.6 / F13.10).
3
+ *
4
+ * Parsed `contributes` blocks in, **gated and ordered** contribution lists out.
5
+ * Nothing here renders; the host mounts (`GisContributedStatusItems`, the two
6
+ * context-menu mounts, the `views` bridge) read from it.
7
+ *
8
+ * ## Three properties that are contractual
9
+ *
10
+ * 1. **`when` and `enabledWhen` are evaluated on every point.** `when` false ⇒
11
+ * the contribution is not in the list at all. `enabledWhen` false ⇒ it is in
12
+ * the list with `gate.enabled === false` and its `disabledReason`, so the
13
+ * host renders it disabled rather than hiding it. `views` carries `when`
14
+ * only — a disabled-but-visible panel has no meaning (F13.3).
15
+ * 2. **Compile once, dependency-indexed.** Every distinct expression is
16
+ * compiled by X1's store (which caches by source text, *including* failed
17
+ * parses) and watched through `store.watch`, which re-evaluates only when a
18
+ * key in that expression's own read-set changes and only notifies on an
19
+ * actual boolean flip. No expression is ever re-parsed, and an unrelated key
20
+ * change costs nothing.
21
+ * 3. **Order is deterministic and never install-order** (F13.10). statusItems:
22
+ * `priority` desc → plugin id → item id. menus: group order
23
+ * `navigation → modification → export → plugin`, then `order` asc → plugin
24
+ * id → command. views: `order` asc → plugin id → view id.
25
+ *
26
+ * ## Failing closed on a malformed expression
27
+ *
28
+ * XB1 deliberately never interprets when-expressions, so a syntactically
29
+ * invalid `when` publishes fine and arrives here. F13.3 does not say what to do
30
+ * with it. The rule taken, and documented at the call site:
31
+ *
32
+ * - a `when` that will not compile ⇒ **not rendered** (fail closed — the author
33
+ * asked for conditional visibility and the host cannot honour the condition);
34
+ * - an `enabledWhen` that will not compile ⇒ **rendered, disabled**, with the
35
+ * generic host reason (the item is real; only its enablement is unknowable).
36
+ *
37
+ * Either way one contribution degrades and the plugin keeps working, which is
38
+ * the same posture X1's store takes for an unknown key.
39
+ */
40
+ import type { NgisUnsubscribe } from "../map-api";
41
+ import { type NgisContextStore } from "../context/store";
42
+ import { type NgisContributes, type NgisMenuGroup, type NgisMenuItemContribution, type NgisMenuSlot, type NgisStatusItemContribution, type NgisSymbolRendererContribution, type NgisToolContribution, type NgisViewContribution } from "./types";
43
+ /**
44
+ * The evaluated `when` / `enabledWhen` answer for one contribution.
45
+ *
46
+ * `disabledReason` is the plugin's **literal** string (F13.11 — plugin strings
47
+ * are never message keys) or `null`, in which case the host substitutes its own
48
+ * localized generic reason from `GIS.contrib`. Returning `null` rather than a
49
+ * baked-in English fallback is what keeps this module i18n-free and keeps the
50
+ * host string localized in both locales.
51
+ */
52
+ export interface NgisContributionGateState {
53
+ /** `when` — false means the caller never sees this entry at all. */
54
+ readonly visible: boolean;
55
+ /** `enabledWhen` — false means rendered but disabled. */
56
+ readonly enabled: boolean;
57
+ /** The plugin's literal reason, or `null` for the host's generic string. */
58
+ readonly disabledReason: string | null;
59
+ }
60
+ export interface NgisRegisteredStatusItem {
61
+ /** `<pluginId>::<item.id>` — stable across re-evaluations; a React key. */
62
+ readonly key: string;
63
+ readonly pluginId: string;
64
+ readonly item: NgisStatusItemContribution;
65
+ readonly gate: NgisContributionGateState;
66
+ /**
67
+ * The resolved `badge.contextKey` value, coerced to a number, or `null` when
68
+ * no badge is declared / the key is unpublished / the value is not numeric.
69
+ * Coerced here rather than in the host so the badge cannot render `[object
70
+ * Object]` for a plugin that pointed at an array-valued key.
71
+ */
72
+ readonly badge: number | null;
73
+ }
74
+ export interface NgisRegisteredMenuItem {
75
+ /** `<pluginId>::<slot>::<command>::<index>` — commands may legitimately
76
+ * repeat within a slot with different labels, so the index is part of it. */
77
+ readonly key: string;
78
+ readonly pluginId: string;
79
+ readonly slot: NgisMenuSlot;
80
+ /** Resolved group — `"plugin"` when the manifest omitted it (F13.3). */
81
+ readonly group: NgisMenuGroup;
82
+ readonly item: NgisMenuItemContribution;
83
+ readonly gate: NgisContributionGateState;
84
+ }
85
+ export interface NgisRegisteredView {
86
+ readonly key: string;
87
+ readonly pluginId: string;
88
+ readonly view: NgisViewContribution;
89
+ /** `views` takes `when` only, so `enabled` is always `true` here. */
90
+ readonly gate: NgisContributionGateState;
91
+ }
92
+ export interface NgisRegisteredTool {
93
+ readonly key: string;
94
+ readonly pluginId: string;
95
+ readonly tool: NgisToolContribution;
96
+ readonly gate: NgisContributionGateState;
97
+ }
98
+ /**
99
+ * A T3 renderer one installed plugin **declares** (F24.13).
100
+ *
101
+ * No `gate`: `symbolRenderers` carries neither `when` nor `enabledWhen`, and
102
+ * that is the contract rather than an omission — a renderer is selected by a
103
+ * *symbol manifest*, not by the host chrome, so there is no surface on which a
104
+ * hidden-or-disabled state would mean anything. Registration is therefore
105
+ * unconditional and the ordering rules above do not apply either: lookup is by
106
+ * `(pluginId, rendererId)`, which is what a `plugin:<extId>@<version>/<id>`
107
+ * reference names.
108
+ */
109
+ export interface NgisRegisteredSymbolRenderer {
110
+ /** `<pluginId>::<renderer.id>`. */
111
+ readonly key: string;
112
+ readonly pluginId: string;
113
+ readonly renderer: NgisSymbolRendererContribution;
114
+ }
115
+ /** One consistent read of every contribution point — the `useSyncExternalStore`
116
+ * snapshot. Referentially stable until a registration or a gate actually
117
+ * changes. */
118
+ export interface NgisContributionSnapshot {
119
+ readonly statusItems: readonly NgisRegisteredStatusItem[];
120
+ readonly menus: Readonly<Record<NgisMenuSlot, readonly NgisRegisteredMenuItem[]>>;
121
+ readonly views: readonly NgisRegisteredView[];
122
+ readonly tools: readonly NgisRegisteredTool[];
123
+ /** F24.13. Sorted by plugin id then renderer id, like every other point. */
124
+ readonly symbolRenderers: readonly NgisRegisteredSymbolRenderer[];
125
+ }
126
+ export interface NgisContributionRegistry {
127
+ /**
128
+ * Register (or replace) one plugin's parsed contributions. Passing `null` —
129
+ * an absent or refused block — registers nothing but still claims the plugin
130
+ * id, so a later `unregister` is symmetric.
131
+ *
132
+ * Returns a disposer, matching every other registry in `@/sdk`
133
+ * (`workspacePanelRegistry`, `gisRailToolRegistry`, `gisCommandRegistry`).
134
+ * Unlike the plugin *record* map, this registry is **last-wins**: a
135
+ * re-register replaces, because a version swap (F13.8) must not be blocked by
136
+ * a first-wins rule on data.
137
+ */
138
+ register(pluginId: string, contributes: NgisContributes | null): NgisUnsubscribe;
139
+ /** Drops a plugin's contributions. `false` if it was not registered. */
140
+ unregister(pluginId: string): boolean;
141
+ /** Registered plugin ids, sorted — deterministic for tests and inspectors. */
142
+ pluginIds(): readonly string[];
143
+ /** All contribution points in one consistent, referentially stable read. */
144
+ snapshot(): NgisContributionSnapshot;
145
+ /** Visible status items in F13.10 order. Convenience over `snapshot()`. */
146
+ statusItems(): readonly NgisRegisteredStatusItem[];
147
+ /** Visible menu items for one slot, in F13.10 group/order sequence. */
148
+ menuItems(slot: NgisMenuSlot): readonly NgisRegisteredMenuItem[];
149
+ /** Visible declarative views, `order` asc. */
150
+ views(): readonly NgisRegisteredView[];
151
+ /** Visible tool stanzas. Mounting them is F13.9's rail-overflow seam. */
152
+ tools(): readonly NgisRegisteredTool[];
153
+ /** Every declared T3 renderer (F24.13). */
154
+ symbolRenderers(): readonly NgisRegisteredSymbolRenderer[];
155
+ /**
156
+ * The declaration a `plugin:<extId>@<version>/<rendererId>` reference names,
157
+ * or `null`. **Answerable with the bundle un-imported** — that is what keeps
158
+ * declaring a renderer from forcing eager activation (F13.4, F24.13).
159
+ */
160
+ symbolRenderer(pluginId: string, rendererId: string): NgisRegisteredSymbolRenderer | null;
161
+ subscribe(listener: () => void): NgisUnsubscribe;
162
+ }
163
+ export interface NgisContributionRegistryOptions {
164
+ /** The context store gating is evaluated against. Tests inject an isolated
165
+ * `createNgisContextStore()`; production uses the host-wide singleton. */
166
+ context?: NgisContextStore;
167
+ }
168
+ export declare function createNgisContributionRegistry(options?: NgisContributionRegistryOptions): NgisContributionRegistry;
169
+ /**
170
+ * The host-wide contribution registry.
171
+ *
172
+ * A module-level singleton for the same reason `workspacePanelRegistry`,
173
+ * `gisRailToolRegistry` and `ngisContextStore` are: there is exactly one host,
174
+ * and the mounts (a status row in the GIS top bar, two context menus inside
175
+ * shared scene components) must reach it without a prop chain through files
176
+ * this session does not own. Tests build isolated instances with
177
+ * `createNgisContributionRegistry({ context: createNgisContextStore() })`.
178
+ */
179
+ export declare const ngisContributionRegistry: NgisContributionRegistry;
180
+ /**
181
+ * Splits an ordered status-item list at F13.10's host-row capacity.
182
+ *
183
+ * The cap is a *rendering* rule, not a validation rule: a plugin may legally
184
+ * declare two items and six plugins may legally be installed. The overflow
185
+ * collapses into a `+N` popover rather than disappearing.
186
+ */
187
+ export declare function splitStatusItemsAtCap(items: readonly NgisRegisteredStatusItem[], cap?: number): {
188
+ visible: readonly NgisRegisteredStatusItem[];
189
+ overflow: readonly NgisRegisteredStatusItem[];
190
+ };
191
+ /**
192
+ * Groups an ordered menu list into F13.10's separated groups, preserving the
193
+ * fixed `navigation → modification → export → plugin` sequence and dropping
194
+ * groups with no visible item (so the host never renders a stray separator).
195
+ */
196
+ export declare function groupMenuItems(items: readonly NgisRegisteredMenuItem[]): readonly {
197
+ group: NgisMenuGroup;
198
+ items: readonly NgisRegisteredMenuItem[];
199
+ }[];
@@ -0,0 +1,107 @@
1
+ /**
2
+ * The **code** half of F24.13's T3 bridge (Stage 24 W3, S24-31).
3
+ *
4
+ * `contributes.symbolRenderers` is data — an id, a geometry, a param form and a
5
+ * slot list, parsed off the boot payload before any bundle is fetched. This
6
+ * module is the other side of F13.3's split rule: what the *bundle* exports, and
7
+ * where it lands once the plugin has been activated.
8
+ *
9
+ * ## Why the functions live on the plugin object rather than in `capabilities`
10
+ *
11
+ * `KNOWN_CAPABILITY_KEYS` is frozen at `panels|railTools|layerTypes|commands` in
12
+ * both repos (F13.3), and `plugin-runtime.ts` refuses an unknown capability key
13
+ * with `incompatible` — so a sixth capability key would make every plugin that
14
+ * used it fail negotiation on any host older than this one. `symbolRenderers`
15
+ * is therefore a **sibling of `manifest`** on the plugin object, exactly as
16
+ * `activate`/`deactivate` are, and the runtime publishes it here at activation
17
+ * and disposes it at teardown along with every other registration it made.
18
+ *
19
+ * ## Lazy by construction
20
+ *
21
+ * Nothing in this module is populated by parsing a manifest. A declared renderer
22
+ * is answerable from `ngisContributionRegistry.symbolRenderer(...)` with the
23
+ * bundle un-imported; the *function* only appears here once someone has resolved
24
+ * a symbol that names it and the plugin has been activated in consequence
25
+ * (F13.4, F24.13). That ordering is the whole reason the declaration and the
26
+ * function are two different things.
27
+ */
28
+ import type { NgisUnsubscribe } from "../map-api";
29
+ /**
30
+ * F24.13's frozen render context: `{ data, params, bindings, time, dataTime,
31
+ * pixelRatio, zoom }`.
32
+ *
33
+ * **No host handle, and that is the F15.2 worker-readiness rule, not an
34
+ * oversight**: everything a renderer reads has to be JSON, and so is everything
35
+ * it returns, so the same function can one day run somewhere a host facade
36
+ * cannot be passed. It is also async-free — a renderer returns descriptors, it
37
+ * does not go and fetch anything.
38
+ */
39
+ export interface NgisSymbolRenderContext {
40
+ /** Whatever the host's builder feeds the stack — today the scene resource's
41
+ * vector-tile URL, the same value every other symbol layer reads. */
42
+ data: unknown;
43
+ /** The symbol's resolved param values, after defaults and bindings. */
44
+ params: Readonly<Record<string, string | number | boolean>>;
45
+ /** The resolved F24.5 slots, by slot name. */
46
+ bindings: Readonly<Record<string, unknown>>;
47
+ /** The wall clock (F24.7), in seconds. `0` when nothing drives a clock. */
48
+ time: number;
49
+ /** The data clock (F24.7), in seconds. */
50
+ dataTime: number;
51
+ pixelRatio: number;
52
+ zoom: number;
53
+ }
54
+ /**
55
+ * What a T3 render function returns: **data, never a deck object** (F24.13 as
56
+ * amended 2026-09-02).
57
+ *
58
+ * The clause used to say `Layer[]`, and it cited F15.2's worker-readiness rule
59
+ * in the same sentence — while F15.2(1) forbids a host-crossing surface from
60
+ * returning *"a class instance"*, which a deck `Layer` is. Honouring only half
61
+ * of that rule cost the bundle: a plugin that constructs `Layer`s must `import`
62
+ * deck at runtime, so it either ships its own copy (the dogfood measured
63
+ * 1,463,082 bytes against 5.9–11.1 KB for the packages that do not, and two deck
64
+ * copies means two layer managers over one map) or deck's public API becomes a
65
+ * frozen plugin ABI.
66
+ *
67
+ * So the plugin names a layer **type** and hands over JSON props; the host looks
68
+ * the type up in its own allowlist, constructs it from its own deck and assigns
69
+ * the id. `type` is a string here rather than a union because the allowlist is
70
+ * the *host's* — a plugin compiled against an older SDK must not be prevented
71
+ * from naming a type a newer host has, and a type no host has is refused at
72
+ * build time with `incompatible` rather than silently dropped.
73
+ *
74
+ * **Nesting.** `props` is JSON, and a nested descriptor is JSON too: a tile
75
+ * layer's `renderSubLayers` prop may itself be a descriptor, which is how a
76
+ * plugin says "an `MVTLayer` whose tiles draw as `ScatterplotLayer`s" without
77
+ * writing the closure that deck's prop actually wants. The host writes that
78
+ * closure. Anywhere else, `renderSubLayers` is refused.
79
+ */
80
+ export interface NgisSymbolLayerDescriptor {
81
+ /** A stock deck layer type on the host's allowlist, e.g. `"ScatterplotLayer"`. */
82
+ type: string;
83
+ /** JSON props for the constructed layer. The host owns `id`; setting it here has no effect. */
84
+ props?: Readonly<Record<string, unknown>>;
85
+ }
86
+ export type NgisSymbolRendererFn = (context: NgisSymbolRenderContext) => NgisSymbolLayerDescriptor[];
87
+ /** What the bundle exports: renderer id → render function (F24.13). */
88
+ export type NgisSymbolRendererModule = Readonly<Record<string, NgisSymbolRendererFn>>;
89
+ /**
90
+ * Publish one activated plugin's render functions. Called by
91
+ * `plugin-runtime.ts` at activation, and disposed by the same disposer chain
92
+ * that unwinds `panels`/`railTools`/`layerTypes`/`commands` — so a function can
93
+ * never outlive the record that owns it.
94
+ *
95
+ * Last-wins by plugin id, like `ngisContributionRegistry.register`, because a
96
+ * version swap (F13.8) must not be blocked by a first-wins rule.
97
+ */
98
+ export declare function publishNgisSymbolRenderers(pluginId: string, version: string, renderers: NgisSymbolRendererModule): NgisUnsubscribe;
99
+ /**
100
+ * The activated function a `plugin:<extId>@<version>/<rendererId>` reference
101
+ * names, or `null` — including when the activated bundle is a *different*
102
+ * version from the one the reference pinned, which is a real mismatch rather
103
+ * than a near-miss to paper over.
104
+ */
105
+ export declare function getNgisSymbolRenderer(pluginId: string, version: string, rendererId: string): NgisSymbolRendererFn | null;
106
+ /** Test seam: forget every published module. */
107
+ export declare function resetNgisSymbolRenderers(): void;