@evolu/common 6.0.1-preview.9 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/src/Array.d.ts +256 -12
- package/dist/src/Array.d.ts.map +1 -1
- package/dist/src/Array.js +215 -9
- package/dist/src/Assert.d.ts +0 -13
- package/dist/src/Assert.d.ts.map +1 -1
- package/dist/src/Assert.js +0 -15
- package/dist/src/Brand.d.ts +75 -0
- package/dist/src/Brand.d.ts.map +1 -0
- package/dist/src/Brand.js +1 -0
- package/dist/src/Buffer.d.ts +1 -1
- package/dist/src/Buffer.d.ts.map +1 -1
- package/dist/src/Buffer.js +8 -7
- package/dist/src/Cache.d.ts +44 -0
- package/dist/src/Cache.d.ts.map +1 -0
- package/dist/src/Cache.js +52 -0
- package/dist/src/Callbacks.d.ts +45 -12
- package/dist/src/Callbacks.d.ts.map +1 -1
- package/dist/src/Callbacks.js +14 -7
- package/dist/src/Console.d.ts +31 -6
- package/dist/src/Console.d.ts.map +1 -1
- package/dist/src/Console.js +72 -9
- package/dist/src/Crypto.d.ts +56 -42
- package/dist/src/Crypto.d.ts.map +1 -1
- package/dist/src/Crypto.js +40 -53
- package/dist/src/Evolu/Db.d.ts +162 -74
- package/dist/src/Evolu/Db.d.ts.map +1 -1
- package/dist/src/Evolu/Db.js +284 -702
- package/dist/src/Evolu/Diff.d.ts +3 -3
- package/dist/src/Evolu/Diff.d.ts.map +1 -1
- package/dist/src/Evolu/Diff.js +7 -5
- package/dist/src/Evolu/Evolu.d.ts +213 -133
- package/dist/src/Evolu/Evolu.d.ts.map +1 -1
- package/dist/src/Evolu/Evolu.js +189 -180
- package/dist/src/Evolu/Internal.d.ts +0 -2
- package/dist/src/Evolu/Internal.d.ts.map +1 -1
- package/dist/src/Evolu/Internal.js +0 -2
- package/dist/src/Evolu/LocalAuth.d.ts +150 -0
- package/dist/src/Evolu/LocalAuth.d.ts.map +1 -0
- package/dist/src/Evolu/LocalAuth.js +174 -0
- package/dist/src/Evolu/Owner.d.ts +273 -120
- package/dist/src/Evolu/Owner.d.ts.map +1 -1
- package/dist/src/Evolu/Owner.js +130 -104
- package/dist/src/Evolu/Platform.d.ts +9 -7
- package/dist/src/Evolu/Platform.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.d.ts +268 -240
- package/dist/src/Evolu/Protocol.d.ts.map +1 -1
- package/dist/src/Evolu/Protocol.js +595 -447
- package/dist/src/Evolu/Public.d.ts +6 -8
- package/dist/src/Evolu/Public.d.ts.map +1 -1
- package/dist/src/Evolu/Public.js +2 -3
- package/dist/src/Evolu/PublicKysely.d.ts.map +1 -1
- package/dist/src/Evolu/PublicKysely.js +3 -4
- package/dist/src/Evolu/Query.d.ts +2 -1
- package/dist/src/Evolu/Query.d.ts.map +1 -1
- package/dist/src/Evolu/Query.js +1 -1
- package/dist/src/Evolu/Relay.d.ts +91 -8
- package/dist/src/Evolu/Relay.d.ts.map +1 -1
- package/dist/src/Evolu/Relay.js +214 -88
- package/dist/src/Evolu/Schema.d.ts +125 -47
- package/dist/src/Evolu/Schema.d.ts.map +1 -1
- package/dist/src/Evolu/Schema.js +175 -31
- package/dist/src/Evolu/Storage.d.ts +249 -27
- package/dist/src/Evolu/Storage.d.ts.map +1 -1
- package/dist/src/Evolu/Storage.js +198 -92
- package/dist/src/Evolu/Sync.d.ts +68 -13
- package/dist/src/Evolu/Sync.d.ts.map +1 -1
- package/dist/src/Evolu/Sync.js +469 -20
- package/dist/src/Evolu/Timestamp.d.ts +83 -30
- package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
- package/dist/src/Evolu/Timestamp.js +79 -34
- package/dist/src/Identicon.d.ts +35 -0
- package/dist/src/Identicon.d.ts.map +1 -0
- package/dist/src/Identicon.js +143 -0
- package/dist/src/Instances.d.ts +34 -0
- package/dist/src/Instances.d.ts.map +1 -0
- package/dist/src/Instances.js +44 -0
- package/dist/src/Number.d.ts +4 -3
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +5 -4
- package/dist/src/Object.d.ts +10 -4
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +9 -3
- package/dist/src/Platform.d.ts +20 -0
- package/dist/src/Platform.d.ts.map +1 -0
- package/dist/src/Platform.js +22 -0
- package/dist/src/Random.d.ts +3 -2
- package/dist/src/Random.d.ts.map +1 -1
- package/dist/src/Relation.d.ts +79 -0
- package/dist/src/Relation.d.ts.map +1 -0
- package/dist/src/Relation.js +127 -0
- package/dist/src/Resources.d.ts +118 -0
- package/dist/src/Resources.d.ts.map +1 -0
- package/dist/src/Resources.js +197 -0
- package/dist/src/Result.d.ts +184 -52
- package/dist/src/Result.d.ts.map +1 -1
- package/dist/src/Result.js +30 -241
- package/dist/src/Skiplist.js +2 -1
- package/dist/src/Sqlite.d.ts +89 -5
- package/dist/src/Sqlite.d.ts.map +1 -1
- package/dist/src/Sqlite.js +136 -9
- package/dist/src/Task.d.ts +586 -0
- package/dist/src/Task.d.ts.map +1 -0
- package/dist/src/Task.js +469 -0
- package/dist/src/Time.d.ts +66 -1
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +99 -5
- package/dist/src/Type.d.ts +676 -343
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +718 -467
- package/dist/src/Types.d.ts +1 -75
- package/dist/src/Types.d.ts.map +1 -1
- package/dist/src/WebSocket.d.ts +5 -2
- package/dist/src/WebSocket.d.ts.map +1 -1
- package/dist/src/WebSocket.js +12 -18
- package/dist/src/Worker.d.ts +39 -11
- package/dist/src/Worker.d.ts.map +1 -1
- package/dist/src/Worker.js +22 -4
- package/dist/src/index.d.ts +8 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +8 -3
- package/package.json +14 -13
- package/src/Array.ts +301 -19
- package/src/Assert.ts +0 -21
- package/src/Brand.ts +75 -0
- package/src/Buffer.ts +7 -7
- package/src/Cache.ts +85 -0
- package/src/Callbacks.ts +62 -22
- package/src/Console.ts +91 -11
- package/src/Crypto.ts +94 -90
- package/src/Evolu/Db.ts +519 -1026
- package/src/Evolu/Diff.ts +7 -5
- package/src/Evolu/Evolu.ts +476 -360
- package/src/Evolu/Internal.ts +0 -2
- package/src/Evolu/LocalAuth.ts +463 -0
- package/src/Evolu/Owner.ts +355 -228
- package/src/Evolu/Platform.ts +9 -9
- package/src/Evolu/Protocol.ts +846 -742
- package/src/Evolu/Public.ts +7 -14
- package/src/Evolu/PublicKysely.ts +4 -5
- package/src/Evolu/Query.ts +3 -2
- package/src/Evolu/Relay.ts +406 -103
- package/src/Evolu/Schema.ts +323 -91
- package/src/Evolu/Storage.ts +559 -137
- package/src/Evolu/Sync.ts +819 -36
- package/src/Evolu/Timestamp.ts +90 -58
- package/src/Identicon.ts +197 -0
- package/src/Instances.ts +90 -0
- package/src/Number.ts +6 -10
- package/src/Object.ts +13 -5
- package/src/Platform.ts +26 -0
- package/src/Random.ts +3 -2
- package/src/Relation.ts +234 -0
- package/src/Resources.ts +367 -0
- package/src/Result.ts +191 -54
- package/src/Skiplist.ts +1 -1
- package/src/Sqlite.ts +152 -17
- package/src/Task.ts +901 -0
- package/src/Time.ts +180 -5
- package/src/Type.ts +1135 -730
- package/src/Types.ts +1 -77
- package/src/WebSocket.ts +27 -25
- package/src/Worker.ts +72 -23
- package/src/index.ts +8 -3
- package/dist/src/Evolu/Config.d.ts +0 -69
- package/dist/src/Evolu/Config.d.ts.map +0 -1
- package/dist/src/Evolu/Config.js +0 -9
- package/dist/src/Evolu/Kysely.d.ts +0 -6
- package/dist/src/Evolu/Kysely.d.ts.map +0 -1
- package/dist/src/Evolu/Kysely.js +0 -21
- package/dist/src/ManyToManyMap.d.ts +0 -26
- package/dist/src/ManyToManyMap.d.ts.map +0 -1
- package/dist/src/ManyToManyMap.js +0 -92
- package/dist/src/NanoId.d.ts +0 -27
- package/dist/src/NanoId.d.ts.map +0 -1
- package/dist/src/NanoId.js +0 -6
- package/dist/src/Promise.d.ts +0 -180
- package/dist/src/Promise.d.ts.map +0 -1
- package/dist/src/Promise.js +0 -176
- package/src/Evolu/Config.ts +0 -83
- package/src/Evolu/Kysely.ts +0 -38
- package/src/ManyToManyMap.ts +0 -140
- package/src/NanoId.ts +0 -39
- package/src/Promise.ts +0 -295
package/src/Types.ts
CHANGED
|
@@ -79,83 +79,7 @@ export type NullablePartial<
|
|
|
79
79
|
export type IntentionalNever = never;
|
|
80
80
|
|
|
81
81
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
84
|
-
* Branded types enhance type safety by differentiating otherwise identical base
|
|
85
|
-
* types, such as `number` or `string`, to enforce stricter type checks.
|
|
86
|
-
*
|
|
87
|
-
* Supports multiple brands, allowing types to act like flags.
|
|
88
|
-
*
|
|
89
|
-
* ### Example 1: Single Brand
|
|
90
|
-
*
|
|
91
|
-
* ```ts
|
|
92
|
-
* // A branded type definition
|
|
93
|
-
* type UserId = number & Brand<"UserId">;
|
|
94
|
-
*
|
|
95
|
-
* // A function that creates `UserId` values.
|
|
96
|
-
* // Casting with `as UserId` is unsafe, so `createUserId` must be unit-tested.
|
|
97
|
-
* const createUserId = (): UserId => {
|
|
98
|
-
* return 123 as UserId; // Unsafe casting
|
|
99
|
-
* };
|
|
100
|
-
*
|
|
101
|
-
* const userId = createUserId();
|
|
102
|
-
*
|
|
103
|
-
* // A function that accepts only `UserId`.
|
|
104
|
-
* const getUser = (id: UserId) => {
|
|
105
|
-
* // Implementation
|
|
106
|
-
* };
|
|
107
|
-
*
|
|
108
|
-
* getUser(userId); // ✅ Valid
|
|
109
|
-
* getUser(123); // ❌ TypeScript error
|
|
110
|
-
* getUser("123"); // ❌ TypeScript error
|
|
111
|
-
* ```
|
|
112
|
-
*
|
|
113
|
-
* ### Example 2: Multiple Brands
|
|
114
|
-
*
|
|
115
|
-
* ```ts
|
|
116
|
-
* // Define branded types
|
|
117
|
-
* type Min1 = string & Brand<"Min1">;
|
|
118
|
-
* type Max100 = string & Brand<"Max100">;
|
|
119
|
-
* type Min1Max100 = string & Brand<"Min1" | "Max100">;
|
|
120
|
-
*
|
|
121
|
-
* // Functions requiring specific brands
|
|
122
|
-
* const requiresMin1 = (value: Min1): void => {};
|
|
123
|
-
* const requiresMax100 = (value: Max100): void => {};
|
|
124
|
-
*
|
|
125
|
-
* // Values with single brands
|
|
126
|
-
* const min1Value: Min1 = "hello" as Min1;
|
|
127
|
-
* const max100Value: Max100 = "world" as Max100;
|
|
128
|
-
*
|
|
129
|
-
* // Value with multiple brands
|
|
130
|
-
* const min1Max100Value: Min1Max100 = "typescript" as Min1Max100;
|
|
131
|
-
*
|
|
132
|
-
* // Valid cases
|
|
133
|
-
* requiresMin1(min1Value); // ✅ Valid
|
|
134
|
-
* requiresMax100(max100Value); // ✅ Valid
|
|
135
|
-
* requiresMin1(min1Max100Value); // ✅ Valid: Min1Max100 satisfies Min1
|
|
136
|
-
* requiresMax100(min1Max100Value); // ✅ Valid: Min1Max100 satisfies Max100
|
|
137
|
-
* ```
|
|
138
|
-
*/
|
|
139
|
-
export interface Brand<B extends string> {
|
|
140
|
-
readonly [__brand]: Readonly<Record<B, true>>;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
declare const __brand: unique symbol;
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Determines whether a type `T` is a branded type.
|
|
147
|
-
*
|
|
148
|
-
* Works with any base type intersected with a `Brand`.
|
|
149
|
-
*
|
|
150
|
-
* ### Examples
|
|
151
|
-
*
|
|
152
|
-
* - `IsBranded<string>` -> false
|
|
153
|
-
* - `IsBranded<string & Brand<"X">>` -> true
|
|
154
|
-
*/
|
|
155
|
-
export type IsBranded<T> = T extends Brand<string> ? true : false;
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* String | number | bigint | boolean | undefined | null
|
|
82
|
+
* String, number, bigint, boolean, undefined, null
|
|
159
83
|
*
|
|
160
84
|
* https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#literal-types
|
|
161
85
|
*/
|
package/src/WebSocket.ts
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
* @module
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { assertNoErrorInCatch } from "./Assert.js";
|
|
8
7
|
import { constVoid } from "./Function.js";
|
|
9
|
-
import { retry, RetryError, RetryOptions } from "./Promise.js";
|
|
10
8
|
import { err, ok, Result } from "./Result.js";
|
|
9
|
+
import { retry, RetryError, RetryOptions } from "./Task.js";
|
|
10
|
+
import { maxPositiveInt } from "./Type.js";
|
|
11
11
|
|
|
12
12
|
/** WebSocket with auto-reconnect and offline support. */
|
|
13
13
|
export interface WebSocket extends Disposable {
|
|
@@ -20,10 +20,14 @@ export interface WebSocket extends Disposable {
|
|
|
20
20
|
) => Result<void, WebSocketSendError>;
|
|
21
21
|
|
|
22
22
|
readonly getReadyState: () => WebSocketReadyState;
|
|
23
|
+
|
|
24
|
+
/** Returns true if the WebSocket is open and ready to send data. */
|
|
25
|
+
readonly isOpen: () => boolean;
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
/**
|
|
26
|
-
* An error that occurs when trying to send data but WebSocket is
|
|
29
|
+
* An error that occurs when trying to send data but WebSocket is not available
|
|
30
|
+
* or is in the CONNECTING state.
|
|
27
31
|
*
|
|
28
32
|
* https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
|
|
29
33
|
*/
|
|
@@ -141,8 +145,9 @@ export interface WebSocketConnectionCloseError {
|
|
|
141
145
|
*
|
|
142
146
|
* TODO:
|
|
143
147
|
*/
|
|
144
|
-
export const createWebSocket: CreateWebSocket = (
|
|
145
|
-
|
|
148
|
+
export const createWebSocket: CreateWebSocket = (
|
|
149
|
+
url,
|
|
150
|
+
{
|
|
146
151
|
protocols,
|
|
147
152
|
binaryType,
|
|
148
153
|
onOpen,
|
|
@@ -151,14 +156,14 @@ export const createWebSocket: CreateWebSocket = (url, options = {}) => {
|
|
|
151
156
|
onError,
|
|
152
157
|
retryOptions,
|
|
153
158
|
WebSocketConstructor = globalThis.WebSocket,
|
|
154
|
-
} =
|
|
159
|
+
} = {},
|
|
160
|
+
) => {
|
|
155
161
|
let isDisposed = false;
|
|
156
162
|
|
|
157
163
|
const reconnectController = new AbortController();
|
|
158
164
|
|
|
159
165
|
const defaultRetryOptions: RetryOptions<WebSocketRetryError> = {
|
|
160
|
-
|
|
161
|
-
maxRetries: Infinity,
|
|
166
|
+
retries: maxPositiveInt, // Practically infinite retries
|
|
162
167
|
};
|
|
163
168
|
|
|
164
169
|
let socket: globalThis.WebSocket | null = null;
|
|
@@ -186,7 +191,11 @@ export const createWebSocket: CreateWebSocket = (url, options = {}) => {
|
|
|
186
191
|
* - Is rejected when a connection is closed.
|
|
187
192
|
* - Is resolved when WebSocket is disposed().
|
|
188
193
|
*/
|
|
189
|
-
retry(
|
|
194
|
+
void retry(
|
|
195
|
+
{
|
|
196
|
+
...defaultRetryOptions,
|
|
197
|
+
...retryOptions,
|
|
198
|
+
},
|
|
190
199
|
(): Promise<Result<void, WebSocketRetryError>> =>
|
|
191
200
|
new Promise((resolve) => {
|
|
192
201
|
disposePromise = () => {
|
|
@@ -212,6 +221,7 @@ export const createWebSocket: CreateWebSocket = (url, options = {}) => {
|
|
|
212
221
|
? { type: "WebSocketConnectionError", event }
|
|
213
222
|
: { type: "WebSocketConnectError", event };
|
|
214
223
|
onError?.(error);
|
|
224
|
+
|
|
215
225
|
// Trigger reconnect only on WebSocketConnectError.
|
|
216
226
|
if (error.type === "WebSocketConnectError") {
|
|
217
227
|
resolve(err(error));
|
|
@@ -227,20 +237,12 @@ export const createWebSocket: CreateWebSocket = (url, options = {}) => {
|
|
|
227
237
|
onMessage?.(event.data as string | ArrayBuffer | Blob);
|
|
228
238
|
};
|
|
229
239
|
}),
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (result.ok || result.error.type === "RetryAbortError") return;
|
|
237
|
-
onError?.(result.error);
|
|
238
|
-
})
|
|
239
|
-
.catch((error: unknown) => {
|
|
240
|
-
assertNoErrorInCatch("WebSocket retry", error);
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
const webSocket: WebSocket = {
|
|
240
|
+
)(reconnectController).then((result) => {
|
|
241
|
+
if (result.ok || result.error.type === "AbortError") return;
|
|
242
|
+
onError?.(result.error as WebSocketError);
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
return {
|
|
244
246
|
send: (data) => {
|
|
245
247
|
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket/send
|
|
246
248
|
if (!socket || socket.readyState === socket.CONNECTING) {
|
|
@@ -253,6 +255,8 @@ export const createWebSocket: CreateWebSocket = (url, options = {}) => {
|
|
|
253
255
|
getReadyState: () =>
|
|
254
256
|
socket ? nativeToStringState[socket.readyState] : "connecting",
|
|
255
257
|
|
|
258
|
+
isOpen: () => (socket ? socket.readyState === socket.OPEN : false),
|
|
259
|
+
|
|
256
260
|
[Symbol.dispose]() {
|
|
257
261
|
if (isDisposed) return;
|
|
258
262
|
isDisposed = true;
|
|
@@ -261,8 +265,6 @@ export const createWebSocket: CreateWebSocket = (url, options = {}) => {
|
|
|
261
265
|
disposePromise?.();
|
|
262
266
|
},
|
|
263
267
|
};
|
|
264
|
-
|
|
265
|
-
return webSocket;
|
|
266
268
|
};
|
|
267
269
|
|
|
268
270
|
const nativeToStringState: Record<number, WebSocketReadyState> = {
|
package/src/Worker.ts
CHANGED
|
@@ -20,6 +20,32 @@ export interface WorkerPostMessageDep<Output> {
|
|
|
20
20
|
readonly postMessage: (message: Output) => void;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
/**
|
|
24
|
+
* Error reporting wrapper that catches synchronous errors in handlers and
|
|
25
|
+
* converts them to transferable error messages sent to the main thread.
|
|
26
|
+
*/
|
|
27
|
+
export type WithErrorReporting = <A extends Array<any>>(
|
|
28
|
+
handler: (...args: A) => void,
|
|
29
|
+
) => (...args: A) => void;
|
|
30
|
+
|
|
31
|
+
type HasInit<Input> =
|
|
32
|
+
Extract<Input, { type: "init" }> extends never
|
|
33
|
+
? ["Input must contain a variant with { type: 'init' }"]
|
|
34
|
+
: unknown;
|
|
35
|
+
|
|
36
|
+
type HasWorkerErrorOutput<T> =
|
|
37
|
+
Extract<T, { type: "onError" }> extends infer E
|
|
38
|
+
? [E] extends [never]
|
|
39
|
+
? [
|
|
40
|
+
"Output must contain { type: 'onError'; error: TransferableError | ... }",
|
|
41
|
+
]
|
|
42
|
+
: E extends { error: infer Err }
|
|
43
|
+
? TransferableError extends Err
|
|
44
|
+
? unknown
|
|
45
|
+
: ["Output.onError.error must include TransferableError"]
|
|
46
|
+
: ["Output.onError must have an error property"]
|
|
47
|
+
: never;
|
|
48
|
+
|
|
23
49
|
/**
|
|
24
50
|
* Creates a {@link Worker} that supports initialization with dependencies and
|
|
25
51
|
* safe error handling.
|
|
@@ -35,9 +61,7 @@ export const createInitializedWorker = <
|
|
|
35
61
|
readonly init: (
|
|
36
62
|
initMessage: Extract<Input, { type: "init" }>,
|
|
37
63
|
postMessage: (msg: Output) => void,
|
|
38
|
-
|
|
39
|
-
handler: (...args: A) => void,
|
|
40
|
-
) => (...args: A) => void,
|
|
64
|
+
withErrorReporting: WithErrorReporting,
|
|
41
65
|
) => Promise<Deps | null>;
|
|
42
66
|
readonly onMessage: (
|
|
43
67
|
deps: Deps,
|
|
@@ -62,7 +86,11 @@ export const createInitializedWorker = <
|
|
|
62
86
|
} as unknown as Output);
|
|
63
87
|
};
|
|
64
88
|
|
|
65
|
-
|
|
89
|
+
/**
|
|
90
|
+
* Wraps function to catch errors and send them to the main thread instead of
|
|
91
|
+
* crashing the worker.
|
|
92
|
+
*/
|
|
93
|
+
const withErrorReporting =
|
|
66
94
|
<A extends Array<any>>(handler: (...args: A) => void) =>
|
|
67
95
|
(...args: A) => {
|
|
68
96
|
try {
|
|
@@ -78,7 +106,7 @@ export const createInitializedWorker = <
|
|
|
78
106
|
if (!deps) {
|
|
79
107
|
pendingMessages.push(message);
|
|
80
108
|
} else {
|
|
81
|
-
|
|
109
|
+
withErrorReporting(onMessage(deps))(message as NonInitMessage);
|
|
82
110
|
}
|
|
83
111
|
return;
|
|
84
112
|
}
|
|
@@ -89,13 +117,13 @@ export const createInitializedWorker = <
|
|
|
89
117
|
init(
|
|
90
118
|
message as Extract<Input, { type: "init" }>,
|
|
91
119
|
postMessage,
|
|
92
|
-
|
|
120
|
+
withErrorReporting,
|
|
93
121
|
)
|
|
94
122
|
.then((_deps) => {
|
|
95
123
|
if (_deps == null) return;
|
|
96
124
|
deps = _deps;
|
|
97
125
|
for (const message of pendingMessages) {
|
|
98
|
-
|
|
126
|
+
withErrorReporting(onMessage(deps))(message as NonInitMessage);
|
|
99
127
|
}
|
|
100
128
|
pendingMessages.length = 0;
|
|
101
129
|
})
|
|
@@ -110,20 +138,41 @@ export const createInitializedWorker = <
|
|
|
110
138
|
return worker;
|
|
111
139
|
};
|
|
112
140
|
|
|
113
|
-
type
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
:
|
|
141
|
+
/** Type helper to extract message types from a union type */
|
|
142
|
+
export type MessageHandlers<Input extends { readonly type: string }, Deps> = {
|
|
143
|
+
readonly [K in Input["type"]]: (
|
|
144
|
+
deps: Deps,
|
|
145
|
+
) => (message: Extract<Input, { type: K }>) => void;
|
|
146
|
+
};
|
|
117
147
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Creates a {@link Worker} with type-safe message handlers for each message
|
|
150
|
+
* type. This provides better type safety and organization compared to a single
|
|
151
|
+
* onMessage handler.
|
|
152
|
+
*/
|
|
153
|
+
export const createInitializedWorkerWithHandlers = <
|
|
154
|
+
Input extends { readonly type: string } & HasInit<Input>,
|
|
155
|
+
Output extends { readonly type: string } & HasWorkerErrorOutput<Output>,
|
|
156
|
+
Deps,
|
|
157
|
+
>({
|
|
158
|
+
init,
|
|
159
|
+
handlers,
|
|
160
|
+
}: {
|
|
161
|
+
readonly init: (
|
|
162
|
+
initMessage: Extract<Input, { type: "init" }>,
|
|
163
|
+
postMessage: (msg: Output) => void,
|
|
164
|
+
withErrorReporting: WithErrorReporting,
|
|
165
|
+
) => Promise<Deps | null>;
|
|
166
|
+
readonly handlers: Omit<MessageHandlers<Input, Deps>, "init">;
|
|
167
|
+
}): Worker<Input, Output> =>
|
|
168
|
+
createInitializedWorker({
|
|
169
|
+
init,
|
|
170
|
+
onMessage: (deps) => (message) => {
|
|
171
|
+
type NonInitMessageType = Exclude<Input["type"], "init">;
|
|
172
|
+
const messageType = message.type as NonInitMessageType;
|
|
173
|
+
const handler = handlers[messageType];
|
|
174
|
+
|
|
175
|
+
// TypeScript knows handler exists because handlers covers all non-init message types
|
|
176
|
+
handler(deps)(message as Extract<Input, { type: typeof messageType }>);
|
|
177
|
+
},
|
|
178
|
+
});
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export * from "./Array.js";
|
|
2
2
|
export * from "./Assert.js";
|
|
3
3
|
export * from "./BigInt.js";
|
|
4
|
+
export * from "./Brand.js";
|
|
4
5
|
export * from "./Buffer.js";
|
|
6
|
+
export * from "./Cache.js";
|
|
5
7
|
export * from "./Callbacks.js";
|
|
6
8
|
export * from "./Console.js";
|
|
7
9
|
export * from "./Crypto.js";
|
|
@@ -9,18 +11,21 @@ export * from "./Eq.js";
|
|
|
9
11
|
export * from "./Error.js";
|
|
10
12
|
export * from "./Evolu/Public.js";
|
|
11
13
|
export * from "./Function.js";
|
|
12
|
-
export * from "./
|
|
13
|
-
export * from "./
|
|
14
|
+
export * from "./Identicon.js";
|
|
15
|
+
export * from "./Instances.js";
|
|
14
16
|
export * from "./Number.js";
|
|
15
17
|
export * from "./Object.js";
|
|
16
18
|
export * from "./Order.js";
|
|
17
|
-
export * from "./
|
|
19
|
+
export * from "./Platform.js";
|
|
18
20
|
export * from "./Random.js";
|
|
19
21
|
export * from "./Ref.js";
|
|
22
|
+
export * from "./Relation.js";
|
|
23
|
+
export * from "./Resources.js";
|
|
20
24
|
export * from "./Result.js";
|
|
21
25
|
export * from "./Sqlite.js";
|
|
22
26
|
export * from "./Store.js";
|
|
23
27
|
export * from "./String.js";
|
|
28
|
+
export * from "./Task.js";
|
|
24
29
|
export * from "./Time.js";
|
|
25
30
|
export * from "./Type.js";
|
|
26
31
|
export * from "./Types.js";
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { ConsoleConfig } from "../Console.js";
|
|
2
|
-
import { Mnemonic, SimpleName } from "../Type.js";
|
|
3
|
-
import type { DbIndexesBuilder } from "./Kysely.js";
|
|
4
|
-
export interface Config extends ConsoleConfig {
|
|
5
|
-
/**
|
|
6
|
-
* The name of Evolu instances. Evolu is multitenant - it can run more
|
|
7
|
-
* instances concurrently. Every Evolu instance has to have its own unique
|
|
8
|
-
* name. Database files are separated and invisible to each other.
|
|
9
|
-
*
|
|
10
|
-
* The default value is: `Evolu`.
|
|
11
|
-
*
|
|
12
|
-
* ### Example
|
|
13
|
-
*
|
|
14
|
-
* ```ts
|
|
15
|
-
* // name: getOrThrow(SimpleName.from("MyApp"))
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
readonly name: SimpleName;
|
|
19
|
-
/**
|
|
20
|
-
* URL for Evolu sync and backup server.
|
|
21
|
-
*
|
|
22
|
-
* The default value is `https://free.evoluhq.com`.
|
|
23
|
-
*/
|
|
24
|
-
readonly syncUrl: string;
|
|
25
|
-
/**
|
|
26
|
-
* URL to reload browser tabs after reset or restore.
|
|
27
|
-
*
|
|
28
|
-
* The default value is `/`.
|
|
29
|
-
*/
|
|
30
|
-
readonly reloadUrl: string;
|
|
31
|
-
/**
|
|
32
|
-
* Maximum physical clock drift allowed in ms.
|
|
33
|
-
*
|
|
34
|
-
* The default value is 5 * 60 * 1000 (5 minutes).
|
|
35
|
-
*/
|
|
36
|
-
readonly maxDrift: number;
|
|
37
|
-
/**
|
|
38
|
-
* Use the `indexes` option to define SQLite indexes.
|
|
39
|
-
*
|
|
40
|
-
* Table and column names are not typed because Kysely doesn't support it.
|
|
41
|
-
*
|
|
42
|
-
* https://medium.com/@JasonWyatt/squeezing-performance-from-sqlite-indexes-indexes-c4e175f3c346
|
|
43
|
-
*
|
|
44
|
-
* ### Example
|
|
45
|
-
*
|
|
46
|
-
* ```ts
|
|
47
|
-
* const evolu = createEvolu(evoluReactDeps)(Schema, {
|
|
48
|
-
* indexes: (create) => [
|
|
49
|
-
* create("todoCreatedAt").on("todo").column("createdAt"),
|
|
50
|
-
* create("todoCategoryCreatedAt")
|
|
51
|
-
* .on("todoCategory")
|
|
52
|
-
* .column("createdAt"),
|
|
53
|
-
* ],
|
|
54
|
-
* });
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
readonly indexes?: DbIndexesBuilder;
|
|
58
|
-
/**
|
|
59
|
-
* Use this option to create Evolu with the specified mnemonic. If omitted,
|
|
60
|
-
* the mnemonic will be autogenerated. That should be the default behavior
|
|
61
|
-
* until special UX requirements are needed (e.g., multitenancy).
|
|
62
|
-
*/
|
|
63
|
-
readonly mnemonic?: Mnemonic;
|
|
64
|
-
}
|
|
65
|
-
export interface ConfigDep {
|
|
66
|
-
readonly config: Config;
|
|
67
|
-
}
|
|
68
|
-
export declare const defaultConfig: Config;
|
|
69
|
-
//# sourceMappingURL=Config.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Config.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE9C,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,MAAM,WAAW,MAAO,SAAQ,aAAa;IAC3C;;;;;;;;;;;;OAYG;IACH,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAE1B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAEpC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;CAC9B;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,eAAO,MAAM,aAAa,EAAE,MAM3B,CAAC"}
|
package/dist/src/Evolu/Config.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { getOrThrow } from "../Result.js";
|
|
2
|
-
import { SimpleName } from "../Type.js";
|
|
3
|
-
export const defaultConfig = {
|
|
4
|
-
name: getOrThrow(SimpleName.fromParent("Evolu")),
|
|
5
|
-
syncUrl: "wss://free.evoluhq.com",
|
|
6
|
-
reloadUrl: "/",
|
|
7
|
-
maxDrift: 5 * 60 * 1000,
|
|
8
|
-
enableLogging: false,
|
|
9
|
-
};
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { CreateIndexBuilder, Kysely } from "kysely";
|
|
2
|
-
import { DbIndex } from "./Db.js";
|
|
3
|
-
export declare const kysely: Kysely<unknown>;
|
|
4
|
-
export type DbIndexesBuilder = (create: (indexName: string) => CreateIndexBuilder) => ReadonlyArray<CreateIndexBuilder<any>>;
|
|
5
|
-
export declare const createIndexes: (indexes?: DbIndexesBuilder) => ReadonlyArray<DbIndex>;
|
|
6
|
-
//# sourceMappingURL=Kysely.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"Kysely.d.ts","sourceRoot":"","sources":["../../../src/Evolu/Kysely.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAElB,MAAM,EAGP,MAAM,QAAQ,CAAC;AAChB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,eAAO,MAAM,MAAM,iBASjB,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,kBAAkB,KAC9C,aAAa,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC;AAI5C,eAAO,MAAM,aAAa,GACxB,UAAU,gBAAgB,KACzB,aAAa,CAAC,OAAO,CAQvB,CAAC"}
|
package/dist/src/Evolu/Kysely.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { DummyDriver, Kysely, SqliteAdapter, SqliteQueryCompiler, } from "kysely";
|
|
2
|
-
// https://kysely.dev/docs/recipes/splitting-query-building-and-execution
|
|
3
|
-
export const kysely = new Kysely({
|
|
4
|
-
dialect: {
|
|
5
|
-
createAdapter: () => new SqliteAdapter(),
|
|
6
|
-
createDriver: () => new DummyDriver(),
|
|
7
|
-
createIntrospector() {
|
|
8
|
-
throw new Error("Not implemeneted");
|
|
9
|
-
},
|
|
10
|
-
createQueryCompiler: () => new SqliteQueryCompiler(),
|
|
11
|
-
},
|
|
12
|
-
});
|
|
13
|
-
const createIndex = kysely.schema.createIndex.bind(kysely.schema);
|
|
14
|
-
export const createIndexes = (indexes) => {
|
|
15
|
-
if (!indexes)
|
|
16
|
-
return [];
|
|
17
|
-
return indexes(createIndex).map((index) => ({
|
|
18
|
-
name: index.toOperationNode().name.name,
|
|
19
|
-
sql: index.compile().sql,
|
|
20
|
-
}));
|
|
21
|
-
};
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
/** Represents a many-to-many mapping between keys and values. */
|
|
2
|
-
export interface ManyToManyMap<K, V> {
|
|
3
|
-
/** Adds a key-value association to the map. */
|
|
4
|
-
add: (key: K, value: V) => ManyToManyMap<K, V>;
|
|
5
|
-
/** Removes a specific key-value association. */
|
|
6
|
-
remove: (key: K, value: V) => boolean;
|
|
7
|
-
/** Gets all values associated with a key. */
|
|
8
|
-
getValues: (key: K) => Set<V> | undefined;
|
|
9
|
-
/** Gets all keys associated with a value. */
|
|
10
|
-
getKeys: (value: V) => Set<K> | undefined;
|
|
11
|
-
/** Checks if a specific key-value pair exists. */
|
|
12
|
-
hasPair: (key: K, value: V) => boolean;
|
|
13
|
-
/** Checks if a key exists in the map. */
|
|
14
|
-
hasKey(key: K): boolean;
|
|
15
|
-
/** Checks if a value exists in the map. */
|
|
16
|
-
hasValue: (value: V) => boolean;
|
|
17
|
-
/** Deletes all associations for a key. */
|
|
18
|
-
deleteKey: (key: K) => boolean;
|
|
19
|
-
/** Deletes all associations for a value. */
|
|
20
|
-
deleteValue: (value: V) => boolean;
|
|
21
|
-
/** Clears all associations in the map. */
|
|
22
|
-
clear(): void;
|
|
23
|
-
}
|
|
24
|
-
/** Creates a {@link ManyToManyMap}. */
|
|
25
|
-
export declare const createManyToManyMap: <K, V>() => ManyToManyMap<K, V>;
|
|
26
|
-
//# sourceMappingURL=ManyToManyMap.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"ManyToManyMap.d.ts","sourceRoot":"","sources":["../../src/ManyToManyMap.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,MAAM,WAAW,aAAa,CAAC,CAAC,EAAE,CAAC;IACjC,+CAA+C;IAC/C,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAE/C,gDAAgD;IAChD,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEtC,6CAA6C;IAC7C,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAE1C,6CAA6C;IAC7C,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;IAE1C,kDAAkD;IAClD,OAAO,EAAE,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEvC,yCAAyC;IACzC,MAAM,CAAC,GAAG,EAAE,CAAC,GAAG,OAAO,CAAC;IAExB,2CAA2C;IAC3C,QAAQ,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEhC,0CAA0C;IAC1C,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,OAAO,CAAC;IAE/B,4CAA4C;IAC5C,WAAW,EAAE,CAAC,KAAK,EAAE,CAAC,KAAK,OAAO,CAAC;IAEnC,0CAA0C;IAC1C,KAAK,IAAI,IAAI,CAAC;CACf;AAED,uCAAuC;AACvC,eAAO,MAAM,mBAAmB,GAAI,CAAC,EAAE,CAAC,OAAK,aAAa,CAAC,CAAC,EAAE,CAAC,CAyG9D,CAAC"}
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/** Creates a {@link ManyToManyMap}. */
|
|
2
|
-
export const createManyToManyMap = () => {
|
|
3
|
-
const forwardMap = new Map();
|
|
4
|
-
const reverseMap = new Map();
|
|
5
|
-
const map = {
|
|
6
|
-
add(key, value) {
|
|
7
|
-
let values = forwardMap.get(key);
|
|
8
|
-
if (!values) {
|
|
9
|
-
values = new Set();
|
|
10
|
-
forwardMap.set(key, values);
|
|
11
|
-
}
|
|
12
|
-
values.add(value);
|
|
13
|
-
let keys = reverseMap.get(value);
|
|
14
|
-
if (!keys) {
|
|
15
|
-
keys = new Set();
|
|
16
|
-
reverseMap.set(value, keys);
|
|
17
|
-
}
|
|
18
|
-
keys.add(key);
|
|
19
|
-
return map;
|
|
20
|
-
},
|
|
21
|
-
remove(key, value) {
|
|
22
|
-
const values = forwardMap.get(key);
|
|
23
|
-
if (!values?.has(value))
|
|
24
|
-
return false;
|
|
25
|
-
values.delete(value);
|
|
26
|
-
if (values.size === 0) {
|
|
27
|
-
forwardMap.delete(key);
|
|
28
|
-
}
|
|
29
|
-
const keys = reverseMap.get(value);
|
|
30
|
-
if (keys?.size) {
|
|
31
|
-
keys.delete(key);
|
|
32
|
-
if (keys.size === 0) {
|
|
33
|
-
reverseMap.delete(value);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return true;
|
|
37
|
-
},
|
|
38
|
-
getValues(key) {
|
|
39
|
-
return forwardMap.get(key);
|
|
40
|
-
},
|
|
41
|
-
getKeys(value) {
|
|
42
|
-
return reverseMap.get(value);
|
|
43
|
-
},
|
|
44
|
-
hasPair(key, value) {
|
|
45
|
-
const values = forwardMap.get(key);
|
|
46
|
-
return values?.has(value) ?? false;
|
|
47
|
-
},
|
|
48
|
-
hasKey(key) {
|
|
49
|
-
return forwardMap.has(key);
|
|
50
|
-
},
|
|
51
|
-
hasValue(value) {
|
|
52
|
-
return reverseMap.has(value);
|
|
53
|
-
},
|
|
54
|
-
deleteKey(key) {
|
|
55
|
-
const values = forwardMap.get(key);
|
|
56
|
-
if (!values)
|
|
57
|
-
return false;
|
|
58
|
-
for (const value of values) {
|
|
59
|
-
const keys = reverseMap.get(value);
|
|
60
|
-
if (keys) {
|
|
61
|
-
keys.delete(key);
|
|
62
|
-
if (keys.size === 0) {
|
|
63
|
-
reverseMap.delete(value);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
forwardMap.delete(key);
|
|
68
|
-
return true;
|
|
69
|
-
},
|
|
70
|
-
deleteValue(value) {
|
|
71
|
-
const keys = reverseMap.get(value);
|
|
72
|
-
if (!keys)
|
|
73
|
-
return false;
|
|
74
|
-
for (const key of keys) {
|
|
75
|
-
const values = forwardMap.get(key);
|
|
76
|
-
if (values) {
|
|
77
|
-
values.delete(value);
|
|
78
|
-
if (values.size === 0) {
|
|
79
|
-
forwardMap.delete(key);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
reverseMap.delete(value);
|
|
84
|
-
return true;
|
|
85
|
-
},
|
|
86
|
-
clear() {
|
|
87
|
-
forwardMap.clear();
|
|
88
|
-
reverseMap.clear();
|
|
89
|
-
},
|
|
90
|
-
};
|
|
91
|
-
return map;
|
|
92
|
-
};
|
package/dist/src/NanoId.d.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Interface representing a NanoId library.
|
|
3
|
-
*
|
|
4
|
-
* It's useful for testing by allowing ID generation to be mocked, ensuring
|
|
5
|
-
* consistent results.
|
|
6
|
-
*
|
|
7
|
-
* @see https://github.com/ai/nanoid
|
|
8
|
-
*
|
|
9
|
-
* ### Example
|
|
10
|
-
*
|
|
11
|
-
* ```ts
|
|
12
|
-
* const foo = createFoo({
|
|
13
|
-
* ...createNanoIdLib(),
|
|
14
|
-
* ...createTime(),
|
|
15
|
-
* });
|
|
16
|
-
* ```
|
|
17
|
-
*/
|
|
18
|
-
export interface NanoIdLib {
|
|
19
|
-
readonly urlAlphabet: string;
|
|
20
|
-
readonly customAlphabet: (alphabet: string, defaultSize?: number) => (size?: number) => string;
|
|
21
|
-
readonly nanoid: (size?: number) => string;
|
|
22
|
-
}
|
|
23
|
-
export interface NanoIdLibDep {
|
|
24
|
-
readonly nanoIdLib: NanoIdLib;
|
|
25
|
-
}
|
|
26
|
-
export declare const createNanoIdLib: () => NanoIdLib;
|
|
27
|
-
//# sourceMappingURL=NanoId.d.ts.map
|
package/dist/src/NanoId.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"NanoId.d.ts","sourceRoot":"","sources":["../../src/NanoId.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAE7B,QAAQ,CAAC,cAAc,EAAE,CACvB,QAAQ,EAAE,MAAM,EAChB,WAAW,CAAC,EAAE,MAAM,KACjB,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;IAE/B,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,KAAK,MAAM,CAAC;CAC5C;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;CAC/B;AAED,eAAO,MAAM,eAAe,QAAO,SAIjC,CAAC"}
|