@pond-ts/react 0.15.2 → 0.16.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 +192 -1
  2. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -7,10 +7,199 @@ 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.15.2...HEAD
10
+ [Unreleased]: https://github.com/pjm17971/pond-ts/compare/v0.16.1...HEAD
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [0.16.1] — 2026-05-06
15
+
16
+ Patch wave addressing one ergonomic gap surfaced by the gRPC
17
+ experiment ([pond-grpc-experiment#29](https://github.com/pjm17971/pond-grpc-experiment/pull/29))
18
+ plus the v0.16.0 docs deploy that broke since v0.15.2.
19
+
20
+ ### Added
21
+
22
+ - **`PartitionedTimeSeries.aggregate(...)` and `.rolling(...)` now
23
+ auto-inject the partition column into the user's mapping**
24
+ ([#128](https://github.com/pjm17971/pond-ts/pull/128)). The
25
+ natural shape just works:
26
+
27
+ ```ts
28
+ series
29
+ .partitionBy('host')
30
+ .aggregate(Sequence.every('600ms'), { cpu_avg: 'avg' });
31
+ ```
32
+
33
+ Pre-fix this threw `column "host" not in schema` at the rewrap
34
+ step because the user's mapping didn't carry the partition
35
+ column through; users had to add `host: 'first'` mechanically
36
+ to every partitioned-aggregate call. Pond now adds it
37
+ automatically — `'first'` is by-construction-correct since
38
+ every row in a single partition shares that column's value.
39
+ User-supplied mappings for the partition column win (auto-
40
+ inject is a no-op when the user has already opted in).
41
+ Composite partitions (`partitionBy(['host', 'region'])`)
42
+ auto-inject every partition column. Strictly additive — the
43
+ pre-fix workaround pattern still works unchanged.
44
+
45
+ ### Fixed
46
+
47
+ - **Docs deploy workflow unblocked**
48
+ ([#126](https://github.com/pjm17971/pond-ts/pull/126)). Has
49
+ been failing since v0.15.2 with `Cannot find name
50
+ 'queueMicrotask'` — TypeDoc runs the same tsconfig as the
51
+ npm-publish path but from a different cwd, where `@types/node`
52
+ doesn't resolve. Fixed via a one-line ambient declaration in
53
+ `LiveReduce.ts`. No runtime change; `queueMicrotask` is still
54
+ the host-provided global it always was.
55
+
56
+ ### Changed
57
+
58
+ - **Updated `LiveSeries` tool comparisons in the docs**
59
+ ([#127](https://github.com/pjm17971/pond-ts/pull/127)).
60
+ Tightened the Beam/Flink, PondJS, and pandas comparison tables
61
+ to be technically accurate. Doc prose only; no code change.
62
+
63
+ ### Notes
64
+
65
+ - **Captured `@pond-ts/charts` design constraints in PLAN.md**
66
+ ([#128](https://github.com/pjm17971/pond-ts/pull/128)). The
67
+ gRPC experiment's M3.5 friction note hit Recharts' SVG render
68
+ cliff at firehose loads (~75-80k SVG nodes per render, ~1 fps
69
+ at 10 hosts × 70k events/s). Four constraints from real
70
+ workload now baked into the plan so the eventual extraction
71
+ starts with the answer key — not new code, just durable
72
+ design capture.
73
+
74
+ ## [0.16.0] — 2026-05-06
75
+
76
+ Live-API ergonomic wave. Four PRs:
77
+ [#122](https://github.com/pjm17971/pond-ts/pull/122) (buffer-as-window
78
+ Tier 1), [#123](https://github.com/pjm17971/pond-ts/pull/123)
79
+ (`stats()` accessor), [#124](https://github.com/pjm17971/pond-ts/pull/124)
80
+ (`history` option + compile-time fused uniqueness),
81
+ [#125](https://github.com/pjm17971/pond-ts/pull/125) (Tier 2 query
82
+ primitives). Strictly additive surface — no public-API removals or
83
+ narrowings.
84
+
85
+ ### Added
86
+
87
+ - **`live.reduce(mapping, opts?)`** on `LiveSeries` and `LiveView`
88
+ — streaming reduce over the source's current buffer. Mirrors
89
+ `series.reduce(mapping)` from batch but reactive: per-event
90
+ `add`, per-eviction `remove`, microtask-deferred trigger
91
+ emission so retention has run before the snapshot. Closes the
92
+ buffer-as-window persona's biggest ergonomic gap.
93
+ - **`live.timeRange()`** on `LiveSeries` and `LiveView` — O(1)
94
+ temporal extent of the current buffer (`undefined` when empty).
95
+ - **`live.eventRate()`** on `LiveSeries` and `LiveView` — O(1)
96
+ events-per-second over the buffer's time span (zero when fewer
97
+ than two events). Convenience over the existing
98
+ `view.eventRate()` shape; no window argument required.
99
+ - **`live.count()`** on `LiveSeries` (alias for `length`) for
100
+ parity with `LiveView.count()` and chainable composition with
101
+ `eventRate()`.
102
+ - **`stats()` accessor on every live accumulator/series.** Per-class
103
+ shapes, all returning a plain record (cumulative integer counters
104
+ + current-state fields):
105
+
106
+ | Class | Shape |
107
+ |---|---|
108
+ | LiveSeries | `{ ingested, evicted, rejected, length, earliestTs?, latestTs? }` |
109
+ | LiveRollingAggregation | `{ eventsObserved, evictions, emissions, windowSize }` |
110
+ | LiveFusedRolling | `{ eventsObserved, evictions, emissions, windowSize, windowsCount }` |
111
+ | LiveAggregation | `{ eventsObserved, bucketsClosed, openBuckets, openBucketStart? }` |
112
+ | LiveReduce | `{ eventsObserved, evictions, emissions, bufferSize }` |
113
+ | LivePartitionedSeries | `{ partitions, eventsRouted }` |
114
+ | LivePartitionedSyncRolling | `{ partitions, eventsObserved, emissions, windowSize }` |
115
+ | LivePartitionedFusedRolling | `{ partitions, eventsObserved, emissions, windowSize, windowsCount }` |
116
+
117
+ Per-event cost: ~1-3 integer increments in already-existing
118
+ handlers. `stats()` itself is O(1) — or O(partitions) for the
119
+ max-across-partitions `windowSize` on partitioned variants.
120
+ Polling-based by design — wall-clock timers inside pond would
121
+ break the data-is-the-clock invariant.
122
+
123
+ - **`history: false | RetentionPolicy` option on
124
+ `LiveRollingAggregation` and `LiveFusedRolling`** (and
125
+ partitioned variants — threaded through
126
+ `LivePartitionedSeries.rolling` end-to-end). Controls how much
127
+ of the rolling's emitted history the accumulator keeps in its
128
+ own output buffer (the one read by `length` / `at(i)`). Default
129
+ `true` preserves current behavior; `false` skips the push
130
+ entirely (`'event'` listeners and `value()` still work, but
131
+ `length` stays at 0); `RetentionPolicy` (`{ maxEvents?, maxAge? }`)
132
+ caps the buffer using the same shape as `LiveSeries.retention`.
133
+ Stricter validation: rejects 0, negative, or non-integer
134
+ `maxEvents`; `Infinity` is the documented "no cap" sentinel.
135
+
136
+ - **Compile-time uniqueness check on fused output columns**
137
+ (`FusedMappingValid<FM>`). Two windows declaring the same
138
+ output name now fail at the call site with a branded error
139
+ type naming the conflict. Wired into all four fused-rolling
140
+ overloads (LiveSeries, LiveView, root + view
141
+ LivePartitionedSeries). Runtime check still in place.
142
+
143
+ - **Tier 2 query primitives on `LiveSeries` and `LiveView`** —
144
+ pure parity additions mirroring `TimeSeries`:
145
+ - `find(pred)`, `some(pred)`, `every(pred)` — O(N) predicate query
146
+ - `includesKey(key)`, `bisect(key)`, `atOrBefore(key)`,
147
+ `atOrAfter(key)` — O(log N) binary search on the sorted buffer
148
+
149
+ Use cases: "is there already an event with key K?" / "what was
150
+ the most recent event before time T?" Both come up in dashboard
151
+ patterns where the live buffer IS the working set.
152
+
153
+ - **`KeyLike` type** exported from the package root (re-exported
154
+ from `TimeSeries`). Accepts `EventKey | TimestampInput |
155
+ TimeRangeInput | IntervalInput`; normalised by the new query
156
+ primitives.
157
+
158
+ - **`DurationLiteral` and `DurationUnit` types** extracted from
159
+ `utils/duration.ts` and exported. Same shape as before, just
160
+ named.
161
+
162
+ - **Concrete return types from partitioned rolling overloads.**
163
+ `LivePartitionedSeries.rolling` and `LivePartitionedView.rolling`
164
+ clock-trigger and fused-mapping overloads now return the concrete
165
+ `LivePartitionedSyncRolling` / `LivePartitionedFusedRolling`
166
+ classes (instead of bare `LiveSource<...>`), exposing `stats()`
167
+ to callers without a cast. Strictly additive — concrete classes
168
+ implement `LiveSource` plus `stats()`.
169
+
170
+ ### Changed
171
+
172
+ - **`LiveSeries.clear()`** now increments the `evicted` counter
173
+ on `stats()` to match the existing `'evict'` listener fan-out.
174
+ Previously cleared the buffer and fired listeners but didn't
175
+ update the counter.
176
+ - **`LiveSeries` insertion comparator** delegates to
177
+ `EventKey.compare` (was previously `begin/end` only). Affects
178
+ interval-keyed series with same-span / different-value
179
+ intervals: previously stored in arrival order — and broke
180
+ `bisect`/`includesKey` queries — now stored in value-ascending
181
+ order. Time-keyed and timeRange-keyed series unaffected.
182
+ - **`LiveView.map(fn)` runtime check** rejects re-keying maps
183
+ that produce non-monotonic outputs. Throws `ValidationError`
184
+ at append time rather than silently breaking the view's
185
+ sorted-buffer invariant (which Tier 2 query primitives rely
186
+ on). Sane transforms (data-only maps, monotonic time-shifts)
187
+ unaffected.
188
+ - **`LiveAggregationOptions.grace`** type tightened from
189
+ `DurationInput | \`${number}${unit}\`` (redundant union) to
190
+ just `DurationInput`. No behavioral change.
191
+
192
+ ### Notes
193
+
194
+ - React package (`@pond-ts/react`) version-bumped lock-step; no
195
+ hook surface changes in this release. New core hooks
196
+ (`useLiveReduce`, `useStats`, optional-window `useEventRate`)
197
+ are queued for a follow-up — see PLAN.md for the design.
198
+ - Codex caught real bugs on every Layer-2-reviewed PR in this
199
+ wave (1 HIGH + 1 MEDIUM on PR #123, 1 HIGH + 1 MEDIUM on
200
+ PR #124, 2 MEDIUM on PR #125). The Layer 2 + Codex two-pass
201
+ protocol earned its keep again.
202
+
14
203
  ## [0.15.2] — 2026-05-06
15
204
 
16
205
  Performance fix for live rolling at firehose rates. The gRPC
@@ -108,6 +297,8 @@ compaction); any downstream code reading `#entries` directly would
108
297
  break, but those fields are private. Public APIs and types are
109
298
  unchanged.
110
299
 
300
+ [0.16.1]: https://github.com/pjm17971/pond-ts/compare/v0.16.0...v0.16.1
301
+ [0.16.0]: https://github.com/pjm17971/pond-ts/compare/v0.15.2...v0.16.0
111
302
  [0.15.2]: https://github.com/pjm17971/pond-ts/compare/v0.15.1...v0.15.2
112
303
 
113
304
  ## [0.15.1] — 2026-05-05
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pond-ts/react",
3
- "version": "0.15.2",
3
+ "version": "0.16.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.15.0",
34
+ "pond-ts": "^0.16.0",
35
35
  "react": "^18.0.0 || ^19.0.0"
36
36
  },
37
37
  "devDependencies": {