@ewhauser/world-celld 0.1.1 → 0.2.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/dist/worker.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { CreateEventRequest, Event, Hook, RunCreatedEventRequest, Step, ValidQueueName, WorkflowRun } from "@workflow/world";
1
+ import { CreateEventRequest, Event, Hook, RunCreatedEventRequest, Step, TerminalWorkflowRunStatus, ValidQueueName, WorkflowRun } from "@workflow/world";
2
2
  //#region src/worker/router.d.ts
3
3
  /** Minimal structural DO namespace type (celld provides the real thing). */
4
4
  interface DONamespaceLike {
@@ -18,6 +18,71 @@ interface WorkerEnv {
18
18
  }
19
19
  declare function createRouter(env: WorkerEnv): (request: Request) => Promise<Response>;
20
20
  //#endregion
21
+ //#region src/retention.d.ts
22
+ type CleanupPhase = 'retained' | 'index' | 'streams' | 'queues' | 'payload' | 'tombstoned';
23
+ interface CleanupRecord {
24
+ version: 1;
25
+ runId: string;
26
+ workflowName: string;
27
+ createdAt: Date;
28
+ completedAt: Date;
29
+ terminalStatus: TerminalWorkflowRunStatus;
30
+ dueAt: Date;
31
+ queueShards: number;
32
+ phase: CleanupPhase;
33
+ attempts: number;
34
+ lastError?: string;
35
+ lastAttemptAt?: Date;
36
+ tombstonedAt?: Date;
37
+ deletedPayloadKeys: number;
38
+ deletedStreams: number;
39
+ deletedQueueMessages: number;
40
+ }
41
+ interface RunTombstone {
42
+ version: 1;
43
+ runId: string;
44
+ terminalStatus: TerminalWorkflowRunStatus;
45
+ completedAt: Date;
46
+ expiredAt: Date;
47
+ tombstonedAt: Date;
48
+ }
49
+ type RunReadOutcome<T> = {
50
+ ok: true;
51
+ value: T;
52
+ } | {
53
+ ok: false;
54
+ code: 'RUN_EXPIRED';
55
+ message: string;
56
+ tombstone: RunTombstone;
57
+ };
58
+ interface HookIndexReference {
59
+ hookId: string;
60
+ token: string;
61
+ }
62
+ interface ExpireRunIndexesRequest {
63
+ runId: string;
64
+ keys: string[];
65
+ hooks: HookIndexReference[];
66
+ expiredAt: number;
67
+ }
68
+ interface ExpireRunIndexesResult {
69
+ deleted: number;
70
+ }
71
+ interface ExpireRunStreamsResult {
72
+ streams: string[];
73
+ }
74
+ interface ExpireStreamResult {
75
+ deleted: boolean;
76
+ chunks: number;
77
+ }
78
+ interface ExpireQueueRunResult {
79
+ deleted: number;
80
+ }
81
+ interface ScheduleCleanupRequest {
82
+ retentionMs: number;
83
+ queueShards: number;
84
+ }
85
+ //#endregion
21
86
  //#region src/apply-event.d.ts
22
87
  interface ApplyEventRequest {
23
88
  /** The effective run id (already resolved / generated by the caller). */
@@ -31,6 +96,8 @@ interface ApplyEventRequest {
31
96
  runId: string;
32
97
  hookId: string;
33
98
  } | null;
99
+ /** Internal world-celld retention policy captured with the event. */
100
+ cleanup?: ScheduleCleanupRequest;
34
101
  }
35
102
  type ApplyEventErrorCode = 'RUN_NOT_FOUND' | 'STEP_NOT_FOUND' | 'HOOK_NOT_FOUND' | 'ENTITY_CONFLICT' | 'RUN_EXPIRED' | 'TOO_EARLY' | 'RUN_NOT_SUPPORTED' | 'LEGACY_RUN_NOT_SUPPORTED';
36
103
  interface ApplyEventFailure {
@@ -79,6 +146,8 @@ interface EnqueueRequest {
79
146
  pathname: Pathname;
80
147
  /** `stringify(message)` — the exact bytes POSTed to the app on delivery. */
81
148
  body: string;
149
+ /** Owning workflow run; absent only for health-check messages. */
150
+ runId?: string;
82
151
  idempotencyKey?: string;
83
152
  delaySeconds?: number;
84
153
  /**
@@ -98,7 +167,7 @@ type EnqueueOutcome = {
98
167
  deduped: boolean;
99
168
  } | {
100
169
  ok: false;
101
- code: 'CONFIG_MISMATCH';
170
+ code: 'CONFIG_MISMATCH' | 'RUN_EXPIRED';
102
171
  message: string;
103
172
  };
104
173
  //#endregion
@@ -141,6 +210,10 @@ declare class DurableObject<TEnv = unknown> {
141
210
  declare class IndexDO extends DurableObject {
142
211
  get(key: string): Promise<string | null>;
143
212
  put(key: string, value: string): Promise<void>;
213
+ /** Publish a derived index only while its owning run is not expired. */
214
+ putOwned(runId: string, key: string, value: string): Promise<{
215
+ stored: boolean;
216
+ }>;
144
217
  delete(key: string): Promise<void>;
145
218
  list(options?: {
146
219
  prefix?: string;
@@ -161,6 +234,12 @@ declare class IndexDO extends DurableObject {
161
234
  finalizeHookIndexes(token: string, hookId: string, serializedHook: string, owner: HookTokenOwner): Promise<void>;
162
235
  releaseHookToken(token: string, owner: HookTokenOwner): Promise<void>;
163
236
  deleteHookIndexes(token: string, hookId: string, owner: HookTokenOwner): Promise<void>;
237
+ /**
238
+ * Fence a run and remove all of its known derived indexes atomically.
239
+ * Once the fence exists, putOwned() and hook finalization cannot resurrect
240
+ * entries from a delayed request.
241
+ */
242
+ expireRun(request: ExpireRunIndexesRequest): Promise<ExpireRunIndexesResult>;
164
243
  }
165
244
  //#endregion
166
245
  //#region src/worker/durable-objects/QueueDO.d.ts
@@ -179,6 +258,8 @@ declare class IndexDO extends DurableObject {
179
258
  * inflight:<messageId> crash-recovery deadline (epoch ms)
180
259
  * key:<idempotencyKey> active dedup claim -> messageId
181
260
  * dlq:<paddedMs>:<messageId> DeadLetterRow
261
+ * run:<runId>:<messageId> QueueRunReference for retention cleanup
262
+ * expired-run:<runId> run fence preventing delayed enqueue
182
263
  *
183
264
  * celld gotchas designed around:
184
265
  * - celld#144 (alarm handlers can overlap): the storage-only claim phase runs
@@ -196,6 +277,7 @@ interface MessageRow {
196
277
  pathname: 'flow' | 'step';
197
278
  /** Pre-encoded tagged-JSON payload — forwarded byte-identical. */
198
279
  body: string;
280
+ runId?: string;
199
281
  /**
200
282
  * Delivery target captured at enqueue time. Carried per message (not
201
283
  * pinned on the cell) so an app redeploy at a new URL never bricks the
@@ -245,6 +327,8 @@ declare class QueueDO extends DurableObject {
245
327
  rearmAlarm(): Promise<{
246
328
  alarmAt: number | null;
247
329
  }>;
330
+ /** Fence a run and purge every live, inflight, and dead-letter message it owns. */
331
+ expireRun(runId: string, expiredAt: number): Promise<ExpireQueueRunResult>;
248
332
  }
249
333
  //#endregion
250
334
  //#region src/worker/durable-objects/StreamDO.d.ts
@@ -260,16 +344,17 @@ declare class QueueDO extends DurableObject {
260
344
  */
261
345
  declare class StreamDO extends DurableObject {
262
346
  private getMeta;
347
+ private assertOwner;
263
348
  /**
264
349
  * Append a chunk. The index is allocated inside the transaction, so
265
350
  * concurrent writers can never collide or skip.
266
351
  */
267
- writeChunk(data: Uint8Array): Promise<number>;
352
+ writeChunk(runId: string, data: Uint8Array): Promise<number>;
268
353
  /**
269
354
  * Close the stream (idempotent). Readers observe `done: true` once all
270
355
  * previously written chunks have been consumed.
271
356
  */
272
- closeStream(): Promise<void>;
357
+ closeStream(runId: string): Promise<void>;
273
358
  /**
274
359
  * Read up to `limit` chunks starting at `startIndex` (0-based, inclusive).
275
360
  */
@@ -293,11 +378,17 @@ declare class StreamDO extends DurableObject {
293
378
  /**
294
379
  * Register a stream name against this per-run registry instance.
295
380
  */
296
- registerStream(name: string): Promise<void>;
381
+ registerStream(runId: string, name: string): Promise<void>;
297
382
  /**
298
383
  * List stream names registered against this per-run registry instance.
299
384
  */
300
385
  listStreams(): Promise<string[]>;
386
+ /** Fence a run's registry before any stream cells are removed. */
387
+ expireRegistry(runId: string, expiredAt: number): Promise<ExpireRunStreamsResult>;
388
+ /** Remove the registry payload after every referenced stream was fenced. */
389
+ finalizeRegistry(runId: string): Promise<void>;
390
+ /** Delete stream payload while leaving a small ownership tombstone. */
391
+ expireStream(runId: string, expiredAt: number): Promise<ExpireStreamResult>;
301
392
  }
302
393
  //#endregion
303
394
  //#region src/worker/durable-objects/WorkflowRunDO.d.ts
@@ -313,87 +404,59 @@ declare class StreamDO extends DurableObject {
313
404
  */
314
405
  declare class WorkflowRunDO extends DurableObject {
315
406
  private schemaReady;
316
- /**
317
- * Lazily ensure schema migrations have run.
318
- * Memoized so it only runs once per DO instantiation.
319
- */
407
+ private now;
320
408
  private ensureSchema;
321
- /**
322
- * Apply an event: validate, guard, append the event and mutate the entity
323
- * in ONE storage transaction. Guard failures are returned as structured
324
- * outcomes (not thrown) because typed errors do not survive the RPC
325
- * boundary with their `name` intact.
326
- */
409
+ private expiredTombstone;
410
+ private read;
411
+ /** Apply an event and capture all retention metadata in the same transaction. */
327
412
  applyEvent(request: ApplyEventRequest): Promise<ApplyEventOutcome>;
328
- /**
329
- * Get the workflow run
330
- */
331
- getRun(): Promise<WorkflowRun | null>;
332
- /**
333
- * Get a specific step
334
- */
335
- getStep(stepId: string): Promise<Step | null>;
336
- /**
337
- * List steps with real limit/cursor pagination (cursor = last stepId).
338
- */
413
+ getRun(): Promise<RunReadOutcome<WorkflowRun | null>>;
414
+ getStep(stepId: string): Promise<RunReadOutcome<Step | null>>;
339
415
  listSteps(params?: {
340
416
  limit?: number;
341
417
  cursor?: string;
342
418
  sortOrder?: 'asc' | 'desc';
343
- }): Promise<{
419
+ }): Promise<RunReadOutcome<{
344
420
  data: Step[];
345
421
  cursor: string | null;
346
422
  hasMore: boolean;
347
- }>;
348
- /**
349
- * Get a specific event
350
- */
351
- getEvent(eventId: string): Promise<Event | null>;
352
- /**
353
- * List events with real limit/cursor pagination. Events are keyed by their
354
- * monotonic ULID eventId, so storage order == event order.
355
- */
423
+ }>>;
424
+ getEvent(eventId: string): Promise<RunReadOutcome<Event | null>>;
356
425
  listEvents(params?: {
357
426
  limit?: number;
358
427
  cursor?: string;
359
428
  sortOrder?: 'asc' | 'desc';
360
- }): Promise<{
429
+ }): Promise<RunReadOutcome<{
361
430
  data: Event[];
362
431
  cursor: string | null;
363
432
  hasMore: boolean;
364
- }>;
365
- /**
366
- * List hooks with real limit/cursor pagination (cursor = last hookId).
367
- */
433
+ }>>;
368
434
  listHooks(params?: {
369
435
  limit?: number;
370
436
  cursor?: string;
371
437
  sortOrder?: 'asc' | 'desc';
372
- }): Promise<{
438
+ }): Promise<RunReadOutcome<{
373
439
  data: Hook[];
374
440
  cursor: string | null;
375
441
  hasMore: boolean;
376
- }>;
377
- /**
378
- * Claim a queue-message dedup slot. Used on DO instances dedicated to a
379
- * single idempotency key (`claim:<queueName>:<idempotencyKey>`).
380
- *
381
- * - Unclaimed -> claim and proceed.
382
- * - Claimed by the SAME messageId -> redelivery of the same message
383
- * (previous attempt failed transiently) -> proceed.
384
- * - Claimed by a DIFFERENT messageId -> concurrent duplicate -> reject,
385
- * unless the claim is stale (holder crashed / went to the DLQ without
386
- * releasing), in which case the claim is stolen.
387
- */
442
+ }>>;
443
+ getCleanupStatus(): Promise<CleanupRecord | null>;
444
+ /** Explicitly schedule an existing terminal run, used for opt-in backfills. */
445
+ scheduleCleanup(request: ScheduleCleanupRequest): Promise<CleanupRecord | null>;
446
+ cleanupNow(request: ScheduleCleanupRequest): Promise<CleanupRecord | null>;
447
+ rearmCleanup(): Promise<CleanupRecord | null>;
448
+ alarm(): Promise<void>;
449
+ private namespace;
450
+ private setCleanupPhase;
451
+ private executeCleanup;
452
+ private deletePayloadBatch;
453
+ private recordCleanupFailure;
388
454
  claimInflight(params: {
389
455
  messageId: string;
390
456
  staleMs: number;
391
457
  }): Promise<{
392
458
  claimed: boolean;
393
459
  }>;
394
- /**
395
- * Release a queue-message dedup claim after the message was fully handled.
396
- */
397
460
  releaseInflight(): Promise<void>;
398
461
  }
399
462
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","names":[],"sources":["../src/worker/router.ts","../src/apply-event.ts","../src/queue.ts","../src/config.ts","../src/worker/do-base.ts","../src/worker/durable-objects/IndexDO.ts","../src/worker/durable-objects/QueueDO.ts","../src/worker/durable-objects/StreamDO.ts","../src/worker/durable-objects/WorkflowRunDO.ts","../src/worker/worker.ts"],"mappings":";;;UAmBiB;EACf,WAAW;IAAiB;;EAC5B,IAAI;IAAM;;;UAGK;EACf,aAAa;EACb,kBAAkB;EAClB,gBAAgB;EAChB,gBAAgB;EAChB;;iBAmFc,aAAa,KAAK,aAClB,SAAS,YAAU,QAAQ;;;UC3B1B;;EAEf;EACA,MAAM,qBAAqB;;;;;EAK3B;IAAgB;IAAe;;;KAGrB;UAUK;EACf;EACA,MAAM;EACN;;EAEA;;EAEA;;UAGe;EACf;;EAEA,QAAQ;EACR,MAAM;EACN,OAAO;EACP,OAAO;;EAEP,eAAe;IAAQ;IAAgB;;;EAEvC;IAAe;IAAsB,WAAW;;;EAEhD,cAAc;;EAEd,SAAS;;KAGC,oBAAoB,oBAAoB;;;KC/E/C;;;;;;UAoBY;EACf;EACA,WAAW;EACX,UAAU;;EAEV;EACA;EACA;;;;;EAKA,QAAQ;;UAGO;;EAEf;EACA;;KAGU;EACN;EAAU;EAAmB;;EAC7B;EAAW;EAAyB;;;;UCtEzB;EACf;EACA;;;;;;;;;;;;;cCrBW,cAAc;WAEd,KAAK;WACL,KAAK;EADL,YAAA,KAAK,oBACL,KAAK;;;;;;;;;;;;;;;;;cCoBL,gBAAgB;EACrB,IAAI,cAAc;EAKlB,IAAI,aAAa,gBAAgB;EAIjC,OAAO,cAAc;EAIrB,KAAK;IACT;IACA;IACA;IACA;MACE;IACF,MAAM;MAAQ;;IACd;IACA;;EA2BI,iBACJ,eACA,OAAO,iBACN;IAAU;IAAkB,SAAS;;EAmBlC,oBACJ,eACA,gBACA,wBACA,OAAO,iBACN;EAmBG,iBAAiB,eAAe,OAAO,iBAAiB;EAUxD,kBAAkB,eAAe,gBAAgB,OAAO,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UC3GhE;EACf;EACA;EACA;;EAEA;;;;;;;EAOA;EACA;;EAEA;EACA;EACA;;UAGe,sBAAsB;EACrC;;UAGe;EACf;EACA;EACA;EACA;;cAqCW,gBAAgB;;EAoBrB,QAAQ,SAAS,iBAAiB,QAAQ;EA2D1C,SAAS;EA8NT,SAAS,QAAQ;EAgBjB,gBAAgB;IACpB;IACA;MACE;IAAU,MAAM;IAAiB;IAAuB;;;EAkBtD,kBAAkB,oBAAoB;IAAU;;EAkChD,oBAAoB;IAAU;;;;;;EAe9B,cAAc;IAAU;;;;;;;;;;;;;;;cClcnB,iBAAiB;UACd;;;;;EASR,WAAW,MAAM,aAAa;;;;;EAiB9B,eAAe;;;;EAUf,UAAU;IAAU;IAAoB;MAAkB;IAC9D,QAAQ;;IAER;;IAEA;;;;;EAmBI,WAAW;IAAU;IAAmB;;;;;EAQxC,eAAe,eAAe;;;;EAO9B,eAAe;;;;;;;;;;;;;;cCeV,sBAAsB;UACzB;;;;;UAMA;;;;;;;EAaF,WAAW,SAAS,oBAAoB,QAAQ;;;;EAqBhD,UAAU,QAAQ;;;;EASlB,QAAQ,iBAAiB,QAAQ;;;;EASjC,UAAU;IACd;IACA;IACA;MACE;IAAU,MAAM;IAAQ;IAAuB;;;;;EAiB7C,SAAS,kBAAkB,QAAQ;;;;;EAUnC,WAAW;IACf;IACA;IACA;MACE;IAAU,MAAM;IAAS;IAAuB;;;;;EAiB9C,UAAU;IACd;IACA;IACA;MACE;IAAU,MAAM;IAAQ;IAAuB;;;;;;;;;;;;;EAyB7C,cAAc;IAClB;IACA;MACE;IAAU;;;;;EAoBR,mBAAmB;;;;;EChRJ,MAAA,SAAA,SAAO,KAAO,YAAY,QAAQ"}
1
+ {"version":3,"file":"worker.d.ts","names":[],"sources":["../src/worker/router.ts","../src/retention.ts","../src/apply-event.ts","../src/queue.ts","../src/config.ts","../src/worker/do-base.ts","../src/worker/durable-objects/IndexDO.ts","../src/worker/durable-objects/QueueDO.ts","../src/worker/durable-objects/StreamDO.ts","../src/worker/durable-objects/WorkflowRunDO.ts","../src/worker/worker.ts"],"mappings":";;;UAmBiB;EACf,WAAW;IAAiB;;EAC5B,IAAI;IAAM;;;UAGK;EACf,aAAa;EACb,kBAAkB;EAClB,gBAAgB;EAChB,gBAAgB;EAChB;;iBA6Fc,aAAa,KAAK,aAAS,SAClB,YAAU,QAAQ;;;KCpH/B;UAEK;EACf;EACA;EACA;EACA,WAAW;EACX,aAAa;EACb,gBAAgB;EAChB,OAAO;EACP;EACA,OAAO;EACP;EACA;EACA,gBAAgB;EAChB,eAAe;EACf;EACA;EACA;;UAGe;EACf;EACA;EACA,gBAAgB;EAChB,aAAa;EACb,WAAW;EACX,cAAc;;KAGJ,eAAe;EACrB;EAAU,OAAO;;EACjB;EAAW;EAAqB;EAAiB,WAAW;;UAEjD;EACf;EACA;;UAGe;EACf;EACA;EACA,OAAO;EACP;;UAGe;EACf;;UAGe;EACf;;UAGe;EACf;EACA;;UAGe;EACf;;UAGe;EACf;EACA;;;;UCee;;EAEf;EACA,MAAM,qBAAqB;;;;;EAK3B;IAAgB;IAAe;;;EAE/B,UAAU;;KAGA;UAUK;EACf;EACA,MAAM;EACN;;EAEA;;EAEA;;UAGe;EACf;;EAEA,QAAQ;EACR,MAAM;EACN,OAAO;EACP,OAAO;;EAEP,eAAe;IAAQ;IAAgB;;;EAEvC;IAAe;IAAsB,WAAW;;;EAEhD,cAAc;;EAEd,SAAS;;KAGC,oBAAoB,oBAAoB;;;KCjF/C;;;;;;UAoBY;EACf;EACA,WAAW;EACX,UAAU;;EAEV;;EAEA;EACA;EACA;;;;;EAKA,QAAQ;;UAGO;;EAEf;EACA;;KAGU;EACN;EAAU;EAAmB;;EAC7B;EAAW;EAAyC;;;;UCrEzC;EACf;EACA;;;;;;;;;;;;;cCzBW,cAAc;WAEd,KAAK;WACL,KAAK;EAFhB,YACW,KAAK,oBACL,KAAK;;;;;;;;;;;;;;;;;cCqBL,gBAAgB;EACrB,IAAI,cAAc;EAKlB,IAAI,aAAa,gBAAgB;;EAKjC,SAAS,eAAe,aAAa,gBAAgB;IAAU;;EAU/D,OAAO,cAAc;EAIrB,KAAK;IACT;IACA;IACA;IACA;MACE;IACF,MAAM;MAAQ;;IACd;IACA;;EA2BI,iBACJ,eACA,OAAO,iBACN;IAAU;IAAkB,SAAS;;EAmBlC,oBACJ,eACA,gBACA,wBACA,OAAO,iBACN;EA0BG,iBAAiB,eAAe,OAAO,iBAAiB;EAUxD,kBAAkB,eAAe,gBAAgB,OAAO,iBAAiB;;;;;;EA2BzE,UAAU,SAAS,0BAA0B,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UCtJ5C;EACf;EACA;EACA;;EAEA;EACA;;;;;;;EAOA;EACA;;EAEA;EACA;EACA;;UAGe,sBAAsB;EACrC;;UAGe;EACf;EACA;EACA;EACA;;cAyDW,gBAAgB;;EAoBrB,QAAQ,SAAS,iBAAiB,QAAQ;EA2E1C,SAAS;EA4RT,SAAS,QAAQ;EAgBjB,gBAAgB;IACpB;IACA;MACE;IAAU,MAAM;IAAiB;IAAuB;;;EAkBtD,kBAAkB,oBAAoB;IAAU;;EA0ChD,oBAAoB;IAAU;;;;;;EAmB9B,cAAc;IAAU;;;EAMxB,UAAU,eAAe,oBAAoB,QAAQ;;;;;;;;;;;;;;cCrjBhD,iBAAiB;UACd;UAKN;;;;;EAaF,WAAW,eAAe,MAAM,aAAa;;;;;EAsB7C,YAAY,gBAAgB;;;;EAW5B,UAAU;IAAU;IAAoB;MAAkB;IAC9D,QAAQ;;IAER;;IAEA;;;;;EAsBI,WAAW;IAAU;IAAmB;;;;;EAWxC,eAAe,eAAe,eAAe;;;;EAiB7C,eAAe;;EASf,eAAe,eAAe,oBAAoB,QAAQ;;EAgB1D,iBAAiB,gBAAgB;;EAajC,aAAa,eAAe,oBAAoB,QAAQ;;;;;;;;;;;;;;cCCnD,sBAAsB;UACzB;UAEA;UAKA;UAOM;UAWA;;EAQR,WAAW,SAAS,oBAAoB,QAAQ;EA4EhD,UAAU,QAAQ,eAAe;EAIjC,QAAQ,iBAAiB,QAAQ,eAAe;EAMhD,UAAU;IACd;IACA;IACA;MACE,QAAQ;IAAiB,MAAM;IAAQ;IAAuB;;EAe5D,SAAS,kBAAkB,QAAQ,eAAe;EAMlD,WAAW;IACf;IACA;IACA;MACE,QAAQ;IAAiB,MAAM;IAAS;IAAuB;;EAe7D,UAAU;IACd;IACA;IACA;MACE,QAAQ;IAAiB,MAAM;IAAQ;IAAuB;;EAe5D,oBAAoB,QAAQ;;EAM5B,gBAAgB,SAAS,yBAAyB,QAAQ;EAkC1D,WAAW,SAAS,yBAAyB,QAAQ;EAsBrD,gBAAgB,QAAQ;EAYxB,SAAS;UASP;UAQM;UAkBA;UAwFA;UAoCA;EAgBR,cAAc;IAClB;IACA;MACE;IAAU;;EAiBR,mBAAmB;;;;;EC7mBnB,MAAK,SAAU,SAAO,KAAO,YAAY,QAAQ"}