@honua/app-platform 0.1.4-beta.0 → 0.1.9-beta.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 (209) hide show
  1. package/app/index.d.ts.map +1 -1
  2. package/app/index.js +4 -0
  3. package/contract/types.d.ts +1 -1
  4. package/contract/types.d.ts.map +1 -1
  5. package/contract/types.js +4 -0
  6. package/control-plane/admin-client.d.ts +87 -0
  7. package/control-plane/admin-client.d.ts.map +1 -0
  8. package/control-plane/admin-client.js +169 -0
  9. package/control-plane/client.d.ts.map +1 -1
  10. package/control-plane/client.js +21 -3
  11. package/control-plane/commands/catalog.d.ts +133 -0
  12. package/control-plane/commands/catalog.d.ts.map +1 -0
  13. package/control-plane/commands/catalog.js +353 -0
  14. package/control-plane/commands/errors.d.ts +96 -0
  15. package/control-plane/commands/errors.d.ts.map +1 -0
  16. package/control-plane/commands/errors.js +130 -0
  17. package/control-plane/commands/identity.d.ts +71 -0
  18. package/control-plane/commands/identity.d.ts.map +1 -0
  19. package/control-plane/commands/identity.js +0 -0
  20. package/control-plane/commands/index.d.ts +39 -0
  21. package/control-plane/commands/index.d.ts.map +1 -0
  22. package/control-plane/commands/index.js +34 -0
  23. package/control-plane/commands/runtime.d.ts +146 -0
  24. package/control-plane/commands/runtime.d.ts.map +1 -0
  25. package/control-plane/commands/runtime.js +318 -0
  26. package/control-plane/commands/types.d.ts +226 -0
  27. package/control-plane/commands/types.d.ts.map +1 -0
  28. package/control-plane/commands/types.js +30 -0
  29. package/control-plane/commands/validate.d.ts +27 -0
  30. package/control-plane/commands/validate.d.ts.map +1 -0
  31. package/control-plane/commands/validate.js +132 -0
  32. package/control-plane/generated/admin-api.d.ts +30263 -0
  33. package/control-plane/generated/admin-api.d.ts.map +1 -0
  34. package/control-plane/generated/admin-api.js +5 -0
  35. package/control-plane/generated/admin-operations.d.ts +4053 -0
  36. package/control-plane/generated/admin-operations.d.ts.map +1 -0
  37. package/control-plane/generated/admin-operations.js +820 -0
  38. package/control-plane/index.d.ts +11 -0
  39. package/control-plane/index.d.ts.map +1 -1
  40. package/control-plane/index.js +8 -0
  41. package/control-plane/types.d.ts +14 -0
  42. package/control-plane/types.d.ts.map +1 -1
  43. package/controls/catalog.d.ts.map +1 -1
  44. package/controls/catalog.js +12 -1
  45. package/controls/qualification.d.ts.map +1 -1
  46. package/controls/qualification.js +61 -2
  47. package/core/client.d.ts +6 -0
  48. package/core/client.d.ts.map +1 -1
  49. package/core/client.js +12 -10
  50. package/core/credential-redaction.d.ts +163 -0
  51. package/core/credential-redaction.d.ts.map +1 -0
  52. package/core/credential-redaction.js +389 -0
  53. package/core/error-classifications.d.ts +32 -0
  54. package/core/error-classifications.d.ts.map +1 -1
  55. package/core/error-classifications.js +32 -0
  56. package/core/error-code-registry.d.ts +33 -1
  57. package/core/error-code-registry.d.ts.map +1 -1
  58. package/core/error-code-registry.js +32 -0
  59. package/core/errors.d.ts +1 -1
  60. package/core/errors.d.ts.map +1 -1
  61. package/core/geoparquet-sql.d.ts +1 -1
  62. package/core/geoparquet-sql.js +2 -2
  63. package/core/grpc-adapter.d.ts +2 -2
  64. package/core/grpc-adapter.d.ts.map +1 -1
  65. package/core/grpc-adapter.js +30 -6
  66. package/core/job-run-errors.d.ts +10 -0
  67. package/core/job-run-errors.d.ts.map +1 -0
  68. package/core/job-run-errors.js +14 -0
  69. package/core/job-run-lifecycle.d.ts +34 -0
  70. package/core/job-run-lifecycle.d.ts.map +1 -0
  71. package/core/job-run-lifecycle.js +193 -0
  72. package/core/ogc-processes.d.ts +38 -31
  73. package/core/ogc-processes.d.ts.map +1 -1
  74. package/core/ogc-processes.js +123 -173
  75. package/core/process-runner.js +15 -100
  76. package/core/stac.d.ts +2 -1
  77. package/core/stac.d.ts.map +1 -1
  78. package/core/stac.js +29 -11
  79. package/core/surfaces.d.ts +2 -8
  80. package/core/surfaces.d.ts.map +1 -1
  81. package/core/surfaces.js +21 -112
  82. package/core/types.d.ts +22 -8
  83. package/core/types.d.ts.map +1 -1
  84. package/gen/geospatial/v1/common_pb.d.ts +514 -0
  85. package/gen/geospatial/v1/common_pb.d.ts.map +1 -0
  86. package/gen/geospatial/v1/common_pb.js +335 -0
  87. package/gen/geospatial/v1/execution_types_pb.d.ts +1186 -0
  88. package/gen/geospatial/v1/execution_types_pb.d.ts.map +1 -0
  89. package/gen/geospatial/v1/execution_types_pb.js +396 -0
  90. package/gen/geospatial/v1/feature_service_pb.d.ts +403 -0
  91. package/gen/geospatial/v1/feature_service_pb.d.ts.map +1 -0
  92. package/gen/geospatial/v1/feature_service_pb.js +47 -0
  93. package/gen/geospatial/v1/index.d.ts +5 -0
  94. package/gen/geospatial/v1/index.d.ts.map +1 -0
  95. package/gen/geospatial/v1/index.js +9 -0
  96. package/gen/geospatial/v1/spatial_types_pb.d.ts +285 -0
  97. package/gen/geospatial/v1/spatial_types_pb.d.ts.map +1 -0
  98. package/gen/geospatial/v1/spatial_types_pb.js +58 -0
  99. package/gen/geospatial/v1/workspace_artifact_types_pb.d.ts +379 -0
  100. package/gen/geospatial/v1/workspace_artifact_types_pb.d.ts.map +1 -0
  101. package/gen/geospatial/v1/workspace_artifact_types_pb.js +151 -0
  102. package/generated-app/projection.d.ts.map +1 -1
  103. package/generated-app/projection.js +10 -1
  104. package/interactions/declarative-contract.d.ts +149 -0
  105. package/interactions/declarative-contract.d.ts.map +1 -0
  106. package/interactions/declarative-contract.js +293 -0
  107. package/interactions/declarative.d.ts +198 -0
  108. package/interactions/declarative.d.ts.map +1 -0
  109. package/interactions/declarative.js +470 -0
  110. package/interactions/feature-state.d.ts +7 -0
  111. package/interactions/feature-state.d.ts.map +1 -1
  112. package/interactions/feature-state.js +10 -2
  113. package/map/maplibre-target.js +1 -1
  114. package/operate/client.d.ts +11 -1
  115. package/operate/client.d.ts.map +1 -1
  116. package/operate/client.js +39 -2
  117. package/operate/index.d.ts +1 -1
  118. package/operate/index.d.ts.map +1 -1
  119. package/operate/types.d.ts +40 -6
  120. package/operate/types.d.ts.map +1 -1
  121. package/package.json +2 -2
  122. package/query-planner/grpc.d.ts +4 -4
  123. package/query-planner/grpc.d.ts.map +1 -1
  124. package/query-planner/grpc.js +11 -11
  125. package/query-planner/types.d.ts +4 -4
  126. package/query-planner/types.d.ts.map +1 -1
  127. package/realtime/sse.d.ts.map +1 -1
  128. package/realtime/sse.js +7 -1
  129. package/runtime/errors.d.ts +1 -1
  130. package/runtime/errors.d.ts.map +1 -1
  131. package/runtime/errors.js +2 -0
  132. package/runtime/generated/map-package-schema-meta.d.ts +11 -0
  133. package/runtime/generated/map-package-schema-meta.d.ts.map +1 -0
  134. package/runtime/generated/map-package-schema-meta.js +12 -0
  135. package/runtime/generated/map-package-schema-validator.d.ts +16 -0
  136. package/runtime/generated/map-package-schema-validator.d.ts.map +1 -0
  137. package/runtime/generated/map-package-schema-validator.js +1422 -0
  138. package/runtime/index.d.ts +5 -1
  139. package/runtime/index.d.ts.map +1 -1
  140. package/runtime/index.js +6 -0
  141. package/runtime/map-package-export.d.ts +151 -0
  142. package/runtime/map-package-export.d.ts.map +1 -0
  143. package/runtime/map-package-export.js +636 -0
  144. package/runtime/map-package-validation.d.ts +21 -1
  145. package/runtime/map-package-validation.d.ts.map +1 -1
  146. package/runtime/map-package-validation.js +132 -95
  147. package/runtime/map-package.d.ts +80 -0
  148. package/runtime/map-package.d.ts.map +1 -1
  149. package/runtime/style-compose.d.ts.map +1 -1
  150. package/runtime/style-compose.js +78 -9
  151. package/scene-workspace/cesium-adapter.d.ts +8 -8
  152. package/scene-workspace/cesium-adapter.d.ts.map +1 -1
  153. package/scene-workspace/cesium-adapter.js +31 -18
  154. package/scene-workspace/primitives.d.ts.map +1 -1
  155. package/scene-workspace/primitives.js +9 -6
  156. package/scene-workspace/source-to-cesium.js +1 -1
  157. package/studio/chart-spec.d.ts +6 -6
  158. package/studio/chart-spec.d.ts.map +1 -1
  159. package/studio/chart-spec.js +6 -6
  160. package/studio/index.d.ts +17 -7
  161. package/studio/index.d.ts.map +1 -1
  162. package/studio/index.js +15 -5
  163. package/studio/lifecycle-client.d.ts +262 -22
  164. package/studio/lifecycle-client.d.ts.map +1 -1
  165. package/studio/lifecycle-client.js +524 -24
  166. package/studio/lifecycle-errors.d.ts +8 -2
  167. package/studio/lifecycle-errors.d.ts.map +1 -1
  168. package/studio/lifecycle-errors.js +6 -1
  169. package/studio/lifecycle-types.d.ts +228 -8
  170. package/studio/lifecycle-types.d.ts.map +1 -1
  171. package/studio/publication-status.d.ts +55 -0
  172. package/studio/publication-status.d.ts.map +1 -0
  173. package/studio/publication-status.js +103 -0
  174. package/web-components/application-context.d.ts +186 -0
  175. package/web-components/application-context.d.ts.map +1 -0
  176. package/web-components/application-context.js +429 -0
  177. package/web-components/elements.d.ts +10 -1
  178. package/web-components/elements.d.ts.map +1 -1
  179. package/web-components/elements.js +187 -7
  180. package/web-components/export-redaction.d.ts +11 -102
  181. package/web-components/export-redaction.d.ts.map +1 -1
  182. package/web-components/export-redaction.js +7 -260
  183. package/web-components/feature-editor-offline.d.ts +32 -0
  184. package/web-components/feature-editor-offline.d.ts.map +1 -0
  185. package/web-components/feature-editor-offline.js +115 -0
  186. package/web-components/feature-editor-workflow.d.ts +85 -22
  187. package/web-components/feature-editor-workflow.d.ts.map +1 -1
  188. package/web-components/feature-editor-workflow.js +240 -0
  189. package/web-components/feature-editor.d.ts +20 -6
  190. package/web-components/feature-editor.d.ts.map +1 -1
  191. package/web-components/feature-editor.js +159 -7
  192. package/web-components/feature-inspection.d.ts +287 -0
  193. package/web-components/feature-inspection.d.ts.map +1 -0
  194. package/web-components/feature-inspection.js +1464 -0
  195. package/web-components/feature-mutation.d.ts +77 -0
  196. package/web-components/feature-mutation.d.ts.map +1 -0
  197. package/web-components/feature-mutation.js +137 -0
  198. package/web-components/feature-table-engine.d.ts +94 -4
  199. package/web-components/feature-table-engine.d.ts.map +1 -1
  200. package/web-components/feature-table-engine.js +365 -18
  201. package/web-components/feature-table-view.d.ts +35 -1
  202. package/web-components/feature-table-view.d.ts.map +1 -1
  203. package/web-components/feature-table-view.js +128 -12
  204. package/web-components/index.d.ts +14 -6
  205. package/web-components/index.d.ts.map +1 -1
  206. package/web-components/index.js +8 -2
  207. package/gen/honua/v1/feature_service_pb.d.ts +0 -918
  208. package/gen/honua/v1/feature_service_pb.d.ts.map +0 -1
  209. package/gen/honua/v1/feature_service_pb.js +0 -375
