@unmap/geocoding 0.12.0 → 0.14.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/dist/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { RetryPolicy, UnmapError } from '@unmap/core';
2
+ export { RetryPolicy, UnmapError, parseRetryAfter } from '@unmap/core';
3
+
1
4
  /**
2
5
  * Framework-free port of Township Canada's legal-land regex grammar
3
6
  * (`api/packages/shared/regex_rules.js` + `helpers.processInput`).
@@ -211,6 +214,126 @@ type StructuredParseResult = {
211
214
  /** Normalise and validate raw structured input. Returns the cleaned query or one error string. */
212
215
  declare function parseStructuredQuery(raw: Partial<Record<string, string | undefined>>): StructuredParseResult;
213
216
 
217
+ /**
218
+ * Treaty context: `include=treaties` on `/geocode/search` and `/geocode/reverse`.
219
+ *
220
+ * The contract is frozen in `docs/indigenous-context/contract.md`; the decision behind its shape
221
+ * is `docs/decisions/2026-09-22-treaty-context-on-geocode.md`. These types and parsers are shared
222
+ * by the gateway, the civic geocode container and the SDK, like every other request parser here.
223
+ *
224
+ * What the data is, so nothing downstream overstates it: two CIRNAC datasets of the Crown's
225
+ * published treaty representations. A match is a spatial match to a representation, not a
226
+ * determination of rights, title or territory, and `ok` with no matches means "no record in this
227
+ * dataset", never "unceded" and never "no Indigenous rights".
228
+ */
229
+ declare const INCLUDE_VALUES: readonly ["treaties"];
230
+ type IncludeValue = (typeof INCLUDE_VALUES)[number];
231
+ /**
232
+ * Release C values (docs/indigenous-context/community-pilot.md). Refused unless the deployment has
233
+ * switched community context on, which it must not do before a community source is admitted under
234
+ * an agreement with human review (CLAUDE.md rule 6).
235
+ */
236
+ declare const COMMUNITY_INCLUDE_VALUES: readonly ["territories", "acknowledgements"];
237
+ type CommunityIncludeValue = (typeof COMMUNITY_INCLUDE_VALUES)[number];
238
+ interface IncludeParse {
239
+ treaties: boolean;
240
+ territories: boolean;
241
+ acknowledgements: boolean;
242
+ }
243
+ type TreatyPointBasis = "result_point" | "input_point";
244
+ type TreatyCategory = "historic" | "modern";
245
+ type TreatyGeographyKind = "treaty_area" | "overall_treaty_area" | "settlement_land" | "rights_area" | "other" | "unspecified";
246
+ type TreatyRepresentation = "approximate" | "illustrative" | "unspecified";
247
+ type TreatyLang = "en" | "fr";
248
+ interface TreatyMatch {
249
+ /** `<source_id>:<source_record_id>`, stable across refreshes. */
250
+ id: string;
251
+ /** Registry id of the publishing dataset, e.g. `treaties.cirnac-historic`. */
252
+ source_id: string;
253
+ /** The publisher's own key (CIRNAC `TAG_ID`). */
254
+ source_record_id: string;
255
+ category: TreatyCategory;
256
+ /** In the requested language when the source has it; `name_lang` says which it is. */
257
+ name: string;
258
+ name_lang: TreatyLang;
259
+ names: {
260
+ en?: string;
261
+ fr?: string;
262
+ };
263
+ /** The publisher's subtype label ("Numbered Treaty"), same language rule as `name`. */
264
+ subtype?: string;
265
+ subtypes?: {
266
+ en?: string;
267
+ fr?: string;
268
+ };
269
+ geography_kind: TreatyGeographyKind;
270
+ representation: TreatyRepresentation;
271
+ /** Publisher dataset page. Always http(s). */
272
+ source_url: string;
273
+ }
274
+ interface TreatyContext {
275
+ schema_version: 1;
276
+ /** Null only when no version could be resolved; never null when `status` is `ok`. */
277
+ dataset_version: string | null;
278
+ status: "ok" | "unavailable";
279
+ point: {
280
+ lng: number;
281
+ lat: number;
282
+ basis: TreatyPointBasis;
283
+ };
284
+ coverage: {
285
+ scope: "Canada";
286
+ completeness: "partial";
287
+ };
288
+ /** Always empty when `status` is `unavailable`. */
289
+ matches: TreatyMatch[];
290
+ notice_code: "source_limitations_apply";
291
+ }
292
+ /** `include=` on the two endpoints that accept it. Absent or empty means nothing extra. */
293
+ declare function parseInclude(raw: string | undefined, options?: {
294
+ community?: boolean;
295
+ }): IncludeParse | {
296
+ error: string;
297
+ };
298
+ /**
299
+ * `YYYY-MM-DD.` plus twelve lowercase hex characters, with a date that exists. Checked before a
300
+ * version reaches SQL or an R2 key, so `../` and friends never get that far.
301
+ */
302
+ declare function isTreatiesVersion(value: string): boolean;
303
+ declare function parseTreatiesVersion(raw: string | undefined, treatiesIncluded: boolean): {
304
+ version: string | undefined;
305
+ } | {
306
+ error: string;
307
+ };
308
+ /**
309
+ * The label to show for `lang`, and the language it is actually in. `fr` (and `fr-CA`) prefers
310
+ * French; everything else prefers English. The other language is a fallback that is reported,
311
+ * never presented as a translation. No label at all is `undefined`: nothing is invented.
312
+ */
313
+ declare function pickTreatyLabel(labels: {
314
+ en?: string;
315
+ fr?: string;
316
+ }, lang: string): {
317
+ text: string;
318
+ lang: TreatyLang;
319
+ } | undefined;
320
+ /** Historic before modern, then by id; a record delivered twice appears once. */
321
+ declare function orderTreatyMatches(matches: readonly TreatyMatch[]): TreatyMatch[];
322
+ /**
323
+ * Runtime check of a `treaties` object, including the two invariants the type cannot express:
324
+ * `ok` carries a version, and `unavailable` carries no matches. Throws a TypeError otherwise.
325
+ */
326
+ declare function parseTreatyContext(value: unknown): TreatyContext;
327
+ /**
328
+ * The `treaties` object for a lookup that could not run. Shared so the container and the
329
+ * gateway (which enriches legal-land and energy results) produce byte-identical failures.
330
+ */
331
+ declare function unavailableTreatyContext(point: {
332
+ lng: number;
333
+ lat: number;
334
+ basis: TreatyPointBasis;
335
+ }): TreatyContext;
336
+
214
337
  /**
215
338
  * Energy-query detect for wells / facilities.
216
339
  *
@@ -485,6 +608,192 @@ type FocusParse = {
485
608
  } | undefined;
486
609
  declare function parseFocus(raw: string | undefined): FocusParse;
487
610
 
611
+ /**
612
+ * Release C: territories and acknowledgement resources (docs/indigenous-context/community-pilot.md,
613
+ * community-review-packet.md). Built and tested on synthetic data only. No community source is
614
+ * admitted, so a deployment answers `not_enabled` at best, and refuses these include values
615
+ * unless community context has been switched on.
616
+ *
617
+ * The semantics carried here are the review packet's: a territory match is a source-defined
618
+ * record, never an inference from proximity; `community_ids` are relationships the source states;
619
+ * an acknowledgement resource applies only through a reviewed relationship to a matched territory,
620
+ * never by city name or nearest reserve; exact text appears only where republication is permitted,
621
+ * and is never generated or machine-translated.
622
+ */
623
+ /** `not_enabled`: nothing admitted for this collection. Not a successful empty lookup. */
624
+ type CommunityStatus = "ok" | "not_enabled" | "unavailable";
625
+ interface TerritoryMatch {
626
+ /** `<source_id>:<source_record_id>`. */
627
+ id: string;
628
+ source_id: string;
629
+ source_record_id: string;
630
+ name: string;
631
+ /** Language tag of `name` as the source supplied it. */
632
+ name_lang: string;
633
+ /** Only the names and language tags the source supplied. */
634
+ names: Record<string, string>;
635
+ /** Communities the source relates to this record. Never inferred. */
636
+ community_ids: string[];
637
+ representation: "approximate" | "illustrative" | "source_defined";
638
+ source_url: string;
639
+ attribution: string;
640
+ }
641
+ interface TerritoryContext {
642
+ schema_version: 1;
643
+ dataset_version: string | null;
644
+ status: CommunityStatus;
645
+ point: {
646
+ lng: number;
647
+ lat: number;
648
+ basis: TreatyPointBasis;
649
+ };
650
+ coverage: {
651
+ scope: "source_defined";
652
+ completeness: "partial";
653
+ };
654
+ matches: TerritoryMatch[];
655
+ notice_code: "source_limitations_apply";
656
+ }
657
+ interface AcknowledgementResource {
658
+ id: string;
659
+ source_id: string;
660
+ title: string;
661
+ /** The approved original. Always present, so a client can link when it cannot show text. */
662
+ url: string;
663
+ /** Language of the resource as approved. Resources are not translated. */
664
+ language: string;
665
+ attribution: string;
666
+ /** The reviewed explanation of where and how the resource applies. */
667
+ applicability: string;
668
+ /** Territory ids the partner linked this resource to. The only way a resource is matched. */
669
+ applies_to: string[];
670
+ reviewed_at: string;
671
+ content_version: string;
672
+ /** Exact approved wording, only where the agreement permits republication. */
673
+ text?: string;
674
+ }
675
+ interface AcknowledgementContext {
676
+ schema_version: 1;
677
+ dataset_version: string | null;
678
+ status: CommunityStatus;
679
+ point: {
680
+ lng: number;
681
+ lat: number;
682
+ basis: TreatyPointBasis;
683
+ };
684
+ resources: AcknowledgementResource[];
685
+ notice_code: "source_limitations_apply";
686
+ }
687
+ /**
688
+ * The name to show for `lang`: the requested primary language when supplied, otherwise the
689
+ * source's own default. Nothing is translated or invented; `undefined` if neither exists.
690
+ */
691
+ declare function pickCommunityName(names: Record<string, string>, lang: string, defaultLang: string): {
692
+ text: string;
693
+ lang: string;
694
+ } | undefined;
695
+ declare function emptyTerritoryContext(p: {
696
+ lng: number;
697
+ lat: number;
698
+ basis: TreatyPointBasis;
699
+ }, status: Exclude<CommunityStatus, "ok">): TerritoryContext;
700
+ declare function emptyAcknowledgementContext(p: {
701
+ lng: number;
702
+ lat: number;
703
+ basis: TreatyPointBasis;
704
+ }, status: Exclude<CommunityStatus, "ok">): AcknowledgementContext;
705
+ declare function parseTerritoryContext(value: unknown): TerritoryContext;
706
+ declare function parseAcknowledgementContext(value: unknown): AcknowledgementContext;
707
+
708
+ /**
709
+ * Treaty overlay controller (docs/indigenous-context/contract.md, "Tiles").
710
+ *
711
+ * Drawing is the style's job: `overlays: ["treaties"]` composes the catalog layer, in the style's
712
+ * own colours. This helper does the rest: shows or hides historic and modern, and answers "which
713
+ * treaties are here" for a clicked point or a point a keyboard user supplied. The answer comes
714
+ * from the geocoder's full-resolution lookup, never from the tile features, because a tile may
715
+ * have simplified away a small record; the clicked features only say which dataset version is on
716
+ * screen, and every lookup is pinned to it.
717
+ *
718
+ * Each lookup is one reverse geocode call. Creating the controller, toggling and restyling make
719
+ * no requests.
720
+ */
721
+ /** The layer ids `overlays: ["treaties"]` composes (apps/gateway/src/overlays.ts). */
722
+ declare function treatyLayerIds(category: TreatyCategory): [fill: string, line: string];
723
+ /** The slice of a MapLibre map this controller uses. */
724
+ interface TreatyMapLike {
725
+ on(type: "click", listener: (e: {
726
+ lngLat: {
727
+ lng: number;
728
+ lat: number;
729
+ };
730
+ point: unknown;
731
+ }) => void): unknown;
732
+ on(type: "styledata", listener: () => void): unknown;
733
+ off(type: "click", listener: (e: {
734
+ lngLat: {
735
+ lng: number;
736
+ lat: number;
737
+ };
738
+ point: unknown;
739
+ }) => void): unknown;
740
+ off(type: "styledata", listener: () => void): unknown;
741
+ getLayer(id: string): unknown;
742
+ setLayoutProperty(id: string, name: "visibility", value: "visible" | "none"): unknown;
743
+ queryRenderedFeatures(point: unknown, options: {
744
+ layers: string[];
745
+ }): Array<{
746
+ properties?: Record<string, unknown> | null;
747
+ }>;
748
+ }
749
+ /** Anything with the geocoder's `reverse`: `unmap.geocoder`, or a `Geocoder`. */
750
+ interface TreatyLookupClient {
751
+ reverse(lng: number, lat: number, opts?: ReverseOptions): Promise<GeocodeResult[]>;
752
+ }
753
+ interface TreatySelection {
754
+ /** Treaty context for the point, from the full-resolution lookup. */
755
+ context: TreatyContext;
756
+ /** Record ids drawn under the point on screen, deduplicated across tile fragments. */
757
+ drawn: string[];
758
+ /** Categories currently hidden on the map. Their matches are still in `context`. */
759
+ hidden: TreatyCategory[];
760
+ }
761
+ interface TreatyOverlayOptions {
762
+ historic?: boolean;
763
+ modern?: boolean;
764
+ lang?: "en" | "fr";
765
+ /** Answer map clicks. Default true; false leaves lookups to `lookupAt`. */
766
+ interactive?: boolean;
767
+ /** The latest selection. A superseded or destroyed lookup never calls this. */
768
+ onSelect?(selection: TreatySelection): void;
769
+ /**
770
+ * A lookup failed. `code: "treaties_version_not_found"` means the drawn version has been
771
+ * retired: show it as unavailable and offer to reload the map, never newer details.
772
+ */
773
+ onError?(error: Error & {
774
+ code?: string;
775
+ }): void;
776
+ }
777
+ interface TreatyOverlayController {
778
+ setVisibility(value: {
779
+ historic?: boolean;
780
+ modern?: boolean;
781
+ }): void;
782
+ readonly visibility: {
783
+ historic: boolean;
784
+ modern: boolean;
785
+ };
786
+ setLanguage(lang: "en" | "fr"): void;
787
+ /**
788
+ * Treaty context for a point: the non-canvas path (a geocoder result, typed coordinates).
789
+ * `datasetVersion` pins it; omitted, it pins to whatever the map last showed at a click, or the
790
+ * current release when nothing has been clicked.
791
+ */
792
+ lookupAt(point: [number, number], datasetVersion?: string): Promise<TreatySelection | undefined>;
793
+ destroy(): void;
794
+ }
795
+ declare function createTreatyOverlay(map: TreatyMapLike, client: TreatyLookupClient, options?: TreatyOverlayOptions): TreatyOverlayController;
796
+
488
797
  /** Every recognised spelling, lowercase, mapped to its two-letter code. */
