@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/src/Crypto.ts
CHANGED
|
@@ -1,18 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Cryptographic utilities
|
|
2
|
+
* Cryptographic utilities.
|
|
3
3
|
*
|
|
4
|
-
* Type-safe cryptographic operations including random
|
|
4
|
+
* Type-safe cryptographic operations including random bytes generation, SLIP21
|
|
5
5
|
* key derivation, XChaCha20-Poly1305 symmetric encryption, PADMÉ padding, and
|
|
6
6
|
* timing-safe comparisons.
|
|
7
7
|
*
|
|
8
8
|
* @module
|
|
9
9
|
*/
|
|
10
|
+
|
|
10
11
|
import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
|
|
11
12
|
import { hmac } from "@noble/hashes/hmac.js";
|
|
12
13
|
import { sha512 } from "@noble/hashes/sha2.js";
|
|
13
14
|
import { randomBytes, utf8ToBytes } from "@noble/hashes/utils.js";
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
15
|
+
import { arrayFrom } from "./Array.js";
|
|
16
|
+
import type { RandomLibDep } from "./Random.js";
|
|
17
|
+
import type { Result } from "./Result.js";
|
|
18
|
+
import { trySync } from "./Result.js";
|
|
19
|
+
import {
|
|
20
|
+
brand,
|
|
21
|
+
length,
|
|
22
|
+
NonNegativeInt,
|
|
23
|
+
Uint8Array,
|
|
24
|
+
type Typed,
|
|
25
|
+
zeroNonNegativeInt,
|
|
26
|
+
} from "./Type.js";
|
|
16
27
|
|
|
17
28
|
export interface RandomBytes {
|
|
18
29
|
/**
|
|
@@ -23,11 +34,12 @@ export interface RandomBytes {
|
|
|
23
34
|
* generator (crypto.getRandomValues) to generate high-quality entropy
|
|
24
35
|
* suitable for cryptographic operations.
|
|
25
36
|
*
|
|
26
|
-
*
|
|
37
|
+
* ## Type Safety
|
|
27
38
|
*
|
|
28
39
|
* Returns specific branded types for common sizes:
|
|
29
40
|
*
|
|
30
41
|
* - `Random16` for 16-byte values (128 bits)
|
|
42
|
+
* - `Random24` for 24-byte values (192 bits)
|
|
31
43
|
* - `Random32` for 32-byte values (256 bits)
|
|
32
44
|
* - `Random64` for 64-byte values (512 bits)
|
|
33
45
|
* - `Random` for any other size
|
|
@@ -36,12 +48,14 @@ export interface RandomBytes {
|
|
|
36
48
|
*
|
|
37
49
|
* ```ts
|
|
38
50
|
* const nonce = randomBytes.create(16); // Type: Random16
|
|
51
|
+
* const nonce24 = randomBytes.create(24); // Type: Random24
|
|
39
52
|
* const key = randomBytes.create(32); // Type: Random32
|
|
40
53
|
* const seed = randomBytes.create(64); // Type: Random64
|
|
41
54
|
* const custom = randomBytes.create(48); // Type: Random
|
|
42
55
|
* ```
|
|
43
56
|
*/
|
|
44
57
|
create(bytesLength: 16): Entropy16;
|
|
58
|
+
create(bytesLength: 24): Entropy24;
|
|
45
59
|
create(bytesLength: 32): Entropy32;
|
|
46
60
|
create(bytesLength: 64): Entropy64;
|
|
47
61
|
create(bytesLength: number): Entropy;
|
|
@@ -51,22 +65,34 @@ export interface RandomBytesDep {
|
|
|
51
65
|
readonly randomBytes: RandomBytes;
|
|
52
66
|
}
|
|
53
67
|
|
|
54
|
-
const Entropy = brand("Entropy", Uint8Array);
|
|
68
|
+
const Entropy = /*#__PURE__*/ brand("Entropy", Uint8Array);
|
|
55
69
|
type Entropy = typeof Entropy.Type;
|
|
56
70
|
|
|
57
|
-
export const Entropy16 = length(16)(Entropy);
|
|
71
|
+
export const Entropy16 = /*#__PURE__*/ length(16)(Entropy);
|
|
58
72
|
export type Entropy16 = typeof Entropy16.Type;
|
|
59
73
|
|
|
60
|
-
export const
|
|
74
|
+
export const Entropy24 = /*#__PURE__*/ length(24)(Entropy);
|
|
75
|
+
export type Entropy24 = typeof Entropy24.Type;
|
|
76
|
+
|
|
77
|
+
export const Entropy32 = /*#__PURE__*/ length(32)(Entropy);
|
|
61
78
|
export type Entropy32 = typeof Entropy32.Type;
|
|
62
79
|
|
|
63
|
-
export const Entropy64 = length(64)(Entropy);
|
|
80
|
+
export const Entropy64 = /*#__PURE__*/ length(64)(Entropy);
|
|
64
81
|
export type Entropy64 = typeof Entropy64.Type;
|
|
65
82
|
|
|
66
83
|
export const createRandomBytes = (): RandomBytes => ({
|
|
67
84
|
create: randomBytes as RandomBytes["create"],
|
|
68
85
|
});
|
|
69
86
|
|
|
87
|
+
/** Creates seeded random bytes for deterministic tests. */
|
|
88
|
+
export const testCreateRandomBytes = (deps: RandomLibDep): RandomBytes =>
|
|
89
|
+
({
|
|
90
|
+
create: (bytesLength: number) => {
|
|
91
|
+
const array = arrayFrom(bytesLength, () => deps.randomLib.int(0, 255));
|
|
92
|
+
return new globalThis.Uint8Array(array);
|
|
93
|
+
},
|
|
94
|
+
}) as RandomBytes;
|
|
95
|
+
|
|
70
96
|
/**
|
|
71
97
|
* SLIP21.
|
|
72
98
|
*
|
|
@@ -106,71 +132,94 @@ export const deriveSlip21Node = (
|
|
|
106
132
|
return hmac(sha512, parentNode.slice(0, 32), message) as Entropy64;
|
|
107
133
|
};
|
|
108
134
|
|
|
109
|
-
/** The encryption key for
|
|
110
|
-
export const EncryptionKey = brand("EncryptionKey", Entropy32);
|
|
135
|
+
/** The encryption key for symmetric encryption. */
|
|
136
|
+
export const EncryptionKey = /*#__PURE__*/ brand("EncryptionKey", Entropy32);
|
|
111
137
|
export type EncryptionKey = typeof EncryptionKey.Type;
|
|
112
138
|
|
|
113
|
-
/**
|
|
114
|
-
export
|
|
115
|
-
readonly nonceLength: NonNegativeInt;
|
|
139
|
+
/** The nonce length for XChaCha20-Poly1305 encryption. */
|
|
140
|
+
export const xChaCha20Poly1305NonceLength = 24;
|
|
116
141
|
|
|
117
|
-
|
|
142
|
+
/**
|
|
143
|
+
* Branded Uint8Array for XChaCha20-Poly1305 encryption.
|
|
144
|
+
*
|
|
145
|
+
* @see {@link encryptWithXChaCha20Poly1305}
|
|
146
|
+
*/
|
|
147
|
+
export const XChaCha20Poly1305Ciphertext = /*#__PURE__*/ brand(
|
|
148
|
+
"XChaCha20Poly1305Ciphertext",
|
|
149
|
+
Uint8Array,
|
|
150
|
+
);
|
|
151
|
+
export type XChaCha20Poly1305Ciphertext =
|
|
152
|
+
typeof XChaCha20Poly1305Ciphertext.Type;
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Encrypts plaintext with XChaCha20-Poly1305.
|
|
156
|
+
*
|
|
157
|
+
* Generates a random nonce internally and returns both the ciphertext and
|
|
158
|
+
* nonce. The nonce must be stored alongside the ciphertext for decryption.
|
|
159
|
+
*
|
|
160
|
+
* ### Example
|
|
161
|
+
*
|
|
162
|
+
* ```ts
|
|
163
|
+
* const deps = { randomBytes: createRandomBytes() };
|
|
164
|
+
* const [ciphertext, nonce] = encryptWithXChaCha20Poly1305(deps)(
|
|
165
|
+
* utf8ToBytes("secret message"),
|
|
166
|
+
* encryptionKey,
|
|
167
|
+
* );
|
|
168
|
+
* ```
|
|
169
|
+
*
|
|
170
|
+
* @see https://github.com/paulmillr/noble-ciphers
|
|
171
|
+
*/
|
|
172
|
+
export const encryptWithXChaCha20Poly1305 =
|
|
173
|
+
(deps: RandomBytesDep) =>
|
|
174
|
+
(
|
|
118
175
|
plaintext: Uint8Array,
|
|
119
176
|
encryptionKey: EncryptionKey,
|
|
120
|
-
) => {
|
|
121
|
-
|
|
122
|
-
|
|
177
|
+
): [XChaCha20Poly1305Ciphertext, Entropy24] => {
|
|
178
|
+
const nonce = deps.randomBytes.create(xChaCha20Poly1305NonceLength);
|
|
179
|
+
const ciphertext = XChaCha20Poly1305Ciphertext.orThrow(
|
|
180
|
+
xchacha20poly1305(encryptionKey, nonce).encrypt(plaintext),
|
|
181
|
+
);
|
|
182
|
+
return [ciphertext, nonce];
|
|
123
183
|
};
|
|
124
184
|
|
|
125
|
-
|
|
126
|
-
ciphertext: Uint8Array,
|
|
127
|
-
encryptionKey: EncryptionKey,
|
|
128
|
-
nonce: Uint8Array,
|
|
129
|
-
) => Result<Uint8Array, SymmetricCryptoDecryptError>;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export interface SymmetricCryptoDep {
|
|
133
|
-
readonly symmetricCrypto: SymmetricCrypto;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export interface SymmetricCryptoDecryptError {
|
|
137
|
-
readonly type: "SymmetricCryptoDecryptError";
|
|
185
|
+
export interface DecryptWithXChaCha20Poly1305Error extends Typed<"DecryptWithXChaCha20Poly1305Error"> {
|
|
138
186
|
readonly error: unknown;
|
|
139
187
|
}
|
|
140
188
|
|
|
141
189
|
/**
|
|
142
|
-
* XChaCha20-Poly1305
|
|
190
|
+
* Decrypts ciphertext with XChaCha20-Poly1305.
|
|
191
|
+
*
|
|
192
|
+
* Requires the same nonce that was used during encryption. Returns a
|
|
193
|
+
* {@link Result} that may contain a decryption error if the ciphertext was
|
|
194
|
+
* tampered with or the wrong key/nonce was used.
|
|
143
195
|
*
|
|
144
|
-
*
|
|
196
|
+
* ### Example
|
|
197
|
+
*
|
|
198
|
+
* ```ts
|
|
199
|
+
* const result = decryptWithXChaCha20Poly1305(
|
|
200
|
+
* ciphertext,
|
|
201
|
+
* nonce,
|
|
202
|
+
* encryptionKey,
|
|
203
|
+
* );
|
|
204
|
+
* if (!result.ok) {
|
|
205
|
+
* // Handle decryption error
|
|
206
|
+
* return result;
|
|
207
|
+
* }
|
|
208
|
+
* const plaintext = result.value;
|
|
209
|
+
* ```
|
|
145
210
|
*/
|
|
146
|
-
export const
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
);
|
|
159
|
-
return { nonce, ciphertext };
|
|
160
|
-
},
|
|
161
|
-
|
|
162
|
-
decrypt: (ciphertext, encryptionKey, nonce) =>
|
|
163
|
-
trySync(
|
|
164
|
-
() => xchacha20poly1305(encryptionKey, nonce).decrypt(ciphertext),
|
|
165
|
-
(error): SymmetricCryptoDecryptError => ({
|
|
166
|
-
type: "SymmetricCryptoDecryptError",
|
|
167
|
-
error,
|
|
168
|
-
}),
|
|
169
|
-
),
|
|
170
|
-
};
|
|
171
|
-
|
|
172
|
-
return symmetricCrypto;
|
|
173
|
-
};
|
|
211
|
+
export const decryptWithXChaCha20Poly1305 = (
|
|
212
|
+
ciphertext: XChaCha20Poly1305Ciphertext,
|
|
213
|
+
nonce: Entropy24,
|
|
214
|
+
encryptionKey: EncryptionKey,
|
|
215
|
+
): Result<Uint8Array, DecryptWithXChaCha20Poly1305Error> =>
|
|
216
|
+
trySync(
|
|
217
|
+
() => xchacha20poly1305(encryptionKey, nonce).decrypt(ciphertext),
|
|
218
|
+
(error): DecryptWithXChaCha20Poly1305Error => ({
|
|
219
|
+
type: "DecryptWithXChaCha20Poly1305Error",
|
|
220
|
+
error,
|
|
221
|
+
}),
|
|
222
|
+
);
|
|
174
223
|
|
|
175
224
|
/**
|
|
176
225
|
* Returns the PADMÉ padded length for a given input length.
|
|
@@ -183,7 +232,7 @@ export const createSymmetricCrypto = (
|
|
|
183
232
|
export const createPadmePaddedLength = (
|
|
184
233
|
length: NonNegativeInt,
|
|
185
234
|
): NonNegativeInt => {
|
|
186
|
-
if (length <= 0) return
|
|
235
|
+
if (length <= 0) return zeroNonNegativeInt;
|
|
187
236
|
const e = 31 - Math.clz32(length >>> 0);
|
|
188
237
|
const s = 32 - Math.clz32(e >>> 0);
|
|
189
238
|
const z = Math.max(0, e - s);
|
package/src/Eq.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Equality comparison functions and utilities.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Order } from "./Order.js";
|
|
8
|
+
import type {
|
|
9
|
+
JsonArray,
|
|
10
|
+
JsonObject,
|
|
11
|
+
JsonValue,
|
|
12
|
+
JsonValueInput,
|
|
13
|
+
} from "./Type.js";
|
|
3
14
|
|
|
4
15
|
/**
|
|
5
16
|
* Compares two values of the same type `A` for equality.
|
|
@@ -51,6 +62,22 @@ export const createEqArrayLike =
|
|
|
51
62
|
return true;
|
|
52
63
|
};
|
|
53
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Compares two array-like structures by strict reference equality (`===`).
|
|
67
|
+
*
|
|
68
|
+
* Useful for structural sharing checks where elements are compared by identity.
|
|
69
|
+
*
|
|
70
|
+
* ### Example
|
|
71
|
+
*
|
|
72
|
+
* ```ts
|
|
73
|
+
* const a = { x: 1 };
|
|
74
|
+
* const b = { x: 1 };
|
|
75
|
+
* eqArrayStrict([a, a], [a, a]); // true (same references)
|
|
76
|
+
* eqArrayStrict([a], [b]); // false (different references, even if equal values)
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export const eqArrayStrict = /*#__PURE__*/ createEqArrayLike(eqStrict);
|
|
80
|
+
|
|
54
81
|
/**
|
|
55
82
|
* Compares two array-like structures of numbers for equality.
|
|
56
83
|
*
|
|
@@ -62,7 +89,7 @@ export const createEqArrayLike =
|
|
|
62
89
|
* eqArrayNumber([1, 2, 3], [1, 2, 4]); // false
|
|
63
90
|
* ```
|
|
64
91
|
*/
|
|
65
|
-
export const eqArrayNumber = createEqArrayLike(eqNumber);
|
|
92
|
+
export const eqArrayNumber = /*#__PURE__*/ createEqArrayLike(eqNumber);
|
|
66
93
|
|
|
67
94
|
/**
|
|
68
95
|
* Creates an equivalence function for objects based on an equivalence for their
|
package/src/Error.ts
CHANGED
|
@@ -1,64 +1,80 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* contexts, such as Web Workers and the main thread.
|
|
2
|
+
* Error types and utilities for safe error handling.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Typed } from "./Type.js";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A wrapper for unknown errors caught at runtime.
|
|
11
|
+
*
|
|
12
|
+
* When catching errors from unsafe code (third-party libraries, worker
|
|
13
|
+
* boundaries, etc.), we wrap them in `UnknownError` so they can be used in
|
|
14
|
+
* union types and distinguished from other error types.
|
|
8
15
|
*
|
|
9
|
-
* The `error` property contains
|
|
10
|
-
*
|
|
11
|
-
*
|
|
16
|
+
* The `error` property contains error details (including `message`, `stack`,
|
|
17
|
+
* and `cause` if available), a string, or a fallback value.
|
|
18
|
+
*
|
|
19
|
+
* Use {@link createUnknownError} to create instances.
|
|
12
20
|
*/
|
|
13
|
-
export interface
|
|
14
|
-
readonly type: "TransferableError";
|
|
21
|
+
export interface UnknownError extends Typed<"UnknownError"> {
|
|
15
22
|
readonly error: unknown;
|
|
16
23
|
}
|
|
17
24
|
|
|
18
|
-
/**
|
|
19
|
-
|
|
25
|
+
/**
|
|
26
|
+
* Creates an {@link UnknownError} from an unknown error.
|
|
27
|
+
*
|
|
28
|
+
* Error objects cannot be directly structured-cloned (for worker messaging) or
|
|
29
|
+
* JSON-serialized because their properties (`message`, `stack`, `cause`) are
|
|
30
|
+
* non-enumerable. This function extracts those properties into a plain object.
|
|
31
|
+
*/
|
|
32
|
+
export const createUnknownError = (error: unknown): UnknownError => {
|
|
20
33
|
const convertError = (err: Error): Record<string, unknown> => {
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
const result: Record<string, unknown> = Object.getOwnPropertyNames(
|
|
35
|
+
err,
|
|
36
|
+
).reduce<Record<string, unknown>>((acc, key) => {
|
|
37
|
+
const value = (err as never)[key] as unknown;
|
|
38
|
+
if (key === "cause" && value instanceof Error) {
|
|
39
|
+
// Recursively process the `cause` property
|
|
40
|
+
acc[key] = convertError(value);
|
|
41
|
+
} else if (typeof value !== "function") {
|
|
42
|
+
acc[key] = value;
|
|
43
|
+
}
|
|
44
|
+
return acc;
|
|
45
|
+
}, {});
|
|
46
|
+
// Firefox defines `stack` as a getter on Error.prototype, not as an own
|
|
47
|
+
// property, so getOwnPropertyNames misses it. Explicitly include it.
|
|
48
|
+
if (err.stack !== undefined && !("stack" in result)) {
|
|
49
|
+
result.stack = err.stack;
|
|
50
|
+
}
|
|
51
|
+
return result;
|
|
36
52
|
};
|
|
37
53
|
|
|
38
54
|
if (error instanceof Error) {
|
|
39
55
|
return {
|
|
40
|
-
type: "
|
|
56
|
+
type: "UnknownError",
|
|
41
57
|
error: convertError(error),
|
|
42
58
|
};
|
|
43
59
|
}
|
|
44
60
|
|
|
45
61
|
try {
|
|
46
|
-
// Clone other values that are
|
|
62
|
+
// Clone other values that are structured-clonable
|
|
47
63
|
return {
|
|
48
|
-
type: "
|
|
64
|
+
type: "UnknownError",
|
|
49
65
|
error: structuredClone(error),
|
|
50
66
|
};
|
|
51
67
|
} catch {
|
|
52
|
-
// Fallback for non-
|
|
68
|
+
// Fallback for non-clonable values
|
|
53
69
|
try {
|
|
54
70
|
return {
|
|
55
|
-
type: "
|
|
56
|
-
error: String(error),
|
|
71
|
+
type: "UnknownError",
|
|
72
|
+
error: String(error),
|
|
57
73
|
};
|
|
58
74
|
} catch {
|
|
59
75
|
// Final fallback if even `String(error)` fails
|
|
60
76
|
return {
|
|
61
|
-
type: "
|
|
77
|
+
type: "UnknownError",
|
|
62
78
|
error: "[Unserializable Object]",
|
|
63
79
|
};
|
|
64
80
|
}
|
package/src/Function.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Function utilities including exhaustive checks and composition.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
3
6
|
|
|
4
7
|
/**
|
|
5
8
|
* Helper function to ensure exhaustive matching in a switch statement. Throws
|
|
6
9
|
* an error if an unhandled case is encountered.
|
|
7
10
|
*
|
|
8
|
-
* Remember, it's useful only when we don't return anything from the switch
|
|
9
|
-
* statement. Otherwise, a return type of a function is enough.
|
|
10
|
-
*
|
|
11
11
|
* ### Example
|
|
12
12
|
*
|
|
13
13
|
* ```ts
|
|
14
14
|
* type Color = "red" | "green" | "blue";
|
|
15
15
|
*
|
|
16
|
-
*
|
|
16
|
+
* const handleColor = (color: Color): void => {
|
|
17
17
|
* switch (color) {
|
|
18
18
|
* case "red":
|
|
19
19
|
* console.log("Handling red");
|
|
@@ -27,7 +27,63 @@ import { ReadonlyRecord } from "./Object.js";
|
|
|
27
27
|
* default:
|
|
28
28
|
* exhaustiveCheck(color); // Ensures all cases are handled
|
|
29
29
|
* }
|
|
30
|
-
* }
|
|
30
|
+
* };
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* Use this primarily in side-effect switches (`void` branches). For
|
|
34
|
+
* value-producing switches, TypeScript can enforce exhaustiveness without a
|
|
35
|
+
* `default` branch.
|
|
36
|
+
*
|
|
37
|
+
* ### Example
|
|
38
|
+
*
|
|
39
|
+
* Return from each case for value-producing switches.
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* type Color = "red" | "green" | "blue";
|
|
43
|
+
*
|
|
44
|
+
* const colorToHex = (color: Color): string => {
|
|
45
|
+
* switch (color) {
|
|
46
|
+
* case "red":
|
|
47
|
+
* return "#ff0000";
|
|
48
|
+
* case "green":
|
|
49
|
+
* return "#00ff00";
|
|
50
|
+
* case "blue":
|
|
51
|
+
* return "#0000ff";
|
|
52
|
+
* }
|
|
53
|
+
* };
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* ### Example
|
|
57
|
+
*
|
|
58
|
+
* Use assignment + no `default` to get exhaustiveness by definite assignment.
|
|
59
|
+
*
|
|
60
|
+
* ```ts
|
|
61
|
+
* type Input =
|
|
62
|
+
* | { readonly type: "Mutate" }
|
|
63
|
+
* | { readonly type: "Query" }
|
|
64
|
+
* | { readonly type: "Export" };
|
|
65
|
+
*
|
|
66
|
+
* const onInput = (input: Input): void => {
|
|
67
|
+
* let result: "A" | "B" | "C";
|
|
68
|
+
*
|
|
69
|
+
* switch (input.type) {
|
|
70
|
+
* case "Mutate":
|
|
71
|
+
* result = "A";
|
|
72
|
+
* break;
|
|
73
|
+
* case "Query":
|
|
74
|
+
* result = "B";
|
|
75
|
+
* break;
|
|
76
|
+
* case "Export":
|
|
77
|
+
* result = "C";
|
|
78
|
+
* break;
|
|
79
|
+
* }
|
|
80
|
+
*
|
|
81
|
+
* handleKind(result);
|
|
82
|
+
* };
|
|
83
|
+
*
|
|
84
|
+
* const handleKind = (kind: "A" | "B" | "C"): void => {
|
|
85
|
+
* console.log(kind);
|
|
86
|
+
* };
|
|
31
87
|
* ```
|
|
32
88
|
*/
|
|
33
89
|
export const exhaustiveCheck = (value: never): never => {
|
|
@@ -35,7 +91,7 @@ export const exhaustiveCheck = (value: never): never => {
|
|
|
35
91
|
};
|
|
36
92
|
|
|
37
93
|
/**
|
|
38
|
-
* Returns the
|
|
94
|
+
* Returns the value unchanged.
|
|
39
95
|
*
|
|
40
96
|
* Useful as a default transformation, placeholder callback, or when a function
|
|
41
97
|
* is required but no transformation is needed.
|
|
@@ -53,80 +109,96 @@ export const exhaustiveCheck = (value: never): never => {
|
|
|
53
109
|
export const identity = <A>(a: A): A => a;
|
|
54
110
|
|
|
55
111
|
/**
|
|
56
|
-
*
|
|
112
|
+
* A function that takes no arguments and returns a value of type T. Also known
|
|
113
|
+
* as a thunk.
|
|
57
114
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
* {@link
|
|
115
|
+
* Useful for:
|
|
116
|
+
*
|
|
117
|
+
* - Providing default callbacks (see {@link lazyVoid}, {@link lazyTrue}, etc.)
|
|
118
|
+
* - Delaying expensive operations until actually needed
|
|
119
|
+
* - Deferring side effects so the callee controls when they run
|
|
61
120
|
*
|
|
62
121
|
* ### Example
|
|
63
122
|
*
|
|
64
123
|
* ```ts
|
|
65
|
-
* //
|
|
66
|
-
* const
|
|
67
|
-
*
|
|
68
|
-
*
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* const
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
* //
|
|
75
|
-
* const
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
* // Sets, Records, and Maps
|
|
80
|
-
* const ids = readonly(new Set(["a", "b"]));
|
|
81
|
-
* // Type: ReadonlySet<string>
|
|
82
|
-
*
|
|
83
|
-
* const users: Record<UserId, string> = { ... };
|
|
84
|
-
* const readonlyUsers = readonly(users);
|
|
85
|
-
* // Type: ReadonlyRecord<UserId, string>
|
|
86
|
-
*
|
|
87
|
-
* const lookup = readonly(new Map([["key", "value"]]));
|
|
88
|
-
* // Type: ReadonlyMap<string, string>
|
|
124
|
+
* // Default callback
|
|
125
|
+
* const notify = (onDone: Lazy<void> = lazyVoid) => {
|
|
126
|
+
* onDone();
|
|
127
|
+
* };
|
|
128
|
+
*
|
|
129
|
+
* // Delay computation
|
|
130
|
+
* const getData: Lazy<Data> = () => compute();
|
|
131
|
+
* const data = getData();
|
|
132
|
+
*
|
|
133
|
+
* // Defer side effects
|
|
134
|
+
* const schedule = (job: Lazy<void>) => {
|
|
135
|
+
* queueMicrotask(job);
|
|
136
|
+
* };
|
|
137
|
+
* schedule(() => logMetric("loaded"));
|
|
89
138
|
* ```
|
|
90
|
-
*
|
|
91
|
-
* @experimental
|
|
92
139
|
*/
|
|
93
|
-
export
|
|
94
|
-
export function readonly<T>(array: Array<T>): ReadonlyArray<T>;
|
|
95
|
-
export function readonly<T>(set: Set<T>): ReadonlySet<T>;
|
|
96
|
-
export function readonly<K, V>(map: Map<K, V>): ReadonlyMap<K, V>;
|
|
97
|
-
export function readonly<K extends keyof any, V>(
|
|
98
|
-
record: Record<K, V>,
|
|
99
|
-
): ReadonlyRecord<K, V>;
|
|
100
|
-
export function readonly<T, K extends keyof any, V>(
|
|
101
|
-
value: Array<T> | Set<T> | Map<K, V> | Record<K, V>,
|
|
102
|
-
):
|
|
103
|
-
| ReadonlyArray<T>
|
|
104
|
-
| ReadonlySet<T>
|
|
105
|
-
| ReadonlyMap<K, V>
|
|
106
|
-
| ReadonlyRecord<K, V> {
|
|
107
|
-
return value;
|
|
108
|
-
}
|
|
140
|
+
export type Lazy<T> = () => T;
|
|
109
141
|
|
|
110
142
|
/**
|
|
111
|
-
*
|
|
143
|
+
* Creates a {@link Lazy} from a precomputed value.
|
|
112
144
|
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* - Lazy evaluation
|
|
116
|
-
* - Returning constant values
|
|
117
|
-
* - Providing default or placeholder behaviors
|
|
145
|
+
* Use when the value is expensive to compute and want to compute it once at
|
|
146
|
+
* definition time rather than on every call.
|
|
118
147
|
*
|
|
119
148
|
* ### Example
|
|
120
149
|
*
|
|
121
150
|
* ```ts
|
|
122
|
-
*
|
|
123
|
-
* const
|
|
151
|
+
* // Computed once at definition, returned on every call
|
|
152
|
+
* const getConfig = lazy(parseConfig(rawConfig));
|
|
153
|
+
*
|
|
154
|
+
* // vs. computed on every call
|
|
155
|
+
* const getConfig = () => parseConfig(rawConfig);
|
|
124
156
|
* ```
|
|
125
157
|
*/
|
|
126
|
-
export
|
|
158
|
+
export const lazy =
|
|
159
|
+
<T>(value: T): Lazy<T> =>
|
|
160
|
+
() =>
|
|
161
|
+
value;
|
|
162
|
+
|
|
163
|
+
/** A {@link Lazy} that returns `true`. */
|
|
164
|
+
export const lazyTrue: Lazy<true> = /*#__PURE__*/ lazy(true);
|
|
165
|
+
|
|
166
|
+
/** A {@link Lazy} that returns `false`. */
|
|
167
|
+
export const lazyFalse: Lazy<false> = /*#__PURE__*/ lazy(false);
|
|
168
|
+
|
|
169
|
+
/** A {@link Lazy} that returns `null`. */
|
|
170
|
+
export const lazyNull: Lazy<null> = /*#__PURE__*/ lazy(null);
|
|
171
|
+
|
|
172
|
+
/** A {@link Lazy} that returns `undefined`. */
|
|
173
|
+
export const lazyUndefined: Lazy<undefined> = /*#__PURE__*/ lazy(undefined);
|
|
127
174
|
|
|
128
|
-
|
|
129
|
-
export const
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
175
|
+
/** A {@link Lazy} that returns `undefined` for void callbacks. */
|
|
176
|
+
export const lazyVoid: Lazy<void> = lazyUndefined;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Development placeholder that always throws.
|
|
180
|
+
*
|
|
181
|
+
* Use to sketch function bodies before implementing them. TypeScript infers the
|
|
182
|
+
* return type from context, so surrounding code still type-checks. Use an
|
|
183
|
+
* explicit generic when there is no return type annotation.
|
|
184
|
+
*
|
|
185
|
+
* ### Example
|
|
186
|
+
*
|
|
187
|
+
* ```ts
|
|
188
|
+
* // Type inferred from return type annotation
|
|
189
|
+
* const fetchUser = (id: UserId): Result<User, FetchError> => todo();
|
|
190
|
+
*
|
|
191
|
+
* expectTypeOf(fetchUser).returns.toEqualTypeOf<
|
|
192
|
+
* Result<User, FetchError>
|
|
193
|
+
* >();
|
|
194
|
+
*
|
|
195
|
+
* // Explicit generic when no return type
|
|
196
|
+
* const getConfig = () => todo<Config>();
|
|
197
|
+
*
|
|
198
|
+
* expectTypeOf(getConfig).returns.toEqualTypeOf<Config>();
|
|
199
|
+
* ```
|
|
200
|
+
*/
|
|
201
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters
|
|
202
|
+
export const todo = <T>(): T => {
|
|
203
|
+
throw new Error("not yet implemented");
|
|
204
|
+
};
|