@honua/mcp-server 0.1.2-beta.0 → 0.1.8-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.
Files changed (117) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +232 -9
  3. package/dist/src/certification/admin-parity.d.ts +96 -0
  4. package/dist/src/certification/admin-parity.d.ts.map +1 -0
  5. package/dist/src/certification/admin-parity.js +235 -0
  6. package/dist/src/certification/census-fixture-client.d.ts.map +1 -1
  7. package/dist/src/certification/census-fixture-client.js +5 -0
  8. package/dist/src/certification/certifier.d.ts +1 -1
  9. package/dist/src/certification/certifier.d.ts.map +1 -1
  10. package/dist/src/certification/certifier.js +28 -20
  11. package/dist/src/certification/cli.js +1 -1
  12. package/dist/src/certification/cql2.d.ts +24 -0
  13. package/dist/src/certification/cql2.d.ts.map +1 -0
  14. package/dist/src/certification/cql2.js +354 -0
  15. package/dist/src/certification/fixtures.d.ts +8 -0
  16. package/dist/src/certification/fixtures.d.ts.map +1 -1
  17. package/dist/src/certification/fixtures.js +26 -10
  18. package/dist/src/certification/ogc-data.d.ts +30 -0
  19. package/dist/src/certification/ogc-data.d.ts.map +1 -0
  20. package/dist/src/certification/ogc-data.js +726 -0
  21. package/dist/src/certification/ogc-fixture-client.d.ts +4 -0
  22. package/dist/src/certification/ogc-fixture-client.d.ts.map +1 -0
  23. package/dist/src/certification/ogc-fixture-client.js +190 -0
  24. package/dist/src/certification/target.d.ts +10 -1
  25. package/dist/src/certification/target.d.ts.map +1 -1
  26. package/dist/src/certification/target.js +63 -28
  27. package/dist/src/credential-endpoint.d.ts +3 -0
  28. package/dist/src/credential-endpoint.d.ts.map +1 -0
  29. package/dist/src/credential-endpoint.js +24 -0
  30. package/dist/src/eval/cli.js +6 -3
  31. package/dist/src/eval/corpus.d.ts +7 -0
  32. package/dist/src/eval/corpus.d.ts.map +1 -1
  33. package/dist/src/eval/corpus.js +12 -0
  34. package/dist/src/eval/ogc-corpus.d.ts +3 -0
  35. package/dist/src/eval/ogc-corpus.d.ts.map +1 -0
  36. package/dist/src/eval/ogc-corpus.js +437 -0
  37. package/dist/src/eval/runner.d.ts +6 -0
  38. package/dist/src/eval/runner.d.ts.map +1 -1
  39. package/dist/src/eval/runner.js +21 -7
  40. package/dist/src/helpers.d.ts +8 -13
  41. package/dist/src/helpers.d.ts.map +1 -1
  42. package/dist/src/helpers.js +7 -35
  43. package/dist/src/index.d.ts +36 -8
  44. package/dist/src/index.d.ts.map +1 -1
  45. package/dist/src/index.js +55 -18
  46. package/dist/src/neutral/errors.d.ts +73 -0
  47. package/dist/src/neutral/errors.d.ts.map +1 -0
  48. package/dist/src/neutral/errors.js +112 -0
  49. package/dist/src/neutral/filter.d.ts +108 -0
  50. package/dist/src/neutral/filter.d.ts.map +1 -0
  51. package/dist/src/neutral/filter.js +271 -0
  52. package/dist/src/neutral/query.d.ts +101 -0
  53. package/dist/src/neutral/query.d.ts.map +1 -0
  54. package/dist/src/neutral/query.js +180 -0
  55. package/dist/src/neutral/result.d.ts +33 -0
  56. package/dist/src/neutral/result.d.ts.map +1 -0
  57. package/dist/src/neutral/result.js +38 -0
  58. package/dist/src/neutral/source-ref.d.ts +126 -0
  59. package/dist/src/neutral/source-ref.d.ts.map +1 -0
  60. package/dist/src/neutral/source-ref.js +267 -0
  61. package/dist/src/nl-map-control.d.ts.map +1 -1
  62. package/dist/src/proxy.d.ts.map +1 -1
  63. package/dist/src/proxy.js +29 -14
  64. package/dist/src/release/zero-to-map-checkpoint.d.ts +34 -0
  65. package/dist/src/release/zero-to-map-checkpoint.d.ts.map +1 -0
  66. package/dist/src/release/zero-to-map-checkpoint.js +369 -0
  67. package/dist/src/release/zero-to-map-cli.d.ts +51 -0
  68. package/dist/src/release/zero-to-map-cli.d.ts.map +1 -0
  69. package/dist/src/release/zero-to-map-cli.js +880 -0
  70. package/dist/src/release/zero-to-map-provision.d.ts +37 -0
  71. package/dist/src/release/zero-to-map-provision.d.ts.map +1 -0
  72. package/dist/src/release/zero-to-map-provision.js +177 -0
  73. package/dist/src/release/zero-to-map.d.ts +296 -0
  74. package/dist/src/release/zero-to-map.d.ts.map +1 -0
  75. package/dist/src/release/zero-to-map.js +1069 -0
  76. package/dist/src/tools/admin-install-local.d.ts +30 -0
  77. package/dist/src/tools/admin-install-local.d.ts.map +1 -0
  78. package/dist/src/tools/admin-install-local.js +22 -0
  79. package/dist/src/tools/control-plane-command.d.ts +99 -0
  80. package/dist/src/tools/control-plane-command.d.ts.map +1 -0
  81. package/dist/src/tools/control-plane-command.js +180 -0
  82. package/dist/src/tools/count-features.d.ts +85 -11
  83. package/dist/src/tools/count-features.d.ts.map +1 -1
  84. package/dist/src/tools/count-features.js +49 -31
  85. package/dist/src/tools/describe-layer.d.ts +30 -6
  86. package/dist/src/tools/describe-layer.d.ts.map +1 -1
  87. package/dist/src/tools/describe-layer.js +99 -8
  88. package/dist/src/tools/docs-search.d.ts +100 -0
  89. package/dist/src/tools/docs-search.d.ts.map +1 -0
  90. package/dist/src/tools/docs-search.js +381 -0
  91. package/dist/src/tools/get-extent.d.ts +69 -11
  92. package/dist/src/tools/get-extent.d.ts.map +1 -1
  93. package/dist/src/tools/get-extent.js +28 -46
  94. package/dist/src/tools/list-services.d.ts +7 -0
  95. package/dist/src/tools/list-services.d.ts.map +1 -1
  96. package/dist/src/tools/list-services.js +8 -1
  97. package/dist/src/tools/list-sources.d.ts +44 -0
  98. package/dist/src/tools/list-sources.d.ts.map +1 -0
  99. package/dist/src/tools/list-sources.js +138 -0
  100. package/dist/src/tools/query-features.d.ts +99 -19
  101. package/dist/src/tools/query-features.d.ts.map +1 -1
  102. package/dist/src/tools/query-features.js +38 -45
  103. package/dist/src/tools/statistics.d.ts +80 -12
  104. package/dist/src/tools/statistics.d.ts.map +1 -1
  105. package/dist/src/tools/statistics.js +56 -23
  106. package/package.json +37 -8
  107. package/release/zero-to-map/README.md +174 -0
  108. package/release/zero-to-map/configs/claude-code.mcp.json +11 -0
  109. package/release/zero-to-map/configs/claude-desktop.json +11 -0
  110. package/release/zero-to-map/configs/cursor.json +11 -0
  111. package/release/zero-to-map/contracts/aws-ecs-provision-binding.schema.json +59 -0
  112. package/release/zero-to-map/contracts/checkpoint.schema.json +152 -0
  113. package/release/zero-to-map/contracts/console-receipt.schema.json +150 -0
  114. package/release/zero-to-map/contracts/esri-gp-mcp.v1.json +73 -0
  115. package/release/zero-to-map/fixtures/parcels.geojson +33 -0
  116. package/release/zero-to-map/fixtures/zoning.geojson +24 -0
  117. package/release/zero-to-map/journey.v1.json +1248 -0
