@evolu/common 6.0.1-preview.29 → 6.0.1-preview.30

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 (66) hide show
  1. package/dist/src/Buffer.js +7 -6
  2. package/dist/src/Callbacks.d.ts +53 -0
  3. package/dist/src/Callbacks.d.ts.map +1 -0
  4. package/dist/src/Callbacks.js +25 -0
  5. package/dist/src/Crypto.js +3 -3
  6. package/dist/src/Evolu/Db.d.ts +1 -1
  7. package/dist/src/Evolu/Db.d.ts.map +1 -1
  8. package/dist/src/Evolu/Evolu.d.ts.map +1 -1
  9. package/dist/src/Evolu/Evolu.js +12 -12
  10. package/dist/src/Evolu/Owner.d.ts +1 -1
  11. package/dist/src/Evolu/Owner.d.ts.map +1 -1
  12. package/dist/src/Evolu/Owner.js +2 -2
  13. package/dist/src/Evolu/Protocol.d.ts +12 -12
  14. package/dist/src/Evolu/Protocol.d.ts.map +1 -1
  15. package/dist/src/Evolu/Protocol.js +30 -27
  16. package/dist/src/Evolu/Relay.d.ts +4 -3
  17. package/dist/src/Evolu/Relay.d.ts.map +1 -1
  18. package/dist/src/Evolu/Relay.js +6 -8
  19. package/dist/src/Evolu/Storage.d.ts +7 -8
  20. package/dist/src/Evolu/Storage.d.ts.map +1 -1
  21. package/dist/src/Evolu/Storage.js +5 -5
  22. package/dist/src/Evolu/Sync.d.ts.map +1 -1
  23. package/dist/src/Evolu/Sync.js +4 -3
  24. package/dist/src/Evolu/Timestamp.d.ts +1 -0
  25. package/dist/src/Evolu/Timestamp.d.ts.map +1 -1
  26. package/dist/src/Evolu/Timestamp.js +1 -0
  27. package/dist/src/Instances.d.ts +1 -1
  28. package/dist/src/Instances.d.ts.map +1 -1
  29. package/dist/src/Instances.js +1 -1
  30. package/dist/src/Number.d.ts +2 -2
  31. package/dist/src/Number.d.ts.map +1 -1
  32. package/dist/src/Number.js +5 -4
  33. package/dist/src/{RefCountedResourceManager.d.ts → Resources.d.ts} +14 -15
  34. package/dist/src/Resources.d.ts.map +1 -0
  35. package/dist/src/{RefCountedResourceManager.js → Resources.js} +24 -24
  36. package/dist/src/Result.d.ts +1 -1
  37. package/dist/src/Skiplist.js +2 -1
  38. package/dist/src/Task.js +3 -3
  39. package/dist/src/Time.js +2 -2
  40. package/dist/src/index.d.ts +2 -1
  41. package/dist/src/index.d.ts.map +1 -1
  42. package/dist/src/index.js +2 -1
  43. package/package.json +1 -1
  44. package/src/Buffer.ts +6 -6
  45. package/src/{CallbackRegistry.ts → Callbacks.ts} +28 -29
  46. package/src/Crypto.ts +3 -3
  47. package/src/Evolu/Db.ts +1 -1
  48. package/src/Evolu/Evolu.ts +12 -16
  49. package/src/Evolu/Owner.ts +1 -1
  50. package/src/Evolu/Protocol.ts +32 -26
  51. package/src/Evolu/Relay.ts +13 -14
  52. package/src/Evolu/Storage.ts +10 -11
  53. package/src/Evolu/Sync.ts +4 -3
  54. package/src/Evolu/Timestamp.ts +1 -0
  55. package/src/Instances.ts +1 -1
  56. package/src/Number.ts +4 -4
  57. package/src/{RefCountedResourceManager.ts → Resources.ts} +29 -30
  58. package/src/Result.ts +1 -1
  59. package/src/Skiplist.ts +1 -1
  60. package/src/Task.ts +2 -2
  61. package/src/Time.ts +1 -1
  62. package/src/index.ts +2 -1
  63. package/dist/src/CallbackRegistry.d.ts +0 -53
  64. package/dist/src/CallbackRegistry.d.ts.map +0 -1
  65. package/dist/src/CallbackRegistry.js +0 -25
  66. package/dist/src/RefCountedResourceManager.d.ts.map +0 -1
