pond-ts 0.1.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/LICENSE +21 -0
- package/README.md +348 -0
- package/dist/BoundedSequence.d.ts +28 -0
- package/dist/BoundedSequence.d.ts.map +1 -0
- package/dist/BoundedSequence.js +70 -0
- package/dist/BoundedSequence.js.map +1 -0
- package/dist/Event.d.ts +84 -0
- package/dist/Event.d.ts.map +1 -0
- package/dist/Event.js +162 -0
- package/dist/Event.js.map +1 -0
- package/dist/Interval.d.ts +51 -0
- package/dist/Interval.d.ts.map +1 -0
- package/dist/Interval.js +130 -0
- package/dist/Interval.js.map +1 -0
- package/dist/Sequence.d.ts +80 -0
- package/dist/Sequence.d.ts.map +1 -0
- package/dist/Sequence.js +197 -0
- package/dist/Sequence.js.map +1 -0
- package/dist/Time.d.ts +43 -0
- package/dist/Time.d.ts.map +1 -0
- package/dist/Time.js +78 -0
- package/dist/Time.js.map +1 -0
- package/dist/TimeRange.d.ts +45 -0
- package/dist/TimeRange.d.ts.map +1 -0
- package/dist/TimeRange.js +144 -0
- package/dist/TimeRange.js.map +1 -0
- package/dist/TimeSeries.d.ts +337 -0
- package/dist/TimeSeries.d.ts.map +1 -0
- package/dist/TimeSeries.js +1217 -0
- package/dist/TimeSeries.js.map +1 -0
- package/dist/calendar.d.ts +24 -0
- package/dist/calendar.d.ts.map +1 -0
- package/dist/calendar.js +96 -0
- package/dist/calendar.js.map +1 -0
- package/dist/errors.d.ts +4 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +7 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/temporal.d.ts +37 -0
- package/dist/temporal.d.ts.map +1 -0
- package/dist/temporal.js +29 -0
- package/dist/temporal.js.map +1 -0
- package/dist/types.d.ts +175 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +3 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +145 -0
- package/dist/validate.js.map +1 -0
- package/package.json +44 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Peter Murphy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
# pond-ts
|
|
2
|
+
|
|
3
|
+
TypeScript-first time series primitives built around typed events, typed schemas, and explicit temporal keys.
|
|
4
|
+
|
|
5
|
+
The package is intended to work in modern Node and frontend projects. The repo toolchain should work on Node 18, and we can use `nvm` to verify against newer stable Node releases when needed.
|
|
6
|
+
|
|
7
|
+
The library is currently focused on non-streaming analytics:
|
|
8
|
+
|
|
9
|
+
- typed `TimeSeries` construction
|
|
10
|
+
- `Time`, `TimeRange`, and `Interval` keys
|
|
11
|
+
- immutable `Event` objects
|
|
12
|
+
- alignment, aggregation, joins, rolling windows, and smoothing
|
|
13
|
+
- timezone-aware calendar sequences and ingest helpers
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npm install pond-ts
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Build
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm run build
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Format
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
npm run format
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Test
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
npm test
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Verify
|
|
40
|
+
|
|
41
|
+
```sh
|
|
42
|
+
npm run verify
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## License
|
|
46
|
+
|
|
47
|
+
MIT
|
|
48
|
+
|
|
49
|
+
## Core model
|
|
50
|
+
|
|
51
|
+
The key types are:
|
|
52
|
+
|
|
53
|
+
- `Time`: a point in time
|
|
54
|
+
- `TimeRange`: an unlabeled interval
|
|
55
|
+
- `Interval`: a labeled interval
|
|
56
|
+
|
|
57
|
+
An `Event` is a key plus typed data.
|
|
58
|
+
|
|
59
|
+
A `TimeSeries` is an ordered immutable collection of events sharing one schema.
|
|
60
|
+
|
|
61
|
+
## Quick start
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
import { TimeSeries } from 'pond-ts';
|
|
65
|
+
|
|
66
|
+
const schema = [
|
|
67
|
+
{ name: 'time', kind: 'time' },
|
|
68
|
+
{ name: 'cpu', kind: 'number' },
|
|
69
|
+
{ name: 'host', kind: 'string' },
|
|
70
|
+
{ name: 'healthy', kind: 'boolean' },
|
|
71
|
+
] as const;
|
|
72
|
+
|
|
73
|
+
const series = new TimeSeries({
|
|
74
|
+
name: 'cpu',
|
|
75
|
+
schema,
|
|
76
|
+
rows: [
|
|
77
|
+
[new Date('2025-01-01T00:00:00.000Z'), 0.42, 'api-1', true],
|
|
78
|
+
[new Date('2025-01-01T00:01:00.000Z'), 0.51, 'api-2', true],
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const event = series.at(1);
|
|
83
|
+
if (!event) {
|
|
84
|
+
throw new Error('missing event');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
event.key();
|
|
88
|
+
event.timeRange();
|
|
89
|
+
event.get('cpu');
|
|
90
|
+
event.data().host;
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## JSON ingest
|
|
94
|
+
|
|
95
|
+
Use `TimeSeries.fromJSON(...)` for external data and ambiguous local timestamps.
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
import { TimeSeries } from 'pond-ts';
|
|
99
|
+
|
|
100
|
+
const schema = [
|
|
101
|
+
{ name: 'time', kind: 'time' },
|
|
102
|
+
{ name: 'value', kind: 'number' },
|
|
103
|
+
{ name: 'status', kind: 'string', required: false },
|
|
104
|
+
] as const;
|
|
105
|
+
|
|
106
|
+
const series = TimeSeries.fromJSON({
|
|
107
|
+
name: 'cpu',
|
|
108
|
+
schema,
|
|
109
|
+
rows: [
|
|
110
|
+
['2025-01-01T09:00', 0.42, 'ok'],
|
|
111
|
+
['2025-01-01T10:00', 0.51, null],
|
|
112
|
+
],
|
|
113
|
+
parse: { timeZone: 'Europe/Madrid' },
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
## Event and series transforms
|
|
118
|
+
|
|
119
|
+
Event-level transforms:
|
|
120
|
+
|
|
121
|
+
- `get(...)`
|
|
122
|
+
- `set(...)`
|
|
123
|
+
- `merge(...)`
|
|
124
|
+
- `select(...)`
|
|
125
|
+
- `rename(...)`
|
|
126
|
+
- `collapse(...)`
|
|
127
|
+
- `asTime(...)`
|
|
128
|
+
- `asTimeRange()`
|
|
129
|
+
- `asInterval(...)`
|
|
130
|
+
|
|
131
|
+
Series-level transforms:
|
|
132
|
+
|
|
133
|
+
- `map(...)`
|
|
134
|
+
- `select(...)`
|
|
135
|
+
- `rename(...)`
|
|
136
|
+
- `collapse(...)`
|
|
137
|
+
- `asTime(...)`
|
|
138
|
+
- `asTimeRange()`
|
|
139
|
+
- `asInterval(...)`
|
|
140
|
+
|
|
141
|
+
Example:
|
|
142
|
+
|
|
143
|
+
```ts
|
|
144
|
+
const renamed = series.rename({ cpu: 'usage' });
|
|
145
|
+
const selected = renamed.select('usage', 'healthy');
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Temporal selection
|
|
149
|
+
|
|
150
|
+
`TimeSeries` includes both positional and temporal selection methods:
|
|
151
|
+
|
|
152
|
+
- `slice(...)`
|
|
153
|
+
- `filter(...)`
|
|
154
|
+
- `find(...)`
|
|
155
|
+
- `first()`
|
|
156
|
+
- `last()`
|
|
157
|
+
- `before(...)`
|
|
158
|
+
- `after(...)`
|
|
159
|
+
- `within(...)`
|
|
160
|
+
- `overlapping(...)`
|
|
161
|
+
- `containedBy(...)`
|
|
162
|
+
- `trim(...)`
|
|
163
|
+
- `includesKey(...)`
|
|
164
|
+
- `bisect(...)`
|
|
165
|
+
- `atOrBefore(...)`
|
|
166
|
+
- `atOrAfter(...)`
|
|
167
|
+
|
|
168
|
+
Vocabulary is intentionally distinct:
|
|
169
|
+
|
|
170
|
+
- `within(...)`: fully contained
|
|
171
|
+
- `overlapping(...)`: intersects without clipping
|
|
172
|
+
- `trim(...)`: intersects and clips event extents
|
|
173
|
+
|
|
174
|
+
## Sequences
|
|
175
|
+
|
|
176
|
+
Use `Sequence` for unbounded grids and `BoundedSequence` for explicit finite interval lists.
|
|
177
|
+
|
|
178
|
+
Fixed-step sequences:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { Sequence } from 'pond-ts';
|
|
182
|
+
|
|
183
|
+
const minuteGrid = Sequence.every('1m');
|
|
184
|
+
const hourlyGrid = Sequence.hourly();
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Calendar-aware sequences:
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
const localDays = Sequence.calendar('day', {
|
|
191
|
+
timeZone: 'America/New_York',
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Explicit bounded sequences:
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import { BoundedSequence, Interval } from 'pond-ts';
|
|
199
|
+
|
|
200
|
+
const buckets = new BoundedSequence([
|
|
201
|
+
new Interval({ value: 'a', start: 0, end: 10 }),
|
|
202
|
+
new Interval({ value: 'b', start: 20, end: 30 }),
|
|
203
|
+
]);
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Alignment and aggregation
|
|
207
|
+
|
|
208
|
+
Align onto a sequence:
|
|
209
|
+
|
|
210
|
+
```ts
|
|
211
|
+
const aligned = series.align(Sequence.every('1m'), {
|
|
212
|
+
method: 'hold',
|
|
213
|
+
});
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Aggregate into buckets:
|
|
217
|
+
|
|
218
|
+
```ts
|
|
219
|
+
const aggregated = series.aggregate(Sequence.every('5m'), {
|
|
220
|
+
cpu: 'avg',
|
|
221
|
+
host: 'last',
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Built-in aggregations:
|
|
226
|
+
|
|
227
|
+
- `sum`
|
|
228
|
+
- `avg`
|
|
229
|
+
- `min`
|
|
230
|
+
- `max`
|
|
231
|
+
- `count`
|
|
232
|
+
- `first`
|
|
233
|
+
- `last`
|
|
234
|
+
|
|
235
|
+
## Joins
|
|
236
|
+
|
|
237
|
+
Join two aligned or bucketed series:
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
const joined = left.join(right, { type: 'outer' });
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
Supported join types:
|
|
244
|
+
|
|
245
|
+
- `outer`
|
|
246
|
+
- `left`
|
|
247
|
+
- `right`
|
|
248
|
+
- `inner`
|
|
249
|
+
|
|
250
|
+
Join many:
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
const wide = TimeSeries.joinMany([cpu, memory, errors], {
|
|
254
|
+
type: 'outer',
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
Conflict handling:
|
|
259
|
+
|
|
260
|
+
- default: `onConflict: "error"`
|
|
261
|
+
- optional prefixing:
|
|
262
|
+
|
|
263
|
+
```ts
|
|
264
|
+
const joined = left.join(right, {
|
|
265
|
+
onConflict: 'prefix',
|
|
266
|
+
prefixes: ['left', 'right'] as const,
|
|
267
|
+
});
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Rolling windows
|
|
271
|
+
|
|
272
|
+
Event-driven rolling:
|
|
273
|
+
|
|
274
|
+
```ts
|
|
275
|
+
const rolled = series.rolling('5m', {
|
|
276
|
+
cpu: 'avg',
|
|
277
|
+
host: 'last',
|
|
278
|
+
});
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
Sequence-driven rolling:
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
const rolledOnGrid = series.rolling(Sequence.every('1m'), '5m', { cpu: 'avg' });
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Rolling alignment options:
|
|
288
|
+
|
|
289
|
+
- `trailing`
|
|
290
|
+
- `centered`
|
|
291
|
+
- `leading`
|
|
292
|
+
|
|
293
|
+
## Smoothing
|
|
294
|
+
|
|
295
|
+
Smoothing targets one numeric column at a time.
|
|
296
|
+
|
|
297
|
+
Replace the source column:
|
|
298
|
+
|
|
299
|
+
```ts
|
|
300
|
+
const smoothed = series.smooth('cpu', 'ema', { alpha: 0.2 });
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
Append the smoothed output:
|
|
304
|
+
|
|
305
|
+
```ts
|
|
306
|
+
const smoothed = series.smooth('cpu', 'movingAverage', {
|
|
307
|
+
window: '5m',
|
|
308
|
+
alignment: 'centered',
|
|
309
|
+
output: 'cpuAvg',
|
|
310
|
+
});
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Supported smoothing methods:
|
|
314
|
+
|
|
315
|
+
- `ema`
|
|
316
|
+
- `movingAverage`
|
|
317
|
+
- `loess`
|
|
318
|
+
|
|
319
|
+
For interval-like keys, smoothing uses the key midpoint as the internal anchor.
|
|
320
|
+
|
|
321
|
+
## Calendar-aware helpers
|
|
322
|
+
|
|
323
|
+
Primitive helpers normalize local calendar inputs into absolute time:
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
import { Interval, Time, TimeRange } from 'pond-ts';
|
|
327
|
+
|
|
328
|
+
const time = Time.parse('2025-01-01T09:00', { timeZone: 'Europe/Madrid' });
|
|
329
|
+
const day = TimeRange.fromDate('2025-01-01', { timeZone: 'UTC' });
|
|
330
|
+
const month = Interval.fromCalendar('month', '2025-01', {
|
|
331
|
+
timeZone: 'UTC',
|
|
332
|
+
value: '2025-01',
|
|
333
|
+
});
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Current scope
|
|
337
|
+
|
|
338
|
+
This package is batch-oriented and immutable.
|
|
339
|
+
|
|
340
|
+
It does not yet provide a dedicated live/streaming ingestion layer. The current focus is:
|
|
341
|
+
|
|
342
|
+
- type-safe construction
|
|
343
|
+
- temporal modeling
|
|
344
|
+
- composable non-streaming analytics
|
|
345
|
+
|
|
346
|
+
## License
|
|
347
|
+
|
|
348
|
+
No license file is included yet.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Interval } from './Interval.js';
|
|
2
|
+
import { TimeRange } from './TimeRange.js';
|
|
3
|
+
/**
|
|
4
|
+
* A finite ordered list of `Interval` buckets.
|
|
5
|
+
*
|
|
6
|
+
* Use `BoundedSequence` when you already have an explicit interval list, or use
|
|
7
|
+
* `Sequence.bounded(...)` to realize a finite run from an unbounded grid definition.
|
|
8
|
+
*/
|
|
9
|
+
export declare class BoundedSequence {
|
|
10
|
+
#private;
|
|
11
|
+
/** Example: `new BoundedSequence([intervalA, intervalB])`. Creates a finite interval sequence from an explicit list. */
|
|
12
|
+
constructor(intervals: ReadonlyArray<Interval>);
|
|
13
|
+
/** Example: `bounded.length`. Returns the number of intervals in the bounded sequence. */
|
|
14
|
+
get length(): number;
|
|
15
|
+
/** Example: `bounded.at(0)`. Returns the interval at the supplied position, if present. */
|
|
16
|
+
at(index: number): Interval | undefined;
|
|
17
|
+
/** Example: `bounded.first()`. Returns the first interval, if present. */
|
|
18
|
+
first(): Interval | undefined;
|
|
19
|
+
/** Example: `bounded.last()`. Returns the last interval, if present. */
|
|
20
|
+
last(): Interval | undefined;
|
|
21
|
+
/** Example: `bounded.timeRange()`. Returns the finite temporal extent of this bounded sequence, if any. */
|
|
22
|
+
timeRange(): TimeRange | undefined;
|
|
23
|
+
/** Example: `bounded.slice(0, 10)`. Returns a positional half-open slice of the bounded sequence. */
|
|
24
|
+
slice(beginIndex?: number, endIndex?: number): BoundedSequence;
|
|
25
|
+
/** Example: `bounded.intervals()`. Returns the finite explicit intervals represented by this bounded sequence. */
|
|
26
|
+
intervals(): ReadonlyArray<Interval>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=BoundedSequence.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BoundedSequence.d.ts","sourceRoot":"","sources":["../src/BoundedSequence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AA6B3C;;;;;GAKG;AACH,qBAAa,eAAe;;IAG1B,wHAAwH;gBAC5G,SAAS,EAAE,aAAa,CAAC,QAAQ,CAAC;IAM9C,0FAA0F;IAC1F,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,2FAA2F;IAC3F,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIvC,0EAA0E;IAC1E,KAAK,IAAI,QAAQ,GAAG,SAAS;IAI7B,wEAAwE;IACxE,IAAI,IAAI,QAAQ,GAAG,SAAS;IAM5B,2GAA2G;IAC3G,SAAS,IAAI,SAAS,GAAG,SAAS;IASlC,qGAAqG;IACrG,KAAK,CAAC,UAAU,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,eAAe;IAI9D,kHAAkH;IAClH,SAAS,IAAI,aAAa,CAAC,QAAQ,CAAC;CAGrC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { TimeRange } from './TimeRange.js';
|
|
2
|
+
function validateIntervals(intervals) {
|
|
3
|
+
for (let index = 0; index < intervals.length; index += 1) {
|
|
4
|
+
const current = intervals[index];
|
|
5
|
+
if (current.end() <= current.begin()) {
|
|
6
|
+
throw new TypeError('bounded sequence intervals must have positive duration');
|
|
7
|
+
}
|
|
8
|
+
if (index === 0) {
|
|
9
|
+
continue;
|
|
10
|
+
}
|
|
11
|
+
const previous = intervals[index - 1];
|
|
12
|
+
if (current.begin() < previous.begin()) {
|
|
13
|
+
throw new TypeError('bounded sequence intervals must be sorted by start time');
|
|
14
|
+
}
|
|
15
|
+
if (current.begin() < previous.end()) {
|
|
16
|
+
throw new TypeError('bounded sequence intervals must not overlap');
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A finite ordered list of `Interval` buckets.
|
|
22
|
+
*
|
|
23
|
+
* Use `BoundedSequence` when you already have an explicit interval list, or use
|
|
24
|
+
* `Sequence.bounded(...)` to realize a finite run from an unbounded grid definition.
|
|
25
|
+
*/
|
|
26
|
+
export class BoundedSequence {
|
|
27
|
+
#intervals;
|
|
28
|
+
/** Example: `new BoundedSequence([intervalA, intervalB])`. Creates a finite interval sequence from an explicit list. */
|
|
29
|
+
constructor(intervals) {
|
|
30
|
+
validateIntervals(intervals);
|
|
31
|
+
this.#intervals = Object.freeze(intervals.slice());
|
|
32
|
+
Object.freeze(this);
|
|
33
|
+
}
|
|
34
|
+
/** Example: `bounded.length`. Returns the number of intervals in the bounded sequence. */
|
|
35
|
+
get length() {
|
|
36
|
+
return this.#intervals.length;
|
|
37
|
+
}
|
|
38
|
+
/** Example: `bounded.at(0)`. Returns the interval at the supplied position, if present. */
|
|
39
|
+
at(index) {
|
|
40
|
+
return this.#intervals[index];
|
|
41
|
+
}
|
|
42
|
+
/** Example: `bounded.first()`. Returns the first interval, if present. */
|
|
43
|
+
first() {
|
|
44
|
+
return this.at(0);
|
|
45
|
+
}
|
|
46
|
+
/** Example: `bounded.last()`. Returns the last interval, if present. */
|
|
47
|
+
last() {
|
|
48
|
+
return this.#intervals.length === 0
|
|
49
|
+
? undefined
|
|
50
|
+
: this.#intervals[this.#intervals.length - 1];
|
|
51
|
+
}
|
|
52
|
+
/** Example: `bounded.timeRange()`. Returns the finite temporal extent of this bounded sequence, if any. */
|
|
53
|
+
timeRange() {
|
|
54
|
+
const first = this.first();
|
|
55
|
+
const last = this.last();
|
|
56
|
+
if (!first || !last) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return new TimeRange({ start: first.begin(), end: last.end() });
|
|
60
|
+
}
|
|
61
|
+
/** Example: `bounded.slice(0, 10)`. Returns a positional half-open slice of the bounded sequence. */
|
|
62
|
+
slice(beginIndex, endIndex) {
|
|
63
|
+
return new BoundedSequence(this.#intervals.slice(beginIndex, endIndex));
|
|
64
|
+
}
|
|
65
|
+
/** Example: `bounded.intervals()`. Returns the finite explicit intervals represented by this bounded sequence. */
|
|
66
|
+
intervals() {
|
|
67
|
+
return this.#intervals;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=BoundedSequence.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BoundedSequence.js","sourceRoot":"","sources":["../src/BoundedSequence.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAE3C,SAAS,iBAAiB,CAAC,SAAkC;IAC3D,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,SAAS,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACzD,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAE,CAAC;QAElC,IAAI,OAAO,CAAC,GAAG,EAAE,IAAI,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;YACrC,MAAM,IAAI,SAAS,CACjB,wDAAwD,CACzD,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,SAAS;QACX,CAAC;QAED,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,GAAG,CAAC,CAAE,CAAC;QACvC,IAAI,OAAO,CAAC,KAAK,EAAE,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;YACvC,MAAM,IAAI,SAAS,CACjB,yDAAyD,CAC1D,CAAC;QACJ,CAAC;QAED,IAAI,OAAO,CAAC,KAAK,EAAE,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC;YACrC,MAAM,IAAI,SAAS,CAAC,6CAA6C,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,OAAO,eAAe;IACjB,UAAU,CAA0B;IAE7C,wHAAwH;IACxH,YAAY,SAAkC;QAC5C,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAC7B,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC,CAAC;QACnD,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;IAED,0FAA0F;IAC1F,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;IAChC,CAAC;IAED,2FAA2F;IAC3F,EAAE,CAAC,KAAa;QACd,OAAO,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IAChC,CAAC;IAED,0EAA0E;IAC1E,KAAK;QACH,OAAO,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,wEAAwE;IACxE,IAAI;QACF,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,KAAK,CAAC;YACjC,CAAC,CAAC,SAAS;YACX,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,2GAA2G;IAC3G,SAAS;QACP,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QACzB,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;YACpB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,IAAI,SAAS,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,qGAAqG;IACrG,KAAK,CAAC,UAAmB,EAAE,QAAiB;QAC1C,OAAO,IAAI,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC1E,CAAC;IAED,kHAAkH;IAClH,SAAS;QACP,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;CACF"}
|
package/dist/Event.d.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { Interval } from './Interval.js';
|
|
2
|
+
import { Time } from './Time.js';
|
|
3
|
+
import { TimeRange } from './TimeRange.js';
|
|
4
|
+
import type { EventKey, IntervalValue, TemporalLike } from './temporal.js';
|
|
5
|
+
type ScalarValue = number | string | boolean;
|
|
6
|
+
type CollapseData<D, Keys extends keyof D, Name extends string, R extends ScalarValue, Append extends boolean = false> = Append extends true ? Readonly<D & Record<Name, R>> : Readonly<Omit<D, Keys> & Record<Name, R>>;
|
|
7
|
+
type SelectData<D, Keys extends keyof D> = Readonly<Pick<D, Keys>>;
|
|
8
|
+
type RenameMap<D> = Partial<{
|
|
9
|
+
[K in keyof D & string]: string;
|
|
10
|
+
}>;
|
|
11
|
+
type RenameData<D, Mapping extends RenameMap<D>> = Readonly<{
|
|
12
|
+
[Name in keyof D & string as Name extends keyof Mapping ? Mapping[Name] extends string ? Mapping[Name] : Name : Name]: D[Name];
|
|
13
|
+
}>;
|
|
14
|
+
/**
|
|
15
|
+
* An immutable event made of a temporal key and typed payload data.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* const event = new Event(
|
|
20
|
+
* new Time(new Date("2025-01-01T00:00:00.000Z")),
|
|
21
|
+
* { cpu: 0.42, host: "api-1" },
|
|
22
|
+
* );
|
|
23
|
+
*
|
|
24
|
+
* event.get("cpu"); // 0.42
|
|
25
|
+
* event.timeRange(); // TimeRange for the event extent
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare class Event<K extends EventKey, D> {
|
|
29
|
+
#private;
|
|
30
|
+
/** Example: `new Event(new Time(Date.now()), { value: 1 })`. Creates an immutable event from a key and typed payload object. */
|
|
31
|
+
constructor(key: K, data: D);
|
|
32
|
+
/** Example: `event.key()`. Returns the event key. */
|
|
33
|
+
key(): K;
|
|
34
|
+
/** Example: `event.withKey(new Time(Date.now()))`. Returns a new event with the same payload and a different key. */
|
|
35
|
+
withKey<NextKey extends EventKey>(key: NextKey): Event<NextKey, D>;
|
|
36
|
+
/** Example: `event.type()`. Returns the underlying key kind. */
|
|
37
|
+
type(): K['kind'];
|
|
38
|
+
/** Example: `event.data()`. Returns the immutable event payload. */
|
|
39
|
+
data(): Readonly<D>;
|
|
40
|
+
/** Example: `event.get("value")`. Returns a single payload field by name. */
|
|
41
|
+
get<Field extends keyof D>(field: Field): Readonly<D>[Field];
|
|
42
|
+
/** Example: `event.set("value", 2)`. Returns a new event with one payload field replaced. */
|
|
43
|
+
set<Field extends keyof D>(field: Field, value: D[Field]): Event<K, D>;
|
|
44
|
+
/** Example: `event.merge({ host: "api-1" })`. Returns a new event with a shallow payload merge applied. */
|
|
45
|
+
merge<U extends object>(patch: U): Event<K, Readonly<D & U>>;
|
|
46
|
+
/** Example: `event.select("cpu", "healthy")`. Returns a new event containing only the selected payload fields. */
|
|
47
|
+
select<const Keys extends readonly (keyof D)[]>(...keys: Keys): Event<K, SelectData<D, Keys[number]>>;
|
|
48
|
+
/** Example: `event.rename({ cpu: "usage" })`. Returns a new event with payload fields renamed according to the supplied mapping. */
|
|
49
|
+
rename<const Mapping extends RenameMap<D>>(mapping: Mapping): Event<K, RenameData<D, Mapping>>;
|
|
50
|
+
/** Example: `event.collapse(["in", "out"], "avg", fn)`. Collapses selected payload fields into a single derived field using the supplied reducer. */
|
|
51
|
+
collapse<const Keys extends readonly (keyof D)[], Name extends string, R extends ScalarValue>(keys: Keys, output: Name, reducer: (values: Pick<D, Keys[number]>) => R): Event<K, CollapseData<D, Keys[number], Name, R>>;
|
|
52
|
+
collapse<const Keys extends readonly (keyof D)[], Name extends string, R extends ScalarValue>(keys: Keys, output: Name, reducer: (values: Pick<D, Keys[number]>) => R, options: {
|
|
53
|
+
append: true;
|
|
54
|
+
}): Event<K, CollapseData<D, Keys[number], Name, R, true>>;
|
|
55
|
+
/** Example: `event.timeRange()`. Returns the event extent as a `TimeRange`. */
|
|
56
|
+
timeRange(): TimeRange;
|
|
57
|
+
/** Example: `event.begin()`. Returns the inclusive event start in milliseconds since epoch. */
|
|
58
|
+
begin(): number;
|
|
59
|
+
/** Example: `event.end()`. Returns the inclusive event end in milliseconds since epoch. */
|
|
60
|
+
end(): number;
|
|
61
|
+
/** Example: `event.overlaps(range)`. Returns `true` when the event extent overlaps the supplied temporal value. */
|
|
62
|
+
overlaps(other: TemporalLike): boolean;
|
|
63
|
+
/** Example: `event.contains(time)`. Returns `true` when the event extent fully contains the supplied temporal value. */
|
|
64
|
+
contains(other: TemporalLike): boolean;
|
|
65
|
+
/** Example: `event.isBefore(range)`. Returns `true` when the event ends strictly before the supplied temporal value begins. */
|
|
66
|
+
isBefore(other: TemporalLike): boolean;
|
|
67
|
+
/** Example: `event.isAfter(range)`. Returns `true` when the event begins strictly after the supplied temporal value ends. */
|
|
68
|
+
isAfter(other: TemporalLike): boolean;
|
|
69
|
+
/** Example: `event.intersection(range)`. Returns the temporal intersection of the event extent and the supplied value, if any. */
|
|
70
|
+
intersection(other: TemporalLike): TimeRange | undefined;
|
|
71
|
+
/** Example: `event.trim(range)`. Returns a new event clipped to the supplied temporal value, if the event overlaps it. */
|
|
72
|
+
trim(other: TemporalLike): Event<K, D> | undefined;
|
|
73
|
+
/** Example: `event.asTime({ at: "center" })`. Converts the event key to a point-in-time key using the supplied anchor within the current extent. */
|
|
74
|
+
asTime(options?: {
|
|
75
|
+
at?: 'begin' | 'center' | 'end';
|
|
76
|
+
}): Event<Time, D>;
|
|
77
|
+
/** Example: `event.asTimeRange()`. Converts the event key to an unlabeled `TimeRange` covering the same extent. */
|
|
78
|
+
asTimeRange(): Event<TimeRange, D>;
|
|
79
|
+
/** Example: `event.asInterval("bucket-a")`. Converts the event key to a labeled `Interval` covering the same extent. */
|
|
80
|
+
asInterval(value: IntervalValue): Event<Interval, D>;
|
|
81
|
+
asInterval(getValue: (event: Event<K, D>) => IntervalValue): Event<Interval, D>;
|
|
82
|
+
}
|
|
83
|
+
export {};
|
|
84
|
+
//# sourceMappingURL=Event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Event.d.ts","sourceRoot":"","sources":["../src/Event.ts"],"names":[],"mappings":"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"}
|