@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.
Files changed (251) hide show
  1. package/README.md +4 -61
  2. package/dist/src/Array.d.ts +343 -102
  3. package/dist/src/Array.d.ts.map +1 -1
  4. package/dist/src/Array.js +181 -85
  5. package/dist/src/Assert.d.ts +57 -11
  6. package/dist/src/Assert.d.ts.map +1 -1
  7. package/dist/src/Assert.js +47 -11
  8. package/dist/src/BigInt.d.ts +6 -1
  9. package/dist/src/BigInt.d.ts.map +1 -1
  10. package/dist/src/BigInt.js +5 -0
  11. package/dist/src/Brand.d.ts +40 -12
  12. package/dist/src/Brand.d.ts.map +1 -1
  13. package/dist/src/Brand.js +5 -0
  14. package/dist/src/Buffer.d.ts +6 -1
  15. package/dist/src/Buffer.d.ts.map +1 -1
  16. package/dist/src/Buffer.js +7 -2
  17. package/dist/src/Cache.d.ts +10 -2
  18. package/dist/src/Cache.d.ts.map +1 -1
  19. package/dist/src/Cache.js +6 -0
  20. package/dist/src/Callbacks.d.ts +10 -7
  21. package/dist/src/Callbacks.d.ts.map +1 -1
  22. package/dist/src/Callbacks.js +23 -13
  23. package/dist/src/Console.d.ts +361 -69
  24. package/dist/src/Console.d.ts.map +1 -1
  25. package/dist/src/Console.js +217 -117
  26. package/dist/src/Crypto.d.ts +70 -21
  27. package/dist/src/Crypto.d.ts.map +1 -1
  28. package/dist/src/Crypto.js +72 -27
  29. package/dist/src/Eq.d.ts +22 -2
  30. package/dist/src/Eq.d.ts.map +1 -1
  31. package/dist/src/Eq.js +21 -1
  32. package/dist/src/Error.d.ts +23 -12
  33. package/dist/src/Error.d.ts.map +1 -1
  34. package/dist/src/Error.js +27 -11
  35. package/dist/src/Function.d.ts +128 -56
  36. package/dist/src/Function.d.ts.map +1 -1
  37. package/dist/src/Function.js +118 -14
  38. package/dist/src/Identicon.d.ts +5 -0
  39. package/dist/src/Identicon.d.ts.map +1 -1
  40. package/dist/src/Identicon.js +6 -1
  41. package/dist/src/Lookup.d.ts +160 -0
  42. package/dist/src/Lookup.d.ts.map +1 -0
  43. package/dist/src/Lookup.js +192 -0
  44. package/dist/src/Microtask.d.ts +21 -0
  45. package/dist/src/Microtask.d.ts.map +1 -0
  46. package/dist/src/Microtask.js +37 -0
  47. package/dist/src/Number.d.ts +18 -4
  48. package/dist/src/Number.d.ts.map +1 -1
  49. package/dist/src/Number.js +23 -1
  50. package/dist/src/Object.d.ts +110 -5
  51. package/dist/src/Object.d.ts.map +1 -1
  52. package/dist/src/Object.js +108 -5
  53. package/dist/src/Option.d.ts +58 -0
  54. package/dist/src/Option.d.ts.map +1 -0
  55. package/dist/src/Option.js +43 -0
  56. package/dist/src/Order.d.ts +5 -0
  57. package/dist/src/Order.d.ts.map +1 -1
  58. package/dist/src/Order.js +8 -3
  59. package/dist/src/Platform.d.ts +36 -2
  60. package/dist/src/Platform.d.ts.map +1 -1
  61. package/dist/src/Platform.js +10 -6
  62. package/dist/src/Polyfills.d.ts +27 -0
  63. package/dist/src/Polyfills.d.ts.map +1 -0
  64. package/dist/src/Polyfills.js +299 -0
  65. package/dist/src/Random.d.ts +18 -7
  66. package/dist/src/Random.d.ts.map +1 -1
  67. package/dist/src/Random.js +9 -7
  68. package/dist/src/Redacted.d.ts +7 -4
  69. package/dist/src/Redacted.d.ts.map +1 -1
  70. package/dist/src/Redacted.js +5 -0
  71. package/dist/src/Ref.d.ts +31 -16
  72. package/dist/src/Ref.d.ts.map +1 -1
  73. package/dist/src/Ref.js +35 -7
  74. package/dist/src/RefCount.d.ts +62 -0
  75. package/dist/src/RefCount.d.ts.map +1 -0
  76. package/dist/src/RefCount.js +83 -0
  77. package/dist/src/Relation.d.ts +84 -29
  78. package/dist/src/Relation.d.ts.map +1 -1
  79. package/dist/src/Relation.js +83 -105
  80. package/dist/src/Resource.d.ts +263 -0
  81. package/dist/src/Resource.d.ts.map +1 -0
  82. package/dist/src/Resource.js +389 -0
  83. package/dist/src/Result.d.ts +390 -374
  84. package/dist/src/Result.d.ts.map +1 -1
  85. package/dist/src/Result.js +142 -70
  86. package/dist/src/Schedule.d.ts +953 -0
  87. package/dist/src/Schedule.d.ts.map +1 -0
  88. package/dist/src/Schedule.js +1199 -0
  89. package/dist/src/Set.d.ts +181 -0
  90. package/dist/src/Set.d.ts.map +1 -0
  91. package/dist/src/Set.js +137 -0
  92. package/dist/src/Skiplist.d.ts +6 -1
  93. package/dist/src/Skiplist.d.ts.map +1 -1
  94. package/dist/src/Skiplist.js +5 -0
  95. package/dist/src/Sqlite.d.ts +160 -60
  96. package/dist/src/Sqlite.d.ts.map +1 -1
  97. package/dist/src/Sqlite.js +290 -190
  98. package/dist/src/Store.d.ts +36 -28
  99. package/dist/src/Store.d.ts.map +1 -1
  100. package/dist/src/Store.js +55 -15
  101. package/dist/src/String.d.ts +5 -0
  102. package/dist/src/String.d.ts.map +1 -1
  103. package/dist/src/String.js +5 -0
  104. package/dist/src/Task.d.ts +2263 -423
  105. package/dist/src/Task.d.ts.map +1 -1
  106. package/dist/src/Task.js +1488 -348
  107. package/dist/src/Test.d.ts +122 -0
  108. package/dist/src/Test.d.ts.map +1 -0
  109. package/dist/src/Test.js +66 -0
  110. package/dist/src/Time.d.ts +201 -48
  111. package/dist/src/Time.d.ts.map +1 -1
  112. package/dist/src/Time.js +190 -86
  113. package/dist/src/Tracer.d.ts +48 -0
  114. package/dist/src/Tracer.d.ts.map +1 -0
  115. package/dist/src/Tracer.js +6 -0
  116. package/dist/src/Type.d.ts +582 -209
  117. package/dist/src/Type.d.ts.map +1 -1
  118. package/dist/src/Type.js +362 -240
  119. package/dist/src/Types.d.ts +160 -6
  120. package/dist/src/Types.d.ts.map +1 -1
  121. package/dist/src/Types.js +22 -2
  122. package/dist/src/WebSocket.d.ts +113 -58
  123. package/dist/src/WebSocket.d.ts.map +1 -1
  124. package/dist/src/WebSocket.js +210 -118
  125. package/dist/src/Worker.d.ts +245 -60
  126. package/dist/src/Worker.d.ts.map +1 -1
  127. package/dist/src/Worker.js +220 -64
  128. package/dist/src/index.d.ts +25 -3
  129. package/dist/src/index.d.ts.map +1 -1
  130. package/dist/src/index.js +19 -3
  131. package/dist/src/local-first/Db.d.ts +24 -213
  132. package/dist/src/local-first/Db.d.ts.map +1 -1
  133. package/dist/src/local-first/Db.js +622 -293
  134. package/dist/src/local-first/Error.d.ts +12 -0
  135. package/dist/src/local-first/Error.d.ts.map +1 -0
  136. package/dist/src/local-first/Error.js +6 -0
  137. package/dist/src/local-first/Evolu.d.ts +330 -285
  138. package/dist/src/local-first/Evolu.d.ts.map +1 -1
  139. package/dist/src/local-first/Evolu.js +472 -402
  140. package/dist/src/local-first/LocalAuth.d.ts +10 -10
  141. package/dist/src/local-first/LocalAuth.d.ts.map +1 -1
  142. package/dist/src/local-first/LocalAuth.js +6 -1
  143. package/dist/src/local-first/Owner.d.ts +70 -27
  144. package/dist/src/local-first/Owner.d.ts.map +1 -1
  145. package/dist/src/local-first/Owner.js +27 -14
  146. package/dist/src/local-first/Protocol.d.ts +58 -50
  147. package/dist/src/local-first/Protocol.d.ts.map +1 -1
  148. package/dist/src/local-first/Protocol.js +253 -155
  149. package/dist/src/local-first/Query.d.ts +133 -43
  150. package/dist/src/local-first/Query.d.ts.map +1 -1
  151. package/dist/src/local-first/Query.js +139 -90
  152. package/dist/src/local-first/Relay.d.ts +18 -38
  153. package/dist/src/local-first/Relay.d.ts.map +1 -1
  154. package/dist/src/local-first/Relay.js +59 -171
  155. package/dist/src/local-first/Schema.d.ts +139 -144
  156. package/dist/src/local-first/Schema.d.ts.map +1 -1
  157. package/dist/src/local-first/Schema.js +78 -163
  158. package/dist/src/local-first/Shared.d.ts +125 -0
  159. package/dist/src/local-first/Shared.d.ts.map +1 -0
  160. package/dist/src/local-first/Shared.js +569 -0
  161. package/dist/src/local-first/Storage.d.ts +50 -53
  162. package/dist/src/local-first/Storage.d.ts.map +1 -1
  163. package/dist/src/local-first/Storage.js +121 -173
  164. package/dist/src/local-first/Timestamp.d.ts +28 -35
  165. package/dist/src/local-first/Timestamp.d.ts.map +1 -1
  166. package/dist/src/local-first/Timestamp.js +24 -25
  167. package/dist/src/local-first/index.d.ts +2 -15
  168. package/dist/src/local-first/index.d.ts.map +1 -1
  169. package/dist/src/local-first/index.js +2 -15
  170. package/package.json +36 -26
  171. package/src/Array.ts +467 -106
  172. package/src/Assert.ts +87 -12
  173. package/src/BigInt.ts +7 -1
  174. package/src/Brand.ts +41 -12
  175. package/src/Buffer.ts +10 -4
  176. package/src/Cache.ts +11 -2
  177. package/src/Callbacks.ts +33 -23
  178. package/src/Console.ts +567 -178
  179. package/src/Crypto.ts +111 -62
  180. package/src/Eq.ts +30 -3
  181. package/src/Error.ts +50 -34
  182. package/src/Function.ts +140 -68
  183. package/src/Identicon.ts +7 -1
  184. package/src/Lookup.ts +415 -0
  185. package/src/Microtask.ts +58 -0
  186. package/src/Number.ts +40 -7
  187. package/src/Object.ts +155 -16
  188. package/src/Option.ts +74 -0
  189. package/src/Order.ts +11 -3
  190. package/src/Platform.ts +43 -7
  191. package/src/Polyfills.ts +465 -0
  192. package/src/Random.ts +25 -11
  193. package/src/Redacted.ts +8 -4
  194. package/src/Ref.ts +72 -21
  195. package/src/RefCount.ts +170 -0
  196. package/src/Relation.ts +188 -136
  197. package/src/Resource.ts +864 -0
  198. package/src/Result.ts +548 -381
  199. package/src/Schedule.ts +1471 -0
  200. package/src/Set.ts +247 -0
  201. package/src/Skiplist.ts +7 -1
  202. package/src/Sqlite.ts +409 -304
  203. package/src/Store.ts +94 -48
  204. package/src/String.ts +6 -0
  205. package/src/Task.ts +3685 -740
  206. package/src/Test.ts +162 -0
  207. package/src/Time.ts +348 -145
  208. package/src/Tracer.ts +54 -0
  209. package/src/Type.ts +1064 -630
  210. package/src/Types.ts +202 -7
  211. package/src/WebSocket.ts +311 -178
  212. package/src/Worker.ts +527 -147
  213. package/src/index.ts +74 -3
  214. package/src/local-first/Db.ts +871 -597
  215. package/src/local-first/Error.ts +17 -0
  216. package/src/local-first/Evolu.ts +884 -823
  217. package/src/local-first/LocalAuth.ts +10 -10
  218. package/src/local-first/Owner.ts +94 -42
  219. package/src/local-first/Protocol.ts +440 -303
  220. package/src/local-first/Query.ts +243 -194
  221. package/src/local-first/Relay.ts +91 -252
  222. package/src/local-first/Schema.ts +284 -394
  223. package/src/local-first/Shared.ts +932 -0
  224. package/src/local-first/Storage.ts +209 -282
  225. package/src/local-first/Timestamp.ts +38 -45
  226. package/src/local-first/index.ts +2 -16
  227. package/LICENSE +0 -21
  228. package/dist/src/Instances.d.ts +0 -34
  229. package/dist/src/Instances.d.ts.map +0 -1
  230. package/dist/src/Instances.js +0 -44
  231. package/dist/src/Resources.d.ts +0 -118
  232. package/dist/src/Resources.d.ts.map +0 -1
  233. package/dist/src/Resources.js +0 -197
  234. package/dist/src/local-first/Platform.d.ts +0 -25
  235. package/dist/src/local-first/Platform.d.ts.map +0 -1
  236. package/dist/src/local-first/Platform.js +0 -1
  237. package/dist/src/local-first/Public.d.ts +0 -22
  238. package/dist/src/local-first/Public.d.ts.map +0 -1
  239. package/dist/src/local-first/Public.js +0 -15
  240. package/dist/src/local-first/PublicKysely.d.ts +0 -148
  241. package/dist/src/local-first/PublicKysely.d.ts.map +0 -1
  242. package/dist/src/local-first/PublicKysely.js +0 -184
  243. package/dist/src/local-first/Sync.d.ts +0 -112
  244. package/dist/src/local-first/Sync.d.ts.map +0 -1
  245. package/dist/src/local-first/Sync.js +0 -529
  246. package/src/Instances.ts +0 -90
  247. package/src/Resources.ts +0 -367
  248. package/src/local-first/Platform.ts +0 -27
  249. package/src/local-first/Public.ts +0 -42
  250. package/src/local-first/PublicKysely.ts +0 -239
  251. package/src/local-first/Sync.ts +0 -960