489
798
  declare const REGIONS: Readonly<Record<string, string>>;
490
799
  /**
@@ -573,11 +882,175 @@ declare function parseRuralRoute(q: string): RuralRouteQuery | null;
573
882
  */
574
883
  declare function looksLikeRuralRoute(q: string): boolean;
575
884
 
885
+ /**
886
+ * Typed client for the Places API (gateway `/places/*`).
887
+ *
888
+ * It lives in `@unmap/geocoding` rather than in a package of its own because places ARE the
889
+ * geocoding corpus: the same rows, the same container, the same taxonomy. A twelfth npm package
890
+ * would also mean a twelfth entry in the changesets fixed group and a twelfth trusted publisher
891
+ * to configure, which is real founder work for no boundary that exists in the code.
892
+ *
893
+ * `Geocoder.nearby()` is untouched and still answers in the geocoder's own shape. This is the
894
+ * Place shape over the same rows.
895
+ */
896
+ /** A Canadian point of interest, as `/places/*` returns it. */
897
+ interface Place {
898
+ /** `um:place:<id>`. Opaque: a corpus rebuild may renumber the tail, so do not parse it. */
899
+ id: string;
900
+ /** The corpus id, for `POST /places/{id}/feedback`. */
901
+ source_id: string;
902
+ name: string;
903
+ /** Every language and alternate spelling the corpus holds, including syllabics where recorded. */
904
+ names: Record<string, string>;
905
+ /** Taxonomy id, e.g. `finance.bank`. */
906
+ category: string | null;
907
+ /** The part before the dot, e.g. `finance`. */
908
+ category_group: string | null;
909
+ /** `[lng, lat]`, WGS84. */
910
+ coordinates: [number, number];
911
+ address: {
912
+ housenumber?: string;
913
+ street?: string;
914
+ city?: string;
915
+ region?: string;
916
+ postcode?: string;
917
+ country?: string;
918
+ };
919
+ /** Metres from the anchor. Only on `nearby()`. */
920
+ distance?: number;
921
+ /** Registry id of the dataset, for provenance. */
922
+ source: string;
923
+ }
924
+ /**
925
+ * The envelope `/places/*` answers in.
926
+ *
927
+ * `meta` is deliberately surfaced rather than unwrapped away: a caller that cannot see
928
+ * `attribution` cannot comply with the licence the data came under, and one that cannot see
929
+ * `status` cannot tell fresh data from stale.
930
+ */
931
+ interface PlacesResponse<T> {
932
+ data: T;
933
+ meta: {
934
+ status: "current" | "stale" | "partial" | "unknown";
935
+ attribution: string;
936
+ unmap_updated_at: string;
937
+ source?: string;
938
+ source_updated_at?: string | null;
939
+ };
940
+ }
941
+ interface PlacesOptions {
942
+ key: string;
943
+ gateway?: string;
944
+ fetch?: typeof fetch;
945
+ /**
946
+ * Retry policy for `429`, `502`, `503` and transport failures. `false` disables it.
947
+ *
948
+ * On by default. `Retry-After` is on a `429` other than `billing_required`, and on a container
949
+ * `503`. A `502` has none: routing uses `routing_failed`, and `/elevation` uses
950
+ * `upstream_error`. With no header the client backs off itself. A wait longer than
951
+ * `maxDelayMs` (10 s) is not slept through; the error carries `retryAfterSeconds` instead.
952
+ * See `RetryPolicy` in `@unmap/core`.
953
+ */
954
+ retry?: RetryPolicy | false;
955
+ }
956
+ interface PlaceSearchOptions {
957
+ limit?: number;
958
+ lang?: string;
959
+ /**
960
+ * [minLng, minLat, maxLng, maxLat] hard filter. Excludes; name the city in the query to merely prefer.
961
+ * A corner outside WGS84 is status 400, code `bad_request`. A box outside Canada stays a filter.
962
+ */
963
+ bbox?: [number, number, number, number];
964
+ signal?: AbortSignal;
965
+ }
966
+ interface PlaceNearbyOptions {
967
+ /** `[lng, lat]`. Exactly one of `near` or `bbox`. */
968
+ near?: [number, number];
969
+ bbox?: [number, number, number, number];
970
+ /** Metres, clamped server-side to 50..50000. */
971
+ radius?: number;
972
+ limit?: number;
973
+ lang?: string;
974
+ signal?: AbortSignal;
975
+ }
976
+ /**
977
+ * A places failure.
978
+ *
979
+ * Extends `UnmapError`, so `catch (e) { if (e instanceof UnmapError) }` catches this alongside
980
+ * every other unmap client's errors. `instanceof PlacesError` keeps working, and `status` and `code`
981
+ * are still where they were; `retryAfterSeconds` is new and comes from the header.
982
+ */
983
+ declare class PlacesError extends UnmapError {
984
+ constructor(status: number, message: string, code?: string, retryAfterSeconds?: number);
985
+ }
986
+ /**
987
+ * Canadian places.
988
+ *
989
+ * const places = new Places({ key: "um_live_..." });
990
+ * const { data } = await places.nearby("bakery", { near: [-114.07, 51.05] });
991
+ *
992
+ * ## Fields this does not carry
993
+ *
994
+ * No `phone`, `website`, `opening_hours`, `accessibility` or `operator`. The corpus does not hold
995
+ * them, so they are ABSENT from the response rather than null: an absent key is a statement about
996
+ * unmap's coverage and is true, while `"phone": null` would be a statement about the place and
997
+ * usually a false one. The types above reflect that rather than declaring optional fields nothing
998
+ * ever populates.
999
+ */
1000
+ declare class Places {
1001
+ private readonly key;
1002
+ private readonly base;
1003
+ private readonly fetchImpl;
1004
+ private readonly retry;
1005
+ constructor(opts: PlacesOptions);
1006
+ /**
1007
+ * Search places by name.
1008
+ *
1009
+ * Unlike `Geocoder.search()`, which returns whatever best matches and for "Calgary" is the city
1010
+ * itself, this returns places. A missing query is 400 `bad_request` (`q is required`). A bbox
1011
+ * corner outside WGS84 is the same status and code. A box outside Canada stays a filter.
1012
+ */
1013
+ search(q: string, opts?: PlaceSearchOptions): Promise<PlacesResponse<Place[]>>;
1014
+ /**
1015
+ * Places of a category near a point.
1016
+ *
1017
+ * `category` takes a taxonomy id (`health.pharmacy`) or a word in English or French
1018
+ * (`pharmacy`, `pharmacie`); the gateway resolves aliases, so `"boulangerie"` works. An anchor
1019
+ * outside Canada rejects with status 422 and code `outside_coverage`. A longitude or latitude
1020
+ * outside WGS84, including a bbox corner, rejects with status 400 and code `bad_request`.
1021
+ */
1022
+ nearby(category: string | readonly string[], opts?: PlaceNearbyOptions): Promise<PlacesResponse<Place[]>>;
1023
+ /**
1024
+ * One place by its unmap id.
1025
+ *
1026
+ * Throws `PlacesError` with status 404 when it does not exist. A malformed id is also a 404,
1027
+ * because from a caller's side "does not exist" and "is not a well-formed id" are the same
1028
+ * answer; the gateway's message distinguishes them as far as it honestly can.
1029
+ */
1030
+ get(id: string, opts?: {
1031
+ lang?: string;
1032
+ signal?: AbortSignal;
1033
+ }): Promise<PlacesResponse<Place>>;
1034
+ private request;
1035
+ }
1036
+
1037
+ /** Largest `queries` array `POST /geocode/batch` accepts. Payload size, not pool size. */
1038
+ declare const GEOCODE_BATCH_MAX = 100;
576
1039
  interface GeocoderOptions {
577
1040
  key: string;
578
1041
  gateway?: string;
579
1042
  /** Override the fetch implementation (tests, non-global environments). */
580
1043
  fetch?: typeof fetch;
1044
+ /**
1045
+ * Retry policy for `429`, `502`, `503` and transport failures. `false` disables it.
1046
+ *
1047
+ * On by default. `Retry-After` is on a `429` other than `billing_required`, and on a container
1048
+ * `503`. A `502` has none. The client that reads the header is better placed to honour it than
1049
+ * every caller re-deriving the same loop, and it backs off itself when the header is absent.
1050
+ * A wait longer than `maxDelayMs` (10 s) is not slept through; the error carries
1051
+ * `retryAfterSeconds` instead. See `RetryPolicy` in `@unmap/core`.
1052
+ */
1053
+ retry?: RetryPolicy | false;
581
1054
  }
