@pond-ts/react 0.20.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.
- package/CHANGELOG.md +104 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,13 +7,116 @@ 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.22.0...HEAD
|
|
11
|
+
[0.22.0]: https://github.com/pjm17971/pond-ts/compare/v0.21.0...v0.22.0
|
|
12
|
+
[0.21.0]: https://github.com/pjm17971/pond-ts/compare/v0.20.0...v0.21.0
|
|
11
13
|
[0.20.0]: https://github.com/pjm17971/pond-ts/compare/v0.19.0...v0.20.0
|
|
12
14
|
[0.19.0]: https://github.com/pjm17971/pond-ts/compare/v0.18.0...v0.19.0
|
|
13
15
|
[0.18.0]: https://github.com/pjm17971/pond-ts/compare/v0.17.1...v0.18.0
|
|
14
16
|
|
|
15
17
|
## [Unreleased]
|
|
16
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
|
+
|
|
74
|
+
## [0.21.0] — 2026-06-11
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
|
|
78
|
+
- **`TimeSeries.mapColumns({ col: (value) => newValue })`** — a per-cell column
|
|
79
|
+
value transform. The column-scoped counterpart of the event-based `map()`:
|
|
80
|
+
where `map(schema, event => newEvent)` rebuilds whole rows through an
|
|
81
|
+
arbitrary closure (and can change the schema/key), `mapColumns` transforms
|
|
82
|
+
individual columns' values in place, reading the columns directly (no
|
|
83
|
+
per-row `Event`) so it stays on the fast columnar path. Same kind in/out
|
|
84
|
+
(number→number, string→string, …), so the schema is unchanged; missing cells
|
|
85
|
+
carry (the mapper isn't called on `undefined`). ~5–6× faster than the
|
|
86
|
+
`map()` workaround on a build → transform → read pipeline.
|
|
87
|
+
|
|
88
|
+
### Changed
|
|
89
|
+
|
|
90
|
+
- **`select` / `rename` / `slice` / `cumulative` / `diff` / `rate` /
|
|
91
|
+
`pctChange` / `fill` / `shift` / `collapse` are now column-native.** They
|
|
92
|
+
reshape the columnar store directly instead of materializing events, so the
|
|
93
|
+
columnar construction win is preserved through these transforms — build →
|
|
94
|
+
transform → read pipelines run several× faster (~7–10× for `select` /
|
|
95
|
+
`rename` / `slice`; ~5–7× for the `cumulative` / `diff` / `rate` / `fill` /
|
|
96
|
+
`shift` / `collapse` folds). No API change for type-correct callers (one
|
|
97
|
+
narrow `fill` behavior change is noted under Fixed). `cumulative` / `diff` /
|
|
98
|
+
`rate` / `pctChange` / `fill` / `shift` / `collapse` are also the first
|
|
99
|
+
operators extracted into `batch/operators/` (internal refactor); `fill`
|
|
100
|
+
rebuilds only the columns it actually changes; `slice` normalizes
|
|
101
|
+
`Array.prototype.slice` semantics onto a zero-copy `withRowRange` reshape;
|
|
102
|
+
`collapse` reads only the keyed columns and passes the kept columns through
|
|
103
|
+
by reference.
|
|
104
|
+
|
|
105
|
+
### Fixed
|
|
106
|
+
|
|
107
|
+
- **`rename` now rejects target-name collisions** (e.g. renaming `a` → `b`
|
|
108
|
+
when `b` already exists) with a clear error, instead of silently producing a
|
|
109
|
+
duplicate-named schema. Also fixes a prototype-chain bug where a column named
|
|
110
|
+
`toString` (or another `Object.prototype` member) could be corrupted during
|
|
111
|
+
a rename.
|
|
112
|
+
- **`fill` now throws on a kind-mismatched literal** (e.g.
|
|
113
|
+
`fill({ value: 'banana' })` where `value` is numeric — type-allowed because
|
|
114
|
+
mapping values are the broad `FillStrategy | ScalarValue`) with a clear
|
|
115
|
+
`RangeError` naming the column, instead of silently producing an
|
|
116
|
+
internally-inconsistent series (the old events path returned the literal
|
|
117
|
+
from `.get()` while the numeric column read `NaN`). The throw is
|
|
118
|
+
gap-dependent — it only fires when the literal would actually be placed.
|
|
119
|
+
|
|
17
120
|
## [0.20.0] — 2026-06-04
|
|
18
121
|
|
|
19
122
|
Two internal performance improvements driven by the dashboard experiment at
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pond-ts/react",
|
|
3
|
-
"version": "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.
|
|
35
|
+
"pond-ts": "^0.22.0",
|
|
36
36
|
"react": "^18.0.0 || ^19.0.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|