@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.
- package/LICENSE +201 -0
- package/README.md +232 -9
- package/dist/src/certification/admin-parity.d.ts +96 -0
- package/dist/src/certification/admin-parity.d.ts.map +1 -0
- package/dist/src/certification/admin-parity.js +235 -0
- package/dist/src/certification/census-fixture-client.d.ts.map +1 -1
- package/dist/src/certification/census-fixture-client.js +5 -0
- package/dist/src/certification/certifier.d.ts +1 -1
- package/dist/src/certification/certifier.d.ts.map +1 -1
- package/dist/src/certification/certifier.js +28 -20
- package/dist/src/certification/cli.js +1 -1
- package/dist/src/certification/cql2.d.ts +24 -0
- package/dist/src/certification/cql2.d.ts.map +1 -0
- package/dist/src/certification/cql2.js +354 -0
- package/dist/src/certification/fixtures.d.ts +8 -0
- package/dist/src/certification/fixtures.d.ts.map +1 -1
- package/dist/src/certification/fixtures.js +26 -10
- package/dist/src/certification/ogc-data.d.ts +30 -0
- package/dist/src/certification/ogc-data.d.ts.map +1 -0
- package/dist/src/certification/ogc-data.js +726 -0
- package/dist/src/certification/ogc-fixture-client.d.ts +4 -0
- package/dist/src/certification/ogc-fixture-client.d.ts.map +1 -0
- package/dist/src/certification/ogc-fixture-client.js +190 -0
- package/dist/src/certification/target.d.ts +10 -1
- package/dist/src/certification/target.d.ts.map +1 -1
- package/dist/src/certification/target.js +63 -28
- package/dist/src/credential-endpoint.d.ts +3 -0
- package/dist/src/credential-endpoint.d.ts.map +1 -0
- package/dist/src/credential-endpoint.js +24 -0
- package/dist/src/eval/cli.js +6 -3
- package/dist/src/eval/corpus.d.ts +7 -0
- package/dist/src/eval/corpus.d.ts.map +1 -1
- package/dist/src/eval/corpus.js +12 -0
- package/dist/src/eval/ogc-corpus.d.ts +3 -0
- package/dist/src/eval/ogc-corpus.d.ts.map +1 -0
- package/dist/src/eval/ogc-corpus.js +437 -0
- package/dist/src/eval/runner.d.ts +6 -0
- package/dist/src/eval/runner.d.ts.map +1 -1
- package/dist/src/eval/runner.js +21 -7
- package/dist/src/helpers.d.ts +8 -13
- package/dist/src/helpers.d.ts.map +1 -1
- package/dist/src/helpers.js +7 -35
- package/dist/src/index.d.ts +36 -8
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +55 -18
- package/dist/src/neutral/errors.d.ts +73 -0
- package/dist/src/neutral/errors.d.ts.map +1 -0
- package/dist/src/neutral/errors.js +112 -0
- package/dist/src/neutral/filter.d.ts +108 -0
- package/dist/src/neutral/filter.d.ts.map +1 -0
- package/dist/src/neutral/filter.js +271 -0
- package/dist/src/neutral/query.d.ts +101 -0
- package/dist/src/neutral/query.d.ts.map +1 -0
- package/dist/src/neutral/query.js +180 -0
- package/dist/src/neutral/result.d.ts +33 -0
- package/dist/src/neutral/result.d.ts.map +1 -0
- package/dist/src/neutral/result.js +38 -0
- package/dist/src/neutral/source-ref.d.ts +126 -0
- package/dist/src/neutral/source-ref.d.ts.map +1 -0
- package/dist/src/neutral/source-ref.js +267 -0
- package/dist/src/nl-map-control.d.ts.map +1 -1
- package/dist/src/proxy.d.ts.map +1 -1
- package/dist/src/proxy.js +29 -14
- package/dist/src/release/zero-to-map-checkpoint.d.ts +34 -0
- package/dist/src/release/zero-to-map-checkpoint.d.ts.map +1 -0
- package/dist/src/release/zero-to-map-checkpoint.js +369 -0
- package/dist/src/release/zero-to-map-cli.d.ts +51 -0
- package/dist/src/release/zero-to-map-cli.d.ts.map +1 -0
- package/dist/src/release/zero-to-map-cli.js +880 -0
- package/dist/src/release/zero-to-map-provision.d.ts +37 -0
- package/dist/src/release/zero-to-map-provision.d.ts.map +1 -0
- package/dist/src/release/zero-to-map-provision.js +177 -0
- package/dist/src/release/zero-to-map.d.ts +296 -0
- package/dist/src/release/zero-to-map.d.ts.map +1 -0
- package/dist/src/release/zero-to-map.js +1069 -0
- package/dist/src/tools/admin-install-local.d.ts +30 -0
- package/dist/src/tools/admin-install-local.d.ts.map +1 -0
- package/dist/src/tools/admin-install-local.js +22 -0
- package/dist/src/tools/control-plane-command.d.ts +99 -0
- package/dist/src/tools/control-plane-command.d.ts.map +1 -0
- package/dist/src/tools/control-plane-command.js +180 -0
- package/dist/src/tools/count-features.d.ts +85 -11
- package/dist/src/tools/count-features.d.ts.map +1 -1
- package/dist/src/tools/count-features.js +49 -31
- package/dist/src/tools/describe-layer.d.ts +30 -6
- package/dist/src/tools/describe-layer.d.ts.map +1 -1
- package/dist/src/tools/describe-layer.js +99 -8
- package/dist/src/tools/docs-search.d.ts +100 -0
- package/dist/src/tools/docs-search.d.ts.map +1 -0
- package/dist/src/tools/docs-search.js +381 -0
- package/dist/src/tools/get-extent.d.ts +69 -11
- package/dist/src/tools/get-extent.d.ts.map +1 -1
- package/dist/src/tools/get-extent.js +28 -46
- package/dist/src/tools/list-services.d.ts +7 -0
- package/dist/src/tools/list-services.d.ts.map +1 -1
- package/dist/src/tools/list-services.js +8 -1
- package/dist/src/tools/list-sources.d.ts +44 -0
- package/dist/src/tools/list-sources.d.ts.map +1 -0
- package/dist/src/tools/list-sources.js +138 -0
- package/dist/src/tools/query-features.d.ts +99 -19
- package/dist/src/tools/query-features.d.ts.map +1 -1
- package/dist/src/tools/query-features.js +38 -45
- package/dist/src/tools/statistics.d.ts +80 -12
- package/dist/src/tools/statistics.d.ts.map +1 -1
- package/dist/src/tools/statistics.js +56 -23
- package/package.json +37 -8
- package/release/zero-to-map/README.md +174 -0
- package/release/zero-to-map/configs/claude-code.mcp.json +11 -0
- package/release/zero-to-map/configs/claude-desktop.json +11 -0
- package/release/zero-to-map/configs/cursor.json +11 -0
- package/release/zero-to-map/contracts/aws-ecs-provision-binding.schema.json +59 -0
- package/release/zero-to-map/contracts/checkpoint.schema.json +152 -0
- package/release/zero-to-map/contracts/console-receipt.schema.json +150 -0
- package/release/zero-to-map/contracts/esri-gp-mcp.v1.json +73 -0
- package/release/zero-to-map/fixtures/parcels.geojson +33 -0
- package/release/zero-to-map/fixtures/zoning.geojson +24 -0
- 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":"AAAA,OAAO,EACL,KAAK,wBAAwB,
|
|
1
|
+
{"version":3,"file":"nl-map-control.d.ts","sourceRoot":"","sources":["../../src/nl-map-control.ts"],"names":[],"mappings":"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"}
|
package/dist/src/proxy.d.ts.map
CHANGED
|
@@ -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;
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
25
|
-
remoteUrl
|
|
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
|
|
45
|
-
|
|
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"}
|