@evolu/common 6.0.1-preview.28 → 6.0.1-preview.29
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/dist/src/Array.d.ts +58 -5
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +53 -5
- package/dist/src/Evolu/Evolu.d.ts +3 -3
- package/dist/src/Evolu/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu/Evolu.js +3 -3
- package/dist/src/Evolu/Owner.d.ts +48 -19
- package/dist/src/Evolu/Owner.d.ts.map +1 -1
- package/dist/src/Evolu/Owner.js +11 -2
- package/dist/src/Evolu/Protocol.d.ts +31 -31
- package/dist/src/Evolu/Protocol.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.js +51 -28
- package/dist/src/Evolu/Relay.d.ts +40 -25
- package/dist/src/Evolu/Relay.d.ts.map +1 -1
- package/dist/src/Evolu/Relay.js +106 -49
- package/dist/src/Evolu/Storage.d.ts +59 -12
- package/dist/src/Evolu/Storage.d.ts.map +1 -1
- package/dist/src/Evolu/Storage.js +77 -50
- package/dist/src/Evolu/Sync.d.ts.map +1 -1
- package/dist/src/Evolu/Sync.js +14 -5
- package/dist/src/Evolu/Timestamp.d.ts +25 -0
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
- package/dist/src/Evolu/Timestamp.js +25 -0
- package/dist/src/Instances.d.ts +34 -0
- package/dist/src/Instances.d.ts.map +1 -0
- package/dist/src/{Multiton.js → Instances.js} +20 -9
- package/dist/src/Sqlite.d.ts +6 -0
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +6 -0
- package/dist/src/Task.d.ts +75 -0
- package/dist/src/Task.d.ts.map +1 -1
- package/dist/src/Task.js +29 -6
- package/dist/src/Time.d.ts +7 -1
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +13 -2
- package/dist/src/Type.d.ts +56 -9
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +40 -8
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/package.json +1 -1
- package/src/Array.ts +76 -11
- package/src/Evolu/Evolu.ts +4 -5
- package/src/Evolu/Owner.ts +75 -26
- package/src/Evolu/Protocol.ts +90 -61
- package/src/Evolu/Relay.ts +182 -77
- package/src/Evolu/Storage.ts +157 -67
- package/src/Evolu/Sync.ts +18 -6
- package/src/Evolu/Timestamp.ts +25 -0
- package/src/Instances.ts +90 -0
- package/src/Sqlite.ts +6 -0
- package/src/Task.ts +88 -7
- package/src/Time.ts +13 -2
- package/src/Type.ts +56 -9
- package/src/index.ts +1 -1
- package/dist/src/Multiton.d.ts +0 -50
- package/dist/src/Multiton.d.ts.map +0 -1
- package/src/Multiton.ts +0 -98
package/src/Time.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { assert } from "./Assert.js";
|
|
7
8
|
import { DateIso, NonNegativeInt } from "./Type.js";
|
|
8
9
|
|
|
9
10
|
/** Retrieves the current time in milliseconds, similar to `Date.now()`. */
|
|
@@ -16,14 +17,24 @@ export interface TimeDep {
|
|
|
16
17
|
readonly time: Time;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
/**
|
|
20
|
+
/**
|
|
21
|
+
* Creates a {@link Time} using Date.now().
|
|
22
|
+
*
|
|
23
|
+
* If the system clock is misconfigured (out of allowed range), the application
|
|
24
|
+
* will fail with an assertion error. This is intentional - there's no
|
|
25
|
+
* reasonable fallback when the system clock is fundamentally wrong.
|
|
26
|
+
*/
|
|
20
27
|
export const createTime = (): Time => {
|
|
21
28
|
const time: Time = {
|
|
22
29
|
now: () => {
|
|
23
30
|
const iso = time.nowIso();
|
|
24
31
|
return new globalThis.Date(iso).getTime();
|
|
25
32
|
},
|
|
26
|
-
nowIso: () =>
|
|
33
|
+
nowIso: () => {
|
|
34
|
+
const iso = new globalThis.Date().toISOString();
|
|
35
|
+
assert(DateIso.is(iso), "System clock returned invalid ISO date");
|
|
36
|
+
return iso;
|
|
37
|
+
},
|
|
27
38
|
};
|
|
28
39
|
return time;
|
|
29
40
|
};
|
package/src/Type.ts
CHANGED
|
@@ -215,6 +215,9 @@ export interface Type<
|
|
|
215
215
|
/**
|
|
216
216
|
* Creates `T` from an `Input` value, throwing an error if validation fails.
|
|
217
217
|
*
|
|
218
|
+
* Throws an Error with the Type validation error in its `cause` property,
|
|
219
|
+
* making it debuggable while avoiding the need for custom error messages.
|
|
220
|
+
*
|
|
218
221
|
* This is a convenience method that combines `from` with `getOrThrow`.
|
|
219
222
|
*
|
|
220
223
|
* **When to use:**
|
|
@@ -222,7 +225,11 @@ export interface Type<
|
|
|
222
225
|
* - Configuration values that are guaranteed to be valid (e.g., hardcoded
|
|
223
226
|
* constants)
|
|
224
227
|
* - Application startup where failure should crash the program
|
|
225
|
-
* -
|
|
228
|
+
* - As an alternative to assertions when the Type error in the thrown Error's
|
|
229
|
+
* `cause` provides sufficient debugging information
|
|
230
|
+
* - Test code with known valid inputs (when error message clarity is not
|
|
231
|
+
* critical; for better test error messages, use Vitest `schemaMatching` +
|
|
232
|
+
* `assert` with `.is()`)
|
|
226
233
|
*
|
|
227
234
|
* ### Example
|
|
228
235
|
*
|
|
@@ -233,6 +240,14 @@ export interface Type<
|
|
|
233
240
|
* // ✅ Good: App configuration that should crash on invalid values
|
|
234
241
|
* const appName = SimpleName.orThrow("MyApp");
|
|
235
242
|
*
|
|
243
|
+
* // ✅ Good: Instead of assert when Type error is clear enough
|
|
244
|
+
* // Context makes it obvious: count increments from non-negative value
|
|
245
|
+
* const currentCount = counts.get(id) ?? 0;
|
|
246
|
+
* const newCount = PositiveInt.orThrow(currentCount + 1);
|
|
247
|
+
*
|
|
248
|
+
* // ✅ Good: Test setup with known valid values
|
|
249
|
+
* const testUser = User.orThrow({ name: "Alice", age: 30 });
|
|
250
|
+
*
|
|
236
251
|
* // ❌ Avoid: User input (use `from` instead)
|
|
237
252
|
* const userAge = PositiveInt.orThrow(userInput); // Could crash!
|
|
238
253
|
*
|
|
@@ -1822,19 +1837,35 @@ export const formatNonNegativeError =
|
|
|
1822
1837
|
(error) => `The value ${error.value} must be non-negative (≥ 0).`,
|
|
1823
1838
|
);
|
|
1824
1839
|
|
|
1825
|
-
/**
|
|
1840
|
+
/**
|
|
1841
|
+
* Non-negative number (≥ 0).
|
|
1842
|
+
*
|
|
1843
|
+
* @category Number
|
|
1844
|
+
*/
|
|
1826
1845
|
export const NonNegativeNumber = nonNegative(Number);
|
|
1827
1846
|
export type NonNegativeNumber = typeof NonNegativeNumber.Type;
|
|
1828
1847
|
|
|
1829
|
-
/**
|
|
1848
|
+
/**
|
|
1849
|
+
* Positive number (> 0).
|
|
1850
|
+
*
|
|
1851
|
+
* @category Number
|
|
1852
|
+
*/
|
|
1830
1853
|
export const PositiveNumber = positive(NonNegativeNumber);
|
|
1831
1854
|
export type PositiveNumber = typeof PositiveNumber.Type;
|
|
1832
1855
|
|
|
1833
|
-
/**
|
|
1856
|
+
/**
|
|
1857
|
+
* Non-positive number (≤ 0).
|
|
1858
|
+
*
|
|
1859
|
+
* @category Number
|
|
1860
|
+
*/
|
|
1834
1861
|
export const NonPositiveNumber = nonPositive(Number);
|
|
1835
1862
|
export type NonPositiveNumber = typeof NonPositiveNumber.Type;
|
|
1836
1863
|
|
|
1837
|
-
/**
|
|
1864
|
+
/**
|
|
1865
|
+
* Negative number (< 0).
|
|
1866
|
+
*
|
|
1867
|
+
* @category Number
|
|
1868
|
+
*/
|
|
1838
1869
|
export const NegativeNumber = negative(NonPositiveNumber);
|
|
1839
1870
|
export type NegativeNumber = typeof NegativeNumber.Type;
|
|
1840
1871
|
|
|
@@ -1870,11 +1901,19 @@ export const formatIntError = createTypeErrorFormatter<IntError>(
|
|
|
1870
1901
|
export const Int = int(Number);
|
|
1871
1902
|
export type Int = typeof Int.Type;
|
|
1872
1903
|
|
|
1873
|
-
/**
|
|
1904
|
+
/**
|
|
1905
|
+
* Non-negative integer (≥ 0).
|
|
1906
|
+
*
|
|
1907
|
+
* @category Number
|
|
1908
|
+
*/
|
|
1874
1909
|
export const NonNegativeInt = nonNegative(Int);
|
|
1875
1910
|
export type NonNegativeInt = typeof NonNegativeInt.Type;
|
|
1876
1911
|
|
|
1877
|
-
/**
|
|
1912
|
+
/**
|
|
1913
|
+
* Positive integer (> 0).
|
|
1914
|
+
*
|
|
1915
|
+
* @category Number
|
|
1916
|
+
*/
|
|
1878
1917
|
export const PositiveInt = positive(NonNegativeInt);
|
|
1879
1918
|
export type PositiveInt = typeof PositiveInt.Type;
|
|
1880
1919
|
|
|
@@ -1883,11 +1922,19 @@ export const maxPositiveInt = PositiveInt.orThrow(
|
|
|
1883
1922
|
globalThis.Number.MAX_SAFE_INTEGER,
|
|
1884
1923
|
);
|
|
1885
1924
|
|
|
1886
|
-
/**
|
|
1925
|
+
/**
|
|
1926
|
+
* Non-positive integer (≤ 0).
|
|
1927
|
+
*
|
|
1928
|
+
* @category Number
|
|
1929
|
+
*/
|
|
1887
1930
|
export const NonPositiveInt = nonPositive(Int);
|
|
1888
1931
|
export type NonPositiveInt = typeof NonPositiveInt.Type;
|
|
1889
1932
|
|
|
1890
|
-
/**
|
|
1933
|
+
/**
|
|
1934
|
+
* Negative integer (< 0).
|
|
1935
|
+
*
|
|
1936
|
+
* @category Number
|
|
1937
|
+
*/
|
|
1891
1938
|
export const NegativeInt = negative(NonPositiveInt);
|
|
1892
1939
|
export type NegativeInt = typeof NegativeInt.Type;
|
|
1893
1940
|
|
package/src/index.ts
CHANGED
|
@@ -12,8 +12,8 @@ export * from "./Error.js";
|
|
|
12
12
|
export * from "./Evolu/Public.js";
|
|
13
13
|
export * from "./Function.js";
|
|
14
14
|
export * from "./Identicon.js";
|
|
15
|
+
export * from "./Instances.js";
|
|
15
16
|
export * from "./ManyToManyMap.js";
|
|
16
|
-
export * from "./Multiton.js";
|
|
17
17
|
export * from "./Number.js";
|
|
18
18
|
export * from "./Object.js";
|
|
19
19
|
export * from "./Order.js";
|
package/dist/src/Multiton.d.ts
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Manages multiple named instances using the Multiton pattern.
|
|
3
|
-
*
|
|
4
|
-
* Unlike Singleton (one instance globally), Multiton maintains one instance per
|
|
5
|
-
* unique key.
|
|
6
|
-
*
|
|
7
|
-
* **Note:** Multiton is generally considered an anti-pattern because it
|
|
8
|
-
* introduces hidden global state and makes testing harder. Use it only when
|
|
9
|
-
* there's a compelling reason, such as:
|
|
10
|
-
*
|
|
11
|
-
* - Supporting hot reloading while preserving state across module reloads
|
|
12
|
-
* - Enforcing physical constraints (e.g., preventing multiple SQLite connections
|
|
13
|
-
* to the same database, which causes corruption)
|
|
14
|
-
* - Managing resources where instance identity is intrinsic to correctness
|
|
15
|
-
*
|
|
16
|
-
* For most cases, prefer explicit dependency injection and instance management.
|
|
17
|
-
*
|
|
18
|
-
* Compatibility and future work:
|
|
19
|
-
*
|
|
20
|
-
* - We will adopt the ECMAScript `DisposableStack` for structured cleanup and
|
|
21
|
-
* robust error handling as runtimes converge (Node.js ≥ 24, Safari stable).
|
|
22
|
-
* Safari Technology Preview already includes support, so broad availability
|
|
23
|
-
* is expected soon.
|
|
24
|
-
* - Until then, this module uses a simple Map-based approach and calls
|
|
25
|
-
* `instance[Symbol.dispose]()` directly during disposal.
|
|
26
|
-
* - We don't use a polyfill because we avoid global mutation, keep bundles lean,
|
|
27
|
-
* and prefer explicit feature detection.
|
|
28
|
-
* - MDN reference:
|
|
29
|
-
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DisposableStack
|
|
30
|
-
*/
|
|
31
|
-
export interface Multiton<K extends string, T extends Disposable> extends Disposable {
|
|
32
|
-
/**
|
|
33
|
-
* Ensures an instance exists for the given key, creating it if necessary. If
|
|
34
|
-
* the instance already exists, the optional `onCacheHit` callback is invoked
|
|
35
|
-
* to update the existing instance.
|
|
36
|
-
*/
|
|
37
|
-
readonly ensure: (key: K, create: () => T, onCacheHit?: (instance: T) => void) => T;
|
|
38
|
-
/** Gets an instance by key, or returns `null` if it doesn't exist. */
|
|
39
|
-
readonly get: (key: K) => T | null;
|
|
40
|
-
/** Checks if an instance exists for the given key. */
|
|
41
|
-
readonly has: (key: K) => boolean;
|
|
42
|
-
/**
|
|
43
|
-
* Removes and disposes an instance by key. Returns `true` if the instance
|
|
44
|
-
* existed and was disposed, `false` otherwise.
|
|
45
|
-
*/
|
|
46
|
-
readonly disposeInstance: (key: K) => boolean;
|
|
47
|
-
}
|
|
48
|
-
/** Creates a {@link Multiton} instance manager. */
|
|
49
|
-
export declare const createMultiton: <K extends string, T extends Disposable>() => Multiton<K, T>;
|
|
50
|
-
//# sourceMappingURL=Multiton.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Multiton.d.ts","sourceRoot":"","sources":["../../src/Multiton.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,SAAS,MAAM,EAAE,CAAC,SAAS,UAAU,CAC9D,SAAQ,UAAU;IAClB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,CACf,GAAG,EAAE,CAAC,EACN,MAAM,EAAE,MAAM,CAAC,EACf,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,KAAK,IAAI,KAC/B,CAAC,CAAC;IAEP,sEAAsE;IACtE,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC;IAEnC,sDAAsD;IACtD,QAAQ,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;IAElC;;;OAGG;IACH,QAAQ,CAAC,eAAe,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;CAC/C;AAED,mDAAmD;AACnD,eAAO,MAAM,cAAc,GACzB,CAAC,SAAS,MAAM,EAChB,CAAC,SAAS,UAAU,OACjB,QAAQ,CAAC,CAAC,EAAE,CAAC,CAqCjB,CAAC"}
|
package/src/Multiton.ts
DELETED
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Manages multiple named instances using the Multiton pattern.
|
|
3
|
-
*
|
|
4
|
-
* Unlike Singleton (one instance globally), Multiton maintains one instance per
|
|
5
|
-
* unique key.
|
|
6
|
-
*
|
|
7
|
-
* **Note:** Multiton is generally considered an anti-pattern because it
|
|
8
|
-
* introduces hidden global state and makes testing harder. Use it only when
|
|
9
|
-
* there's a compelling reason, such as:
|
|
10
|
-
*
|
|
11
|
-
* - Supporting hot reloading while preserving state across module reloads
|
|
12
|
-
* - Enforcing physical constraints (e.g., preventing multiple SQLite connections
|
|
13
|
-
* to the same database, which causes corruption)
|
|
14
|
-
* - Managing resources where instance identity is intrinsic to correctness
|
|
15
|
-
*
|
|
16
|
-
* For most cases, prefer explicit dependency injection and instance management.
|
|
17
|
-
*
|
|
18
|
-
* Compatibility and future work:
|
|
19
|
-
*
|
|
20
|
-
* - We will adopt the ECMAScript `DisposableStack` for structured cleanup and
|
|
21
|
-
* robust error handling as runtimes converge (Node.js ≥ 24, Safari stable).
|
|
22
|
-
* Safari Technology Preview already includes support, so broad availability
|
|
23
|
-
* is expected soon.
|
|
24
|
-
* - Until then, this module uses a simple Map-based approach and calls
|
|
25
|
-
* `instance[Symbol.dispose]()` directly during disposal.
|
|
26
|
-
* - We don't use a polyfill because we avoid global mutation, keep bundles lean,
|
|
27
|
-
* and prefer explicit feature detection.
|
|
28
|
-
* - MDN reference:
|
|
29
|
-
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DisposableStack
|
|
30
|
-
*/
|
|
31
|
-
export interface Multiton<K extends string, T extends Disposable>
|
|
32
|
-
extends Disposable {
|
|
33
|
-
/**
|
|
34
|
-
* Ensures an instance exists for the given key, creating it if necessary. If
|
|
35
|
-
* the instance already exists, the optional `onCacheHit` callback is invoked
|
|
36
|
-
* to update the existing instance.
|
|
37
|
-
*/
|
|
38
|
-
readonly ensure: (
|
|
39
|
-
key: K,
|
|
40
|
-
create: () => T,
|
|
41
|
-
onCacheHit?: (instance: T) => void,
|
|
42
|
-
) => T;
|
|
43
|
-
|
|
44
|
-
/** Gets an instance by key, or returns `null` if it doesn't exist. */
|
|
45
|
-
readonly get: (key: K) => T | null;
|
|
46
|
-
|
|
47
|
-
/** Checks if an instance exists for the given key. */
|
|
48
|
-
readonly has: (key: K) => boolean;
|
|
49
|
-
|
|
50
|
-
/**
|
|
51
|
-
* Removes and disposes an instance by key. Returns `true` if the instance
|
|
52
|
-
* existed and was disposed, `false` otherwise.
|
|
53
|
-
*/
|
|
54
|
-
readonly disposeInstance: (key: K) => boolean;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
/** Creates a {@link Multiton} instance manager. */
|
|
58
|
-
export const createMultiton = <
|
|
59
|
-
K extends string,
|
|
60
|
-
T extends Disposable,
|
|
61
|
-
>(): Multiton<K, T> => {
|
|
62
|
-
const instances = new Map<K, T>();
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
ensure: (key, create, onCacheHit) => {
|
|
66
|
-
let instance = instances.get(key);
|
|
67
|
-
|
|
68
|
-
if (instance == null) {
|
|
69
|
-
instance = create();
|
|
70
|
-
instances.set(key, instance);
|
|
71
|
-
} else if (onCacheHit) {
|
|
72
|
-
onCacheHit(instance);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return instance;
|
|
76
|
-
},
|
|
77
|
-
|
|
78
|
-
get: (key) => instances.get(key) ?? null,
|
|
79
|
-
|
|
80
|
-
has: (key) => instances.has(key),
|
|
81
|
-
|
|
82
|
-
disposeInstance: (key) => {
|
|
83
|
-
const instance = instances.get(key);
|
|
84
|
-
if (instance) {
|
|
85
|
-
instance[Symbol.dispose]();
|
|
86
|
-
return instances.delete(key);
|
|
87
|
-
}
|
|
88
|
-
return false;
|
|
89
|
-
},
|
|
90
|
-
|
|
91
|
-
[Symbol.dispose]: () => {
|
|
92
|
-
for (const instance of instances.values()) {
|
|
93
|
-
instance[Symbol.dispose]();
|
|
94
|
-
}
|
|
95
|
-
instances.clear();
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
};
|