@chrtco/sdk 0.10.2 → 0.10.4
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 +20 -0
- package/README.md +80 -1
- package/dist/atlas/browser.cjs.map +1 -1
- package/dist/atlas/browser.js.map +1 -1
- package/dist/index.cjs +699 -411
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +484 -162
- package/dist/index.d.ts +484 -162
- package/dist/index.js +695 -411
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,26 @@ All notable changes to `@chrtco/sdk` will be documented in this file.
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
7
|
### Added
|
|
8
|
+
- **Render-mode lever on the Style API** (`sail#2`): `StyleUrlOptions.mode` /
|
|
9
|
+
`OfflineFetchStyleOptions.mode` — `"continuous"` (default) or
|
|
10
|
+
`"chart:{band}"` (`chart:Overview | chart:General | chart:Coastal |
|
|
11
|
+
chart:Approach | chart:Harbor`) — threads `?mode=` to the served style
|
|
12
|
+
routes (online `style.json` and offline `/v1/offline/styles/{region}`),
|
|
13
|
+
which lock the portrayal to one scale band with cascade fallback: the
|
|
14
|
+
served twin of the app's Map Mode toggle, now available to every API
|
|
15
|
+
consumer, online and offshore. New exports: `ChrtStyleMode`,
|
|
16
|
+
`CHRT_STYLE_MODES`, `normalizeStyleMode()`, `styleModeBand()`.
|
|
17
|
+
`OfflineStyleResponse.mode` echoes the resolved mode. Servers reject
|
|
18
|
+
invalid modes AND unknown style-route query params with typed 400s
|
|
19
|
+
(`invalid_mode` / `unknown_param`) instead of silently serving the
|
|
20
|
+
default document.
|
|
21
|
+
- **`OfflineFetchStyleOptions.symbols`** — the offline style route has
|
|
22
|
+
accepted `?symbols=s52|s101|chrt|raster` all along, but
|
|
23
|
+
`chrt.offline.fetchStyle()` had no way to send it, so native clients could
|
|
24
|
+
only ever fetch the default `s52` offline style. Now threaded through
|
|
25
|
+
(omitted → worker default `s52`), typed with the same `ChrtSymbolSet` as
|
|
26
|
+
the online `StyleUrlOptions.symbols`. `OfflineStyleResponse.symbols` types
|
|
27
|
+
the echoed set the worker already returns.
|
|
8
28
|
- **Served styles now render in MapLibre Native as shipped.** Every generated
|
|
9
29
|
style begins with a `chrt-background` layer (S-52 NODTA backdrop per
|
|
10
30
|
palette) — previously native renderers drew a black void and
|
package/README.md
CHANGED
|
@@ -243,7 +243,8 @@ curl -X POST https://api.chrt.co/v1/mint/tile-token \
|
|
|
243
243
|
curl https://tiles.chrt.co/v1/styles/NOAA_ENC/style.json?theme=day \
|
|
244
244
|
-H "Authorization: Bearer $TOKEN"
|
|
245
245
|
|
|
246
|
-
|
|
246
|
+
# --compressed matters: see "Tiles are gzipped" below.
|
|
247
|
+
curl --compressed https://tiles.chrt.co/v1/tiles/NOAA_ENC/12/1234/1543.mvt \
|
|
247
248
|
-H "Authorization: Bearer $TOKEN"
|
|
248
249
|
```
|
|
249
250
|
|
|
@@ -251,6 +252,29 @@ The returned document is a standard MapLibre style — hand it to MapLibre Nativ
|
|
|
251
252
|
`maplibre-gl`, or any renderer that speaks the style spec. Point your renderer's request transformer
|
|
252
253
|
at the same `Authorization: Bearer` header so tile requests carry it too.
|
|
253
254
|
|
|
255
|
+
### Tiles are gzipped — send `Accept-Encoding: gzip`
|
|
256
|
+
|
|
257
|
+
Tiles are stored gzip-compressed in the PMTiles archive, and the edge negotiates per request:
|
|
258
|
+
ask for `gzip` and you get gzip (`content-encoding: gzip` on the response); ask for `identity`,
|
|
259
|
+
or send no `Accept-Encoding` at all, and you get the uncompressed bytes.
|
|
260
|
+
|
|
261
|
+
**This changes tile-budget arithmetic by 2–2.5×.** MapLibre GL JS, MapLibre Native, every browser,
|
|
262
|
+
and this SDK all send `Accept-Encoding: gzip` automatically — the compressed figure is what your
|
|
263
|
+
users actually transfer. **Plain `curl` sends no `Accept-Encoding` at all**, so `curl -o tile.mvt`
|
|
264
|
+
measures the *uncompressed* size. Use `curl --compressed` (as above), or read `content-encoding`
|
|
265
|
+
off the response, before sizing a cache, a bundle, or a data plan.
|
|
266
|
+
|
|
267
|
+
Reference measurement, prod `NOAA_ENC`, 2026-07-27, tile `z11/620/757` (Boston):
|
|
268
|
+
|
|
269
|
+
| `Accept-Encoding` | Bytes on the wire |
|
|
270
|
+
|---|---|
|
|
271
|
+
| *(absent)* / `identity` | 1,152,506 B (1.10 MB) |
|
|
272
|
+
| `gzip` | 462,273 B (451 KB) |
|
|
273
|
+
|
|
274
|
+
Tile size tracks **feature density** far more than zoom — a harbor tile over a dense port dwarfs an
|
|
275
|
+
offshore tile at the same zoom, and a tile with no data returns `204` with no body at all. Sample a
|
|
276
|
+
spread of tiles across your own area of operations rather than extrapolating from one.
|
|
277
|
+
|
|
254
278
|
The REST endpoints in the table below (`/v1/features`, `/v1/query`, `/v1/query/ahead`, `/v1/cells`,
|
|
255
279
|
`/v1/coverage`) take the API key directly as `x-api-key` — no token minting needed.
|
|
256
280
|
|
|
@@ -342,6 +366,9 @@ call any language can make. Everything marked **JS-only** runs in-process and ha
|
|
|
342
366
|
| `chrt.cells.get(id)` | `GET /v1/cells/{id}` | |
|
|
343
367
|
| `chrt.coverage.list(opts?)` | `GET /v1/coverage` | |
|
|
344
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` |
|
|
345
372
|
| `chrt.warmTiles(region?)` | `POST /v1/mint/tile-token` | |
|
|
346
373
|
| `chrt.styleUrl(opts?)` | `GET {tileBaseUrl}/v1/styles/{region}/style.json` | mints first |
|
|
347
374
|
| `chrt.fetchStyle(opts?)` | same, then fetches it | |
|
|
@@ -594,3 +621,55 @@ try {
|
|
|
594
621
|
## License
|
|
595
622
|
|
|
596
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.
|