pond-ts 0.22.0 → 0.24.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 (198) hide show
  1. package/CHANGELOG.md +125 -1
  2. package/README.md +18 -14
  3. package/dist/batch/aggregate-columns.d.ts +0 -24
  4. package/dist/batch/aggregate-columns.js +47 -32
  5. package/dist/batch/partitioned-time-series.d.ts +4 -20
  6. package/dist/batch/partitioned-time-series.js +25 -67
  7. package/dist/batch/time-series.d.ts +11 -20
  8. package/dist/batch/time-series.js +154 -15
  9. package/dist/batch/validate.js +2 -2
  10. package/dist/cjs-fallback.cjs +15 -0
  11. package/dist/index.d.ts +1 -1
  12. package/dist/live/live-aggregation.d.ts +2 -2
  13. package/dist/live/live-partitioned-series.d.ts +8 -31
  14. package/dist/live/live-rolling-aggregation.d.ts +2 -2
  15. package/dist/live/live-series.d.ts +5 -10
  16. package/dist/live/live-series.js +2 -1
  17. package/dist/live/live-view.d.ts +5 -10
  18. package/dist/live/live-view.js +1 -0
  19. package/dist/reducers/first.js +1 -0
  20. package/dist/reducers/last.js +1 -0
  21. package/dist/reducers/types.d.ts +16 -0
  22. package/dist/schema/aggregate.d.ts +162 -64
  23. package/dist/schema/events.d.ts +10 -0
  24. package/dist/schema/index.d.ts +1 -2
  25. package/dist/schema/index.js +8 -0
  26. package/dist/schema/reduce.d.ts +34 -4
  27. package/dist/schema/rolling.d.ts +1 -1
  28. package/package.json +4 -3
  29. package/dist/batch/aggregate-columns.d.ts.map +0 -1
  30. package/dist/batch/aggregate-columns.js.map +0 -1
  31. package/dist/batch/index.d.ts.map +0 -1
  32. package/dist/batch/index.js.map +0 -1
  33. package/dist/batch/json.d.ts.map +0 -1
  34. package/dist/batch/json.js.map +0 -1
  35. package/dist/batch/operators/collapse.d.ts.map +0 -1
  36. package/dist/batch/operators/collapse.js.map +0 -1
  37. package/dist/batch/operators/cumulative.d.ts.map +0 -1
  38. package/dist/batch/operators/cumulative.js.map +0 -1
  39. package/dist/batch/operators/diff-rate.d.ts.map +0 -1
  40. package/dist/batch/operators/diff-rate.js.map +0 -1
  41. package/dist/batch/operators/fill.d.ts.map +0 -1
  42. package/dist/batch/operators/fill.js.map +0 -1
  43. package/dist/batch/operators/map.d.ts.map +0 -1
  44. package/dist/batch/operators/map.js.map +0 -1
  45. package/dist/batch/operators/shift.d.ts.map +0 -1
  46. package/dist/batch/operators/shift.js.map +0 -1
  47. package/dist/batch/partitioned-time-series.d.ts.map +0 -1
  48. package/dist/batch/partitioned-time-series.js.map +0 -1
  49. package/dist/batch/time-series.d.ts.map +0 -1
  50. package/dist/batch/time-series.js.map +0 -1
  51. package/dist/batch/validate.d.ts.map +0 -1
  52. package/dist/batch/validate.js.map +0 -1
  53. package/dist/column.d.ts.map +0 -1
  54. package/dist/column.js.map +0 -1
  55. package/dist/columnar/array-column.d.ts.map +0 -1
  56. package/dist/columnar/array-column.js.map +0 -1
  57. package/dist/columnar/builder.d.ts.map +0 -1
  58. package/dist/columnar/builder.js.map +0 -1
  59. package/dist/columnar/chunked-column.d.ts.map +0 -1
  60. package/dist/columnar/chunked-column.js.map +0 -1
  61. package/dist/columnar/column.d.ts.map +0 -1
  62. package/dist/columnar/column.js.map +0 -1
  63. package/dist/columnar/concat.d.ts.map +0 -1
  64. package/dist/columnar/concat.js.map +0 -1
  65. package/dist/columnar/index.d.ts.map +0 -1
  66. package/dist/columnar/index.js.map +0 -1
  67. package/dist/columnar/key-column.d.ts.map +0 -1
  68. package/dist/columnar/key-column.js.map +0 -1
  69. package/dist/columnar/ring-buffer.d.ts.map +0 -1
  70. package/dist/columnar/ring-buffer.js.map +0 -1
  71. package/dist/columnar/scatter.d.ts.map +0 -1
  72. package/dist/columnar/scatter.js.map +0 -1
  73. package/dist/columnar/store.d.ts.map +0 -1
  74. package/dist/columnar/store.js.map +0 -1
  75. package/dist/columnar/string-column.d.ts.map +0 -1
  76. package/dist/columnar/string-column.js.map +0 -1
  77. package/dist/columnar/types.d.ts.map +0 -1
  78. package/dist/columnar/types.js.map +0 -1
  79. package/dist/columnar/validity.d.ts.map +0 -1
  80. package/dist/columnar/validity.js.map +0 -1
  81. package/dist/columnar/view.d.ts.map +0 -1
  82. package/dist/columnar/view.js.map +0 -1
  83. package/dist/core/calendar.d.ts.map +0 -1
  84. package/dist/core/calendar.js.map +0 -1
  85. package/dist/core/duration.d.ts.map +0 -1
  86. package/dist/core/duration.js.map +0 -1
  87. package/dist/core/errors.d.ts.map +0 -1
  88. package/dist/core/errors.js.map +0 -1
  89. package/dist/core/event.d.ts.map +0 -1
  90. package/dist/core/event.js.map +0 -1
  91. package/dist/core/index.d.ts.map +0 -1
  92. package/dist/core/index.js.map +0 -1
  93. package/dist/core/interval.d.ts.map +0 -1
  94. package/dist/core/interval.js.map +0 -1
  95. package/dist/core/temporal.d.ts.map +0 -1
  96. package/dist/core/temporal.js.map +0 -1
  97. package/dist/core/time-range.d.ts.map +0 -1
  98. package/dist/core/time-range.js.map +0 -1
  99. package/dist/core/time.d.ts.map +0 -1
  100. package/dist/core/time.js.map +0 -1
  101. package/dist/index.d.ts.map +0 -1
  102. package/dist/index.js.map +0 -1
  103. package/dist/live/index.d.ts.map +0 -1
  104. package/dist/live/index.js.map +0 -1
  105. package/dist/live/live-aggregation.d.ts.map +0 -1
  106. package/dist/live/live-aggregation.js.map +0 -1
  107. package/dist/live/live-chunked-storage.d.ts.map +0 -1
  108. package/dist/live/live-chunked-storage.js.map +0 -1
  109. package/dist/live/live-fused-rolling.d.ts.map +0 -1
  110. package/dist/live/live-fused-rolling.js.map +0 -1
  111. package/dist/live/live-history.d.ts.map +0 -1
  112. package/dist/live/live-history.js.map +0 -1
  113. package/dist/live/live-partitioned-fused-rolling.d.ts.map +0 -1
  114. package/dist/live/live-partitioned-fused-rolling.js.map +0 -1
  115. package/dist/live/live-partitioned-series.d.ts.map +0 -1
  116. package/dist/live/live-partitioned-series.js.map +0 -1
  117. package/dist/live/live-partitioned-sync-rolling.d.ts.map +0 -1
  118. package/dist/live/live-partitioned-sync-rolling.js.map +0 -1
  119. package/dist/live/live-reduce.d.ts.map +0 -1
  120. package/dist/live/live-reduce.js.map +0 -1
  121. package/dist/live/live-rolling-aggregation.d.ts.map +0 -1
  122. package/dist/live/live-rolling-aggregation.js.map +0 -1
  123. package/dist/live/live-series.d.ts.map +0 -1
  124. package/dist/live/live-series.js.map +0 -1
  125. package/dist/live/live-storage.d.ts.map +0 -1
  126. package/dist/live/live-storage.js.map +0 -1
  127. package/dist/live/live-view.d.ts.map +0 -1
  128. package/dist/live/live-view.js.map +0 -1
  129. package/dist/live/series-store.d.ts.map +0 -1
  130. package/dist/live/series-store.js.map +0 -1
  131. package/dist/live/triggers.d.ts.map +0 -1
  132. package/dist/live/triggers.js.map +0 -1
  133. package/dist/reducers/avg.d.ts.map +0 -1
  134. package/dist/reducers/avg.js.map +0 -1
  135. package/dist/reducers/count.d.ts.map +0 -1
  136. package/dist/reducers/count.js.map +0 -1
  137. package/dist/reducers/difference.d.ts.map +0 -1
  138. package/dist/reducers/difference.js.map +0 -1
  139. package/dist/reducers/first.d.ts.map +0 -1
  140. package/dist/reducers/first.js.map +0 -1
  141. package/dist/reducers/index.d.ts.map +0 -1
  142. package/dist/reducers/index.js.map +0 -1
  143. package/dist/reducers/keep.d.ts.map +0 -1
  144. package/dist/reducers/keep.js.map +0 -1
  145. package/dist/reducers/last.d.ts.map +0 -1
  146. package/dist/reducers/last.js.map +0 -1
  147. package/dist/reducers/max.d.ts.map +0 -1
  148. package/dist/reducers/max.js.map +0 -1
  149. package/dist/reducers/median.d.ts.map +0 -1
  150. package/dist/reducers/median.js.map +0 -1
  151. package/dist/reducers/min.d.ts.map +0 -1
  152. package/dist/reducers/min.js.map +0 -1
  153. package/dist/reducers/percentile.d.ts.map +0 -1
  154. package/dist/reducers/percentile.js.map +0 -1
  155. package/dist/reducers/rolling.d.ts.map +0 -1
  156. package/dist/reducers/rolling.js.map +0 -1
  157. package/dist/reducers/samples.d.ts.map +0 -1
  158. package/dist/reducers/samples.js.map +0 -1
  159. package/dist/reducers/stdev.d.ts.map +0 -1
  160. package/dist/reducers/stdev.js.map +0 -1
  161. package/dist/reducers/sum.d.ts.map +0 -1
  162. package/dist/reducers/sum.js.map +0 -1
  163. package/dist/reducers/top.d.ts.map +0 -1
  164. package/dist/reducers/top.js.map +0 -1
  165. package/dist/reducers/types.d.ts.map +0 -1
  166. package/dist/reducers/types.js.map +0 -1
  167. package/dist/reducers/unique.d.ts.map +0 -1
  168. package/dist/reducers/unique.js.map +0 -1
  169. package/dist/schema/aggregate.d.ts.map +0 -1
  170. package/dist/schema/aggregate.js.map +0 -1
  171. package/dist/schema/diff.d.ts.map +0 -1
  172. package/dist/schema/diff.js.map +0 -1
  173. package/dist/schema/events.d.ts.map +0 -1
  174. package/dist/schema/events.js.map +0 -1
  175. package/dist/schema/index.d.ts.map +0 -1
  176. package/dist/schema/index.js.map +0 -1
  177. package/dist/schema/join.d.ts.map +0 -1
  178. package/dist/schema/join.js.map +0 -1
  179. package/dist/schema/json.d.ts.map +0 -1
  180. package/dist/schema/json.js.map +0 -1
  181. package/dist/schema/public.d.ts.map +0 -1
  182. package/dist/schema/public.js.map +0 -1
  183. package/dist/schema/reduce.d.ts.map +0 -1
  184. package/dist/schema/reduce.js.map +0 -1
  185. package/dist/schema/reshape.d.ts.map +0 -1
  186. package/dist/schema/reshape.js.map +0 -1
  187. package/dist/schema/rolling.d.ts.map +0 -1
  188. package/dist/schema/rolling.js.map +0 -1
  189. package/dist/schema/series.d.ts.map +0 -1
  190. package/dist/schema/series.js.map +0 -1
  191. package/dist/sequence/bounded-sequence.d.ts.map +0 -1
  192. package/dist/sequence/bounded-sequence.js.map +0 -1
  193. package/dist/sequence/index.d.ts.map +0 -1
  194. package/dist/sequence/index.js.map +0 -1
  195. package/dist/sequence/sample.d.ts.map +0 -1
  196. package/dist/sequence/sample.js.map +0 -1
  197. package/dist/sequence/sequence.d.ts.map +0 -1
  198. package/dist/sequence/sequence.js.map +0 -1
