@pond-ts/react 0.12.1 → 0.13.1

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.
Files changed (2) hide show
  1. package/CHANGELOG.md +172 -1
  2. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -7,10 +7,181 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
7
7
  file covers both packages. Pre-1.0: minor bumps may include new features and
8
8
  type-level changes; patch bumps are strictly additive.
9
9
 
10
- [Unreleased]: https://github.com/pjm17971/pond-ts/compare/v0.12.1...HEAD
10
+ [Unreleased]: https://github.com/pjm17971/pond-ts/compare/v0.13.1...HEAD
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [0.13.1] — 2026-05-01
15
+
16
+ Strictly additive over v0.13.0. Adds a sugar factory on `Trigger`
17
+ following Codex feedback after adopting v0.12 triggers in the
18
+ production webapp telemetry app: the explicit form
19
+ (`Trigger.clock(Sequence.every('30s'))`) is "ceremony-heavy for the
20
+ common case."
21
+
22
+ ### Added
23
+
24
+ - **`Trigger.every(duration, options?)`** — sugar for the common
25
+ `Trigger.clock(Sequence.every(duration, options))` pattern. Removes
26
+ the need to import `Sequence` for trigger-only use sites. Forwards
27
+ `{ anchor }` to `Sequence.every` and inherits the same fixed-step
28
+ validation:
29
+
30
+ ```ts
31
+ // Before
32
+ live.rolling('1m', mapping, {
33
+ trigger: Trigger.clock(Sequence.every('30s')),
34
+ });
35
+
36
+ // After
37
+ live.rolling('1m', mapping, { trigger: Trigger.every('30s') });
38
+
39
+ // Anchored variant (passes through to Sequence.every):
40
+ Trigger.every('30s', { anchor: 5_000 });
41
+ ```
42
+
43
+ The explicit `Trigger.clock(seq)` form remains for callers who
44
+ already hold a `Sequence` object (e.g. one shared across batch
45
+ `series.aggregate(seq, ...)` and live triggers) — `Trigger.every`
46
+ always builds a fresh `Sequence`.
47
+
48
+ ### Docs
49
+
50
+ - Telemetry recipe and live-transforms doc updated to lead with
51
+ the sugar form. `Trigger.clock` documented as the explicit form
52
+ for "I already have a Sequence object" cases.
53
+ - JSDoc on `LiveRollingAggregation.trigger` and the partitioned
54
+ rolling clock-trigger example updated to show the sugar.
55
+
56
+ ### Tests
57
+
58
+ - 3 new tests in `test/Triggers.test.ts` covering: sugar produces
59
+ `kind: 'clock'` with correct stepMs/anchor; anchor option
60
+ forwards correctly; behavioural equivalence between
61
+ `Trigger.every('30s')` and `Trigger.clock(Sequence.every('30s'))`
62
+ pinned by emission-time comparison through a real
63
+ `LiveRollingAggregation`.
64
+ - Total core tests: 1063 (was 1060).
65
+
66
+ [0.13.1]: https://github.com/pjm17971/pond-ts/compare/v0.13.0...v0.13.1
67
+
68
+ ## [0.13.0] — 2026-05-01
69
+
70
+ The "AggregateOutputMap on live" release. Closes the feature-parity
71
+ gap between batch and live aggregation: the `{ alias: { from, using } }`
72
+ mapping shape that batch `TimeSeries.rolling`/`aggregate` already
73
+ accepted now works on `LiveSeries.rolling`, `LiveSeries.aggregate`,
74
+ and the synchronised partitioned form. Multiple stats from one
75
+ source column in a single rolling deque — no more "one rolling per
76
+ percentile" workaround.
77
+
78
+ The shared runtime helper (`normalizeAggregateColumns`) was already
79
+ doing the work for batch; this release extracts it to
80
+ `aggregate-columns.ts` and threads the type-level overloads through
81
+ the live surface.
82
+
83
+ ### Added
84
+
85
+ - **`AggregateOutputMap` on `LiveSeries.rolling` and
86
+ `LiveSeries.aggregate`.** Compose multiple built-in reducers from
87
+ one source column in a single pass:
88
+
89
+ ```ts
90
+ const band = live.rolling('1m', {
91
+ mean: { from: 'cpu', using: 'avg' },
92
+ sd: { from: 'cpu', using: 'stdev' },
93
+ });
94
+ band.value(); // { mean, sd } — single deque, one walk
95
+ ```
96
+
97
+ Threaded through `LiveView.rolling`/`aggregate`,
98
+ `LiveAggregation.rolling`, `LiveRollingAggregation.aggregate`,
99
+ `LivePartitionedSeries.rolling`, and `LivePartitionedView.rolling`
100
+ — so chained pipelines (`live.filter(...).rolling(...)`,
101
+ `live.partitionBy(c).fill(...).rolling(..., { trigger: ... })`)
102
+ accept either shape.
103
+
104
+ - **Synchronised partitioned rolling with `AggregateOutputMap`.**
105
+ `partitionBy(col).rolling(window, mapping, { trigger: Trigger.clock(seq) })`
106
+ now accepts the alias form. Output schema becomes
107
+ `[time, <partitionColumn>, ...aliasColumns]`. The collision check
108
+ rejects when an alias output collides with the partition column
109
+ name (compare against the alias, not the source column).
110
+
111
+ ### Changed
112
+
113
+ - **Better error message when a custom-function reducer is passed to
114
+ live aggregation.** `LiveAggregation` already failed at construction
115
+ via `resolveReducer(reducer)` (with a generic `unsupported aggregate
116
+ reducer` message); now the eager built-in-name check runs first and
117
+ emits a targeted error pointing at the `AggregateOutputMap` alias
118
+ workaround. Same eager behavior on `LivePartitionedSyncRolling`,
119
+ which previously failed lazily when the first partition spawned —
120
+ now fails at construction. Aligns with `LiveRollingAggregation`'s
121
+ long-standing eager check.
122
+
123
+ - **Shared `normalizeAggregateColumns` helper.** Extracted from
124
+ `TimeSeries.ts` into `aggregate-columns.ts` and used by all three
125
+ live accumulators (`LiveRollingAggregation`, `LiveAggregation`,
126
+ `LivePartitionedSyncRolling`). Single source of truth for column
127
+ normalisation; identical error messages across batch and live
128
+ (`unknown source column`).
129
+
130
+ ### Constraints
131
+
132
+ - **Custom-function reducers remain batch-only.** Live rolling and
133
+ live aggregation still require built-in reducer names (`'avg'`,
134
+ `'p95'`, etc.). Custom `(values) => ...` functions don't have the
135
+ incremental add/remove machinery the live path needs and are
136
+ rejected at construction with a clear error pointing at the
137
+ `AggregateOutputMap` workaround. This is the established
138
+ recommendation: alias multiple built-ins to compose stats from
139
+ one source column.
140
+
141
+ ### Fixed
142
+
143
+ - **`partitionBy(...).rolling(..., options)` now accepts `options` as
144
+ a variable typed `LiveRollingOptions`, not just inline literals.**
145
+ Pre-fix, the four narrowed overloads on
146
+ `LivePartitionedSeries.rolling` and `LivePartitionedView.rolling`
147
+ required TS to see the `trigger` field's discriminator at the call
148
+ site — so a caller writing
149
+ `const opts: LiveRollingOptions = { trigger: Trigger.event() };
150
+ partitioned.rolling(window, mapping, opts);` got `TS2769 No
151
+ overload matches this call`. Pre-existing hole on the partitioned
152
+ surface; surfaced by the v0.13.0 Codex adversarial pass. Closed by
153
+ adding catch-all overloads that accept the broader
154
+ `LiveRollingOptions` and return the union of both trigger
155
+ branches; the four narrowed overloads above still match inline
156
+ literals first, so callers keep the precise return type when they
157
+ pass the trigger inline. Pinned with `test-d/types.test-d.ts`
158
+ coverage using both inline-literal and variable forms.
159
+
160
+ ### Tests
161
+
162
+ - 16 new tests in `test/LiveAggregateOutputMap.test.ts` covering:
163
+ flat live rolling/aggregate with the alias form, chained-view
164
+ rolling/aggregate, `LiveAggregation.rolling` and
165
+ `LiveRollingAggregation.aggregate` chainable accumulators,
166
+ per-partition rolling, synchronised partitioned rolling with
167
+ alias outputs, output-vs-source column-collision rejection on
168
+ the synced form, and explicit kind override.
169
+ - 2 existing tests updated (`LiveAggregation` and
170
+ `LiveRollingAggregation` "unknown column" → "unknown source column"
171
+ to match the shared helper's error string).
172
+ - Test count: 1060 (was 1044).
173
+
174
+ ### Docs
175
+
176
+ - `transforms/rolling.mdx`: live section now documents the
177
+ `AggregateOutputMap` shape with a band-chart example, plus a
178
+ callout that custom functions remain batch-only.
179
+ - `recipes/telemetry-reporting.mdx`: "Want multiple percentiles?"
180
+ section rewritten — the workaround note is gone, replaced with
181
+ the single-pass `{ p50, p95, p99 }` pattern.
182
+
183
+ [0.13.0]: https://github.com/pjm17971/pond-ts/compare/v0.12.1...v0.13.0
184
+
14
185
  ## [0.12.1] — 2026-05-01
15
186
 
16
187
  Strictly additive over v0.12.0. Closes the chained-view restriction
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pond-ts/react",
3
- "version": "0.12.1",
3
+ "version": "0.13.1",
4
4
  "description": "React hooks for pond-ts live time series",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -31,7 +31,7 @@
31
31
  "test:runtime": "vitest run"
32
32
  },
33
33
  "peerDependencies": {
34
- "pond-ts": "^0.12.0",
34
+ "pond-ts": "^0.13.0",
35
35
  "react": "^18.0.0 || ^19.0.0"
36
36
  },
37
37
  "devDependencies": {