@@ -4,10 +4,9 @@ import { PositiveInt } from "./Type.js";
4
4
  /**
5
5
  * A generic resource manager that handles reference counting and delayed
6
6
  * disposal of shared resources. Useful for managing expensive resources like
7
- * WebSocket connections, database connections, or file handles that need to be
8
- * shared among multiple consumers.
7
+ * WebSocket connections that need to be shared among multiple consumers.
9
8
  */
10
- export interface RefCountedResourceManager<
9
+ export interface Resources<
11
10
  TResource extends Disposable,
12
11
  TResourceKey extends string,
13
12
  TResourceConfig,
@@ -73,7 +72,7 @@ export interface ConsumerNotFoundError<
73
72
  readonly resourceKey: TResourceKey;
74
73
  }
75
74
 
76
- export interface ResourceManagerConfig<
75
+ export interface ResourcesConfig<
77
76
  TResource extends Disposable,
78
77
  TResourceKey extends string,
79
78
  TResourceConfig,
@@ -118,16 +117,16 @@ export interface ResourceManagerConfig<
118
117
  }
119
118
 
120
119
  /**
121
- * Creates a reference-counted resource manager.
120
+ * Creates {@link Resources}.
122
121
  *
123
- * This manager tracks which consumers are using which resources and maintains
124
- * reference counts to know when it's safe to dispose resources. Resources are
125
- * created on-demand and disposed with a configurable delay to avoid churn.
122
+ * This tracks which consumers are using which resources and maintains reference
123
+ * counts to know when it's safe to dispose resources. Resources are created
124
+ * on-demand and disposed with a configurable delay to avoid churn.
126
125
  *
127
126
  * ### Example Usage
128
127
  *
129
128
  * ```ts
130
- * // WebSocket connections manager
129
+ * // WebSocket connections
131
130
  * interface WebSocketConfig {
132
131
  * readonly url: WebSocketUrl;
133
132
  * }
@@ -135,7 +134,7 @@ export interface ResourceManagerConfig<
135
134
  * type WebSocketUrl = string & Brand<"WebSocketUrl">;
136
135
  * type UserId = string & Brand<"UserId">;
137
136
  *
138
- * const wsManager = createRefCountedResourceManager<
137
+ * const webSockets = createResources<
139
138
  * WebSocket,
140
139
  * WebSocketUrl,
141
140
  * WebSocketConfig,
@@ -149,16 +148,16 @@ export interface ResourceManagerConfig<
149
148
  * });
150
149
  *
151
150
  * // Add users to WebSocket connections
152
- * wsManager.addConsumer(user1, [
151
+ * webSockets.addConsumer(user1, [
153
152
  * { url: "ws://server1.com" as WebSocketUrl },
154
153
  * { url: "ws://server2.com" as WebSocketUrl },
155
154
  * ]);
156
- * wsManager.addConsumer(user2, [
155
+ * webSockets.addConsumer(user2, [
157
156
  * { url: "ws://server1.com" as WebSocketUrl },
158
157
  * ]);
159
158
  *
160
159
  * // Remove users - server1 stays alive (user2 still using it)
161
- * wsManager.removeConsumer(user1, [
160
+ * webSockets.removeConsumer(user1, [
162
161
  * { url: "ws://server1.com" as WebSocketUrl },
163
162
  * { url: "ws://server2.com" as WebSocketUrl },
164
163
  * ]);
@@ -166,21 +165,21 @@ export interface ResourceManagerConfig<
166
165
  * // server2 gets disposed after delay, server1 stays alive
167
166
  * ```
168
167
  */
169
- export const createRefCountedResourceManager = <
168
+ export const createResources = <
170
169
  TResource extends Disposable,
171
170
  TResourceKey extends string,