@@ -12,7 +12,7 @@ import { TimeRange } from '../core/time-range.js';
12
12
  import { compareEventKeys } from '../core/temporal.js';
13
13
  import { PartitionedTimeSeries } from './partitioned-time-series.js';
14
14
  import { Sequence } from '../sequence/sequence.js';
15
- import { IntervalKeyColumn, TimeKeyColumn, TimeRangeKeyColumn, float64ColumnFromArray, stringColumnFromArray, withColumnsRenamed, withColumnsSelected, withKeyColumn, withRowRange, } from '../columnar/index.js';
15
+ import { IntervalKeyColumn, TimeKeyColumn, TimeRangeKeyColumn, float64ColumnFromArray, stringColumnFromArray, withColumnsRenamed, withColumnsSelected, withKeyColumn, withRowRange, withRowSelection, } from '../columnar/index.js';
16
16
  import { SeriesStore } from '../live/series-store.js';
17
17
  import { parseDuration } from '../core/duration.js';
18
18
  import { resolveReducer, } from '../reducers/index.js';
@@ -468,6 +468,7 @@ export class TimeSeries {
468
468
  name: input.name,
469
469
  schema: input.schema,
470
470
  rows: parseJsonRows(input.schema, input.rows, input.parse),
471
+ sort: input.sort ?? false,
471
472
  });
472
473
  }