package/src/Object.ts CHANGED
@@ -1,28 +1,77 @@
1
+ /**
2
+ * Object utilities.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ /**
8
+ * A read-only `Record<K, V>` with `K extends keyof any` to preserve branded key
9
+ * types (e.g., in {@link mapObject}).
10
+ */
11
+ export type ReadonlyRecord<K extends keyof any, V> = Readonly<Record<K, V>>;
12
+
1
13
  /**
2
14
  * Checks if a value is a plain object (e.g., created with `{}` or `Object`).
3
15
  *
16
+ * Accepts objects with `Object.prototype` and objects with a `null` prototype
17
+ * created via `Object.create(null)`. Rejects class instances and other built-in
18
+ * objects because their prototype chain includes an application-specific or
19
+ * built-in prototype before `Object.prototype`.
20
+ *
21
+ * The prototype-chain check uses structure instead of `prototype ===
22
+ * Object.prototype` so it also works for plain objects coming from another
23
+ * JavaScript realm.
24
+ *
4
25
  * ### Example
5
26
  *
6
27
  * ```ts
7
28
  * isPlainObject({}); // true
29
+ * isPlainObject(Object.create(null)); // true
8
30
  * isPlainObject(new Date()); // false
31
+ * isPlainObject(new (class Example {})()); // false
9
32
  * isPlainObject([]); // false
10
33
  * isPlainObject(null); // false
11
34
  * ```
12
35
  */
