@chrtco/sdk 0.8.1 → 0.9.1
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/CHANGELOG.md +40 -0
- package/dist/atlas/browser.cjs +4311 -5
- package/dist/atlas/browser.cjs.map +1 -1
- package/dist/atlas/browser.d.cts +29 -1
- package/dist/atlas/browser.d.ts +29 -1
- package/dist/atlas/browser.js +4308 -5
- package/dist/atlas/browser.js.map +1 -1
- package/dist/index.cjs +8581 -657
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1395 -163
- package/dist/index.d.ts +1395 -163
- package/dist/index.js +8516 -657
- package/dist/index.js.map +1 -1
- package/package.json +3 -20
package/dist/index.d.cts
CHANGED
|
@@ -434,21 +434,172 @@ declare class HttpClient {
|
|
|
434
434
|
}>;
|
|
435
435
|
}
|
|
436
436
|
|
|
437
|
+
/**
|
|
438
|
+
* Tile authentication for the `tiles.chrt.co` PMTiles path.
|
|
439
|
+
*
|
|
440
|
+
* The CHRT tile-worker serves raw MVT at
|
|
441
|
+
* `https://tiles.chrt.co/v1/tiles/{region}/{z}/{x}/{y}.mvt`
|
|
442
|
+
* and authenticates each request with a short-lived ES256 JWT (5-min default,
|
|
443
|
+
* 15-min max) carried in the `Authorization: Bearer` header. This module mints
|
|
444
|
+
* those JWTs from the customer's API key and produces a MapLibre / Mapbox GL
|
|
445
|
+
* `transformRequest` that attaches the Bearer to tile requests only.
|
|
446
|
+
*
|
|
447
|
+
* Responsibilities (mirrors the first-party web client at
|
|
448
|
+
* `src/lib/map/tile-token-client.ts`, adapted to be instance-scoped and
|
|
449
|
+
* zero-dependency so it runs in browsers, Node 18+, Deno, and Bun):
|
|
450
|
+
* - Mint via `POST {baseUrl}/mint/tile-token` (default
|
|
451
|
+
* `https://api.chrt.co/v1/mint/tile-token`) with the `x-api-key` header.
|
|
452
|
+
* - Cache tokens in memory, keyed by region; refresh silently 30s before
|
|
453
|
+
* expiry so long-lived maps never flicker.
|
|
454
|
+
* - Expose a SYNC `transformRequest` (MapLibre requires sync) that attaches
|
|
455
|
+
* the cached Bearer; it kicks off a background mint on first use so the
|
|
456
|
+
* cache warms within one round-trip.
|
|
457
|
+
*
|
|
458
|
+
* NOTE: the public mint route `POST /v1/mint/tile-token` (the sibling of the
|
|
459
|
+
* existing `/v1/mint/offline-token`) must be present on the `api.chrt.co`
|
|
460
|
+
* edge worker for this path to serve. Until it lands, mints fail with a
|
|
461
|
+
* network/HTTP error surfaced through `getToken()`.
|
|
462
|
+
*/
|
|
463
|
+
|
|
464
|
+
/** Default chart region — the one consolidated PMTiles served per region. */
|
|
465
|
+
declare const DEFAULT_TILE_REGION = "NOAA_ENC";
|
|
466
|
+
/** Default tile-worker origin. Override via `ChrtConfig.tileBaseUrl`. */
|
|
467
|
+
declare const DEFAULT_TILE_BASE_URL = "https://tiles.chrt.co";
|
|
468
|
+
/** Full token response from the mint endpoint. */
|
|
469
|
+
interface TileTokenResponse {
|
|
470
|
+
/** ES256-signed JWT; do not log. */
|
|
471
|
+
token: string;
|
|
472
|
+
/** Unix seconds (matches JWT `exp`). */
|
|
473
|
+
expiresAt: number;
|
|
474
|
+
/** Key id used to sign (matches JWT header `kid`). */
|
|
475
|
+
kid: string;
|
|
476
|
+
/** Build id/tag pinned into the JWT — the tile-worker cache key. */
|
|
477
|
+
buildTag: string;
|
|
478
|
+
/** Echo of the region the token is scoped to. */
|
|
479
|
+
region: string;
|
|
480
|
+
}
|
|
481
|
+
/** Typed error codes the mint flow surfaces; callers switch on `.code`. */
|
|
482
|
+
type TileTokenErrorCode = "invalid_api_key" | "feature_flag_disabled" | "region_not_licensed" | "tile_quota_exceeded" | "region_not_available" | "network_error" | "unexpected_response";
|
|
483
|
+
declare class TileTokenError extends Error {
|
|
484
|
+
readonly code: TileTokenErrorCode;
|
|
485
|
+
readonly status?: number;
|
|
486
|
+
constructor(code: TileTokenErrorCode, message: string, status?: number);
|
|
487
|
+
}
|
|
488
|
+
/** MapLibre / Mapbox GL `transformRequest` return shape. */
|
|
489
|
+
interface TransformedRequest {
|
|
490
|
+
url: string;
|
|
491
|
+
headers?: Record<string, string>;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* Instance-scoped tile-token manager. One per `Chrt` client so multiple
|
|
495
|
+
* clients (e.g. different API keys) never share a cache.
|
|
496
|
+
*/
|
|
497
|
+
declare class TileAuth {
|
|
498
|
+
private readonly http;
|
|
499
|
+
private readonly cache;
|
|
500
|
+
private readonly pending;
|
|
501
|
+
private readonly defaultRegion;
|
|
502
|
+
private readonly tileBaseUrl;
|
|
503
|
+
private lifecycleRegistered;
|
|
504
|
+
constructor(http: HttpClient, opts?: {
|
|
505
|
+
region?: string;
|
|
506
|
+
tileBaseUrl?: string;
|
|
507
|
+
});
|
|
508
|
+
/** Mint once via the HTTP client (POST `/mint/tile-token`, `x-api-key`). */
|
|
509
|
+
private mintOnce;
|
|
510
|
+
/** Mint with exponential backoff on network errors only. */
|
|
511
|
+
private mintWithRetry;
|
|
512
|
+
private scheduleRefresh;
|
|
513
|
+
private refreshInBackground;
|
|
514
|
+
private store;
|
|
515
|
+
/**
|
|
516
|
+
* Fetch (or reuse a cached) tile token for `region`. Concurrent callers for
|
|
517
|
+
* the same region await the same in-flight mint.
|
|
518
|
+
*/
|
|
519
|
+
getToken(region?: string): Promise<TileTokenResponse>;
|
|
520
|
+
/** Synchronous cache peek — null if absent or within the stale grace window. */
|
|
521
|
+
peek(region?: string): string | null;
|
|
522
|
+
/**
|
|
523
|
+
* Produce a MapLibre / Mapbox GL `transformRequest`. Attaches
|
|
524
|
+
* `Authorization: Bearer <jwt>` only to CHRT tile URLs and the CHRT
|
|
525
|
+
* served-style URL (`/v1/styles/{region}/style.json`); sprite, glyph, and
|
|
526
|
+
* third-party URLs pass through untouched (never leak the token to
|
|
527
|
+
* third-party CDNs). Kicks off a background mint immediately so the cache
|
|
528
|
+
* warms within one round-trip; the first tile or two may go
|
|
529
|
+
* unauthenticated and be retried by the renderer. When pointing a map's
|
|
530
|
+
* `style` at the served style URL, obtain it via `chrt.styleUrl()` — it
|
|
531
|
+
* awaits the mint, so the style request (which MapLibre does NOT retry)
|
|
532
|
+
* is guaranteed to carry auth.
|
|
533
|
+
*/
|
|
534
|
+
transformRequest(region?: string): (url: string) => TransformedRequest | undefined;
|
|
535
|
+
/** Clear the cached token + timer for a region. */
|
|
536
|
+
invalidate(region?: string): void;
|
|
537
|
+
/**
|
|
538
|
+
* Browser-only defense against `setTimeout` freezing while a tab is
|
|
539
|
+
* suspended (laptop sleep, mobile background, bfcache restore): proactively
|
|
540
|
+
* re-mint near-expiry entries on wake. Inert under SSR / Node / Deno.
|
|
541
|
+
*/
|
|
542
|
+
private registerLifecycleHandlers;
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/** Palette themes served by the Style API (S-52 colour tables). */
|
|
546
|
+
type ChrtStyleTheme = "day" | "dusk" | "night";
|
|
547
|
+
interface StyleUrlOptions {
|
|
548
|
+
/** Palette: "day" (default), "dusk", or "night". Omit to get the style's
|
|
549
|
+
* default — for keys with a bound CHRTstyle custom style, that's the
|
|
550
|
+
* style's default palette. */
|
|
551
|
+
theme?: ChrtStyleTheme;
|
|
552
|
+
/** Symbol artwork family: "s52" (default) or "s101" (official S-101
|
|
553
|
+
* Portrayal Catalogue symbols). Load the matching images client-side
|
|
554
|
+
* via `loadS101SymbolImages` / `loadChrtSymbolImages` from
|
|
555
|
+
* `@chrtco/sdk/atlas/browser`. */
|
|
556
|
+
symbols?: "s52" | "s101" | "chrt";
|
|
557
|
+
}
|
|
558
|
+
interface FetchStyleOptions extends StyleUrlOptions {
|
|
559
|
+
signal?: AbortSignal;
|
|
560
|
+
}
|
|
437
561
|
declare class TilesEndpoint {
|
|
438
562
|
private http;
|
|
563
|
+
private tileAuth;
|
|
439
564
|
private readonly region;
|
|
440
565
|
private readonly tileBaseUrl;
|
|
441
|
-
constructor(http: HttpClient, opts?: {
|
|
566
|
+
constructor(http: HttpClient, tileAuth: TileAuth, opts?: {
|
|
442
567
|
region?: string;
|
|
443
568
|
tileBaseUrl?: string;
|
|
444
569
|
});
|
|
570
|
+
private styleEndpoint;
|
|
571
|
+
/**
|
|
572
|
+
* URL of the served S-52 style for the configured region — the CHRTstyle
|
|
573
|
+
* Style API (`GET /v1/styles/{region}/style.json`). The served document
|
|
574
|
+
* honors the API key's bound custom style (a Dev+ feature configured at
|
|
575
|
+
* platform → Map Styles); Free keys and unbound keys get the default
|
|
576
|
+
* themes, identical to the locally generated `chrt.style()`.
|
|
577
|
+
*
|
|
578
|
+
* The endpoint is JWT-gated, so pair the URL with
|
|
579
|
+
* `chrt.transformRequest()`, which attaches the Bearer token to both the
|
|
580
|
+
* style request and its tile requests. This method is async because it
|
|
581
|
+
* pre-mints the tile token, guaranteeing the auth cache is warm before
|
|
582
|
+
* MapLibre fetches the URL.
|
|
583
|
+
*
|
|
584
|
+
* @example
|
|
585
|
+
* const map = new maplibregl.Map({
|
|
586
|
+
* container: 'map',
|
|
587
|
+
* style: await chrt.styleUrl({ theme: 'dusk' }),
|
|
588
|
+
* transformRequest: chrt.transformRequest(),
|
|
589
|
+
* });
|
|
590
|
+
*/
|
|
591
|
+
styleUrl(opts?: StyleUrlOptions): Promise<string>;
|
|
445
592
|
/**
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
593
|
+
* Fetch the served S-52 style as a MapLibre style object (see
|
|
594
|
+
* {@link styleUrl} for what "served" means). Prefer this over `styleUrl()`
|
|
595
|
+
* when you want to inspect or mutate the document, or when you can't use
|
|
596
|
+
* `transformRequest` for the style request itself.
|
|
597
|
+
*
|
|
598
|
+
* Falls back nowhere: a network or auth failure throws (`ChrtError` /
|
|
599
|
+
* `TileTokenError`). For an offline-capable local fallback, use
|
|
600
|
+
* `chrt.style()` — the client-side generator.
|
|
450
601
|
*/
|
|
451
|
-
|
|
602
|
+
fetchStyle(opts?: FetchStyleOptions): Promise<MapLibreStyle>;
|
|
452
603
|
/**
|
|
453
604
|
* Vector tile URL template for the configured region, served by the
|
|
454
605
|
* tile-worker at `tiles.chrt.co`. Tiles are JWT-gated — pair this with
|
|
@@ -574,6 +725,775 @@ declare class OfflineEndpoint {
|
|
|
574
725
|
private persistManifestEntry;
|
|
575
726
|
}
|
|
576
727
|
|
|
728
|
+
/** Style-layer ids (CHRT S-52 atlas) that carry point nav-aid features. */
|
|
729
|
+
declare const NAV_AID_QUERY_LAYERS: string[];
|
|
730
|
+
/** Style-layer ids for area / hazard / regulated / infrastructure features. */
|
|
731
|
+
declare const AREA_QUERY_LAYERS: string[];
|
|
732
|
+
/**
|
|
733
|
+
* Bridge style layers, queried separately so bridges win over overlapping
|
|
734
|
+
* area polygons (click order: nav-aid → bridge → area).
|
|
735
|
+
*/
|
|
736
|
+
declare const BRIDGE_QUERY_LAYERS: string[];
|
|
737
|
+
interface DecodedBridge {
|
|
738
|
+
name: string | null;
|
|
739
|
+
categoryCode: number | null;
|
|
740
|
+
categoryLabel: string | null;
|
|
741
|
+
verticalClearance: number | null;
|
|
742
|
+
verticalClearanceClosed: number | null;
|
|
743
|
+
verticalClearanceOpen: number | null;
|
|
744
|
+
horizontalClearance: number | null;
|
|
745
|
+
status: string | null;
|
|
746
|
+
condition: string | null;
|
|
747
|
+
information: string | null;
|
|
748
|
+
nationalName: string | null;
|
|
749
|
+
sourceIndication: string | null;
|
|
750
|
+
sourceDate: string | null;
|
|
751
|
+
}
|
|
752
|
+
/** Decode a BRIDGE feature's S-57 attributes into a typed record. */
|
|
753
|
+
declare function decodeBridgeProps(props: Record<string, unknown>): DecodedBridge;
|
|
754
|
+
/** A decoded label/value row, ready for direct display. */
|
|
755
|
+
interface DecodedProperty {
|
|
756
|
+
label: string;
|
|
757
|
+
value: string;
|
|
758
|
+
}
|
|
759
|
+
interface DecodedAreaFeature {
|
|
760
|
+
type: string;
|
|
761
|
+
title: string;
|
|
762
|
+
properties: DecodedProperty[];
|
|
763
|
+
}
|
|
764
|
+
/** Decode properties for area/hazard/regulated features into a human-readable record. */
|
|
765
|
+
declare function decodeAreaFeatureProps(layerName: string, props: Record<string, unknown>): DecodedAreaFeature;
|
|
766
|
+
interface SectorInfo {
|
|
767
|
+
sectorStart: number;
|
|
768
|
+
sectorEnd: number;
|
|
769
|
+
colour: string;
|
|
770
|
+
colourHex: string;
|
|
771
|
+
notation: string;
|
|
772
|
+
nominalRange?: number | null;
|
|
773
|
+
}
|
|
774
|
+
interface DecodedNavAid {
|
|
775
|
+
name: string;
|
|
776
|
+
/** Full official OBJNAM (e.g., "Boston South Channel Buoy 7") */
|
|
777
|
+
fullName: string | null;
|
|
778
|
+
type: string;
|
|
779
|
+
layerName: string;
|
|
780
|
+
colour: string | null;
|
|
781
|
+
colourHex: string;
|
|
782
|
+
/** Primary light colour hex (from co-located LIGHTS or own COLOUR for LIGHTS features) */
|
|
783
|
+
lightColourHex: string;
|
|
784
|
+
/** All light colours for alternating lights (e.g. ["#ffffff", "#ef4444"] for W R) */
|
|
785
|
+
colourHexList: string[];
|
|
786
|
+
shape: string | null;
|
|
787
|
+
topmark: string | null;
|
|
788
|
+
topmarkMeaning: string | null;
|
|
789
|
+
lightCharacter: string | null;
|
|
790
|
+
lightCharacterFull: string | null;
|
|
791
|
+
period: number | null;
|
|
792
|
+
group: number[] | null;
|
|
793
|
+
fogSignal: string | null;
|
|
794
|
+
fogSignalAbbr: string | null;
|
|
795
|
+
radarReflector: boolean;
|
|
796
|
+
depth: number | null;
|
|
797
|
+
status: string | null;
|
|
798
|
+
markingSystem: string | null;
|
|
799
|
+
category: string | null;
|
|
800
|
+
information: string | null;
|
|
801
|
+
notation: string;
|
|
802
|
+
coordinates: [number, number] | null;
|
|
803
|
+
sectors: SectorInfo[];
|
|
804
|
+
orientation: number | null;
|
|
805
|
+
isDirectional: boolean;
|
|
806
|
+
isSectorLight: boolean;
|
|
807
|
+
}
|
|
808
|
+
/**
|
|
809
|
+
* Parse ALL numeric codes from a list-type S-57 attribute (COLOUR, RESTRN, …).
|
|
810
|
+
* List attributes arrive as native arrays (["1","3"]) on the GeoJSON source
|
|
811
|
+
* path, JSON-stringified arrays ('["1","3"]') after tippecanoe/PMTiles, or
|
|
812
|
+
* comma/semicolon-separated scalars in legacy/normalized data.
|
|
813
|
+
*/
|
|
814
|
+
declare function parseListCodes(val: unknown): number[];
|
|
815
|
+
/**
|
|
816
|
+
* Derive a mariner shorthand name from a verbose S-57 OBJNAM + COLOUR.
|
|
817
|
+
* e.g. "Weymouth Back River Channel Lighted Buoy 8" + COLOUR=3 → R "8"
|
|
818
|
+
*/
|
|
819
|
+
declare function deriveMarinerName(objnam: string, colourCode: number | null): string;
|
|
820
|
+
/**
|
|
821
|
+
* What an S-57 TOPSHP topmark *denotes* given the parent buoy/beacon layer.
|
|
822
|
+
*
|
|
823
|
+
* IALA topmark shapes carry the same meaning in IALA-A and IALA-B regions —
|
|
824
|
+
* only the colour conventions differ between regions — so the meaning is a
|
|
825
|
+
* function of (TOPSHP, parent layer) and we don't need to consult MARSYS.
|
|
826
|
+
*
|
|
827
|
+
* Returns null when the shape/parent combination has no canonical meaning
|
|
828
|
+
* (e.g. a board topmark on a private daymark), so callers can simply skip
|
|
829
|
+
* rendering the hint.
|
|
830
|
+
*/
|
|
831
|
+
declare function getTopmarkMeaning(topshpCode: number | null, rawLayer: string): string | null;
|
|
832
|
+
declare function decodeNavAidProps(layerName: string, props: Record<string, unknown>, coords?: [number, number]): DecodedNavAid;
|
|
833
|
+
interface FlashPhase {
|
|
834
|
+
on: boolean;
|
|
835
|
+
duration: number;
|
|
836
|
+
color?: string;
|
|
837
|
+
}
|
|
838
|
+
interface FlashPattern {
|
|
839
|
+
phases: FlashPhase[];
|
|
840
|
+
totalCycle: number;
|
|
841
|
+
notation: string;
|
|
842
|
+
}
|
|
843
|
+
declare function buildFlashPattern(decoded: DecodedNavAid): FlashPattern | null;
|
|
844
|
+
/** Minimal GeoJSON shapes for the sector-arc builders (kept dependency-free). */
|
|
845
|
+
interface SectorArcFeature {
|
|
846
|
+
type: "Feature";
|
|
847
|
+
properties: Record<string, unknown>;
|
|
848
|
+
geometry: {
|
|
849
|
+
type: "Polygon" | "LineString" | "Point";
|
|
850
|
+
coordinates: unknown;
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
interface SectorArcFeatureCollection {
|
|
854
|
+
type: "FeatureCollection";
|
|
855
|
+
features: SectorArcFeature[];
|
|
856
|
+
}
|
|
857
|
+
/**
|
|
858
|
+
* Build all sectors from multiple LIGHTS features at the same position.
|
|
859
|
+
* Each LIGHTS feature with SECTR1/SECTR2 defines one sector.
|
|
860
|
+
*/
|
|
861
|
+
declare function buildSectorsFromFeatures(features: Array<{
|
|
862
|
+
properties: Record<string, unknown>;
|
|
863
|
+
}>): SectorInfo[];
|
|
864
|
+
/**
|
|
865
|
+
* Generate a GeoJSON arc polygon for a sector light.
|
|
866
|
+
* Bearings are TRUE bearings FROM the light (as seen FROM a vessel).
|
|
867
|
+
* S-57 SECTR1/SECTR2 define the arc as seen FROM seaward looking AT the light,
|
|
868
|
+
* so we draw arcs in bearing order from the light's position.
|
|
869
|
+
*
|
|
870
|
+
* When `innerRadiusNm > 0`, the polygon is an annulus segment (band) —
|
|
871
|
+
* a ring slice between the inner and outer radius — instead of a pie wedge.
|
|
872
|
+
*
|
|
873
|
+
* @param center [lng, lat]
|
|
874
|
+
* @param startBearing degrees true (clockwise from north)
|
|
875
|
+
* @param endBearing degrees true
|
|
876
|
+
* @param radiusNm outer radius in nautical miles
|
|
877
|
+
* @param innerRadiusNm inner radius in nautical miles (0 = pie wedge)
|
|
878
|
+
* @param steps number of arc segments
|
|
879
|
+
*/
|
|
880
|
+
declare function buildSectorArcGeoJSON(center: [number, number], startBearing: number, endBearing: number, radiusNm?: number, innerRadiusNm?: number, steps?: number): SectorArcFeature;
|
|
881
|
+
/**
|
|
882
|
+
* Build a complete GeoJSON FeatureCollection of sector arcs for rendering.
|
|
883
|
+
* Each feature has color/notation properties for styling.
|
|
884
|
+
*
|
|
885
|
+
* Default behavior is a thin band (annulus segment) at the perimeter —
|
|
886
|
+
* sectors read as a colored ring around the light rather than a pie wedge.
|
|
887
|
+
* Set `innerRadiusFrac = 0` for the legacy pie-wedge appearance.
|
|
888
|
+
*/
|
|
889
|
+
declare function buildSectorArcsFC(center: [number, number], sectors: SectorInfo[], radiusNm?: number, innerRadiusFrac?: number): SectorArcFeatureCollection;
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Safety & attribution invariants for CHRTinteract.
|
|
893
|
+
*
|
|
894
|
+
* Per `.chrt/ai-agent-guide.md` §"Safety & Disclaimers" and the platform's
|
|
895
|
+
* non-negotiable stewardship invariants, EVERY InspectResult and the built-in
|
|
896
|
+
* popup MUST carry:
|
|
897
|
+
* 1. the non-SOLAS "not for primary navigation" disclaimer,
|
|
898
|
+
* 2. issuing hydrographic-office attribution, and
|
|
899
|
+
* 3. data currency (edition / update_number / issue_date once known).
|
|
900
|
+
*
|
|
901
|
+
* Wording matches the canonical text in `@chrtco/mcp` (`safety.ts`) so it can
|
|
902
|
+
* never drift between surfaces. Do not weaken or remove.
|
|
903
|
+
*/
|
|
904
|
+
|
|
905
|
+
/** The canonical non-SOLAS disclaimer. Present on every InspectResult. */
|
|
906
|
+
declare const NON_SOLAS_DISCLAIMER: string;
|
|
907
|
+
/** Short form for space-constrained UI (the built-in popup footer). */
|
|
908
|
+
declare const NON_SOLAS_DISCLAIMER_SHORT = "Not for primary navigation";
|
|
909
|
+
/** Safety, attribution, and currency context attached to every InspectResult. */
|
|
910
|
+
interface InspectNotice {
|
|
911
|
+
/** Non-SOLAS disclaimer — always `NON_SOLAS_DISCLAIMER`. */
|
|
912
|
+
disclaimer: string;
|
|
913
|
+
/** Issuing hydrographic-office / source attribution line. */
|
|
914
|
+
attribution: string;
|
|
915
|
+
/**
|
|
916
|
+
* Data-currency line. Before enrichment this states how to resolve currency;
|
|
917
|
+
* after `inspect({ enrich: true })` it carries the source cell's edition,
|
|
918
|
+
* update number, and issue date.
|
|
919
|
+
*/
|
|
920
|
+
dataCurrency: string;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
/**
|
|
924
|
+
* Public types for CHRTinteract — click-to-inspect for CHRT charts.
|
|
925
|
+
*/
|
|
926
|
+
|
|
927
|
+
/**
|
|
928
|
+
* A chart feature to inspect. Structurally compatible with a MapLibre / Mapbox
|
|
929
|
+
* GL `MapGeoJSONFeature` (what `queryRenderedFeatures` returns), and with a
|
|
930
|
+
* plain `{ layer, properties }` object for headless use.
|
|
931
|
+
*/
|
|
932
|
+
interface InspectableFeature {
|
|
933
|
+
/** Vector-tile attributes (LITCHR, COLOUR, OBJNAM, …). */
|
|
934
|
+
properties?: Record<string, unknown> | null;
|
|
935
|
+
/** MVT source-layer name, e.g. "BOYLAT" (set by queryRenderedFeatures). */
|
|
936
|
+
sourceLayer?: string;
|
|
937
|
+
/** Style layer that rendered the feature, or a raw layer name string. */
|
|
938
|
+
layer?: {
|
|
939
|
+
id?: string;
|
|
940
|
+
} | string;
|
|
941
|
+
/** GeoJSON geometry — Point coordinates locate the popup / enrichment. */
|
|
942
|
+
geometry?: {
|
|
943
|
+
type?: string;
|
|
944
|
+
coordinates?: unknown;
|
|
945
|
+
} | null;
|
|
946
|
+
}
|
|
947
|
+
interface InspectOptions {
|
|
948
|
+
/**
|
|
949
|
+
* Override the layer used for decoding (style-layer id like "enc-BOYLAT" or
|
|
950
|
+
* raw S-57 name like "BOYLAT"). Defaults to the feature's own layer.
|
|
951
|
+
*/
|
|
952
|
+
layer?: string;
|
|
953
|
+
/** Coordinates [lng, lat] when the feature's geometry doesn't carry them. */
|
|
954
|
+
coordinates?: [number, number];
|
|
955
|
+
/**
|
|
956
|
+
* Fetch full S-57 properties + source-cell provenance (edition, update,
|
|
957
|
+
* issue date) through the CHRT features API. **Metered** — counts against
|
|
958
|
+
* the key's monthly `featureCalls` quota.
|
|
959
|
+
*/
|
|
960
|
+
enrich?: boolean;
|
|
961
|
+
/** AbortSignal for the enrichment fetches. */
|
|
962
|
+
signal?: AbortSignal;
|
|
963
|
+
}
|
|
964
|
+
/** Source-cell provenance + full properties resolved by `enrich: true`. */
|
|
965
|
+
interface InspectEnrichment {
|
|
966
|
+
/** Whether a matching feature was found in the features API. */
|
|
967
|
+
matched: boolean;
|
|
968
|
+
/** Full S-57 properties from the source data (superset of tile attrs). */
|
|
969
|
+
properties: Record<string, unknown> | null;
|
|
970
|
+
/** The ENC cell the feature came from. */
|
|
971
|
+
cellId: string | null;
|
|
972
|
+
/** Cell metadata — edition / update_number / issue_date live here. */
|
|
973
|
+
cell: CellDetail | null;
|
|
974
|
+
}
|
|
975
|
+
interface InspectResultCommon {
|
|
976
|
+
/** Raw S-57 object class, e.g. "BOYLAT". */
|
|
977
|
+
layer: string;
|
|
978
|
+
/** The style-layer id the feature was resolved from, e.g. "enc-BOYLAT". */
|
|
979
|
+
layerId: string;
|
|
980
|
+
/** Human-readable object class, e.g. "Lateral Buoy". */
|
|
981
|
+
objectClass: string;
|
|
982
|
+
/** Display title (mariner shorthand, OBJNAM, or object class). */
|
|
983
|
+
title: string;
|
|
984
|
+
/** [lng, lat] when known. */
|
|
985
|
+
coordinates: [number, number] | null;
|
|
986
|
+
/** Decoded, display-ready label/value rows. */
|
|
987
|
+
properties: DecodedProperty[];
|
|
988
|
+
/** The merged tile attributes the decode ran on. */
|
|
989
|
+
raw: Record<string, unknown>;
|
|
990
|
+
/** Non-SOLAS disclaimer + HO attribution + data currency. Always present. */
|
|
991
|
+
notice: InspectNotice;
|
|
992
|
+
/** Present when `inspect({ enrich: true })` was used. */
|
|
993
|
+
enrichment: InspectEnrichment | null;
|
|
994
|
+
}
|
|
995
|
+
/** A decoded navigational aid (buoy, beacon, light, fog signal, landmark…). */
|
|
996
|
+
interface NavAidInspectResult extends InspectResultCommon {
|
|
997
|
+
kind: "navaid";
|
|
998
|
+
/** Full decoded nav-aid record (colours, topmark, sectors, fog, status…). */
|
|
999
|
+
navAid: DecodedNavAid;
|
|
1000
|
+
/** Mariner light characteristic, e.g. "Fl(2+1) W 10s". Null when unlit. */
|
|
1001
|
+
characteristic: string | null;
|
|
1002
|
+
/** Flash/eclipse timing phases for animating the light. Null when unlit. */
|
|
1003
|
+
flashPattern: FlashPattern | null;
|
|
1004
|
+
}
|
|
1005
|
+
/** A decoded bridge (clearances, category, condition). */
|
|
1006
|
+
interface BridgeInspectResult extends InspectResultCommon {
|
|
1007
|
+
kind: "bridge";
|
|
1008
|
+
bridge: DecodedBridge;
|
|
1009
|
+
}
|
|
1010
|
+
/** A decoded area / hazard / regulated / infrastructure feature. */
|
|
1011
|
+
interface AreaInspectResult extends InspectResultCommon {
|
|
1012
|
+
kind: "area";
|
|
1013
|
+
area: DecodedAreaFeature;
|
|
1014
|
+
}
|
|
1015
|
+
type InspectResult = NavAidInspectResult | BridgeInspectResult | AreaInspectResult;
|
|
1016
|
+
/** Successful server-side entitlement check. */
|
|
1017
|
+
interface InteractEntitlement {
|
|
1018
|
+
enabled: true;
|
|
1019
|
+
/** The team's plan id (e.g. "dev", "pro"), when the server includes it. */
|
|
1020
|
+
plan?: string;
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Structural subset of the MapLibre / Mapbox GL `Map` interface used by
|
|
1024
|
+
* `attach()`. Declared structurally so `maplibre-gl` stays an optional peer
|
|
1025
|
+
* dependency — any GL JS map instance satisfies it.
|
|
1026
|
+
*/
|
|
1027
|
+
interface InteractMapLike {
|
|
1028
|
+
on(event: string, listener: (ev: InteractMapMouseEvent) => void): unknown;
|
|
1029
|
+
off(event: string, listener: (ev: InteractMapMouseEvent) => void): unknown;
|
|
1030
|
+
queryRenderedFeatures(pointOrBox?: unknown, options?: {
|
|
1031
|
+
layers?: string[];
|
|
1032
|
+
}): InspectableFeature[];
|
|
1033
|
+
getLayer(id: string): unknown;
|
|
1034
|
+
getContainer(): HTMLElement;
|
|
1035
|
+
project(lngLat: [number, number]): {
|
|
1036
|
+
x: number;
|
|
1037
|
+
y: number;
|
|
1038
|
+
};
|
|
1039
|
+
/** Present on real GL JS maps; lets `inspectAll()` accept screen points. */
|
|
1040
|
+
unproject?(point: [number, number]): {
|
|
1041
|
+
lng: number;
|
|
1042
|
+
lat: number;
|
|
1043
|
+
};
|
|
1044
|
+
}
|
|
1045
|
+
/** The subset of a GL JS MapMouseEvent that attach() consumes. */
|
|
1046
|
+
interface InteractMapMouseEvent {
|
|
1047
|
+
point: {
|
|
1048
|
+
x: number;
|
|
1049
|
+
y: number;
|
|
1050
|
+
};
|
|
1051
|
+
lngLat: {
|
|
1052
|
+
lng: number;
|
|
1053
|
+
lat: number;
|
|
1054
|
+
};
|
|
1055
|
+
}
|
|
1056
|
+
/**
|
|
1057
|
+
* A click location for candidate decoding: screen pixels always, geographic
|
|
1058
|
+
* coordinates when resolvable. `InteractMapMouseEvent` is assignable.
|
|
1059
|
+
*/
|
|
1060
|
+
interface ClickAnchor {
|
|
1061
|
+
point: {
|
|
1062
|
+
x: number;
|
|
1063
|
+
y: number;
|
|
1064
|
+
};
|
|
1065
|
+
lngLat: {
|
|
1066
|
+
lng: number;
|
|
1067
|
+
lat: number;
|
|
1068
|
+
} | null;
|
|
1069
|
+
}
|
|
1070
|
+
/** Context passed to `onInspect` alongside the result. */
|
|
1071
|
+
interface InspectEventContext {
|
|
1072
|
+
/** Click location. */
|
|
1073
|
+
lngLat: {
|
|
1074
|
+
lng: number;
|
|
1075
|
+
lat: number;
|
|
1076
|
+
};
|
|
1077
|
+
/** Click location in screen pixels. */
|
|
1078
|
+
point: {
|
|
1079
|
+
x: number;
|
|
1080
|
+
y: number;
|
|
1081
|
+
};
|
|
1082
|
+
/** The rendered feature the result was decoded from. */
|
|
1083
|
+
feature: InspectableFeature;
|
|
1084
|
+
}
|
|
1085
|
+
/**
|
|
1086
|
+
* What kind of click target a candidate is. Drives the primary priority
|
|
1087
|
+
* band (point > line > area) — distinct from `kind`, which describes the
|
|
1088
|
+
* decode shape (a WRECKS point is `kind: "area"` decode-wise but a "point"
|
|
1089
|
+
* click target).
|
|
1090
|
+
*/
|
|
1091
|
+
type InspectTargetClass = "point" | "line" | "area";
|
|
1092
|
+
/**
|
|
1093
|
+
* One deduplicated feature under a click, ready for a disambiguation list.
|
|
1094
|
+
* Plain serializable data — resolve the full {@link InspectResult} (with
|
|
1095
|
+
* the v1 co-located merge and optional enrichment) by selecting it via
|
|
1096
|
+
* `attach()`'s candidate flow or `inspectAll().select()`.
|
|
1097
|
+
*/
|
|
1098
|
+
interface InspectCandidate {
|
|
1099
|
+
/** Raw S-57 object class, e.g. "BOYLAT". */
|
|
1100
|
+
layer: string;
|
|
1101
|
+
/** Style-layer id the feature was rendered by, e.g. "enc-BOYLAT". */
|
|
1102
|
+
layerId: string;
|
|
1103
|
+
/** Decode shape this candidate resolves to on selection. */
|
|
1104
|
+
kind: "navaid" | "bridge" | "area";
|
|
1105
|
+
/** Click-target class driving the priority band. */
|
|
1106
|
+
targetClass: InspectTargetClass;
|
|
1107
|
+
/**
|
|
1108
|
+
* Priority rank (lower = higher priority): `band * 1000 + classRank`,
|
|
1109
|
+
* band 0/1/2 for point/line/area targets.
|
|
1110
|
+
*/
|
|
1111
|
+
rank: number;
|
|
1112
|
+
/** Display title (same derivation as the selected InspectResult's). */
|
|
1113
|
+
title: string;
|
|
1114
|
+
/** Human-readable object class, e.g. "Lateral Buoy". */
|
|
1115
|
+
objectClass: string;
|
|
1116
|
+
/** [lng, lat] when the feature carries Point geometry. */
|
|
1117
|
+
coordinates: [number, number] | null;
|
|
1118
|
+
/**
|
|
1119
|
+
* Source-cell-scoped S-57 identity the dedupe folded on
|
|
1120
|
+
* (`{cell}|{LNAM}`), or null when the tiles carry no identity attrs
|
|
1121
|
+
* (such features are never folded).
|
|
1122
|
+
*/
|
|
1123
|
+
identity: string | null;
|
|
1124
|
+
/**
|
|
1125
|
+
* Raw S-57 classes of co-located child objects collapsed into this
|
|
1126
|
+
* candidate (e.g. ["LIGHTS", "TOPMAR"] on a lit buoy). Selecting the
|
|
1127
|
+
* candidate merges their attributes via the v1 pipeline.
|
|
1128
|
+
*/
|
|
1129
|
+
collapsedChildren: string[];
|
|
1130
|
+
/** The underlying rendered feature (pass to `inspect()` for headless decode). */
|
|
1131
|
+
feature: InspectableFeature;
|
|
1132
|
+
/** Non-SOLAS disclaimer + attribution + data currency. Always present. */
|
|
1133
|
+
notice: InspectNotice;
|
|
1134
|
+
}
|
|
1135
|
+
/** Options shared by every candidate-collecting entry point. */
|
|
1136
|
+
interface CandidateQueryOptions {
|
|
1137
|
+
/**
|
|
1138
|
+
* Pixel radius around the click for point/line targets (a finger- and
|
|
1139
|
+
* line-width-friendly hit box). Area (polygon) candidates always require
|
|
1140
|
+
* the exact click point to fall inside them. Default: 8. Pass 0 to query
|
|
1141
|
+
* the exact point only.
|
|
1142
|
+
*/
|
|
1143
|
+
tolerance?: number;
|
|
1144
|
+
/**
|
|
1145
|
+
* Fold co-located S-57 child objects (LIGHTS, TOPMAR, FOGSIG, RTPBCN,
|
|
1146
|
+
* DAYMAR) into their parent buoy/beacon candidate. Default: true.
|
|
1147
|
+
*/
|
|
1148
|
+
collapseChildren?: boolean;
|
|
1149
|
+
/** Override the queried nav-aid style-layer ids. */
|
|
1150
|
+
navAidLayers?: string[];
|
|
1151
|
+
/** Override the queried bridge style-layer ids. */
|
|
1152
|
+
bridgeLayers?: string[];
|
|
1153
|
+
/** Override the queried area style-layer ids. */
|
|
1154
|
+
areaLayers?: string[];
|
|
1155
|
+
}
|
|
1156
|
+
/** Context passed to `onCandidates` when a click hits several features. */
|
|
1157
|
+
interface CandidatesEventContext {
|
|
1158
|
+
/** Click location. */
|
|
1159
|
+
lngLat: {
|
|
1160
|
+
lng: number;
|
|
1161
|
+
lat: number;
|
|
1162
|
+
};
|
|
1163
|
+
/** Click location in screen pixels. */
|
|
1164
|
+
point: {
|
|
1165
|
+
x: number;
|
|
1166
|
+
y: number;
|
|
1167
|
+
};
|
|
1168
|
+
/**
|
|
1169
|
+
* Resolve one candidate to its full InspectResult (v1 co-located merge +
|
|
1170
|
+
* the attach-level `enrich` setting). Also drives the built-in popup and
|
|
1171
|
+
* `onInspect`, so custom candidate UIs stay one line.
|
|
1172
|
+
*/
|
|
1173
|
+
select: (candidate: InspectCandidate) => Promise<InspectResult>;
|
|
1174
|
+
}
|
|
1175
|
+
/** Return shape of `chrt.interact.inspectAll()`. */
|
|
1176
|
+
interface InspectCandidateSet {
|
|
1177
|
+
/** Deduplicated candidates under the point, highest priority first. */
|
|
1178
|
+
candidates: InspectCandidate[];
|
|
1179
|
+
/**
|
|
1180
|
+
* Resolve one candidate to its full InspectResult (v1 co-located
|
|
1181
|
+
* attribute merge; `enrich: true` adds source-cell provenance — metered).
|
|
1182
|
+
*/
|
|
1183
|
+
select(candidate: InspectCandidate, opts?: {
|
|
1184
|
+
enrich?: boolean;
|
|
1185
|
+
signal?: AbortSignal;
|
|
1186
|
+
}): Promise<InspectResult>;
|
|
1187
|
+
}
|
|
1188
|
+
interface AttachOptions extends CandidateQueryOptions {
|
|
1189
|
+
/**
|
|
1190
|
+
* Receive every InspectResult (headless mode). Fires whether or not the
|
|
1191
|
+
* built-in popup is enabled.
|
|
1192
|
+
*/
|
|
1193
|
+
onInspect?: (result: InspectResult, ctx: InspectEventContext) => void;
|
|
1194
|
+
/**
|
|
1195
|
+
* Called when a click hits SEVERAL features (after dedupe/collapse),
|
|
1196
|
+
* with the priority-ordered candidates — render your own disambiguation
|
|
1197
|
+
* UI and resolve a choice via `ctx.select(candidate)`. When provided,
|
|
1198
|
+
* multi-hit clicks fire this instead of auto-inspecting the top
|
|
1199
|
+
* candidate. Single hits skip straight to `onInspect` / the popup.
|
|
1200
|
+
*/
|
|
1201
|
+
onCandidates?: (candidates: InspectCandidate[], ctx: CandidatesEventContext) => void;
|
|
1202
|
+
/** Called when a click hits no inspectable feature. */
|
|
1203
|
+
onMiss?: (ctx: {
|
|
1204
|
+
lngLat: {
|
|
1205
|
+
lng: number;
|
|
1206
|
+
lat: number;
|
|
1207
|
+
};
|
|
1208
|
+
}) => void;
|
|
1209
|
+
/**
|
|
1210
|
+
* Show the built-in minimal popup (plain DOM, no framework) — the result
|
|
1211
|
+
* card, and a candidate list when a click hits several features.
|
|
1212
|
+
* Default: true when neither `onInspect` nor `onCandidates` is provided,
|
|
1213
|
+
* false otherwise.
|
|
1214
|
+
*/
|
|
1215
|
+
popup?: boolean;
|
|
1216
|
+
/**
|
|
1217
|
+
* Auto-enrich every inspected result through the features API (metered —
|
|
1218
|
+
* counts against the key's `featureCalls` quota). Default: false.
|
|
1219
|
+
*/
|
|
1220
|
+
enrich?: boolean;
|
|
1221
|
+
}
|
|
1222
|
+
/** Handle returned by `attach()`. */
|
|
1223
|
+
interface InteractHandle {
|
|
1224
|
+
/** Remove the click handler and any open popup. */
|
|
1225
|
+
detach(): void;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
/**
|
|
1229
|
+
* Typed errors for the CHRTinteract flow. Mirrors the `TileTokenError` /
|
|
1230
|
+
* `OfflineError` pattern: a `code` discriminator so callers can branch
|
|
1231
|
+
* messaging (upgrade prompt vs. auth failure vs. transient network).
|
|
1232
|
+
*/
|
|
1233
|
+
type InteractErrorCode =
|
|
1234
|
+
/** The team's plan does not include CHRTinteract (Dev tier and above). */
|
|
1235
|
+
"interact_not_enabled"
|
|
1236
|
+
/** The API key was rejected (unknown, disabled, or expired). */
|
|
1237
|
+
| "invalid_api_key"
|
|
1238
|
+
/** The key was explicitly narrowed to scopes that exclude interact. */
|
|
1239
|
+
| "missing_scope"
|
|
1240
|
+
/** Feature enrichment failed (features/cells API error). */
|
|
1241
|
+
| "enrich_failed"
|
|
1242
|
+
/** The inspected feature could not be resolved to a chart layer. */
|
|
1243
|
+
| "unknown_layer"
|
|
1244
|
+
/** Transport-level failure reaching the entitlement endpoint. */
|
|
1245
|
+
| "network_error"
|
|
1246
|
+
/** The server answered with a shape the SDK doesn't recognize. */
|
|
1247
|
+
| "unexpected_response";
|
|
1248
|
+
declare class InteractError extends Error {
|
|
1249
|
+
readonly code: InteractErrorCode;
|
|
1250
|
+
readonly status?: number;
|
|
1251
|
+
/** The team's current plan id, when the server included it (denials). */
|
|
1252
|
+
readonly plan?: string;
|
|
1253
|
+
constructor(code: InteractErrorCode, message: string, opts?: {
|
|
1254
|
+
status?: number;
|
|
1255
|
+
plan?: string;
|
|
1256
|
+
});
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1259
|
+
/**
|
|
1260
|
+
* Multi-feature candidate collection for CHRTinteract (interact v1.1).
|
|
1261
|
+
*
|
|
1262
|
+
* A chart click rarely hits exactly one feature: a buoy sits on a channel
|
|
1263
|
+
* over a depth area, dense harbors stack nav aids over regulated areas over
|
|
1264
|
+
* DEPARE. This module turns "everything under (or near) the click" into a
|
|
1265
|
+
* deduplicated, priority-ordered candidate list:
|
|
1266
|
+
*
|
|
1267
|
+
* 1. COLLECT — queryRenderedFeatures over the interact layer sets with a
|
|
1268
|
+
* pixel tolerance box for point/line targets; polygon (area) targets
|
|
1269
|
+
* are kept only when they contain the exact click point.
|
|
1270
|
+
* 2. DEDUPE — the same S-57 object comes back once per tile it was split
|
|
1271
|
+
* into and once per style layer that rendered it. Features are folded
|
|
1272
|
+
* by source-cell-scoped S-57 identity: LNAM (the AGEN+FIDN+FIDS long
|
|
1273
|
+
* name — verified present on 100% of features in served CHRT tiles),
|
|
1274
|
+
* falling back to the AGEN/FIDN/FIDS composite.
|
|
1275
|
+
* 3. COLLAPSE — S-57 child objects (LIGHTS, TOPMAR, FOGSIG, RTPBCN,
|
|
1276
|
+
* DAYMAR) co-located with a parent buoy/beacon in the same hit set are
|
|
1277
|
+
* folded into the parent candidate; selecting the parent runs the v1
|
|
1278
|
+
* co-located merge so the light/topmark attributes surface there. A
|
|
1279
|
+
* mariner reads a lit buoy as ONE aid, not three S-57 objects.
|
|
1280
|
+
* 4. RANK — class priority: point targets > line targets > area targets,
|
|
1281
|
+
* with a within-band ladder kept value-coherent with the atlas label
|
|
1282
|
+
* ladder (`LABEL_PRIORITY` in atlas/labels.ts — the P4 collision
|
|
1283
|
+
* model). Area features NEVER preempt the buoy above them, but they
|
|
1284
|
+
* always remain in the list, so open water resolves to its DEPARE.
|
|
1285
|
+
*
|
|
1286
|
+
* Everything here is pure and map-optional: `collectCandidates()` works on
|
|
1287
|
+
* any InspectableFeature[]; `collectClickCandidates()` adds the
|
|
1288
|
+
* queryRenderedFeatures wiring. Entitlement enforcement stays in
|
|
1289
|
+
* `InteractClient` — these are building blocks, useless without CHRT tiles.
|
|
1290
|
+
*/
|
|
1291
|
+
|
|
1292
|
+
/**
|
|
1293
|
+
* Within-band class ladder — lower = higher priority. Value-coherent with
|
|
1294
|
+
* the atlas label-collision ladder (`LABEL_PRIORITY`, atlas/labels.ts):
|
|
1295
|
+
* classes present in both carry the SAME value, so "what places first on
|
|
1296
|
+
* the chart" and "what lists first under a click" never invert. Documented
|
|
1297
|
+
* exceptions live in {@link INSPECT_RANK_DEVIATIONS}; the coherence unit
|
|
1298
|
+
* test (candidates.test.ts) enforces equal-unless-deviating.
|
|
1299
|
+
*
|
|
1300
|
+
* Rungs (mirroring the label ladder's tiers, extended for area classes the
|
|
1301
|
+
* label ladder never ranks):
|
|
1302
|
+
*
|
|
1303
|
+
* 100 — safety-critical: lights, hazards (rocks, obstructions, wrecks),
|
|
1304
|
+
* overhead clearances
|
|
1305
|
+
* 200 — nav-aid primaries: buoys, beacons, light vessels/floats
|
|
1306
|
+
* 250 — nav-aid auxiliaries: fog signals, radar beacons, daymarks,
|
|
1307
|
+
* topmarks, radio stations
|
|
1308
|
+
* 260 — bridges (interact-specific: preempt the water/contours below)
|
|
1309
|
+
* 300 — depth field: contours
|
|
1310
|
+
* 350 — caution / regulated / traffic areas
|
|
1311
|
+
* 400 — structures: landmarks, moorings, shoreline constructions
|
|
1312
|
+
* 410 — subsea infrastructure lines: cables, pipelines
|
|
1313
|
+
* 420 — channel & berthing infrastructure
|
|
1314
|
+
* 500 — ambient annotation: seabed, kelp, magnetic variation
|
|
1315
|
+
* 610 — DEPARE: the canonical "what water is this" answer
|
|
1316
|
+
* 640 — hydrographic context: rivers, canals, lakes, coastline
|
|
1317
|
+
* 700 — land / ambient areas
|
|
1318
|
+
*/
|
|
1319
|
+
declare const INSPECT_CLASS_RANK: Record<string, number>;
|
|
1320
|
+
/** Rank for queried classes not in the ladder (mirrors DEFAULT_LABEL_PRIORITY). */
|
|
1321
|
+
declare const DEFAULT_INSPECT_CLASS_RANK = 450;
|
|
1322
|
+
/**
|
|
1323
|
+
* Classes whose interact rank deliberately differs from the atlas
|
|
1324
|
+
* LABEL_PRIORITY value, with why. The coherence test allows exactly these.
|
|
1325
|
+
*/
|
|
1326
|
+
declare const INSPECT_RANK_DEVIATIONS: Record<string, string>;
|
|
1327
|
+
/** Compose the candidate rank: primary target band, then class ladder. */
|
|
1328
|
+
declare function candidateRank(targetClass: InspectTargetClass, rawLayer: string): number;
|
|
1329
|
+
/**
|
|
1330
|
+
* Source-cell-scoped S-57 identity for a rendered feature.
|
|
1331
|
+
*
|
|
1332
|
+
* CHRT tiles carry the GDAL S-57 feature-identity attributes end-to-end
|
|
1333
|
+
* (verified against served prod tiles: LNAM/FIDN/FIDS/AGEN present on
|
|
1334
|
+
* 100% of features): LNAM is the AGEN+FIDN+FIDS "long name" — the stable
|
|
1335
|
+
* object identity that survives a feature being split across tile
|
|
1336
|
+
* boundaries or rendered by several style layers. Scoped by `_cell_id`
|
|
1337
|
+
* because the same real-world object legitimately appears in multiple
|
|
1338
|
+
* source cells (band overlap) with distinct provenance.
|
|
1339
|
+
*
|
|
1340
|
+
* Returns null when the attributes are absent (never dedupe blind).
|
|
1341
|
+
*/
|
|
1342
|
+
declare function featureIdentity(feature: InspectableFeature): string | null;
|
|
1343
|
+
/**
|
|
1344
|
+
* Resolve a candidate's click-target class: rendered geometry first (the
|
|
1345
|
+
* truth for classes with point/line/area variants), style-layer suffix
|
|
1346
|
+
* next, class default last (nav aids → point, everything else → area).
|
|
1347
|
+
*/
|
|
1348
|
+
declare function resolveTargetClass(layerId: string, feature: InspectableFeature): InspectTargetClass;
|
|
1349
|
+
/**
|
|
1350
|
+
* Turn raw rendered features into the deduplicated, priority-ordered
|
|
1351
|
+
* candidate list. Pure — usable on any queryRenderedFeatures result (or
|
|
1352
|
+
* plain `{ layer, properties }` objects) without a map.
|
|
1353
|
+
*
|
|
1354
|
+
* Order in = render order (queryRenderedFeatures returns topmost first);
|
|
1355
|
+
* the sort is stable, so equal-rank candidates keep that visual order.
|
|
1356
|
+
*/
|
|
1357
|
+
declare function collectCandidates(features: InspectableFeature[], opts?: Pick<CandidateQueryOptions, "collapseChildren">): InspectCandidate[];
|
|
1358
|
+
/** Default pixel tolerance around the click for point/line targets. */
|
|
1359
|
+
declare const DEFAULT_CLICK_TOLERANCE = 8;
|
|
1360
|
+
/**
|
|
1361
|
+
* Collect every inspectable candidate under (or within `tolerance` px of)
|
|
1362
|
+
* a click point: one tolerance-box query over the interact layer sets,
|
|
1363
|
+
* plus an exact-point query that gates polygon candidates — an area
|
|
1364
|
+
* feature is only offered when the click actually falls inside it, while
|
|
1365
|
+
* points and lines get the forgiving hit box.
|
|
1366
|
+
*/
|
|
1367
|
+
declare function collectClickCandidates(map: InteractMapLike, point: {
|
|
1368
|
+
x: number;
|
|
1369
|
+
y: number;
|
|
1370
|
+
}, opts?: CandidateQueryOptions): InspectCandidate[];
|
|
1371
|
+
|
|
1372
|
+
/**
|
|
1373
|
+
* Map wiring for CHRTinteract — click → candidates → inspect().
|
|
1374
|
+
*
|
|
1375
|
+
* v1 was a faithful port of the first-party `/map` click pipeline
|
|
1376
|
+
* (`src/hooks/use-map-renderer.tsx` in the platform repo): nav-aid point
|
|
1377
|
+
* features → bridges → area features, taking the topmost hit. v1.1 keeps
|
|
1378
|
+
* that decode intact but routes every click through the candidate
|
|
1379
|
+
* collector (candidates.ts): all features under the click are deduped by
|
|
1380
|
+
* S-57 identity and priority-ordered, `decodeClick` resolves the TOP
|
|
1381
|
+
* candidate, and the attach handler in index.ts surfaces the rest for
|
|
1382
|
+
* disambiguation.
|
|
1383
|
+
*
|
|
1384
|
+
* Attribute merging (S-57 encodes lights/fog/topmarks as separate child
|
|
1385
|
+
* objects co-located with their parent buoy/beacon) — unchanged from v1:
|
|
1386
|
+
* - OBJNAM / COLOUR inherited from a co-located parent buoy/beacon
|
|
1387
|
+
* - CATFOG from a co-located FOGSIG
|
|
1388
|
+
* - RETRFL presence from a co-located RTPBCN
|
|
1389
|
+
* - TOPSHP from a co-located TOPMAR
|
|
1390
|
+
* - LITCHR / SIGPER / SIGGRP / LIGHT_COLOUR / CATLIT from the primary
|
|
1391
|
+
* co-located LIGHTS (preferring a non-sector light)
|
|
1392
|
+
* - all co-located LIGHTS combined into the sector list
|
|
1393
|
+
*
|
|
1394
|
+
* MapLibre / Mapbox GL is NOT imported — the map is consumed through the
|
|
1395
|
+
* structural `InteractMapLike` interface, so `maplibre-gl` remains an
|
|
1396
|
+
* optional peer dependency.
|
|
1397
|
+
*/
|
|
1398
|
+
|
|
1399
|
+
/**
|
|
1400
|
+
* Resolve ONE candidate to its full InspectResult at a click location:
|
|
1401
|
+
* nav-aid classes run the co-located child-object merge, everything else
|
|
1402
|
+
* decodes directly (bridges/areas anchor to the click point when the
|
|
1403
|
+
* feature carries no Point geometry). Exported for tests.
|
|
1404
|
+
*/
|
|
1405
|
+
declare function decodeCandidate(map: InteractMapLike, candidate: InspectCandidate, at: ClickAnchor, opts?: AttachOptions): InspectResult;
|
|
1406
|
+
|
|
1407
|
+
/**
|
|
1408
|
+
* CHRTinteract — productized click-to-inspect for CHRT charts.
|
|
1409
|
+
*
|
|
1410
|
+
* `chrt.interact.attach(map)` wires click → decode → popup/callback onto any
|
|
1411
|
+
* MapLibre / Mapbox GL map showing CHRT tiles; `chrt.interact.inspect(feature)`
|
|
1412
|
+
* decodes a single feature headlessly. Both enforce the Dev-tier-and-above
|
|
1413
|
+
* entitlement server-side before doing any work, and every result carries the
|
|
1414
|
+
* non-SOLAS disclaimer, hydrographic-office attribution, and data currency.
|
|
1415
|
+
*
|
|
1416
|
+
* Included with the Dev plan and above. Free-plan keys receive an
|
|
1417
|
+
* `InteractError` with code `interact_not_enabled`.
|
|
1418
|
+
*/
|
|
1419
|
+
|
|
1420
|
+
declare class InteractClient {
|
|
1421
|
+
private readonly http;
|
|
1422
|
+
private readonly entitlementClient;
|
|
1423
|
+
constructor(http: HttpClient);
|
|
1424
|
+
/**
|
|
1425
|
+
* Check the CHRTinteract entitlement for this API key (server-side, plan
|
|
1426
|
+
* derived, cached per client). Throws `InteractError` with code
|
|
1427
|
+
* `interact_not_enabled` for Free-plan teams.
|
|
1428
|
+
*/
|
|
1429
|
+
entitlement(): Promise<InteractEntitlement>;
|
|
1430
|
+
/**
|
|
1431
|
+
* Decode a chart feature (from `queryRenderedFeatures`, the features API,
|
|
1432
|
+
* or plain `{ layer, properties }`) into a typed {@link InspectResult}.
|
|
1433
|
+
*
|
|
1434
|
+
* The first call performs the server-side entitlement check. With
|
|
1435
|
+
* `{ enrich: true }` the result is upgraded with full S-57 properties and
|
|
1436
|
+
* source-cell provenance (edition / update / issue date) via the features
|
|
1437
|
+
* API — metered against the key's `featureCalls` quota.
|
|
1438
|
+
*
|
|
1439
|
+
* @example
|
|
1440
|
+
* const result = await chrt.interact.inspect(feature);
|
|
1441
|
+
* if (result.kind === "navaid") console.log(result.characteristic); // "Fl R 4s"
|
|
1442
|
+
*/
|
|
1443
|
+
inspect(feature: InspectableFeature, opts?: InspectOptions): Promise<InspectResult>;
|
|
1444
|
+
/**
|
|
1445
|
+
* Collect EVERY inspectable feature under a point on a CHRT map —
|
|
1446
|
+
* deduplicated across tile boundaries by S-57 identity (`LNAM`) and
|
|
1447
|
+
* ordered by class priority (point targets > lines > areas, safety
|
|
1448
|
+
* classes first within each band). Area features never preempt the buoy
|
|
1449
|
+
* on top of them but always stay selectable: a click on open water
|
|
1450
|
+
* resolves to its DEPARE.
|
|
1451
|
+
*
|
|
1452
|
+
* `point` is a screen pixel point (`e.point` from a map click) or
|
|
1453
|
+
* `[lng, lat]`. Point/line targets are picked up within
|
|
1454
|
+
* `opts.tolerance` px (default 8); polygon candidates require the exact
|
|
1455
|
+
* point to fall inside them.
|
|
1456
|
+
*
|
|
1457
|
+
* The first call performs the server-side entitlement check.
|
|
1458
|
+
*
|
|
1459
|
+
* @example
|
|
1460
|
+
* const { candidates, select } = await chrt.interact.inspectAll(map, e.point);
|
|
1461
|
+
* const result = await select(candidates[0]); // full decode (+ merge)
|
|
1462
|
+
*/
|
|
1463
|
+
inspectAll(map: InteractMapLike, point: {
|
|
1464
|
+
x: number;
|
|
1465
|
+
y: number;
|
|
1466
|
+
} | [number, number], opts?: CandidateQueryOptions): Promise<InspectCandidateSet>;
|
|
1467
|
+
/**
|
|
1468
|
+
* Attach click-to-inspect to a MapLibre / Mapbox GL map rendering CHRT
|
|
1469
|
+
* tiles. Resolves once the server-side entitlement check passes; rejects
|
|
1470
|
+
* with `InteractError` (`interact_not_enabled` on Free plans) otherwise —
|
|
1471
|
+
* no listeners are wired on denial.
|
|
1472
|
+
*
|
|
1473
|
+
* Headless-first: pass `onInspect` to receive every decoded
|
|
1474
|
+
* {@link InspectResult} and render your own UI. Without callbacks, the
|
|
1475
|
+
* built-in minimal popup is shown (opt back in explicitly with
|
|
1476
|
+
* `popup: true` to have both).
|
|
1477
|
+
*
|
|
1478
|
+
* A click that hits SEVERAL features (deduplicated by S-57 identity)
|
|
1479
|
+
* disambiguates instead of silently taking the topmost:
|
|
1480
|
+
* - `onCandidates` provided → it receives the priority-ordered list;
|
|
1481
|
+
* resolve a choice with `ctx.select(candidate)`.
|
|
1482
|
+
* - built-in popup → shows a candidate list; picking a row opens the
|
|
1483
|
+
* result card.
|
|
1484
|
+
* - `onInspect` only → the top candidate is inspected immediately, and
|
|
1485
|
+
* clicking the SAME spot again cycles to the next candidate — so an
|
|
1486
|
+
* area feature under a buoy is reachable with a second click.
|
|
1487
|
+
*
|
|
1488
|
+
* @example
|
|
1489
|
+
* const handle = await chrt.interact.attach(map, {
|
|
1490
|
+
* onInspect: (result) => console.log(result.title, result.characteristic),
|
|
1491
|
+
* });
|
|
1492
|
+
* // later: handle.detach();
|
|
1493
|
+
*/
|
|
1494
|
+
attach(map: InteractMapLike, opts?: AttachOptions): Promise<InteractHandle>;
|
|
1495
|
+
}
|
|
1496
|
+
|
|
577
1497
|
/** S-52 display categories – controls default visibility */
|
|
578
1498
|
type DisplayCategory = "BASE" | "STANDARD" | "OTHER" | "MARINERS" | "META";
|
|
579
1499
|
/** Mapbox GL layer type we'll use for this entry */
|
|
@@ -759,6 +1679,72 @@ type LabelBehavior = "feature-band-gated" | "orientation-cross-band";
|
|
|
759
1679
|
declare const LABEL_BEHAVIOR: Record<string, LabelBehavior>;
|
|
760
1680
|
/** Returns the rendering strategy for an S-57 class. Unknown classes default to band-gated. */
|
|
761
1681
|
declare function getLabelBehavior(layerName: string): LabelBehavior;
|
|
1682
|
+
/**
|
|
1683
|
+
* Class-based label priority ladder — THE single collision-priority model
|
|
1684
|
+
* for feature labels (portrayal-excellence P4). Converges the previous
|
|
1685
|
+
* per-mechanism patches (SAFETY_CRITICAL_LABELS allow-overlap, the
|
|
1686
|
+
* band-5/6-only Harbor collision discipline) into one explicit ranking.
|
|
1687
|
+
*
|
|
1688
|
+
* Rank semantics: LOWER rank = higher priority. The rank drives two
|
|
1689
|
+
* mechanisms that must stay in agreement:
|
|
1690
|
+
*
|
|
1691
|
+
* 1. `symbol-sort-key` — every feature label carries
|
|
1692
|
+
* `rank*1000 + within-class-key`, so if label layers are ever merged
|
|
1693
|
+
* (the P8 style fan-out reduction), placement priority survives the
|
|
1694
|
+
* merge unchanged.
|
|
1695
|
+
* 2. Label LAYER ORDER — MapLibre places symbols topmost-layer-first, so
|
|
1696
|
+
* `style-generator.ts` emits feature-label layers lowest-priority
|
|
1697
|
+
* first: safety-critical classes end up topmost and claim collision
|
|
1698
|
+
* space before anything else. (`symbol-sort-key` alone cannot do
|
|
1699
|
+
* this — it only orders placement WITHIN a layer.)
|
|
1700
|
+
*
|
|
1701
|
+
* The ladder (safety-critical > nav-aids > depth field > structures >
|
|
1702
|
+
* ambient notes):
|
|
1703
|
+
*
|
|
1704
|
+
* 100 — Safety-critical: light characteristics (LIGHTS), hazard depth
|
|
1705
|
+
* callouts (UWTROC/OBSTRN/WRECKS VALSOU), overhead clearances
|
|
1706
|
+
* (CBLOHD/PIPOHD VERCLR). Irreducible mariner-safety text.
|
|
1707
|
+
* 200 — Nav-aid designations: buoy / beacon `R "4"` labels.
|
|
1708
|
+
* 250 — Auxiliary nav-aid info: fog signal type (FOGSIG).
|
|
1709
|
+
* 300 — Depth field: soundings, contour values. Individually droppable —
|
|
1710
|
+
* a hidden sounding has visible neighbors.
|
|
1711
|
+
* 400 — Structures: bridges, landmarks, piers, moorings, buildings.
|
|
1712
|
+
* 500 — Ambient annotation: seabed nature, magnetic variation, kelp.
|
|
1713
|
+
* 900 — Orientation names (SEAARE etc.) — not part of this ladder;
|
|
1714
|
+
* they keep their settled watermark model (cell-band fan +
|
|
1715
|
+
* dominance composition + `orientationLabelLayout`) and always
|
|
1716
|
+
* paint underneath feature labels.
|
|
1717
|
+
*
|
|
1718
|
+
* Safety guardrail: a lower rung never blocks a higher rung — placement
|
|
1719
|
+
* order guarantees the safety-critical label got the space first. Density
|
|
1720
|
+
* relief comes from dropping the LOWEST rung in a pile-up, never the top.
|
|
1721
|
+
*/
|
|
1722
|
+
declare const LABEL_PRIORITY: Record<string, number>;
|
|
1723
|
+
/**
|
|
1724
|
+
* Resolve the priority rank for an S-57 class's label. Orientation classes
|
|
1725
|
+
* report 900 regardless of ladder membership (PRDARE etc.) so the
|
|
1726
|
+
* layer-order sort in style-generator.ts can treat priority uniformly.
|
|
1727
|
+
*/
|
|
1728
|
+
declare function getLabelPriority(layerName: string): number;
|
|
1729
|
+
/**
|
|
1730
|
+
* Compose a `symbol-sort-key` from a class rank and an optional
|
|
1731
|
+
* within-class key expression. The within-class key is clamped to
|
|
1732
|
+
* [0, 999] so it can never bleed into a neighboring rank's band.
|
|
1733
|
+
*/
|
|
1734
|
+
declare function labelSortKey(rank: number, within?: unknown): ExpressionSpecification | number;
|
|
1735
|
+
/**
|
|
1736
|
+
* Extract the trailing designation token from a nav-aid OBJNAM.
|
|
1737
|
+
*
|
|
1738
|
+
* NOAA names channel aids "<waterway> <type> Buoy|Beacon <designation>"
|
|
1739
|
+
* where the designation is 1-4 alphanumerics: "4", "18A", "B", "BG".
|
|
1740
|
+
* Returns null when the name has no designation (trailing token is a
|
|
1741
|
+
* stopword type-name, or longer than 4 chars).
|
|
1742
|
+
*
|
|
1743
|
+
* This is the TS twin of `navAidDesignationTextExpression` — the GeoJSON
|
|
1744
|
+
* preprocessing path uses this function, the PMTiles path uses the GL
|
|
1745
|
+
* expression. Keep the two in agreement (see label-priority.test.ts).
|
|
1746
|
+
*/
|
|
1747
|
+
declare function extractNavAidDesignation(objnam: string): string | null;
|
|
762
1748
|
/** Get label config for a given S-57 layer, or null if no labels */
|
|
763
1749
|
declare function getLabelConfig(layerName: string, opts?: LabelConfigOptions): LabelLayerConfig | null;
|
|
764
1750
|
/**
|
|
@@ -1027,59 +2013,6 @@ declare const S101_SYMBOL_GROUPS: {
|
|
|
1027
2013
|
|
|
1028
2014
|
declare const S101_NEW_SYMBOLS: NauticalSymbol[];
|
|
1029
2015
|
|
|
1030
|
-
/**
|
|
1031
|
-
* S-52 SVG Loader — pure (DOM-free) string operations over the inlined S-52
|
|
1032
|
-
* SVG catalogue in `s52-svgs-generated.ts`. SVG files use S-52 color token
|
|
1033
|
-
* names (e.g., CHBLK, LITRD) as fill/stroke values; `applyColorTheme` swaps
|
|
1034
|
-
* those tokens for hex from the active palette.
|
|
1035
|
-
*
|
|
1036
|
-
* Browser-only image loaders live in `./s52-svg-loader-browser.ts` (sub-export
|
|
1037
|
-
* `@chrtco/sdk/atlas/browser`) — they use `new Image()` and require a DOM.
|
|
1038
|
-
*/
|
|
1039
|
-
|
|
1040
|
-
/**
|
|
1041
|
-
* Get raw SVG string for an S-52 symbol by name (e.g., "BOYCAN01").
|
|
1042
|
-
* Returns null if the symbol is not found.
|
|
1043
|
-
*/
|
|
1044
|
-
declare function getS52SvgString(symbolName: string): string | null;
|
|
1045
|
-
/**
|
|
1046
|
-
* Get an S-52 SVG string with color tokens resolved to hex values
|
|
1047
|
-
* from the specified color table.
|
|
1048
|
-
*/
|
|
1049
|
-
declare function getThemedS52Svg(symbolName: string, colorTable?: ColorTableName): string | null;
|
|
1050
|
-
/**
|
|
1051
|
-
* Replace S-52 color token names in an SVG string with hex colors
|
|
1052
|
-
* from the active color table.
|
|
1053
|
-
*
|
|
1054
|
-
* Matches tokens in fill="TOKEN" and stroke="TOKEN" attribute values.
|
|
1055
|
-
*/
|
|
1056
|
-
declare function applyColorTheme(svgString: string, colorTable?: ColorTableName): string;
|
|
1057
|
-
/** Get a list of all available S-52 point symbol names. */
|
|
1058
|
-
declare function getAvailablePointSymbols(): string[];
|
|
1059
|
-
/** Get a list of all available S-52 pattern names. */
|
|
1060
|
-
declare function getAvailablePatterns(): string[];
|
|
1061
|
-
/** Get a list of all available S-52 line symbol names. */
|
|
1062
|
-
declare function getAvailableLineSymbols(): string[];
|
|
1063
|
-
/** Stats for debugging */
|
|
1064
|
-
declare function getS52SymbolStats(): {
|
|
1065
|
-
pointCount: number;
|
|
1066
|
-
patternCount: number;
|
|
1067
|
-
lineCount: number;
|
|
1068
|
-
totalCount: number;
|
|
1069
|
-
};
|
|
1070
|
-
|
|
1071
|
-
/**
|
|
1072
|
-
* Zoom range of CHRT tile builds — kept in lockstep with the baremetal
|
|
1073
|
-
* tippecanoe invocation (tools/chrt-baremetal/server/src/tilebuild/per-layer-zoom.ts).
|
|
1074
|
-
*
|
|
1075
|
-
* Per-S-57-class minzoom/maxzoom narrowing is handled inside the MVT at
|
|
1076
|
-
* tile-build time via per-feature `tippecanoe.minzoom/maxzoom`; these two
|
|
1077
|
-
* constants are the outer envelope the MapLibre source declares, so the
|
|
1078
|
-
* client doesn't request tiles outside what the pmtiles can actually serve.
|
|
1079
|
-
*/
|
|
1080
|
-
declare const BUILD_MINZOOM = 3;
|
|
1081
|
-
declare const BUILD_MAXZOOM = 14;
|
|
1082
|
-
|
|
1083
2016
|
/**
|
|
1084
2017
|
* Post-consolidation (2026-04): one consolidated PMTiles per region, all
|
|
1085
2018
|
* S-57 classes as distinct MVT layers inside. The MapLibre style emits one
|
|
@@ -1205,24 +2138,39 @@ interface BandPriorityRange {
|
|
|
1205
2138
|
* (drawn last in the z-stack, so its opaque fills cover lower bands),
|
|
1206
2139
|
* and lower bands fill in where the higher band has no coverage.
|
|
1207
2140
|
*
|
|
1208
|
-
* Cross-band visual overlap (doubled coastlines,
|
|
2141
|
+
* Cross-band visual overlap (doubled coastlines, duplicate labels) is
|
|
1209
2142
|
* suppressed by the `_dominated_by_min` per-feature tag added at NDJSON
|
|
1210
2143
|
* export time (see `tools/chrt-baremetal/server/src/tilebuild/dominanceIndex.ts`):
|
|
1211
2144
|
* every feature whose centroid sits inside a higher-band cell's M_COVR
|
|
1212
2145
|
* coverage polygon is tagged with the LOWEST band code (2..6) that
|
|
1213
2146
|
* dominates it, and `makeBandVariants()` in the style generator emits
|
|
1214
2147
|
* per-(featureBand, dominatorBand) layer variants gated by `maxzoom =
|
|
1215
|
-
*
|
|
1216
|
-
* exactly the zoom where its dominator becomes eligible
|
|
1217
|
-
* low-zoom "black silhouettes" bug where a
|
|
1218
|
-
* a band-5 cell was dropped at z7 even
|
|
1219
|
-
*
|
|
1220
|
-
*
|
|
1221
|
-
*
|
|
2148
|
+
* dominatedVariantMaxzoom(D)`. The dominated feature renders until
|
|
2149
|
+
* exactly the zoom where its dominator becomes eligible AND has data in
|
|
2150
|
+
* the tiles — solving the low-zoom "black silhouettes" bug where a
|
|
2151
|
+
* band-3 LNDARE dominated by a band-5 cell was dropped at z7 even
|
|
2152
|
+
* though band 5 wasn't yet rendering at z7.
|
|
2153
|
+
*
|
|
2154
|
+
* Opaque base-area FILLS are exempt from dominance gating entirely (see
|
|
2155
|
+
* `DOMINANCE_EXEMPT_FILL_CLASSES` in the style generator): band-major
|
|
2156
|
+
* draw order already makes the most-detailed band's opaque fill win at
|
|
2157
|
+
* any covered pixel, and the coarser band shows through wherever the
|
|
2158
|
+
* detailed band has no data — which is exactly the fallback semantics
|
|
2159
|
+
* the cascade wants. The 2026-07 E1/E2 void diagnosis
|
|
2160
|
+
* (docs/validation/portrayal-p1-p3-void-diagnosis-2026-07.md) proved
|
|
2161
|
+
* per-feature dominance gating on fills structurally unsound: the tag is
|
|
2162
|
+
* point-sampled but hides the WHOLE feature, so a Gulf-spanning band-1
|
|
2163
|
+
* DEPARE tagged dominated-by-2 left dark voids across every part of the
|
|
2164
|
+
* Gulf that band 2 doesn't actually cover.
|
|
1222
2165
|
*
|
|
1223
2166
|
* Bands 5 and 6 both start at z11; band 6 (Berthing) is drawn AFTER
|
|
1224
2167
|
* band 5 (Harbor) so where Berthing exists it visually wins, and
|
|
1225
2168
|
* Harbor shows through everywhere else.
|
|
2169
|
+
*
|
|
2170
|
+
* Band 1 starts at z0: the P3 low-zoom contract (charts never disappear
|
|
2171
|
+
* from world view down) needs Overview-band data renderable as soon as
|
|
2172
|
+
* tiles exist. Builds older than the z0 floor simply have no tiles below
|
|
2173
|
+
* z3, so the widened range is a no-op against them.
|
|
1226
2174
|
*/
|
|
1227
2175
|
declare const BAND_PRIORITY_RANGES: Record<BandCode, BandPriorityRange>;
|
|
1228
2176
|
/**
|
|
@@ -1356,6 +2304,15 @@ interface StyleGeneratorOptions extends BuildSourcesOptions {
|
|
|
1356
2304
|
* round so the rendered numbers match. Default "meters".
|
|
1357
2305
|
*/
|
|
1358
2306
|
depthUnits?: "meters" | "feet";
|
|
2307
|
+
/**
|
|
2308
|
+
* Which symbol artwork the style references. "s52" (default) uses the
|
|
2309
|
+
* PresLib-derived S-52 set; "s101" rewrites icon references to the
|
|
2310
|
+
* official S-101 Portrayal Catalogue symbols (s101: image namespace)
|
|
2311
|
+
* where a counterpart exists — see s101-style.ts. "chrt" applies the
|
|
2312
|
+
* CHRT house ATON/LIGHTS glyphs with colour-true tinting — see
|
|
2313
|
+
* chrt-style.ts. Selection logic differences are documented per module.
|
|
2314
|
+
*/
|
|
2315
|
+
symbolSet?: "s52" | "s101" | "chrt";
|
|
1359
2316
|
/**
|
|
1360
2317
|
* S-52 §SOUNDG02 — soundings shoaler than this depth (metres) render in
|
|
1361
2318
|
* the high-contrast color; deeper soundings render in the muted color.
|
|
@@ -1385,109 +2342,355 @@ declare function getStyleStats(style: MapboxStyle): {
|
|
|
1385
2342
|
objectClasses: Set<string>;
|
|
1386
2343
|
};
|
|
1387
2344
|
|
|
2345
|
+
declare const S101_SOURCE_COMMIT = "05063500e898544c90078ab78a61efc72b7e62f3";
|
|
2346
|
+
|
|
1388
2347
|
/**
|
|
1389
|
-
*
|
|
2348
|
+
* S-101 symbol-set support (portrayal-excellence 7c, first slice).
|
|
1390
2349
|
*
|
|
1391
|
-
* The
|
|
1392
|
-
*
|
|
1393
|
-
*
|
|
1394
|
-
*
|
|
1395
|
-
*
|
|
1396
|
-
*
|
|
2350
|
+
* The vendored official S-101 Portrayal Catalogue symbols (see
|
|
2351
|
+
* `assets/s101/PROVENANCE.md`) are registered on the map under the
|
|
2352
|
+
* `s101:` image namespace so they can coexist with the S-52 set. A style
|
|
2353
|
+
* document is switched to the S-101 symbol set by rewriting every
|
|
2354
|
+
* icon-image reference whose symbol has an official S-101 counterpart —
|
|
2355
|
+
* selection logic (the S-52 lookup expressions) is unchanged, only the
|
|
2356
|
+
* artwork swaps. That is deliberate and documented: the S-101 rule engine
|
|
2357
|
+
* (Lua rules in the PC's `Rules/`) is the later 7c phase; the official
|
|
2358
|
+
* SVGs themselves are exact today.
|
|
1397
2359
|
*
|
|
1398
|
-
*
|
|
1399
|
-
*
|
|
1400
|
-
*
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
2360
|
+
* Colour theming resolves through the OFFICIAL S-101 day/dusk/night
|
|
2361
|
+
* profiles (from the PC's {day,dusk,night}SvgStyle.css), not CHRT's S-52
|
|
2362
|
+
* tables — the S-101 style is spec-true end to end at the symbol level.
|
|
2363
|
+
*/
|
|
2364
|
+
|
|
2365
|
+
/** MapLibre image-id namespace for the S-101 symbol set. */
|
|
2366
|
+
declare const S101_ICON_PREFIX = "s101:";
|
|
2367
|
+
/** All vendored S-101 symbol names (unprefixed). */
|
|
2368
|
+
declare const S101_SYMBOL_NAMES: ReadonlySet<string>;
|
|
2369
|
+
/** Resolve an S-101 colour token via the official profile for `table`. */
|
|
2370
|
+
declare function resolveS101Color(token: string, table?: ColorTableName): string;
|
|
2371
|
+
/**
|
|
2372
|
+
* Get an S-101 symbol SVG with its colour tokens resolved through the
|
|
2373
|
+
* official S-101 profile. Returns null for unknown symbols.
|
|
2374
|
+
*/
|
|
2375
|
+
declare function getThemedS101Svg(symbolName: string, table?: ColorTableName): string | null;
|
|
2376
|
+
/**
|
|
2377
|
+
* Switch a generated style document to the S-101 symbol set. Symbol names
|
|
2378
|
+
* without an official S-101 counterpart keep their S-52 image (both sets
|
|
2379
|
+
* are loaded by `loadChartSymbolImages`), so coverage can only grow as the
|
|
2380
|
+
* PC adds symbols. Returns the same style object (mutated), for chaining.
|
|
2381
|
+
*/
|
|
2382
|
+
declare function applyS101SymbolSet(style: MapboxStyle): MapboxStyle;
|
|
2383
|
+
|
|
2384
|
+
/**
|
|
2385
|
+
* CHRT house ATON/LIGHTS symbol set (portrayal-excellence 7d, ATON slice).
|
|
1408
2386
|
*
|
|
1409
|
-
*
|
|
1410
|
-
*
|
|
1411
|
-
*
|
|
1412
|
-
*
|
|
2387
|
+
* Design intent (Anthony's brief): clear, simplified silhouettes;
|
|
2388
|
+
* colour-true marks — a green buoy IS green, a red buoy IS red, exactly
|
|
2389
|
+
* as encoded in the feature's COLOUR attribute; sound-capable aids show a
|
|
2390
|
+
* sound badge, radar-capable aids show a radar badge.
|
|
2391
|
+
*
|
|
2392
|
+
* Mechanics:
|
|
2393
|
+
* - Tintable bodies (lateral/special buoys, beacons, daymarks, the light
|
|
2394
|
+
* flare) ship as single-colour SDF glyphs; a layer-level `icon-color`
|
|
2395
|
+
* expression tints them from the FIRST listed COLOUR code (the dominant
|
|
2396
|
+
* band per S-57 encoding). Region conventions fall out of the data —
|
|
2397
|
+
* nothing here hardcodes IALA A/B.
|
|
2398
|
+
* - Identity-coloured marks (cardinals, isolated danger, safe water) are
|
|
2399
|
+
* fixed-palette glyphs: their colour scheme is invariant under IALA and
|
|
2400
|
+
* single-tint would destroy the meaning. MapLibre ignores `icon-color`
|
|
2401
|
+
* for non-SDF images, so both kinds coexist in one layer.
|
|
2402
|
+
* - Capability badges ride the existing child-symbol mechanics: FOGSIG
|
|
2403
|
+
* features render the sound badge, RTPBCN/RDOSTA the radar badge, at
|
|
2404
|
+
* their S-52 child offsets beside the parent aid.
|
|
2405
|
+
*
|
|
2406
|
+
* The house palette below is a v1 placeholder tuned for legibility against
|
|
2407
|
+
* CHRT's water fills — the 7d design pass (Anthony + design) owns the
|
|
2408
|
+
* final values. Naming/pricing of the house style is an OPEN decision
|
|
2409
|
+
* (see .chrt/plans/chrt-portrayal-excellence.md P7d); nothing here touches
|
|
2410
|
+
* pricing or entitlements.
|
|
1413
2411
|
*/
|
|
1414
2412
|
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
interface TileTokenResponse {
|
|
1421
|
-
/** ES256-signed JWT; do not log. */
|
|
1422
|
-
token: string;
|
|
1423
|
-
/** Unix seconds (matches JWT `exp`). */
|
|
1424
|
-
expiresAt: number;
|
|
1425
|
-
/** Key id used to sign (matches JWT header `kid`). */
|
|
1426
|
-
kid: string;
|
|
1427
|
-
/** Build id/tag pinned into the JWT — the tile-worker cache key. */
|
|
1428
|
-
buildTag: string;
|
|
1429
|
-
/** Echo of the region the token is scoped to. */
|
|
1430
|
-
region: string;
|
|
1431
|
-
}
|
|
1432
|
-
/** Typed error codes the mint flow surfaces; callers switch on `.code`. */
|
|
1433
|
-
type TileTokenErrorCode = "invalid_api_key" | "feature_flag_disabled" | "region_not_licensed" | "tile_quota_exceeded" | "region_not_available" | "network_error" | "unexpected_response";
|
|
1434
|
-
declare class TileTokenError extends Error {
|
|
1435
|
-
readonly code: TileTokenErrorCode;
|
|
1436
|
-
readonly status?: number;
|
|
1437
|
-
constructor(code: TileTokenErrorCode, message: string, status?: number);
|
|
1438
|
-
}
|
|
1439
|
-
/** MapLibre / Mapbox GL `transformRequest` return shape. */
|
|
1440
|
-
interface TransformedRequest {
|
|
1441
|
-
url: string;
|
|
1442
|
-
headers?: Record<string, string>;
|
|
1443
|
-
}
|
|
2413
|
+
declare const CHRT_ICON_PREFIX = "chrt:";
|
|
2414
|
+
/** Glyphs registered as SDF (tintable via icon-color). */
|
|
2415
|
+
declare const CHRT_SDF_GLYPHS: ReadonlySet<string>;
|
|
2416
|
+
/** All house glyph names. */
|
|
2417
|
+
declare const CHRT_GLYPH_NAMES: ReadonlySet<string>;
|
|
1444
2418
|
/**
|
|
1445
|
-
*
|
|
1446
|
-
*
|
|
2419
|
+
* House ATON palette — S-57 COLOUR code → hex. v1 placeholder values
|
|
2420
|
+
* (see module header); chosen for contrast on the CHRT day water ramp.
|
|
1447
2421
|
*/
|
|
1448
|
-
declare
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
2422
|
+
declare const CHRT_ATON_COLORS: Record<string, string>;
|
|
2423
|
+
/** First-listed-colour-wins tint expression for SDF bodies. */
|
|
2424
|
+
declare function chrtAtonTintExpression(): unknown[];
|
|
2425
|
+
/** Lights tint: exact colour (incl. blue/orange — the house style renders
|
|
2426
|
+
* the encoded colour, unlike the S-52 three-bucket flares); colourless
|
|
2427
|
+
* lights read as white with the dark halo carrying contrast. */
|
|
2428
|
+
declare function chrtLightTintExpression(): unknown[];
|
|
2429
|
+
/**
|
|
2430
|
+
* Switch a generated style document to the CHRT house symbol set: rewrite
|
|
2431
|
+
* the ATON/LIGHTS icon expressions and inject the colour-true tint on
|
|
2432
|
+
* tintable layers. Returns the same style object (mutated).
|
|
2433
|
+
*/
|
|
2434
|
+
declare function applyChrtSymbolSet(style: MapboxStyle): MapboxStyle;
|
|
2435
|
+
|
|
2436
|
+
/**
|
|
2437
|
+
* S-52 SVG Loader — pure (DOM-free) string operations over the inlined S-52
|
|
2438
|
+
* SVG catalogue in `s52-svgs-generated.ts`. SVG files use S-52 color token
|
|
2439
|
+
* names (e.g., CHBLK, LITRD) as fill/stroke values; `applyColorTheme` swaps
|
|
2440
|
+
* those tokens for hex from the active palette.
|
|
2441
|
+
*
|
|
2442
|
+
* Browser-only image loaders live in `./s52-svg-loader-browser.ts` (sub-export
|
|
2443
|
+
* `@chrtco/sdk/atlas/browser`) — they use `new Image()` and require a DOM.
|
|
2444
|
+
*/
|
|
2445
|
+
|
|
2446
|
+
/**
|
|
2447
|
+
* Get raw SVG string for an S-52 symbol by name (e.g., "BOYCAN01").
|
|
2448
|
+
* Returns null if the symbol is not found.
|
|
2449
|
+
*/
|
|
2450
|
+
declare function getS52SvgString(symbolName: string): string | null;
|
|
2451
|
+
/**
|
|
2452
|
+
* Get an S-52 SVG string with color tokens resolved to hex values
|
|
2453
|
+
* from the specified color table.
|
|
2454
|
+
*/
|
|
2455
|
+
declare function getThemedS52Svg(symbolName: string, colorTable?: ColorTableName): string | null;
|
|
2456
|
+
/**
|
|
2457
|
+
* Replace S-52 color token names in an SVG string with hex colors
|
|
2458
|
+
* from the active color table.
|
|
2459
|
+
*
|
|
2460
|
+
* Matches tokens in fill="TOKEN" and stroke="TOKEN" attribute values.
|
|
2461
|
+
*/
|
|
2462
|
+
declare function applyColorTheme(svgString: string, colorTable?: ColorTableName): string;
|
|
2463
|
+
/** Get a list of all available S-52 point symbol names. */
|
|
2464
|
+
declare function getAvailablePointSymbols(): string[];
|
|
2465
|
+
/** Get a list of all available S-52 pattern names. */
|
|
2466
|
+
declare function getAvailablePatterns(): string[];
|
|
2467
|
+
/** Get a list of all available S-52 line symbol names. */
|
|
2468
|
+
declare function getAvailableLineSymbols(): string[];
|
|
2469
|
+
/** Stats for debugging */
|
|
2470
|
+
declare function getS52SymbolStats(): {
|
|
2471
|
+
pointCount: number;
|
|
2472
|
+
patternCount: number;
|
|
2473
|
+
lineCount: number;
|
|
2474
|
+
totalCount: number;
|
|
2475
|
+
};
|
|
2476
|
+
|
|
2477
|
+
/**
|
|
2478
|
+
* Zoom range of CHRT tile builds — kept in lockstep with the baremetal
|
|
2479
|
+
* tippecanoe invocation (tools/chrt-baremetal/server/src/tilebuild/per-layer-zoom.ts).
|
|
2480
|
+
*
|
|
2481
|
+
* Per-S-57-class minzoom/maxzoom narrowing is handled inside the MVT at
|
|
2482
|
+
* tile-build time via per-feature `tippecanoe.minzoom/maxzoom`; these two
|
|
2483
|
+
* constants are the outer envelope the MapLibre source declares, so the
|
|
2484
|
+
* client doesn't request tiles outside what the pmtiles can actually serve.
|
|
2485
|
+
*/
|
|
2486
|
+
declare const BUILD_MINZOOM = 0;
|
|
2487
|
+
declare const BUILD_MAXZOOM = 14;
|
|
2488
|
+
|
|
2489
|
+
/**
|
|
2490
|
+
* CHRTstyle custom styles — the customer-facing map_styles config applied
|
|
2491
|
+
* on top of the generated S-52 style.
|
|
2492
|
+
*
|
|
2493
|
+
* A team's `map_styles` row (platform → Map Styles) stores S-52 rendering
|
|
2494
|
+
* preferences: which colour tables are enabled, the default palette, the
|
|
2495
|
+
* S-52 display mode, per-group visibility/scale/collision knobs, and an
|
|
2496
|
+
* optional layer whitelist. Keys bind a style via `api_keys.map_style_id`;
|
|
2497
|
+
* `mint-tile-token` embeds `style_id` + `style_rev` claims for entitled
|
|
2498
|
+
* (Dev+) plans, and the tile-worker's `/v1/styles/{region}/style.json`
|
|
2499
|
+
* route resolves the config and calls `generateCustomStyle()` here.
|
|
2500
|
+
*
|
|
2501
|
+
* This module is the single source of truth for:
|
|
2502
|
+
* - the settings shapes (`NavAidSettings` etc. — the platform app
|
|
2503
|
+
* re-exports them from `src/lib/map/nav-aid-settings.ts`),
|
|
2504
|
+
* - sanitization of the stored JSONB (never trust row contents: the
|
|
2505
|
+
* table has no CHECK constraints, so clamp + whitelist everything),
|
|
2506
|
+
* - the static application of those settings to a generated style.
|
|
2507
|
+
*
|
|
2508
|
+
* Safety invariants honored here:
|
|
2509
|
+
* - `allowOverlap: false` (the default) leaves the generator's S-52
|
|
2510
|
+
* collision discipline untouched — safety-critical classes keep their
|
|
2511
|
+
* forced `*-allow-overlap: true`. `allowOverlap: true` only ever ADDS
|
|
2512
|
+
* visibility, never removes it.
|
|
2513
|
+
* - Sanitization can only narrow values into UI-legal ranges; unknown
|
|
2514
|
+
* fields are dropped, so a hand-crafted row can't smuggle arbitrary
|
|
2515
|
+
* style JSON into served output.
|
|
2516
|
+
*/
|
|
2517
|
+
|
|
2518
|
+
interface NavAidSettings {
|
|
2519
|
+
buoysVisible: boolean;
|
|
2520
|
+
beaconsVisible: boolean;
|
|
2521
|
+
lightsVisible: boolean;
|
|
2522
|
+
/** null = S-52 default, 0 = always show, 1-14 = custom minzoom */
|
|
2523
|
+
scaminOverride: number | null;
|
|
2524
|
+
/** Icon size multiplier (0.2–2.0) */
|
|
2525
|
+
iconScale: number;
|
|
2526
|
+
/** When true, icon-size is a flat value (no zoom interpolation) */
|
|
2527
|
+
iconSizeLocked: boolean;
|
|
2528
|
+
/** Allow icons to overlap at all zooms */
|
|
2529
|
+
allowOverlap: boolean;
|
|
2530
|
+
/** Show sector light arcs on map */
|
|
2531
|
+
showSectorArcs: boolean;
|
|
2532
|
+
/** Show fog signal icons */
|
|
2533
|
+
fogSignalsVisible: boolean;
|
|
2534
|
+
/** Show radar transponder / radar station icons */
|
|
2535
|
+
radarVisible: boolean;
|
|
2536
|
+
}
|
|
2537
|
+
interface LabelSettings {
|
|
2538
|
+
navAidLabelsVisible: boolean;
|
|
2539
|
+
landLabelsVisible: boolean;
|
|
2540
|
+
structureLabelsVisible: boolean;
|
|
2541
|
+
/** Show depth contour (DEPCNT) value labels */
|
|
2542
|
+
depthContoursVisible: boolean;
|
|
2543
|
+
/** Show full OBJNAM instead of mariner shorthand for nav aids */
|
|
2544
|
+
navAidFullNames: boolean;
|
|
2545
|
+
/** null = use default minzoom, 0-14 = custom override */
|
|
2546
|
+
minzoomOverride: number | null;
|
|
2547
|
+
/** Text size multiplier (0.5–2.0) */
|
|
2548
|
+
textScale: number;
|
|
2549
|
+
/** Allow text labels to overlap */
|
|
2550
|
+
allowOverlap: boolean;
|
|
2551
|
+
}
|
|
2552
|
+
interface SoundingSettings {
|
|
2553
|
+
visible: boolean;
|
|
2554
|
+
minzoomOverride: number | null;
|
|
2555
|
+
textScale: number;
|
|
2556
|
+
allowOverlap: boolean;
|
|
2557
|
+
/** Show depth units suffix */
|
|
2558
|
+
showUnits: boolean;
|
|
1473
2559
|
/**
|
|
1474
|
-
*
|
|
1475
|
-
*
|
|
1476
|
-
*
|
|
1477
|
-
* CDNs). Kicks off a background mint immediately so the cache warms within
|
|
1478
|
-
* one round-trip; the first tile or two may go unauthenticated and be
|
|
1479
|
-
* retried by the renderer.
|
|
2560
|
+
* S-52 §SOUNDG02 safety contour (metres). Soundings shoaler than this
|
|
2561
|
+
* render in high-contrast SNDG2; deeper soundings render in muted SNDG1.
|
|
2562
|
+
* Default 10 m.
|
|
1480
2563
|
*/
|
|
1481
|
-
|
|
1482
|
-
/**
|
|
1483
|
-
|
|
2564
|
+
safetyContour: number;
|
|
2565
|
+
/** Numeral weight; semibold reads sharper at small sizes on screen. */
|
|
2566
|
+
fontWeight: "regular" | "semibold";
|
|
2567
|
+
/** When false, all soundings render in a single shade (SNDG2). */
|
|
2568
|
+
twoShade: boolean;
|
|
2569
|
+
}
|
|
2570
|
+
interface WaterBodySettings {
|
|
2571
|
+
seaAreasVisible: boolean;
|
|
2572
|
+
lakesVisible: boolean;
|
|
2573
|
+
riversVisible: boolean;
|
|
2574
|
+
canalsVisible: boolean;
|
|
2575
|
+
minzoomOverride: number | null;
|
|
2576
|
+
textScale: number;
|
|
2577
|
+
allowOverlap: boolean;
|
|
2578
|
+
/** Uppercase major sea area names (raster chart style) */
|
|
2579
|
+
uppercaseSeaAreas: boolean;
|
|
2580
|
+
}
|
|
2581
|
+
declare const DEFAULT_NAV_AID_SETTINGS: NavAidSettings;
|
|
2582
|
+
declare const DEFAULT_LABEL_SETTINGS: LabelSettings;
|
|
2583
|
+
declare const DEFAULT_SOUNDING_SETTINGS: SoundingSettings;
|
|
2584
|
+
declare const DEFAULT_WATER_BODY_SETTINGS: WaterBodySettings;
|
|
2585
|
+
/** Nav-aid layer groups keyed by toggle name */
|
|
2586
|
+
declare const NAV_AID_LAYER_GROUPS: Record<string, string[]>;
|
|
2587
|
+
/** All nav-aid layer names (flat set for quick lookups) */
|
|
2588
|
+
declare const ALL_NAV_AID_LAYERS: Set<string>;
|
|
2589
|
+
/** Label layer groups keyed by toggle name (soundings moved to own panel) */
|
|
2590
|
+
declare const LABEL_LAYER_GROUPS: Record<string, string[]>;
|
|
2591
|
+
/** Sounding layers */
|
|
2592
|
+
declare const SOUNDING_LAYERS: string[];
|
|
2593
|
+
/** Water body layer groups keyed by toggle name */
|
|
2594
|
+
declare const WATER_BODY_LAYER_GROUPS: Record<string, string[]>;
|
|
2595
|
+
/** All water body layer names (flat set for quick lookups) */
|
|
2596
|
+
declare const ALL_WATER_BODY_LAYERS: Set<string>;
|
|
2597
|
+
/** Check if a nav-aid layer is visible given current settings */
|
|
2598
|
+
declare function isNavAidLayerVisible(layerName: string, settings: NavAidSettings): boolean;
|
|
2599
|
+
/** Check if a label layer is visible given current settings */
|
|
2600
|
+
declare function isLabelLayerVisible(layerName: string, settings: LabelSettings): boolean;
|
|
2601
|
+
/** Check if a sounding layer is visible */
|
|
2602
|
+
declare function isSoundingLayerVisible(settings: SoundingSettings): boolean;
|
|
2603
|
+
/** Check if a water body layer is visible given current settings */
|
|
2604
|
+
declare function isWaterBodyLayerVisible(layerName: string, settings: WaterBodySettings): boolean;
|
|
2605
|
+
interface CustomStyleConfig {
|
|
2606
|
+
/** Palettes the customer allows their end users to request. Never empty. */
|
|
2607
|
+
enabled_color_tables: ColorTableName[];
|
|
2608
|
+
/** Palette served when the request omits `theme` (or requests a disabled one). */
|
|
2609
|
+
default_color_table: ColorTableName;
|
|
1484
2610
|
/**
|
|
1485
|
-
*
|
|
1486
|
-
*
|
|
1487
|
-
*
|
|
2611
|
+
* S-52 display mode: BASE ⊂ STANDARD ⊂ ALL. Carried through sanitization
|
|
2612
|
+
* but NOT applied as a render filter in v1: the platform's vector map
|
|
2613
|
+
* renders every class regardless of mode (the mode only filters the /map
|
|
2614
|
+
* sidebar list), and several CHRT-structural classes (e.g. SEAARE, the
|
|
2615
|
+
* cross-band base water fill) sit in category OTHER — filtering them out
|
|
2616
|
+
* under the DB-default `STANDARD` would serve charts with the base water
|
|
2617
|
+
* missing. Render-filtering by display category is a documented follow-up
|
|
2618
|
+
* that needs its own category audit first.
|
|
1488
2619
|
*/
|
|
1489
|
-
|
|
2620
|
+
display_mode: DisplayMode;
|
|
2621
|
+
nav_aid_settings: NavAidSettings;
|
|
2622
|
+
label_settings: LabelSettings;
|
|
2623
|
+
sounding_settings: SoundingSettings;
|
|
2624
|
+
water_body_settings: WaterBodySettings;
|
|
2625
|
+
/** Whitelist of S-57 classes to render; null = all. */
|
|
2626
|
+
visible_layers: string[] | null;
|
|
2627
|
+
}
|
|
2628
|
+
declare const DEFAULT_CUSTOM_STYLE_CONFIG: CustomStyleConfig;
|
|
2629
|
+
/**
|
|
2630
|
+
* Sanitize a raw `map_styles` row (or any untrusted JSON) into a fully
|
|
2631
|
+
* populated `CustomStyleConfig`. Unknown fields are dropped, enums are
|
|
2632
|
+
* validated, numerics are clamped to the UI's legal ranges, and missing
|
|
2633
|
+
* fields fall back to the platform defaults. Never throws.
|
|
2634
|
+
*/
|
|
2635
|
+
declare function sanitizeCustomStyleConfig(raw: unknown): CustomStyleConfig;
|
|
2636
|
+
/** Normalize a `?theme=` value to a colour table name; null for anything else. */
|
|
2637
|
+
declare function normalizeTheme(raw: string | null | undefined): ColorTableName | null;
|
|
2638
|
+
interface ResolvedTheme {
|
|
2639
|
+
palette: ColorTableName;
|
|
2640
|
+
/** True when the requested theme was disabled by the custom style and the
|
|
2641
|
+
* default palette was served instead. */
|
|
2642
|
+
themeFellBack: boolean;
|
|
2643
|
+
}
|
|
2644
|
+
/**
|
|
2645
|
+
* Pick the palette to serve. A requested theme that the custom style has
|
|
2646
|
+
* disabled falls back to the style's default palette — an end user of a
|
|
2647
|
+
* CHRT customer should get a chart, not a dead map, when the customer
|
|
2648
|
+
* narrowed the palette set.
|
|
2649
|
+
*/
|
|
2650
|
+
declare function resolveCustomTheme(config: CustomStyleConfig, requested: ColorTableName | null): ResolvedTheme;
|
|
2651
|
+
/**
|
|
2652
|
+
* Scale the numeric outputs of a size-valued expression. Handles plain
|
|
2653
|
+
* numbers plus the output positions of `interpolate`, `step`, `case`, and
|
|
2654
|
+
* `match` expressions; anything else is returned unchanged (defensive: a
|
|
2655
|
+
* mis-scaled comparison operand would corrupt the expression, so only
|
|
2656
|
+
* positions that are guaranteed to be size outputs are touched).
|
|
2657
|
+
*/
|
|
2658
|
+
declare function scaleSizeValue(value: unknown, factor: number): unknown;
|
|
2659
|
+
/**
|
|
2660
|
+
* Apply a sanitized custom-style config to a generated style, statically.
|
|
2661
|
+
*
|
|
2662
|
+
* Mirrors the platform map's runtime settings semantics (visibility per
|
|
2663
|
+
* class group, icon/text scale, allow-overlap, minzoom overrides, SEAARE
|
|
2664
|
+
* uppercase, layer whitelist) as build-time layer transforms. Fields with
|
|
2665
|
+
* no static vector-tile equivalent (`navAidFullNames`, `showUnits`,
|
|
2666
|
+
* `iconSizeLocked`, `showSectorArcs` need per-feature preprocessing) and
|
|
2667
|
+
* `display_mode` (see `CustomStyleConfig.display_mode`) are not applied
|
|
2668
|
+
* here — documented in the Style API docs.
|
|
2669
|
+
*
|
|
2670
|
+
* Sounding *rendering* settings (safetyContour / twoShade / fontWeight)
|
|
2671
|
+
* are generator options, not layer transforms — `generateCustomStyle()`
|
|
2672
|
+
* threads them into `generateStyle()`.
|
|
2673
|
+
*
|
|
2674
|
+
* The input style is mutated in place and returned (callers generate a
|
|
2675
|
+
* fresh style per request; a defensive deep-clone would be pure waste on
|
|
2676
|
+
* a ~700-layer document).
|
|
2677
|
+
*/
|
|
2678
|
+
declare function applyCustomStyleSettings(style: MapboxStyle, config: CustomStyleConfig): MapboxStyle;
|
|
2679
|
+
interface GenerateCustomStyleOptions extends StyleGeneratorOptions {
|
|
2680
|
+
/** Requested palette (already normalized); null/undefined = style default. */
|
|
2681
|
+
theme?: ColorTableName | null;
|
|
2682
|
+
}
|
|
2683
|
+
interface GeneratedCustomStyle {
|
|
2684
|
+
style: MapboxStyle;
|
|
2685
|
+
palette: ColorTableName;
|
|
2686
|
+
themeFellBack: boolean;
|
|
1490
2687
|
}
|
|
2688
|
+
/**
|
|
2689
|
+
* Generate the S-52 style for a customer's custom-style config: resolve the
|
|
2690
|
+
* palette against the config's enabled set, thread the sounding rendering
|
|
2691
|
+
* settings into the generator, then apply the static layer transforms.
|
|
2692
|
+
*/
|
|
2693
|
+
declare function generateCustomStyle(config: CustomStyleConfig, opts?: GenerateCustomStyleOptions): GeneratedCustomStyle;
|
|
1491
2694
|
|
|
1492
2695
|
/**
|
|
1493
2696
|
* Generic async auto-pagination generator.
|
|
@@ -1602,6 +2805,12 @@ declare class Chrt {
|
|
|
1602
2805
|
* requires `manifestPath`.
|
|
1603
2806
|
*/
|
|
1604
2807
|
readonly offline: OfflineEndpoint;
|
|
2808
|
+
/**
|
|
2809
|
+
* CHRTinteract — click-to-inspect: `attach(map)` for wired popups/events,
|
|
2810
|
+
* `inspect(feature)` for headless decode. Included with the Dev plan and
|
|
2811
|
+
* above; enforced server-side at attach/inspect time.
|
|
2812
|
+
*/
|
|
2813
|
+
readonly interact: InteractClient;
|
|
1605
2814
|
private featuresEp;
|
|
1606
2815
|
private queryEp;
|
|
1607
2816
|
private http;
|
|
@@ -1651,15 +2860,38 @@ declare class Chrt {
|
|
|
1651
2860
|
* transformRequest: chrt.transformRequest(),
|
|
1652
2861
|
* });
|
|
1653
2862
|
*
|
|
1654
|
-
* @remarks
|
|
2863
|
+
* @remarks Pass `symbolSet: "s101"` for the official S-101 Portrayal
|
|
2864
|
+
* Catalogue symbol artwork (load images via `loadS101SymbolImages` from
|
|
2865
|
+
* `@chrtco/sdk/atlas/browser`); default is the S-52 set. Generated
|
|
2866
|
+
* locally, so it never applies a key-bound CHRTstyle custom style — use
|
|
2867
|
+
* {@link styleUrl} / {@link fetchStyle} (the served Style API) for that.
|
|
1655
2868
|
*/
|
|
1656
2869
|
style(opts?: ChrtStyleOptions): MapboxStyle;
|
|
1657
2870
|
/**
|
|
1658
|
-
*
|
|
1659
|
-
*
|
|
1660
|
-
*
|
|
2871
|
+
* URL of the served S-52 style — the CHRTstyle Style API at
|
|
2872
|
+
* `tiles.chrt.co/v1/styles/{region}/style.json`. Unlike {@link style}
|
|
2873
|
+
* (generated locally), the served document honors the API key's bound
|
|
2874
|
+
* CHRTstyle custom style: palettes, layer visibility, label/icon scale,
|
|
2875
|
+
* and the rest of the platform's Map Styles settings, applied server-side
|
|
2876
|
+
* and tier-gated (custom styles are Dev+; Free keys get the default
|
|
2877
|
+
* themes). Async because it pre-mints the tile token, so the style
|
|
2878
|
+
* request is guaranteed to carry auth via `transformRequest()`.
|
|
2879
|
+
*
|
|
2880
|
+
* @example
|
|
2881
|
+
* const map = new maplibregl.Map({
|
|
2882
|
+
* container: 'map',
|
|
2883
|
+
* style: await chrt.styleUrl({ theme: 'day' }),
|
|
2884
|
+
* transformRequest: chrt.transformRequest(),
|
|
2885
|
+
* });
|
|
2886
|
+
*/
|
|
2887
|
+
styleUrl(opts?: StyleUrlOptions): Promise<string>;
|
|
2888
|
+
/**
|
|
2889
|
+
* Fetch the served S-52 style (see {@link styleUrl}) as a MapLibre style
|
|
2890
|
+
* object — inspect or mutate it before handing it to the map.
|
|
2891
|
+
* `chrt.style()` remains the local generator that needs no network
|
|
2892
|
+
* round-trip (and therefore applies no custom style).
|
|
1661
2893
|
*/
|
|
1662
|
-
|
|
2894
|
+
fetchStyle(opts?: FetchStyleOptions): Promise<MapLibreStyle>;
|
|
1663
2895
|
/**
|
|
1664
2896
|
* Returns a `transformRequest` for Mapbox GL JS / MapLibre GL JS that mints a
|
|
1665
2897
|
* short-lived tile JWT from your API key and attaches it as
|
|
@@ -1684,4 +2916,4 @@ declare class Chrt {
|
|
|
1684
2916
|
warmTiles(region?: string): Promise<void>;
|
|
1685
2917
|
}
|
|
1686
2918
|
|
|
1687
|
-
export { type AtlasStyle, BAND_DRAW_ORDER, BAND_PRIORITY_RANGES, type BBox, BUILD_MAXZOOM, BUILD_MINZOOM, type BandCode, type BandPriorityRange, type BuildOfflineStyleOptions, type BuildSourcesOptions, CHART_BAND_CODES, CHART_CASCADE_CODES, CHART_SECTIONS, type CellDeletedEvent, type CellDetail, type CellEventData, type CellNewEvent, type CellUpdatedData, type CellUpdatedEvent, type CellsOptions, type CellsResponse, type ChartSection, Chrt, type ChrtConfig, ChrtError, type ChrtStyleOptions, ColorTableName, type CoverageOptions, type CoverageResponse, type CoverageSource, DEFAULT_REGION, DEFAULT_TILE_BASE_URL, DEFAULT_TILE_REGION, type DisplayCategory, type DisplayMode, type FeatureCollection, type FeaturesOptions, FileSystemAdapter, type GeoJsonFeature, type GeoJsonGeometry, type GeomType, LABELED_LAYERS, LABEL_BEHAVIOR, type LabelBehavior, type LabelConfigOptions, type LabelLayerConfig, type LookupEntry, type MapLibreStyle, type MapboxStyle, type MapboxVectorSource, NAUTICAL_SYMBOLS, type NauticalCategory, type NauticalSymbol, type OfflineBundleResponse, type OfflineDownloadOptions, type OfflineDownloadProgress, type OfflineDownloadResult, OfflineError, type OfflineErrorCode, type OfflineFetchStyleOptions, type OfflineHeartbeatOptions, type OfflineRegionSummary, type OfflineRemoveOptions, OfflineStyleError, type OfflineStylePlatform, type OfflineStyleResponse, type PmtilesVectorSource, type QueryOptions, type ResolvedStyle, type RouteFeatureQueryOptions, type RouteFeatureQueryResponse, type RouteQueryOptions, type RouteQueryResponse, type S101Feature, S101_CHART_SECTIONS, S101_FEATURES, S101_NEW_SYMBOLS, S101_SYMBOL_GROUPS, S52_DRAW_ORDER, S52_LOOKUP, SYMBOL_GROUPS, SYMBOL_MAP, type ScaleBand, type SourceMode, type StyleGeneratorOptions, type StyleLayer, type SymbolGroup, TileAuth, type TileGroup, type TileGroupsResponse, TileTokenError, type TileTokenErrorCode, type TileTokenResponse, type TransformRequest, type TransformedRequest, type VectorSourceSpec, type WebhookEvent, type WebhookEventType, type WebhookPayload, applyColorTheme, bandFilterExpression, buildLabelLayer, buildLayersForClass, buildOfflineStyle, buildSources, combineWithBandFilter, daymarkColor, decimateFeatures, depareColor, depareFillExpression, generateSpriteManifest, generateSpriteSheet, generateStyle, generateStyleJSON, getAvailableLineSymbols, getAvailablePatterns, getAvailablePointSymbols, getCollisionSettings, getDrawPriority, getGridSizeForZoom, getIconExpression, getLabelBehavior, getLabelConfig, getLookupEntry, getMaxCellsForZoom, getOrderedClasses, getS52SvgString, getS52SymbolStats, getStyleStats, getSymbolSvgString, getThemedS52Svg, hazardColor, hazardFillExpression, isNavAidLayer, isVisibleInMode, lateralColor, lateralFillExpression, lightColor, lightFillExpression, paginate, parseWebhook, preprocessLights, preprocessNavAids, preprocessSoundings, preprocessWaterBodies, resolveStyle, scaminToMinZoom, withinBboxFilter, worldMinusBboxPolygon };
|
|
2919
|
+
export { ALL_NAV_AID_LAYERS, ALL_WATER_BODY_LAYERS, AREA_QUERY_LAYERS, type AreaInspectResult, type AtlasStyle, type AttachOptions, BAND_DRAW_ORDER, BAND_PRIORITY_RANGES, type BBox, BRIDGE_QUERY_LAYERS, BUILD_MAXZOOM, BUILD_MINZOOM, type BandCode, type BandPriorityRange, type BridgeInspectResult, type BuildOfflineStyleOptions, type BuildSourcesOptions, CHART_BAND_CODES, CHART_CASCADE_CODES, CHART_SECTIONS, CHRT_ATON_COLORS, CHRT_GLYPH_NAMES, CHRT_ICON_PREFIX, CHRT_SDF_GLYPHS, type CandidateQueryOptions, type CandidatesEventContext, type CellDeletedEvent, type CellDetail, type CellEventData, type CellNewEvent, type CellUpdatedData, type CellUpdatedEvent, type CellsOptions, type CellsResponse, type ChartSection, Chrt, type ChrtConfig, ChrtError, type ChrtStyleOptions, type ChrtStyleTheme, type ClickAnchor, ColorTableName, type CoverageOptions, type CoverageResponse, type CoverageSource, type CustomStyleConfig, DEFAULT_CLICK_TOLERANCE, DEFAULT_CUSTOM_STYLE_CONFIG, DEFAULT_INSPECT_CLASS_RANK, DEFAULT_LABEL_SETTINGS, DEFAULT_NAV_AID_SETTINGS, DEFAULT_REGION, DEFAULT_SOUNDING_SETTINGS, DEFAULT_TILE_BASE_URL, DEFAULT_TILE_REGION, DEFAULT_WATER_BODY_SETTINGS, type DecodedAreaFeature, type DecodedBridge, type DecodedNavAid, type DecodedProperty, type DisplayCategory, type DisplayMode, type FeatureCollection, type FeaturesOptions, type FetchStyleOptions, FileSystemAdapter, type FlashPattern, type FlashPhase, type GenerateCustomStyleOptions, type GeneratedCustomStyle, type GeoJsonFeature, type GeoJsonGeometry, type GeomType, INSPECT_CLASS_RANK, INSPECT_RANK_DEVIATIONS, type InspectCandidate, type InspectCandidateSet, type InspectEnrichment, type InspectEventContext, type InspectNotice, type InspectOptions, type InspectResult, type InspectTargetClass, type InspectableFeature, InteractClient, type InteractEntitlement, InteractError, type InteractErrorCode, type InteractHandle, type InteractMapLike, type InteractMapMouseEvent, LABELED_LAYERS, LABEL_BEHAVIOR, LABEL_LAYER_GROUPS, LABEL_PRIORITY, type LabelBehavior, type LabelConfigOptions, type LabelLayerConfig, type LabelSettings, type LookupEntry, type MapLibreStyle, type MapboxStyle, type MapboxVectorSource, NAUTICAL_SYMBOLS, NAV_AID_LAYER_GROUPS, NAV_AID_QUERY_LAYERS, NON_SOLAS_DISCLAIMER, NON_SOLAS_DISCLAIMER_SHORT, type NauticalCategory, type NauticalSymbol, type NavAidInspectResult, type NavAidSettings, type OfflineBundleResponse, type OfflineDownloadOptions, type OfflineDownloadProgress, type OfflineDownloadResult, OfflineError, type OfflineErrorCode, type OfflineFetchStyleOptions, type OfflineHeartbeatOptions, type OfflineRegionSummary, type OfflineRemoveOptions, OfflineStyleError, type OfflineStylePlatform, type OfflineStyleResponse, type PmtilesVectorSource, type QueryOptions, type ResolvedStyle, type ResolvedTheme, type RouteFeatureQueryOptions, type RouteFeatureQueryResponse, type RouteQueryOptions, type RouteQueryResponse, type S101Feature, S101_CHART_SECTIONS, S101_FEATURES, S101_ICON_PREFIX, S101_NEW_SYMBOLS, S101_SOURCE_COMMIT, S101_SYMBOL_GROUPS, S101_SYMBOL_NAMES, S52_DRAW_ORDER, S52_LOOKUP, SOUNDING_LAYERS, SYMBOL_GROUPS, SYMBOL_MAP, type ScaleBand, type SectorArcFeature, type SectorArcFeatureCollection, type SectorInfo, type SoundingSettings, type SourceMode, type StyleGeneratorOptions, type StyleLayer, type StyleUrlOptions, type SymbolGroup, TileAuth, type TileGroup, type TileGroupsResponse, TileTokenError, type TileTokenErrorCode, type TileTokenResponse, type TransformRequest, type TransformedRequest, type VectorSourceSpec, WATER_BODY_LAYER_GROUPS, type WaterBodySettings, type WebhookEvent, type WebhookEventType, type WebhookPayload, applyChrtSymbolSet, applyColorTheme, applyCustomStyleSettings, applyS101SymbolSet, bandFilterExpression, buildFlashPattern, buildLabelLayer, buildLayersForClass, buildOfflineStyle, buildSectorArcGeoJSON, buildSectorArcsFC, buildSectorsFromFeatures, buildSources, candidateRank, chrtAtonTintExpression, chrtLightTintExpression, collectCandidates, collectClickCandidates, combineWithBandFilter, daymarkColor, decimateFeatures, decodeAreaFeatureProps, decodeBridgeProps, decodeCandidate, decodeNavAidProps, depareColor, depareFillExpression, deriveMarinerName, extractNavAidDesignation, featureIdentity, generateCustomStyle, generateSpriteManifest, generateSpriteSheet, generateStyle, generateStyleJSON, getAvailableLineSymbols, getAvailablePatterns, getAvailablePointSymbols, getCollisionSettings, getDrawPriority, getGridSizeForZoom, getIconExpression, getLabelBehavior, getLabelConfig, getLabelPriority, getLookupEntry, getMaxCellsForZoom, getOrderedClasses, getS52SvgString, getS52SymbolStats, getStyleStats, getSymbolSvgString, getThemedS101Svg, getThemedS52Svg, getTopmarkMeaning, hazardColor, hazardFillExpression, isLabelLayerVisible, isNavAidLayer, isNavAidLayerVisible, isSoundingLayerVisible, isVisibleInMode, isWaterBodyLayerVisible, labelSortKey, lateralColor, lateralFillExpression, lightColor, lightFillExpression, normalizeTheme, paginate, parseListCodes, parseWebhook, preprocessLights, preprocessNavAids, preprocessSoundings, preprocessWaterBodies, resolveCustomTheme, resolveS101Color, resolveStyle, resolveTargetClass, sanitizeCustomStyleConfig, scaleSizeValue, scaminToMinZoom, withinBboxFilter, worldMinusBboxPolygon };
|