@@ -0,0 +1,126 @@
1
+ import type { HonuaClient } from "@honua/sdk-js";
2
+ import type { CapabilityAwareSource, SourceDescriptor, SourceLocator } from "@honua/sdk-js/contract";
3
+ import { z } from "zod";
4
+ /**
5
+ * PROTOCOL-NEUTRAL source addressing for the MCP tool contract (issue #1005).
6
+ *
7
+ * The tool surface used to address data the way GeoServices does — a required
8
+ * `serviceId` string plus a required numeric `layerId`. That vocabulary is
9
+ * meaningless on OGC API Features, STAC, WFS, and OData, so a "vendor-neutral"
10
+ * server whose only addressing mode is Esri-shaped concedes the claim on
11
+ * inspection.
12
+ *
13
+ * A source is now addressed the way the SDK addresses one: a
14
+ * `SourceDescriptor` (protocol + locator) resolved into a canonical
15
+ * `Source` through `createDataset`. Over the wire that descriptor is carried as
16
+ * one compact string:
17
+ *
18
+ * ```text
19
+ * <protocol>:<address>
20
+ * ```
21
+ *
22
+ * | protocol | address form | example |
23
+ * | ------------------------------- | --------------------- | -------------------------------------- |
24
+ * | `geoservices-feature-service` | `<serviceId>/<layer>` | `geoservices-feature-service:Parks/0` |
25
+ * | `geoservices-map-service` | `<serviceId>/<layer>` | `geoservices-map-service:Basemap/2` |
26
+ * | `ogc-features` | `<collectionId>` | `ogc-features:hotels` |
27
+ * | `ogc-records` | `<collectionId>` | `ogc-records:catalog` |
28
+ * | `stac` | `<collectionId>` | `stac:sentinel-2-l2a` |
29
+ * | `wfs` | `<typeName>` | `wfs:topp:states` |
30
+ * | `odata` | `<entitySet>` | `odata:People` |
31
+ *
32
+ * `honua_list_sources` emits exactly these strings, so the normal agent flow is
33
+ * discover-then-address with no parsing on the client side. The reference is
34
+ * deliberately fail-closed: an unrecognized protocol token is refused with the
35
+ * accepted forms rather than guessed at, because guessing "which protocol did
36
+ * they mean" is how a neutral surface silently becomes a single-vendor one.
37
+ *
38
+ * The legacy `serviceId` + `layerId` pair is still accepted (see
39
+ * {@link legacyGeoServicesRef}) but is deprecated and is no longer *required* by
40
+ * any schema.
41
+ */
42
+ /** Protocols reachable through a `<protocol>:<address>` source reference. */
43
+ export declare const SOURCE_REF_PROTOCOLS: readonly ["geoservices-feature-service", "geoservices-map-service", "ogc-features", "ogc-records", "stac", "wfs", "odata"];
44
+ export type SourceRefProtocol = (typeof SOURCE_REF_PROTOCOLS)[number];
45
+ /** Endpoint layouts an OGC API / STAC source may be published under. */
46
+ export declare const SOURCE_LAYOUTS: readonly ["honua-facade", "ogc-api", "auto", "stac-api", "stac-static"];
47
+ export type SourceLayout = (typeof SOURCE_LAYOUTS)[number];
48
+ /** A parsed, validated protocol-neutral source reference. */
49
+ export interface ParsedSourceRef {
50
+ /** Canonical `<protocol>:<address>` form (aliases normalized). */
51
+ readonly ref: string;
52
+ readonly protocol: SourceRefProtocol;
53
+ readonly address: string;
54
+ readonly layout?: SourceLayout;
55
+ }
56
+ export declare class SourceRefError extends Error {
57
+ readonly code = "INVALID_SOURCE_REFERENCE";
58
+ constructor(message: string);
59
+ }
60
+ /**
61
+ * Parse a `<protocol>:<address>` source reference. Fails closed: an omitted or
62
+ * unrecognized protocol token is refused with the accepted forms instead of
63
+ * being inferred, so a mistyped reference can never silently resolve against
64
+ * the wrong protocol.
65
+ */
66
+ export declare function parseSourceRef(raw: string, layout?: SourceLayout): ParsedSourceRef;
67
+ /** Build the canonical reference for the deprecated GeoServices `serviceId`/`layerId` pair. */
68
+ export declare function legacyGeoServicesRef(serviceId: string, layerId: number): string;
69
+ /** Project a parsed reference onto the SDK's protocol-neutral `SourceLocator`. */
70
+ export declare function toSourceLocator(ref: ParsedSourceRef, baseUrl: string): SourceLocator;
71
+ /** Build the `SourceDescriptor` a reference denotes, without contacting the endpoint. */
72
+ export declare function toSourceDescriptor(ref: ParsedSourceRef, baseUrl: string): SourceDescriptor;
73
+ /** A resolved source plus the neutral identity it was addressed by. */
74
+ export interface ResolvedSource {
75
+ readonly ref: ParsedSourceRef;
76
+ readonly descriptor: SourceDescriptor;
77
+ readonly source: CapabilityAwareSource;
78
+ /** True when the caller used the deprecated `serviceId`/`layerId` pair. */
79
+ readonly legacyAddressing: boolean;
80
+ }
81
+ /**
82
+ * Zod fields every source-addressed tool mixes into its input schema.
83
+ *
84
+ * `source` is the protocol-neutral reference; `serviceId`/`layerId` remain as
85
+ * OPTIONAL, deprecated compatibility inputs so existing MCP clients keep
86
+ * working. No Esri-only field is required by any tool schema.
87
+ */
88
+ export declare const sourceRefFields: {
89
+ readonly source: z.ZodOptional<z.ZodString>;
90
+ readonly layout: z.ZodOptional<z.ZodEnum<["honua-facade", "ogc-api", "auto", "stac-api", "stac-static"]>>;
91
+ readonly serviceId: z.ZodOptional<z.ZodString>;
92
+ readonly layerId: z.ZodOptional<z.ZodNumber>;
93
+ };
94
+ export type SourceRefInput = {
95
+ source?: string | undefined;
96
+ layout?: SourceLayout | undefined;
97
+ serviceId?: string | undefined;
98
+ layerId?: number | undefined;
99
+ };
100
+ /** Resolve the neutral reference an input addresses (without building a `Source`). */
101
+ export declare function resolveSourceRef(input: SourceRefInput): {
102
+ ref: ParsedSourceRef;
103
+ legacyAddressing: boolean;
104
+ };
105
+ /**
106
+ * Resolve an input onto a canonical `Source`.
107
+ *
108
+ * The dataset runs under the `degraded` capability policy so a protocol that
109
+ * cannot serve a request first-party (OGC API Features has no server-side
110
+ * aggregation, for example) answers with an explicit `Result.degraded` reason
111
+ * instead of failing outright. Capabilities the protocol cannot serve at all
112
+ * still throw `HonuaCapabilityNotSupportedError`, which the tool layer turns
113
+ * into a structured tool error — never a silent empty result.
114
+ */
115
+ export declare function resolveSource(client: HonuaClient, input: SourceRefInput): ResolvedSource;
116
+ /** True when a resolved source speaks a GeoServices (Esri) protocol. */
117
+ export declare function isGeoServicesProtocol(protocol: string): boolean;
118
+ /**
119
+ * Resolve the OGC API Features endpoint layout a metadata call must use.
120
+ *
121
+ * `honua-facade` (the default) needs no resolution; a third-party OGC API root
122
+ * is discovered from its landing page once and cached on the client. STAC
123
+ * layouts are not OGC API Features layouts and resolve to `undefined`.
124
+ */
125
+ export declare function ogcLayoutFor(client: HonuaClient, layout: SourceLayout | undefined): Promise<import("../../../dist/src/core/types.js").OgcEndpointLayout> | Promise<undefined>;
126
+ //# sourceMappingURL=source-ref.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source-ref.d.ts","sourceRoot":"","sources":["../../../src/neutral/source-ref.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,qBAAqB,EAAY,gBAAgB,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE/G,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,oBAAoB,4HAQvB,CAAC;AAEX,MAAM,MAAM,iBAAiB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAetE,wEAAwE;AACxE,eAAO,MAAM,cAAc,yEAA0E,CAAC;AAEtG,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,6DAA6D;AAC7D,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;CAChC;AAED,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,8BAA8B;gBAE/B,OAAO,EAAE,MAAM;CAI5B;AAwBD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,eAAe,CA0BlF;AAED,+FAA+F;AAC/F,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/E;AAiBD,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,GAAG,aAAa,CAiBpF;AAED,yFAAyF;AACzF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,eAAe,EAAE,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAO1F;AAED,uEAAuE;AACvE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,GAAG,EAAE,eAAe,CAAC;IAC9B,QAAQ,CAAC,UAAU,EAAE,gBAAgB,CAAC;IACtC,QAAQ,CAAC,MAAM,EAAE,qBAAqB,CAAC;IACvC,2EAA2E;IAC3E,QAAQ,CAAC,gBAAgB,EAAE,OAAO,CAAC;CACpC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,eAAe;;;;;CAyBlB,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG;IAC3B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B,CAAC;AAEF,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG;IAAE,GAAG,EAAE,eAAe,CAAC;IAAC,gBAAgB,EAAE,OAAO,CAAA;CAAE,CAuB3G;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,cAAc,GAAG,cAAc,CAiCxF;AAED,wEAAwE;AACxE,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,GAAG,SAAS,6FAKjF"}
@@ -0,0 +1,267 @@
1
+ import { HonuaCapabilityNotSupportedError } from "@honua/sdk-js";
2
+ import { PROTOCOL_DEFAULT_CAPABILITIES, createDataset } from "@honua/sdk-js/contract";
3
+ import { z } from "zod";
4
+ /**
5
+ * PROTOCOL-NEUTRAL source addressing for the MCP tool contract (issue #1005).
6
+ *
7
+ * The tool surface used to address data the way GeoServices does — a required
8
+ * `serviceId` string plus a required numeric `layerId`. That vocabulary is
9
+ * meaningless on OGC API Features, STAC, WFS, and OData, so a "vendor-neutral"
10
+ * server whose only addressing mode is Esri-shaped concedes the claim on
11
+ * inspection.
12
+ *
13
+ * A source is now addressed the way the SDK addresses one: a
14
+ * `SourceDescriptor` (protocol + locator) resolved into a canonical
15
+ * `Source` through `createDataset`. Over the wire that descriptor is carried as
16
+ * one compact string:
17
+ *
18
+ * ```text
19
+ * <protocol>:<address>
20
+ * ```
21
+ *
22
+ * | protocol | address form | example |
23
+ * | ------------------------------- | --------------------- | -------------------------------------- |
24
+ * | `geoservices-feature-service` | `<serviceId>/<layer>` | `geoservices-feature-service:Parks/0` |
25
+ * | `geoservices-map-service` | `<serviceId>/<layer>` | `geoservices-map-service:Basemap/2` |
26
+ * | `ogc-features` | `<collectionId>` | `ogc-features:hotels` |
27
+ * | `ogc-records` | `<collectionId>` | `ogc-records:catalog` |
28
+ * | `stac` | `<collectionId>` | `stac:sentinel-2-l2a` |
29
+ * | `wfs` | `<typeName>` | `wfs:topp:states` |
30
+ * | `odata` | `<entitySet>` | `odata:People` |
31
+ *
32
+ * `honua_list_sources` emits exactly these strings, so the normal agent flow is
33
+ * discover-then-address with no parsing on the client side. The reference is
34
+ * deliberately fail-closed: an unrecognized protocol token is refused with the
35
+ * accepted forms rather than guessed at, because guessing "which protocol did
36
+ * they mean" is how a neutral surface silently becomes a single-vendor one.
37
+ *
38
+ * The legacy `serviceId` + `layerId` pair is still accepted (see
39
+ * {@link legacyGeoServicesRef}) but is deprecated and is no longer *required* by
40
+ * any schema.
41
+ */
42
+ /** Protocols reachable through a `<protocol>:<address>` source reference. */
43
+ export const SOURCE_REF_PROTOCOLS = [
44
+ "geoservices-feature-service",
45
+ "geoservices-map-service",
46
+ "ogc-features",
47
+ "ogc-records",
48
+ "stac",
49
+ "wfs",
50
+ "odata",
51
+ ];
52
+ /** Short, human-friendly aliases accepted in place of the canonical token. */
53
+ const PROTOCOL_ALIASES = {
54
+ geoservices: "geoservices-feature-service",
55
+ "feature-service": "geoservices-feature-service",
56
+ featureserver: "geoservices-feature-service",
57
+ "map-service": "geoservices-map-service",
58
+ mapserver: "geoservices-map-service",
59
+ ogc: "ogc-features",
60
+ "ogc-api-features": "ogc-features",
61
+ features: "ogc-features",
62
+ records: "ogc-records",
63
+ };
64
+ /** Endpoint layouts an OGC API / STAC source may be published under. */
65
+ export const SOURCE_LAYOUTS = ["honua-facade", "ogc-api", "auto", "stac-api", "stac-static"];
66
+ export class SourceRefError extends Error {
67
+ code = "INVALID_SOURCE_REFERENCE";
68
+ constructor(message) {
69
+ super(message);
70
+ this.name = "SourceRefError";
71
+ }
72
+ }
73
+ const ACCEPTED_FORMS = SOURCE_REF_PROTOCOLS.map((protocol) => {
74
+ switch (protocol) {
75
+ case "geoservices-feature-service":
76
+ case "geoservices-map-service":
77
+ return `${protocol}:<serviceId>/<layerId>`;
78
+ case "wfs":
79
+ return `${protocol}:<typeName>`;
80
+ case "odata":
81
+ return `${protocol}:<entitySet>`;
82
+ default:
83
+ return `${protocol}:<collectionId>`;
84
+ }
85
+ }).join(", ");
86
+ function normalizeProtocolToken(token) {
87
+ const normalized = token.trim().toLowerCase();
88
+ if (SOURCE_REF_PROTOCOLS.includes(normalized)) {
89
+ return normalized;
90
+ }
91
+ return PROTOCOL_ALIASES[normalized];
92
+ }
93
+ /**
94
+ * Parse a `<protocol>:<address>` source reference. Fails closed: an omitted or
95
+ * unrecognized protocol token is refused with the accepted forms instead of
96
+ * being inferred, so a mistyped reference can never silently resolve against
97
+ * the wrong protocol.
98
+ */
99
+ export function parseSourceRef(raw, layout) {
100
+ const value = raw.trim();
101
+ if (value.length === 0) {
102
+ throw new SourceRefError(`source must be a non-empty "<protocol>:<address>" reference. Accepted: ${ACCEPTED_FORMS}`);
103
+ }
104
+ const separator = value.indexOf(":");
105
+ if (separator < 0) {
106
+ throw new SourceRefError(`source "${raw}" is missing its protocol prefix. Use "<protocol>:<address>" (accepted: ${ACCEPTED_FORMS}), or call honua_list_sources to discover exact source references.`);
107
+ }
108
+ const protocol = normalizeProtocolToken(value.slice(0, separator));
109
+ if (!protocol) {
110
+ throw new SourceRefError(`source "${raw}" names an unknown protocol "${value.slice(0, separator)}". Accepted: ${ACCEPTED_FORMS}.`);
111
+ }
112
+ // The address keeps every remaining colon: a WFS typeName is namespace-qualified
113
+ // (`topp:states`) and splitting it again would corrupt the identifier.
114
+ const address = value.slice(separator + 1).trim();
115
+ if (address.length === 0) {
116
+ throw new SourceRefError(`source "${raw}" is missing its address. Accepted: ${ACCEPTED_FORMS}.`);
117
+ }
118
+ return { ref: `${protocol}:${address}`, protocol, address, ...(layout ? { layout } : {}) };
119
+ }
120
+ /** Build the canonical reference for the deprecated GeoServices `serviceId`/`layerId` pair. */
121
+ export function legacyGeoServicesRef(serviceId, layerId) {
122
+ return `geoservices-feature-service:${serviceId}/${layerId}`;
123
+ }
124
+ function splitGeoServicesAddress(ref) {
125
+ const slash = ref.address.lastIndexOf("/");
126
+ if (slash <= 0 || slash === ref.address.length - 1) {
127
+ throw new SourceRefError(`source "${ref.ref}" must address a layer as "<serviceId>/<layerId>" (e.g. "${ref.protocol}:Parks/0").`);
128
+ }
129
+ const serviceId = ref.address.slice(0, slash);
130
+ const rawLayer = ref.address.slice(slash + 1);
131
+ if (!/^\d+$/.test(rawLayer)) {
132
+ throw new SourceRefError(`source "${ref.ref}" has a non-numeric layer id "${rawLayer}"; expected a whole number.`);
133
+ }
134
+ return { serviceId, layerId: Number.parseInt(rawLayer, 10) };
135
+ }
136
+ /** Project a parsed reference onto the SDK's protocol-neutral `SourceLocator`. */
137
+ export function toSourceLocator(ref, baseUrl) {
138
+ const layout = ref.layout && ref.layout !== "honua-facade" ? { layout: ref.layout } : {};
139
+ switch (ref.protocol) {
140
+ case "geoservices-feature-service":
141
+ case "geoservices-map-service": {
142
+ const { serviceId, layerId } = splitGeoServicesAddress(ref);
143
+ return { url: baseUrl, serviceId, layerId };
144
+ }
145
+ case "ogc-features":
146
+ case "ogc-records":
147
+ case "stac":
148
+ return { url: baseUrl, collectionId: ref.address, ...layout };
149
+ case "wfs":
150
+ return { url: baseUrl, typeName: ref.address };
151
+ case "odata":
152
+ return { url: baseUrl, entitySet: ref.address };
153
+ }
154
+ }
155
+ /** Build the `SourceDescriptor` a reference denotes, without contacting the endpoint. */
156
+ export function toSourceDescriptor(ref, baseUrl) {
157
+ return {
158
+ id: ref.ref,
159
+ protocol: ref.protocol,
160
+ locator: toSourceLocator(ref, baseUrl),
161
+ capabilities: PROTOCOL_DEFAULT_CAPABILITIES[ref.protocol],
162
+ };
163
+ }
164
+ /**
165
+ * Zod fields every source-addressed tool mixes into its input schema.
166
+ *
167
+ * `source` is the protocol-neutral reference; `serviceId`/`layerId` remain as
168
+ * OPTIONAL, deprecated compatibility inputs so existing MCP clients keep
169
+ * working. No Esri-only field is required by any tool schema.
170
+ */
171
+ export const sourceRefFields = {
172
+ source: z
173
+ .string()
174
+ .optional()
175
+ .describe('Protocol-neutral source reference "<protocol>:<address>" as emitted by honua_list_sources — e.g. "ogc-features:hotels", "stac:sentinel-2-l2a", "wfs:topp:states", "odata:People", "geoservices-feature-service:Parks/0". Preferred over the deprecated serviceId/layerId pair.'),
176
+ layout: z
177
+ .enum(SOURCE_LAYOUTS)
178
+ .optional()
179
+ .describe('Endpoint layout for OGC API / STAC sources: "honua-facade" (default, Honua server paths), "ogc-api"/"auto" (third-party OGC API root), "stac-api"/"stac-static" (STAC). Ignored by other protocols.'),
180
+ serviceId: z
181
+ .string()
182
+ .optional()
183
+ .describe("[DEPRECATED — use `source`] GeoServices service id. Only meaningful on an Esri FeatureServer/MapServer."),
184
+ layerId: z
185
+ .number()
186
+ .int()
187
+ .nonnegative()
188
+ .optional()
189
+ .describe("[DEPRECATED — use `source`] GeoServices layer id within the service. Required with `serviceId`."),
190
+ };
191
+ /** Resolve the neutral reference an input addresses (without building a `Source`). */
192
+ export function resolveSourceRef(input) {
193
+ if (input.source !== undefined && input.source.trim().length > 0) {
194
+ return { ref: parseSourceRef(input.source, input.layout), legacyAddressing: false };
195
+ }
196
+ if (input.serviceId !== undefined && input.serviceId.trim().length > 0) {
197
+ if (input.layerId === undefined) {
198
+ throw new SourceRefError(`serviceId "${input.serviceId}" was given without layerId. Pass both, or (preferred) a protocol-neutral \`source\` reference such as "geoservices-feature-service:${input.serviceId}/0".`);
199
+ }
200
+ return {
201
+ ref: parseSourceRef(legacyGeoServicesRef(input.serviceId, input.layerId), input.layout),
202
+ legacyAddressing: true,
203
+ };
204
+ }
205
+ if (input.layerId !== undefined) {
206
+ throw new SourceRefError("layerId was given without serviceId. Pass both, or (preferred) a protocol-neutral `source` reference.");
207
+ }
208
+ throw new SourceRefError(`no source was addressed. Pass \`source\` as "<protocol>:<address>" (accepted: ${ACCEPTED_FORMS}); call honua_list_sources to discover the exact references this endpoint serves.`);
209
+ }
210
+ /**
211
+ * Resolve an input onto a canonical `Source`.
212
+ *
213
+ * The dataset runs under the `degraded` capability policy so a protocol that
214
+ * cannot serve a request first-party (OGC API Features has no server-side
215
+ * aggregation, for example) answers with an explicit `Result.degraded` reason
216
+ * instead of failing outright. Capabilities the protocol cannot serve at all
217
+ * still throw `HonuaCapabilityNotSupportedError`, which the tool layer turns
218
+ * into a structured tool error — never a silent empty result.
219
+ */
220
+ export function resolveSource(client, input) {
221
+ const { ref, legacyAddressing } = resolveSourceRef(input);
222
+ const descriptor = toSourceDescriptor(ref, client.serverBaseUrl);
223
+ const dataset = createDataset({
224
+ id: `honua-mcp:${ref.ref}`,
225
+ client,
226
+ sources: [descriptor],
227
+ capabilityPolicy: "degraded",
228
+ // The standalone server points at arbitrary public endpoints; a Honua
229
+ // server-version handshake is neither available nor meaningful there.
230
+ skipCompatibilityCheck: true,
231
+ });
232
+ let source;
233
+ try {
234
+ source = dataset.source(descriptor.id);
235
+ }
236
+ catch (error) {
237
+ // A capability refusal is the SDK's own honest signal and travels as-is.
238
+ // Anything else (an incomplete locator, a runtime that cannot construct the
239
+ // protocol adapter) becomes an actionable addressing error rather than an
240
+ // opaque stack trace.
241
+ if (error instanceof HonuaCapabilityNotSupportedError) {
242
+ throw error;
243
+ }
244
+ throw new SourceRefError(`source "${ref.ref}" could not be resolved to a runtime adapter: ${error instanceof Error ? error.message : String(error)}`);
245
+ }
246
+ if (!source) {
247
+ throw new SourceRefError(`source "${ref.ref}" could not be resolved to a runtime adapter.`);
248
+ }
249
+ return { ref, descriptor, source, legacyAddressing };
250
+ }
251
+ /** True when a resolved source speaks a GeoServices (Esri) protocol. */
252
+ export function isGeoServicesProtocol(protocol) {
253
+ return protocol.startsWith("geoservices-") || protocol === "grpc";
254
+ }
255
+ /**
256
+ * Resolve the OGC API Features endpoint layout a metadata call must use.
257
+ *
258
+ * `honua-facade` (the default) needs no resolution; a third-party OGC API root
259
+ * is discovered from its landing page once and cached on the client. STAC
260
+ * layouts are not OGC API Features layouts and resolve to `undefined`.
261
+ */
262
+ export function ogcLayoutFor(client, layout) {
263
+ if (layout === "ogc-api" || layout === "auto") {
264
+ return client.resolveOgcFeaturesLayout(layout);
265
+ }
266
+ return Promise.resolve(undefined);
267
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"nl-map-control.d.ts","sourceRoot":"","sources":["../../src/nl-map-control.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"nl-map-control.d.ts","sourceRoot":"","sources":["../../src/nl-map-control.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/proxy.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAEnE,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAiBnE;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,YAAY;IAC3B,sFAAsF;IACtF,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,YAAY,CAqBtF;AAED,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CASlF;AAED,oFAAoF;AACpF,wBAAsB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAQ5E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA+C1D;AAOD;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBlF"}
1
+ {"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/proxy.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAEnE,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAkBnE;;;;;;;;;;;;;;;GAeG;AAEH,MAAM,WAAW,YAAY;IAC3B,sFAAsF;IACtF,SAAS,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,4EAA4E;IAC5E,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B;AAsBD,wBAAgB,mBAAmB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,YAAY,CAqBtF;AAED,mFAAmF;AACnF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUlF;AAED,oFAAoF;AACpF,wBAAsB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAS5E;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA+C1D;AAOD;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBlF"}
package/dist/src/proxy.js CHANGED
@@ -5,30 +5,44 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
5
5
  import { Server } from "@modelcontextprotocol/sdk/server/index.js";
6
6
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
7
7
  import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourceTemplatesRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, PromptListChangedNotificationSchema, ReadResourceRequestSchema, ResourceListChangedNotificationSchema, ToolListChangedNotificationSchema, } from "@modelcontextprotocol/sdk/types.js";
8
+ import { requireSecureCredentialEndpoint } from "./credential-endpoint.js";
8
9
  import { SERVER_VERSION } from "./index.js";
10
+ function isConfigured(value) {
11
+ return value !== undefined && value.length > 0;
12
+ }
13
+ function validateAuthentication(options) {
14
+ const hasBearer = isConfigured(options.authToken);
15
+ const hasApiKey = isConfigured(options.apiKey);
16
+ if (hasBearer && hasApiKey) {
17
+ throw new Error("Configure exactly one upstream authentication scheme: unset either authToken/HONUA_MCP_AUTH_TOKEN or apiKey/HONUA_ADMIN_KEY/HONUA_API_KEY");
18
+ }
19
+ return hasBearer ? "bearer" : hasApiKey ? "api-key" : "anonymous";
20
+ }
21
+ function validateProxyOptions(options) {
22
+ const authMode = validateAuthentication(options);
23
+ return requireSecureCredentialEndpoint(options.remoteUrl, "remoteUrl", authMode !== "anonymous");
24
+ }
9
25
  export function resolveProxyOptions(env = process.env) {
10
26
  const remoteUrl = env.HONUA_MCP_REMOTE_URL ?? env.HONUA_MCP_URL;
11
27
  if (!remoteUrl) {
12
28
  throw new Error("HONUA_MCP_REMOTE_URL environment variable is required (the remote honua /mcp endpoint to proxy).");
13
29
  }
14
- let parsed;
15
- try {
16
- parsed = new URL(remoteUrl);
17
- }
18
- catch {
19
- throw new Error(`HONUA_MCP_REMOTE_URL must be a valid absolute URL: ${remoteUrl}`);
20
- }
21
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
22
- throw new Error(`HONUA_MCP_REMOTE_URL must use http or https: ${remoteUrl}`);
30
+ const hasAdminKey = isConfigured(env.HONUA_ADMIN_KEY);
31
+ const hasApiKey = isConfigured(env.HONUA_API_KEY);
32
+ if (hasAdminKey && hasApiKey) {
33
+ throw new Error("Configure one API-key source: unset either HONUA_ADMIN_KEY or HONUA_API_KEY; credential precedence is not allowed");
23
34
  }
24
- return {
25
- remoteUrl: parsed.toString(),
35
+ const options = {
36
+ remoteUrl,
26
37
  authToken: env.HONUA_MCP_AUTH_TOKEN,
27
- apiKey: env.HONUA_API_KEY,
38
+ apiKey: hasAdminKey ? env.HONUA_ADMIN_KEY : hasApiKey ? env.HONUA_API_KEY : undefined,
28
39
  };
40
+ const parsed = validateProxyOptions(options);
41
+ return { ...options, remoteUrl: parsed.toString() };
29
42
  }
30
43
  /** Build request headers for the upstream connection from the resolved options. */
31
44
  export function buildUpstreamHeaders(options) {
45
+ validateProxyOptions(options);
32
46
  const headers = {};
33
47
  if (options.authToken) {
34
48
  headers.Authorization = `Bearer ${options.authToken}`;
@@ -41,8 +55,9 @@ export function buildUpstreamHeaders(options) {
41
55
  /** Connect an upstream MCP client to the remote honua /mcp over streamable HTTP. */
42
56
  export async function connectUpstream(options) {
43
57
  const headers = buildUpstreamHeaders(options);
44
- const transport = new StreamableHTTPClientTransport(new URL(options.remoteUrl), {
45
- requestInit: Object.keys(headers).length > 0 ? { headers } : undefined,
58
+ const remoteUrl = validateProxyOptions(options);
59
+ const transport = new StreamableHTTPClientTransport(remoteUrl, {
60
+ requestInit: { ...(Object.keys(headers).length > 0 ? { headers } : {}), redirect: "manual" },
46
61
  });
47
62
  const client = new Client({ name: "honua-mcp-stdio-proxy", version: SERVER_VERSION });
48
63
  await client.connect(transport);
@@ -0,0 +1,34 @@
1
+ import { type JourneyPauseSnapshot, type JourneyReceiptRequest, type JourneyResumeState } from "./zero-to-map.js";
2
+ export declare const ZERO_TO_MAP_CHECKPOINT_SCHEMA: "honua.zero-to-map.checkpoint/v1";
3
+ export declare const ZERO_TO_MAP_CHECKPOINT_MAX_AGE_MS: number;
4
+ export interface ZeroToMapCheckpointBindings {
5
+ readonly journeyId: string;
6
+ readonly releaseContract: string;
7
+ readonly target: "local-docker" | "aws-ecs";
8
+ readonly planSha256: string;
9
+ readonly sourceRevision: string;
10
+ readonly mcpEndpointSha256: string;
11
+ readonly candidateId: string;
12
+ readonly releaseId: string;
13
+ readonly provisionReceiptSha256?: string;
14
+ }
15
+ export interface ZeroToMapCheckpoint extends ZeroToMapCheckpointBindings {
16
+ readonly schemaVersion: typeof ZERO_TO_MAP_CHECKPOINT_SCHEMA;
17
+ readonly state: "paused" | "consumed";
18
+ readonly createdAt: string;
19
+ readonly resume: JourneyResumeState;
20
+ readonly consoleReceiptRequest: JourneyReceiptRequest;
21
+ readonly consumedAt?: string;
22
+ readonly finalReceiptSha256?: string;
23
+ readonly integrity: {
24
+ readonly algorithm: "sha256";
25
+ readonly digest: string;
26
+ };
27
+ }
28
+ export declare function createZeroToMapCheckpoint(bindings: ZeroToMapCheckpointBindings, snapshot: JourneyPauseSnapshot, createdAt?: string): ZeroToMapCheckpoint;
29
+ export declare function consumeZeroToMapCheckpoint(checkpoint: ZeroToMapCheckpoint, finalReceiptSha256: string, consumedAt?: string): ZeroToMapCheckpoint;
30
+ export declare function parseZeroToMapCheckpoint(value: unknown): ZeroToMapCheckpoint;
31
+ export declare function assertZeroToMapCheckpointFresh(checkpoint: ZeroToMapCheckpoint, now?: Date): void;
32
+ export declare function assertZeroToMapCheckpointDigest(checkpoint: ZeroToMapCheckpoint, expectedDigest: string): void;
33
+ export declare function assertZeroToMapCheckpointBindings(checkpoint: ZeroToMapCheckpoint, expected: ZeroToMapCheckpointBindings): void;
34
+ //# sourceMappingURL=zero-to-map-checkpoint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zero-to-map-checkpoint.d.ts","sourceRoot":"","sources":["../../../src/release/zero-to-map-checkpoint.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAE1B,KAAK,kBAAkB,EAMxB,MAAM,kBAAkB,CAAC;AAE1B,eAAO,MAAM,6BAA6B,EAAG,iCAA0C,CAAC;AACxF,eAAO,MAAM,iCAAiC,QAAuB,CAAC;AAEtE,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,SAAS,CAAC;IAC5C,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,sBAAsB,CAAC,EAAE,MAAM,CAAC;CAC1C;AAED,MAAM,WAAW,mBAAoB,SAAQ,2BAA2B;IACtE,QAAQ,CAAC,aAAa,EAAE,OAAO,6BAA6B,CAAC;IAC7D,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,UAAU,CAAC;IACtC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC;IACpC,QAAQ,CAAC,qBAAqB,EAAE,qBAAqB,CAAC;IACtD,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE;QAClB,QAAQ,CAAC,SAAS,EAAE,QAAQ,CAAC;QAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;KACzB,CAAC;CACH;AAID,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,2BAA2B,EACrC,QAAQ,EAAE,oBAAoB,EAC9B,SAAS,SAA2B,GACnC,mBAAmB,CAqBrB;AAED,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,mBAAmB,EAC/B,kBAAkB,EAAE,MAAM,EAC1B,UAAU,SAA2B,GACpC,mBAAmB,CAIrB;AAED,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAkF5E;AAED,wBAAgB,8BAA8B,CAAC,UAAU,EAAE,mBAAmB,EAAE,GAAG,OAAa,GAAG,IAAI,CAKtG;AAED,wBAAgB,+BAA+B,CAAC,UAAU,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,GAAG,IAAI,CAI7G;AAED,wBAAgB,iCAAiC,CAC/C,UAAU,EAAE,mBAAmB,EAC/B,QAAQ,EAAE,2BAA2B,GACpC,IAAI,CAIN"}