@@ -0,0 +1,470 @@
1
+ /**
2
+ * `@honua/sdk-js/interactions/declarative` — compiles a standard
3
+ * `interactions[]` block (geospatial-mcp ADR-0030) onto this SDK's existing
4
+ * imperative binding primitives.
5
+ *
6
+ * The standard constrains the *document*, not the dispatcher: "client
7
+ * runtimes implement dispatch by compiling bindings onto whatever imperative
8
+ * primitives they already have". That is exactly what this module does — it
9
+ * owns no event plumbing of its own, only a compile table from the closed
10
+ * (`on.event`, `do.verb`) vocabulary onto `createSelectionHandler`,
11
+ * `createHoverHandler`, `bindTableSelectionToExploration`,
12
+ * `bindFilterControlsToExploration`, and `subscribeExplorationSelector`.
13
+ *
14
+ * Three properties are load-bearing and asserted by the suite:
15
+ *
16
+ * 1. **Validate before binding.** `compileHonuaInteractions` runs the whole
17
+ * block through {@link validateHonuaInteractions} plus reference
18
+ * resolution against the components it was handed. A block with issues
19
+ * binds *nothing* — the standard rejects over-cap and malformed documents
20
+ * rather than truncating them.
21
+ * 2. **Actions never emit events.** A verb-driven state change must not
22
+ * re-enter the dispatcher. Two mechanisms enforce it: every compiled
23
+ * handler is skipped while an action is in flight (`#dispatching`), and
24
+ * exploration-backed subscriptions run with the view controller's default
25
+ * `includeSelf: false`, so a change this compiler originated is never
26
+ * delivered back to this compiler. There is no cycle detection because
27
+ * there can be no cycle.
28
+ * 3. **Unsupported pairs are named, never dropped.** When a binding's
29
+ * (`on.event`, `do.verb`) pair — or the component behind a ref — has no
30
+ * primitive to compile onto, it lands in
31
+ * {@link HonuaCompiledInteractions.unsupported} with the pair spelled out,
32
+ * so a host can surface a real "this runtime cannot honor that binding"
33
+ * message instead of silently rendering an inert app.
34
+ *
35
+ * @experimental The compiler surface tracks geospatial-mcp ADR-0030 while
36
+ * that ADR is Proposed; the component-adapter shapes may gain fields.
37
+ *
38
+ * @module
39
+ */
40
+ import { sourceFeatureSelectionTarget } from "../exploration/selection.js";
41
+ import { subscribeExplorationSelector } from "../exploration/selectors.js";
42
+ import { bindFilterControlsToExploration, bindTableSelectionToExploration } from "./exploration-bindings.js";
43
+ import { createHoverHandler, createSelectionHandler } from "./feature-state.js";
44
+ import { parseHonuaInteractionRef, resolveHonuaInteractionArgs, validateHonuaInteractions, } from "./declarative-contract.js";
45
+ export * from "./declarative-contract.js";
46
+ // ── Compiler ──────────────────────────────────────────────────
47
+ const EMPTY_RESULT_BASE = { bindings: [], disabled: [] };
48
+ /**
49
+ * Compiles an `interactions[]` block onto live components. Returns disposers;
50
+ * never throws for a bad document — a malformed or over-cap block comes back
51
+ * as `{ ok: false, issues }` with nothing bound.
52
+ */
53
+ export function compileHonuaInteractions(interactions, options) {
54
+ const validation = validateHonuaInteractions(interactions, {
55
+ ...(options.fanOutCap !== undefined ? { fanOutCap: options.fanOutCap } : {}),
56
+ });
57
+ const components = options.components ?? {};
58
+ const declared = Array.isArray(interactions) ? interactions : [];
59
+ const refIssues = validation.ok ? resolveReferenceIssues(declared, components) : [];
60
+ const issues = [...validation.issues, ...refIssues];
61
+ if (issues.length > 0) {
62
+ return {
63
+ ok: false,
64
+ issues,
65
+ ...EMPTY_RESULT_BASE,
66
+ unsupported: [],
67
+ dispose: () => undefined,
68
+ };
69
+ }
70
+ const compiler = new InteractionCompiler(options, components);
71
+ for (const interaction of declared)
72
+ compiler.compile(interaction);
73
+ return compiler.result();
74
+ }
75
+ function resolveReferenceIssues(interactions, components) {
76
+ const issues = [];
77
+ interactions.forEach((interaction, index) => {
78
+ for (const side of ["on", "do"]) {
79
+ const ref = interaction[side].ref;
80
+ if (resolveComponent(ref, components) !== undefined)
81
+ continue;
82
+ issues.push({
83
+ code: "invalid-ref",
84
+ interactionId: interaction.id,
85
+ path: `interactions[${index}].${side}.ref`,
86
+ message: `\`${ref}\` does not resolve to a declared component.`,
87
+ });
88
+ }
89
+ });
90
+ return issues;
91
+ }
92
+ function resolveComponent(ref, components) {
93
+ const parsed = parseHonuaInteractionRef(ref);
94
+ if (!parsed)
95
+ return undefined;
96
+ if (parsed.kind === "map") {
97
+ return components.map ? { kind: "map", id: "map", component: components.map } : undefined;
98
+ }
99
+ const id = parsed.id;
100
+ const table = {
101
+ layer: components.layers,
102
+ widget: components.widgets,
103
+ control: components.controls,
104
+ };
105
+ const component = table[parsed.kind]?.[id];
106
+ if (!component)
107
+ return undefined;
108
+ return { kind: parsed.kind, id, component };
109
+ }
110
+ class InteractionCompiler {
111
+ #view;
112
+ #components;
113
+ #onDispatch;
114
+ #bindings = [];
115
+ #unsupported = [];
116
+ #disabled = [];
117
+ /** Re-entrancy guard: an event delivered while an action runs is dropped (actions never emit events). */
118
+ #dispatching = false;
119
+ #disposed = false;
120
+ constructor(options, components) {
121
+ this.#view = options.view;
122
+ this.#components = components;
123
+ this.#onDispatch = options.onDispatch;
124
+ }
125
+ compile(interaction) {
126
+ if (interaction.disabled === true) {
127
+ this.#disabled.push(interaction.id);
128
+ return;
129
+ }
130
+ const source = resolveComponent(interaction.on.ref, this.#components);
131
+ const target = resolveComponent(interaction.do.ref, this.#components);
132
+ const action = this.#compileAction(interaction, target);
133
+ if (typeof action === "string") {
134
+ this.#reject(interaction, action);
135
+ return;
136
+ }
137
+ const dispose = this.#compileEvent(interaction, source, action);
138
+ if (typeof dispose === "string") {
139
+ this.#reject(interaction, dispose);
140
+ return;
141
+ }
142
+ let released = false;
143
+ this.#bindings.push({
144
+ interactionId: interaction.id,
145
+ on: { ref: interaction.on.ref, event: interaction.on.event },
146
+ do: { ref: interaction.do.ref, verb: interaction.do.verb },
147
+ pair: pairLabel(interaction),
148
+ dispose: () => {
149
+ if (released)
150
+ return;
151
+ released = true;
152
+ dispose();
153
+ },
154
+ });
155
+ }
156
+ result() {
157
+ const bindings = [...this.#bindings];
158
+ return {
159
+ ok: this.#unsupported.length === 0,
160
+ issues: [],
161
+ bindings,
162
+ unsupported: [...this.#unsupported],
163
+ disabled: [...this.#disabled],
164
+ dispose: () => {
165
+ if (this.#disposed)
166
+ return;
167
+ this.#disposed = true;
168
+ for (const binding of bindings)
169
+ binding.dispose();
170
+ },
171
+ };
172
+ }
173
+ #reject(interaction, reason) {
174
+ this.#unsupported.push({
175
+ interactionId: interaction.id,
176
+ on: { ref: interaction.on.ref, event: interaction.on.event },
177
+ do: { ref: interaction.do.ref, verb: interaction.do.verb },
178
+ pair: pairLabel(interaction),
179
+ reason,
180
+ });
181
+ }
182
+ // ── Event side ──────────────────────────────────────────────
183
+ /** Returns a disposer, or a string reason the pair is unsupported. */
184
+ #compileEvent(interaction, source, action) {
185
+ const emit = (payload) => {
186
+ if (this.#disposed || this.#dispatching)
187
+ return;
188
+ this.#dispatching = true;
189
+ try {
190
+ action(payload);
191
+ }
192
+ finally {
193
+ this.#dispatching = false;
194
+ }
195
+ };
196
+ switch (interaction.on.event) {
197
+ case "featureSelect": {
198
+ if (source.kind !== "layer")
199
+ return `\`featureSelect\` is a layer event; \`${interaction.on.ref}\` is not a layer.`;
200
+ const map = source.component.map;
201
+ if (!map)
202
+ return `Layer "${source.id}" declares no \`map\`, so \`featureSelect\` has no primitive to bind to.`;
203
+ const sourceId = source.component.sourceId ?? source.id;
204
+ const handle = createSelectionHandler(map, {
205
+ source: sourceId,
206
+ layer: source.component.layerId ?? source.id,
207
+ ...(source.component.sourceLayer ? { sourceLayer: source.component.sourceLayer } : {}),
208
+ ...(source.component.multiSelect !== undefined ? { multiSelect: source.component.multiSelect } : {}),
209
+ onSelectionTargetsChange: (targets) => emit(featureSelectPayload(sourceId, targets)),
210
+ });
211
+ return () => handle.remove();
212
+ }
213
+ case "featureHover": {
214
+ if (source.kind !== "layer")
215
+ return `\`featureHover\` is a layer event; \`${interaction.on.ref}\` is not a layer.`;
216
+ const map = source.component.map;
217
+ if (!map)
218
+ return `Layer "${source.id}" declares no \`map\`, so \`featureHover\` has no primitive to bind to.`;
219
+ const sourceId = source.component.sourceId ?? source.id;
220
+ const handle = createHoverHandler(map, {
221
+ source: sourceId,
222
+ layer: source.component.layerId ?? source.id,
223
+ ...(source.component.sourceLayer ? { sourceLayer: source.component.sourceLayer } : {}),
224
+ onHoverTargetChange: (hovered) => emit(featureHoverPayload(sourceId, hovered)),
225
+ });
226
+ return () => handle.remove();
227
+ }
228
+ case "selection": {
229
+ if (source.kind !== "widget")
230
+ return `\`selection\` is a widget event; \`${interaction.on.ref}\` is not a widget.`;
231
+ // Compiled onto the table/grid selection primitive: a widget publishes
232
+ // and observes selection through the shared exploration slice.
233
+ const unsubscribe = bindTableSelectionToExploration(this.#view).subscribe((selection) => emit(selectionPayload(selection)));
234
+ return unsubscribe;
235
+ }
236
+ case "change": {
237
+ if (source.kind !== "control")
238
+ return `\`change\` is a control event; \`${interaction.on.ref}\` is not a control.`;
239
+ // Compiled onto the filter-control primitive, keyed by the control's
240
+ // own id — the same key `bindFilterControlsToExploration().setFilter`
241
+ // writes, so a filter bar built on that primitive needs no adapter.
242
+ const controlId = source.id;
243
+ let previous = this.#view.state.filters[controlId];
244
+ const unsubscribe = bindFilterControlsToExploration(this.#view).subscribe((filters) => {
245
+ const clause = filters[controlId];
246
+ if (clause === previous)
247
+ return;
248
+ previous = clause;
249
+ emit(changePayload(controlId, clause, filters));
250
+ });
251
+ return unsubscribe;
252
+ }
253
+ case "viewportChange": {
254
+ if (source.kind !== "map")
255
+ return "`viewportChange` is a map event; only `map` publishes it.";
256
+ // Compiled onto the shared extent slice — the slice
257
+ // `bindMapExtentToExploration` publishes into.
258
+ const unsubscribe = subscribeExplorationSelector(this.#view, "extent", (state) => state.extent, (extent) => emit(viewportPayload(extent)), { fireImmediately: false });
259
+ return unsubscribe;
260
+ }
261
+ }
262
+ }
263
+ // ── Action side ─────────────────────────────────────────────
264
+ /** Returns an action, or a string reason the pair is unsupported. */
265
+ #compileAction(interaction, target) {
266
+ const verb = interaction.do.verb;
267
+ const declaredArgs = interaction.do.args;
268
+ const observe = (args) => {
269
+ this.#onDispatch?.({
270
+ interactionId: interaction.id,
271
+ event: interaction.on.event,
272
+ verb,
273
+ ref: interaction.do.ref,
274
+ args,
275
+ });
276
+ };
277
+ switch (verb) {
278
+ case "setFilter": {
279
+ const setFilter = componentSetFilter(target);
280
+ const filterId = target.kind === "map" ? "map" : target.id;
281
+ return (payload) => {
282
+ const args = resolveHonuaInteractionArgs(declaredArgs, payload);
283
+ const clause = filterClauseFromArgs(args);
284
+ if (setFilter)
285
+ setFilter(clause);
286
+ else if (clause)
287
+ this.#view.setFilter(filterId, clause);
288
+ else
289
+ this.#view.clearFilter(filterId);
290
+ observe(args);
291
+ };
292
+ }
293
+ case "setViewport": {
294
+ if (target.kind !== "map")
295
+ return "`setViewport` targets `map`; no other component accepts it.";
296
+ const component = target.component;
297
+ return (payload) => {
298
+ const args = resolveHonuaInteractionArgs(declaredArgs, payload);
299
+ const viewport = viewportFromArgs(args);
300
+ if (component.setViewport)
301
+ component.setViewport(viewport);
302
+ else
303
+ this.#view.setExtent(extentFromBbox(viewport.bbox));
304
+ observe(args);
305
+ };
306
+ }
307
+ case "selectFeature": {
308
+ if (target.kind === "control")
309
+ return "`selectFeature` has no control-side primitive.";
310
+ const fallbackSourceId = target.kind === "layer" ? (target.component.sourceId ?? target.id) : target.id;
311
+ const selection = bindTableSelectionToExploration(this.#view);
312
+ return (payload) => {
313
+ const args = resolveHonuaInteractionArgs(declaredArgs, payload);
314
+ const featureId = args.featureId ?? args.id;
315
+ if (featureId === undefined || featureId === null) {
316
+ selection.clearSelection();
317
+ observe(args);
318
+ return;
319
+ }
320
+ const sourceId = typeof args.sourceId === "string" ? args.sourceId : fallbackSourceId;
321
+ const target_ = sourceFeatureSelectionTarget(sourceId, featureId);
322
+ selection.select([target_], { replace: args.replace !== false });
323
+ observe(args);
324
+ };
325
+ }
326
+ case "runWidgetQuery": {
327
+ if (target.kind !== "widget")
328
+ return "`runWidgetQuery` targets `widget:{id}`; no other component accepts it.";
329
+ const runQuery = target.component.runQuery;
330
+ if (!runQuery) {
331
+ return `Widget "${target.id}" declares no \`runQuery\`, and there is no exploration-level fallback for \`runWidgetQuery\`.`;
332
+ }
333
+ return (payload) => {
334
+ const args = resolveHonuaInteractionArgs(declaredArgs, payload);
335
+ runQuery(args);
336
+ observe(args);
337
+ };
338
+ }
339
+ case "setVisibility": {
340
+ if (target.kind === "map")
341
+ return "`setVisibility` targets a layer, widget, or control, never `map`.";
342
+ const setVisibility = target.component.setVisibility;
343
+ if (!setVisibility) {
344
+ return `${target.kind === "layer" ? "Layer" : target.kind === "widget" ? "Widget" : "Control"} "${target.id}" declares no \`setVisibility\`.`;
345
+ }
346
+ return (payload) => {
347
+ const args = resolveHonuaInteractionArgs(declaredArgs, payload);
348
+ setVisibility(args.visible !== false);
349
+ observe(args);
350
+ };
351
+ }
352
+ }
353
+ }
354
+ }
355
+ // ── Payload builders ──────────────────────────────────────────
356
+ function featureSelectPayload(sourceId, targets) {
357
+ const first = targets[0];
358
+ return {
359
+ sourceId: first?.sourceId ?? sourceId,
360
+ ...(first ? { featureId: first.id } : {}),
361
+ ...(first?.sourceLayer ? { sourceLayer: first.sourceLayer } : {}),
362
+ targets,
363
+ count: targets.length,
364
+ };
365
+ }
366
+ function featureHoverPayload(sourceId, hovered) {
367
+ return {
368
+ sourceId: hovered?.sourceId ?? sourceId,
369
+ ...(hovered ? { featureId: hovered.id } : {}),
370
+ ...(hovered?.sourceLayer ? { sourceLayer: hovered.sourceLayer } : {}),
371
+ ...(hovered ? { target: hovered } : {}),
372
+ hovering: hovered !== undefined,
373
+ };
374
+ }
375
+ function selectionPayload(selection) {
376
+ const first = selection[0];
377
+ const qualified = typeof first === "object" && first !== null ? first : undefined;
378
+ return {
379
+ targets: selection,
380
+ count: selection.length,
381
+ ...(qualified ? { sourceId: qualified.sourceId, featureId: qualified.id } : {}),
382
+ ...(qualified === undefined && first !== undefined ? { featureId: first } : {}),
383
+ };
384
+ }
385
+ function changePayload(id, clause, filters) {
386
+ return {
387
+ id,
388
+ ...(clause ? { field: clause.field, operator: clause.operator, value: clause.value, clause } : {}),
389
+ filters,
390
+ };
391
+ }
392
+ function viewportPayload(extent) {
393
+ return {
394
+ ...(extent ? { bbox: [extent.xmin, extent.ymin, extent.xmax, extent.ymax], extent } : {}),
395
+ };
396
+ }
397
+ // ── Argument projection ───────────────────────────────────────
398
+ function componentSetFilter(target) {
399
+ if (target.kind === "map")
400
+ return undefined;
401
+ const setFilter = target.component.setFilter;
402
+ return setFilter ? (clause) => setFilter(clause) : undefined;
403
+ }
404
+ const FILTER_OPERATORS = new Set([
405
+ "=",
406
+ "!=",
407
+ "<",
408
+ "<=",
409
+ ">",
410
+ ">=",
411
+ "in",
412
+ "not-in",
413
+ "between",
414
+ "like",
415
+ "is-null",
416
+ "is-not-null",
417
+ ]);
418
+ function filterClauseFromArgs(args) {
419
+ const declared = args.clause;
420
+ if (declared && typeof declared === "object" && !Array.isArray(declared)) {
421
+ const clause = declared;
422
+ if (typeof clause.field === "string") {
423
+ return {
424
+ field: clause.field,
425
+ operator: FILTER_OPERATORS.has(clause.operator) ? clause.operator : "=",
426
+ value: clause.value,
427
+ ...(Array.isArray(clause.appliesTo) ? { appliesTo: clause.appliesTo } : {}),
428
+ };
429
+ }
430
+ }
431
+ if (typeof args.field !== "string")
432
+ return undefined;
433
+ // A `$event.*` path that resolved to nothing clears the filter rather than
434
+ // installing an `= undefined` clause nothing can translate.
435
+ if (args.value === undefined && !isValuelessOperator(args.operator))
436
+ return undefined;
437
+ return {
438
+ field: args.field,
439
+ operator: FILTER_OPERATORS.has(args.operator) ? args.operator : "=",
440
+ value: args.value,
441
+ ...(Array.isArray(args.appliesTo) ? { appliesTo: args.appliesTo } : {}),
442
+ };
443
+ }
444
+ function isValuelessOperator(operator) {
445
+ return operator === "is-null" || operator === "is-not-null";
446
+ }
447
+ function viewportFromArgs(args) {
448
+ const bbox = numberTuple(args.bbox, 4);
449
+ const center = numberTuple(args.center, 2);
450
+ return {
451
+ ...(bbox ? { bbox } : {}),
452
+ ...(center ? { center } : {}),
453
+ ...(typeof args.zoom === "number" ? { zoom: args.zoom } : {}),
454
+ ...(typeof args.pitch === "number" ? { pitch: args.pitch } : {}),
455
+ ...(typeof args.bearing === "number" ? { bearing: args.bearing } : {}),
456
+ };
457
+ }
458
+ function numberTuple(value, length) {
459
+ if (!Array.isArray(value) || value.length !== length)
460
+ return undefined;
461
+ return value.every((entry) => typeof entry === "number" && Number.isFinite(entry))
462
+ ? value
463
+ : undefined;
464
+ }
465
+ function extentFromBbox(bbox) {
466
+ return bbox ? { xmin: bbox[0], ymin: bbox[1], xmax: bbox[2], ymax: bbox[3] } : undefined;
467
+ }
468
+ function pairLabel(interaction) {
469
+ return `${interaction.on.event} -> ${interaction.do.verb}`;
470
+ }
@@ -61,6 +61,13 @@ export interface HoverHandlerOptions {
61
61
  stateKey?: string;
62
62
  /** Source layer (required for vector-tile sources). */
63
63
  sourceLayer?: string;
64
+ /**
65
+ * Called whenever the hovered feature changes, with the source-qualified
66
+ * target or `undefined` when the pointer leaves the layer. Mirrors
67
+ * {@link SelectionHandlerOptions.onSelectionTargetsChange} so a hover, like
68
+ * a selection, can be published without re-reading `hoveredId` on a timer.
69
+ */
70
+ onHoverTargetChange?: (hovered: SourceQualifiedFeatureSelectionTarget | undefined) => void;
64
71
  }