13
36
  export const isPlainObject = (
14
37
  value: unknown,
15
- ): value is Record<string, unknown> =>
16
- Object.prototype.toString.call(value) === "[object Object]";
38
+ ): value is Record<string, unknown> => {
39
+ if (Object.prototype.toString.call(value) !== "[object Object]") {
40
+ return false;
41
+ }
42
+
43
+ const prototype = Object.getPrototypeOf(value) as object | null;
44
+ return prototype === null || Object.getPrototypeOf(prototype) === null;
45
+ };
17
46
 
18
47
  /**
19
- * A read-only `Record<K, V>` with `K extends keyof any` to preserve branded key
20
- * types (e.g., in {@link mapObject}).
48
+ * Checks if a value is a function.
49
+ *
50
+ * ### Example
51
+ *
52
+ * ```ts
53
+ * isFunction(() => {}); // true
54
+ * isFunction(function () {}); // true
55
+ * isFunction({}); // false
56
+ * ```
21
57
  */
22
- export type ReadonlyRecord<K extends keyof any, V> = Readonly<Record<K, V>>;
58
+ export const isFunction = (value: unknown): value is globalThis.Function =>
59
+ typeof value === "function";
23
60
 
24
- // A helper type to remove symbol keys (e.g for branded objects).
25
- type StringKeyOf<T> = Extract<keyof T, string>;
61
+ /**
62
+ * Checks if a value is {@link Iterable}.
63
+ *
64
+ * ### Example
65
+ *
66
+ * ```ts
67
+ * isIterable([1, 2, 3]); // true
68
+ * isIterable("abc"); // true
69
+ * isIterable({}); // false
70
+ * ```
71
+ */
72
+ export const isIterable = (value: unknown): value is Iterable<unknown> =>
73
+ value != null &&
74
+ typeof (value as Iterable<unknown>)[Symbol.iterator] === "function";
26
75
 
