@chrtco/sdk 0.10.38 → 0.10.40

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 CHANGED
@@ -4,6 +4,140 @@ All notable changes to `@chrtco/sdk` will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ### Added
8
+ - `MarineZoneRef.bbox` on `weather.marineForecast()` — `[west, south, east, north]` of the
9
+ forecast's zone, from the same build as the `NWS_MARINE_ZONES` tile source. A camera hint: fit
10
+ the map to it; draw the zone from the tiles, never the box. `west > east` crosses 180°.
11
+ - **`RELIEF_ENCODING` / `RELIEF_TILE_SIZE`** — `CHRT_RELIEF`'s raster-dem
12
+ `encoding` (`"terrarium"`) and tile size (512), the values `buildSources()`
13
+ emits for the relief source. Exported for consumers that describe that
14
+ source themselves, such as the tile-worker's TileJSON.
15
+
16
+ ## [0.10.40]
17
+
18
+ The first publish since 0.10.39 (2026-09-11, from `ada7e73e`). The publish
19
+ workflow's typecheck failed on every merge to `main` from 2026-09-11 to
20
+ 2026-09-26 — the SDK's decode parity suite compiles the app's reference
21
+ decoder, which had begun importing `@chrtco/sdk` by name, and inside the
22
+ package that name resolved to a `dist/` not yet built — so everything below
23
+ reached `main` without reaching npm. No function signature is removed or
24
+ narrowed; the **Changed** entries are behaviour and type-shape changes to read
25
+ before upgrading.
26
+
27
+ ### Added
28
+ - **`weather.conditions({ hours })` — a station's recent history.** Adds
29
+ `series` to `MarineConditionsResponse`: the chosen station's readings over
30
+ the last `hours` hours (1–1080), oldest first, each in the top-level shape
31
+ (`MarineConditionsObservation`). Never interpolated or gap-filled;
32
+ `series.cadenceMinutes` gives the station's normal spacing. Without `hours`
33
+ the response is unchanged. New types: `MarineConditionsSeries`,
34
+ `MarineConditionsObservation`.
35
+ - **`StyleUrlOptions.units`** — `"metric"` (default) or `"imperial"`, sent by
36
+ `styleUrl()` / `fetchStyle()` as `?units=imperial` to
37
+ `GET /v1/styles/{region}/style.json`. The served style then prints
38
+ soundings, depth-contour labels, dredged-channel notes and bridge notes in
39
+ feet. Send the reader's setting here rather than converting soundings
40
+ client-side: a bridge note is composed text a client cannot rewrite, and
41
+ soundings in feet beside a clearance in metres is the disagreement this
42
+ prevents. Metric spells nothing, so existing style URLs and their cache
43
+ keys are unchanged; any other value is a typed 400 `invalid_units`.
44
+ - **`SIGSEQ` light rhythms.** `parseSigseqTerms(sigseq, sigper)` reads a
45
+ light's charted on/off sequence (`"00.4+(03.6)"` — 0.4 s lit, 3.6 s dark),
46
+ checked against `SIGPER`, and returns the phases or a typed refusal
47
+ (`SigseqRefusal`: `"malformed" | "nonPositiveDuration" | "sigperMismatch"`,
48
+ or `"absent"` when the light charts no sequence) — never an invented rhythm. `rhythmProperties()`, `lampRhythmOpacity()` and
49
+ `lampRhythmColour()` turn a parsed rhythm into feature properties and paint
50
+ expressions so a map can flash every light on the GPU from one paint update
51
+ per tick. Also `SIGSEQ_MAX_TERMS`, `SIGPER_TOLERANCE_SECONDS`,
52
+ `LAMP_TICK_MS`, `ParsedSigseqTerms`, `SigseqTerm`. The first-party app now
53
+ reads SIGSEQ through this parser: one grammar.
54
+ - **Night lamps.** `buildLampLayers(sourceId, ct)` returns two circle layers
55
+ on `LIGHTS` (`LAMP_GLOW_LAYER_ID` / `LAMP_CORE_LAYER_ID`, `LAMP_LAYER_IDS`)
56
+ that draw lighted aids as points of light: coloured by the same LIGHTS05
57
+ reading as the flare, sized by nominal range (`VALNMR`), viewport-aligned so
58
+ they neither grow nor lie flat under pitch. They carry only lights that are
59
+ steady from every bearing (no `SECTR1`, no `SIGSEQ`). Every generated style
60
+ now includes them **hidden** (`visibility: "none"`); show them with
61
+ `setLayoutProperty`.
62
+ - **The app-embeddable CHRT_BASE bundle.** `applyBaseBundle(style, { tiles })`
63
+ points a style's `CHRT_BASE` source at a local copy of the z0–6 world
64
+ basemap bundle and drops every base layer the bundle cannot feed. With
65
+ `BASE_BUNDLE_ID`, `BASE_BUNDLE_SCHEMA` (`chrt.basemap-bundle/1`),
66
+ `BASE_BUNDLE_MAXZOOM` (6), `BASE_BUNDLE_SOURCE_LAYERS`,
67
+ `BASE_BUNDLE_ATTRIBUTION` (`"© CHRT · Made with Natural Earth"`) and
68
+ `BASE_CLIENT_RASTER_BEFORE_ID`. The online `CHRT_BASE` source now declares
69
+ its credit (`BASE_ATTRIBUTION`, which also names OpenStreetMap for the
70
+ z9–11 inland-water tier) through the new optional
71
+ `PmtilesVectorSource.attribution`.
72
+ - **Terrain ordering helpers** — `drapedFirst()`, `drapeHalves()`,
73
+ `isDrapeable()`, `terrainStackCount()`, `DRAPEABLE_LAYER_TYPES`. See
74
+ *Generated styles are ordered draped-first* below.
75
+ - **Band aliases** — `BAND_CODE_ALIASES`, `cellBandCharacters()`,
76
+ `cellBandMatch()`. See the USACE fix below.
77
+
78
+ ### Changed
79
+ - **Generated styles are ordered draped-first.** The generator's last pass is
80
+ now a stable partition: every background, fill, line, raster and hillshade
81
+ layer in its existing order, then every symbol and circle layer in theirs.
82
+ With MapLibre terrain on, the interleaved order cut a z12+ chart into ~130
83
+ render stacks, each re-rendered every frame (24.6 fps → 52.6 fps measured at
84
+ pitch 45, MapLibre 5.24); draped-first is one stack. It applies to the flat
85
+ chart too — it is the S-52 display order (areas, lines, then point symbols
86
+ and text) — and the only pixels that move are where a symbol used to sit
87
+ under a later line or fill (0.1–2.8 % of pixels across six measured views).
88
+ If you insert your own layers into a generated style by `beforeId`, re-check
89
+ where they land.
90
+ - **Land mode: `LAKARE` relocates with the water family under CHRTland.**
91
+ Within a band the order is water → land → lake; across bands the finer
92
+ band's land paints after the coarser band's lake. A coarse band's
93
+ generalised lake no longer bleeds over CHRTland (Tisbury Great Pond at
94
+ z13.5).
95
+ - **The charted water/land repaint now sits beneath the CHRT_BASE
96
+ inland-water pair**, not above it. Its band-4/5/6 `LNDARE` clones have no
97
+ holes for ponds the chart does not chart, so above the pair they painted
98
+ every uncharted lake inside fine-band coverage as land.
99
+ - **`buildSectorArcsFC()` no longer draws the derived all-round arcs.**
100
+ `buildSectorsFromFeatures()` still emits them (`allRound: true`) — they are
101
+ what a reader in the uncovered arc sees, and a bearing lookup needs them —
102
+ but S-52 LIGHTS05 gives an all-round light its flare and no arc. This
103
+ reverses the drawing half of the 0.10.x entry *All-round lights co-located
104
+ with sector lights were not drawn*, below.
105
+ - **Sector arcs are coloured per S-52 LIGHTS05.** `SectorInfo` gains
106
+ `colourCodes` (every charted `COLOUR`, in order — an alternating sector has
107
+ two), `arcColourToken` / `arcColourHex` (`LITRD` / `LITGN` / `LITYW` — white,
108
+ yellow and orange all draw yellow — `CHMGD` where the colours do not
109
+ resolve, `CHBRN` when obscured), `obscured` (`LITVIS` 3, 7 or 8), and
110
+ `sigseq` / `sigper`. `buildSectorsFromFeatures(features, ct = "DAY")` takes
111
+ the palette `arcColourHex` is resolved in, and each arc feature from
112
+ `buildSectorArcsFC()` carries `arcColourHex`, `arcColourToken` and
113
+ `obscured`. **These fields are required**: code that builds `SectorInfo`
114
+ literals by hand must now supply them.
115
+ - **`buildFlashPattern()` uses the chart's own timing first.**
116
+ `DecodedNavAid` gains `sigseq`. When a light carries a valid `SIGSEQ` the
117
+ pattern is its charted phases and `FlashPattern.timing` is `"charted"`;
118
+ otherwise it is the previous animation of the character code, marked
119
+ `"invented"`. (Before, every pattern was invented — 400 ms flashes and
120
+ 300 ms gaps — though 74 % of charted lights carry their real sequence.)
121
+ `DecodedNavAid.sigseq` and `FlashPattern.timing` are required fields.
122
+
123
+ ### Fixed
124
+ - **USACE Inland ENC features were filtered out by every band-5 gate.** USACE
125
+ cell ids are `U37…`: the third character is `7` on every cell and means
126
+ nothing. The pipeline builds the product as band 5, but the style's band-5
127
+ gates read that character and never matched `7`, so the offline
128
+ `USACE_IENC` bundle rendered blank. `BAND_CODE_ALIASES = { "5": ["7"] }` is
129
+ folded into `bandFilterExpression()` and the orientation-label fan
130
+ (`cellBandMatch()`); a gate admits `7` exactly when it admits `5`. This is
131
+ not a seventh band — draw order and priorities are unchanged.
132
+
133
+ ## [0.10.0 – 0.10.39] — 2026-07-15 to 2026-09-11
134
+
135
+ Published by the publish workflow's auto-bump while `package.json` stayed at
136
+ 0.10.0, so no per-version sections were cut. The entries below are the
137
+ `[Unreleased]` section as it stood at `ada7e73e`, the commit 0.10.39 was
138
+ published from. For what a single version contains, run
139
+ `npm view @chrtco/sdk@<version> gitHead`.
140
+
7
141
  ### Fixed
8
142
  - **Sector-light arcs were drawn on the wrong side of the light.**
9
143
  `buildSectorArcGeoJSON()` / `buildSectorArcsFC()` painted each sector at the