65
72
  /** Handle returned by {@link createHoverHandler} for cleanup. */
66
73
  export interface HoverHandle {
@@ -1 +1 @@
1
- {"version":3,"file":"feature-state.d.ts","sourceRoot":"","sources":["../../../src/interactions/feature-state.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"feature-state.d.ts","sourceRoot":"","sources":["../../../src/interactions/feature-state.ts"],"names":[],"mappings":"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"}
@@ -50,23 +50,31 @@ export function removeFeatureState(map, source, id, key, sourceLayer) {
50
50
  * ```
51
51
  */
52
52
  export function createHoverHandler(map, options) {
53
- const { source, layer, stateKey = "hover", sourceLayer } = options;
53
+ const { source, layer, stateKey = "hover", sourceLayer, onHoverTargetChange } = options;
54
54
  let hoveredId;
55
55
  function onMouseMove(...args) {
56
56
  const e = args[0];
57
57
  const featureId = e?.features?.[0]?.id;
58
58
  if (featureId === undefined || featureId === null)
59
59
  return;
60
- if (hoveredId !== undefined && hoveredId !== featureId) {
60
+ const changed = hoveredId !== featureId;
61
+ if (hoveredId !== undefined && changed) {
61
62
  map.setFeatureState({ source, id: hoveredId, sourceLayer }, { [stateKey]: false });
62
63
  }
63
64
  hoveredId = featureId;
64
65
  map.setFeatureState({ source, id: hoveredId, sourceLayer }, { [stateKey]: true });
66
+ // Feature-state is re-set idempotently on every mousemove (unchanged
67
+ // behavior); the callback fires only on an actual hover *change* so a
68
+ // declarative binding sees one event per hovered feature, not one per
69
+ // pointer sample.
70
+ if (changed)
71
+ onHoverTargetChange?.(sourceFeatureSelectionTarget(source, featureId, { sourceLayer }));
65
72
  }
66
73
  function onMouseLeave() {
67
74
  if (hoveredId !== undefined) {
68
75
  map.setFeatureState({ source, id: hoveredId, sourceLayer }, { [stateKey]: false });
69
76
  hoveredId = undefined;
77
+ onHoverTargetChange?.(undefined);
70
78
  }
71
79
  }
72
80
  map.on("mousemove", layer, onMouseMove);
@@ -89,7 +89,7 @@ export function createHonuaMapLibreStyle(options = {}) {
89
89
  ...(options.name ? { name: options.name } : {}),
90
90
  ...(options.center ? { center: options.center } : {}),
91
91
  ...(options.zoom !== undefined ? { zoom: options.zoom } : {}),
92
- metadata: options.basemap ? { "honua:arcgis-basemap": options.basemap } : undefined,
92
+ ...(options.basemap ? { metadata: { "honua:arcgis-basemap": options.basemap } } : {}),
93
93
  sources,
94
94
  layers,
95
95
  };
@@ -1,6 +1,6 @@
1
1
  import type { HonuaClient } from "../core/client.js";
2
2
  import type { QueryMethod } from "../core/types.js";
3
- import { type HonuaAlert, type HonuaAlertActionRequest, type HonuaAlertRule, type HonuaAlertRuleTestResult, type HonuaAlertRuleWriteRequest, type HonuaGeofenceZone, type HonuaGeofenceZoneWriteRequest, type HonuaInvestigation, type HonuaInvestigationCreateRequest, type HonuaInvestigationPinRequest, type HonuaJobActionRequest, type HonuaJobArtifact, type HonuaJobLog, type HonuaJobRunDetail, type HonuaJobRunSummary, type HonuaLogRecord, type HonuaObservabilityTarget, type HonuaOperateCapability, type HonuaOperateListOptions, type HonuaOperatePage, type HonuaOperateRawRequest, type HonuaOperateRequestOptions, type HonuaOperateResult, type HonuaOperationalEvent, type HonuaServerTelemetryStatus } from "./types.js";
3
+ import { type HonuaAlert, type HonuaAlertActionRequest, type HonuaAlertRule, type HonuaAlertRuleTestRequest, type HonuaAlertRuleTestResult, type HonuaAlertRuleWriteRequest, type HonuaGeofenceZone, type HonuaGeofenceZoneWriteRequest, type HonuaInvestigation, type HonuaInvestigationCreateRequest, type HonuaInvestigationPinRequest, type HonuaJobActionRequest, type HonuaJobArtifact, type HonuaJobLog, type HonuaJobRunDetail, type HonuaJobRunSummary, type HonuaLogRecord, type HonuaObservabilityTarget, type HonuaOperateCapability, type HonuaOperateListOptions, type HonuaOperatePage, type HonuaOperateRawRequest, type HonuaOperateRequestOptions, type HonuaOperateResult, type HonuaOperationalEvent, type HonuaServerTelemetryStatus } from "./types.js";
4
4
  export interface HonuaOperateClientOptions {
5
5
  readonly client: HonuaClient;
6
6
  readonly basePath?: string;
@@ -29,6 +29,10 @@ export declare class HonuaOperateClient {
29
29
  requestJson<T>(capability: HonuaOperateCapability, method: QueryMethod, path: string, body?: unknown, options?: HonuaOperateRequestOptions & {
30
30
  okStatuses?: readonly number[];
31
31
  }): Promise<HonuaOperateResult<T>>;
32
+ /** @internal Request a server path outside the experimental Operate base. */
33
+ requestServerJson<T>(capability: HonuaOperateCapability, method: QueryMethod, path: string, body?: unknown, options?: HonuaOperateRequestOptions & {
34
+ okStatuses?: readonly number[];
35
+ }): Promise<HonuaOperateResult<T>>;
32
36
  requestPage<T>(capability: HonuaOperateCapability, path: string, options?: HonuaOperateListOptions): Promise<HonuaOperateResult<HonuaOperatePage<T>>>;
33
37
  resolvePath(path: string): string;
34
38
  }
@@ -63,6 +67,12 @@ export declare class HonuaAlertRulesClient {
63
67
  create(request: HonuaAlertRuleWriteRequest, options?: HonuaOperateRequestOptions): Promise<HonuaOperateResult<HonuaAlertRule>>;
64
68
  update(ruleId: string, request: HonuaAlertRuleWriteRequest, options?: HonuaOperateRequestOptions): Promise<HonuaOperateResult<HonuaAlertRule>>;
65
69
  delete(ruleId: string, options?: HonuaOperateRequestOptions): Promise<HonuaOperateResult<void>>;
70
+ /** Evaluate an unpersisted rule (and optional zone) against the server contract. */
71
+ test(request: HonuaAlertRuleTestRequest, options?: HonuaOperateRequestOptions): Promise<HonuaOperateResult<HonuaAlertRuleTestResult>>;
72
+ /**
73
+ * @deprecated The server has no persisted-rule test route. Pass a
74
+ * {@link HonuaAlertRuleTestRequest} draft instead. See honua-server#3388.
75
+ */
66
76
  test(ruleId: string, options?: HonuaOperateRequestOptions): Promise<HonuaOperateResult<HonuaAlertRuleTestResult>>;
67
77
  }
68
78
  export declare class HonuaGeofencesClient {
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/operate/client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/operate/client.ts"],"names":[],"mappings":"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"}
package/operate/client.js CHANGED
@@ -60,6 +60,18 @@ export class HonuaOperateClient {
60
60
  return unsupportedFromError(capability, error);
61
61
  }
62
62
  }
63
+ /** @internal Request a server path outside the experimental Operate base. */
64
+ async requestServerJson(capability, method, path, body, options = {}) {
65
+ try {
66
+ const response = await this.#client.pipelineFetch(method, path, { headers: jsonHeaders(options.headers), body: body === undefined ? null : JSON.stringify(body) }, options.signal, options.okStatuses ? { okStatuses: options.okStatuses } : {});
67
+ if (response.status === 204)
68
+ return supported(undefined);
69
+ return supported((await readJson(response)));
70
+ }
71
+ catch (error) {
72
+ return unsupportedFromError(capability, error);
73
+ }
74
+ }
63
75
  async requestPage(capability, path, options = {}) {
64
76
  try {
65
77
  const hasValidator = Boolean(options.validator?.etag || options.validator?.lastModified);
@@ -165,8 +177,17 @@ export class HonuaAlertRulesClient {
165
177
  okStatuses: [204],
166
178
  });
167
179
  }
168
- test(ruleId, options = {}) {
169
- return this.#operate.requestJson("alert-rules", "POST", `/alert-rules/${encodeURIComponent(ruleId)}/test`, {}, options);
180
+ test(request, options = {}) {
181
+ if (typeof request === "string") {
182
+ throw new TypeError(`alertRules.test(${JSON.stringify(request)}) can no longer target a persisted rule; pass { rule, zone? } to evaluate a draft via POST /api/v1/admin/alerts/rules/test`);
183
+ }
184
+ return this.#operate
185
+ .requestServerJson("alert-rules", "POST", "/api/v1/admin/alerts/rules/test", request, options)
186
+ .then((response) => {
187
+ if (!response.supported)
188
+ return response;
189
+ return supported(alertRuleTestResult(response.value.data));
190
+ });
170
191
  }
171
192
  }
172
193
  export class HonuaGeofencesClient {
@@ -255,6 +276,22 @@ function normalizeBasePath(basePath) {
255
276
  function supported(value) {
256
277
  return { supported: true, value };
257
278
  }
279
+ function alertRuleTestResult(value) {
280
+ if (!value || typeof value !== "object")
281
+ throw new TypeError("Alert-rule test response is missing data.");
282
+ const result = value;
283
+ if (typeof result.isValid !== "boolean" ||
284
+ !Array.isArray(result.errors) ||
285
+ !result.errors.every((entry) => typeof entry === "string") ||
286
+ !Array.isArray(result.warnings) ||
287
+ !result.warnings.every((entry) => typeof entry === "string") ||
288
+ !Array.isArray(result.deliveryChannels) ||
289
+ typeof result.evaluatedAt !== "string" ||
290
+ result.evaluatedAt.length === 0) {
291
+ throw new TypeError("Alert-rule test response data does not match the generated server contract.");
292
+ }
293
+ return result;
294
+ }
258
295
  function unsupportedFromError(capability, error) {
259
296
  if (error instanceof HonuaHttpError && (error.statusCode === 404 || error.statusCode === 501)) {
260
297
  return unsupportedFromStatus(capability, error.statusCode, error.body);