@evolu/common 7.4.1 → 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 +851 -430
  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 -824
  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 +206 -277
  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 -526
  246. package/src/Instances.ts +0 -92
  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 -949
package/src/Assert.ts CHANGED
@@ -1,4 +1,12 @@
1
- import type { Type } from "./Type.js";
1
+ /**
2
+ * Runtime assertions for invariant checking.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ import type { Ok, Result } from "./Result.js";
8
+ import type { AbortError } from "./Task.js";
9
+ import type { AnyType, InferType, Type } from "./Type.js";
2
10
 
3
11
  /**
4
12
  * Ensures a condition is true, throwing an error with the provided message if
@@ -7,23 +15,15 @@ import type { Type } from "./Type.js";
7
15
  * Prevents invalid states from propagating through the system by halting
8
16
  * execution when a condition fails, improving reliability and debuggability.
9
17
  *
10
- * **Warning**: Do not use this instead of {@link Type}. Assertions are intended
11
- * for conditions that are logically guaranteed but not statically known by
12
- * TypeScript, or for catching and signaling developer mistakes eagerly (e.g.,
13
- * invalid configuration).
18
+ * Do not use this instead of {@link Type}. Assertions are intended for
19
+ * conditions that are logically guaranteed but not statically known by
20
+ * TypeScript, or for catching and signaling developer mistakes eagerly.
14
21
  *
15
22
  * ### Example
16
23
  *
17
24
  * ```ts
18
25
  * assert(true, "true is not true"); // no-op
19
26
  * assert(false, "true is not true"); // throws Error
20
- *
21
- * const length = buffer.getLength();
22
- * // We know length is logically non-negative, but TypeScript doesn't
23
- * assert(
24
- * NonNegativeInt.is(length),
25
- * "buffer length should be non-negative",
26
- * );
27
27
  * ```
28
28
  */
