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.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +348 -0
  3. package/dist/BoundedSequence.d.ts +28 -0
  4. package/dist/BoundedSequence.d.ts.map +1 -0
  5. package/dist/BoundedSequence.js +70 -0
  6. package/dist/BoundedSequence.js.map +1 -0
  7. package/dist/Event.d.ts +84 -0
  8. package/dist/Event.d.ts.map +1 -0
  9. package/dist/Event.js +162 -0
  10. package/dist/Event.js.map +1 -0
  11. package/dist/Interval.d.ts +51 -0
  12. package/dist/Interval.d.ts.map +1 -0
  13. package/dist/Interval.js +130 -0
  14. package/dist/Interval.js.map +1 -0
  15. package/dist/Sequence.d.ts +80 -0
  16. package/dist/Sequence.d.ts.map +1 -0
  17. package/dist/Sequence.js +197 -0
  18. package/dist/Sequence.js.map +1 -0
  19. package/dist/Time.d.ts +43 -0
  20. package/dist/Time.d.ts.map +1 -0
  21. package/dist/Time.js +78 -0
  22. package/dist/Time.js.map +1 -0
  23. package/dist/TimeRange.d.ts +45 -0
  24. package/dist/TimeRange.d.ts.map +1 -0
  25. package/dist/TimeRange.js +144 -0
  26. package/dist/TimeRange.js.map +1 -0
  27. package/dist/TimeSeries.d.ts +337 -0
  28. package/dist/TimeSeries.d.ts.map +1 -0
  29. package/dist/TimeSeries.js +1217 -0
  30. package/dist/TimeSeries.js.map +1 -0
  31. package/dist/calendar.d.ts +24 -0
  32. package/dist/calendar.d.ts.map +1 -0
  33. package/dist/calendar.js +96 -0
  34. package/dist/calendar.js.map +1 -0
  35. package/dist/errors.d.ts +4 -0
  36. package/dist/errors.d.ts.map +1 -0
  37. package/dist/errors.js +7 -0
  38. package/dist/errors.js.map +1 -0
  39. package/dist/index.d.ts +13 -0
  40. package/dist/index.d.ts.map +1 -0
  41. package/dist/index.js +9 -0
  42. package/dist/index.js.map +1 -0
  43. package/dist/temporal.d.ts +37 -0
  44. package/dist/temporal.d.ts.map +1 -0
  45. package/dist/temporal.js +29 -0
  46. package/dist/temporal.js.map +1 -0
  47. package/dist/types.d.ts +175 -0
  48. package/dist/types.d.ts.map +1 -0
  49. package/dist/types.js +2 -0
  50. package/dist/types.js.map +1 -0
  51. package/dist/validate.d.ts +3 -0
  52. package/dist/validate.d.ts.map +1 -0
  53. package/dist/validate.js +145 -0
  54. package/dist/validate.js.map +1 -0
  55. package/package.json +44 -0
