@evolu/common 7.4.0 → 8.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -61
- package/dist/src/Array.d.ts +343 -102
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +181 -85
- package/dist/src/Assert.d.ts +57 -11
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +47 -11
- package/dist/src/BigInt.d.ts +6 -1
- package/dist/src/BigInt.d.ts.map +1 -1
- package/dist/src/BigInt.js +5 -0
- package/dist/src/Brand.d.ts +40 -12
- package/dist/src/Brand.d.ts.map +1 -1
- package/dist/src/Brand.js +5 -0
- package/dist/src/Buffer.d.ts +6 -1
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Buffer.js +7 -2
- package/dist/src/Cache.d.ts +10 -2
- package/dist/src/Cache.d.ts.map +1 -1
- package/dist/src/Cache.js +6 -0
- package/dist/src/Callbacks.d.ts +10 -7
- package/dist/src/Callbacks.d.ts.map +1 -1
- package/dist/src/Callbacks.js +23 -13
- package/dist/src/Console.d.ts +361 -69
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +217 -117
- package/dist/src/Crypto.d.ts +70 -21
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +72 -27
- package/dist/src/Eq.d.ts +22 -2
- package/dist/src/Eq.d.ts.map +1 -1
- package/dist/src/Eq.js +21 -1
- package/dist/src/Error.d.ts +23 -12
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +27 -11
- package/dist/src/Function.d.ts +128 -56
- package/dist/src/Function.d.ts.map +1 -1
- package/dist/src/Function.js +118 -14
- package/dist/src/Identicon.d.ts +5 -0
- package/dist/src/Identicon.d.ts.map +1 -1
- package/dist/src/Identicon.js +6 -1
- package/dist/src/Lookup.d.ts +160 -0
- package/dist/src/Lookup.d.ts.map +1 -0
- package/dist/src/Lookup.js +192 -0
- package/dist/src/Microtask.d.ts +21 -0
- package/dist/src/Microtask.d.ts.map +1 -0
- package/dist/src/Microtask.js +37 -0
- package/dist/src/Number.d.ts +18 -4
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +23 -1
- package/dist/src/Object.d.ts +110 -5
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +108 -5
- package/dist/src/Option.d.ts +58 -0
- package/dist/src/Option.d.ts.map +1 -0
- package/dist/src/Option.js +43 -0
- package/dist/src/Order.d.ts +5 -0
- package/dist/src/Order.d.ts.map +1 -1
- package/dist/src/Order.js +8 -3
- package/dist/src/Platform.d.ts +36 -2
- package/dist/src/Platform.d.ts.map +1 -1
- package/dist/src/Platform.js +10 -6
- package/dist/src/Polyfills.d.ts +27 -0
- package/dist/src/Polyfills.d.ts.map +1 -0
- package/dist/src/Polyfills.js +299 -0
- package/dist/src/Random.d.ts +18 -7
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Random.js +9 -7
- package/dist/src/Redacted.d.ts +7 -4
- package/dist/src/Redacted.d.ts.map +1 -1
- package/dist/src/Redacted.js +5 -0
- package/dist/src/Ref.d.ts +31 -16
- package/dist/src/Ref.d.ts.map +1 -1
- package/dist/src/Ref.js +35 -7
- package/dist/src/RefCount.d.ts +62 -0
- package/dist/src/RefCount.d.ts.map +1 -0
- package/dist/src/RefCount.js +83 -0
- package/dist/src/Relation.d.ts +84 -29
- package/dist/src/Relation.d.ts.map +1 -1
- package/dist/src/Relation.js +83 -105
- package/dist/src/Resource.d.ts +263 -0
- package/dist/src/Resource.d.ts.map +1 -0
- package/dist/src/Resource.js +389 -0
- package/dist/src/Result.d.ts +390 -374
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +142 -70
- package/dist/src/Schedule.d.ts +953 -0
- package/dist/src/Schedule.d.ts.map +1 -0
- package/dist/src/Schedule.js +1199 -0
- package/dist/src/Set.d.ts +181 -0
- package/dist/src/Set.d.ts.map +1 -0
- package/dist/src/Set.js +137 -0
- package/dist/src/Skiplist.d.ts +6 -1
- package/dist/src/Skiplist.d.ts.map +1 -1
- package/dist/src/Skiplist.js +5 -0
- package/dist/src/Sqlite.d.ts +160 -60
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +290 -190
- package/dist/src/Store.d.ts +36 -28
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +55 -15
- package/dist/src/String.d.ts +5 -0
- package/dist/src/String.d.ts.map +1 -1
- package/dist/src/String.js +5 -0
- package/dist/src/Task.d.ts +2263 -423
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +1488 -348
- package/dist/src/Test.d.ts +122 -0
- package/dist/src/Test.d.ts.map +1 -0
- package/dist/src/Test.js +66 -0
- package/dist/src/Time.d.ts +201 -48
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +190 -86
- package/dist/src/Tracer.d.ts +48 -0
- package/dist/src/Tracer.d.ts.map +1 -0
- package/dist/src/Tracer.js +6 -0
- package/dist/src/Type.d.ts +582 -209
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +362 -240
- package/dist/src/Types.d.ts +160 -6
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/Types.js +22 -2
- package/dist/src/WebSocket.d.ts +113 -58
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +210 -118
- package/dist/src/Worker.d.ts +245 -60
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +220 -64
- package/dist/src/index.d.ts +25 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +19 -3
- package/dist/src/local-first/Db.d.ts +24 -213
- package/dist/src/local-first/Db.d.ts.map +1 -1
- package/dist/src/local-first/Db.js +622 -293
- package/dist/src/local-first/Error.d.ts +12 -0
- package/dist/src/local-first/Error.d.ts.map +1 -0
- package/dist/src/local-first/Error.js +6 -0
- package/dist/src/local-first/Evolu.d.ts +330 -285
- package/dist/src/local-first/Evolu.d.ts.map +1 -1
- package/dist/src/local-first/Evolu.js +472 -402
- package/dist/src/local-first/LocalAuth.d.ts +10 -10
- package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
- package/dist/src/local-first/LocalAuth.js +6 -1
- package/dist/src/local-first/Owner.d.ts +70 -27
- package/dist/src/local-first/Owner.d.ts.map +1 -1
- package/dist/src/local-first/Owner.js +27 -14
- package/dist/src/local-first/Protocol.d.ts +58 -50
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +253 -155
- package/dist/src/local-first/Query.d.ts +133 -43
- package/dist/src/local-first/Query.d.ts.map +1 -1
- package/dist/src/local-first/Query.js +139 -90
- package/dist/src/local-first/Relay.d.ts +18 -38
- package/dist/src/local-first/Relay.d.ts.map +1 -1
- package/dist/src/local-first/Relay.js +59 -171
- package/dist/src/local-first/Schema.d.ts +139 -144
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Schema.js +78 -163
- package/dist/src/local-first/Shared.d.ts +125 -0
- package/dist/src/local-first/Shared.d.ts.map +1 -0
- package/dist/src/local-first/Shared.js +569 -0
- package/dist/src/local-first/Storage.d.ts +50 -53
- package/dist/src/local-first/Storage.d.ts.map +1 -1
- package/dist/src/local-first/Storage.js +121 -173
- package/dist/src/local-first/Timestamp.d.ts +28 -35
- package/dist/src/local-first/Timestamp.d.ts.map +1 -1
- package/dist/src/local-first/Timestamp.js +24 -25
- package/dist/src/local-first/index.d.ts +2 -15
- package/dist/src/local-first/index.d.ts.map +1 -1
- package/dist/src/local-first/index.js +2 -15
- package/package.json +36 -26
- package/src/Array.ts +467 -106
- package/src/Assert.ts +87 -12
- package/src/BigInt.ts +7 -1
- package/src/Brand.ts +41 -12
- package/src/Buffer.ts +10 -4
- package/src/Cache.ts +11 -2
- package/src/Callbacks.ts +33 -23
- package/src/Console.ts +567 -178
- package/src/Crypto.ts +111 -62
- package/src/Eq.ts +30 -3
- package/src/Error.ts +50 -34
- package/src/Function.ts +140 -68
- package/src/Identicon.ts +7 -1
- package/src/Lookup.ts +415 -0
- package/src/Microtask.ts +58 -0
- package/src/Number.ts +40 -7
- package/src/Object.ts +155 -16
- package/src/Option.ts +74 -0
- package/src/Order.ts +11 -3
- package/src/Platform.ts +43 -7
- package/src/Polyfills.ts +465 -0
- package/src/Random.ts +25 -11
- package/src/Redacted.ts +8 -4
- package/src/Ref.ts +72 -21
- package/src/RefCount.ts +170 -0
- package/src/Relation.ts +188 -136
- package/src/Resource.ts +864 -0
- package/src/Result.ts +548 -381
- package/src/Schedule.ts +1471 -0
- package/src/Set.ts +247 -0
- package/src/Skiplist.ts +7 -1
- package/src/Sqlite.ts +409 -304
- package/src/Store.ts +94 -48
- package/src/String.ts +6 -0
- package/src/Task.ts +3685 -740
- package/src/Test.ts +162 -0
- package/src/Time.ts +348 -145
- package/src/Tracer.ts +54 -0
- package/src/Type.ts +1064 -630
- package/src/Types.ts +202 -7
- package/src/WebSocket.ts +311 -178
- package/src/Worker.ts +527 -147
- package/src/index.ts +74 -3
- package/src/local-first/Db.ts +871 -597
- package/src/local-first/Error.ts +17 -0
- package/src/local-first/Evolu.ts +884 -823
- package/src/local-first/LocalAuth.ts +10 -10
- package/src/local-first/Owner.ts +94 -42
- package/src/local-first/Protocol.ts +440 -303
- package/src/local-first/Query.ts +243 -194
- package/src/local-first/Relay.ts +91 -252
- package/src/local-first/Schema.ts +284 -394
- package/src/local-first/Shared.ts +932 -0
- package/src/local-first/Storage.ts +209 -282
- package/src/local-first/Timestamp.ts +38 -45
- package/src/local-first/index.ts +2 -16
- package/LICENSE +0 -21
- package/dist/src/Instances.d.ts +0 -34
- package/dist/src/Instances.d.ts.map +0 -1
- package/dist/src/Instances.js +0 -44
- package/dist/src/Resources.d.ts +0 -118
- package/dist/src/Resources.d.ts.map +0 -1
- package/dist/src/Resources.js +0 -197
- package/dist/src/local-first/Platform.d.ts +0 -25
- package/dist/src/local-first/Platform.d.ts.map +0 -1
- package/dist/src/local-first/Platform.js +0 -1
- package/dist/src/local-first/Public.d.ts +0 -22
- package/dist/src/local-first/Public.d.ts.map +0 -1
- package/dist/src/local-first/Public.js +0 -15
- package/dist/src/local-first/PublicKysely.d.ts +0 -148
- package/dist/src/local-first/PublicKysely.d.ts.map +0 -1
- package/dist/src/local-first/PublicKysely.js +0 -184
- package/dist/src/local-first/Sync.d.ts +0 -112
- package/dist/src/local-first/Sync.d.ts.map +0 -1
- package/dist/src/local-first/Sync.js +0 -529
- package/src/Instances.ts +0 -90
- package/src/Resources.ts +0 -367
- package/src/local-first/Platform.ts +0 -27
- package/src/local-first/Public.ts +0 -42
- package/src/local-first/PublicKysely.ts +0 -239
- package/src/local-first/Sync.ts +0 -960
package/dist/src/Time.js
CHANGED
|
@@ -1,114 +1,218 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Time representations, durations, and scheduling utilities.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
1
6
|
import { assert } from "./Assert.js";
|
|
2
|
-
import {
|
|
7
|
+
import { brand, lessThan, NonNegativeInt } from "./Type.js";
|
|
3
8
|
/**
|
|
4
|
-
* Creates a {@link Time} using Date.now().
|
|
9
|
+
* Creates a {@link Time} using `Date.now()` and `globalThis.setTimeout`.
|
|
5
10
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* reasonable fallback when the system clock is fundamentally wrong.
|
|
11
|
+
* Throws if the system clock returns an out-of-range value. This is intentional
|
|
12
|
+
* — there's no reasonable fallback for a misconfigured clock.
|
|
9
13
|
*/
|
|
10
14
|
export const createTime = () => {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
assert(DateIso.is(iso), "System clock returned invalid ISO date");
|
|
19
|
-
return iso;
|
|
15
|
+
const getNowMillis = () => Millis.orThrow(globalThis.Date.now());
|
|
16
|
+
return {
|
|
17
|
+
now: () => getNowMillis(),
|
|
18
|
+
nowDateIso: () => millisToDateIso(getNowMillis()),
|
|
19
|
+
setTimeout: (callback, delay) => globalThis.setTimeout(callback, durationToMillis(delay)),
|
|
20
|
+
clearTimeout: (id) => {
|
|
21
|
+
globalThis.clearTimeout(id);
|
|
20
22
|
},
|
|
21
23
|
};
|
|
22
|
-
return time;
|
|
23
24
|
};
|
|
24
25
|
/**
|
|
25
|
-
* Creates a {@link
|
|
26
|
-
*
|
|
26
|
+
* Creates a {@link TestTime} with controllable timers for testing.
|
|
27
|
+
*
|
|
28
|
+
* Time starts at `startAt` (default 0) and only advances when `advance()` is
|
|
29
|
+
* called. Timeouts scheduled via `setTimeout` fire when time is advanced past
|
|
30
|
+
* their deadline.
|
|
31
|
+
*
|
|
32
|
+
* Set `autoIncrement` to automatically increment time by 1ms after each `now()`
|
|
33
|
+
* call via microtask (useful for tests that need monotonically increasing
|
|
34
|
+
* values without explicit `advance()` calls).
|
|
27
35
|
*/
|
|
28
|
-
export const
|
|
29
|
-
let now =
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
export const testCreateTime = (options) => {
|
|
37
|
+
let now = options?.startAt ?? minMillis;
|
|
38
|
+
const autoIncrement = options?.autoIncrement ?? false;
|
|
39
|
+
let nextId = 1;
|
|
40
|
+
const pending = new Map();
|
|
41
|
+
const getNowMillis = () => {
|
|
42
|
+
const result = now;
|
|
43
|
+
if (autoIncrement) {
|
|
33
44
|
queueMicrotask(() => {
|
|
34
|
-
now
|
|
45
|
+
now = Millis.orThrow(now + 1);
|
|
35
46
|
});
|
|
36
|
-
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
now: () => getNowMillis(),
|
|
52
|
+
nowDateIso: () => millisToDateIso(getNowMillis()),
|
|
53
|
+
setTimeout: (callback, delay) => {
|
|
54
|
+
const id = nextId++;
|
|
55
|
+
pending.set(id, { callback, runAt: now + durationToMillis(delay) });
|
|
56
|
+
return id;
|
|
57
|
+
},
|
|
58
|
+
clearTimeout: (id) => {
|
|
59
|
+
pending.delete(id);
|
|
60
|
+
},
|
|
61
|
+
advance: (duration) => {
|
|
62
|
+
now = Millis.orThrow(now + durationToMillis(duration));
|
|
63
|
+
for (const [id, timeout] of pending) {
|
|
64
|
+
if (timeout.runAt <= now) {
|
|
65
|
+
pending.delete(id);
|
|
66
|
+
timeout.callback();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
37
69
|
},
|
|
38
|
-
nowIso: () => DateIso.orThrow(new globalThis.Date(time.now()).toISOString()),
|
|
39
70
|
};
|
|
40
|
-
return time;
|
|
41
71
|
};
|
|
72
|
+
// Literal (not expression like 1 + 2) to preserve type for Brand<"LessThan...">
|
|
73
|
+
const maxMillisWithInfinity = 281474976710655;
|
|
74
|
+
/**
|
|
75
|
+
* Milliseconds timestamp, like `Date.now()`.
|
|
76
|
+
*
|
|
77
|
+
* The maximum value is 281474976710654 (281474976710655 - 1, reserved for
|
|
78
|
+
* infinity). This enables efficient binary serialization, saving 2 bytes
|
|
79
|
+
* compared to typical 8-byte (64-bit) timestamps.
|
|
80
|
+
*
|
|
81
|
+
* `new Date(281474976710654).toString()` = Tue Aug 02 10889 07:31:49
|
|
82
|
+
*
|
|
83
|
+
* If a system clock exceeds this range, operations will throw. This is
|
|
84
|
+
* intentional — there's no reasonable fallback for a misconfigured clock.
|
|
85
|
+
*/
|
|
86
|
+
export const Millis = /*#__PURE__*/ brand("Millis",
|
|
87
|
+
/*#__PURE__*/ lessThan(maxMillisWithInfinity)(NonNegativeInt));
|
|
88
|
+
/** Minimum {@link Millis} value. */
|
|
89
|
+
export const minMillis = 0;
|
|
90
|
+
/** Maximum {@link Millis} value. */
|
|
91
|
+
export const maxMillis = (maxMillisWithInfinity - 1);
|
|
92
|
+
/**
|
|
93
|
+
* Converts {@link Millis} to {@link DateIso}.
|
|
94
|
+
*
|
|
95
|
+
* This is a safe cast because {@link Millis} guarantees a valid timestamp range
|
|
96
|
+
* that always produces a valid ISO string.
|
|
97
|
+
*/
|
|
98
|
+
export const millisToDateIso = (value) => new globalThis.Date(value).toISOString();
|
|
42
99
|
/**
|
|
43
100
|
* Converts a duration to milliseconds.
|
|
44
101
|
*
|
|
45
|
-
* Accepts either a {@link
|
|
46
|
-
*
|
|
102
|
+
* Accepts either a {@link DurationLiteral} (e.g., "5m", "1.5s") or
|
|
103
|
+
* {@link Millis}.
|
|
47
104
|
*
|
|
48
105
|
* ### Example
|
|
49
106
|
*
|
|
50
107
|
* ```ts
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
108
|
+
* durationToMillis("1ms"); // 1
|
|
109
|
+
* durationToMillis("500ms"); // 500
|
|
110
|
+
* durationToMillis("1.5s"); // 1500
|
|
111
|
+
* durationToMillis("30s"); // 30000
|
|
112
|
+
* durationToMillis("5m"); // 300000
|
|
113
|
+
* durationToMillis("12h"); // 43200000
|
|
114
|
+
* durationToMillis("7d"); // 604800000
|
|
115
|
+
* durationToMillis(Millis.orThrow(5000)); // 5000 (already Millis)
|
|
59
116
|
* ```
|
|
60
117
|
*/
|
|
61
|
-
export const
|
|
62
|
-
|
|
63
|
-
if (typeof duration === "number") {
|
|
118
|
+
export const durationToMillis = (duration) => {
|
|
119
|
+
if (typeof duration === "number")
|
|
64
120
|
return duration;
|
|
121
|
+
const num = parseFloat(duration);
|
|
122
|
+
const unit = duration.endsWith("ms") ? "ms" : duration.at(-1);
|
|
123
|
+
assert(unit in durationUnits, `Unknown duration unit: ${unit}`);
|
|
124
|
+
return Millis.orThrow(Math.round(num * durationUnits[unit]));
|
|
125
|
+
};
|
|
126
|
+
/**
|
|
127
|
+
* Returns a Promise that resolves after the specified duration.
|
|
128
|
+
*
|
|
129
|
+
* Uses {@link Duration} parsing and `globalThis.setTimeout`.
|
|
130
|
+
*
|
|
131
|
+
* ### Example
|
|
132
|
+
*
|
|
133
|
+
* ```ts
|
|
134
|
+
* await setTimeout("1ms");
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export const setTimeout = (duration) => new Promise((resolve) => {
|
|
138
|
+
globalThis.setTimeout(resolve, durationToMillis(duration));
|
|
139
|
+
});
|
|
140
|
+
const durationUnits = {
|
|
141
|
+
ms: 1,
|
|
142
|
+
s: 1000,
|
|
143
|
+
m: 60000,
|
|
144
|
+
h: 3600000,
|
|
145
|
+
d: 86400000,
|
|
146
|
+
w: 604800000, // 7 days
|
|
147
|
+
y: 31536000000, // 365 days
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Frame budget at 60fps (16ms).
|
|
151
|
+
*
|
|
152
|
+
* Work exceeding this blocks a frame, causing visible jank in animations.
|
|
153
|
+
*/
|
|
154
|
+
export const ms60fps = 16;
|
|
155
|
+
/**
|
|
156
|
+
* Frame budget at 120fps (8ms).
|
|
157
|
+
*
|
|
158
|
+
* For high refresh rate displays. Work exceeding this blocks a frame.
|
|
159
|
+
*/
|
|
160
|
+
export const ms120fps = 8;
|
|
161
|
+
/**
|
|
162
|
+
* Long task threshold (50ms).
|
|
163
|
+
*
|
|
164
|
+
* Tasks exceeding this are "long tasks" per web standards. Use with
|
|
165
|
+
* {@link yieldNow} to yield periodically and keep UI responsive.
|
|
166
|
+
*
|
|
167
|
+
* @see https://web.dev/articles/optimize-long-tasks
|
|
168
|
+
*/
|
|
169
|
+
export const msLongTask = 50;
|
|
170
|
+
/**
|
|
171
|
+
* Formats {@link Millis} as a human-readable duration string.
|
|
172
|
+
*
|
|
173
|
+
* - Under 1 minute: `1.234s`
|
|
174
|
+
* - Under 1 hour: `1m30.000s`
|
|
175
|
+
* - 1 hour or more: `1h30m45.000s`
|
|
176
|
+
*
|
|
177
|
+
* ### Example
|
|
178
|
+
*
|
|
179
|
+
* ```ts
|
|
180
|
+
* formatMillisAsDuration(1234 as Millis); // "1.234s"
|
|
181
|
+
* formatMillisAsDuration(90000 as Millis); // "1m30.000s"
|
|
182
|
+
* formatMillisAsDuration(3661000 as Millis); // "1h1m1.000s"
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
export const formatMillisAsDuration = (millis) => {
|
|
186
|
+
const elapsed = millis / 1000;
|
|
187
|
+
if (elapsed < 60) {
|
|
188
|
+
return `${elapsed.toFixed(3)}s`;
|
|
65
189
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
s
|
|
70
|
-
m: 60000,
|
|
71
|
-
h: 3600000,
|
|
72
|
-
d: 86400000, // 24 * 60 * 60 * 1000
|
|
73
|
-
};
|
|
74
|
-
let total = 0;
|
|
75
|
-
let i = 0;
|
|
76
|
-
while (i < duration.length) {
|
|
77
|
-
// Skip whitespace
|
|
78
|
-
while (i < duration.length && duration[i] === " ") {
|
|
79
|
-
i++;
|
|
80
|
-
}
|
|
81
|
-
if (i >= duration.length)
|
|
82
|
-
break;
|
|
83
|
-
// Parse number
|
|
84
|
-
let numStr = "";
|
|
85
|
-
while (i < duration.length && duration[i] >= "0" && duration[i] <= "9") {
|
|
86
|
-
numStr += duration[i];
|
|
87
|
-
i++;
|
|
88
|
-
}
|
|
89
|
-
if (numStr === "")
|
|
90
|
-
break;
|
|
91
|
-
// Parse unit (ms or single char s/m/h/d)
|
|
92
|
-
let unit = "";
|
|
93
|
-
if (i < duration.length) {
|
|
94
|
-
if (duration[i] === "m" &&
|
|
95
|
-
i + 1 < duration.length &&
|
|
96
|
-
duration[i + 1] === "s") {
|
|
97
|
-
unit = "ms";
|
|
98
|
-
i += 2;
|
|
99
|
-
}
|
|
100
|
-
else if (duration[i] === "s" ||
|
|
101
|
-
duration[i] === "m" ||
|
|
102
|
-
duration[i] === "h" ||
|
|
103
|
-
duration[i] === "d") {
|
|
104
|
-
unit = duration[i];
|
|
105
|
-
i++;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
if (unit === "")
|
|
109
|
-
break;
|
|
110
|
-
const value = parseInt(numStr, 10);
|
|
111
|
-
total += value * units[unit];
|
|
190
|
+
else if (elapsed < 3600) {
|
|
191
|
+
const minutes = Math.floor(elapsed / 60);
|
|
192
|
+
const seconds = (elapsed % 60).toFixed(3);
|
|
193
|
+
return `${minutes}m${seconds}s`;
|
|
112
194
|
}
|
|
113
|
-
|
|
195
|
+
else {
|
|
196
|
+
const hours = Math.floor(elapsed / 3600);
|
|
197
|
+
const minutes = Math.floor((elapsed % 3600) / 60);
|
|
198
|
+
const seconds = ((elapsed % 3600) % 60).toFixed(3);
|
|
199
|
+
return `${hours}h${minutes}m${seconds}s`;
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Formats {@link Millis} as `HH:MM:SS.mmm`.
|
|
204
|
+
*
|
|
205
|
+
* ### Example
|
|
206
|
+
*
|
|
207
|
+
* ```ts
|
|
208
|
+
* formatMillisAsClockTime(Millis.orThrow(Date.now())); // "14:32:15.234"
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
export const formatMillisAsClockTime = (millis) => {
|
|
212
|
+
const date = new globalThis.Date(millis);
|
|
213
|
+
const hours = date.getHours().toString().padStart(2, "0");
|
|
214
|
+
const minutes = date.getMinutes().toString().padStart(2, "0");
|
|
215
|
+
const seconds = date.getSeconds().toString().padStart(2, "0");
|
|
216
|
+
const ms = date.getMilliseconds().toString().padStart(3, "0");
|
|
217
|
+
return `${hours}:${minutes}:${seconds}.${ms}`;
|
|
114
218
|
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal tracer interface for observability.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
import type { Ref } from "./Ref.js";
|
|
7
|
+
/**
|
|
8
|
+
* Minimal tracer interface for observability.
|
|
9
|
+
*
|
|
10
|
+
* Tracer provides unified observability for both sync and async code. Use it
|
|
11
|
+
* directly for sync operations, or let {@link Run} use it automatically for
|
|
12
|
+
* async tasks.
|
|
13
|
+
*
|
|
14
|
+
* ### Example
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* // Sync code — use tracer directly
|
|
18
|
+
* const result = deps.tracer?.span("parseData", () => parseData(input));
|
|
19
|
+
*
|
|
20
|
+
* // Async code — Run traces automatically
|
|
21
|
+
* await using run = createRun(deps);
|
|
22
|
+
* const result = await run(fetchUser(id)); // Traced if tracer provided
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* TODO: Complete implementation with OpenTelemetry adapter.
|
|
26
|
+
*/
|
|
27
|
+
export interface Tracer {
|
|
28
|
+
/**
|
|
29
|
+
* Wraps a sync function in a traced span.
|
|
30
|
+
*
|
|
31
|
+
* Records start time, end time, and success/failure status.
|
|
32
|
+
*/
|
|
33
|
+
readonly span: <T>(name: string, fn: () => T) => T;
|
|
34
|
+
/** Records an event/fact (e.g., "user.purchased", "sync.completed"). */
|
|
35
|
+
readonly event: (name: string, data?: unknown) => void;
|
|
36
|
+
}
|
|
37
|
+
export interface TracerDep {
|
|
38
|
+
readonly tracer: Tracer;
|
|
39
|
+
}
|
|
40
|
+
/** Configuration for tracing. */
|
|
41
|
+
export interface TracerConfig {
|
|
42
|
+
/** When `true`, enables trace data collection. Can be toggled at runtime. */
|
|
43
|
+
readonly tracing?: Ref<boolean>;
|
|
44
|
+
}
|
|
45
|
+
export interface TracerConfigDep {
|
|
46
|
+
readonly tracerConfig: TracerConfig;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=Tracer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Tracer.d.ts","sourceRoot":"","sources":["../../src/Tracer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAGpC;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,WAAW,MAAM;IACrB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAEnD,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;CACxD;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,iCAAiC;AACjC,MAAM,WAAW,YAAY;IAC3B,6EAA6E;IAC7E,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,YAAY,EAAE,YAAY,CAAC;CACrC"}
|