@evolu/common 5.4.8 → 6.0.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 +30 -34
- package/dist/src/Array.d.ts +17 -0
- package/dist/src/Array.d.ts.map +1 -0
- package/dist/src/Array.js +12 -0
- package/dist/src/Assert.d.ts +68 -0
- package/dist/src/Assert.d.ts.map +1 -0
- package/dist/src/Assert.js +77 -0
- package/dist/src/BigInt.d.ts +20 -0
- package/dist/src/BigInt.d.ts.map +1 -0
- package/dist/src/BigInt.js +18 -0
- package/dist/src/Buffer.d.ts +92 -0
- package/dist/src/Buffer.d.ts.map +1 -0
- package/dist/src/Buffer.js +62 -0
- package/dist/src/Callbacks.d.ts +20 -0
- package/dist/src/Callbacks.d.ts.map +1 -0
- package/dist/src/Callbacks.js +18 -0
- package/dist/src/Console.d.ts +78 -0
- package/dist/src/Console.d.ts.map +1 -0
- package/dist/src/Console.js +103 -0
- package/dist/src/Crypto.d.ts +72 -39
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +89 -54
- package/dist/src/Eq.d.ts +97 -0
- package/dist/src/Eq.d.ts.map +1 -0
- package/dist/src/Eq.js +167 -0
- package/dist/src/Error.d.ts +14 -10
- package/dist/src/Error.d.ts.map +1 -1
- package/dist/src/Error.js +43 -11
- package/dist/src/Evolu/Config.d.ts +69 -0
- package/dist/src/Evolu/Config.d.ts.map +1 -0
- package/dist/src/Evolu/Config.js +9 -0
- package/dist/src/Evolu/Db.d.ts +126 -0
- package/dist/src/Evolu/Db.d.ts.map +1 -0
- package/dist/src/Evolu/Db.js +774 -0
- package/dist/src/Evolu/Diff.d.ts +43 -0
- package/dist/src/Evolu/Diff.d.ts.map +1 -0
- package/dist/src/Evolu/Diff.js +95 -0
- package/dist/src/Evolu/Evolu.d.ts +334 -0
- package/dist/src/Evolu/Evolu.d.ts.map +1 -0
- package/dist/src/Evolu/Evolu.js +434 -0
- package/dist/src/Evolu/Internal.d.ts +26 -0
- package/dist/src/Evolu/Internal.d.ts.map +1 -0
- package/dist/src/Evolu/Internal.js +25 -0
- package/dist/src/Evolu/Kysely.d.ts +6 -0
- package/dist/src/Evolu/Kysely.d.ts.map +1 -0
- package/dist/src/Evolu/Kysely.js +21 -0
- package/dist/src/Evolu/Owner.d.ts +155 -0
- package/dist/src/Evolu/Owner.d.ts.map +1 -0
- package/dist/src/Evolu/Owner.js +126 -0
- package/dist/src/Evolu/Platform.d.ts +23 -0
- package/dist/src/Evolu/Platform.d.ts.map +1 -0
- package/dist/src/Evolu/Platform.js +1 -0
- package/dist/src/Evolu/Protocol.d.ts +401 -0
- package/dist/src/Evolu/Protocol.d.ts.map +1 -0
- package/dist/src/Evolu/Protocol.js +1151 -0
- package/dist/src/Evolu/Public.d.ts +18 -0
- package/dist/src/Evolu/Public.d.ts.map +1 -0
- package/dist/src/Evolu/Public.js +11 -0
- package/dist/src/Evolu/PublicKysely.d.ts +148 -0
- package/dist/src/Evolu/PublicKysely.d.ts.map +1 -0
- package/dist/src/Evolu/PublicKysely.js +185 -0
- package/dist/src/Evolu/Query.d.ts +63 -0
- package/dist/src/Evolu/Query.d.ts.map +1 -0
- package/dist/src/Evolu/Query.js +61 -0
- package/dist/src/Evolu/Relay.d.ts +13 -0
- package/dist/src/Evolu/Relay.d.ts.map +1 -0
- package/dist/src/Evolu/Relay.js +109 -0
- package/dist/src/Evolu/Schema.d.ts +201 -0
- package/dist/src/Evolu/Schema.d.ts.map +1 -0
- package/dist/src/Evolu/Schema.js +150 -0
- package/dist/src/Evolu/Storage.d.ts +49 -0
- package/dist/src/Evolu/Storage.d.ts.map +1 -0
- package/dist/src/Evolu/Storage.js +1111 -0
- package/dist/src/Evolu/Sync.d.ts +59 -0
- package/dist/src/Evolu/Sync.d.ts.map +1 -0
- package/dist/src/Evolu/Sync.js +29 -0
- package/dist/src/Evolu/Timestamp.d.ts +106 -0
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -0
- package/dist/src/Evolu/Timestamp.js +179 -0
- package/dist/src/Function.d.ts +54 -0
- package/dist/src/Function.d.ts.map +1 -0
- package/dist/src/Function.js +38 -0
- package/dist/src/ManyToManyMap.d.ts +26 -0
- package/dist/src/ManyToManyMap.d.ts.map +1 -0
- package/dist/src/ManyToManyMap.js +92 -0
- package/dist/src/NanoId.d.ts +27 -0
- package/dist/src/NanoId.d.ts.map +1 -0
- package/dist/src/NanoId.js +6 -0
- package/dist/src/Number.d.ts +42 -0
- package/dist/src/Number.d.ts.map +1 -0
- package/dist/src/Number.js +55 -0
- package/dist/src/Object.d.ts +35 -0
- package/dist/src/Object.d.ts.map +1 -0
- package/dist/src/Object.js +36 -0
- package/dist/src/Order.d.ts +90 -0
- package/dist/src/Order.d.ts.map +1 -0
- package/dist/src/Order.js +85 -0
- package/dist/src/Promise.d.ts +180 -0
- package/dist/src/Promise.d.ts.map +1 -0
- package/dist/src/Promise.js +176 -0
- package/dist/src/Random.d.ts +52 -0
- package/dist/src/Random.d.ts.map +1 -0
- package/dist/src/Random.js +29 -0
- package/dist/src/Ref.d.ts +40 -0
- package/dist/src/Ref.d.ts.map +1 -0
- package/dist/src/Ref.js +13 -0
- package/dist/src/Result.d.ts +421 -0
- package/dist/src/Result.d.ts.map +1 -0
- package/dist/src/Result.js +357 -0
- package/dist/src/Skiplist.d.ts +23 -0
- package/dist/src/Skiplist.d.ts.map +1 -0
- package/dist/src/Skiplist.js +58 -0
- package/dist/src/Sqlite.d.ts +116 -52
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +183 -67
- package/dist/src/Store.d.ts +45 -8
- package/dist/src/Store.d.ts.map +1 -1
- package/dist/src/Store.js +33 -17
- package/dist/src/String.d.ts +2 -0
- package/dist/src/String.d.ts.map +1 -0
- package/dist/src/String.js +14 -0
- package/dist/src/Time.d.ts +20 -0
- package/dist/src/Time.d.ts.map +1 -0
- package/dist/src/Time.js +25 -0
- package/dist/src/Type.d.ts +1937 -0
- package/dist/src/Type.d.ts.map +1 -0
- package/dist/src/Type.js +2002 -0
- package/dist/src/Types.d.ts +188 -0
- package/dist/src/Types.d.ts.map +1 -0
- package/dist/src/Types.js +6 -0
- package/dist/src/WebSocket.d.ts +112 -0
- package/dist/src/WebSocket.d.ts.map +1 -0
- package/dist/src/WebSocket.js +139 -0
- package/dist/src/Worker.d.ts +44 -0
- package/dist/src/Worker.d.ts.map +1 -0
- package/dist/src/Worker.js +66 -0
- package/dist/src/index.d.ts +24 -11
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +24 -11
- package/package.json +29 -38
- package/src/Array.ts +39 -0
- package/src/Assert.ts +116 -0
- package/src/BigInt.ts +29 -0
- package/src/Buffer.ts +175 -0
- package/src/Callbacks.ts +43 -0
- package/src/Console.ts +159 -0
- package/src/Crypto.ts +169 -115
- package/src/Eq.ts +204 -0
- package/src/Error.ts +57 -20
- package/src/Evolu/Config.ts +83 -0
- package/src/Evolu/Db.ts +1275 -0
- package/src/Evolu/Diff.ts +142 -0
- package/src/Evolu/Evolu.ts +947 -0
- package/src/Evolu/Internal.ts +26 -0
- package/src/Evolu/Kysely.ts +38 -0
- package/src/Evolu/Owner.ts +296 -0
- package/src/Evolu/Platform.ts +27 -0
- package/src/Evolu/Protocol.ts +1857 -0
- package/src/Evolu/Public.ts +43 -0
- package/src/Evolu/PublicKysely.ts +240 -0
- package/src/Evolu/Query.ts +167 -0
- package/src/Evolu/Relay.ts +142 -0
- package/src/Evolu/Schema.ts +417 -0
- package/src/Evolu/Storage.ts +1281 -0
- package/src/Evolu/Sync.ts +105 -0
- package/src/Evolu/Timestamp.ts +311 -0
- package/src/Function.ts +58 -0
- package/src/ManyToManyMap.ts +140 -0
- package/src/NanoId.ts +39 -0
- package/src/Number.ts +90 -0
- package/src/Object.ts +64 -0
- package/src/Order.ts +113 -0
- package/src/Promise.ts +295 -0
- package/src/Random.ts +68 -0
- package/src/Ref.ts +63 -0
- package/src/Result.ts +453 -0
- package/src/Skiplist.ts +102 -0
- package/src/Sqlite.ts +366 -153
- package/src/Store.ts +79 -36
- package/src/String.ts +10 -0
- package/src/Time.ts +36 -0
- package/src/Type.ts +3978 -0
- package/src/Types.ts +209 -0
- package/src/WebSocket.ts +273 -0
- package/src/Worker.ts +129 -0
- package/src/index.ts +24 -11
- package/dist/src/Config.d.ts +0 -56
- package/dist/src/Config.d.ts.map +0 -1
- package/dist/src/Config.js +0 -39
- package/dist/src/Crdt.d.ts +0 -89
- package/dist/src/Crdt.d.ts.map +0 -1
- package/dist/src/Crdt.js +0 -181
- package/dist/src/Db.d.ts +0 -107
- package/dist/src/Db.d.ts.map +0 -1
- package/dist/src/Db.js +0 -443
- package/dist/src/Diff.d.ts +0 -27
- package/dist/src/Diff.d.ts.map +0 -1
- package/dist/src/Diff.js +0 -84
- package/dist/src/Evolu.d.ts +0 -426
- package/dist/src/Evolu.d.ts.map +0 -1
- package/dist/src/Evolu.js +0 -333
- package/dist/src/Model.d.ts +0 -141
- package/dist/src/Model.d.ts.map +0 -1
- package/dist/src/Model.js +0 -125
- package/dist/src/Murmurhash.d.ts +0 -2
- package/dist/src/Murmurhash.d.ts.map +0 -1
- package/dist/src/Murmurhash.js +0 -60
- package/dist/src/Owner.d.ts +0 -33
- package/dist/src/Owner.d.ts.map +0 -1
- package/dist/src/Owner.js +0 -26
- package/dist/src/Platform.d.ts +0 -37
- package/dist/src/Platform.d.ts.map +0 -1
- package/dist/src/Platform.js +0 -11
- package/dist/src/Protobuf.d.ts +0 -81
- package/dist/src/Protobuf.d.ts.map +0 -1
- package/dist/src/Protobuf.js +0 -92
- package/dist/src/Public.d.ts +0 -13
- package/dist/src/Public.d.ts.map +0 -1
- package/dist/src/Public.js +0 -6
- package/dist/src/Socket.d.ts +0 -8
- package/dist/src/Socket.d.ts.map +0 -1
- package/dist/src/Socket.js +0 -51
- package/dist/src/Sql.d.ts +0 -12
- package/dist/src/Sql.d.ts.map +0 -1
- package/dist/src/Sql.js +0 -30
- package/dist/src/Sync.d.ts +0 -70
- package/dist/src/Sync.d.ts.map +0 -1
- package/dist/src/Sync.js +0 -127
- package/src/Config.ts +0 -119
- package/src/Crdt.ts +0 -361
- package/src/Db.ts +0 -955
- package/src/Diff.ts +0 -114
- package/src/Evolu.ts +0 -1016
- package/src/Model.ts +0 -233
- package/src/Murmurhash.ts +0 -70
- package/src/Owner.ts +0 -69
- package/src/Platform.ts +0 -47
- package/src/Protobuf.ts +0 -155
- package/src/Public.ts +0 -12
- package/src/Socket.ts +0 -83
- package/src/Sql.ts +0 -41
- package/src/Sync.ts +0 -315
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@evolu/common",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
|
+
"description": "TypeScript library and local-first framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"evolu",
|
|
7
7
|
"local-first",
|
|
@@ -22,19 +22,17 @@
|
|
|
22
22
|
".": {
|
|
23
23
|
"types": "./dist/src/index.d.ts",
|
|
24
24
|
"import": "./dist/src/index.js",
|
|
25
|
-
"browser": "./dist/src/index.js"
|
|
25
|
+
"browser": "./dist/src/index.js",
|
|
26
|
+
"react-native": "./dist/src/index.js"
|
|
26
27
|
},
|
|
27
|
-
"./
|
|
28
|
-
"import": "./dist/src/
|
|
28
|
+
"./evolu": {
|
|
29
|
+
"import": "./dist/src/Evolu/Internal.js"
|
|
29
30
|
}
|
|
30
31
|
},
|
|
31
|
-
"react-native": {
|
|
32
|
-
"./index.js": "./dist/src/index.js"
|
|
33
|
-
},
|
|
34
32
|
"typesVersions": {
|
|
35
33
|
"*": {
|
|
36
|
-
"
|
|
37
|
-
"./dist/src/
|
|
34
|
+
"evolu": [
|
|
35
|
+
"./dist/src/Evolu/Internal.d.ts"
|
|
38
36
|
]
|
|
39
37
|
}
|
|
40
38
|
},
|
|
@@ -44,45 +42,38 @@
|
|
|
44
42
|
"README.md"
|
|
45
43
|
],
|
|
46
44
|
"dependencies": {
|
|
47
|
-
"@noble/ciphers": "^1.
|
|
48
|
-
"@noble/hashes": "^1.
|
|
49
|
-
"@
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"nanoid": "^
|
|
45
|
+
"@noble/ciphers": "^1.3.0",
|
|
46
|
+
"@noble/hashes": "^1.8.0",
|
|
47
|
+
"@scure/bip39": "^1.6.0",
|
|
48
|
+
"kysely": "^0.28.2",
|
|
49
|
+
"msgpackr": "^1.11.4",
|
|
50
|
+
"nanoid": "^3.3.11",
|
|
51
|
+
"random": "^5.4.0"
|
|
53
52
|
},
|
|
54
53
|
"devDependencies": {
|
|
55
|
-
"@
|
|
56
|
-
"@
|
|
57
|
-
"@
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"@evolu/tsconfig": "0.0.2",
|
|
65
|
-
"eslint-config-evolu": "1.0.0"
|
|
66
|
-
},
|
|
67
|
-
"peerDependencies": {
|
|
68
|
-
"@effect/platform": "0.69.9",
|
|
69
|
-
"@effect/schema": "0.75.5",
|
|
70
|
-
"effect": "3.10.4"
|
|
54
|
+
"@bokuweb/zstd-wasm": "0.0.27",
|
|
55
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
56
|
+
"@types/ws": "^8.18.1",
|
|
57
|
+
"better-sqlite3": "^11.10.0",
|
|
58
|
+
"shx": "^0.3.4",
|
|
59
|
+
"typescript": "^5.8.3",
|
|
60
|
+
"vitest": "^3.2.2",
|
|
61
|
+
"ws": "^8.18.2",
|
|
62
|
+
"@evolu/tsconfig": "0.0.2"
|
|
71
63
|
},
|
|
72
64
|
"publishConfig": {
|
|
73
65
|
"access": "public"
|
|
74
66
|
},
|
|
75
67
|
"engines": {
|
|
76
|
-
"node": ">=
|
|
68
|
+
"node": ">=22.0.0"
|
|
77
69
|
},
|
|
78
70
|
"sideEffects": [],
|
|
79
71
|
"scripts": {
|
|
80
72
|
"dev": "tsc --watch",
|
|
81
|
-
"build": "rm -rf dist ./README.md && tsc && cp ../../README.md ./",
|
|
82
|
-
"
|
|
83
|
-
"
|
|
84
|
-
"clean": "rm -rf .turbo node_modules dist",
|
|
73
|
+
"build": "shx rm -rf dist ./README.md && tsc && shx cp ../../README.md ./",
|
|
74
|
+
"test": "vitest --disableConsoleIntercept",
|
|
75
|
+
"clean": "shx rm -rf .turbo node_modules dist",
|
|
85
76
|
"format": "prettier --write \"src/*.{ts,tsx,md}\"",
|
|
86
|
-
"
|
|
77
|
+
"bench": "vitest bench"
|
|
87
78
|
}
|
|
88
79
|
}
|
package/src/Array.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/** An array with at least one element. */
|
|
2
|
+
export type NonEmptyArray<T> = [T, ...Array<T>];
|
|
3
|
+
|
|
4
|
+
/** Checks if an array is non-empty. */
|
|
5
|
+
export const isNonEmptyArray = <T>(
|
|
6
|
+
array: Array<T>,
|
|
7
|
+
): array is NonEmptyArray<T> => array.length > 0;
|
|
8
|
+
|
|
9
|
+
/** A readonly array with at least one element. */
|
|
10
|
+
export type NonEmptyReadonlyArray<T> = readonly [T, ...ReadonlyArray<T>];
|
|
11
|
+
|
|
12
|
+
/** Checks if an array is non-empty. */
|
|
13
|
+
export const isNonEmptyReadonlyArray = <T>(
|
|
14
|
+
array: ReadonlyArray<T>,
|
|
15
|
+
): array is NonEmptyReadonlyArray<T> => array.length > 0;
|
|
16
|
+
|
|
17
|
+
/** Appends an item to an array returning a non-empty array. */
|
|
18
|
+
export const appendToArray = <T>(
|
|
19
|
+
item: T,
|
|
20
|
+
array: ReadonlyArray<T>,
|
|
21
|
+
): NonEmptyReadonlyArray<T> =>
|
|
22
|
+
[...array, item] as unknown as NonEmptyReadonlyArray<T>;
|
|
23
|
+
|
|
24
|
+
/** Prepends an item to an array returning a non-empty array. */
|
|
25
|
+
export const prependToArray = <T>(
|
|
26
|
+
item: T,
|
|
27
|
+
array: ReadonlyArray<T>,
|
|
28
|
+
): NonEmptyReadonlyArray<T> =>
|
|
29
|
+
[item, ...array] as unknown as NonEmptyReadonlyArray<T>;
|
|
30
|
+
|
|
31
|
+
/** Maps a non-empty array using a mapper function. */
|
|
32
|
+
export const mapNonEmptyArray = <T, U>(
|
|
33
|
+
array: NonEmptyReadonlyArray<T>,
|
|
34
|
+
mapper: (item: T, index: number) => U,
|
|
35
|
+
): NonEmptyReadonlyArray<U> =>
|
|
36
|
+
array.map(mapper) as unknown as NonEmptyReadonlyArray<U>;
|
|
37
|
+
|
|
38
|
+
/** Shifts an item from a non-empty array, guaranteed to return T. */
|
|
39
|
+
export const shiftArray = <T>(array: NonEmptyArray<T>): T => array.shift() as T;
|
package/src/Assert.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 🚨
|
|
3
|
+
*
|
|
4
|
+
* This module provides assertion utilities to prevent invalid states from
|
|
5
|
+
* propagating through the system by halting execution when a condition fails,
|
|
6
|
+
* improving reliability and debuggability.
|
|
7
|
+
*
|
|
8
|
+
* **Warning**: Do not use this instead of {@link Type}. Assertions are intended
|
|
9
|
+
* for conditions that are logically guaranteed but not statically known by
|
|
10
|
+
* TypeScript, or for catching and signaling developer mistakes eagerly (e.g.,
|
|
11
|
+
* invalid configuration).
|
|
12
|
+
*
|
|
13
|
+
* @module
|
|
14
|
+
*/
|
|
15
|
+
import type { Type } from "./Type.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Ensures a condition is true, throwing an error with the provided message if
|
|
19
|
+
* not.
|
|
20
|
+
*
|
|
21
|
+
* Prevents invalid states from propagating through the system by halting
|
|
22
|
+
* execution when a condition fails, improving reliability and debuggability.
|
|
23
|
+
*
|
|
24
|
+
* **Warning**: Do not use this instead of {@link Type}. Assertions are intended
|
|
25
|
+
* for conditions that are logically guaranteed but not statically known by
|
|
26
|
+
* TypeScript, or for catching and signaling developer mistakes eagerly (e.g.,
|
|
27
|
+
* invalid configuration).
|
|
28
|
+
*
|
|
29
|
+
* ### Example
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* assert(true, "true is not true"); // no-op
|
|
33
|
+
* assert(false, "true is not true"); // throws Error
|
|
34
|
+
*
|
|
35
|
+
* const size = fooSize - buffer.getLength();
|
|
36
|
+
* // Ensure required type
|
|
37
|
+
* assert(PositiveInt.is(size), "size is not positive int");
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export const assert: (
|
|
41
|
+
condition: unknown,
|
|
42
|
+
message: string,
|
|
43
|
+
) => asserts condition = (condition, message) => {
|
|
44
|
+
if (!condition) {
|
|
45
|
+
throw new Error(message);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Asserts that an array is non-empty.
|
|
51
|
+
*
|
|
52
|
+
* Ensures the provided array has at least one element, helping TypeScript infer
|
|
53
|
+
* the array as non-empty when this is logically guaranteed but not statically
|
|
54
|
+
* known.
|
|
55
|
+
*
|
|
56
|
+
* ### Example
|
|
57
|
+
*
|
|
58
|
+
* ```ts
|
|
59
|
+
* assertNonEmptyArray([1, 2, 3]); // no-op
|
|
60
|
+
* assertNonEmptyArray([]); // throws Error
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export const assertNonEmptyArray: <T>(
|
|
64
|
+
arr: Array<T>,
|
|
65
|
+
message?: string,
|
|
66
|
+
) => asserts arr is [T, ...Array<T>] = (
|
|
67
|
+
arr,
|
|
68
|
+
message = "Expected a non-empty array.",
|
|
69
|
+
) => {
|
|
70
|
+
assert(arr.length > 0, message);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Asserts that a readonly array is non-empty.
|
|
75
|
+
*
|
|
76
|
+
* Ensures the provided readonly array has at least one element, helping
|
|
77
|
+
* TypeScript infer non-emptiness when this is logically guaranteed but not
|
|
78
|
+
* statically known.
|
|
79
|
+
*
|
|
80
|
+
* ### Example
|
|
81
|
+
*
|
|
82
|
+
* ```ts
|
|
83
|
+
* assertNonEmptyReadonlyArray([1, 2, 3]); // no-op
|
|
84
|
+
* assertNonEmptyReadonlyArray([]); // throws Error
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export const assertNonEmptyReadonlyArray: <T>(
|
|
88
|
+
arr: ReadonlyArray<T>,
|
|
89
|
+
message?: string,
|
|
90
|
+
) => asserts arr is readonly [T, ...Array<T>] = (
|
|
91
|
+
arr,
|
|
92
|
+
message = "Expected a non-empty readonly array.",
|
|
93
|
+
) => {
|
|
94
|
+
assert(arr.length > 0, message);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Asserts no error reaches a `.catch` block, throwing a developer error if it
|
|
99
|
+
* does. Used in Promise chains where errors indicate bugs to be fixed.
|
|
100
|
+
*
|
|
101
|
+
* ### Example
|
|
102
|
+
*
|
|
103
|
+
* ```ts
|
|
104
|
+
* Promise.reject("test").catch((e) =>
|
|
105
|
+
* assertNoErrorInCatch("WebSocket retry", e),
|
|
106
|
+
* );
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
export function assertNoErrorInCatch(context: string, error: unknown): never {
|
|
110
|
+
throw Object.assign(
|
|
111
|
+
new Error(
|
|
112
|
+
`Error in ${context}: an unexpected error reached a catch block and requires a fix`,
|
|
113
|
+
),
|
|
114
|
+
{ cause: error },
|
|
115
|
+
);
|
|
116
|
+
}
|
package/src/BigInt.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Predicate } from "./Types.js";
|
|
2
|
+
|
|
3
|
+
/** Increments a bigint by 1. */
|
|
4
|
+
export const incrementBigInt = (n: bigint): bigint => n + 1n;
|
|
5
|
+
|
|
6
|
+
/** Decrements a bigint by 1. */
|
|
7
|
+
export const decrementBigInt = (n: bigint): bigint => n - 1n;
|
|
8
|
+
|
|
9
|
+
/** Clamps a bigint within a given range. */
|
|
10
|
+
export const clampBigInt =
|
|
11
|
+
(min: bigint, max: bigint) =>
|
|
12
|
+
(n: bigint): bigint =>
|
|
13
|
+
n < min ? min : n > max ? max : n;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Creates a predicate that checks if a BigInt is within a range, inclusive.
|
|
17
|
+
*
|
|
18
|
+
* ### Example
|
|
19
|
+
*
|
|
20
|
+
* ```ts
|
|
21
|
+
* const isBetween10And20 = isBetweenBigInt(10n, 20n);
|
|
22
|
+
* console.log(isBetween10And20(15n)); // true
|
|
23
|
+
* console.log(isBetween10And20(25n)); // false
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export const isBetweenBigInt =
|
|
27
|
+
(min: bigint, max: bigint): Predicate<bigint> =>
|
|
28
|
+
(value) =>
|
|
29
|
+
value >= min && value <= max;
|
package/src/Buffer.ts
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { Result } from "./Result.js";
|
|
2
|
+
import { NonNegativeInt } from "./Type.js";
|
|
3
|
+
export {
|
|
4
|
+
bytesToHex,
|
|
5
|
+
bytesToUtf8,
|
|
6
|
+
concatBytes,
|
|
7
|
+
hexToBytes,
|
|
8
|
+
utf8ToBytes,
|
|
9
|
+
} from "@noble/ciphers/utils";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Custom error for {@link Buffer}-related failures like premature end of data.
|
|
13
|
+
* Provides better stack traces for debugging binary protocol issues.
|
|
14
|
+
*/
|
|
15
|
+
export class BufferError extends Error {
|
|
16
|
+
constructor(message: string) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = this.constructor.name;
|
|
19
|
+
|
|
20
|
+
Error.captureStackTrace(this, this.constructor);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* A Buffer is a dynamic, resizable container for binary data, optimized for
|
|
26
|
+
* scenarios where the final size is unknown. It grows exponentially (doubling
|
|
27
|
+
* its capacity) to minimize memory reallocations and uses `subarray` for
|
|
28
|
+
* efficient, copy-free data access in methods like `unwrap` and `shift`.
|
|
29
|
+
*
|
|
30
|
+
* ### Recommended Usage
|
|
31
|
+
*
|
|
32
|
+
* Create as few Buffers as possible—typically one main Buffer for the final
|
|
33
|
+
* output. Temporary Buffers are allowed when necessary (e.g., for
|
|
34
|
+
* variable-length headers), but avoid excessive allocations. Buffers can be
|
|
35
|
+
* reused within functions by leveraging `reset` to clear contents while
|
|
36
|
+
* preserving capacity, or `truncate` to adjust the length to a specific size,
|
|
37
|
+
* reducing the need for new allocations. Pass Buffers to `encode*` functions to
|
|
38
|
+
* append serialized data and use `decode*` functions to extract data. Both
|
|
39
|
+
* `shift` and `shiftN` throw an {@link BufferError} with message "Buffer parse
|
|
40
|
+
* ended prematurely" on failure, as do higher-level `decode*` functions,
|
|
41
|
+
* providing stack traces for debugging instead of using {@link Result}. This
|
|
42
|
+
* avoids allocation overhead in success cases and leverages exceptions'
|
|
43
|
+
* diagnostic benefits.
|
|
44
|
+
*
|
|
45
|
+
* ### Example
|
|
46
|
+
*
|
|
47
|
+
* ```ts
|
|
48
|
+
* const buffer = createBuffer();
|
|
49
|
+
* encodeNonNegativeInt(buffer, someInt);
|
|
50
|
+
* encodeId(buffer, someId);
|
|
51
|
+
* const result = buffer.unwrap(); // Final serialized data
|
|
52
|
+
*
|
|
53
|
+
* // Decoding example (throws on error)
|
|
54
|
+
* try {
|
|
55
|
+
* const num = decodeNonNegativeInt(buffer);
|
|
56
|
+
* const id = decodeId(buffer);
|
|
57
|
+
* } catch (e) {
|
|
58
|
+
* console.error(e.stack); // Stack trace for debugging
|
|
59
|
+
* }
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* For more on exponential growth, see:
|
|
63
|
+
* https://blog.mozilla.org/nnethercote/2014/11/04/please-grow-your-buffers-exponentially
|
|
64
|
+
*/
|
|
65
|
+
export interface Buffer {
|
|
66
|
+
/** Returns the total allocated size of the buffer. */
|
|
67
|
+
getCapacity: () => NonNegativeInt;
|
|
68
|
+
|
|
69
|
+
/** Returns the current number of bytes stored in the buffer. */
|
|
70
|
+
getLength: () => NonNegativeInt;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Appends binary data to the buffer, resizing if necessary. Throws if
|
|
74
|
+
* `arg.length` is not a non-negative integer.
|
|
75
|
+
*/
|
|
76
|
+
extend: (arg: Uint8Array | ArrayLike<number>) => void;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Removes and returns the first byte. Throws an `Error` with message "Buffer
|
|
80
|
+
* parse ended prematurely" if the buffer is empty.
|
|
81
|
+
*/
|
|
82
|
+
shift: () => NonNegativeInt;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Removes and returns the first `n` bytes. Throws an `Error` with message
|
|
86
|
+
* "Buffer parse ended prematurely" if fewer than `n` bytes remain.
|
|
87
|
+
*/
|
|
88
|
+
shiftN: (n: NonNegativeInt) => Uint8Array;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Truncates the buffer to the specified length, discarding data from the end.
|
|
92
|
+
* Throws if the new length is greater than the current length.
|
|
93
|
+
*/
|
|
94
|
+
truncate: (length: NonNegativeInt) => void;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Resets the buffer to its initial empty state, preserving its capacity.
|
|
98
|
+
*
|
|
99
|
+
* This allows efficient buffer reuse without reallocating memory. Use this
|
|
100
|
+
* when you want to clear the buffer and write new data, avoiding unnecessary
|
|
101
|
+
* allocations.
|
|
102
|
+
*/
|
|
103
|
+
reset: () => void;
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Returns a view of the buffer’s current data. Do not modify this array, as
|
|
107
|
+
* it directly alters the buffer’s internal state, potentially breaking
|
|
108
|
+
* subsequent operations.
|
|
109
|
+
*/
|
|
110
|
+
unwrap: () => Uint8Array;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export const createBuffer = (
|
|
114
|
+
arrayLike?: Uint8Array | ArrayLike<number>,
|
|
115
|
+
): Buffer => {
|
|
116
|
+
let value = arrayLike
|
|
117
|
+
? new globalThis.Uint8Array(arrayLike)
|
|
118
|
+
: new globalThis.Uint8Array(512);
|
|
119
|
+
let length = (arrayLike ? arrayLike.length : 0) as NonNegativeInt;
|
|
120
|
+
|
|
121
|
+
const buffer: Buffer = {
|
|
122
|
+
getCapacity: () => value.length as NonNegativeInt,
|
|
123
|
+
|
|
124
|
+
getLength: () => length,
|
|
125
|
+
|
|
126
|
+
extend: (arg) => {
|
|
127
|
+
const targetSize = length + arg.length;
|
|
128
|
+
if (value.length < targetSize) {
|
|
129
|
+
const oldValue = value;
|
|
130
|
+
const newCapacity = Math.max(value.length * 2, targetSize);
|
|
131
|
+
value = new globalThis.Uint8Array(newCapacity);
|
|
132
|
+
value.set(oldValue);
|
|
133
|
+
}
|
|
134
|
+
value.set(arg, length);
|
|
135
|
+
length = (length + arg.length) as NonNegativeInt;
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
shift: () => {
|
|
139
|
+
if (length === 0) {
|
|
140
|
+
throw new BufferError("Buffer parse ended prematurely");
|
|
141
|
+
}
|
|
142
|
+
const first = value[0];
|
|
143
|
+
value = value.subarray(1);
|
|
144
|
+
length--;
|
|
145
|
+
return first as NonNegativeInt;
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
shiftN: (n) => {
|
|
149
|
+
if (length < n) {
|
|
150
|
+
throw new BufferError("Buffer parse ended prematurely");
|
|
151
|
+
}
|
|
152
|
+
const subarray = value.subarray(0, n);
|
|
153
|
+
value = value.subarray(n);
|
|
154
|
+
length = (length - n) as NonNegativeInt;
|
|
155
|
+
return subarray;
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
truncate: (newLength) => {
|
|
159
|
+
if (newLength > length) {
|
|
160
|
+
throw new BufferError(
|
|
161
|
+
"Cannot truncate to a length greater than current",
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
length = newLength;
|
|
165
|
+
},
|
|
166
|
+
|
|
167
|
+
reset: () => {
|
|
168
|
+
length = 0 as NonNegativeInt;
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
unwrap: () => value.subarray(0, length),
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
return buffer;
|
|
175
|
+
};
|
package/src/Callbacks.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { NanoIdLibDep } from "./NanoId.js";
|
|
2
|
+
import { Brand } from "./Types.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Manages one-time callback functions.
|
|
6
|
+
*
|
|
7
|
+
* Allows registering callbacks with a unique ID and executing them once with an
|
|
8
|
+
* optional argument. Executed callbacks are automatically removed.
|
|
9
|
+
*
|
|
10
|
+
* This is useful for managing event-driven or asynchronous workflows where
|
|
11
|
+
* callbacks need to be invoked only once.
|
|
12
|
+
*/
|
|
13
|
+
export interface Callbacks {
|
|
14
|
+
/** Registers a callback function and returns a unique ID. */
|
|
15
|
+
readonly register: (callback: (arg?: unknown) => void) => CallbackId;
|
|
16
|
+
|
|
17
|
+
/** Executes and removes a callback associated with the given ID. */
|
|
18
|
+
readonly execute: (id: CallbackId, arg?: unknown) => void;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type CallbackId = string & Brand<"CallbackId">;
|
|
22
|
+
|
|
23
|
+
export const createCallbacks = (deps: NanoIdLibDep): Callbacks => {
|
|
24
|
+
const callbackMap = new Map<CallbackId, (arg?: unknown) => void>();
|
|
25
|
+
|
|
26
|
+
const callbacks: Callbacks = {
|
|
27
|
+
register: (callback) => {
|
|
28
|
+
const id = deps.nanoIdLib.nanoid() as CallbackId;
|
|
29
|
+
callbackMap.set(id, callback);
|
|
30
|
+
return id;
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
execute: (id, arg) => {
|
|
34
|
+
const callback = callbackMap.get(id);
|
|
35
|
+
if (callback) {
|
|
36
|
+
callbackMap.delete(id);
|
|
37
|
+
callback(arg);
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return callbacks;
|
|
43
|
+
};
|
package/src/Console.ts
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 📝 Cross-platform console
|
|
3
|
+
*
|
|
4
|
+
* Console abstraction for Chrome 123+, Firefox 125+, Safari 18.1+, Node.js
|
|
5
|
+
* 22.x+, and React Native 0.75+. Includes methods guaranteed to be available in
|
|
6
|
+
* these environments and expected to remain compatible in future versions.
|
|
7
|
+
* Output formatting may vary (e.g., interactive UI in browsers vs. text in
|
|
8
|
+
* Node.js/React Native), but functionality is consistent across platforms.
|
|
9
|
+
*
|
|
10
|
+
* **Convention**: Use a tag (e.g., `[db]`) as the first argument for log
|
|
11
|
+
* filtering.
|
|
12
|
+
*
|
|
13
|
+
* ### Example
|
|
14
|
+
*
|
|
15
|
+
* ```ts
|
|
16
|
+
* deps.console.log("[db]", "send data message", protocolMessage);
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* **Tip**: In browser dev tools, you can filter logs by tag (e.g., `[db]`) to
|
|
20
|
+
* quickly find relevant messages.
|
|
21
|
+
*
|
|
22
|
+
* **Warning**: If you encounter platform-specific issues or missing methods,
|
|
23
|
+
* please contribute a PR with details about the environment and behavior.
|
|
24
|
+
*
|
|
25
|
+
* @module
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Cross-platform Console interface for Chrome 123+, Firefox 125+, Safari 18.1+,
|
|
30
|
+
* Node.js 22.x+, and React Native 0.75+
|
|
31
|
+
*/
|
|
32
|
+
export interface Console {
|
|
33
|
+
/** Controls whether console methods produce output (default: true) */
|
|
34
|
+
enabled?: boolean;
|
|
35
|
+
|
|
36
|
+
/** Outputs a message to the console */
|
|
37
|
+
log: (...args: Array<any>) => void;
|
|
38
|
+
|
|
39
|
+
/** Outputs an informational message (often same as log) */
|
|
40
|
+
info: (...args: Array<any>) => void;
|
|
41
|
+
|
|
42
|
+
/** Outputs a warning message */
|
|
43
|
+
warn: (...args: Array<any>) => void;
|
|
44
|
+
|
|
45
|
+
/** Outputs an error message */
|
|
46
|
+
error: (...args: Array<any>) => void;
|
|
47
|
+
|
|
48
|
+
/** Outputs a debug message */
|
|
49
|
+
debug: (...args: Array<any>) => void;
|
|
50
|
+
|
|
51
|
+
/** Starts a timer with an optional label */
|
|
52
|
+
time: (label?: string) => void;
|
|
53
|
+
|
|
54
|
+
/** Ends a timer and logs the elapsed time */
|
|
55
|
+
timeEnd: (label?: string) => void;
|
|
56
|
+
|
|
57
|
+
/** Displays an object's properties in a detailed format */
|
|
58
|
+
dir: (object: any, options?: any) => void;
|
|
59
|
+
|
|
60
|
+
/** Displays tabular data as a table */
|
|
61
|
+
table: (tabularData: any, properties?: Array<string>) => void;
|
|
62
|
+
|
|
63
|
+
/** Logs the number of times this has been called with the given label */
|
|
64
|
+
count: (label?: string) => void;
|
|
65
|
+
|
|
66
|
+
/** Resets the counter for the given label */
|
|
67
|
+
countReset: (label?: string) => void;
|
|
68
|
+
|
|
69
|
+
/** Writes a message if the value is falsy, otherwise does nothing */
|
|
70
|
+
assert: (value: any, message?: string, ...optionalParams: Array<any>) => void;
|
|
71
|
+
|
|
72
|
+
/** Logs the elapsed time for a timer without ending it */
|
|
73
|
+
timeLog: (label?: string, ...data: Array<any>) => void;
|
|
74
|
+
|
|
75
|
+
/** Prints a stack trace with an optional message */
|
|
76
|
+
trace: (message?: any, ...optionalParams: Array<any>) => void;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Dependency interface for injecting a Console instance. */
|
|
80
|
+
export interface ConsoleDep {
|
|
81
|
+
readonly console: Console;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export interface ConsoleConfig {
|
|
85
|
+
/**
|
|
86
|
+
* Enable or disable console logging (default: false). When true, logs are
|
|
87
|
+
* output to the {@link Console}; when false, logging is disabled for all
|
|
88
|
+
* methods except `error`, which always outputs to ensure critical issues are
|
|
89
|
+
* not missed.
|
|
90
|
+
*/
|
|
91
|
+
readonly enableLogging?: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Creates a console instance using the global console. */
|
|
95
|
+
export const createConsole = (config: ConsoleConfig = {}): Console => {
|
|
96
|
+
const instance: Console = {
|
|
97
|
+
enabled: config.enableLogging ?? false,
|
|
98
|
+
|
|
99
|
+
log: (...args) => {
|
|
100
|
+
// eslint-disable-next-line no-console, @typescript-eslint/no-unsafe-argument
|
|
101
|
+
if (instance.enabled) console.log(...args);
|
|
102
|
+
},
|
|
103
|
+
info: (...args) => {
|
|
104
|
+
// eslint-disable-next-line no-console, @typescript-eslint/no-unsafe-argument
|
|
105
|
+
if (instance.enabled) console.info(...args);
|
|
106
|
+
},
|
|
107
|
+
warn: (...args) => {
|
|
108
|
+
// eslint-disable-next-line no-console, @typescript-eslint/no-unsafe-argument
|
|
109
|
+
if (instance.enabled) console.warn(...args);
|
|
110
|
+
},
|
|
111
|
+
error: (...args) => {
|
|
112
|
+
// Always log errors, even if disabled
|
|
113
|
+
// eslint-disable-next-line no-console, @typescript-eslint/no-unsafe-argument
|
|
114
|
+
console.error(...args);
|
|
115
|
+
},
|
|
116
|
+
debug: (...args) => {
|
|
117
|
+
// eslint-disable-next-line no-console, @typescript-eslint/no-unsafe-argument
|
|
118
|
+
if (instance.enabled) console.debug(...args);
|
|
119
|
+
},
|
|
120
|
+
time: (label) => {
|
|
121
|
+
// eslint-disable-next-line no-console
|
|
122
|
+
if (instance.enabled) console.time(label);
|
|
123
|
+
},
|
|
124
|
+
timeEnd: (label) => {
|
|
125
|
+
// eslint-disable-next-line no-console
|
|
126
|
+
if (instance.enabled) console.timeEnd(label);
|
|
127
|
+
},
|
|
128
|
+
dir: (object, options) => {
|
|
129
|
+
// eslint-disable-next-line no-console
|
|
130
|
+
if (instance.enabled) console.dir(object, options);
|
|
131
|
+
},
|
|
132
|
+
table: (tabularData, properties) => {
|
|
133
|
+
// eslint-disable-next-line no-console
|
|
134
|
+
if (instance.enabled) console.table(tabularData, properties);
|
|
135
|
+
},
|
|
136
|
+
count: (label) => {
|
|
137
|
+
// eslint-disable-next-line no-console
|
|
138
|
+
if (instance.enabled) console.count(label);
|
|
139
|
+
},
|
|
140
|
+
countReset: (label) => {
|
|
141
|
+
// eslint-disable-next-line no-console
|
|
142
|
+
if (instance.enabled) console.countReset(label);
|
|
143
|
+
},
|
|
144
|
+
assert: (value, message, ...optionalParams) => {
|
|
145
|
+
// eslint-disable-next-line no-console, @typescript-eslint/no-unsafe-argument
|
|
146
|
+
if (instance.enabled) console.assert(value, message, ...optionalParams);
|
|
147
|
+
},
|
|
148
|
+
timeLog: (label, ...data) => {
|
|
149
|
+
// eslint-disable-next-line no-console, @typescript-eslint/no-unsafe-argument
|
|
150
|
+
if (instance.enabled) console.timeLog(label, ...data);
|
|
151
|
+
},
|
|
152
|
+
trace: (message, ...optionalParams) => {
|
|
153
|
+
// eslint-disable-next-line no-console, @typescript-eslint/no-unsafe-argument
|
|
154
|
+
if (instance.enabled) console.trace(message, ...optionalParams);
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
return instance;
|
|
159
|
+
};
|