27
76
  /**
28
77
  * Like `Object.entries` but preserves branded keys.
@@ -42,6 +91,51 @@ export const objectToEntries = <T extends Record<string, any>>(
42
91
  [StringKeyOf<T>, T[StringKeyOf<T>]]
43
92
  > as ReadonlyArray<[StringKeyOf<T>, T[StringKeyOf<T>]]>;
44
93
 
94
+ // A helper type to remove symbol keys (e.g for branded objects).
95
+ type StringKeyOf<T> = Extract<keyof T, string>;
96
+
97
+ /**
98
+ * Creates an object from key-value pairs, preserving branded key types.
99
+ *
100
+ * The inverse of {@link objectToEntries}. Use when you need type-safe
101
+ * reconstruction of objects with branded keys.
102
+ *
103
+ * ### Example
104
+ *
105
+ * ```ts
106
+ * type UserId = string & { readonly __brand: "UserId" };
107
+ * const entries: ReadonlyArray<[UserId, string]> = [
108
+ * ["u1" as UserId, "Alice"],
109
+ * ];
110
+ * const users = objectFromEntries(entries); // ReadonlyRecord<UserId, string>
111
+ * ```
112
+ */
113
+ export const objectFromEntries = <K extends string, V>(
114
+ entries: Iterable<readonly [K, V]>,
115
+ ): ReadonlyRecord<K, V> => Object.fromEntries(entries) as ReadonlyRecord<K, V>;
116
+
117
+ /**
118
+ * Creates an object by mapping keys to values.
119
+ *
120
+ * The inverse of `Object.keys` — instead of extracting keys from an object,
121
+ * builds an object from keys with a mapper function.
122
+ *
123
+ * ### Example
124
+ *
125
+ * ```ts
126
+ * objectFrom(["en", "fr", "de"], loadTranslations);
127
+ * // { en: Translations, fr: Translations, de: Translations }
128
+ *
129
+ * objectFrom(["trace", "debug", "log"], (level) => createHandler(level));
130
+ * // { trace: Handler, debug: Handler, log: Handler }
131
+ * ```
132
+ */
133
+ export const objectFrom = <K extends string, V>(
134
+ keys: ReadonlyArray<K>,
135
+ getValue: (key: K) => V,
136
+ ): ReadonlyRecord<K, V> =>
137
+ Object.fromEntries(keys.map((k) => [k, getValue(k)])) as ReadonlyRecord<K, V>;
138
+
45
139
  /**
46
140
  * Maps a `ReadonlyRecord<K, V>` to a new `ReadonlyRecord<K, U>`, preserving
47
141
  * branded key types (e.g., `type Id = 'id' & string`) lost by `Object.entries`.
@@ -50,13 +144,15 @@ export const objectToEntries = <T extends Record<string, any>>(
50
144
  export const mapObject = <K extends string, V, U>(
51
145
  record: ReadonlyRecord<K, V>,
52
146
  fn: (value: V, key: K) => U,
53
- ): ReadonlyRecord<K, U> =>
54
- Object.fromEntries(
55
- Object.entries(record).map(([key, value]) => [
56
- key,
57
- fn(value as V, key as K),
58
- ]),
59
- ) as ReadonlyRecord<K, U>;
147
+ ): ReadonlyRecord<K, U> => {
148
+ const out = Object.create(null) as Record<K, U>;
149
+
150
+ for (const key in record) {
151
+ out[key as K] = fn(record[key as K], key as K);
152
+ }
153
+
154
+ return out as ReadonlyRecord<K, U>;
155
+ };
60
156
 
61
157
  /** Conditionally excludes a property from an object. */
