@honua/react 0.0.20-alpha.0 → 0.1.1-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 +12 -1
- package/contract/index.d.ts.map +1 -1
- package/contract/index.js +4 -0
- package/contract/pmtiles.d.ts +193 -0
- package/contract/pmtiles.d.ts.map +1 -0
- package/contract/pmtiles.js +195 -0
- 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 +57 -15
- package/contract/source.d.ts.map +1 -1
- package/contract/source.js +368 -65
- package/contract/types.d.ts +171 -6
- package/contract/types.d.ts.map +1 -1
- package/contract/types.js +14 -14
- package/core/auth/client-credentials-provider.d.ts +51 -0
- package/core/auth/client-credentials-provider.d.ts.map +1 -0
- package/core/auth/client-credentials-provider.js +115 -0
- package/core/auth/credential-store.d.ts +52 -0
- package/core/auth/credential-store.d.ts.map +1 -0
- package/core/auth/credential-store.js +82 -0
- package/core/auth/index.d.ts +23 -0
- package/core/auth/index.d.ts.map +1 -0
- package/core/auth/index.js +20 -0
- package/core/auth/oauth2-provider.d.ts +114 -0
- package/core/auth/oauth2-provider.d.ts.map +1 -0
- package/core/auth/oauth2-provider.js +408 -0
- package/core/auth/pkce.d.ts +25 -0
- package/core/auth/pkce.d.ts.map +1 -0
- package/core/auth/pkce.js +46 -0
- package/core/auth/static-providers.d.ts +20 -0
- package/core/auth/static-providers.d.ts.map +1 -0
- package/core/auth/static-providers.js +26 -0
- package/core/auth/token-endpoint.d.ts +40 -0
- package/core/auth/token-endpoint.d.ts.map +1 -0
- package/core/auth/token-endpoint.js +133 -0
- package/core/auth/types.d.ts +144 -0
- package/core/auth/types.d.ts.map +1 -0
- package/core/auth/types.js +8 -0
- 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 +35 -2
- package/core/client.d.ts.map +1 -1
- package/core/client.js +167 -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 +73 -25
- package/core/errors.d.ts.map +1 -1
- package/core/errors.js +113 -46
- package/core/geoparquet-sql.d.ts +190 -0
- package/core/geoparquet-sql.d.ts.map +1 -0
- package/core/geoparquet-sql.js +368 -0
- 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-endpoint-layout.d.ts +70 -0
- package/core/ogc-endpoint-layout.d.ts.map +1 -0
- package/core/ogc-endpoint-layout.js +173 -0
- package/core/ogc-features.d.ts.map +1 -1
- package/core/ogc-features.js +35 -17
- 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 +55 -0
- package/core/stac-static.d.ts.map +1 -0
- package/core/stac-static.js +386 -0
- package/core/stac.d.ts +12 -0
- package/core/stac.d.ts.map +1 -1
- package/core/stac.js +45 -15
- package/core/surfaces.d.ts +13 -0
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +127 -16
- package/core/types.d.ts +174 -7
- package/core/types.d.ts.map +1 -1
- package/core/wfs-capabilities.d.ts +12 -0
- package/core/wfs-capabilities.d.ts.map +1 -1
- package/core/wfs-capabilities.js +22 -3
- package/core/wfs.d.ts +13 -0
- package/core/wfs.d.ts.map +1 -1
- package/core/wfs.js +35 -5
- 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/identity-manager.d.ts +43 -0
- package/esri-compat/identity-manager.d.ts.map +1 -1
- package/esri-compat/identity-manager.js +131 -1
- 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/oauth-info.d.ts +15 -0
- package/esri-compat/oauth-info.d.ts.map +1 -1
- package/esri-compat/oauth-info.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 +19 -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 +8 -2
- package/runtime/index.d.ts.map +1 -1
- package/runtime/index.js +4 -4
- package/runtime/load-package.d.ts.map +1 -1
- package/runtime/load-package.js +8 -0
- package/runtime/map-package-validation.d.ts +0 -13
- package/runtime/map-package-validation.d.ts.map +1 -1
- package/runtime/map-package-validation.js +0 -12
- package/runtime/map-package.d.ts +1 -1
- package/runtime/map-package.d.ts.map +1 -1
- 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/pmtiles-protocol.d.ts +77 -0
- package/runtime/pmtiles-protocol.d.ts.map +1 -0
- package/runtime/pmtiles-protocol.js +120 -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 +36 -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
|
@@ -86,6 +86,33 @@ export class OAuthInfoCompat {
|
|
|
86
86
|
this.notifyWatchers("preserveUrlHash", this.preserveUrlHash);
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Derive an {@link OAuth2Config} from this Esri-style OAuth info so it can back
|
|
91
|
+
* a real `oauth2(...)` provider from `@honua/sdk-js/auth`. Endpoints default to
|
|
92
|
+
* the ArcGIS Portal shape (`<portalUrl>/sharing/rest/oauth2/authorize` and
|
|
93
|
+
* `/token`); pass explicit endpoints or a `redirectUri` via `overrides`.
|
|
94
|
+
*/
|
|
95
|
+
toOAuth2Config(overrides = {}) {
|
|
96
|
+
const clientId = overrides.clientId ?? this.appId;
|
|
97
|
+
if (!clientId) {
|
|
98
|
+
throw new Error("OAuthInfoCompat.toOAuth2Config requires an appId (or an explicit clientId override).");
|
|
99
|
+
}
|
|
100
|
+
const redirectUri = overrides.redirectUri;
|
|
101
|
+
if (!redirectUri) {
|
|
102
|
+
throw new Error("OAuthInfoCompat.toOAuth2Config requires a redirectUri override.");
|
|
103
|
+
}
|
|
104
|
+
const portalBase = this.portalUrl.replace(/\/+$/, "");
|
|
105
|
+
const { redirectUri: _redirectUri, clientId: _clientId, ...rest } = overrides;
|
|
106
|
+
return {
|
|
107
|
+
authorizationEndpoint: `${portalBase}/sharing/rest/oauth2/authorize`,
|
|
108
|
+
tokenEndpoint: `${portalBase}/sharing/rest/oauth2/token`,
|
|
109
|
+
clientId,
|
|
110
|
+
redirectUri,
|
|
111
|
+
mode: this.popup ? "popup" : "redirect",
|
|
112
|
+
...(this.expiration !== undefined ? { extraAuthorizationParams: { expiration: String(this.expiration) } } : {}),
|
|
113
|
+
...rest,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
89
116
|
clone() {
|
|
90
117
|
return new OAuthInfoCompat(this.toJSON());
|
|
91
118
|
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
import { HonuaClient } from "../core/client.js";
|
|
2
|
+
import { FeatureLayerCompat } from "./feature-layer.js";
|
|
3
|
+
/**
|
|
4
|
+
* A single item as returned by the Honua Portal facade
|
|
5
|
+
* (`/sharing/rest/search` and `/sharing/rest/content/items/{id}`). Mirrors the
|
|
6
|
+
* ArcGIS Portal item shape so a repointed app reads the same fields.
|
|
7
|
+
*/
|
|
8
|
+
export interface PortalItem {
|
|
9
|
+
id: string;
|
|
10
|
+
owner: string;
|
|
11
|
+
created: number;
|
|
12
|
+
modified: number;
|
|
13
|
+
type: string;
|
|
14
|
+
typeKeywords: string[];
|
|
15
|
+
title: string;
|
|
16
|
+
snippet: string | null;
|
|
17
|
+
description: string | null;
|
|
18
|
+
tags: string[];
|
|
19
|
+
/** Absolute service URL, e.g. `.../rest/services/{name}/FeatureServer`. */
|
|
20
|
+
url: string | null;
|
|
21
|
+
access: "public" | "org" | "private" | string;
|
|
22
|
+
extent: number[][] | null;
|
|
23
|
+
spatialReference: string | null;
|
|
24
|
+
culture: string | null;
|
|
25
|
+
numComments: number;
|
|
26
|
+
numViews: number;
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
}
|
|
29
|
+
/** Parsed `/sharing/rest/search` response. */
|
|
30
|
+
export interface PortalSearchResult {
|
|
31
|
+
query: string;
|
|
32
|
+
total: number;
|
|
33
|
+
/** 1-based index of the first result in this page. */
|
|
34
|
+
start: number;
|
|
35
|
+
num: number;
|
|
36
|
+
/** Index of the next page's first result, or `-1` on the last page. */
|
|
37
|
+
nextStart: number;
|
|
38
|
+
results: PortalItem[];
|
|
39
|
+
}
|
|
40
|
+
/** `/sharing/rest/info` response (subset the client relies on). */
|
|
41
|
+
export interface PortalInfo {
|
|
42
|
+
authInfo?: {
|
|
43
|
+
isTokenBasedSecurity?: boolean;
|
|
44
|
+
tokenServicesUrl?: string;
|
|
45
|
+
};
|
|
46
|
+
[key: string]: unknown;
|
|
47
|
+
}
|
|
48
|
+
/** `/sharing/rest/portals/self` response (subset the client relies on). */
|
|
49
|
+
export interface PortalSelf {
|
|
50
|
+
id?: string;
|
|
51
|
+
isPortal?: boolean;
|
|
52
|
+
name?: string;
|
|
53
|
+
portalName?: string;
|
|
54
|
+
user?: {
|
|
55
|
+
username: string;
|
|
56
|
+
fullName?: string;
|
|
57
|
+
role?: string;
|
|
58
|
+
} | null;
|
|
59
|
+
[key: string]: unknown;
|
|
60
|
+
}
|
|
61
|
+
/** Options accepted by {@link PortalCompat}. */
|
|
62
|
+
export interface PortalCompatOptions {
|
|
63
|
+
/**
|
|
64
|
+
* Portal base URL. Accepts either a portal root (`https://portal.example`) or
|
|
65
|
+
* a `/sharing/rest` base; both normalize to the `.../sharing/rest` endpoint
|
|
66
|
+
* base. Defaults to {@link esriConfig.portalUrl}.
|
|
67
|
+
*/
|
|
68
|
+
portalUrl?: string;
|
|
69
|
+
/** Pre-obtained token to attach to authenticated calls. */
|
|
70
|
+
token?: string;
|
|
71
|
+
/** Static API key (falls back to {@link esriConfig.apiKey}). */
|
|
72
|
+
apiKey?: string;
|
|
73
|
+
/** Override the global `fetch` implementation (useful in tests). */
|
|
74
|
+
fetchFn?: typeof fetch;
|
|
75
|
+
}
|
|
76
|
+
/** Options for {@link PortalCompat.generateToken}. */
|
|
77
|
+
export interface PortalGenerateTokenOptions {
|
|
78
|
+
username: string;
|
|
79
|
+
password: string;
|
|
80
|
+
/** Referer registered with the token. Defaults to the portal origin. */
|
|
81
|
+
referer?: string;
|
|
82
|
+
/** Esri `client` param (`"referer"` | `"requestip"` | `"ip"`). Defaults to `"referer"`. */
|
|
83
|
+
client?: string;
|
|
84
|
+
/** Token lifetime in minutes. */
|
|
85
|
+
expirationMinutes?: number;
|
|
86
|
+
}
|
|
87
|
+
/** Result of {@link PortalCompat.generateToken}. */
|
|
88
|
+
export interface PortalTokenCredential {
|
|
89
|
+
token: string;
|
|
90
|
+
/** Absolute expiry as a unix-millisecond timestamp. */
|
|
91
|
+
expiresAtMs: number;
|
|
92
|
+
ssl: boolean;
|
|
93
|
+
}
|
|
94
|
+
/** Options for {@link PortalCompat.search}. */
|
|
95
|
+
export interface PortalSearchOptions {
|
|
96
|
+
q?: string;
|
|
97
|
+
start?: number;
|
|
98
|
+
num?: number;
|
|
99
|
+
token?: string;
|
|
100
|
+
}
|
|
101
|
+
/** Options for {@link PortalCompat.getItem}. */
|
|
102
|
+
export interface PortalGetItemOptions {
|
|
103
|
+
token?: string;
|
|
104
|
+
}
|
|
105
|
+
/** Options for {@link PortalCompat.openFeatureLayer}. */
|
|
106
|
+
export interface PortalOpenOptions {
|
|
107
|
+
/** Layer id to open for Feature Service items. Defaults to the service's first advertised layer. */
|
|
108
|
+
layerId?: number;
|
|
109
|
+
}
|
|
110
|
+
interface PortalOpenResultBase {
|
|
111
|
+
/** Resolved portal item. */
|
|
112
|
+
item: PortalItem;
|
|
113
|
+
/** Service base (`.../rest/services`-prefixed origin/prefix) without the service segment. */
|
|
114
|
+
baseUrl: string;
|
|
115
|
+
/** Service (folder/name) id parsed from the item URL. */
|
|
116
|
+
serviceId: string;
|
|
117
|
+
/** Authenticated client bound to `baseUrl`, carrying the portal credential. */
|
|
118
|
+
client: HonuaClient;
|
|
119
|
+
}
|
|
120
|
+
/** Feature Service open result: includes a ready-to-use {@link FeatureLayerCompat}. */
|
|
121
|
+
export interface PortalFeatureServiceOpenResult extends PortalOpenResultBase {
|
|
122
|
+
type: "feature-service";
|
|
123
|
+
layerId: number;
|
|
124
|
+
layer: FeatureLayerCompat;
|
|
125
|
+
}
|
|
126
|
+
/** Map/Image Service open result: the resolved, authenticated service handle. */
|
|
127
|
+
export interface PortalServiceOpenResult extends PortalOpenResultBase {
|
|
128
|
+
type: "map-service" | "image-service";
|
|
129
|
+
}
|
|
130
|
+
export type PortalOpenResult = PortalFeatureServiceOpenResult | PortalServiceOpenResult;
|
|
131
|
+
/** Error thrown when the Portal facade returns an Esri error envelope. */
|
|
132
|
+
export declare class PortalError extends Error {
|
|
133
|
+
readonly code: number | string | undefined;
|
|
134
|
+
readonly details: unknown;
|
|
135
|
+
constructor(message: string, code?: number | string, details?: unknown);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Client for a Honua `/sharing/rest` Portal facade. Lets a repointed ArcGIS app
|
|
139
|
+
* authenticate, search for items, and open an item that resolves to a
|
|
140
|
+
* `/rest/services` URL — carrying the portal token through to the opened layer
|
|
141
|
+
* so the whole flow authenticates end to end.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```ts
|
|
145
|
+
* import { PortalCompat } from "@honua/sdk-js/esri-compat";
|
|
146
|
+
*
|
|
147
|
+
* const portal = new PortalCompat({ portalUrl: "https://honua.example" });
|
|
148
|
+
* await portal.generateToken({ username: "u", password: "p" });
|
|
149
|
+
* const { results } = await portal.search({ q: "roads" });
|
|
150
|
+
* const opened = await portal.openFeatureLayer(results[0]);
|
|
151
|
+
* if (opened.type === "feature-service") {
|
|
152
|
+
* await opened.layer.queryFeatures({ where: "1=1" });
|
|
153
|
+
* }
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export declare class PortalCompat {
|
|
157
|
+
/** Normalized `.../sharing/rest` base for this portal. */
|
|
158
|
+
readonly sharingRestBase: string;
|
|
159
|
+
private token;
|
|
160
|
+
private tokenExpiresAtMs;
|
|
161
|
+
private readonly apiKey;
|
|
162
|
+
private readonly fetchFn;
|
|
163
|
+
constructor(options?: PortalCompatOptions);
|
|
164
|
+
/** The currently held portal token, if any. */
|
|
165
|
+
getToken(): string | undefined;
|
|
166
|
+
/**
|
|
167
|
+
* Exchange username/password for a portal token via
|
|
168
|
+
* `POST /sharing/rest/generateToken`. Stores the token on this instance and
|
|
169
|
+
* returns the credential (`expires` ms → `expiresAtMs`).
|
|
170
|
+
*/
|
|
171
|
+
generateToken(options: PortalGenerateTokenOptions): Promise<PortalTokenCredential>;
|
|
172
|
+
/** `GET /sharing/rest/info`. */
|
|
173
|
+
getInfo(): Promise<PortalInfo>;
|
|
174
|
+
/** `GET /sharing/rest/portals/self` (attaches the token when present). */
|
|
175
|
+
getPortalSelf(): Promise<PortalSelf>;
|
|
176
|
+
/** `GET /sharing/rest/search`. */
|
|
177
|
+
search(options?: PortalSearchOptions): Promise<PortalSearchResult>;
|
|
178
|
+
/** `GET /sharing/rest/content/items/{id}`. */
|
|
179
|
+
getItem(itemId: string, options?: PortalGetItemOptions): Promise<PortalItem>;
|
|
180
|
+
/**
|
|
181
|
+
* Resolve an item (fetching it when given an id), parse its service `url`, and
|
|
182
|
+
* return an authenticated handle. Feature Service items yield a
|
|
183
|
+
* {@link FeatureLayerCompat} bound to a client carrying the portal token;
|
|
184
|
+
* Map/Image Service items yield the resolved `{ baseUrl, serviceId, client }`.
|
|
185
|
+
*/
|
|
186
|
+
openFeatureLayer(itemOrId: string | PortalItem, options?: PortalOpenOptions): Promise<PortalOpenResult>;
|
|
187
|
+
/**
|
|
188
|
+
* Register the currently held token with the shared {@link identityManager}
|
|
189
|
+
* under this portal's `/sharing/rest` server, so subsequent esri-compat calls
|
|
190
|
+
* resolve the same credential.
|
|
191
|
+
*/
|
|
192
|
+
registerWithIdentityManager(): void;
|
|
193
|
+
private buildAuthenticatedClient;
|
|
194
|
+
private getJson;
|
|
195
|
+
}
|
|
196
|
+
export {};
|
|
197
|
+
//# sourceMappingURL=portal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portal.d.ts","sourceRoot":"","sources":["../../../src/esri-compat/portal.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { HonuaClient } from "../core/client.js";
|
|
2
|
+
import { esriConfig } from "./esri-config.js";
|
|
3
|
+
import { FeatureLayerCompat } from "./feature-layer.js";
|
|
4
|
+
import { identityManager } from "./identity-manager.js";
|
|
5
|
+
import { createArcGisTokenInterceptor } from "./request.js";
|
|
6
|
+
import { parseFeatureLayerUrl, parseImageServiceUrl, parseMapServiceUrl } from "./url.js";
|
|
7
|
+
/** Error thrown when the Portal facade returns an Esri error envelope. */
|
|
8
|
+
export class PortalError extends Error {
|
|
9
|
+
code;
|
|
10
|
+
details;
|
|
11
|
+
constructor(message, code, details) {
|
|
12
|
+
super(message);
|
|
13
|
+
this.name = "PortalError";
|
|
14
|
+
this.code = code;
|
|
15
|
+
this.details = details;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Client for a Honua `/sharing/rest` Portal facade. Lets a repointed ArcGIS app
|
|
20
|
+
* authenticate, search for items, and open an item that resolves to a
|
|
21
|
+
* `/rest/services` URL — carrying the portal token through to the opened layer
|
|
22
|
+
* so the whole flow authenticates end to end.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```ts
|
|
26
|
+
* import { PortalCompat } from "@honua/sdk-js/esri-compat";
|
|
27
|
+
*
|
|
28
|
+
* const portal = new PortalCompat({ portalUrl: "https://honua.example" });
|
|
29
|
+
* await portal.generateToken({ username: "u", password: "p" });
|
|
30
|
+
* const { results } = await portal.search({ q: "roads" });
|
|
31
|
+
* const opened = await portal.openFeatureLayer(results[0]);
|
|
32
|
+
* if (opened.type === "feature-service") {
|
|
33
|
+
* await opened.layer.queryFeatures({ where: "1=1" });
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export class PortalCompat {
|
|
38
|
+
/** Normalized `.../sharing/rest` base for this portal. */
|
|
39
|
+
sharingRestBase;
|
|
40
|
+
token;
|
|
41
|
+
tokenExpiresAtMs;
|
|
42
|
+
apiKey;
|
|
43
|
+
fetchFn;
|
|
44
|
+
constructor(options = {}) {
|
|
45
|
+
this.sharingRestBase = normalizeSharingRestBase(options.portalUrl ?? esriConfig.portalUrl);
|
|
46
|
+
this.token = options.token;
|
|
47
|
+
this.tokenExpiresAtMs = undefined;
|
|
48
|
+
this.apiKey = options.apiKey ?? esriConfig.apiKey;
|
|
49
|
+
// Bind so passing a bare `window.fetch`/`globalThis.fetch` cannot throw an
|
|
50
|
+
// "Illegal invocation" when called as `this.fetchFn(...)`.
|
|
51
|
+
this.fetchFn = (options.fetchFn ?? fetch).bind(globalThis);
|
|
52
|
+
}
|
|
53
|
+
/** The currently held portal token, if any. */
|
|
54
|
+
getToken() {
|
|
55
|
+
return this.token;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Exchange username/password for a portal token via
|
|
59
|
+
* `POST /sharing/rest/generateToken`. Stores the token on this instance and
|
|
60
|
+
* returns the credential (`expires` ms → `expiresAtMs`).
|
|
61
|
+
*/
|
|
62
|
+
async generateToken(options) {
|
|
63
|
+
const referer = options.referer ?? defaultReferer(this.sharingRestBase);
|
|
64
|
+
const body = new URLSearchParams();
|
|
65
|
+
body.set("username", options.username);
|
|
66
|
+
body.set("password", options.password);
|
|
67
|
+
body.set("client", options.client ?? "referer");
|
|
68
|
+
if (referer) {
|
|
69
|
+
body.set("referer", referer);
|
|
70
|
+
}
|
|
71
|
+
if (typeof options.expirationMinutes === "number" && Number.isFinite(options.expirationMinutes)) {
|
|
72
|
+
body.set("expiration", String(options.expirationMinutes));
|
|
73
|
+
}
|
|
74
|
+
body.set("f", "json");
|
|
75
|
+
const response = await this.fetchFn(`${this.sharingRestBase}/generateToken`, {
|
|
76
|
+
method: "POST",
|
|
77
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
78
|
+
body: body.toString(),
|
|
79
|
+
});
|
|
80
|
+
const json = (await response.json());
|
|
81
|
+
throwIfEsriError(json, "Portal generateToken failed.");
|
|
82
|
+
if (typeof json.token !== "string" || json.token.length === 0) {
|
|
83
|
+
throw new PortalError("Portal generateToken response did not include a token.");
|
|
84
|
+
}
|
|
85
|
+
const expiresAtMs = typeof json.expires === "number" && Number.isFinite(json.expires) ? json.expires : 0;
|
|
86
|
+
this.token = json.token;
|
|
87
|
+
this.tokenExpiresAtMs = expiresAtMs || undefined;
|
|
88
|
+
return { token: json.token, expiresAtMs, ssl: json.ssl ?? true };
|
|
89
|
+
}
|
|
90
|
+
/** `GET /sharing/rest/info`. */
|
|
91
|
+
async getInfo() {
|
|
92
|
+
return this.getJson("/info", {}, undefined);
|
|
93
|
+
}
|
|
94
|
+
/** `GET /sharing/rest/portals/self` (attaches the token when present). */
|
|
95
|
+
async getPortalSelf() {
|
|
96
|
+
return this.getJson("/portals/self", {}, this.token);
|
|
97
|
+
}
|
|
98
|
+
/** `GET /sharing/rest/search`. */
|
|
99
|
+
async search(options = {}) {
|
|
100
|
+
const params = {
|
|
101
|
+
q: options.q,
|
|
102
|
+
start: options.start,
|
|
103
|
+
num: options.num,
|
|
104
|
+
};
|
|
105
|
+
const raw = await this.getJson("/search", params, options.token ?? this.token);
|
|
106
|
+
return {
|
|
107
|
+
query: raw.query ?? options.q ?? "",
|
|
108
|
+
total: raw.total ?? 0,
|
|
109
|
+
start: raw.start ?? options.start ?? 1,
|
|
110
|
+
num: raw.num ?? options.num ?? 0,
|
|
111
|
+
nextStart: raw.nextStart ?? -1,
|
|
112
|
+
results: Array.isArray(raw.results) ? raw.results : [],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/** `GET /sharing/rest/content/items/{id}`. */
|
|
116
|
+
async getItem(itemId, options = {}) {
|
|
117
|
+
return this.getJson(`/content/items/${encodeURIComponent(itemId)}`, {}, options.token ?? this.token);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Resolve an item (fetching it when given an id), parse its service `url`, and
|
|
121
|
+
* return an authenticated handle. Feature Service items yield a
|
|
122
|
+
* {@link FeatureLayerCompat} bound to a client carrying the portal token;
|
|
123
|
+
* Map/Image Service items yield the resolved `{ baseUrl, serviceId, client }`.
|
|
124
|
+
*/
|
|
125
|
+
async openFeatureLayer(itemOrId, options = {}) {
|
|
126
|
+
const item = typeof itemOrId === "string" ? await this.getItem(itemOrId) : itemOrId;
|
|
127
|
+
if (!item.url) {
|
|
128
|
+
throw new PortalError(`Portal item ${item.id} has no service URL to open.`);
|
|
129
|
+
}
|
|
130
|
+
const serviceUrl = trimTrailingSlashes(item.url);
|
|
131
|
+
if (isFeatureService(item.type, serviceUrl)) {
|
|
132
|
+
const hasLayerId = /\/FeatureServer\/\d+$/i.test(serviceUrl);
|
|
133
|
+
const service = parseFeatureLayerUrl(hasLayerId ? serviceUrl : `${serviceUrl}/0`);
|
|
134
|
+
const client = this.buildAuthenticatedClient(service.baseUrl);
|
|
135
|
+
let layerId = service.layerId;
|
|
136
|
+
if (!hasLayerId) {
|
|
137
|
+
if (options.layerId !== undefined) {
|
|
138
|
+
layerId = options.layerId;
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
const metadata = await client.getFeatureServiceMetadata(service.serviceId);
|
|
142
|
+
const firstLayerId = metadata.layers?.[0]?.id;
|
|
143
|
+
if (typeof firstLayerId !== "number" || !Number.isSafeInteger(firstLayerId)) {
|
|
144
|
+
throw new PortalError(`Portal Feature Service item ${item.id} does not advertise a layer to open.`);
|
|
145
|
+
}
|
|
146
|
+
layerId = firstLayerId;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const layerUrl = hasLayerId ? serviceUrl : `${serviceUrl}/${layerId}`;
|
|
150
|
+
const parsed = parseFeatureLayerUrl(layerUrl);
|
|
151
|
+
const layer = new FeatureLayerCompat({ url: layerUrl, client, title: item.title, id: item.id });
|
|
152
|
+
return {
|
|
153
|
+
type: "feature-service",
|
|
154
|
+
item,
|
|
155
|
+
baseUrl: parsed.baseUrl,
|
|
156
|
+
serviceId: parsed.serviceId,
|
|
157
|
+
layerId: parsed.layerId,
|
|
158
|
+
client,
|
|
159
|
+
layer,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
if (isImageService(item.type, serviceUrl)) {
|
|
163
|
+
const parsed = parseImageServiceUrl(serviceUrl);
|
|
164
|
+
const client = this.buildAuthenticatedClient(parsed.baseUrl);
|
|
165
|
+
return { type: "image-service", item, baseUrl: parsed.baseUrl, serviceId: parsed.serviceId, client };
|
|
166
|
+
}
|
|
167
|
+
const parsed = parseMapServiceUrl(serviceUrl);
|
|
168
|
+
const client = this.buildAuthenticatedClient(parsed.baseUrl);
|
|
169
|
+
return { type: "map-service", item, baseUrl: parsed.baseUrl, serviceId: parsed.serviceId, client };
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Register the currently held token with the shared {@link identityManager}
|
|
173
|
+
* under this portal's `/sharing/rest` server, so subsequent esri-compat calls
|
|
174
|
+
* resolve the same credential.
|
|
175
|
+
*/
|
|
176
|
+
registerWithIdentityManager() {
|
|
177
|
+
if (!this.token) {
|
|
178
|
+
throw new PortalError("PortalCompat has no token to register; call generateToken first.");
|
|
179
|
+
}
|
|
180
|
+
identityManager.registerToken({
|
|
181
|
+
server: this.sharingRestBase,
|
|
182
|
+
token: this.token,
|
|
183
|
+
...(this.tokenExpiresAtMs !== undefined ? { expires: this.tokenExpiresAtMs } : {}),
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
buildAuthenticatedClient(baseUrl) {
|
|
187
|
+
const interceptors = [];
|
|
188
|
+
if (this.token) {
|
|
189
|
+
interceptors.push(createArcGisTokenInterceptor({ getToken: () => this.token }));
|
|
190
|
+
}
|
|
191
|
+
return new HonuaClient({
|
|
192
|
+
baseUrl,
|
|
193
|
+
fetchFn: this.fetchFn,
|
|
194
|
+
...(this.apiKey ? { apiKey: this.apiKey } : {}),
|
|
195
|
+
...(interceptors.length > 0 ? { interceptors } : {}),
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
async getJson(path, params, token) {
|
|
199
|
+
const query = new URLSearchParams();
|
|
200
|
+
query.set("f", "json");
|
|
201
|
+
for (const [key, value] of Object.entries(params)) {
|
|
202
|
+
if (value !== undefined && value !== null && value !== "") {
|
|
203
|
+
query.set(key, String(value));
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (token) {
|
|
207
|
+
query.set("token", token);
|
|
208
|
+
}
|
|
209
|
+
const response = await this.fetchFn(`${this.sharingRestBase}${path}?${query.toString()}`);
|
|
210
|
+
const json = (await response.json());
|
|
211
|
+
throwIfEsriError(json, `Portal request to ${path} failed.`);
|
|
212
|
+
return json;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
function normalizeSharingRestBase(portalUrl) {
|
|
216
|
+
const trimmed = trimTrailingSlashes(portalUrl);
|
|
217
|
+
if (/\/sharing\/rest$/i.test(trimmed)) {
|
|
218
|
+
return trimmed;
|
|
219
|
+
}
|
|
220
|
+
return `${trimmed}/sharing/rest`;
|
|
221
|
+
}
|
|
222
|
+
function trimTrailingSlashes(value) {
|
|
223
|
+
let end = value.length;
|
|
224
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47) {
|
|
225
|
+
end--;
|
|
226
|
+
}
|
|
227
|
+
return value.slice(0, end);
|
|
228
|
+
}
|
|
229
|
+
function defaultReferer(sharingRestBase) {
|
|
230
|
+
if (globalThis.location?.origin) {
|
|
231
|
+
return globalThis.location.origin;
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
return new URL(sharingRestBase).origin;
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function isFeatureService(type, serviceUrl) {
|
|
241
|
+
return /feature\s*service/i.test(type) || /\/FeatureServer(\/\d+)?$/i.test(serviceUrl);
|
|
242
|
+
}
|
|
243
|
+
function isImageService(type, serviceUrl) {
|
|
244
|
+
return /image\s*service/i.test(type) || /\/ImageServer(\/\d+)?$/i.test(serviceUrl);
|
|
245
|
+
}
|
|
246
|
+
function throwIfEsriError(json, fallbackMessage) {
|
|
247
|
+
if (json && typeof json === "object" && json.error) {
|
|
248
|
+
const { code, message, details } = json.error;
|
|
249
|
+
throw new PortalError(message ?? fallbackMessage, code, details);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridges the esri-compat renderer shims to the first-class renderer objects
|
|
3
|
+
* in `@honua/sdk-js/style` (issue #497 REQ-002). The compat classes stay
|
|
4
|
+
* pure state holders; these helpers project their state through the same
|
|
5
|
+
* WebMap symbol/renderer conversion path the WebMap converter uses, so the
|
|
6
|
+
* SDK has exactly one class-breaks/unique-value implementation.
|
|
7
|
+
*
|
|
8
|
+
* Kept out of the compat classes themselves so consumers who never emit
|
|
9
|
+
* renderer objects do not pay for the conversion pipeline.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import type { ClassBreaksRenderer, UniqueValueRenderer } from "../style/renderers.js";
|
|
14
|
+
import type { WarningCollector } from "../webmap/warnings.js";
|
|
15
|
+
import type { ClassBreaksRendererCompat } from "./class-breaks-renderer.js";
|
|
16
|
+
import type { UniqueValueRendererCompat } from "./unique-value-renderer.js";
|
|
17
|
+
/** Result of projecting a compat renderer to a renderer object. @experimental */
|
|
18
|
+
export interface CompatRendererProjection<R> {
|
|
19
|
+
/** The emitted renderer object, or `undefined` when nothing was convertible. */
|
|
20
|
+
readonly renderer: R | undefined;
|
|
21
|
+
/** Symbol/renderer conversion warnings collected during projection. */
|
|
22
|
+
readonly warnings: WarningCollector["warnings"];
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Emit a first-class {@link ClassBreaksRenderer} from a
|
|
26
|
+
* `ClassBreaksRendererCompat` shim. Compat `minValue`/`maxValue` map to the
|
|
27
|
+
* WebMap `classMinValue`/`classMaxValue` fields and symbols convert through
|
|
28
|
+
* the shared WebMap symbol pipeline.
|
|
29
|
+
*
|
|
30
|
+
* @experimental
|
|
31
|
+
*/
|
|
32
|
+
export declare function rendererObjectFromClassBreaksCompat(compat: ClassBreaksRendererCompat): CompatRendererProjection<ClassBreaksRenderer>;
|
|
33
|
+
/**
|
|
34
|
+
* Emit a first-class {@link UniqueValueRenderer} from a
|
|
35
|
+
* `UniqueValueRendererCompat` shim.
|
|
36
|
+
*
|
|
37
|
+
* @experimental
|
|
38
|
+
*/
|
|
39
|
+
export declare function rendererObjectFromUniqueValueCompat(compat: UniqueValueRendererCompat): CompatRendererProjection<UniqueValueRenderer>;
|
|
40
|
+
//# sourceMappingURL=renderer-objects.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renderer-objects.d.ts","sourceRoot":"","sources":["../../../src/esri-compat/renderer-objects.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAGtF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAE5E,iFAAiF;AACjF,MAAM,WAAW,wBAAwB,CAAC,CAAC;IACzC,gFAAgF;IAChF,QAAQ,CAAC,QAAQ,EAAE,CAAC,GAAG,SAAS,CAAC;IACjC,uEAAuE;IACvE,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC,UAAU,CAAC,CAAC;CACjD;AAED;;;;;;;GAOG;AACH,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,yBAAyB,GAChC,wBAAwB,CAAC,mBAAmB,CAAC,CAmB/C;AAED;;;;;GAKG;AACH,wBAAgB,mCAAmC,CACjD,MAAM,EAAE,yBAAyB,GAChC,wBAAwB,CAAC,mBAAmB,CAAC,CAmB/C"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridges the esri-compat renderer shims to the first-class renderer objects
|
|
3
|
+
* in `@honua/sdk-js/style` (issue #497 REQ-002). The compat classes stay
|
|
4
|
+
* pure state holders; these helpers project their state through the same
|
|
5
|
+
* WebMap symbol/renderer conversion path the WebMap converter uses, so the
|
|
6
|
+
* SDK has exactly one class-breaks/unique-value implementation.
|
|
7
|
+
*
|
|
8
|
+
* Kept out of the compat classes themselves so consumers who never emit
|
|
9
|
+
* renderer objects do not pay for the conversion pipeline.
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
import { classBreaksRendererFromWebMap, uniqueValueRendererFromWebMap } from "../webmap/convert-renderer.js";
|
|
14
|
+
import { createWarningCollector } from "../webmap/warnings.js";
|
|
15
|
+
/**
|
|
16
|
+
* Emit a first-class {@link ClassBreaksRenderer} from a
|
|
17
|
+
* `ClassBreaksRendererCompat` shim. Compat `minValue`/`maxValue` map to the
|
|
18
|
+
* WebMap `classMinValue`/`classMaxValue` fields and symbols convert through
|
|
19
|
+
* the shared WebMap symbol pipeline.
|
|
20
|
+
*
|
|
21
|
+
* @experimental
|
|
22
|
+
*/
|
|
23
|
+
export function rendererObjectFromClassBreaksCompat(compat) {
|
|
24
|
+
const warn = createWarningCollector();
|
|
25
|
+
const renderer = classBreaksRendererFromWebMap({
|
|
26
|
+
type: "classBreaks",
|
|
27
|
+
field: compat.field,
|
|
28
|
+
minValue: compat.minValue,
|
|
29
|
+
defaultSymbol: compat.defaultSymbol,
|
|
30
|
+
defaultLabel: compat.defaultLabel,
|
|
31
|
+
classBreakInfos: compat.classBreakInfos.map((info) => ({
|
|
32
|
+
classMinValue: info.minValue,
|
|
33
|
+
classMaxValue: info.maxValue,
|
|
34
|
+
label: info.label,
|
|
35
|
+
symbol: info.symbol,
|
|
36
|
+
})),
|
|
37
|
+
}, warn);
|
|
38
|
+
return { renderer, warnings: warn.warnings };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Emit a first-class {@link UniqueValueRenderer} from a
|
|
42
|
+
* `UniqueValueRendererCompat` shim.
|
|
43
|
+
*
|
|
44
|
+
* @experimental
|
|
45
|
+
*/
|
|
46
|
+
export function rendererObjectFromUniqueValueCompat(compat) {
|
|
47
|
+
const warn = createWarningCollector();
|
|
48
|
+
const renderer = uniqueValueRendererFromWebMap({
|
|
49
|
+
type: "uniqueValue",
|
|
50
|
+
field1: compat.field,
|
|
51
|
+
field2: compat.field2,
|
|
52
|
+
field3: compat.field3,
|
|
53
|
+
defaultSymbol: compat.defaultSymbol,
|
|
54
|
+
defaultLabel: compat.defaultLabel,
|
|
55
|
+
uniqueValueInfos: compat.uniqueValueInfos.map((info) => ({
|
|
56
|
+
value: info.value,
|
|
57
|
+
label: info.label,
|
|
58
|
+
symbol: info.symbol,
|
|
59
|
+
})),
|
|
60
|
+
}, warn);
|
|
61
|
+
return { renderer, warnings: warn.warnings };
|
|
62
|
+
}
|
package/esri-compat/sketch.d.ts
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
|
+
import type { EditSketchTool } from "../contract/edit-sketch.js";
|
|
2
|
+
import type { SnappingConfig } from "../contract/edit-snapping.js";
|
|
1
3
|
import { CompatEventBus } from "./event-bus.js";
|
|
4
|
+
import { type SnappingOptionsCompat } from "./snapping.js";
|
|
2
5
|
export type SketchCreationModeCompat = "single" | "update" | "continuous";
|
|
3
6
|
export type SketchToolCompat = "point" | "polyline" | "polygon" | "rectangle" | "circle";
|
|
7
|
+
/**
|
|
8
|
+
* Duck-typed subset of the runtime terra-draw sketch handle
|
|
9
|
+
* (`bindTerraDrawSketch` / `createTerraDrawSketch` from
|
|
10
|
+
* `@honua/sdk-js/runtime`) that the Sketch shim can delegate tool modes to.
|
|
11
|
+
* Structural on purpose: the compat layer never imports the optional
|
|
12
|
+
* terra-draw peer, it only feature-detects a binding the app wired up.
|
|
13
|
+
*
|
|
14
|
+
* @experimental
|
|
15
|
+
*/
|
|
16
|
+
export interface SketchToolBindingCompat {
|
|
17
|
+
setTool(tool: EditSketchTool): unknown;
|
|
18
|
+
select?(): void;
|
|
19
|
+
cancel?(): void;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Feature-detect a terra-draw sketch binding: any object exposing a callable
|
|
23
|
+
* `setTool` qualifies; anything else (including `undefined` when terra-draw
|
|
24
|
+
* is not installed) resolves to `undefined` and the shim keeps its current
|
|
25
|
+
* headless behavior.
|
|
26
|
+
*
|
|
27
|
+
* @experimental
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveSketchToolBindingCompat(value: unknown): SketchToolBindingCompat | undefined;
|
|
4
30
|
export interface SketchCreateOptionsCompat {
|
|
5
31
|
mode?: "click" | "freehand" | "hybrid";
|
|
6
32
|
}
|
|
@@ -20,6 +46,15 @@ export interface SketchCompatOptions {
|
|
|
20
46
|
creationMode?: SketchCreationModeCompat;
|
|
21
47
|
defaultCreateOptions?: Partial<SketchCreateOptionsCompat>;
|
|
22
48
|
defaultUpdateOptions?: Partial<SketchUpdateOptionsCompat>;
|
|
49
|
+
snappingOptions?: SnappingOptionsCompat;
|
|
50
|
+
/**
|
|
51
|
+
* Optional terra-draw sketch binding (see {@link SketchToolBindingCompat}).
|
|
52
|
+
* When present, `create`/`update`/`cancel`/`reset` delegate tool-mode
|
|
53
|
+
* changes to the binding; otherwise the shim keeps its headless behavior.
|
|
54
|
+
*
|
|
55
|
+
* @experimental
|
|
56
|
+
*/
|
|
57
|
+
sketchBinding?: unknown;
|
|
23
58
|
}
|
|
24
59
|
export interface SketchCreateResultCompat {
|
|
25
60
|
state: "complete" | "cancel";
|
|
@@ -46,8 +81,16 @@ export declare class SketchCompat {
|
|
|
46
81
|
activeCreateOptions: Partial<SketchCreateOptionsCompat> | undefined;
|
|
47
82
|
activeUpdateGraphics: Record<string, unknown>[];
|
|
48
83
|
activeUpdateOptions: Partial<SketchUpdateOptionsCompat> | undefined;
|
|
84
|
+
snappingOptions: SnappingOptionsCompat;
|
|
49
85
|
private readonly watchListeners;
|
|
86
|
+
private readonly sketchBinding;
|
|
50
87
|
constructor(options?: SketchCompatOptions);
|
|
88
|
+
/** Whether tool modes delegate to a terra-draw sketch binding. @experimental */
|
|
89
|
+
delegatesToSketchBinding(): boolean;
|
|
90
|
+
/** Replace the ArcGIS-shaped snapping options and notify watchers. */
|
|
91
|
+
setSnappingOptions(options: SnappingOptionsCompat): void;
|
|
92
|
+
/** The snapping options mapped onto the contract `SnappingConfig`. */
|
|
93
|
+
snappingConfig(): SnappingConfig;
|
|
51
94
|
load(): Promise<SketchCompat>;
|
|
52
95
|
when(callback?: (widget: SketchCompat) => void): Promise<SketchCompat>;
|
|
53
96
|
watch(propertyName: string, listener: (value: unknown) => void): SketchHandleCompat;
|