@pond-ts/react 0.16.0 → 0.17.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 +165 -15
  2. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -7,10 +7,158 @@ 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.16.0...HEAD
10
+ [Unreleased]: https://github.com/pjm17971/pond-ts/compare/v0.17.0...HEAD
11
11
 
12
12
  ## [Unreleased]
13
13
 
14
+ ## [0.17.0] — 2026-05-08
15
+
16
+ `sample({...})` operator wave: bounded-memory stream thinning, surfaced
17
+ by the gRPC experiment's M3.5 finish-line work
18
+ ([friction note](https://github.com/pjm17971/pond-grpc-experiment/blob/main/friction-notes/rfcs/bounded-memory-sampling.md)
19
+ with measured firehose numbers). Decouples downstream baseline window
20
+ length from event rate — at firehose rates × stride 10, `sd / sqrt(N)`
21
+ standard error stays well below per-event noise while a 5-minute
22
+ baseline that wouldn't fit in a Node heap un-sampled does at
23
+ stride 10. PR [#129](https://github.com/pjm17971/pond-ts/pull/129).
24
+
25
+ ### Added
26
+
27
+ - **`series.sample({ stride | reservoir })`** on `TimeSeries` and
28
+ `PartitionedTimeSeries` — single-pass thinning that keeps the
29
+ `TimeSeries<S>` schema. Stride is deterministic 1-in-N
30
+ (`{ stride: N }`); reservoir is random K-of-N via single-pass
31
+ [Vitter's Algorithm R](https://en.wikipedia.org/wiki/Reservoir_sampling#Simple:_Algorithm_R)
32
+ (`{ reservoir: { size: K } }`), sorted by key on output to preserve
33
+ the chronological invariant. The canonical visualization shape:
34
+
35
+ ```ts
36
+ series.sample({ reservoir: { size: 500 } }).toRows();
37
+ ```
38
+
39
+ 500 uncorrelated points drawn uniformly from the source — no
40
+ `aggregate(seq, ...)` grid collapse, no regular-spacing artifact,
41
+ fixed point count regardless of source size. Per-partition state on
42
+ `PartitionedTimeSeries.sample(...)` — each partition gets its own
43
+ K-event reservoir or stride counter.
44
+
45
+ - **`live.sample({ stride })`** on `LiveSeries`, `LiveView`,
46
+ `LivePartitionedSeries`, `LivePartitionedView` — closure-captured
47
+ counter inside a `LiveView<S>`, so the chainable surface (`filter`,
48
+ `rolling`, `reduce`, `select`, `map`, `diff`, `rate`, `cumulative`,
49
+ `fill`) is immediately available downstream of the sample. The
50
+ bounded-memory firehose pattern:
51
+
52
+ ```ts
53
+ live.partitionBy('host').sample({ stride: 10 }).rolling('5m', mapping);
54
+ ```
55
+
56
+ Each host's stream is thinned 1-in-10 before flowing into a per-host
57
+ 5m rolling window. `live.stats().ingested` and `live.on('batch', cb)`
58
+ are upstream of any `.sample(...)` op — they continue counting true
59
+ throughput; only consumers downstream see the thinned stream.
60
+
61
+ - **Sampling docs page** at
62
+ [`pond-ts/transforms/sampling`](https://pjm17971.github.io/pond-ts/docs/pond-ts/transforms/sampling/)
63
+ covering when-to-use-which decision table, both strategies, the
64
+ visualization shape, multi-entity considerations, and a forward-link
65
+ to the live counterpart. New `## Sampling: bounded-memory thinning`
66
+ section in
67
+ [Live transforms](https://pjm17971.github.io/pond-ts/docs/pond-ts/live/live-transforms#sampling).
68
+
69
+ ### Deferred
70
+
71
+ - **Live-side reservoir sampling** is queued for v0.18.0+. Algorithm R's
72
+ random-slot replacement produces non-prefix evictions, but the existing
73
+ live-eviction protocol (`'evict'` event + cutoff-based mirroring in
74
+ `LiveView`) assumes prefix evictions only. Bridging needs an exact-
75
+ removal eviction channel — arriving with the streaming RFC's
76
+ `LiveChange` model (Phase 4.5 milestone A). For visualization-shaped
77
+ reservoir today, materialize via `live.toTimeSeries().sample({ reservoir })`.
78
+
79
+ ### Notes
80
+
81
+ - **Multi-entity bias trap** is documented in JSDoc on the pre-partition
82
+ sites (`LiveSeries.sample`, `LiveView.sample`) with the
83
+ `partitionBy(...).sample(...)` recommendation, matching the existing
84
+ convention for `rolling` / `aggregate` / `fill` / `diff` / `rate` /
85
+ `cumulative` / `pctChange` / `reduce`. An earlier iteration of #129
86
+ shipped a type-level `unsafeGlobal: true` token; pulled during review
87
+ for consistency with how every other stateful live operator handles
88
+ the same multi-entity consideration. Token-of-the-week novelty was
89
+ the wrong shape; the doc warning is the same answer the other
90
+ operators already give.
91
+
92
+ - **Legacy `rolling.sample(seq)` doc references removed.** Pre-v0.12
93
+ pond exposed `LiveRollingAggregation.sample(sequence)` as a separate
94
+ method (deleted in v0.12.0, replaced by `Trigger.every`). Active doc
95
+ references in `pond-ts/live/triggering.mdx`,
96
+ `pond-ts/transforms/alignment.mdx`, `pond-ts/transforms/rolling.mdx`,
97
+ and `pond-ts/live/live-transforms.mdx` removed to eliminate the
98
+ naming-collision confusion now that `series.sample({ stride | reservoir })`
99
+ is a real but completely unrelated operator. Historical record
100
+ preserved in PLAN.md, the v0.11.8 CHANGELOG entry, and the triggers RFC.
101
+
102
+ ## [0.16.1] — 2026-05-06
103
+
104
+ Patch wave addressing one ergonomic gap surfaced by the gRPC
105
+ experiment ([pond-grpc-experiment#29](https://github.com/pjm17971/pond-grpc-experiment/pull/29))
106
+ plus the v0.16.0 docs deploy that broke since v0.15.2.
107
+
108
+ ### Added
109
+
110
+ - **`PartitionedTimeSeries.aggregate(...)` and `.rolling(...)` now
111
+ auto-inject the partition column into the user's mapping**
112
+ ([#128](https://github.com/pjm17971/pond-ts/pull/128)). The
113
+ natural shape just works:
114
+
115
+ ```ts
116
+ series
117
+ .partitionBy('host')
118
+ .aggregate(Sequence.every('600ms'), { cpu_avg: 'avg' });
119
+ ```
120
+
121
+ Pre-fix this threw `column "host" not in schema` at the rewrap
122
+ step because the user's mapping didn't carry the partition
123
+ column through; users had to add `host: 'first'` mechanically
124
+ to every partitioned-aggregate call. Pond now adds it
125
+ automatically — `'first'` is by-construction-correct since
126
+ every row in a single partition shares that column's value.
127
+ User-supplied mappings for the partition column win (auto-
128
+ inject is a no-op when the user has already opted in).
129
+ Composite partitions (`partitionBy(['host', 'region'])`)
130
+ auto-inject every partition column. Strictly additive — the
131
+ pre-fix workaround pattern still works unchanged.
132
+
133
+ ### Fixed
134
+
135
+ - **Docs deploy workflow unblocked**
136
+ ([#126](https://github.com/pjm17971/pond-ts/pull/126)). Has
137
+ been failing since v0.15.2 with `Cannot find name
138
+ 'queueMicrotask'` — TypeDoc runs the same tsconfig as the
139
+ npm-publish path but from a different cwd, where `@types/node`
140
+ doesn't resolve. Fixed via a one-line ambient declaration in
141
+ `LiveReduce.ts`. No runtime change; `queueMicrotask` is still
142
+ the host-provided global it always was.
143
+
144
+ ### Changed
145
+
146
+ - **Updated `LiveSeries` tool comparisons in the docs**
147
+ ([#127](https://github.com/pjm17971/pond-ts/pull/127)).
148
+ Tightened the Beam/Flink, PondJS, and pandas comparison tables
149
+ to be technically accurate. Doc prose only; no code change.
150
+
151
+ ### Notes
152
+
153
+ - **Captured `@pond-ts/charts` design constraints in PLAN.md**
154
+ ([#128](https://github.com/pjm17971/pond-ts/pull/128)). The
155
+ gRPC experiment's M3.5 friction note hit Recharts' SVG render
156
+ cliff at firehose loads (~75-80k SVG nodes per render, ~1 fps
157
+ at 10 hosts × 70k events/s). Four constraints from real
158
+ workload now baked into the plan so the eventual extraction
159
+ starts with the answer key — not new code, just durable
160
+ design capture.
161
+
14
162
  ## [0.16.0] — 2026-05-06
15
163
 
16
164
  Live-API ergonomic wave. Four PRs:
@@ -41,17 +189,17 @@ narrowings.
41
189
  `eventRate()`.
42
190
  - **`stats()` accessor on every live accumulator/series.** Per-class
43
191
  shapes, all returning a plain record (cumulative integer counters
44
- + current-state fields):
45
-
46
- | Class | Shape |
47
- |---|---|
48
- | LiveSeries | `{ ingested, evicted, rejected, length, earliestTs?, latestTs? }` |
49
- | LiveRollingAggregation | `{ eventsObserved, evictions, emissions, windowSize }` |
50
- | LiveFusedRolling | `{ eventsObserved, evictions, emissions, windowSize, windowsCount }` |
51
- | LiveAggregation | `{ eventsObserved, bucketsClosed, openBuckets, openBucketStart? }` |
52
- | LiveReduce | `{ eventsObserved, evictions, emissions, bufferSize }` |
53
- | LivePartitionedSeries | `{ partitions, eventsRouted }` |
54
- | LivePartitionedSyncRolling | `{ partitions, eventsObserved, emissions, windowSize }` |
192
+ - current-state fields):
193
+
194
+ | Class | Shape |
195
+ | --------------------------- | --------------------------------------------------------------------- |
196
+ | LiveSeries | `{ ingested, evicted, rejected, length, earliestTs?, latestTs? }` |
197
+ | LiveRollingAggregation | `{ eventsObserved, evictions, emissions, windowSize }` |
198
+ | LiveFusedRolling | `{ eventsObserved, evictions, emissions, windowSize, windowsCount }` |
199
+ | LiveAggregation | `{ eventsObserved, bucketsClosed, openBuckets, openBucketStart? }` |
200
+ | LiveReduce | `{ eventsObserved, evictions, emissions, bufferSize }` |
201
+ | LivePartitionedSeries | `{ partitions, eventsRouted }` |
202
+ | LivePartitionedSyncRolling | `{ partitions, eventsObserved, emissions, windowSize }` |
55
203
  | LivePartitionedFusedRolling | `{ partitions, eventsObserved, emissions, windowSize, windowsCount }` |
56
204
 
57
205
  Per-event cost: ~1-3 integer increments in already-existing
@@ -92,7 +240,7 @@ narrowings.
92
240
 
93
241
  - **`KeyLike` type** exported from the package root (re-exported
94
242
  from `TimeSeries`). Accepts `EventKey | TimestampInput |
95
- TimeRangeInput | IntervalInput`; normalised by the new query
243
+ TimeRangeInput | IntervalInput`; normalised by the new query
96
244
  primitives.
97
245
 
98
246
  - **`DurationLiteral` and `DurationUnit` types** extracted from
@@ -126,8 +274,8 @@ narrowings.
126
274
  on). Sane transforms (data-only maps, monotonic time-shifts)
127
275
  unaffected.
128
276
  - **`LiveAggregationOptions.grace`** type tightened from
129
- `DurationInput | \`${number}${unit}\`` (redundant union) to
130
- just `DurationInput`. No behavioral change.
277
+ `DurationInput | \`${number}${unit}\``(redundant union) to
278
+ just`DurationInput`. No behavioral change.
131
279
 
132
280
  ### Notes
133
281
 
@@ -237,6 +385,8 @@ compaction); any downstream code reading `#entries` directly would
237
385
  break, but those fields are private. Public APIs and types are
238
386
  unchanged.
239
387
 
388
+ [0.17.0]: https://github.com/pjm17971/pond-ts/compare/v0.16.1...v0.17.0
389
+ [0.16.1]: https://github.com/pjm17971/pond-ts/compare/v0.16.0...v0.16.1
240
390
  [0.16.0]: https://github.com/pjm17971/pond-ts/compare/v0.15.2...v0.16.0
241
391
  [0.15.2]: https://github.com/pjm17971/pond-ts/compare/v0.15.1...v0.15.2
242
392
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pond-ts/react",
3
- "version": "0.16.0",
3
+ "version": "0.17.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.16.0",
34
+ "pond-ts": "^0.17.0",
35
35
  "react": "^18.0.0 || ^19.0.0"
36
36
  },
37
37
  "devDependencies": {