@enormora/clock 0.0.1 → 0.0.3

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Christian Rackerseder
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,250 @@
1
+ # @enormora/clock
2
+
3
+ Explicit time and timer access for TypeScript applications.
4
+
5
+ `@enormora/clock` provides a small dependency-injection boundary around time-related side effects:
6
+
7
+ - reading wall time as `Date`, Unix epoch milliseconds, or Unix epoch microseconds
8
+ - reading monotonic time and its Unix epoch origin
9
+ - scheduling and clearing timeouts
10
+ - scheduling and clearing intervals
11
+ - replacing real time with a deterministic clock in tests
12
+
13
+ It is not a date-time utility library or a general scheduler framework. The package keeps time access explicit so
14
+ application code does not need to call `Date.now()`, `new Date()`, `performance.now()`, `setTimeout`, or `setInterval`
15
+ directly.
16
+
17
+ ## Installation
18
+
19
+ ```sh
20
+ npm install @enormora/clock
21
+ ```
22
+
23
+ The package is ESM-only and requires Node.js `^24.15.0 || ^26.0.0`.
24
+
25
+ The root export keeps all clocks available from one import. Prefer explicit module subpaths when code only needs one
26
+ clock:
27
+
28
+ - `@enormora/clock/clock`
29
+ - `@enormora/clock/temporal-clock`
30
+ - `@enormora/clock/deterministic-clock`
31
+
32
+ ## Real Clock
33
+
34
+ Use `createClock()` at the application boundary and pass the resulting `Clock` into code that needs time.
35
+
36
+ ```ts
37
+ import { createClock } from '@enormora/clock/clock';
38
+
39
+ const clock = createClock();
40
+
41
+ console.log(clock.currentUnixEpochMilliseconds);
42
+ console.log(clock.currentUnixEpochMicroseconds);
43
+ console.log(clock.currentDate.toISOString());
44
+ ```
45
+
46
+ The real clock delegates to the runtime:
47
+
48
+ - `currentDate` returns a new `Date`
49
+ - `currentUnixEpochMilliseconds` uses `Date.now()`
50
+ - `currentUnixEpochMicroseconds` uses `Date.now() * 1000n`
51
+ - `monotonicTimeOriginUnixEpochMicroseconds` uses `performance.timeOrigin`
52
+ - `currentMonotonicMicroseconds` uses `performance.now()`
53
+ - timer functions call `globalThis`
54
+
55
+ `currentUnixEpochMicroseconds` communicates the unit, not a guaranteed resolution. Date-backed clocks expose
56
+ millisecond-resolution wall time in microseconds.
57
+
58
+ ## Temporal Clock
59
+
60
+ Use `createTemporalClock()` when the runtime provides `Temporal`.
61
+
62
+ ```ts
63
+ import { createTemporalClock } from '@enormora/clock/temporal-clock';
64
+
65
+ const clock = createTemporalClock();
66
+
67
+ console.log(clock.currentUnixEpochMicroseconds);
68
+ ```
69
+
70
+ The Temporal clock implements the same `Clock` interface. It uses `Temporal.Now.instant()` for wall time and
71
+ `performance` for monotonic time. Importing the module works without Temporal, but calling `createTemporalClock()`
72
+ throws when `globalThis.Temporal` is unavailable.
73
+
74
+ ## Dependency Injection
75
+
76
+ Prefer accepting a `Clock` as an explicit dependency for code that depends on time.
77
+
78
+ ```ts
79
+ import type { Clock } from '@enormora/clock/clock';
80
+
81
+ type Session = {
82
+ readonly expiresAtUnixEpochMilliseconds: number;
83
+ };
84
+
85
+ export function isSessionExpired(clock: Clock, session: Session): boolean {
86
+ return (
87
+ clock.currentUnixEpochMilliseconds >= session.expiresAtUnixEpochMilliseconds
88
+ );
89
+ }
90
+ ```
91
+
92
+ Use wall time for calendar time, storage, and user-facing timestamps. Use monotonic values for elapsed time and
93
+ durations.
94
+
95
+ ## Deterministic Clock
96
+
97
+ Use `createDeterministicClock()` in tests or deterministic environments.
98
+
99
+ ```ts
100
+ import { createDeterministicClock } from '@enormora/clock/deterministic-clock';
101
+
102
+ const clock = createDeterministicClock({
103
+ initialUnixEpochMicroseconds: 1_704_067_200_000_000n
104
+ });
105
+
106
+ console.log(clock.currentDate.toISOString());
107
+
108
+ clock.advanceByMilliseconds(1000);
109
+
110
+ console.log(clock.currentUnixEpochMilliseconds);
111
+ ```
112
+
113
+ The deterministic clock implements the same `Clock` interface and adds:
114
+
115
+ - `setCurrentUnixEpochMicroseconds(nextUnixEpochMicroseconds)`
116
+ - `advanceByMicroseconds(delayInMicroseconds)`
117
+ - `advanceByMilliseconds(delayInMilliseconds)`
118
+
119
+ Wall time and monotonic time are stored in microseconds. Timers are scheduled against monotonic time, so setting wall
120
+ time does not run or delay timers.
121
+
122
+ ## Testing Timers
123
+
124
+ The deterministic clock runs scheduled callbacks when monotonic time is advanced far enough.
125
+
126
+ ```ts
127
+ import assert from 'node:assert';
128
+ import { createDeterministicClock } from '@enormora/clock/deterministic-clock';
129
+
130
+ const clock = createDeterministicClock({
131
+ initialUnixEpochMicroseconds: 0n
132
+ });
133
+ const calls: string[] = [];
134
+
135
+ clock.setTimeout(
136
+ (value) => {
137
+ calls.push(value);
138
+ },
139
+ 100,
140
+ 'done'
141
+ );
142
+
143
+ clock.advanceByMilliseconds(99);
144
+ assert.deepStrictEqual(calls, []);
145
+
146
+ clock.advanceByMilliseconds(1);
147
+ assert.deepStrictEqual(calls, [ 'done' ]);
148
+ ```
149
+
150
+ Intervals run once for each elapsed interval.
151
+
152
+ ```ts
153
+ import assert from 'node:assert';
154
+ import { createDeterministicClock } from '@enormora/clock/deterministic-clock';
155
+
156
+ const clock = createDeterministicClock({
157
+ initialUnixEpochMicroseconds: 0n
158
+ });
159
+ let count = 0;
160
+
161
+ const intervalIdentifier = clock.setInterval(() => {
162
+ count += 1;
163
+ }, 100);
164
+
165
+ clock.advanceByMilliseconds(250);
166
+ assert.strictEqual(count, 2);
167
+
168
+ clock.clearInterval(intervalIdentifier);
169
+ clock.advanceByMilliseconds(500);
170
+ assert.strictEqual(count, 2);
171
+ ```
172
+
173
+ ## Timer Behavior
174
+
175
+ Timeouts:
176
+
177
+ - execute once
178
+ - execute only after the clock reaches their scheduled monotonic time
179
+ - execute in scheduled monotonic time order
180
+ - execute in registration order when multiple timeouts share the same scheduled time
181
+ - can use a delay of `0`
182
+ - reject negative and non-finite delays
183
+
184
+ Intervals:
185
+
186
+ - execute repeatedly
187
+ - execute once per elapsed interval when time advances
188
+ - stop after `clearInterval`
189
+ - reject `0`, negative, non-finite, and sub-microsecond delays
190
+
191
+ The deterministic clock rejects intervals that would round down to zero microseconds because they cannot advance safely.
192
+
193
+ ## API
194
+
195
+ ```ts
196
+ declare const timeoutIdentifierBrand: unique symbol;
197
+ declare const intervalIdentifierBrand: unique symbol;
198
+
199
+ export type TimeoutIdentifier = {
200
+ readonly [timeoutIdentifierBrand]: 'TimeoutIdentifier';
201
+ };
202
+
203
+ export type IntervalIdentifier = {
204
+ readonly [intervalIdentifierBrand]: 'IntervalIdentifier';
205
+ };
206
+
207
+ export type Clock = {
208
+ readonly currentDate: Date;
209
+ readonly currentUnixEpochMilliseconds: number;
210
+ readonly currentUnixEpochMicroseconds: bigint;
211
+ readonly monotonicTimeOriginUnixEpochMicroseconds: bigint;
212
+ readonly currentMonotonicMicroseconds: bigint;
213
+ readonly setTimeout: <HandlerArguments extends readonly unknown[]>(
214
+ handler: (...handlerArguments: HandlerArguments) => void,
215
+ delayInMilliseconds: number,
216
+ ...handlerArguments: HandlerArguments
217
+ ) => TimeoutIdentifier;
218
+ readonly clearTimeout: (timeoutIdentifier: TimeoutIdentifier) => void;
219
+ readonly setInterval: <HandlerArguments extends readonly unknown[]>(
220
+ handler: (...handlerArguments: HandlerArguments) => void,
221
+ delayInMilliseconds: number,
222
+ ...handlerArguments: HandlerArguments
223
+ ) => IntervalIdentifier;
224
+ readonly clearInterval: (intervalIdentifier: IntervalIdentifier) => void;
225
+ };
226
+ ```
227
+
228
+ ```ts
229
+ export type DeterministicClock = Clock & {
230
+ readonly setCurrentUnixEpochMicroseconds: (
231
+ nextUnixEpochMicroseconds: bigint
232
+ ) => void;
233
+ readonly advanceByMicroseconds: (delayInMicroseconds: bigint) => void;
234
+ readonly advanceByMilliseconds: (delayInMilliseconds: number) => void;
235
+ };
236
+ ```
237
+
238
+ ```ts
239
+ export function createClock(): Clock;
240
+ ```
241
+
242
+ ```ts
243
+ export function createTemporalClock(): Clock;
244
+ ```
245
+
246
+ ```ts
247
+ export function createDeterministicClock(options: {
248
+ readonly initialUnixEpochMicroseconds: bigint;
249
+ }): DeterministicClock;
250
+ ```
package/clock.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ declare const timeoutIdentifierBrand: unique symbol;
2
+ declare const intervalIdentifierBrand: unique symbol;
3
+ export type TimeoutIdentifier = {
4
+ readonly [timeoutIdentifierBrand]: 'TimeoutIdentifier';
5
+ };
6
+ export type IntervalIdentifier = {
7
+ readonly [intervalIdentifierBrand]: 'IntervalIdentifier';
8
+ };
9
+ export type Clock = {
10
+ readonly currentDate: Date;
11
+ readonly currentUnixEpochMilliseconds: number;
12
+ readonly currentUnixEpochMicroseconds: bigint;
13
+ readonly monotonicTimeOriginUnixEpochMicroseconds: bigint;
14
+ readonly currentMonotonicMicroseconds: bigint;
15
+ readonly setTimeout: <HandlerArguments extends readonly unknown[]>(handler: (...handlerArguments: HandlerArguments) => void, delayInMilliseconds: number, ...handlerArguments: HandlerArguments) => TimeoutIdentifier;
16
+ readonly clearTimeout: (timeoutIdentifier: TimeoutIdentifier) => void;
17
+ readonly setInterval: <HandlerArguments extends readonly unknown[]>(handler: (...handlerArguments: HandlerArguments) => void, delayInMilliseconds: number, ...handlerArguments: HandlerArguments) => IntervalIdentifier;
18
+ readonly clearInterval: (intervalIdentifier: IntervalIdentifier) => void;
19
+ };
20
+ export {};
21
+ //# sourceMappingURL=clock.d.ts.map
package/clock.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.d.ts","sourceRoot":"","sources":["../../../source/clock.ts"],"names":[],"mappings":"AAEA,OAAO,CAAC,MAAM,sBAAsB,EAAE,OAAO,MAAM,CAAC;AACpD,OAAO,CAAC,MAAM,uBAAuB,EAAE,OAAO,MAAM,CAAC;AAErD,MAAM,MAAM,iBAAiB,GAAG;IAC5B,QAAQ,CAAC,CAAC,sBAAsB,CAAC,EAAE,mBAAmB,CAAC;CAC1D,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC7B,QAAQ,CAAC,CAAC,uBAAuB,CAAC,EAAE,oBAAoB,CAAC;CAC5D,CAAC;AAEF,MAAM,MAAM,KAAK,GAAG;IAChB,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC;IAC3B,QAAQ,CAAC,4BAA4B,EAAE,MAAM,CAAC;IAC9C,QAAQ,CAAC,4BAA4B,EAAE,MAAM,CAAC;IAC9C,QAAQ,CAAC,wCAAwC,EAAE,MAAM,CAAC;IAC1D,QAAQ,CAAC,4BAA4B,EAAE,MAAM,CAAC;IAC9C,QAAQ,CAAC,UAAU,EAAE,CAAC,gBAAgB,SAAS,SAAS,OAAO,EAAE,EAC7D,OAAO,EAAE,CAAC,GAAG,gBAAgB,EAAE,gBAAgB,KAAK,IAAI,EACxD,mBAAmB,EAAE,MAAM,EAC3B,GAAG,gBAAgB,EAAE,gBAAgB,KACpC,iBAAiB,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,CAAC,iBAAiB,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACtE,QAAQ,CAAC,WAAW,EAAE,CAAC,gBAAgB,SAAS,SAAS,OAAO,EAAE,EAC9D,OAAO,EAAE,CAAC,GAAG,gBAAgB,EAAE,gBAAgB,KAAK,IAAI,EACxD,mBAAmB,EAAE,MAAM,EAC3B,GAAG,gBAAgB,EAAE,gBAAgB,KACpC,kBAAkB,CAAC;IACxB,QAAQ,CAAC,aAAa,EAAE,CAAC,kBAAkB,EAAE,kBAAkB,KAAK,IAAI,CAAC;CAC5E,CAAC;AAEF,MAAM,CAA0B,EAS/B,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { type Clock as RuntimeClock, type IntervalIdentifier as RuntimeIntervalIdentifier, type TimeoutIdentifier as RuntimeTimeoutIdentifier } from './clock.ts';
2
+ export type Clock = RuntimeClock;
3
+ export type TimeoutIdentifier = RuntimeTimeoutIdentifier;
4
+ export type IntervalIdentifier = RuntimeIntervalIdentifier;
5
+ export declare function createClock(): RuntimeClock;
6
+ //# sourceMappingURL=clock.entry-point.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.entry-point.d.ts","sourceRoot":"","sources":["../../../source/clock.entry-point.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,KAAK,KAAK,IAAI,YAAY,EAC1B,KAAK,kBAAkB,IAAI,yBAAyB,EACpD,KAAK,iBAAiB,IAAI,wBAAwB,EACrD,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,KAAK,GAAG,YAAY,CAAC;AACjC,MAAM,MAAM,iBAAiB,GAAG,wBAAwB,CAAC;AACzD,MAAM,MAAM,kBAAkB,GAAG,yBAAyB,CAAC;AAE3D,wBAAgB,WAAW,IAAI,YAAY,CA+B1C"}
@@ -0,0 +1,26 @@
1
+ import { createClock as createClockFromDependencies } from "./clock.js";
2
+ export function createClock() {
3
+ return createClockFromDependencies({
4
+ currentDate() {
5
+ return new Date();
6
+ },
7
+ currentUnixEpochMilliseconds() {
8
+ return Date.now();
9
+ },
10
+ monotonicTimeOriginMilliseconds: globalThis.performance.timeOrigin,
11
+ currentMonotonicMilliseconds: globalThis.performance.now.bind(globalThis.performance),
12
+ setTimeout(handler, delayInMilliseconds, ...handlerArguments) {
13
+ return globalThis.setTimeout(handler, delayInMilliseconds, ...handlerArguments);
14
+ },
15
+ clearTimeout(timeoutIdentifier) {
16
+ globalThis.clearTimeout(timeoutIdentifier);
17
+ },
18
+ setInterval(handler, delayInMilliseconds, ...handlerArguments) {
19
+ return globalThis.setInterval(handler, delayInMilliseconds, ...handlerArguments);
20
+ },
21
+ clearInterval(intervalIdentifier) {
22
+ globalThis.clearInterval(intervalIdentifier);
23
+ }
24
+ });
25
+ }
26
+ //# sourceMappingURL=clock.entry-point.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.entry-point.js","sourceRoot":"","sources":["../../../source/clock.entry-point.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,WAAW,IAAI,2BAA2B,EAI7C,MAAM,YAAY,CAAC;AAMpB,MAAM,UAAU,WAAW;IACvB,OAAO,2BAA2B,CAAC;QAC/B,WAAW;YACP,OAAO,IAAI,IAAI,EAAE,CAAC;QACtB,CAAC;QACD,4BAA4B;YACxB,OAAO,IAAI,CAAC,GAAG,EAAE,CAAC;QACtB,CAAC;QACD,+BAA+B,EAAE,UAAU,CAAC,WAAW,CAAC,UAAU;QAClE,4BAA4B,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QACrF,UAAU,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,gBAAgB;YACxD,OAAO,UAAU,CAAC,UAAU,CACxB,OAAO,EACP,mBAAmB,EACnB,GAAG,gBAAgB,CACiB,CAAC;QAC7C,CAAC;QACD,YAAY,CAAC,iBAAiB;YAC1B,UAAU,CAAC,YAAY,CAAC,iBAAwE,CAAC,CAAC;QACtG,CAAC;QACD,WAAW,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,gBAAgB;YACzD,OAAO,UAAU,CAAC,WAAW,CACzB,OAAO,EACP,mBAAmB,EACnB,GAAG,gBAAgB,CACkB,CAAC;QAC9C,CAAC;QACD,aAAa,CAAC,kBAAkB;YAC5B,UAAU,CAAC,aAAa,CAAC,kBAA0E,CAAC,CAAC;QACzG,CAAC;KACJ,CAAC,CAAC;AACP,CAAC"}
package/clock.js ADDED
@@ -0,0 +1,28 @@
1
+ const microsecondsPerMillisecond = 1000n;
2
+ function millisecondsToMicroseconds(milliseconds) {
3
+ return BigInt(Math.floor(milliseconds * Number(microsecondsPerMillisecond)));
4
+ }
5
+ export function createClock(dependencies) {
6
+ return {
7
+ get currentDate() {
8
+ return dependencies.currentDate();
9
+ },
10
+ get currentUnixEpochMilliseconds() {
11
+ return dependencies.currentUnixEpochMilliseconds();
12
+ },
13
+ get currentUnixEpochMicroseconds() {
14
+ return millisecondsToMicroseconds(dependencies.currentUnixEpochMilliseconds());
15
+ },
16
+ get monotonicTimeOriginUnixEpochMicroseconds() {
17
+ return millisecondsToMicroseconds(dependencies.monotonicTimeOriginMilliseconds);
18
+ },
19
+ get currentMonotonicMicroseconds() {
20
+ return millisecondsToMicroseconds(dependencies.currentMonotonicMilliseconds());
21
+ },
22
+ setTimeout: dependencies.setTimeout,
23
+ clearTimeout: dependencies.clearTimeout,
24
+ setInterval: dependencies.setInterval,
25
+ clearInterval: dependencies.clearInterval
26
+ };
27
+ }
28
+ //# sourceMappingURL=clock.js.map
package/clock.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clock.js","sourceRoot":"","sources":["../../../source/clock.ts"],"names":[],"mappings":"AAAA,MAAM,0BAA0B,GAAG,KAAK,CAAC;AA4CzC,SAAS,0BAA0B,CAAC,YAAoB;IACpD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,MAAM,CAAC,0BAA0B,CAAC,CAAC,CAAC,CAAC;AACjF,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,YAA+B;IACvD,OAAO;QACH,IAAI,WAAW;YACX,OAAO,YAAY,CAAC,WAAW,EAAE,CAAC;QACtC,CAAC;QAED,IAAI,4BAA4B;YAC5B,OAAO,YAAY,CAAC,4BAA4B,EAAE,CAAC;QACvD,CAAC;QAED,IAAI,4BAA4B;YAC5B,OAAO,0BAA0B,CAAC,YAAY,CAAC,4BAA4B,EAAE,CAAC,CAAC;QACnF,CAAC;QAED,IAAI,wCAAwC;YACxC,OAAO,0BAA0B,CAAC,YAAY,CAAC,+BAA+B,CAAC,CAAC;QACpF,CAAC;QAED,IAAI,4BAA4B;YAC5B,OAAO,0BAA0B,CAAC,YAAY,CAAC,4BAA4B,EAAE,CAAC,CAAC;QACnF,CAAC;QAED,UAAU,EAAE,YAAY,CAAC,UAAU;QAEnC,YAAY,EAAE,YAAY,CAAC,YAAY;QAEvC,WAAW,EAAE,YAAY,CAAC,WAAW;QAErC,aAAa,EAAE,YAAY,CAAC,aAAa;KAC5C,CAAC;AACN,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Clock } from './clock.ts';
2
+ export type DeterministicClock = Clock & {
3
+ readonly setCurrentUnixEpochMicroseconds: (nextUnixEpochMicroseconds: bigint) => void;
4
+ readonly advanceByMicroseconds: (delayInMicroseconds: bigint) => void;
5
+ readonly advanceByMilliseconds: (delayInMilliseconds: number) => void;
6
+ };
7
+ export type DeterministicClockOptions = {
8
+ readonly initialUnixEpochMicroseconds: bigint;
9
+ };
10
+ export declare function createDeterministicClock(options: DeterministicClockOptions): DeterministicClock;
11
+ //# sourceMappingURL=deterministic-clock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deterministic-clock.d.ts","sourceRoot":"","sources":["../../../source/deterministic-clock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGxC,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG;IACrC,QAAQ,CAAC,+BAA+B,EAAE,CAAC,yBAAyB,EAAE,MAAM,KAAK,IAAI,CAAC;IACtF,QAAQ,CAAC,qBAAqB,EAAE,CAAC,mBAAmB,EAAE,MAAM,KAAK,IAAI,CAAC;IACtE,QAAQ,CAAC,qBAAqB,EAAE,CAAC,mBAAmB,EAAE,MAAM,KAAK,IAAI,CAAC;CACzE,CAAC;AAEF,MAAM,MAAM,yBAAyB,GAAG;IACpC,QAAQ,CAAC,4BAA4B,EAAE,MAAM,CAAC;CACjD,CAAC;AA4LF,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,kBAAkB,CAkE/F"}
@@ -0,0 +1,170 @@
1
+ import { validateIntervalDelayInMilliseconds, validateTimeoutDelayInMilliseconds } from "./timer-delay.js";
2
+ const microsecondsPerMillisecond = 1000n;
3
+ const minimumDelayInMicroseconds = 0n;
4
+ function compareMicroseconds(firstMicroseconds, secondMicroseconds) {
5
+ if (firstMicroseconds < secondMicroseconds) {
6
+ return -1;
7
+ }
8
+ if (firstMicroseconds > secondMicroseconds) {
9
+ return 1;
10
+ }
11
+ return 0;
12
+ }
13
+ function compareTimeoutEntries(firstTimeoutEntry, secondTimeoutEntry) {
14
+ const [firstTimeoutIdentifier, firstTimeoutRegistration] = firstTimeoutEntry;
15
+ const [secondTimeoutIdentifier, secondTimeoutRegistration] = secondTimeoutEntry;
16
+ const timeoutExecutionOrder = compareMicroseconds(firstTimeoutRegistration.executionMonotonicMicroseconds, secondTimeoutRegistration.executionMonotonicMicroseconds);
17
+ if (timeoutExecutionOrder !== 0) {
18
+ return timeoutExecutionOrder;
19
+ }
20
+ return firstTimeoutIdentifier - secondTimeoutIdentifier;
21
+ }
22
+ function millisecondsToMicroseconds(milliseconds) {
23
+ return BigInt(Math.floor(milliseconds * Number(microsecondsPerMillisecond)));
24
+ }
25
+ function unixEpochMillisecondsFromMicroseconds(unixEpochMicroseconds) {
26
+ return Number(unixEpochMicroseconds / microsecondsPerMillisecond);
27
+ }
28
+ function ensureValidDateUnixEpochMicroseconds(unixEpochMicroseconds) {
29
+ const unixEpochMilliseconds = unixEpochMillisecondsFromMicroseconds(unixEpochMicroseconds);
30
+ const date = new Date(unixEpochMilliseconds);
31
+ if (Number.isNaN(date.getTime())) {
32
+ throw new RangeError('Invalid Unix epoch microseconds, must be representable as a Date');
33
+ }
34
+ }
35
+ function validateDelayInMicroseconds(delayInMicroseconds) {
36
+ if (delayInMicroseconds < minimumDelayInMicroseconds) {
37
+ throw new RangeError(`Invalid delay ${delayInMicroseconds.toString()}, must be greater than or equal to 0`);
38
+ }
39
+ }
40
+ function createTimeoutController(currentMonotonicMicroseconds) {
41
+ let nextTimeoutIdentifier = 0;
42
+ const timeoutRegistrations = new Map();
43
+ function runDueTimeoutRegistrations() {
44
+ const dueTimeoutEntries = Array
45
+ .from(timeoutRegistrations)
46
+ .filter(function ([, timeoutRegistration]) {
47
+ return timeoutRegistration.executionMonotonicMicroseconds <= currentMonotonicMicroseconds();
48
+ })
49
+ .toSorted(compareTimeoutEntries);
50
+ dueTimeoutEntries.forEach(function ([timeoutIdentifier, timeoutRegistration]) {
51
+ timeoutRegistrations.delete(timeoutIdentifier);
52
+ timeoutRegistration.execute();
53
+ });
54
+ }
55
+ return {
56
+ runDueTimeoutRegistrations,
57
+ setTimeout(handler, delayInMilliseconds, ...handlerArguments) {
58
+ validateTimeoutDelayInMilliseconds(delayInMilliseconds);
59
+ const timeoutIdentifier = nextTimeoutIdentifier;
60
+ nextTimeoutIdentifier += 1;
61
+ const delayInMicroseconds = millisecondsToMicroseconds(delayInMilliseconds);
62
+ timeoutRegistrations.set(timeoutIdentifier, {
63
+ execute() {
64
+ handler(...handlerArguments);
65
+ },
66
+ executionMonotonicMicroseconds: currentMonotonicMicroseconds() + delayInMicroseconds
67
+ });
68
+ return timeoutIdentifier;
69
+ },
70
+ clearTimeout(timeoutIdentifier) {
71
+ timeoutRegistrations.delete(timeoutIdentifier);
72
+ }
73
+ };
74
+ }
75
+ function createIntervalController(currentMonotonicMicroseconds) {
76
+ let nextIntervalIdentifier = 0;
77
+ const intervalRegistrations = new Map();
78
+ function runDueIntervalRegistrations() {
79
+ intervalRegistrations.forEach(function (intervalRegistration, intervalIdentifier) {
80
+ const { delayInMicroseconds, execute } = intervalRegistration;
81
+ let { nextExecutionMonotonicMicroseconds } = intervalRegistration;
82
+ while (nextExecutionMonotonicMicroseconds <= currentMonotonicMicroseconds()) {
83
+ execute();
84
+ if (!intervalRegistrations.has(intervalIdentifier)) {
85
+ return;
86
+ }
87
+ nextExecutionMonotonicMicroseconds += delayInMicroseconds;
88
+ intervalRegistrations.set(intervalIdentifier, {
89
+ delayInMicroseconds,
90
+ execute,
91
+ nextExecutionMonotonicMicroseconds
92
+ });
93
+ }
94
+ });
95
+ }
96
+ return {
97
+ runDueIntervalRegistrations,
98
+ setInterval(handler, delayInMilliseconds, ...handlerArguments) {
99
+ validateIntervalDelayInMilliseconds(delayInMilliseconds);
100
+ const intervalIdentifier = nextIntervalIdentifier;
101
+ nextIntervalIdentifier += 1;
102
+ const delayInMicroseconds = millisecondsToMicroseconds(delayInMilliseconds);
103
+ if (delayInMicroseconds <= minimumDelayInMicroseconds) {
104
+ throw new RangeError(`Invalid interval delay ${delayInMilliseconds}, must be at least 1 microsecond`);
105
+ }
106
+ intervalRegistrations.set(intervalIdentifier, {
107
+ delayInMicroseconds,
108
+ execute() {
109
+ handler(...handlerArguments);
110
+ },
111
+ nextExecutionMonotonicMicroseconds: currentMonotonicMicroseconds() + delayInMicroseconds
112
+ });
113
+ return intervalIdentifier;
114
+ },
115
+ clearInterval(intervalIdentifier) {
116
+ intervalRegistrations.delete(intervalIdentifier);
117
+ }
118
+ };
119
+ }
120
+ export function createDeterministicClock(options) {
121
+ const { initialUnixEpochMicroseconds } = options;
122
+ ensureValidDateUnixEpochMicroseconds(initialUnixEpochMicroseconds);
123
+ let currentUnixEpochMicroseconds = initialUnixEpochMicroseconds;
124
+ let currentMonotonicMicroseconds = minimumDelayInMicroseconds;
125
+ function currentMonotonicMicrosecondsReader() {
126
+ return currentMonotonicMicroseconds;
127
+ }
128
+ const timeoutController = createTimeoutController(currentMonotonicMicrosecondsReader);
129
+ const intervalController = createIntervalController(currentMonotonicMicrosecondsReader);
130
+ function advanceClockByMicroseconds(delayInMicroseconds) {
131
+ validateDelayInMicroseconds(delayInMicroseconds);
132
+ const nextUnixEpochMicroseconds = currentUnixEpochMicroseconds + delayInMicroseconds;
133
+ ensureValidDateUnixEpochMicroseconds(nextUnixEpochMicroseconds);
134
+ currentUnixEpochMicroseconds = nextUnixEpochMicroseconds;
135
+ currentMonotonicMicroseconds += delayInMicroseconds;
136
+ intervalController.runDueIntervalRegistrations();
137
+ timeoutController.runDueTimeoutRegistrations();
138
+ }
139
+ return {
140
+ get currentDate() {
141
+ return new Date(unixEpochMillisecondsFromMicroseconds(currentUnixEpochMicroseconds));
142
+ },
143
+ get currentUnixEpochMilliseconds() {
144
+ return unixEpochMillisecondsFromMicroseconds(currentUnixEpochMicroseconds);
145
+ },
146
+ get currentUnixEpochMicroseconds() {
147
+ return currentUnixEpochMicroseconds;
148
+ },
149
+ get monotonicTimeOriginUnixEpochMicroseconds() {
150
+ return initialUnixEpochMicroseconds;
151
+ },
152
+ get currentMonotonicMicroseconds() {
153
+ return currentMonotonicMicroseconds;
154
+ },
155
+ setCurrentUnixEpochMicroseconds(nextUnixEpochMicroseconds) {
156
+ ensureValidDateUnixEpochMicroseconds(nextUnixEpochMicroseconds);
157
+ currentUnixEpochMicroseconds = nextUnixEpochMicroseconds;
158
+ },
159
+ advanceByMicroseconds: advanceClockByMicroseconds,
160
+ advanceByMilliseconds(delayInMilliseconds) {
161
+ validateTimeoutDelayInMilliseconds(delayInMilliseconds);
162
+ advanceClockByMicroseconds(millisecondsToMicroseconds(delayInMilliseconds));
163
+ },
164
+ setTimeout: timeoutController.setTimeout,
165
+ clearTimeout: timeoutController.clearTimeout,
166
+ setInterval: intervalController.setInterval,
167
+ clearInterval: intervalController.clearInterval
168
+ };
169
+ }
170
+ //# sourceMappingURL=deterministic-clock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deterministic-clock.js","sourceRoot":"","sources":["../../../source/deterministic-clock.ts"],"names":[],"mappings":"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"}
package/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export { createClock } from './clock.entry-point.ts';
2
+ export type { Clock, IntervalIdentifier, TimeoutIdentifier } from './clock.entry-point.ts';
3
+ export { createTemporalClock } from './temporal-clock.entry-point.ts';
4
+ export { createDeterministicClock } from './deterministic-clock.ts';
5
+ export type { DeterministicClock, DeterministicClockOptions } from './deterministic-clock.ts';
6
+ //# sourceMappingURL=index.d.ts.map
package/index.d.ts.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../source/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrD,YAAY,EAAE,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3F,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACpE,YAAY,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC"}
package/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { createClock } from "./clock.entry-point.js";
2
+ export { createTemporalClock } from "./temporal-clock.entry-point.js";
3
+ export { createDeterministicClock } from "./deterministic-clock.js";
4
+ //# sourceMappingURL=index.js.map
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../source/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAErD,OAAO,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,34 @@
1
1
  {
2
- "name": "@enormora/clock",
3
- "version": "0.0.1",
4
- "description": "Placeholder claiming the npm package name \"@enormora/clock\" so a trusted publisher can be configured. See https://github.com/npm/cli/issues/8544.",
5
- "license": "MIT",
6
- "deprecated": "Placeholder published as a workaround so a Trusted Publisher could be configured. See https://github.com/npm/cli/issues/8544."
7
- }
2
+ "author": "Christian Rackerseder <git@echooff.de>",
3
+ "description": "Explicit time and timer access for TypeScript applications",
4
+ "engines": {
5
+ "node": "^24.15.0 || ^26.0.0"
6
+ },
7
+ "exports": {
8
+ ".": {
9
+ "import": "./index.js",
10
+ "types": "./index.d.ts"
11
+ },
12
+ "./clock": {
13
+ "import": "./clock.entry-point.js",
14
+ "types": "./clock.entry-point.d.ts"
15
+ },
16
+ "./deterministic-clock": {
17
+ "import": "./deterministic-clock.js",
18
+ "types": "./deterministic-clock.d.ts"
19
+ },
20
+ "./temporal-clock": {
21
+ "import": "./temporal-clock.entry-point.js",
22
+ "types": "./temporal-clock.entry-point.d.ts"
23
+ }
24
+ },
25
+ "license": "MIT",
26
+ "name": "@enormora/clock",
27
+ "repository": {
28
+ "type": "git",
29
+ "url": "git+ssh://git@github.com/enormora/clock.git"
30
+ },
31
+ "sideEffects": false,
32
+ "type": "module",
33
+ "version": "0.0.3"
34
+ }
package/sbom.cdx.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
3
+ "bomFormat": "CycloneDX",
4
+ "specVersion": "1.6",
5
+ "version": 1,
6
+ "metadata": {
7
+ "tools": {
8
+ "components": [
9
+ {
10
+ "type": "application",
11
+ "name": "packtory",
12
+ "version": "0.0.114"
13
+ }
14
+ ]
15
+ },
16
+ "component": {
17
+ "type": "library",
18
+ "name": "@enormora/clock",
19
+ "version": "0.0.3",
20
+ "bom-ref": "pkg:npm/@enormora/clock@0.0.3",
21
+ "purl": "pkg:npm/@enormora/clock@0.0.3"
22
+ }
23
+ },
24
+ "components": [],
25
+ "dependencies": [
26
+ {
27
+ "ref": "pkg:npm/@enormora/clock@0.0.3"
28
+ }
29
+ ]
30
+ }
@@ -0,0 +1,3 @@
1
+ import type { Clock } from './clock.ts';
2
+ export declare function createTemporalClock(): Clock;
3
+ //# sourceMappingURL=temporal-clock.entry-point.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temporal-clock.entry-point.d.ts","sourceRoot":"","sources":["../../../source/temporal-clock.entry-point.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACR,KAAK,EAGR,MAAM,YAAY,CAAC;AA2BpB,wBAAgB,mBAAmB,IAAI,KAAK,CA4B3C"}
@@ -0,0 +1,29 @@
1
+ import { createTemporalClock as createTemporalClockFromDependencies } from "./temporal-clock.js";
2
+ function readTemporalClockApi() {
3
+ const temporalClockApi = globalThis.Temporal;
4
+ if (temporalClockApi === undefined) {
5
+ throw new ReferenceError('Temporal is not available');
6
+ }
7
+ return temporalClockApi;
8
+ }
9
+ export function createTemporalClock() {
10
+ const temporalClockApi = readTemporalClockApi();
11
+ return createTemporalClockFromDependencies({
12
+ currentInstant: temporalClockApi.Now.instant.bind(temporalClockApi.Now),
13
+ monotonicTimeOriginMilliseconds: globalThis.performance.timeOrigin,
14
+ currentMonotonicMilliseconds: globalThis.performance.now.bind(globalThis.performance),
15
+ setTimeout(handler, delayInMilliseconds, ...handlerArguments) {
16
+ return globalThis.setTimeout(handler, delayInMilliseconds, ...handlerArguments);
17
+ },
18
+ clearTimeout(timeoutIdentifier) {
19
+ globalThis.clearTimeout(timeoutIdentifier);
20
+ },
21
+ setInterval(handler, delayInMilliseconds, ...handlerArguments) {
22
+ return globalThis.setInterval(handler, delayInMilliseconds, ...handlerArguments);
23
+ },
24
+ clearInterval(intervalIdentifier) {
25
+ globalThis.clearInterval(intervalIdentifier);
26
+ }
27
+ });
28
+ }
29
+ //# sourceMappingURL=temporal-clock.entry-point.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temporal-clock.entry-point.js","sourceRoot":"","sources":["../../../source/temporal-clock.entry-point.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,IAAI,mCAAmC,EAAE,MAAM,qBAAqB,CAAC;AAsBjG,SAAS,oBAAoB;IACzB,MAAM,gBAAgB,GAAI,UAAoC,CAAC,QAAQ,CAAC;IAExE,IAAI,gBAAgB,KAAK,SAAS,EAAE,CAAC;QACjC,MAAM,IAAI,cAAc,CAAC,2BAA2B,CAAC,CAAC;IAC1D,CAAC;IAED,OAAO,gBAAgB,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,mBAAmB;IAC/B,MAAM,gBAAgB,GAAG,oBAAoB,EAAE,CAAC;IAEhD,OAAO,mCAAmC,CAAC;QACvC,cAAc,EAAE,gBAAgB,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC;QACvE,+BAA+B,EAAE,UAAU,CAAC,WAAW,CAAC,UAAU;QAClE,4BAA4B,EAAE,UAAU,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QACrF,UAAU,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,gBAAgB;YACxD,OAAO,UAAU,CAAC,UAAU,CACxB,OAAO,EACP,mBAAmB,EACnB,GAAG,gBAAgB,CACiB,CAAC;QAC7C,CAAC;QACD,YAAY,CAAC,iBAAiB;YAC1B,UAAU,CAAC,YAAY,CAAC,iBAAwE,CAAC,CAAC;QACtG,CAAC;QACD,WAAW,CAAC,OAAO,EAAE,mBAAmB,EAAE,GAAG,gBAAgB;YACzD,OAAO,UAAU,CAAC,WAAW,CACzB,OAAO,EACP,mBAAmB,EACnB,GAAG,gBAAgB,CACkB,CAAC;QAC9C,CAAC;QACD,aAAa,CAAC,kBAAkB;YAC5B,UAAU,CAAC,aAAa,CAAC,kBAA0E,CAAC,CAAC;QACzG,CAAC;KACJ,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,29 @@
1
+ const microsecondsPerMillisecond = 1000;
2
+ const nanosecondsPerMicrosecond = 1000n;
3
+ function millisecondsToMicroseconds(milliseconds) {
4
+ return BigInt(Math.floor(milliseconds * microsecondsPerMillisecond));
5
+ }
6
+ export function createTemporalClock(dependencies) {
7
+ return {
8
+ get currentDate() {
9
+ return new Date(dependencies.currentInstant().epochMilliseconds);
10
+ },
11
+ get currentUnixEpochMilliseconds() {
12
+ return dependencies.currentInstant().epochMilliseconds;
13
+ },
14
+ get currentUnixEpochMicroseconds() {
15
+ return dependencies.currentInstant().epochNanoseconds / nanosecondsPerMicrosecond;
16
+ },
17
+ get monotonicTimeOriginUnixEpochMicroseconds() {
18
+ return millisecondsToMicroseconds(dependencies.monotonicTimeOriginMilliseconds);
19
+ },
20
+ get currentMonotonicMicroseconds() {
21
+ return millisecondsToMicroseconds(dependencies.currentMonotonicMilliseconds());
22
+ },
23
+ setTimeout: dependencies.setTimeout,
24
+ clearTimeout: dependencies.clearTimeout,
25
+ setInterval: dependencies.setInterval,
26
+ clearInterval: dependencies.clearInterval
27
+ };
28
+ }
29
+ //# sourceMappingURL=temporal-clock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"temporal-clock.js","sourceRoot":"","sources":["../../../source/temporal-clock.ts"],"names":[],"mappings":"AAiBA,MAAM,0BAA0B,GAAG,IAAI,CAAC;AACxC,MAAM,yBAAyB,GAAG,KAAK,CAAC;AAExC,SAAS,0BAA0B,CAAC,YAAoB;IACpD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,0BAA0B,CAAC,CAAC,CAAC;AACzE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,YAAuC;IACvE,OAAO;QACH,IAAI,WAAW;YACX,OAAO,IAAI,IAAI,CAAC,YAAY,CAAC,cAAc,EAAE,CAAC,iBAAiB,CAAC,CAAC;QACrE,CAAC;QAED,IAAI,4BAA4B;YAC5B,OAAO,YAAY,CAAC,cAAc,EAAE,CAAC,iBAAiB,CAAC;QAC3D,CAAC;QAED,IAAI,4BAA4B;YAC5B,OAAO,YAAY,CAAC,cAAc,EAAE,CAAC,gBAAgB,GAAG,yBAAyB,CAAC;QACtF,CAAC;QAED,IAAI,wCAAwC;YACxC,OAAO,0BAA0B,CAAC,YAAY,CAAC,+BAA+B,CAAC,CAAC;QACpF,CAAC;QAED,IAAI,4BAA4B;YAC5B,OAAO,0BAA0B,CAAC,YAAY,CAAC,4BAA4B,EAAE,CAAC,CAAC;QACnF,CAAC;QAED,UAAU,EAAE,YAAY,CAAC,UAAU;QAEnC,YAAY,EAAE,YAAY,CAAC,YAAY;QAEvC,WAAW,EAAE,YAAY,CAAC,WAAW;QAErC,aAAa,EAAE,YAAY,CAAC,aAAa;KAC5C,CAAC;AACN,CAAC"}
package/timer-delay.js ADDED
@@ -0,0 +1,18 @@
1
+ export function validateFiniteDelayInMilliseconds(delayInMilliseconds) {
2
+ if (!Number.isFinite(delayInMilliseconds)) {
3
+ throw new TypeError('Invalid delay, must be a finite number');
4
+ }
5
+ }
6
+ export function validateTimeoutDelayInMilliseconds(delayInMilliseconds) {
7
+ validateFiniteDelayInMilliseconds(delayInMilliseconds);
8
+ if (delayInMilliseconds < 0) {
9
+ throw new RangeError(`Invalid timeout delay ${delayInMilliseconds}, must be greater than or equal to 0`);
10
+ }
11
+ }
12
+ export function validateIntervalDelayInMilliseconds(delayInMilliseconds) {
13
+ validateFiniteDelayInMilliseconds(delayInMilliseconds);
14
+ if (delayInMilliseconds <= 0) {
15
+ throw new RangeError(`Invalid interval delay ${delayInMilliseconds}, must be greater than 0`);
16
+ }
17
+ }
18
+ //# sourceMappingURL=timer-delay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"timer-delay.js","sourceRoot":"","sources":["../../../source/timer-delay.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,iCAAiC,CAAC,mBAA2B;IACzE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;QACxC,MAAM,IAAI,SAAS,CAAC,wCAAwC,CAAC,CAAC;IAClE,CAAC;AACL,CAAC;AAED,MAAM,UAAU,kCAAkC,CAAC,mBAA2B;IAC1E,iCAAiC,CAAC,mBAAmB,CAAC,CAAC;IAEvD,IAAI,mBAAmB,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,UAAU,CAAC,yBAAyB,mBAAmB,sCAAsC,CAAC,CAAC;IAC7G,CAAC;AACL,CAAC;AAED,MAAM,UAAU,mCAAmC,CAAC,mBAA2B;IAC3E,iCAAiC,CAAC,mBAAmB,CAAC,CAAC;IAEvD,IAAI,mBAAmB,IAAI,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,UAAU,CAAC,0BAA0B,mBAAmB,0BAA0B,CAAC,CAAC;IAClG,CAAC;AACL,CAAC"}
package/readme.md DELETED
@@ -1,7 +0,0 @@
1
- # @enormora/clock
2
-
3
- This version is a placeholder published only to claim the npm name `@enormora/clock` so a Trusted Publisher
4
- can subsequently be configured for it. It contains no real package content and is published already
5
- deprecated.
6
-
7
- Workaround context: https://github.com/npm/cli/issues/8544