582
1055
  type GeocodeLayer = "address" | "street" | "locality" | "region" | "poi" | "legal_land" | "well" | "facility" | "parcel";
583
1056
  /**
@@ -657,11 +1130,19 @@ interface GeocodeResult {
657
1130
  type: "Polygon" | "MultiPolygon";
658
1131
  coordinates: number[][][] | number[][][][];
659
1132
  };
1133
+ /**
1134
+ * Treaty context for this result, only with `include=treaties`. On search it describes the
1135
+ * result's own point; on reverse, the coordinate that was sent.
1136
+ */
1137
+ treaties?: TreatyContext;
660
1138
  }
661
1139
  interface SearchOptions {
662
1140
  limit?: number;
663
1141
  lang?: string;
664
- /** [minLng, minLat, maxLng, maxLat] hard filter. Excludes; see `focus` to merely prefer. */
1142
+ /**
1143
+ * [minLng, minLat, maxLng, maxLat] hard filter. Excludes; see `focus` to merely prefer.
1144
+ * A corner outside WGS84 is status 400, code `bad_request`. A box outside Canada stays a filter.
1145
+ */
665
1146
  bbox?: [number, number, number, number];
666
1147
  /** [lng, lat] soft proximity preference. Moves ranking toward the point, excludes nothing. */
667
1148
  focus?: [number, number];
@@ -677,6 +1158,21 @@ interface SearchOptions {
677
1158
  region?: string;
678
1159
  signal?: AbortSignal;
679
1160
  }
1161
+ /**
1162
+ * Treaty context (`include=treaties`), on `search` and `reverse` only. See TreatyContext: a match
1163
+ * is to the Crown's published representation, and an empty `ok` is not a statement about rights.
1164
+ */
1165
+ interface TreatyOptions {
1166
+ /** `["treaties"]` adds `treaties` to every result. Omitted, responses are unchanged. */
1167
+ include?: IncludeValue[];
1168
+ /** Pin the treaty dataset version (e.g. the one a map overlay feature carries). */
1169
+ treatiesVersion?: string;
1170
+ }
1171
+ interface ReverseOptions extends TreatyOptions {
1172
+ lang?: string;
1173
+ limit?: number;
1174
+ signal?: AbortSignal;
1175
+ }
680
1176
  interface NearbyOptions {
681
1177
  /** [lng, lat] anchor to sort by distance from. Exactly one of `near` or `bbox`. */
682
1178
  near?: [number, number];
@@ -688,22 +1184,30 @@ interface NearbyOptions {
688
1184
  lang?: string;
689
1185
  signal?: AbortSignal;
690
1186
  }
691
- declare class GeocoderError extends Error {
692
- readonly status: number;
693
- /** The gateway's machine-readable `code`, when the response carried one (e.g. `unauthorized`). */
694
- readonly code?: string | undefined;
695
- constructor(status: number, message: string,
696
- /** The gateway's machine-readable `code`, when the response carried one (e.g. `unauthorized`). */
697
- code?: string | undefined);
1187
+ /**
1188
+ * A geocoding failure.
1189
+ *
1190
+ * Extends `UnmapError`, so `catch (e) { if (e instanceof UnmapError) }` catches this alongside
1191
+ * every other unmap client's errors. `instanceof GeocoderError` keeps working, and `status` and
1192
+ * `code` are still where they were; `retryAfterSeconds` is new and comes from the header.
1193
+ */
1194
+ declare class GeocoderError extends UnmapError {
1195
+ constructor(status: number, message: string, code?: string, retryAfterSeconds?: number);
698
1196
  }
699
1197
  /** Typed client for the unmap geocoding API (gateway `/geocode/*`). */
700
1198
  declare class Geocoder {
701
1199
  private readonly key;
702
1200
  private readonly base;
703
1201
  private readonly fetchImpl;
1202
+ private readonly retry;
704
1203
  constructor(opts: GeocoderOptions);
705
1204
  /** Full-text search. */
706
- search(q: string, opts?: SearchOptions): Promise<GeocodeResult[]>;
1205
+ search(q: string, opts?: SearchOptions & TreatyOptions): Promise<GeocodeResult[]>;
1206
+ /**
1207
+ * Many searches in one or more `POST /geocode/batch` calls, chunked at
1208
+ * {@link GEOCODE_BATCH_MAX}. Results stay aligned to `queries`.
1209
+ */
1210
+ batch(queries: string[], opts?: SearchOptions): Promise<GeocodeResult[][]>;
707
1211
  /** Type-ahead suggestions for partial input. */
708
1212
  autocomplete(q: string, opts?: SearchOptions): Promise<GeocodeResult[]>;
709
1213
  /**
@@ -719,14 +1223,17 @@ declare class Geocoder {
719
1223
  * Category search: POIs of a kind near a point, sorted by distance (metres, in each
720
1224
  * result's `distance`). `category` takes canonical taxonomy ids ("health.pharmacy") or
721
1225
  * plain words in English or French ("pharmacy", "pharmacie") — the gateway resolves
722
- * aliases, so this client passes the value through untouched.
1226
+ * aliases, so this client passes the value through untouched. An anchor outside Canada rejects
1227
+ * with status 422 and code `outside_coverage`; the corpus is not queried. A longitude or
1228
+ * latitude outside WGS84, including a bbox corner, rejects with status 400 and code `bad_request`.
723
1229
  */
724
1230
  nearby(category: string | string[], opts?: NearbyOptions): Promise<GeocodeResult[]>;
725
- /** Reverse geocode a coordinate. */
726
- reverse(lng: number, lat: number, opts?: {
727
- lang?: string;
728
- signal?: AbortSignal;
729
- }): Promise<GeocodeResult[]>;
1231
+ /**
1232
+ * Reverse geocode a coordinate. A point outside Canada rejects with status 422 and code
1233
+ * `outside_coverage`. A longitude or latitude outside WGS84 rejects with status 400 and code
1234
+ * `bad_request`.
1235
+ */
1236
+ reverse(lng: number, lat: number, opts?: ReverseOptions): Promise<GeocodeResult[]>;
730
1237
  /**
731
1238
  * Which catalog features contain a point. Default layer is `municipalities`
732
1239
  * (core). `survey.dls` / `survey.nts` need the `legal-land` add-on.
@@ -742,8 +1249,9 @@ declare class Geocoder {
742
1249
  * layers need `mining`. Empty until the matching table is loaded.
743
1250
  */
744
1251
  queryLayer(opts: QueryOptions): Promise<QueryResponse>;
1252
+ private postJson;
745
1253
  private requestJson;
746
1254
  private query;
747
1255
  }
748
1256
 
749
- export { AMBIGUOUS_SCORE_RATIO, CIVIC_SEARCH_LAYERS, type CivicSearchLayer, CsvParser, type CsvProblem, type CsvRecord, DEFAULT_IDENTIFY_LAYERS, DEFAULT_QUERY_LIMIT, ENERGY_IDENTIFY_LAYER_IDS, ENERGY_SEARCH_LAYERS, type EnergyDetails, type EnergyQuery, type EnergyQueryKind, type EnergySearchLayer, type FocusParse, type GeocodeLayer, type GeocodeMatchReason, type GeocodeMatchType, type GeocodePrecision, type GeocodeResult, type GeocodeSource, Geocoder, GeocoderError, type GeocoderOptions, IDENTIFY_LAYER_IDS, type IdentifyLayerId, type IdentifyOptions, type IdentifyResponse, type IdentifyResult, LAND_IDENTIFY_LAYER_IDS, type LegalLandComponents, type LegalLandDetails, type LegalLandLayerSystem, type LegalLandParse, type LegalLandSystem, type LegalLandUnit, MAX_QUERY_LIMIT, MINING_IDENTIFY_LAYER_IDS, type NearbyOptions, OUTPUT_COLUMNS, OUTPUT_PREFIX, type OutputColumn, type ParcelQuery, QUERY_LAYER_IDS, type QueryBbox, type QueryLayerId, type QueryOptions, type QueryResponse, REGIONS, REGION_CODES, REGION_KEYS, type ReviewReason, type RowStatus, type RuralRouteKind, type RuralRouteQuery, STRUCTURED_FIELDS, type SearchLayersParse, type SearchOptions, type StructuredOptions, type StructuredParseResult, type StructuredQuery, alignRow, classify, encodeField, encodeRow, energySearchRequested, escapeForSpreadsheet, isEnergyIdentifyLayer, isEnergySearchSource, isIdentifyLayer, isLandIdentifyLayer, knownIdentifyLayers, knownQueryLayers, knownSearchLayers, looksLikeEnergyQuery, looksLikeFormula, looksLikeLegalLand, looksLikeParcel, looksLikeRuralRoute, outputValues, parseEnergyQuery, parseEnergySearchLayers, parseFocus, parseIdentifyAt, parseIdentifyLayers, parseLegalLand, parseParcel, parseQueryBbox, parseQueryLayer, parseQueryLimit, parseRegion, parseRuralRoute, parseSearchLayers, parseStructuredQuery, regionForms, resolveOutputHeader, toLegalLandDetails };
1257
+ export { AMBIGUOUS_SCORE_RATIO, type AcknowledgementContext, type AcknowledgementResource, CIVIC_SEARCH_LAYERS, COMMUNITY_INCLUDE_VALUES, type CivicSearchLayer, type CommunityIncludeValue, type CommunityStatus, CsvParser, type CsvProblem, type CsvRecord, DEFAULT_IDENTIFY_LAYERS, DEFAULT_QUERY_LIMIT, ENERGY_IDENTIFY_LAYER_IDS, ENERGY_SEARCH_LAYERS, type EnergyDetails, type EnergyQuery, type EnergyQueryKind, type EnergySearchLayer, type FocusParse, GEOCODE_BATCH_MAX, type GeocodeLayer, type GeocodeMatchReason, type GeocodeMatchType, type GeocodePrecision, type GeocodeResult, type GeocodeSource, Geocoder, GeocoderError, type GeocoderOptions, IDENTIFY_LAYER_IDS, INCLUDE_VALUES, type IdentifyLayerId, type IdentifyOptions, type IdentifyResponse, type IdentifyResult, type IncludeParse, type IncludeValue, LAND_IDENTIFY_LAYER_IDS, type LegalLandComponents, type LegalLandDetails, type LegalLandLayerSystem, type LegalLandParse, type LegalLandSystem, type LegalLandUnit, MAX_QUERY_LIMIT, MINING_IDENTIFY_LAYER_IDS, type NearbyOptions, OUTPUT_COLUMNS, OUTPUT_PREFIX, type OutputColumn, type ParcelQuery, type Place, type PlaceNearbyOptions, type PlaceSearchOptions, Places, PlacesError, type PlacesOptions, type PlacesResponse, QUERY_LAYER_IDS, type QueryBbox, type QueryLayerId, type QueryOptions, type QueryResponse, REGIONS, REGION_CODES, REGION_KEYS, type ReverseOptions, type ReviewReason, type RowStatus, type RuralRouteKind, type RuralRouteQuery, STRUCTURED_FIELDS, type SearchLayersParse, type SearchOptions, type StructuredOptions, type StructuredParseResult, type StructuredQuery, type TerritoryContext, type TerritoryMatch, type TreatyCategory, type TreatyContext, type TreatyGeographyKind, type TreatyLang, type TreatyLookupClient, type TreatyMapLike, type TreatyMatch, type TreatyOptions, type TreatyOverlayController, type TreatyOverlayOptions, type TreatyPointBasis, type TreatyRepresentation, type TreatySelection, alignRow, classify, createTreatyOverlay, emptyAcknowledgementContext, emptyTerritoryContext, encodeField, encodeRow, energySearchRequested, escapeForSpreadsheet, isEnergyIdentifyLayer, isEnergySearchSource, isIdentifyLayer, isLandIdentifyLayer, isTreatiesVersion, knownIdentifyLayers, knownQueryLayers, knownSearchLayers, looksLikeEnergyQuery, looksLikeFormula, looksLikeLegalLand, looksLikeParcel, looksLikeRuralRoute, orderTreatyMatches, outputValues, parseAcknowledgementContext, parseEnergyQuery, parseEnergySearchLayers, parseFocus, parseIdentifyAt, parseIdentifyLayers, parseInclude, parseLegalLand, parseParcel, parseQueryBbox, parseQueryLayer, parseQueryLimit, parseRegion, parseRuralRoute, parseSearchLayers, parseStructuredQuery, parseTerritoryContext, parseTreatiesVersion, parseTreatyContext, pickCommunityName, pickTreatyLabel, regionForms, resolveOutputHeader, toLegalLandDetails, treatyLayerIds, unavailableTreatyContext };