62
158
  export const excludeProp = <T extends object, K extends keyof T>(
@@ -90,6 +186,16 @@ export const createRecord = <K extends string = string, V = unknown>(): Record<
90
186
  V
91
187
  > => Object.create(null) as Record<K, V>;
92
188
 
189
+ /**
190
+ * An empty readonly record.
191
+ *
192
+ * Use as a default or initial value to avoid allocating new empty records.
193
+ *
194
+ * @group Constants
195
+ */
196
+ export const emptyRecord: Readonly<Record<string, never>> =
197
+ /*#__PURE__*/ createRecord();
198
+
93
199
  /**
94
200
  * Safely gets a property from a record, returning `undefined` if the key
95
201
  * doesn't exist.
@@ -107,5 +213,38 @@ export const createRecord = <K extends string = string, V = unknown>(): Record<
107
213
  */
108
214
  export const getProperty = <K extends string, V>(
109
215
  record: ReadonlyRecord<K, V>,
110
- key: string,
111
- ): V | undefined => (key in record ? record[key as K] : undefined);
216
+ key: K,
217
+ ): V | undefined => (key in record ? record[key] : undefined);
218
+
219
+ /**
220
+ * A disposable wrapper around `URL.createObjectURL` that automatically revokes
221
+ * the URL when disposed. Use with the `using` declaration for automatic
222
+ * cleanup.
223
+ *
224
+ * ### Example
225
+ *
226
+ * ```ts
227
+ * const blob = new Blob(["hello"], { type: "text/plain" });
228
+ * using objectUrl = createObjectURL(blob);
229
+ * console.log(objectUrl.url); // blob:...
230
+ * // URL.revokeObjectURL is automatically called when the scope ends
231
+ * ```
232
+ *
233
+ * This ensures the URL is always revoked when the scope ends, even if an error
234
+ * occurs, preventing memory leaks from unreleased blob URLs.
235
+ */
236
+ export interface ObjectURL extends Disposable {
237
+ /** The object URL string created by `URL.createObjectURL`. */
238
+ readonly url: string;
239
+ }
240
+
241
+ /** Creates a disposable {@link ObjectURL} for the given blob. */
242
+ export const createObjectURL = (blob: Blob): ObjectURL => {
243
+ const url = URL.createObjectURL(blob);
244
+ return {
245
+ url,
246
+ [Symbol.dispose]: () => {
247
+ URL.revokeObjectURL(url);
248
+ },
249
+ };
250
+ };
package/src/Option.ts ADDED
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Optional value container.
3
+ *
4
+ * Distinguishes absence from values like `null` or `undefined`.
5
+ *
6
+ * Use Option when the value itself can be `null` or `undefined`. For APIs where
7
+ * `null` means "not found", just use `T | null` directly.
8
+ *
9
+ * ### Example
10
+ *
11
+ * ```ts
12
+ * // A cache that can store any value, including null and undefined
13
+ * const cache = new Map<string, Option<unknown>>();
14
+ *
15
+ * const get = (key: string): Option<unknown> => cache.get(key) ?? none;
16
+ *
17
+ * cache.set("a", some(null)); // Stored null
18
+ * cache.set("b", some(undefined)); // Stored undefined
19
+ *
20
+ * isSome(get("a")); // true — value is null
21
+ * isSome(get("b")); // true — value is undefined
22
+ * isNone(get("c")); // true — key doesn't exist
23
+ * ```
24
+ *
25
+ * @module
26
+ */
27
+
28
+ /** Optional value. */
29
+ import type { Typed } from "./Type.js";
30
+
31
+ /** Optional value. */
32
+ export type Option<T> = Some<T> | None;
33
+
34
+ /** Present value in an {@link Option}. */
35
+ export interface Some<out T> extends Typed<"Some"> {
36
+ readonly value: T;
37
+ }
38
+
39
+ /** Absent value in an {@link Option}. */
40
+ export interface None extends Typed<"None"> {}
41
+
42
+ /**
43
+ * Extracts the value type from an {@link Option} or {@link Some}.
44
+ *
45
+ * @group Utilities
46
+ */
47
+ export type InferOption<O extends Option<any>> =
48
+ O extends Some<infer T> ? T : never;
49
+
50
+ /** Creates a {@link Some}. */
51
+ export const some = <T>(value: T): Option<T> => ({
52
+ type: "Some",
53
+ value,
54
+ });
55
+
56
+ /** Shared {@link None} instance. */
57
+ export const none: None = { type: "None" };
58
+
59
+ /** Type guard for {@link Some}. */
60
+ export const isSome = <T>(option: Option<T>): option is Some<T> =>
61
+ option.type === "Some";
62
+
63
+ /** Type guard for {@link None}. */
64
+ export const isNone = <T>(option: Option<T>): option is None =>
65
+ option.type === "None";
66
+
67
+ /**
68
+ * Converts a nullable value to an {@link Option}.
69
+ *
70
+ * `null` and `undefined` become {@link none}.
71
+ */
72
+ export const fromNullable = <T>(
73
+ value: T | null | undefined,
74
+ ): Option<NonNullable<T>> => (value == null ? none : some(value));
package/src/Order.ts CHANGED
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Ordering and comparison utilities.
3
+ *
4
+ * @module
5
+ */
6
+
1
7
  /**
2
8
  * Compares two values of type `A` and returns their ordering.
3
9
  *
@@ -61,7 +67,9 @@ export const reverseOrder =
61
67
  * ["c", "b", "a"].toSorted(orderString); // ["a", "b", "c"]
62
68
  * ```
63
69
  */
