@pond-ts/react 0.12.0 → 0.13.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.
Files changed (2) hide show
  1. package/CHANGELOG.md +167 -1
  2. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -7,10 +7,176 @@ 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.0...HEAD
10
+ [Unreleased]: https://github.com/pjm17971/pond-ts/compare/v0.13.0...HEAD
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [0.13.0] — 2026-05-01
15
+
16
+ The "AggregateOutputMap on live" release. Closes the feature-parity
17
+ gap between batch and live aggregation: the `{ alias: { from, using } }`
18
+ mapping shape that batch `TimeSeries.rolling`/`aggregate` already
19
+ accepted now works on `LiveSeries.rolling`, `LiveSeries.aggregate`,
20
+ and the synchronised partitioned form. Multiple stats from one
21
+ source column in a single rolling deque — no more "one rolling per
22
+ percentile" workaround.
23
+
24
+ The shared runtime helper (`normalizeAggregateColumns`) was already
25
+ doing the work for batch; this release extracts it to
26
+ `aggregate-columns.ts` and threads the type-level overloads through
27
+ the live surface.
28
+
29
+ ### Added
30
+
31
+ - **`AggregateOutputMap` on `LiveSeries.rolling` and
32
+ `LiveSeries.aggregate`.** Compose multiple built-in reducers from
33
+ one source column in a single pass:
34
+
35
+ ```ts
36
+ const band = live.rolling('1m', {
37
+ mean: { from: 'cpu', using: 'avg' },
38
+ sd: { from: 'cpu', using: 'stdev' },
39
+ });
40
+ band.value(); // { mean, sd } — single deque, one walk
41
+ ```
42
+
43
+ Threaded through `LiveView.rolling`/`aggregate`,
44
+ `LiveAggregation.rolling`, `LiveRollingAggregation.aggregate`,
45
+ `LivePartitionedSeries.rolling`, and `LivePartitionedView.rolling`
46
+ — so chained pipelines (`live.filter(...).rolling(...)`,
47
+ `live.partitionBy(c).fill(...).rolling(..., { trigger: ... })`)
48
+ accept either shape.
49
+
50
+ - **Synchronised partitioned rolling with `AggregateOutputMap`.**
51
+ `partitionBy(col).rolling(window, mapping, { trigger: Trigger.clock(seq) })`
52
+ now accepts the alias form. Output schema becomes
53
+ `[time, <partitionColumn>, ...aliasColumns]`. The collision check
54
+ rejects when an alias output collides with the partition column
55
+ name (compare against the alias, not the source column).
56
+
57
+ ### Changed
58
+
59
+ - **Better error message when a custom-function reducer is passed to
60
+ live aggregation.** `LiveAggregation` already failed at construction
61
+ via `resolveReducer(reducer)` (with a generic `unsupported aggregate
62
+ reducer` message); now the eager built-in-name check runs first and
63
+ emits a targeted error pointing at the `AggregateOutputMap` alias
64
+ workaround. Same eager behavior on `LivePartitionedSyncRolling`,
65
+ which previously failed lazily when the first partition spawned —
66
+ now fails at construction. Aligns with `LiveRollingAggregation`'s
67
+ long-standing eager check.
68
+
69
+ - **Shared `normalizeAggregateColumns` helper.** Extracted from
70
+ `TimeSeries.ts` into `aggregate-columns.ts` and used by all three
71
+ live accumulators (`LiveRollingAggregation`, `LiveAggregation`,
72
+ `LivePartitionedSyncRolling`). Single source of truth for column
73
+ normalisation; identical error messages across batch and live
74
+ (`unknown source column`).
75
+
76
+ ### Constraints
77
+
78
+ - **Custom-function reducers remain batch-only.** Live rolling and
79
+ live aggregation still require built-in reducer names (`'avg'`,
80
+ `'p95'`, etc.). Custom `(values) => ...` functions don't have the
81
+ incremental add/remove machinery the live path needs and are
82
+ rejected at construction with a clear error pointing at the
83
+ `AggregateOutputMap` workaround. This is the established
84
+ recommendation: alias multiple built-ins to compose stats from
85
+ one source column.
86
+
87
+ ### Fixed
88
+
89
+ - **`partitionBy(...).rolling(..., options)` now accepts `options` as
90
+ a variable typed `LiveRollingOptions`, not just inline literals.**
91
+ Pre-fix, the four narrowed overloads on
92
+ `LivePartitionedSeries.rolling` and `LivePartitionedView.rolling`
93
+ required TS to see the `trigger` field's discriminator at the call
94
+ site — so a caller writing
95
+ `const opts: LiveRollingOptions = { trigger: Trigger.event() };
96
+ partitioned.rolling(window, mapping, opts);` got `TS2769 No
97
+ overload matches this call`. Pre-existing hole on the partitioned
98
+ surface; surfaced by the v0.13.0 Codex adversarial pass. Closed by
99
+ adding catch-all overloads that accept the broader
100
+ `LiveRollingOptions` and return the union of both trigger
101
+ branches; the four narrowed overloads above still match inline
102
+ literals first, so callers keep the precise return type when they
103
+ pass the trigger inline. Pinned with `test-d/types.test-d.ts`
104
+ coverage using both inline-literal and variable forms.
105
+
106
+ ### Tests
107
+
108
+ - 16 new tests in `test/LiveAggregateOutputMap.test.ts` covering:
109
+ flat live rolling/aggregate with the alias form, chained-view
110
+ rolling/aggregate, `LiveAggregation.rolling` and
111
+ `LiveRollingAggregation.aggregate` chainable accumulators,
112
+ per-partition rolling, synchronised partitioned rolling with
113
+ alias outputs, output-vs-source column-collision rejection on
114
+ the synced form, and explicit kind override.
115
+ - 2 existing tests updated (`LiveAggregation` and
116
+ `LiveRollingAggregation` "unknown column" → "unknown source column"
117
+ to match the shared helper's error string).
118
+ - Test count: 1060 (was 1044).
119
+
120
+ ### Docs
121
+
122
+ - `transforms/rolling.mdx`: live section now documents the
123
+ `AggregateOutputMap` shape with a band-chart example, plus a
124
+ callout that custom functions remain batch-only.
125
+ - `recipes/telemetry-reporting.mdx`: "Want multiple percentiles?"
126
+ section rewritten — the workaround note is gone, replaced with
127
+ the single-pass `{ p50, p95, p99 }` pattern.
128
+
129
+ [0.13.0]: https://github.com/pjm17971/pond-ts/compare/v0.12.1...v0.13.0
130
+
131
+ ## [0.12.1] — 2026-05-01
132
+
133
+ Strictly additive over v0.12.0. Closes the chained-view restriction
134
+ on synchronised partitioned rolling. The trigger option now applies
135
+ consistently across the entire `rolling()` surface — chained sugar
136
+ methods on the partitioned surface (`fill`, `diff`, `rate`,
137
+ `pctChange`, `cumulative`) no longer break it.
138
+
139
+ ### Changed
140
+
141
+ - **`partitionBy(col).<chained>().rolling(window, m, { trigger: Trigger.clock(seq) })` now works.**
142
+ Previously this threw a clear-but-restrictive error. The chain
143
+ factory runs per partition; the sync rolling subscribes to each
144
+ chain output instead of the raw partition events. Output schema is
145
+ unchanged (`[time, <partitionColumn>, ...mappingColumns]`); the
146
+ partition tag is set from the routing key, so chains that drop the
147
+ partition column still emit correctly.
148
+
149
+ Motivating example — per-host gap-filling before synchronised
150
+ ticks:
151
+
152
+ ```ts
153
+ const ticks = live
154
+ .partitionBy('host')
155
+ .fill({ cpu: 'hold' })
156
+ .rolling(
157
+ '1m',
158
+ { cpu: 'avg' },
159
+ { trigger: Trigger.clock(Sequence.every('200ms')) },
160
+ );
161
+ ```
162
+
163
+ Coherence-of-feature fix: the trigger concept now applies wherever
164
+ `rolling()` appears in the partitioned chain, not just in the
165
+ one-step case. Captured in the RFC's post-implementation notes
166
+ alongside the deferred-and-now-shipped section.
167
+
168
+ ### Tests
169
+
170
+ - 4 new tests in `test/Triggers.test.ts` covering chained-view sync
171
+ rolling: `fill().rolling(.., trigger)`, output schema, cross-
172
+ partition synchronisation through the chain, dispose semantics
173
+ through the chain, and replay-on-construction with the chain factory.
174
+ - 1 test removed (the throw-on-chained-view assertion that no longer
175
+ applies).
176
+ - Test count: 34 (was 30). Total core tests: 1043 (was 1039).
177
+
178
+ [0.12.1]: https://github.com/pjm17971/pond-ts/compare/v0.12.0...v0.12.1
179
+
14
180
  ## [0.12.0] — 2026-05-01
15
181
 
16
182
  The "triggers" release. Major redesign of how live accumulators
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pond-ts/react",
3
- "version": "0.12.0",
3
+ "version": "0.13.0",
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": {