@evolu/common 6.0.1-preview.3 → 6.0.1-preview.31

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.
Files changed (173) hide show
  1. package/dist/src/Array.d.ts +69 -5
  2. package/dist/src/Array.d.ts.map +1 -1
  3. package/dist/src/Array.js +64 -5
  4. package/dist/src/Assert.d.ts +6 -16
  5. package/dist/src/Assert.d.ts.map +1 -1
  6. package/dist/src/Assert.js +6 -18
  7. package/dist/src/Brand.d.ts +75 -0
  8. package/dist/src/Brand.d.ts.map +1 -0
  9. package/dist/src/Brand.js +1 -0
  10. package/dist/src/Buffer.d.ts +1 -1
  11. package/dist/src/Buffer.d.ts.map +1 -1
  12. package/dist/src/Buffer.js +8 -7
  13. package/dist/src/Cache.d.ts +44 -0
  14. package/dist/src/Cache.d.ts.map +1 -0
  15. package/dist/src/Cache.js +52 -0
  16. package/dist/src/Callbacks.d.ts +45 -12
  17. package/dist/src/Callbacks.d.ts.map +1 -1
  18. package/dist/src/Callbacks.js +14 -7
  19. package/dist/src/Console.d.ts +31 -6
  20. package/dist/src/Console.d.ts.map +1 -1
  21. package/dist/src/Console.js +72 -9
  22. package/dist/src/Crypto.d.ts +61 -34
  23. package/dist/src/Crypto.d.ts.map +1 -1
  24. package/dist/src/Crypto.js +32 -45
  25. package/dist/src/Evolu/Db.d.ts +161 -65
  26. package/dist/src/Evolu/Db.d.ts.map +1 -1
  27. package/dist/src/Evolu/Db.js +286 -694
  28. package/dist/src/Evolu/Diff.d.ts +3 -3
  29. package/dist/src/Evolu/Diff.d.ts.map +1 -1
  30. package/dist/src/Evolu/Diff.js +7 -5
  31. package/dist/src/Evolu/Evolu.d.ts +208 -133
  32. package/dist/src/Evolu/Evolu.d.ts.map +1 -1
  33. package/dist/src/Evolu/Evolu.js +188 -183
  34. package/dist/src/Evolu/Internal.d.ts +0 -2
  35. package/dist/src/Evolu/Internal.d.ts.map +1 -1
  36. package/dist/src/Evolu/Internal.js +0 -2
  37. package/dist/src/Evolu/LocalAuth.d.ts +150 -0
  38. package/dist/src/Evolu/LocalAuth.d.ts.map +1 -0
  39. package/dist/src/Evolu/LocalAuth.js +174 -0
  40. package/dist/src/Evolu/Owner.d.ts +273 -120
  41. package/dist/src/Evolu/Owner.d.ts.map +1 -1
  42. package/dist/src/Evolu/Owner.js +130 -104
  43. package/dist/src/Evolu/Platform.d.ts +9 -7
  44. package/dist/src/Evolu/Platform.d.ts.map +1 -1
  45. package/dist/src/Evolu/Protocol.d.ts +277 -232
  46. package/dist/src/Evolu/Protocol.d.ts.map +1 -1
  47. package/dist/src/Evolu/Protocol.js +603 -378
  48. package/dist/src/Evolu/Public.d.ts +6 -8
  49. package/dist/src/Evolu/Public.d.ts.map +1 -1
  50. package/dist/src/Evolu/Public.js +2 -3
  51. package/dist/src/Evolu/PublicKysely.js +3 -3
  52. package/dist/src/Evolu/Query.d.ts +2 -1
  53. package/dist/src/Evolu/Query.d.ts.map +1 -1
  54. package/dist/src/Evolu/Relay.d.ts +92 -7
  55. package/dist/src/Evolu/Relay.d.ts.map +1 -1
  56. package/dist/src/Evolu/Relay.js +238 -76
  57. package/dist/src/Evolu/Schema.d.ts +129 -73
  58. package/dist/src/Evolu/Schema.d.ts.map +1 -1
  59. package/dist/src/Evolu/Schema.js +169 -89
  60. package/dist/src/Evolu/Storage.d.ts +240 -26
  61. package/dist/src/Evolu/Storage.d.ts.map +1 -1
  62. package/dist/src/Evolu/Storage.js +189 -91
  63. package/dist/src/Evolu/Sync.d.ts +67 -13
  64. package/dist/src/Evolu/Sync.d.ts.map +1 -1
  65. package/dist/src/Evolu/Sync.js +441 -20
  66. package/dist/src/Evolu/Timestamp.d.ts +85 -27
  67. package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
  68. package/dist/src/Evolu/Timestamp.js +77 -18
  69. package/dist/src/Identicon.d.ts +35 -0
  70. package/dist/src/Identicon.d.ts.map +1 -0
  71. package/dist/src/Identicon.js +143 -0
  72. package/dist/src/Instances.d.ts +34 -0
  73. package/dist/src/Instances.d.ts.map +1 -0
  74. package/dist/src/Instances.js +44 -0
  75. package/dist/src/ManyToManyMap.d.ts +71 -10
  76. package/dist/src/ManyToManyMap.d.ts.map +1 -1
  77. package/dist/src/ManyToManyMap.js +41 -6
  78. package/dist/src/Number.d.ts +4 -3
  79. package/dist/src/Number.d.ts.map +1 -1
  80. package/dist/src/Number.js +5 -4
  81. package/dist/src/Platform.d.ts +20 -0
  82. package/dist/src/Platform.d.ts.map +1 -0
  83. package/dist/src/Platform.js +22 -0
  84. package/dist/src/Random.d.ts +3 -2
  85. package/dist/src/Random.d.ts.map +1 -1
  86. package/dist/src/Resources.d.ts +118 -0
  87. package/dist/src/Resources.d.ts.map +1 -0
  88. package/dist/src/Resources.js +197 -0
  89. package/dist/src/Result.d.ts +184 -52
  90. package/dist/src/Result.d.ts.map +1 -1
  91. package/dist/src/Result.js +30 -241
  92. package/dist/src/Skiplist.js +2 -1
  93. package/dist/src/Sqlite.d.ts +63 -5
  94. package/dist/src/Sqlite.d.ts.map +1 -1
  95. package/dist/src/Sqlite.js +110 -9
  96. package/dist/src/Task.d.ts +586 -0
  97. package/dist/src/Task.d.ts.map +1 -0
  98. package/dist/src/Task.js +469 -0
  99. package/dist/src/Time.d.ts +66 -1
  100. package/dist/src/Time.d.ts.map +1 -1
  101. package/dist/src/Time.js +99 -5
  102. package/dist/src/Type.d.ts +622 -340
  103. package/dist/src/Type.d.ts.map +1 -1
  104. package/dist/src/Type.js +666 -464
  105. package/dist/src/Types.d.ts +1 -75
  106. package/dist/src/Types.d.ts.map +1 -1
  107. package/dist/src/WebSocket.d.ts +5 -2
  108. package/dist/src/WebSocket.d.ts.map +1 -1
  109. package/dist/src/WebSocket.js +12 -18
  110. package/dist/src/Worker.d.ts +39 -11
  111. package/dist/src/Worker.d.ts.map +1 -1
  112. package/dist/src/Worker.js +22 -4
  113. package/dist/src/index.d.ts +7 -2
  114. package/dist/src/index.d.ts.map +1 -1
  115. package/dist/src/index.js +7 -2
  116. package/package.json +14 -13
  117. package/src/Array.ts +90 -11
  118. package/src/Assert.ts +6 -24
  119. package/src/Brand.ts +75 -0
  120. package/src/Buffer.ts +7 -7
  121. package/src/Cache.ts +85 -0
  122. package/src/Callbacks.ts +62 -22
  123. package/src/Console.ts +91 -11
  124. package/src/Crypto.ts +97 -82
  125. package/src/Evolu/Db.ts +517 -1020
  126. package/src/Evolu/Diff.ts +7 -5
  127. package/src/Evolu/Evolu.ts +464 -355
  128. package/src/Evolu/Internal.ts +0 -2
  129. package/src/Evolu/LocalAuth.ts +463 -0
  130. package/src/Evolu/Owner.ts +355 -228
  131. package/src/Evolu/Platform.ts +9 -9
  132. package/src/Evolu/Protocol.ts +859 -676
  133. package/src/Evolu/Public.ts +7 -14
  134. package/src/Evolu/PublicKysely.ts +3 -3
  135. package/src/Evolu/Query.ts +2 -1
  136. package/src/Evolu/Relay.ts +437 -93
  137. package/src/Evolu/Schema.ts +391 -191
  138. package/src/Evolu/Storage.ts +532 -135
  139. package/src/Evolu/Sync.ts +766 -37
  140. package/src/Evolu/Timestamp.ts +88 -35
  141. package/src/Identicon.ts +197 -0
  142. package/src/Instances.ts +90 -0
  143. package/src/ManyToManyMap.ts +124 -24
  144. package/src/Number.ts +6 -10
  145. package/src/Platform.ts +26 -0
  146. package/src/Random.ts +3 -2
  147. package/src/Resources.ts +367 -0
  148. package/src/Result.ts +191 -54
  149. package/src/Skiplist.ts +1 -1
  150. package/src/Sqlite.ts +122 -17
  151. package/src/Task.ts +901 -0
  152. package/src/Time.ts +180 -5
  153. package/src/Type.ts +1084 -727
  154. package/src/Types.ts +1 -77
  155. package/src/WebSocket.ts +27 -25
  156. package/src/Worker.ts +72 -23
  157. package/src/index.ts +7 -2
  158. package/dist/src/Evolu/Config.d.ts +0 -69
  159. package/dist/src/Evolu/Config.d.ts.map +0 -1
  160. package/dist/src/Evolu/Config.js +0 -9
  161. package/dist/src/Evolu/Kysely.d.ts +0 -6
  162. package/dist/src/Evolu/Kysely.d.ts.map +0 -1
  163. package/dist/src/Evolu/Kysely.js +0 -21
  164. package/dist/src/NanoId.d.ts +0 -27
  165. package/dist/src/NanoId.d.ts.map +0 -1
  166. package/dist/src/NanoId.js +0 -6
  167. package/dist/src/Promise.d.ts +0 -180
  168. package/dist/src/Promise.d.ts.map +0 -1
  169. package/dist/src/Promise.js +0 -176
  170. package/src/Evolu/Config.ts +0 -83
  171. package/src/Evolu/Kysely.ts +0 -38
  172. package/src/NanoId.ts +0 -39
  173. package/src/Promise.ts +0 -295