64
- export const orderString: Order<string> = createOrder((a, b) => a < b);
70
+ export const orderString: Order<string> = /*#__PURE__*/ createOrder(
71
+ (a, b) => a < b,
72
+ );
65
73
 
66
74
  /**
67
75
  * An order for numbers in ascending order.
@@ -78,7 +86,7 @@ export const orderString: Order<string> = createOrder((a, b) => a < b);
78
86
  * reverseOrder(orderNumber)(1, 1); // 0
79
87
  * ```
80
88
  */
81
- export const orderNumber = createOrder<number>((a, b) => a < b);
89
+ export const orderNumber = /*#__PURE__*/ createOrder<number>((a, b) => a < b);
82
90
 
83
91
  /**
84
92
  * An order for bigints in ascending order.
@@ -92,7 +100,7 @@ export const orderNumber = createOrder<number>((a, b) => a < b);
92
100
  * [2n, 1n, 3n].toSorted(orderBigInt); // [1n, 2n, 3n]
93
101
  * ```
94
102
  */
95
- export const orderBigInt = createOrder<bigint>((a, b) => a < b);
103
+ export const orderBigInt = /*#__PURE__*/ createOrder<bigint>((a, b) => a < b);
96
104
 
97
105
  /** An {@link Order} for Uint8Array. */
