@honua/app-platform 0.1.2-beta.0 → 0.1.7-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/app/index.d.ts.map +1 -1
- package/app/index.js +4 -0
- package/collaboration/client.d.ts.map +1 -1
- package/connect-url-safety.d.ts +53 -0
- package/connect-url-safety.js +189 -0
- package/contract/discovery.d.ts +34 -0
- package/contract/discovery.d.ts.map +1 -1
- package/contract/index.d.ts +7 -5
- package/contract/index.d.ts.map +1 -1
- package/contract/index.js +3 -2
- package/contract/pmtiles.d.ts +10 -1
- package/contract/pmtiles.d.ts.map +1 -1
- package/contract/pmtiles.js +10 -2
- package/contract/protocol-module.d.ts +84 -9
- package/contract/protocol-module.d.ts.map +1 -1
- package/contract/query-filter-fes.d.ts +18 -0
- package/contract/query-filter-fes.d.ts.map +1 -0
- package/contract/query-filter-fes.js +122 -0
- package/contract/query-filter.d.ts +300 -0
- package/contract/query-filter.d.ts.map +1 -0
- package/contract/query-filter.js +883 -0
- package/contract/schema.d.ts +12 -0
- package/contract/schema.d.ts.map +1 -1
- package/contract/schema.js +34 -0
- package/contract/source-capability-support.d.ts.map +1 -1
- package/contract/source-capability-support.js +15 -3
- package/contract/source.d.ts +45 -25
- package/contract/source.d.ts.map +1 -1
- package/contract/source.js +719 -479
- package/contract/types.d.ts +88 -19
- package/contract/types.d.ts.map +1 -1
- package/contract/types.js +4 -0
- package/contract/widget-source.d.ts.map +1 -1
- package/controls/basemap-switcher.d.ts +19 -11
- package/controls/basemap-switcher.d.ts.map +1 -1
- package/controls/basemap-switcher.js +58 -25
- package/controls/catalog.d.ts +105 -0
- package/controls/catalog.d.ts.map +1 -0
- package/controls/catalog.js +341 -0
- package/controls/element-utils.d.ts +9 -0
- package/controls/element-utils.d.ts.map +1 -1
- package/controls/element-utils.js +17 -0
- package/controls/index.d.ts +29 -8
- package/controls/index.d.ts.map +1 -1
- package/controls/index.js +26 -8
- package/controls/layer-list.d.ts +13 -5
- package/controls/layer-list.d.ts.map +1 -1
- package/controls/layer-list.js +72 -15
- package/controls/legend.d.ts +32 -5
- package/controls/legend.d.ts.map +1 -1
- package/controls/legend.js +95 -25
- package/controls/qualification.d.ts +152 -0
- package/controls/qualification.d.ts.map +1 -0
- package/controls/qualification.js +1265 -0
- package/controls/registry.d.ts +104 -0
- package/controls/registry.d.ts.map +1 -0
- package/controls/registry.js +150 -0
- package/controls/swipe-control.d.ts +6 -1
- package/controls/swipe-control.d.ts.map +1 -1
- package/controls/swipe-control.js +82 -20
- package/core/client.d.ts +51 -21
- package/core/client.d.ts.map +1 -1
- package/core/client.js +234 -54
- package/core/error-classifications.d.ts +23 -0
- package/core/error-classifications.d.ts.map +1 -1
- package/core/error-classifications.js +23 -0
- package/core/error-code-registry.d.ts +24 -1
- package/core/error-code-registry.d.ts.map +1 -1
- package/core/error-code-registry.js +23 -0
- package/core/error-envelope.js +2 -0
- package/core/errors.d.ts +2 -2
- package/core/errors.d.ts.map +1 -1
- package/core/errors.js +1 -1
- package/core/geoparquet-sql.d.ts +69 -5
- package/core/geoparquet-sql.d.ts.map +1 -1
- package/core/geoparquet-sql.js +327 -10
- package/core/odata-write-codec.d.ts.map +1 -1
- package/core/odata-write-codec.js +0 -1
- package/core/odata.d.ts +6 -0
- package/core/odata.d.ts.map +1 -1
- package/core/odata.js +6 -1
- package/core/ogc-processes.d.ts +182 -25
- package/core/ogc-processes.d.ts.map +1 -1
- package/core/ogc-processes.js +602 -30
- package/core/process-runner.d.ts +8 -1
- package/core/process-runner.d.ts.map +1 -1
- package/core/process-runner.js +1 -0
- package/core/protocol-transport.d.ts +2 -0
- package/core/protocol-transport.d.ts.map +1 -1
- package/core/stac.d.ts +32 -0
- package/core/stac.d.ts.map +1 -1
- package/core/stac.js +158 -23
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +273 -68
- package/core/types.d.ts +138 -11
- package/core/types.d.ts.map +1 -1
- package/core/wfs-axis-order.d.ts +18 -0
- package/core/wfs-axis-order.d.ts.map +1 -0
- package/core/wfs-axis-order.js +108 -0
- package/core/wfs-capabilities.d.ts +65 -24
- package/core/wfs-capabilities.d.ts.map +1 -1
- package/core/wfs-capabilities.js +237 -27
- package/core/wfs-filter.d.ts +26 -3
- package/core/wfs-filter.d.ts.map +1 -1
- package/core/wfs-filter.js +48 -53
- package/core/wfs-protocol-error.d.ts +12 -0
- package/core/wfs-protocol-error.d.ts.map +1 -0
- package/core/wfs-protocol-error.js +13 -0
- package/core/wfs.d.ts +53 -1
- package/core/wfs.d.ts.map +1 -1
- package/core/wfs.js +251 -29
- package/core/wms-feature-info.d.ts +92 -0
- package/core/wms-feature-info.d.ts.map +1 -0
- package/core/wms-feature-info.js +285 -0
- package/core/wms.d.ts +9 -0
- package/core/wms.d.ts.map +1 -1
- package/core/wms.js +17 -5
- package/esri-compat/event-bus.d.ts +20 -0
- package/esri-compat/event-bus.d.ts.map +1 -1
- package/esri-compat/feature-filter.d.ts +46 -1
- package/esri-compat/feature-filter.d.ts.map +1 -1
- package/esri-compat/feature-filter.js +49 -0
- package/esri-compat/geojson-layer.d.ts +4 -2
- package/esri-compat/geojson-layer.d.ts.map +1 -1
- package/esri-compat/geojson-layer.js +4 -2
- package/esri-compat/identity-manager.js +2 -2
- package/esri-compat/imagery-layer.d.ts +2 -1
- package/esri-compat/imagery-layer.d.ts.map +1 -1
- package/esri-compat/imagery-layer.js +2 -1
- package/esri-compat/layer-list.d.ts +8 -1
- package/esri-compat/layer-list.d.ts.map +1 -1
- package/esri-compat/layer-list.js +11 -4
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +1 -1
- package/esri-compat/locator.d.ts +297 -0
- package/esri-compat/locator.d.ts.map +1 -0
- package/esri-compat/locator.js +579 -0
- package/esri-compat/map-image-layer.d.ts.map +1 -1
- package/esri-compat/map-view.d.ts.map +1 -1
- package/esri-compat/map-view.js +1 -1
- package/esri-compat/scene-view.d.ts.map +1 -1
- package/esri-compat/time-slider.d.ts +29 -0
- package/esri-compat/time-slider.d.ts.map +1 -1
- package/esri-compat/time-slider.js +117 -0
- package/esri-compat/wfs-layer.d.ts +2 -1
- package/esri-compat/wfs-layer.d.ts.map +1 -1
- package/esri-compat/wfs-layer.js +2 -1
- package/esri-compat/widget-host.d.ts +42 -6
- package/esri-compat/widget-host.d.ts.map +1 -1
- package/esri-compat/widget-host.js +99 -10
- package/generated-app/projection.d.ts.map +1 -1
- package/generated-app/runtime.d.ts.map +1 -1
- package/interactions/declarative-contract.d.ts +149 -0
- package/interactions/declarative-contract.d.ts.map +1 -0
- package/interactions/declarative-contract.js +293 -0
- package/interactions/declarative.d.ts +198 -0
- package/interactions/declarative.d.ts.map +1 -0
- package/interactions/declarative.js +470 -0
- package/interactions/feature-state.d.ts +7 -0
- package/interactions/feature-state.d.ts.map +1 -1
- package/interactions/feature-state.js +10 -2
- package/map/data-to-map-bridge.d.ts +1 -1
- package/map/data-to-map-bridge.d.ts.map +1 -1
- package/map/data-to-map-bridge.js +1 -2
- package/map/honua-map.d.ts.map +1 -1
- package/map/honua-map.js +1 -1
- package/map/index.d.ts +2 -0
- package/map/index.d.ts.map +1 -1
- package/map/index.js +2 -0
- package/map/maplibre-target.js +1 -1
- package/map/realtime-reconciliation-adapter.d.ts +98 -0
- package/map/realtime-reconciliation-adapter.d.ts.map +1 -0
- package/map/realtime-reconciliation-adapter.js +84 -0
- package/map/temporal-playback.d.ts +25 -0
- package/map/temporal-playback.d.ts.map +1 -1
- package/map/temporal-playback.js +29 -1
- package/operator/workspace/workspace.d.ts.map +1 -1
- package/operator/workspace/workspace.js +0 -2
- package/package.json +4 -3
- package/query-planner/canonical-filter.d.ts +30 -0
- package/query-planner/canonical-filter.d.ts.map +1 -0
- package/query-planner/canonical-filter.js +30 -0
- package/query-planner/columnar-plan.d.ts +63 -0
- package/query-planner/columnar-plan.d.ts.map +1 -0
- package/query-planner/columnar-plan.js +94 -0
- package/query-planner/diagnostics.d.ts +3 -3
- package/query-planner/diagnostics.d.ts.map +1 -1
- package/query-planner/diagnostics.js +17 -4
- package/query-planner/duckdb.d.ts.map +1 -1
- package/query-planner/duckdb.js +16 -2
- package/query-planner/execution-context.d.ts.map +1 -1
- package/query-planner/execution-context.js +3 -1
- package/query-planner/executor.d.ts.map +1 -1
- package/query-planner/executor.js +7 -1
- package/query-planner/geoservices.d.ts.map +1 -1
- package/query-planner/geoservices.js +24 -5
- package/query-planner/grpc.d.ts.map +1 -1
- package/query-planner/grpc.js +29 -5
- package/query-planner/index.d.ts +20 -5
- package/query-planner/index.d.ts.map +1 -1
- package/query-planner/index.js +16 -3
- package/query-planner/ir.d.ts +6 -1
- package/query-planner/ir.d.ts.map +1 -1
- package/query-planner/ir.js +63 -1
- package/query-planner/odata-protocol-module.d.ts +54 -0
- package/query-planner/odata-protocol-module.d.ts.map +1 -0
- package/query-planner/odata-protocol-module.js +199 -0
- package/query-planner/odata-v1.d.ts +23 -0
- package/query-planner/odata-v1.d.ts.map +1 -0
- package/query-planner/odata-v1.js +202 -0
- package/query-planner/odata.d.ts +0 -3
- package/query-planner/odata.d.ts.map +1 -1
- package/query-planner/odata.js +0 -143
- package/query-planner/ogc-features.d.ts.map +1 -1
- package/query-planner/ogc-features.js +23 -1
- package/query-planner/planner.d.ts +2 -2
- package/query-planner/planner.d.ts.map +1 -1
- package/query-planner/planner.js +146 -27
- package/query-planner/representation.d.ts +59 -0
- package/query-planner/representation.d.ts.map +1 -0
- package/query-planner/representation.js +140 -0
- package/query-planner/types.d.ts +153 -3
- package/query-planner/types.d.ts.map +1 -1
- package/query-planner/wfs-protocol-module.d.ts +57 -0
- package/query-planner/wfs-protocol-module.d.ts.map +1 -0
- package/query-planner/wfs-protocol-module.js +731 -0
- package/query-planner/wfs-v1.d.ts +41 -0
- package/query-planner/wfs-v1.d.ts.map +1 -0
- package/query-planner/wfs-v1.js +366 -0
- package/query-planner/wfs.d.ts +1 -3
- package/query-planner/wfs.d.ts.map +1 -1
- package/query-planner/wfs.js +1 -70
- package/realtime/checkpoint-store.d.ts +206 -0
- package/realtime/checkpoint-store.d.ts.map +1 -0
- package/realtime/checkpoint-store.js +504 -0
- package/realtime/honua-server.d.ts +8 -0
- package/realtime/honua-server.d.ts.map +1 -1
- package/realtime/honua-server.js +123 -14
- package/realtime/index.d.ts +4 -0
- package/realtime/index.d.ts.map +1 -1
- package/realtime/index.js +2 -0
- package/realtime/reconciliation.d.ts +245 -0
- package/realtime/reconciliation.d.ts.map +1 -0
- package/realtime/reconciliation.js +377 -0
- package/realtime/resumable-transport.d.ts.map +1 -1
- package/realtime/sse.d.ts.map +1 -1
- package/realtime/sse.js +7 -1
- package/realtime/websocket.d.ts.map +1 -1
- package/realtime/wire.d.ts +2 -1
- package/realtime/wire.d.ts.map +1 -1
- package/realtime/wire.js +24 -8
- package/replica-sync/errors.d.ts +19 -1
- package/replica-sync/errors.d.ts.map +1 -1
- package/replica-sync/errors.js +16 -0
- package/replica-sync/geoservices.d.ts +260 -0
- package/replica-sync/geoservices.d.ts.map +1 -0
- package/replica-sync/geoservices.js +1093 -0
- package/replica-sync/index.d.ts +5 -1
- package/replica-sync/index.d.ts.map +1 -1
- package/replica-sync/index.js +3 -1
- package/replica-sync/transport-conformance.d.ts +58 -0
- package/replica-sync/transport-conformance.d.ts.map +1 -0
- package/replica-sync/transport-conformance.js +265 -0
- package/replica-sync/types.d.ts +22 -0
- package/replica-sync/types.d.ts.map +1 -1
- package/runtime/index.d.ts +6 -2
- package/runtime/index.d.ts.map +1 -1
- package/runtime/index.js +3 -1
- package/runtime/load-package.d.ts +24 -0
- package/runtime/load-package.d.ts.map +1 -1
- package/runtime/load-package.js +45 -1
- package/runtime/maplibre-renderer.d.ts +11 -0
- package/runtime/maplibre-renderer.d.ts.map +1 -1
- package/runtime/maplibre-renderer.js +32 -7
- package/runtime/offline-region-protocol.d.ts +73 -0
- package/runtime/offline-region-protocol.d.ts.map +1 -0
- package/runtime/offline-region-protocol.js +63 -0
- package/runtime/offline-region-style.d.ts +78 -0
- package/runtime/offline-region-style.d.ts.map +1 -0
- package/runtime/offline-region-style.js +147 -0
- package/runtime/pmtiles-protocol.d.ts +7 -8
- package/runtime/pmtiles-protocol.d.ts.map +1 -1
- package/runtime/pmtiles-protocol.js +19 -66
- package/runtime/protocol-registry.d.ts +55 -0
- package/runtime/protocol-registry.d.ts.map +1 -0
- package/runtime/protocol-registry.js +103 -0
- package/runtime/runtime.d.ts +2 -0
- package/runtime/runtime.d.ts.map +1 -1
- package/runtime/runtime.js +6 -1
- package/runtime/style-compose.d.ts.map +1 -1
- package/runtime/style-compose.js +78 -9
- package/scene-workspace/analysis-widgets.d.ts +4 -2
- package/scene-workspace/analysis-widgets.d.ts.map +1 -1
- package/scene-workspace/analysis-widgets.js +4 -2
- package/scene-workspace/camera-correspondence.d.ts +151 -0
- package/scene-workspace/camera-correspondence.d.ts.map +1 -0
- package/scene-workspace/camera-correspondence.js +220 -0
- package/scene-workspace/cesium-adapter.d.ts +230 -29
- package/scene-workspace/cesium-adapter.d.ts.map +1 -1
- package/scene-workspace/cesium-adapter.js +741 -56
- package/scene-workspace/cesium-mount.d.ts +205 -0
- package/scene-workspace/cesium-mount.d.ts.map +1 -0
- package/scene-workspace/cesium-mount.js +392 -0
- package/scene-workspace/cesium-scene-owner.d.ts +160 -0
- package/scene-workspace/cesium-scene-owner.d.ts.map +1 -0
- package/scene-workspace/cesium-scene-owner.js +205 -0
- package/scene-workspace/cesium-state-sync.d.ts +101 -0
- package/scene-workspace/cesium-state-sync.d.ts.map +1 -0
- package/scene-workspace/cesium-state-sync.js +432 -0
- package/scene-workspace/cesium-time.d.ts +346 -0
- package/scene-workspace/cesium-time.d.ts.map +1 -0
- package/scene-workspace/cesium-time.js +403 -0
- package/scene-workspace/index.d.ts +42 -10
- package/scene-workspace/index.d.ts.map +1 -1
- package/scene-workspace/index.js +32 -7
- package/scene-workspace/maplibre-state-sync.d.ts +112 -0
- package/scene-workspace/maplibre-state-sync.d.ts.map +1 -0
- package/scene-workspace/maplibre-state-sync.js +400 -0
- package/scene-workspace/primitives.d.ts +237 -3
- package/scene-workspace/primitives.d.ts.map +1 -1
- package/scene-workspace/primitives.js +1087 -17
- package/scene-workspace/scene-discovery.d.ts +5 -2
- package/scene-workspace/scene-discovery.d.ts.map +1 -1
- package/scene-workspace/scene-discovery.js +5 -2
- package/scene-workspace/scene-view.d.ts +5 -2
- package/scene-workspace/scene-view.d.ts.map +1 -1
- package/scene-workspace/scene-view.js +5 -2
- package/scene-workspace/source-to-cesium.d.ts +141 -8
- package/scene-workspace/source-to-cesium.d.ts.map +1 -1
- package/scene-workspace/source-to-cesium.js +497 -72
- package/scene-workspace/state-sync-port-kit.d.ts +156 -0
- package/scene-workspace/state-sync-port-kit.d.ts.map +1 -0
- package/scene-workspace/state-sync-port-kit.js +319 -0
- package/scene-workspace/state-sync.d.ts +34 -1
- package/scene-workspace/state-sync.d.ts.map +1 -1
- package/scene-workspace/state-sync.js +48 -0
- package/scene-workspace/types.d.ts +8 -0
- package/scene-workspace/types.d.ts.map +1 -1
- package/scene-workspace/types.js +2 -0
- package/scene-workspace/workspace.d.ts +12 -1
- package/scene-workspace/workspace.d.ts.map +1 -1
- package/scene-workspace/workspace.js +13 -0
- package/studio/index.d.ts +24 -7
- package/studio/index.d.ts.map +1 -1
- package/studio/index.js +21 -7
- package/studio/lifecycle-client.d.ts +164 -0
- package/studio/lifecycle-client.d.ts.map +1 -0
- package/studio/lifecycle-client.js +299 -0
- package/studio/lifecycle-errors.d.ts +91 -0
- package/studio/lifecycle-errors.d.ts.map +1 -0
- package/studio/lifecycle-errors.js +77 -0
- package/studio/lifecycle-types.d.ts +321 -0
- package/studio/lifecycle-types.d.ts.map +1 -0
- package/studio/lifecycle-types.js +22 -0
- package/web-components/controller.d.ts.map +1 -1
- package/web-components/csp-styles.d.ts +6 -0
- package/web-components/csp-styles.d.ts.map +1 -0
- package/web-components/csp-styles.js +53 -0
- package/web-components/elements.d.ts +158 -2
- package/web-components/elements.d.ts.map +1 -1
- package/web-components/elements.js +1302 -215
- package/web-components/export-redaction.d.ts +252 -0
- package/web-components/export-redaction.d.ts.map +1 -0
- package/web-components/export-redaction.js +588 -0
- package/web-components/export.d.ts +417 -0
- package/web-components/export.d.ts.map +1 -0
- package/web-components/export.js +719 -0
- package/web-components/feature-editor-model.d.ts +265 -0
- package/web-components/feature-editor-model.d.ts.map +1 -0
- package/web-components/feature-editor-model.js +438 -0
- package/web-components/feature-editor-sketch.d.ts +125 -0
- package/web-components/feature-editor-sketch.d.ts.map +1 -0
- package/web-components/feature-editor-sketch.js +194 -0
- package/web-components/feature-editor-workflow.d.ts +286 -0
- package/web-components/feature-editor-workflow.d.ts.map +1 -0
- package/web-components/feature-editor-workflow.js +889 -0
- package/web-components/feature-editor.d.ts +83 -0
- package/web-components/feature-editor.d.ts.map +1 -0
- package/web-components/feature-editor.js +829 -0
- package/web-components/feature-table-engine.d.ts +465 -0
- package/web-components/feature-table-engine.d.ts.map +1 -0
- package/web-components/feature-table-engine.js +1360 -0
- package/web-components/feature-table-view.d.ts +95 -0
- package/web-components/feature-table-view.d.ts.map +1 -0
- package/web-components/feature-table-view.js +343 -0
- package/web-components/index.d.ts +34 -3
- package/web-components/index.d.ts.map +1 -1
- package/web-components/index.js +35 -2
- package/web-components/maplibre-renderer.d.ts.map +1 -1
- package/web-components/maplibre-renderer.js +13 -4
- package/web-components/measurement.d.ts +3 -1
- package/web-components/measurement.d.ts.map +1 -1
- package/web-components/measurement.js +62 -18
- package/web-components/time-slider.d.ts +122 -0
- package/web-components/time-slider.d.ts.map +1 -0
- package/web-components/time-slider.js +740 -0
- package/web-components/types.d.ts +310 -0
- package/web-components/types.d.ts.map +1 -1
- package/webmap/convert-label.js +0 -1
- package/webmap/convert-symbol.d.ts.map +1 -1
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shipped 2D {@link SceneStateSyncPort}: a live MapLibre GL map bound to the
|
|
3
|
+
* shared scene state.
|
|
4
|
+
*
|
|
5
|
+
* The synchronizer in `state-sync.ts` is a transport and deliberately never
|
|
6
|
+
* touches a renderer. This module is the other half for the 2D side — it reads
|
|
7
|
+
* and writes a real map for camera, selection, filters, time, and detail, and it
|
|
8
|
+
* reports what a Web Mercator plane cannot hold instead of quietly dropping it.
|
|
9
|
+
*
|
|
10
|
+
* The map is duck-typed: nothing here imports the renderer package, so a 3D-only
|
|
11
|
+
* or headless consumer pays no 2D cost, and a test can drive the port with a
|
|
12
|
+
* plain object.
|
|
13
|
+
*
|
|
14
|
+
* @beta Part of the beta `@honua/app-platform/scene-workspace` surface.
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import { type MapLibreCameraGeometry } from "./camera-correspondence.js";
|
|
18
|
+
import { type SceneStateSyncPortDegradation, type SceneStateSyncRendererPort } from "./state-sync-port-kit.js";
|
|
19
|
+
import { type SceneStateSyncIdentity } from "./state-sync.js";
|
|
20
|
+
/** A feature-state address, the same shape the 2D renderer takes. */
|
|
21
|
+
interface FeatureStateAddress {
|
|
22
|
+
readonly source: string;
|
|
23
|
+
readonly id: string | number;
|
|
24
|
+
readonly sourceLayer?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The slice of a live 2D map this port drives.
|
|
28
|
+
*
|
|
29
|
+
* Only `getCenter`/`getZoom`/`getBearing`/`getPitch`/`jumpTo`/`on`/`off` are
|
|
30
|
+
* required — everything else is feature-detected, and a missing capability
|
|
31
|
+
* narrows the port's declared fidelity rather than throwing at apply time.
|
|
32
|
+
*/
|
|
33
|
+
export interface MapLibreStateSyncTarget {
|
|
34
|
+
getCenter(): {
|
|
35
|
+
readonly lng: number;
|
|
36
|
+
readonly lat: number;
|
|
37
|
+
} | readonly [number, number];
|
|
38
|
+
getZoom(): number;
|
|
39
|
+
getBearing(): number;
|
|
40
|
+
getPitch(): number;
|
|
41
|
+
getRoll?(): number;
|
|
42
|
+
jumpTo(options: {
|
|
43
|
+
center?: [number, number];
|
|
44
|
+
zoom?: number;
|
|
45
|
+
bearing?: number;
|
|
46
|
+
pitch?: number;
|
|
47
|
+
roll?: number;
|
|
48
|
+
}): void;
|
|
49
|
+
on(type: "moveend" | "rotateend" | "pitchend", listener: () => void): unknown;
|
|
50
|
+
off(type: "moveend" | "rotateend" | "pitchend", listener: () => void): unknown;
|
|
51
|
+
getMinZoom?(): number;
|
|
52
|
+
getMaxZoom?(): number;
|
|
53
|
+
getMaxPitch?(): number;
|
|
54
|
+
getCanvas?(): {
|
|
55
|
+
readonly clientHeight?: number;
|
|
56
|
+
} | null | undefined;
|
|
57
|
+
getContainer?(): {
|
|
58
|
+
readonly clientHeight?: number;
|
|
59
|
+
} | null | undefined;
|
|
60
|
+
getStyle?(): {
|
|
61
|
+
readonly layers?: readonly {
|
|
62
|
+
readonly id?: unknown;
|
|
63
|
+
readonly type?: unknown;
|
|
64
|
+
readonly source?: unknown;
|
|
65
|
+
}[];
|
|
66
|
+
} | null | undefined;
|
|
67
|
+
getFilter?(id: string): unknown;
|
|
68
|
+
setFilter?(id: string, filter: unknown): void;
|
|
69
|
+
getSource?(id: string): unknown;
|
|
70
|
+
setFeatureState?(target: FeatureStateAddress, state: Record<string, unknown>): void;
|
|
71
|
+
removeFeatureState?(target: FeatureStateAddress, key?: string): void;
|
|
72
|
+
}
|
|
73
|
+
export interface CreateMapLibreStateSyncPortOptions {
|
|
74
|
+
/** Port identifier; must satisfy the envelope's credential-free id charset. */
|
|
75
|
+
readonly id?: string;
|
|
76
|
+
/** Shared-plan identity stamped onto everything this port publishes. */
|
|
77
|
+
readonly identity: SceneStateSyncIdentity;
|
|
78
|
+
readonly now?: () => string;
|
|
79
|
+
/**
|
|
80
|
+
* Override the viewport/lens geometry the zoom-to-height correspondence uses.
|
|
81
|
+
* By default the viewport height is read from the live map on every
|
|
82
|
+
* conversion, so a resized map stays correct.
|
|
83
|
+
*/
|
|
84
|
+
readonly geometry?: Partial<MapLibreCameraGeometry>;
|
|
85
|
+
/** Feature-state key written for selected features. Defaults to `selected`. */
|
|
86
|
+
readonly selectionStateKey?: string;
|
|
87
|
+
/** Feature-state key written for the detail target. Defaults to `detail`. */
|
|
88
|
+
readonly detailStateKey?: string;
|
|
89
|
+
/**
|
|
90
|
+
* Layers the port may filter. Defaults to every filterable layer in the
|
|
91
|
+
* current style. Style-authored filters are preserved: the port captures each
|
|
92
|
+
* layer's original filter once and composes shared clauses on top of it.
|
|
93
|
+
*/
|
|
94
|
+
readonly filterLayers?: readonly string[];
|
|
95
|
+
/**
|
|
96
|
+
* Numeric epoch-millisecond field the `time` slice is applied against. Without
|
|
97
|
+
* it the port declares `time` outbound-unsupported rather than pretending.
|
|
98
|
+
*/
|
|
99
|
+
readonly timeField?: string;
|
|
100
|
+
readonly onDegraded?: (degradation: SceneStateSyncPortDegradation) => void;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Bind a live 2D map to the shared scene state.
|
|
104
|
+
*
|
|
105
|
+
* Camera changes are published automatically from the map's own `moveend` /
|
|
106
|
+
* `rotateend` / `pitchend` events. Selection, filters, time, detail, and
|
|
107
|
+
* attribution have no renderer event to hang off — those are host decisions —
|
|
108
|
+
* so the host publishes them with {@link SceneStateSyncRendererPort.publish}.
|
|
109
|
+
*/
|
|
110
|
+
export declare function createMapLibreStateSyncPort(map: MapLibreStateSyncTarget, options: CreateMapLibreStateSyncPortOptions): SceneStateSyncRendererPort;
|
|
111
|
+
export {};
|
|
112
|
+
//# sourceMappingURL=maplibre-state-sync.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"maplibre-state-sync.d.ts","sourceRoot":"","sources":["../../../src/scene-workspace/maplibre-state-sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The shipped 2D {@link SceneStateSyncPort}: a live MapLibre GL map bound to the
|
|
3
|
+
* shared scene state.
|
|
4
|
+
*
|
|
5
|
+
* The synchronizer in `state-sync.ts` is a transport and deliberately never
|
|
6
|
+
* touches a renderer. This module is the other half for the 2D side — it reads
|
|
7
|
+
* and writes a real map for camera, selection, filters, time, and detail, and it
|
|
8
|
+
* reports what a Web Mercator plane cannot hold instead of quietly dropping it.
|
|
9
|
+
*
|
|
10
|
+
* The map is duck-typed: nothing here imports the renderer package, so a 3D-only
|
|
11
|
+
* or headless consumer pays no 2D cost, and a test can drive the port with a
|
|
12
|
+
* plain object.
|
|
13
|
+
*
|
|
14
|
+
* @beta Part of the beta `@honua/app-platform/scene-workspace` surface.
|
|
15
|
+
* @module
|
|
16
|
+
*/
|
|
17
|
+
import { DEFAULT_MAPLIBRE_CAMERA_GEOMETRY, mapLibreViewToSceneCamera, sceneCameraToMapLibreView, } from "./camera-correspondence.js";
|
|
18
|
+
import { compileMapLibreFilters } from "./primitives.js";
|
|
19
|
+
import { createPortCore, } from "./state-sync-port-kit.js";
|
|
20
|
+
import { HonuaSceneStateSyncError, } from "./state-sync.js";
|
|
21
|
+
const FILTERABLE_LAYER_TYPES = new Set(["fill", "line", "circle", "symbol", "fill-extrusion", "heatmap"]);
|
|
22
|
+
const DEFAULT_PORT_ID = "maplibre-state-sync";
|
|
23
|
+
/**
|
|
24
|
+
* Bind a live 2D map to the shared scene state.
|
|
25
|
+
*
|
|
26
|
+
* Camera changes are published automatically from the map's own `moveend` /
|
|
27
|
+
* `rotateend` / `pitchend` events. Selection, filters, time, detail, and
|
|
28
|
+
* attribution have no renderer event to hang off — those are host decisions —
|
|
29
|
+
* so the host publishes them with {@link SceneStateSyncRendererPort.publish}.
|
|
30
|
+
*/
|
|
31
|
+
export function createMapLibreStateSyncPort(map, options) {
|
|
32
|
+
if (map === null || typeof map !== "object")
|
|
33
|
+
throw new HonuaSceneStateSyncError("invalid-input", "map must be a live 2D map instance");
|
|
34
|
+
for (const method of ["getCenter", "getZoom", "getBearing", "getPitch", "jumpTo", "on", "off"]) {
|
|
35
|
+
if (typeof map[method] !== "function")
|
|
36
|
+
throw new HonuaSceneStateSyncError("invalid-input", `map.${method} must be a function`);
|
|
37
|
+
}
|
|
38
|
+
if (options === null || typeof options !== "object" || options.identity === undefined)
|
|
39
|
+
throw new HonuaSceneStateSyncError("invalid-input", "options.identity is required");
|
|
40
|
+
const id = options.id ?? DEFAULT_PORT_ID;
|
|
41
|
+
const selectionStateKey = options.selectionStateKey ?? "selected";
|
|
42
|
+
const detailStateKey = options.detailStateKey ?? "detail";
|
|
43
|
+
const featureStateCapable = typeof map.setFeatureState === "function" && typeof map.removeFeatureState === "function";
|
|
44
|
+
const filterCapable = typeof map.setFilter === "function";
|
|
45
|
+
const rollSupported = typeof map.getRoll === "function";
|
|
46
|
+
const timeField = typeof options.timeField === "string" && options.timeField.length > 0 ? options.timeField : undefined;
|
|
47
|
+
const baselineFilters = new Map();
|
|
48
|
+
const appliedSelection = [];
|
|
49
|
+
let appliedDetail;
|
|
50
|
+
let currentFilters = Object.freeze({});
|
|
51
|
+
let currentTime = Object.freeze({});
|
|
52
|
+
let applying = false;
|
|
53
|
+
let cameraEventDuringApply = false;
|
|
54
|
+
const core = createPortCore({
|
|
55
|
+
id,
|
|
56
|
+
renderer: "maplibre",
|
|
57
|
+
identity: options.identity,
|
|
58
|
+
...(options.now ? { now: options.now } : {}),
|
|
59
|
+
...(options.onDegraded ? { onDegraded: options.onDegraded } : {}),
|
|
60
|
+
bind: () => {
|
|
61
|
+
const handler = () => {
|
|
62
|
+
if (applying) {
|
|
63
|
+
cameraEventDuringApply = true;
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
core.publish("camera", readCamera());
|
|
67
|
+
};
|
|
68
|
+
const events = ["moveend", "rotateend", "pitchend"];
|
|
69
|
+
for (const event of events)
|
|
70
|
+
map.on(event, handler);
|
|
71
|
+
return () => {
|
|
72
|
+
for (const event of events)
|
|
73
|
+
map.off(event, handler);
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
function geometry() {
|
|
78
|
+
const viewportHeightPixels = positive(options.geometry?.viewportHeightPixels) ??
|
|
79
|
+
positive(map.getCanvas?.()?.clientHeight) ??
|
|
80
|
+
positive(map.getContainer?.()?.clientHeight) ??
|
|
81
|
+
DEFAULT_MAPLIBRE_CAMERA_GEOMETRY.viewportHeightPixels;
|
|
82
|
+
return {
|
|
83
|
+
viewportHeightPixels,
|
|
84
|
+
fovRadians: positive(options.geometry?.fovRadians) ?? DEFAULT_MAPLIBRE_CAMERA_GEOMETRY.fovRadians,
|
|
85
|
+
tileSizePixels: positive(options.geometry?.tileSizePixels) ?? DEFAULT_MAPLIBRE_CAMERA_GEOMETRY.tileSizePixels,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function limits() {
|
|
89
|
+
return {
|
|
90
|
+
minZoom: numberOr(map.getMinZoom?.(), 0),
|
|
91
|
+
maxZoom: numberOr(map.getMaxZoom?.(), 22),
|
|
92
|
+
maxPitch: numberOr(map.getMaxPitch?.(), 60),
|
|
93
|
+
rollSupported,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function readCamera() {
|
|
97
|
+
const center = map.getCenter();
|
|
98
|
+
const [longitude, latitude] = Array.isArray(center)
|
|
99
|
+
? [center[0], center[1]]
|
|
100
|
+
: [center.lng, center.lat];
|
|
101
|
+
return mapLibreViewToSceneCamera({
|
|
102
|
+
center: [longitude, latitude],
|
|
103
|
+
zoom: map.getZoom(),
|
|
104
|
+
bearing: map.getBearing(),
|
|
105
|
+
pitch: map.getPitch(),
|
|
106
|
+
roll: rollSupported ? numberOr(map.getRoll?.(), 0) : 0,
|
|
107
|
+
}, geometry());
|
|
108
|
+
}
|
|
109
|
+
function applyCamera(camera, revision) {
|
|
110
|
+
if (camera === undefined)
|
|
111
|
+
return;
|
|
112
|
+
const projection = sceneCameraToMapLibreView(camera, { geometry: geometry(), limits: limits() });
|
|
113
|
+
for (const degradation of projection.degradations) {
|
|
114
|
+
core.degrade("camera", degradation.code, degradation.message, {
|
|
115
|
+
revision,
|
|
116
|
+
requested: degradation.requested,
|
|
117
|
+
applied: degradation.applied,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
cameraEventDuringApply = false;
|
|
121
|
+
applying = true;
|
|
122
|
+
try {
|
|
123
|
+
map.jumpTo({
|
|
124
|
+
center: [projection.view.center[0], projection.view.center[1]],
|
|
125
|
+
zoom: projection.view.zoom,
|
|
126
|
+
bearing: projection.view.bearing,
|
|
127
|
+
pitch: projection.view.pitch,
|
|
128
|
+
...(rollSupported ? { roll: projection.view.roll } : {}),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
finally {
|
|
132
|
+
applying = false;
|
|
133
|
+
}
|
|
134
|
+
// The 2D map applies `jumpTo` synchronously and fires its move events inside
|
|
135
|
+
// that call, so the read-back below is the settled state. Both the read-back
|
|
136
|
+
// and the delivered pose are registered as echoes: when the plane clamped
|
|
137
|
+
// something, the clamped read-back must acknowledge rather than publish, or
|
|
138
|
+
// the 3D view would be dragged down to the 2D limits.
|
|
139
|
+
core.markApplied("camera", revision, readCamera(), camera);
|
|
140
|
+
if (cameraEventDuringApply) {
|
|
141
|
+
cameraEventDuringApply = false;
|
|
142
|
+
core.publish("camera", readCamera());
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function resolveFilterLayers() {
|
|
146
|
+
const styleLayers = map.getStyle?.()?.layers ?? [];
|
|
147
|
+
const resolved = [];
|
|
148
|
+
for (const layer of styleLayers) {
|
|
149
|
+
const layerId = typeof layer.id === "string" ? layer.id : undefined;
|
|
150
|
+
const source = typeof layer.source === "string" ? layer.source : undefined;
|
|
151
|
+
const type = typeof layer.type === "string" ? layer.type : undefined;
|
|
152
|
+
if (!layerId || !source || !type || !FILTERABLE_LAYER_TYPES.has(type))
|
|
153
|
+
continue;
|
|
154
|
+
if (options.filterLayers && !options.filterLayers.includes(layerId))
|
|
155
|
+
continue;
|
|
156
|
+
resolved.push({ id: layerId, source });
|
|
157
|
+
}
|
|
158
|
+
return resolved;
|
|
159
|
+
}
|
|
160
|
+
function timeClauses() {
|
|
161
|
+
if (!timeField)
|
|
162
|
+
return [];
|
|
163
|
+
const clauses = [];
|
|
164
|
+
const start = epochMs(currentTime.startTime);
|
|
165
|
+
const current = epochMs(currentTime.currentTime);
|
|
166
|
+
if (start !== undefined)
|
|
167
|
+
clauses.push([">=", timeField, start]);
|
|
168
|
+
if (current !== undefined)
|
|
169
|
+
clauses.push(["<=", timeField, current]);
|
|
170
|
+
return clauses;
|
|
171
|
+
}
|
|
172
|
+
function applyFilterComposition(slice, revision) {
|
|
173
|
+
if (!filterCapable)
|
|
174
|
+
return;
|
|
175
|
+
const layers = resolveFilterLayers();
|
|
176
|
+
if (layers.length === 0) {
|
|
177
|
+
core.degrade(slice, "filters-no-target-layers", "The current style has no filterable layer, so shared clauses had nowhere to land.", { revision });
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
const time = timeClauses();
|
|
181
|
+
for (const layer of layers) {
|
|
182
|
+
if (!baselineFilters.has(layer.id))
|
|
183
|
+
baselineFilters.set(layer.id, map.getFilter?.(layer.id));
|
|
184
|
+
const baseline = baselineFilters.get(layer.id);
|
|
185
|
+
const compiled = compileMapLibreFilters(currentFilters, layer.source).slice(1);
|
|
186
|
+
const parts = [...(baseline === undefined ? [] : [baseline]), ...compiled, ...time];
|
|
187
|
+
try {
|
|
188
|
+
map.setFilter?.(layer.id, parts.length === 0 ? undefined : ["all", ...parts]);
|
|
189
|
+
}
|
|
190
|
+
catch (cause) {
|
|
191
|
+
core.degrade(slice, "filters-layer-rejected", `Layer ${layer.id} rejected the composed filter: ${describe(cause)}`, { revision });
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function addressFor(target) {
|
|
196
|
+
if (typeof target === "string" || typeof target === "number")
|
|
197
|
+
return { source: options.identity.sourceId, id: target };
|
|
198
|
+
if (target === null || typeof target !== "object")
|
|
199
|
+
return undefined;
|
|
200
|
+
const record = target;
|
|
201
|
+
if (typeof record.sourceId !== "string")
|
|
202
|
+
return undefined;
|
|
203
|
+
if (typeof record.id !== "string" && typeof record.id !== "number")
|
|
204
|
+
return undefined;
|
|
205
|
+
return {
|
|
206
|
+
source: record.sourceId,
|
|
207
|
+
id: record.id,
|
|
208
|
+
...(typeof record.sourceLayer === "string" ? { sourceLayer: record.sourceLayer } : {}),
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function applySelection(targets, revision) {
|
|
212
|
+
if (!featureStateCapable)
|
|
213
|
+
return;
|
|
214
|
+
for (const address of appliedSelection.splice(0)) {
|
|
215
|
+
try {
|
|
216
|
+
map.removeFeatureState?.(address, selectionStateKey);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
// A source removed since the last application cannot retain state.
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
for (const target of targets) {
|
|
223
|
+
const address = addressFor(target);
|
|
224
|
+
if (!address) {
|
|
225
|
+
core.degrade("selection", "selection-target-unresolved", "Selection target carries no source-qualified identity.", {
|
|
226
|
+
revision,
|
|
227
|
+
});
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
if (typeof map.getSource === "function" && map.getSource(address.source) === undefined) {
|
|
231
|
+
core.degrade("selection", "selection-source-missing", `Source ${address.source} is not in the current style, so its selection cannot be drawn.`, { revision });
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
map.setFeatureState?.(address, { [selectionStateKey]: true });
|
|
235
|
+
appliedSelection.push(address);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
function applyDetail(detail, revision) {
|
|
239
|
+
if (!featureStateCapable)
|
|
240
|
+
return;
|
|
241
|
+
if (appliedDetail) {
|
|
242
|
+
try {
|
|
243
|
+
map.removeFeatureState?.(appliedDetail, detailStateKey);
|
|
244
|
+
}
|
|
245
|
+
catch {
|
|
246
|
+
// Same as selection: a departed source holds no state.
|
|
247
|
+
}
|
|
248
|
+
appliedDetail = undefined;
|
|
249
|
+
}
|
|
250
|
+
const target = detail.target ??
|
|
251
|
+
(detail.sourceId !== undefined && detail.featureId !== undefined
|
|
252
|
+
? { sourceId: detail.sourceId, id: detail.featureId }
|
|
253
|
+
: undefined);
|
|
254
|
+
if (target === undefined)
|
|
255
|
+
return;
|
|
256
|
+
const address = addressFor(target);
|
|
257
|
+
if (!address) {
|
|
258
|
+
core.degrade("detail", "detail-target-unresolved", "Detail target carries no source-qualified identity.", {
|
|
259
|
+
revision,
|
|
260
|
+
});
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
map.setFeatureState?.(address, { [detailStateKey]: true });
|
|
264
|
+
appliedDetail = address;
|
|
265
|
+
}
|
|
266
|
+
function apply(delivery) {
|
|
267
|
+
const { slice, value, revision } = delivery.envelope;
|
|
268
|
+
switch (slice) {
|
|
269
|
+
case "camera":
|
|
270
|
+
applyCamera(value, revision);
|
|
271
|
+
return;
|
|
272
|
+
case "filters":
|
|
273
|
+
currentFilters = value;
|
|
274
|
+
applyFilterComposition("filters", revision);
|
|
275
|
+
core.markApplied("filters", revision, currentFilters);
|
|
276
|
+
return;
|
|
277
|
+
case "time":
|
|
278
|
+
currentTime = value;
|
|
279
|
+
if (!timeField) {
|
|
280
|
+
core.degrade("time", "time-field-unconfigured", "No temporal field is configured, so shared time cannot reach a 2D layer filter.", { revision });
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
applyFilterComposition("time", revision);
|
|
284
|
+
core.markApplied("time", revision, currentTime);
|
|
285
|
+
return;
|
|
286
|
+
case "selection":
|
|
287
|
+
applySelection(value, revision);
|
|
288
|
+
core.markApplied("selection", revision, value);
|
|
289
|
+
return;
|
|
290
|
+
case "detail":
|
|
291
|
+
applyDetail(value, revision);
|
|
292
|
+
core.markApplied("detail", revision, value);
|
|
293
|
+
return;
|
|
294
|
+
default:
|
|
295
|
+
// `attribution` and `realtime` are credential-free host read models; the
|
|
296
|
+
// port records them for echo suppression and declares them `equivalent`
|
|
297
|
+
// rather than rewriting the renderer's own credit control.
|
|
298
|
+
core.markApplied(slice, revision, value);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
const port = {
|
|
302
|
+
id,
|
|
303
|
+
renderer: "maplibre",
|
|
304
|
+
mappings: buildMappings({ featureStateCapable, filterCapable, rollSupported, timeField }),
|
|
305
|
+
subscribe(listener, signal) {
|
|
306
|
+
return core.subscribe(listener, signal);
|
|
307
|
+
},
|
|
308
|
+
apply(delivery) {
|
|
309
|
+
apply(delivery);
|
|
310
|
+
},
|
|
311
|
+
publish(slice, value) {
|
|
312
|
+
return core.publish(slice, value);
|
|
313
|
+
},
|
|
314
|
+
readFromRenderer(slice) {
|
|
315
|
+
if (slice !== "camera")
|
|
316
|
+
return "unsupported";
|
|
317
|
+
return core.publish("camera", readCamera());
|
|
318
|
+
},
|
|
319
|
+
get degradations() {
|
|
320
|
+
return core.degradations;
|
|
321
|
+
},
|
|
322
|
+
get disposed() {
|
|
323
|
+
return core.disposed;
|
|
324
|
+
},
|
|
325
|
+
dispose() {
|
|
326
|
+
if (core.disposed)
|
|
327
|
+
return;
|
|
328
|
+
for (const address of appliedSelection.splice(0)) {
|
|
329
|
+
try {
|
|
330
|
+
map.removeFeatureState?.(address, selectionStateKey);
|
|
331
|
+
}
|
|
332
|
+
catch {
|
|
333
|
+
// Teardown never throws on a renderer that is already gone.
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (appliedDetail) {
|
|
337
|
+
try {
|
|
338
|
+
map.removeFeatureState?.(appliedDetail, detailStateKey);
|
|
339
|
+
}
|
|
340
|
+
catch {
|
|
341
|
+
// As above.
|
|
342
|
+
}
|
|
343
|
+
appliedDetail = undefined;
|
|
344
|
+
}
|
|
345
|
+
for (const [layerId, baseline] of baselineFilters) {
|
|
346
|
+
try {
|
|
347
|
+
map.setFilter?.(layerId, baseline);
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
// A layer removed since the first application needs no restore.
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
baselineFilters.clear();
|
|
354
|
+
core.dispose();
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
return port;
|
|
358
|
+
}
|
|
359
|
+
function buildMappings(capabilities) {
|
|
360
|
+
const mapping = (inbound, outbound, code, message) => Object.freeze({ inbound, outbound, code, message });
|
|
361
|
+
return Object.freeze({
|
|
362
|
+
camera: mapping("exact", "equivalent", "maplibre-2d-camera", `Zoom maps to camera height through the documented ground-resolution correspondence.${capabilities.rollSupported ? "" : " Camera roll is dropped."} Latitudes beyond the Web Mercator limit, pitches beyond the map maximum, and heights outside the zoom range are clamped and reported.`),
|
|
363
|
+
selection: capabilities.featureStateCapable
|
|
364
|
+
? mapping("exact", "exact", "maplibre-feature-state-selection", "Source-qualified selection is written as feature state on the addressed source.")
|
|
365
|
+
: mapping("exact", "unsupported", "maplibre-feature-state-unavailable", "This map exposes no feature-state API, so shared selection cannot be drawn."),
|
|
366
|
+
filters: capabilities.filterCapable
|
|
367
|
+
? mapping("exact", "exact", "maplibre-layer-filter", "Protocol-neutral clauses compile to layer filters composed on top of the style's own filter.")
|
|
368
|
+
: mapping("exact", "unsupported", "maplibre-layer-filter-unavailable", "This map exposes no setFilter API, so shared filters cannot be applied."),
|
|
369
|
+
time: capabilities.timeField && capabilities.filterCapable
|
|
370
|
+
? mapping("exact", "equivalent", "maplibre-time-window-filter", `Shared time is applied as an epoch-millisecond window on ${capabilities.timeField}; the 2D renderer has no clock of its own.`)
|
|
371
|
+
: mapping("exact", "unsupported", "maplibre-time-field-unconfigured", "No temporal field is configured for this map, so shared time has nothing to filter."),
|
|
372
|
+
detail: capabilities.featureStateCapable
|
|
373
|
+
? mapping("exact", "exact", "maplibre-feature-state-detail", "The detail target is written as feature state so the drawn feature reflects the open detail view.")
|
|
374
|
+
: mapping("exact", "unsupported", "maplibre-feature-state-unavailable", "This map exposes no feature-state API, so the detail target cannot be drawn."),
|
|
375
|
+
attribution: mapping("exact", "equivalent", "maplibre-attribution-ids", "Credential-free attribution identifiers are shared for the host to render; the map's own attribution control is not rewritten."),
|
|
376
|
+
realtime: mapping("exact", "equivalent", "maplibre-realtime-status", "Realtime status is shared for the host to render; a 2D map has no realtime surface of its own."),
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
function positive(value) {
|
|
380
|
+
return typeof value === "number" && Number.isFinite(value) && value > 0 ? value : undefined;
|
|
381
|
+
}
|
|
382
|
+
function numberOr(value, fallback) {
|
|
383
|
+
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
384
|
+
}
|
|
385
|
+
function epochMs(value) {
|
|
386
|
+
if (typeof value !== "string")
|
|
387
|
+
return undefined;
|
|
388
|
+
const parsed = Date.parse(value);
|
|
389
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
390
|
+
}
|
|
391
|
+
function describe(cause) {
|
|
392
|
+
const text = cause instanceof Error ? cause.message : String(cause);
|
|
393
|
+
return [...text]
|
|
394
|
+
.map((character) => {
|
|
395
|
+
const code = character.charCodeAt(0);
|
|
396
|
+
return code <= 31 || code === 127 ? " " : character;
|
|
397
|
+
})
|
|
398
|
+
.join("")
|
|
399
|
+
.slice(0, 160);
|
|
400
|
+
}
|