@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 +55 -0
- package/dist/index.cjs +143 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +442 -1
- package/dist/index.d.ts +442 -1
- package/dist/index.js +142 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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,
|