@chrtco/sdk 0.4.0 → 0.5.0

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 ADDED
@@ -0,0 +1,46 @@
1
+ # Changelog
2
+
3
+ All notable changes to `@chrtco/sdk` will be documented in this file.
4
+
5
+ ## [0.5.0] — 2026-04-23
6
+ - **CHRToffline** — download MBTiles bundles for offline rendering:
7
+ - `chrt.offline.list()`, `chrt.offline.download(region, opts)`, `chrt.offline.remove(region, opts)`, `chrt.offline.heartbeat(opts?)`, `chrt.offline.setStorageBudget(bytes, fs)`
8
+ - HTTP Range-based download resumption via `.partial` sidecar file
9
+ - SHA-256 verification before rename to final path
10
+ - `AbortSignal` support; interrupted downloads leave `.partial` on disk for resume
11
+ - Progress callback throttled to max(1 MB, 1%) boundaries; always fires at 0 and completion
12
+ - Optional local manifest (`ChrtConfig.manifestPath`) for budget enforcement and device-state tracking
13
+ - Typed errors via `OfflineError` with `code` discriminator (`budget_exceeded`, `download_corrupt`, `network_interrupted`, `coverage_denied`, `quota_exceeded`, `offline_not_enabled`, `sha_missing`, `missing_device_id`, `missing_manifest_path`, `region_not_available`, `invalid_api_key`, `unexpected_response`)
14
+ - **New config options**: `deviceId` (required for `offline.*`), `manifestPath` (optional)
15
+ - **New sub-export `@chrtco/sdk/node`**: `nodeFileSystemAdapter()` — Node 18+ implementation of `FileSystemAdapter` (core remains zero runtime deps)
16
+ - **Runtime target v1**: Node, Bun, Deno only. React Native and browser support deferred to a follow-up phase.
17
+ - **Internal**: SDK mints its own short-lived offline JWTs; customers never see them. Mint + offline traffic routes through `api.chrt.co/v1/mint/offline-token` and `api.chrt.co/v1/offline/*` (new `api-worker` proxy).
18
+
19
+ ## [0.4.0] — 2026-03-27 (republish)
20
+ - **Coverage endpoint** — `chrt.coverage.list()` returns chart sources by country with cell counts
21
+ - **Webhook event types** — discriminated-union types for `cell.updated`, `cell.new`, `cell.deleted` payloads; `parseWebhook()` runtime helper
22
+ - **Async auto-pagination** — `chrt.featuresIter()` and `chrt.cellsIter()` return `AsyncIterable` for `for-await-of` loops
23
+ - **AbortController support** — all request methods accept `signal?: AbortSignal` for cancellation
24
+
25
+ ## [0.3.2] — 2026-03-27
26
+ - Fixed CI publish pipeline (removed --provenance flag incompatible with private repos)
27
+
28
+ ## [0.3.1] — 2026-03-27
29
+ - Improved README with clearer quick-start examples and configuration options
30
+
31
+ ## [0.3.0] — 2026-03-26
32
+ - Reordered package exports for bundler compatibility (types first)
33
+ - Updated docs with Mapbox GL JS / MapLibre integration examples
34
+
35
+ ## [0.2.0] — 2026-02-01
36
+ - Added Feature API endpoint (`chrt.features()`) with bbox, layer filtering, pagination
37
+ - Added Spatial Query endpoint (`chrt.query()`) with point + radius search
38
+ - Added Cell Metadata endpoints (`chrt.cells.list()`, `chrt.cells.get()`)
39
+
40
+ ## [0.1.0] — 2026-01-15
41
+ - Initial release
42
+ - Chrt client with API key authentication
43
+ - Tiles endpoints: `styleUrl()`, `tileUrl()`, `groups()`
44
+ - `transformRequest()` helper for Mapbox GL / MapLibre
45
+ - `ChrtError` typed error class
46
+ - Configurable retries on 5xx responses
package/README.md CHANGED
@@ -121,6 +121,75 @@ try {
121
121
  }