172
171
  TResourceConfig,
173
172
  TConsumer,
174
173
  TConsumerId extends string,
175
174
  >(
176
- config: ResourceManagerConfig<
175
+ config: ResourcesConfig<
177
176
  TResource,
178
177
  TResourceKey,
179
178
  TResourceConfig,
180
179
  TConsumer,
181
180
  TConsumerId
182
181
  >,
183
- ): RefCountedResourceManager<
182
+ ): Resources<
184
183
  TResource,
185
184
  TResourceKey,
186
185
  TResourceConfig,
@@ -189,7 +188,7 @@ export const createRefCountedResourceManager = <
189
188
  > => {
190
189
  let isDisposed = false;
191
190
 
192
- const resources = new Map<TResourceKey, TResource>();
191
+ const resourcesMap = new Map<TResourceKey, TResource>();
193
192
  const consumerCounts = new Map<TResourceKey, Map<TConsumerId, PositiveInt>>();
194
193
  const consumers = new Map<TConsumerId, TConsumer>();
195
194
  const disposalTimeouts = new Map<
@@ -207,18 +206,18 @@ export const createRefCountedResourceManager = <
207
206
  disposalTimeouts.delete(key);
208
207
  }
209
208
 
210
- if (!resources.has(key)) {
209
+ if (!resourcesMap.has(key)) {
211
210
  const resource = config.createResource(resourceConfig);
212
- resources.set(key, resource);
211
+ resourcesMap.set(key, resource);
213
212
  }
214
213
  };
215
214
 
216
215
  const scheduleDisposal = (key: TResourceKey): void => {
217
216
  const timeout = setTimeout(() => {
218
- const resource = resources.get(key);
217
+ const resource = resourcesMap.get(key);
219
218
  if (resource) {
220
219
  resource[Symbol.dispose]();
221
- resources.delete(key);
220
+ resourcesMap.delete(key);
222
221
  }
223
222
  disposalTimeouts.delete(key);
224
223
  }, disposalDelay);
@@ -226,7 +225,7 @@ export const createRefCountedResourceManager = <
226
225
  disposalTimeouts.set(key, timeout);
227
226
  };
228
227
 
229
- const manager: RefCountedResourceManager<
228
+ const resources: Resources<
230
229
  TResource,
231
230
  TResourceKey,
232
231
  TResourceConfig,
@@ -257,7 +256,7 @@ export const createRefCountedResourceManager = <
257
256
 
258
257
  // Call onConsumerAdded callback only when consumer is added for the first time (0 -> 1)
259
258
  if (currentCount === 0 && config.onConsumerAdded) {
260
- const resource = resources.get(resourceKey);
259
+ const resource = resourcesMap.get(resourceKey);
261
260
  if (resource) {
262
261
  config.onConsumerAdded(consumer, resource, resourceKey);
263
262
  }
@@ -291,7 +290,7 @@ export const createRefCountedResourceManager = <
291
290
 
292
291
  // Call onConsumerRemoved callback only when consumer is completely removed (1 -> 0)
293
292
  if (config.onConsumerRemoved) {
294
- const resource = resources.get(key);
293
+ const resource = resourcesMap.get(key);
295
294
  if (resource) {
296
295
  config.onConsumerRemoved(consumer, resource, key);
297
296
  }
@@ -306,7 +305,7 @@ export const createRefCountedResourceManager = <
306
305
  }
307
306
  }
308
307
 
