@honua/react 0.1.7-beta.0 → 0.1.10-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/control-plane/admin-client.d.ts +89 -0
- package/control-plane/admin-client.d.ts.map +1 -0
- package/control-plane/admin-client.js +200 -0
- package/control-plane/client.d.ts +1 -1
- package/control-plane/client.d.ts.map +1 -1
- package/control-plane/client.js +145 -11
- package/control-plane/commands/catalog.d.ts +133 -0
- package/control-plane/commands/catalog.d.ts.map +1 -0
- package/control-plane/commands/catalog.js +365 -0
- package/control-plane/commands/errors.d.ts +96 -0
- package/control-plane/commands/errors.d.ts.map +1 -0
- package/control-plane/commands/errors.js +130 -0
- package/control-plane/commands/identity.d.ts +71 -0
- package/control-plane/commands/identity.d.ts.map +1 -0
- package/control-plane/commands/identity.js +0 -0
- package/control-plane/commands/index.d.ts +39 -0
- package/control-plane/commands/index.d.ts.map +1 -0
- package/control-plane/commands/index.js +34 -0
- package/control-plane/commands/runtime.d.ts +146 -0
- package/control-plane/commands/runtime.d.ts.map +1 -0
- package/control-plane/commands/runtime.js +330 -0
- package/control-plane/commands/types.d.ts +228 -0
- package/control-plane/commands/types.d.ts.map +1 -0
- package/control-plane/commands/types.js +30 -0
- package/control-plane/commands/validate.d.ts +27 -0
- package/control-plane/commands/validate.d.ts.map +1 -0
- package/control-plane/commands/validate.js +132 -0
- package/control-plane/generated/admin-api.d.ts +30265 -0
- package/control-plane/generated/admin-api.d.ts.map +1 -0
- package/control-plane/generated/admin-api.js +5 -0
- package/control-plane/generated/admin-operations.d.ts +4053 -0
- package/control-plane/generated/admin-operations.d.ts.map +1 -0
- package/control-plane/generated/admin-operations.js +820 -0
- package/control-plane/index.d.ts +11 -0
- package/control-plane/index.d.ts.map +1 -1
- package/control-plane/index.js +8 -0
- package/control-plane/types.d.ts +14 -0
- package/control-plane/types.d.ts.map +1 -1
- package/core/client.d.ts.map +1 -1
- package/core/client.js +29 -31
- package/core/credential-redaction.d.ts +163 -0
- package/core/credential-redaction.d.ts.map +1 -0
- package/core/credential-redaction.js +389 -0
- package/core/error-classifications.d.ts +15 -0
- package/core/error-classifications.d.ts.map +1 -1
- package/core/error-classifications.js +15 -0
- package/core/error-code-registry.d.ts +15 -0
- package/core/error-code-registry.d.ts.map +1 -1
- package/core/error-code-registry.js +15 -0
- package/core/error-envelope.d.ts +31 -0
- package/core/error-envelope.d.ts.map +1 -1
- package/core/error-envelope.js +11 -0
- package/core/errors.d.ts +15 -3
- package/core/errors.d.ts.map +1 -1
- package/core/errors.js +254 -2
- package/core/geometry-input-sr.d.ts +3 -0
- package/core/geometry-input-sr.d.ts.map +1 -0
- package/core/geometry-input-sr.js +28 -0
- package/core/geoservices.d.ts.map +1 -1
- package/core/geoservices.js +33 -6
- package/core/grpc-adapter.d.ts +2 -2
- package/core/grpc-adapter.d.ts.map +1 -1
- package/core/grpc-adapter.js +41 -9
- package/core/job-run-errors.d.ts +10 -0
- package/core/job-run-errors.d.ts.map +1 -0
- package/core/job-run-errors.js +14 -0
- package/core/job-run-lifecycle.d.ts +34 -0
- package/core/job-run-lifecycle.d.ts.map +1 -0
- package/core/job-run-lifecycle.js +193 -0
- package/core/ogc-processes.d.ts +38 -31
- package/core/ogc-processes.d.ts.map +1 -1
- package/core/ogc-processes.js +123 -173
- package/core/pbf-decoder.d.ts.map +1 -1
- package/core/pbf-decoder.js +16 -4
- package/core/process-runner.js +15 -100
- package/core/protocol-transport.d.ts +6 -1
- package/core/protocol-transport.d.ts.map +1 -1
- package/core/request-pipeline.d.ts +6 -3
- package/core/request-pipeline.d.ts.map +1 -1
- package/core/request-pipeline.js +28 -11
- package/core/spatial-filter.d.ts +4 -4
- package/core/spatial-filter.d.ts.map +1 -1
- package/core/spatial-filter.js +7 -7
- package/core/surfaces.d.ts +2 -8
- package/core/surfaces.d.ts.map +1 -1
- package/core/surfaces.js +21 -112
- package/core/types.d.ts +21 -9
- package/core/types.d.ts.map +1 -1
- package/esri-compat/class-breaks-renderer.d.ts +2 -0
- package/esri-compat/class-breaks-renderer.d.ts.map +1 -1
- package/esri-compat/class-breaks-renderer.js +7 -0
- package/esri-compat/controls.d.ts +10 -1
- package/esri-compat/controls.d.ts.map +1 -1
- package/esri-compat/controls.js +86 -2
- package/esri-compat/directions.d.ts +35 -0
- package/esri-compat/directions.d.ts.map +1 -1
- package/esri-compat/directions.js +153 -2
- package/esri-compat/expand.d.ts +1 -0
- package/esri-compat/expand.d.ts.map +1 -1
- package/esri-compat/expand.js +61 -0
- package/esri-compat/feature-layer.d.ts +29 -4
- package/esri-compat/feature-layer.d.ts.map +1 -1
- package/esri-compat/feature-layer.js +335 -13
- package/esri-compat/geometry-engine.d.ts +4 -0
- package/esri-compat/geometry-engine.d.ts.map +1 -1
- package/esri-compat/geometry-engine.js +8 -1
- package/esri-compat/graphic.d.ts +7 -4
- package/esri-compat/graphic.d.ts.map +1 -1
- package/esri-compat/legend.d.ts +2 -1
- package/esri-compat/legend.d.ts.map +1 -1
- package/esri-compat/legend.js +15 -0
- package/esri-compat/map-view-mount.d.ts +48 -0
- package/esri-compat/map-view-mount.d.ts.map +1 -0
- package/esri-compat/map-view-mount.js +344 -0
- package/esri-compat/map-view.d.ts +38 -6
- package/esri-compat/map-view.d.ts.map +1 -1
- package/esri-compat/map-view.js +467 -33
- package/esri-compat/portal.d.ts +2 -0
- package/esri-compat/portal.d.ts.map +1 -1
- package/esri-compat/portal.js +7 -2
- package/esri-compat/renderer-objects.d.ts +7 -2
- package/esri-compat/renderer-objects.d.ts.map +1 -1
- package/esri-compat/renderer-objects.js +16 -5
- package/esri-compat/route-layer.d.ts +8 -0
- package/esri-compat/route-layer.d.ts.map +1 -1
- package/esri-compat/route-layer.js +24 -4
- package/esri-compat/route-task.d.ts +5 -1
- package/esri-compat/route-task.d.ts.map +1 -1
- package/esri-compat/route-task.js +119 -7
- package/esri-compat/scene-view.d.ts.map +1 -1
- package/esri-compat/scene-view.js +1 -0
- package/esri-compat/search.d.ts +2 -1
- package/esri-compat/search.d.ts.map +1 -1
- package/esri-compat/search.js +52 -2
- package/esri-compat/unique-value-renderer.d.ts +2 -0
- package/esri-compat/unique-value-renderer.d.ts.map +1 -1
- package/esri-compat/unique-value-renderer.js +7 -0
- package/esri-compat/web-map.d.ts +10 -0
- package/esri-compat/web-map.d.ts.map +1 -1
- package/esri-compat/web-map.js +102 -0
- package/gen/geospatial/v1/common_pb.d.ts +514 -0
- package/gen/geospatial/v1/common_pb.d.ts.map +1 -0
- package/gen/geospatial/v1/common_pb.js +335 -0
- package/gen/geospatial/v1/execution_types_pb.d.ts +1186 -0
- package/gen/geospatial/v1/execution_types_pb.d.ts.map +1 -0
- package/gen/geospatial/v1/execution_types_pb.js +396 -0
- package/gen/geospatial/v1/feature_service_pb.d.ts +403 -0
- package/gen/geospatial/v1/feature_service_pb.d.ts.map +1 -0
- package/gen/geospatial/v1/feature_service_pb.js +47 -0
- package/gen/geospatial/v1/index.d.ts +5 -0
- package/gen/geospatial/v1/index.d.ts.map +1 -0
- package/gen/geospatial/v1/index.js +9 -0
- package/gen/geospatial/v1/spatial_types_pb.d.ts +285 -0
- package/gen/geospatial/v1/spatial_types_pb.d.ts.map +1 -0
- package/gen/geospatial/v1/spatial_types_pb.js +58 -0
- package/gen/geospatial/v1/workspace_artifact_types_pb.d.ts +379 -0
- package/gen/geospatial/v1/workspace_artifact_types_pb.d.ts.map +1 -0
- package/gen/geospatial/v1/workspace_artifact_types_pb.js +151 -0
- package/generated-app/projection.d.ts.map +1 -1
- package/generated-app/projection.js +10 -1
- package/map/webmap-maplibre.d.ts +2 -1
- package/map/webmap-maplibre.d.ts.map +1 -1
- package/map/webmap-maplibre.js +3 -0
- package/package.json +3 -3
- package/query-planner/geoservices.d.ts.map +1 -1
- package/query-planner/geoservices.js +2 -0
- package/query-planner/grpc.d.ts +4 -4
- package/query-planner/grpc.d.ts.map +1 -1
- package/query-planner/grpc.js +11 -11
- package/query-planner/types.d.ts +6 -4
- package/query-planner/types.d.ts.map +1 -1
- package/realtime/honua-server.d.ts +4 -0
- package/realtime/honua-server.d.ts.map +1 -1
- package/realtime/honua-server.js +10 -0
- package/realtime/resumable.js +9 -0
- package/realtime/types.d.ts +8 -0
- package/realtime/types.d.ts.map +1 -1
- package/runtime/errors.d.ts +1 -1
- package/runtime/errors.d.ts.map +1 -1
- package/runtime/errors.js +2 -0
- package/runtime/generated/map-package-schema-meta.d.ts +11 -0
- package/runtime/generated/map-package-schema-meta.d.ts.map +1 -0
- package/runtime/generated/map-package-schema-meta.js +12 -0
- package/runtime/generated/map-package-schema-validator.d.ts +16 -0
- package/runtime/generated/map-package-schema-validator.d.ts.map +1 -0
- package/runtime/generated/map-package-schema-validator.js +1422 -0
- package/runtime/index.d.ts +5 -1
- package/runtime/index.d.ts.map +1 -1
- package/runtime/index.js +6 -0
- package/runtime/map-package-export.d.ts +151 -0
- package/runtime/map-package-export.d.ts.map +1 -0
- package/runtime/map-package-export.js +636 -0
- package/runtime/map-package-validation.d.ts +21 -1
- package/runtime/map-package-validation.d.ts.map +1 -1
- package/runtime/map-package-validation.js +132 -95
- package/runtime/map-package.d.ts +80 -0
- package/runtime/map-package.d.ts.map +1 -1
- package/studio/capability-manifest.d.ts +10 -0
- package/studio/capability-manifest.d.ts.map +1 -1
- package/studio/capability-manifest.js +38 -0
- package/studio/chart-spec.d.ts +6 -6
- package/studio/chart-spec.d.ts.map +1 -1
- package/studio/chart-spec.js +6 -6
- package/studio/command-adapter.d.ts +35 -0
- package/studio/command-adapter.d.ts.map +1 -0
- package/studio/command-adapter.js +36 -0
- package/studio/generated/studio-api.d.ts +1062 -0
- package/studio/generated/studio-api.d.ts.map +1 -0
- package/studio/generated/studio-api.js +4 -0
- package/studio/index.d.ts +25 -13
- package/studio/index.d.ts.map +1 -1
- package/studio/index.js +21 -10
- package/studio/lifecycle-client.d.ts +262 -22
- package/studio/lifecycle-client.d.ts.map +1 -1
- package/studio/lifecycle-client.js +543 -24
- package/studio/lifecycle-errors.d.ts +8 -2
- package/studio/lifecycle-errors.d.ts.map +1 -1
- package/studio/lifecycle-errors.js +6 -1
- package/studio/lifecycle-types.d.ts +237 -38
- package/studio/lifecycle-types.d.ts.map +1 -1
- package/studio/lifecycle-types.js +5 -12
- package/studio/publication-status.d.ts +55 -0
- package/studio/publication-status.d.ts.map +1 -0
- package/studio/publication-status.js +103 -0
- package/studio/types.d.ts +37 -7
- package/studio/types.d.ts.map +1 -1
- package/studio/types.js +5 -3
- package/studio/validate.d.ts.map +1 -1
- package/studio/validate.js +104 -7
- package/style/renderers.d.ts +6 -1
- package/style/renderers.d.ts.map +1 -1
- package/style/renderers.js +11 -6
- package/style/visual-variables.d.ts +43 -0
- package/style/visual-variables.d.ts.map +1 -0
- package/style/visual-variables.js +183 -0
- package/webmap/convert-layer.d.ts +2 -1
- package/webmap/convert-layer.d.ts.map +1 -1
- package/webmap/convert-layer.js +20 -3
- package/webmap/convert-renderer.d.ts +10 -3
- package/webmap/convert-renderer.d.ts.map +1 -1
- package/webmap/convert-renderer.js +190 -36
- package/webmap/index.d.ts +1 -0
- package/webmap/index.d.ts.map +1 -1
- package/webmap/parse.d.ts +2 -1
- package/webmap/parse.d.ts.map +1 -1
- package/webmap/parse.js +1 -1
- package/gen/honua/v1/feature_service_pb.d.ts +0 -918
- package/gen/honua/v1/feature_service_pb.d.ts.map +0 -1
- package/gen/honua/v1/feature_service_pb.js +0 -375
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential-recognition and redaction primitives shared by every Honua export
|
|
3
|
+
* pipeline.
|
|
4
|
+
*
|
|
5
|
+
* These were extracted verbatim from `src/web-components/export-redaction.ts`
|
|
6
|
+
* (issue #683) when the runtime's portable MapPackage export (#1426) needed the
|
|
7
|
+
* same scanner. There must be exactly one credential recognizer in this SDK: a
|
|
8
|
+
* second copy would drift, and the copy that drifts is the one that leaks. The
|
|
9
|
+
* web-components module re-exports every symbol below so its published surface
|
|
10
|
+
* is unchanged, and keeps the app-platform-specific state projection that
|
|
11
|
+
* layers on top of these primitives.
|
|
12
|
+
*
|
|
13
|
+
* This module lives in `src/core` rather than `src/web-components` because
|
|
14
|
+
* `src/runtime` ships in the stable-tier `@honua/sdk` split package while
|
|
15
|
+
* `src/web-components` ships in `@honua/app-platform`; the runtime cannot
|
|
16
|
+
* reach across that boundary (`scripts/prepare-split-packages.mjs`).
|
|
17
|
+
*
|
|
18
|
+
* Deliberately dependency-free apart from the SDK's shared error base: no
|
|
19
|
+
* `node:crypto`, no DOM, no renderer. Safe in a browser, a worker, or an SSR
|
|
20
|
+
* render pass.
|
|
21
|
+
*
|
|
22
|
+
* @module
|
|
23
|
+
*/
|
|
24
|
+
import { HonuaSdkError } from "./error-envelope.js";
|
|
25
|
+
/** Placeholder substituted for any value the export pipeline refuses to emit. */
|
|
26
|
+
export const HONUA_EXPORT_REDACTED = "[REDACTED]";
|
|
27
|
+
/** Thrown when the export pipeline cannot produce a provably credential-free artifact. */
|
|
28
|
+
export class HonuaExportSafetyError extends HonuaSdkError {
|
|
29
|
+
reason;
|
|
30
|
+
constructor(message, reason = "assertion") {
|
|
31
|
+
super("app.export-unsafe", message);
|
|
32
|
+
this.name = "HonuaExportSafetyError";
|
|
33
|
+
this.reason = reason;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// ── credential recognition ───────────────────────────────────────────────
|
|
37
|
+
/**
|
|
38
|
+
* Property names that are never exported, whatever their value. Matched
|
|
39
|
+
* case-insensitively against the whole key (substring match), so `apiKey`,
|
|
40
|
+
* `X-API-KEY`, `refresh_token`, and `sessionCookie` are all caught.
|
|
41
|
+
*
|
|
42
|
+
* The `<qualifier>Key` family is enumerated rather than reduced to a bare
|
|
43
|
+
* `key`: `key` alone would refuse `primaryKey`, `layerKey`, `sortKey`, and the
|
|
44
|
+
* MapLibre style spec's own `*-key` properties, and an exporter that withholds
|
|
45
|
+
* a table's primary key is not safer, only broken. The qualifiers listed here
|
|
46
|
+
* have no innocent reading — `adminKey` in particular is the property name this
|
|
47
|
+
* repository's own CLI configuration uses for the root administrator
|
|
48
|
+
* credential (`profiles.<name>.adminKey`), so it must never ride out of an
|
|
49
|
+
* export or a diagnostic bundle.
|
|
50
|
+
*/
|
|
51
|
+
const SENSITIVE_KEY = /(?:api[-_]?key|(?:access|admin|encryption|master|root|signing)[-_]?key|auth|bearer|cookie|credential|cred(?:s)?\b|jwt|nonce|pass(?:word|wd)?|private[-_]?key|pwd|secret|session|sig(?:nature)?|subscription[-_]?key|token)/i;
|
|
52
|
+
/** Property names that leak *authorization scope* rather than the secret itself. */
|
|
53
|
+
const AUTHORIZATION_SCOPE_KEY = /(?:^|[-_.])(?:scope|scopes|audience|aud|tenant|tenant[-_]?id|client[-_]?id|grant|grant[-_]?type|roles|permissions|principal|subject|assume[-_]?role)(?:$|[-_.])/i;
|
|
54
|
+
/** Query-parameter names that make a URL a *signed* URL (presigned S3/GCS/SAS/Esri/CDN). */
|
|
55
|
+
const SIGNED_QUERY_NAME = /(?:^|[-_])(?:sig|signature|token|access[-_]?token|id[-_]?token|refresh[-_]?token|api[-_]?key|apikey|key|subscription[-_]?key|code|password|pwd|auth|jwt|hmac|policy|credential|se|sp|sv|st|srt|ss|skoid|sktid|sig)(?:$|[-_])/i;
|
|
56
|
+
/**
|
|
57
|
+
* Free-text credential shapes. Every pattern is a linear scan over bounded
|
|
58
|
+
* character classes — no nested quantifiers, no backtracking traps (the repo's
|
|
59
|
+
* CodeQL ReDoS rule).
|
|
60
|
+
*/
|
|
61
|
+
const CREDENTIAL_PATTERNS = [
|
|
62
|
+
[/\b(?:Bearer|Basic|Digest|Negotiate)\s+[A-Za-z0-9._~+/=-]{8,}/gi, "[REDACTED_AUTH]"],
|
|
63
|
+
// `scheme://user:password@host` — basic-auth credentials embedded in a URL.
|
|
64
|
+
// `projectExportEndpoint` refuses these structurally, but a URL can also reach
|
|
65
|
+
// an export through an adapter's free-text error message, so the text scan has
|
|
66
|
+
// to recognize the same shape.
|
|
67
|
+
[/\b[a-z][a-z0-9+.-]{1,31}:\/\/[^\s/@:]{1,128}:[^\s/@]{1,128}@/gi, "[REDACTED_URL_CREDENTIALS]@"],
|
|
68
|
+
[/\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{4,}/g, "[REDACTED_JWT]"],
|
|
69
|
+
[/\bAKIA[0-9A-Z]{16}\b/g, "[REDACTED_AWS_KEY]"],
|
|
70
|
+
[/\bASIA[0-9A-Z]{16}\b/g, "[REDACTED_AWS_KEY]"],
|
|
71
|
+
[/\bAIza[0-9A-Za-z_-]{20,}/g, "[REDACTED_PROVIDER_TOKEN]"],
|
|
72
|
+
[/\bgh[pousr]_[A-Za-z0-9]{16,}/g, "[REDACTED_PROVIDER_TOKEN]"],
|
|
73
|
+
[/\bglpat-[A-Za-z0-9_-]{10,}/g, "[REDACTED_PROVIDER_TOKEN]"],
|
|
74
|
+
[/\bxox[baprs]-[A-Za-z0-9-]{8,}/gi, "[REDACTED_PROVIDER_TOKEN]"],
|
|
75
|
+
[/\b(?:sk|pk|rk)_(?:live|test)_[A-Za-z0-9]{8,}/gi, "[REDACTED_PROVIDER_TOKEN]"],
|
|
76
|
+
[/\bsk-[A-Za-z0-9]{16,}/g, "[REDACTED_PROVIDER_TOKEN]"],
|
|
77
|
+
// Labelled `name=value` / `name: value` pairs. The name alternation covers
|
|
78
|
+
// the short, provider-specific parameter names real signed URLs use — Azure
|
|
79
|
+
// SAS `sig`/`sv`/`se`/`st`, AWS/GCS `x-amz-signature`/`x-goog-signature`, and
|
|
80
|
+
// the bare `key` that tile providers favour — because those values are
|
|
81
|
+
// frequently *short* (a 24-character SAS signature is common) and so slip
|
|
82
|
+
// under any entropy heuristic. `\b` before each name keeps `turnkey=` and
|
|
83
|
+
// `monkey=` from matching.
|
|
84
|
+
[
|
|
85
|
+
/\b(access[-_]?key|admin[-_]?key|api[-_]?key|apikey|authorization|client[-_]?secret|cookie|credential|encryption[-_]?key|jwt|key|master[-_]?key|pass(?:password)?|password|pwd|root[-_]?key|se|secret|session|sig|signature|signing[-_]?key|st|subscription[-_]?key|sv|token|x-amz-[a-z-]{1,32}|x-goog-[a-z-]{1,32})\s*[:=]\s*(?:"[^"]{0,512}"|'[^']{0,512}'|[^\s&,;}"']{1,512})/gi,
|
|
86
|
+
`$1=${HONUA_EXPORT_REDACTED}`,
|
|
87
|
+
],
|
|
88
|
+
];
|
|
89
|
+
/**
|
|
90
|
+
* High-entropy blob heuristic, applied last so labelled matches win first.
|
|
91
|
+
*
|
|
92
|
+
* Deliberately excludes `/` and `-` from the character class. Including them
|
|
93
|
+
* made ordinary URL paths match — `arcgis/rest/services/Roads/FeatureServer/0`
|
|
94
|
+
* is 41 characters of `[A-Za-z0-9/]` and was being reported as a secret, which
|
|
95
|
+
* would have thrown away the endpoint an attribution block legitimately needs.
|
|
96
|
+
* Base64 blobs containing `/` still get caught: in practice they appear as a
|
|
97
|
+
* labelled parameter value or an `Authorization` header, both of which the
|
|
98
|
+
* patterns above match first.
|
|
99
|
+
*/
|
|
100
|
+
const OPAQUE_SECRET = /\b[A-Za-z0-9_+=]{40,}\b/g;
|
|
101
|
+
function decodePercentEncoding(value) {
|
|
102
|
+
let decoded = value;
|
|
103
|
+
for (let pass = 0; pass < 2; pass += 1) {
|
|
104
|
+
if (!decoded.includes("%"))
|
|
105
|
+
break;
|
|
106
|
+
let next;
|
|
107
|
+
try {
|
|
108
|
+
next = decodeURIComponent(decoded);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
113
|
+
if (next === decoded)
|
|
114
|
+
break;
|
|
115
|
+
decoded = next;
|
|
116
|
+
}
|
|
117
|
+
return decoded;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Redacts credential material from arbitrary human-readable text: adapter
|
|
121
|
+
* error messages, titles, status strings, log lines, event detail messages.
|
|
122
|
+
*
|
|
123
|
+
* Percent-encoded payloads are decoded (twice, bounded) before matching so a
|
|
124
|
+
* `%42earer%20abc` style evasion cannot slip a token past the scan; the
|
|
125
|
+
* returned string is the redacted *decoded* form when decoding changed
|
|
126
|
+
* anything, because emitting the still-encoded original would defeat the
|
|
127
|
+
* point.
|
|
128
|
+
*/
|
|
129
|
+
export function redactHonuaExportText(value) {
|
|
130
|
+
if (value.length === 0)
|
|
131
|
+
return value;
|
|
132
|
+
let redacted = decodePercentEncoding(value);
|
|
133
|
+
for (const [pattern, replacement] of CREDENTIAL_PATTERNS) {
|
|
134
|
+
redacted = redacted.replace(pattern, replacement);
|
|
135
|
+
}
|
|
136
|
+
return redacted.replace(OPAQUE_SECRET, "[REDACTED_TOKEN]");
|
|
137
|
+
}
|
|
138
|
+
/** Whether `value` still looks like it carries credential material. */
|
|
139
|
+
export function containsCredentialMaterial(value) {
|
|
140
|
+
return redactHonuaExportText(value) !== decodePercentEncoding(value);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Fail-closed assertion for finished export payloads (REQ-002). Throws
|
|
144
|
+
* {@link HonuaExportSafetyError} rather than scrubbing, because reaching this
|
|
145
|
+
* point with credential material means an earlier layer is broken.
|
|
146
|
+
*/
|
|
147
|
+
export function assertCredentialFreeExportText(value, label) {
|
|
148
|
+
if (containsCredentialMaterial(value)) {
|
|
149
|
+
throw new HonuaExportSafetyError(`${label} still contains credential material after redaction; refusing to emit the export.`, "assertion");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// ── binary artifact scanning ─────────────────────────────────────────────
|
|
153
|
+
/** Shortest printable run worth scanning. Below this it is structural noise, not text. */
|
|
154
|
+
const MIN_PRINTABLE_RUN = 4;
|
|
155
|
+
/** Printable text accumulated before a chunk is scanned and flushed. */
|
|
156
|
+
const PRINTABLE_CHUNK_BYTES = 1 << 20;
|
|
157
|
+
/**
|
|
158
|
+
* Characters carried between chunks so a token straddling a flush boundary is
|
|
159
|
+
* still matched. Comfortably longer than the longest pattern this module has.
|
|
160
|
+
*/
|
|
161
|
+
const PRINTABLE_CHUNK_OVERLAP = 512;
|
|
162
|
+
/**
|
|
163
|
+
* Extracts runs of printable ASCII from a binary buffer, joined by newlines.
|
|
164
|
+
*
|
|
165
|
+
* This is the `strings(1)` idea, and it exists because "binary" is not a
|
|
166
|
+
* security boundary. A PNG `tEXt`/`iTXt` chunk, a JPEG `COM` marker, PDF
|
|
167
|
+
* metadata or an embedded XMP packet, an EXIF `UserComment`, a ZIP comment —
|
|
168
|
+
* all carry plainly readable text inside a buffer that will never decode as
|
|
169
|
+
* UTF-8 as a whole. Scanning only whole-buffer-decodable artifacts would let a
|
|
170
|
+
* token ride out inside any of them.
|
|
171
|
+
*
|
|
172
|
+
* Runs shorter than {@link MIN_PRINTABLE_RUN} are dropped: they are the
|
|
173
|
+
* incidental byte values that fall in the ASCII range inside compressed data,
|
|
174
|
+
* and keeping them would produce noise without ever forming a credential.
|
|
175
|
+
*/
|
|
176
|
+
export function extractPrintableRuns(bytes, start = 0, end = bytes.byteLength) {
|
|
177
|
+
const runs = [];
|
|
178
|
+
let current = "";
|
|
179
|
+
for (let index = start; index < end; index += 1) {
|
|
180
|
+
const byte = bytes[index];
|
|
181
|
+
// Printable ASCII plus tab. Deliberately not the full latin-1 upper range:
|
|
182
|
+
// every credential shape this module recognizes is ASCII, and admitting
|
|
183
|
+
// 0x80-0xFF would turn arbitrary compressed data into "text".
|
|
184
|
+
if ((byte >= 0x20 && byte <= 0x7e) || byte === 0x09) {
|
|
185
|
+
current += String.fromCharCode(byte);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if (current.length >= MIN_PRINTABLE_RUN)
|
|
189
|
+
runs.push(current);
|
|
190
|
+
current = "";
|
|
191
|
+
}
|
|
192
|
+
if (current.length >= MIN_PRINTABLE_RUN)
|
|
193
|
+
runs.push(current);
|
|
194
|
+
return runs.join("\n");
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Fail-closed credential scan over a binary artifact (REQ-002).
|
|
198
|
+
*
|
|
199
|
+
* Scans in bounded chunks with an overlap, so an arbitrarily large artifact
|
|
200
|
+
* costs bounded memory while a token that straddles a chunk boundary is still
|
|
201
|
+
* caught. Throws {@link HonuaExportSafetyError} on a hit, like the text scan —
|
|
202
|
+
* a credential surviving to this point means an earlier layer is broken, and
|
|
203
|
+
* emitting the bytes anyway is the one outcome that cannot be walked back.
|
|
204
|
+
*/
|
|
205
|
+
export function assertCredentialFreeExportBytes(bytes, label) {
|
|
206
|
+
let carry = "";
|
|
207
|
+
for (let offset = 0; offset < bytes.byteLength; offset += PRINTABLE_CHUNK_BYTES) {
|
|
208
|
+
const end = Math.min(bytes.byteLength, offset + PRINTABLE_CHUNK_BYTES);
|
|
209
|
+
const printable = extractPrintableRuns(bytes, offset, end);
|
|
210
|
+
if (printable.length === 0 && carry.length === 0)
|
|
211
|
+
continue;
|
|
212
|
+
assertCredentialFreeExportText(`${carry}${printable}`, label);
|
|
213
|
+
carry = printable.slice(-PRINTABLE_CHUNK_OVERLAP);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Reduces a source URL to `origin + pathname`, always dropping the query
|
|
218
|
+
* string and fragment.
|
|
219
|
+
*
|
|
220
|
+
* Query strings are where every practical map-service credential lives (Esri
|
|
221
|
+
* `?token=`, Azure SAS `?sv=...&sig=`, S3/GCS presigned `?X-Amz-Signature=`,
|
|
222
|
+
* tile-provider `?api_key=`), and a partial per-parameter allowlist has to be
|
|
223
|
+
* right about every provider forever. Dropping the whole query is the only
|
|
224
|
+
* rule that is right by construction; the origin+path that remains is what an
|
|
225
|
+
* attribution/provenance block legitimately needs.
|
|
226
|
+
*
|
|
227
|
+
* Non-HTTP(S) schemes (`data:`, `blob:`, `file:`), URLs with embedded
|
|
228
|
+
* `user:password@` userinfo, and unparseable strings yield no endpoint at all.
|
|
229
|
+
*/
|
|
230
|
+
export function projectExportEndpoint(url) {
|
|
231
|
+
const trimmed = url.trim();
|
|
232
|
+
if (trimmed.length === 0 || trimmed.length > 4096) {
|
|
233
|
+
return { endpoint: undefined, reason: "unsupported-value" };
|
|
234
|
+
}
|
|
235
|
+
let parsed;
|
|
236
|
+
try {
|
|
237
|
+
parsed = new URL(trimmed);
|
|
238
|
+
}
|
|
239
|
+
catch {
|
|
240
|
+
// Relative locators carry no host and therefore no credential context, but
|
|
241
|
+
// they can still carry a query string; keep only the path portion.
|
|
242
|
+
const [path] = trimmed.split(/[?#]/, 1);
|
|
243
|
+
if (path.length === 0 || containsCredentialMaterial(path)) {
|
|
244
|
+
return { endpoint: undefined, reason: "credential-pattern" };
|
|
245
|
+
}
|
|
246
|
+
return path === trimmed ? { endpoint: path } : { endpoint: path, reason: "signed-url" };
|
|
247
|
+
}
|
|
248
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
249
|
+
return { endpoint: undefined, reason: "unsupported-value" };
|
|
250
|
+
}
|
|
251
|
+
if (parsed.username.length > 0 || parsed.password.length > 0) {
|
|
252
|
+
return { endpoint: undefined, reason: "signed-url" };
|
|
253
|
+
}
|
|
254
|
+
const hadSecretQuery = [...parsed.searchParams.keys()].some((name) => SIGNED_QUERY_NAME.test(name) || SENSITIVE_KEY.test(name));
|
|
255
|
+
const endpoint = `${parsed.origin}${parsed.pathname}`;
|
|
256
|
+
if (containsCredentialMaterial(endpoint)) {
|
|
257
|
+
return { endpoint: undefined, reason: "credential-pattern" };
|
|
258
|
+
}
|
|
259
|
+
const droppedSomething = parsed.search.length > 0 || parsed.hash.length > 0;
|
|
260
|
+
if (hadSecretQuery)
|
|
261
|
+
return { endpoint, reason: "signed-url" };
|
|
262
|
+
return droppedSomething ? { endpoint, reason: "unsupported-value" } : { endpoint };
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Removes credential material from a URL while leaving the URL *functional*.
|
|
266
|
+
*
|
|
267
|
+
* This is the counterpart to {@link projectExportEndpoint}, not a replacement
|
|
268
|
+
* for it. `projectExportEndpoint` reduces a URL to origin+path for a
|
|
269
|
+
* provenance/attribution block, where the query is never needed and dropping
|
|
270
|
+
* all of it is right by construction. That rule cannot be used on a URL the
|
|
271
|
+
* artifact still has to *fetch*: an OGC WMS `GetMap` request, an Esri
|
|
272
|
+
* `?f=json` endpoint, and a tile template with `?format=pbf` all carry their
|
|
273
|
+
* operation in the query string, and a portable map that lost it would import
|
|
274
|
+
* as a map that no longer renders.
|
|
275
|
+
*
|
|
276
|
+
* So this function removes exactly what is credential-bearing — `user:pass@`
|
|
277
|
+
* userinfo, and query parameters whose *name* reads as a secret or a
|
|
278
|
+
* signature — and then re-scans the remainder, refusing to emit anything that
|
|
279
|
+
* still looks like it carries a token. Non-HTTP(S) schemes are refused
|
|
280
|
+
* outright; `data:` payloads are handled by the caller, which can bound and
|
|
281
|
+
* scan the decoded bytes with {@link assertCredentialFreeExportBytes}.
|
|
282
|
+
*/
|
|
283
|
+
export function stripCredentialsFromUrl(url) {
|
|
284
|
+
const trimmed = url.trim();
|
|
285
|
+
if (trimmed.length === 0 || trimmed.length > 8192) {
|
|
286
|
+
return { url: undefined, reason: "unsupported-value" };
|
|
287
|
+
}
|
|
288
|
+
let parsed;
|
|
289
|
+
try {
|
|
290
|
+
parsed = new URL(trimmed);
|
|
291
|
+
}
|
|
292
|
+
catch {
|
|
293
|
+
parsed = undefined;
|
|
294
|
+
}
|
|
295
|
+
if (parsed === undefined) {
|
|
296
|
+
// Relative or template locator: no host, so no userinfo, but it can still
|
|
297
|
+
// carry a query string. Filter the query the same way and keep the rest.
|
|
298
|
+
const hashIndex = trimmed.indexOf("#");
|
|
299
|
+
const withoutHash = hashIndex === -1 ? trimmed : trimmed.slice(0, hashIndex);
|
|
300
|
+
const queryIndex = withoutHash.indexOf("?");
|
|
301
|
+
const pathPart = queryIndex === -1 ? withoutHash : withoutHash.slice(0, queryIndex);
|
|
302
|
+
const queryPart = queryIndex === -1 ? "" : withoutHash.slice(queryIndex + 1);
|
|
303
|
+
const { query, dropped } = filterCredentialQuery(queryPart);
|
|
304
|
+
const rebuilt = query.length > 0 ? `${pathPart}?${query}` : pathPart;
|
|
305
|
+
if (rebuilt.length === 0 || containsCredentialMaterial(rebuilt)) {
|
|
306
|
+
return { url: undefined, reason: "credential-pattern" };
|
|
307
|
+
}
|
|
308
|
+
// Nothing was dropped: return the caller's exact string rather than a
|
|
309
|
+
// reassembled one, so a safe URL round-trips byte-for-byte.
|
|
310
|
+
return dropped ? { url: rebuilt, reason: "signed-url" } : { url: trimmed };
|
|
311
|
+
}
|
|
312
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
313
|
+
return { url: undefined, reason: "unsupported-value" };
|
|
314
|
+
}
|
|
315
|
+
let dropped = false;
|
|
316
|
+
if (parsed.username.length > 0 || parsed.password.length > 0) {
|
|
317
|
+
parsed.username = "";
|
|
318
|
+
parsed.password = "";
|
|
319
|
+
dropped = true;
|
|
320
|
+
}
|
|
321
|
+
for (const name of [...parsed.searchParams.keys()]) {
|
|
322
|
+
if (SIGNED_QUERY_NAME.test(name) || SENSITIVE_KEY.test(name)) {
|
|
323
|
+
parsed.searchParams.delete(name);
|
|
324
|
+
dropped = true;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
// `URL` percent-encodes `{`/`}`, which would break a MapLibre tile template
|
|
328
|
+
// (`{z}/{x}/{y}`, `{bbox-epsg-3857}`). Restore them; they are structural, not
|
|
329
|
+
// credential material.
|
|
330
|
+
const rebuilt = parsed.toString().replace(/%7B/g, "{").replace(/%7D/g, "}");
|
|
331
|
+
if (containsCredentialMaterial(rebuilt)) {
|
|
332
|
+
return { url: undefined, reason: "credential-pattern" };
|
|
333
|
+
}
|
|
334
|
+
// Nothing was dropped: return the caller's exact string. `URL.toString()`
|
|
335
|
+
// normalizes (a bare origin gains a trailing `/`, reserved characters are
|
|
336
|
+
// re-encoded), and a portable artifact should not have its endpoints
|
|
337
|
+
// rewritten when there was nothing to remove.
|
|
338
|
+
return dropped ? { url: rebuilt, reason: "signed-url" } : { url: trimmed };
|
|
339
|
+
}
|
|
340
|
+
function filterCredentialQuery(query) {
|
|
341
|
+
if (query.length === 0)
|
|
342
|
+
return { query: "", dropped: false };
|
|
343
|
+
const kept = [];
|
|
344
|
+
let dropped = false;
|
|
345
|
+
for (const pair of query.split("&")) {
|
|
346
|
+
if (pair.length === 0)
|
|
347
|
+
continue;
|
|
348
|
+
const eq = pair.indexOf("=");
|
|
349
|
+
const name = eq === -1 ? pair : pair.slice(0, eq);
|
|
350
|
+
if (SIGNED_QUERY_NAME.test(name) || SENSITIVE_KEY.test(name)) {
|
|
351
|
+
dropped = true;
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
kept.push(pair);
|
|
355
|
+
}
|
|
356
|
+
return { query: kept.join("&"), dropped };
|
|
357
|
+
}
|
|
358
|
+
// ── header + key allowlists ──────────────────────────────────────────────
|
|
359
|
+
const EXPORTABLE_HEADERS = new Set(["accept", "accept-language", "content-type", "user-agent"]);
|
|
360
|
+
/**
|
|
361
|
+
* Filters a header map down to the export allowlist, recording every drop.
|
|
362
|
+
* Exposed so adapters can prove — in their own tests — that no `Authorization`,
|
|
363
|
+
* `Cookie`, or provider-specific key header rides along with export metadata.
|
|
364
|
+
*/
|
|
365
|
+
export function sanitizeHonuaExportHeaders(headers) {
|
|
366
|
+
const redactions = [];
|
|
367
|
+
const output = {};
|
|
368
|
+
for (const [rawName, rawValue] of Object.entries(headers ?? {})) {
|
|
369
|
+
const name = rawName.toLowerCase();
|
|
370
|
+
if (!EXPORTABLE_HEADERS.has(name)) {
|
|
371
|
+
redactions.push({
|
|
372
|
+
path: `headers[${name}]`,
|
|
373
|
+
reason: SENSITIVE_KEY.test(name) || AUTHORIZATION_SCOPE_KEY.test(name) ? "sensitive-key" : "private-header",
|
|
374
|
+
});
|
|
375
|
+
continue;
|
|
376
|
+
}
|
|
377
|
+
const value = redactHonuaExportText(rawValue);
|
|
378
|
+
if (value !== rawValue) {
|
|
379
|
+
redactions.push({ path: `headers[${name}]`, reason: "credential-pattern" });
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
output[name] = value.slice(0, 512);
|
|
383
|
+
}
|
|
384
|
+
return { headers: output, redactions };
|
|
385
|
+
}
|
|
386
|
+
/** Whether a property name is refused outright by the export pipeline. */
|
|
387
|
+
export function isSensitiveExportKey(name) {
|
|
388
|
+
return SENSITIVE_KEY.test(name) || AUTHORIZATION_SCOPE_KEY.test(name);
|
|
389
|
+
}
|
|
@@ -47,6 +47,19 @@ export declare const HONUA_ERROR_RUNTIME_CLASSIFICATIONS: Readonly<{
|
|
|
47
47
|
readonly "core.coverage.unsupported-format": HonuaErrorRuntimeClassification;
|
|
48
48
|
readonly "core.coverage.service-error": HonuaErrorRuntimeClassification;
|
|
49
49
|
readonly "core.coverage.wcs-exception": HonuaErrorRuntimeClassification;
|
|
50
|
+
readonly "core.zarr.invalid-request": HonuaErrorRuntimeClassification;
|
|
51
|
+
readonly "core.zarr.invalid-response": HonuaErrorRuntimeClassification;
|
|
52
|
+
readonly "core.zarr.response-too-large": HonuaErrorRuntimeClassification;
|
|
53
|
+
readonly "core.zarr.metadata-pending": HonuaErrorRuntimeClassification;
|
|
54
|
+
readonly "core.zarr.missing-spatial-extent": HonuaErrorRuntimeClassification;
|
|
55
|
+
readonly "core.zarr.no-tileable-variable": HonuaErrorRuntimeClassification;
|
|
56
|
+
readonly "core.zarr.missing-spatial-reference": HonuaErrorRuntimeClassification;
|
|
57
|
+
readonly "core.zarr.spatial-reference-mismatch": HonuaErrorRuntimeClassification;
|
|
58
|
+
readonly "core.zarr.unsupported-version": HonuaErrorRuntimeClassification;
|
|
59
|
+
readonly "core.zarr.unsupported-codec": HonuaErrorRuntimeClassification;
|
|
60
|
+
readonly "core.zarr.unsupported-dtype": HonuaErrorRuntimeClassification;
|
|
61
|
+
readonly "core.zarr.ambiguous-dimensions": HonuaErrorRuntimeClassification;
|
|
62
|
+
readonly "core.zarr.service-error": HonuaErrorRuntimeClassification;
|
|
50
63
|
readonly "discovery.ambiguous-protocol": HonuaErrorRuntimeClassification;
|
|
51
64
|
readonly "discovery.ambiguous-source": HonuaErrorRuntimeClassification;
|
|
52
65
|
readonly "discovery.invalid-cloud-native-input": HonuaErrorRuntimeClassification;
|
|
@@ -106,6 +119,8 @@ export declare const HONUA_ERROR_RUNTIME_CLASSIFICATIONS: Readonly<{
|
|
|
106
119
|
readonly "runtime.map-package.fetch": HonuaErrorRuntimeClassification;
|
|
107
120
|
readonly "runtime.map-package.load": HonuaErrorRuntimeClassification;
|
|
108
121
|
readonly "runtime.map-package.validate": HonuaErrorRuntimeClassification;
|
|
122
|
+
readonly "runtime.map-package.export": HonuaErrorRuntimeClassification;
|
|
123
|
+
readonly "runtime.map-package.import": HonuaErrorRuntimeClassification;
|
|
109
124
|
readonly "runtime.map-package.update": HonuaErrorRuntimeClassification;
|
|
110
125
|
readonly "runtime.map-package.style-compose": HonuaErrorRuntimeClassification;
|
|
111
126
|
readonly "runtime.map-package.source-bind": HonuaErrorRuntimeClassification;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-classifications.d.ts","sourceRoot":"","sources":["../../../src/core/error-classifications.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAkB,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAErG;;;;;;;;GAQG;AACH,MAAM,MAAM,+BAA+B,GAAG,SAAS;IACrD,MAAM,EAAE,gBAAgB;IACxB,QAAQ,EAAE,kBAAkB;IAC5B,SAAS,EAAE,OAAO;CACnB,CAAC;AAEF,gBAAgB;AAChB,eAAO,MAAM,mCAAmC
|
|
1
|
+
{"version":3,"file":"error-classifications.d.ts","sourceRoot":"","sources":["../../../src/core/error-classifications.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAkB,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAErG;;;;;;;;GAQG;AACH,MAAM,MAAM,+BAA+B,GAAG,SAAS;IACrD,MAAM,EAAE,gBAAgB;IACxB,QAAQ,EAAE,kBAAkB;IAC5B,SAAS,EAAE,OAAO;CACnB,CAAC;AAEF,gBAAgB;AAChB,eAAO,MAAM,mCAAmC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA6K6B,CAAC"}
|
|
@@ -32,6 +32,19 @@ export const HONUA_ERROR_RUNTIME_CLASSIFICATIONS = Object.freeze({
|
|
|
32
32
|
"core.coverage.unsupported-format": runtimeClassification("core", "capability", false),
|
|
33
33
|
"core.coverage.service-error": runtimeClassification("core", "protocol", false),
|
|
34
34
|
"core.coverage.wcs-exception": runtimeClassification("core", "protocol", false),
|
|
35
|
+
"core.zarr.invalid-request": runtimeClassification("core", "validation", false),
|
|
36
|
+
"core.zarr.invalid-response": runtimeClassification("core", "protocol", false),
|
|
37
|
+
"core.zarr.response-too-large": runtimeClassification("core", "validation", false),
|
|
38
|
+
"core.zarr.metadata-pending": runtimeClassification("core", "capability", false),
|
|
39
|
+
"core.zarr.missing-spatial-extent": runtimeClassification("core", "capability", false),
|
|
40
|
+
"core.zarr.no-tileable-variable": runtimeClassification("core", "capability", false),
|
|
41
|
+
"core.zarr.missing-spatial-reference": runtimeClassification("core", "capability", false),
|
|
42
|
+
"core.zarr.spatial-reference-mismatch": runtimeClassification("core", "capability", false),
|
|
43
|
+
"core.zarr.unsupported-version": runtimeClassification("core", "capability", false),
|
|
44
|
+
"core.zarr.unsupported-codec": runtimeClassification("core", "capability", false),
|
|
45
|
+
"core.zarr.unsupported-dtype": runtimeClassification("core", "capability", false),
|
|
46
|
+
"core.zarr.ambiguous-dimensions": runtimeClassification("core", "validation", false),
|
|
47
|
+
"core.zarr.service-error": runtimeClassification("core", "protocol", false),
|
|
35
48
|
"discovery.ambiguous-protocol": runtimeClassification("discovery", "validation", false),
|
|
36
49
|
"discovery.ambiguous-source": runtimeClassification("discovery", "validation", false),
|
|
37
50
|
"discovery.invalid-cloud-native-input": runtimeClassification("discovery", "validation", false),
|
|
@@ -91,6 +104,8 @@ export const HONUA_ERROR_RUNTIME_CLASSIFICATIONS = Object.freeze({
|
|
|
91
104
|
"runtime.map-package.fetch": runtimeClassification("runtime", "network", true),
|
|
92
105
|
"runtime.map-package.load": runtimeClassification("runtime", "internal", false),
|
|
93
106
|
"runtime.map-package.validate": runtimeClassification("runtime", "validation", false),
|
|
107
|
+
"runtime.map-package.export": runtimeClassification("runtime", "validation", false),
|
|
108
|
+
"runtime.map-package.import": runtimeClassification("runtime", "validation", false),
|
|
94
109
|
"runtime.map-package.update": runtimeClassification("runtime", "internal", false),
|
|
95
110
|
"runtime.map-package.style-compose": runtimeClassification("runtime", "validation", false),
|
|
96
111
|
"runtime.map-package.source-bind": runtimeClassification("runtime", "internal", false),
|
|
@@ -51,6 +51,19 @@ export declare const HONUA_ERROR_CODE_REGISTRY: Readonly<{
|
|
|
51
51
|
readonly "core.coverage.unsupported-format": HonuaErrorCodeDescriptor;
|
|
52
52
|
readonly "core.coverage.service-error": HonuaErrorCodeDescriptor;
|
|
53
53
|
readonly "core.coverage.wcs-exception": HonuaErrorCodeDescriptor;
|
|
54
|
+
readonly "core.zarr.invalid-request": HonuaErrorCodeDescriptor;
|
|
55
|
+
readonly "core.zarr.invalid-response": HonuaErrorCodeDescriptor;
|
|
56
|
+
readonly "core.zarr.response-too-large": HonuaErrorCodeDescriptor;
|
|
57
|
+
readonly "core.zarr.metadata-pending": HonuaErrorCodeDescriptor;
|
|
58
|
+
readonly "core.zarr.missing-spatial-extent": HonuaErrorCodeDescriptor;
|
|
59
|
+
readonly "core.zarr.no-tileable-variable": HonuaErrorCodeDescriptor;
|
|
60
|
+
readonly "core.zarr.missing-spatial-reference": HonuaErrorCodeDescriptor;
|
|
61
|
+
readonly "core.zarr.spatial-reference-mismatch": HonuaErrorCodeDescriptor;
|
|
62
|
+
readonly "core.zarr.unsupported-version": HonuaErrorCodeDescriptor;
|
|
63
|
+
readonly "core.zarr.unsupported-codec": HonuaErrorCodeDescriptor;
|
|
64
|
+
readonly "core.zarr.unsupported-dtype": HonuaErrorCodeDescriptor;
|
|
65
|
+
readonly "core.zarr.ambiguous-dimensions": HonuaErrorCodeDescriptor;
|
|
66
|
+
readonly "core.zarr.service-error": HonuaErrorCodeDescriptor;
|
|
54
67
|
readonly "discovery.ambiguous-protocol": HonuaErrorCodeDescriptor;
|
|
55
68
|
readonly "discovery.ambiguous-source": HonuaErrorCodeDescriptor;
|
|
56
69
|
readonly "discovery.invalid-cloud-native-input": HonuaErrorCodeDescriptor;
|
|
@@ -110,6 +123,8 @@ export declare const HONUA_ERROR_CODE_REGISTRY: Readonly<{
|
|
|
110
123
|
readonly "runtime.map-package.fetch": HonuaErrorCodeDescriptor;
|
|
111
124
|
readonly "runtime.map-package.load": HonuaErrorCodeDescriptor;
|
|
112
125
|
readonly "runtime.map-package.validate": HonuaErrorCodeDescriptor;
|
|
126
|
+
readonly "runtime.map-package.export": HonuaErrorCodeDescriptor;
|
|
127
|
+
readonly "runtime.map-package.import": HonuaErrorCodeDescriptor;
|
|
113
128
|
readonly "runtime.map-package.update": HonuaErrorCodeDescriptor;
|
|
114
129
|
readonly "runtime.map-package.style-compose": HonuaErrorCodeDescriptor;
|
|
115
130
|
readonly "runtime.map-package.source-bind": HonuaErrorCodeDescriptor;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-code-registry.d.ts","sourceRoot":"","sources":["../../../src/core/error-code-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,WAAW,GACX,OAAO,GACP,KAAK,GACL,SAAS,GACT,UAAU,GACV,SAAS,GACT,QAAQ,GACR,SAAS,GACT,OAAO,GACP,KAAK,CAAC;AAEV,MAAM,MAAM,kBAAkB,GAC1B,gBAAgB,GAChB,cAAc,GACd,YAAY,GACZ,UAAU,GACV,SAAS,GACT,UAAU,GACV,SAAS,GACT,YAAY,CAAC;AAEjB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB
|
|
1
|
+
{"version":3,"file":"error-code-registry.d.ts","sourceRoot":"","sources":["../../../src/core/error-code-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,MAAM,gBAAgB,GACxB,MAAM,GACN,WAAW,GACX,OAAO,GACP,KAAK,GACL,SAAS,GACT,UAAU,GACV,SAAS,GACT,QAAQ,GACR,SAAS,GACT,OAAO,GACP,KAAK,CAAC;AAEV,MAAM,MAAM,kBAAkB,GAC1B,gBAAgB,GAChB,cAAc,GACd,YAAY,GACZ,UAAU,GACV,SAAS,GACT,UAAU,GACV,SAAS,GACT,YAAY,CAAC;AAEjB,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,QAAQ,EAAE,kBAAkB,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;GAGG;AACH,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqrBwB,CAAC;AAE/D,MAAM,MAAM,cAAc,GAAG,MAAM,OAAO,yBAAyB,CAAC"}
|
|
@@ -35,6 +35,19 @@ export const HONUA_ERROR_CODE_REGISTRY = Object.freeze({
|
|
|
35
35
|
"core.coverage.unsupported-format": classification("core", "capability", false, "Coverage format is unsupported"),
|
|
36
36
|
"core.coverage.service-error": classification("core", "protocol", false, "Coverage service rejected the request"),
|
|
37
37
|
"core.coverage.wcs-exception": classification("core", "protocol", false, "WCS exception report"),
|
|
38
|
+
"core.zarr.invalid-request": classification("core", "validation", false, "Zarr request is invalid"),
|
|
39
|
+
"core.zarr.invalid-response": classification("core", "protocol", false, "Zarr response is invalid"),
|
|
40
|
+
"core.zarr.response-too-large": classification("core", "validation", false, "Zarr response exceeds its byte limit"),
|
|
41
|
+
"core.zarr.metadata-pending": classification("core", "capability", false, "Zarr metadata scan is pending"),
|
|
42
|
+
"core.zarr.missing-spatial-extent": classification("core", "capability", false, "Zarr storage spatial extent is missing or unusable"),
|
|
43
|
+
"core.zarr.no-tileable-variable": classification("core", "capability", false, "Zarr metadata contains no tileable variable"),
|
|
44
|
+
"core.zarr.missing-spatial-reference": classification("core", "capability", false, "Zarr registration is missing a positive storage SRID for tile handoff"),
|
|
45
|
+
"core.zarr.spatial-reference-mismatch": classification("core", "capability", false, "Zarr storage and tile matrix spatial references do not match"),
|
|
46
|
+
"core.zarr.unsupported-version": classification("core", "capability", false, "Zarr version is unsupported"),
|
|
47
|
+
"core.zarr.unsupported-codec": classification("core", "capability", false, "Zarr codec is unsupported"),
|
|
48
|
+
"core.zarr.unsupported-dtype": classification("core", "capability", false, "Zarr dtype is unsupported"),
|
|
49
|
+
"core.zarr.ambiguous-dimensions": classification("core", "validation", false, "Zarr dimensions are ambiguous"),
|
|
50
|
+
"core.zarr.service-error": classification("core", "protocol", false, "Zarr service rejected the request"),
|
|
38
51
|
"discovery.ambiguous-protocol": classification("discovery", "validation", false, "Multiple protocols match the endpoint"),
|
|
39
52
|
"discovery.ambiguous-source": classification("discovery", "validation", false, "Multiple sources match the selection"),
|
|
40
53
|
"discovery.invalid-cloud-native-input": classification("discovery", "validation", false, "Cloud-native discovery input is invalid or ambiguous"),
|
|
@@ -94,6 +107,8 @@ export const HONUA_ERROR_CODE_REGISTRY = Object.freeze({
|
|
|
94
107
|
"runtime.map-package.fetch": classification("runtime", "network", true, "Map package fetch failed"),
|
|
95
108
|
"runtime.map-package.load": classification("runtime", "internal", false, "Map package load failed"),
|
|
96
109
|
"runtime.map-package.validate": classification("runtime", "validation", false, "Map package validation failed"),
|
|
110
|
+
"runtime.map-package.export": classification("runtime", "validation", false, "Map package export refused"),
|
|
111
|
+
"runtime.map-package.import": classification("runtime", "validation", false, "Map package import refused"),
|
|
97
112
|
"runtime.map-package.update": classification("runtime", "internal", false, "Map package update failed"),
|
|
98
113
|
"runtime.map-package.style-compose": classification("runtime", "validation", false, "Map package style composition failed"),
|
|
99
114
|
"runtime.map-package.source-bind": classification("runtime", "internal", false, "Map package source binding failed"),
|
package/core/error-envelope.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface HonuaErrorMetadata {
|
|
|
17
17
|
readonly operationId?: string;
|
|
18
18
|
readonly requestId?: string;
|
|
19
19
|
readonly context?: Readonly<Record<string, unknown>>;
|
|
20
|
+
readonly terminalReceipt?: HonuaTerminalFailureReceipt;
|
|
20
21
|
}
|
|
21
22
|
export interface HonuaErrorOptions extends ErrorOptions, HonuaErrorMetadata {
|
|
22
23
|
}
|
|
@@ -29,9 +30,38 @@ export interface SerializedHonuaError {
|
|
|
29
30
|
readonly retryable: boolean;
|
|
30
31
|
readonly operationId?: string;
|
|
31
32
|
readonly requestId?: string;
|
|
33
|
+
readonly receipt?: HonuaTerminalFailureReceipt;
|
|
32
34
|
readonly context: HonuaErrorEnvelopeContext;
|
|
33
35
|
readonly cause?: SerializedHonuaErrorCause;
|
|
34
36
|
}
|
|
37
|
+
/** Stable failure classes shared by HTTP, GeoServices, and gRPC terminal receipts. */
|
|
38
|
+
export type HonuaFailureKind = "authentication" | "authorization" | "not-found" | "validation" | "conflict" | "throttled" | "unavailable" | "unknown";
|
|
39
|
+
/** One field- or item-addressable server rejection. */
|
|
40
|
+
export interface HonuaFieldFailure {
|
|
41
|
+
readonly code?: string;
|
|
42
|
+
readonly severity?: string;
|
|
43
|
+
readonly path?: string;
|
|
44
|
+
readonly fieldId?: string;
|
|
45
|
+
readonly itemIndex?: number;
|
|
46
|
+
readonly message?: string;
|
|
47
|
+
}
|
|
48
|
+
/** Protocol-native metadata retained at a terminal transport boundary. */
|
|
49
|
+
export interface HonuaProtocolMetadata {
|
|
50
|
+
readonly initial: Readonly<Record<string, readonly string[]>>;
|
|
51
|
+
readonly trailing: Readonly<Record<string, readonly string[]>>;
|
|
52
|
+
}
|
|
53
|
+
/** Machine-actionable receipt exposed by every remote terminal SDK error. */
|
|
54
|
+
export interface HonuaTerminalFailureReceipt {
|
|
55
|
+
readonly transportStatus?: number;
|
|
56
|
+
readonly protocolCode?: number | string;
|
|
57
|
+
readonly kind: HonuaFailureKind;
|
|
58
|
+
readonly code?: string;
|
|
59
|
+
readonly retryable: boolean;
|
|
60
|
+
readonly retryAfterMs?: number;
|
|
61
|
+
readonly correlationId?: string;
|
|
62
|
+
readonly fieldErrors: readonly HonuaFieldFailure[];
|
|
63
|
+
readonly protocolMetadata: HonuaProtocolMetadata;
|
|
64
|
+
}
|
|
35
65
|
export interface SerializedHonuaErrorCause {
|
|
36
66
|
readonly name: string;
|
|
37
67
|
readonly domain?: HonuaErrorDomain;
|
|
@@ -49,6 +79,7 @@ export declare abstract class HonuaSdkError extends Error {
|
|
|
49
79
|
readonly retryable: boolean;
|
|
50
80
|
readonly operationId: string | undefined;
|
|
51
81
|
readonly requestId: string | undefined;
|
|
82
|
+
readonly terminalReceipt: HonuaTerminalFailureReceipt | undefined;
|
|
52
83
|
readonly context: HonuaErrorEnvelopeContext;
|
|
53
84
|
protected constructor(code: HonuaErrorCode, message: string, options?: HonuaErrorOptions);
|
|
54
85
|
/** Safe JSON projection. Raw messages, stacks, details, bodies, and causes are intentionally omitted. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-envelope.d.ts","sourceRoot":"","sources":["../../../src/core/error-envelope.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAErG,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,0BAA0B,CAAC;AAElC,eAAO,MAAM,gBAAgB,EAAG,oBAA6B,CAAC;AAE9D,MAAM,MAAM,8BAA8B,GACtC,IAAI,GACJ,OAAO,GACP,MAAM,GACN,MAAM,GACN,SAAS,8BAA8B,EAAE,GACzC;IAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,GAAG,8BAA8B,CAAA;CAAE,CAAC;AAE/D,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,8BAA8B,CAAC,CAAC,CAAC;AAEjG,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"error-envelope.d.ts","sourceRoot":"","sources":["../../../src/core/error-envelope.ts"],"names":[],"mappings":"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"}
|
package/core/error-envelope.js
CHANGED
|
@@ -18,6 +18,7 @@ export class HonuaSdkError extends Error {
|
|
|
18
18
|
retryable;
|
|
19
19
|
operationId;
|
|
20
20
|
requestId;
|
|
21
|
+
terminalReceipt;
|
|
21
22
|
context;
|
|
22
23
|
constructor(code, message, options = {}) {
|
|
23
24
|
const [domain, category, retryable] = errorCodeClassification(code);
|
|
@@ -29,6 +30,7 @@ export class HonuaSdkError extends Error {
|
|
|
29
30
|
this.retryable = retryable;
|
|
30
31
|
this.operationId = sanitizeIdentifier(options.operationId);
|
|
31
32
|
this.requestId = sanitizeIdentifier(options.requestId);
|
|
33
|
+
this.terminalReceipt = options.terminalReceipt;
|
|
32
34
|
this.context = sanitizeHonuaErrorContext(options.context);
|
|
33
35
|
}
|
|
34
36
|
/** Safe JSON projection. Raw messages, stacks, details, bodies, and causes are intentionally omitted. */
|
|
@@ -69,6 +71,7 @@ export function serializeHonuaError(error) {
|
|
|
69
71
|
const cause = serializeCause(ownDataProperty(error, "cause"));
|
|
70
72
|
const operationId = sanitizeIdentifier(asOptionalString(ownDataProperty(error, "operationId")));
|
|
71
73
|
const requestId = sanitizeIdentifier(asOptionalString(ownDataProperty(error, "requestId")));
|
|
74
|
+
const receipt = ownDataProperty(error, "terminalReceipt");
|
|
72
75
|
const context = ownDataProperty(error, "context");
|
|
73
76
|
return {
|
|
74
77
|
kind: HONUA_ERROR_KIND,
|
|
@@ -79,10 +82,18 @@ export function serializeHonuaError(error) {
|
|
|
79
82
|
retryable,
|
|
80
83
|
...(operationId ? { operationId } : {}),
|
|
81
84
|
...(requestId ? { requestId } : {}),
|
|
85
|
+
...(isTerminalFailureReceipt(receipt) ? { receipt } : {}),
|
|
82
86
|
context: isRecord(context) && !Array.isArray(context) ? sanitizeHonuaErrorContext(context) : emptyContext(),
|
|
83
87
|
...(cause ? { cause } : {}),
|
|
84
88
|
};
|
|
85
89
|
}
|
|
90
|
+
function isTerminalFailureReceipt(value) {
|
|
91
|
+
return (isRecord(value) &&
|
|
92
|
+
typeof ownDataProperty(value, "kind") === "string" &&
|
|
93
|
+
typeof ownDataProperty(value, "retryable") === "boolean" &&
|
|
94
|
+
Array.isArray(ownDataProperty(value, "fieldErrors")) &&
|
|
95
|
+
isRecord(ownDataProperty(value, "protocolMetadata")));
|
|
96
|
+
}
|
|
86
97
|
/** Redact structured context before it is stored on an SDK error. */
|
|
87
98
|
export function sanitizeHonuaErrorContext(context) {
|
|
88
99
|
if (!context)
|