98
106
  export const orderUint8Array: Order<Uint8Array> = (a, b) => {
package/src/Platform.ts CHANGED
@@ -1,9 +1,14 @@
1
- /** Detects if the code is running in React Native environment. */
2
- export const isReactNative =
3
- typeof navigator !== "undefined" &&
4
- "product" in navigator &&
5
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
6
- (navigator as any).product === "ReactNative";
1
+ /**
2
+ * Platform runtime utilities and capability abstractions.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ /** Returns true if running in React Native with Hermes engine. */
8
+ export const isHermes = "HermesInternal" in globalThis;
9
+
10
+ /** Returns true if running in a server environment (no DOM). */
11
+ export const isServer = typeof document === "undefined";
7
12
 
8
13
  /**
9
14
  * Detects if Node.js Buffer is available and should be used.
@@ -17,4 +22,35 @@ export const isReactNative =
17
22
  * @see https://github.com/craftzdog/react-native-quick-base64#installation
18
23
  */
19
24
  export const hasNodeBuffer =
20
- !isReactNative && typeof globalThis.Buffer !== "undefined";
25
+ !isHermes && typeof globalThis.Buffer !== "undefined";
26
+
27
+ /**
28
+ * FlushSync is for libraries like React to flush updates synchronously inside
29
+ * the provided callback to ensure the DOM is updated immediately.
30
+ *
31
+ * For example, with React, when we want to focus on an element rendered as a
32
+ * result of a mutation, Evolu ensures all DOM changes are flushed synchronously
33
+ * if an onComplete callback is used.
34
+ *
35
+ * https://react.dev/reference/react-dom/flushSync
36
+ */
37
+ export type FlushSync = (callback: () => void) => void;
38
+
39
+ export interface FlushSyncDep {
40
+ readonly flushSync: FlushSync;
41
+ }
42
+
43
+ /**
44
+ * Reload the app in a platform-specific way.
45
+ *
46
+ * Use this after purging persistent storage to clear in-memory state and ensure
47
+ * the app starts fresh. It does not purge storage itself.
48
+ *
49
+ * - Web: Redirects to the specified URL (defaults to `/`)
50
+ * - React Native: Restarts the app (URL ignored)
51
+ */
52
+ export type ReloadApp = (url?: string) => void;
53
+
54
+ export interface ReloadAppDep {
55
+ readonly reloadApp: ReloadApp;
56
+ }