@chrtco/sdk 0.10.3 → 0.10.5

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/README.md CHANGED
@@ -366,6 +366,9 @@ call any language can make. Everything marked **JS-only** runs in-process and ha
366
366
  | `chrt.cells.get(id)` | `GET /v1/cells/{id}` | |
367
367
  | `chrt.coverage.list(opts?)` | `GET /v1/coverage` | |
368
368
  | `chrt.coverage.forRoute(opts)` | `GET /v1/coverage/route` | which cells a passage needs |
369
+ | `chrt.weather.conditions(opts)` | `GET /v1/weather/conditions` | observed at sea (NDBC); needs `weather:read` |
370
+ | `chrt.weather.alerts(opts)` | `GET /v1/weather/marine-alerts` | active NWS warnings; needs `weather:read` |
371
+ | `chrt.weather.forecast(opts)` | `GET /v1/weather/marine-forecast` | NWS zone forecast; needs `weather:read` |
369
372
  | `chrt.warmTiles(region?)` | `POST /v1/mint/tile-token` | |
370
373
  | `chrt.styleUrl(opts?)` | `GET {tileBaseUrl}/v1/styles/{region}/style.json` | mints first |
371
374
  | `chrt.fetchStyle(opts?)` | same, then fetches it | |
@@ -618,3 +621,55 @@ try {
618
621
  ## License
619
622
 
620
623
  MIT
624
+
625
+ ## CHRTweather (marine weather)
626
+
627
+ NOAA-backed marine weather on the same client and the same key. **U.S. waters only**, and every
628
+ call needs the **`weather:read` scope** — a chart key does not carry it implicitly, so ask CHRT to
629
+ enable it. Without it you get `403 weather_not_entitled`, which retrying will never fix.
630
+
631
+ ```ts
632
+ // Observed — a measurement from the nearest buoy, NOT live.
633
+ const now = await chrt.weather.conditions({ lat: 41.0, lon: -71.1 });
634
+ console.log(now.observed.ageMinutes); // display this: median ~40 min old
635
+ console.log(now.conditions.windSpeed); // undefined => NOT REPORTED, not calm
636
+ console.log(now.unavailable); // what this station did not report
637
+
638
+ // Warnings — poll these cheaply (~60 s) without pulling a forecast.
639
+ const { alerts } = await chrt.weather.alerts({ lat: 42.5, lon: -70.3 });
640
+
641
+ // Forecast — the NWS zone narrative.
642
+ const fc = await chrt.weather.forecast({ zone: "LEZ166" });
643
+ for (const p of fc.periods) console.log(p.label, p.text);
644
+ ```
645
+
646
+ Three rules govern reading any of it. They are the difference between a useful readout and a
647
+ dangerous one.
648
+
649
+ **An empty result never means calm water.** No alerts in force, no buoy in range, no marine zone at
650
+ this position — each means *we do not know* or *nothing is posted*, never *conditions are good*.
651
+ There is deliberately no `safe` or `status` field to bind a green tick to. Render "no warnings in
652
+ force", never "conditions are good".
653
+
654
+ **Absent is not zero.** A measurement a station did not report, or a phrase the forecast parser
655
+ could not read, is omitted rather than defaulted — `conditions.windSpeed === undefined` means the
656
+ buoy sent NDBC's `MM` missing-value sentinel, and rendering that as `0 kn` puts a false calm on a
657
+ sailing display. `"winds less than 10 knots"` gives you `maxKn` and no `minKn` for the same reason.
658
+
659
+ **On the forecast, `text` is authoritative.** The structured `wind` / `seas` / `swell` fields are
660
+ parsed from NWS's own sentence, and where they disagree the text wins — some content exists only
661
+ there. Periods are NWS's own and are neither hourly nor uniform (`OVERNIGHT`, `TUE NIGHT`,
662
+ `WED NIGHT THROUGH THU NIGHT`); a single period can span days, so do not flatten them into an
663
+ hourly series.
664
+
665
+ Two field-level traps worth naming:
666
+
667
+ - **`expires` vs `ends`** on an alert. `expires` is when the *bulletin* lapses; `ends` is when the
668
+ *hazard* passes. Routinely hours apart. Describe the hazard with `ends`.
669
+ - **`seas.minFt`/`maxFt` vs `seas.occasionalFt`.** The range is the mean of the highest **1/3**;
670
+ `occasionalFt` (Great Lakes only) is the mean of the highest **1/10**. In *"Waves 2 to 4 ft …
671
+ occasionally to 8 ft"* the 8 ft wave is the one that knocks a small boat down — never average it
672
+ into the range.
673
+
674
+ CHRT is **not** the issuing authority. Every response carries `attribution` and `disclaimer`;
675
+ display them, and always consult NWS and VHF broadcasts.
package/dist/index.cjs CHANGED
@@ -96,6 +96,7 @@ __export(index_exports, {
96
96
  TileAuth: () => TileAuth,
97
97
  TileTokenError: () => TileTokenError,
98
98
  WATER_BODY_LAYER_GROUPS: () => WATER_BODY_LAYER_GROUPS,
99
+ WeatherEndpoint: () => WeatherEndpoint,
99
100
  applyChrtSymbolSet: () => applyChrtSymbolSet,
100
101
  applyColorTheme: () => applyColorTheme,
101
102
  applyCustomStyleSettings: () => applyCustomStyleSettings,
@@ -647,6 +648,79 @@ var CellsEndpoint = class {
647
648
  }
648
649
  };
649
650
 
651
+ // src/endpoints/weather.ts
652
+ var WeatherEndpoint = class {
653
+ constructor(http) {
654
+ this.http = http;
655
+ }
656
+ /**
657
+ * Observed conditions from the nearest reporting NOAA NDBC station.
658
+ *
659
+ * A **measurement, not a forecast**, and not live — most buoys report hourly
660
+ * and the median observation is around 40 minutes old. `observed.ageMinutes`
661
+ * is on every response and should be displayed: a readout that looks current
662
+ * but is 90 minutes stale is worse than one that says so.
663
+ *
664
+ * `unavailable` names every field the station did not report, so absence is
665
+ * stated rather than inferred from a missing key.
666
+ */
667
+ async conditions(options) {
668
+ return this.http.request(
669
+ "/weather/conditions",
670
+ {
671
+ lat: options.lat,
672
+ lon: options.lon,
673
+ units: options.units,
674
+ station: options.station
675
+ },
676
+ options.signal
677
+ );
678
+ }
679
+ /**
680
+ * Active NWS marine warnings for the zone — Small Craft Advisory, Gale,
681
+ * Storm, Hurricane Force Wind, Special Marine Warning. Most severe first.
682
+ *
683
+ * Its own call, so warnings can be re-checked cheaply (~60 s) without pulling
684
+ * a forecast you already have.
685
+ *
686
+ * **`expires` and `ends` are different.** `expires` is when the *bulletin*
687
+ * lapses — alerts are usually re-issued before then. `ends` is when the
688
+ * *hazard* is expected to be over. They are routinely hours apart, so
689
+ * describe the hazard with `ends` and use `expires` only to decide when to
690
+ * re-fetch.
691
+ *
692
+ * Display `instruction` verbatim: it is NWS's own advice to mariners.
693
+ */
694
+ async alerts(options) {
695
+ return this.http.request(
696
+ "/weather/marine-alerts",
697
+ { lat: options.lat, lon: options.lon, zone: options.zone },
698
+ options.signal
699
+ );
700
+ }
701
+ /**
702
+ * The NWS marine zone forecast — U.S. coastal and Great Lakes waters.
703
+ *
704
+ * Periods are NWS's own and are **neither hourly nor uniform**: `OVERNIGHT`,
705
+ * `TUE NIGHT`, `WED NIGHT THROUGH THU NIGHT`. A single period can span days.
706
+ * Flattening them into an hourly series invents resolution the data does not
707
+ * have.
708
+ *
709
+ * `expires` is the forecast's **own** stated validity, taken from the
710
+ * bulletin, not a TTL CHRT invented. `source.productId` identifies the
711
+ * upstream NWS product, so you can verify CHRT against NOAA directly.
712
+ *
713
+ * Offshore zones are not yet supported and fail with `501`.
714
+ */
715
+ async forecast(options) {
716
+ return this.http.request(
717
+ "/weather/marine-forecast",
718
+ { lat: options.lat, lon: options.lon, zone: options.zone },
719
+ options.signal
720
+ );
721
+ }
722
+ };
723
+
650
724
  // src/endpoints/coverage.ts
651
725
  var METRES_PER_NAUTICAL_MILE = 1852;
652
726
  var CoverageEndpoint = class {
@@ -726,6 +800,37 @@ var FeaturesEndpoint = class {
726
800
  }
727
801
  };
728
802
 
803
+ // src/endpoints/search.ts
804
+ var SearchEndpoint = class {
805
+ constructor(http) {
806
+ this.http = http;
807
+ }
808
+ /**
809
+ * Search the gazetteer.
810
+ *
811
+ * `near` biases ranking and never filters — "Newport" is Rhode Island, Oregon
812
+ * *and* California, and all three come back with the nearest first. `bbox`
813
+ * does filter.
814
+ */
815
+ async find(options) {
816
+ return this.http.request(
817
+ "/search",
818
+ {
819
+ q: options.q,
820
+ near: options.near ? `${options.near[0]},${options.near[1]}` : void 0,
821
+ bbox: options.bbox ? options.bbox.join(",") : void 0,
822
+ kind: options.kind,
823
+ // Both spellings are accepted server-side; the SDK sends the
824
+ // comma-joined form so one array maps to one query parameter.
825
+ layer: Array.isArray(options.layer) ? options.layer.join(",") : options.layer,
826
+ limit: options.limit,
827
+ offset: options.offset
828
+ },
829
+ options.signal
830
+ );
831
+ }
832
+ };
833
+
729
834
  // src/endpoints/query.ts
730
835
  var METRES_PER_NAUTICAL_MILE2 = 1852;
731
836
  var QueryEndpoint = class {
@@ -28582,6 +28687,14 @@ var Chrt = class {
28582
28687
  cells;
28583
28688
  /** Coverage data — list available chart sources */
28584
28689
  coverage;
28690
+ /**
28691
+ * CHRTweather — NOAA-backed marine weather: observed conditions, active
28692
+ * warnings, and the NWS zone forecast. U.S. waters only, and requires the
28693
+ * `weather:read` scope on your key — a chart key does not carry it.
28694
+ *
28695
+ * An empty result from any of these never means calm water.
28696
+ */
28697
+ weather;
28585
28698
  /**
28586
28699
  * CHRToffline — download MBTiles bundles for offline use.
28587
28700
  * Requires `deviceId` in config. Manifest-based budget enforcement
@@ -28595,6 +28708,7 @@ var Chrt = class {
28595
28708
  */
28596
28709
  interact;
28597
28710
  featuresEp;
28711
+ searchEp;
28598
28712
  queryEp;
28599
28713
  http;
28600
28714
  tileAuth;
@@ -28613,7 +28727,9 @@ var Chrt = class {
28613
28727
  this.tiles = new TilesEndpoint(this.http, this.tileAuth, tileOpts);
28614
28728
  this.cells = new CellsEndpoint(this.http);
28615
28729
  this.coverage = new CoverageEndpoint(this.http);
28730
+ this.weather = new WeatherEndpoint(this.http);
28616
28731
  this.featuresEp = new FeaturesEndpoint(this.http);
28732
+ this.searchEp = new SearchEndpoint(this.http);
28617
28733
  this.queryEp = new QueryEndpoint(this.http);
28618
28734
  this.offline = new OfflineEndpoint(this.http, config.deviceId, config.manifestPath);
28619
28735
  this.interact = new InteractClient(this.http);
@@ -28623,6 +28739,32 @@ var Chrt = class {
28623
28739
  async features(options) {
28624
28740
  return this.featuresEp.list(options);
28625
28741
  }
28742
+ /**
28743
+ * CHRTsearch — find charted places by name.
28744
+ *
28745
+ * The only CHRT surface addressed by NAME rather than by space or identifier.
28746
+ * Text in, a small ranked list of named charted places out.
28747
+ *
28748
+ * ```ts
28749
+ * const { results } = await chrt.search({ q: "cutty harbor", near: [-70.93, 41.42] });
28750
+ * // -> [{ name: "Cuttyhunk Harbor Channel", class: "Fairway", kind: "place", ... }]
28751
+ * ```
28752
+ *
28753
+ * Three things worth knowing before wiring it to a text field:
28754
+ *
28755
+ * 1. **Pass `near`.** It biases ranking and never filters. "Newport" is
28756
+ * Rhode Island, Oregon *and* California; without `near` the first row is
28757
+ * the wrong Newport most of the time.
28758
+ * 2. **It is metered separately** from `features()` — exhausting one does not
28759
+ * affect the other. Sized for a typeahead, and not gated by tier.
28760
+ * 3. **An empty `results` array is not proof a place does not exist.** If the
28761
+ * response carries a `coverage` block, CHRT holds no charts at that
28762
+ * position and the search could not run there. That is a different answer
28763
+ * from "nothing matched", and neither means the water is clear.
28764
+ */
28765
+ async search(options) {
28766
+ return this.searchEp.find(options);
28767
+ }
28626
28768
  /** Spatial proximity query around a point */
28627
28769
  async query(options) {
28628
28770
  return this.queryEp.nearby(options);
@@ -28949,6 +29091,7 @@ var Chrt = class {
28949
29091
  TileAuth,
28950
29092
  TileTokenError,
28951
29093
  WATER_BODY_LAYER_GROUPS,
29094
+ WeatherEndpoint,
28952
29095
  applyChrtSymbolSet,
28953
29096
  applyColorTheme,
28954
29097
  applyCustomStyleSettings,