@hyperfrontend/time-utils 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +43 -37
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.cjs.js +4 -0
- package/_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.esm.js +3 -2
- package/bundle/index.iife.js +4 -2
- package/bundle/index.iife.min.js +1 -1
- package/bundle/index.umd.js +4 -2
- package/bundle/index.umd.min.js +1 -1
- package/index.cjs.js +4 -4
- package/index.d.ts +1 -1
- package/index.esm.js +5 -5
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.0.1](https://github.com/AndrewRedican/hyperfrontend/compare/106ce4517092cdfa9f222b73d938d272c333d69b...adf0a4f77dece2be855e7ab88185a4fe84e7b16b) - 2026-09-14
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- reject a non-finite base time window instead of returning an invalid date
|
|
10
|
+
|
|
5
11
|
## [1.0.0](https://github.com/AndrewRedican/hyperfrontend/compare/5f116abb8ba6355dfb283fa03b7481e5eb029480...4b34883aead4c721f021465b19fa5bdd49514d37) - 2026-08-31
|
|
6
12
|
|
|
7
13
|
### Features
|
package/README.md
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://www.hyperfrontend.dev/docs/libraries/utils/time/">
|
|
3
|
+
<img width="640" height="180" src="https://www.hyperfrontend.dev/media/banner-time-utils/banner.gif" alt="@hyperfrontend/time-utils">
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
2
6
|
|
|
3
7
|
<p align="center">
|
|
4
8
|
<a href="https://github.com/AndrewRedican/hyperfrontend/actions/workflows/ci-lib-time-utils.yml">
|
|
@@ -33,6 +37,12 @@
|
|
|
33
37
|
<img src="https://img.shields.io/badge/tree%20shakeable-%E2%9C%93-success?style=flat-square" alt="Tree Shakeable">
|
|
34
38
|
</p>
|
|
35
39
|
|
|
40
|
+
<p align="center">
|
|
41
|
+
<a href="https://www.hyperfrontend.dev/docs/libraries/utils/time/">
|
|
42
|
+
<img width="640" height="360" src="https://www.hyperfrontend.dev/media/time-utils-countdown/hero.gif" alt="Two stacked 30-second countdown bars draining in parallel: the setTimeout bar runs red straight to zero, while the createTimer bar holds green at 21.0s through a pause and then continues down from there">
|
|
43
|
+
</a>
|
|
44
|
+
</p>
|
|
45
|
+
|
|
36
46
|
Functional time utilities for async operations, intervals, and time normalization.
|
|
37
47
|
|
|
38
48
|
• 👉 See [**documentation**](https://www.hyperfrontend.dev/docs/libraries/utils/time/)
|
|
@@ -40,32 +50,28 @@ Functional time utilities for async operations, intervals, and time normalizatio
|
|
|
40
50
|
|
|
41
51
|
## What is @hyperfrontend/time-utils?
|
|
42
52
|
|
|
43
|
-
`@hyperfrontend/time-utils` provides composable, testable utilities for working with time-based operations in JavaScript. The library focuses on enhancing the control and flexibility of standard timing APIs (`setTimeout`, `setInterval`) while adding specialized utilities for async workflows and time window calculations.
|
|
53
|
+
[`@hyperfrontend/time-utils`](https://www.hyperfrontend.dev/docs/libraries/utils/time/) provides composable, testable utilities for working with time-based operations in JavaScript. The library focuses on enhancing the control and flexibility of standard timing APIs (`setTimeout`, `setInterval`) while adding specialized utilities for async workflows and time window calculations.
|
|
44
54
|
|
|
45
55
|
Unlike the native timing APIs which offer limited lifecycle control, this library wraps them in functional interfaces that support pausing, resuming, resetting, and subscription management. All utilities return immutable objects with frozen APIs, preventing accidental mutation while maintaining predictable behavior.
|
|
46
56
|
|
|
47
57
|
### Key Features
|
|
48
58
|
|
|
49
|
-
- **Controllable timers** - Pause, resume, and reset `setTimeout` operations with tracked remaining time
|
|
50
|
-
- **Multi-subscriber clocks** - Observable interval loops supporting multiple callbacks with unified start/stop control
|
|
51
|
-
- **Promise-based delays** - Async/await compatible `sleep()` utility for sequential code flows
|
|
52
|
-
- **Time window normalization** - Bucket timestamps into fixed intervals (e.g., 5-minute windows for aggregation)
|
|
59
|
+
- **[Controllable timers](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-createTimer)** - Pause, resume, and reset `setTimeout` operations with tracked remaining time
|
|
60
|
+
- **[Multi-subscriber clocks](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-createClock)** - Observable interval loops supporting multiple callbacks with unified start/stop control
|
|
61
|
+
- **[Promise-based delays](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-sleep)** - Async/await compatible `sleep()` utility for sequential code flows
|
|
62
|
+
- **[Time window normalization](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-normalizeToBaseTimeWindow)** - Bucket timestamps into fixed intervals (e.g., 5-minute windows for aggregation)
|
|
53
63
|
- **Functional cleanup** - All repeating operations return cleanup functions for straightforward teardown
|
|
54
64
|
- **Immutable APIs** - All returned objects are frozen, preventing accidental state modifications
|
|
55
65
|
- **Zero dependencies** - Self-contained timing utilities with no external dependencies
|
|
56
66
|
- **TypeScript native** - Full type definitions with comprehensive JSDoc documentation
|
|
57
67
|
|
|
58
|
-
### Architecture Highlights
|
|
59
|
-
|
|
60
|
-
All timing abstractions maintain internal state privately while exposing frozen API objects, following the revealing module pattern. Timer implementations track elapsed time explicitly to enable pause/resume functionality, while clock implementations manage subscriber arrays with simple filter-based unsubscription. The library avoids classes and prototypes in favor of factory functions that return object literals.
|
|
61
|
-
|
|
62
68
|
## Why Use @hyperfrontend/time-utils?
|
|
63
69
|
|
|
64
70
|
### 1. Pause/Resume Capabilities Native APIs Lack
|
|
65
71
|
|
|
66
72
|
JavaScript's `setTimeout` and `setInterval` cannot be paused: once started, they either complete or get cancelled. This creates problems for features like user-initiated pauses in games, animations during background tabs, or request throttling. `createTimer()` tracks elapsed time internally, enabling pause/resume without restarting from the beginning or losing progress.
|
|
67
73
|
|
|
68
|
-
**Example:** A countdown timer in a game needs to pause when the user switches tabs. With `setTimeout`, you'd need to calculate remaining time manually and create a new timeout. With `createTimer
|
|
74
|
+
**Example:** A countdown timer in a game needs to pause when the user switches tabs. With `setTimeout`, you'd need to calculate remaining time manually and create a new timeout. With [`createTimer`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-createTimer), just call `timer.pause()`.
|
|
69
75
|
|
|
70
76
|
### 2. Multi-Subscriber Interval Management
|
|
71
77
|
|
|
@@ -162,7 +168,8 @@ async function retryWithDelay(fn, attempts = 3) {
|
|
|
162
168
|
import { normalizeToBaseTimeWindow } from '@hyperfrontend/time-utils'
|
|
163
169
|
|
|
164
170
|
// Group metrics into 5-minute windows
|
|
165
|
-
const
|
|
171
|
+
const times = ['10:03:45', '10:07:22', '10:12:03']
|
|
172
|
+
const events = times.map((time) => new Date(`2024-01-17T${time}Z`))
|
|
166
173
|
|
|
167
174
|
const buckets = new Map()
|
|
168
175
|
events.forEach((timestamp) => {
|
|
@@ -171,8 +178,9 @@ events.forEach((timestamp) => {
|
|
|
171
178
|
buckets.set(key, (buckets.get(key) || 0) + 1)
|
|
172
179
|
})
|
|
173
180
|
|
|
174
|
-
// Results:
|
|
175
|
-
// "2024-01-17T10:00:00Z" →
|
|
181
|
+
// Results: 10:07:22 floors to 10:05, not to 10:00, so the three events land in three separate buckets
|
|
182
|
+
// "2024-01-17T10:00:00Z" → 1 event
|
|
183
|
+
// "2024-01-17T10:05:00Z" → 1 event
|
|
176
184
|
// "2024-01-17T10:10:00Z" → 1 event
|
|
177
185
|
```
|
|
178
186
|
|
|
@@ -192,34 +200,32 @@ cleanup()
|
|
|
192
200
|
|
|
193
201
|
## API Overview
|
|
194
202
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
203
|
+
Five functions, one gap they all fill: `setTimeout` and `setInterval` schedule work but give you nothing to steer it with afterwards. Two of the five are where you
|
|
204
|
+
start. [`createTimer`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-createTimer) is a timeout you can interrupt: pausing banks whatever was
|
|
205
|
+
left of the delay instead of discarding it, so resuming runs out that remainder rather than serving the full delay again, and `reset(newDelay?)` is the one call
|
|
206
|
+
that does start over. [`createClock`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-createClock) solves the opposite problem, fanning a single
|
|
207
|
+
interval out to any number of subscribers, so ten widgets on a one-second cadence share one tick and one `Date` rather than drifting apart on ten intervals of
|
|
208
|
+
their own.
|
|
201
209
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
- `clock.subscribe(callback)` - Adds callback to subscriber list
|
|
206
|
-
- `clock.unsubscribe(callback)` - Removes callback from subscribers
|
|
207
|
-
- `clock.interval` - Read-only interval duration
|
|
210
|
+
Both hand back a frozen object rather than a numeric handle you are expected to hold onto and clear. A [`Timer`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-Timer)
|
|
211
|
+
is [`pause`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-Timer-prop-pause), [`resume`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-Timer-prop-resume) and [`reset`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-Timer-prop-reset); a [`Clock`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-Clock) is [`start`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-Clock-prop-start), [`stop`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-Clock-prop-stop), [`subscribe`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-Clock-prop-subscribe), [`unsubscribe`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-Clock-prop-unsubscribe)
|
|
212
|
+
and a read-only [`interval`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-Clock-prop-interval). One detail worth knowing before your first call: a timer is created idle, so nothing is scheduled until you `resume()` it once.
|
|
208
213
|
|
|
209
|
-
|
|
214
|
+
The remaining three are single-purpose and take no object at all. [`sleep`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-sleep) is a delay you can
|
|
215
|
+
`await` in sequence. [`setIntervalCallback`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-setIntervalCallback) is a repeating interval for the case
|
|
216
|
+
where teardown is all you want back, returning the cleanup function directly. And
|
|
217
|
+
[`normalizeToBaseTimeWindow`](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-normalizeToBaseTimeWindow) floors a `Date` to a window boundary and
|
|
218
|
+
returns a new `Date`, which is how independent callers derive the same bucket key from clocks that never agreed to the millisecond.
|
|
210
219
|
|
|
211
|
-
|
|
212
|
-
- **`setIntervalCallback(callback, interval)`** - Simple setInterval wrapper returning cleanup function
|
|
213
|
-
- **`normalizeToBaseTimeWindow(time, baseTimeWindow)`** - Rounds timestamp down to nearest time window boundary (window in minutes)
|
|
220
|
+
Every signature, option and return type is in the [API reference](https://www.hyperfrontend.dev/docs/libraries/utils/time/#api-reference).
|
|
214
221
|
|
|
215
222
|
## Compatibility
|
|
216
223
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
| Deno, Bun, Cloudflare Workers | ✅ |
|
|
224
|
+
<p align="center">
|
|
225
|
+
<a href="https://www.hyperfrontend.dev/docs/libraries/utils/time/#compatibility">
|
|
226
|
+
<img width="640" height="150" src="https://www.hyperfrontend.dev/media/runtimes-time-utils/runtimes.png" alt="Runs in Node.js 18 or later, evergreen browsers and web workers">
|
|
227
|
+
</a>
|
|
228
|
+
</p>
|
|
223
229
|
|
|
224
230
|
### Output Formats
|
|
225
231
|
|
|
@@ -244,7 +250,7 @@ cleanup()
|
|
|
244
250
|
</script>
|
|
245
251
|
```
|
|
246
252
|
|
|
247
|
-
**Global variable:** `HyperfrontendTimeUtils`
|
|
253
|
+
**Global variable:** [`HyperfrontendTimeUtils`](https://www.hyperfrontend.dev/docs/libraries/utils/time/)
|
|
248
254
|
|
|
249
255
|
### Dependencies
|
|
250
256
|
|
package/bundle/index.iife.js
CHANGED
|
@@ -88,15 +88,17 @@ var HyperfrontendTimeUtils = (function (exports) {
|
|
|
88
88
|
const _Math = globalThis.Math;
|
|
89
89
|
const floor = _Math.floor;
|
|
90
90
|
|
|
91
|
+
const _Number = globalThis.Number;
|
|
91
92
|
const _isNaN = globalThis.isNaN;
|
|
93
|
+
const isFinite = _Number.isFinite;
|
|
92
94
|
const globalIsNaN = _isNaN;
|
|
93
95
|
|
|
94
96
|
function normalizeToBaseTimeWindow(time, baseTimeWindow) {
|
|
95
97
|
if (!time || !(time instanceof Date) || globalIsNaN(time.getTime())) {
|
|
96
98
|
throw createError('Invalid time input');
|
|
97
99
|
}
|
|
98
|
-
if (baseTimeWindow <= 0) {
|
|
99
|
-
throw createError('Base time window must be positive');
|
|
100
|
+
if (!isFinite(baseTimeWindow) || baseTimeWindow <= 0) {
|
|
101
|
+
throw createError('Base time window must be a positive finite number');
|
|
100
102
|
}
|
|
101
103
|
const timeInMs = time.getTime();
|
|
102
104
|
const windowInMs = baseTimeWindow * 60 * 1000;
|
package/bundle/index.iife.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var HyperfrontendTimeUtils=function(e){"use strict";const l=globalThis.Date,t=globalThis.Reflect;function n(...e){return t.construct(l,e)}const i=l.now,o=globalThis.Object.freeze,s=globalThis.setTimeout,r=globalThis.setInterval,a=globalThis.clearTimeout,
|
|
1
|
+
var HyperfrontendTimeUtils=function(e){"use strict";const l=globalThis.Date,t=globalThis.Reflect;function n(...e){return t.construct(l,e)}const i=l.now,o=globalThis.Object.freeze,s=globalThis.setTimeout,r=globalThis.setInterval,a=globalThis.clearTimeout,u=globalThis.clearInterval,c=(e,l,...t)=>s(e,l,...t),b=(e,l,...t)=>r(e,l,...t),T=e=>{u(e)};const f=globalThis.Error,h=globalThis.Reflect,g=(e,l)=>h.construct(f,[e,l]),m=globalThis.Math.floor,d=globalThis.Number,v=globalThis.isNaN,p=d.isFinite,w=v;const I=globalThis.Promise,R=globalThis.Reflect;return I.resolve.bind(I),I.reject.bind(I),I.all.bind(I),I.race.bind(I),I.allSettled.bind(I),I.any.bind(I),I.withResolvers?.bind(I),e.createClock=function(e=1e3){let l=null,t=[];return o({start:()=>{null===l&&(l=b(()=>{const e=n();t.forEach(l=>l(e))},e))},stop:()=>{null!==l&&(T(l),l=null)},subscribe:e=>{t.push(e)},unsubscribe:e=>{t=t.filter(l=>l!==e)},interval:e})},e.createTimer=function(e,l){let t=null,n=null,s=l;const r=()=>{if(null!==t){a(t);const e=i();null!==n&&(s-=e-n),t=null}},u=()=>{null===t&&(n=i(),t=c(()=>{e(),t=null},s))};return o({pause:r,resume:u,reset:(e=l)=>{r(),s=e,u()}})},e.normalizeToBaseTimeWindow=function(e,l){if(!e||!(e instanceof Date)||w(e.getTime()))throw g("Invalid time input");if(!p(l)||l<=0)throw g("Base time window must be a positive finite number");const t=e.getTime(),i=60*l*1e3;return n(m(t/i)*i)},e.setIntervalCallback=function(e,l){const t=b(e,l);return()=>T(t)},e.sleep=function(e){return l=l=>c(l,e),R.construct(I,[l]);var l},e}({});
|
package/bundle/index.umd.js
CHANGED
|
@@ -91,15 +91,17 @@
|
|
|
91
91
|
const _Math = globalThis.Math;
|
|
92
92
|
const floor = _Math.floor;
|
|
93
93
|
|
|
94
|
+
const _Number = globalThis.Number;
|
|
94
95
|
const _isNaN = globalThis.isNaN;
|
|
96
|
+
const isFinite = _Number.isFinite;
|
|
95
97
|
const globalIsNaN = _isNaN;
|
|
96
98
|
|
|
97
99
|
function normalizeToBaseTimeWindow(time, baseTimeWindow) {
|
|
98
100
|
if (!time || !(time instanceof Date) || globalIsNaN(time.getTime())) {
|
|
99
101
|
throw createError('Invalid time input');
|
|
100
102
|
}
|
|
101
|
-
if (baseTimeWindow <= 0) {
|
|
102
|
-
throw createError('Base time window must be positive');
|
|
103
|
+
if (!isFinite(baseTimeWindow) || baseTimeWindow <= 0) {
|
|
104
|
+
throw createError('Base time window must be a positive finite number');
|
|
103
105
|
}
|
|
104
106
|
const timeInMs = time.getTime();
|
|
105
107
|
const windowInMs = baseTimeWindow * 60 * 1000;
|
package/bundle/index.umd.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).HyperfrontendTimeUtils={})}(this,function(e){"use strict";const t=globalThis.Date,l=globalThis.Reflect;function n(...e){return l.construct(t,e)}const i=t.now,o=globalThis.Object.freeze,s=globalThis.setTimeout,r=globalThis.setInterval,a=globalThis.clearTimeout,u=globalThis.clearInterval,c=(e,t,...l)=>s(e,t,...l),
|
|
1
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).HyperfrontendTimeUtils={})}(this,function(e){"use strict";const t=globalThis.Date,l=globalThis.Reflect;function n(...e){return l.construct(t,e)}const i=t.now,o=globalThis.Object.freeze,s=globalThis.setTimeout,r=globalThis.setInterval,a=globalThis.clearTimeout,u=globalThis.clearInterval,c=(e,t,...l)=>s(e,t,...l),b=(e,t,...l)=>r(e,t,...l),f=e=>{u(e)};const T=globalThis.Error,h=globalThis.Reflect,d=(e,t)=>h.construct(T,[e,t]),g=globalThis.Math.floor,m=globalThis.Number,p=globalThis.isNaN,v=m.isFinite,w=p;const y=globalThis.Promise,I=globalThis.Reflect;y.resolve.bind(y),y.reject.bind(y),y.all.bind(y),y.race.bind(y),y.allSettled.bind(y),y.any.bind(y),y.withResolvers?.bind(y),e.createClock=function(e=1e3){let t=null,l=[];return o({start:()=>{null===t&&(t=b(()=>{const e=n();l.forEach(t=>t(e))},e))},stop:()=>{null!==t&&(f(t),t=null)},subscribe:e=>{l.push(e)},unsubscribe:e=>{l=l.filter(t=>t!==e)},interval:e})},e.createTimer=function(e,t){let l=null,n=null,s=t;const r=()=>{if(null!==l){a(l);const e=i();null!==n&&(s-=e-n),l=null}},u=()=>{null===l&&(n=i(),l=c(()=>{e(),l=null},s))};return o({pause:r,resume:u,reset:(e=t)=>{r(),s=e,u()}})},e.normalizeToBaseTimeWindow=function(e,t){if(!e||!(e instanceof Date)||w(e.getTime()))throw d("Invalid time input");if(!v(t)||t<=0)throw d("Base time window must be a positive finite number");const l=e.getTime(),i=60*t*1e3;return n(g(l/i)*i)},e.setIntervalCallback=function(e,t){const l=b(e,t);return()=>f(l)},e.sleep=function(e){return t=t=>c(t,e),I.construct(y,[t]);var t}});
|
package/index.cjs.js
CHANGED
|
@@ -93,7 +93,7 @@ function createTimer(callback, delay) {
|
|
|
93
93
|
if (timerId !== null) {
|
|
94
94
|
index_cjs_js$1.clearTimeout(timerId);
|
|
95
95
|
const now = index_cjs_js$2.dateNow();
|
|
96
|
-
|
|
96
|
+
// why: start is always set when timerId is not null, so the guard never falls through.
|
|
97
97
|
if (start !== null) {
|
|
98
98
|
remaining -= now - start;
|
|
99
99
|
}
|
|
@@ -121,7 +121,7 @@ function createTimer(callback, delay) {
|
|
|
121
121
|
* Normalizes a given time to the nearest base time window.
|
|
122
122
|
*
|
|
123
123
|
* @param time - The Date object to normalize to the nearest time window
|
|
124
|
-
* @param baseTimeWindow - The size of the time window in minutes for normalization
|
|
124
|
+
* @param baseTimeWindow - The size of the time window in minutes for normalization; must be a positive finite number
|
|
125
125
|
* @returns A new Date object normalized to the start of the time window
|
|
126
126
|
*
|
|
127
127
|
* @example Normalizing to 15-minute buckets
|
|
@@ -136,8 +136,8 @@ function normalizeToBaseTimeWindow(time, baseTimeWindow) {
|
|
|
136
136
|
if (!time || !(time instanceof Date) || index_cjs_js$3.globalIsNaN(time.getTime())) {
|
|
137
137
|
throw index_cjs_js$4.createError('Invalid time input');
|
|
138
138
|
}
|
|
139
|
-
if (baseTimeWindow <= 0) {
|
|
140
|
-
throw index_cjs_js$4.createError('Base time window must be positive');
|
|
139
|
+
if (!index_cjs_js$3.isFinite(baseTimeWindow) || baseTimeWindow <= 0) {
|
|
140
|
+
throw index_cjs_js$4.createError('Base time window must be a positive finite number');
|
|
141
141
|
}
|
|
142
142
|
const timeInMs = time.getTime();
|
|
143
143
|
const windowInMs = baseTimeWindow * 60 * 1000;
|
package/index.d.ts
CHANGED
|
@@ -81,7 +81,7 @@ declare function createTimer(callback: () => void, delay: number): Timer;
|
|
|
81
81
|
* Normalizes a given time to the nearest base time window.
|
|
82
82
|
*
|
|
83
83
|
* @param time - The Date object to normalize to the nearest time window
|
|
84
|
-
* @param baseTimeWindow - The size of the time window in minutes for normalization
|
|
84
|
+
* @param baseTimeWindow - The size of the time window in minutes for normalization; must be a positive finite number
|
|
85
85
|
* @returns A new Date object normalized to the start of the time window
|
|
86
86
|
*
|
|
87
87
|
* @example Normalizing to 15-minute buckets
|
package/index.esm.js
CHANGED
|
@@ -3,7 +3,7 @@ import { freeze } from './_dependencies/@hyperfrontend/immutable-api-utils/built
|
|
|
3
3
|
import { setInterval, clearInterval, setTimeout, clearTimeout } from './_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/timers/index.esm.js';
|
|
4
4
|
import { createError } from './_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/error/index.esm.js';
|
|
5
5
|
import { floor } from './_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/math/index.esm.js';
|
|
6
|
-
import { globalIsNaN } from './_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.esm.js';
|
|
6
|
+
import { globalIsNaN, isFinite } from './_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/number/index.esm.js';
|
|
7
7
|
import { createPromise } from './_dependencies/@hyperfrontend/immutable-api-utils/built-in-copy/promise/index.esm.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -91,7 +91,7 @@ function createTimer(callback, delay) {
|
|
|
91
91
|
if (timerId !== null) {
|
|
92
92
|
clearTimeout(timerId);
|
|
93
93
|
const now = dateNow();
|
|
94
|
-
|
|
94
|
+
// why: start is always set when timerId is not null, so the guard never falls through.
|
|
95
95
|
if (start !== null) {
|
|
96
96
|
remaining -= now - start;
|
|
97
97
|
}
|
|
@@ -119,7 +119,7 @@ function createTimer(callback, delay) {
|
|
|
119
119
|
* Normalizes a given time to the nearest base time window.
|
|
120
120
|
*
|
|
121
121
|
* @param time - The Date object to normalize to the nearest time window
|
|
122
|
-
* @param baseTimeWindow - The size of the time window in minutes for normalization
|
|
122
|
+
* @param baseTimeWindow - The size of the time window in minutes for normalization; must be a positive finite number
|
|
123
123
|
* @returns A new Date object normalized to the start of the time window
|
|
124
124
|
*
|
|
125
125
|
* @example Normalizing to 15-minute buckets
|
|
@@ -134,8 +134,8 @@ function normalizeToBaseTimeWindow(time, baseTimeWindow) {
|
|
|
134
134
|
if (!time || !(time instanceof Date) || globalIsNaN(time.getTime())) {
|
|
135
135
|
throw createError('Invalid time input');
|
|
136
136
|
}
|
|
137
|
-
if (baseTimeWindow <= 0) {
|
|
138
|
-
throw createError('Base time window must be positive');
|
|
137
|
+
if (!isFinite(baseTimeWindow) || baseTimeWindow <= 0) {
|
|
138
|
+
throw createError('Base time window must be a positive finite number');
|
|
139
139
|
}
|
|
140
140
|
const timeInMs = time.getTime();
|
|
141
141
|
const windowInMs = baseTimeWindow * 60 * 1000;
|