@honua/react 0.1.0-beta.0 → 0.1.2-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.
- package/contract/discovery.d.ts +231 -0
- package/contract/discovery.d.ts.map +1 -0
- package/contract/discovery.js +554 -0
- package/contract/edit-sketch.d.ts +8 -0
- package/contract/edit-sketch.d.ts.map +1 -1
- package/contract/edit-sketch.js +15 -0
- package/contract/edit-snapping.d.ts +160 -0
- package/contract/edit-snapping.d.ts.map +1 -0
- package/contract/edit-snapping.js +675 -0
- package/contract/generated/projjson-v0.7-crs-validator.d.ts +35 -0
- package/contract/generated/projjson-v0.7-crs-validator.d.ts.map +1 -0
- package/contract/generated/projjson-v0.7-crs-validator.js +3941 -0
- package/contract/index.d.ts +11 -2
- package/contract/index.d.ts.map +1 -1
- package/contract/index.js +4 -1
- package/contract/pmtiles.d.ts +31 -0
- package/contract/pmtiles.d.ts.map +1 -1
- package/contract/pmtiles.js +60 -20
- package/contract/protocol-module.d.ts +70 -0
- package/contract/protocol-module.d.ts.map +1 -0
- package/contract/protocol-module.js +1 -0
- package/contract/schema-envelope.d.ts +26 -0
- package/contract/schema-envelope.d.ts.map +1 -0
- package/contract/schema-envelope.js +25 -0
- package/contract/schema.d.ts +582 -0
- package/contract/schema.d.ts.map +1 -0
- package/contract/schema.js +2483 -0
- package/contract/source-capability-support.d.ts +6 -0
- package/contract/source-capability-support.d.ts.map +1 -0
- package/contract/source-capability-support.js +154 -0
- package/contract/source.d.ts +35 -17
- package/contract/source.d.ts.map +1 -1
- package/contract/source.js +267 -71
- package/contract/types.d.ts +140 -4
- package/contract/types.d.ts.map +1 -1
- package/contract/types.js +6 -14
- package/core/bounded-json.d.ts +4 -0
- package/core/bounded-json.d.ts.map +1 -0
- package/core/bounded-json.js +38 -0
- package/core/cache-state.d.ts +9 -0
- package/core/cache-state.d.ts.map +1 -1
- package/core/cache-state.js +10 -0
- package/core/capabilities-xml.d.ts +33 -0
- package/core/capabilities-xml.d.ts.map +1 -0
- package/core/capabilities-xml.js +331 -0
- package/core/client.d.ts +4 -1
- package/core/client.d.ts.map +1 -1
- package/core/client.js +115 -29
- package/core/error-classifications.d.ts +153 -0
- package/core/error-classifications.d.ts.map +1 -0
- package/core/error-classifications.js +140 -0
- package/core/error-code-registry.d.ts +158 -0
- package/core/error-code-registry.d.ts.map +1 -0
- package/core/error-code-registry.js +143 -0
- package/core/error-envelope.d.ts +68 -0
- package/core/error-envelope.d.ts.map +1 -0
- package/core/error-envelope.js +357 -0
- package/core/errors.d.ts +45 -29
- package/core/errors.d.ts.map +1 -1
- package/core/errors.js +97 -50
- package/core/geoparquet-sql.d.ts +30 -2
- package/core/geoparquet-sql.d.ts.map +1 -1
- package/core/geoparquet-sql.js +38 -3
- package/core/odata-key-path.d.ts +12 -0
- package/core/odata-key-path.d.ts.map +1 -0
- package/core/odata-key-path.js +28 -0
- package/core/odata-write-codec.d.ts +66 -0
- package/core/odata-write-codec.d.ts.map +1 -0
- package/core/odata-write-codec.js +1083 -0
- package/core/odata.d.ts +59 -7
- package/core/odata.d.ts.map +1 -1
- package/core/odata.js +431 -99
- package/core/ogc-features.d.ts.map +1 -1
- package/core/ogc-features.js +3 -0
- package/core/ogc-maps.d.ts +7 -0
- package/core/ogc-maps.d.ts.map +1 -1
- package/core/ogc-maps.js +46 -7
- package/core/ogc-processes.d.ts +2 -1
- package/core/ogc-processes.d.ts.map +1 -1
- package/core/ogc-processes.js +33 -5
- package/core/ogc-records.d.ts +9 -0
- package/core/ogc-records.d.ts.map +1 -1
- package/core/ogc-records.js +78 -29
- package/core/ogc-tiles.d.ts +10 -1
- package/core/ogc-tiles.d.ts.map +1 -1
- package/core/ogc-tiles.js +56 -17
- package/core/path-utils.d.ts +9 -0
- package/core/path-utils.d.ts.map +1 -1
- package/core/path-utils.js +19 -0
- package/core/protocol-transport.d.ts +1 -0
- package/core/protocol-transport.d.ts.map +1 -1
- package/core/request-pipeline.d.ts.map +1 -1
- package/core/request-pipeline.js +1 -1
- package/core/spatial-filter.d.ts +8 -4
- package/core/spatial-filter.d.ts.map +1 -1
- package/core/spatial-filter.js +206 -16
- package/core/stac-static.d.ts +6 -2
- package/core/stac-static.d.ts.map +1 -1
- package/core/stac-static.js +260 -69
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +69 -5
- package/core/types.d.ts +125 -7
- package/core/types.d.ts.map +1 -1
- package/core/wfs-capabilities.d.ts +2 -0
- package/core/wfs-capabilities.d.ts.map +1 -1
- package/core/wfs-capabilities.js +8 -1
- package/core/wfs.d.ts.map +1 -1
- package/core/wfs.js +10 -0
- package/core/wms-capabilities.d.ts +56 -84
- package/core/wms-capabilities.d.ts.map +1 -1
- package/core/wms-capabilities.js +212 -509
- package/core/wmts-capabilities.d.ts +62 -62
- package/core/wmts-capabilities.d.ts.map +1 -1
- package/core/wmts-capabilities.js +224 -371
- package/esri-compat/editor.d.ts +8 -0
- package/esri-compat/editor.d.ts.map +1 -1
- package/esri-compat/editor.js +13 -0
- package/esri-compat/feature-layer.d.ts +2 -0
- package/esri-compat/feature-layer.d.ts.map +1 -1
- package/esri-compat/feature-layer.js +1 -0
- package/esri-compat/layer-list.d.ts +11 -0
- package/esri-compat/layer-list.d.ts.map +1 -1
- package/esri-compat/layer-list.js +49 -0
- package/esri-compat/legend.d.ts +10 -0
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +27 -0
- package/esri-compat/portal.d.ts +197 -0
- package/esri-compat/portal.d.ts.map +1 -0
- package/esri-compat/portal.js +251 -0
- package/esri-compat/renderer-objects.d.ts +40 -0
- package/esri-compat/renderer-objects.d.ts.map +1 -0
- package/esri-compat/renderer-objects.js +62 -0
- package/esri-compat/sketch.d.ts +43 -0
- package/esri-compat/sketch.d.ts.map +1 -1
- package/esri-compat/sketch.js +46 -0
- package/esri-compat/snapping.d.ts +43 -0
- package/esri-compat/snapping.d.ts.map +1 -0
- package/esri-compat/snapping.js +45 -0
- package/esri-compat/url.d.ts.map +1 -1
- package/esri-compat/url.js +1 -1
- package/esri-compat/widget-host.d.ts +84 -0
- package/esri-compat/widget-host.d.ts.map +1 -0
- package/esri-compat/widget-host.js +159 -0
- package/filter-registry/index.d.ts +145 -0
- package/filter-registry/index.d.ts.map +1 -0
- package/filter-registry/index.js +531 -0
- package/generated-app/errors.d.ts +18 -2
- package/generated-app/errors.d.ts.map +1 -1
- package/generated-app/errors.js +44 -11
- package/map/automatic-mount-integration.d.ts +134 -0
- package/map/automatic-mount-integration.d.ts.map +1 -0
- package/map/automatic-mount-integration.js +305 -0
- package/map/automatic-source-strategy.d.ts +125 -0
- package/map/automatic-source-strategy.d.ts.map +1 -0
- package/map/automatic-source-strategy.js +494 -0
- package/map/data-to-map-bridge.d.ts +293 -0
- package/map/data-to-map-bridge.d.ts.map +1 -0
- package/map/data-to-map-bridge.js +817 -0
- package/map/geojson-projection.d.ts +33 -0
- package/map/geojson-projection.d.ts.map +1 -0
- package/map/geojson-projection.js +118 -0
- package/map/index.d.ts +14 -0
- package/map/index.d.ts.map +1 -1
- package/map/index.js +8 -0
- package/map/raster-source-spec.d.ts +30 -0
- package/map/raster-source-spec.d.ts.map +1 -0
- package/map/raster-source-spec.js +190 -0
- package/map/raster-source-strategy.d.ts +65 -0
- package/map/raster-source-strategy.d.ts.map +1 -0
- package/map/raster-source-strategy.js +232 -0
- package/map/source-to-maplibre.d.ts +91 -0
- package/map/source-to-maplibre.d.ts.map +1 -0
- package/map/source-to-maplibre.js +454 -0
- package/map/temporal-playback.d.ts +139 -0
- package/map/temporal-playback.d.ts.map +1 -0
- package/map/temporal-playback.js +247 -0
- package/package.json +14 -1
- package/query-planner/canonical.d.ts +7 -0
- package/query-planner/canonical.d.ts.map +1 -0
- package/query-planner/canonical.js +145 -0
- package/query-planner/cql2-json.d.ts +17 -0
- package/query-planner/cql2-json.d.ts.map +1 -0
- package/query-planner/cql2-json.js +646 -0
- package/query-planner/diagnostics.d.ts +35 -0
- package/query-planner/diagnostics.d.ts.map +1 -0
- package/query-planner/diagnostics.js +373 -0
- package/query-planner/duckdb.d.ts +79 -0
- package/query-planner/duckdb.d.ts.map +1 -0
- package/query-planner/duckdb.js +758 -0
- package/query-planner/execution-context.d.ts +5 -0
- package/query-planner/execution-context.d.ts.map +1 -0
- package/query-planner/execution-context.js +50 -0
- package/query-planner/executor.d.ts +5 -0
- package/query-planner/executor.d.ts.map +1 -0
- package/query-planner/executor.js +223 -0
- package/query-planner/geoservices.d.ts +91 -0
- package/query-planner/geoservices.d.ts.map +1 -0
- package/query-planner/geoservices.js +667 -0
- package/query-planner/grpc.d.ts +100 -0
- package/query-planner/grpc.d.ts.map +1 -0
- package/query-planner/grpc.js +736 -0
- package/query-planner/index.d.ts +44 -0
- package/query-planner/index.d.ts.map +1 -0
- package/query-planner/index.js +30 -0
- package/query-planner/ir.d.ts +20 -0
- package/query-planner/ir.d.ts.map +1 -0
- package/query-planner/ir.js +417 -0
- package/query-planner/local-aggregate.d.ts +5 -0
- package/query-planner/local-aggregate.d.ts.map +1 -0
- package/query-planner/local-aggregate.js +126 -0
- package/query-planner/odata.d.ts +48 -0
- package/query-planner/odata.d.ts.map +1 -0
- package/query-planner/odata.js +662 -0
- package/query-planner/ogc-compiler.d.ts +55 -0
- package/query-planner/ogc-compiler.d.ts.map +1 -0
- package/query-planner/ogc-compiler.js +480 -0
- package/query-planner/ogc-features.d.ts +53 -0
- package/query-planner/ogc-features.d.ts.map +1 -0
- package/query-planner/ogc-features.js +617 -0
- package/query-planner/planner.d.ts +17 -0
- package/query-planner/planner.d.ts.map +1 -0
- package/query-planner/planner.js +818 -0
- package/query-planner/resource.d.ts +94 -0
- package/query-planner/resource.d.ts.map +1 -0
- package/query-planner/resource.js +526 -0
- package/query-planner/semantic-canonical.d.ts +15 -0
- package/query-planner/semantic-canonical.d.ts.map +1 -0
- package/query-planner/semantic-canonical.js +62 -0
- package/query-planner/semantic-compat.d.ts +10 -0
- package/query-planner/semantic-compat.d.ts.map +1 -0
- package/query-planner/semantic-compat.js +35 -0
- package/query-planner/semantic-compiler.d.ts +64 -0
- package/query-planner/semantic-compiler.d.ts.map +1 -0
- package/query-planner/semantic-compiler.js +81 -0
- package/query-planner/semantic-literals.d.ts +30 -0
- package/query-planner/semantic-literals.d.ts.map +1 -0
- package/query-planner/semantic-literals.js +133 -0
- package/query-planner/semantic-types.d.ts +265 -0
- package/query-planner/semantic-types.d.ts.map +1 -0
- package/query-planner/semantic-types.js +1 -0
- package/query-planner/semantic.d.ts +54 -0
- package/query-planner/semantic.d.ts.map +1 -0
- package/query-planner/semantic.js +1421 -0
- package/query-planner/types.d.ts +560 -0
- package/query-planner/types.d.ts.map +1 -0
- package/query-planner/types.js +49 -0
- package/query-planner/wfs-semantic.d.ts +58 -0
- package/query-planner/wfs-semantic.d.ts.map +1 -0
- package/query-planner/wfs-semantic.js +547 -0
- package/query-planner/wfs.d.ts +6 -0
- package/query-planner/wfs.d.ts.map +1 -0
- package/query-planner/wfs.js +71 -0
- package/react/external-map.d.ts +67 -0
- package/react/external-map.d.ts.map +1 -0
- package/react/external-map.js +63 -0
- package/react/honua-map.d.ts.map +1 -1
- package/react/honua-map.js +3 -2
- package/react/honua-source-layer.d.ts +110 -0
- package/react/honua-source-layer.d.ts.map +1 -0
- package/react/honua-source-layer.js +101 -0
- package/react/hooks.d.ts +28 -0
- package/react/hooks.d.ts.map +1 -1
- package/react/hooks.js +26 -4
- package/react/index.d.ts +8 -0
- package/react/index.d.ts.map +1 -1
- package/react/index.js +5 -0
- package/react/query-cache.d.ts +26 -4
- package/react/query-cache.d.ts.map +1 -1
- package/react/query-cache.js +51 -8
- package/react/selection.d.ts +177 -0
- package/react/selection.d.ts.map +1 -0
- package/react/selection.js +0 -0
- package/react/use-mounted-source.d.ts +69 -0
- package/react/use-mounted-source.d.ts.map +1 -0
- package/react/use-mounted-source.js +346 -0
- package/runtime/edit-snapping.d.ts +107 -0
- package/runtime/edit-snapping.d.ts.map +1 -0
- package/runtime/edit-snapping.js +190 -0
- package/runtime/errors.d.ts +3 -2
- package/runtime/errors.d.ts.map +1 -1
- package/runtime/errors.js +19 -2
- package/runtime/index.d.ts +6 -0
- package/runtime/index.d.ts.map +1 -1
- package/runtime/index.js +3 -0
- package/runtime/maplibre-renderer.d.ts +41 -0
- package/runtime/maplibre-renderer.d.ts.map +1 -0
- package/runtime/maplibre-renderer.js +322 -0
- package/runtime/query-tiles.d.ts +2 -1
- package/runtime/query-tiles.d.ts.map +1 -1
- package/runtime/query-tiles.js +6 -2
- package/runtime/source-bridge.d.ts +4 -4
- package/runtime/source-bridge.d.ts.map +1 -1
- package/runtime/source-bridge.js +9 -56
- package/runtime/style-interactions.d.ts +3 -2
- package/runtime/style-interactions.d.ts.map +1 -1
- package/runtime/style-interactions.js +11 -3
- package/runtime/terra-draw-sketch.d.ts +275 -0
- package/runtime/terra-draw-sketch.d.ts.map +1 -0
- package/runtime/terra-draw-sketch.js +404 -0
- package/source-capability-registry.d.ts +1 -0
- package/source-capability-registry.js +1 -0
- package/source-capability-types.d.ts +186 -0
- package/source-capability-types.js +7 -0
- package/style/index.d.ts +2 -0
- package/style/index.d.ts.map +1 -1
- package/style/index.js +2 -0
- package/style/renderers.d.ts +326 -0
- package/style/renderers.d.ts.map +1 -0
- package/style/renderers.js +517 -0
- package/webmap/convert-renderer.d.ts +24 -3
- package/webmap/convert-renderer.d.ts.map +1 -1
- package/webmap/convert-renderer.js +93 -112
- package/webmap/index.d.ts +1 -1
- package/webmap/index.d.ts.map +1 -1
- package/webmap/index.js +1 -1
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@honua/sdk-js/filter-registry` — shared filter / crossfilter registry.
|
|
3
|
+
*
|
|
4
|
+
* Protocol-neutral state container for map, chart, table, search, and control
|
|
5
|
+
* filters. Projection helpers translate active clauses into existing SDK
|
|
6
|
+
* query, linked-view, widget, runtime-style, and URL state.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { createFilterRegistry, projectFilterRegistryToQuery } from "@honua/sdk-js/filter-registry";
|
|
11
|
+
*
|
|
12
|
+
* const registry = createFilterRegistry();
|
|
13
|
+
* registry.set("status", { field: "STATUS", op: "=", value: "ACTIVE" });
|
|
14
|
+
* registry.set("severity", { field: "SEVERITY", op: ">=", value: 3 });
|
|
15
|
+
*
|
|
16
|
+
* const query = projectFilterRegistryToQuery(registry, { sourceId: "incidents" });
|
|
17
|
+
* const { features } = await dataset.source("incidents")!.queryAll(query);
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @packageDocumentation
|
|
21
|
+
*/
|
|
22
|
+
const SERVER_FILTER_PROTOCOLS = new Set([
|
|
23
|
+
"grpc",
|
|
24
|
+
"geoservices-feature-service",
|
|
25
|
+
"geoservices-map-service",
|
|
26
|
+
"ogc-features",
|
|
27
|
+
"wfs",
|
|
28
|
+
"odata",
|
|
29
|
+
]);
|
|
30
|
+
const FILTER_OWNER_KINDS = new Set([
|
|
31
|
+
"map",
|
|
32
|
+
"chart",
|
|
33
|
+
"table",
|
|
34
|
+
"search",
|
|
35
|
+
"control",
|
|
36
|
+
"component",
|
|
37
|
+
]);
|
|
38
|
+
const FILTER_LIFECYCLES = new Set(["persistent", "session", "transient"]);
|
|
39
|
+
const FILTER_EFFECTS = new Set(["filter", "crossfilter", "selection", "search", "spatial-mask"]);
|
|
40
|
+
const FILTER_OPERATORS = new Set([
|
|
41
|
+
"=",
|
|
42
|
+
"!=",
|
|
43
|
+
"<",
|
|
44
|
+
"<=",
|
|
45
|
+
">",
|
|
46
|
+
">=",
|
|
47
|
+
"in",
|
|
48
|
+
"not-in",
|
|
49
|
+
"between",
|
|
50
|
+
"like",
|
|
51
|
+
"is-null",
|
|
52
|
+
"is-not-null",
|
|
53
|
+
]);
|
|
54
|
+
const FILTER_FIELD_IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*(?:\.[A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
55
|
+
/** Create an in-memory filter registry with owner-scoped mutation helpers. */
|
|
56
|
+
export function createFilterRegistry(options = {}) {
|
|
57
|
+
let clauses = normalizeClauses(options.initialClauses ?? []);
|
|
58
|
+
let snapshot = freezeSnapshot({ version: 1, clauses });
|
|
59
|
+
const listeners = new Set();
|
|
60
|
+
function publish(previous, changedIds) {
|
|
61
|
+
if (changedIds.size === 0)
|
|
62
|
+
return;
|
|
63
|
+
const event = { snapshot, previous, changedIds };
|
|
64
|
+
for (const listener of [...listeners])
|
|
65
|
+
listener(event);
|
|
66
|
+
}
|
|
67
|
+
function commit(nextClauses, changedIds) {
|
|
68
|
+
const previous = snapshot;
|
|
69
|
+
clauses = normalizeClauses(nextClauses);
|
|
70
|
+
snapshot = freezeSnapshot({ version: 1, clauses });
|
|
71
|
+
publish(previous, changedIds);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
get snapshot() {
|
|
75
|
+
return snapshot;
|
|
76
|
+
},
|
|
77
|
+
upsert(clause) {
|
|
78
|
+
const byId = new Map(clauses.map((entry) => [entry.id, entry]));
|
|
79
|
+
const existing = byId.get(clause.id);
|
|
80
|
+
if (existing && valuesEqual(existing, clause))
|
|
81
|
+
return;
|
|
82
|
+
byId.set(clause.id, normalizeClause(clause));
|
|
83
|
+
commit([...byId.values()], new Set([clause.id]));
|
|
84
|
+
},
|
|
85
|
+
remove(id) {
|
|
86
|
+
if (!clauses.some((clause) => clause.id === id))
|
|
87
|
+
return;
|
|
88
|
+
commit(clauses.filter((clause) => clause.id !== id), new Set([id]));
|
|
89
|
+
},
|
|
90
|
+
clearOwner(owner) {
|
|
91
|
+
const changed = clauses.filter((clause) => ownerKey(clause.owner) === ownerKey(owner)).map((clause) => clause.id);
|
|
92
|
+
if (changed.length === 0)
|
|
93
|
+
return;
|
|
94
|
+
commit(clauses.filter((clause) => ownerKey(clause.owner) !== ownerKey(owner)), new Set(changed));
|
|
95
|
+
},
|
|
96
|
+
clearSource(sourceId) {
|
|
97
|
+
const changed = clauses
|
|
98
|
+
.filter((clause) => appliesExplicitlyToSource(clause, sourceId))
|
|
99
|
+
.map((clause) => clause.id);
|
|
100
|
+
if (changed.length === 0)
|
|
101
|
+
return;
|
|
102
|
+
commit(clauses.filter((clause) => !appliesExplicitlyToSource(clause, sourceId)), new Set(changed));
|
|
103
|
+
},
|
|
104
|
+
setEnabled(id, enabled) {
|
|
105
|
+
let changed = false;
|
|
106
|
+
const next = clauses.map((clause) => {
|
|
107
|
+
if (clause.id !== id || (clause.enabled ?? true) === enabled)
|
|
108
|
+
return clause;
|
|
109
|
+
changed = true;
|
|
110
|
+
return { ...clause, enabled };
|
|
111
|
+
});
|
|
112
|
+
if (changed)
|
|
113
|
+
commit(next, new Set([id]));
|
|
114
|
+
},
|
|
115
|
+
replace(nextSnapshot) {
|
|
116
|
+
if (nextSnapshot.version !== 1)
|
|
117
|
+
throw new Error(`Unsupported filter registry snapshot version ${nextSnapshot.version}`);
|
|
118
|
+
const next = normalizeClauses(nextSnapshot.clauses);
|
|
119
|
+
if (valuesEqual(clauses, next))
|
|
120
|
+
return;
|
|
121
|
+
const ids = new Set([...clauses.map((clause) => clause.id), ...next.map((clause) => clause.id)]);
|
|
122
|
+
commit(next, ids);
|
|
123
|
+
},
|
|
124
|
+
subscribe(listener) {
|
|
125
|
+
listeners.add(listener);
|
|
126
|
+
return () => listeners.delete(listener);
|
|
127
|
+
},
|
|
128
|
+
select(selector, listener, options = {}) {
|
|
129
|
+
const equals = options.equals ?? valuesEqual;
|
|
130
|
+
let current = selector(snapshot);
|
|
131
|
+
if (options.fireImmediately)
|
|
132
|
+
listener(current, undefined);
|
|
133
|
+
return this.subscribe((event) => {
|
|
134
|
+
const next = selector(event.snapshot);
|
|
135
|
+
if (equals(current, next))
|
|
136
|
+
return;
|
|
137
|
+
current = next;
|
|
138
|
+
listener(next, event);
|
|
139
|
+
});
|
|
140
|
+
},
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
/** Return active clauses in deterministic id order, optionally source-scoped. */
|
|
144
|
+
export function selectActiveFilterClauses(snapshot, options = {}) {
|
|
145
|
+
return snapshot.clauses
|
|
146
|
+
.filter(isFilterClause)
|
|
147
|
+
.filter((clause) => (options.includeDisabled || (clause.enabled ?? true)) && appliesToSource(clause, options.sourceId))
|
|
148
|
+
.sort(compareClause);
|
|
149
|
+
}
|
|
150
|
+
/** Project active registry clauses into query/widget/linked-view/runtime state. */
|
|
151
|
+
export function projectFilterRegistryToQuery(snapshot, options = {}) {
|
|
152
|
+
const active = selectActiveFilterClauses(snapshot, options);
|
|
153
|
+
const filters = toProjectionFilters(active);
|
|
154
|
+
const linkedViewFilters = toLinkedViewFilters(active);
|
|
155
|
+
const where = compileWhere(active);
|
|
156
|
+
const spatialFilter = firstSpatialFilter(active);
|
|
157
|
+
const query = {
|
|
158
|
+
...(options.baseQuery ?? {}),
|
|
159
|
+
...(combineWhere(options.baseQuery?.where, where) ? { where: combineWhere(options.baseQuery?.where, where) } : {}),
|
|
160
|
+
...((options.baseQuery?.spatialFilter ?? spatialFilter)
|
|
161
|
+
? { spatialFilter: options.baseQuery?.spatialFilter ?? spatialFilter }
|
|
162
|
+
: {}),
|
|
163
|
+
};
|
|
164
|
+
const projection = {
|
|
165
|
+
filters,
|
|
166
|
+
...(spatialFilter ? { spatialFilter } : {}),
|
|
167
|
+
};
|
|
168
|
+
const linkedView = {
|
|
169
|
+
filters: linkedViewFilters,
|
|
170
|
+
...(spatialFilter ? { spatialFilter } : {}),
|
|
171
|
+
orderBy: (query.orderBy ?? []),
|
|
172
|
+
pagination: (query.pagination ?? {}),
|
|
173
|
+
...(query.outFields ? { outFields: query.outFields } : {}),
|
|
174
|
+
grouping: [],
|
|
175
|
+
...(query.aggregation ? { aggregation: query.aggregation } : {}),
|
|
176
|
+
selection: [],
|
|
177
|
+
};
|
|
178
|
+
const degraded = degradationFor(options.source, active);
|
|
179
|
+
return {
|
|
180
|
+
query,
|
|
181
|
+
...(where ? { where } : {}),
|
|
182
|
+
projection,
|
|
183
|
+
linkedView,
|
|
184
|
+
runtimeFilter: compileRuntimeStyleFilter(active),
|
|
185
|
+
...(degraded.length > 0 ? { degraded } : {}),
|
|
186
|
+
cacheKey: serializeFilterRegistry(snapshot, { sourceId: options.sourceId }),
|
|
187
|
+
cacheable: active.every((clause) => clause.cacheable !== false && clause.lifecycle !== "transient"),
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
/** Project active clauses directly into a `WidgetSourceProjection`. */
|
|
191
|
+
export function projectFilterRegistryToWidgetProjection(snapshot, options = {}) {
|
|
192
|
+
const projection = projectFilterRegistryToQuery(snapshot, options).projection;
|
|
193
|
+
return projection;
|
|
194
|
+
}
|
|
195
|
+
/** Project active clauses into the linked-view projection consumed by existing helpers. */
|
|
196
|
+
export function projectFilterRegistryToLinkedView(snapshot, options = {}) {
|
|
197
|
+
return projectFilterRegistryToQuery(snapshot, options).linkedView;
|
|
198
|
+
}
|
|
199
|
+
/** Compile active field clauses into a MapLibre-compatible expression tree. */
|
|
200
|
+
export function compileRuntimeStyleFilter(clauses) {
|
|
201
|
+
const parts = clauses
|
|
202
|
+
.filter((clause) => (clause.enabled ?? true) && clause.field && clause.operator)
|
|
203
|
+
.map(compileRuntimeClause)
|
|
204
|
+
.filter((entry) => entry !== undefined);
|
|
205
|
+
if (parts.length === 0)
|
|
206
|
+
return undefined;
|
|
207
|
+
return parts.length === 1 ? parts[0] : ["all", ...parts];
|
|
208
|
+
}
|
|
209
|
+
/** Deterministic URL/cache serialization. Secret or large values are omitted. */
|
|
210
|
+
export function serializeFilterRegistry(snapshot, options = {}) {
|
|
211
|
+
const shareable = {
|
|
212
|
+
version: 1,
|
|
213
|
+
clauses: selectActiveFilterClauses(snapshot, options)
|
|
214
|
+
.filter((clause) => clause.lifecycle !== "transient")
|
|
215
|
+
.map(shareableClause),
|
|
216
|
+
};
|
|
217
|
+
return stableShareStringify(shareable);
|
|
218
|
+
}
|
|
219
|
+
/** Parse a registry serialization produced by `serializeFilterRegistry`. */
|
|
220
|
+
export function parseFilterRegistry(value) {
|
|
221
|
+
if (!value)
|
|
222
|
+
return freezeSnapshot({ version: 1, clauses: [] });
|
|
223
|
+
try {
|
|
224
|
+
const parsed = JSON.parse(value);
|
|
225
|
+
if (parsed.version !== 1 || !Array.isArray(parsed.clauses))
|
|
226
|
+
return freezeSnapshot({ version: 1, clauses: [] });
|
|
227
|
+
return freezeSnapshot({ version: 1, clauses: normalizeClauses(parsed.clauses.filter(isFilterClause)) });
|
|
228
|
+
}
|
|
229
|
+
catch {
|
|
230
|
+
return freezeSnapshot({ version: 1, clauses: [] });
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
function toProjectionFilters(clauses) {
|
|
234
|
+
const out = {};
|
|
235
|
+
for (const clause of clauses) {
|
|
236
|
+
if (!clause.field || !clause.operator)
|
|
237
|
+
continue;
|
|
238
|
+
out[clause.id] = {
|
|
239
|
+
field: clause.field,
|
|
240
|
+
operator: clause.operator,
|
|
241
|
+
...(clause.value !== undefined ? { value: clause.value } : {}),
|
|
242
|
+
...(Array.isArray(clause.sourceScope) ? { appliesTo: clause.sourceScope } : {}),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
return out;
|
|
246
|
+
}
|
|
247
|
+
function toLinkedViewFilters(clauses) {
|
|
248
|
+
const out = {};
|
|
249
|
+
for (const clause of clauses) {
|
|
250
|
+
if (!clause.field || !clause.operator)
|
|
251
|
+
continue;
|
|
252
|
+
out[clause.id] = {
|
|
253
|
+
field: clause.field,
|
|
254
|
+
operator: clause.operator,
|
|
255
|
+
...(clause.value !== undefined ? { value: clause.value } : {}),
|
|
256
|
+
...(Array.isArray(clause.sourceScope) ? { appliesTo: clause.sourceScope } : {}),
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
return out;
|
|
260
|
+
}
|
|
261
|
+
function compileWhere(clauses) {
|
|
262
|
+
const parts = clauses
|
|
263
|
+
.map(compileClauseWhere)
|
|
264
|
+
.filter((entry) => entry !== undefined)
|
|
265
|
+
.map((entry) => `(${entry})`);
|
|
266
|
+
return parts.length > 0 ? parts.join(" AND ") : undefined;
|
|
267
|
+
}
|
|
268
|
+
function compileClauseWhere(clause) {
|
|
269
|
+
if (!clause.field || !clause.operator)
|
|
270
|
+
return undefined;
|
|
271
|
+
const field = sqlIdentifier(clause.field);
|
|
272
|
+
if (!field)
|
|
273
|
+
return undefined;
|
|
274
|
+
switch (clause.operator) {
|
|
275
|
+
case "=":
|
|
276
|
+
return `${field} = ${literal(clause.value)}`;
|
|
277
|
+
case "!=":
|
|
278
|
+
return `${field} <> ${literal(clause.value)}`;
|
|
279
|
+
case "<":
|
|
280
|
+
case "<=":
|
|
281
|
+
case ">":
|
|
282
|
+
case ">=":
|
|
283
|
+
return `${field} ${clause.operator} ${literal(clause.value)}`;
|
|
284
|
+
case "in":
|
|
285
|
+
case "not-in":
|
|
286
|
+
if (!Array.isArray(clause.value) || clause.value.length === 0)
|
|
287
|
+
return undefined;
|
|
288
|
+
return `${field} ${clause.operator === "not-in" ? "NOT " : ""}IN (${clause.value.map(literal).join(", ")})`;
|
|
289
|
+
case "between":
|
|
290
|
+
if (!Array.isArray(clause.value) || clause.value.length < 2)
|
|
291
|
+
return undefined;
|
|
292
|
+
return `${field} BETWEEN ${literal(clause.value[0])} AND ${literal(clause.value[1])}`;
|
|
293
|
+
case "like":
|
|
294
|
+
return `${field} LIKE ${literal(clause.value)}`;
|
|
295
|
+
case "is-null":
|
|
296
|
+
return `${field} IS NULL`;
|
|
297
|
+
case "is-not-null":
|
|
298
|
+
return `${field} IS NOT NULL`;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
function compileRuntimeClause(clause) {
|
|
302
|
+
if (!clause.field || !clause.operator)
|
|
303
|
+
return undefined;
|
|
304
|
+
const get = ["get", clause.field];
|
|
305
|
+
switch (clause.operator) {
|
|
306
|
+
case "=":
|
|
307
|
+
return ["==", get, clause.value];
|
|
308
|
+
case "!=":
|
|
309
|
+
return ["!=", get, clause.value];
|
|
310
|
+
case "<":
|
|
311
|
+
case "<=":
|
|
312
|
+
case ">":
|
|
313
|
+
case ">=":
|
|
314
|
+
return [clause.operator, get, clause.value];
|
|
315
|
+
case "in":
|
|
316
|
+
return Array.isArray(clause.value) ? ["in", get, ["literal", clause.value]] : undefined;
|
|
317
|
+
case "not-in":
|
|
318
|
+
return Array.isArray(clause.value) ? ["!", ["in", get, ["literal", clause.value]]] : undefined;
|
|
319
|
+
case "is-null":
|
|
320
|
+
return ["==", get, null];
|
|
321
|
+
case "is-not-null":
|
|
322
|
+
return ["!=", get, null];
|
|
323
|
+
case "between":
|
|
324
|
+
if (!Array.isArray(clause.value) || clause.value.length < 2)
|
|
325
|
+
return undefined;
|
|
326
|
+
return ["all", [">=", get, clause.value[0]], ["<=", get, clause.value[1]]];
|
|
327
|
+
case "like":
|
|
328
|
+
return undefined;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
function degradationFor(source, clauses) {
|
|
332
|
+
if (!source || clauses.length === 0)
|
|
333
|
+
return [];
|
|
334
|
+
const fieldClauses = clauses.filter((clause) => clause.field && clause.operator);
|
|
335
|
+
if (fieldClauses.length === 0)
|
|
336
|
+
return [];
|
|
337
|
+
const canQuery = source.capabilities.has("query");
|
|
338
|
+
const canServerFilter = canQuery && (source.capabilities.has("sql") || SERVER_FILTER_PROTOCOLS.has(source.protocol));
|
|
339
|
+
if (canServerFilter)
|
|
340
|
+
return [];
|
|
341
|
+
return [
|
|
342
|
+
degradedReason("query", source, `Filter registry kept ${fieldClauses.length} field filter(s) for runtime/client evaluation because ${source.protocol} cannot apply them server-side.`),
|
|
343
|
+
];
|
|
344
|
+
}
|
|
345
|
+
function degradedReason(capability, source, reason) {
|
|
346
|
+
return { capability, protocol: source.protocol, sourceId: source.id, reason };
|
|
347
|
+
}
|
|
348
|
+
function firstSpatialFilter(clauses) {
|
|
349
|
+
for (const clause of clauses) {
|
|
350
|
+
if (clause.spatialScope?.filter)
|
|
351
|
+
return clause.spatialScope.filter;
|
|
352
|
+
if (clause.spatialScope?.extent) {
|
|
353
|
+
const extent = clause.spatialScope.extent;
|
|
354
|
+
return {
|
|
355
|
+
geometryType: "esriGeometryEnvelope",
|
|
356
|
+
geometry: { ...extent },
|
|
357
|
+
spatialRel: "esriSpatialRelIntersects",
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return undefined;
|
|
362
|
+
}
|
|
363
|
+
function appliesToSource(clause, sourceId) {
|
|
364
|
+
if (!sourceId)
|
|
365
|
+
return true;
|
|
366
|
+
if (!clause.sourceScope || clause.sourceScope === "all")
|
|
367
|
+
return true;
|
|
368
|
+
return clause.sourceScope.includes(sourceId);
|
|
369
|
+
}
|
|
370
|
+
function appliesExplicitlyToSource(clause, sourceId) {
|
|
371
|
+
return Array.isArray(clause.sourceScope) && clause.sourceScope.includes(sourceId);
|
|
372
|
+
}
|
|
373
|
+
function shareableClause(clause) {
|
|
374
|
+
const normalized = normalizeClause(clause);
|
|
375
|
+
if (normalized.value === undefined)
|
|
376
|
+
return normalized;
|
|
377
|
+
const maxBytes = normalized.valuePolicy?.maxSerializedBytes ?? 2048;
|
|
378
|
+
const encoded = stableStringify(normalized.value);
|
|
379
|
+
if (normalized.valuePolicy?.secret || encoded.length > maxBytes) {
|
|
380
|
+
const { value: _value, ...withoutValue } = normalized;
|
|
381
|
+
return withoutValue;
|
|
382
|
+
}
|
|
383
|
+
return normalized;
|
|
384
|
+
}
|
|
385
|
+
function normalizeClauses(input) {
|
|
386
|
+
const byId = new Map();
|
|
387
|
+
for (const clause of input)
|
|
388
|
+
byId.set(clause.id, normalizeClause(clause));
|
|
389
|
+
return deepFreeze([...byId.values()].sort(compareClause));
|
|
390
|
+
}
|
|
391
|
+
function normalizeClause(clause) {
|
|
392
|
+
if (!isFilterClause(clause))
|
|
393
|
+
throw new Error("Invalid filter registry clause");
|
|
394
|
+
return deepFreeze({
|
|
395
|
+
id: clause.id,
|
|
396
|
+
owner: { kind: clause.owner.kind, id: clause.owner.id },
|
|
397
|
+
...(clause.field !== undefined ? { field: clause.field } : {}),
|
|
398
|
+
...(clause.operator !== undefined ? { operator: clause.operator } : {}),
|
|
399
|
+
...(clause.value !== undefined ? { value: cloneJsonLike(clause.value) } : {}),
|
|
400
|
+
...(clause.spatialScope !== undefined ? { spatialScope: cloneJsonLike(clause.spatialScope) } : {}),
|
|
401
|
+
enabled: clause.enabled ?? true,
|
|
402
|
+
lifecycle: clause.lifecycle ?? "session",
|
|
403
|
+
effect: clause.effect ?? (clause.spatialScope ? "spatial-mask" : "filter"),
|
|
404
|
+
sourceScope: cloneSourceScope(clause.sourceScope ?? "all"),
|
|
405
|
+
...(clause.cacheable !== undefined ? { cacheable: clause.cacheable } : {}),
|
|
406
|
+
...(clause.valuePolicy !== undefined ? { valuePolicy: cloneJsonLike(clause.valuePolicy) } : {}),
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
function compareClause(left, right) {
|
|
410
|
+
return left.id.localeCompare(right.id);
|
|
411
|
+
}
|
|
412
|
+
function ownerKey(owner) {
|
|
413
|
+
return `${owner.kind}:${owner.id}`;
|
|
414
|
+
}
|
|
415
|
+
function literal(value) {
|
|
416
|
+
if (value === null || value === undefined)
|
|
417
|
+
return "NULL";
|
|
418
|
+
if (typeof value === "number" || typeof value === "bigint")
|
|
419
|
+
return String(value);
|
|
420
|
+
if (typeof value === "boolean")
|
|
421
|
+
return value ? "TRUE" : "FALSE";
|
|
422
|
+
return `'${String(value).replace(/'/g, "''")}'`;
|
|
423
|
+
}
|
|
424
|
+
function sqlIdentifier(field) {
|
|
425
|
+
return FILTER_FIELD_IDENTIFIER.test(field) ? field : undefined;
|
|
426
|
+
}
|
|
427
|
+
function combineWhere(left, right) {
|
|
428
|
+
if (left && right)
|
|
429
|
+
return `(${left}) AND (${right})`;
|
|
430
|
+
return left || right || undefined;
|
|
431
|
+
}
|
|
432
|
+
function stableStringify(value) {
|
|
433
|
+
return JSON.stringify(sortJsonValue(value, false));
|
|
434
|
+
}
|
|
435
|
+
function stableShareStringify(value) {
|
|
436
|
+
return JSON.stringify(sortJsonValue(value, true));
|
|
437
|
+
}
|
|
438
|
+
function sortJsonValue(value, stripValuePolicy) {
|
|
439
|
+
if (Array.isArray(value))
|
|
440
|
+
return value.map((entry) => sortJsonValue(entry, stripValuePolicy));
|
|
441
|
+
if (!value || typeof value !== "object")
|
|
442
|
+
return value;
|
|
443
|
+
const out = {};
|
|
444
|
+
for (const key of Object.keys(value).sort()) {
|
|
445
|
+
if (stripValuePolicy && key === "valuePolicy")
|
|
446
|
+
continue;
|
|
447
|
+
out[key] = sortJsonValue(value[key], stripValuePolicy);
|
|
448
|
+
}
|
|
449
|
+
return out;
|
|
450
|
+
}
|
|
451
|
+
function valuesEqual(left, right) {
|
|
452
|
+
return stableStringify(left) === stableStringify(right);
|
|
453
|
+
}
|
|
454
|
+
function isFilterClause(value) {
|
|
455
|
+
if (!isRecord(value))
|
|
456
|
+
return false;
|
|
457
|
+
const record = value;
|
|
458
|
+
return (typeof record.id === "string" &&
|
|
459
|
+
record.id.length > 0 &&
|
|
460
|
+
isFilterRegistryOwner(record.owner) &&
|
|
461
|
+
validOptional(record.field, (field) => typeof field === "string" && FILTER_FIELD_IDENTIFIER.test(field)) &&
|
|
462
|
+
validOptional(record.operator, (operator) => typeof operator === "string" && FILTER_OPERATORS.has(operator)) &&
|
|
463
|
+
validOptional(record.sourceScope, isFilterSourceScope) &&
|
|
464
|
+
validOptional(record.lifecycle, (lifecycle) => typeof lifecycle === "string" && FILTER_LIFECYCLES.has(lifecycle)) &&
|
|
465
|
+
validOptional(record.effect, (effect) => typeof effect === "string" && FILTER_EFFECTS.has(effect)) &&
|
|
466
|
+
validOptional(record.enabled, (enabled) => typeof enabled === "boolean") &&
|
|
467
|
+
validOptional(record.cacheable, (cacheable) => typeof cacheable === "boolean") &&
|
|
468
|
+
validOptional(record.spatialScope, isRecord) &&
|
|
469
|
+
validOptional(record.valuePolicy, isFilterValuePolicy));
|
|
470
|
+
}
|
|
471
|
+
function isFilterRegistryOwner(value) {
|
|
472
|
+
if (!isRecord(value))
|
|
473
|
+
return false;
|
|
474
|
+
return (typeof value.kind === "string" &&
|
|
475
|
+
FILTER_OWNER_KINDS.has(value.kind) &&
|
|
476
|
+
typeof value.id === "string" &&
|
|
477
|
+
value.id.length > 0);
|
|
478
|
+
}
|
|
479
|
+
function isFilterSourceScope(value) {
|
|
480
|
+
return (value === "all" || (Array.isArray(value) && value.every((entry) => typeof entry === "string" && entry.length > 0)));
|
|
481
|
+
}
|
|
482
|
+
function isFilterValuePolicy(value) {
|
|
483
|
+
if (!isRecord(value))
|
|
484
|
+
return false;
|
|
485
|
+
return (validOptional(value.secret, (secret) => typeof secret === "boolean") &&
|
|
486
|
+
validOptional(value.maxSerializedBytes, (maxSerializedBytes) => typeof maxSerializedBytes === "number" && Number.isFinite(maxSerializedBytes)));
|
|
487
|
+
}
|
|
488
|
+
function validOptional(value, validate) {
|
|
489
|
+
return value === undefined || validate(value);
|
|
490
|
+
}
|
|
491
|
+
function cloneSourceScope(sourceScope) {
|
|
492
|
+
return Array.isArray(sourceScope) ? deepFreeze([...sourceScope]) : sourceScope;
|
|
493
|
+
}
|
|
494
|
+
function freezeSnapshot(snapshot) {
|
|
495
|
+
return deepFreeze(snapshot);
|
|
496
|
+
}
|
|
497
|
+
function cloneJsonLike(value) {
|
|
498
|
+
if (Array.isArray(value))
|
|
499
|
+
return value.map(cloneJsonLike);
|
|
500
|
+
if (value instanceof Date)
|
|
501
|
+
return new Date(value.getTime());
|
|
502
|
+
if (isPlainRecord(value)) {
|
|
503
|
+
const out = {};
|
|
504
|
+
for (const key of Object.keys(value))
|
|
505
|
+
out[key] = cloneJsonLike(value[key]);
|
|
506
|
+
return out;
|
|
507
|
+
}
|
|
508
|
+
return value;
|
|
509
|
+
}
|
|
510
|
+
function deepFreeze(value) {
|
|
511
|
+
if (!value || typeof value !== "object" || Object.isFrozen(value))
|
|
512
|
+
return value;
|
|
513
|
+
if (Array.isArray(value)) {
|
|
514
|
+
for (const entry of value)
|
|
515
|
+
deepFreeze(entry);
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
for (const key of Object.keys(value))
|
|
519
|
+
deepFreeze(value[key]);
|
|
520
|
+
}
|
|
521
|
+
return Object.freeze(value);
|
|
522
|
+
}
|
|
523
|
+
function isRecord(value) {
|
|
524
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
525
|
+
}
|
|
526
|
+
function isPlainRecord(value) {
|
|
527
|
+
if (!isRecord(value))
|
|
528
|
+
return false;
|
|
529
|
+
const prototype = Object.getPrototypeOf(value);
|
|
530
|
+
return prototype === Object.prototype || prototype === null;
|
|
531
|
+
}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
|
+
import { HonuaSdkError } from "../core/error-envelope.js";
|
|
9
10
|
export type HonuaGeneratedAppErrorCode = "unsupported-profile" | "unsupported-widget" | "missing-manifest" | "missing-manifest-artifact" | "missing-map-package" | "map-package-mismatch" | "missing-widget" | "missing-binding" | "map-load-failed" | "data-load-failed" | "render-failed" | "disposed";
|
|
10
11
|
export type HonuaGeneratedAppErrorStage = "manifest" | "projection" | "load" | "interaction" | "render" | "dispose";
|
|
11
12
|
export interface HonuaGeneratedAppErrorDetail {
|
|
@@ -25,7 +26,23 @@ export interface HonuaGeneratedAppDiagnostic {
|
|
|
25
26
|
readonly message: string;
|
|
26
27
|
readonly detail?: HonuaGeneratedAppErrorDetail;
|
|
27
28
|
}
|
|
28
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Tagged generated-app preview/runtime failure. Participates in the shared
|
|
31
|
+
* SDK error envelope (`isHonuaError`, `serializeHonuaError`) while
|
|
32
|
+
* preserving the legacy `.code`/`.stage`/`.detail`/`.cause` fields consumed
|
|
33
|
+
* by {@link toGeneratedAppDiagnostic}. `detail` is an open, caller-supplied
|
|
34
|
+
* bag (`expected`/`received`/etc.) and is deliberately kept local-only — it
|
|
35
|
+
* is never placed in the envelope's serialized `context`.
|
|
36
|
+
*
|
|
37
|
+
* The base `HonuaSdkError.toJSON()` (the redacted envelope projection) is
|
|
38
|
+
* inherited unchanged, so `JSON.stringify(error)` now returns the safe,
|
|
39
|
+
* sanitized `SerializedHonuaError` shape rather than the raw diagnostic
|
|
40
|
+
* (which could otherwise echo an unsanitized `detail`). Callers that need
|
|
41
|
+
* the legacy `{name, code, stage, message, detail}` diagnostic shape use
|
|
42
|
+
* {@link toGeneratedAppDiagnostic}, which reads the documented fields
|
|
43
|
+
* directly rather than relying on `toJSON()`.
|
|
44
|
+
*/
|
|
45
|
+
export declare class HonuaGeneratedAppError extends HonuaSdkError {
|
|
29
46
|
readonly code: HonuaGeneratedAppErrorCode;
|
|
30
47
|
readonly stage: HonuaGeneratedAppErrorStage;
|
|
31
48
|
readonly detail: HonuaGeneratedAppErrorDetail | undefined;
|
|
@@ -35,7 +52,6 @@ export declare class HonuaGeneratedAppError extends Error {
|
|
|
35
52
|
readonly detail?: HonuaGeneratedAppErrorDetail;
|
|
36
53
|
readonly cause?: unknown;
|
|
37
54
|
});
|
|
38
|
-
toJSON(): HonuaGeneratedAppDiagnostic;
|
|
39
55
|
}
|
|
40
56
|
export declare function toGeneratedAppDiagnostic(error: unknown): HonuaGeneratedAppDiagnostic;
|
|
41
57
|
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/generated-app/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,0BAA0B,GAClC,qBAAqB,GACrB,oBAAoB,GACpB,kBAAkB,GAClB,2BAA2B,GAC3B,qBAAqB,GACrB,sBAAsB,GACtB,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,kBAAkB,GAClB,eAAe,GACf,UAAU,CAAC;AAEf,MAAM,MAAM,2BAA2B,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEpH,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,2BAA2B,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,4BAA4B,CAAC;CAChD;
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/generated-app/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAuB,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAE/E,MAAM,MAAM,0BAA0B,GAClC,qBAAqB,GACrB,oBAAoB,GACpB,kBAAkB,GAClB,2BAA2B,GAC3B,qBAAqB,GACrB,sBAAsB,GACtB,gBAAgB,GAChB,iBAAiB,GACjB,iBAAiB,GACjB,kBAAkB,GAClB,eAAe,GACf,UAAU,CAAC;AAEf,MAAM,MAAM,2BAA2B,GAAG,UAAU,GAAG,YAAY,GAAG,MAAM,GAAG,aAAa,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEpH,MAAM,WAAW,4BAA4B;IAC3C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;CACnC;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,QAAQ,CAAC,IAAI,EAAE,0BAA0B,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,2BAA2B,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,4BAA4B,CAAC;CAChD;AAqBD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,sBAAuB,SAAQ,aAAa;IACvD,SAAgB,IAAI,EAAE,0BAA0B,CAAC;IACjD,SAAgB,KAAK,EAAE,2BAA2B,CAAC;IACnD,SAAgB,MAAM,EAAE,4BAA4B,GAAG,SAAS,CAAC;IACjE,SAAyB,KAAK,EAAE,OAAO,CAAC;gBAGtC,IAAI,EAAE,0BAA0B,EAChC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE;QACP,QAAQ,CAAC,KAAK,EAAE,2BAA2B,CAAC;QAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,4BAA4B,CAAC;QAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;KAC1B;CASJ;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,2BAA2B,CAgBpF"}
|
package/generated-app/errors.js
CHANGED
|
@@ -6,32 +6,65 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @module
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
import { HonuaSdkError } from "../core/error-envelope.js";
|
|
10
|
+
/**
|
|
11
|
+
* Legacy detailed reason codes mapped to registered `app.*` `sdkCode`
|
|
12
|
+
* values, one-to-one.
|
|
13
|
+
*/
|
|
14
|
+
const GENERATED_APP_ERROR_SDK_CODES = {
|
|
15
|
+
"unsupported-profile": "app.unsupported-profile",
|
|
16
|
+
"unsupported-widget": "app.unsupported-widget",
|
|
17
|
+
"missing-manifest": "app.missing-manifest",
|
|
18
|
+
"missing-manifest-artifact": "app.missing-manifest-artifact",
|
|
19
|
+
"missing-map-package": "app.missing-map-package",
|
|
20
|
+
"map-package-mismatch": "app.map-package-mismatch",
|
|
21
|
+
"missing-widget": "app.missing-widget",
|
|
22
|
+
"missing-binding": "app.missing-binding",
|
|
23
|
+
"map-load-failed": "app.map-load-failed",
|
|
24
|
+
"data-load-failed": "app.data-load-failed",
|
|
25
|
+
"render-failed": "app.render-failed",
|
|
26
|
+
disposed: "app.disposed",
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Tagged generated-app preview/runtime failure. Participates in the shared
|
|
30
|
+
* SDK error envelope (`isHonuaError`, `serializeHonuaError`) while
|
|
31
|
+
* preserving the legacy `.code`/`.stage`/`.detail`/`.cause` fields consumed
|
|
32
|
+
* by {@link toGeneratedAppDiagnostic}. `detail` is an open, caller-supplied
|
|
33
|
+
* bag (`expected`/`received`/etc.) and is deliberately kept local-only — it
|
|
34
|
+
* is never placed in the envelope's serialized `context`.
|
|
35
|
+
*
|
|
36
|
+
* The base `HonuaSdkError.toJSON()` (the redacted envelope projection) is
|
|
37
|
+
* inherited unchanged, so `JSON.stringify(error)` now returns the safe,
|
|
38
|
+
* sanitized `SerializedHonuaError` shape rather than the raw diagnostic
|
|
39
|
+
* (which could otherwise echo an unsanitized `detail`). Callers that need
|
|
40
|
+
* the legacy `{name, code, stage, message, detail}` diagnostic shape use
|
|
41
|
+
* {@link toGeneratedAppDiagnostic}, which reads the documented fields
|
|
42
|
+
* directly rather than relying on `toJSON()`.
|
|
43
|
+
*/
|
|
44
|
+
export class HonuaGeneratedAppError extends HonuaSdkError {
|
|
10
45
|
code;
|
|
11
46
|
stage;
|
|
12
47
|
detail;
|
|
13
48
|
cause;
|
|
14
49
|
constructor(code, message, options) {
|
|
15
|
-
super(message);
|
|
50
|
+
super(GENERATED_APP_ERROR_SDK_CODES[code], message, options.cause === undefined ? {} : { cause: options.cause });
|
|
16
51
|
this.name = "HonuaGeneratedAppError";
|
|
17
52
|
this.code = code;
|
|
18
53
|
this.stage = options.stage;
|
|
19
54
|
this.detail = options.detail;
|
|
20
55
|
this.cause = options.cause;
|
|
21
56
|
}
|
|
22
|
-
|
|
57
|
+
}
|
|
58
|
+
export function toGeneratedAppDiagnostic(error) {
|
|
59
|
+
if (error instanceof HonuaGeneratedAppError) {
|
|
23
60
|
return {
|
|
24
61
|
name: "HonuaGeneratedAppError",
|
|
25
|
-
code:
|
|
26
|
-
stage:
|
|
27
|
-
message:
|
|
28
|
-
...(
|
|
62
|
+
code: error.code,
|
|
63
|
+
stage: error.stage,
|
|
64
|
+
message: error.message,
|
|
65
|
+
...(error.detail ? { detail: error.detail } : {}),
|
|
29
66
|
};
|
|
30
67
|
}
|
|
31
|
-
}
|
|
32
|
-
export function toGeneratedAppDiagnostic(error) {
|
|
33
|
-
if (error instanceof HonuaGeneratedAppError)
|
|
34
|
-
return error.toJSON();
|
|
35
68
|
return {
|
|
36
69
|
name: "HonuaGeneratedAppError",
|
|
37
70
|
code: "render-failed",
|