@pond-ts/react 0.11.8 → 0.12.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.
- package/CHANGELOG.md +184 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,10 +7,192 @@ 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.
|
|
10
|
+
[Unreleased]: https://github.com/pjm17971/pond-ts/compare/v0.12.1...HEAD
|
|
11
11
|
|
|
12
12
|
## [Unreleased]
|
|
13
13
|
|
|
14
|
+
## [0.12.1] — 2026-05-01
|
|
15
|
+
|
|
16
|
+
Strictly additive over v0.12.0. Closes the chained-view restriction
|
|
17
|
+
on synchronised partitioned rolling. The trigger option now applies
|
|
18
|
+
consistently across the entire `rolling()` surface — chained sugar
|
|
19
|
+
methods on the partitioned surface (`fill`, `diff`, `rate`,
|
|
20
|
+
`pctChange`, `cumulative`) no longer break it.
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
|
|
24
|
+
- **`partitionBy(col).<chained>().rolling(window, m, { trigger: Trigger.clock(seq) })` now works.**
|
|
25
|
+
Previously this threw a clear-but-restrictive error. The chain
|
|
26
|
+
factory runs per partition; the sync rolling subscribes to each
|
|
27
|
+
chain output instead of the raw partition events. Output schema is
|
|
28
|
+
unchanged (`[time, <partitionColumn>, ...mappingColumns]`); the
|
|
29
|
+
partition tag is set from the routing key, so chains that drop the
|
|
30
|
+
partition column still emit correctly.
|
|
31
|
+
|
|
32
|
+
Motivating example — per-host gap-filling before synchronised
|
|
33
|
+
ticks:
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
const ticks = live
|
|
37
|
+
.partitionBy('host')
|
|
38
|
+
.fill({ cpu: 'hold' })
|
|
39
|
+
.rolling(
|
|
40
|
+
'1m',
|
|
41
|
+
{ cpu: 'avg' },
|
|
42
|
+
{ trigger: Trigger.clock(Sequence.every('200ms')) },
|
|
43
|
+
);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Coherence-of-feature fix: the trigger concept now applies wherever
|
|
47
|
+
`rolling()` appears in the partitioned chain, not just in the
|
|
48
|
+
one-step case. Captured in the RFC's post-implementation notes
|
|
49
|
+
alongside the deferred-and-now-shipped section.
|
|
50
|
+
|
|
51
|
+
### Tests
|
|
52
|
+
|
|
53
|
+
- 4 new tests in `test/Triggers.test.ts` covering chained-view sync
|
|
54
|
+
rolling: `fill().rolling(.., trigger)`, output schema, cross-
|
|
55
|
+
partition synchronisation through the chain, dispose semantics
|
|
56
|
+
through the chain, and replay-on-construction with the chain factory.
|
|
57
|
+
- 1 test removed (the throw-on-chained-view assertion that no longer
|
|
58
|
+
applies).
|
|
59
|
+
- Test count: 34 (was 30). Total core tests: 1043 (was 1039).
|
|
60
|
+
|
|
61
|
+
[0.12.1]: https://github.com/pjm17971/pond-ts/compare/v0.12.0...v0.12.1
|
|
62
|
+
|
|
63
|
+
## [0.12.0] — 2026-05-01
|
|
64
|
+
|
|
65
|
+
The "triggers" release. Major redesign of how live accumulators
|
|
66
|
+
control emission cadence — `Trigger` is now a first-class concept
|
|
67
|
+
shaped by two converging real-world use cases (synchronised
|
|
68
|
+
partitioned tick aggregation in the gRPC pipeline experiment,
|
|
69
|
+
sequence-sampled rolling in webapp telemetry).
|
|
70
|
+
|
|
71
|
+
Two correctness audits before publish: a Layer 2 Claude review
|
|
72
|
+
(column collision, dispose, late-spawn, peer-dep) and a Codex
|
|
73
|
+
adversarial review (quiet-partition stale samples, pre-existing
|
|
74
|
+
data replay at construction, spawn-listener cleanup). All findings
|
|
75
|
+
fixed and pinned with regression tests. 1039 / 1039 tests pass.
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
|
|
79
|
+
- **Trigger as a first-class concept.** A new `Trigger` factory
|
|
80
|
+
exposed at the package root lets `LiveRollingAggregation` switch
|
|
81
|
+
emission cadence without changing any other shape:
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
import { LiveSeries, Sequence, Trigger } from 'pond-ts';
|
|
85
|
+
|
|
86
|
+
// Webapp telemetry: rolling 1m p95, emit on every 30 s of event-time
|
|
87
|
+
const rolling = timings.rolling(
|
|
88
|
+
'1m',
|
|
89
|
+
{ latency: 'p95' },
|
|
90
|
+
{ trigger: Trigger.clock(Sequence.every('30s')) },
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
rolling.on('event', (e) =>
|
|
94
|
+
fetch('/api/telemetry', { method: 'POST', body: JSON.stringify(e.data()) }),
|
|
95
|
+
);
|
|
96
|
+
rolling.value(); // current rolling-window snapshot, independent of trigger
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Two trigger variants in this release:
|
|
100
|
+
- **`Trigger.event()`** — per-event emission. Default; the historical
|
|
101
|
+
behavior of `LiveRollingAggregation` when no trigger is specified.
|
|
102
|
+
- **`Trigger.clock(sequence)`** — sequence-triggered emission. One
|
|
103
|
+
snapshot fires when a source event crosses an epoch-aligned
|
|
104
|
+
boundary of the (fixed-step) `Sequence`. Output keyed at boundary
|
|
105
|
+
instants. Calendar sequences are rejected upfront.
|
|
106
|
+
|
|
107
|
+
Future variants (`Trigger.count(n)`, custom predicates, compound
|
|
108
|
+
triggers) are reserved but not yet shipped.
|
|
109
|
+
|
|
110
|
+
- **Synchronised partitioned rolling.** `LivePartitionedSeries.rolling`
|
|
111
|
+
now accepts a clock trigger. The output is a
|
|
112
|
+
`LiveSource<RowSchema>` whose schema is `[time, <partitionColumn>,
|
|
113
|
+
...mappingColumns]`; on every boundary crossing, one event fires
|
|
114
|
+
per known partition, all sharing the same boundary timestamp.
|
|
115
|
+
Synchronised across partitions by construction (the bucket index is
|
|
116
|
+
shared, not per-partition).
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
// Dashboard tick aggregation: 100 hosts, 200ms cadence
|
|
120
|
+
const ticks = live
|
|
121
|
+
.partitionBy('host')
|
|
122
|
+
.rolling(
|
|
123
|
+
'1m',
|
|
124
|
+
{ cpu: 'avg' },
|
|
125
|
+
{ trigger: Trigger.clock(Sequence.every('200ms')) },
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
ticks.on('event', (e) => {
|
|
129
|
+
// e.begin() === <boundary timestamp>, same for every host this tick
|
|
130
|
+
// e.get('host') === 'api-1' | 'api-2' | …
|
|
131
|
+
// e.get('cpu') === <rolling avg for that host>
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Restricted to direct-after-`partitionBy` in this release: chained
|
|
136
|
+
sugar (`partitionBy(c).fill(...).rolling(...)`) rejects clock
|
|
137
|
+
triggers with a clear error. Lifts in a future release once a real
|
|
138
|
+
use case appears.
|
|
139
|
+
|
|
140
|
+
Closes the gRPC experiment's M3.5 dashboard friction note (the
|
|
141
|
+
hand-rolled `HostAggregator` becomes ~10 lines of pond code).
|
|
142
|
+
|
|
143
|
+
### Removed (breaking — pre-1.0)
|
|
144
|
+
|
|
145
|
+
- **`LiveSequenceRollingAggregation`** class deleted. Its capability
|
|
146
|
+
is preserved as `LiveRollingAggregation` with
|
|
147
|
+
`{ trigger: Trigger.clock(sequence) }`. Migration: replace
|
|
148
|
+
`live.rolling('1m', m).sample(seq)` with
|
|
149
|
+
`live.rolling('1m', m, { trigger: Trigger.clock(seq) })`. Single
|
|
150
|
+
rolling object now serves both backend reporting and direct
|
|
151
|
+
`.value()` reads (no separate sampler reference).
|
|
152
|
+
- **`.sample(sequence)`** method removed from `LiveRollingAggregation`.
|
|
153
|
+
Use the trigger option above.
|
|
154
|
+
|
|
155
|
+
### Changed
|
|
156
|
+
|
|
157
|
+
- **`LiveRollingOptions`** gains an optional `trigger?: Trigger`
|
|
158
|
+
field. Default behavior (no `trigger` specified) is unchanged from
|
|
159
|
+
v0.11.x — per-event emission. Backward compatible for everyone
|
|
160
|
+
who didn't use `.sample()`.
|
|
161
|
+
|
|
162
|
+
### Performance
|
|
163
|
+
|
|
164
|
+
- New benchmark `scripts/perf-triggers.mjs` covers both
|
|
165
|
+
non-partitioned and synchronised partitioned cases. Headline numbers
|
|
166
|
+
on a current MacBook Pro:
|
|
167
|
+
- Non-partitioned: clock(30s) ~50% faster than per-event baseline
|
|
168
|
+
(emission is rarer); clock(1s) similar.
|
|
169
|
+
- Synchronised partitioned (100 hosts, 30k events at realistic
|
|
170
|
+
rates): ~300 ns/emission at 200ms cadence; +205% over per-
|
|
171
|
+
partition baseline at the high end. Well within budget for the
|
|
172
|
+
motivating dashboard use case.
|
|
173
|
+
|
|
174
|
+
### Notes
|
|
175
|
+
|
|
176
|
+
- **`docs/rfcs/triggers.md`** captures the full design rationale,
|
|
177
|
+
the four sign-off questions, and the migration plan. Read this if
|
|
178
|
+
you want the "why this shape" context.
|
|
179
|
+
|
|
180
|
+
### Known limitations
|
|
181
|
+
|
|
182
|
+
- **Synchronised partitioned rolling output type is loose** —
|
|
183
|
+
`LiveSource<SeriesSchema>` rather than a schema-narrowed shape.
|
|
184
|
+
Runtime schema is correct; only static types widen. Tightening is
|
|
185
|
+
queued for a follow-up release.
|
|
186
|
+
- **Synchronised partitioned rolling rejects column-name collisions**
|
|
187
|
+
between the partition column and any reducer-output column at
|
|
188
|
+
construction (e.g. `partitionBy('cpu').rolling('1m', { cpu: 'avg' }, { trigger })`).
|
|
189
|
+
Rename the reducer output (once `AggregateOutputMap` lands on live
|
|
190
|
+
rolling) or partition by a different column.
|
|
191
|
+
- **Late-spawn partitions only appear in ticks after their first event
|
|
192
|
+
arrives.** A partition unknown to the sync source contributes no
|
|
193
|
+
row to the current tick. Use `partitionBy(col, { groups: [...] })`
|
|
194
|
+
to eagerly include partitions from construction.
|
|
195
|
+
|
|
14
196
|
## [0.11.8] — 2026-04-30
|
|
15
197
|
|
|
16
198
|
### Added
|
|
@@ -61,6 +243,7 @@ type-level changes; patch bumps are strictly additive.
|
|
|
61
243
|
frontend-collection → backend-summary pattern using `.sample()`,
|
|
62
244
|
plus the React in-app display via `useLiveQuery`.
|
|
63
245
|
|
|
246
|
+
[0.12.0]: https://github.com/pjm17971/pond-ts/compare/v0.11.8...v0.12.0
|
|
64
247
|
[0.11.8]: https://github.com/pjm17971/pond-ts/compare/v0.11.7...v0.11.8
|
|
65
248
|
|
|
66
249
|
## [0.11.7] — 2026-04-29
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pond-ts/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.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.
|
|
34
|
+
"pond-ts": "^0.12.0",
|
|
35
35
|
"react": "^18.0.0 || ^19.0.0"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|