package/src/Crypto.ts CHANGED
@@ -3,51 +3,65 @@
3
3
  *
4
4
  * @module
5
5
  */
6
-
7
- import { xchacha20poly1305 } from "@noble/ciphers/chacha";
8
- import { hmac } from "@noble/hashes/hmac";
9
- import { sha512 } from "@noble/hashes/sha2";
10
- import { randomBytes } from "@noble/hashes/utils";
11
- import * as bip39 from "@scure/bip39";
12
- import { wordlist } from "@scure/bip39/wordlists/english";
13
- import { urlAlphabet } from "nanoid";
14
- import { getOrThrow, Result, trySync } from "./Result.js";
15
- import {
16
- brand,
17
- Id,
18
- length,
19
- Mnemonic,
20
- NonNegativeInt,
21
- Uint8Array,
22
- } from "./Type.js";
23
- import { Brand } from "./Types.js";
24
-
25
- /** `Uint8Array` created by {@link createRandomBytes}. */
26
- export type RandomBytes = Uint8Array & Brand<"RandomBytes">;
27
-
28
- export type CreateRandomBytes = (bytesLength?: number) => RandomBytes;
29
-
30
- export interface CreateRandomBytesDep {
31
- readonly createRandomBytes: CreateRandomBytes;
6
+ import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
7
+ import { hmac } from "@noble/hashes/hmac.js";
8
+ import { sha512 } from "@noble/hashes/sha2.js";
9
+ import { randomBytes, utf8ToBytes } from "@noble/hashes/utils.js";
10
+ import { Result, trySync } from "./Result.js";
11
+ import { brand, length, NonNegativeInt, Uint8Array } from "./Type.js";
12
+
13
+ export interface RandomBytes {
14
+ /**
15
+ * Creates cryptographically secure random bytes with type-safe length
16
+ * branding.
17
+ *
18
+ * Uses the operating system's cryptographically secure random number
19
+ * generator (crypto.getRandomValues) to generate high-quality entropy
20
+ * suitable for cryptographic operations.
21
+ *
22
+ * ### Type Safety
23
+ *
24
+ * Returns specific branded types for common sizes:
25
+ *
26
+ * - `Random16` for 16-byte values (128 bits)
27
+ * - `Random32` for 32-byte values (256 bits)
28
+ * - `Random64` for 64-byte values (512 bits)
29
+ * - `Random` for any other size
30
+ *
31
+ * ### Example
32
+ *
33
+ * ```ts
34
+ * const nonce = randomBytes.create(16); // Type: Random16
35
+ * const key = randomBytes.create(32); // Type: Random32
36
+ * const seed = randomBytes.create(64); // Type: Random64
37
+ * const custom = randomBytes.create(48); // Type: Random
38
+ * ```
39
+ */
40
+ create(bytesLength: 16): Entropy16;
41
+ create(bytesLength: 32): Entropy32;
42
+ create(bytesLength: 64): Entropy64;
43
+ create(bytesLength: number): Entropy;
32
44
  }
33
45
 
34
- /** Cryptographically secure PRNG. Uses internal OS-level crypto.getRandomValues. */
35
- export const createRandomBytes: CreateRandomBytes = (bytesLength = 32) =>
36
- randomBytes(bytesLength) as RandomBytes;
46
+ export interface RandomBytesDep {
47
+ readonly randomBytes: RandomBytes;
48
+ }
37
49
 
38
- export type CreateMnemonic = () => Mnemonic;
50
+ const Entropy = brand("Entropy", Uint8Array);
51
+ type Entropy = typeof Entropy.Type;
39
52
 
40
- export interface CreateMnemonicDep {
41
- readonly createMnemonic: CreateMnemonic;
42
- }
53
+ export const Entropy16 = length(16)(Entropy);
54
+ export type Entropy16 = typeof Entropy16.Type;
43
55
 
44
- export const createEnglishMnemonic: CreateMnemonic = () =>
45
- bip39.generateMnemonic(wordlist, 128) as Mnemonic;
56
+ export const Entropy32 = length(32)(Entropy);
57
+ export type Entropy32 = typeof Entropy32.Type;
46
58
 
47
- export type MnemonicSeed = Uint8Array & Brand<"MnemonicSeed">;
59
+ export const Entropy64 = length(64)(Entropy);
60
+ export type Entropy64 = typeof Entropy64.Type;
48
61
 
49
- export const mnemonicToMnemonicSeed = (mnemonic: Mnemonic): MnemonicSeed =>
50
- bip39.mnemonicToSeedSync(mnemonic) as MnemonicSeed;
62
+ export const createRandomBytes = (): RandomBytes => ({
63
+ create: randomBytes as RandomBytes["create"],
64
+ });
51
65
 
52
66
  /**
53
67
  * SLIP21.
@@ -55,54 +69,43 @@ export const mnemonicToMnemonicSeed = (mnemonic: Mnemonic): MnemonicSeed =>
55
69
  * https://github.com/satoshilabs/slips/blob/master/slip-0021.md
56
70
  */
57
71
  export const createSlip21 = (
58
- seed: MnemonicSeed,
59
- path: ReadonlyArray<string>,
60
- ): Uint8Array => {
61
- let m = hmac(sha512, "Symmetric key seed", seed);
62
- for (const component of path) {
63
- const p = new TextEncoder().encode(component);
64
- const e = new globalThis.Uint8Array(p.byteLength + 1);
65
- e[0] = 0;
66
- e.set(p, 1);
67
- m = hmac(sha512, m.slice(0, 32), e);
72
+ seed: Entropy16 | Entropy32 | Entropy64,
73
+ path: ReadonlyArray<string | number>,
74
+ ): Entropy32 => {
75
+ let currentNode = hmac(
76
+ sha512,
77
+ utf8ToBytes("Symmetric key seed"),
78
+ seed,
79
+ ) as Entropy64;
80
+
81
+ for (const element of path) {
82
+ const label = typeof element === "number" ? element.toString() : element;
83
+ currentNode = deriveSlip21Node(label, currentNode);
68
84
  }
69
- return m.slice(32, 64);
85
+
86
+ return currentNode.slice(32, 64) as Entropy32;
70
87
  };
71
88
 
72
89
  /**
73
- * Creates a 21-character Base64URL ID (also known as nanoid) from a SLIP-21
74
- * derived key.
90
+ * Derives a single node in the SLIP-21 hierarchical key derivation.
75
91
  *
76
- * Reduces the 256-bit SLIP-21 output to 126 bits (21 chars × 6 bits) for a
77
- * compact, human-readable, and shareable identifier suitable for UI display or
78
- * URL use. While this lowers entropy, 126 bits remains cryptographically secure
79
- * for uniqueness and unpredictability in most applications (comparable to
80
- * UUIDv4's 122 bits).
81
- *
82
- * See https://github.com/satoshilabs/slips/blob/master/slip-0021.md
92
+ * @see {@link createSlip21}
83
93
  */
84
- export const createSlip21Id = (
85
- seed: MnemonicSeed,
86
- path: ReadonlyArray<string>,
87
- ): Id => {
88
- const slip21 = createSlip21(seed, path);
89
- let id = "" as Id;
90
-
91
- // Convert the key to the Id/NanoId/Base64Url format.
92
- for (let i = 0; i < 21; i++) {
93
- id = (id + urlAlphabet[slip21[i] & 63]) as Id;
94
- }
95
-
96
- return id;
94
+ export const deriveSlip21Node = (
95
+ label: string,
96
+ parentNode: Entropy64,
97
+ ): Entropy64 => {
98
+ const labelBytes = utf8ToBytes(label);
99
+ const message = new globalThis.Uint8Array(labelBytes.byteLength + 1);
100
+ message[0] = 0;
101
+ message.set(labelBytes, 1);
102
+ return hmac(sha512, parentNode.slice(0, 32), message) as Entropy64;
97
103
  };
98
104
 
99
105
  /** The encryption key for {@link SymmetricCrypto}. */
100
- export const EncryptionKey = brand("EncryptionKey", length(32)(Uint8Array));
106
+ export const EncryptionKey = brand("EncryptionKey", Entropy32);
101
107
  export type EncryptionKey = typeof EncryptionKey.Type;
102
108
 
103
- export const createEncryptionKey = (seed: MnemonicSeed): EncryptionKey =>
104
- createSlip21(seed, ["Evolu", "Encryption Key"]) as EncryptionKey;
105
-
106
109
  /** Symmetric cryptography. */
107
110
  export interface SymmetricCrypto {
108
111
  readonly nonceLength: NonNegativeInt;
@@ -137,15 +140,15 @@ export interface SymmetricCryptoDecryptError {
137
140
  * https://github.com/paulmillr/noble-ciphers?tab=readme-ov-file#which-cipher-should-i-pick
138
141
  */
139
142
  export const createSymmetricCrypto = (
140
- deps: CreateRandomBytesDep,
143
+ deps: RandomBytesDep,
141
144
  ): SymmetricCrypto => {
142
- const nonceLength = getOrThrow(NonNegativeInt.from(24));
145
+ const nonceLength = NonNegativeInt.orThrow(24);
143
146
 
144
147
  const symmetricCrypto: SymmetricCrypto = {
145
148
  nonceLength,
146
149
 
147
150
  encrypt: (plaintext, encryptionKey) => {
148
- const nonce = deps.createRandomBytes(nonceLength);
151
+ const nonce = deps.randomBytes.create(nonceLength);
149
152
  const ciphertext = xchacha20poly1305(encryptionKey, nonce).encrypt(
150
153
  plaintext,
151
154
  );
@@ -173,19 +176,31 @@ export const createSymmetricCrypto = (
173
176
  * https://bford.info/pub/sec/purb.pdf
174
177
  */
175
178
  export const padmePaddedLength = (length: NonNegativeInt): NonNegativeInt => {
176
- if (length <= 0) return 0 as NonNegativeInt;
179
+ if (length <= 0) return NonNegativeInt.orThrow(0);
177
180
  const e = 31 - Math.clz32(length >>> 0);
178
181
  const s = 32 - Math.clz32(e >>> 0);
179
182
  const z = Math.max(0, e - s);
180
183
  const mask = (1 << z) - 1;
181
- return ((length + mask) & ~mask) as NonNegativeInt;
184
+ return NonNegativeInt.orThrow((length + mask) & ~mask);
182
185
  };
183
186
 
184
187
  /**
185
188
  * Returns the PADMÉ padding length for a given input length. Uses
186
189
  * {@link padmePaddedLength}.
187
190
  */
188
-
189
191
  export const padmePaddingLength = (length: NonNegativeInt): NonNegativeInt => {
190
- return (padmePaddedLength(length) - length) as NonNegativeInt;
192
+ return NonNegativeInt.orThrow(padmePaddedLength(length) - length);
191
193
  };
194
+
195
+ /**
196
+ * Performs a timing-safe comparison of two Uint8Arrays. Returns true if they
197
+ * are equal, false otherwise. Takes constant time regardless of where the
198
+ * arrays differ.
199
+ *
200
+ * @see https://nodejs.org/api/crypto.html#cryptotimingsafeequala-b
201
+ */
202
+ export type TimingSafeEqual = (a: Uint8Array, b: Uint8Array) => boolean;
203
+
204
+ export interface TimingSafeEqualDep {
205
+ readonly timingSafeEqual: TimingSafeEqual;
206
+ }