@honua/react 0.1.0-beta.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 +11 -2
- package/contract/index.d.ts.map +1 -1
- package/contract/index.js +4 -1
- package/contract/pmtiles.d.ts +31 -0
- package/contract/pmtiles.d.ts.map +1 -1
- package/contract/pmtiles.js +60 -20
- package/contract/protocol-module.d.ts +70 -0
- package/contract/protocol-module.d.ts.map +1 -0
- package/contract/protocol-module.js +1 -0
- package/contract/schema-envelope.d.ts +26 -0
- package/contract/schema-envelope.d.ts.map +1 -0
- package/contract/schema-envelope.js +25 -0
- package/contract/schema.d.ts +582 -0
- package/contract/schema.d.ts.map +1 -0
- package/contract/schema.js +2483 -0
- package/contract/source-capability-support.d.ts +6 -0
- package/contract/source-capability-support.d.ts.map +1 -0
- package/contract/source-capability-support.js +154 -0
- package/contract/source.d.ts +35 -17
- package/contract/source.d.ts.map +1 -1
- package/contract/source.js +267 -71
- package/contract/types.d.ts +140 -4
- package/contract/types.d.ts.map +1 -1
- package/contract/types.js +6 -14
- package/core/bounded-json.d.ts +4 -0
- package/core/bounded-json.d.ts.map +1 -0
- package/core/bounded-json.js +38 -0
- package/core/cache-state.d.ts +9 -0
- package/core/cache-state.d.ts.map +1 -1
- package/core/cache-state.js +10 -0
- package/core/capabilities-xml.d.ts +33 -0
- package/core/capabilities-xml.d.ts.map +1 -0
- package/core/capabilities-xml.js +331 -0
- package/core/client.d.ts +4 -1
- package/core/client.d.ts.map +1 -1
- package/core/client.js +115 -29
- package/core/error-classifications.d.ts +153 -0
- package/core/error-classifications.d.ts.map +1 -0
- package/core/error-classifications.js +140 -0
- package/core/error-code-registry.d.ts +158 -0
- package/core/error-code-registry.d.ts.map +1 -0
- package/core/error-code-registry.js +143 -0
- package/core/error-envelope.d.ts +68 -0
- package/core/error-envelope.d.ts.map +1 -0
- package/core/error-envelope.js +357 -0
- package/core/errors.d.ts +45 -29
- package/core/errors.d.ts.map +1 -1
- package/core/errors.js +97 -50
- package/core/geoparquet-sql.d.ts +30 -2
- package/core/geoparquet-sql.d.ts.map +1 -1
- package/core/geoparquet-sql.js +38 -3
- package/core/odata-key-path.d.ts +12 -0
- package/core/odata-key-path.d.ts.map +1 -0
- package/core/odata-key-path.js +28 -0
- package/core/odata-write-codec.d.ts +66 -0
- package/core/odata-write-codec.d.ts.map +1 -0
- package/core/odata-write-codec.js +1083 -0
- package/core/odata.d.ts +59 -7
- package/core/odata.d.ts.map +1 -1
- package/core/odata.js +431 -99
- package/core/ogc-features.d.ts.map +1 -1
- package/core/ogc-features.js +3 -0
- package/core/ogc-maps.d.ts +7 -0
- package/core/ogc-maps.d.ts.map +1 -1
- package/core/ogc-maps.js +46 -7
- package/core/ogc-processes.d.ts +2 -1
- package/core/ogc-processes.d.ts.map +1 -1
- package/core/ogc-processes.js +33 -5
- package/core/ogc-records.d.ts +9 -0
- package/core/ogc-records.d.ts.map +1 -1
- package/core/ogc-records.js +78 -29
- package/core/ogc-tiles.d.ts +10 -1
- package/core/ogc-tiles.d.ts.map +1 -1
- package/core/ogc-tiles.js +56 -17
- package/core/path-utils.d.ts +9 -0
- package/core/path-utils.d.ts.map +1 -1
- package/core/path-utils.js +19 -0
- package/core/protocol-transport.d.ts +1 -0
- package/core/protocol-transport.d.ts.map +1 -1
- package/core/request-pipeline.d.ts.map +1 -1
- package/core/request-pipeline.js +1 -1
- package/core/spatial-filter.d.ts +8 -4
- package/core/spatial-filter.d.ts.map +1 -1
- package/core/spatial-filter.js +206 -16
- package/core/stac-static.d.ts +6 -2
- package/core/stac-static.d.ts.map +1 -1
- package/core/stac-static.js +260 -69
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +69 -5
- package/core/types.d.ts +125 -7
- package/core/types.d.ts.map +1 -1
- package/core/wfs-capabilities.d.ts +2 -0
- package/core/wfs-capabilities.d.ts.map +1 -1
- package/core/wfs-capabilities.js +8 -1
- package/core/wfs.d.ts.map +1 -1
- package/core/wfs.js +10 -0
- package/core/wms-capabilities.d.ts +56 -84
- package/core/wms-capabilities.d.ts.map +1 -1
- package/core/wms-capabilities.js +212 -509
- package/core/wmts-capabilities.d.ts +62 -62
- package/core/wmts-capabilities.d.ts.map +1 -1
- package/core/wmts-capabilities.js +224 -371
- package/esri-compat/editor.d.ts +8 -0
- package/esri-compat/editor.d.ts.map +1 -1
- package/esri-compat/editor.js +13 -0
- package/esri-compat/feature-layer.d.ts +2 -0
- package/esri-compat/feature-layer.d.ts.map +1 -1
- package/esri-compat/feature-layer.js +1 -0
- package/esri-compat/layer-list.d.ts +11 -0
- package/esri-compat/layer-list.d.ts.map +1 -1
- package/esri-compat/layer-list.js +49 -0
- package/esri-compat/legend.d.ts +10 -0
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +27 -0
- package/esri-compat/portal.d.ts +197 -0
- package/esri-compat/portal.d.ts.map +1 -0
- package/esri-compat/portal.js +251 -0
- package/esri-compat/renderer-objects.d.ts +40 -0
- package/esri-compat/renderer-objects.d.ts.map +1 -0
- package/esri-compat/renderer-objects.js +62 -0
- package/esri-compat/sketch.d.ts +43 -0
- package/esri-compat/sketch.d.ts.map +1 -1
- package/esri-compat/sketch.js +46 -0
- package/esri-compat/snapping.d.ts +43 -0
- package/esri-compat/snapping.d.ts.map +1 -0
- package/esri-compat/snapping.js +45 -0
- package/esri-compat/url.d.ts.map +1 -1
- package/esri-compat/url.js +1 -1
- package/esri-compat/widget-host.d.ts +84 -0
- package/esri-compat/widget-host.d.ts.map +1 -0
- package/esri-compat/widget-host.js +159 -0
- package/filter-registry/index.d.ts +145 -0
- package/filter-registry/index.d.ts.map +1 -0
- package/filter-registry/index.js +531 -0
- package/generated-app/errors.d.ts +18 -2
- package/generated-app/errors.d.ts.map +1 -1
- package/generated-app/errors.js +44 -11
- package/map/automatic-mount-integration.d.ts +134 -0
- package/map/automatic-mount-integration.d.ts.map +1 -0
- package/map/automatic-mount-integration.js +305 -0
- package/map/automatic-source-strategy.d.ts +125 -0
- package/map/automatic-source-strategy.d.ts.map +1 -0
- package/map/automatic-source-strategy.js +494 -0
- package/map/data-to-map-bridge.d.ts +293 -0
- package/map/data-to-map-bridge.d.ts.map +1 -0
- package/map/data-to-map-bridge.js +817 -0
- package/map/geojson-projection.d.ts +33 -0
- package/map/geojson-projection.d.ts.map +1 -0
- package/map/geojson-projection.js +118 -0
- package/map/index.d.ts +14 -0
- package/map/index.d.ts.map +1 -1
- package/map/index.js +8 -0
- package/map/raster-source-spec.d.ts +30 -0
- package/map/raster-source-spec.d.ts.map +1 -0
- package/map/raster-source-spec.js +190 -0
- package/map/raster-source-strategy.d.ts +65 -0
- package/map/raster-source-strategy.d.ts.map +1 -0
- package/map/raster-source-strategy.js +232 -0
- package/map/source-to-maplibre.d.ts +91 -0
- package/map/source-to-maplibre.d.ts.map +1 -0
- package/map/source-to-maplibre.js +454 -0
- package/map/temporal-playback.d.ts +139 -0
- package/map/temporal-playback.d.ts.map +1 -0
- package/map/temporal-playback.js +247 -0
- package/package.json +14 -1
- package/query-planner/canonical.d.ts +7 -0
- package/query-planner/canonical.d.ts.map +1 -0
- package/query-planner/canonical.js +145 -0
- package/query-planner/cql2-json.d.ts +17 -0
- package/query-planner/cql2-json.d.ts.map +1 -0
- package/query-planner/cql2-json.js +646 -0
- package/query-planner/diagnostics.d.ts +35 -0
- package/query-planner/diagnostics.d.ts.map +1 -0
- package/query-planner/diagnostics.js +373 -0
- package/query-planner/duckdb.d.ts +79 -0
- package/query-planner/duckdb.d.ts.map +1 -0
- package/query-planner/duckdb.js +758 -0
- package/query-planner/execution-context.d.ts +5 -0
- package/query-planner/execution-context.d.ts.map +1 -0
- package/query-planner/execution-context.js +50 -0
- package/query-planner/executor.d.ts +5 -0
- package/query-planner/executor.d.ts.map +1 -0
- package/query-planner/executor.js +223 -0
- package/query-planner/geoservices.d.ts +91 -0
- package/query-planner/geoservices.d.ts.map +1 -0
- package/query-planner/geoservices.js +667 -0
- package/query-planner/grpc.d.ts +100 -0
- package/query-planner/grpc.d.ts.map +1 -0
- package/query-planner/grpc.js +736 -0
- package/query-planner/index.d.ts +44 -0
- package/query-planner/index.d.ts.map +1 -0
- package/query-planner/index.js +30 -0
- package/query-planner/ir.d.ts +20 -0
- package/query-planner/ir.d.ts.map +1 -0
- package/query-planner/ir.js +417 -0
- package/query-planner/local-aggregate.d.ts +5 -0
- package/query-planner/local-aggregate.d.ts.map +1 -0
- package/query-planner/local-aggregate.js +126 -0
- package/query-planner/odata.d.ts +48 -0
- package/query-planner/odata.d.ts.map +1 -0
- package/query-planner/odata.js +662 -0
- package/query-planner/ogc-compiler.d.ts +55 -0
- package/query-planner/ogc-compiler.d.ts.map +1 -0
- package/query-planner/ogc-compiler.js +480 -0
- package/query-planner/ogc-features.d.ts +53 -0
- package/query-planner/ogc-features.d.ts.map +1 -0
- package/query-planner/ogc-features.js +617 -0
- package/query-planner/planner.d.ts +17 -0
- package/query-planner/planner.d.ts.map +1 -0
- package/query-planner/planner.js +818 -0
- package/query-planner/resource.d.ts +94 -0
- package/query-planner/resource.d.ts.map +1 -0
- package/query-planner/resource.js +526 -0
- package/query-planner/semantic-canonical.d.ts +15 -0
- package/query-planner/semantic-canonical.d.ts.map +1 -0
- package/query-planner/semantic-canonical.js +62 -0
- package/query-planner/semantic-compat.d.ts +10 -0
- package/query-planner/semantic-compat.d.ts.map +1 -0
- package/query-planner/semantic-compat.js +35 -0
- package/query-planner/semantic-compiler.d.ts +64 -0
- package/query-planner/semantic-compiler.d.ts.map +1 -0
- package/query-planner/semantic-compiler.js +81 -0
- package/query-planner/semantic-literals.d.ts +30 -0
- package/query-planner/semantic-literals.d.ts.map +1 -0
- package/query-planner/semantic-literals.js +133 -0
- package/query-planner/semantic-types.d.ts +265 -0
- package/query-planner/semantic-types.d.ts.map +1 -0
- package/query-planner/semantic-types.js +1 -0
- package/query-planner/semantic.d.ts +54 -0
- package/query-planner/semantic.d.ts.map +1 -0
- package/query-planner/semantic.js +1421 -0
- package/query-planner/types.d.ts +560 -0
- package/query-planner/types.d.ts.map +1 -0
- package/query-planner/types.js +49 -0
- package/query-planner/wfs-semantic.d.ts +58 -0
- package/query-planner/wfs-semantic.d.ts.map +1 -0
- package/query-planner/wfs-semantic.js +547 -0
- package/query-planner/wfs.d.ts +6 -0
- package/query-planner/wfs.d.ts.map +1 -0
- package/query-planner/wfs.js +71 -0
- package/react/external-map.d.ts +67 -0
- package/react/external-map.d.ts.map +1 -0
- package/react/external-map.js +63 -0
- package/react/honua-map.d.ts.map +1 -1
- package/react/honua-map.js +3 -2
- package/react/honua-source-layer.d.ts +110 -0
- package/react/honua-source-layer.d.ts.map +1 -0
- package/react/honua-source-layer.js +101 -0
- package/react/hooks.d.ts +28 -0
- package/react/hooks.d.ts.map +1 -1
- package/react/hooks.js +26 -4
- package/react/index.d.ts +8 -0
- package/react/index.d.ts.map +1 -1
- package/react/index.js +5 -0
- package/react/query-cache.d.ts +26 -4
- package/react/query-cache.d.ts.map +1 -1
- package/react/query-cache.js +51 -8
- package/react/selection.d.ts +177 -0
- package/react/selection.d.ts.map +1 -0
- package/react/selection.js +0 -0
- package/react/use-mounted-source.d.ts +69 -0
- package/react/use-mounted-source.d.ts.map +1 -0
- package/react/use-mounted-source.js +346 -0
- package/runtime/edit-snapping.d.ts +107 -0
- package/runtime/edit-snapping.d.ts.map +1 -0
- package/runtime/edit-snapping.js +190 -0
- package/runtime/errors.d.ts +3 -2
- package/runtime/errors.d.ts.map +1 -1
- package/runtime/errors.js +19 -2
- package/runtime/index.d.ts +6 -0
- package/runtime/index.d.ts.map +1 -1
- package/runtime/index.js +3 -0
- package/runtime/maplibre-renderer.d.ts +41 -0
- package/runtime/maplibre-renderer.d.ts.map +1 -0
- package/runtime/maplibre-renderer.js +322 -0
- package/runtime/query-tiles.d.ts +2 -1
- package/runtime/query-tiles.d.ts.map +1 -1
- package/runtime/query-tiles.js +6 -2
- package/runtime/source-bridge.d.ts +4 -4
- package/runtime/source-bridge.d.ts.map +1 -1
- package/runtime/source-bridge.js +9 -56
- package/runtime/style-interactions.d.ts +3 -2
- package/runtime/style-interactions.d.ts.map +1 -1
- package/runtime/style-interactions.js +11 -3
- package/runtime/terra-draw-sketch.d.ts +275 -0
- package/runtime/terra-draw-sketch.d.ts.map +1 -0
- package/runtime/terra-draw-sketch.js +404 -0
- package/source-capability-registry.d.ts +1 -0
- package/source-capability-registry.js +1 -0
- package/source-capability-types.d.ts +186 -0
- package/source-capability-types.js +7 -0
- package/style/index.d.ts +2 -0
- package/style/index.d.ts.map +1 -1
- package/style/index.js +2 -0
- package/style/renderers.d.ts +326 -0
- package/style/renderers.d.ts.map +1 -0
- package/style/renderers.js +517 -0
- package/webmap/convert-renderer.d.ts +24 -3
- package/webmap/convert-renderer.d.ts.map +1 -1
- package/webmap/convert-renderer.js +93 -112
- package/webmap/index.d.ts +1 -1
- package/webmap/index.d.ts.map +1 -1
- package/webmap/index.js +1 -1
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/** Discriminant for versioned, serializable query resource handles. */
|
|
2
|
+
export declare const QUERY_RESOURCE_HANDLE_KIND: "honua.query-resource";
|
|
3
|
+
/** First opaque query resource handle format. */
|
|
4
|
+
export declare const QUERY_RESOURCE_HANDLE_VERSION: "1.0";
|
|
5
|
+
/** Credential-free resolver identity embedded in a GeoParquet resource handle. */
|
|
6
|
+
export interface GeoParquetResolverResourceReferenceV1 {
|
|
7
|
+
readonly kind: "resolver";
|
|
8
|
+
/** Canonical lowercase reverse-DNS resolver identifier. */
|
|
9
|
+
readonly resolver: string;
|
|
10
|
+
/** Stable logical resource id. It must never be derived from a credential. */
|
|
11
|
+
readonly id: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Serializable identity for a GeoParquet resource whose private locator is
|
|
15
|
+
* supplied only at execution time.
|
|
16
|
+
*/
|
|
17
|
+
export interface GeoParquetResourceHandleV1 {
|
|
18
|
+
readonly kind: typeof QUERY_RESOURCE_HANDLE_KIND;
|
|
19
|
+
readonly version: typeof QUERY_RESOURCE_HANDLE_VERSION;
|
|
20
|
+
readonly protocol: "geoparquet";
|
|
21
|
+
readonly resource: GeoParquetResolverResourceReferenceV1;
|
|
22
|
+
/** Stable, non-secret authorization partition id; never a token or credential. */
|
|
23
|
+
readonly authorizationContextId: string;
|
|
24
|
+
/** Data revision/validator identity. Credential rotation must not change it. */
|
|
25
|
+
readonly resourceVersion?: string;
|
|
26
|
+
}
|
|
27
|
+
/** Ephemeral raw GeoParquet addressing returned at the trusted execution boundary. */
|
|
28
|
+
export interface ResolvedGeoParquetResource {
|
|
29
|
+
/**
|
|
30
|
+
* One to 64 values, each at most 16 KiB UTF-8 and at most 128 KiB in
|
|
31
|
+
* aggregate. Never persist, log, fingerprint, or place them in a query plan.
|
|
32
|
+
*/
|
|
33
|
+
readonly sources: readonly string[];
|
|
34
|
+
}
|
|
35
|
+
/** Per-execution authorization and cancellation state supplied to a resolver. */
|
|
36
|
+
export interface GeoParquetResourceResolutionContext {
|
|
37
|
+
/** Must exactly match the stable, non-secret partition id in the handle. */
|
|
38
|
+
readonly authorizationContextId: string;
|
|
39
|
+
readonly signal?: AbortSignal;
|
|
40
|
+
}
|
|
41
|
+
/** Injected, lifecycle-scoped GeoParquet locator resolver. */
|
|
42
|
+
export type GeoParquetResourceResolver = (handle: GeoParquetResourceHandleV1, context: GeoParquetResourceResolutionContext) => ResolvedGeoParquetResource | Promise<ResolvedGeoParquetResource>;
|
|
43
|
+
/** Input used to register or atomically replace one private resource locator. */
|
|
44
|
+
export interface RegisterGeoParquetResourceInput {
|
|
45
|
+
readonly id: string;
|
|
46
|
+
readonly authorizationContextId: string;
|
|
47
|
+
readonly resourceVersion?: string;
|
|
48
|
+
/** Private addressing subject to the same fixed bounds as resolved sources. */
|
|
49
|
+
readonly sources: readonly string[];
|
|
50
|
+
/** Private Unix epoch deadline in milliseconds; expiry occurs at `now >= expiresAt`. */
|
|
51
|
+
readonly expiresAt?: number;
|
|
52
|
+
}
|
|
53
|
+
/** Stable identity input for a handle whose private locator is registered elsewhere. */
|
|
54
|
+
export interface CreateGeoParquetResourceHandleInput {
|
|
55
|
+
readonly resolver: string;
|
|
56
|
+
readonly id: string;
|
|
57
|
+
readonly authorizationContextId: string;
|
|
58
|
+
readonly resourceVersion?: string;
|
|
59
|
+
}
|
|
60
|
+
/** Options for an ephemeral, in-memory resolver registry. */
|
|
61
|
+
export interface GeoParquetResourceRegistryOptions {
|
|
62
|
+
/** Canonical lowercase reverse-DNS resolver identifier embedded in handles. */
|
|
63
|
+
readonly resolver: string;
|
|
64
|
+
/** May tighten, but never raise, the SDK's hard 4,096-entry ceiling. */
|
|
65
|
+
readonly maxEntries?: number;
|
|
66
|
+
/** Injectable finite Unix epoch millisecond clock for lifecycle control and tests. */
|
|
67
|
+
readonly now?: () => number;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Lifecycle-scoped private resource registry. This is isolation, not encrypted
|
|
71
|
+
* storage: call `dispose()` when the owning client/session ends.
|
|
72
|
+
*/
|
|
73
|
+
export interface GeoParquetResourceRegistry {
|
|
74
|
+
register(input: RegisterGeoParquetResourceInput): GeoParquetResourceHandleV1;
|
|
75
|
+
readonly resolver: GeoParquetResourceResolver;
|
|
76
|
+
/** Idempotently removes a handle without revealing whether it existed. */
|
|
77
|
+
revoke(handle: GeoParquetResourceHandleV1): void;
|
|
78
|
+
/** Idempotently clears every private locator and closes the registry. */
|
|
79
|
+
dispose(): void;
|
|
80
|
+
}
|
|
81
|
+
/** Create a credential-free handle without registering or resolving a locator. */
|
|
82
|
+
export declare function createGeoParquetResourceHandle(input: CreateGeoParquetResourceHandleInput): GeoParquetResourceHandleV1;
|
|
83
|
+
/** Parse an exact v1 handle without invoking accessors or retaining rejected input. */
|
|
84
|
+
export declare function parseGeoParquetResourceHandle(value: unknown): GeoParquetResourceHandleV1;
|
|
85
|
+
/** Stable credential-free fingerprint for plan/cache identity. */
|
|
86
|
+
export declare function hashGeoParquetResourceHandle(value: unknown): `sha256:${string}`;
|
|
87
|
+
/**
|
|
88
|
+
* Resolve a handle through an injected resolver after enforcing scope,
|
|
89
|
+
* cancellation, output bounds, and fixed-message error redaction.
|
|
90
|
+
*/
|
|
91
|
+
export declare function resolveGeoParquetResource(value: unknown, resolver: GeoParquetResourceResolver, context: GeoParquetResourceResolutionContext): Promise<ResolvedGeoParquetResource>;
|
|
92
|
+
/** Create a bounded in-memory registry for private, rotation-friendly locators. */
|
|
93
|
+
export declare function createGeoParquetResourceRegistry(options: GeoParquetResourceRegistryOptions): GeoParquetResourceRegistry;
|
|
94
|
+
//# sourceMappingURL=resource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resource.d.ts","sourceRoot":"","sources":["../../../src/query-planner/resource.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,526 @@
|
|
|
1
|
+
import { HonuaAbortError } from "../core/errors.js";
|
|
2
|
+
import { canonicalStringify, sha256, toJsonValue } from "./canonical.js";
|
|
3
|
+
import { HonuaQueryPlanExecutionError } from "./types.js";
|
|
4
|
+
/** Discriminant for versioned, serializable query resource handles. */
|
|
5
|
+
export const QUERY_RESOURCE_HANDLE_KIND = "honua.query-resource";
|
|
6
|
+
/** First opaque query resource handle format. */
|
|
7
|
+
export const QUERY_RESOURCE_HANDLE_VERSION = "1.0";
|
|
8
|
+
const DEFAULT_MAX_ENTRIES = 256;
|
|
9
|
+
const HARD_MAX_ENTRIES = 4_096;
|
|
10
|
+
const MAX_SOURCE_COUNT = 64;
|
|
11
|
+
const MAX_SOURCE_BYTES = 16_384;
|
|
12
|
+
const MAX_TOTAL_SOURCE_BYTES = 131_072;
|
|
13
|
+
const MAX_RESOLVER_LENGTH = 255;
|
|
14
|
+
const MAX_IDENTITY_LENGTH = 256;
|
|
15
|
+
const EXTENSION_IDENTIFIER_PATTERN = /^[a-z0-9](?:[a-z0-9_-]*\.)+[a-z0-9][a-z0-9_-]*$/;
|
|
16
|
+
const RESOURCE_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:~-]*$/;
|
|
17
|
+
const AUTHORIZATION_CONTEXT_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/~-]*$/;
|
|
18
|
+
const JWT_SHAPE = /^eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}$/;
|
|
19
|
+
const INVALID_HANDLE_MESSAGE = "GeoParquet resource handle is invalid";
|
|
20
|
+
const RESOURCE_UNAVAILABLE_MESSAGE = "GeoParquet resource is unavailable";
|
|
21
|
+
const RESOURCE_EXPIRED_MESSAGE = "GeoParquet resource authorization has expired";
|
|
22
|
+
const RESOLUTION_FAILED_MESSAGE = "GeoParquet resource resolution failed";
|
|
23
|
+
const INVALID_REGISTRY_OPTIONS_MESSAGE = "GeoParquet resource registry options are invalid";
|
|
24
|
+
const INVALID_REGISTRATION_MESSAGE = "GeoParquet resource registration is invalid";
|
|
25
|
+
const EXPIRED_ENTRY = Object.freeze({ state: "expired" });
|
|
26
|
+
/** Create a credential-free handle without registering or resolving a locator. */
|
|
27
|
+
export function createGeoParquetResourceHandle(input) {
|
|
28
|
+
const parsed = inspectRecord(input, ["resolver", "id", "authorizationContextId"], ["resourceVersion"]);
|
|
29
|
+
if (!parsed)
|
|
30
|
+
throw invalidHandle();
|
|
31
|
+
return parseGeoParquetResourceHandle({
|
|
32
|
+
kind: QUERY_RESOURCE_HANDLE_KIND,
|
|
33
|
+
version: QUERY_RESOURCE_HANDLE_VERSION,
|
|
34
|
+
protocol: "geoparquet",
|
|
35
|
+
resource: {
|
|
36
|
+
kind: "resolver",
|
|
37
|
+
resolver: parsed.get("resolver"),
|
|
38
|
+
id: parsed.get("id"),
|
|
39
|
+
},
|
|
40
|
+
authorizationContextId: parsed.get("authorizationContextId"),
|
|
41
|
+
...(parsed.has("resourceVersion") ? { resourceVersion: parsed.get("resourceVersion") } : {}),
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/** Parse an exact v1 handle without invoking accessors or retaining rejected input. */
|
|
45
|
+
export function parseGeoParquetResourceHandle(value) {
|
|
46
|
+
const parsed = inspectRecord(value, ["kind", "version", "protocol", "resource", "authorizationContextId"], ["resourceVersion"]);
|
|
47
|
+
if (!parsed)
|
|
48
|
+
throw invalidHandle();
|
|
49
|
+
const resource = inspectRecord(parsed.get("resource"), ["kind", "resolver", "id"]);
|
|
50
|
+
const resolver = resource?.get("resolver");
|
|
51
|
+
const id = resource?.get("id");
|
|
52
|
+
const authorizationContextId = parsed.get("authorizationContextId");
|
|
53
|
+
const resourceVersion = parsed.get("resourceVersion");
|
|
54
|
+
const hasResourceVersion = parsed.has("resourceVersion");
|
|
55
|
+
if (parsed.get("kind") !== QUERY_RESOURCE_HANDLE_KIND ||
|
|
56
|
+
parsed.get("version") !== QUERY_RESOURCE_HANDLE_VERSION ||
|
|
57
|
+
parsed.get("protocol") !== "geoparquet" ||
|
|
58
|
+
resource?.get("kind") !== "resolver" ||
|
|
59
|
+
!isResolverIdentifier(resolver) ||
|
|
60
|
+
!isResourceIdentity(id) ||
|
|
61
|
+
!isAuthorizationContextId(authorizationContextId)) {
|
|
62
|
+
throw invalidHandle();
|
|
63
|
+
}
|
|
64
|
+
let normalizedResourceVersion;
|
|
65
|
+
if (hasResourceVersion) {
|
|
66
|
+
if (!isResourceIdentity(resourceVersion))
|
|
67
|
+
throw invalidHandle();
|
|
68
|
+
normalizedResourceVersion = resourceVersion;
|
|
69
|
+
}
|
|
70
|
+
return freezeHandle({
|
|
71
|
+
resource: { resolver, id },
|
|
72
|
+
authorizationContextId,
|
|
73
|
+
...(normalizedResourceVersion !== undefined ? { resourceVersion: normalizedResourceVersion } : {}),
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
/** Stable credential-free fingerprint for plan/cache identity. */
|
|
77
|
+
export function hashGeoParquetResourceHandle(value) {
|
|
78
|
+
const handle = parseGeoParquetResourceHandle(value);
|
|
79
|
+
return sha256(canonicalStringify(toJsonValue(handle)));
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Resolve a handle through an injected resolver after enforcing scope,
|
|
83
|
+
* cancellation, output bounds, and fixed-message error redaction.
|
|
84
|
+
*/
|
|
85
|
+
export async function resolveGeoParquetResource(value, resolver, context) {
|
|
86
|
+
const handle = parseGeoParquetResourceHandle(value);
|
|
87
|
+
const safeContext = parseResolutionContext(context);
|
|
88
|
+
if (typeof resolver !== "function")
|
|
89
|
+
throw resolutionFailed();
|
|
90
|
+
if (isSignalAborted(safeContext.signal))
|
|
91
|
+
throw new HonuaAbortError();
|
|
92
|
+
if (safeContext.authorizationContextId !== handle.authorizationContextId)
|
|
93
|
+
throw resourceUnavailable();
|
|
94
|
+
let pending;
|
|
95
|
+
try {
|
|
96
|
+
pending = resolver(handle, safeContext);
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
throw normalizeResolverFailure(error, safeContext.signal);
|
|
100
|
+
}
|
|
101
|
+
let resolved;
|
|
102
|
+
try {
|
|
103
|
+
resolved = await awaitAbortable(pending, safeContext.signal);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
throw normalizeResolverFailure(error, safeContext.signal);
|
|
107
|
+
}
|
|
108
|
+
const output = inspectRecord(resolved, ["sources"]);
|
|
109
|
+
const sources = output ? copyBoundedSources(output.get("sources")) : undefined;
|
|
110
|
+
if (!sources)
|
|
111
|
+
throw resolutionFailed();
|
|
112
|
+
return Object.freeze({ sources });
|
|
113
|
+
}
|
|
114
|
+
/** Create a bounded in-memory registry for private, rotation-friendly locators. */
|
|
115
|
+
export function createGeoParquetResourceRegistry(options) {
|
|
116
|
+
const parsedOptions = inspectRecord(options, ["resolver"], ["maxEntries", "now"]);
|
|
117
|
+
const resolverId = parsedOptions?.get("resolver");
|
|
118
|
+
const configuredMaxEntries = parsedOptions?.get("maxEntries");
|
|
119
|
+
const configuredNow = parsedOptions?.get("now");
|
|
120
|
+
if (!parsedOptions ||
|
|
121
|
+
!isResolverIdentifier(resolverId) ||
|
|
122
|
+
(configuredMaxEntries !== undefined && !isMaxEntries(configuredMaxEntries)) ||
|
|
123
|
+
(configuredNow !== undefined && !isClock(configuredNow))) {
|
|
124
|
+
throw new TypeError(INVALID_REGISTRY_OPTIONS_MESSAGE);
|
|
125
|
+
}
|
|
126
|
+
const maxEntries = configuredMaxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
127
|
+
const now = configuredNow ?? Date.now;
|
|
128
|
+
const entries = new Map();
|
|
129
|
+
let disposed = false;
|
|
130
|
+
let readingClock = false;
|
|
131
|
+
const readCurrentTime = () => {
|
|
132
|
+
if (readingClock)
|
|
133
|
+
throw resolutionFailed();
|
|
134
|
+
readingClock = true;
|
|
135
|
+
try {
|
|
136
|
+
return readClock(now);
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
readingClock = false;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const resolver = (handleValue, contextValue) => {
|
|
143
|
+
const handle = parseGeoParquetResourceHandle(handleValue);
|
|
144
|
+
const context = parseResolutionContext(contextValue);
|
|
145
|
+
if (isSignalAborted(context.signal))
|
|
146
|
+
throw new HonuaAbortError();
|
|
147
|
+
if (context.authorizationContextId !== handle.authorizationContextId ||
|
|
148
|
+
handle.resource.resolver !== resolverId ||
|
|
149
|
+
disposed) {
|
|
150
|
+
throw resourceUnavailable();
|
|
151
|
+
}
|
|
152
|
+
const key = resourceKey(handle);
|
|
153
|
+
const entry = entries.get(key);
|
|
154
|
+
if (!entry)
|
|
155
|
+
throw resourceUnavailable();
|
|
156
|
+
if (entry.state === "expired")
|
|
157
|
+
throw resourceExpired();
|
|
158
|
+
if (entry.expiresAt !== undefined) {
|
|
159
|
+
const currentTime = readCurrentTime();
|
|
160
|
+
if (disposed || entries.get(key) !== entry)
|
|
161
|
+
throw resourceUnavailable();
|
|
162
|
+
if (currentTime >= entry.expiresAt) {
|
|
163
|
+
entries.set(key, EXPIRED_ENTRY);
|
|
164
|
+
throw resourceExpired();
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
return Object.freeze({ sources: entry.sources });
|
|
168
|
+
};
|
|
169
|
+
const registry = {
|
|
170
|
+
register(input) {
|
|
171
|
+
if (disposed)
|
|
172
|
+
throw resourceUnavailable();
|
|
173
|
+
const registration = parseRegistration(input);
|
|
174
|
+
const handle = freezeHandle({
|
|
175
|
+
resource: { resolver: resolverId, id: registration.id },
|
|
176
|
+
authorizationContextId: registration.authorizationContextId,
|
|
177
|
+
...(registration.resourceVersion !== undefined ? { resourceVersion: registration.resourceVersion } : {}),
|
|
178
|
+
});
|
|
179
|
+
const key = resourceKey(handle);
|
|
180
|
+
if (!entries.has(key) && entries.size >= maxEntries)
|
|
181
|
+
reclaimExpiredEntries(entries, maxEntries);
|
|
182
|
+
if (!entries.has(key) && entries.size >= maxEntries && hasExpiringEntries(entries)) {
|
|
183
|
+
const snapshot = [...entries.entries()];
|
|
184
|
+
const currentTime = readCurrentTime();
|
|
185
|
+
if (disposed || !entriesMatchSnapshot(entries, snapshot))
|
|
186
|
+
throw resourceUnavailable();
|
|
187
|
+
reclaimExpiredEntries(entries, maxEntries, currentTime);
|
|
188
|
+
}
|
|
189
|
+
if (!entries.has(key) && entries.size >= maxEntries)
|
|
190
|
+
throw resourceUnavailable();
|
|
191
|
+
entries.set(key, Object.freeze({
|
|
192
|
+
state: "active",
|
|
193
|
+
sources: registration.sources,
|
|
194
|
+
...(registration.expiresAt !== undefined ? { expiresAt: registration.expiresAt } : {}),
|
|
195
|
+
}));
|
|
196
|
+
return handle;
|
|
197
|
+
},
|
|
198
|
+
resolver,
|
|
199
|
+
revoke(handleValue) {
|
|
200
|
+
const handle = parseGeoParquetResourceHandle(handleValue);
|
|
201
|
+
if (handle.resource.resolver === resolverId)
|
|
202
|
+
entries.delete(resourceKey(handle));
|
|
203
|
+
},
|
|
204
|
+
dispose() {
|
|
205
|
+
if (disposed)
|
|
206
|
+
return;
|
|
207
|
+
disposed = true;
|
|
208
|
+
entries.clear();
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
return Object.freeze(registry);
|
|
212
|
+
}
|
|
213
|
+
function parseRegistration(input) {
|
|
214
|
+
const parsed = inspectRecord(input, ["id", "authorizationContextId", "sources"], ["resourceVersion", "expiresAt"]);
|
|
215
|
+
const id = parsed?.get("id");
|
|
216
|
+
const authorizationContextId = parsed?.get("authorizationContextId");
|
|
217
|
+
const resourceVersion = parsed?.get("resourceVersion");
|
|
218
|
+
const expiresAt = parsed?.get("expiresAt");
|
|
219
|
+
const sources = parsed ? copyBoundedSources(parsed.get("sources")) : undefined;
|
|
220
|
+
if (!parsed ||
|
|
221
|
+
!isResourceIdentity(id) ||
|
|
222
|
+
!isAuthorizationContextId(authorizationContextId) ||
|
|
223
|
+
(resourceVersion !== undefined && !isResourceIdentity(resourceVersion)) ||
|
|
224
|
+
(expiresAt !== undefined && !isEpochMilliseconds(expiresAt)) ||
|
|
225
|
+
!sources) {
|
|
226
|
+
throw new TypeError(INVALID_REGISTRATION_MESSAGE);
|
|
227
|
+
}
|
|
228
|
+
return {
|
|
229
|
+
id,
|
|
230
|
+
authorizationContextId,
|
|
231
|
+
...(resourceVersion !== undefined ? { resourceVersion } : {}),
|
|
232
|
+
sources,
|
|
233
|
+
...(expiresAt !== undefined ? { expiresAt } : {}),
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function parseResolutionContext(value) {
|
|
237
|
+
const parsed = inspectRecord(value, ["authorizationContextId"], ["signal"]);
|
|
238
|
+
const authorizationContextId = parsed?.get("authorizationContextId");
|
|
239
|
+
const signal = parsed?.get("signal");
|
|
240
|
+
if (!parsed ||
|
|
241
|
+
!isAuthorizationContextId(authorizationContextId) ||
|
|
242
|
+
(signal !== undefined && !isAbortSignal(signal))) {
|
|
243
|
+
throw resourceUnavailable();
|
|
244
|
+
}
|
|
245
|
+
return Object.freeze({
|
|
246
|
+
authorizationContextId,
|
|
247
|
+
...(signal !== undefined ? { signal } : {}),
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
function freezeHandle(input) {
|
|
251
|
+
const resource = Object.freeze({
|
|
252
|
+
kind: "resolver",
|
|
253
|
+
resolver: input.resource.resolver,
|
|
254
|
+
id: input.resource.id,
|
|
255
|
+
});
|
|
256
|
+
return Object.freeze({
|
|
257
|
+
kind: QUERY_RESOURCE_HANDLE_KIND,
|
|
258
|
+
version: QUERY_RESOURCE_HANDLE_VERSION,
|
|
259
|
+
protocol: "geoparquet",
|
|
260
|
+
resource,
|
|
261
|
+
authorizationContextId: input.authorizationContextId,
|
|
262
|
+
...(input.resourceVersion !== undefined ? { resourceVersion: input.resourceVersion } : {}),
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
function resourceKey(handle) {
|
|
266
|
+
return canonicalStringify(toJsonValue([
|
|
267
|
+
handle.resource.resolver,
|
|
268
|
+
handle.resource.id,
|
|
269
|
+
handle.authorizationContextId,
|
|
270
|
+
handle.resourceVersion ?? null,
|
|
271
|
+
]));
|
|
272
|
+
}
|
|
273
|
+
function reclaimExpiredEntries(entries, maxEntries, currentTime) {
|
|
274
|
+
for (const [key, entry] of entries) {
|
|
275
|
+
if (entry.state === "expired" ||
|
|
276
|
+
(currentTime !== undefined && entry.expiresAt !== undefined && currentTime >= entry.expiresAt)) {
|
|
277
|
+
entries.delete(key);
|
|
278
|
+
}
|
|
279
|
+
if (entries.size < maxEntries)
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function hasExpiringEntries(entries) {
|
|
284
|
+
for (const entry of entries.values()) {
|
|
285
|
+
if (entry.state === "active" && entry.expiresAt !== undefined)
|
|
286
|
+
return true;
|
|
287
|
+
}
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
function entriesMatchSnapshot(entries, snapshot) {
|
|
291
|
+
return entries.size === snapshot.length && snapshot.every(([key, entry]) => entries.get(key) === entry);
|
|
292
|
+
}
|
|
293
|
+
function inspectRecord(value, requiredKeys, optionalKeys = []) {
|
|
294
|
+
try {
|
|
295
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
296
|
+
return undefined;
|
|
297
|
+
const prototype = Object.getPrototypeOf(value);
|
|
298
|
+
if (prototype !== Object.prototype && prototype !== null)
|
|
299
|
+
return undefined;
|
|
300
|
+
const keys = Reflect.ownKeys(value);
|
|
301
|
+
if (keys.some((key) => typeof key !== "string"))
|
|
302
|
+
return undefined;
|
|
303
|
+
const allowed = new Set([...requiredKeys, ...optionalKeys]);
|
|
304
|
+
if (keys.length < requiredKeys.length || keys.length > allowed.size)
|
|
305
|
+
return undefined;
|
|
306
|
+
if (keys.some((key) => typeof key !== "string" || !allowed.has(key)))
|
|
307
|
+
return undefined;
|
|
308
|
+
const result = new Map();
|
|
309
|
+
for (const key of requiredKeys) {
|
|
310
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
311
|
+
if (!descriptor || !descriptor.enumerable || !("value" in descriptor))
|
|
312
|
+
return undefined;
|
|
313
|
+
result.set(key, descriptor.value);
|
|
314
|
+
}
|
|
315
|
+
for (const key of optionalKeys) {
|
|
316
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
317
|
+
if (!descriptor)
|
|
318
|
+
continue;
|
|
319
|
+
if (!descriptor.enumerable || !("value" in descriptor))
|
|
320
|
+
return undefined;
|
|
321
|
+
result.set(key, descriptor.value);
|
|
322
|
+
}
|
|
323
|
+
return result;
|
|
324
|
+
}
|
|
325
|
+
catch {
|
|
326
|
+
return undefined;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function copyBoundedSources(value) {
|
|
330
|
+
try {
|
|
331
|
+
if (!Array.isArray(value) || Object.getPrototypeOf(value) !== Array.prototype)
|
|
332
|
+
return undefined;
|
|
333
|
+
const lengthDescriptor = Object.getOwnPropertyDescriptor(value, "length");
|
|
334
|
+
const length = lengthDescriptor && "value" in lengthDescriptor ? lengthDescriptor.value : undefined;
|
|
335
|
+
if (typeof length !== "number" || !Number.isInteger(length) || length < 1 || length > MAX_SOURCE_COUNT) {
|
|
336
|
+
return undefined;
|
|
337
|
+
}
|
|
338
|
+
const keys = Reflect.ownKeys(value);
|
|
339
|
+
if (keys.length !== length + 1 || keys.some((key) => typeof key !== "string"))
|
|
340
|
+
return undefined;
|
|
341
|
+
if (keys.some((key) => typeof key === "string" && key !== "length" && !isArrayIndex(key, length))) {
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
344
|
+
let totalBytes = 0;
|
|
345
|
+
const copy = [];
|
|
346
|
+
for (let index = 0; index < length; index++) {
|
|
347
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
348
|
+
if (!descriptor || !descriptor.enumerable || !("value" in descriptor))
|
|
349
|
+
return undefined;
|
|
350
|
+
const source = descriptor.value;
|
|
351
|
+
if (typeof source !== "string" ||
|
|
352
|
+
source.length === 0 ||
|
|
353
|
+
source.length > MAX_SOURCE_BYTES ||
|
|
354
|
+
containsControlCharacter(source)) {
|
|
355
|
+
return undefined;
|
|
356
|
+
}
|
|
357
|
+
const bytes = new TextEncoder().encode(source).byteLength;
|
|
358
|
+
if (bytes > MAX_SOURCE_BYTES)
|
|
359
|
+
return undefined;
|
|
360
|
+
totalBytes += bytes;
|
|
361
|
+
if (totalBytes > MAX_TOTAL_SOURCE_BYTES)
|
|
362
|
+
return undefined;
|
|
363
|
+
copy.push(source);
|
|
364
|
+
}
|
|
365
|
+
return Object.freeze(copy);
|
|
366
|
+
}
|
|
367
|
+
catch {
|
|
368
|
+
return undefined;
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
function isArrayIndex(key, length) {
|
|
372
|
+
if (!/^(?:0|[1-9][0-9]*)$/.test(key))
|
|
373
|
+
return false;
|
|
374
|
+
const index = Number(key);
|
|
375
|
+
return Number.isSafeInteger(index) && index >= 0 && index < length;
|
|
376
|
+
}
|
|
377
|
+
function containsControlCharacter(value) {
|
|
378
|
+
for (let index = 0; index < value.length; index++) {
|
|
379
|
+
const code = value.charCodeAt(index);
|
|
380
|
+
if (code <= 0x1f || code === 0x7f)
|
|
381
|
+
return true;
|
|
382
|
+
}
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
function isResolverIdentifier(value) {
|
|
386
|
+
return typeof value === "string" && value.length <= MAX_RESOLVER_LENGTH && EXTENSION_IDENTIFIER_PATTERN.test(value);
|
|
387
|
+
}
|
|
388
|
+
function isResourceIdentity(value) {
|
|
389
|
+
return (typeof value === "string" &&
|
|
390
|
+
value.length <= MAX_IDENTITY_LENGTH &&
|
|
391
|
+
RESOURCE_ID_PATTERN.test(value) &&
|
|
392
|
+
!JWT_SHAPE.test(value));
|
|
393
|
+
}
|
|
394
|
+
function isAuthorizationContextId(value) {
|
|
395
|
+
return (typeof value === "string" &&
|
|
396
|
+
value.length <= MAX_IDENTITY_LENGTH &&
|
|
397
|
+
AUTHORIZATION_CONTEXT_PATTERN.test(value) &&
|
|
398
|
+
!value.endsWith("/") &&
|
|
399
|
+
!value.includes("//") &&
|
|
400
|
+
!value.split("/").some((segment) => segment === "." || segment === "..") &&
|
|
401
|
+
!JWT_SHAPE.test(value));
|
|
402
|
+
}
|
|
403
|
+
function isMaxEntries(value) {
|
|
404
|
+
return typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= HARD_MAX_ENTRIES;
|
|
405
|
+
}
|
|
406
|
+
function isClock(value) {
|
|
407
|
+
return typeof value === "function";
|
|
408
|
+
}
|
|
409
|
+
function isEpochMilliseconds(value) {
|
|
410
|
+
return typeof value === "number" && Number.isFinite(value) && value >= 0;
|
|
411
|
+
}
|
|
412
|
+
function isAbortSignal(value) {
|
|
413
|
+
try {
|
|
414
|
+
return (value !== null &&
|
|
415
|
+
typeof value === "object" &&
|
|
416
|
+
typeof value.aborted === "boolean" &&
|
|
417
|
+
typeof value.addEventListener === "function" &&
|
|
418
|
+
typeof value.removeEventListener === "function");
|
|
419
|
+
}
|
|
420
|
+
catch {
|
|
421
|
+
return false;
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
function isSignalAborted(signal) {
|
|
425
|
+
try {
|
|
426
|
+
return signal?.aborted === true;
|
|
427
|
+
}
|
|
428
|
+
catch {
|
|
429
|
+
throw resolutionFailed();
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
function readClock(now) {
|
|
433
|
+
try {
|
|
434
|
+
const value = now();
|
|
435
|
+
if (!isEpochMilliseconds(value))
|
|
436
|
+
throw resolutionFailed();
|
|
437
|
+
return value;
|
|
438
|
+
}
|
|
439
|
+
catch {
|
|
440
|
+
throw resolutionFailed();
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function awaitAbortable(value, signal) {
|
|
444
|
+
const pending = Promise.resolve(value);
|
|
445
|
+
if (!signal)
|
|
446
|
+
return pending;
|
|
447
|
+
if (isSignalAborted(signal)) {
|
|
448
|
+
void pending.catch(() => undefined);
|
|
449
|
+
throw new HonuaAbortError();
|
|
450
|
+
}
|
|
451
|
+
return new Promise((resolve, reject) => {
|
|
452
|
+
let settled = false;
|
|
453
|
+
const finish = (callback) => {
|
|
454
|
+
if (settled)
|
|
455
|
+
return;
|
|
456
|
+
settled = true;
|
|
457
|
+
try {
|
|
458
|
+
signal.removeEventListener("abort", abort);
|
|
459
|
+
}
|
|
460
|
+
catch {
|
|
461
|
+
// The fixed failure below retains no foreign signal data.
|
|
462
|
+
}
|
|
463
|
+
callback();
|
|
464
|
+
};
|
|
465
|
+
const abort = () => finish(() => reject(new HonuaAbortError()));
|
|
466
|
+
try {
|
|
467
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
468
|
+
}
|
|
469
|
+
catch {
|
|
470
|
+
void pending.catch(() => undefined);
|
|
471
|
+
finish(() => reject(resolutionFailed()));
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
try {
|
|
475
|
+
if (isSignalAborted(signal)) {
|
|
476
|
+
abort();
|
|
477
|
+
void pending.catch(() => undefined);
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
catch (error) {
|
|
482
|
+
void pending.catch(() => undefined);
|
|
483
|
+
finish(() => reject(error));
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
pending.then((result) => finish(() => resolve(result)), (error) => finish(() => reject(error)));
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
function normalizeResolverFailure(error, signal) {
|
|
490
|
+
if (isSignalAborted(signal))
|
|
491
|
+
return new HonuaAbortError();
|
|
492
|
+
try {
|
|
493
|
+
if (error instanceof HonuaQueryPlanExecutionError) {
|
|
494
|
+
const code = ownDataProperty(error, "code");
|
|
495
|
+
if (code === "resource-unavailable")
|
|
496
|
+
return resourceUnavailable();
|
|
497
|
+
if (code === "resource-expired")
|
|
498
|
+
return resourceExpired();
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
catch {
|
|
502
|
+
// Proxy and cross-realm failures are projected to the same fixed error.
|
|
503
|
+
}
|
|
504
|
+
return resolutionFailed();
|
|
505
|
+
}
|
|
506
|
+
function ownDataProperty(value, key) {
|
|
507
|
+
try {
|
|
508
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
509
|
+
return descriptor && "value" in descriptor ? descriptor.value : undefined;
|
|
510
|
+
}
|
|
511
|
+
catch {
|
|
512
|
+
return undefined;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
function invalidHandle() {
|
|
516
|
+
return new HonuaQueryPlanExecutionError("invalid-resource-handle", INVALID_HANDLE_MESSAGE);
|
|
517
|
+
}
|
|
518
|
+
function resourceUnavailable() {
|
|
519
|
+
return new HonuaQueryPlanExecutionError("resource-unavailable", RESOURCE_UNAVAILABLE_MESSAGE);
|
|
520
|
+
}
|
|
521
|
+
function resourceExpired() {
|
|
522
|
+
return new HonuaQueryPlanExecutionError("resource-expired", RESOURCE_EXPIRED_MESSAGE);
|
|
523
|
+
}
|
|
524
|
+
function resolutionFailed() {
|
|
525
|
+
return new HonuaQueryPlanExecutionError("resource-resolution-failed", RESOLUTION_FAILED_MESSAGE);
|
|
526
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CanonicalSemanticQueryOptions } from "./semantic-types.js";
|
|
2
|
+
export declare const SEMANTIC_QUERY_CANONICAL_KIND: "honua.semantic-query-canonical";
|
|
3
|
+
export declare const SEMANTIC_QUERY_CANONICAL_VERSION: 1;
|
|
4
|
+
export declare const SEMANTIC_QUERY_HASH_DOMAIN: "honua.semantic-query.hash.v1";
|
|
5
|
+
/**
|
|
6
|
+
* Serialize a validated semantic query plus its schema/CRS/policy identity.
|
|
7
|
+
* Object keys are UTF-8 deterministically ordered; array order stays
|
|
8
|
+
* significant. Volatile execution state is not accepted by the semantic AST.
|
|
9
|
+
*/
|
|
10
|
+
export declare function serializeCanonicalSemanticQuery(value: unknown, options?: CanonicalSemanticQueryOptions): string;
|
|
11
|
+
/** Return a fresh UTF-8 byte copy of the canonical semantic-query envelope. */
|
|
12
|
+
export declare function canonicalSemanticQueryBytes(value: unknown, options?: CanonicalSemanticQueryOptions): Uint8Array;
|
|
13
|
+
/** Domain-separated SHA-256 identity for a canonical semantic query. */
|
|
14
|
+
export declare function hashSemanticQuery(value: unknown, options?: CanonicalSemanticQueryOptions): `sha256:${string}`;
|
|
15
|
+
//# sourceMappingURL=semantic-canonical.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic-canonical.d.ts","sourceRoot":"","sources":["../../../src/query-planner/semantic-canonical.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,qBAAqB,CAAC;AAIzE,eAAO,MAAM,6BAA6B,EAAG,gCAAyC,CAAC;AACvF,eAAO,MAAM,gCAAgC,EAAG,CAAU,CAAC;AAC3D,eAAO,MAAM,0BAA0B,EAAG,8BAAuC,CAAC;AAKlF;;;;GAIG;AACH,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,6BAAkC,GAAG,MAAM,CAoBnH;AAED,+EAA+E;AAC/E,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,6BAAkC,GAAG,UAAU,CAEnH;AAED,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,GAAE,6BAAkC,GAAG,UAAU,MAAM,EAAE,CAEjH"}
|