package/dist/Event.js ADDED
@@ -0,0 +1,162 @@
1
+ import { Interval } from './Interval.js';
2
+ import { Time } from './Time.js';
3
+ import { TimeRange } from './TimeRange.js';
4
+ /**
5
+ * An immutable event made of a temporal key and typed payload data.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const event = new Event(
10
+ * new Time(new Date("2025-01-01T00:00:00.000Z")),
11
+ * { cpu: 0.42, host: "api-1" },
12
+ * );
13
+ *
14
+ * event.get("cpu"); // 0.42
15
+ * event.timeRange(); // TimeRange for the event extent
16
+ * ```
17
+ */
18
+ export class Event {
19
+ #key;
20
+ #data;
21
+ /** Example: `new Event(new Time(Date.now()), { value: 1 })`. Creates an immutable event from a key and typed payload object. */
22
+ constructor(key, data) {
23
+ this.#key = key;
24
+ this.#data = Object.freeze({ ...data });
25
+ Object.freeze(this);
26
+ }
27
+ /** Example: `event.key()`. Returns the event key. */
28
+ key() {
29
+ return this.#key;
30
+ }
31
+ /** Example: `event.withKey(new Time(Date.now()))`. Returns a new event with the same payload and a different key. */
32
+ withKey(key) {
33
+ return new Event(key, this.#data);
34
+ }
35
+ /** Example: `event.type()`. Returns the underlying key kind. */
36
+ type() {
37
+ return this.#key.kind;
38
+ }
39
+ /** Example: `event.data()`. Returns the immutable event payload. */
40
+ data() {
41
+ return this.#data;
42
+ }
43
+ /** Example: `event.get("value")`. Returns a single payload field by name. */
44
+ get(field) {
45
+ return this.#data[field];
46
+ }
47
+ /** Example: `event.set("value", 2)`. Returns a new event with one payload field replaced. */
48
+ set(field, value) {
49
+ return new Event(this.#key, {
50
+ ...this.#data,
51
+ [field]: value,
52
+ });
53
+ }
54
+ /** Example: `event.merge({ host: "api-1" })`. Returns a new event with a shallow payload merge applied. */
55
+ merge(patch) {
56
+ return new Event(this.#key, {
57
+ ...this.#data,
58
+ ...patch,
59
+ });
60
+ }
61
+ /** Example: `event.select("cpu", "healthy")`. Returns a new event containing only the selected payload fields. */
62
+ select(...keys) {
63
+ const selected = {};
64
+ for (const key of keys) {
65
+ selected[key] = this.#data[key];
66
+ }
67
+ return new Event(this.#key, selected);
68
+ }
69
+ /** Example: `event.rename({ cpu: "usage" })`. Returns a new event with payload fields renamed according to the supplied mapping. */
70
+ rename(mapping) {
71
+ const renamed = {};
72
+ for (const [key, value] of Object.entries(this.#data)) {
73
+ const nextKey = mapping[key] ?? key;
74
+ renamed[nextKey] = value;
75
+ }
76
+ return new Event(this.#key, renamed);
77
+ }
78
+ collapse(keys, output, reducer, options) {
79
+ const selected = {};
80
+ for (const key of keys) {
81
+ selected[key] = this.#data[key];
82
+ }
83
+ const collapsedValue = reducer(selected);
84
+ const append = options?.append === true;
85
+ if (append) {
86
+ return new Event(this.#key, {
87
+ ...this.#data,
88
+ [output]: collapsedValue,
89
+ });
90
+ }
91
+ const nextData = {};
92
+ for (const [key, value] of Object.entries(this.#data)) {
93
+ if (!keys.includes(key)) {
94
+ nextData[key] = value;
95
+ }
96
+ }
97
+ nextData[output] = collapsedValue;
98
+ return new Event(this.#key, nextData);
99
+ }
100
+ /** Example: `event.timeRange()`. Returns the event extent as a `TimeRange`. */
101
+ timeRange() {
102
+ const key = this.key();
103
+ return key instanceof TimeRange
104
+ ? key
105
+ : new TimeRange({ start: key.begin(), end: key.end() });
106
+ }
107
+ /** Example: `event.begin()`. Returns the inclusive event start in milliseconds since epoch. */
108
+ begin() {
109
+ return this.#key.begin();
110
+ }
111
+ /** Example: `event.end()`. Returns the inclusive event end in milliseconds since epoch. */
112
+ end() {
113
+ return this.#key.end();
114
+ }
115
+ /** Example: `event.overlaps(range)`. Returns `true` when the event extent overlaps the supplied temporal value. */
116
+ overlaps(other) {
117
+ return this.#key.overlaps(other);
118
+ }
119
+ /** Example: `event.contains(time)`. Returns `true` when the event extent fully contains the supplied temporal value. */
120
+ contains(other) {
121
+ return this.#key.contains(other);
122
+ }
123
+ /** Example: `event.isBefore(range)`. Returns `true` when the event ends strictly before the supplied temporal value begins. */
124
+ isBefore(other) {
125
+ return this.#key.isBefore(other);
126
+ }
127
+ /** Example: `event.isAfter(range)`. Returns `true` when the event begins strictly after the supplied temporal value ends. */
128
+ isAfter(other) {
129
+ return this.#key.isAfter(other);
130
+ }
131
+ /** Example: `event.intersection(range)`. Returns the temporal intersection of the event extent and the supplied value, if any. */
132
+ intersection(other) {
133
+ return this.#key.intersection(other);
134
+ }
135
+ /** Example: `event.trim(range)`. Returns a new event clipped to the supplied temporal value, if the event overlaps it. */
136
+ trim(other) {
137
+ const trimmedKey = this.#key.trim(other);
138
+ if (!trimmedKey) {
139
+ return undefined;
140
+ }
141
+ return new Event(trimmedKey, this.#data);
142
+ }
143
+ /** Example: `event.asTime({ at: "center" })`. Converts the event key to a point-in-time key using the supplied anchor within the current extent. */
144
+ asTime(options = {}) {
145
+ const at = options.at ?? 'begin';
146
+ const timestamp = at === 'center'
147
+ ? this.begin() + (this.end() - this.begin()) / 2
148
+ : at === 'end'
149
+ ? this.end()
150
+ : this.begin();
151
+ return this.withKey(new Time(timestamp));
152
+ }
153
+ /** Example: `event.asTimeRange()`. Converts the event key to an unlabeled `TimeRange` covering the same extent. */
154
+ asTimeRange() {
155
+ return this.withKey(new TimeRange({ start: this.begin(), end: this.end() }));
156
+ }
157
+ asInterval(value) {
158
+ const nextValue = typeof value === 'function' ? value(this) : value;
159
+ return this.withKey(new Interval({ value: nextValue, start: this.begin(), end: this.end() }));
160
+ }
161
+ }
162
+ //# sourceMappingURL=Event.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Event.js","sourceRoot":"","sources":["../src/Event.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { type CalendarOptions, type CalendarUnit, type TimeZoneOptions } from './calendar.js';
2
+ import { TimeRange } from './TimeRange.js';
3
+ import type { EventKey, IntervalInput, IntervalValue, TemporalLike } from './temporal.js';
4
+ /** A labeled time interval event key. Example: `new Interval({ value: "bucket", start, end })`. */
5
+ export declare class Interval implements EventKey {
6
+ readonly kind = "interval";
7
+ readonly value: IntervalValue;
8
+ readonly start: number;
9
+ readonly endMs: number;
10
+ /** Example: `Interval.fromDate("2025-01-01", { timeZone: "UTC" })`. Creates a labeled local-day interval using the ISO date string as the default label. */
11
+ static fromDate(reference: string, options?: TimeZoneOptions & {
12
+ value?: IntervalValue;
13
+ }): Interval;
14
+ /** Example: `Interval.fromCalendar("month", "2025-01", { timeZone: "America/New_York", value: "2025-01" })`. Creates a labeled calendar interval for the supplied reference. */
15
+ static fromCalendar(unit: CalendarUnit, reference: string, options?: CalendarOptions & {
16
+ value?: IntervalValue;
17
+ }): Interval;
18
+ /** Example: `new Interval(["bucket", start, end])`. Creates a labeled interval key from a `{ value, start, end }` object or tuple. */
19
+ constructor(input: IntervalInput);
20
+ /** Example: `interval.type() // "interval"`. Returns the key kind. */
21
+ type(): 'interval';
22
+ /** Example: `interval.begin()`. Returns the inclusive start of the interval in milliseconds since epoch. */
23
+ begin(): number;
24
+ /** Example: `interval.end()`. Returns the inclusive end of the interval in milliseconds since epoch. */
25
+ end(): number;
26
+ /** Example: `interval.valueOf()`. Returns the interval label. */
27
+ valueOf(): IntervalValue;
28
+ /** Example: `interval.asString()`. Returns the interval label as a string. */
29
+ asString(): string;
30
+ /** Example: `interval.timeRange()`. Returns the interval extent as a `TimeRange`. */
31
+ timeRange(): TimeRange;
32
+ /** Example: `interval.duration()`. Returns the temporal duration of the interval in milliseconds. */
33
+ duration(): number;
34
+ /** Example: `interval.overlaps(range)`. Returns `true` when this interval overlaps the supplied temporal value. */
35
+ overlaps(other: TemporalLike): boolean;
36
+ /** Example: `interval.contains(range)`. Returns `true` when this interval fully contains the supplied temporal value. */
37
+ contains(other: TemporalLike): boolean;
38
+ /** Example: `interval.isBefore(range)`. Returns `true` when this interval ends strictly before the supplied temporal value begins. */
39
+ isBefore(other: TemporalLike): boolean;
40
+ /** Example: `interval.isAfter(range)`. Returns `true` when this interval begins strictly after the supplied temporal value ends. */
41
+ isAfter(other: TemporalLike): boolean;
42
+ /** Example: `interval.intersection(range)`. Returns the temporal intersection with the supplied value, if any. */
43
+ intersection(other: TemporalLike): TimeRange | undefined;
44
+ /** Example: `interval.trim(range)`. Returns this interval clipped to the supplied temporal value, preserving its label when overlapping. */
45
+ trim(other: TemporalLike): Interval | undefined;
46
+ /** Example: `interval.equals(otherInterval)`. Returns `true` when the supplied key has the same label and temporal extent. */
47
+ equals(other: EventKey): boolean;
48
+ /** Example: `interval.compare(otherInterval)`. Compares this key to another key for ordering. */
49
+ compare(other: EventKey): number;
50
+ }
51
+ //# sourceMappingURL=Interval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Interval.d.ts","sourceRoot":"","sources":["../src/Interval.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,eAAe,EACrB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EACV,QAAQ,EACR,aAAa,EACb,aAAa,EACb,YAAY,EAEb,MAAM,eAAe,CAAC;AAavB,mGAAmG;AACnG,qBAAa,QAAS,YAAW,QAAQ;IACvC,QAAQ,CAAC,IAAI,cAAc;IAC3B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,4JAA4J;IAC5J,MAAM,CAAC,QAAQ,CACb,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,eAAe,GAAG;QAAE,KAAK,CAAC,EAAE,aAAa,CAAA;KAAO,GACxD,QAAQ;IASX,gLAAgL;IAChL,MAAM,CAAC,YAAY,CACjB,IAAI,EAAE,YAAY,EAClB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE,eAAe,GAAG;QAAE,KAAK,CAAC,EAAE,aAAa,CAAA;KAAO,GACxD,QAAQ;IASX,sIAAsI;gBAC1H,KAAK,EAAE,aAAa;IAyBhC,sEAAsE;IACtE,IAAI,IAAI,UAAU;IAIlB,4GAA4G;IAC5G,KAAK,IAAI,MAAM;IAIf,wGAAwG;IACxG,GAAG,IAAI,MAAM;IAIb,iEAAiE;IACjE,OAAO,IAAI,aAAa;IAIxB,8EAA8E;IAC9E,QAAQ,IAAI,MAAM;IAIlB,qFAAqF;IACrF,SAAS,IAAI,SAAS;IAItB,qGAAqG;IACrG,QAAQ,IAAI,MAAM;IAIlB,mHAAmH;IACnH,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO;IAItC,yHAAyH;IACzH,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO;IAItC,sIAAsI;IACtI,QAAQ,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO;IAItC,oIAAoI;IACpI,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO;IAIrC,kHAAkH;IAClH,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS;IAIxD,4IAA4I;IAC5I,IAAI,CAAC,KAAK,EAAE,YAAY,GAAG,QAAQ,GAAG,SAAS;IAY/C,8HAA8H;IAC9H,MAAM,CAAC,KAAK,EAAE,QAAQ,GAAG,OAAO;IAShC,iGAAiG;IACjG,OAAO,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM;CAOjC"}
@@ -0,0 +1,130 @@
1
+ import { calendarRangeForReference, dayRangeForDate, } from './calendar.js';
2
+ import { TimeRange } from './TimeRange.js';
3
+ import { compareEventKeys, compareIntervalValues, normalizeTimestamp, } from './temporal.js';
4
+ /** A labeled time interval event key. Example: `new Interval({ value: "bucket", start, end })`. */
5
+ export class Interval {
6
+ kind = 'interval';
7
+ value;
8
+ start;
9
+ endMs;
10
+ /** Example: `Interval.fromDate("2025-01-01", { timeZone: "UTC" })`. Creates a labeled local-day interval using the ISO date string as the default label. */
11
+ static fromDate(reference, options = {}) {
12
+ const range = dayRangeForDate(reference, options);
13
+ return new Interval({
14
+ value: options.value ?? reference,
15
+ start: range.start,
16
+ end: range.end,
17
+ });
18
+ }
19
+ /** Example: `Interval.fromCalendar("month", "2025-01", { timeZone: "America/New_York", value: "2025-01" })`. Creates a labeled calendar interval for the supplied reference. */
20
+ static fromCalendar(unit, reference, options = {}) {
21
+ const range = calendarRangeForReference(unit, reference, options);
22
+ return new Interval({
23
+ value: options.value ?? reference,
24
+ start: range.start,
25
+ end: range.end,
26
+ });
27
+ }
28
+ /** Example: `new Interval(["bucket", start, end])`. Creates a labeled interval key from a `{ value, start, end }` object or tuple. */
29
+ constructor(input) {
30
+ let value;
31
+ let rawStart;
32
+ let rawEnd;
33
+ if (Array.isArray(input)) {
34
+ value = input[0];
35
+ rawStart = input[1];
36
+ rawEnd = input[2];
37
+ }
38
+ else {
39
+ const objectInput = input;
40
+ value = objectInput.value;
41
+ rawStart = objectInput.start;
42
+ rawEnd = objectInput.end;
43
+ }
44
+ const start = normalizeTimestamp(rawStart, 'interval start');
45
+ const end = normalizeTimestamp(rawEnd, 'interval end');
46
+ if (start > end) {
47
+ throw new TypeError('interval start must be <= end');
48
+ }
49
+ this.value = value;
50
+ this.start = start;
51
+ this.endMs = end;
52
+ Object.freeze(this);
53
+ }
54
+ /** Example: `interval.type() // "interval"`. Returns the key kind. */
55
+ type() {
56
+ return this.kind;
57
+ }
58
+ /** Example: `interval.begin()`. Returns the inclusive start of the interval in milliseconds since epoch. */
59
+ begin() {
60
+ return this.start;
61
+ }
62
+ /** Example: `interval.end()`. Returns the inclusive end of the interval in milliseconds since epoch. */
63
+ end() {
64
+ return this.endMs;
65
+ }
66
+ /** Example: `interval.valueOf()`. Returns the interval label. */
67
+ valueOf() {
68
+ return this.value;
69
+ }
70
+ /** Example: `interval.asString()`. Returns the interval label as a string. */
71
+ asString() {
72
+ return String(this.value);
73
+ }
74
+ /** Example: `interval.timeRange()`. Returns the interval extent as a `TimeRange`. */
75
+ timeRange() {
76
+ return new TimeRange({ start: this.start, end: this.endMs });
77
+ }
78
+ /** Example: `interval.duration()`. Returns the temporal duration of the interval in milliseconds. */
79
+ duration() {
80
+ return this.endMs - this.start;
81
+ }
82
+ /** Example: `interval.overlaps(range)`. Returns `true` when this interval overlaps the supplied temporal value. */
83
+ overlaps(other) {
84
+ return this.timeRange().overlaps(other);
85
+ }
86
+ /** Example: `interval.contains(range)`. Returns `true` when this interval fully contains the supplied temporal value. */
87
+ contains(other) {
88
+ return this.timeRange().contains(other);
89
+ }
90
+ /** Example: `interval.isBefore(range)`. Returns `true` when this interval ends strictly before the supplied temporal value begins. */
91
+ isBefore(other) {
92
+ return this.timeRange().isBefore(other);
93
+ }
94
+ /** Example: `interval.isAfter(range)`. Returns `true` when this interval begins strictly after the supplied temporal value ends. */
95
+ isAfter(other) {
96
+ return this.timeRange().isAfter(other);
97
+ }
98
+ /** Example: `interval.intersection(range)`. Returns the temporal intersection with the supplied value, if any. */
99
+ intersection(other) {
100
+ return this.timeRange().intersection(other);
101
+ }
102
+ /** Example: `interval.trim(range)`. Returns this interval clipped to the supplied temporal value, preserving its label when overlapping. */
103
+ trim(other) {
104
+ const range = this.intersection(other);
105
+ if (!range) {
106
+ return undefined;
107
+ }
108
+ return new Interval({
109
+ value: this.value,
110
+ start: range.begin(),
111
+ end: range.end(),
112
+ });
113
+ }
114
+ /** Example: `interval.equals(otherInterval)`. Returns `true` when the supplied key has the same label and temporal extent. */
115
+ equals(other) {
116
+ return (other instanceof Interval &&
117
+ this.start === other.start &&
118
+ this.endMs === other.endMs &&
119
+ this.value === other.value);
120
+ }
121
+ /** Example: `interval.compare(otherInterval)`. Compares this key to another key for ordering. */
122
+ compare(other) {
123
+ const base = compareEventKeys(this, other);
124
+ if (base !== 0 || !(other instanceof Interval)) {
125
+ return base;
126
+ }
127
+ return compareIntervalValues(this.value, other.value);
128
+ }
129
+ }
130
+ //# sourceMappingURL=Interval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Interval.js","sourceRoot":"","sources":["../src/Interval.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,yBAAyB,EACzB,eAAe,GAIhB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAQ3C,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,eAAe,CAAC;AAQvB,mGAAmG;AACnG,MAAM,OAAO,QAAQ;IACV,IAAI,GAAG,UAAU,CAAC;IAClB,KAAK,CAAgB;IACrB,KAAK,CAAS;IACd,KAAK,CAAS;IAEvB,4JAA4J;IAC5J,MAAM,CAAC,QAAQ,CACb,SAAiB,EACjB,UAAuD,EAAE;QAEzD,MAAM,KAAK,GAAG,eAAe,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QAClD,OAAO,IAAI,QAAQ,CAAC;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,SAAS;YACjC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,EAAE,KAAK,CAAC,GAAG;SACf,CAAC,CAAC;IACL,CAAC;IAED,gLAAgL;IAChL,MAAM,CAAC,YAAY,CACjB,IAAkB,EAClB,SAAiB,EACjB,UAAuD,EAAE;QAEzD,MAAM,KAAK,GAAG,yBAAyB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QAClE,OAAO,IAAI,QAAQ,CAAC;YAClB,KAAK,EAAE,OAAO,CAAC,KAAK,IAAI,SAAS;YACjC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,EAAE,KAAK,CAAC,GAAG;SACf,CAAC,CAAC;IACL,CAAC;IAED,sIAAsI;IACtI,YAAY,KAAoB;QAC9B,IAAI,KAAoB,CAAC;QACzB,IAAI,QAAwB,CAAC;QAC7B,IAAI,MAAsB,CAAC;QAC3B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACjB,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YACpB,MAAM,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;aAAM,CAAC;YACN,MAAM,WAAW,GAAG,KAA4B,CAAC;YACjD,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC;YAC1B,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC;YAC7B,MAAM,GAAG,WAAW,CAAC,GAAG,CAAC;QAC3B,CAAC;QACD,MAAM,KAAK,GAAG,kBAAkB,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;QAC7D,MAAM,GAAG,GAAG,kBAAkB,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;QACvD,IAAI,KAAK,GAAG,GAAG,EAAE,CAAC;YAChB,MAAM,IAAI,SAAS,CAAC,+BAA+B,CAAC,CAAC;QACvD,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC;QACjB,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC;IAED,sEAAsE;IACtE,IAAI;QACF,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,4GAA4G;IAC5G,KAAK;QACH,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,wGAAwG;IACxG,GAAG;QACD,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,iEAAiE;IACjE,OAAO;QACL,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAED,8EAA8E;IAC9E,QAAQ;QACN,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,qFAAqF;IACrF,SAAS;QACP,OAAO,IAAI,SAAS,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/D,CAAC;IAED,qGAAqG;IACrG,QAAQ;QACN,OAAO,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;IACjC,CAAC;IAED,mHAAmH;IACnH,QAAQ,CAAC,KAAmB;QAC1B,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAED,yHAAyH;IACzH,QAAQ,CAAC,KAAmB;QAC1B,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAED,sIAAsI;IACtI,QAAQ,CAAC,KAAmB;QAC1B,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC1C,CAAC;IAED,oIAAoI;IACpI,OAAO,CAAC,KAAmB;QACzB,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC;IAED,kHAAkH;IAClH,YAAY,CAAC,KAAmB;QAC9B,OAAO,IAAI,CAAC,SAAS,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED,4IAA4I;IAC5I,IAAI,CAAC,KAAmB;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,OAAO,IAAI,QAAQ,CAAC;YAClB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE;YACpB,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE;SACjB,CAAC,CAAC;IACL,CAAC;IAED,8HAA8H;IAC9H,MAAM,CAAC,KAAe;QACpB,OAAO,CACL,KAAK,YAAY,QAAQ;YACzB,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK;YAC1B,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK;YAC1B,IAAI,CAAC,KAAK,KAAK,KAAK,CAAC,KAAK,CAC3B,CAAC;IACJ,CAAC;IAED,iGAAiG;IACjG,OAAO,CAAC,KAAe;QACrB,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;QAC3C,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,YAAY,QAAQ,CAAC,EAAE,CAAC;YAC/C,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,qBAAqB,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;IACxD,CAAC;CACF"}
@@ -0,0 +1,80 @@
1
+ import { BoundedSequence } from './BoundedSequence.js';
2
+ import { type CalendarOptions, type CalendarUnit, type WeekStartsOn } from './calendar.js';
3
+ import type { TemporalLike, TimestampInput } from './temporal.js';
4
+ export type DurationInput = number | `${number}${'ms' | 's' | 'm' | 'h' | 'd'}`;
5
+ export type SequenceSample = 'begin' | 'center';
6
+ type FixedSequenceInput = {
7
+ every: DurationInput;
8
+ anchor?: TimestampInput;
9
+ };
10
+ type CalendarSequenceInput = {
11
+ unit: CalendarUnit;
12
+ timeZone: string;
13
+ weekStartsOn?: WeekStartsOn;
14
+ };
15
+ /**
16
+ * An unbounded fixed-step grid definition used for alignment or aggregation.
17
+ *
18
+ * `Sequence` defines where buckets fall. Call `bounded(...)` to realize a finite `BoundedSequence`
19
+ * over a specific range.
20
+ *
21
+ * Important distinction:
22
+ * - the sequence `anchor` defines where the unbounded grid starts
23
+ * - the caller-supplied `range` defines which finite slice is realized
24
+ *
25
+ * The default anchor is Unix epoch `0`.
26
+ */
27
+ export declare class Sequence {
28
+ #private;
29
+ constructor(input: FixedSequenceInput | CalendarSequenceInput);
30
+ /**
31
+ * Creates an unbounded fixed-step sequence.
32
+ *
33
+ * The returned sequence is a grid definition, not a finite bucket list. By default the grid is
34
+ * anchored at Unix epoch `0`, which makes independently-created sequences line up by default.
35
+ * Use `bounded(...)` or series operations like `align(...)` / `aggregate(...)` to realize a
36
+ * finite slice of the grid over a concrete range.
37
+ */
38
+ static every(every: DurationInput, options?: {
39
+ anchor?: TimestampInput;
40
+ }): Sequence;
41
+ /** Example: `Sequence.hourly()`. Creates an hourly fixed-step sequence. */
42
+ static hourly(options?: {
43
+ anchor?: TimestampInput;
44
+ }): Sequence;
45
+ /** Example: `Sequence.daily()`. Creates a daily fixed-step sequence. */
46
+ static daily(options?: {
47
+ anchor?: TimestampInput;
48
+ }): Sequence;
49
+ /**
50
+ * Creates an unbounded calendar-aware sequence.
51
+ *
52
+ * Calendar sequences step by local calendar boundaries in an IANA time zone instead of by a
53
+ * fixed millisecond duration. Supported units are `"day"`, `"week"`, and `"month"`.
54
+ *
55
+ * Defaults:
56
+ * - `timeZone`: `"UTC"`
57
+ */
58
+ static calendar(unit: CalendarUnit, options?: CalendarOptions): Sequence;
59
+ /** Example: `sequence.kind()`. Returns whether this sequence is fixed-step or calendar-aware. */
60
+ kind(): 'fixed' | 'calendar';
61
+ /** Example: `sequence.anchor()`. Returns the millisecond anchor used by this grid definition. */
62
+ anchor(): number;
63
+ /** Example: `sequence.stepMs()`. Returns the fixed interval size in milliseconds. */
64
+ stepMs(): number;
65
+ /** Example: `sequence.timeZone()`. Returns the IANA time zone for calendar-aware sequences, if any. */
66
+ timeZone(): string | undefined;
67
+ /**
68
+ * Example: `sequence.bounded(new TimeRange({ start, end }))`.
69
+ * Realizes a finite `BoundedSequence` over the supplied range.
70
+ *
71
+ * Sample position controls which interval starts are selected:
72
+ * `begin` includes buckets whose starts fall within the range, while `center` includes buckets
73
+ * whose midpoints fall within the range.
74
+ */
75
+ bounded(range: TemporalLike, options?: {
76
+ sample?: SequenceSample;
77
+ }): BoundedSequence;
78
+ }
79
+ export {};
80
+ //# sourceMappingURL=Sequence.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sequence.d.ts","sourceRoot":"","sources":["../src/Sequence.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,YAAY,EAMlB,MAAM,eAAe,CAAC;AAGvB,OAAO,KAAK,EACV,YAAY,EACZ,cAAc,EAGf,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,GAAG,MAAM,GAAG,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,CAAC;AAChF,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,CAAC;AAEhD,KAAK,kBAAkB,GAAG;IACxB,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,CAAC,EAAE,cAAc,CAAC;CACzB,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,IAAI,EAAE,YAAY,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,CAAC;AAqEF;;;;;;;;;;;GAWG;AACH,qBAAa,QAAQ;;gBAQP,KAAK,EAAE,kBAAkB,GAAG,qBAAqB;IAc7D;;;;;;;OAOG;IACH,MAAM,CAAC,KAAK,CACV,KAAK,EAAE,aAAa,EACpB,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,cAAc,CAAA;KAAO,GACxC,QAAQ;IAMX,2EAA2E;IAC3E,MAAM,CAAC,MAAM,CAAC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,cAAc,CAAA;KAAO,GAAG,QAAQ;IAIlE,wEAAwE;IACxE,MAAM,CAAC,KAAK,CAAC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,cAAc,CAAA;KAAO,GAAG,QAAQ;IAIjE;;;;;;;;OAQG;IACH,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,OAAO,GAAE,eAAoB,GAAG,QAAQ;IAO5E,iGAAiG;IACjG,IAAI,IAAI,OAAO,GAAG,UAAU;IAI5B,iGAAiG;IACjG,MAAM,IAAI,MAAM;IAShB,qFAAqF;IACrF,MAAM,IAAI,MAAM;IAShB,uGAAuG;IACvG,QAAQ,IAAI,MAAM,GAAG,SAAS;IAI9B;;;;;;;OAOG;IACH,OAAO,CACL,KAAK,EAAE,YAAY,EACnB,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,cAAc,CAAA;KAAO,GACxC,eAAe;CA0DnB"}
@@ -0,0 +1,197 @@
1
+ import { BoundedSequence } from './BoundedSequence.js';
2
+ import { normalizeWeekStartsOn, nextCalendarStart, plainDateToStart, resolveTimeZone, toPlainDateStart, } from './calendar.js';
3
+ import { Interval } from './Interval.js';
4
+ import { TimeRange } from './TimeRange.js';
5
+ function normalizeTimestamp(value) {
6
+ return value instanceof Date ? value.getTime() : value;
7
+ }
8
+ function toTimeRange(value) {
9
+ if (typeof value === 'object' &&
10
+ value !== null &&
11
+ 'timeRange' in value &&
12
+ typeof value.timeRange === 'function') {
13
+ return value.timeRange();
14
+ }
15
+ if (typeof value === 'object' &&
16
+ value !== null &&
17
+ 'begin' in value &&
18
+ 'end' in value) {
19
+ return new TimeRange({ start: value.begin(), end: value.end() });
20
+ }
21
+ if (value instanceof Date || typeof value === 'number') {
22
+ const timestamp = normalizeTimestamp(value);
23
+ return new TimeRange({ start: timestamp, end: timestamp });
24
+ }
25
+ if (Array.isArray(value)) {
26
+ if (value.length === 2) {
27
+ return new TimeRange(value);
28
+ }
29
+ return new Interval(value).timeRange();
30
+ }
31
+ if ('value' in value) {
32
+ return new Interval(value).timeRange();
33
+ }
34
+ return new TimeRange(value);
35
+ }
36
+ function parseDuration(value) {
37
+ if (typeof value === 'number') {
38
+ if (!Number.isFinite(value) || value <= 0) {
39
+ throw new TypeError('sequence duration must be a positive finite number of milliseconds');
40
+ }
41
+ return value;
42
+ }
43
+ const match = /^(\d+)(ms|s|m|h|d)$/.exec(value);
44
+ if (!match) {
45
+ throw new TypeError(`unsupported duration '${value}'`);
46
+ }
47
+ const amount = Number(match[1]);
48
+ const unit = match[2];
49
+ const multiplier = unit === 'ms'
50
+ ? 1
51
+ : unit === 's'
52
+ ? 1_000
53
+ : unit === 'm'
54
+ ? 60_000
55
+ : unit === 'h'
56
+ ? 3_600_000
57
+ : 86_400_000;
58
+ return amount * multiplier;
59
+ }
60
+ /**
61
+ * An unbounded fixed-step grid definition used for alignment or aggregation.
62
+ *
63
+ * `Sequence` defines where buckets fall. Call `bounded(...)` to realize a finite `BoundedSequence`
64
+ * over a specific range.
65
+ *
66
+ * Important distinction:
67
+ * - the sequence `anchor` defines where the unbounded grid starts
68
+ * - the caller-supplied `range` defines which finite slice is realized
69
+ *
70
+ * The default anchor is Unix epoch `0`.
71
+ */
72
+ export class Sequence {
73
+ #kind;
74
+ #stepMs;
75
+ #anchorMs;
76
+ #calendarUnit;
77
+ #timeZone;
78
+ #weekStartsOn;
79
+ constructor(input) {
80
+ if ('every' in input) {
81
+ this.#kind = 'fixed';
82
+ this.#stepMs = parseDuration(input.every);
83
+ this.#anchorMs = normalizeTimestamp(input.anchor ?? 0);
84
+ }
85
+ else {
86
+ this.#kind = 'calendar';
87
+ this.#calendarUnit = input.unit;
88
+ this.#timeZone = input.timeZone;
89
+ this.#weekStartsOn = normalizeWeekStartsOn(input.weekStartsOn);
90
+ }
91
+ Object.freeze(this);
92
+ }
93
+ /**
94
+ * Creates an unbounded fixed-step sequence.
95
+ *
96
+ * The returned sequence is a grid definition, not a finite bucket list. By default the grid is
97
+ * anchored at Unix epoch `0`, which makes independently-created sequences line up by default.
98
+ * Use `bounded(...)` or series operations like `align(...)` / `aggregate(...)` to realize a
99
+ * finite slice of the grid over a concrete range.
100
+ */
101
+ static every(every, options = {}) {
102
+ return options.anchor === undefined
103
+ ? new Sequence({ every })
104
+ : new Sequence({ every, anchor: options.anchor });
105
+ }
106
+ /** Example: `Sequence.hourly()`. Creates an hourly fixed-step sequence. */
107
+ static hourly(options = {}) {
108
+ return Sequence.every('1h', options);
109
+ }
110
+ /** Example: `Sequence.daily()`. Creates a daily fixed-step sequence. */
111
+ static daily(options = {}) {
112
+ return Sequence.every('1d', options);
113
+ }
114
+ /**
115
+ * Creates an unbounded calendar-aware sequence.
116
+ *
117
+ * Calendar sequences step by local calendar boundaries in an IANA time zone instead of by a
118
+ * fixed millisecond duration. Supported units are `"day"`, `"week"`, and `"month"`.
119
+ *
120
+ * Defaults:
121
+ * - `timeZone`: `"UTC"`
122
+ */
123
+ static calendar(unit, options = {}) {
124
+ const timeZone = resolveTimeZone(options);
125
+ return options.weekStartsOn === undefined
126
+ ? new Sequence({ unit, timeZone })
127
+ : new Sequence({ unit, timeZone, weekStartsOn: options.weekStartsOn });
128
+ }
129
+ /** Example: `sequence.kind()`. Returns whether this sequence is fixed-step or calendar-aware. */
130
+ kind() {
131
+ return this.#kind;
132
+ }
133
+ /** Example: `sequence.anchor()`. Returns the millisecond anchor used by this grid definition. */
134
+ anchor() {
135
+ if (this.#kind !== 'fixed') {
136
+ throw new TypeError('calendar sequences do not have a fixed millisecond anchor');
137
+ }
138
+ return this.#anchorMs;
139
+ }
140
+ /** Example: `sequence.stepMs()`. Returns the fixed interval size in milliseconds. */
141
+ stepMs() {
142
+ if (this.#kind !== 'fixed') {
143
+ throw new TypeError('calendar sequences do not have a fixed millisecond step size');
144
+ }
145
+ return this.#stepMs;
146
+ }
147
+ /** Example: `sequence.timeZone()`. Returns the IANA time zone for calendar-aware sequences, if any. */
148
+ timeZone() {
149
+ return this.#timeZone;
150
+ }
151
+ /**
152
+ * Example: `sequence.bounded(new TimeRange({ start, end }))`.
153
+ * Realizes a finite `BoundedSequence` over the supplied range.
154
+ *
155
+ * Sample position controls which interval starts are selected:
156
+ * `begin` includes buckets whose starts fall within the range, while `center` includes buckets
157
+ * whose midpoints fall within the range.
158
+ */
159
+ bounded(range, options = {}) {
160
+ const sample = options.sample ?? 'begin';
161
+ const requested = toTimeRange(range);
162
+ const intervals = [];
163
+ if (this.#kind === 'fixed') {
164
+ const stepMs = this.#stepMs;
165
+ const anchorMs = this.#anchorMs;
166
+ const sampleOffset = sample === 'center' ? stepMs / 2 : 0;
167
+ const firstIndex = Math.ceil((requested.begin() - sampleOffset - anchorMs) / stepMs);
168
+ const lastIndex = Math.floor((requested.end() - sampleOffset - anchorMs) / stepMs);
169
+ for (let index = firstIndex; index <= lastIndex; index += 1) {
170
+ const start = anchorMs + index * stepMs;
171
+ intervals.push(new Interval({ value: start, start, end: start + stepMs }));
172
+ }
173
+ return new BoundedSequence(intervals);
174
+ }
175
+ const timeZone = this.#timeZone;
176
+ const unit = this.#calendarUnit;
177
+ const weekStartsOn = this.#weekStartsOn;
178
+ let currentDate = toPlainDateStart(requested.begin(), timeZone, unit, weekStartsOn);
179
+ while (true) {
180
+ const currentStart = plainDateToStart(currentDate, timeZone);
181
+ const nextDate = nextCalendarStart(currentDate, unit);
182
+ const nextStart = plainDateToStart(nextDate, timeZone);
183
+ const start = currentStart.epochMilliseconds;
184
+ const end = nextStart.epochMilliseconds;
185
+ const sampleTime = sample === 'center' ? start + (end - start) / 2 : start;
186
+ if (sampleTime > requested.end()) {
187
+ break;
188
+ }
189
+ if (sampleTime >= requested.begin()) {
190
+ intervals.push(new Interval({ value: start, start, end }));
191
+ }
192
+ currentDate = nextDate;
193
+ }
194
+ return new BoundedSequence(intervals);
195
+ }
196
+ }
197
+ //# sourceMappingURL=Sequence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Sequence.js","sourceRoot":"","sources":["../src/Sequence.ts"],"names":[],"mappings":"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"}