473
474
  /**
@@ -587,13 +588,21 @@ export class TimeSeries {
587
588
  }
588
589
  else {
589
590
  this.schema = Object.freeze(input.schema.slice());
591
+ // `{ sort: true }` sorts unsorted input by key before intake (otherwise
592
+ // the intake's non-decreasing-order check throws). Stable, so rows with
593
+ // equal keys keep their input order; same key comparator as
594
+ // `fromEvents` / `concat`. Copies the array — the caller's `rows` is not
595
+ // mutated.
596
+ const rows = input.sort
597
+ ? [...input.rows].sort((a, b) => compareEventKeys(toKey(a[0]), toKey(b[0])))
598
+ : input.rows;
590
599
  // `SeriesStore.fromValidatedRows` runs the column-native
591
600
  // intake (`validateAndNormalizeColumnar`) — same validation
592
601
  // rules as the pre-2a row-shape `validateAndNormalize` but
593
602
  // writes directly into columnar buffers without allocating
594
603
  // Event objects + frozen data dicts. Events lazy-materialize
595
604
  // on first `eventAt(i)` access via the store's per-row cache.
596
- this.#store = SeriesStore.fromValidatedRows(this.schema, input.rows);
605
+ this.#store = SeriesStore.fromValidatedRows(this.schema, rows);
597
606
  }
598
607
  Object.freeze(this);
599
608
  }
@@ -701,6 +710,98 @@ export class TimeSeries {
701
710
  };
702
711
  return new TimeSeries(trustedInput);
703
712
  }
713
+ /**
714
+ * @internal Per-row partition-key encoder, mirroring the (removed)
715
+ * event-based `partitionKeyOf` exactly: single column → `String(value)`,
716
+ * or `' undefined'` (leading space, so it can't collide with the literal
717
+ * string `'undefined'`) for a missing cell; composite → `JSON.stringify`
718
+ * of the cells with a `?? null` fallback. Reads cells by index off the
719
+ * store — no event materialization; array cells stringify as the event
720
+ * path did. Shared by `_partitionByColumns` and `_distinctPartitionKeys`
721
+ * so the encoding can't drift between the split and the declared-`groups`
722
+ * membership check.
723
+ */
724
+ #partitionKeyEncoder(by) {
725
+ const store = this.#store.store;
726
+ if (by.length === 1) {
727
+ // Single-column fast path — no per-row array allocation.
728
+ const col = store.columns.get(by[0]);
729
+ return (i) => {
730
+ const value = col.read(i);
731
+ return value === undefined ? ' undefined' : `${String(value)}`;
732
+ };
733
+ }
734
+ const cols = by.map((name) => store.columns.get(name));
735
+ const parts = new Array(cols.length);
736
+ return (i) => {
737
+ for (let c = 0; c < cols.length; c += 1) {
738
+ parts[c] = cols[c].read(i) ?? null;
739
+ }
740
+ return JSON.stringify(parts);
741
+ };
742
+ }
743
+ /**
744
+ * @internal Columnar partition split — groups row indices by the partition
745
+ * key (see {@link TimeSeries.#partitionKeyEncoder}), gathers each group via
746
+ * `withRowSelection`, and wraps it as a trusted-store `TimeSeries`, with
747
+ * **no event materialization**. The columnar dual of the old
748
+ * `fromEvents`-per-bucket split that `PartitionedTimeSeries` paid through
749
+ * `this.events`. First-encountered partition order is preserved (Map
750
+ * insertion order), matching the previous `bucketByPartition`.
751
+ *
752
+ * **Identity note:** each sub-series lazily materializes its own `Event`
753
+ * objects from the gathered store — it does NOT reuse the source's `Event`
754
+ * instances (the old `fromEvents` path did). Cell values are identical;
755
+ * only object identity differs, and only for the no-transform paths
756
+ * (`toMap()` / `apply(g => g)`). `collect()` returns the source unchanged,
757
+ * so it is unaffected. This is the deliberate cost of skipping
758
+ * materialization.
759
+ *
760
+ * Used by `PartitionedTimeSeries` (`collect` / sugar via `applyToSource`,
761
+ * and `toMap`).
762
+ */
763
+ _partitionByColumns(by) {
764
+ const columnarStore = this.#store.store;
765
+ const length = columnarStore.length;
766
+ const encode = this.#partitionKeyEncoder(by);
767
+ const groups = new Map();
768
+ for (let i = 0; i < length; i += 1) {
769
+ const key = encode(i);
770
+ let indices = groups.get(key);
771
+ if (indices === undefined) {
772
+ indices = [];
773
+ groups.set(key, indices);
774
+ }
775
+ indices.push(i);
776
+ }
777
+ const result = new Map();
778
+ for (const [key, rowIndices] of groups) {
779
+ const sub = withRowSelection(columnarStore, new Int32Array(rowIndices));
780
+ result.set(key, TimeSeries.#fromTrustedStore(this.name, this.schema, sub));
781
+ }
782
+ return result;
783
+ }
784
+ /**
785
+ * @internal Distinct partition keys in first-encountered order, encoded by
786
+ * {@link TimeSeries.#partitionKeyEncoder} (identical to
787
+ * `_partitionByColumns`). Scans the partition columns off the store — no
788
+ * event materialization. Used by `PartitionedTimeSeries`'s declared-`groups`
789
+ * membership check so that path is materialization-free too.
790
+ */
791
+ _distinctPartitionKeys(by) {
792
+ const length = this.#store.store.length;
793
+ const encode = this.#partitionKeyEncoder(by);
794
+ const seen = new Set();
795
+ const keys = [];
796
+ for (let i = 0; i < length; i += 1) {
797
+ const key = encode(i);
798
+ if (!seen.has(key)) {
799
+ seen.add(key);
800
+ keys.push(key);
801
+ }
802
+ }
803
+ return keys;
804
+ }
704
805
  /**
705
806
  * Example: `series.events`. Returns the full event array.
706
807
  *
@@ -782,14 +883,18 @@ export class TimeSeries {
782
883
  * series.events[i]` holds whenever both are accessed.
783
884
  */
784
885
  at(index) {
785
- // Match pre-2a array-indexing semantics: non-integer or NaN
786
- // inputs return undefined rather than throwing downstream from
787
- // `#store.eventAt`. `this.events[NaN]` returned undefined per
788
- // JS array semantics (key coercion + miss); the direct route
789
- // to `#store.eventAt(NaN)` would proceed past the bounds check
790
- // and attempt key materialization at the invalid row. Closed
791
- // Codex round 4's medium finding on PR #150.
792
- if (!Number.isInteger(index) || index < 0 || index >= this.#store.length) {
886
+ // Non-integer / NaN inputs return undefined rather than throwing
887
+ // downstream from `#store.eventAt` (`this.events[NaN]` returned undefined
888
+ // per JS array semantics; the direct route to `#store.eventAt(NaN)` would
889
+ // proceed past the bounds check and materialize a key at an invalid row).
890
+ // Closed Codex round 4's medium finding on PR #150.
891
+ if (!Number.isInteger(index))
892
+ return undefined;
893
+ // Negative indices count from the end parity with `LiveSeries.at` and
894
+ // `Array.prototype.at` (`at(-1)` is the last event).
895
+ if (index < 0)
896
+ index += this.#store.length;
897
+ if (index < 0 || index >= this.#store.length) {
793
898
  return undefined;
794
899
  }
795
900
  return this.#store.eventAt(index);
@@ -1292,7 +1397,8 @@ export class TimeSeries {
1292
1397
  }
1293
1398
  pivotByGroup(groupCol, valueCol, options = {}) {
1294
1399
  if (this.schema[0].kind !== 'time') {
1295
- throw new TypeError(`pivotByGroup requires a time-keyed series; got ${this.schema[0].kind}`);
1400
+ throw new TypeError(`pivotByGroup requires a time-keyed series; got ${this.schema[0].kind}` +
1401
+ ` — piping from aggregate/materialize? call .asTime({ at: 'begin' }) first`);
1296
1402
  }
1297
1403
  const valueColumnDef = this.schema.find((c) => c.name === valueCol);
1298
1404
  if (!valueColumnDef) {
@@ -2387,12 +2493,37 @@ export class TimeSeries {
2387
2493
  }
2388
2494
  /** Example: `series.timeRange()`. Returns the overall temporal extent of the series, if the series is not empty. */
2389
2495
  timeRange() {
2390
- const first = this.first();
2391
- if (!first) {
2496
+ // Columnar key-axis read. The old implementation reduced over
2497
+ // `this.events`, materializing every Event (the ~495 ns/row + heap
2498
+ // tax) on every call — including the cold `aggregate()` default
2499
+ // range, which erased the 3B fast-path win for one-shot pipelines.
2500
+ const key = this.keyColumn();
2501
+ const n = key.length;
2502
+ if (n === 0) {
2392
2503
  return undefined;
2393
2504
  }
2394
- const start = first.begin();
2395
- const end = this.events.reduce((maxEnd, event) => Math.max(maxEnd, event.end()), first.end());
2505
+ // `begin` is sorted non-decreasing (the intake invariant) for every
2506
+ // key kind, so the minimum start is always `begin[0]`.
2507
+ const start = key.begin[0];
2508
+ let end;
2509
+ if (key.kind === 'time') {
2510
+ // Point-in-time keys: `end === begin`, and begin is sorted, so the
2511
+ // maximum end is the final begin. O(1).
2512
+ end = key.begin[n - 1];
2513
+ }
2514
+ else {
2515
+ // Range / interval keys: `begin[i] <= end[i]` per row, but `end` is
2516
+ // NOT monotonic (a long early event can outlast the final row), so
2517
+ // the max end needs a scan — a typed-array scan, not Event
2518
+ // materialization. Seeds with `end[0]` and maxes the rest, matching
2519
+ // the old `reduce` seeded at `first.end()`.
2520
+ const ends = key.end;
2521
+ end = ends[0];
2522
+ for (let i = 1; i < n; i += 1) {
2523
+ if (ends[i] > end)
2524
+ end = ends[i];
2525
+ }
2526
+ }
2396
2527
  return new TimeRange({ start, end });
2397
2528
  }
2398
2529
  /** Example: `series.overlaps(range)`. Returns `true` when the overall series extent overlaps the supplied temporal value. */
@@ -2826,6 +2957,12 @@ export class TimeSeries {
2826
2957
  rollingOptions.alignment = alignment;
2827
2958
  if (minSamples !== undefined)
2828
2959
  rollingOptions.minSamples = minSamples;
2960
+ // Trust boundary: a generic mapping can't prove it satisfies the
2961
+ // public overload's ValidatedAggregateMap constraint (S is
2962
+ // unresolved here), so route through the broad-schema escape hatch
2963
+ // — for concrete SeriesSchema the constraint degrades to the
2964
+ // permissive AggregateMap by design. The computed spec keys are
2965
+ // collision-checked above.
2829
2966
  const rolling = this.rolling(window, {
2830
2967
  [avgName]: { from: col, using: 'avg' },
2831
2968
  [sdName]: { from: col, using: 'stdev' },
@@ -2920,6 +3057,8 @@ export class TimeSeries {
2920
3057
  rollingOptions.alignment = alignment;
2921
3058
  if (minSamples !== undefined)
2922
3059
  rollingOptions.minSamples = minSamples;
3060
+ // Trust boundary: see baseline() above — generic mapping routed
3061
+ // through the broad-schema escape hatch of ValidatedAggregateMap.
2923
3062
  const rolling = this.rolling(window, rollingMapping, rollingOptions);
2924
3063
  const kept = [];
2925
3064
  for (let i = 0; i < this.events.length; i += 1) {
@@ -376,11 +376,11 @@ export function validateAndNormalizeColumnar(input) {
376
376
  const prevBegin = beginBuf[i - 1];
377
377
  const curBegin = beginBuf[i];
378
378
  if (prevBegin > curBegin) {
379
- throw new ValidationError(`row ${i} is out of order`);
379
+ throw new ValidationError(`row ${i} is out of order — keys must be non-decreasing; pass { sort: true } to sort rows on construction, or pre-sort them`);
380
380
  }
381
381
  if (prevBegin === curBegin && endBuf !== beginBuf) {
382
382
  if (endBuf[i - 1] > endBuf[i]) {
383
- throw new ValidationError(`row ${i} is out of order`);
383
+ throw new ValidationError(`row ${i} is out of order — keys must be non-decreasing; pass { sort: true } to sort rows on construction, or pre-sort them`);
384
384
  }
385
385
  }
386
386
  }
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ // pond-ts ships as ES modules only. This stub is the `require` target in the
4
+ // package's `exports` map so that CommonJS consumers get a clear, actionable
5
+ // error instead of Node's cryptic `ERR_PACKAGE_PATH_NOT_EXPORTED`.
6
+ //
7
+ // It is copied verbatim into `dist/` during `prepack` (see package.json) so it
8
+ // rides along in the published tarball; the source of truth lives at the
9
+ // package root and is never touched by `tsc`.
10
+
11
+ throw new Error(
12
+ 'pond-ts is an ES module package and cannot be loaded with require(). ' +
13
+ "Use `import { TimeSeries } from 'pond-ts'` instead, or a dynamic " +
14
+ "`await import('pond-ts')` from CommonJS. See https://nodejs.org/api/esm.html.",
15
+ );
package/dist/index.d.ts CHANGED
@@ -29,7 +29,7 @@ export { ArrayColumn } from './columnar/array-column.js';
29
29
  export { ChunkedArrayColumn, ChunkedBooleanColumn, ChunkedFloat64Column, ChunkedStringColumn, } from './columnar/chunked-column.js';
30
30
  export { type IntervalLabelKind, type KeyColumn, IntervalKeyColumn, TimeKeyColumn, TimeRangeKeyColumn, } from './columnar/key-column.js';
31
31
  export { type ValidityBitmap } from './columnar/validity.js';
32
- export type { AlignSchema, ArrayColumnNameForSchema, BaselineSchema, AggregateFunction, AggregateReducer, AggregateOutputMap, AggregateOutputSpec, AggregateMap, AggregateSchema, ColumnDef, CollapseData, ArrayAggregateAppendSchema, ArrayAggregateKind, ArrayAggregateReplaceSchema, ArrayExplodeAppendSchema, ArrayExplodeReplaceSchema, CollapseSchema, DedupeKeep, EventDataForSchema, EventForSchema, EventKeyForKind, FillMapping, FillStrategy, MaterializeSchema, EventKeyForSchema, FirstColKind, FirstColumn, IntervalKeyedSchema, JsonIntervalInput, JsonObjectRowForSchema, JsonRowFormat, JsonRowForSchema, JsonTimeRangeInput, JsonTimestampInput, JsonValueForKind, RollingAlignment, RollingSchema, JoinConflictMode, JoinManySchema, PrefixedJoinManySchema, PrefixedJoinSchema, LiveSource, JoinType, JoinSchema, NormalizedRowForSchema, NormalizedObjectRowForSchema, NormalizedObjectRow, NormalizedValueForKind, ReduceResult, RenameData, RenameMap, RenameSchema, RekeySchema, RowForSchema, ArrayValue, ColumnValue, ScalarKind, ScalarValue, CustomAggregateReducer, DiffSchema, NumericColumnNameForSchema, SmoothMethod, SmoothAppendSchema, SmoothSchema, SelectData, SelectSchema, SeriesSchema, TimeKeyedSchema, TimeSeriesInput, TimeSeriesJsonInput, TimeRangeKeyedSchema, ValueColumnsForSchema, ValueColumn, ValueForKind, } from './schema/index.js';
32
+ export type { AlignSchema, ArrayColumnNameForSchema, BaselineSchema, AggregateFunction, AggregateReducer, AggregateOutputMap, AggregateOutputSpec, AggregateMap, AggregateSchema, ValidatedAggregateMap, ColumnDef, CollapseData, ArrayAggregateAppendSchema, ArrayAggregateKind, ArrayAggregateReplaceSchema, ArrayExplodeAppendSchema, ArrayExplodeReplaceSchema, CollapseSchema, DedupeKeep, EventDataForSchema, EventForSchema, EventKeyForKind, FillMapping, FillStrategy, MaterializeSchema, EventKeyForSchema, FirstColKind, FirstColumn, IntervalKeyedSchema, JsonIntervalInput, JsonObjectRowForSchema, JsonRowFormat, JsonRowForSchema, JsonTimeRangeInput, JsonTimestampInput, JsonValueForKind, RollingAlignment, RollingSchema, JoinConflictMode, JoinManySchema, PrefixedJoinManySchema, PrefixedJoinSchema, LiveSource, JoinType, JoinSchema, NormalizedRowForSchema, NormalizedObjectRowForSchema, NormalizedObjectRow, NormalizedValueForKind, ReduceResult, RenameData, RenameMap, RenameSchema, RekeySchema, RowForSchema, ArrayValue, ColumnValue, ScalarKind, ScalarValue, CustomAggregateReducer, DiffSchema, NumericColumnNameForSchema, SmoothMethod, SmoothAppendSchema, SmoothSchema, SelectData, SelectSchema, SeriesSchema, TimeKeyedSchema, TimeSeriesInput, TimeSeriesJsonInput, TimeRangeKeyedSchema, ValueColumnsForSchema, ValueColumn, ValueForKind, } from './schema/index.js';
33
33
  export type { CalendarOptions, CalendarUnit, TimeZoneOptions, } from './core/calendar.js';
34
34
  export type { EventKey, IntervalInput, IntervalValue, TemporalLike, TimeRangeInput, TimestampInput, } from './core/temporal.js';
35
35
  export type { DurationInput } from './core/duration.js';
@@ -4,7 +4,7 @@ import { LiveView, type LiveFillMapping, type LiveFillStrategy } from './live-vi
4
4
  import { LiveRollingAggregation, type LiveRollingOptions, type RollingWindow } from './live-rolling-aggregation.js';
5
5
  import { TimeSeries } from '../batch/time-series.js';
6
6
  import type { Sequence } from '../sequence/sequence.js';
7
- import type { AggregateMap, AggregateOutputMap, DiffSchema, EventDataForSchema, EventForSchema, LiveSource, NumericColumnNameForSchema, ColumnValue, RollingSchema, SelectSchema, SeriesSchema } from '../schema/index.js';
7
+ import type { AggregateMap, AggregateOutputMap, DiffSchema, EventDataForSchema, EventForSchema, LiveSource, NumericColumnNameForSchema, ColumnValue, RollingSchema, SelectSchema, SeriesSchema, ValidatedAggregateMap } from '../schema/index.js';
8
8
  import type { RollingOutputMapSchema } from '../schema/index.js';
9
9
  import type { DurationInput } from '../core/duration.js';
10
10
  type ClosedEvent = Event<Interval, Record<string, ColumnValue | undefined>>;
@@ -48,7 +48,7 @@ export declare class LiveAggregation<S extends SeriesSchema, Out extends SeriesS
48
48
  cumulative<const Targets extends NumericColumnNameForSchema<Out>>(spec: {
49
49
  [K in Targets]: 'sum' | 'max' | 'min' | 'count' | ((acc: number, value: number) => number);
50
50
  }): LiveView<DiffSchema<Out, Targets>>;
51
- rolling<const M extends AggregateMap<Out>>(windowSize: RollingWindow, mapping: M, options?: LiveRollingOptions): LiveRollingAggregation<Out, RollingSchema<Out, M>>;
51
+ rolling<const M extends ValidatedAggregateMap<Out, M>>(windowSize: RollingWindow, mapping: M, options?: LiveRollingOptions): LiveRollingAggregation<Out, RollingSchema<Out, M>>;
52
52
  rolling<const M extends AggregateOutputMap<Out>>(windowSize: RollingWindow, mapping: M, options?: LiveRollingOptions): LiveRollingAggregation<Out, RollingOutputMapSchema<Out, M>>;
53
53
  /**
54
54
  * Pipeline stats snapshot — cumulative counters since
@@ -4,9 +4,8 @@ import { LivePartitionedFusedRolling } from './live-partitioned-fused-rolling.js
4
4
  import type { SampleStrategy } from '../sequence/sample.js';
5
5
  import { type LiveFillMapping, type LiveFillStrategy } from './live-view.js';
6
6
  import type { Trigger } from './triggers.js';
7
- import { type AggregateMap, type AggregateOutputMap, type DiffSchema, type EventDataForSchema, type LiveSource, type NumericColumnNameForSchema, type RollingSchema, type SeriesSchema } from '../schema/index.js';
8
- import type { RollingOutputMapSchema } from '../schema/index.js';
9
- import type { FusedMapping, FusedMappingValid, FusedPartitionedRollingSchema } from '../schema/index.js';
7
+ import { type DiffSchema, type EventDataForSchema, type LiveSource, type NumericColumnNameForSchema, type RollingSchema, type SeriesSchema } from '../schema/index.js';
8
+ import type { FusedMapping, FusedMappingValid, FusedPartitionedRollingSchema, ValidatedAggregateMap } from '../schema/index.js';
10
9
  import type { DurationInput } from '../core/duration.js';
11
10
  import type { LiveRollingOptions, RollingWindow } from './live-rolling-aggregation.js';
12
11
  /**
@@ -252,28 +251,17 @@ export declare class LivePartitionedSeries<S extends SeriesSchema, K extends str
252
251
  * );
253
252
  * ```
254
253
  */
255
- rolling<const M extends AggregateMap<S>>(window: RollingWindow, mapping: M, options?: LiveRollingOptions & {
254
+ rolling<const M extends ValidatedAggregateMap<S, M>>(window: RollingWindow, mapping: M, options?: LiveRollingOptions & {
256
255
  trigger?: {
257
256
  kind: 'event' | 'count';
258
257
  };
259
258
  }): LivePartitionedView<S, RollingSchema<S, M>, K, ByCol>;
260
- rolling<const M extends AggregateOutputMap<S>>(window: RollingWindow, mapping: M, options?: LiveRollingOptions & {
261
- trigger?: {
262
- kind: 'event' | 'count';
263
- };
264
- }): LivePartitionedView<S, RollingOutputMapSchema<S, M>, K, ByCol>;
265
- rolling<const M extends AggregateMap<S>>(window: RollingWindow, mapping: M, options: LiveRollingOptions & {
266
- trigger: {
267
- kind: 'clock';
268
- } & Trigger;
269
- }): LivePartitionedSyncRolling<S, K, SeriesSchema>;
270
- rolling<const M extends AggregateOutputMap<S>>(window: RollingWindow, mapping: M, options: LiveRollingOptions & {
259
+ rolling<const M extends ValidatedAggregateMap<S, M>>(window: RollingWindow, mapping: M, options: LiveRollingOptions & {
271
260
  trigger: {
272
261
  kind: 'clock';
273
262
  } & Trigger;
274
263
  }): LivePartitionedSyncRolling<S, K, SeriesSchema>;
275
- rolling<const M extends AggregateMap<S>>(window: RollingWindow, mapping: M, options: LiveRollingOptions): LivePartitionedView<S, RollingSchema<S, M>, K, ByCol> | LivePartitionedSyncRolling<S, K, SeriesSchema>;
276
- rolling<const M extends AggregateOutputMap<S>>(window: RollingWindow, mapping: M, options: LiveRollingOptions): LivePartitionedView<S, RollingOutputMapSchema<S, M>, K, ByCol> | LivePartitionedSyncRolling<S, K, SeriesSchema>;
264
+ rolling<const M extends ValidatedAggregateMap<S, M>>(window: RollingWindow, mapping: M, options: LiveRollingOptions): LivePartitionedView<S, RollingSchema<S, M>, K, ByCol> | LivePartitionedSyncRolling<S, K, SeriesSchema>;
277
265
  /**
278
266
  * Keyed-form fused multi-window partitioned rolling. Maintains N
279
267
  * windows per partition in a single ingest pass over a single
@@ -437,28 +425,17 @@ export declare class LivePartitionedView<SBase extends SeriesSchema, R extends S
437
425
  * partition column with a passthrough reducer (e.g.
438
426
  * `host: 'last'`) to keep it visible in the unified output.
439
427
  */
440
- rolling<const M extends AggregateMap<R>>(window: RollingWindow, mapping: M, options?: LiveRollingOptions & {
428
+ rolling<const M extends ValidatedAggregateMap<R, M>>(window: RollingWindow, mapping: M, options?: LiveRollingOptions & {
441
429
  trigger?: {
442
430
  kind: 'event' | 'count';
443
431
  };
444
432
  }): LivePartitionedView<SBase, RollingSchema<R, M>, K, ByCol>;
445
- rolling<const M extends AggregateOutputMap<R>>(window: RollingWindow, mapping: M, options?: LiveRollingOptions & {
446
- trigger?: {
447
- kind: 'event' | 'count';
448
- };
449
- }): LivePartitionedView<SBase, RollingOutputMapSchema<R, M>, K, ByCol>;
450
- rolling<const M extends AggregateMap<R>>(window: RollingWindow, mapping: M, options: LiveRollingOptions & {
451
- trigger: {
452
- kind: 'clock';
453
- } & Trigger;
454
- }): LivePartitionedSyncRolling<R, K, SeriesSchema>;
455
- rolling<const M extends AggregateOutputMap<R>>(window: RollingWindow, mapping: M, options: LiveRollingOptions & {
433
+ rolling<const M extends ValidatedAggregateMap<R, M>>(window: RollingWindow, mapping: M, options: LiveRollingOptions & {
456
434
  trigger: {
457
435
  kind: 'clock';
458
436
  } & Trigger;
459
437
  }): LivePartitionedSyncRolling<R, K, SeriesSchema>;
460
- rolling<const M extends AggregateMap<R>>(window: RollingWindow, mapping: M, options: LiveRollingOptions): LivePartitionedView<SBase, RollingSchema<R, M>, K, ByCol> | LivePartitionedSyncRolling<R, K, SeriesSchema>;
461
- rolling<const M extends AggregateOutputMap<R>>(window: RollingWindow, mapping: M, options: LiveRollingOptions): LivePartitionedView<SBase, RollingOutputMapSchema<R, M>, K, ByCol> | LivePartitionedSyncRolling<R, K, SeriesSchema>;
438
+ rolling<const M extends ValidatedAggregateMap<R, M>>(window: RollingWindow, mapping: M, options: LiveRollingOptions): LivePartitionedView<SBase, RollingSchema<R, M>, K, ByCol> | LivePartitionedSyncRolling<R, K, SeriesSchema>;
462
439
  /**
463
440
  * Keyed-form fused multi-window rolling on a chained
464
441
  * `LivePartitionedView`. Same shape as the root variant — each
@@ -2,7 +2,7 @@ import { LiveAggregation } from './live-aggregation.js';
2
2
  import { LiveView, type LiveFillMapping, type LiveFillStrategy } from './live-view.js';
3
3
  import type { Sequence } from '../sequence/sequence.js';
4
4
  import { type Trigger } from './triggers.js';
5
- import type { AggregateMap, AggregateOutputMap, AggregateSchema, DiffSchema, EventDataForSchema, EventForSchema, LiveSource, NumericColumnNameForSchema, SelectSchema, SeriesSchema, ColumnValue } from '../schema/index.js';
5
+ import type { AggregateMap, AggregateOutputMap, AggregateSchema, DiffSchema, EventDataForSchema, EventForSchema, LiveSource, NumericColumnNameForSchema, SelectSchema, SeriesSchema, ColumnValue, ValidatedAggregateMap } from '../schema/index.js';
6
6
  import type { AggregateOutputMapResultSchema } from '../schema/index.js';
7
7
  import type { DurationInput } from '../core/duration.js';
8
8
  import type { RetentionPolicy } from './live-series.js';
@@ -107,7 +107,7 @@ export declare class LiveRollingAggregation<S extends SeriesSchema, Out extends
107
107
  cumulative<const Targets extends NumericColumnNameForSchema<Out>>(spec: {
108
108
  [K in Targets]: 'sum' | 'max' | 'min' | 'count' | ((acc: number, value: number) => number);
109
109
  }): LiveView<DiffSchema<Out, Targets>>;
110
- aggregate<const M extends AggregateMap<Out>>(sequence: Sequence, mapping: M): LiveAggregation<Out, AggregateSchema<Out, M>>;
110
+ aggregate<const M extends ValidatedAggregateMap<Out, M>>(sequence: Sequence, mapping: M): LiveAggregation<Out, AggregateSchema<Out, M>>;
111
111
  aggregate<const M extends AggregateOutputMap<Out>>(sequence: Sequence, mapping: M): LiveAggregation<Out, AggregateOutputMapResultSchema<Out, M>>;
112
112
  /**
113
113
  * Pipeline stats snapshot — cumulative counters since
@@ -5,12 +5,11 @@ import { LiveRollingAggregation, type LiveRollingOptions, type RollingWindow } f
5
5
  import { TimeSeries, type KeyLike } from '../batch/time-series.js';
6
6
  import type { TimeZoneOptions } from '../core/calendar.js';
7
7
  import type { Sequence } from '../sequence/sequence.js';
8
- import { EMITS_EVICT, type AggregateMap, type AggregateOutputMap, type AggregateSchema, type DiffSchema, type EventDataForSchema, type EventForSchema, type JsonObjectRowForSchema, type JsonRowForSchema, type NormalizedObjectRow, type NormalizedRowForSchema, type NumericColumnNameForSchema, type RollingSchema, type RowForSchema, type SelectSchema, type SeriesSchema, type TimeSeriesJsonInput, type TimeSeriesJsonOutputArray, type TimeSeriesJsonOutputObject } from '../schema/index.js';
9
- import type { AggregateOutputMapResultSchema, RollingOutputMapSchema } from '../schema/index.js';
8
+ import { type AggregateSchema, type DiffSchema, type EventDataForSchema, type EventForSchema, type JsonObjectRowForSchema, type JsonRowForSchema, type NormalizedObjectRow, type NormalizedRowForSchema, type NumericColumnNameForSchema, type RollingSchema, type RowForSchema, type SelectSchema, type SeriesSchema, type TimeSeriesJsonInput, type TimeSeriesJsonOutputArray, type TimeSeriesJsonOutputObject } from '../schema/index.js';
10
9
  import { LiveFusedRolling } from './live-fused-rolling.js';
11
10
  import { LiveReduce } from './live-reduce.js';
12
11
  import type { SampleStrategy } from '../sequence/sample.js';
13
- import type { FusedMapping, FusedMappingValid, FusedRollingSchema } from '../schema/index.js';
12
+ import type { FusedMapping, FusedMappingValid, FusedRollingSchema, ValidatedAggregateMap } from '../schema/index.js';
14
13
  import type { DurationInput } from '../core/duration.js';
15
14
  export type OrderingMode = 'strict' | 'drop' | 'reorder';
16
15
  export type RetentionPolicy = {
@@ -44,7 +43,6 @@ type BatchListener<S extends SeriesSchema> = (events: ReadonlyArray<EventForSche
44
43
  type EvictListener<S extends SeriesSchema> = (events: ReadonlyArray<EventForSchema<S>>) => void;
45
44
  export declare class LiveSeries<S extends SeriesSchema> {
46
45
  #private;
47
- readonly [EMITS_EVICT]: true;
48
46
  readonly name: string;
49
47
  readonly schema: S;
50
48
  constructor(options: LiveSeriesOptions<S>);
@@ -239,10 +237,8 @@ export declare class LiveSeries<S extends SeriesSchema> {
239
237
  sample(strategy: SampleStrategy): LiveView<S>;
240
238
  select<const Keys extends readonly (keyof EventDataForSchema<S>)[]>(...keys: Keys): LiveView<SelectSchema<S, Keys[number] & string>>;
241
239
  window(size: RollingWindow): LiveView<S>;
242
- aggregate<const M extends AggregateMap<S>>(sequence: Sequence, mapping: M): LiveAggregation<S, AggregateSchema<S, M>>;
243
- aggregate<const M extends AggregateOutputMap<S>>(sequence: Sequence, mapping: M): LiveAggregation<S, AggregateOutputMapResultSchema<S, M>>;
244
- rolling<const M extends AggregateMap<S>>(window: RollingWindow, mapping: M, options?: LiveRollingOptions): LiveRollingAggregation<S, RollingSchema<S, M>>;
245
- rolling<const M extends AggregateOutputMap<S>>(window: RollingWindow, mapping: M, options?: LiveRollingOptions): LiveRollingAggregation<S, RollingOutputMapSchema<S, M>>;
240
+ aggregate<const M extends ValidatedAggregateMap<S, M>>(sequence: Sequence, mapping: M): LiveAggregation<S, AggregateSchema<S, M>>;
241
+ rolling<const M extends ValidatedAggregateMap<S, M>>(window: RollingWindow, mapping: M, options?: LiveRollingOptions): LiveRollingAggregation<S, RollingSchema<S, M>>;
246
242
  /**
247
243
  * Keyed-form fused multi-window rolling. Maintains N windows in
248
244
  * one ingest pass over a single shared deque; emits one merged
@@ -278,8 +274,7 @@ export declare class LiveSeries<S extends SeriesSchema> {
278
274
  * `[time, ...mappingColumns]`. Composes with the rest of the
279
275
  * live operator surface.
280
276
  */
281
- reduce<const M extends AggregateMap<S>>(mapping: M, options?: LiveRollingOptions): LiveReduce<S, RollingSchema<S, M>>;
282
- reduce<const M extends AggregateOutputMap<S>>(mapping: M, options?: LiveRollingOptions): LiveReduce<S, RollingOutputMapSchema<S, M>>;
277
+ reduce<const M extends ValidatedAggregateMap<S, M>>(mapping: M, options?: LiveRollingOptions): LiveReduce<S, RollingSchema<S, M>>;
283
278
  /**
284
279
  * Time span of the current buffer — `last.begin() - first.begin()`
285
280
  * in milliseconds. Returns `0` if the buffer is empty or holds a
@@ -87,6 +87,7 @@ function assertCellKind(kind, value, name) {
87
87
  }
88
88
  // ── LiveSeries ──────────────────────────────────────────────────
89
89
  export class LiveSeries {
90
+ /** @internal */
90
91
  [EMITS_EVICT] = true;
91
92
  name;
92
93
  schema;
@@ -373,7 +374,7 @@ export class LiveSeries {
373
374
  rows,
374
375
  });
375
376
  // INTRA-batch order is enforced by `validateAndNormalizeColumnar`
376
- // above (it throws `ValidationError("row N is out of order")`). The
377
+ // above (it throws a `ValidationError` naming the out-of-order row). The
377
378
  // cross-batch boundary check + commit/fan-out live in `#commitChunk`.
378
379
  const store = ColumnarStore.fromTrustedStore(this.schema, keys, columns);
379
380
  this.#commitChunk(store);
@@ -7,9 +7,8 @@ import { TimeSeries, type KeyLike } from '../batch/time-series.js';
7
7
  import type { Sequence } from '../sequence/sequence.js';
8
8
  import { TimeKeyColumn } from '../columnar/key-column.js';
9
9
  import type { PublicColumnForKind, KeyColumnForSchema } from '../column.js';
10
- import { EMITS_EVICT, type AggregateMap, type AggregateOutputMap, type AggregateSchema, type DiffSchema, type EventDataForSchema, type EventForSchema, type LiveSource, type NumericColumnNameForSchema, type ValueColumnNameForSchema, type RollingSchema, type ScalarValue, type SelectSchema, type SeriesSchema, type ValueColumnsForSchema } from '../schema/index.js';
11
- import type { AggregateOutputMapResultSchema, RollingOutputMapSchema } from '../schema/index.js';
12
- import type { FusedMapping, FusedMappingValid, FusedRollingSchema } from '../schema/index.js';
10
+ import { type AggregateSchema, type DiffSchema, type EventDataForSchema, type EventForSchema, type LiveSource, type NumericColumnNameForSchema, type ValueColumnNameForSchema, type RollingSchema, type ScalarValue, type SelectSchema, type SeriesSchema, type ValueColumnsForSchema } from '../schema/index.js';
11
+ import type { FusedMapping, FusedMappingValid, FusedRollingSchema, ValidatedAggregateMap } from '../schema/index.js';
13
12
  export type LiveFillStrategy = 'hold' | 'zero';
14
13
  export type LiveFillMapping<S extends SeriesSchema> = {
15
14
  [K in ValueColumnsForSchema<S>[number]['name']]?: LiveFillStrategy | ScalarValue;
@@ -40,7 +39,6 @@ type ViewOptions<S extends SeriesSchema> = {
40
39
  type TimeKeyOnly<S extends SeriesSchema> = KeyColumnForSchema<S> extends TimeKeyColumn ? KeyColumnForSchema<S> : 'LiveView.keyColumn() supports time-keyed views only — use toTimeSeries() for other key kinds';
41
40
  export declare class LiveView<S extends SeriesSchema> implements LiveSource<S> {
42
41
  #private;
43
- readonly [EMITS_EVICT]: true;
44
42
  readonly name: string;
45
43
  readonly schema: S;
46
44
  constructor(source: LiveSource<any>, process: (event: any) => EventForSchema<S> | undefined, options?: ViewOptions<S>);
@@ -122,10 +120,8 @@ export declare class LiveView<S extends SeriesSchema> implements LiveSource<S> {
122
120
  * is per-event derivative of the named columns.
123
121
  */
124
122
  eventRate(): number;
125
- aggregate<const M extends AggregateMap<S>>(sequence: Sequence, mapping: M): LiveAggregation<S, AggregateSchema<S, M>>;
126
- aggregate<const M extends AggregateOutputMap<S>>(sequence: Sequence, mapping: M): LiveAggregation<S, AggregateOutputMapResultSchema<S, M>>;
127
- rolling<const M extends AggregateMap<S>>(window: RollingWindow, mapping: M, options?: LiveRollingOptions): LiveRollingAggregation<S, RollingSchema<S, M>>;
128
- rolling<const M extends AggregateOutputMap<S>>(window: RollingWindow, mapping: M, options?: LiveRollingOptions): LiveRollingAggregation<S, RollingOutputMapSchema<S, M>>;
123
+ aggregate<const M extends ValidatedAggregateMap<S, M>>(sequence: Sequence, mapping: M): LiveAggregation<S, AggregateSchema<S, M>>;
124
+ rolling<const M extends ValidatedAggregateMap<S, M>>(window: RollingWindow, mapping: M, options?: LiveRollingOptions): LiveRollingAggregation<S, RollingSchema<S, M>>;
129
125
  /**
130
126
  * Keyed-form fused multi-window rolling on a `LiveView`. See
131
127
  * {@link LiveSeries.rolling} for the full surface — chained-from-
@@ -137,8 +133,7 @@ export declare class LiveView<S extends SeriesSchema> implements LiveSource<S> {
137
133
  * Streaming reduce over the view's current buffer. See
138
134
  * {@link LiveSeries.reduce} for the full surface.
139
135
  */
140
- reduce<const M extends AggregateMap<S>>(mapping: M, options?: LiveRollingOptions): LiveReduce<S, RollingSchema<S, M>>;
141
- reduce<const M extends AggregateOutputMap<S>>(mapping: M, options?: LiveRollingOptions): LiveReduce<S, RollingOutputMapSchema<S, M>>;
136
+ reduce<const M extends ValidatedAggregateMap<S, M>>(mapping: M, options?: LiveRollingOptions): LiveReduce<S, RollingSchema<S, M>>;
142
137
  diff<const Target extends NumericColumnNameForSchema<S>>(columns: Target | readonly Target[], options?: {
143
138
  drop?: boolean;
144
139
  }): LiveView<DiffSchema<S, Target>>;
@@ -11,6 +11,7 @@ import { TimeKeyColumn } from '../columnar/key-column.js';
11
11
  import { EMITS_EVICT, } from '../schema/index.js';
12
12
  import { parseDuration } from '../core/duration.js';
13
13
  export class LiveView {
14
+ /** @internal */
14
15
  [EMITS_EVICT] = true;
15
16
  name;
16
17
  schema;
@@ -1,6 +1,7 @@
1
1
  import { rollingOrderedEntries } from './rolling.js';
2
2
  export const first = {
3
3
  outputKind: 'source',
4
+ definedBoundary: 'first',
4
5
  reduce(defined) {
5
6
  return defined[0];
6
7
  },
@@ -1,6 +1,7 @@
1
1
  import { rollingOrderedEntries } from './rolling.js';
2
2
  export const last = {
3
3
  outputKind: 'source',
4
+ definedBoundary: 'last',
4
5
  reduce(defined) {
5
6
  return defined[defined.length - 1];
6
7
  },
@@ -85,6 +85,22 @@ export type ReducerDef = {
85
85
  * `reduceColumn` may assume the column is a packed `Float64Column`.
86
86
  */
87
87
  reduceColumn?(col: Float64Column): ColumnValue | undefined;
88
+ /**
89
+ * **Columnar fast-path for boundary selectors.** Present only on
90
+ * `first` / `last`. Marks the reducer as "pick the {first|last}
91
+ * *defined* value in the bucket" — which a columnar caller can compute
92
+ * as a boundary scan over the source column (via `col.read(i)`, any
93
+ * kind / any storage) instead of bailing the whole call to the row
94
+ * path just because these reducers lack a numeric `reduceColumn`.
95
+ *
96
+ * Semantics match `reduce` / `bucketState` exactly: scan past *missing*
97
+ * cells to the first/last cell whose `read(i)` is not `undefined`; an
98
+ * all-missing or empty bucket yields `undefined`. This is what lets the
99
+ * partitioned-`aggregate` fast path run — the auto-injected
100
+ * partition-column reducer is `'first'` (see `PartitionedTimeSeries`),
101
+ * which previously tripped the all-or-nothing gate for every call.
102
+ */
103
+ definedBoundary?: 'first' | 'last';
88
104
  /** Return a fresh incremental state for one aggregation bucket. */
89
105
  bucketState(): AggregateBucketState;
90
106
  /** Return a fresh incremental state for one rolling window column. */