Skip to main content

Concepts

pond-ts is an in-memory TypeScript time series library covering both batch and streaming use cases as peers — same schema type, same operator surface, different cost models. Not a database, not a query engine, not a full streaming system.

Mental model

A series is a schema-typed, ordered collection of events. Events carry a temporal key plus a typed payload. Operators transform series into series; reducers compress events into values.

Mental model: a TimeSeries / LiveSeries flows through grid-
preserving transforms (filter, map, rolling, smooth, ...) into
another TimeSeries / accumulator, then through grid-changing
windowing (aggregate, rolling, reduce) into a bucketed series or
scalar record

The schema S carries through every transform — the type system narrows column shapes correctly without as casts.

Core primitives

PrimitiveWhat it isPage
Temporal keysTime / TimeRange / Interval — points and spans on the timelineTemporal keys
SequencesGrid definitions (fixed-step / calendar / bounded)Sequences
SeriesTimeSeries (batch) and LiveSeries (streaming) — peersSeries
Temporal relationswithin / overlapping / trim; tail, first, last as conceptsTemporal relations
WindowingFull / fixed / rolling / streaming-rolling / multi-window — five modesWindowing
TriggersWhen live aggregations emit (event / every / count)Triggers
PartitioningPer-entity scope: split, operate, fan inPartitioning
Late data"Data is the clock"; ordering modes; grace windowsLate data

Read the pages reference-style — definitional, no walkthroughs. The operator pages assume the vocabulary these introduce.

Coming from pandas?

pandas's .resample() covers both directions; pond-ts splits them:

  • Downsample (fewer rows out than in) — aggregate(seq, mapping).resample().agg()
  • Upsample / regrid (one row per grid point, hold or interpolate) — align(seq, { method }).asfreq() + .ffill() / .interpolate('time')
  • rolling(window, mapping).rolling().agg()
  • within(range) / overlapping(range) / trim(range).loc[] slicing with three explicit semantics
  • reduce(mapping).agg() on the whole frame
  • groupBy(col).groupby(col)

See Aggregation for the deep dive on bucketing.

Coming from pondjs?

pondjspond-ts
TimeSeries (sorted)TimeSeries (1:1 conceptually; methods differ)
Collection (unordered)TimeSeries — pond-ts only exposes the sorted variant
IndexedEventEvent<Interval>
TimeRangeEventEvent<TimeRange>
Pipeline + processorsmethod chain on TimeSeries
Pond / Aggregatorbatch aggregate() or LiveAggregation

Pond-ts deliberately drops the Collection / TimeSeries distinction. A bucket is a smaller TimeSeries, so anything that works on a series works on a bucket — same API, no second primitive to learn.

What pond-ts isn't

  • Not a database. No persistence layer. Snapshots round-trip through JSON; the storage is your problem.
  • Not a query engine. No SQL surface. Operators are the query surface, end-to-end typed.
  • Not a full streaming engine. LiveSeries is a bounded in-process buffer with bounded reorder tolerance. No watermarks, no exactly-once, no retraction. See Late data for the trade-offs.
  • Not a chart library. series.toPoints() is the bridge; pick any chart library that consumes [x, y] tuples.