122
122
  ```
123
123
 
124
+ ## Offline Downloads (CHRToffline)
125
+
126
+ Download MBTiles bundles for offline rendering. Bundles are SHA-256 verified before commit. Interrupted downloads resume from a `.partial` sidecar file.
127
+
128
+ **Runtime support in v1:** Node 18+, Bun, Deno. Browser and React Native are deferred to a follow-up.
129
+
130
+ ```typescript
131
+ import { Chrt } from '@chrtco/sdk';
132
+ import { nodeFileSystemAdapter } from '@chrtco/sdk/node';
133
+
134
+ const chrt = new Chrt({
135
+ apiKey: process.env.CHRT_API_KEY!,
136
+ // Required for offline.* — generate once at first launch, persist per
137
+ // install. Echoed into the offline JWT + heartbeat for device-level usage
138
+ // tracking.
139
+ deviceId: 'my-app-install-uuid',
140
+ // Optional — enables budget enforcement + `list()` of local state. If
141
+ // unset, budget is not enforced and `setStorageBudget()` throws.
142
+ manifestPath: './chrt-offline-manifest.json',
143
+ });
144
+
145
+ const fs = nodeFileSystemAdapter();
146
+
147
+ // Optional: cap total local storage across all regions.
148
+ await chrt.offline.setStorageBudget(10 * 1024 ** 3, fs); // 10 GB
149
+
150
+ // List what you're licensed to download.
151
+ const regions = await chrt.offline.list();
152
+
153
+ // Download a region. Resumes from a partial if one exists.
154
+ await chrt.offline.download('NOAA_ENC', {
155
+ path: './noaa.mbtiles',
156
+ fs,
157
+ onProgress: (p) => console.log(`${p.fraction * 100}%`),
158
+ });
159
+
160
+ // Remove a region (deletes the file + updates manifest + heartbeats).
161
+ await chrt.offline.remove('NOAA_ENC', { path: './noaa.mbtiles', fs });
162
+
163
+ // Manual heartbeat — call at app launch + every 24h while running.
164
+ await chrt.offline.heartbeat({ fs }); // derives regions + total from manifest
165
+ ```
166
+
167
+ ### Typed offline errors
168
+
169
+ ```typescript
170
+ import { OfflineError } from '@chrtco/sdk';
171
+
172
+ try {
173
+ await chrt.offline.download('NOAA_ENC', { path: './noaa.mbtiles', fs });
174
+ } catch (e) {
175
+ if (e instanceof OfflineError) {
176
+ switch (e.code) {
177
+ case 'budget_exceeded': console.log(e.detail); break;
178
+ case 'download_corrupt': console.log('SHA mismatch'); break;
179
+ case 'network_interrupted': console.log('resume later'); break;
180
+ case 'coverage_denied': console.log('region not licensed'); break;
181
+ case 'offline_not_enabled': console.log('enable use_offline on this API key'); break;
182
+ }
183
+ }
184
+ }
185
+ ```
186
+
187
+ ### Notes
188
+
189
+ - The SDK mints its own short-lived JWTs internally. You never see them.
190
+ - Heartbeats in v1 are manual — auto-scheduling comes in a later phase.
191
+ - A budget smaller than current usage will not auto-prune; it only refuses new downloads. Use `remove()` explicitly.
192
+
124
193
  ## License
125
194
 
126
195
  MIT
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Pluggable filesystem surface used by the offline endpoints.
3
+ *
4
+ * The core SDK is zero-dependency and can't import `node:*`. Callers bring
5
+ * their own adapter — `@chrtco/sdk/node` ships the Node 18+ implementation;
6
+ * future adapters (Bun/Deno-native, React Native, browser-OPFS) slot in the
7
+ * same shape without touching the endpoint code.
8
+ *
9
+ * Paths are plain strings. All methods are async. Streaming SHA-256 lives on
10
+ * the adapter so each runtime can use its native streaming digest primitive
11
+ * (Node: `crypto.createHash`; browser-OPFS: chunked `SubtleCrypto` etc.).
12
+ */
13
+ interface FileSystemAdapter {
14
+ exists(path: string): Promise<boolean>;
15
+ stat(path: string): Promise<{
16
+ size: number;
17
+ }>;
18
+ /** Returns a WritableStream for the given path. `append: true` opens in append mode; otherwise the file is truncated. */
19
+ writeStream(path: string, opts?: {
20
+ append?: boolean;
21
+ }): Promise<WritableStream<Uint8Array>>;
22
+ rename(from: string, to: string): Promise<void>;
23
+ unlink(path: string): Promise<void>;
24
+ mkdir(path: string, opts?: {
25
+ recursive?: boolean;
26
+ }): Promise<void>;
27
+ readFile(path: string): Promise<Uint8Array>;
28
+ writeFile(path: string, data: Uint8Array): Promise<void>;
29
+ /** Compute SHA-256 of the file at `path`. Lowercase hex. Must stream for large files. */
30
+ sha256(path: string): Promise<string>;
31
+ }
32
+
33
+ export type { FileSystemAdapter as F };
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Pluggable filesystem surface used by the offline endpoints.
3
+ *
4
+ * The core SDK is zero-dependency and can't import `node:*`. Callers bring
5
+ * their own adapter — `@chrtco/sdk/node` ships the Node 18+ implementation;
6
+ * future adapters (Bun/Deno-native, React Native, browser-OPFS) slot in the
7
+ * same shape without touching the endpoint code.
8
+ *
9
+ * Paths are plain strings. All methods are async. Streaming SHA-256 lives on
10
+ * the adapter so each runtime can use its native streaming digest primitive
11
+ * (Node: `crypto.createHash`; browser-OPFS: chunked `SubtleCrypto` etc.).
12
+ */
13
+ interface FileSystemAdapter {
14
+ exists(path: string): Promise<boolean>;
15
+ stat(path: string): Promise<{
16
+ size: number;
17
+ }>;
18
+ /** Returns a WritableStream for the given path. `append: true` opens in append mode; otherwise the file is truncated. */
19
+ writeStream(path: string, opts?: {
20
+ append?: boolean;
21
+ }): Promise<WritableStream<Uint8Array>>;
22
+ rename(from: string, to: string): Promise<void>;
23
+ unlink(path: string): Promise<void>;
24
+ mkdir(path: string, opts?: {
25
+ recursive?: boolean;
26
+ }): Promise<void>;
27
+ readFile(path: string): Promise<Uint8Array>;
28
+ writeFile(path: string, data: Uint8Array): Promise<void>;
29
+ /** Compute SHA-256 of the file at `path`. Lowercase hex. Must stream for large files. */
30
+ sha256(path: string): Promise<string>;
31
+ }
32
+
33
+ export type { FileSystemAdapter as F };