@pond-ts/fit 0.67.0 → 0.69.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/AGENTS.md +253 -0
- package/API.md +88 -83
- package/CHANGELOG.md +109 -1
- package/README.md +6 -2
- package/package.json +26 -5
package/AGENTS.md
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# Using pond from a coding agent
|
|
2
|
+
|
|
3
|
+
You are reading this because a project depends on `pond-ts` or one of the
|
|
4
|
+
`@pond-ts/*` packages, or because you are deciding whether it should. This
|
|
5
|
+
file is the shortest route to correct code. It ships inside every pond
|
|
6
|
+
tarball as `AGENTS.md`, next to `API.md` (every public export, one line
|
|
7
|
+
each, with its source file) and `CHANGELOG.md`.
|
|
8
|
+
|
|
9
|
+
Docs: <https://pond-ts.org> · index for agents: <https://pond-ts.org/llms.txt>
|
|
10
|
+
· source: <https://github.com/pond-ts/pond>.
|
|
11
|
+
|
|
12
|
+
## What pond is, in three lines
|
|
13
|
+
|
|
14
|
+
- A **typed, immutable time series** (`TimeSeries`) whose schema is declared
|
|
15
|
+
once `as const` and narrows every downstream transform — no casts.
|
|
16
|
+
- The **same operator vocabulary on a streaming buffer** (`LiveSeries`):
|
|
17
|
+
push events in, subscribe to incremental `rolling` / `aggregate` views,
|
|
18
|
+
bounded by retention.
|
|
19
|
+
- **Domain packages on top**: React hooks, canvas charts that read a series
|
|
20
|
+
directly, financial studies + trading calendars, fitness analytics, and an
|
|
21
|
+
experimental processing-graph runtime.
|
|
22
|
+
|
|
23
|
+
## Which package
|
|
24
|
+
|
|
25
|
+
| You need to… | Install | Import from |
|
|
26
|
+
| ----------------------------------------------------------------------- | ------------------------------------ | ----------------------------------------------------- |
|
|
27
|
+
| Load timestamped rows; bucket, regrid, roll, fill, join, partition them | `pond-ts` | `'pond-ts'` |
|
|
28
|
+
| Ingest a live feed and keep rolling stats over the last N minutes | `pond-ts` | `'pond-ts'` (`LiveSeries`) |
|
|
29
|
+
| Share a series' type across a wire boundary with zero runtime | `pond-ts` | `'pond-ts/types'` |
|
|
30
|
+
| Own / subscribe to a series inside React | `@pond-ts/react` | `'@pond-ts/react'` |
|
|
31
|
+
| Draw it (line, area, band, bar, scatter, box, candlestick, heat map) | `@pond-ts/charts` (+ react, pond-ts) | `'@pond-ts/charts'` |
|
|
32
|
+
| OHLCV bars, SMA/EMA/RSI/MACD/Bollinger/ATR/VWAP…, market-hours calendar | `@pond-ts/financial` | `'@pond-ts/financial'`, `'@pond-ts/financial/fluent'` |
|
|
33
|
+
| GPS / power / heart-rate activity analytics | `@pond-ts/fit` | `'@pond-ts/fit'` |
|
|
34
|
+
| Computations as JSON plans with caching + provenance (experimental) | `@pond-ts/process` | `'@pond-ts/process'` |
|
|
35
|
+
|
|
36
|
+
All six release together under one version and release often. Install with
|
|
37
|
+
`@latest` rather than a version written from memory (a cold-start agent once
|
|
38
|
+
wrote `^0.3.0` and spent turns on a 2024 API); keep their ranges in step — a
|
|
39
|
+
pre-1.0 caret (`^0.67.0`) does **not** span minors.
|
|
40
|
+
|
|
41
|
+
## The idioms that cover most jobs
|
|
42
|
+
|
|
43
|
+
### 1. Declare the schema, build the series
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { TimeSeries, Sequence } from 'pond-ts';
|
|
47
|
+
|
|
48
|
+
const schema = [
|
|
49
|
+
{ name: 'time', kind: 'time' },
|
|
50
|
+
{ name: 'host', kind: 'string' },
|
|
51
|
+
{ name: 'latencyMs', kind: 'number' },
|
|
52
|
+
] as const; // ← load-bearing. Without it every column widens to string.
|
|
53
|
+
|
|
54
|
+
const s = TimeSeries.fromJSON({
|
|
55
|
+
name: 'latency',
|
|
56
|
+
schema,
|
|
57
|
+
rows, // positional tuples [time, host, latencyMs] or objects { time, host, latencyMs }
|
|
58
|
+
sort: true, // input not already time-ordered? sort on construction (stable)
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Time cells accept ms-since-epoch numbers, `Date`s, or ISO strings **with an
|
|
63
|
+
offset** (`…Z`, `…+01:00`). A wall-clock string with no offset is read as
|
|
64
|
+
**UTC** unless you pass `parse: { timeZone: 'America/New_York' }` — it does
|
|
65
|
+
not throw, it silently shifts by the zone's offset.
|
|
66
|
+
|
|
67
|
+
Other doors: `TimeSeries.fromPoints(points)` for wide `{ ts, a, b }` rows,
|
|
68
|
+
`fromColumns` for struct-of-arrays / `Float64Array`, `fromArrow` for an Arrow
|
|
69
|
+
table, `fromEvents`. `toJSON()` round-trips.
|
|
70
|
+
|
|
71
|
+
### 2. Downsample, regrid, slide — three different verbs
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
// Fewer rows out than in: one row per bucket.
|
|
75
|
+
const perMin = s.aggregate(Sequence.every('1m'), {
|
|
76
|
+
latencyMs: 'avg', // reducer by column …
|
|
77
|
+
p95: { from: 'latencyMs', using: 'p95' }, // … or a named output; reducers: sum avg min max count first last median stdev pNN
|
|
78
|
+
host: 'last',
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Same information, on a regular grid (hold / interpolate). No reduction.
|
|
82
|
+
const gridded = s.align(Sequence.every('10s'), { method: 'hold' });
|
|
83
|
+
|
|
84
|
+
// One output per input event, looking back over a window.
|
|
85
|
+
const rolled = s.rolling('5m', {
|
|
86
|
+
latencyMs: 'avg',
|
|
87
|
+
sd: { from: 'latencyMs', using: 'stdev' },
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`Sequence.every()` takes fixed durations only (`'10s'`, `'5m'`, `'1h'`,
|
|
92
|
+
`'1d'`). Months, weeks-in-a-zone, calendar days: `Sequence.calendar('month',
|
|
93
|
+
{ timeZone })`. Common shortcuts: `s.baseline('latencyMs', { window: '1h',
|
|
94
|
+
sigma: 2 })` appends avg / sd / upper / lower in one pass;
|
|
95
|
+
`s.outliers(col, { window, sigma })` keeps only the rows outside the band.
|
|
96
|
+
|
|
97
|
+
### 3. Per-entity, then flatten
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
const perHost = s
|
|
101
|
+
.partitionBy('host') // every stateful operator below runs per host
|
|
102
|
+
.rolling('5m', { latencyMs: 'avg' })
|
|
103
|
+
.collect(); // one flat TimeSeries, `host` carried through (type and runtime)
|
|
104
|
+
// or .toMap() → Map<host, TimeSeries>
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
`aggregate` and `rolling` under `partitionBy` carry the partition column
|
|
108
|
+
through in both the runtime **and** the static type (since 0.68), so
|
|
109
|
+
`e.get('host')` works on the collected result without naming it. On 0.67 or
|
|
110
|
+
older, name it in the mapping — `{ host: 'first', … }`.
|
|
111
|
+
|
|
112
|
+
### 4. Clean, fill, join, read out
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
const clean = s.dedupe().fill({ latencyMs: 'hold' }); // also 'linear', 'zero', gap caps
|
|
116
|
+
const joined = a.join(b); // on the time key; see API.md for options
|
|
117
|
+
clean.toPoints(); // [{ ts, host, latencyMs }, …] — chart-library friendly
|
|
118
|
+
clean.toRows(); // positional tuples
|
|
119
|
+
clean.column('latencyMs').mean(); // typed column: min/max/sum/mean/stdev/median/percentile
|
|
120
|
+
clean.column('latencyMs').toFloat64Array(); // zero-copy for canvas / WebGL loops
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Everything returns a **new** series. There is no `push` on a `TimeSeries`;
|
|
124
|
+
if you are appending, you want a `LiveSeries`.
|
|
125
|
+
|
|
126
|
+
### 5. Streaming
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
import { LiveSeries, Sequence } from 'pond-ts';
|
|
130
|
+
|
|
131
|
+
const live = new LiveSeries({
|
|
132
|
+
name: 'latency',
|
|
133
|
+
schema,
|
|
134
|
+
retention: { maxAge: '15m' }, // or { maxEvents: 10_000 }
|
|
135
|
+
ordering: 'reorder', // tolerate late rows …
|
|
136
|
+
graceWindow: '5s', // … up to this late
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const view = live.partitionBy('host').rolling('5m', { latencyMs: 'avg' });
|
|
140
|
+
const stop = view.on('event', (e) => render(e.get('host'), e.get('latencyMs')));
|
|
141
|
+
|
|
142
|
+
live.push([Date.now(), 'api-1', 42]); // validated against the schema
|
|
143
|
+
live.pushMany(batch);
|
|
144
|
+
const snapshot = live.toTimeSeries(); // immutable batch copy for analytics
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
`live.aggregate(Sequence.every('1m'), …)` emits `'bucket'` (partial) and
|
|
148
|
+
`'close'` (final) events. Retention bounds memory; `sample({ stride })`
|
|
149
|
+
between `partitionBy` and a long `rolling` bounds it further at firehose
|
|
150
|
+
rates.
|
|
151
|
+
|
|
152
|
+
### React and charts
|
|
153
|
+
|
|
154
|
+
```tsx
|
|
155
|
+
import { useLiveSeries } from '@pond-ts/react';
|
|
156
|
+
import {
|
|
157
|
+
ChartContainer,
|
|
158
|
+
ChartRow,
|
|
159
|
+
Layers,
|
|
160
|
+
LineChart,
|
|
161
|
+
YAxis,
|
|
162
|
+
} from '@pond-ts/charts';
|
|
163
|
+
|
|
164
|
+
const [live, snap] = useLiveSeries({
|
|
165
|
+
name: 'latency',
|
|
166
|
+
schema,
|
|
167
|
+
retention: { maxAge: '10m' },
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
<ChartContainer width={800} cursor="crosshair" panZoom>
|
|
171
|
+
<ChartRow height={240}>
|
|
172
|
+
<YAxis id="ms" />
|
|
173
|
+
<Layers>
|
|
174
|
+
{snap && <LineChart series={snap} column="latencyMs" axis="ms" />}
|
|
175
|
+
</Layers>
|
|
176
|
+
</ChartRow>
|
|
177
|
+
</ChartContainer>;
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Charts read a pond series directly — do the maths in pond (`rolling`,
|
|
181
|
+
`aggregate`, `align`) and hand the result to a layer. `useLiveSeries`'s snapshot is `null` before the first
|
|
182
|
+
push, hence the guard. `width` is a pixel
|
|
183
|
+
number or `'auto'` (the parent then needs a definite width, or nothing draws).
|
|
184
|
+
Hooks: `useTimeSeries`, `useLiveSeries`, `useSnapshot`, `useLiveQuery`,
|
|
185
|
+
`useDerived`, `useWindow`, `useCurrent`, `useLatest`.
|
|
186
|
+
|
|
187
|
+
### Financial
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
import '@pond-ts/financial/fluent'; // once, anywhere: adds studies to TimeSeries
|
|
191
|
+
import { TradingCalendar } from '@pond-ts/financial';
|
|
192
|
+
|
|
193
|
+
const studied = bars
|
|
194
|
+
.sma({ period: 20 })
|
|
195
|
+
.rsi({ period: 14 })
|
|
196
|
+
.bollinger({ period: 20 });
|
|
197
|
+
// or, function form: sma(bars, { period: 20 })
|
|
198
|
+
const cal = TradingCalendar.fromRules(
|
|
199
|
+
{ timeZone: 'America/New_York', open: '09:30', close: '16:00' },
|
|
200
|
+
{ from: '2026-01-05', to: '2026-02-13' },
|
|
201
|
+
);
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Studies read `'close'` by default, take **bar-count** periods, append
|
|
205
|
+
columns, preserve row count (warm-up rows are `undefined`). Sixty-plus of
|
|
206
|
+
them; `import { STUDIES } from '@pond-ts/financial/catalog'` lists them at runtime. Session-aligned bars: `ticks.aggregate(cal.barSequence('5m'), {...})`.
|
|
207
|
+
|
|
208
|
+
## Mistakes agents actually make
|
|
209
|
+
|
|
210
|
+
1. **Dropping `as const` on the schema.** Everything compiles and every
|
|
211
|
+
column is `string`. If `.get('x')` is not `number | undefined`, this is
|
|
212
|
+
why.
|
|
213
|
+
2. **`aggregate` when you meant `rolling`, or vice versa.** `aggregate`
|
|
214
|
+
changes the row count (one per bucket); `rolling` keeps it (one per
|
|
215
|
+
event); `align` puts rows on a grid without reducing.
|
|
216
|
+
3. **`Sequence.every('1M')` for months.** Not fixed-length → use
|
|
217
|
+
`Sequence.calendar('month', { timeZone })`.
|
|
218
|
+
4. **Wall-clock strings without a zone.** `'2025-01-01T09:00'` is read as
|
|
219
|
+
UTC — no error, every instant shifted by your offset. Add
|
|
220
|
+
`parse: { timeZone }` or use offset strings / ms numbers.
|
|
221
|
+
5. **Unsorted rows.** The constructor throws and names the row; pass
|
|
222
|
+
`sort: true` rather than sorting by hand.
|
|
223
|
+
6. **Mutating.** Nothing mutates. Capture the return value.
|
|
224
|
+
7. **Iterating events in a hot loop for a chart.** Use `column(name)` /
|
|
225
|
+
`toFloat64Array()` or hand the series to `@pond-ts/charts` — do not
|
|
226
|
+
rebuild point arrays per frame.
|
|
227
|
+
8. **Mismatched package versions.** All `pond-ts` / `@pond-ts/*` at the same
|
|
228
|
+
version, always.
|
|
229
|
+
9. **Reaching for a chart-library adapter first.** If the project uses React,
|
|
230
|
+
`@pond-ts/charts` consumes the series with no adapter; `toPoints()` is the
|
|
231
|
+
bridge for other libraries.
|
|
232
|
+
10. **Aggregating in one zone and charting in another.** `Sequence.calendar`
|
|
233
|
+
defaults to **UTC**; a chart's time axis defaults to the **viewer's**
|
|
234
|
+
zone. Pass the same `timeZone` to both — `Sequence.calendar('day', {
|
|
235
|
+
timeZone })` and `<ChartContainer timeZone={timeZone}>` — and a bucket
|
|
236
|
+
edge and the tick that labels it are one instant. A
|
|
237
|
+
`TradingCalendar.fromRules` carries its zone; `calendar={cal}` renders in
|
|
238
|
+
it with no further wiring.
|
|
239
|
+
|
|
240
|
+
## Where to read next
|
|
241
|
+
|
|
242
|
+
- `API.md` (this folder) — find any export and its source file.
|
|
243
|
+
- <https://pond-ts.org/llms.txt> — every docs page with a one-line
|
|
244
|
+
description; `https://pond-ts.org/llms-<area>.txt` for a single-fetch dump
|
|
245
|
+
of one area (`pond-ts`, `charts`, `financial`, …).
|
|
246
|
+
- <https://pond-ts.org/docs/pond-ts/mental-model> — one picture, and the
|
|
247
|
+
pandas / pondjs translation tables.
|
|
248
|
+
- <https://pond-ts.org/docs/how-to-guides> — end-to-end builds with the
|
|
249
|
+
friction already ironed out (dashboard, messy CSV ingest, histograms,
|
|
250
|
+
large series).
|
|
251
|
+
- Claude Code users: `/plugin marketplace add pond-ts/pond` then
|
|
252
|
+
`/plugin install pond-ts@pond-ts` installs skills for core, charts and
|
|
253
|
+
financial.
|
package/API.md
CHANGED
|
@@ -40,13 +40,13 @@ next door is the point.
|
|
|
40
40
|
|
|
41
41
|
### Series classes & construction
|
|
42
42
|
|
|
43
|
-
| Export | Purpose
|
|
44
|
-
| ----------------------- |
|
|
45
|
-
| `TimeSeries` | Immutable time-indexed collection, columnar storage
|
|
46
|
-
| `ValueSeries` | Series keyed by a monotonic non-time value axis
|
|
47
|
-
| `PartitionedTimeSeries` | Scoped view for per-partition stateful transforms
|
|
48
|
-
| `Sequence` | Infinite grid of time buckets (
|
|
49
|
-
| `BoundedSequence` | Finite ordered list of explicit interval buckets
|
|
43
|
+
| Export | Purpose | Source |
|
|
44
|
+
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
|
|
45
|
+
| `TimeSeries` | Immutable time-indexed collection, columnar storage | `packages/core/src/batch/time-series.ts` |
|
|
46
|
+
| `ValueSeries` | Series keyed by a monotonic non-time value axis | `packages/core/src/batch/value-series.ts` |
|
|
47
|
+
| `PartitionedTimeSeries` | Scoped view for per-partition stateful transforms; `<S, K, By>` — `By` is the partition column names, carried into `aggregate` / `rolling` result types | `packages/core/src/batch/partitioned-time-series.ts` |
|
|
48
|
+
| `Sequence` | Infinite grid of time buckets: fixed-step (hourly, every N) or calendar (day/week/month/quarter/year in an IANA zone, default UTC) | `packages/core/src/sequence/sequence.ts` |
|
|
49
|
+
| `BoundedSequence` | Finite ordered list of explicit interval buckets | `packages/core/src/sequence/bounded-sequence.ts` |
|
|
50
50
|
|
|
51
51
|
Static constructors on `TimeSeries`: `fromJSON()` (row tuples/objects),
|
|
52
52
|
`fromColumns()` (struct-of-arrays; `number` + `string` value columns),
|
|
@@ -99,13 +99,14 @@ Value-axis wire types
|
|
|
99
99
|
|
|
100
100
|
### Temporal keys & events
|
|
101
101
|
|
|
102
|
-
| Export | Purpose
|
|
103
|
-
| ------------- |
|
|
104
|
-
| `Time` | Point-in-time event key
|
|
105
|
-
| `TimeRange` | Interval event key (start/end)
|
|
106
|
-
| `Interval` | Labeled time-interval event key
|
|
107
|
-
| `
|
|
108
|
-
| `
|
|
102
|
+
| Export | Purpose | Source |
|
|
103
|
+
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------- |
|
|
104
|
+
| `Time` | Point-in-time event key | `packages/core/src/core/time.ts` |
|
|
105
|
+
| `TimeRange` | Interval event key (start/end) | `packages/core/src/core/time-range.ts` |
|
|
106
|
+
| `Interval` | Labeled time-interval event key | `packages/core/src/core/interval.ts` |
|
|
107
|
+
| `TimeZone` | IANA zone as a calendar: `startOf` / `next` / `parts` / `instant` / `offsetAt` / `abbreviation`; interned, transition-cached; what `Sequence.calendar` buckets with | `packages/core/src/core/time-zone.ts` |
|
|
108
|
+
| `Event` | Immutable event: temporal key + typed payload | `packages/core/src/core/event.ts` |
|
|
109
|
+
| `toTimeRange` | Coerce temporal values to `TimeRange` | `packages/core/src/core/time-range.ts` |
|
|
109
110
|
|
|
110
111
|
### TimeSeries methods (all in `packages/core/src/batch/time-series.ts`)
|
|
111
112
|
|
|
@@ -125,10 +126,11 @@ Value-axis wire types
|
|
|
125
126
|
`arrayContainsAny()`, `arrayAggregate()`, `arrayExplode()`
|
|
126
127
|
- **Gap fill / dedupe**: `fill()`, `materialize()`, `dedupe()`
|
|
127
128
|
- **Aggregate/group**: `aggregate(sequence, spec)`, `reduce()`, `groupBy()`,
|
|
128
|
-
`partitionBy()`, `byColumn()` (
|
|
129
|
+
`partitionBy()`, `byColumn(col, bins, mapping)` (numeric binning of a column into
|
|
130
|
+
fixed-`width` or explicit-`edges` bins, then reduce per bin — histograms),
|
|
129
131
|
`rollingByColumn()`, `byValue(axis)` (project onto a `ValueSeries`)
|
|
130
132
|
- **Windowing/smoothing**: `rolling(window, spec, opts)`, `smooth(column,
|
|
131
|
-
method)` (
|
|
133
|
+
method, opts)` (`'ema'` / `'movingAverage'` / `'loess'`), `align(method, opts)`
|
|
132
134
|
- **Differential/statistical**: `diff()`, `rate()`, `pctChange()`,
|
|
133
135
|
`cumulative()`, `scan()` (custom stateful reducer), `shift()`, `baseline()`
|
|
134
136
|
(rolling avg/sd/bands), `outliers()` (deviation from baseline)
|
|
@@ -157,14 +159,14 @@ Deliberately small — the ordering-based slice of the algebra, no calendar ops
|
|
|
157
159
|
|
|
158
160
|
### Key exported types (batch)
|
|
159
161
|
|
|
160
|
-
| Type group | Names
|
|
161
|
-
| ----------------- |
|
|
162
|
-
| Schema contract | `SeriesSchema`, `RowForSchema`, `EventForSchema`, `EventDataForSchema`, `EventKeyForSchema`, `TimeSeriesInput`, `TimeSeriesJsonInput`
|
|
163
|
-
| Aggregation specs | `AggregateReducer`, `AggregateMap`, `AggregateOutputMap`, `AggregateSchema`, `BinReducerName`, `BinOutput`
|
|
164
|
-
| Operation schemas | `RollingSchema`, `RollingAlignment`, `AlignSchema`, `DiffSchema`, `SmoothSchema`, `SmoothMethod`, `FillStrategy`, `FillMapping`
|
|
165
|
-
| Column/data kinds | `Column`, `KeyColumn`, `ColumnKind`, `ScalarKind`, `ScalarValue`, `ColumnValue`, `ArrayValue`, `ValidityBitmap`
|
|
166
|
-
| JSON wire format | `JsonRowFormat`, `JsonRowForSchema`, `JsonObjectRowForSchema`, `JsonValueForKind`, `JsonTimestampInput`, `JsonTimeRangeInput`, `JsonIntervalInput`
|
|
167
|
-
| Temporal utility | `TemporalLike`, `DurationInput`, `CalendarUnit`, `TimeZoneOptions`, `KeyLike`, `BatchSampleStrategy`, `SequenceSample`, `SequenceCoverage`
|
|
162
|
+
| Type group | Names | Source |
|
|
163
|
+
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
164
|
+
| Schema contract | `SeriesSchema`, `RowForSchema`, `EventForSchema`, `EventDataForSchema`, `EventKeyForSchema`, `TimeSeriesInput`, `TimeSeriesJsonInput` | `packages/core/src/schema/index.ts` |
|
|
165
|
+
| Aggregation specs | `AggregateReducer`, `AggregateMap`, `AggregateOutputMap`, `AggregateSchema`, `BinReducerName`, `BinOutput` | `packages/core/src/schema/index.ts`, `packages/core/src/column.ts` |
|
|
166
|
+
| Operation schemas | `RollingSchema`, `RollingAlignment`, `AlignSchema`, `DiffSchema`, `SmoothSchema`, `SmoothMethod`, `FillStrategy`, `FillMapping` | `packages/core/src/schema/index.ts` |
|
|
167
|
+
| Column/data kinds | `Column`, `KeyColumn`, `ColumnKind`, `ScalarKind`, `ScalarValue`, `ColumnValue`, `ArrayValue`, `ValidityBitmap` | `packages/core/src/columnar/` |
|
|
168
|
+
| JSON wire format | `JsonRowFormat`, `JsonRowForSchema`, `JsonObjectRowForSchema`, `JsonValueForKind`, `JsonTimestampInput`, `JsonTimeRangeInput`, `JsonIntervalInput` | `packages/core/src/schema/index.ts` |
|
|
169
|
+
| Temporal utility | `TemporalLike`, `DurationInput`, `CalendarUnit`, `TimeZoneOptions`, `Disambiguation`, `ZonedParts`, `ZonedPartsInput`, `StartOfOptions`, `KeyLike`, `BatchSampleStrategy`, `SequenceSample`, `SequenceCoverage` | `packages/core/src/core/`, `packages/core/src/sequence/` |
|
|
168
170
|
|
|
169
171
|
The `pond-ts/types` subpath re-exports the schema-as-contract types with zero
|
|
170
172
|
runtime (`packages/core/src/schema/public.ts`).
|
|
@@ -249,17 +251,17 @@ Types: `UseSnapshotOptions`, `SnapshotSource` (structural — covers
|
|
|
249
251
|
|
|
250
252
|
### Components — layout & axes
|
|
251
253
|
|
|
252
|
-
| Component | Key props
|
|
253
|
-
| --------------------------- |
|
|
254
|
-
| `ChartContainer` | `width`, `range?`, `theme?`, `cursor?`, `panZoom?`, `xScale?`, `bounds?`, `showAxis?`, `calendar?`, `origin?`, `maxBandWidth?`/`bandAlign?`, `onTrackerChanged?`, `onDrawStats?` | Root: shared x-scale, interactions, annotations
|
|
255
|
-
| `ChartRow` | `height`, `cursor?` (deprecated — mount a cursor in the row)
|
|
256
|
-
| `Layers` | children
|
|
257
|
-
| `YAxis` | `id` (req), `side?`, `scale?` (`'linear'` \| `'log'` \| `'symlog'`), `linearWindow?`, `min?`/`max?`, `format?`, `width?`, `hide?`
|
|
258
|
-
| `XAxis` | `side?`, `label?`, `format?`, `ticks?`, `transform?`, `dateStyle?`
|
|
259
|
-
| `TimeAxis` / `CategoryAxis` | (XAxis props)
|
|
260
|
-
| `Canvas` | `width`, `height`, `draw`
|
|
261
|
-
| `Selector` | `enabled?` (default `true`), `selected?` (mark \| set), `hovered?`, `onSelect?`, `onHover?`, `children?`
|
|
262
|
-
| `MultiSelector` | `enabled?`, `selected?`, `hovered?`, `sequence?`, `onSelect?`, `onHover?`, `children?`
|
|
254
|
+
| Component | Key props | Purpose | Source |
|
|
255
|
+
| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
256
|
+
| `ChartContainer` | `width`, `range?`, `theme?`, `cursor?`, `panZoom?`, `xScale?`, `bounds?`, `showAxis?`, `calendar?`, `timeZone?`, `origin?`, `maxBandWidth?`/`bandAlign?`, `onTrackerChanged?`, `onDrawStats?` | Root: shared x-scale, interactions, annotations; `timeZone` renders the time axis in an IANA zone (default: viewer-local; a `calendar.timeZone` supplies the default) | `packages/charts/src/ChartContainer.tsx` |
|
|
257
|
+
| `ChartRow` | `height`, `cursor?` (deprecated — mount a cursor in the row) | One stacked plot band; owns its y-axes | `packages/charts/src/ChartRow.tsx` |
|
|
258
|
+
| `Layers` | children | Mandatory z-stack inside a row (back-to-front) | `packages/charts/src/Layers.tsx` |
|
|
259
|
+
| `YAxis` | `id` (req), `side?`, `scale?` (`'linear'` \| `'log'` \| `'symlog'`), `linearWindow?`, `min?`/`max?`, `format?`, `width?`, `hide?` | Y-axis gutter; layers bind via their `axis` prop | `packages/charts/src/YAxis.tsx` |
|
|
260
|
+
| `XAxis` | `side?`, `label?`, `format?`, `ticks?`, `transform?`, `dateStyle?`, `timeZone?` (this strip in another IANA zone) | Placeable x-axis strip; kind inferred from data | `packages/charts/src/XAxis.tsx` |
|
|
261
|
+
| `TimeAxis` / `CategoryAxis` | (XAxis props) | Thin `XAxis` presets | `packages/charts/src/TimeAxis.tsx`, `CategoryAxis.tsx` |
|
|
262
|
+
| `Canvas` | `width`, `height`, `draw` | Low-level DPR-aware canvas primitive | `packages/charts/src/Canvas.tsx` |
|
|
263
|
+
| `Selector` | `enabled?` (default `true`), `selected?` (mark \| set), `hovered?`, `onSelect?`, `onHover?`, `children?` | Wraps its scope; mounting enables click-select and owns the state it drives (RFC A10) | `packages/charts/src/selectors.tsx` |
|
|
264
|
+
| `MultiSelector` | `enabled?`, `selected?`, `hovered?`, `sequence?`, `onSelect?`, `onHover?`, `children?` | Sweep-select superset of `Selector`: drag sweeps marks, release reports `(hits, modifiers, spans)` — plural, one per swept layer (RFC A5.2) | `packages/charts/src/selectors.tsx` |
|
|
263
265
|
|
|
264
266
|
### Components — draw layers
|
|
265
267
|
|
|
@@ -385,44 +387,47 @@ Series shapes (same file): `ChartSeries`, `BandSeries`, `BoxSeries`,
|
|
|
385
387
|
|
|
386
388
|
### Live values, scales & key types
|
|
387
389
|
|
|
388
|
-
| Export | Purpose
|
|
389
|
-
| ------------------------------------------ |
|
|
390
|
-
| `createLiveValue` / `LiveValue` | Imperative push channel for high-frequency indicator updates (isolated repaint)
|
|
391
|
-
| `scaleTradingTime` / `TradingTimeScale` | Discontinuous time scale collapsing closed-market gaps
|
|
392
|
-
| `DiscontinuityProvider` | Gap topology consumed by the trading-time scale
|
|
393
|
-
| `
|
|
394
|
-
| `
|
|
395
|
-
| `
|
|
396
|
-
| `
|
|
397
|
-
| `
|
|
398
|
-
| `
|
|
399
|
-
| `
|
|
400
|
-
| `
|
|
401
|
-
| `
|
|
402
|
-
| `
|
|
403
|
-
| `
|
|
404
|
-
| `
|
|
405
|
-
| `
|
|
406
|
-
| `
|
|
407
|
-
| `
|
|
408
|
-
| `
|
|
409
|
-
| `
|
|
410
|
-
| `
|
|
411
|
-
| `
|
|
412
|
-
| `
|
|
413
|
-
| `
|
|
414
|
-
| `
|
|
415
|
-
| `
|
|
416
|
-
| `
|
|
417
|
-
| `
|
|
418
|
-
| `
|
|
419
|
-
| `
|
|
420
|
-
| `
|
|
421
|
-
| `
|
|
422
|
-
| `
|
|
423
|
-
| `
|
|
424
|
-
| `
|
|
425
|
-
| `
|
|
390
|
+
| Export | Purpose | Source |
|
|
391
|
+
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------- |
|
|
392
|
+
| `createLiveValue` / `LiveValue` | Imperative push channel for high-frequency indicator updates (isolated repaint) | `packages/charts/src/indicators.tsx` |
|
|
393
|
+
| `scaleTradingTime` / `TradingTimeScale` | Discontinuous time scale collapsing closed-market gaps; `scaleTradingTime(provider, { timeZone })` runs its tick ladder and labels in an IANA zone; `.withTimeZone(zone)` / `.timeZone()` re-derive the same mapping in another zone | `packages/charts/src/tradingTimeScale.ts` |
|
|
394
|
+
| `DiscontinuityProvider` | Gap topology consumed by the trading-time scale; optional `withTimeZone(zone)` for providers whose day anchors move with the zone | `packages/charts/src/tradingTimeScale.ts` |
|
|
395
|
+
| `identityProvider` | The gap-free provider a plain continuous time axis runs on; `identityProvider({ timeZone })` puts its day anchors on that zone's midnights | `packages/charts/src/tradingTimeScale.ts` |
|
|
396
|
+
| `TradingCalendarLike` | Structural shape of a trading calendar `ChartContainer calendar` accepts: `discontinuities({ spacing })` + optional `timeZone` (the axis default) | `packages/charts/src/tradingTimeScale.ts` |
|
|
397
|
+
| `ScaleTimeZoneOptions` | `{ timeZone? }` for `scaleTradingTime` / `identityProvider` | `packages/charts/src/tradingTimeScale.ts` |
|
|
398
|
+
| `scaleBand` / `ScaleBand` | Ordinal slot scale for the category axis | `packages/charts/src/bandScale.ts` |
|
|
399
|
+
| `GapMode` | `'none' \| 'empty' \| 'dashed' \| 'step' \| 'fade'` (Line/Area `gaps` prop) | `packages/charts/src/gaps.ts` |
|
|
400
|
+
| `DecimateOption` | `<LineChart decimate>` — M4 viewport decimation (`bool \| { threshold }`) | `packages/charts/src/decimate.ts` |
|
|
401
|
+
| `CursorMode` | `'none' \| 'line' \| 'point' \| 'inline' \| 'flag' \| 'crosshair' \| 'region'` | `packages/charts/src/context.ts` |
|
|
402
|
+
| `TrackerInfo` / `TrackerSample` | Hover readout payload (`onTrackerChanged`) | `packages/charts/src/context.ts` |
|
|
403
|
+
| `AnnotationKind` / `CreateSpec` | Annotation identity + draw-gesture payload (`onCreate`) | `packages/charts/src/context.ts` |
|
|
404
|
+
| `SelectInfo` | Selection/hover payload (`Selector`/`MultiSelector` `onSelect`/`onHover`) | `packages/charts/src/context.ts` |
|
|
405
|
+
| `SelectModifiers` | Keyboard modifiers on a click, 2nd arg to `onSelect` | `packages/charts/src/context.ts` |
|
|
406
|
+
| `SelectorProps` | `<Selector>`'s props — `enabled?` / `selected?` / `hovered?` / `onSelect?` / `onHover?` / `children?` | `packages/charts/src/selectors.tsx` |
|
|
407
|
+
| `MultiSelectorProps` | `<MultiSelector>`'s props — the above plus `sequence?`, with plural callbacks | `packages/charts/src/selectors.tsx` |
|
|
408
|
+
| `RangeSpan` | `<RangeCursor onDragRelease>` payload — `{ x: [lo, hi], y? }` in axis units | `packages/charts/src/context.ts` |
|
|
409
|
+
| `SpanSelection` | Range entry for `selected` — one layer's marks over `x`/`y`/`rows` (RFC A5.2) | `packages/charts/src/context.ts` |
|
|
410
|
+
| `SelectionEntry` | One `selected` array entry: `SelectInfo \| SpanSelection` | `packages/charts/src/context.ts` |
|
|
411
|
+
| `selectionContains` | Is a hit in a mixed selection? The same membership predicate the layers run | `packages/charts/src/span.ts` |
|
|
412
|
+
| `sameMark` | Are two hits the same mark? Full identity (`id`, `mark`-or-`key`, `label`) | `packages/charts/src/span.ts` |
|
|
413
|
+
| `isSpanSelection` | Entry discriminant — narrows a `SelectionEntry` to `SpanSelection` | `packages/charts/src/span.ts` |
|
|
414
|
+
| `DrawStatsFrame` / `LayerDrawInfo` | Per-repaint draw-cost + decimation stats (`ChartContainer` `onDrawStats`) | `packages/charts/src/context.ts` |
|
|
415
|
+
| `TimeGrain` | Coarse time unit for grain-aware formatting | `packages/charts/src/tickLadder.ts` |
|
|
416
|
+
| `SwatchSpec` / `LegendItemInput` | Legend swatch vocabulary + explicit-rows input (`<Legend items>`) | `packages/charts/src/swatch.ts` |
|
|
417
|
+
| `useChartLegend` | Headless legend hook: rows (items grouped by chart row) + `hover`/`select` verbs | `packages/charts/src/useChartLegend.ts` |
|
|
418
|
+
| `ChartLegend` / `LegendRow` / `LegendItem` | The hook's return shape (`rows` group `items`; items carry `selected`/`hovered`) | `packages/charts/src/useChartLegend.ts` |
|
|
419
|
+
| `useChartFrame` | Resolved plot geometry: plot rect, gutters, x scale, a row's y scales, band slot edges | `packages/charts/src/useChartFrame.ts` |
|
|
420
|
+
| `ChartFrame` / `ChartFrameRow` | The hook's return shape — container x half, plus a row y half that is `null` outside a `<ChartRow>` | `packages/charts/src/useChartFrame.ts` |
|
|
421
|
+
| `ChartBands` / `ChartBand` | Ordinal slot geometry on a category axis (`count`/`pitch`/`labels`/`at(i)`); `null` on time/value | `packages/charts/src/useChartFrame.ts` |
|
|
422
|
+
| `ChartXScale` | The union the container's shared x scale resolves to (time / linear / trading / band / elapsed) | `packages/charts/src/context.ts` |
|
|
423
|
+
| `LegendPlacement` | `'top-left' \| 'top-right' \| 'bottom-left' \| 'bottom-right'` | `packages/charts/src/Legend.tsx` |
|
|
424
|
+
| `Curve` | Path interpolation: `'linear' \| 'monotone' \| 'natural' \| 'basis' \| 'step'` | `packages/charts/src/curve.ts` |
|
|
425
|
+
| `RadiusEncoding` / `ColorEncoding` | Data-driven scatter size/colour | `packages/charts/src/encoding.ts` |
|
|
426
|
+
| `CandleVariant` / `ColorBy` | OHLC mark shape / colouring strategy | `packages/charts/src/ohlc.ts` |
|
|
427
|
+
| `AxisFormat` / `CursorFormat` | Tick and cursor-readout formatting (d3 specifier or fn) | `packages/charts/src/format.ts` |
|
|
428
|
+
| `AxisTransform` | Monotonic `to`/`from` pair for derived-unit x-axis relabeling | `packages/charts/src/derivedTicks.ts` |
|
|
429
|
+
| `AxisMouseEvent` / `AxisMouseHandler` | Axis `onMouseEvent` payload — the mouse event, the axis's `id`, and the value/label under the pointer | `packages/charts/src/axis-events.ts` |
|
|
430
|
+
| `Orientation` | Bar growth direction | `packages/charts/src/bars.ts` |
|
|
426
431
|
|
|
427
432
|
---
|
|
428
433
|
|
|
@@ -617,16 +622,16 @@ erased types. A separate subpath: importing it pulls in every study.
|
|
|
617
622
|
|
|
618
623
|
### Trading calendars & sessions
|
|
619
624
|
|
|
620
|
-
| Export | Purpose
|
|
621
|
-
| ------------------------------------------------------------------------ |
|
|
622
|
-
| `TradingCalendar` |
|
|
623
|
-
| `generateSessions` | `Session[]` from `SessionRules` over a date range (DST-correct)
|
|
624
|
-
| `normalizeSessions` | Validate + sort an explicit session list
|
|
625
|
-
| `identityDiscontinuity` / `segmentDiscontinuity` / `weekendSkip` | `DiscontinuityProvider`s for the trading-time axis
|
|
626
|
-
| Types | `Session`, `SessionBreak`, `SessionRules`, `DateRange`, `InstantRange`, `TaggedSchema`, `LiveSegment`, `DiscontinuityProvider`
|
|
627
|
-
| `SessionSource` / `SessionAnchorOptions` | The session-anchored studies' input: `TradingCalendar \| Session[]` (`sessions`), or a session-id column name (`session`), plus `stamped`
|
|
628
|
-
| `PIVOT_METHODS` / `PivotMethod` | The four pivot formula sets (`standard`, `fibonacci`, `woodie`, `camarilla`)
|
|
629
|
-
| `PivotPointsSchema` / `CamarillaPivotPointsSchema` / `PivotPointsResult` | `pivotPoints`' method-dependent appended-schema types (7 columns, or 9 for Camarilla)
|
|
625
|
+
| Export | Purpose | Source |
|
|
626
|
+
| ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------- |
|
|
627
|
+
| `TradingCalendar` | `timeZone` (the exchange zone: `fromRules`' `rules.timeZone`, or `fromSessions(list, { timeZone })`) + query API: `.sessions()`, `.sessionOn()`, `.isTradingDay()`, `.isOpen()`, `.sessionsInRange()`, `.sessionSequence()`, `.barSequence(period)`, `.tagSessions()`, `.discontinuities()` | `packages/financial/src/calendar/` |
|
|
628
|
+
| `generateSessions` | `Session[]` from `SessionRules` over a date range (DST-correct) | `packages/financial/src/calendar/` |
|
|
629
|
+
| `normalizeSessions` | Validate + sort an explicit session list | `packages/financial/src/calendar/` |
|
|
630
|
+
| `identityDiscontinuity` / `segmentDiscontinuity` / `weekendSkip` | `DiscontinuityProvider`s for the trading-time axis | `packages/financial/src/calendar/` |
|
|
631
|
+
| Types | `Session`, `SessionBreak`, `SessionRules`, `DateRange`, `InstantRange`, `TaggedSchema`, `LiveSegment`, `DiscontinuityProvider` | `packages/financial/src/calendar/` |
|
|
632
|
+
| `SessionSource` / `SessionAnchorOptions` | The session-anchored studies' input: `TradingCalendar \| Session[]` (`sessions`), or a session-id column name (`session`), plus `stamped` | `packages/financial/src/contract/session-anchor.ts` |
|
|
633
|
+
| `PIVOT_METHODS` / `PivotMethod` | The four pivot formula sets (`standard`, `fibonacci`, `woodie`, `camarilla`) | `packages/financial/src/kernels/pivot.ts` |
|
|
634
|
+
| `PivotPointsSchema` / `CamarillaPivotPointsSchema` / `PivotPointsResult` | `pivotPoints`' method-dependent appended-schema types (7 columns, or 9 for Camarilla) | `packages/financial/src/studies/pivot-points.ts` |
|
|
630
635
|
|
|
631
636
|
### Contract & constants
|
|
632
637
|
|
package/CHANGELOG.md
CHANGED
|
@@ -8,7 +8,9 @@ The `@pond-ts` packages — `pond-ts`, `@pond-ts/react`, `@pond-ts/charts`,
|
|
|
8
8
|
under a single `v*` tag, so this file covers them all. Pre-1.0: minor bumps may
|
|
9
9
|
include new features and type-level changes; patch bumps are strictly additive.
|
|
10
10
|
|
|
11
|
-
[Unreleased]: https://github.com/pond-ts/pond/compare/v0.
|
|
11
|
+
[Unreleased]: https://github.com/pond-ts/pond/compare/v0.69.0...HEAD
|
|
12
|
+
[0.69.0]: https://github.com/pond-ts/pond/compare/v0.68.0...v0.69.0
|
|
13
|
+
[0.68.0]: https://github.com/pond-ts/pond/compare/v0.67.0...v0.68.0
|
|
12
14
|
[0.67.0]: https://github.com/pond-ts/pond/compare/v0.66.0...v0.67.0
|
|
13
15
|
[0.66.0]: https://github.com/pond-ts/pond/compare/v0.65.0...v0.66.0
|
|
14
16
|
[0.65.0]: https://github.com/pond-ts/pond/compare/v0.64.0...v0.65.0
|
|
@@ -70,6 +72,112 @@ include new features and type-level changes; patch bumps are strictly additive.
|
|
|
70
72
|
|
|
71
73
|
## [Unreleased]
|
|
72
74
|
|
|
75
|
+
## [0.69.0] — 2026-09-13
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
|
|
79
|
+
- **`<ChartContainer timeZone>` — the time axis in any IANA zone
|
|
80
|
+
([PND-TZAXIS]).** Day / week / month ticks land on that zone's midnights,
|
|
81
|
+
Mondays and month starts; labels, the stacked date bands, the hierarchical
|
|
82
|
+
grid, session dividers and every cursor / marker / annotation readout read
|
|
83
|
+
in it. **Omitted ⇒ the viewer's zone**, exactly as before. The d3 specifier
|
|
84
|
+
strings on `timeFormat` / `cursorFormat` are unchanged; `%Z` / `%z` now read
|
|
85
|
+
the zone's abbreviation / offset. Sub-day ticks align to the zone's wall
|
|
86
|
+
clock, so a 6 h grain reads 00 / 06 / 12 / 18 across a DST jump instead of
|
|
87
|
+
drifting by an hour until the next midnight. The resolved zone is on the
|
|
88
|
+
chart context as `timeZone`. Built on core's `TimeZone` ([PND-TZCAL]), so a
|
|
89
|
+
`Sequence.calendar('day', { timeZone })` bucket edge and the tick that
|
|
90
|
+
labels it are one instant — pinned by a cross-package test.
|
|
91
|
+
- **`<XAxis timeZone>` — a second strip in another zone.** Two time axes
|
|
92
|
+
over one shared mapping, each ticking and labelling (and pilling) in its
|
|
93
|
+
own zone: `<XAxis side="top" timeZone="America/New_York" />` above a
|
|
94
|
+
UTC container's own strip below. Backed by
|
|
95
|
+
`TradingTimeScale.withTimeZone(zone)` / `.timeZone()` and an optional
|
|
96
|
+
`DiscontinuityProvider.withTimeZone` (the identity provider re-derives its
|
|
97
|
+
day anchors; a trading calendar's session opens are zone-independent).
|
|
98
|
+
- **`TradingCalendarLike.timeZone?`** — a calendar that carries its exchange
|
|
99
|
+
zone supplies the axis default (`calendar={cal}` renders in exchange time
|
|
100
|
+
wherever it is viewed); an explicit `timeZone` prop wins.
|
|
101
|
+
- `scaleTradingTime(provider, { timeZone })` and
|
|
102
|
+
`identityProvider({ timeZone })` take the zone directly for consumers
|
|
103
|
+
building the scale themselves; `identityProvider`, `TradingCalendarLike`
|
|
104
|
+
and `ScaleTimeZoneOptions` are now exported. Internally the tick ladder
|
|
105
|
+
runs on a `TickCalendar` seam whose local implementation is the previous
|
|
106
|
+
`Date` arithmetic verbatim — the default path is unchanged.
|
|
107
|
+
- **`TradingCalendar.timeZone` ([PND-TZFIN]).** `@pond-ts/financial`'s
|
|
108
|
+
calendar keeps the zone its sessions were resolved in — `fromRules` carries
|
|
109
|
+
`rules.timeZone`, `fromSessions(list, { timeZone })` takes it — so
|
|
110
|
+
`<ChartContainer calendar={cal}>` renders the axis in exchange time with no
|
|
111
|
+
further wiring.
|
|
112
|
+
- `@pond-ts/charts` now depends on `d3-time-format` directly (it was already
|
|
113
|
+
a transitive dependency via `d3-scale`).
|
|
114
|
+
- **`TimeZone` — the zone-calendar primitive ([PND-TZCAL]).** `pond-ts`
|
|
115
|
+
exports `TimeZone.of(id)` (interned; also `TimeZone.UTC`,
|
|
116
|
+
`TimeZone.local()`) with `startOf(unit, t)`, `next(unit, t)`, `parts(t)`,
|
|
117
|
+
`instant(parts, { disambiguation })`, `offsetAt(t)` and
|
|
118
|
+
`abbreviation(t, { locale })`. Temporal underneath, but each zone caches its
|
|
119
|
+
offset transitions as it discovers them, so steady-state calls are integer
|
|
120
|
+
arithmetic: `startOf('day')` went from ~24 µs to ~23 ns per call, and a
|
|
121
|
+
three-year hourly series aggregated to `America/New_York` days from 38 ms
|
|
122
|
+
to 0.5 ms. `Sequence.calendar`, `TimeRange.fromCalendar` and
|
|
123
|
+
`Interval.fromCalendar` now bucket through it (no behaviour change; pinned
|
|
124
|
+
against Temporal on eight zones including southern-hemisphere DST, a
|
|
125
|
+
30-minute DST shift, a +05:30 zone, a day with no midnight and Samoa's
|
|
126
|
+
skipped day). This is the primitive the charts' time axis will place and
|
|
127
|
+
label ticks with, so a bucket edge and the tick that labels it are one
|
|
128
|
+
instant. First task of the time-zone plan
|
|
129
|
+
(`docs/plans/PND_TIMEZONE_PLAN.md`).
|
|
130
|
+
- **`CalendarUnit` gains `'quarter'` and `'year'`** for
|
|
131
|
+
`Sequence.calendar`, `TimeRange.fromCalendar` and `Interval.fromCalendar`.
|
|
132
|
+
|
|
133
|
+
### Changed
|
|
134
|
+
|
|
135
|
+
- **`Sequence.calendar` validates its inputs at construction.** An unknown
|
|
136
|
+
unit (`'hour'`) or zone (`'Nowhere'`) now throws `RangeError` immediately;
|
|
137
|
+
before, an unknown unit silently produced wrong buckets (the two unit
|
|
138
|
+
dispatchers fell through to different defaults — the 2026-06 audit's §6
|
|
139
|
+
finding) and an unknown zone failed only on first `bounded()`.
|
|
140
|
+
|
|
141
|
+
### Fixed
|
|
142
|
+
|
|
143
|
+
- **`pond-ts`: two type-level corners of [PND-PARTCOL] (0.68.0) found by the Codex pass on #724.** (1) On a broad `TimeSeries<SeriesSchema>` with a _literal_ partition column, the injected `'first'` could not look up a kind and typed the column as `undefined`; `WithPartitionColumns` now takes the schema and leaves the mapping alone when the schema is broad, so the result type is exactly 0.67's. (2) `By` had no variance pin, so `PartitionedTimeSeries<S, K, 'host'>` accepted a view partitioned by `region` (and an untyped view could be narrowed to any column); a phantom contravariant member now rejects both while a specialised view still assigns to the legacy `PartitionedTimeSeries<S>` shape. Type tests cover both plus the `K`-survives-`smooth`/`baseline` claim. No runtime change.
|
|
144
|
+
- **Docs said a wall-clock string without `parse.timeZone` throws. It never
|
|
145
|
+
did** ([PND-TZDOCS]) — it is read as UTC, silently. `creating.mdx`, the
|
|
146
|
+
agent guide (`AGENTS.md`) and the decision table now say so and describe
|
|
147
|
+
how the shift shows up. The agent guide also gains the one time-zone rule:
|
|
148
|
+
pass the same `timeZone` to `Sequence.calendar` and `<ChartContainer>`.
|
|
149
|
+
The aggregation page cross-links `Sequence.calendar` for weekly / monthly
|
|
150
|
+
bars (issue #358 item 1, supersedes #359). The finance gallery's off-chart
|
|
151
|
+
readout takes the calendar's zone instead of hard-coding New York; the
|
|
152
|
+
Niño 3.4 heat map's year grain uses `Sequence.calendar('year')`.
|
|
153
|
+
|
|
154
|
+
## [0.68.0] — 2026-09-13
|
|
155
|
+
|
|
156
|
+
### Added
|
|
157
|
+
|
|
158
|
+
- **Agent adoption tranche ([PND-ADOPTMETA] / [PND-ADOPTLINKS] /
|
|
159
|
+
[PND-LLMSTXT] / [PND-AGENTGUIDE] / [PND-SKILL] / [PND-CONTEXT7]).** Every
|
|
160
|
+
package now declares `keywords`, `homepage` and `bugs` (there were none —
|
|
161
|
+
`pond-ts` ranked last in `npm search "time series"`). Every tarball ships an
|
|
162
|
+
`AGENTS.md` (source `docs/agents/USING_POND.md`): which package for which
|
|
163
|
+
task, the core idioms, the mistakes agents make. `pond-ts.org/llms.txt` is
|
|
164
|
+
now llmstxt.org-shaped (titles + descriptions per page, one section per
|
|
165
|
+
docs area, `Optional` links to `API.md` / the agent guide) with per-area
|
|
166
|
+
`llms-<area>.txt` dumps so a single fetch stays small. A Claude Code plugin
|
|
167
|
+
marketplace lives in the repo (`/plugin marketplace add pond-ts/pond`) with
|
|
168
|
+
`pond-ts`, `pond-charts` and `pond-financial` skills. `context7.json`
|
|
169
|
+
configures docs-MCP indexing. Plan and baseline:
|
|
170
|
+
`docs/plans/PND_ADOPTION_PLAN.md`.
|
|
171
|
+
|
|
172
|
+
- **Agent guide + skill hardened by the first cold-start run** (`docs/agents/USING_POND.md`, shipped as `AGENTS.md`; `plugins/pond-ts/skills/pond-ts`): install with `@latest` and the `.d.ts` paths that carry signatures. Cold-start harness committed at `docs/adoption/cold-start/`.
|
|
173
|
+
|
|
174
|
+
### Fixed
|
|
175
|
+
|
|
176
|
+
- **`pond-ts`: the partition column is now in the static type after a partitioned `aggregate` / `rolling` ([PND-PARTCOL]).** `series.partitionBy('host').aggregate(seq, { p95: { from: 'ms', using: 'p95' } }).collect()` always carried `host` at runtime (auto-injected as `'first'`) but the result type omitted it, so `e.get('host')` failed to compile — every fresh agent in the cold-start experiment hit or pre-empted it. `PartitionedTimeSeries` gains a third type parameter `By` (the partition column names, captured by `partitionBy`, default `never`), and the two schema-replacing operators are typed over `WithPartitionColumns<Mapping, By>` — the user's keys win, kind and all; missing partition columns are added as `'first'`. Composite partitions and typed `groups` carry through; `smooth` / `baseline` under `partitionBy` now also keep `K`. Additive: untyped views are unchanged.
|
|
177
|
+
- `@pond-ts/charts` and `@pond-ts/fit` READMEs (rendered on npm) and eight
|
|
178
|
+
docs pages pointed at the retired `pjm17971.github.io/pond-ts` site /
|
|
179
|
+
`pjm17971/pond-ts` repo; now `pond-ts.org` / `pond-ts/pond`.
|
|
180
|
+
|
|
73
181
|
## [0.67.0] — 2026-09-11
|
|
74
182
|
|
|
75
183
|
### Added
|
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# @pond-ts/fit
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@pond-ts/fit)
|
|
4
|
+
[](https://github.com/pond-ts/pond/actions/workflows/ci.yml)
|
|
5
|
+
[](https://pond-ts.org/docs/fit/)
|
|
6
|
+
|
|
3
7
|
**Fitness & activity analytics on [pond-ts](https://www.npmjs.com/package/pond-ts).**
|
|
4
8
|
|
|
5
9
|
Turn raw activity streams (GPS, power, heart rate, cadence, …) into a typed,
|
|
@@ -61,8 +65,8 @@ Speed.mps(5.5).format('imperial'); // "12.3 mph"
|
|
|
61
65
|
|
|
62
66
|
## Documentation
|
|
63
67
|
|
|
64
|
-
Guides and the full API live at **<https://
|
|
65
|
-
Source and issues: [github.com/
|
|
68
|
+
Guides and the full API live at **<https://pond-ts.org/docs/fit/>**.
|
|
69
|
+
Source and issues: [github.com/pond-ts/pond](https://github.com/pond-ts/pond).
|
|
66
70
|
|
|
67
71
|
## License
|
|
68
72
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,28 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pond-ts/fit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.69.0",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "Fitness & activity domain library on pond-ts
|
|
5
|
+
"description": "Fitness & activity domain library on pond-ts: typed quantities, canonical activity series, and analytics (geo distance/elevation, power NP/IF/TSS, zones, splits)",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"time-series",
|
|
8
|
+
"timeseries",
|
|
9
|
+
"typescript",
|
|
10
|
+
"streaming",
|
|
11
|
+
"analytics",
|
|
12
|
+
"fitness",
|
|
13
|
+
"cycling",
|
|
14
|
+
"running",
|
|
15
|
+
"gps",
|
|
16
|
+
"geo",
|
|
17
|
+
"power",
|
|
18
|
+
"heart-rate",
|
|
19
|
+
"training-load",
|
|
20
|
+
"pond-ts"
|
|
21
|
+
],
|
|
22
|
+
"homepage": "https://pond-ts.org/docs/fit/",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/pond-ts/pond/issues"
|
|
25
|
+
},
|
|
6
26
|
"license": "MIT",
|
|
7
27
|
"repository": {
|
|
8
28
|
"type": "git",
|
|
@@ -25,20 +45,21 @@
|
|
|
25
45
|
"files": [
|
|
26
46
|
"dist",
|
|
27
47
|
"CHANGELOG.md",
|
|
28
|
-
"API.md"
|
|
48
|
+
"API.md",
|
|
49
|
+
"AGENTS.md"
|
|
29
50
|
],
|
|
30
51
|
"scripts": {
|
|
31
52
|
"build": "tsc -p tsconfig.json",
|
|
32
53
|
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
33
54
|
"format:check": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\"",
|
|
34
|
-
"prepack": "cp ../../LICENSE ./LICENSE && cp ../../CHANGELOG.md ./CHANGELOG.md && cp ../../API.md ./API.md && npm run build && cp cjs-fallback.cjs dist/cjs-fallback.cjs && find dist -name '*.map' -delete",
|
|
55
|
+
"prepack": "cp ../../LICENSE ./LICENSE && cp ../../CHANGELOG.md ./CHANGELOG.md && cp ../../API.md ./API.md && cp ../../docs/agents/USING_POND.md ./AGENTS.md && npm run build && cp cjs-fallback.cjs dist/cjs-fallback.cjs && find dist -name '*.map' -delete",
|
|
35
56
|
"test": "npm run test:type && npm run test:runtime",
|
|
36
57
|
"test:type": "tsc -p tsconfig.types.json",
|
|
37
58
|
"test:runtime": "vitest run",
|
|
38
59
|
"verify": "npm run format:check && npm run build && npm test"
|
|
39
60
|
},
|
|
40
61
|
"peerDependencies": {
|
|
41
|
-
"pond-ts": "^0.
|
|
62
|
+
"pond-ts": "^0.69.0"
|
|
42
63
|
},
|
|
43
64
|
"devDependencies": {
|
|
44
65
|
"typescript": "^5.6.3",
|