309
- if (!manager.hasConsumerAnyResource(consumer)) {
308
+ if (!resources.hasConsumerAnyResource(consumer)) {
310
309
  consumers.delete(consumerId);
311
310
  }
312
311
 
@@ -315,7 +314,7 @@ export const createRefCountedResourceManager = <
315
314
 
316
315
  getResource: (key) => {
317
316
  if (isDisposed) return null;
318
- return resources.get(key) ?? null;
317
+ return resourcesMap.get(key) ?? null;
319
318
  },
320
319
 
321
320
  getConsumersForResource: (key) => {
@@ -339,7 +338,7 @@ export const createRefCountedResourceManager = <
339
338
  if (!consumer) return null;
340
339
 
341
340
  // Only return consumer if it's currently using any resources
342
- if (!manager.hasConsumerAnyResource(consumer)) {
341
+ if (!resources.hasConsumerAnyResource(consumer)) {
343
342
  return null;
344
343
  }
345
344
 
@@ -355,14 +354,14 @@ export const createRefCountedResourceManager = <
355
354
  }
356
355
  disposalTimeouts.clear();
357
356
 
358
- for (const resource of resources.values()) {
357
+ for (const resource of resourcesMap.values()) {
359
358
  resource[Symbol.dispose]();
360
359
  }
361
- resources.clear();
360
+ resourcesMap.clear();
362
361
  consumerCounts.clear();
363
362
  consumers.clear();
364
363
  },
365
364
  };
366
365
 
367
- return manager;
366
+ return resources;
368
367
  };
package/src/Result.ts CHANGED
@@ -287,7 +287,7 @@
287
287
  *
288
288
  * ```ts
289
289
  * for (const query of [
290
- * sql`drop table evolu_owner;`,
290
+ * sql`drop table evolu_config;`,
291
291
  * sql`drop table evolu_message;`,
292
292
  * ]) {
293
293
  * const result = deps.sqlite.exec(query);
package/src/Skiplist.ts CHANGED
@@ -25,7 +25,7 @@ export const createSkiplistLevel =
25
25
  while (deps.random.next() <= probability && level < maxLevel) {
26
26
  level += 1;
27
27
  }
28
- return level as PositiveInt;
28
+ return PositiveInt.orThrow(level);
29
29
  },
30
30
  };
31
31
  };
package/src/Task.ts CHANGED
@@ -577,7 +577,7 @@ export const retry = <T, E>(
577
577
  }
578
578
 
579
579
  // Wait before retry
580
- const delayResult = await wait(delay as NonNegativeInt)(context);
580
+ const delayResult = await wait(NonNegativeInt.orThrow(delay))(context);
581
581
  if (!delayResult.ok) {
582
582
  // If delay was aborted, return AbortError (will be handled by toTask)
583
583
  return delayResult;
@@ -770,7 +770,7 @@ export interface Mutex extends Disposable {
770
770
  * ```
771
771
  */