29
29
  export const assert: (
@@ -82,3 +82,78 @@ export const assertNonEmptyReadonlyArray: <T>(
82
82
  ) => {
83
83
  assert(arr.length > 0, message);
84
84
  };
85
+
86
+ /**
87
+ * Ensures a value conforms to a {@link Type}.
88
+ *
89
+ * Uses the Type name for the default error message.
90
+ *
91
+ * ### Example
92
+ *
93
+ * ```ts
94
+ * const length = buffer.getLength();
95
+ *
96
+ * // We know length is logically non-negative, but TypeScript doesn't.
97
+ * assertType(NonNegativeInt, length);
98
+ * ```
99
+ */
100
+ export const assertType: <T extends AnyType>(
101
+ type: T,
102
+ value: unknown,
103
+ message?: string,
104
+ ) => asserts value is InferType<T> = (type, value, message) => {
105
+ assert(type.is(value), message ?? `Expected ${type.name}.`);
106
+ };
107
+
108
+ /**
109
+ * Asserts that a {@link Result} did not fail with `AbortError`.
110
+ *
111
+ * Use when abort would indicate a programmer error rather than ordinary control
112
+ * flow.
113
+ *
114
+ * In general, abort is normal control flow. Stopping work and returning
115
+ * `AbortError` is the correct behavior when a `Run` or `Fiber` is cancelled.
116
+ *
117
+ * Use `assertNotAborted` only to protect invariants in code that has already
118
+ * decided abort must not happen, such as resource helpers built on
119
+ * `unabortable`. In those places it helps fail fast on mistakes, because
120
+ * TypeScript cannot fully enforce that lifecycle logic is correct.
121
+ */
122
+ export function assertNotAborted<T>(
123
+ result: Result<T, AbortError>,
124
+ message?: string,
125
+ ): asserts result is Ok<T>;
126
+ export function assertNotAborted<T, E>(
127
+ result: Result<T, E | AbortError>,
128
+ message?: string,
129
+ ): asserts result is Result<T, E>;
130
+ export function assertNotAborted<T, E>(
131
+ result: Result<T, E | AbortError>,
132
+ message = "Expected result to not be aborted.",
133
+ ): asserts result is Result<T, E> {
134
+ const isAbortError =
135
+ !result.ok &&
136
+ (result.error as { readonly type?: unknown }).type === "AbortError";
137
+
138
+ assert(!isAbortError, message);
139
+ }
140
+
141
+ /**
142
+ * Guards synchronous methods on objects that may be called after disposal.
143
+ *
144
+ * Use when an API must fail fast before touching already-disposed state.
145
+ *
146
+ * ### Example
147
+ *
148
+ * ```ts
149
+ * const stack = new globalThis.AsyncDisposableStack();
150
+ * assertNotDisposed(stack); // no-op
151
+ * await stack.disposeAsync();
152
+ * assertNotDisposed(stack); // throws Error
153
+ * ```
154
+ */
155
+ export const assertNotDisposed = (
156
+ value: globalThis.DisposableStack | globalThis.AsyncDisposableStack,
157
+ ): void => {
158
+ assert(!value.disposed, "Expected value to not be disposed.");
159
+ };
package/src/BigInt.ts CHANGED
@@ -1,4 +1,10 @@
1
- import { Predicate } from "./Types.js";
1
+ /**
2
+ * BigInt arithmetic and comparison utilities.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ import type { Predicate } from "./Types.js";
2
8
 
3
9
  /** Increments a bigint by 1. */
4
10
  export const incrementBigInt = (n: bigint): bigint => n + 1n;
package/src/Brand.ts CHANGED
@@ -1,12 +1,21 @@
1
1
  /**
2
2
  * A utility interface for creating branded types.
3
3
  *
4
- * Branded types enhance type safety by differentiating otherwise identical base
5
- * types, such as `number` or `string`, to enforce stricter type checks.
4
+ * @module
5
+ */
6
+
7
+ /**
8
+ * An interface for creating branded types.
6
9
  *
7
- * Supports multiple brands, allowing types to act like flags.
10
+ * Branded types enhance type safety by distinguishing otherwise identical
11
+ * types, such as `number` or `string`, to enforce stricter type checks. For
12
+ * example, instead of a plain `number`, use `PositiveInt`. Instead of a plain
13
+ * `string`, use `TrimmedString`.
8
14
  *
9
- * ### Example 1: Single Brand
15
+ * Avoid primitive types in domain code—brand everything. Evolu Type provides
16
+ * many brand helpers.
17
+ *
18
+ * ### Single Brand
10
19
  *
11
20
  * ```ts
12
21
  * // A branded type definition
@@ -25,12 +34,12 @@
25
34
  * // Implementation
26
35
  * };
27
36
  *
28
- * getUser(userId); // Valid
29
- * getUser(123); // TypeScript error
30
- * getUser("123"); // TypeScript error
37
+ * getUser(userId); // Valid
38
+ * getUser(123); // TypeScript error
39
+ * getUser("123"); // TypeScript error
31
40
  * ```
32
41
  *
33
- * ### Example 2: Multiple Brands
42
+ * ### Multiple Brands (to act like flags)
34
43
  *
35
44
  * ```ts
36
45
  * // Define branded types
@@ -50,10 +59,30 @@
50
59
  * const min1Max100Value: Min1Max100 = "typescript" as Min1Max100;
51
60
  *
52
61
  * // Valid cases
53
- * requiresMin1(min1Value); // Valid
54
- * requiresMax100(max100Value); // Valid
55
- * requiresMin1(min1Max100Value); // Valid: Min1Max100 satisfies Min1
56
- * requiresMax100(min1Max100Value); // Valid: Min1Max100 satisfies Max100
62
+ * requiresMin1(min1Value); // Valid
63
+ * requiresMax100(max100Value); // Valid
64
+ * requiresMin1(min1Max100Value); // Valid: Min1Max100 satisfies Min1
65
+ * requiresMax100(min1Max100Value); // Valid: Min1Max100 satisfies Max100
66
+ * ```
67
+ *
68
+ * ### Standalone Brand
69
+ *
70
+ * Brand can be used alone without a base type for purely nominal typing. This
71
+ * is useful for opaque values where the internal structure is hidden and type
72
+ * identity is based on name only. For example, platform-specific handles can be
73
+ * branded to prevent accidental mixing of implementations while keeping common
74
+ * code platform-agnostic.
75
+ *
76
+ * ```ts
77
+ * // A nominal type with no underlying structure exposed
78
+ * type NativePort = Brand<"NativePort">;
79
+ *
80
+ * // Only values explicitly cast to NativePort are accepted
81
+ * const requiresNativePort = (port: NativePort): void => {};
82
+ *
83
+ * const port: NativePort = nativeValue as NativePort;
84
+ * requiresNativePort(port); // Valid
85
+ * requiresNativePort(nativeValue); // TypeScript error
57
86
  * ```
58
87
  */
59
88
  export interface Brand<B extends string> {
package/src/Buffer.ts CHANGED
@@ -1,5 +1,11 @@
1
- import { Result } from "./Result.js";
2
- import { NonNegativeInt } from "./Type.js";
1
+ /**
2
+ * Binary data handling and byte array utilities.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ import type { Result } from "./Result.js";
8
+ import { NonNegativeInt, zeroNonNegativeInt } from "./Type.js";
3
9
  export {
4
10
  bytesToHex,
5
11
  bytesToUtf8,
@@ -27,7 +33,7 @@ export class BufferError extends Error {
27
33
  * its capacity) to minimize memory reallocations and uses `subarray` for
28
34
  * efficient, copy-free data access in methods like `unwrap` and `shift`.
29
35
  *
30
- * ### Recommended Usage
36
+ * ## Recommended Usage
31
37
  *
32
38
  * Create as few Buffers as possible—typically one main Buffer for the final
33
39
  * output. Temporary Buffers are allowed when necessary (e.g., for
@@ -166,7 +172,7 @@ export const createBuffer = (
166
172
  },
167
173
 
168
174
  reset: () => {
169
- length = NonNegativeInt.orThrow(0);
175
+ length = zeroNonNegativeInt;
170
176
  },
171
177
 
172
178
  unwrap: () => value.subarray(0, length),
package/src/Cache.ts CHANGED
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Cache implementations including LRU eviction.
3
+ *
4
+ * @module
5
+ */
6
+
1
7
  import { PositiveInt } from "./Type.js";
2
8
 
3
9
  /**
@@ -5,8 +11,11 @@ import { PositiveInt } from "./Type.js";
5
11
  *
6
12
  * Keys are compared by reference (standard Map semantics).
7
13
  *
8
- * Note: Cache does not extend Map because eviction policies (like in LRU)
9
- * violate the Liskov Substitution Principle.
14
+ * Note: Cache has a Map-like API but does not extend Map because it behaves
15
+ * differently. Eviction policies (like LRU) can remove entries implicitly, and
16
+ * code that accepts a Map can assume values remain until deleted explicitly. An
17
+ * evicting cache is not a safe substitute for Map (Liskov Substitution
18
+ * Principle).
10
19
  */
11
20
  export interface Cache<K, V> {
12
21
  /** Checks if a key exists in the cache. */
package/src/Callbacks.ts CHANGED
@@ -1,7 +1,13 @@
1
- import { Brand } from "./Brand.js";
2
- import { RandomBytesDep } from "./Crypto.js";
3
- import { Result } from "./Result.js";
1
+ /**
2
+ * Request-response correlation for callbacks across boundaries.
3
+ *
4
+ * @module
5
+ */
6
+
7
+ import type { RandomBytesDep } from "./Crypto.js";
8
+ import type { Result } from "./Result.js";
4
9
  import { createId, Id } from "./Type.js";
10
+ import type { Callback } from "./Types.js";
5
11
 
6
12
  /**
7
13
  * Request-response correlation for callbacks across boundaries.
@@ -42,42 +48,46 @@ import { createId, Id } from "./Type.js";
42
48
  * @template T - The type of argument passed to callbacks (defaults to undefined
43
49
  * for no-argument callbacks)
44
50
  */
45
- export interface Callbacks<T = undefined> {
51
+ export interface Callbacks<T = undefined> extends Disposable {
46
52
  /** Registers a callback function and returns a unique ID. */
47
- readonly register: (callback: (arg: T) => void) => CallbackId;
53
+ readonly register: (callback: Callback<T>) => Id;
48
54
 
49
55
  /** Executes and removes a callback associated with the given ID. */
50
56
  readonly execute: T extends undefined
51
- ? (id: CallbackId) => undefined
52
- : (id: CallbackId, arg: T) => undefined;
57
+ ? (id: Id) => undefined
58
+ : (id: Id, arg: T) => undefined;
53
59
  }
54
60
 
55
- /** Unique identifier for a callback in {@link Callbacks}. */
56
- export type CallbackId = Id & Brand<"Callback">;
57
-
58
61
  /** Creates a {@link Callbacks} registry for managing callbacks. */
59
62
  export const createCallbacks = <T = undefined>(
60
63
  deps: RandomBytesDep,
61
64
  ): Callbacks<T> => {
62
- const callbackMap = new Map<CallbackId, (arg: T) => void>();
65
+ const callbackMap = new Map<Id, Callback<T>>();
66
+
67
+ const execute: Callbacks<T>["execute"] = ((id: Id, ...args: Array<T>) => {
68
+ const callback = callbackMap.get(id);
69
+ if (!callback) return undefined;
70
+ callbackMap.delete(id);
71
+ if (args.length === 0) {
72
+ // Called without argument (undefined case)
73
+ (callback as () => void)();
74
+ } else {
75
+ callback(args[0]);
76
+ }
77
+ return undefined;
78
+ }) as Callbacks<T>["execute"];
63
79
 
64
80
  return {
65
81
  register: (callback) => {
66
- const id = createId<"Callback">(deps);
82
+ const id = createId(deps);
67
83
  callbackMap.set(id, callback);
68
84
  return id;
69
85
  },
70
86
 
71
- execute: (id: CallbackId, ...args: T extends undefined ? [] : [T]) => {
72
- const callback = callbackMap.get(id);
73
- if (!callback) return;
74
- callbackMap.delete(id);
75
- if (args.length === 0) {
76
- // Called without argument (undefined case)
77
- (callback as () => void)();
78
- } else {
79
- callback(args[0]);
80
- }
87
+ execute,
88
+
89
+ [Symbol.dispose]: () => {
90
+ callbackMap.clear();
81
91
  },
82
- } as Callbacks<T>;
92
+ };
83
93
  };