@mostlyrightmd/core 0.1.0-rc.7
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/LICENSE +21 -0
- package/README.md +3 -0
- package/dist/discovery/index.cjs +1646 -0
- package/dist/discovery/index.cjs.map +1 -0
- package/dist/discovery/index.d.cts +313 -0
- package/dist/discovery/index.d.ts +313 -0
- package/dist/discovery/index.mjs +1609 -0
- package/dist/discovery/index.mjs.map +1 -0
- package/dist/formats/index.cjs +498 -0
- package/dist/formats/index.cjs.map +1 -0
- package/dist/formats/index.d.cts +97 -0
- package/dist/formats/index.d.ts +97 -0
- package/dist/formats/index.mjs +465 -0
- package/dist/formats/index.mjs.map +1 -0
- package/dist/index.cjs +1624 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +559 -0
- package/dist/index.d.ts +559 -0
- package/dist/index.global.js +1582 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.mjs +1557 -0
- package/dist/index.mjs.map +1 -0
- package/dist/internal/bounds.cjs +125 -0
- package/dist/internal/bounds.cjs.map +1 -0
- package/dist/internal/bounds.d.cts +36 -0
- package/dist/internal/bounds.d.ts +36 -0
- package/dist/internal/bounds.mjs +81 -0
- package/dist/internal/bounds.mjs.map +1 -0
- package/dist/internal/cache/fs.cjs +217 -0
- package/dist/internal/cache/fs.cjs.map +1 -0
- package/dist/internal/cache/fs.d.cts +57 -0
- package/dist/internal/cache/fs.d.ts +57 -0
- package/dist/internal/cache/fs.mjs +179 -0
- package/dist/internal/cache/fs.mjs.map +1 -0
- package/dist/internal/cache/index.browser.cjs +1184 -0
- package/dist/internal/cache/index.browser.cjs.map +1 -0
- package/dist/internal/cache/index.browser.d.cts +20 -0
- package/dist/internal/cache/index.browser.d.ts +20 -0
- package/dist/internal/cache/index.browser.mjs +36 -0
- package/dist/internal/cache/index.browser.mjs.map +1 -0
- package/dist/internal/cache/index.cjs +1389 -0
- package/dist/internal/cache/index.cjs.map +1 -0
- package/dist/internal/cache/index.d.cts +16 -0
- package/dist/internal/cache/index.d.ts +16 -0
- package/dist/internal/cache/index.mjs +40 -0
- package/dist/internal/cache/index.mjs.map +1 -0
- package/dist/internal/chunk-PKJXHY27.mjs +1137 -0
- package/dist/internal/chunk-PKJXHY27.mjs.map +1 -0
- package/dist/internal/convert.cjs +161 -0
- package/dist/internal/convert.cjs.map +1 -0
- package/dist/internal/convert.d.cts +44 -0
- package/dist/internal/convert.d.ts +44 -0
- package/dist/internal/convert.mjs +117 -0
- package/dist/internal/convert.mjs.map +1 -0
- package/dist/internal/fs-O6XR4WWW.mjs +183 -0
- package/dist/internal/fs-O6XR4WWW.mjs.map +1 -0
- package/dist/internal/keys-B7C8C88N.d.cts +191 -0
- package/dist/internal/keys-B7C8C88N.d.ts +191 -0
- package/dist/internal/merge/index.cjs +75 -0
- package/dist/internal/merge/index.cjs.map +1 -0
- package/dist/internal/merge/index.d.cts +74 -0
- package/dist/internal/merge/index.d.ts +74 -0
- package/dist/internal/merge/index.mjs +46 -0
- package/dist/internal/merge/index.mjs.map +1 -0
- package/dist/internal/pairs.cjs +328 -0
- package/dist/internal/pairs.cjs.map +1 -0
- package/dist/internal/pairs.d.cts +105 -0
- package/dist/internal/pairs.d.ts +105 -0
- package/dist/internal/pairs.mjs +298 -0
- package/dist/internal/pairs.mjs.map +1 -0
- package/dist/qc/index.cjs +247 -0
- package/dist/qc/index.cjs.map +1 -0
- package/dist/qc/index.d.cts +140 -0
- package/dist/qc/index.d.ts +140 -0
- package/dist/qc/index.mjs +212 -0
- package/dist/qc/index.mjs.map +1 -0
- package/dist/temporal/index.cjs +504 -0
- package/dist/temporal/index.cjs.map +1 -0
- package/dist/temporal/index.d.cts +121 -0
- package/dist/temporal/index.d.ts +121 -0
- package/dist/temporal/index.mjs +474 -0
- package/dist/temporal/index.mjs.map +1 -0
- package/dist/transforms/index.cjs +399 -0
- package/dist/transforms/index.cjs.map +1 -0
- package/dist/transforms/index.d.cts +193 -0
- package/dist/transforms/index.d.ts +193 -0
- package/dist/transforms/index.mjs +362 -0
- package/dist/transforms/index.mjs.map +1 -0
- package/dist/validator.cjs +1870 -0
- package/dist/validator.cjs.map +1 -0
- package/dist/validator.d.cts +30 -0
- package/dist/validator.d.ts +30 -0
- package/dist/validator.mjs +1843 -0
- package/dist/validator.mjs.map +1 -0
- package/package.json +115 -0
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/** Optional setters for cache writes. */
|
|
2
|
+
interface CacheSetOptions {
|
|
3
|
+
/** Time-to-live in milliseconds. Implementations may honor or ignore. */
|
|
4
|
+
readonly ttlMs?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Pluggable key/value cache contract used throughout the SDK.
|
|
8
|
+
*
|
|
9
|
+
* All methods are async — concrete implementations may resolve immediately
|
|
10
|
+
* (MemoryStore) or do I/O (FsStore / IndexedDBStore).
|
|
11
|
+
*
|
|
12
|
+
* Semantic contract:
|
|
13
|
+
* - `get<T>(key)` returns the stored value or `null` on miss. NEVER throws
|
|
14
|
+
* on miss.
|
|
15
|
+
* - `set<T>(key, value, opts?)` overwrites. ttlMs is implementation-honored
|
|
16
|
+
* (MemoryStore + IndexedDBStore honor it; FsStore ignores in v0.1).
|
|
17
|
+
* - `delete(key)` is a no-op on miss; returns void.
|
|
18
|
+
* - `withLock<T>(key, fn)` runs `fn` under a key-scoped exclusive lock and
|
|
19
|
+
* releases on settle (resolve OR throw). Nested calls to the same key
|
|
20
|
+
* serialize; calls to different keys MAY run in parallel.
|
|
21
|
+
*/
|
|
22
|
+
interface CacheStore {
|
|
23
|
+
get<T = unknown>(key: string): Promise<T | null>;
|
|
24
|
+
set<T = unknown>(key: string, value: T, opts?: CacheSetOptions): Promise<void>;
|
|
25
|
+
delete(key: string): Promise<void>;
|
|
26
|
+
withLock<T>(key: string, fn: () => Promise<T>): Promise<T>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Cache-coverage summary for a station.
|
|
31
|
+
*
|
|
32
|
+
* Mirrors Python `availability()` return shape.
|
|
33
|
+
*/
|
|
34
|
+
interface AvailabilityResult {
|
|
35
|
+
station: string;
|
|
36
|
+
/** Count of distinct (year, month) observation cache entries. */
|
|
37
|
+
monthsCached: number;
|
|
38
|
+
/** Earliest cached month as `"YYYY-MM"`, or null if none. */
|
|
39
|
+
firstMonth: string | null;
|
|
40
|
+
/** Latest cached month as `"YYYY-MM"`, or null if none. */
|
|
41
|
+
lastMonth: string | null;
|
|
42
|
+
/** Count of cached climate years. */
|
|
43
|
+
climateYears: number;
|
|
44
|
+
/** Earliest cached climate year as `"YYYY"`, or null if none. */
|
|
45
|
+
firstClimateYear: string | null;
|
|
46
|
+
/** Latest cached climate year as `"YYYY"`, or null if none. */
|
|
47
|
+
lastClimateYear: string | null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Optional adapter that lets `availability()` enumerate keys from a store.
|
|
51
|
+
*
|
|
52
|
+
* CacheStore's mandatory contract is opaque key-value: get/set/delete/withLock.
|
|
53
|
+
* Discovery needs to enumerate which keys exist for a station — this is
|
|
54
|
+
* implementation-specific (Memory iterates its Map, IndexedDB uses
|
|
55
|
+
* `getAllKeys`, Fs walks the directory tree). Stores that support enumeration
|
|
56
|
+
* implement the optional `listKeys(prefix)` method and `availability()` uses
|
|
57
|
+
* it; stores without it return zero-coverage but never throw.
|
|
58
|
+
*
|
|
59
|
+
* Listed keys may exceed the requested prefix in the result (callers filter);
|
|
60
|
+
* `listKeys` is best-effort.
|
|
61
|
+
*/
|
|
62
|
+
interface KeyEnumerableStore extends CacheStore {
|
|
63
|
+
listKeys(prefix: string): Promise<ReadonlyArray<string>>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Options for `availability()`.
|
|
67
|
+
*/
|
|
68
|
+
interface AvailabilityOptions {
|
|
69
|
+
/**
|
|
70
|
+
* If true, confirm each candidate key with `cache.get()` before counting.
|
|
71
|
+
* Eliminates the small overcount possible on stores whose `listKeys()` can
|
|
72
|
+
* return keys with already-expired TTL entries (FsStore and IndexedDBStore
|
|
73
|
+
* lazy-evict on `get`, not on `listKeys` — codex iter-3 P2). Off by default
|
|
74
|
+
* because the v0.1.0 `research()` flow never writes with `ttlMs`, so the
|
|
75
|
+
* overcount window is empty; turn on only if you populate the cache with
|
|
76
|
+
* explicit TTLs.
|
|
77
|
+
*
|
|
78
|
+
* Cost: one `get()` per matching key. On warm caches this is cheap
|
|
79
|
+
* (MemoryStore + IndexedDBStore in-memory). On FsStore it reads each
|
|
80
|
+
* candidate's file.
|
|
81
|
+
*/
|
|
82
|
+
readonly validate?: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Return a summary of cached coverage for `station`.
|
|
86
|
+
*
|
|
87
|
+
* Stores without enumeration support return a zero-coverage result with the
|
|
88
|
+
* station name populated (counts all zero, dates null).
|
|
89
|
+
*
|
|
90
|
+
* Pass `{ validate: true }` to confirm each candidate key via `cache.get()`
|
|
91
|
+
* — needed if your callers populate the cache with `ttlMs` and might query
|
|
92
|
+
* after expiry. The v0.1.0 `research()` flow does not use `ttlMs`, so the
|
|
93
|
+
* default (fast scan, no validation) is correct for the canonical path.
|
|
94
|
+
*/
|
|
95
|
+
declare function availability(station: string, cache: CacheStore, opts?: AvailabilityOptions): Promise<AvailabilityResult>;
|
|
96
|
+
|
|
97
|
+
/** Minimal row shape consumed by `internationalDailyExtremes`. */
|
|
98
|
+
interface InternationalRow {
|
|
99
|
+
/** ISO 8601 UTC instant. Must end with `Z` or include an offset. */
|
|
100
|
+
observed_at?: string | null;
|
|
101
|
+
/** Air temperature in degrees Celsius. */
|
|
102
|
+
temp_c?: number | null;
|
|
103
|
+
/** 1-hour precipitation total in millimeters. */
|
|
104
|
+
precip_mm_1h?: number | null;
|
|
105
|
+
/** Source identifier (preserved on the tmin/tmax aggregate). */
|
|
106
|
+
source?: string | null;
|
|
107
|
+
}
|
|
108
|
+
interface DailyExtreme {
|
|
109
|
+
/** Station-local calendar date as `YYYY-MM-DD`. */
|
|
110
|
+
localDate: string;
|
|
111
|
+
/** Count of rows with a parseable temp_c. */
|
|
112
|
+
nObs: number;
|
|
113
|
+
/** Min temperature in °C, or null on low coverage. */
|
|
114
|
+
tempMinC: number | null;
|
|
115
|
+
/** Max temperature in °C, or null on low coverage. */
|
|
116
|
+
tempMaxC: number | null;
|
|
117
|
+
/** Mean temperature in °C, or null on low coverage. */
|
|
118
|
+
tempMeanC: number | null;
|
|
119
|
+
/** Min temperature in °F, or null on low coverage. */
|
|
120
|
+
tempMinF: number | null;
|
|
121
|
+
/** Max temperature in °F, or null on low coverage. */
|
|
122
|
+
tempMaxF: number | null;
|
|
123
|
+
/** Total 1-hour precipitation across the local day, in mm. */
|
|
124
|
+
precipMm: number;
|
|
125
|
+
/** Source identifier of the row that produced tmin (or null on low coverage). */
|
|
126
|
+
sourceTmin: string | null;
|
|
127
|
+
/** Source identifier of the row that produced tmax (or null on low coverage). */
|
|
128
|
+
sourceTmax: string | null;
|
|
129
|
+
}
|
|
130
|
+
interface InternationalDailyExtremesOptions {
|
|
131
|
+
/** IANA timezone identifier for the station, e.g. `"Asia/Tokyo"`. Required. */
|
|
132
|
+
stationTz: string;
|
|
133
|
+
/**
|
|
134
|
+
* Decimal places for HALF_UP rounding. Defaults to 0 (whole °C) — the
|
|
135
|
+
* international convention. Pass `1` for US-station tenths.
|
|
136
|
+
*/
|
|
137
|
+
precision?: number;
|
|
138
|
+
/**
|
|
139
|
+
* Minimum number of observations required for tmin/tmax/tmean to be
|
|
140
|
+
* populated. Defaults to 12 (the Python threshold). Tests can override.
|
|
141
|
+
*/
|
|
142
|
+
minObs?: number;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Roll up observation rows to per-local-calendar-day temperature extremes.
|
|
146
|
+
*
|
|
147
|
+
* @param rows raw observation rows (any source). Rows without a parseable
|
|
148
|
+
* `observed_at` are dropped.
|
|
149
|
+
* @param opts `stationTz` is required. Optional `precision` (default 0;
|
|
150
|
+
* pass 1 for US-station tenths) and `minObs` (default 12).
|
|
151
|
+
*
|
|
152
|
+
* @returns one entry per local calendar day with at least one row. Days
|
|
153
|
+
* with fewer than `minObs` rows have temps set to null.
|
|
154
|
+
*/
|
|
155
|
+
declare function internationalDailyExtremes(rows: ReadonlyArray<InternationalRow>, opts: InternationalDailyExtremesOptions): DailyExtreme[];
|
|
156
|
+
|
|
157
|
+
/** Immutable reproducibility token stamping a single research() call. */
|
|
158
|
+
interface DataVersion {
|
|
159
|
+
readonly sdkVersion: string;
|
|
160
|
+
readonly schemaIds: ReadonlyArray<string>;
|
|
161
|
+
readonly sources: ReadonlyArray<string>;
|
|
162
|
+
readonly codeSha: string;
|
|
163
|
+
readonly dataSha: string;
|
|
164
|
+
readonly token: string;
|
|
165
|
+
}
|
|
166
|
+
interface DataVersionComponents {
|
|
167
|
+
sdkVersion: string;
|
|
168
|
+
schemaIds: ReadonlyArray<string>;
|
|
169
|
+
sources: ReadonlyArray<string>;
|
|
170
|
+
codeSha: string;
|
|
171
|
+
dataSha: string;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Build a frozen DataVersion from explicit components.
|
|
175
|
+
*
|
|
176
|
+
* Mirrors Python `DataVersion.from_components`: sorts schemaIds + sources
|
|
177
|
+
* INTERNALLY before the canonical hash so input order does not affect the
|
|
178
|
+
* token, but preserves the caller's order on the returned object's
|
|
179
|
+
* `schemaIds` and `sources` arrays. Codex iter-5 P2: prior version sorted
|
|
180
|
+
* the stored arrays alphabetically too, which masked source-priority order
|
|
181
|
+
* (e.g. `awc.live, ghcnh, iem.archive, ...` instead of the canonical
|
|
182
|
+
* `iem.archive, iem.live, awc.live, ghcnh, nws.cli` precedence Python
|
|
183
|
+
* preserves on the tuple).
|
|
184
|
+
*/
|
|
185
|
+
declare function dataVersionFromComponents(components: DataVersionComponents): Promise<DataVersion>;
|
|
186
|
+
/**
|
|
187
|
+
* Build a DataVersion for a research() call. Mirrors Python `DataVersion.for_research`:
|
|
188
|
+
* the codeSha encodes the call signature (`research:STATION:FROM:TO`) and dataSha
|
|
189
|
+
* is supplied by the caller (typically a cache fingerprint).
|
|
190
|
+
*
|
|
191
|
+
* The schema ids + source contract match the v0.1.0 Python SDK exactly so tokens
|
|
192
|
+
* computed in TS match tokens computed in Python for the same inputs.
|
|
193
|
+
*/
|
|
194
|
+
declare function dataVersionForResearch(args: {
|
|
195
|
+
sdkVersion: string;
|
|
196
|
+
station: string;
|
|
197
|
+
fromDate: string;
|
|
198
|
+
toDate: string;
|
|
199
|
+
dataSha: string;
|
|
200
|
+
}): Promise<DataVersion>;
|
|
201
|
+
|
|
202
|
+
/** Frozen snapshot wrapper around row data + provenance. */
|
|
203
|
+
interface DataSnapshot {
|
|
204
|
+
/** ISO 8601 UTC instant when the snapshot was built (always ends with Z). */
|
|
205
|
+
readonly knowledgeTime: string;
|
|
206
|
+
/** Schema id the rows conform to. */
|
|
207
|
+
readonly schemaId: string;
|
|
208
|
+
/** Source identifier (e.g. `iem.archive`, `awc.live`). Snapshot-scoped. */
|
|
209
|
+
readonly source: string;
|
|
210
|
+
/** Row payload — opaque to this layer. Frozen. */
|
|
211
|
+
readonly rows: ReadonlyArray<Readonly<Record<string, unknown>>>;
|
|
212
|
+
/** Optional reproducibility token. */
|
|
213
|
+
readonly dataVersion: DataVersion | null;
|
|
214
|
+
/** Optional arbitrary metadata. JSON-safe-coerced on `toDict`. */
|
|
215
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
216
|
+
/** JSON-safe dict form. */
|
|
217
|
+
toDict(): Record<string, unknown>;
|
|
218
|
+
/** TOON-v3 tabular form (rows only — provenance lives in the dict form). */
|
|
219
|
+
toToon(): string;
|
|
220
|
+
}
|
|
221
|
+
interface BuildSnapshotOptions {
|
|
222
|
+
schemaId: string;
|
|
223
|
+
source: string;
|
|
224
|
+
rows: ReadonlyArray<Record<string, unknown>>;
|
|
225
|
+
knowledgeTime?: Date | string;
|
|
226
|
+
dataVersion?: DataVersion | null;
|
|
227
|
+
metadata?: Record<string, unknown>;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Build a frozen DataSnapshot.
|
|
231
|
+
*
|
|
232
|
+
* Throws RangeError on invalid `knowledgeTime`. Row payloads are shallow-
|
|
233
|
+
* cloned and frozen so callers can't mutate snapshot state post-build.
|
|
234
|
+
*/
|
|
235
|
+
declare function buildSnapshot(opts: BuildSnapshotOptions): DataSnapshot;
|
|
236
|
+
|
|
237
|
+
interface TradewindsErrorOptions {
|
|
238
|
+
errorCode?: string;
|
|
239
|
+
source?: string | null;
|
|
240
|
+
requestId?: string | null;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Base class for all mostlyright structured errors.
|
|
244
|
+
*
|
|
245
|
+
* `errorCode` is a stable enum (e.g. "SOURCE_UNAVAILABLE") used by callers /
|
|
246
|
+
* agents to branch on without parsing message text. `source` is the source id
|
|
247
|
+
* involved (e.g. "iem.archive") when applicable, and `requestId` correlates a
|
|
248
|
+
* JSON-RPC / MCP request id when applicable.
|
|
249
|
+
*/
|
|
250
|
+
declare class TradewindsError extends Error {
|
|
251
|
+
/** Subclass override — the stable string enum surfaced via `errorCode`. */
|
|
252
|
+
static defaultErrorCode: string;
|
|
253
|
+
readonly errorCode: string;
|
|
254
|
+
readonly source: string | null;
|
|
255
|
+
readonly requestId: string | null;
|
|
256
|
+
constructor(message?: string, options?: TradewindsErrorOptions);
|
|
257
|
+
/**
|
|
258
|
+
* Subclass hook returning the structured attributes for `toDict`.
|
|
259
|
+
* Values are passed through `toJsonSafe` by `toDict()`, so subclasses
|
|
260
|
+
* don't need to coerce values themselves.
|
|
261
|
+
*/
|
|
262
|
+
protected payload(): Record<string, unknown>;
|
|
263
|
+
/** Return a JSON-safe dict suitable for MCP `error.data`. */
|
|
264
|
+
toDict(): Record<string, unknown>;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
interface SchemaInfo {
|
|
268
|
+
readonly id: string;
|
|
269
|
+
readonly title: string;
|
|
270
|
+
readonly columnCount: number;
|
|
271
|
+
readonly columns: ReadonlyArray<{
|
|
272
|
+
readonly name: string;
|
|
273
|
+
readonly description: string;
|
|
274
|
+
readonly nullable: boolean;
|
|
275
|
+
}>;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Register or override a schema for `describe()`. Built-in v0.1.0 schemas
|
|
279
|
+
* are registered at module load (BUILT_IN_SCHEMAS); callers may add custom
|
|
280
|
+
* schemas or override built-ins (e.g. with richer descriptions).
|
|
281
|
+
*/
|
|
282
|
+
declare function registerSchema(info: SchemaInfo): void;
|
|
283
|
+
/**
|
|
284
|
+
* Return a multi-line description of a registered schema.
|
|
285
|
+
*
|
|
286
|
+
* @throws TradewindsError if `schemaId` is not registered. The error code is
|
|
287
|
+
* `UNKNOWN_SCHEMA` so callers can distinguish from validation/IO errors.
|
|
288
|
+
*/
|
|
289
|
+
declare function describe(schemaId: string): string;
|
|
290
|
+
/** Thrown by `describe` when `schemaId` is not registered. */
|
|
291
|
+
declare class UnknownSchemaError extends TradewindsError {
|
|
292
|
+
constructor(message: string);
|
|
293
|
+
static readonly defaultErrorCode = "UNKNOWN_SCHEMA";
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Return the transforms surface as a stable-sorted list.
|
|
297
|
+
*
|
|
298
|
+
* Matches Python `feature_catalog()`'s ordering — alphabetical on the
|
|
299
|
+
* snake_case names, here the camelCase TS names sorted identically.
|
|
300
|
+
*/
|
|
301
|
+
declare function featureCatalog(): ReadonlyArray<string>;
|
|
302
|
+
/**
|
|
303
|
+
* Climate-gap scanning is Python-only in v0.1.0 (TS has no climate-year
|
|
304
|
+
* parquet cache yet). Throws to match the documented contract.
|
|
305
|
+
*/
|
|
306
|
+
declare function climateGaps(_station: string, _fromDate: string, _toDate: string): never;
|
|
307
|
+
/** Thrown by `climateGaps` until the TS climate cache lands. */
|
|
308
|
+
declare class ClimateGapsNotImplementedError extends TradewindsError {
|
|
309
|
+
constructor(message: string);
|
|
310
|
+
static readonly defaultErrorCode = "NOT_IMPLEMENTED";
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export { type AvailabilityOptions, type AvailabilityResult, type BuildSnapshotOptions, ClimateGapsNotImplementedError, type DailyExtreme, type DataSnapshot, type DataVersion, type DataVersionComponents, type InternationalDailyExtremesOptions, type InternationalRow, type KeyEnumerableStore, UnknownSchemaError, availability, buildSnapshot, climateGaps, dataVersionForResearch, dataVersionFromComponents, describe, featureCatalog, internationalDailyExtremes, registerSchema };
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/** Optional setters for cache writes. */
|
|
2
|
+
interface CacheSetOptions {
|
|
3
|
+
/** Time-to-live in milliseconds. Implementations may honor or ignore. */
|
|
4
|
+
readonly ttlMs?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Pluggable key/value cache contract used throughout the SDK.
|
|
8
|
+
*
|
|
9
|
+
* All methods are async — concrete implementations may resolve immediately
|
|
10
|
+
* (MemoryStore) or do I/O (FsStore / IndexedDBStore).
|
|
11
|
+
*
|
|
12
|
+
* Semantic contract:
|
|
13
|
+
* - `get<T>(key)` returns the stored value or `null` on miss. NEVER throws
|
|
14
|
+
* on miss.
|
|
15
|
+
* - `set<T>(key, value, opts?)` overwrites. ttlMs is implementation-honored
|
|
16
|
+
* (MemoryStore + IndexedDBStore honor it; FsStore ignores in v0.1).
|
|
17
|
+
* - `delete(key)` is a no-op on miss; returns void.
|
|
18
|
+
* - `withLock<T>(key, fn)` runs `fn` under a key-scoped exclusive lock and
|
|
19
|
+
* releases on settle (resolve OR throw). Nested calls to the same key
|
|
20
|
+
* serialize; calls to different keys MAY run in parallel.
|
|
21
|
+
*/
|
|
22
|
+
interface CacheStore {
|
|
23
|
+
get<T = unknown>(key: string): Promise<T | null>;
|
|
24
|
+
set<T = unknown>(key: string, value: T, opts?: CacheSetOptions): Promise<void>;
|
|
25
|
+
delete(key: string): Promise<void>;
|
|
26
|
+
withLock<T>(key: string, fn: () => Promise<T>): Promise<T>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Cache-coverage summary for a station.
|
|
31
|
+
*
|
|
32
|
+
* Mirrors Python `availability()` return shape.
|
|
33
|
+
*/
|
|
34
|
+
interface AvailabilityResult {
|
|
35
|
+
station: string;
|
|
36
|
+
/** Count of distinct (year, month) observation cache entries. */
|
|
37
|
+
monthsCached: number;
|
|
38
|
+
/** Earliest cached month as `"YYYY-MM"`, or null if none. */
|
|
39
|
+
firstMonth: string | null;
|
|
40
|
+
/** Latest cached month as `"YYYY-MM"`, or null if none. */
|
|
41
|
+
lastMonth: string | null;
|
|
42
|
+
/** Count of cached climate years. */
|
|
43
|
+
climateYears: number;
|
|
44
|
+
/** Earliest cached climate year as `"YYYY"`, or null if none. */
|
|
45
|
+
firstClimateYear: string | null;
|
|
46
|
+
/** Latest cached climate year as `"YYYY"`, or null if none. */
|
|
47
|
+
lastClimateYear: string | null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Optional adapter that lets `availability()` enumerate keys from a store.
|
|
51
|
+
*
|
|
52
|
+
* CacheStore's mandatory contract is opaque key-value: get/set/delete/withLock.
|
|
53
|
+
* Discovery needs to enumerate which keys exist for a station — this is
|
|
54
|
+
* implementation-specific (Memory iterates its Map, IndexedDB uses
|
|
55
|
+
* `getAllKeys`, Fs walks the directory tree). Stores that support enumeration
|
|
56
|
+
* implement the optional `listKeys(prefix)` method and `availability()` uses
|
|
57
|
+
* it; stores without it return zero-coverage but never throw.
|
|
58
|
+
*
|
|
59
|
+
* Listed keys may exceed the requested prefix in the result (callers filter);
|
|
60
|
+
* `listKeys` is best-effort.
|
|
61
|
+
*/
|
|
62
|
+
interface KeyEnumerableStore extends CacheStore {
|
|
63
|
+
listKeys(prefix: string): Promise<ReadonlyArray<string>>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Options for `availability()`.
|
|
67
|
+
*/
|
|
68
|
+
interface AvailabilityOptions {
|
|
69
|
+
/**
|
|
70
|
+
* If true, confirm each candidate key with `cache.get()` before counting.
|
|
71
|
+
* Eliminates the small overcount possible on stores whose `listKeys()` can
|
|
72
|
+
* return keys with already-expired TTL entries (FsStore and IndexedDBStore
|
|
73
|
+
* lazy-evict on `get`, not on `listKeys` — codex iter-3 P2). Off by default
|
|
74
|
+
* because the v0.1.0 `research()` flow never writes with `ttlMs`, so the
|
|
75
|
+
* overcount window is empty; turn on only if you populate the cache with
|
|
76
|
+
* explicit TTLs.
|
|
77
|
+
*
|
|
78
|
+
* Cost: one `get()` per matching key. On warm caches this is cheap
|
|
79
|
+
* (MemoryStore + IndexedDBStore in-memory). On FsStore it reads each
|
|
80
|
+
* candidate's file.
|
|
81
|
+
*/
|
|
82
|
+
readonly validate?: boolean;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Return a summary of cached coverage for `station`.
|
|
86
|
+
*
|
|
87
|
+
* Stores without enumeration support return a zero-coverage result with the
|
|
88
|
+
* station name populated (counts all zero, dates null).
|
|
89
|
+
*
|
|
90
|
+
* Pass `{ validate: true }` to confirm each candidate key via `cache.get()`
|
|
91
|
+
* — needed if your callers populate the cache with `ttlMs` and might query
|
|
92
|
+
* after expiry. The v0.1.0 `research()` flow does not use `ttlMs`, so the
|
|
93
|
+
* default (fast scan, no validation) is correct for the canonical path.
|
|
94
|
+
*/
|
|
95
|
+
declare function availability(station: string, cache: CacheStore, opts?: AvailabilityOptions): Promise<AvailabilityResult>;
|
|
96
|
+
|
|
97
|
+
/** Minimal row shape consumed by `internationalDailyExtremes`. */
|
|
98
|
+
interface InternationalRow {
|
|
99
|
+
/** ISO 8601 UTC instant. Must end with `Z` or include an offset. */
|
|
100
|
+
observed_at?: string | null;
|
|
101
|
+
/** Air temperature in degrees Celsius. */
|
|
102
|
+
temp_c?: number | null;
|
|
103
|
+
/** 1-hour precipitation total in millimeters. */
|
|
104
|
+
precip_mm_1h?: number | null;
|
|
105
|
+
/** Source identifier (preserved on the tmin/tmax aggregate). */
|
|
106
|
+
source?: string | null;
|
|
107
|
+
}
|
|
108
|
+
interface DailyExtreme {
|
|
109
|
+
/** Station-local calendar date as `YYYY-MM-DD`. */
|
|
110
|
+
localDate: string;
|
|
111
|
+
/** Count of rows with a parseable temp_c. */
|
|
112
|
+
nObs: number;
|
|
113
|
+
/** Min temperature in °C, or null on low coverage. */
|
|
114
|
+
tempMinC: number | null;
|
|
115
|
+
/** Max temperature in °C, or null on low coverage. */
|
|
116
|
+
tempMaxC: number | null;
|
|
117
|
+
/** Mean temperature in °C, or null on low coverage. */
|
|
118
|
+
tempMeanC: number | null;
|
|
119
|
+
/** Min temperature in °F, or null on low coverage. */
|
|
120
|
+
tempMinF: number | null;
|
|
121
|
+
/** Max temperature in °F, or null on low coverage. */
|
|
122
|
+
tempMaxF: number | null;
|
|
123
|
+
/** Total 1-hour precipitation across the local day, in mm. */
|
|
124
|
+
precipMm: number;
|
|
125
|
+
/** Source identifier of the row that produced tmin (or null on low coverage). */
|
|
126
|
+
sourceTmin: string | null;
|
|
127
|
+
/** Source identifier of the row that produced tmax (or null on low coverage). */
|
|
128
|
+
sourceTmax: string | null;
|
|
129
|
+
}
|
|
130
|
+
interface InternationalDailyExtremesOptions {
|
|
131
|
+
/** IANA timezone identifier for the station, e.g. `"Asia/Tokyo"`. Required. */
|
|
132
|
+
stationTz: string;
|
|
133
|
+
/**
|
|
134
|
+
* Decimal places for HALF_UP rounding. Defaults to 0 (whole °C) — the
|
|
135
|
+
* international convention. Pass `1` for US-station tenths.
|
|
136
|
+
*/
|
|
137
|
+
precision?: number;
|
|
138
|
+
/**
|
|
139
|
+
* Minimum number of observations required for tmin/tmax/tmean to be
|
|
140
|
+
* populated. Defaults to 12 (the Python threshold). Tests can override.
|
|
141
|
+
*/
|
|
142
|
+
minObs?: number;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Roll up observation rows to per-local-calendar-day temperature extremes.
|
|
146
|
+
*
|
|
147
|
+
* @param rows raw observation rows (any source). Rows without a parseable
|
|
148
|
+
* `observed_at` are dropped.
|
|
149
|
+
* @param opts `stationTz` is required. Optional `precision` (default 0;
|
|
150
|
+
* pass 1 for US-station tenths) and `minObs` (default 12).
|
|
151
|
+
*
|
|
152
|
+
* @returns one entry per local calendar day with at least one row. Days
|
|
153
|
+
* with fewer than `minObs` rows have temps set to null.
|
|
154
|
+
*/
|
|
155
|
+
declare function internationalDailyExtremes(rows: ReadonlyArray<InternationalRow>, opts: InternationalDailyExtremesOptions): DailyExtreme[];
|
|
156
|
+
|
|
157
|
+
/** Immutable reproducibility token stamping a single research() call. */
|
|
158
|
+
interface DataVersion {
|
|
159
|
+
readonly sdkVersion: string;
|
|
160
|
+
readonly schemaIds: ReadonlyArray<string>;
|
|
161
|
+
readonly sources: ReadonlyArray<string>;
|
|
162
|
+
readonly codeSha: string;
|
|
163
|
+
readonly dataSha: string;
|
|
164
|
+
readonly token: string;
|
|
165
|
+
}
|
|
166
|
+
interface DataVersionComponents {
|
|
167
|
+
sdkVersion: string;
|
|
168
|
+
schemaIds: ReadonlyArray<string>;
|
|
169
|
+
sources: ReadonlyArray<string>;
|
|
170
|
+
codeSha: string;
|
|
171
|
+
dataSha: string;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Build a frozen DataVersion from explicit components.
|
|
175
|
+
*
|
|
176
|
+
* Mirrors Python `DataVersion.from_components`: sorts schemaIds + sources
|
|
177
|
+
* INTERNALLY before the canonical hash so input order does not affect the
|
|
178
|
+
* token, but preserves the caller's order on the returned object's
|
|
179
|
+
* `schemaIds` and `sources` arrays. Codex iter-5 P2: prior version sorted
|
|
180
|
+
* the stored arrays alphabetically too, which masked source-priority order
|
|
181
|
+
* (e.g. `awc.live, ghcnh, iem.archive, ...` instead of the canonical
|
|
182
|
+
* `iem.archive, iem.live, awc.live, ghcnh, nws.cli` precedence Python
|
|
183
|
+
* preserves on the tuple).
|
|
184
|
+
*/
|
|
185
|
+
declare function dataVersionFromComponents(components: DataVersionComponents): Promise<DataVersion>;
|
|
186
|
+
/**
|
|
187
|
+
* Build a DataVersion for a research() call. Mirrors Python `DataVersion.for_research`:
|
|
188
|
+
* the codeSha encodes the call signature (`research:STATION:FROM:TO`) and dataSha
|
|
189
|
+
* is supplied by the caller (typically a cache fingerprint).
|
|
190
|
+
*
|
|
191
|
+
* The schema ids + source contract match the v0.1.0 Python SDK exactly so tokens
|
|
192
|
+
* computed in TS match tokens computed in Python for the same inputs.
|
|
193
|
+
*/
|
|
194
|
+
declare function dataVersionForResearch(args: {
|
|
195
|
+
sdkVersion: string;
|
|
196
|
+
station: string;
|
|
197
|
+
fromDate: string;
|
|
198
|
+
toDate: string;
|
|
199
|
+
dataSha: string;
|
|
200
|
+
}): Promise<DataVersion>;
|
|
201
|
+
|
|
202
|
+
/** Frozen snapshot wrapper around row data + provenance. */
|
|
203
|
+
interface DataSnapshot {
|
|
204
|
+
/** ISO 8601 UTC instant when the snapshot was built (always ends with Z). */
|
|
205
|
+
readonly knowledgeTime: string;
|
|
206
|
+
/** Schema id the rows conform to. */
|
|
207
|
+
readonly schemaId: string;
|
|
208
|
+
/** Source identifier (e.g. `iem.archive`, `awc.live`). Snapshot-scoped. */
|
|
209
|
+
readonly source: string;
|
|
210
|
+
/** Row payload — opaque to this layer. Frozen. */
|
|
211
|
+
readonly rows: ReadonlyArray<Readonly<Record<string, unknown>>>;
|
|
212
|
+
/** Optional reproducibility token. */
|
|
213
|
+
readonly dataVersion: DataVersion | null;
|
|
214
|
+
/** Optional arbitrary metadata. JSON-safe-coerced on `toDict`. */
|
|
215
|
+
readonly metadata: Readonly<Record<string, unknown>>;
|
|
216
|
+
/** JSON-safe dict form. */
|
|
217
|
+
toDict(): Record<string, unknown>;
|
|
218
|
+
/** TOON-v3 tabular form (rows only — provenance lives in the dict form). */
|
|
219
|
+
toToon(): string;
|
|
220
|
+
}
|
|
221
|
+
interface BuildSnapshotOptions {
|
|
222
|
+
schemaId: string;
|
|
223
|
+
source: string;
|
|
224
|
+
rows: ReadonlyArray<Record<string, unknown>>;
|
|
225
|
+
knowledgeTime?: Date | string;
|
|
226
|
+
dataVersion?: DataVersion | null;
|
|
227
|
+
metadata?: Record<string, unknown>;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Build a frozen DataSnapshot.
|
|
231
|
+
*
|
|
232
|
+
* Throws RangeError on invalid `knowledgeTime`. Row payloads are shallow-
|
|
233
|
+
* cloned and frozen so callers can't mutate snapshot state post-build.
|
|
234
|
+
*/
|
|
235
|
+
declare function buildSnapshot(opts: BuildSnapshotOptions): DataSnapshot;
|
|
236
|
+
|
|
237
|
+
interface TradewindsErrorOptions {
|
|
238
|
+
errorCode?: string;
|
|
239
|
+
source?: string | null;
|
|
240
|
+
requestId?: string | null;
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Base class for all mostlyright structured errors.
|
|
244
|
+
*
|
|
245
|
+
* `errorCode` is a stable enum (e.g. "SOURCE_UNAVAILABLE") used by callers /
|
|
246
|
+
* agents to branch on without parsing message text. `source` is the source id
|
|
247
|
+
* involved (e.g. "iem.archive") when applicable, and `requestId` correlates a
|
|
248
|
+
* JSON-RPC / MCP request id when applicable.
|
|
249
|
+
*/
|
|
250
|
+
declare class TradewindsError extends Error {
|
|
251
|
+
/** Subclass override — the stable string enum surfaced via `errorCode`. */
|
|
252
|
+
static defaultErrorCode: string;
|
|
253
|
+
readonly errorCode: string;
|
|
254
|
+
readonly source: string | null;
|
|
255
|
+
readonly requestId: string | null;
|
|
256
|
+
constructor(message?: string, options?: TradewindsErrorOptions);
|
|
257
|
+
/**
|
|
258
|
+
* Subclass hook returning the structured attributes for `toDict`.
|
|
259
|
+
* Values are passed through `toJsonSafe` by `toDict()`, so subclasses
|
|
260
|
+
* don't need to coerce values themselves.
|
|
261
|
+
*/
|
|
262
|
+
protected payload(): Record<string, unknown>;
|
|
263
|
+
/** Return a JSON-safe dict suitable for MCP `error.data`. */
|
|
264
|
+
toDict(): Record<string, unknown>;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
interface SchemaInfo {
|
|
268
|
+
readonly id: string;
|
|
269
|
+
readonly title: string;
|
|
270
|
+
readonly columnCount: number;
|
|
271
|
+
readonly columns: ReadonlyArray<{
|
|
272
|
+
readonly name: string;
|
|
273
|
+
readonly description: string;
|
|
274
|
+
readonly nullable: boolean;
|
|
275
|
+
}>;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Register or override a schema for `describe()`. Built-in v0.1.0 schemas
|
|
279
|
+
* are registered at module load (BUILT_IN_SCHEMAS); callers may add custom
|
|
280
|
+
* schemas or override built-ins (e.g. with richer descriptions).
|
|
281
|
+
*/
|
|
282
|
+
declare function registerSchema(info: SchemaInfo): void;
|
|
283
|
+
/**
|
|
284
|
+
* Return a multi-line description of a registered schema.
|
|
285
|
+
*
|
|
286
|
+
* @throws TradewindsError if `schemaId` is not registered. The error code is
|
|
287
|
+
* `UNKNOWN_SCHEMA` so callers can distinguish from validation/IO errors.
|
|
288
|
+
*/
|
|
289
|
+
declare function describe(schemaId: string): string;
|
|
290
|
+
/** Thrown by `describe` when `schemaId` is not registered. */
|
|
291
|
+
declare class UnknownSchemaError extends TradewindsError {
|
|
292
|
+
constructor(message: string);
|
|
293
|
+
static readonly defaultErrorCode = "UNKNOWN_SCHEMA";
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Return the transforms surface as a stable-sorted list.
|
|
297
|
+
*
|
|
298
|
+
* Matches Python `feature_catalog()`'s ordering — alphabetical on the
|
|
299
|
+
* snake_case names, here the camelCase TS names sorted identically.
|
|
300
|
+
*/
|
|
301
|
+
declare function featureCatalog(): ReadonlyArray<string>;
|
|
302
|
+
/**
|
|
303
|
+
* Climate-gap scanning is Python-only in v0.1.0 (TS has no climate-year
|
|
304
|
+
* parquet cache yet). Throws to match the documented contract.
|
|
305
|
+
*/
|
|
306
|
+
declare function climateGaps(_station: string, _fromDate: string, _toDate: string): never;
|
|
307
|
+
/** Thrown by `climateGaps` until the TS climate cache lands. */
|
|
308
|
+
declare class ClimateGapsNotImplementedError extends TradewindsError {
|
|
309
|
+
constructor(message: string);
|
|
310
|
+
static readonly defaultErrorCode = "NOT_IMPLEMENTED";
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export { type AvailabilityOptions, type AvailabilityResult, type BuildSnapshotOptions, ClimateGapsNotImplementedError, type DailyExtreme, type DataSnapshot, type DataVersion, type DataVersionComponents, type InternationalDailyExtremesOptions, type InternationalRow, type KeyEnumerableStore, UnknownSchemaError, availability, buildSnapshot, climateGaps, dataVersionForResearch, dataVersionFromComponents, describe, featureCatalog, internationalDailyExtremes, registerSchema };
|