772
772
  export const createMutex = (): Mutex => {
773
- const mutex = createSemaphore(1 as PositiveInt);
773
+ const mutex = createSemaphore(PositiveInt.orThrow(1));
774
774
 
775
775
  return {
776
776
  withLock: mutex.withPermit,
package/src/Time.ts CHANGED
@@ -207,5 +207,5 @@ export const durationToNonNegativeInt = (
207
207
  total += value * units[unit as keyof typeof units];
208
208
  }
209
209
 
210
- return total as NonNegativeInt;
210
+ return NonNegativeInt.orThrow(total);
211
211
  };
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@ export * from "./BigInt.js";
4
4
  export * from "./Brand.js";
5
5
  export * from "./Buffer.js";
6
6
  export * from "./Cache.js";
7
- export * from "./CallbackRegistry.js";
7
+ export * from "./Callbacks.js";
8
8
  export * from "./Console.js";
9
9
  export * from "./Crypto.js";
10
10
  export * from "./Eq.js";
@@ -20,6 +20,7 @@ export * from "./Order.js";
20
20
  export * from "./Platform.js";
21
21
  export * from "./Random.js";
22
22
  export * from "./Ref.js";
23
+ export * from "./Resources.js";
23
24
  export * from "./Result.js";
24
25
  export * from "./Sqlite.js";
25
26
  export * from "./Store.js";
@@ -1,53 +0,0 @@
1
- import { Brand } from "./Brand.js";
2
- import { RandomBytesDep } from "./Crypto.js";
3
- import { Id } from "./Type.js";
4
- /**
5
- * A registry for one-time callback functions.
6
- *
7
- * Stores callbacks with unique IDs and executes them once with an optional
8
- * argument. Executed callbacks are automatically removed from the registry.
9
- *
10
- * This is useful for correlating asynchronous operations across boundaries
11
- * where callback functions cannot be passed directly (e.g., web workers).
12
- *
13
- * The `execute` method intentionally does not use try-catch or {@link Result}
14
- * because it's the callback's responsibility to handle its own errors. The
15
- * registry is just a correlation mechanism and should not interfere with error
16
- * handling or debugging by masking the original error location.
17
- *
18
- * ### Example
19
- *
20
- * ```ts
21
- * // No-argument callbacks
22
- * const registry = createCallbackRegistry(deps);
23
- * const id = registry.register(() => console.log("called"));
24
- * registry.execute(id);
25
- *
26
- * // With argument callbacks
27
- * const stringRegistry = createCallbackRegistry<string>(deps);
28
- * const id = stringRegistry.register((value) => {
29
- * console.log(value);
30
- * });
31
- * stringRegistry.execute(id, "hello");
32
- *
33
- * // Promise.withResolvers pattern
34
- * const promiseRegistry = createCallbackRegistry<string>(deps);
35
- * const { promise, resolve } = Promise.withResolvers<string>();
36
- * const id = promiseRegistry.register(resolve);
37
- * promiseRegistry.execute(id, "resolved value");
38
- * await promise; // "resolved value"
39
- * ```
40
- *
41
- * @template T - The type of argument passed to callbacks (defaults to undefined
42
- * for no-argument callbacks)
43
- */
44
- export interface CallbackRegistry<T = undefined> {
45
- /** Registers a callback function and returns a unique ID. */
46
- readonly register: (callback: (arg: T) => void) => CallbackId;
47
- /** Executes and removes a callback associated with the given ID. */
48
- readonly execute: T extends undefined ? (id: CallbackId) => undefined : (id: CallbackId, arg: T) => undefined;
49
- }
50
- export type CallbackId = Id & Brand<"Callback">;
51
- /** Creates a new {@link CallbackRegistry} for one-time callback functions. */
52
- export declare const createCallbackRegistry: <T = undefined>(deps: RandomBytesDep) => CallbackRegistry<T>;
53
- //# sourceMappingURL=CallbackRegistry.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CallbackRegistry.d.ts","sourceRoot":"","sources":["../../src/CallbackRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,OAAO,EAAY,EAAE,EAAE,MAAM,WAAW,CAAC;AAEzC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,WAAW,gBAAgB,CAAC,CAAC,GAAG,SAAS;IAC7C,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,IAAI,KAAK,UAAU,CAAC;IAE9D,oEAAoE;IACpE,QAAQ,CAAC,OAAO,EAAE,CAAC,SAAS,SAAS,GACjC,CAAC,EAAE,EAAE,UAAU,KAAK,SAAS,GAC7B,CAAC,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,CAAC,KAAK,SAAS,CAAC;CAC3C;AAED,MAAM,MAAM,UAAU,GAAG,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC;AAEhD,8EAA8E;AAC9E,eAAO,MAAM,sBAAsB,GAAI,CAAC,GAAG,SAAS,EAClD,MAAM,cAAc,KACnB,gBAAgB,CAAC,CAAC,CAuBpB,CAAC"}
@@ -1,25 +0,0 @@
1
- import { createId } from "./Type.js";
2
- /** Creates a new {@link CallbackRegistry} for one-time callback functions. */
3
- export const createCallbackRegistry = (deps) => {
4
- const callbackMap = new Map();
5
- return {
6
- register: (callback) => {
7
- const id = createId(deps);
8
- callbackMap.set(id, callback);
9
- return id;
10
- },
11
- execute: (id, ...args) => {
12
- const callback = callbackMap.get(id);
13
- if (callback) {
14
- callbackMap.delete(id);
15
- if (args.length === 0) {
16
- // Called without argument (undefined case)
17
- callback();
18
- }
19
- else {
20
- callback(args[0]);
21
- }
22
- }
23
- },
24
- };
25
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"RefCountedResourceManager.d.ts","sourceRoot":"","sources":["../../src/RefCountedResourceManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAW,MAAM,EAAE,MAAM,aAAa,CAAC;AAG9C;;;;;GAKG;AACH,MAAM,WAAW,yBAAyB,CACxC,SAAS,SAAS,UAAU,EAC5B,YAAY,SAAS,MAAM,EAC3B,eAAe,EACf,SAAS,EACT,WAAW,SAAS,MAAM,CAC1B,SAAQ,UAAU;IAClB;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,CACpB,QAAQ,EAAE,SAAS,EACnB,eAAe,EAAE,aAAa,CAAC,eAAe,CAAC,KAC5C,IAAI,CAAC;IAEV;;;;;;OAMG;IACH,QAAQ,CAAC,cAAc,EAAE,CACvB,QAAQ,EAAE,SAAS,EACnB,eAAe,EAAE,aAAa,CAAC,eAAe,CAAC,KAC5C,MAAM,CACT,IAAI,EACF,qBAAqB,CAAC,YAAY,CAAC,GACnC,qBAAqB,CAAC,WAAW,EAAE,YAAY,CAAC,CACnD,CAAC;IAEF,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,SAAS,GAAG,IAAI,CAAC;IAE9D,wEAAwE;IACxE,QAAQ,CAAC,uBAAuB,EAAE,CAChC,GAAG,EAAE,YAAY,KACd,aAAa,CAAC,WAAW,CAAC,CAAC;IAEhC,6DAA6D;IAC7D,QAAQ,CAAC,sBAAsB,EAAE,CAAC,QAAQ,EAAE,SAAS,KAAK,OAAO,CAAC;IAElE;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,CAAC,UAAU,EAAE,WAAW,KAAK,SAAS,GAAG,IAAI,CAAC;CACrE;AAED,iFAAiF;AACjF,MAAM,WAAW,qBAAqB,CAAC,YAAY,SAAS,MAAM,GAAG,MAAM;IACzE,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;IACvC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC;CACpC;AAED,8EAA8E;AAC9E,MAAM,WAAW,qBAAqB,CACpC,WAAW,SAAS,MAAM,GAAG,MAAM,EACnC,YAAY,SAAS,MAAM,GAAG,MAAM;IAEpC,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;IACvC,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC;CACpC;AAED,MAAM,WAAW,qBAAqB,CACpC,SAAS,SAAS,UAAU,EAC5B,YAAY,SAAS,MAAM,EAC3B,eAAe,EACf,SAAS,EACT,WAAW,SAAS,MAAM;IAE1B,mDAAmD;IACnD,QAAQ,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,SAAS,CAAC;IAEhE,sEAAsE;IACtE,QAAQ,CAAC,cAAc,EAAE,CAAC,MAAM,EAAE,eAAe,KAAK,YAAY,CAAC;IAEnE,2EAA2E;IAC3E,QAAQ,CAAC,aAAa,EAAE,CAAC,QAAQ,EAAE,SAAS,KAAK,WAAW,CAAC;IAE7D;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAEhC;;;;OAIG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,CACzB,QAAQ,EAAE,SAAS,EACnB,QAAQ,EAAE,SAAS,EACnB,WAAW,EAAE,YAAY,KACtB,IAAI,CAAC;IAEV;;;OAGG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,CAC3B,QAAQ,EAAE,SAAS,EACnB,QAAQ,EAAE,SAAS,EACnB,WAAW,EAAE,YAAY,KACtB,IAAI,CAAC;CACX;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AACH,eAAO,MAAM,+BAA+B,GAC1C,SAAS,SAAS,UAAU,EAC5B,YAAY,SAAS,MAAM,EAC3B,eAAe,EACf,SAAS,EACT,WAAW,SAAS,MAAM,EAE1B,QAAQ,qBAAqB,CAC3B,SAAS,EACT,YAAY,EACZ,eAAe,EACf,SAAS,EACT,WAAW,CACZ,KACA,yBAAyB,CAC1B,SAAS,EACT,YAAY,EACZ,eAAe,EACf,SAAS,EACT,WAAW,CAoLZ,CAAC"}