@pond-ts/react 0.21.0 → 0.22.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 +57 -1
  2. package/package.json +2 -2
package/CHANGELOG.md CHANGED
@@ -7,7 +7,8 @@ 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.21.0...HEAD
10
+ [Unreleased]: https://github.com/pjm17971/pond-ts/compare/v0.22.0...HEAD
11
+ [0.22.0]: https://github.com/pjm17971/pond-ts/compare/v0.21.0...v0.22.0
11
12
  [0.21.0]: https://github.com/pjm17971/pond-ts/compare/v0.20.0...v0.21.0
12
13
  [0.20.0]: https://github.com/pjm17971/pond-ts/compare/v0.19.0...v0.20.0
13
14
  [0.19.0]: https://github.com/pjm17971/pond-ts/compare/v0.18.0...v0.19.0
@@ -15,6 +16,61 @@ type-level changes; patch bumps are strictly additive.
15
16
 
16
17
  ## [Unreleased]
17
18
 
19
+ ## [0.22.0] — 2026-06-12
20
+
21
+ ### Changed
22
+
23
+ - **`asTime` / `asTimeRange` / `asInterval` are now column-native.** They
24
+ reinterpret the key's kind (a "rekey") straight off the existing key's
25
+ `begin` / `end` buffers instead of materializing events — value columns pass
26
+ through by reference. `asTimeRange` and `asTime` with `begin` / `end` reuse
27
+ the key buffer zero-copy (≈ **9×** faster on a build → rekey → read pipeline);
28
+ `asTime({ at: 'center' })` adds one midpoint pass; `asInterval` builds the
29
+ label column (string → `StringColumn`, number → `Float64Column`, inferred
30
+ from the first label and required consistent across rows). `asTime` with
31
+ `center` / `end` throws if anchoring a source with overlapping extents would
32
+ produce a non-monotonic time axis (preserving the prior validation — `begin`
33
+ is always sorted and is exempt).
34
+ - **Breaking: `asInterval`'s label function now receives the interval's
35
+ `TimeRange` (its `[begin, end]` extent) and index — not the whole `Event`.**
36
+ The canonical form is unchanged: `series.asInterval(range => range.begin())`
37
+ works exactly as before (both `Event` and `TimeRange` expose `begin()` /
38
+ `end()`). Only a label fn that read a _value column_ off the event (e.g.
39
+ `event => event.get('label')`) needs rewriting — compute the label before
40
+ `asInterval`, or derive it from the extent. The constant form
41
+ (`asInterval('bucket')` / `asInterval(42)`) is unaffected. (Pre-1.0 minor;
42
+ this is the change that lets the function form stay on the columnar path.)
43
+
44
+ ### Fixed
45
+
46
+ - **`mapColumns` rejects a non-finite numeric result at write.** A mapper on a
47
+ `number` column that returns `NaN` or `±Infinity` now throws a `RangeError`,
48
+ consistent with construction intake (which already rejects non-finite
49
+ numbers). Previously the value was packed into the column, where the reduce
50
+ fast path and the row path could disagree on the same bucket (e.g.
51
+ `aggregate('min')` returning a different result depending on which path ran).
52
+ A stored `NaN` is still a defined value the mapper sees — map it to a finite
53
+ number, or to `undefined` (missing), to clean it. (Closes a hole introduced
54
+ alongside `mapColumns` in 0.21.0.)
55
+ - **`aggregate('stdev')` is now numerically stable and path-independent.** The
56
+ bucketed row path (`bucketState`) used a one-pass `sq/n − mean²` accumulator
57
+ that cancels catastrophically on near-equal large-magnitude values —
58
+ returning `0` (e.g. `[1e10, 1e10+1, 1e10+2, 1e10+3]` → `0` instead of
59
+ `≈1.118`), or a negative variance whose `sqrt` is `NaN` that the validating
60
+ constructor then rejected with a throw. Because the columnar fast path is
61
+ all-or-nothing, an unrelated mapping (e.g. a `count` over a string column)
62
+ could silently flip the _same_ series' stdev. All three batch paths (`reduce`,
63
+ `reduceColumn`, `bucketState`) now share **one Welford recurrence** — O(1) per
64
+ element, no buffer (so the live aggregation path that shares `bucketState`
65
+ stays O(1)), `m2 ≥ 0` by construction — so they agree regardless of magnitude.
66
+ (Even the prior two-pass `Σv/n`-then-deviations drifted ~8.7% from the true
67
+ value at `2^52`, where the summed mean rounds — so unifying on Welford, not
68
+ two-pass, was necessary.) **Correction:** 0.21.0's columnar `aggregate()` fast
69
+ path (#186) was described as "signature + semantics unchanged", but it did
70
+ change released `stdev` output for fast-path-qualifying aggregates; this fix
71
+ makes every path agree. (`rolling`/`smooth` stdev keep the one-pass form for
72
+ now — a separate, deferred item.)
73
+
18
74
  ## [0.21.0] — 2026-06-11
19
75
 
20
76
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pond-ts/react",
3
- "version": "0.21.0",
3
+ "version": "0.22.0",
4
4
  "description": "React hooks for pond-ts live time series",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -32,7 +32,7 @@
32
32
  "test:runtime": "vitest run"
33
33
  },
34
34
  "peerDependencies": {
35
- "pond-ts": "^0.21.0",
35
+ "pond-ts": "^0.22.0",
36
36
  "react": "^18.0.0 || ^19.0.0"
37
37
  },
38
38
  "devDependencies": {