@workglow/storage 0.2.26 → 0.2.27

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 (38) hide show
  1. package/dist/browser.js +218 -12
  2. package/dist/browser.js.map +13 -13
  3. package/dist/bun.js +703 -24
  4. package/dist/bun.js.map +18 -17
  5. package/dist/common-server.d.ts +1 -0
  6. package/dist/common-server.d.ts.map +1 -1
  7. package/dist/node.js +703 -24
  8. package/dist/node.js.map +18 -17
  9. package/dist/queue/IQueueStorage.d.ts +25 -2
  10. package/dist/queue/IQueueStorage.d.ts.map +1 -1
  11. package/dist/queue/InMemoryQueueStorage.d.ts +1 -0
  12. package/dist/queue/InMemoryQueueStorage.d.ts.map +1 -1
  13. package/dist/queue/IndexedDbQueueStorage.d.ts +1 -0
  14. package/dist/queue/IndexedDbQueueStorage.d.ts.map +1 -1
  15. package/dist/queue/PostgresQueueStorage.d.ts +24 -3
  16. package/dist/queue/PostgresQueueStorage.d.ts.map +1 -1
  17. package/dist/queue/SqliteQueueStorage.d.ts +8 -0
  18. package/dist/queue/SqliteQueueStorage.d.ts.map +1 -1
  19. package/dist/queue/SupabaseQueueStorage.d.ts +1 -0
  20. package/dist/queue/SupabaseQueueStorage.d.ts.map +1 -1
  21. package/dist/queue/TelemetryQueueStorage.d.ts +2 -1
  22. package/dist/queue/TelemetryQueueStorage.d.ts.map +1 -1
  23. package/dist/queue-limiter/IRateLimiterStorage.d.ts +46 -0
  24. package/dist/queue-limiter/IRateLimiterStorage.d.ts.map +1 -1
  25. package/dist/queue-limiter/InMemoryRateLimiterStorage.d.ts +12 -1
  26. package/dist/queue-limiter/InMemoryRateLimiterStorage.d.ts.map +1 -1
  27. package/dist/queue-limiter/IndexedDbRateLimiterStorage.d.ts +28 -1
  28. package/dist/queue-limiter/IndexedDbRateLimiterStorage.d.ts.map +1 -1
  29. package/dist/queue-limiter/PostgresRateLimiterStorage.d.ts +4 -1
  30. package/dist/queue-limiter/PostgresRateLimiterStorage.d.ts.map +1 -1
  31. package/dist/queue-limiter/SqliteRateLimiterStorage.d.ts +10 -1
  32. package/dist/queue-limiter/SqliteRateLimiterStorage.d.ts.map +1 -1
  33. package/dist/queue-limiter/SupabaseRateLimiterStorage.d.ts +6 -1
  34. package/dist/queue-limiter/SupabaseRateLimiterStorage.d.ts.map +1 -1
  35. package/dist/tabular/IndexedDbTabularStorage.d.ts.map +1 -1
  36. package/dist/tabular/SharedInMemoryTabularStorage.d.ts +2 -1
  37. package/dist/tabular/SharedInMemoryTabularStorage.d.ts.map +1 -1
  38. package/package.json +3 -3
@@ -18,11 +18,11 @@
18
18
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { JsonSchema } from \"@workglow/util/schema\";\nimport { createServiceToken, EventEmitter, makeFingerprint } from \"@workglow/util\";\nimport { JSONValue } from \"../tabular/ITabularStorage\";\nimport {\n IKvStorage,\n KvEventListener,\n KvEventListeners,\n KvEventName,\n KvEventParameters,\n} from \"./IKvStorage\";\n\nexport const KV_REPOSITORY = createServiceToken<IKvStorage<any, any, any>>(\"storage.kvRepository\");\n\n/**\n * Abstract base class for key-value storage repositories.\n * Has a basic event emitter for listening to repository events.\n *\n * @template Key - The type of the primary key\n * @template Value - The type of the value being stored\n * @template Combined - Combined type of Key & Value\n */\nexport abstract class KvStorage<\n Key extends string = string,\n Value extends any = any,\n Combined = { key: Key; value: Value },\n> implements IKvStorage<Key, Value, Combined> {\n /** Event emitter for repository events */\n protected events = new EventEmitter<KvEventListeners<Key, Value, Combined>>();\n\n /**\n * Creates a new KvStorage instance\n */\n constructor(\n public keySchema: JsonSchema = { type: \"string\" },\n public valueSchema: JsonSchema = {}\n ) {}\n\n /**\n * Stores a row in the repository.\n * @param key - The primary key\n * @param value - The value to store\n */\n abstract put(key: Key, value: Value): Promise<void>;\n\n /**\n * Stores multiple rows in the repository in a bulk operation.\n * @param items - Array of key-value pairs to store\n */\n abstract putBulk(items: Array<{ key: Key; value: Value }>): Promise<void>;\n\n /**\n * Retrieves a value by its key.\n * This is a convenience method that automatically converts simple types to structured format if using default schema.\n *\n * @param key - Primary key to look up (basic key like default schema)\n * @returns The stored value or undefined if not found\n */\n abstract get(key: Key): Promise<Value | undefined>;\n\n /**\n * Deletes a row from the repository.\n * @param key - The primary key of the row to delete\n */\n abstract delete(key: Key): Promise<void>;\n\n /**\n * Retrieves all rows from the repository.\n * @returns An array of all rows in the repository or undefined if empty\n */\n abstract getAll(): Promise<Combined[] | undefined>;\n\n /**\n * Deletes all rows from the repository.\n */\n abstract deleteAll(): Promise<void>;\n\n /**\n * Retrieves the number of rows in the repository.\n * @returns The number of rows in the repository\n */\n abstract size(): Promise<number>;\n\n /**\n * Generates a consistent string identifier for a given key.\n *\n * @param object - Object to convert\n * @returns Promise resolving to a string fingerprint of the object for use as an id\n */\n public async getObjectAsIdString(object: JSONValue): Promise<string> {\n return await makeFingerprint(object);\n }\n\n /**\n * Adds an event listener for a specific event\n * @param name The name of the event to listen for\n * @param fn The callback function to execute when the event occurs\n */\n on<Event extends KvEventName>(name: Event, fn: KvEventListener<Event, Key, Value, Combined>) {\n this.events.on(name, fn);\n }\n\n /**\n * Removes an event listener for a specific event\n * @param name The name of the event to remove the listener from\n * @param fn The callback function to remove\n */\n off<Event extends KvEventName>(name: Event, fn: KvEventListener<Event, Key, Value, Combined>) {\n this.events.off(name, fn);\n }\n\n /**\n * Adds an event listener that will only be called once\n * @param name The name of the event to listen for\n * @param fn The callback function to execute when the event occurs\n */\n once<Event extends KvEventName>(name: Event, fn: KvEventListener<Event, Key, Value, Combined>) {\n this.events.once(name, fn);\n }\n\n /**\n * Emits an event with the specified name and arguments\n * @param name The name of the event to emit\n * @param args The arguments to pass to the event listeners\n */\n emit<Event extends KvEventName>(\n name: Event,\n ...args: KvEventParameters<Event, Key, Value, Combined>\n ) {\n this.events.emit(name, ...args);\n }\n\n /**\n * Returns when the event was emitted (promise form of once)\n * @param name The name of the event to check\n * @returns true if the event has listeners, false otherwise\n */\n waitOn<Event extends KvEventName>(\n name: Event\n ): Promise<KvEventParameters<Event, Key, Value, Combined>> {\n return this.events.waitOn(name) as Promise<KvEventParameters<Event, Key, Value, Combined>>;\n }\n}\n",
19
19
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { BaseTabularStorage } from \"../tabular/BaseTabularStorage\";\nimport { DefaultKeyValueKey, DefaultKeyValueSchema } from \"./IKvStorage\";\nimport { KvStorage } from \"./KvStorage\";\n\n/**\n * Abstract base class for key-value storage repositories that uses a tabular repository for storage.\n * Has a basic event emitter for listening to repository events.\n *\n * @template Key - The type of the primary key\n * @template Value - The type of the value being stored\n * @template Combined - Combined type of Key & Value\n */\n/** Schema types that are stored as-is without JSON serialization */\nconst PRIMITIVE_SCHEMA_TYPES = new Set([\"number\", \"boolean\", \"string\", \"blob\"]);\n\nexport abstract class KvViaTabularStorage<\n Key extends string = string,\n Value extends any = any,\n Combined = { key: Key; value: Value },\n> extends KvStorage<Key, Value, Combined> {\n public abstract tabularRepository: BaseTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >;\n\n /** Whether values need JSON serialization (cached from schema) */\n private get needsJsonSerialization(): boolean {\n if (this._needsJsonSerialization === undefined) {\n const schemaType =\n typeof this.valueSchema === \"object\" &&\n this.valueSchema !== null &&\n \"type\" in this.valueSchema\n ? this.valueSchema.type\n : undefined;\n this._needsJsonSerialization = !PRIMITIVE_SCHEMA_TYPES.has(schemaType as string);\n }\n return this._needsJsonSerialization;\n }\n private _needsJsonSerialization: boolean | undefined;\n\n /**\n * Sets up the database for the repository.\n * Must be called before using any other methods.\n */\n public async setupDatabase(): Promise<void> {\n await this.tabularRepository.setupDatabase?.();\n }\n\n /**\n * Stores a row in the repository.\n * @param key - The primary key\n * @param value - The value to store\n */\n public async put(key: Key, value: Value): Promise<void> {\n if (this.needsJsonSerialization) {\n value = JSON.stringify(value) as Value;\n }\n await this.tabularRepository.put({ key, value });\n }\n\n /**\n * Stores multiple rows in the repository in a bulk operation.\n * @param items - Array of key-value pairs to store\n */\n public async putBulk(items: Array<{ key: Key; value: Value }>): Promise<void> {\n const entities = this.needsJsonSerialization\n ? items.map(({ key, value }) => ({ key, value: JSON.stringify(value) as Value }))\n : items;\n\n await this.tabularRepository.putBulk(entities);\n }\n\n /**\n * Retrieves a value by its key.\n * This is a convenience method that automatically converts simple types to structured format if using default schema.\n *\n * @param key - Primary key to look up (basic key like default schema)\n * @returns The stored value or undefined if not found\n */\n public async get(key: Key): Promise<Value | undefined> {\n const result = await this.tabularRepository.get({ key });\n if (!result) return undefined;\n\n if (this.needsJsonSerialization) {\n try {\n return JSON.parse(result.value as unknown as string) as Value;\n } catch (e) {\n return result.value as unknown as Value;\n }\n }\n return result.value as unknown as Value;\n }\n\n /**\n * Deletes a row from the repository.\n * @param key - The primary key of the row to delete\n */\n public async delete(key: Key): Promise<void> {\n return await this.tabularRepository.delete({ key });\n }\n\n /**\n * Retrieves all rows from the repository.\n * @returns An array of all rows in the repository or undefined if empty\n */\n public async getAll(): Promise<Combined[] | undefined> {\n const values = await this.tabularRepository.getAll();\n if (values) {\n return values.map(\n (value) =>\n ({\n key: value.key,\n value: (() => {\n if (this.needsJsonSerialization && typeof value.value === \"string\") {\n try {\n return JSON.parse(value.value);\n } catch (e) {\n return value.value;\n }\n }\n return value.value;\n })(),\n }) as Combined\n );\n }\n }\n\n /**\n * Deletes all rows from the repository.\n */\n public async deleteAll(): Promise<void> {\n return await this.tabularRepository.deleteAll();\n }\n\n /**\n * Retrieves the number of rows in the repository.\n * @returns The number of rows in the repository\n */\n public async size(): Promise<number> {\n return await this.tabularRepository.size();\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n destroy(): void {\n this.tabularRepository.destroy();\n }\n}\n",
20
20
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { JSONValue } from \"../tabular/ITabularStorage\";\nimport { traced } from \"../util/traced\";\nimport type { IKvStorage, KvEventListener, KvEventName, KvEventParameters } from \"./IKvStorage\";\n\n/**\n * Telemetry wrapper for any IKvStorage implementation.\n * Creates spans for all storage operations.\n */\nexport class TelemetryKvStorage<\n Key extends string | number = string,\n Value extends any = any,\n Combined = { key: Key; value: Value },\n> implements IKvStorage<Key, Value, Combined> {\n constructor(\n private readonly storageName: string,\n private readonly inner: IKvStorage<Key, Value, Combined>\n ) {}\n\n put(key: Key, value: Value): Promise<void> {\n return traced(\"workglow.storage.kv.put\", this.storageName, () => this.inner.put(key, value));\n }\n putBulk(items: Array<{ key: Key; value: Value }>): Promise<void> {\n return traced(\"workglow.storage.kv.putBulk\", this.storageName, () => this.inner.putBulk(items));\n }\n get(key: Key): Promise<Value | undefined> {\n return traced(\"workglow.storage.kv.get\", this.storageName, () => this.inner.get(key));\n }\n delete(key: Key): Promise<void> {\n return traced(\"workglow.storage.kv.delete\", this.storageName, () => this.inner.delete(key));\n }\n getAll(): Promise<Combined[] | undefined> {\n return traced(\"workglow.storage.kv.getAll\", this.storageName, () => this.inner.getAll());\n }\n deleteAll(): Promise<void> {\n return traced(\"workglow.storage.kv.deleteAll\", this.storageName, () => this.inner.deleteAll());\n }\n size(): Promise<number> {\n return traced(\"workglow.storage.kv.size\", this.storageName, () => this.inner.size());\n }\n getObjectAsIdString(object: JSONValue): Promise<string> {\n return this.inner.getObjectAsIdString(object);\n }\n\n // Event delegation — no telemetry needed\n on<Event extends KvEventName>(name: Event, fn: KvEventListener<Event, Key, Value, Combined>) {\n this.inner.on(name, fn);\n }\n off<Event extends KvEventName>(name: Event, fn: KvEventListener<Event, Key, Value, Combined>) {\n this.inner.off(name, fn);\n }\n emit<Event extends KvEventName>(\n name: Event,\n ...args: KvEventParameters<Event, Key, Value, Combined>\n ) {\n this.inner.emit(name, ...args);\n }\n once<Event extends KvEventName>(name: Event, fn: KvEventListener<Event, Key, Value, Combined>) {\n this.inner.once(name, fn);\n }\n waitOn<Event extends KvEventName>(\n name: Event\n ): Promise<KvEventParameters<Event, Key, Value, Combined>> {\n return this.inner.waitOn(name);\n }\n}\n",
21
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {\n createServiceToken,\n EventEmitter,\n getLogger,\n makeFingerprint,\n sleep,\n uuid4,\n} from \"@workglow/util\";\nimport {\n IQueueStorage,\n JobStatus,\n JobStorageFormat,\n QueueChangePayload,\n QueueStorageOptions,\n QueueSubscribeOptions,\n} from \"./IQueueStorage\";\n\n/**\n * Event listeners for queue storage events\n */\ntype QueueEventListeners<Input, Output> = {\n change: (payload: QueueChangePayload<Input, Output>) => void;\n};\n\nexport const IN_MEMORY_QUEUE_STORAGE = createServiceToken<IQueueStorage<any, any>>(\n \"jobqueue.storage.inMemory\"\n);\n\n/**\n * In-memory implementation of a job queue that manages asynchronous tasks.\n * Supports job scheduling, status tracking, result caching, and prefix-based filtering.\n */\nexport class InMemoryQueueStorage<Input, Output> implements IQueueStorage<Input, Output> {\n /** The prefix values for filtering jobs */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n /** Event emitter for change notifications */\n protected readonly events = new EventEmitter<QueueEventListeners<Input, Output>>();\n\n /**\n * Creates a new in-memory job queue\n * @param queueName - Name of the queue\n * @param options - Optional configuration including prefix filters\n */\n constructor(\n public readonly queueName: string,\n options?: QueueStorageOptions\n ) {\n this.jobQueue = [];\n this.prefixValues = options?.prefixValues ?? {};\n }\n\n /** Internal array storing all jobs */\n public jobQueue: Array<JobStorageFormat<Input, Output> & Record<string, unknown>>;\n\n /**\n * Checks if a job matches the current prefix values\n */\n private matchesPrefixes(job: JobStorageFormat<Input, Output> & Record<string, unknown>): boolean {\n for (const [key, value] of Object.entries(this.prefixValues)) {\n if (job[key] !== value) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Returns a filtered and sorted list of pending jobs that are ready to run\n * Sorts by creation time to maintain FIFO order\n */\n private pendingQueue(): Array<JobStorageFormat<Input, Output> & Record<string, unknown>> {\n const now = new Date().toISOString();\n return this.jobQueue\n .filter((job) => this.matchesPrefixes(job))\n .filter((job) => job.status === JobStatus.PENDING)\n .filter((job) => !job.run_after || job.run_after <= now)\n .sort((a, b) => (a.run_after || \"\").localeCompare(b.run_after || \"\"));\n }\n\n /**\n * Adds a new job to the queue\n * Generates an ID and fingerprint if not provided\n */\n public async add(job: JobStorageFormat<Input, Output>): Promise<unknown> {\n await sleep(0);\n const now = new Date().toISOString();\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n jobWithPrefixes.id = jobWithPrefixes.id ?? uuid4();\n jobWithPrefixes.job_run_id = jobWithPrefixes.job_run_id ?? uuid4();\n jobWithPrefixes.queue = this.queueName;\n jobWithPrefixes.fingerprint = await makeFingerprint(jobWithPrefixes.input);\n jobWithPrefixes.status = JobStatus.PENDING;\n jobWithPrefixes.progress = 0;\n jobWithPrefixes.progress_message = \"\";\n jobWithPrefixes.progress_details = null;\n jobWithPrefixes.created_at = now;\n jobWithPrefixes.run_after = now;\n\n // Add prefix values to the job\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n\n this.jobQueue.push(jobWithPrefixes);\n this.events.emit(\"change\", { type: \"INSERT\", new: jobWithPrefixes });\n return jobWithPrefixes.id;\n }\n\n /**\n * Retrieves a job from the queue by its id.\n * @param id - The id of the job to retrieve.\n * @returns A promise that resolves to the job or undefined if the job is not found.\n */\n public async get(id: unknown): Promise<JobStorageFormat<Input, Output> | undefined> {\n await sleep(0);\n const job = this.jobQueue.find((j) => j.id === id);\n if (job && this.matchesPrefixes(job)) {\n return job;\n }\n return undefined;\n }\n\n /**\n * Retrieves a slice of jobs from the queue.\n * @param status - The status of the jobs to retrieve.\n * @param num - The number of jobs to retrieve.\n * @returns A promise that resolves to an array of jobs.\n */\n public async peek(\n status: JobStatus = JobStatus.PENDING,\n num: number = 100\n ): Promise<Array<JobStorageFormat<Input, Output>>> {\n await sleep(0);\n num = Number(num) || 100;\n return this.jobQueue\n .filter((j) => this.matchesPrefixes(j))\n .sort((a, b) => (a.run_after || \"\").localeCompare(b.run_after || \"\"))\n .filter((j) => j.status === status)\n .slice(0, num);\n }\n\n /**\n * Retrieves the next available job that is ready to be processed\n * Updates the job status to PROCESSING before returning\n * @param workerId - Worker ID to associate with the job\n * @returns The next job or undefined if no job is available\n */\n public async next(workerId: string): Promise<JobStorageFormat<Input, Output> | undefined> {\n await sleep(0);\n const top = this.pendingQueue();\n\n const job = top[0];\n if (job) {\n const oldJob = { ...job };\n job.status = JobStatus.PROCESSING;\n job.last_ran_at = new Date().toISOString();\n job.worker_id = workerId;\n this.events.emit(\"change\", { type: \"UPDATE\", old: oldJob, new: job });\n return job;\n }\n }\n\n /**\n * Retrieves the size of the queue for a given status\n * @param status - The status of the jobs to retrieve.\n * @returns A promise that resolves to the number of jobs.\n */\n public async size(status = JobStatus.PENDING): Promise<number> {\n await sleep(0);\n return this.jobQueue.filter((j) => this.matchesPrefixes(j) && j.status === status).length;\n }\n\n /**\n * Saves the progress of a job\n * @param jobId - The id of the job to save the progress for.\n * @param progress - The progress of the job.\n * @param message - The message of the job.\n * @param details - The details of the job.\n */\n public async saveProgress(\n id: unknown,\n progress: number,\n message: string,\n details: Record<string, any> | null\n ): Promise<void> {\n await sleep(0);\n const job = this.jobQueue.find((j) => j.id === id && this.matchesPrefixes(j));\n if (!job) {\n // Job not found - this can happen if the job was already completed/removed\n // or if there's a race condition. Silently ignore progress updates for missing jobs.\n const jobWithAnyPrefix = this.jobQueue.find((j) => j.id === id);\n getLogger().warn(\"Job not found for progress update\", {\n id,\n reason: jobWithAnyPrefix ? \"prefix_mismatch\" : \"missing\",\n existingStatus: jobWithAnyPrefix?.status,\n queueName: this.queueName,\n prefixValues: this.prefixValues,\n });\n return;\n }\n\n // Skip progress updates for jobs that are already completed or failed\n // to avoid unnecessary updates and potential race conditions\n if (job.status === JobStatus.COMPLETED || job.status === JobStatus.FAILED) {\n getLogger().warn(\"Job already completed or failed for progress update\", {\n id,\n status: job.status,\n completedAt: job.completed_at,\n error: job.error,\n });\n return;\n }\n\n const oldJob = { ...job };\n job.progress = progress;\n job.progress_message = message;\n job.progress_details = details;\n this.events.emit(\"change\", { type: \"UPDATE\", old: oldJob, new: job });\n }\n\n /**\n * Marks a job as complete with its output or error\n * Handles run_attempts for failed jobs and triggers completion callbacks\n * @param id - ID of the job to complete\n * @param output - Result of the job execution\n * @param error - Optional error message if job failed\n */\n public async complete(job: JobStorageFormat<Input, Output>) {\n await sleep(0);\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n const index = this.jobQueue.findIndex((j) => j.id === job.id && this.matchesPrefixes(j));\n if (index !== -1) {\n const existing = this.jobQueue[index];\n const currentAttempts = existing?.run_attempts ?? 0;\n jobWithPrefixes.run_attempts = currentAttempts + 1;\n // Preserve prefix values from the existing job\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n this.jobQueue[index] = jobWithPrefixes;\n this.events.emit(\"change\", { type: \"UPDATE\", old: existing, new: jobWithPrefixes });\n }\n }\n\n /**\n * Releases a claimed job back to PENDING without incrementing run_attempts.\n * @param id - The id of the claimed job to release.\n */\n public async release(id: unknown): Promise<void> {\n await sleep(0);\n const job = this.jobQueue.find((j) => j.id === id && this.matchesPrefixes(j));\n if (job) {\n const oldJob = { ...job };\n job.status = JobStatus.PENDING;\n job.worker_id = null;\n job.progress = 0;\n job.progress_message = \"\";\n job.progress_details = null;\n this.events.emit(\"change\", { type: \"UPDATE\", old: oldJob, new: job });\n }\n }\n\n /**\n * Aborts a job\n * @param id - The id of the job to abort.\n */\n public async abort(id: unknown): Promise<void> {\n await sleep(0);\n const job = this.jobQueue.find((j) => j.id === id && this.matchesPrefixes(j));\n if (job) {\n const oldJob = { ...job };\n job.status = JobStatus.ABORTING;\n this.events.emit(\"change\", { type: \"UPDATE\", old: oldJob, new: job });\n }\n }\n\n /**\n * Retrieves all jobs by their job_run_id.\n * @param job_run_id - The job_run_id of the jobs to retrieve.\n * @returns A promise that resolves to an array of jobs.\n */\n public async getByRunId(runId: string): Promise<Array<JobStorageFormat<Input, Output>>> {\n await sleep(0);\n return this.jobQueue.filter((job) => this.matchesPrefixes(job) && job.job_run_id === runId);\n }\n\n /**\n * Deletes all jobs from the queue that match the current prefix values.\n */\n public async deleteAll(): Promise<void> {\n await sleep(0);\n const deletedJobs = this.jobQueue.filter((job) => this.matchesPrefixes(job));\n this.jobQueue = this.jobQueue.filter((job) => !this.matchesPrefixes(job));\n for (const job of deletedJobs) {\n this.events.emit(\"change\", { type: \"DELETE\", old: job });\n }\n }\n\n /**\n * Looks up cached output for a given input\n * Uses input fingerprinting for efficient matching\n * @param input - The input to look up the cached output for.\n * @returns The cached output or null if not found\n */\n public async outputForInput(input: Input): Promise<Output | null> {\n await sleep(0);\n const fingerprint = await makeFingerprint(input);\n return (\n this.jobQueue.find(\n (j) =>\n this.matchesPrefixes(j) &&\n j.fingerprint === fingerprint &&\n j.status === JobStatus.COMPLETED\n )?.output ?? null\n );\n }\n\n /**\n * Deletes a job by its ID\n */\n public async delete(id: unknown): Promise<void> {\n await sleep(0);\n const deletedJob = this.jobQueue.find((job) => job.id === id && this.matchesPrefixes(job));\n this.jobQueue = this.jobQueue.filter((job) => !(job.id === id && this.matchesPrefixes(job)));\n if (deletedJob) {\n this.events.emit(\"change\", { type: \"DELETE\", old: deletedJob });\n }\n }\n\n /**\n * Delete jobs with a specific status older than a cutoff date\n * @param status - Status of jobs to delete\n * @param olderThanMs - Delete jobs completed more than this many milliseconds ago\n */\n public async deleteJobsByStatusAndAge(status: JobStatus, olderThanMs: number): Promise<void> {\n await sleep(0);\n const cutoffDate = new Date(Date.now() - olderThanMs).toISOString();\n const deletedJobs = this.jobQueue.filter(\n (job) =>\n this.matchesPrefixes(job) &&\n job.status === status &&\n job.completed_at &&\n job.completed_at <= cutoffDate\n );\n this.jobQueue = this.jobQueue.filter(\n (job) =>\n !this.matchesPrefixes(job) ||\n job.status !== status ||\n !job.completed_at ||\n job.completed_at > cutoffDate\n );\n for (const job of deletedJobs) {\n this.events.emit(\"change\", { type: \"DELETE\", old: job });\n }\n }\n\n /**\n * Sets up the database schema and tables.\n * No-op for in-memory storage as it doesn't require database setup.\n */\n public async setupDatabase(): Promise<void> {\n // No-op for in-memory storage\n }\n\n /**\n * Checks if a job matches the specified prefix filter\n * @param job - The job to check\n * @param prefixFilter - The prefix filter (undefined = use instance prefixes, {} = no filter)\n */\n private matchesPrefixFilter(\n job: JobStorageFormat<Input, Output>,\n prefixFilter?: Readonly<Record<string, string | number>>\n ): boolean {\n // If prefixFilter is explicitly an empty object, no prefix filtering\n if (prefixFilter && Object.keys(prefixFilter).length === 0) {\n return true;\n }\n\n // Use provided prefixFilter or fall back to instance's prefixValues\n const filterValues = prefixFilter ?? this.prefixValues;\n\n // If no filter values, match all\n if (Object.keys(filterValues).length === 0) {\n return true;\n }\n\n // Check each filter value\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n for (const [key, value] of Object.entries(filterValues)) {\n if (jobWithPrefixes[key] !== value) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Subscribes to changes in the queue.\n * Since InMemory is both client and server, changes are detected via local events.\n *\n * @param callback - Function called when a change occurs\n * @param options - Subscription options including prefix filter\n * @returns Unsubscribe function\n */\n public subscribeToChanges(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void {\n const prefixFilter = options?.prefixFilter;\n\n // Create a filtered callback wrapper\n const filteredCallback = (change: QueueChangePayload<Input, Output>) => {\n // Check if either old or new job matches the filter\n const newMatches = change.new ? this.matchesPrefixFilter(change.new, prefixFilter) : false;\n const oldMatches = change.old ? this.matchesPrefixFilter(change.old, prefixFilter) : false;\n\n if (!newMatches && !oldMatches) {\n return;\n }\n\n callback(change);\n };\n\n return this.events.subscribe(\"change\", filteredCallback);\n }\n}\n",
22
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken } from \"@workglow/util\";\n\nexport const QUEUE_STORAGE = createServiceToken<IQueueStorage<any, any>>(\"jobqueue.storage\");\n\n/**\n * The type of a prefix column.\n * - \"uuid\" maps to UUID in PostgreSQL/Supabase, TEXT in SQLite/IndexedDB/InMemory\n * - \"number\" maps to INTEGER in PostgreSQL/Supabase/SQLite, number in IndexedDB/InMemory\n */\nexport type PrefixColumnType = \"uuid\" | \"number\";\n\n/**\n * Defines a prefix column for queue storage filtering.\n */\nexport interface PrefixColumn {\n readonly name: string;\n readonly type: PrefixColumnType;\n}\n\n/**\n * Options for configuring queue storage with prefix filters.\n */\nexport interface QueueStorageOptions {\n /** The prefix column definitions for this storage */\n readonly prefixes?: readonly PrefixColumn[];\n /** The values for each prefix column */\n readonly prefixValues?: Readonly<Record<string, string | number>>;\n}\n\nexport type JobStatus = \"PENDING\" | \"PROCESSING\" | \"COMPLETED\" | \"ABORTING\" | \"FAILED\" | \"DISABLED\";\nexport const JobStatus = {\n PENDING: \"PENDING\",\n PROCESSING: \"PROCESSING\",\n COMPLETED: \"COMPLETED\",\n ABORTING: \"ABORTING\",\n FAILED: \"FAILED\",\n DISABLED: \"DISABLED\",\n} as const satisfies Record<JobStatus, JobStatus>;\n\n/**\n * Type of change that occurred in the queue\n */\nexport type QueueChangeType = \"INSERT\" | \"UPDATE\" | \"DELETE\";\n\n/**\n * Payload describing a change to a job\n */\nexport interface QueueChangePayload<Input, Output> {\n readonly type: QueueChangeType;\n readonly old?: JobStorageFormat<Input, Output>;\n readonly new?: JobStorageFormat<Input, Output>;\n}\n\n/**\n * Options for subscribing to queue changes\n */\nexport interface QueueSubscribeOptions {\n /** Polling interval in milliseconds (used by implementations that rely on polling) */\n readonly pollingIntervalMs?: number;\n /**\n * Custom prefix filter for this subscription.\n *\n * - If not provided (undefined): Uses the storage instance's configured prefixValues\n * - If empty object ({}): Receives ALL changes across all prefix combinations\n * - If partial object: Receives changes matching the specified subset of prefixes\n *\n * @example\n * // Storage configured with prefixes: [{name: \"user_id\"}, {name: \"project_id\"}]\n * // and prefixValues: {user_id: \"abc\", project_id: \"123\"}\n *\n * // Subscribe to only this user+project (default behavior)\n * storage.subscribeToChanges(callback);\n *\n * // Subscribe to all projects for this user\n * storage.subscribeToChanges(callback, { prefixFilter: { user_id: \"abc\" } });\n *\n * // Subscribe to ALL jobs in this queue (admin/supervisor view)\n * storage.subscribeToChanges(callback, { prefixFilter: {} });\n */\n readonly prefixFilter?: Readonly<Record<string, string | number>>;\n}\n\n/**\n * Details about a job that reflect the structure in the database.\n */\nexport type JobStorageFormat<Input, Output> = {\n id?: unknown;\n job_run_id?: string;\n queue?: string;\n input: Input;\n output?: Output | null;\n error?: string | null;\n error_code?: string | null;\n fingerprint?: string;\n max_retries?: number;\n status?: JobStatus;\n created_at?: string;\n deadline_at?: string | null;\n last_ran_at?: string | null;\n run_after: string | null;\n completed_at: string | null;\n run_attempts?: number;\n progress?: number;\n progress_message?: string;\n progress_details?: Record<string, any> | null;\n worker_id?: string | null;\n};\n\n/**\n * Interface defining the storage operations for a job queue\n */\nexport interface IQueueStorage<Input, Output> {\n /**\n * Adds a job to the queue storage\n * @param job - The job to add to the queue storage\n * @returns The ID of the job\n */\n add(job: JobStorageFormat<Input, Output>): Promise<unknown>;\n\n /**\n * Gets a job from the queue storage by ID\n * @param id - The ID of the job to get\n * @returns The job with the given ID\n */\n get(id: unknown): Promise<JobStorageFormat<Input, Output> | undefined>;\n\n /**\n * Gets the next job from the queue storage\n * @param workerId - Worker ID to associate with the job (required)\n * @returns The next job from the queue storage\n */\n next(workerId: string): Promise<JobStorageFormat<Input, Output> | undefined>;\n\n /**\n * Releases a job that was just claimed by {@link next} but won't be\n * processed (e.g. the worker was stopped mid-claim). Resets status to\n * PENDING and clears worker_id WITHOUT incrementing run_attempts —\n * the worker never actually attempted execution, so the retry budget\n * must be preserved.\n * @param id - The id of the claimed job to release.\n */\n release(id: unknown): Promise<void>;\n\n /**\n * Peeks at the next job(s) from the queue storage without removing them\n * @param status - The status of the jobs to peek at\n * @param num - The number of jobs to peek at\n * @returns The jobs with the given status\n */\n peek(status?: JobStatus, num?: number): Promise<Array<JobStorageFormat<Input, Output>>>;\n\n /**\n * Gets the size of the queue storage\n * @param status - The status of the jobs to get the size for\n * @returns The size of the queue storage\n */\n size(status?: JobStatus): Promise<number>;\n\n /**\n * Completes a job in the queue storage\n * @param job - The job to complete\n */\n complete(job: JobStorageFormat<Input, Output>): Promise<void>;\n\n /**\n * Deletes all jobs from the queue storage\n */\n deleteAll(): Promise<void>;\n\n /**\n * Gets the output for a given input from the queue storage\n * @param input - The input to get the output for\n * @returns The output of the job\n */\n outputForInput(input: Input): Promise<Output | null>;\n\n /**\n * Aborts a job in the queue storage\n * @param id - The ID of the job to abort\n */\n abort(id: unknown): Promise<void>;\n\n /**\n * Gets the jobs by job run ID from the queue storage\n * @param runId - The job run ID of the jobs to get\n * @returns The jobs with the given job run ID\n */\n getByRunId(runId: string): Promise<Array<JobStorageFormat<Input, Output>>>;\n\n /**\n * Saves progress updates for a job in the queue storage\n * @param id - The ID of the job to save the progress for\n * @param progress - The progress of the job\n * @param message - The message of the job\n * @param details - The details of the job\n */\n saveProgress(\n id: unknown,\n progress: number,\n message: string,\n details: Record<string, any> | null\n ): Promise<void>;\n\n /**\n * Deletes a job by its ID from the queue storage\n * @param id - The ID of the job to delete\n */\n delete(id: unknown): Promise<void>;\n\n /**\n * Deletes jobs from the queue storage that are of a specific status and older than the specified time\n * @param status - The status of the jobs to delete\n * @param olderThanMs - The time in milliseconds that the jobs must be older than to be deleted\n */\n deleteJobsByStatusAndAge(status: JobStatus, olderThanMs: number): Promise<void>;\n\n /**\n * Sets up the database schema and tables.\n * This method should be called before using the storage in tests.\n * For production use, database setup should be done via migrations.\n */\n setupDatabase(): Promise<void>;\n\n /**\n * Subscribes to changes in the queue (including remote changes).\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (e.g., polling interval)\n * @returns Unsubscribe function\n */\n subscribeToChanges(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void;\n}\n",
23
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { traced } from \"../util/traced\";\nimport type {\n IQueueStorage,\n JobStatus,\n JobStorageFormat,\n QueueChangePayload,\n QueueSubscribeOptions,\n} from \"./IQueueStorage\";\n\n/**\n * Telemetry wrapper for any IQueueStorage implementation.\n * Creates spans for all queue storage operations.\n */\nexport class TelemetryQueueStorage<Input, Output> implements IQueueStorage<Input, Output> {\n constructor(\n private readonly storageName: string,\n private readonly inner: IQueueStorage<Input, Output>\n ) {}\n\n add(job: JobStorageFormat<Input, Output>): Promise<unknown> {\n return traced(\"workglow.storage.queue.add\", this.storageName, () => this.inner.add(job));\n }\n get(id: unknown): Promise<JobStorageFormat<Input, Output> | undefined> {\n return traced(\"workglow.storage.queue.get\", this.storageName, () => this.inner.get(id));\n }\n next(workerId: string): Promise<JobStorageFormat<Input, Output> | undefined> {\n return traced(\"workglow.storage.queue.next\", this.storageName, () => this.inner.next(workerId));\n }\n peek(status?: JobStatus, num?: number): Promise<Array<JobStorageFormat<Input, Output>>> {\n return traced(\"workglow.storage.queue.peek\", this.storageName, () =>\n this.inner.peek(status, num)\n );\n }\n size(status?: JobStatus): Promise<number> {\n return traced(\"workglow.storage.queue.size\", this.storageName, () => this.inner.size(status));\n }\n complete(job: JobStorageFormat<Input, Output>): Promise<void> {\n return traced(\"workglow.storage.queue.complete\", this.storageName, () =>\n this.inner.complete(job)\n );\n }\n release(id: unknown): Promise<void> {\n return traced(\"workglow.storage.queue.release\", this.storageName, () => this.inner.release(id));\n }\n deleteAll(): Promise<void> {\n return traced(\"workglow.storage.queue.deleteAll\", this.storageName, () =>\n this.inner.deleteAll()\n );\n }\n outputForInput(input: Input): Promise<Output | null> {\n return traced(\"workglow.storage.queue.outputForInput\", this.storageName, () =>\n this.inner.outputForInput(input)\n );\n }\n abort(id: unknown): Promise<void> {\n return traced(\"workglow.storage.queue.abort\", this.storageName, () => this.inner.abort(id));\n }\n getByRunId(runId: string): Promise<Array<JobStorageFormat<Input, Output>>> {\n return traced(\"workglow.storage.queue.getByRunId\", this.storageName, () =>\n this.inner.getByRunId(runId)\n );\n }\n saveProgress(\n id: unknown,\n progress: number,\n message: string,\n details: Record<string, any> | null\n ): Promise<void> {\n return traced(\"workglow.storage.queue.saveProgress\", this.storageName, () =>\n this.inner.saveProgress(id, progress, message, details)\n );\n }\n delete(id: unknown): Promise<void> {\n return traced(\"workglow.storage.queue.delete\", this.storageName, () => this.inner.delete(id));\n }\n deleteJobsByStatusAndAge(status: JobStatus, olderThanMs: number): Promise<void> {\n return traced(\"workglow.storage.queue.deleteJobsByStatusAndAge\", this.storageName, () =>\n this.inner.deleteJobsByStatusAndAge(status, olderThanMs)\n );\n }\n setupDatabase(): Promise<void> {\n return this.inner.setupDatabase();\n }\n subscribeToChanges(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void {\n return this.inner.subscribeToChanges(callback, options);\n }\n}\n",
24
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken, sleep } from \"@workglow/util\";\nimport { IRateLimiterStorage, RateLimiterStorageOptions } from \"./IRateLimiterStorage\";\n\nexport const IN_MEMORY_RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\n \"ratelimiter.storage.inMemory\"\n);\n\n/**\n * Record of a job execution stored in memory.\n */\ninterface ExecutionEntry {\n readonly queueName: string;\n readonly executedAt: Date;\n}\n\n/**\n * In-memory implementation of rate limiter storage.\n * Manages execution records and next available times for rate limiting.\n */\nexport class InMemoryRateLimiterStorage implements IRateLimiterStorage {\n /** The prefix values for filtering */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n\n /** Execution records keyed by a composite of prefix values and queue name */\n private readonly executions: Map<string, ExecutionEntry[]> = new Map();\n\n /** Next available times keyed by a composite of prefix values and queue name */\n private readonly nextAvailableTimes: Map<string, Date> = new Map();\n\n constructor(options?: RateLimiterStorageOptions) {\n this.prefixValues = options?.prefixValues ?? {};\n }\n\n /**\n * Creates a storage key from the queue name and prefix values.\n */\n private makeKey(queueName: string): string {\n const prefixPart = Object.entries(this.prefixValues)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}:${v}`)\n .join(\"|\");\n return prefixPart ? `${prefixPart}|${queueName}` : queueName;\n }\n\n public async setupDatabase(): Promise<void> {\n // No-op for in-memory storage\n }\n\n public async recordExecution(queueName: string): Promise<void> {\n await sleep(0);\n const key = this.makeKey(queueName);\n const executions = this.executions.get(key) ?? [];\n executions.push({\n queueName,\n executedAt: new Date(),\n });\n this.executions.set(key, executions);\n }\n\n public async getExecutionCount(queueName: string, windowStartTime: string): Promise<number> {\n await sleep(0);\n const key = this.makeKey(queueName);\n const executions = this.executions.get(key) ?? [];\n const windowStart = new Date(windowStartTime);\n return executions.filter((e) => e.executedAt > windowStart).length;\n }\n\n public async getOldestExecutionAtOffset(\n queueName: string,\n offset: number\n ): Promise<string | undefined> {\n await sleep(0);\n const key = this.makeKey(queueName);\n const executions = this.executions.get(key) ?? [];\n const sorted = [...executions].sort((a, b) => a.executedAt.getTime() - b.executedAt.getTime());\n const execution = sorted[offset];\n return execution?.executedAt.toISOString();\n }\n\n public async getNextAvailableTime(queueName: string): Promise<string | undefined> {\n await sleep(0);\n const key = this.makeKey(queueName);\n const time = this.nextAvailableTimes.get(key);\n return time?.toISOString();\n }\n\n public async setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void> {\n await sleep(0);\n const key = this.makeKey(queueName);\n this.nextAvailableTimes.set(key, new Date(nextAvailableAt));\n }\n\n public async clear(queueName: string): Promise<void> {\n await sleep(0);\n const key = this.makeKey(queueName);\n this.executions.delete(key);\n this.nextAvailableTimes.delete(key);\n }\n}\n",
25
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken } from \"@workglow/util\";\nimport type { PrefixColumn } from \"../queue/IQueueStorage\";\n\nexport const RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\"ratelimiter.storage\");\n\n/**\n * Options for configuring rate limiter storage with prefix filters.\n */\nexport interface RateLimiterStorageOptions {\n /** The prefix column definitions for this storage */\n readonly prefixes?: readonly PrefixColumn[];\n /** The values for each prefix column */\n readonly prefixValues?: Readonly<Record<string, string | number>>;\n}\n\n/**\n * Record of a job execution for rate limiting tracking.\n */\nexport interface ExecutionRecord {\n readonly id?: unknown;\n readonly queue_name: string;\n readonly executed_at: string;\n}\n\n/**\n * Record of the next available time for a queue.\n */\nexport interface NextAvailableRecord {\n readonly queue_name: string;\n readonly next_available_at: string;\n}\n\n/**\n * Interface defining the storage operations for a rate limiter.\n * This separates the storage concerns from the rate limiting logic.\n */\nexport interface IRateLimiterStorage {\n /**\n * Sets up the database schema and tables.\n * This method should be called before using the storage.\n * For production use, database setup should be done via migrations.\n */\n setupDatabase(): Promise<void>;\n\n /**\n * Records a job execution for rate limiting tracking.\n * @param queueName - The name of the queue\n */\n recordExecution(queueName: string): Promise<void>;\n\n /**\n * Gets the count of executions within a time window.\n * @param queueName - The name of the queue\n * @param windowStartTime - The start of the time window (ISO string)\n * @returns The count of executions within the window\n */\n getExecutionCount(queueName: string, windowStartTime: string): Promise<number>;\n\n /**\n * Gets the oldest execution time within the window, offset by a count.\n * Used to calculate when the rate limit will allow the next execution.\n * @param queueName - The name of the queue\n * @param offset - The offset (typically maxExecutions - 1)\n * @returns The execution time or undefined if not enough executions\n */\n getOldestExecutionAtOffset(queueName: string, offset: number): Promise<string | undefined>;\n\n /**\n * Gets the next available time for a queue.\n * @param queueName - The name of the queue\n * @returns The next available time or undefined if not set\n */\n getNextAvailableTime(queueName: string): Promise<string | undefined>;\n\n /**\n * Sets the next available time for a queue.\n * @param queueName - The name of the queue\n * @param nextAvailableAt - The next available time (ISO string)\n */\n setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void>;\n\n /**\n * Clears all rate limit entries for a queue.\n * @param queueName - The name of the queue\n */\n clear(queueName: string): Promise<void>;\n}\n",
21
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {\n createServiceToken,\n EventEmitter,\n getLogger,\n makeFingerprint,\n sleep,\n uuid4,\n} from \"@workglow/util\";\nimport {\n IQueueStorage,\n JobStatus,\n JobStorageFormat,\n QueueChangePayload,\n QueueStorageOptions,\n QueueSubscribeOptions,\n} from \"./IQueueStorage\";\n\n/**\n * Event listeners for queue storage events\n */\ntype QueueEventListeners<Input, Output> = {\n change: (payload: QueueChangePayload<Input, Output>) => void;\n};\n\nexport const IN_MEMORY_QUEUE_STORAGE = createServiceToken<IQueueStorage<any, any>>(\n \"jobqueue.storage.inMemory\"\n);\n\n/**\n * In-memory implementation of a job queue that manages asynchronous tasks.\n * Supports job scheduling, status tracking, result caching, and prefix-based filtering.\n */\nexport class InMemoryQueueStorage<Input, Output> implements IQueueStorage<Input, Output> {\n public readonly scope = \"process\" as const;\n /** The prefix values for filtering jobs */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n /** Event emitter for change notifications */\n protected readonly events = new EventEmitter<QueueEventListeners<Input, Output>>();\n\n /**\n * Creates a new in-memory job queue\n * @param queueName - Name of the queue\n * @param options - Optional configuration including prefix filters\n */\n constructor(\n public readonly queueName: string,\n options?: QueueStorageOptions\n ) {\n this.jobQueue = [];\n this.prefixValues = options?.prefixValues ?? {};\n }\n\n /** Internal array storing all jobs */\n public jobQueue: Array<JobStorageFormat<Input, Output> & Record<string, unknown>>;\n\n /**\n * Checks if a job matches the current prefix values\n */\n private matchesPrefixes(job: JobStorageFormat<Input, Output> & Record<string, unknown>): boolean {\n for (const [key, value] of Object.entries(this.prefixValues)) {\n if (job[key] !== value) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Returns a filtered and sorted list of pending jobs that are ready to run\n * Sorts by creation time to maintain FIFO order\n */\n private pendingQueue(): Array<JobStorageFormat<Input, Output> & Record<string, unknown>> {\n const now = new Date().toISOString();\n return this.jobQueue\n .filter((job) => this.matchesPrefixes(job))\n .filter((job) => job.status === JobStatus.PENDING)\n .filter((job) => !job.run_after || job.run_after <= now)\n .sort((a, b) => (a.run_after || \"\").localeCompare(b.run_after || \"\"));\n }\n\n /**\n * Adds a new job to the queue\n * Generates an ID and fingerprint if not provided\n */\n public async add(job: JobStorageFormat<Input, Output>): Promise<unknown> {\n await sleep(0);\n const now = new Date().toISOString();\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n jobWithPrefixes.id = jobWithPrefixes.id ?? uuid4();\n jobWithPrefixes.job_run_id = jobWithPrefixes.job_run_id ?? uuid4();\n jobWithPrefixes.queue = this.queueName;\n jobWithPrefixes.fingerprint = await makeFingerprint(jobWithPrefixes.input);\n jobWithPrefixes.status = JobStatus.PENDING;\n jobWithPrefixes.progress = 0;\n jobWithPrefixes.progress_message = \"\";\n jobWithPrefixes.progress_details = null;\n jobWithPrefixes.created_at = now;\n jobWithPrefixes.run_after = now;\n\n // Add prefix values to the job\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n\n this.jobQueue.push(jobWithPrefixes);\n this.events.emit(\"change\", { type: \"INSERT\", new: jobWithPrefixes });\n return jobWithPrefixes.id;\n }\n\n /**\n * Retrieves a job from the queue by its id.\n * @param id - The id of the job to retrieve.\n * @returns A promise that resolves to the job or undefined if the job is not found.\n */\n public async get(id: unknown): Promise<JobStorageFormat<Input, Output> | undefined> {\n await sleep(0);\n const job = this.jobQueue.find((j) => j.id === id);\n if (job && this.matchesPrefixes(job)) {\n return job;\n }\n return undefined;\n }\n\n /**\n * Retrieves a slice of jobs from the queue.\n * @param status - The status of the jobs to retrieve.\n * @param num - The number of jobs to retrieve.\n * @returns A promise that resolves to an array of jobs.\n */\n public async peek(\n status: JobStatus = JobStatus.PENDING,\n num: number = 100\n ): Promise<Array<JobStorageFormat<Input, Output>>> {\n await sleep(0);\n num = Number(num) || 100;\n return this.jobQueue\n .filter((j) => this.matchesPrefixes(j))\n .sort((a, b) => (a.run_after || \"\").localeCompare(b.run_after || \"\"))\n .filter((j) => j.status === status)\n .slice(0, num);\n }\n\n /**\n * Retrieves the next available job that is ready to be processed\n * Updates the job status to PROCESSING before returning\n * @param workerId - Worker ID to associate with the job\n * @returns The next job or undefined if no job is available\n */\n public async next(workerId: string): Promise<JobStorageFormat<Input, Output> | undefined> {\n await sleep(0);\n const top = this.pendingQueue();\n\n const job = top[0];\n if (job) {\n const oldJob = { ...job };\n job.status = JobStatus.PROCESSING;\n job.last_ran_at = new Date().toISOString();\n job.worker_id = workerId;\n this.events.emit(\"change\", { type: \"UPDATE\", old: oldJob, new: job });\n return job;\n }\n }\n\n /**\n * Retrieves the size of the queue for a given status\n * @param status - The status of the jobs to retrieve.\n * @returns A promise that resolves to the number of jobs.\n */\n public async size(status = JobStatus.PENDING): Promise<number> {\n await sleep(0);\n return this.jobQueue.filter((j) => this.matchesPrefixes(j) && j.status === status).length;\n }\n\n /**\n * Saves the progress of a job\n * @param jobId - The id of the job to save the progress for.\n * @param progress - The progress of the job.\n * @param message - The message of the job.\n * @param details - The details of the job.\n */\n public async saveProgress(\n id: unknown,\n progress: number,\n message: string,\n details: Record<string, any> | null\n ): Promise<void> {\n await sleep(0);\n const job = this.jobQueue.find((j) => j.id === id && this.matchesPrefixes(j));\n if (!job) {\n // Job not found - this can happen if the job was already completed/removed\n // or if there's a race condition. Silently ignore progress updates for missing jobs.\n const jobWithAnyPrefix = this.jobQueue.find((j) => j.id === id);\n getLogger().warn(\"Job not found for progress update\", {\n id,\n reason: jobWithAnyPrefix ? \"prefix_mismatch\" : \"missing\",\n existingStatus: jobWithAnyPrefix?.status,\n queueName: this.queueName,\n prefixValues: this.prefixValues,\n });\n return;\n }\n\n // Skip progress updates for jobs that are already completed or failed\n // to avoid unnecessary updates and potential race conditions\n if (job.status === JobStatus.COMPLETED || job.status === JobStatus.FAILED) {\n getLogger().warn(\"Job already completed or failed for progress update\", {\n id,\n status: job.status,\n completedAt: job.completed_at,\n error: job.error,\n });\n return;\n }\n\n const oldJob = { ...job };\n job.progress = progress;\n job.progress_message = message;\n job.progress_details = details;\n this.events.emit(\"change\", { type: \"UPDATE\", old: oldJob, new: job });\n }\n\n /**\n * Marks a job as complete with its output or error\n * Handles run_attempts for failed jobs and triggers completion callbacks\n * @param id - ID of the job to complete\n * @param output - Result of the job execution\n * @param error - Optional error message if job failed\n */\n public async complete(job: JobStorageFormat<Input, Output>) {\n await sleep(0);\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n const index = this.jobQueue.findIndex((j) => j.id === job.id && this.matchesPrefixes(j));\n if (index !== -1) {\n const existing = this.jobQueue[index];\n const currentAttempts = existing?.run_attempts ?? 0;\n jobWithPrefixes.run_attempts = currentAttempts + 1;\n // Preserve prefix values from the existing job\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n this.jobQueue[index] = jobWithPrefixes;\n this.events.emit(\"change\", { type: \"UPDATE\", old: existing, new: jobWithPrefixes });\n }\n }\n\n /**\n * Releases a claimed job back to PENDING without incrementing run_attempts.\n * @param id - The id of the claimed job to release.\n */\n public async release(id: unknown): Promise<void> {\n await sleep(0);\n const job = this.jobQueue.find((j) => j.id === id && this.matchesPrefixes(j));\n if (job) {\n const oldJob = { ...job };\n job.status = JobStatus.PENDING;\n job.worker_id = null;\n job.progress = 0;\n job.progress_message = \"\";\n job.progress_details = null;\n this.events.emit(\"change\", { type: \"UPDATE\", old: oldJob, new: job });\n }\n }\n\n /**\n * Aborts a job\n * @param id - The id of the job to abort.\n */\n public async abort(id: unknown): Promise<void> {\n await sleep(0);\n const job = this.jobQueue.find((j) => j.id === id && this.matchesPrefixes(j));\n if (job) {\n const oldJob = { ...job };\n job.status = JobStatus.ABORTING;\n this.events.emit(\"change\", { type: \"UPDATE\", old: oldJob, new: job });\n }\n }\n\n /**\n * Retrieves all jobs by their job_run_id.\n * @param job_run_id - The job_run_id of the jobs to retrieve.\n * @returns A promise that resolves to an array of jobs.\n */\n public async getByRunId(runId: string): Promise<Array<JobStorageFormat<Input, Output>>> {\n await sleep(0);\n return this.jobQueue.filter((job) => this.matchesPrefixes(job) && job.job_run_id === runId);\n }\n\n /**\n * Deletes all jobs from the queue that match the current prefix values.\n */\n public async deleteAll(): Promise<void> {\n await sleep(0);\n const deletedJobs = this.jobQueue.filter((job) => this.matchesPrefixes(job));\n this.jobQueue = this.jobQueue.filter((job) => !this.matchesPrefixes(job));\n for (const job of deletedJobs) {\n this.events.emit(\"change\", { type: \"DELETE\", old: job });\n }\n }\n\n /**\n * Looks up cached output for a given input\n * Uses input fingerprinting for efficient matching\n * @param input - The input to look up the cached output for.\n * @returns The cached output or null if not found\n */\n public async outputForInput(input: Input): Promise<Output | null> {\n await sleep(0);\n const fingerprint = await makeFingerprint(input);\n return (\n this.jobQueue.find(\n (j) =>\n this.matchesPrefixes(j) &&\n j.fingerprint === fingerprint &&\n j.status === JobStatus.COMPLETED\n )?.output ?? null\n );\n }\n\n /**\n * Deletes a job by its ID\n */\n public async delete(id: unknown): Promise<void> {\n await sleep(0);\n const deletedJob = this.jobQueue.find((job) => job.id === id && this.matchesPrefixes(job));\n this.jobQueue = this.jobQueue.filter((job) => !(job.id === id && this.matchesPrefixes(job)));\n if (deletedJob) {\n this.events.emit(\"change\", { type: \"DELETE\", old: deletedJob });\n }\n }\n\n /**\n * Delete jobs with a specific status older than a cutoff date\n * @param status - Status of jobs to delete\n * @param olderThanMs - Delete jobs completed more than this many milliseconds ago\n */\n public async deleteJobsByStatusAndAge(status: JobStatus, olderThanMs: number): Promise<void> {\n await sleep(0);\n const cutoffDate = new Date(Date.now() - olderThanMs).toISOString();\n const deletedJobs = this.jobQueue.filter(\n (job) =>\n this.matchesPrefixes(job) &&\n job.status === status &&\n job.completed_at &&\n job.completed_at <= cutoffDate\n );\n this.jobQueue = this.jobQueue.filter(\n (job) =>\n !this.matchesPrefixes(job) ||\n job.status !== status ||\n !job.completed_at ||\n job.completed_at > cutoffDate\n );\n for (const job of deletedJobs) {\n this.events.emit(\"change\", { type: \"DELETE\", old: job });\n }\n }\n\n /**\n * Sets up the database schema and tables.\n * No-op for in-memory storage as it doesn't require database setup.\n */\n public async setupDatabase(): Promise<void> {\n // No-op for in-memory storage\n }\n\n /**\n * Checks if a job matches the specified prefix filter\n * @param job - The job to check\n * @param prefixFilter - The prefix filter (undefined = use instance prefixes, {} = no filter)\n */\n private matchesPrefixFilter(\n job: JobStorageFormat<Input, Output>,\n prefixFilter?: Readonly<Record<string, string | number>>\n ): boolean {\n // If prefixFilter is explicitly an empty object, no prefix filtering\n if (prefixFilter && Object.keys(prefixFilter).length === 0) {\n return true;\n }\n\n // Use provided prefixFilter or fall back to instance's prefixValues\n const filterValues = prefixFilter ?? this.prefixValues;\n\n // If no filter values, match all\n if (Object.keys(filterValues).length === 0) {\n return true;\n }\n\n // Check each filter value\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n for (const [key, value] of Object.entries(filterValues)) {\n if (jobWithPrefixes[key] !== value) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Subscribes to changes in the queue.\n * Since InMemory is both client and server, changes are detected via local events.\n *\n * @param callback - Function called when a change occurs\n * @param options - Subscription options including prefix filter\n * @returns Unsubscribe function\n */\n public subscribeToChanges(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void {\n const prefixFilter = options?.prefixFilter;\n\n // Create a filtered callback wrapper\n const filteredCallback = (change: QueueChangePayload<Input, Output>) => {\n // Check if either old or new job matches the filter\n const newMatches = change.new ? this.matchesPrefixFilter(change.new, prefixFilter) : false;\n const oldMatches = change.old ? this.matchesPrefixFilter(change.old, prefixFilter) : false;\n\n if (!newMatches && !oldMatches) {\n return;\n }\n\n callback(change);\n };\n\n return this.events.subscribe(\"change\", filteredCallback);\n }\n}\n",
22
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken } from \"@workglow/util\";\n\nexport const QUEUE_STORAGE = createServiceToken<IQueueStorage<any, any>>(\"jobqueue.storage\");\n\n/**\n * The type of a prefix column.\n * - \"uuid\" maps to UUID in PostgreSQL/Supabase, TEXT in SQLite/IndexedDB/InMemory\n * - \"number\" maps to INTEGER in PostgreSQL/Supabase/SQLite, number in IndexedDB/InMemory\n */\nexport type PrefixColumnType = \"uuid\" | \"number\";\n\n/**\n * Defines a prefix column for queue storage filtering.\n */\nexport interface PrefixColumn {\n readonly name: string;\n readonly type: PrefixColumnType;\n}\n\n/**\n * Options for configuring queue storage with prefix filters.\n */\nexport interface QueueStorageOptions {\n /** The prefix column definitions for this storage */\n readonly prefixes?: readonly PrefixColumn[];\n /** The values for each prefix column */\n readonly prefixValues?: Readonly<Record<string, string | number>>;\n}\n\nexport type JobStatus = \"PENDING\" | \"PROCESSING\" | \"COMPLETED\" | \"ABORTING\" | \"FAILED\" | \"DISABLED\";\nexport const JobStatus = {\n PENDING: \"PENDING\",\n PROCESSING: \"PROCESSING\",\n COMPLETED: \"COMPLETED\",\n ABORTING: \"ABORTING\",\n FAILED: \"FAILED\",\n DISABLED: \"DISABLED\",\n} as const satisfies Record<JobStatus, JobStatus>;\n\n/**\n * Type of change that occurred in the queue.\n *\n * `RESYNC` is a synthetic event emitted by some backends (e.g. Postgres\n * LISTEN/NOTIFY) after a (re)connect to indicate that arbitrary changes may\n * have happened during a disconnect window. Subscribers should treat it as a\n * \"kick the workers, re-poll state\" signal — `old` and `new` are both\n * undefined.\n */\nexport type QueueChangeType = \"INSERT\" | \"UPDATE\" | \"DELETE\" | \"RESYNC\";\n\n/**\n * Payload describing a change to a job\n */\nexport interface QueueChangePayload<Input, Output> {\n readonly type: QueueChangeType;\n readonly old?: JobStorageFormat<Input, Output>;\n readonly new?: JobStorageFormat<Input, Output>;\n}\n\n/**\n * Options for subscribing to queue changes\n */\nexport interface QueueSubscribeOptions {\n /** Polling interval in milliseconds (used by implementations that rely on polling) */\n readonly pollingIntervalMs?: number;\n /**\n * Custom prefix filter for this subscription.\n *\n * - If not provided (undefined): Uses the storage instance's configured prefixValues\n * - If empty object ({}): Receives ALL changes across all prefix combinations\n * - If partial object: Receives changes matching the specified subset of prefixes\n *\n * @example\n * // Storage configured with prefixes: [{name: \"user_id\"}, {name: \"project_id\"}]\n * // and prefixValues: {user_id: \"abc\", project_id: \"123\"}\n *\n * // Subscribe to only this user+project (default behavior)\n * storage.subscribeToChanges(callback);\n *\n * // Subscribe to all projects for this user\n * storage.subscribeToChanges(callback, { prefixFilter: { user_id: \"abc\" } });\n *\n * // Subscribe to ALL jobs in this queue (admin/supervisor view)\n * storage.subscribeToChanges(callback, { prefixFilter: {} });\n */\n readonly prefixFilter?: Readonly<Record<string, string | number>>;\n}\n\n/**\n * Details about a job that reflect the structure in the database.\n */\nexport type JobStorageFormat<Input, Output> = {\n id?: unknown;\n job_run_id?: string;\n queue?: string;\n input: Input;\n output?: Output | null;\n error?: string | null;\n error_code?: string | null;\n fingerprint?: string;\n max_retries?: number;\n status?: JobStatus;\n created_at?: string;\n deadline_at?: string | null;\n last_ran_at?: string | null;\n run_after: string | null;\n completed_at: string | null;\n run_attempts?: number;\n progress?: number;\n progress_message?: string;\n progress_details?: Record<string, any> | null;\n worker_id?: string | null;\n};\n\n/**\n * Whether a queue storage's state is shared across processes.\n *\n * - `\"process\"` — in-memory / per-process state. Workers in the same process\n * share it, but separate processes do not.\n * - `\"cluster\"` — state lives in shared external storage (Postgres, Supabase,\n * etc.) visible to every process. Pairing a `\"process\"`-scoped limiter with\n * a `\"cluster\"`-scoped queue almost always indicates a misconfiguration.\n */\nexport type QueueStorageScope = \"process\" | \"cluster\";\n\n/**\n * Interface defining the storage operations for a job queue\n */\nexport interface IQueueStorage<Input, Output> {\n /**\n * Whether this storage is shared across processes. In-memory / browser\n * backends MUST report `\"process\"`. Shared databases (Postgres, Supabase)\n * report `\"cluster\"`. Used by JobQueueServer to detect process-scoped\n * limiters paired with cluster-scoped queues.\n */\n readonly scope: QueueStorageScope;\n\n /**\n * Adds a job to the queue storage\n * @param job - The job to add to the queue storage\n * @returns The ID of the job\n */\n add(job: JobStorageFormat<Input, Output>): Promise<unknown>;\n\n /**\n * Gets a job from the queue storage by ID\n * @param id - The ID of the job to get\n * @returns The job with the given ID\n */\n get(id: unknown): Promise<JobStorageFormat<Input, Output> | undefined>;\n\n /**\n * Gets the next job from the queue storage\n * @param workerId - Worker ID to associate with the job (required)\n * @returns The next job from the queue storage\n */\n next(workerId: string): Promise<JobStorageFormat<Input, Output> | undefined>;\n\n /**\n * Releases a job that was just claimed by {@link next} but won't be\n * processed (e.g. the worker was stopped mid-claim). Resets status to\n * PENDING and clears worker_id WITHOUT incrementing run_attempts —\n * the worker never actually attempted execution, so the retry budget\n * must be preserved.\n * @param id - The id of the claimed job to release.\n */\n release(id: unknown): Promise<void>;\n\n /**\n * Peeks at the next job(s) from the queue storage without removing them\n * @param status - The status of the jobs to peek at\n * @param num - The number of jobs to peek at\n * @returns The jobs with the given status\n */\n peek(status?: JobStatus, num?: number): Promise<Array<JobStorageFormat<Input, Output>>>;\n\n /**\n * Gets the size of the queue storage\n * @param status - The status of the jobs to get the size for\n * @returns The size of the queue storage\n */\n size(status?: JobStatus): Promise<number>;\n\n /**\n * Completes a job in the queue storage\n * @param job - The job to complete\n */\n complete(job: JobStorageFormat<Input, Output>): Promise<void>;\n\n /**\n * Deletes all jobs from the queue storage\n */\n deleteAll(): Promise<void>;\n\n /**\n * Gets the output for a given input from the queue storage\n * @param input - The input to get the output for\n * @returns The output of the job\n */\n outputForInput(input: Input): Promise<Output | null>;\n\n /**\n * Aborts a job in the queue storage\n * @param id - The ID of the job to abort\n */\n abort(id: unknown): Promise<void>;\n\n /**\n * Gets the jobs by job run ID from the queue storage\n * @param runId - The job run ID of the jobs to get\n * @returns The jobs with the given job run ID\n */\n getByRunId(runId: string): Promise<Array<JobStorageFormat<Input, Output>>>;\n\n /**\n * Saves progress updates for a job in the queue storage\n * @param id - The ID of the job to save the progress for\n * @param progress - The progress of the job\n * @param message - The message of the job\n * @param details - The details of the job\n */\n saveProgress(\n id: unknown,\n progress: number,\n message: string,\n details: Record<string, any> | null\n ): Promise<void>;\n\n /**\n * Deletes a job by its ID from the queue storage\n * @param id - The ID of the job to delete\n */\n delete(id: unknown): Promise<void>;\n\n /**\n * Deletes jobs from the queue storage that are of a specific status and older than the specified time\n * @param status - The status of the jobs to delete\n * @param olderThanMs - The time in milliseconds that the jobs must be older than to be deleted\n */\n deleteJobsByStatusAndAge(status: JobStatus, olderThanMs: number): Promise<void>;\n\n /**\n * Sets up the database schema and tables.\n * This method should be called before using the storage in tests.\n * For production use, database setup should be done via migrations.\n */\n setupDatabase(): Promise<void>;\n\n /**\n * Subscribes to changes in the queue (including remote changes).\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (e.g., polling interval)\n * @returns Unsubscribe function\n */\n subscribeToChanges(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void;\n}\n",
23
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { traced } from \"../util/traced\";\nimport type {\n IQueueStorage,\n JobStatus,\n JobStorageFormat,\n QueueChangePayload,\n QueueStorageScope,\n QueueSubscribeOptions,\n} from \"./IQueueStorage\";\n\n/**\n * Telemetry wrapper for any IQueueStorage implementation.\n * Creates spans for all queue storage operations.\n */\nexport class TelemetryQueueStorage<Input, Output> implements IQueueStorage<Input, Output> {\n constructor(\n private readonly storageName: string,\n private readonly inner: IQueueStorage<Input, Output>\n ) {}\n\n public get scope(): QueueStorageScope {\n return this.inner.scope;\n }\n\n add(job: JobStorageFormat<Input, Output>): Promise<unknown> {\n return traced(\"workglow.storage.queue.add\", this.storageName, () => this.inner.add(job));\n }\n get(id: unknown): Promise<JobStorageFormat<Input, Output> | undefined> {\n return traced(\"workglow.storage.queue.get\", this.storageName, () => this.inner.get(id));\n }\n next(workerId: string): Promise<JobStorageFormat<Input, Output> | undefined> {\n return traced(\"workglow.storage.queue.next\", this.storageName, () => this.inner.next(workerId));\n }\n peek(status?: JobStatus, num?: number): Promise<Array<JobStorageFormat<Input, Output>>> {\n return traced(\"workglow.storage.queue.peek\", this.storageName, () =>\n this.inner.peek(status, num)\n );\n }\n size(status?: JobStatus): Promise<number> {\n return traced(\"workglow.storage.queue.size\", this.storageName, () => this.inner.size(status));\n }\n complete(job: JobStorageFormat<Input, Output>): Promise<void> {\n return traced(\"workglow.storage.queue.complete\", this.storageName, () =>\n this.inner.complete(job)\n );\n }\n release(id: unknown): Promise<void> {\n return traced(\"workglow.storage.queue.release\", this.storageName, () => this.inner.release(id));\n }\n deleteAll(): Promise<void> {\n return traced(\"workglow.storage.queue.deleteAll\", this.storageName, () =>\n this.inner.deleteAll()\n );\n }\n outputForInput(input: Input): Promise<Output | null> {\n return traced(\"workglow.storage.queue.outputForInput\", this.storageName, () =>\n this.inner.outputForInput(input)\n );\n }\n abort(id: unknown): Promise<void> {\n return traced(\"workglow.storage.queue.abort\", this.storageName, () => this.inner.abort(id));\n }\n getByRunId(runId: string): Promise<Array<JobStorageFormat<Input, Output>>> {\n return traced(\"workglow.storage.queue.getByRunId\", this.storageName, () =>\n this.inner.getByRunId(runId)\n );\n }\n saveProgress(\n id: unknown,\n progress: number,\n message: string,\n details: Record<string, any> | null\n ): Promise<void> {\n return traced(\"workglow.storage.queue.saveProgress\", this.storageName, () =>\n this.inner.saveProgress(id, progress, message, details)\n );\n }\n delete(id: unknown): Promise<void> {\n return traced(\"workglow.storage.queue.delete\", this.storageName, () => this.inner.delete(id));\n }\n deleteJobsByStatusAndAge(status: JobStatus, olderThanMs: number): Promise<void> {\n return traced(\"workglow.storage.queue.deleteJobsByStatusAndAge\", this.storageName, () =>\n this.inner.deleteJobsByStatusAndAge(status, olderThanMs)\n );\n }\n setupDatabase(): Promise<void> {\n return this.inner.setupDatabase();\n }\n subscribeToChanges(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void {\n return this.inner.subscribeToChanges(callback, options);\n }\n}\n",
24
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken, sleep, uuid4 } from \"@workglow/util\";\nimport {\n IRateLimiterStorage,\n RateLimiterStorageOptions,\n RateLimiterStorageScope,\n} from \"./IRateLimiterStorage\";\n\nexport const IN_MEMORY_RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\n \"ratelimiter.storage.inMemory\"\n);\n\n/**\n * Record of a job execution stored in memory.\n */\ninterface ExecutionEntry {\n /** Per-row id; serves as the opaque token returned by tryReserveExecution. */\n readonly id: string;\n readonly queueName: string;\n readonly executedAt: Date;\n}\n\n/**\n * In-memory implementation of rate limiter storage.\n * Manages execution records and next available times for rate limiting.\n */\nexport class InMemoryRateLimiterStorage implements IRateLimiterStorage {\n public readonly scope: RateLimiterStorageScope = \"process\";\n\n /** The prefix values for filtering */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n\n /** Execution records keyed by a composite of prefix values and queue name */\n private readonly executions: Map<string, ExecutionEntry[]> = new Map();\n\n /** Next available times keyed by a composite of prefix values and queue name */\n private readonly nextAvailableTimes: Map<string, Date> = new Map();\n\n /**\n * Per-key promise chain used to serialize {@link tryReserveExecution} so\n * concurrent callers cannot both observe `count < max` before either\n * inserts. Each key's chain is replaced with the next pending operation\n * before the current one returns, giving FIFO mutex semantics.\n */\n private readonly reserveChains: Map<string, Promise<unknown>> = new Map();\n\n constructor(options?: RateLimiterStorageOptions) {\n this.prefixValues = options?.prefixValues ?? {};\n }\n\n /**\n * Creates a storage key from the queue name and prefix values.\n */\n private makeKey(queueName: string): string {\n const prefixPart = Object.entries(this.prefixValues)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([k, v]) => `${k}:${v}`)\n .join(\"|\");\n return prefixPart ? `${prefixPart}|${queueName}` : queueName;\n }\n\n public async setupDatabase(): Promise<void> {\n // No-op for in-memory storage\n }\n\n /**\n * Run `fn` under a per-key mutex. Without this, two concurrent\n * `tryReserveExecution` calls would both `await sleep(0)`, both observe the\n * same execution count, and both insert — overshooting the configured limit.\n */\n private async withKeyLock<T>(key: string, fn: () => T | Promise<T>): Promise<T> {\n const previous = this.reserveChains.get(key) ?? Promise.resolve();\n let release!: (value: unknown) => void;\n const next = new Promise((resolve) => {\n release = resolve;\n });\n this.reserveChains.set(key, next);\n try {\n await previous;\n return await fn();\n } finally {\n release(undefined);\n if (this.reserveChains.get(key) === next) {\n this.reserveChains.delete(key);\n }\n }\n }\n\n public async tryReserveExecution(\n queueName: string,\n maxExecutions: number,\n windowMs: number\n ): Promise<unknown | null> {\n const key = this.makeKey(queueName);\n return this.withKeyLock(key, () => {\n const now = Date.now();\n const windowStart = new Date(now - windowMs);\n const executions = this.executions.get(key) ?? [];\n const live = executions.filter((e) => e.executedAt > windowStart);\n if (live.length >= maxExecutions) {\n // Compact while we're here.\n if (live.length !== executions.length) {\n this.executions.set(key, live);\n }\n return null;\n }\n const next = this.nextAvailableTimes.get(key);\n if (next && next.getTime() > now) {\n return null;\n }\n const id = uuid4();\n live.push({ id, queueName, executedAt: new Date(now) });\n this.executions.set(key, live);\n return id;\n });\n }\n\n public async releaseExecution(queueName: string, token: unknown): Promise<void> {\n if (token === null || token === undefined) return;\n const key = this.makeKey(queueName);\n await this.withKeyLock(key, () => {\n const executions = this.executions.get(key);\n if (!executions || executions.length === 0) return;\n // Delete by id — NEVER by recency. Two concurrent acquirers can hold\n // tokens for different rows; popping the most recent would release the\n // other worker's slot.\n const idx = executions.findIndex((e) => e.id === token);\n if (idx === -1) return;\n executions.splice(idx, 1);\n this.executions.set(key, executions);\n });\n }\n\n public async recordExecution(queueName: string): Promise<void> {\n await sleep(0);\n const key = this.makeKey(queueName);\n const executions = this.executions.get(key) ?? [];\n executions.push({\n id: uuid4(),\n queueName,\n executedAt: new Date(),\n });\n this.executions.set(key, executions);\n }\n\n public async getExecutionCount(queueName: string, windowStartTime: string): Promise<number> {\n await sleep(0);\n const key = this.makeKey(queueName);\n const executions = this.executions.get(key) ?? [];\n const windowStart = new Date(windowStartTime);\n return executions.filter((e) => e.executedAt > windowStart).length;\n }\n\n public async getOldestExecutionAtOffset(\n queueName: string,\n offset: number\n ): Promise<string | undefined> {\n await sleep(0);\n const key = this.makeKey(queueName);\n const executions = this.executions.get(key) ?? [];\n const sorted = [...executions].sort((a, b) => a.executedAt.getTime() - b.executedAt.getTime());\n const execution = sorted[offset];\n return execution?.executedAt.toISOString();\n }\n\n public async getNextAvailableTime(queueName: string): Promise<string | undefined> {\n await sleep(0);\n const key = this.makeKey(queueName);\n const time = this.nextAvailableTimes.get(key);\n return time?.toISOString();\n }\n\n public async setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void> {\n await sleep(0);\n const key = this.makeKey(queueName);\n this.nextAvailableTimes.set(key, new Date(nextAvailableAt));\n }\n\n public async clear(queueName: string): Promise<void> {\n await sleep(0);\n const key = this.makeKey(queueName);\n this.executions.delete(key);\n this.nextAvailableTimes.delete(key);\n }\n}\n",
25
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken } from \"@workglow/util\";\nimport type { PrefixColumn } from \"../queue/IQueueStorage\";\n\nexport const RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\"ratelimiter.storage\");\n\n/**\n * Whether a rate-limiter storage's state is shared across processes.\n *\n * - `\"process\"` — in-memory / per-process state. Multiple workers in the same\n * process share it, but separate processes do not.\n * - `\"cluster\"` — state lives in shared external storage (Postgres, Supabase,\n * etc.) visible to every process.\n */\nexport type RateLimiterStorageScope = \"process\" | \"cluster\";\n\n/**\n * Options for configuring rate limiter storage with prefix filters.\n */\nexport interface RateLimiterStorageOptions {\n /** The prefix column definitions for this storage */\n readonly prefixes?: readonly PrefixColumn[];\n /** The values for each prefix column */\n readonly prefixValues?: Readonly<Record<string, string | number>>;\n}\n\n/**\n * Record of a job execution for rate limiting tracking.\n */\nexport interface ExecutionRecord {\n readonly id?: unknown;\n readonly queue_name: string;\n readonly executed_at: string;\n}\n\n/**\n * Record of the next available time for a queue.\n */\nexport interface NextAvailableRecord {\n readonly queue_name: string;\n readonly next_available_at: string;\n}\n\n/**\n * Interface defining the storage operations for a rate limiter.\n * This separates the storage concerns from the rate limiting logic.\n */\nexport interface IRateLimiterStorage {\n /**\n * Whether this storage is shared across processes. In-memory backends MUST\n * report `\"process\"`. Shared databases (Postgres, Supabase) report\n * `\"cluster\"`.\n */\n readonly scope: RateLimiterStorageScope;\n\n /**\n * Sets up the database schema and tables.\n * This method should be called before using the storage.\n * For production use, database setup should be done via migrations.\n */\n setupDatabase(): Promise<void>;\n\n /**\n * Atomic check-and-record. Inserts an execution row and returns the\n * inserted row's id iff BOTH (a) fewer than `maxExecutions` rows have\n * `executed_at > (now - windowMs)` AND (b) any persisted `nextAvailableAt`\n * is in the past or absent. Returns `null` without writing anything\n * otherwise.\n *\n * The returned id MUST be passed to {@link releaseExecution} to free the\n * slot — otherwise concurrent acquirers would race to delete the wrong\n * worker's row when one of them rolls back.\n *\n * Implementations MUST serialize concurrent callers (advisory locks,\n * `BEGIN IMMEDIATE`, per-key mutex, etc.) so the count-then-insert window\n * is uninterruptible.\n *\n * @param queueName - The name of the queue\n * @param maxExecutions - Max allowed executions in the window\n * @param windowMs - Window size in milliseconds\n * @returns the inserted row's id on success, or `null` on failure\n */\n tryReserveExecution(\n queueName: string,\n maxExecutions: number,\n windowMs: number\n ): Promise<unknown | null>;\n\n /**\n * Release the execution row identified by `token` (the value previously\n * returned from {@link tryReserveExecution}). No-op if the row no longer\n * exists.\n *\n * Critical: implementations MUST delete by id, NOT by recency or position.\n * Two concurrent workers can hold tokens for different rows; deleting the\n * \"most recent\" row would release another worker's reservation.\n */\n releaseExecution(queueName: string, token: unknown): Promise<void>;\n\n /**\n * Records a job execution for rate limiting tracking.\n * @param queueName - The name of the queue\n */\n recordExecution(queueName: string): Promise<void>;\n\n /**\n * Gets the count of executions within a time window.\n * @param queueName - The name of the queue\n * @param windowStartTime - The start of the time window (ISO string)\n * @returns The count of executions within the window\n */\n getExecutionCount(queueName: string, windowStartTime: string): Promise<number>;\n\n /**\n * Gets the oldest execution time within the window, offset by a count.\n * Used to calculate when the rate limit will allow the next execution.\n * @param queueName - The name of the queue\n * @param offset - The offset (typically maxExecutions - 1)\n * @returns The execution time or undefined if not enough executions\n */\n getOldestExecutionAtOffset(queueName: string, offset: number): Promise<string | undefined>;\n\n /**\n * Gets the next available time for a queue.\n * @param queueName - The name of the queue\n * @returns The next available time or undefined if not set\n */\n getNextAvailableTime(queueName: string): Promise<string | undefined>;\n\n /**\n * Sets the next available time for a queue.\n * @param queueName - The name of the queue\n * @param nextAvailableAt - The next available time (ISO string)\n */\n setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void>;\n\n /**\n * Clears all rate limit entries for a queue.\n * @param queueName - The name of the queue\n */\n clear(queueName: string): Promise<void>;\n}\n",
26
26
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * Configuration options for the hybrid subscription manager\n */\nexport interface HybridManagerOptions {\n /** Default polling interval in milliseconds for backup polling */\n readonly defaultIntervalMs?: number;\n /** Backup polling interval in milliseconds (0 to disable, default: 5000) */\n readonly backupPollingIntervalMs?: number;\n /** Enable BroadcastChannel notifications (default: true) */\n readonly useBroadcastChannel?: boolean;\n /** BroadcastChannel name for cross-tab communication */\n readonly broadcastChannelName?: string;\n}\n\n// Re-use types from PollingSubscriptionManager to avoid duplication\nimport type {\n ChangeCallback,\n ChangePayloadFactory,\n ItemComparator,\n StateFetcher,\n} from \"./PollingSubscriptionManager\";\n\n/**\n * Options for subscribing to changes\n */\nexport interface HybridSubscriptionOptions {\n /** Polling interval in milliseconds (not used if BroadcastChannel is active) */\n readonly intervalMs?: number;\n}\n\n/**\n * Internal subscription record\n */\ninterface Subscription<ChangePayload> {\n readonly callback: ChangeCallback<ChangePayload>;\n readonly intervalMs: number;\n}\n\n/**\n * BroadcastChannel message types\n */\ntype BroadcastMessage =\n | { readonly type: \"CHANGE\" }\n | { readonly type: \"HEARTBEAT\"; readonly tabId: string; readonly timestamp: number };\n\n/**\n * Manages hybrid event + polling subscriptions efficiently by using BroadcastChannel\n * for instant cross-tab change notifications with optional backup polling for reliability.\n *\n * This manager combines three notification mechanisms:\n * 1. Local event notifications for same-tab changes (instant)\n * 2. BroadcastChannel for cross-tab change notifications (near-instant)\n * 3. Optional backup polling for reliability (infrequent, 5-10s)\n *\n * When BroadcastChannel is not available, falls back to local events only (assumes single tab).\n *\n * @template Item - The type of items being tracked\n * @template Key - The type of key used to identify items\n * @template ChangePayload - The type of change payload sent to subscribers\n */\nexport class HybridSubscriptionManager<Item, Key, ChangePayload> {\n /** Map of interval (ms) to interval ID and subscriber list */\n private readonly subscribers = new Set<Subscription<ChangePayload>>();\n\n /** Current known state from last fetch */\n private lastKnownState = new Map<Key, Item>();\n\n /** Whether the manager has been initialized with a state fetch */\n private initialized = false;\n\n /** BroadcastChannel for cross-tab communication */\n private channel: BroadcastChannel | null = null;\n\n /** Backup polling interval ID */\n private backupPollingIntervalId: ReturnType<typeof setInterval> | null = null;\n\n /** Function to fetch current state */\n private readonly fetchState: StateFetcher<Item, Key>;\n\n /** Function to compare items for equality */\n private readonly compareItems: ItemComparator<Item>;\n\n /** Factory for creating change payloads */\n private readonly payloadFactory: ChangePayloadFactory<Item, ChangePayload>;\n\n /** Configuration options */\n private readonly options: Required<HybridManagerOptions>;\n\n /** Whether BroadcastChannel is available */\n private readonly hasBroadcastChannel: boolean;\n\n /**\n * Creates a new HybridSubscriptionManager\n *\n * @param channelName - Name for the BroadcastChannel (should be unique per storage instance)\n * @param fetchState - Function that returns the current state as a Map\n * @param compareItems - Function that compares two items for equality\n * @param payloadFactory - Factory for creating INSERT/UPDATE/DELETE payloads\n * @param options - Configuration options\n */\n constructor(\n channelName: string,\n fetchState: StateFetcher<Item, Key>,\n compareItems: ItemComparator<Item>,\n payloadFactory: ChangePayloadFactory<Item, ChangePayload>,\n options?: HybridManagerOptions\n ) {\n this.fetchState = fetchState;\n this.compareItems = compareItems;\n this.payloadFactory = payloadFactory;\n\n this.options = {\n defaultIntervalMs: options?.defaultIntervalMs ?? 1000,\n backupPollingIntervalMs: options?.backupPollingIntervalMs ?? 5000,\n useBroadcastChannel: options?.useBroadcastChannel ?? true,\n broadcastChannelName: options?.broadcastChannelName ?? channelName,\n };\n\n this.hasBroadcastChannel =\n this.options.useBroadcastChannel && typeof BroadcastChannel !== \"undefined\";\n\n if (this.hasBroadcastChannel) {\n this.initializeBroadcastChannel();\n }\n }\n\n /**\n * Initializes the BroadcastChannel and sets up message handlers\n */\n private initializeBroadcastChannel(): void {\n try {\n this.channel = new BroadcastChannel(this.options.broadcastChannelName);\n this.channel.onmessage = (event: MessageEvent<BroadcastMessage>) => {\n this.handleBroadcastMessage(event.data);\n };\n } catch (error) {\n console.error(\"Failed to initialize BroadcastChannel:\", error);\n this.channel = null;\n }\n }\n\n /**\n * Handles incoming BroadcastChannel messages\n */\n private async handleBroadcastMessage(message: BroadcastMessage): Promise<void> {\n if (message.type === \"CHANGE\") {\n // Another tab made a change - poll for updates\n await this.pollAndNotify();\n }\n // HEARTBEAT messages could be used for tab detection in future\n }\n\n /**\n * Notifies other tabs that a local change occurred\n * Should be called after any local mutation\n */\n notifyLocalChange(): void {\n // Immediately poll and notify local subscribers\n this.pollAndNotify();\n\n // Broadcast change notification to other tabs\n if (this.channel) {\n try {\n this.channel.postMessage({ type: \"CHANGE\" } as BroadcastMessage);\n } catch (error) {\n // Ignore broadcast errors\n }\n }\n }\n\n /**\n * Subscribe to changes\n *\n * @param callback - Function called when changes are detected\n * @param options - Subscription options\n * @returns Unsubscribe function\n */\n subscribe(\n callback: ChangeCallback<ChangePayload>,\n options?: HybridSubscriptionOptions\n ): () => void {\n const interval = options?.intervalMs ?? this.options.defaultIntervalMs;\n const subscription: Subscription<ChangePayload> = {\n callback,\n intervalMs: interval,\n };\n\n const isFirstSubscriber = this.subscribers.size === 0;\n this.subscribers.add(subscription);\n\n if (isFirstSubscriber) {\n // First subscriber - initialize and set up backup polling\n if (!this.initialized) {\n this.initialized = true;\n // Don't await - let it run async to avoid blocking\n void this.initAndNotify(subscription);\n } else {\n // Send current state to new subscriber\n this.notifySubscriberOfCurrentState(subscription);\n }\n\n // Start backup polling if configured\n // When BroadcastChannel is active, use backup polling for reliability\n // When BroadcastChannel is not available/disabled, use polling as the primary mechanism\n if (this.options.backupPollingIntervalMs > 0) {\n this.startBackupPolling();\n }\n } else {\n this.notifySubscriberOfCurrentState(subscription);\n }\n\n return () => {\n this.subscribers.delete(subscription);\n\n // If no more subscribers, stop backup polling\n if (this.subscribers.size === 0) {\n this.stopBackupPolling();\n }\n };\n }\n\n /**\n * Initialize state and notify first subscriber\n */\n private async initAndNotify(subscription: Subscription<ChangePayload>): Promise<void> {\n try {\n this.lastKnownState = await this.fetchState();\n // Notify the new subscriber of initial state as INSERTs\n for (const [, item] of this.lastKnownState) {\n const payload = this.payloadFactory.insert(item);\n try {\n subscription.callback(payload);\n } catch {\n // Ignore callback errors\n }\n }\n } catch {\n // Ignore fetch errors during initialization\n }\n }\n\n /**\n * Send current state to a subscriber\n */\n private notifySubscriberOfCurrentState(subscription: Subscription<ChangePayload>): void {\n // Send current state as INSERTs to the new subscriber\n for (const [, item] of this.lastKnownState) {\n const payload = this.payloadFactory.insert(item);\n try {\n subscription.callback(payload);\n } catch {\n // Ignore callback errors\n }\n }\n }\n\n /**\n * Poll for changes and notify all subscribers\n */\n private async pollAndNotify(): Promise<void> {\n if (this.subscribers.size === 0) return;\n\n try {\n const currentState = await this.fetchState();\n const changes: ChangePayload[] = [];\n\n // Detect new and updated items\n for (const [key, item] of currentState) {\n const oldItem = this.lastKnownState.get(key);\n if (!oldItem) {\n changes.push(this.payloadFactory.insert(item));\n } else if (!this.compareItems(oldItem, item)) {\n changes.push(this.payloadFactory.update(oldItem, item));\n }\n }\n\n // Detect deleted items\n for (const [key, item] of this.lastKnownState) {\n if (!currentState.has(key)) {\n changes.push(this.payloadFactory.delete(item));\n }\n }\n\n // Update state\n this.lastKnownState = currentState;\n\n // Broadcast changes to all subscribers\n for (const change of changes) {\n for (const sub of this.subscribers) {\n try {\n sub.callback(change);\n } catch {\n // Ignore callback errors\n }\n }\n }\n } catch {\n // Ignore polling errors\n }\n }\n\n /**\n * Start backup polling\n */\n private startBackupPolling(): void {\n if (this.backupPollingIntervalId) return;\n\n this.backupPollingIntervalId = setInterval(\n () => this.pollAndNotify(),\n this.options.backupPollingIntervalMs\n );\n }\n\n /**\n * Stop backup polling\n */\n private stopBackupPolling(): void {\n if (this.backupPollingIntervalId) {\n clearInterval(this.backupPollingIntervalId);\n this.backupPollingIntervalId = null;\n }\n }\n\n /**\n * Get the number of active subscriptions\n */\n get subscriptionCount(): number {\n return this.subscribers.size;\n }\n\n /**\n * Check if there are any active subscriptions\n */\n get hasSubscriptions(): boolean {\n return this.subscribers.size > 0;\n }\n\n /**\n * Check if BroadcastChannel is available and active\n */\n get isBroadcastChannelActive(): boolean {\n return this.channel !== null;\n }\n\n /**\n * Destroy the manager and clean up all resources\n */\n destroy(): void {\n this.stopBackupPolling();\n if (this.channel) {\n this.channel.close();\n this.channel = null;\n }\n this.subscribers.clear();\n this.lastKnownState.clear();\n this.initialized = false;\n }\n}\n",
27
27
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\n/**\n * Configuration options for the polling subscription manager\n */\nexport interface PollingManagerOptions {\n /** Default polling interval in milliseconds */\n readonly defaultIntervalMs?: number;\n}\n\n/**\n * A callback function that is called when changes are detected\n */\nexport type ChangeCallback<T> = (change: T) => void;\n\n/**\n * A function that fetches the current state for comparison\n */\nexport type StateFetcher<Item, Key> = () => Promise<Map<Key, Item>>;\n\n/**\n * A function that compares two items for equality\n */\nexport type ItemComparator<Item> = (a: Item, b: Item) => boolean;\n\n/**\n * A factory function that creates change payloads\n */\nexport interface ChangePayloadFactory<Item, ChangePayload> {\n /** Create an INSERT change payload */\n readonly insert: (item: Item) => ChangePayload;\n /** Create an UPDATE change payload */\n readonly update: (oldItem: Item, newItem: Item) => ChangePayload;\n /** Create a DELETE change payload */\n readonly delete: (item: Item) => ChangePayload;\n}\n\n/**\n * Options for subscribing to changes\n */\nexport interface PollingSubscriptionOptions {\n /** Polling interval in milliseconds */\n readonly intervalMs?: number;\n}\n\n/**\n * Internal subscription record\n */\ninterface Subscription<ChangePayload> {\n readonly callback: ChangeCallback<ChangePayload>;\n readonly intervalMs: number;\n}\n\n/**\n * Manages polling-based subscriptions efficiently by consolidating multiple\n * subscribers into a single polling loop per interval tier.\n *\n * Instead of each subscription creating its own polling interval, this manager\n * groups subscriptions by their requested polling interval and runs a single\n * poll for each group, broadcasting changes to all subscribers in that group.\n *\n * @template Item - The type of items being tracked\n * @template Key - The type of key used to identify items\n * @template ChangePayload - The type of change payload sent to subscribers\n */\nexport class PollingSubscriptionManager<Item, Key, ChangePayload> {\n /** Map of interval (ms) to interval ID and subscriber list */\n private readonly intervals = new Map<\n number,\n {\n intervalId: ReturnType<typeof setInterval>;\n subscribers: Set<Subscription<ChangePayload>>;\n }\n >();\n\n /** Current known state from last poll */\n private lastKnownState = new Map<Key, Item>();\n\n /** Whether the manager has been initialized with a state fetch */\n private initialized = false;\n\n /** Whether initialization is currently in progress (guards against poll/init race) */\n private initializing = false;\n\n /** Function to fetch current state */\n private readonly fetchState: StateFetcher<Item, Key>;\n\n /** Function to compare items for equality */\n private readonly compareItems: ItemComparator<Item>;\n\n /** Factory for creating change payloads */\n private readonly payloadFactory: ChangePayloadFactory<Item, ChangePayload>;\n\n /** Default polling interval */\n private readonly defaultIntervalMs: number;\n\n /**\n * Creates a new PollingSubscriptionManager\n *\n * @param fetchState - Function that returns the current state as a Map\n * @param compareItems - Function that compares two items for equality\n * @param payloadFactory - Factory for creating INSERT/UPDATE/DELETE payloads\n * @param options - Configuration options\n */\n constructor(\n fetchState: StateFetcher<Item, Key>,\n compareItems: ItemComparator<Item>,\n payloadFactory: ChangePayloadFactory<Item, ChangePayload>,\n options?: PollingManagerOptions\n ) {\n this.fetchState = fetchState;\n this.compareItems = compareItems;\n this.payloadFactory = payloadFactory;\n this.defaultIntervalMs = options?.defaultIntervalMs ?? 1000;\n }\n\n /**\n * Subscribe to changes with a specific polling interval\n *\n * @param callback - Function called when changes are detected\n * @param options - Subscription options including interval\n * @returns Unsubscribe function\n */\n subscribe(\n callback: ChangeCallback<ChangePayload>,\n options?: PollingSubscriptionOptions\n ): () => void {\n const interval = options?.intervalMs ?? this.defaultIntervalMs;\n const subscription: Subscription<ChangePayload> = {\n callback,\n intervalMs: interval,\n };\n\n let intervalGroup = this.intervals.get(interval);\n if (!intervalGroup) {\n // First subscriber for this interval - create the polling loop\n const subscribers = new Set<Subscription<ChangePayload>>();\n const intervalId = setInterval(() => this.poll(subscribers), interval);\n\n intervalGroup = { intervalId, subscribers };\n this.intervals.set(interval, intervalGroup);\n\n // Run initial poll if this is the first subscriber ever\n if (!this.initialized) {\n this.initialized = true;\n this.initializing = true;\n this.initAndPoll(subscription);\n } else {\n // Run immediate poll for new subscriber\n this.pollForNewSubscriber(subscription);\n }\n } else {\n // New subscriber joining existing interval - send them current state\n this.pollForNewSubscriber(subscription);\n }\n\n intervalGroup.subscribers.add(subscription);\n\n return () => {\n const group = this.intervals.get(interval);\n if (group) {\n group.subscribers.delete(subscription);\n\n // If no more subscribers for this interval, clean up\n if (group.subscribers.size === 0) {\n clearInterval(group.intervalId);\n this.intervals.delete(interval);\n }\n }\n };\n }\n\n /**\n * Initialize state and run first poll\n */\n private async initAndPoll(newSubscription: Subscription<ChangePayload>): Promise<void> {\n try {\n this.lastKnownState = await this.fetchState();\n // Notify the new subscriber of initial state as INSERTs\n for (const [, item] of this.lastKnownState) {\n const payload = this.payloadFactory.insert(item);\n try {\n newSubscription.callback(payload);\n } catch {\n // Ignore callback errors\n }\n }\n } catch {\n // Ignore fetch errors during initialization\n } finally {\n this.initializing = false;\n }\n }\n\n /**\n * Send current state to a new subscriber\n */\n private pollForNewSubscriber(subscription: Subscription<ChangePayload>): void {\n // Send current state as INSERTs to the new subscriber\n for (const [, item] of this.lastKnownState) {\n const payload = this.payloadFactory.insert(item);\n try {\n subscription.callback(payload);\n } catch {\n // Ignore callback errors\n }\n }\n }\n\n /**\n * Poll for changes and notify all subscribers in the given set\n */\n private async poll(subscribers: Set<Subscription<ChangePayload>>): Promise<void> {\n if (subscribers.size === 0) return;\n // Skip polling while initAndPoll is still running to avoid racing on lastKnownState\n if (this.initializing) return;\n\n try {\n const currentState = await this.fetchState();\n const changes: ChangePayload[] = [];\n\n // Detect new and updated items\n for (const [key, item] of currentState) {\n const oldItem = this.lastKnownState.get(key);\n if (!oldItem) {\n changes.push(this.payloadFactory.insert(item));\n } else if (!this.compareItems(oldItem, item)) {\n changes.push(this.payloadFactory.update(oldItem, item));\n }\n }\n\n // Detect deleted items\n for (const [key, item] of this.lastKnownState) {\n if (!currentState.has(key)) {\n changes.push(this.payloadFactory.delete(item));\n }\n }\n\n // Update state\n this.lastKnownState = currentState;\n\n // Broadcast changes to all subscribers\n for (const change of changes) {\n for (const sub of subscribers) {\n try {\n sub.callback(change);\n } catch {\n // Ignore callback errors\n }\n }\n }\n } catch {\n // Ignore polling errors\n }\n }\n\n /**\n * Get the number of active subscriptions across all intervals\n */\n get subscriptionCount(): number {\n let count = 0;\n for (const group of this.intervals.values()) {\n count += group.subscribers.size;\n }\n return count;\n }\n\n /**\n * Check if there are any active subscriptions\n */\n get hasSubscriptions(): boolean {\n return this.intervals.size > 0;\n }\n\n /**\n * Destroy the manager and clean up all intervals\n */\n destroy(): void {\n for (const group of this.intervals.values()) {\n clearInterval(group.intervalId);\n }\n this.intervals.clear();\n this.lastKnownState.clear();\n this.initialized = false;\n this.initializing = false;\n }\n}\n",
28
28
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArrayConstructor,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { cosineSimilarity } from \"@workglow/util/schema\";\nimport { InMemoryTabularStorage } from \"../tabular/InMemoryTabularStorage\";\nimport type { HybridSearchOptions, IVectorStorage, VectorSearchOptions } from \"./IVectorStorage\";\nimport { getMetadataProperty, getVectorProperty } from \"./IVectorStorage\";\n\n/**\n * Check if metadata matches filter\n */\nfunction matchesFilter<Metadata>(metadata: Metadata, filter: Partial<Metadata>): boolean {\n for (const [key, value] of Object.entries(filter)) {\n if (metadata[key as keyof Metadata] !== value) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Simple full-text search scoring (keyword matching)\n */\nfunction textRelevance(text: string, query: string): number {\n const textLower = text.toLowerCase();\n const queryLower = query.toLowerCase();\n const queryWords = queryLower.split(/\\s+/).filter((w) => w.length > 0);\n if (queryWords.length === 0) {\n return 0;\n }\n let matches = 0;\n for (const word of queryWords) {\n if (textLower.includes(word)) {\n matches++;\n }\n }\n return matches / queryWords.length;\n}\n\n/**\n * In-memory document chunk vector repository implementation.\n * Extends InMemoryTabularStorage for storage.\n * Suitable for testing and small-scale browser applications.\n * Supports all vector types including quantized formats.\n *\n * @template Metadata - The metadata type for the document chunk\n * @template VectorCtor - Constructor for stored vectors (default {@link typeof Float32Array})\n */\nexport class InMemoryVectorStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n Metadata extends Record<string, unknown> = Record<string, unknown>,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n>\n extends InMemoryTabularStorage<Schema, PrimaryKeyNames, Entity>\n implements IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames>\n{\n private vectorDimensions: number;\n private vectorPropertyName: keyof Entity;\n private metadataPropertyName: keyof Entity | undefined;\n\n /**\n * Creates a new in-memory document chunk vector repository\n * @param schema - The schema definition for the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable\n * @param dimensions - The number of dimensions of the vector\n * @param _vectorCtor - TypedArray constructor (unused, for API compatibility)\n */\n constructor(\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n dimensions: number,\n _vectorCtor: TypedArrayConstructor = Float32Array\n ) {\n super(schema, primaryKeyNames, indexes);\n\n this.vectorDimensions = dimensions;\n\n // Cache vector and metadata property names from schema\n const vectorProp = getVectorProperty(schema);\n if (!vectorProp) {\n throw new Error(\"Schema must have a property with type array and format TypedArray\");\n }\n this.vectorPropertyName = vectorProp as keyof Entity;\n this.metadataPropertyName = getMetadataProperty(schema) as keyof Entity | undefined;\n }\n\n /**\n * Get the vector dimensions\n * @returns The vector dimensions\n */\n getVectorDimensions(): number {\n return this.vectorDimensions;\n }\n\n async similaritySearch(\n query: TypedArray,\n options: VectorSearchOptions<Record<string, unknown>> = {}\n ) {\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n const results: Array<Entity & { score: number }> = [];\n\n const allEntities = (await this.getAll()) || [];\n\n for (const entity of allEntities) {\n const vector = entity[this.vectorPropertyName] as TypedArray;\n const metadata = this.metadataPropertyName\n ? (entity[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n // Apply filter if provided\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n // Calculate similarity\n const score = cosineSimilarity(query, vector);\n\n // Apply threshold\n if (score < scoreThreshold) {\n continue;\n }\n\n results.push({\n ...entity,\n score,\n } as Entity & { score: number });\n }\n\n // Sort by score descending and take top K\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\n }\n\n async hybridSearch(query: TypedArray, options: HybridSearchOptions<Record<string, unknown>>) {\n const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;\n\n if (!textQuery || textQuery.trim().length === 0) {\n // Fall back to regular vector search if no text query\n return this.similaritySearch(query, { topK, filter, scoreThreshold });\n }\n\n const results: Array<Entity & { score: number }> = [];\n const allEntities = (await this.getAll()) || [];\n\n for (const entity of allEntities) {\n // In memory, vectors are stored as TypedArrays directly (not serialized)\n const vector = entity[this.vectorPropertyName] as TypedArray;\n const metadata = this.metadataPropertyName\n ? (entity[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n // Apply filter if provided\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n // Calculate vector similarity\n const vectorScore = cosineSimilarity(query, vector);\n\n // Calculate text relevance (simple keyword matching)\n const metadataText = Object.values(metadata ?? {})\n .join(\" \")\n .toLowerCase();\n const textScore = textRelevance(metadataText, textQuery);\n\n // Combine scores\n const combinedScore = vectorWeight * vectorScore + (1 - vectorWeight) * textScore;\n\n // Apply threshold\n if (combinedScore < scoreThreshold) {\n continue;\n }\n\n results.push({\n ...entity,\n score: combinedScore,\n } as Entity & { score: number });\n }\n\n // Sort by combined score descending and take top K\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\n }\n}\n",
@@ -30,20 +30,20 @@
30
30
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport type {\n AutoGeneratedKeys,\n InsertEntity,\n SimplifyPrimaryKey,\n} from \"../tabular/ITabularStorage\";\nimport { TelemetryTabularStorage } from \"../tabular/TelemetryTabularStorage\";\nimport { traced } from \"../util/traced\";\nimport type { HybridSearchOptions, IVectorStorage, VectorSearchOptions } from \"./IVectorStorage\";\n\n/**\n * Telemetry wrapper for any IVectorStorage implementation.\n * Extends TelemetryTabularStorage and adds spans for vector-specific operations.\n */\nexport class TelemetryVectorStorage<\n Metadata extends Record<string, unknown> | undefined,\n Schema extends DataPortSchemaObject,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]> = ReadonlyArray<\n keyof Schema[\"properties\"]\n >,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n InsertType = InsertEntity<Entity, AutoGeneratedKeys<Schema>>,\n>\n extends TelemetryTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, InsertType>\n implements IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames, PrimaryKey, InsertType>\n{\n private readonly vectorInner: IVectorStorage<\n Metadata,\n Schema,\n Entity,\n PrimaryKeyNames,\n PrimaryKey,\n InsertType\n >;\n\n constructor(\n storageName: string,\n inner: IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames, PrimaryKey, InsertType>\n ) {\n super(storageName, inner);\n this.vectorInner = inner;\n }\n\n getVectorDimensions(): number {\n return this.vectorInner.getVectorDimensions();\n }\n\n similaritySearch(\n query: TypedArray,\n options?: VectorSearchOptions<Metadata>\n ): Promise<(Entity & { score: number })[]> {\n return traced(\"workglow.storage.vector.similaritySearch\", this.storageName, () =>\n this.vectorInner.similaritySearch(query, options)\n );\n }\n\n hybridSearch(\n query: TypedArray,\n options: HybridSearchOptions<Metadata>\n ): Promise<(Entity & { score: number })[]> {\n if (!this.vectorInner.hybridSearch) {\n throw new Error(\"hybridSearch is not supported by the underlying storage implementation\");\n }\n return traced(\"workglow.storage.vector.hybridSearch\", this.storageName, () =>\n this.vectorInner.hybridSearch!(query, options)\n );\n }\n}\n",
31
31
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { CredentialPutOptions, ICredentialStore } from \"@workglow/util\";\nimport { decrypt, encrypt } from \"@workglow/util\";\nimport type { IKvStorage } from \"../kv/IKvStorage\";\n\n/**\n * Serialized form of a credential stored in the KV backend\n */\ninterface StoredCredential {\n readonly encrypted: string;\n readonly iv: string;\n readonly label: string | undefined;\n readonly provider: string | undefined;\n readonly createdAt: string;\n readonly updatedAt: string;\n readonly expiresAt: string | undefined;\n}\n\n/**\n * Credential store that encrypts values with AES-256-GCM before persisting\n * them to an {@link IKvStorage} backend.\n *\n * Works with any KV backend (SQLite, PostgreSQL, IndexedDB, in-memory, etc.).\n * Uses the Web Crypto API (available in Node 20+, Bun, and browsers).\n *\n * @example\n * ```ts\n * import { SqliteKvStorage } from \"@workglow/storage\";\n *\n * const kv = new SqliteKvStorage(\":memory:\");\n * const store = new EncryptedKvCredentialStore(kv, \"my-encryption-key\");\n *\n * await store.put(\"openai-api-key\", \"sk-...\", { provider: \"openai\" });\n * const key = await store.get(\"openai-api-key\"); // \"sk-...\"\n * ```\n */\nexport class EncryptedKvCredentialStore implements ICredentialStore {\n /** Per-instance cache of derived CryptoKey instances keyed by base64(salt). */\n private readonly keyCache = new Map<string, CryptoKey>();\n\n constructor(\n private readonly kv: IKvStorage<string, StoredCredential>,\n private readonly passphrase: string\n ) {\n if (!passphrase) {\n throw new Error(\"EncryptedKvCredentialStore requires a non-empty passphrase.\");\n }\n }\n\n async get(key: string): Promise<string | undefined> {\n const raw = (await this.kv.get(key)) as StoredCredential | undefined;\n if (!raw) return undefined;\n\n if (raw.expiresAt && new Date(raw.expiresAt) <= new Date()) {\n await this.kv.delete(key);\n return undefined;\n }\n\n return decrypt(raw.encrypted, raw.iv, this.passphrase, this.keyCache);\n }\n\n async put(key: string, value: string, options?: CredentialPutOptions): Promise<void> {\n const now = new Date();\n const existing = (await this.kv.get(key)) as StoredCredential | undefined;\n\n const { encrypted, iv } = await encrypt(value, this.passphrase, this.keyCache);\n\n const stored: StoredCredential = {\n encrypted,\n iv,\n label: options?.label ?? existing?.label,\n provider: options?.provider ?? existing?.provider,\n createdAt: existing?.createdAt ?? now.toISOString(),\n updatedAt: now.toISOString(),\n expiresAt: options?.expiresAt ? options.expiresAt.toISOString() : existing?.expiresAt,\n };\n\n await this.kv.put(key, stored);\n }\n\n async delete(key: string): Promise<boolean> {\n const exists = (await this.kv.get(key)) !== undefined;\n if (exists) {\n await this.kv.delete(key);\n }\n return exists;\n }\n\n async has(key: string): Promise<boolean> {\n const raw = (await this.kv.get(key)) as StoredCredential | undefined;\n if (!raw) return false;\n\n if (raw.expiresAt && new Date(raw.expiresAt) <= new Date()) {\n await this.kv.delete(key);\n return false;\n }\n return true;\n }\n\n async keys(): Promise<readonly string[]> {\n const all = await this.kv.getAll();\n if (!all) return [];\n\n const now = new Date();\n const result: string[] = [];\n for (const entry of all) {\n if (entry.value.expiresAt && new Date(entry.value.expiresAt) <= now) {\n await this.kv.delete(entry.key);\n continue;\n }\n result.push(entry.key);\n }\n return result;\n }\n\n async deleteAll(): Promise<void> {\n await this.kv.deleteAll();\n }\n}\n",
32
32
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { CredentialPutOptions, ICredentialStore } from \"@workglow/util\";\nimport type { IKvStorage } from \"../kv/IKvStorage\";\nimport { EncryptedKvCredentialStore } from \"./EncryptedKvCredentialStore\";\n\n/**\n * An {@link ICredentialStore} wrapper that starts in a locked state and defers\n * construction of the underlying {@link EncryptedKvCredentialStore} until\n * {@link unlock} is called with a passphrase.\n *\n * **Locked behavior** (before {@link unlock}):\n * - `get()` returns `undefined` (falls through in a {@link ChainedCredentialStore})\n * - `has()` returns `false`\n * - `keys()` returns `[]`\n * - `put()` throws an error\n * - `delete()` returns `false`\n * - `deleteAll()` is a no-op\n *\n * **Unlocked behavior**: all methods delegate to the inner\n * {@link EncryptedKvCredentialStore}.\n *\n * @example\n * ```ts\n * const lazy = new LazyEncryptedCredentialStore(kvStorage);\n * await lazy.get(\"key\"); // undefined (locked)\n *\n * lazy.unlock(\"my-passphrase\");\n * await lazy.get(\"key\"); // decrypted value\n *\n * lazy.lock(); // discards inner store\n * await lazy.get(\"key\"); // undefined again\n * ```\n */\nexport class LazyEncryptedCredentialStore implements ICredentialStore {\n private inner: EncryptedKvCredentialStore | undefined;\n\n constructor(private readonly kv: IKvStorage<string, unknown>) {}\n\n /**\n * Whether the store is currently unlocked and able to decrypt credentials.\n */\n get isUnlocked(): boolean {\n return this.inner !== undefined;\n }\n\n /**\n * Unlock the store by providing a passphrase. Creates the underlying\n * {@link EncryptedKvCredentialStore} using the same KV backend.\n *\n * @throws if the passphrase is empty\n */\n unlock(passphrase: string): void {\n this.inner = new EncryptedKvCredentialStore(this.kv as IKvStorage<string, any>, passphrase);\n }\n\n /**\n * Lock the store, discarding the inner {@link EncryptedKvCredentialStore}\n * and its derived key cache.\n */\n lock(): void {\n this.inner = undefined;\n }\n\n async get(key: string): Promise<string | undefined> {\n if (!this.inner) return undefined;\n return this.inner.get(key);\n }\n\n async put(key: string, value: string, options?: CredentialPutOptions): Promise<void> {\n if (!this.inner) {\n throw new Error(\"Credential store is locked. Call unlock() before storing credentials.\");\n }\n return this.inner.put(key, value, options);\n }\n\n async delete(key: string): Promise<boolean> {\n if (!this.inner) return false;\n return this.inner.delete(key);\n }\n\n async has(key: string): Promise<boolean> {\n if (!this.inner) return false;\n return this.inner.has(key);\n }\n\n async keys(): Promise<readonly string[]> {\n if (!this.inner) return [];\n return this.inner.keys();\n }\n\n async deleteAll(): Promise<void> {\n if (!this.inner) return;\n return this.inner.deleteAll();\n }\n}\n",
33
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken, deepEqual, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { HybridSubscriptionManager } from \"../util/HybridSubscriptionManager\";\nimport {\n ensureIndexedDbTable,\n ExpectedIndexDefinition,\n MigrationOptions,\n} from \"../util/IndexedDbTable\";\nimport {\n BaseTabularStorage,\n ClientProvidedKeysOption,\n KeyGenerationStrategy,\n} from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\nimport { pickCoveringIndex } from \"./coveringIndexPicker\";\n\nexport const IDB_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.indexedDb\"\n);\n\n/**\n * Polling change-detection comparator for the hybrid subscription manager.\n *\n * Naively comparing entities via serialized equality is correct but\n * O(size-of-entity) per poll. That falls apart for tables\n * holding large blobs — e.g. an `activities` row whose `output_data` carries\n * a multi-megabyte `Uint8ClampedArray`: each poll cycle (default 1 s) would\n * stringify ~16 MB per row × N rows, locking the main thread.\n *\n * Fast path: if both rows expose a string `updated_at`, compare just those.\n * The repositories in this codebase bump `updated_at` on every write (see\n * `ActivityRepository.updateActivity`), so the timestamp is a sufficient\n * change witness. Fall back to the structural compare for tables that don't\n * follow that convention so correctness is preserved everywhere.\n */\nfunction compareEntitiesForChange<T>(a: T, b: T): boolean {\n const au = (a as { updated_at?: unknown })?.updated_at;\n const bu = (b as { updated_at?: unknown })?.updated_at;\n if (typeof au === \"string\" && typeof bu === \"string\") {\n return au === bu;\n }\n return deepEqual(a, b);\n}\n\n/**\n * A tabular repository implementation using IndexedDB for browser-based storage.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class IndexedDbTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n /** Promise that resolves to the IndexedDB database instance */\n private db: IDBDatabase | undefined;\n /** Promise to track ongoing database setup to prevent concurrent setup calls */\n private setupPromise: Promise<IDBDatabase> | null = null;\n /** Migration options for database schema changes */\n private migrationOptions: MigrationOptions;\n /** Shared hybrid subscription manager */\n private hybridManager: HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > | null = null;\n /** Hybrid subscription options */\n private readonly hybridOptions: {\n readonly useBroadcastChannel: boolean;\n readonly backupPollingIntervalMs: number;\n };\n /**\n * Indexes safe for cursor-based narrowing. An IDB index excludes records\n * whose keyPath has any undefined component, so iterating an index can miss\n * records when an indexed column is optional in the schema. Native\n * `count(range)` and cursor scans are only correct over indexes whose every\n * column is required. Computed lazily on first use.\n */\n private cursorSafeIndexes: Array<Array<keyof Entity>> | undefined;\n\n /**\n * Creates a new IndexedDB-based tabular repository.\n * @param table - Name of the IndexedDB store to use.\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param migrationOptions - Options for handling database schema migrations\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n public table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n migrationOptions: MigrationOptions & {\n readonly useBroadcastChannel?: boolean;\n readonly backupPollingIntervalMs?: number;\n } = {},\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.migrationOptions = migrationOptions;\n this.hybridOptions = {\n useBroadcastChannel: migrationOptions.useBroadcastChannel ?? true,\n backupPollingIntervalMs: migrationOptions.backupPollingIntervalMs ?? 5000,\n };\n }\n\n /**\n * Internal method to get the database, setting it up if needed.\n * This ensures lazy initialization of the database.\n */\n private async getDb(): Promise<IDBDatabase> {\n if (this.db) return this.db;\n await this.setupDatabase();\n return this.db!;\n }\n\n /**\n * Sets up the IndexedDB database table with the required schema and indexes.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n if (this.db) return;\n if (this.setupPromise) {\n await this.setupPromise;\n return;\n }\n\n this.setupPromise = this.performSetup();\n try {\n this.db = await this.setupPromise;\n } finally {\n this.setupPromise = null;\n }\n }\n\n /**\n * Internal method to perform the actual database setup\n */\n private async performSetup(): Promise<IDBDatabase> {\n const pkColumns = super.primaryKeyColumns() as string[];\n\n // Create index definitions for both single and compound indexes\n const expectedIndexes: ExpectedIndexDefinition[] = [];\n\n for (const spec of this.indexes) {\n // Handle compound index\n const columns = spec as Array<keyof Entity>;\n // Skip if this is just the primary key or a prefix of it\n if (columns.length <= pkColumns.length) {\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n\n // Create compound index name and keyPath\n const columnNames = columns.map((col) => String(col));\n const indexName = columnNames.join(\"_\");\n expectedIndexes.push({\n name: indexName,\n keyPath: columnNames.length === 1 ? columnNames[0] : columnNames,\n options: { unique: false },\n });\n }\n\n const primaryKey = pkColumns.length === 1 ? pkColumns[0] : pkColumns;\n\n // Determine if we should use autoIncrement\n // IndexedDB autoIncrement only works with single numeric keys\n const useAutoIncrement =\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyStrategy === \"autoincrement\" &&\n pkColumns.length === 1;\n\n // Ensure that our table is created/upgraded only if the structure (indexes) has changed.\n return await ensureIndexedDbTable(\n this.table,\n primaryKey,\n expectedIndexes,\n this.migrationOptions,\n useAutoIncrement\n );\n }\n\n /**\n * Generates a key value for UUID keys\n * Integer autoincrement keys are handled by IndexedDB's autoIncrement\n * @param columnName - Name of the column to generate a key for\n * @param strategy - The generation strategy to use\n * @returns The generated key value\n */\n protected override generateKeyValue(\n columnName: string,\n strategy: KeyGenerationStrategy\n ): string | number {\n if (strategy === \"uuid\") {\n return uuid4();\n }\n // autoincrement is handled by IndexedDB's autoIncrement option\n throw new Error(\n `IndexedDB autoincrement keys are generated by the database, not client-side. Column: ${columnName}`\n );\n }\n\n /**\n * Stores a row in the repository.\n * @param record - The entity to store (may be missing auto-generated keys).\n * @returns The stored entity\n * @emits put - Emitted when the value is successfully stored\n */\n async put(record: InsertType): Promise<Entity> {\n const db = await this.getDb();\n let recordToStore = record as unknown as Entity;\n\n // Handle auto-generated keys\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const clientProvidedValue = (record as Record<string, unknown>)[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // UUID generation - must be done client-side\n let shouldGenerate = false;\n if (this.clientProvidedKeys === \"never\") {\n shouldGenerate = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldGenerate = false;\n } else {\n // \"if-missing\"\n shouldGenerate = !hasClientValue;\n }\n\n if (shouldGenerate) {\n const generatedValue = this.generateKeyValue(keyName, \"uuid\");\n recordToStore = { ...record, [keyName]: generatedValue } as Entity;\n }\n } else if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // Autoincrement handled by IndexedDB\n // If clientProvidedKeys is \"always\", require the value\n if (this.clientProvidedKeys === \"always\" && !hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n // If clientProvidedKeys is \"never\", omit the key to let IDB generate\n if (this.clientProvidedKeys === \"never\") {\n const { [keyName]: _, ...rest } = record as Record<string, unknown>;\n recordToStore = rest as Entity;\n }\n // \"if-missing\": use client value if provided, omit if not\n }\n }\n\n // Merge key and value, ensuring all fields are at the root level for indexing\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.put(recordToStore);\n request.onerror = () => {\n reject(request.error);\n };\n request.onsuccess = () => {\n // For autoincrement keys, we need to update the record with the generated key\n if (\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyName &&\n this.autoGeneratedKeyStrategy === \"autoincrement\"\n ) {\n const keyName = String(this.autoGeneratedKeyName);\n if (recordToStore[keyName as keyof Entity] === undefined) {\n // Get the generated key from the request result\n recordToStore = { ...recordToStore, [keyName]: request.result } as Entity;\n }\n }\n this.events.emit(\"put\", recordToStore);\n resolve(recordToStore);\n };\n transaction.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * Stores multiple rows in the repository in a bulk operation.\n * @param records - Array of entities to store (may be missing auto-generated keys).\n * @returns Array of stored entities\n * @emits put - Emitted for each record successfully stored\n */\n async putBulk(records: InsertType[]): Promise<Entity[]> {\n // Use individual put calls to ensure auto-generated keys are handled correctly\n return await Promise.all(records.map((record) => this.put(record)));\n }\n\n protected override getPrimaryKeyAsOrderedArray(key: PrimaryKey) {\n return super\n .getPrimaryKeyAsOrderedArray(key)\n .map((value) => (typeof value === \"bigint\" ? value.toString() : value));\n }\n\n private getIndexedKey(key: PrimaryKey): any {\n const keys = super\n .getPrimaryKeyAsOrderedArray(key)\n .map((value) => (typeof value === \"bigint\" ? value.toString() : value));\n return keys.length === 1 ? keys[0] : keys;\n }\n\n /**\n * Retrieves a value from the repository by its key.\n * @param key - The key object.\n * @returns The value object or undefined if not found.\n * @emits get - Emitted when the value is successfully retrieved\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.get(this.getIndexedKey(key));\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n if (!request.result) {\n this.events.emit(\"get\", key, undefined);\n resolve(undefined);\n return;\n }\n this.events.emit(\"get\", key, request.result);\n resolve(request.result);\n };\n });\n }\n\n /**\n * Returns an array of all entries in the repository, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of all entries in the repository.\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n const db = await this.getDb();\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.getAll();\n return new Promise((resolve, reject) => {\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n let values: Entity[] = request.result;\n if (values.length === 0) {\n resolve(undefined);\n return;\n }\n\n if (options?.orderBy && options.orderBy.length > 0) {\n values.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n if (options?.offset !== undefined) {\n values = values.slice(options.offset);\n }\n\n if (options?.limit !== undefined) {\n values = values.slice(0, options.limit);\n }\n\n resolve(values.length > 0 ? values : undefined);\n };\n });\n }\n\n /**\n * Deletes a row from the repository.\n * @param key - The key object to delete.\n */\n async delete(key: PrimaryKey): Promise<void> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.delete(this.getIndexedKey(key));\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.events.emit(\"delete\", key as keyof Entity);\n resolve();\n };\n transaction.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * Deletes all records from the repository.\n * @emits clearall - Emitted when all values are deleted\n */\n async deleteAll(): Promise<void> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.clear();\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.events.emit(\"clearall\");\n resolve();\n };\n transaction.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * Returns the total number of rows in the repository.\n * @returns Count of stored items.\n */\n async size(): Promise<number> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.count();\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n });\n }\n\n /**\n * Returns the subset of configured indexes safe to use for cursor-based\n * narrowing — those whose every column is required by the schema. IDB\n * excludes records with undefined keyPath components from indexes, so\n * iterating an index would silently miss records when any indexed column\n * is optional.\n */\n private getCursorSafeIndexes(): Array<Array<keyof Entity>> {\n if (this.cursorSafeIndexes) return this.cursorSafeIndexes;\n const required = new Set(this.schema.required ?? []);\n this.cursorSafeIndexes = this.indexes.filter((columns) =>\n columns.every((column) => required.has(String(column)))\n );\n return this.cursorSafeIndexes;\n }\n\n /**\n * Picks the best index to narrow a criteria-based scan, preferring indexes\n * whose prefix covers every criteria column (so callers can use the native\n * `count()` API) and falling back to the longest equality-prefix match.\n *\n * Upper bound uses `[]` as a sentinel that compares greater than any\n * primitive value at the next index position (per IndexedDB key ordering:\n * array > binary > string > date > number). Assumes subsequent indexed\n * columns hold primitive values — array-valued columns would compare\n * greater than `[]` and slip outside the range.\n */\n private createIndexedRange(\n store: IDBObjectStore,\n criteria: SearchCriteria<Entity>\n ):\n | {\n source: IDBObjectStore | IDBIndex;\n range: IDBKeyRange | undefined;\n coversCriteria: boolean;\n }\n | undefined {\n const criteriaColumns = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaColumns.length === 0) return undefined;\n\n let best:\n | {\n indexName: string;\n prefixValues: unknown[];\n fullMatch: boolean;\n coversCriteria: boolean;\n }\n | undefined;\n\n for (const indexColumns of this.getCursorSafeIndexes()) {\n const prefixValues: unknown[] = [];\n for (const column of indexColumns) {\n const value = this.getEqualityCriterionValue(criteria, column);\n if (value === undefined) break;\n prefixValues.push(value);\n }\n\n if (prefixValues.length === 0) continue;\n\n const indexedPrefix = indexColumns.slice(0, prefixValues.length);\n const coversCriteria = criteriaColumns.every((column) => indexedPrefix.includes(column));\n\n const better =\n !best ||\n (coversCriteria && !best.coversCriteria) ||\n (coversCriteria === best.coversCriteria && prefixValues.length > best.prefixValues.length);\n\n if (better) {\n best = {\n indexName: indexColumns.map((column) => String(column)).join(\"_\"),\n prefixValues,\n fullMatch: prefixValues.length === indexColumns.length,\n coversCriteria,\n };\n }\n }\n\n if (!best) return undefined;\n\n const range = best.fullMatch\n ? IDBKeyRange.only(best.prefixValues.length === 1 ? best.prefixValues[0] : best.prefixValues)\n : IDBKeyRange.bound(best.prefixValues, [...best.prefixValues, []]);\n\n return {\n source: store.index(best.indexName),\n range,\n coversCriteria: best.coversCriteria,\n };\n }\n\n /**\n * Counts rows matching the specified search criteria.\n *\n * Uses the native `count()` API when an index prefix covers every criteria\n * column. Otherwise narrows via the longest matching index prefix and\n * filters the remaining columns during cursor iteration. Falls back to a\n * full store scan only when no index applies.\n */\n override async count(criteria?: SearchCriteria<Entity>): Promise<number> {\n if (!criteria || Object.keys(criteria).length === 0) {\n return await this.size();\n }\n\n this.validateQueryParams(criteria);\n const db = await this.getDb();\n\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const plan = this.createIndexedRange(store, criteria);\n\n if (plan?.coversCriteria) {\n const request = plan.source.count(plan.range);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n return;\n }\n\n const source = plan?.source ?? store;\n const range = plan?.range;\n let count = 0;\n const request = source.openCursor(range);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n resolve(count);\n return;\n }\n if (this.matchesCriteria(cursor.value as Entity, criteria)) {\n count += 1;\n }\n cursor.continue();\n };\n });\n }\n\n /**\n * Fetches a page of records from the repository.\n * @param offset - Number of records to skip\n * @param limit - Maximum number of records to return\n * @returns Array of entities or undefined if no records found\n */\n async getBulk(offset: number, limit: number): Promise<Entity[] | undefined> {\n if (offset < 0) {\n throw new RangeError(`offset must be non-negative, got ${offset}`);\n }\n if (limit <= 0) {\n return undefined;\n }\n\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.openCursor();\n const entities: Entity[] = [];\n let skipped = false;\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n const cursor = request.result;\n if (cursor) {\n // Skip to offset using advance\n if (!skipped && offset > 0) {\n skipped = true;\n cursor.advance(offset);\n return;\n }\n\n // Collect records up to the limit\n entities.push(cursor.value);\n if (entities.length === limit) {\n resolve(entities);\n return;\n }\n cursor.continue();\n } else {\n // No more records\n resolve(entities.length > 0 ? entities : undefined);\n }\n };\n });\n }\n\n /**\n * Checks if a record matches all criteria conditions.\n * @param record - The record to check\n * @param criteria - The search criteria\n * @returns true if all conditions match\n */\n private matchesCriteria(record: Entity, criteria: DeleteSearchCriteria<Entity>): boolean {\n for (const column of Object.keys(criteria) as Array<keyof Entity>) {\n const criterion = criteria[column];\n const recordValue = record[column];\n\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n // Skip null values for comparison operators\n if (operator !== \"=\" && (recordValue === null || recordValue === undefined)) {\n return false;\n }\n\n switch (operator) {\n case \"=\":\n if (recordValue !== value) return false;\n break;\n case \"<\":\n if (!(recordValue < value)) return false;\n break;\n case \"<=\":\n if (!(recordValue <= value)) return false;\n break;\n case \">\":\n if (!(recordValue > value)) return false;\n break;\n case \">=\":\n if (!(recordValue >= value)) return false;\n break;\n default:\n return false;\n }\n }\n return true;\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Supports multiple columns with optional comparison operators.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n */\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaKeys.length === 0) {\n return;\n }\n\n const db = await this.getDb();\n\n return new Promise(async (resolve, reject) => {\n try {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n\n // Set up transaction event handlers\n transaction.oncomplete = () => {\n this.events.emit(\"delete\", criteriaKeys[0] as keyof Entity);\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n\n transaction.onerror = () => {\n reject(transaction.error);\n };\n\n // Get all records and filter\n const getAllRequest = store.getAll();\n\n getAllRequest.onsuccess = () => {\n const allRecords: Entity[] = getAllRequest.result;\n\n // Filter records that match all criteria\n const recordsToDelete = allRecords.filter((record) =>\n this.matchesCriteria(record, criteria)\n );\n\n if (recordsToDelete.length === 0) {\n // No records to delete\n return;\n }\n\n // Delete each record that matches the criteria\n for (const record of recordsToDelete) {\n // Extract the primary key from the record\n const primaryKey = this.primaryKeyColumns().reduce((key, col) => {\n // @ts-ignore - We know these properties exist on the record\n key[col] = record[col];\n return key;\n }, {} as PrimaryKey);\n\n // Delete the record using the primary key\n const request = store.delete(this.getIndexedKey(primaryKey));\n\n request.onerror = () => {\n console.error(\"Error deleting record:\", request.error);\n };\n }\n };\n\n getAllRequest.onerror = () => {\n reject(getAllRequest.error);\n };\n } catch (error) {\n reject(error);\n }\n });\n }\n\n private getEqualityCriterionValue(\n criteria: SearchCriteria<Entity>,\n column: keyof Entity\n ): Entity[keyof Entity] | undefined {\n const criterion = criteria[column];\n if (criterion === undefined) return undefined;\n if (isSearchCondition(criterion)) {\n return criterion.operator === \"=\" ? (criterion.value as Entity[keyof Entity]) : undefined;\n }\n return criterion as Entity[keyof Entity];\n }\n\n private compareByOrder(a: Entity, b: Entity, options?: QueryOptions<Entity>): number {\n if (!options?.orderBy) return 0;\n for (const { column, direction } of options.orderBy) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n }\n\n private createIndexedQuery(\n store: IDBObjectStore,\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): {\n source: IDBObjectStore | IDBIndex;\n range: IDBKeyRange | undefined;\n direction: IDBCursorDirection;\n satisfiesOrder: boolean;\n appliedLimit: boolean;\n appliedOffset: boolean;\n skipRemaining: number;\n } {\n const orderBy = options?.orderBy ?? [];\n let best:\n | {\n indexName: string;\n prefixValues: unknown[];\n fullMatch: boolean;\n satisfiesOrder: boolean;\n direction: IDBCursorDirection;\n }\n | undefined;\n\n for (const indexColumns of this.getCursorSafeIndexes()) {\n const prefixValues: unknown[] = [];\n for (const column of indexColumns) {\n const value = this.getEqualityCriterionValue(criteria, column);\n if (value === undefined) break;\n prefixValues.push(value);\n }\n\n if (prefixValues.length === 0) continue;\n\n const remainingColumns = indexColumns.slice(prefixValues.length);\n let redundantOrderPrefixLength = 0;\n while (\n redundantOrderPrefixLength < orderBy.length &&\n redundantOrderPrefixLength < prefixValues.length &&\n orderBy[redundantOrderPrefixLength]?.column === indexColumns[redundantOrderPrefixLength]\n ) {\n redundantOrderPrefixLength++;\n }\n const normalizedOrderBy = orderBy.slice(redundantOrderPrefixLength);\n const satisfiesOrder =\n normalizedOrderBy.length === 0 ||\n (normalizedOrderBy.length <= remainingColumns.length &&\n normalizedOrderBy.every((order, index) => order.column === remainingColumns[index]) &&\n orderBy.every((order) => order.direction === orderBy[0]?.direction));\n\n if (!satisfiesOrder && best) continue;\n\n if (\n !best ||\n (satisfiesOrder && !best.satisfiesOrder) ||\n prefixValues.length > best.prefixValues.length\n ) {\n best = {\n indexName: indexColumns.map((column) => String(column)).join(\"_\"),\n prefixValues,\n fullMatch: prefixValues.length === indexColumns.length,\n satisfiesOrder,\n direction: orderBy[0]?.direction === \"DESC\" ? \"prev\" : \"next\",\n };\n }\n }\n\n const appliedLimit = Boolean(best?.satisfiesOrder && options?.limit !== undefined);\n const appliedOffset = Boolean(best?.satisfiesOrder && options?.offset !== undefined);\n\n if (!best) {\n return {\n source: store,\n range: undefined,\n direction: orderBy[0]?.direction === \"DESC\" ? \"prev\" : \"next\",\n satisfiesOrder: false,\n appliedLimit: false,\n appliedOffset: false,\n skipRemaining: 0,\n };\n }\n\n const source = store.index(best.indexName);\n // See createIndexedRange for the `[]` upper-bound sentinel rationale.\n const keyRange = best.fullMatch\n ? IDBKeyRange.only(best.prefixValues.length === 1 ? best.prefixValues[0] : best.prefixValues)\n : IDBKeyRange.bound(best.prefixValues, [...best.prefixValues, []]);\n\n return {\n source,\n range: keyRange,\n direction: best.direction,\n satisfiesOrder: best.satisfiesOrder,\n appliedLimit,\n appliedOffset,\n skipRemaining: appliedOffset ? (options?.offset ?? 0) : 0,\n };\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering, limit, and offset.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of matching entities or undefined if no matches found\n */\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n this.validateQueryParams(criteria, options);\n const db = await this.getDb();\n\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const indexedQuery = this.createIndexedQuery(store, criteria, options);\n const results: Entity[] = [];\n const request = indexedQuery.source.openCursor(indexedQuery.range, indexedQuery.direction);\n\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n let finalResults = results;\n\n if (!indexedQuery.satisfiesOrder && options?.orderBy && options.orderBy.length > 0) {\n finalResults = [...finalResults].sort((a, b) => this.compareByOrder(a, b, options));\n }\n\n if (!indexedQuery.appliedOffset && options?.offset !== undefined) {\n finalResults = finalResults.slice(options.offset);\n }\n\n if (!indexedQuery.appliedLimit && options?.limit !== undefined) {\n finalResults = finalResults.slice(0, options.limit);\n }\n\n const result = finalResults.length > 0 ? finalResults : undefined;\n this.events.emit(\"query\", criteria as Partial<Entity>, result);\n resolve(result);\n return;\n }\n\n const record = cursor.value as Entity;\n if (this.matchesCriteria(record, criteria)) {\n if (indexedQuery.skipRemaining > 0) {\n indexedQuery.skipRemaining -= 1;\n } else {\n results.push(record);\n if (indexedQuery.appliedLimit && results.length === options?.limit) {\n const result = results.length > 0 ? results : undefined;\n this.events.emit(\"query\", criteria as Partial<Entity>, result);\n resolve(result);\n return;\n }\n }\n }\n\n cursor.continue();\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Strict, projected query served entirely by a covering compound index.\n * Uses `openKeyCursor` — never reads `cursor.value` — so only the index key\n * bytes are loaded into memory. Ideal for tables with large value blobs.\n *\n * Throws {@link CoveringIndexMissingError} when no registered index can serve\n * the request (i.e. the index does not cover all select + orderBy columns).\n */\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n this.validateSelect(options);\n this.validateQueryParams(criteria, options);\n\n const registered = this.indexes.map((cols) => {\n const cs = Array.isArray(cols) ? (cols as string[]) : [cols as string];\n return { name: cs.join(\"_\"), keyPath: cs };\n });\n\n const picked = pickCoveringIndex({\n table: this.table,\n indexes: registered,\n criteriaColumns: Object.keys(criteria),\n orderByColumns: (options.orderBy ?? []).map((o) => ({\n column: String(o.column),\n direction: o.direction,\n })),\n selectColumns: options.select.map(String),\n primaryKeyColumns: this.primaryKeyColumns().map(String),\n });\n\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.table, \"readonly\");\n const store = tx.objectStore(this.table);\n const idx = store.index(picked.name);\n\n // Build the equality prefix key range from criteria values.\n // Only push columns whose criterion is a direct equality value (plain value or operator \"=\").\n // Any non-equality operator (>, <, etc.) breaks the prefix; the existing in-cursor\n // compareWithOperator filter below handles those columns.\n const prefix: unknown[] = [];\n for (const col of picked.keyPath) {\n const c = (criteria as Record<string, unknown>)[col];\n if (c === undefined && !(col in (criteria as Record<string, unknown>))) break;\n if (isSearchCondition(c)) {\n if (c.operator !== \"=\") break;\n prefix.push(c.value);\n } else {\n prefix.push(c);\n }\n }\n // Use IDBKeyRange.bound with [] upper sentinel for prefix scans on compound keys.\n // `[...prefix, []]` is greater than any key starting with prefix in IDB's comparison.\n const range =\n prefix.length === 0\n ? undefined\n : prefix.length === picked.keyPath.length\n ? IDBKeyRange.only(prefix.length === 1 ? prefix[0] : prefix)\n : IDBKeyRange.bound(prefix, [...prefix, []]);\n\n const direction: IDBCursorDirection = picked.reverseDirection ? \"prev\" : \"next\";\n // openKeyCursor — never reads cursor.value, only the index key and primaryKey\n const request = idx.openKeyCursor(range, direction);\n const out: Pick<Entity, K>[] = [];\n let toSkip = options.offset ?? 0;\n\n // Precompute lookup maps for the cursor loop (O(keyPath) once, not per-row)\n const keyPathPositions = new Map<string, number>();\n picked.keyPath.forEach((col, i) => keyPathPositions.set(col, i));\n\n const pkCols = this.primaryKeyColumns().map(String);\n const pkPositions = new Map<string, number>();\n pkCols.forEach((col, i) => pkPositions.set(col, i));\n\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n resolve(out);\n return;\n }\n\n const key = cursor.key;\n\n // Decode projected columns from the index key array and primaryKey\n const row = {} as Record<string, unknown>;\n for (const col of options.select) {\n const colStr = String(col);\n const pos = keyPathPositions.get(colStr);\n if (pos !== undefined) {\n // Column is in the index key path — extract from key array\n row[colStr] = Array.isArray(key) ? key[pos] : key;\n } else {\n // Column must be a primary key column — use cursor.primaryKey\n if (pkCols.length === 1 && colStr === pkCols[0]) {\n row[colStr] = cursor.primaryKey;\n } else {\n const pkPos = pkPositions.get(colStr);\n if (pkPos !== undefined) {\n row[colStr] = Array.isArray(cursor.primaryKey)\n ? (cursor.primaryKey as unknown[])[pkPos]\n : cursor.primaryKey;\n }\n }\n }\n }\n\n // Apply non-equality criteria for index positions beyond the equality prefix\n let matches = true;\n for (const [col, crit] of Object.entries(criteria as Record<string, unknown>)) {\n if (!isSearchCondition(crit)) continue; // equality already handled by range\n const pos = keyPathPositions.get(col);\n if (pos === undefined) continue;\n const valFromKey = Array.isArray(key) ? (key as unknown[])[pos] : key;\n if (!compareWithOperator(valFromKey, crit.operator, crit.value)) {\n matches = false;\n break;\n }\n }\n\n if (matches) {\n if (toSkip > 0) {\n toSkip -= 1;\n } else {\n out.push(row as Pick<Entity, K>);\n if (options.limit !== undefined && out.length >= options.limit) {\n resolve(out);\n return;\n }\n }\n }\n\n cursor.continue();\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Gets or creates the shared hybrid subscription manager.\n * This ensures all subscriptions share a single manager.\n */\n private getHybridManager(): HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > {\n if (!this.hybridManager) {\n // Generate unique channel name based on table name\n const channelName = `indexeddb-tabular-${this.table}`;\n\n this.hybridManager = new HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n >(\n channelName,\n async () => {\n // Fetch all entities and create a map keyed by entity fingerprint\n const entities = (await this.getAll()) || [];\n const map = new Map<string, Entity>();\n for (const entity of entities) {\n const { key } = this.separateKeyValueFromCombined(entity);\n const fingerprint = await makeFingerprint(key);\n map.set(fingerprint, entity);\n }\n return map;\n },\n compareEntitiesForChange,\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n },\n {\n defaultIntervalMs: 1000,\n useBroadcastChannel: this.hybridOptions.useBroadcastChannel,\n backupPollingIntervalMs: this.hybridOptions.backupPollingIntervalMs,\n }\n );\n }\n return this.hybridManager;\n }\n\n /**\n * Subscribes to changes in the repository.\n * Uses polling since IndexedDB has no native cross-tab change notifications.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options including polling interval\n * @returns Unsubscribe function\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Note: We don't await setupDatabase() here to keep the method synchronous\n // The getAll() method in the hybrid manager will call setupDatabase() when needed\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n const manager = this.getHybridManager();\n return manager.subscribe(callback, { intervalMs });\n }\n\n /**\n * Destroys this repository and frees up resources.\n */\n public override destroy(): void {\n if (this.hybridManager) {\n this.hybridManager.destroy();\n this.hybridManager = null;\n }\n this.db?.close();\n }\n}\n\n/**\n * Compare two values using a SearchOperator. Used by queryIndex to evaluate\n * non-equality criteria that cannot be expressed as an IDBKeyRange prefix.\n */\nfunction compareWithOperator(a: unknown, op: SearchOperator, b: unknown): boolean {\n const av = a as string | number | null | undefined;\n const bv = b as string | number;\n switch (op) {\n case \"=\":\n return av === bv;\n case \"<\":\n return av !== null && av !== undefined && av < bv;\n case \"<=\":\n return av !== null && av !== undefined && av <= bv;\n case \">\":\n return av !== null && av !== undefined && av > bv;\n case \">=\":\n return av !== null && av !== undefined && av >= bv;\n }\n}\n",
33
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken, deepEqual, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { HybridSubscriptionManager } from \"../util/HybridSubscriptionManager\";\nimport {\n ensureIndexedDbTable,\n ExpectedIndexDefinition,\n MigrationOptions,\n} from \"../util/IndexedDbTable\";\nimport {\n BaseTabularStorage,\n ClientProvidedKeysOption,\n KeyGenerationStrategy,\n} from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\nimport { pickCoveringIndex } from \"./coveringIndexPicker\";\n\nexport const IDB_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.indexedDb\"\n);\n\n/**\n * Polling change-detection comparator for the hybrid subscription manager.\n *\n * Naively comparing entities via serialized equality is correct but\n * O(size-of-entity) per poll. That falls apart for tables\n * holding large blobs — e.g. an `activities` row whose `output_data` carries\n * a multi-megabyte `Uint8ClampedArray`: each poll cycle (default 1 s) would\n * stringify ~16 MB per row × N rows, locking the main thread.\n *\n * Fast path: if both rows expose a string `updated_at`, compare just those.\n * The repositories in this codebase bump `updated_at` on every write (see\n * `ActivityRepository.updateActivity`), so the timestamp is a sufficient\n * change witness. Fall back to the structural compare for tables that don't\n * follow that convention so correctness is preserved everywhere.\n */\nfunction compareEntitiesForChange<T>(a: T, b: T): boolean {\n const au = (a as { updated_at?: unknown })?.updated_at;\n const bu = (b as { updated_at?: unknown })?.updated_at;\n if (typeof au === \"string\" && typeof bu === \"string\") {\n return au === bu;\n }\n return deepEqual(a, b);\n}\n\n/**\n * A tabular repository implementation using IndexedDB for browser-based storage.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class IndexedDbTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n /** Promise that resolves to the IndexedDB database instance */\n private db: IDBDatabase | undefined;\n /** Promise to track ongoing database setup to prevent concurrent setup calls */\n private setupPromise: Promise<IDBDatabase> | null = null;\n /** Migration options for database schema changes */\n private migrationOptions: MigrationOptions;\n /** Shared hybrid subscription manager */\n private hybridManager: HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > | null = null;\n /** Hybrid subscription options */\n private readonly hybridOptions: {\n readonly useBroadcastChannel: boolean;\n readonly backupPollingIntervalMs: number;\n };\n /**\n * Indexes safe for cursor-based narrowing. An IDB index excludes records\n * whose keyPath has any undefined component, so iterating an index can miss\n * records when an indexed column is optional in the schema. Native\n * `count(range)` and cursor scans are only correct over indexes whose every\n * column is required. Computed lazily on first use.\n */\n private cursorSafeIndexes: Array<Array<keyof Entity>> | undefined;\n\n /**\n * Creates a new IndexedDB-based tabular repository.\n * @param table - Name of the IndexedDB store to use.\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param migrationOptions - Options for handling database schema migrations\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n public table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n migrationOptions: MigrationOptions & {\n readonly useBroadcastChannel?: boolean;\n readonly backupPollingIntervalMs?: number;\n } = {},\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.migrationOptions = migrationOptions;\n this.hybridOptions = {\n useBroadcastChannel: migrationOptions.useBroadcastChannel ?? true,\n backupPollingIntervalMs: migrationOptions.backupPollingIntervalMs ?? 5000,\n };\n }\n\n /**\n * Internal method to get the database, setting it up if needed.\n * This ensures lazy initialization of the database.\n */\n private async getDb(): Promise<IDBDatabase> {\n if (this.db) return this.db;\n await this.setupDatabase();\n return this.db!;\n }\n\n /**\n * Sets up the IndexedDB database table with the required schema and indexes.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n if (this.db) return;\n if (this.setupPromise) {\n await this.setupPromise;\n return;\n }\n\n this.setupPromise = this.performSetup();\n try {\n this.db = await this.setupPromise;\n } finally {\n this.setupPromise = null;\n }\n }\n\n /**\n * Internal method to perform the actual database setup\n */\n private async performSetup(): Promise<IDBDatabase> {\n const pkColumns = super.primaryKeyColumns() as string[];\n\n // Create index definitions for both single and compound indexes\n const expectedIndexes: ExpectedIndexDefinition[] = [];\n\n for (const spec of this.indexes) {\n // Handle compound index\n const columns = spec as Array<keyof Entity>;\n // Skip if this is just the primary key or a prefix of it\n if (columns.length <= pkColumns.length) {\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n\n // Create compound index name and keyPath\n const columnNames = columns.map((col) => String(col));\n const indexName = columnNames.join(\"_\");\n expectedIndexes.push({\n name: indexName,\n keyPath: columnNames.length === 1 ? columnNames[0] : columnNames,\n options: { unique: false },\n });\n }\n\n const primaryKey = pkColumns.length === 1 ? pkColumns[0] : pkColumns;\n\n // Determine if we should use autoIncrement\n // IndexedDB autoIncrement only works with single numeric keys\n const useAutoIncrement =\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyStrategy === \"autoincrement\" &&\n pkColumns.length === 1;\n\n // Ensure that our table is created/upgraded only if the structure (indexes) has changed.\n return await ensureIndexedDbTable(\n this.table,\n primaryKey,\n expectedIndexes,\n this.migrationOptions,\n useAutoIncrement\n );\n }\n\n /**\n * Generates a key value for UUID keys\n * Integer autoincrement keys are handled by IndexedDB's autoIncrement\n * @param columnName - Name of the column to generate a key for\n * @param strategy - The generation strategy to use\n * @returns The generated key value\n */\n protected override generateKeyValue(\n columnName: string,\n strategy: KeyGenerationStrategy\n ): string | number {\n if (strategy === \"uuid\") {\n return uuid4();\n }\n // autoincrement is handled by IndexedDB's autoIncrement option\n throw new Error(\n `IndexedDB autoincrement keys are generated by the database, not client-side. Column: ${columnName}`\n );\n }\n\n /**\n * Stores a row in the repository.\n * @param record - The entity to store (may be missing auto-generated keys).\n * @returns The stored entity\n * @emits put - Emitted when the value is successfully stored\n */\n async put(record: InsertType): Promise<Entity> {\n const db = await this.getDb();\n let recordToStore = record as unknown as Entity;\n\n // Handle auto-generated keys\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const clientProvidedValue = (record as Record<string, unknown>)[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // UUID generation - must be done client-side\n let shouldGenerate = false;\n if (this.clientProvidedKeys === \"never\") {\n shouldGenerate = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldGenerate = false;\n } else {\n // \"if-missing\"\n shouldGenerate = !hasClientValue;\n }\n\n if (shouldGenerate) {\n const generatedValue = this.generateKeyValue(keyName, \"uuid\");\n recordToStore = { ...record, [keyName]: generatedValue } as Entity;\n }\n } else if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // Autoincrement handled by IndexedDB\n // If clientProvidedKeys is \"always\", require the value\n if (this.clientProvidedKeys === \"always\" && !hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n // If clientProvidedKeys is \"never\", omit the key to let IDB generate\n if (this.clientProvidedKeys === \"never\") {\n const { [keyName]: _, ...rest } = record as Record<string, unknown>;\n recordToStore = rest as Entity;\n }\n // \"if-missing\": use client value if provided, omit if not\n }\n }\n\n // Merge key and value, ensuring all fields are at the root level for indexing\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.put(recordToStore);\n request.onerror = () => {\n reject(request.error);\n };\n request.onsuccess = () => {\n // For autoincrement keys, we need to update the record with the generated key\n if (\n this.hasAutoGeneratedKey() &&\n this.autoGeneratedKeyName &&\n this.autoGeneratedKeyStrategy === \"autoincrement\"\n ) {\n const keyName = String(this.autoGeneratedKeyName);\n if (recordToStore[keyName as keyof Entity] === undefined) {\n // Get the generated key from the request result\n recordToStore = { ...recordToStore, [keyName]: request.result } as Entity;\n }\n }\n this.events.emit(\"put\", recordToStore);\n resolve(recordToStore);\n };\n transaction.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * Stores multiple rows in the repository in a bulk operation.\n * @param records - Array of entities to store (may be missing auto-generated keys).\n * @returns Array of stored entities\n * @emits put - Emitted for each record successfully stored\n */\n async putBulk(records: InsertType[]): Promise<Entity[]> {\n // Use individual put calls to ensure auto-generated keys are handled correctly\n return await Promise.all(records.map((record) => this.put(record)));\n }\n\n protected override getPrimaryKeyAsOrderedArray(key: PrimaryKey) {\n return super\n .getPrimaryKeyAsOrderedArray(key)\n .map((value) => (typeof value === \"bigint\" ? value.toString() : value));\n }\n\n private getIndexedKey(key: PrimaryKey): any {\n const keys = super\n .getPrimaryKeyAsOrderedArray(key)\n .map((value) => (typeof value === \"bigint\" ? value.toString() : value));\n return keys.length === 1 ? keys[0] : keys;\n }\n\n /**\n * Retrieves a value from the repository by its key.\n * @param key - The key object.\n * @returns The value object or undefined if not found.\n * @emits get - Emitted when the value is successfully retrieved\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.get(this.getIndexedKey(key));\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n if (!request.result) {\n this.events.emit(\"get\", key, undefined);\n resolve(undefined);\n return;\n }\n this.events.emit(\"get\", key, request.result);\n resolve(request.result);\n };\n });\n }\n\n /**\n * Returns an array of all entries in the repository, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of all entries in the repository.\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n const db = await this.getDb();\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.getAll();\n return new Promise((resolve, reject) => {\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n let values: Entity[] = request.result;\n if (values.length === 0) {\n resolve(undefined);\n return;\n }\n\n if (options?.orderBy && options.orderBy.length > 0) {\n values.sort((a, b) => {\n for (const { column, direction } of options.orderBy!) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n });\n }\n\n if (options?.offset !== undefined) {\n values = values.slice(options.offset);\n }\n\n if (options?.limit !== undefined) {\n values = values.slice(0, options.limit);\n }\n\n resolve(values.length > 0 ? values : undefined);\n };\n });\n }\n\n /**\n * Deletes a row from the repository.\n * @param key - The key object to delete.\n */\n async delete(key: PrimaryKey): Promise<void> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.delete(this.getIndexedKey(key));\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.events.emit(\"delete\", key as keyof Entity);\n resolve();\n };\n transaction.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * Deletes all records from the repository.\n * @emits clearall - Emitted when all values are deleted\n */\n async deleteAll(): Promise<void> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n const request = store.clear();\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n this.events.emit(\"clearall\");\n resolve();\n };\n transaction.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n });\n }\n\n /**\n * Returns the total number of rows in the repository.\n * @returns Count of stored items.\n */\n async size(): Promise<number> {\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.count();\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n });\n }\n\n /**\n * Returns the subset of configured indexes safe to use for cursor-based\n * narrowing — those whose every column is required by the schema. IDB\n * excludes records with undefined keyPath components from indexes, so\n * iterating an index would silently miss records when any indexed column\n * is optional.\n */\n private getCursorSafeIndexes(): Array<Array<keyof Entity>> {\n if (this.cursorSafeIndexes) return this.cursorSafeIndexes;\n const required = new Set(this.schema.required ?? []);\n this.cursorSafeIndexes = this.indexes.filter((columns) =>\n columns.every((column) => required.has(String(column)))\n );\n return this.cursorSafeIndexes;\n }\n\n /**\n * Picks the best index to narrow a criteria-based scan, preferring indexes\n * whose prefix covers every criteria column (so callers can use the native\n * `count()` API) and falling back to the longest equality-prefix match.\n *\n * Upper bound uses `[]` as a sentinel that compares greater than any\n * primitive value at the next index position (per IndexedDB key ordering:\n * array > binary > string > date > number). Assumes subsequent indexed\n * columns hold primitive values — array-valued columns would compare\n * greater than `[]` and slip outside the range.\n */\n private createIndexedRange(\n store: IDBObjectStore,\n criteria: SearchCriteria<Entity>\n ):\n | {\n source: IDBObjectStore | IDBIndex;\n range: IDBKeyRange | undefined;\n coversCriteria: boolean;\n }\n | undefined {\n const criteriaColumns = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaColumns.length === 0) return undefined;\n\n let best:\n | {\n indexName: string;\n prefixValues: unknown[];\n fullMatch: boolean;\n coversCriteria: boolean;\n }\n | undefined;\n\n for (const indexColumns of this.getCursorSafeIndexes()) {\n const prefixValues: unknown[] = [];\n for (const column of indexColumns) {\n const value = this.getEqualityCriterionValue(criteria, column);\n if (value === undefined) break;\n prefixValues.push(value);\n }\n\n if (prefixValues.length === 0) continue;\n\n const indexedPrefix = indexColumns.slice(0, prefixValues.length);\n const coversCriteria = criteriaColumns.every((column) => indexedPrefix.includes(column));\n\n const better =\n !best ||\n (coversCriteria && !best.coversCriteria) ||\n (coversCriteria === best.coversCriteria && prefixValues.length > best.prefixValues.length);\n\n if (better) {\n best = {\n indexName: indexColumns.map((column) => String(column)).join(\"_\"),\n prefixValues,\n fullMatch: prefixValues.length === indexColumns.length,\n coversCriteria,\n };\n }\n }\n\n if (!best) return undefined;\n\n const range = best.fullMatch\n ? IDBKeyRange.only(best.prefixValues.length === 1 ? best.prefixValues[0] : best.prefixValues)\n : IDBKeyRange.bound(best.prefixValues, [...best.prefixValues, []]);\n\n return {\n source: store.index(best.indexName),\n range,\n coversCriteria: best.coversCriteria,\n };\n }\n\n /**\n * Counts rows matching the specified search criteria.\n *\n * Uses the native `count()` API when an index prefix covers every criteria\n * column. Otherwise narrows via the longest matching index prefix and\n * filters the remaining columns during cursor iteration. Falls back to a\n * full store scan only when no index applies.\n */\n override async count(criteria?: SearchCriteria<Entity>): Promise<number> {\n if (!criteria || Object.keys(criteria).length === 0) {\n return await this.size();\n }\n\n this.validateQueryParams(criteria);\n const db = await this.getDb();\n\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const plan = this.createIndexedRange(store, criteria);\n\n if (plan?.coversCriteria) {\n const request = plan.source.count(plan.range);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => resolve(request.result);\n return;\n }\n\n const source = plan?.source ?? store;\n const range = plan?.range;\n let count = 0;\n const request = source.openCursor(range);\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n resolve(count);\n return;\n }\n if (this.matchesCriteria(cursor.value as Entity, criteria)) {\n count += 1;\n }\n cursor.continue();\n };\n });\n }\n\n /**\n * Fetches a page of records from the repository.\n * @param offset - Number of records to skip\n * @param limit - Maximum number of records to return\n * @returns Array of entities or undefined if no records found\n */\n async getBulk(offset: number, limit: number): Promise<Entity[] | undefined> {\n if (offset < 0) {\n throw new RangeError(`offset must be non-negative, got ${offset}`);\n }\n if (limit <= 0) {\n return undefined;\n }\n\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const request = store.openCursor();\n const entities: Entity[] = [];\n let skipped = false;\n\n request.onerror = () => reject(request.error);\n request.onsuccess = () => {\n const cursor = request.result;\n if (cursor) {\n // Skip to offset using advance\n if (!skipped && offset > 0) {\n skipped = true;\n cursor.advance(offset);\n return;\n }\n\n // Collect records up to the limit\n entities.push(cursor.value);\n if (entities.length === limit) {\n resolve(entities);\n return;\n }\n cursor.continue();\n } else {\n // No more records\n resolve(entities.length > 0 ? entities : undefined);\n }\n };\n });\n }\n\n /**\n * Checks if a record matches all criteria conditions.\n * @param record - The record to check\n * @param criteria - The search criteria\n * @returns true if all conditions match\n */\n private matchesCriteria(record: Entity, criteria: DeleteSearchCriteria<Entity>): boolean {\n for (const column of Object.keys(criteria) as Array<keyof Entity>) {\n const criterion = criteria[column];\n const recordValue = record[column];\n\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n // Skip null values for comparison operators\n if (operator !== \"=\" && (recordValue === null || recordValue === undefined)) {\n return false;\n }\n\n switch (operator) {\n case \"=\":\n if (recordValue !== value) return false;\n break;\n case \"<\":\n if (!(recordValue < value)) return false;\n break;\n case \"<=\":\n if (!(recordValue <= value)) return false;\n break;\n case \">\":\n if (!(recordValue > value)) return false;\n break;\n case \">=\":\n if (!(recordValue >= value)) return false;\n break;\n default:\n return false;\n }\n }\n return true;\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Supports multiple columns with optional comparison operators.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n */\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaKeys.length === 0) {\n return;\n }\n\n const db = await this.getDb();\n\n return new Promise(async (resolve, reject) => {\n try {\n const transaction = db.transaction(this.table, \"readwrite\");\n const store = transaction.objectStore(this.table);\n\n // Set up transaction event handlers\n transaction.oncomplete = () => {\n this.events.emit(\"delete\", criteriaKeys[0] as keyof Entity);\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n\n transaction.onerror = () => {\n reject(transaction.error);\n };\n\n // Get all records and filter\n const getAllRequest = store.getAll();\n\n getAllRequest.onsuccess = () => {\n const allRecords: Entity[] = getAllRequest.result;\n\n // Filter records that match all criteria\n const recordsToDelete = allRecords.filter((record) =>\n this.matchesCriteria(record, criteria)\n );\n\n if (recordsToDelete.length === 0) {\n // No records to delete\n return;\n }\n\n // Delete each record that matches the criteria\n for (const record of recordsToDelete) {\n // Extract the primary key from the record\n const primaryKey = this.primaryKeyColumns().reduce((key, col) => {\n // @ts-ignore - We know these properties exist on the record\n key[col] = record[col];\n return key;\n }, {} as PrimaryKey);\n\n // Delete the record using the primary key\n const request = store.delete(this.getIndexedKey(primaryKey));\n\n request.onerror = () => {\n console.error(\"Error deleting record:\", request.error);\n };\n }\n };\n\n getAllRequest.onerror = () => {\n reject(getAllRequest.error);\n };\n } catch (error) {\n reject(error);\n }\n });\n }\n\n private getEqualityCriterionValue(\n criteria: SearchCriteria<Entity>,\n column: keyof Entity\n ): Entity[keyof Entity] | undefined {\n const criterion = criteria[column];\n if (criterion === undefined) return undefined;\n if (isSearchCondition(criterion)) {\n return criterion.operator === \"=\" ? (criterion.value as Entity[keyof Entity]) : undefined;\n }\n return criterion as Entity[keyof Entity];\n }\n\n private compareByOrder(a: Entity, b: Entity, options?: QueryOptions<Entity>): number {\n if (!options?.orderBy) return 0;\n for (const { column, direction } of options.orderBy) {\n const aVal = a[column] as string | number | null | undefined;\n const bVal = b[column] as string | number | null | undefined;\n if (aVal == null && bVal == null) continue;\n if (aVal == null) return direction === \"ASC\" ? -1 : 1;\n if (bVal == null) return direction === \"ASC\" ? 1 : -1;\n if (aVal < bVal) return direction === \"ASC\" ? -1 : 1;\n if (aVal > bVal) return direction === \"ASC\" ? 1 : -1;\n }\n return 0;\n }\n\n private createIndexedQuery(\n store: IDBObjectStore,\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): {\n source: IDBObjectStore | IDBIndex;\n range: IDBKeyRange | undefined;\n direction: IDBCursorDirection;\n satisfiesOrder: boolean;\n appliedLimit: boolean;\n appliedOffset: boolean;\n skipRemaining: number;\n } {\n const orderBy = options?.orderBy ?? [];\n let best:\n | {\n indexName: string;\n prefixValues: unknown[];\n fullMatch: boolean;\n satisfiesOrder: boolean;\n direction: IDBCursorDirection;\n }\n | undefined;\n\n for (const indexColumns of this.getCursorSafeIndexes()) {\n const prefixValues: unknown[] = [];\n for (const column of indexColumns) {\n const value = this.getEqualityCriterionValue(criteria, column);\n if (value === undefined) break;\n prefixValues.push(value);\n }\n\n if (prefixValues.length === 0) continue;\n\n const remainingColumns = indexColumns.slice(prefixValues.length);\n let redundantOrderPrefixLength = 0;\n while (\n redundantOrderPrefixLength < orderBy.length &&\n redundantOrderPrefixLength < prefixValues.length &&\n orderBy[redundantOrderPrefixLength]?.column === indexColumns[redundantOrderPrefixLength]\n ) {\n redundantOrderPrefixLength++;\n }\n const normalizedOrderBy = orderBy.slice(redundantOrderPrefixLength);\n const satisfiesOrder =\n normalizedOrderBy.length === 0 ||\n (normalizedOrderBy.length <= remainingColumns.length &&\n normalizedOrderBy.every((order, index) => order.column === remainingColumns[index]) &&\n orderBy.every((order) => order.direction === orderBy[0]?.direction));\n\n if (!satisfiesOrder && best) continue;\n\n if (\n !best ||\n (satisfiesOrder && !best.satisfiesOrder) ||\n prefixValues.length > best.prefixValues.length\n ) {\n best = {\n indexName: indexColumns.map((column) => String(column)).join(\"_\"),\n prefixValues,\n fullMatch: prefixValues.length === indexColumns.length,\n satisfiesOrder,\n direction: orderBy[0]?.direction === \"DESC\" ? \"prev\" : \"next\",\n };\n }\n }\n\n const appliedLimit = Boolean(best?.satisfiesOrder && options?.limit !== undefined);\n const appliedOffset = Boolean(best?.satisfiesOrder && options?.offset !== undefined);\n\n if (!best) {\n return {\n source: store,\n range: undefined,\n direction: orderBy[0]?.direction === \"DESC\" ? \"prev\" : \"next\",\n satisfiesOrder: false,\n appliedLimit: false,\n appliedOffset: false,\n skipRemaining: 0,\n };\n }\n\n const source = store.index(best.indexName);\n // See createIndexedRange for the `[]` upper-bound sentinel rationale.\n const keyRange = best.fullMatch\n ? IDBKeyRange.only(best.prefixValues.length === 1 ? best.prefixValues[0] : best.prefixValues)\n : IDBKeyRange.bound(best.prefixValues, [...best.prefixValues, []]);\n\n return {\n source,\n range: keyRange,\n direction: best.direction,\n satisfiesOrder: best.satisfiesOrder,\n appliedLimit,\n appliedOffset,\n skipRemaining: appliedOffset ? (options?.offset ?? 0) : 0,\n };\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering, limit, and offset.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of matching entities or undefined if no matches found\n */\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n this.validateQueryParams(criteria, options);\n const db = await this.getDb();\n\n return new Promise((resolve, reject) => {\n const transaction = db.transaction(this.table, \"readonly\");\n const store = transaction.objectStore(this.table);\n const indexedQuery = this.createIndexedQuery(store, criteria, options);\n const results: Entity[] = [];\n const request = indexedQuery.source.openCursor(indexedQuery.range, indexedQuery.direction);\n\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n let finalResults = results;\n\n if (!indexedQuery.satisfiesOrder && options?.orderBy && options.orderBy.length > 0) {\n finalResults = [...finalResults].sort((a, b) => this.compareByOrder(a, b, options));\n }\n\n if (!indexedQuery.appliedOffset && options?.offset !== undefined) {\n finalResults = finalResults.slice(options.offset);\n }\n\n if (!indexedQuery.appliedLimit && options?.limit !== undefined) {\n finalResults = finalResults.slice(0, options.limit);\n }\n\n const result = finalResults.length > 0 ? finalResults : undefined;\n this.events.emit(\"query\", criteria as Partial<Entity>, result);\n resolve(result);\n return;\n }\n\n const record = cursor.value as Entity;\n if (this.matchesCriteria(record, criteria)) {\n if (indexedQuery.skipRemaining > 0) {\n indexedQuery.skipRemaining -= 1;\n } else {\n results.push(record);\n if (indexedQuery.appliedLimit && results.length === options?.limit) {\n const result = results.length > 0 ? results : undefined;\n this.events.emit(\"query\", criteria as Partial<Entity>, result);\n resolve(result);\n return;\n }\n }\n }\n\n cursor.continue();\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Strict, projected query served entirely by a covering compound index.\n * Uses `openKeyCursor` — never reads `cursor.value` — so only the index key\n * bytes are loaded into memory. Ideal for tables with large value blobs.\n *\n * Throws {@link CoveringIndexMissingError} when no registered index can serve\n * the request (i.e. the index does not cover all select + orderBy columns).\n */\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n this.validateSelect(options);\n this.validateQueryParams(criteria, options);\n\n const registered = this.indexes.map((cols) => {\n const cs = Array.isArray(cols) ? (cols as string[]) : [cols as string];\n return { name: cs.join(\"_\"), keyPath: cs };\n });\n\n const picked = pickCoveringIndex({\n table: this.table,\n indexes: registered,\n criteriaColumns: Object.keys(criteria),\n orderByColumns: (options.orderBy ?? []).map((o) => ({\n column: String(o.column),\n direction: o.direction,\n })),\n selectColumns: options.select.map(String),\n primaryKeyColumns: this.primaryKeyColumns().map(String),\n });\n\n const db = await this.getDb();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.table, \"readonly\");\n const store = tx.objectStore(this.table);\n const idx = store.index(picked.name);\n\n // Build the equality prefix key range from criteria values.\n // Only push columns whose criterion is a direct equality value (plain value or operator \"=\").\n // Any non-equality operator (>, <, etc.) breaks the prefix; the existing in-cursor\n // compareWithOperator filter below handles those columns.\n const prefix: unknown[] = [];\n for (const col of picked.keyPath) {\n const c = (criteria as Record<string, unknown>)[col];\n if (c === undefined && !(col in (criteria as Record<string, unknown>))) break;\n if (isSearchCondition(c)) {\n if (c.operator !== \"=\") break;\n prefix.push(c.value);\n } else {\n prefix.push(c);\n }\n }\n // Use IDBKeyRange.bound with [] upper sentinel for prefix scans on compound keys.\n // `[...prefix, []]` is greater than any key starting with prefix in IDB's comparison.\n const range =\n prefix.length === 0\n ? undefined\n : prefix.length === picked.keyPath.length\n ? IDBKeyRange.only(prefix.length === 1 ? prefix[0] : prefix)\n : IDBKeyRange.bound(prefix, [...prefix, []]);\n\n const direction: IDBCursorDirection = picked.reverseDirection ? \"prev\" : \"next\";\n // openKeyCursor — never reads cursor.value, only the index key and primaryKey\n const request = idx.openKeyCursor(range, direction);\n const out: Pick<Entity, K>[] = [];\n let toSkip = options.offset ?? 0;\n\n // Precompute lookup maps for the cursor loop (O(keyPath) once, not per-row)\n const keyPathPositions = new Map<string, number>();\n picked.keyPath.forEach((col, i) => keyPathPositions.set(col, i));\n\n const pkCols = this.primaryKeyColumns().map(String);\n const pkPositions = new Map<string, number>();\n pkCols.forEach((col, i) => pkPositions.set(col, i));\n\n request.onsuccess = () => {\n const cursor = request.result;\n if (!cursor) {\n resolve(out);\n return;\n }\n\n const key = cursor.key;\n\n // Decode projected columns from the index key array and primaryKey\n const row = {} as Record<string, unknown>;\n for (const col of options.select) {\n const colStr = String(col);\n const pos = keyPathPositions.get(colStr);\n if (pos !== undefined) {\n // Column is in the index key path — extract from key array\n row[colStr] = Array.isArray(key) ? key[pos] : key;\n } else {\n // Column must be a primary key column — use cursor.primaryKey\n if (pkCols.length === 1 && colStr === pkCols[0]) {\n row[colStr] = cursor.primaryKey;\n } else {\n const pkPos = pkPositions.get(colStr);\n if (pkPos !== undefined) {\n row[colStr] = Array.isArray(cursor.primaryKey)\n ? (cursor.primaryKey as unknown[])[pkPos]\n : cursor.primaryKey;\n }\n }\n }\n }\n\n // Apply criteria for index positions beyond the equality prefix.\n // Positions [0, prefix.length) are guaranteed-equal by the IDBKeyRange,\n // so they don't need re-checking. Positions >= prefix.length must be\n // filtered here — this includes plain-value equalities trailing a\n // non-equality break (criteria like `{a:1, b:>=5, c:3}` with prefix=[1]\n // need an in-cursor `c === 3` check) and any SearchCondition.\n let matches = true;\n for (const [col, crit] of Object.entries(criteria as Record<string, unknown>)) {\n const pos = keyPathPositions.get(col);\n if (pos === undefined) continue;\n if (pos < prefix.length) continue; // covered by IDBKeyRange\n const valFromKey = Array.isArray(key) ? (key as unknown[])[pos] : key;\n const op: SearchOperator = isSearchCondition(crit) ? crit.operator : \"=\";\n const val = isSearchCondition(crit) ? crit.value : crit;\n if (!compareWithOperator(valFromKey, op, val)) {\n matches = false;\n break;\n }\n }\n\n if (matches) {\n if (toSkip > 0) {\n toSkip -= 1;\n } else {\n out.push(row as Pick<Entity, K>);\n if (options.limit !== undefined && out.length >= options.limit) {\n resolve(out);\n return;\n }\n }\n }\n\n cursor.continue();\n };\n\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Gets or creates the shared hybrid subscription manager.\n * This ensures all subscriptions share a single manager.\n */\n private getHybridManager(): HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n > {\n if (!this.hybridManager) {\n // Generate unique channel name based on table name\n const channelName = `indexeddb-tabular-${this.table}`;\n\n this.hybridManager = new HybridSubscriptionManager<\n Entity,\n string,\n TabularChangePayload<Entity>\n >(\n channelName,\n async () => {\n // Fetch all entities and create a map keyed by entity fingerprint\n const entities = (await this.getAll()) || [];\n const map = new Map<string, Entity>();\n for (const entity of entities) {\n const { key } = this.separateKeyValueFromCombined(entity);\n const fingerprint = await makeFingerprint(key);\n map.set(fingerprint, entity);\n }\n return map;\n },\n compareEntitiesForChange,\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n },\n {\n defaultIntervalMs: 1000,\n useBroadcastChannel: this.hybridOptions.useBroadcastChannel,\n backupPollingIntervalMs: this.hybridOptions.backupPollingIntervalMs,\n }\n );\n }\n return this.hybridManager;\n }\n\n /**\n * Subscribes to changes in the repository.\n * Uses polling since IndexedDB has no native cross-tab change notifications.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options including polling interval\n * @returns Unsubscribe function\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Note: We don't await setupDatabase() here to keep the method synchronous\n // The getAll() method in the hybrid manager will call setupDatabase() when needed\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n const manager = this.getHybridManager();\n return manager.subscribe(callback, { intervalMs });\n }\n\n /**\n * Destroys this repository and frees up resources.\n */\n public override destroy(): void {\n if (this.hybridManager) {\n this.hybridManager.destroy();\n this.hybridManager = null;\n }\n this.db?.close();\n }\n}\n\n/**\n * Compare two values using a SearchOperator. Used by queryIndex to evaluate\n * non-equality criteria that cannot be expressed as an IDBKeyRange prefix.\n */\nfunction compareWithOperator(a: unknown, op: SearchOperator, b: unknown): boolean {\n const av = a as string | number | null | undefined;\n const bv = b as string | number;\n switch (op) {\n case \"=\":\n return av === bv;\n case \"<\":\n return av !== null && av !== undefined && av < bv;\n case \"<=\":\n return av !== null && av !== undefined && av <= bv;\n case \">\":\n return av !== null && av !== undefined && av > bv;\n case \">=\":\n return av !== null && av !== undefined && av >= bv;\n }\n}\n",
34
34
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\n// Production-ready IndexedDB table management with proper migration support.\n// Handles schema evolution without data loss by incrementally migrating the database\n// structure and transforming existing data as needed.\n\nimport { deepEqual } from \"@workglow/util\";\n\nexport interface ExpectedIndexDefinition {\n name: string;\n keyPath: string | string[];\n options?: IDBIndexParameters;\n}\n\nexport interface MigrationContext {\n db: IDBDatabase;\n transaction: IDBTransaction;\n oldVersion: number;\n newVersion: number;\n tableName: string;\n}\n\nexport interface DataTransformer {\n (oldData: any): any | Promise<any>;\n}\n\nexport interface MigrationOptions {\n /** Custom data transformer to apply during migration */\n dataTransformer?: DataTransformer;\n /** Whether to allow destructive operations (delete and recreate). Default: false */\n allowDestructiveMigration?: boolean;\n /** Callback for migration progress/logging */\n onMigrationProgress?: (message: string, progress?: number) => void;\n /** Callback for migration errors (non-fatal warnings) */\n onMigrationWarning?: (message: string, error?: Error) => void;\n}\n\ninterface SchemaSnapshot {\n version: number;\n primaryKey: string | string[];\n indexes: ExpectedIndexDefinition[];\n recordCount?: number;\n timestamp: number;\n}\n\nconst METADATA_STORE_NAME = \"__schema_metadata__\";\n\n/**\n * Stores metadata about the database schema for migration tracking\n */\nasync function saveSchemaMetadata(\n db: IDBDatabase,\n tableName: string,\n snapshot: SchemaSnapshot\n): Promise<void> {\n return new Promise((resolve, reject) => {\n try {\n const transaction = db.transaction(METADATA_STORE_NAME, \"readwrite\");\n const store = transaction.objectStore(METADATA_STORE_NAME);\n const request = store.put({ ...snapshot, tableName }, tableName);\n\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n transaction.onerror = () => reject(transaction.error);\n } catch (err) {\n // Metadata store might not exist in old databases, that's OK\n resolve();\n }\n });\n}\n\n/**\n * Opens an IndexedDB database with proper error handling\n */\nasync function openIndexedDbTable(\n tableName: string,\n version?: number,\n upgradeNeededCallback?: (event: IDBVersionChangeEvent) => void\n): Promise<IDBDatabase> {\n return new Promise((resolve, reject) => {\n const openRequest = indexedDB.open(tableName, version);\n\n openRequest.onsuccess = (event) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n // Handle unexpected close\n db.onversionchange = () => {\n db.close();\n };\n\n resolve(db);\n };\n\n openRequest.onupgradeneeded = (event) => {\n if (upgradeNeededCallback) {\n upgradeNeededCallback(event);\n }\n };\n\n openRequest.onerror = () => {\n const error = openRequest.error;\n // Check if it's a VersionError - this means the database exists at a higher version\n if (error && error.name === \"VersionError\") {\n reject(\n new Error(\n `Database ${tableName} exists at a higher version. Cannot open at version ${version || \"current\"}.`\n )\n );\n } else {\n reject(error);\n }\n };\n openRequest.onblocked = () => {\n reject(\n new Error(`Database ${tableName} is blocked. Close all other tabs using this database.`)\n );\n };\n });\n}\n\n/**\n * Deletes an IndexedDB database completely\n */\nasync function deleteIndexedDbTable(tableName: string): Promise<void> {\n return new Promise((resolve, reject) => {\n const deleteRequest = indexedDB.deleteDatabase(tableName);\n\n deleteRequest.onsuccess = () => resolve();\n deleteRequest.onerror = () => reject(deleteRequest.error);\n deleteRequest.onblocked = () => {\n reject(\n new Error(`Cannot delete database ${tableName}. Close all other tabs using this database.`)\n );\n };\n });\n}\n\n/**\n * Compares two schema definitions to determine what changes are needed\n */\ninterface SchemaDiff {\n indexesToAdd: ExpectedIndexDefinition[];\n indexesToRemove: string[];\n indexesToModify: ExpectedIndexDefinition[];\n primaryKeyChanged: boolean;\n needsObjectStoreRecreation: boolean;\n}\n\nfunction compareSchemas(\n store: IDBObjectStore,\n expectedPrimaryKey: string | string[],\n expectedIndexes: ExpectedIndexDefinition[]\n): SchemaDiff {\n const diff: SchemaDiff = {\n indexesToAdd: [],\n indexesToRemove: [],\n indexesToModify: [],\n primaryKeyChanged: false,\n needsObjectStoreRecreation: false,\n };\n\n // Check primary key\n const actualKeyPath = store.keyPath;\n const normalizedExpected = Array.isArray(expectedPrimaryKey)\n ? expectedPrimaryKey\n : expectedPrimaryKey;\n const normalizedActual = Array.isArray(actualKeyPath) ? actualKeyPath : actualKeyPath;\n\n if (!deepEqual(normalizedExpected, normalizedActual)) {\n diff.primaryKeyChanged = true;\n diff.needsObjectStoreRecreation = true;\n return diff; // If primary key changed, we need full recreation\n }\n\n // Build a map of existing indexes\n const existingIndexes = new Map<string, IDBIndex>();\n for (let i = 0; i < store.indexNames.length; i++) {\n const indexName = store.indexNames[i];\n existingIndexes.set(indexName, store.index(indexName));\n }\n\n // Check for indexes to add or modify\n for (const expectedIdx of expectedIndexes) {\n const existingIdx = existingIndexes.get(expectedIdx.name);\n\n if (!existingIdx) {\n diff.indexesToAdd.push(expectedIdx);\n } else {\n // Compare index properties\n const expectedKeyPath = Array.isArray(expectedIdx.keyPath)\n ? expectedIdx.keyPath\n : [expectedIdx.keyPath];\n const actualKeyPath = Array.isArray(existingIdx.keyPath)\n ? existingIdx.keyPath\n : [existingIdx.keyPath];\n\n const keyPathChanged = !deepEqual(expectedKeyPath, actualKeyPath);\n const uniqueChanged = existingIdx.unique !== (expectedIdx.options?.unique ?? false);\n const multiEntryChanged =\n existingIdx.multiEntry !== (expectedIdx.options?.multiEntry ?? false);\n\n if (keyPathChanged || uniqueChanged || multiEntryChanged) {\n diff.indexesToModify.push(expectedIdx);\n }\n\n existingIndexes.delete(expectedIdx.name);\n }\n }\n\n // Remaining indexes should be removed\n diff.indexesToRemove = Array.from(existingIndexes.keys());\n\n return diff;\n}\n\n/**\n * Reads all data from a store\n */\nasync function readAllData(store: IDBObjectStore): Promise<any[]> {\n return new Promise((resolve, reject) => {\n const request = store.getAll();\n request.onsuccess = () => resolve(request.result || []);\n request.onerror = () => reject(request.error);\n });\n}\n\n/**\n * Performs a non-destructive migration by adding/removing indexes\n */\nasync function performIncrementalMigration(\n db: IDBDatabase,\n tableName: string,\n diff: SchemaDiff,\n options: MigrationOptions = {}\n): Promise<IDBDatabase> {\n const currentVersion = db.version;\n const newVersion = currentVersion + 1;\n\n db.close();\n\n options.onMigrationProgress?.(\n `Migrating ${tableName} from version ${currentVersion} to ${newVersion}...`,\n 0\n );\n\n return openIndexedDbTable(tableName, newVersion, (event: IDBVersionChangeEvent) => {\n const transaction = (event.target as IDBOpenDBRequest).transaction!;\n const store = transaction.objectStore(tableName);\n\n // Remove outdated indexes\n for (const indexName of diff.indexesToRemove) {\n options.onMigrationProgress?.(`Removing index: ${indexName}`, 0.2);\n store.deleteIndex(indexName);\n }\n\n // Remove and recreate modified indexes\n for (const indexDef of diff.indexesToModify) {\n options.onMigrationProgress?.(`Updating index: ${indexDef.name}`, 0.4);\n if (store.indexNames.contains(indexDef.name)) {\n store.deleteIndex(indexDef.name);\n }\n store.createIndex(indexDef.name, indexDef.keyPath, indexDef.options);\n }\n\n // Add new indexes\n for (const indexDef of diff.indexesToAdd) {\n options.onMigrationProgress?.(`Adding index: ${indexDef.name}`, 0.6);\n store.createIndex(indexDef.name, indexDef.keyPath, indexDef.options);\n }\n\n options.onMigrationProgress?.(`Migration complete`, 1.0);\n });\n}\n\n/**\n * Performs a destructive migration by recreating the object store\n * This is needed when the primary key changes\n */\nasync function performDestructiveMigration(\n db: IDBDatabase,\n tableName: string,\n primaryKey: string | string[],\n expectedIndexes: ExpectedIndexDefinition[],\n options: MigrationOptions = {},\n autoIncrement: boolean = false\n): Promise<IDBDatabase> {\n if (!options.allowDestructiveMigration) {\n throw new Error(\n `Destructive migration required for ${tableName} but not allowed. ` +\n `Primary key has changed. Set allowDestructiveMigration=true to proceed with data loss, ` +\n `or provide a dataTransformer to migrate data.`\n );\n }\n\n const currentVersion = db.version;\n const newVersion = currentVersion + 1;\n\n options.onMigrationProgress?.(\n `Performing destructive migration of ${tableName}. Reading existing data...`,\n 0\n );\n\n // Read all existing data\n let existingData: any[] = [];\n try {\n const transaction = db.transaction(tableName, \"readonly\");\n const store = transaction.objectStore(tableName);\n existingData = await readAllData(store);\n options.onMigrationProgress?.(`Read ${existingData.length} records`, 0.3);\n } catch (err) {\n options.onMigrationWarning?.(\n `Failed to read existing data during migration: ${err}`,\n err as Error\n );\n }\n\n db.close();\n\n // Apply data transformer if provided\n if (options.dataTransformer && existingData.length > 0) {\n options.onMigrationProgress?.(`Transforming ${existingData.length} records...`, 0.4);\n try {\n const transformed = [];\n for (let i = 0; i < existingData.length; i++) {\n const record = existingData[i];\n const transformedRecord = await options.dataTransformer(record);\n if (transformedRecord !== undefined && transformedRecord !== null) {\n transformed.push(transformedRecord);\n }\n if (i % 100 === 0) {\n options.onMigrationProgress?.(\n `Transformed ${i}/${existingData.length} records`,\n 0.4 + (i / existingData.length) * 0.3\n );\n }\n }\n existingData = transformed;\n options.onMigrationProgress?.(`Transformation complete: ${existingData.length} records`, 0.7);\n } catch (err) {\n options.onMigrationWarning?.(\n `Data transformation failed: ${err}. Some data may be lost.`,\n err as Error\n );\n existingData = [];\n }\n }\n\n // Open with new version and recreate object store\n options.onMigrationProgress?.(`Recreating object store...`, 0.75);\n\n const newDb = await openIndexedDbTable(tableName, newVersion, (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n // Delete old object store if it exists\n if (db.objectStoreNames.contains(tableName)) {\n db.deleteObjectStore(tableName);\n }\n\n // Create new object store with new schema\n const store = db.createObjectStore(tableName, { keyPath: primaryKey, autoIncrement });\n\n // Create indexes\n for (const idx of expectedIndexes) {\n store.createIndex(idx.name, idx.keyPath, idx.options);\n }\n\n // Restore data\n if (existingData.length > 0) {\n options.onMigrationProgress?.(`Restoring ${existingData.length} records...`, 0.8);\n\n for (const record of existingData) {\n try {\n store.put(record);\n } catch (err) {\n options.onMigrationWarning?.(`Failed to restore record: ${err}`, err as Error);\n }\n }\n }\n });\n\n options.onMigrationProgress?.(`Destructive migration complete`, 1.0);\n\n return newDb;\n}\n\n/**\n * Creates a new database with the specified schema\n */\nasync function createNewDatabase(\n tableName: string,\n primaryKey: string | string[],\n expectedIndexes: ExpectedIndexDefinition[],\n options: MigrationOptions = {},\n autoIncrement: boolean = false\n): Promise<IDBDatabase> {\n options.onMigrationProgress?.(`Creating new database: ${tableName}`, 0);\n\n // Delete existing database if it exists to avoid version conflicts\n try {\n await deleteIndexedDbTable(tableName);\n // Wait a bit for deletion to complete\n await new Promise((resolve) => setTimeout(resolve, 50));\n } catch (err) {\n // Ignore errors - database might not exist\n }\n\n const version = 1;\n\n const db = await openIndexedDbTable(tableName, version, (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n // Create metadata store\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n db.createObjectStore(METADATA_STORE_NAME, { keyPath: \"tableName\" });\n }\n\n // Create main object store\n const store = db.createObjectStore(tableName, { keyPath: primaryKey, autoIncrement });\n\n // Create indexes\n for (const idx of expectedIndexes) {\n store.createIndex(idx.name, idx.keyPath, idx.options);\n }\n });\n\n // Save schema metadata\n const snapshot: SchemaSnapshot = {\n version: db.version,\n primaryKey,\n indexes: expectedIndexes,\n recordCount: 0,\n timestamp: Date.now(),\n };\n\n await saveSchemaMetadata(db, tableName, snapshot);\n\n options.onMigrationProgress?.(`Database created successfully`, 1.0);\n\n return db;\n}\n\n/**\n * Ensures that an IndexedDB table exists with the specified schema.\n * Performs migrations as needed without data loss when possible.\n */\nexport async function ensureIndexedDbTable(\n tableName: string,\n primaryKey: string | string[],\n expectedIndexes: ExpectedIndexDefinition[] = [],\n options: MigrationOptions = {},\n autoIncrement: boolean = false\n): Promise<IDBDatabase> {\n try {\n // Try to open existing database at current version (or create if doesn't exist)\n let db: IDBDatabase;\n let wasJustCreated = false;\n try {\n // Open without version - this will open at current version if exists, or create at version 1 if doesn't exist\n db = await openIndexedDbTable(tableName);\n\n // Check if database was just created (version 1 and no object stores)\n // This happens when indexedDB.open creates a new database without stores\n if (db.version === 1 && !db.objectStoreNames.contains(tableName)) {\n wasJustCreated = true;\n db.close();\n }\n } catch (err: any) {\n // If opening fails, database might not exist or there's a version conflict\n // Try to create it fresh\n options.onMigrationProgress?.(\n `Database ${tableName} does not exist or has version conflict, creating...`,\n 0\n );\n return await createNewDatabase(\n tableName,\n primaryKey,\n expectedIndexes,\n options,\n autoIncrement\n );\n }\n\n // If database was just created, we need to create the stores\n // We'll upgrade from version 1 to version 1 (which triggers onupgradeneeded with oldVersion=0)\n // Actually, we need to explicitly create at version 1 with stores\n if (wasJustCreated) {\n options.onMigrationProgress?.(`Creating new database: ${tableName}`, 0);\n // Delete the empty database and create it properly at version 1\n try {\n await deleteIndexedDbTable(tableName);\n await new Promise((resolve) => setTimeout(resolve, 50));\n } catch (err) {\n // Ignore errors\n }\n\n // Create at version 1 with stores\n db = await openIndexedDbTable(tableName, 1, (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n\n // Create metadata store\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n db.createObjectStore(METADATA_STORE_NAME, { keyPath: \"tableName\" });\n }\n\n // Create main object store\n const store = db.createObjectStore(tableName, { keyPath: primaryKey, autoIncrement });\n\n // Create indexes\n for (const idx of expectedIndexes) {\n store.createIndex(idx.name, idx.keyPath, idx.options);\n }\n });\n\n // Save schema metadata\n const snapshot: SchemaSnapshot = {\n version: db.version,\n primaryKey,\n indexes: expectedIndexes,\n recordCount: 0,\n timestamp: Date.now(),\n };\n await saveSchemaMetadata(db, tableName, snapshot);\n\n options.onMigrationProgress?.(`Database created successfully`, 1.0);\n return db;\n }\n\n // Ensure metadata store exists\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n const currentVersion = db.version;\n db.close();\n\n db = await openIndexedDbTable(\n tableName,\n currentVersion + 1,\n (event: IDBVersionChangeEvent) => {\n const db = (event.target as IDBOpenDBRequest).result;\n if (!db.objectStoreNames.contains(METADATA_STORE_NAME)) {\n db.createObjectStore(METADATA_STORE_NAME, { keyPath: \"tableName\" });\n }\n }\n );\n }\n\n // Check if table structure matches expected\n if (!db.objectStoreNames.contains(tableName)) {\n // Object store doesn't exist, create it\n options.onMigrationProgress?.(`Object store ${tableName} does not exist, creating...`, 0);\n db.close();\n return await createNewDatabase(\n tableName,\n primaryKey,\n expectedIndexes,\n options,\n autoIncrement\n );\n }\n\n // Compare schemas to determine what migration is needed\n const transaction = db.transaction(tableName, \"readonly\");\n const store = transaction.objectStore(tableName);\n const diff = compareSchemas(store, primaryKey, expectedIndexes);\n\n await new Promise<void>((resolve) => {\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => resolve();\n });\n\n // Determine migration strategy\n const needsMigration =\n diff.indexesToAdd.length > 0 ||\n diff.indexesToRemove.length > 0 ||\n diff.indexesToModify.length > 0 ||\n diff.needsObjectStoreRecreation;\n\n if (!needsMigration) {\n // Schema matches, no migration needed\n options.onMigrationProgress?.(`Schema for ${tableName} is up to date`, 1.0);\n\n // Update metadata anyway to keep timestamp current\n const snapshot: SchemaSnapshot = {\n version: db.version,\n primaryKey,\n indexes: expectedIndexes,\n timestamp: Date.now(),\n };\n await saveSchemaMetadata(db, tableName, snapshot);\n\n return db;\n }\n\n // Perform appropriate migration\n if (diff.needsObjectStoreRecreation) {\n options.onMigrationProgress?.(\n `Schema change requires object store recreation for ${tableName}`,\n 0\n );\n db = await performDestructiveMigration(\n db,\n tableName,\n primaryKey,\n expectedIndexes,\n options,\n autoIncrement\n );\n } else {\n options.onMigrationProgress?.(`Performing incremental migration for ${tableName}`, 0);\n db = await performIncrementalMigration(db, tableName, diff, options);\n }\n\n // Save updated metadata\n const snapshot: SchemaSnapshot = {\n version: db.version,\n primaryKey,\n indexes: expectedIndexes,\n timestamp: Date.now(),\n };\n await saveSchemaMetadata(db, tableName, snapshot);\n\n return db;\n } catch (err) {\n options.onMigrationWarning?.(`Migration failed for ${tableName}: ${err}`, err as Error);\n throw err;\n }\n}\n\n/**\n * Utility function to delete a database (for testing or cleanup)\n */\nexport async function dropIndexedDbTable(tableName: string): Promise<void> {\n return deleteIndexedDbTable(tableName);\n}\n",
35
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken } from \"@workglow/util\";\nimport { BaseTabularStorage, ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n DeleteSearchCriteria,\n InsertEntity,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\nimport { InMemoryTabularStorage } from \"./InMemoryTabularStorage\";\n\nexport const SHARED_IN_MEMORY_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.sharedInMemory\"\n);\n\nconst SYNC_TIMEOUT = 1000;\nconst MAX_PENDING_MESSAGES = 1000;\n\n/**\n * Message types for BroadcastChannel communication\n */\ntype BroadcastMessage =\n | { type: \"SYNC_REQUEST\" }\n | { type: \"SYNC_RESPONSE\"; data: any[] }\n | { type: \"PUT\"; entity: any }\n | { type: \"PUT_BULK\"; entities: any[] }\n | { type: \"DELETE\"; key: any }\n | { type: \"DELETE_ALL\" }\n | { type: \"DELETE_SEARCH\"; criteria: DeleteSearchCriteria<any> };\n\n/**\n * A tabular repository implementation that shares data across browser tabs/windows\n * using BroadcastChannel API. Uses InMemoryTabularStorage internally and\n * synchronizes changes across all instances.\n *\n * @template Schema - The schema definition for the entity using JSON Schema\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class SharedInMemoryTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n private channel: BroadcastChannel | null = null;\n private channelName: string;\n private inMemoryRepo: InMemoryTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>;\n private isInitialized = false;\n private syncInProgress = false;\n private pendingMessages: BroadcastMessage[] = [];\n\n /**\n * Creates a new SharedInMemoryTabularStorage instance\n * @param channelName - Unique name for the BroadcastChannel (defaults to \"tabular_store\")\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n channelName: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.channelName = channelName;\n this.inMemoryRepo = new InMemoryTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>(\n schema,\n primaryKeyNames,\n indexes,\n clientProvidedKeys\n );\n\n this.setupEventForwarding();\n\n this.initializeBroadcastChannel();\n }\n\n /**\n * Checks if BroadcastChannel is available in the current environment\n */\n private isBroadcastChannelAvailable(): boolean {\n return typeof BroadcastChannel !== \"undefined\";\n }\n\n /**\n * Initializes the BroadcastChannel and sets up message handlers\n */\n private initializeBroadcastChannel(): void {\n if (!this.isBroadcastChannelAvailable()) {\n console.warn(\"BroadcastChannel is not available. Tab synchronization will not work.\");\n return;\n }\n\n try {\n this.channel = new BroadcastChannel(this.channelName);\n this.channel.onmessage = (event: MessageEvent<BroadcastMessage>) => {\n this.handleBroadcastMessage(event.data);\n };\n\n // Request sync from other tabs on initialization\n this.syncFromOtherTabs();\n } catch (error) {\n console.error(\"Failed to initialize BroadcastChannel:\", error);\n }\n }\n\n /**\n * Sets up event forwarding from the internal InMemoryTabularStorage\n */\n private setupEventForwarding(): void {\n this.inMemoryRepo.on(\"put\", (entity) => {\n this.events.emit(\"put\", entity);\n });\n this.inMemoryRepo.on(\"get\", (key, entity) => {\n this.events.emit(\"get\", key, entity);\n });\n this.inMemoryRepo.on(\"query\", (key, entities) => {\n this.events.emit(\"query\", key, entities);\n });\n this.inMemoryRepo.on(\"delete\", (key) => {\n this.events.emit(\"delete\", key);\n });\n this.inMemoryRepo.on(\"clearall\", () => {\n this.events.emit(\"clearall\");\n });\n }\n\n /**\n * Handles incoming BroadcastChannel messages\n */\n private async handleBroadcastMessage(message: BroadcastMessage): Promise<void> {\n if (this.syncInProgress && message.type !== \"SYNC_RESPONSE\") {\n // Queue messages during sync to replay after sync completes\n if (this.pendingMessages.length < MAX_PENDING_MESSAGES) {\n this.pendingMessages.push(message);\n }\n return;\n }\n\n switch (message.type) {\n case \"SYNC_REQUEST\":\n // Respond to sync request with current data\n const all = await this.inMemoryRepo.getAll();\n if (this.channel && all) {\n this.channel.postMessage({\n type: \"SYNC_RESPONSE\",\n data: all,\n } as BroadcastMessage);\n }\n break;\n\n case \"SYNC_RESPONSE\":\n // Copy data from the responding tab\n if (message.data && Array.isArray(message.data)) {\n await this.copyDataFromArray(message.data);\n }\n this.syncInProgress = false;\n await this.drainPendingMessages();\n break;\n\n case \"PUT\":\n // Apply put from another tab\n await this.inMemoryRepo.put(message.entity);\n break;\n\n case \"PUT_BULK\":\n // Apply bulk put from another tab\n await this.inMemoryRepo.putBulk(message.entities);\n break;\n\n case \"DELETE\":\n // Apply delete from another tab\n await this.inMemoryRepo.delete(message.key);\n break;\n\n case \"DELETE_ALL\":\n // Apply deleteAll from another tab\n await this.inMemoryRepo.deleteAll();\n break;\n\n case \"DELETE_SEARCH\":\n // Apply deleteSearch from another tab\n await this.inMemoryRepo.deleteSearch(message.criteria as DeleteSearchCriteria<Entity>);\n break;\n }\n }\n\n /**\n * Drains pending messages that were queued during sync.\n * Uses a while loop to handle messages that may be re-queued during draining\n * (e.g., if a replayed message triggers a new sync cycle).\n */\n private async drainPendingMessages(): Promise<void> {\n while (!this.syncInProgress && this.pendingMessages.length > 0) {\n const messages = this.pendingMessages;\n this.pendingMessages = [];\n for (const message of messages) {\n await this.handleBroadcastMessage(message);\n if (this.syncInProgress) {\n break;\n }\n }\n }\n }\n\n /**\n * Requests synchronization from other tabs\n */\n private syncFromOtherTabs(): void {\n if (!this.channel) return;\n\n this.syncInProgress = true;\n this.channel.postMessage({ type: \"SYNC_REQUEST\" } as BroadcastMessage);\n\n // Set a timeout to stop waiting for sync response\n setTimeout(() => {\n if (this.syncInProgress) {\n this.syncInProgress = false;\n void this.drainPendingMessages().catch((error) => {\n console.error(\"Failed to drain pending messages after sync timeout\", error);\n });\n }\n }, SYNC_TIMEOUT);\n }\n\n /**\n * Copies data from an array of entities into the repository\n */\n private async copyDataFromArray(entities: Entity[]): Promise<void> {\n if (entities.length === 0) return;\n\n // Clear existing data\n await this.inMemoryRepo.deleteAll();\n\n // Bulk insert the new data\n await this.inMemoryRepo.putBulk(entities);\n }\n\n /**\n * Broadcasts a message to other tabs\n */\n private broadcast(message: BroadcastMessage): void {\n if (this.channel) {\n this.channel.postMessage(message);\n }\n }\n\n /**\n * Sets up the database for the repository (syncs from other tabs)\n */\n public override async setupDatabase(): Promise<void> {\n if (this.isInitialized) return;\n this.isInitialized = true;\n await this.syncFromOtherTabs();\n }\n\n /**\n * Stores a key-value pair in the repository\n * @param value - The combined object to store\n * @returns The stored entity\n * @emits 'put' event with the stored entity when successful\n */\n public async put(value: InsertType): Promise<Entity> {\n const result = await this.inMemoryRepo.put(value);\n this.broadcast({ type: \"PUT\", entity: result });\n return result;\n }\n\n /**\n * Stores multiple key-value pairs in the repository in a bulk operation\n * @param values - Array of combined objects to store\n * @returns Array of stored entities\n * @emits 'put' event for each value stored\n */\n public async putBulk(values: InsertType[]): Promise<Entity[]> {\n const result = await this.inMemoryRepo.putBulk(values);\n this.broadcast({ type: \"PUT_BULK\", entities: result });\n return result;\n }\n\n /**\n * Retrieves a value by its key\n * @param key - The primary key object to look up\n * @returns The value object if found, undefined otherwise\n * @emits 'get' event with the fingerprint ID and value when found\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n return await this.inMemoryRepo.get(key);\n }\n\n /**\n * Deletes an entry by its key\n * @param value - The primary key object or entity of the entry to delete\n * @emits 'delete' event with the fingerprint ID when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n await this.inMemoryRepo.delete(value);\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n this.broadcast({ type: \"DELETE\", key });\n }\n\n /**\n * Removes all entries from the repository\n * @emits 'clearall' event when successful\n */\n async deleteAll(): Promise<void> {\n await this.inMemoryRepo.deleteAll();\n this.broadcast({ type: \"DELETE_ALL\" });\n }\n\n /**\n * Returns an array of all entries in the repository, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of all entries in the repository\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n return await this.inMemoryRepo.getAll(options);\n }\n\n /**\n * Returns the number of entries in the repository\n * @returns The total count of stored entries\n */\n async size(): Promise<number> {\n return await this.inMemoryRepo.size();\n }\n\n /**\n * Fetches a page of records from the repository.\n * @param offset - Number of records to skip\n * @param limit - Maximum number of records to return\n * @returns Array of entities or undefined if no records found\n */\n async getBulk(offset: number, limit: number): Promise<Entity[] | undefined> {\n return await this.inMemoryRepo.getBulk(offset, limit);\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering and limit.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering and limit options\n * @returns Array of matching entities or undefined if no matches found\n */\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n return await this.inMemoryRepo.query(criteria, options);\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Supports multiple columns with optional comparison operators.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n */\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n await this.inMemoryRepo.deleteSearch(criteria);\n this.broadcast({\n type: \"DELETE_SEARCH\",\n criteria,\n });\n }\n\n /**\n * Subscribes to changes in the repository.\n * Delegates to the internal InMemoryTabularStorage which monitors local changes.\n * Changes from other tabs/windows are already propagated via BroadcastChannel.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (not used for in-memory)\n * @returns Unsubscribe function\n */\n public override subscribeToChanges(\n callback: (change: any) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n return this.inMemoryRepo.subscribeToChanges(callback, options);\n }\n\n /**\n * Cleanup method to close the BroadcastChannel\n */\n public override destroy(): void {\n if (this.channel) {\n this.channel.close();\n this.channel = null;\n }\n this.inMemoryRepo.destroy();\n }\n}\n",
35
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { DataPortSchemaObject, FromSchema, TypedArraySchemaOptions } from \"@workglow/util/schema\";\nimport { createServiceToken } from \"@workglow/util\";\nimport { BaseTabularStorage, ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n TabularSubscribeOptions,\n} from \"./ITabularStorage\";\nimport { InMemoryTabularStorage } from \"./InMemoryTabularStorage\";\n\nexport const SHARED_IN_MEMORY_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.sharedInMemory\"\n);\n\nconst SYNC_TIMEOUT = 1000;\nconst MAX_PENDING_MESSAGES = 1000;\n\n/**\n * Message types for BroadcastChannel communication\n */\ntype BroadcastMessage =\n | { type: \"SYNC_REQUEST\" }\n | { type: \"SYNC_RESPONSE\"; data: any[] }\n | { type: \"PUT\"; entity: any }\n | { type: \"PUT_BULK\"; entities: any[] }\n | { type: \"DELETE\"; key: any }\n | { type: \"DELETE_ALL\" }\n | { type: \"DELETE_SEARCH\"; criteria: DeleteSearchCriteria<any> };\n\n/**\n * A tabular repository implementation that shares data across browser tabs/windows\n * using BroadcastChannel API. Uses InMemoryTabularStorage internally and\n * synchronizes changes across all instances.\n *\n * @template Schema - The schema definition for the entity using JSON Schema\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class SharedInMemoryTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n private channel: BroadcastChannel | null = null;\n private channelName: string;\n private inMemoryRepo: InMemoryTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>;\n private isInitialized = false;\n private syncInProgress = false;\n private pendingMessages: BroadcastMessage[] = [];\n\n /**\n * Creates a new SharedInMemoryTabularStorage instance\n * @param channelName - Unique name for the BroadcastChannel (defaults to \"tabular_store\")\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n channelName: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.channelName = channelName;\n this.inMemoryRepo = new InMemoryTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey>(\n schema,\n primaryKeyNames,\n indexes,\n clientProvidedKeys\n );\n\n this.setupEventForwarding();\n\n this.initializeBroadcastChannel();\n }\n\n /**\n * Checks if BroadcastChannel is available in the current environment\n */\n private isBroadcastChannelAvailable(): boolean {\n return typeof BroadcastChannel !== \"undefined\";\n }\n\n /**\n * Initializes the BroadcastChannel and sets up message handlers\n */\n private initializeBroadcastChannel(): void {\n if (!this.isBroadcastChannelAvailable()) {\n console.warn(\"BroadcastChannel is not available. Tab synchronization will not work.\");\n return;\n }\n\n try {\n this.channel = new BroadcastChannel(this.channelName);\n this.channel.onmessage = (event: MessageEvent<BroadcastMessage>) => {\n this.handleBroadcastMessage(event.data);\n };\n\n // Request sync from other tabs on initialization\n this.syncFromOtherTabs();\n } catch (error) {\n console.error(\"Failed to initialize BroadcastChannel:\", error);\n }\n }\n\n /**\n * Sets up event forwarding from the internal InMemoryTabularStorage\n */\n private setupEventForwarding(): void {\n this.inMemoryRepo.on(\"put\", (entity) => {\n this.events.emit(\"put\", entity);\n });\n this.inMemoryRepo.on(\"get\", (key, entity) => {\n this.events.emit(\"get\", key, entity);\n });\n this.inMemoryRepo.on(\"query\", (key, entities) => {\n this.events.emit(\"query\", key, entities);\n });\n this.inMemoryRepo.on(\"delete\", (key) => {\n this.events.emit(\"delete\", key);\n });\n this.inMemoryRepo.on(\"clearall\", () => {\n this.events.emit(\"clearall\");\n });\n }\n\n /**\n * Handles incoming BroadcastChannel messages\n */\n private async handleBroadcastMessage(message: BroadcastMessage): Promise<void> {\n if (this.syncInProgress && message.type !== \"SYNC_RESPONSE\") {\n // Queue messages during sync to replay after sync completes\n if (this.pendingMessages.length < MAX_PENDING_MESSAGES) {\n this.pendingMessages.push(message);\n }\n return;\n }\n\n switch (message.type) {\n case \"SYNC_REQUEST\":\n // Respond to sync request with current data\n const all = await this.inMemoryRepo.getAll();\n if (this.channel && all) {\n this.channel.postMessage({\n type: \"SYNC_RESPONSE\",\n data: all,\n } as BroadcastMessage);\n }\n break;\n\n case \"SYNC_RESPONSE\":\n // Copy data from the responding tab\n if (message.data && Array.isArray(message.data)) {\n await this.copyDataFromArray(message.data);\n }\n this.syncInProgress = false;\n await this.drainPendingMessages();\n break;\n\n case \"PUT\":\n // Apply put from another tab\n await this.inMemoryRepo.put(message.entity);\n break;\n\n case \"PUT_BULK\":\n // Apply bulk put from another tab\n await this.inMemoryRepo.putBulk(message.entities);\n break;\n\n case \"DELETE\":\n // Apply delete from another tab\n await this.inMemoryRepo.delete(message.key);\n break;\n\n case \"DELETE_ALL\":\n // Apply deleteAll from another tab\n await this.inMemoryRepo.deleteAll();\n break;\n\n case \"DELETE_SEARCH\":\n // Apply deleteSearch from another tab\n await this.inMemoryRepo.deleteSearch(message.criteria as DeleteSearchCriteria<Entity>);\n break;\n }\n }\n\n /**\n * Drains pending messages that were queued during sync.\n * Uses a while loop to handle messages that may be re-queued during draining\n * (e.g., if a replayed message triggers a new sync cycle).\n */\n private async drainPendingMessages(): Promise<void> {\n while (!this.syncInProgress && this.pendingMessages.length > 0) {\n const messages = this.pendingMessages;\n this.pendingMessages = [];\n for (const message of messages) {\n await this.handleBroadcastMessage(message);\n if (this.syncInProgress) {\n break;\n }\n }\n }\n }\n\n /**\n * Requests synchronization from other tabs\n */\n private syncFromOtherTabs(): void {\n if (!this.channel) return;\n\n this.syncInProgress = true;\n this.channel.postMessage({ type: \"SYNC_REQUEST\" } as BroadcastMessage);\n\n // Set a timeout to stop waiting for sync response\n setTimeout(() => {\n if (this.syncInProgress) {\n this.syncInProgress = false;\n void this.drainPendingMessages().catch((error) => {\n console.error(\"Failed to drain pending messages after sync timeout\", error);\n });\n }\n }, SYNC_TIMEOUT);\n }\n\n /**\n * Copies data from an array of entities into the repository\n */\n private async copyDataFromArray(entities: Entity[]): Promise<void> {\n if (entities.length === 0) return;\n\n // Clear existing data\n await this.inMemoryRepo.deleteAll();\n\n // Bulk insert the new data\n await this.inMemoryRepo.putBulk(entities);\n }\n\n /**\n * Broadcasts a message to other tabs\n */\n private broadcast(message: BroadcastMessage): void {\n if (this.channel) {\n this.channel.postMessage(message);\n }\n }\n\n /**\n * Sets up the database for the repository (syncs from other tabs)\n */\n public override async setupDatabase(): Promise<void> {\n if (this.isInitialized) return;\n this.isInitialized = true;\n await this.syncFromOtherTabs();\n }\n\n /**\n * Stores a key-value pair in the repository\n * @param value - The combined object to store\n * @returns The stored entity\n * @emits 'put' event with the stored entity when successful\n */\n public async put(value: InsertType): Promise<Entity> {\n const result = await this.inMemoryRepo.put(value);\n this.broadcast({ type: \"PUT\", entity: result });\n return result;\n }\n\n /**\n * Stores multiple key-value pairs in the repository in a bulk operation\n * @param values - Array of combined objects to store\n * @returns Array of stored entities\n * @emits 'put' event for each value stored\n */\n public async putBulk(values: InsertType[]): Promise<Entity[]> {\n const result = await this.inMemoryRepo.putBulk(values);\n this.broadcast({ type: \"PUT_BULK\", entities: result });\n return result;\n }\n\n /**\n * Retrieves a value by its key\n * @param key - The primary key object to look up\n * @returns The value object if found, undefined otherwise\n * @emits 'get' event with the fingerprint ID and value when found\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n return await this.inMemoryRepo.get(key);\n }\n\n /**\n * Deletes an entry by its key\n * @param value - The primary key object or entity of the entry to delete\n * @emits 'delete' event with the fingerprint ID when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n await this.inMemoryRepo.delete(value);\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n this.broadcast({ type: \"DELETE\", key });\n }\n\n /**\n * Removes all entries from the repository\n * @emits 'clearall' event when successful\n */\n async deleteAll(): Promise<void> {\n await this.inMemoryRepo.deleteAll();\n this.broadcast({ type: \"DELETE_ALL\" });\n }\n\n /**\n * Returns an array of all entries in the repository, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of all entries in the repository\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n return await this.inMemoryRepo.getAll(options);\n }\n\n /**\n * Returns the number of entries in the repository\n * @returns The total count of stored entries\n */\n async size(): Promise<number> {\n return await this.inMemoryRepo.size();\n }\n\n /**\n * Fetches a page of records from the repository.\n * @param offset - Number of records to skip\n * @param limit - Maximum number of records to return\n * @returns Array of entities or undefined if no records found\n */\n async getBulk(offset: number, limit: number): Promise<Entity[] | undefined> {\n return await this.inMemoryRepo.getBulk(offset, limit);\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering and limit.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering and limit options\n * @returns Array of matching entities or undefined if no matches found\n */\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n return await this.inMemoryRepo.query(criteria, options);\n }\n\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n return await this.inMemoryRepo.queryIndex(criteria, options);\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Supports multiple columns with optional comparison operators.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n */\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n await this.inMemoryRepo.deleteSearch(criteria);\n this.broadcast({\n type: \"DELETE_SEARCH\",\n criteria,\n });\n }\n\n /**\n * Subscribes to changes in the repository.\n * Delegates to the internal InMemoryTabularStorage which monitors local changes.\n * Changes from other tabs/windows are already propagated via BroadcastChannel.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (not used for in-memory)\n * @returns Unsubscribe function\n */\n public override subscribeToChanges(\n callback: (change: any) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n return this.inMemoryRepo.subscribeToChanges(callback, options);\n }\n\n /**\n * Cleanup method to close the BroadcastChannel\n */\n public override destroy(): void {\n if (this.channel) {\n this.channel.close();\n this.channel = null;\n }\n this.inMemoryRepo.destroy();\n }\n}\n",
36
36
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { RealtimeChannel, SupabaseClient } from \"@supabase/supabase-js\";\nimport { createServiceToken } from \"@workglow/util\";\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { BaseSqlTabularStorage } from \"./BaseSqlTabularStorage\";\nimport { ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport {\n AnyTabularStorage,\n AutoGeneratedKeys,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularChangeType,\n TabularSubscribeOptions,\n ValueOptionType,\n} from \"./ITabularStorage\";\nimport { pickCoveringIndex } from \"./coveringIndexPicker\";\nimport { StorageValidationError } from \"./StorageError\";\n\nexport const SUPABASE_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.supabase\"\n);\n\n/**\n * A Supabase-based tabular repository implementation that extends BaseSqlTabularStorage.\n * This class provides persistent storage for data in a Supabase database,\n * making it suitable for multi-user scenarios.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class SupabaseTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseSqlTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n protected readonly client: SupabaseClient;\n private realtimeChannel: RealtimeChannel | null = null;\n\n /**\n * Creates a new SupabaseTabularStorage instance.\n *\n * @param client - Supabase client instance\n * @param table - Name of the table to store data (defaults to \"tabular_store\")\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n client: unknown,\n table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.client = client as SupabaseClient;\n }\n\n /**\n * Initializes the database table with the required schema.\n * Creates the table if it doesn't exist with primary key and value columns.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n const sql = `\n CREATE TABLE IF NOT EXISTS \"${this.table}\" (\n ${this.constructPrimaryKeyColumns('\"')} ${this.constructValueColumns('\"')},\n PRIMARY KEY (${this.primaryKeyColumnList()}) \n )\n `;\n const { error } = await this.client.rpc(\"exec_sql\", { query: sql });\n if (error && !error.message.includes(\"already exists\")) {\n throw error;\n }\n\n // Get primary key columns to avoid creating redundant indexes\n const pkColumns = this.primaryKeyColumns();\n\n // Track created indexes to avoid duplicates and redundant indexes\n const createdIndexes = new Set<string>();\n\n for (const columns of this.indexes) {\n // Skip if this is just the primary key or a prefix of it\n if (columns.length <= pkColumns.length) {\n // @ts-ignore\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n\n // Create index name and column list\n const indexName = `${this.table}_${columns.join(\"_\")}`;\n const columnList = columns.map((col) => `\"${String(col)}\"`).join(\", \");\n\n // Skip if we've already created this index or if it's redundant\n const columnKey = columns.join(\",\");\n if (createdIndexes.has(columnKey)) continue;\n\n // Check if this index would be redundant with an existing one\n const isRedundant = Array.from(createdIndexes).some((existing) => {\n const existingCols = existing.split(\",\");\n return (\n existingCols.length >= columns.length &&\n columns.every((col, idx) => col === existingCols[idx])\n );\n });\n\n if (!isRedundant) {\n const indexSql = `CREATE INDEX IF NOT EXISTS \"${indexName}\" ON \"${this.table}\" (${columnList})`;\n const { error: indexError } = await this.client.rpc(\"exec_sql\", { query: indexSql });\n if (indexError && !indexError.message.includes(\"already exists\")) {\n // Index creation errors are not critical, log and continue\n console.warn(`Failed to create index ${indexName}:`, indexError);\n }\n createdIndexes.add(columnKey);\n }\n }\n }\n\n /**\n * Maps TypeScript/JavaScript types to corresponding PostgreSQL data types.\n * Uses additional schema information like minimum/maximum values, nullable status,\n * and string lengths to create more optimized column types.\n *\n * @param typeDef - The TypeScript/JavaScript type to map\n * @returns The corresponding PostgreSQL data type\n */\n protected override mapTypeToSQL(typeDef: JsonSchema): string {\n // Extract the actual non-null type using base helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return \"TEXT /* boolean schema */\";\n }\n\n // Handle BLOB type\n if (actualType.contentEncoding === \"blob\") return \"BYTEA\";\n\n switch (actualType.type) {\n case \"string\":\n // Handle special string formats\n if (actualType.format === \"date-time\") return \"TIMESTAMP\";\n if (actualType.format === \"date\") return \"DATE\";\n if (actualType.format === \"email\") return \"VARCHAR(255)\";\n if (actualType.format === \"uri\") return \"VARCHAR(2048)\";\n if (actualType.format === \"uuid\") return \"UUID\";\n\n // Use a VARCHAR with maxLength if specified\n if (typeof actualType.maxLength === \"number\") {\n return `VARCHAR(${actualType.maxLength})`;\n }\n\n // Default to TEXT for strings without constraints\n return \"TEXT\";\n\n case \"number\":\n case \"integer\":\n // Handle integer vs floating point\n if (actualType.multipleOf === 1 || actualType.type === \"integer\") {\n // Use PostgreSQL's numeric range types based on min/max values\n if (typeof actualType.minimum === \"number\") {\n if (actualType.minimum >= 0) {\n // For unsigned integers\n if (typeof actualType.maximum === \"number\") {\n if (actualType.maximum <= 32767) return \"SMALLINT\";\n if (actualType.maximum <= 2147483647) return \"INTEGER\";\n }\n return \"BIGINT\";\n }\n }\n\n // Default integer type\n return \"INTEGER\";\n }\n\n // For floating point numbers with precision requirements\n if (actualType.format === \"float\") return \"REAL\";\n if (actualType.format === \"double\") return \"DOUBLE PRECISION\";\n\n // Use NUMERIC with precision/scale if specified\n if (typeof actualType.multipleOf === \"number\") {\n const decimalPlaces = String(actualType.multipleOf).split(\".\")[1]?.length || 0;\n if (decimalPlaces > 0) {\n return `NUMERIC(38, ${decimalPlaces})`;\n }\n }\n\n return \"NUMERIC\";\n\n case \"boolean\":\n return \"BOOLEAN\";\n\n case \"array\":\n // Handle array types (if items type is specified)\n if (\n actualType.items &&\n typeof actualType.items === \"object\" &&\n !Array.isArray(actualType.items)\n ) {\n const itemType = this.mapTypeToSQL(actualType.items as JsonSchema);\n\n // Only use native PostgreSQL arrays for simple scalar types\n // List of types that work well as native PostgreSQL arrays\n const supportedArrayElementTypes = [\n \"TEXT\",\n \"VARCHAR\",\n \"CHAR\",\n \"INTEGER\",\n \"SMALLINT\",\n \"BIGINT\",\n \"REAL\",\n \"DOUBLE PRECISION\",\n \"NUMERIC\",\n \"BOOLEAN\",\n \"UUID\",\n \"DATE\",\n \"TIMESTAMP\",\n ];\n\n // Check if the item type is in our supported list (either exact match or starts with for VARCHAR types)\n const isSupported = supportedArrayElementTypes.some(\n (type) => itemType === type || (itemType.startsWith(type + \"(\") && type !== \"VARCHAR\") // Handle things like VARCHAR(255)\n );\n\n if (isSupported) {\n return `${itemType}[]`;\n } else {\n return \"JSONB /* complex array */\";\n }\n }\n return \"JSONB /* generic array */\";\n\n case \"object\":\n return \"JSONB /* object */\";\n\n default:\n return \"TEXT /* unknown type */\";\n }\n }\n\n /**\n * Generates the SQL column definitions for primary key fields with constraints\n * Handles auto-generated keys using SERIAL for integers and UUID DEFAULT for strings\n * @returns SQL string containing primary key column definitions\n */\n protected override constructPrimaryKeyColumns($delimiter: string = \"\"): string {\n const cols = Object.entries<JsonSchema>(this.primaryKeySchema.properties)\n .map(([key, typeDef]) => {\n // Check if this is an auto-generated key\n if (this.isAutoGeneratedKey(key)) {\n if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // Use SERIAL or BIGSERIAL for auto-increment\n const sqlType = this.mapTypeToSQL(typeDef);\n const isSmallInt = sqlType.includes(\"SMALLINT\");\n const isBigInt = sqlType.includes(\"BIGINT\");\n const serialType = isBigInt ? \"BIGSERIAL\" : isSmallInt ? \"SMALLSERIAL\" : \"SERIAL\";\n return `${$delimiter}${key}${$delimiter} ${serialType}`;\n } else if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // Use UUID with DEFAULT gen_random_uuid()\n return `${$delimiter}${key}${$delimiter} UUID DEFAULT gen_random_uuid()`;\n }\n }\n\n const sqlType = this.mapTypeToSQL(typeDef);\n let constraints = \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${$delimiter}${key}${$delimiter} >= 0)`;\n }\n\n return `${$delimiter}${key}${$delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n return cols;\n }\n\n /**\n * Generates the SQL column definitions for value fields with constraints\n * @returns SQL string containing value column definitions\n */\n protected override constructValueColumns($delimiter: string = \"\"): string {\n const delimiter = $delimiter || '\"';\n const requiredSet = new Set(this.valueSchema.required ?? []);\n const cols = Object.entries<JsonSchema>(this.valueSchema.properties)\n .map(([key, typeDef]) => {\n const sqlType = this.mapTypeToSQL(typeDef);\n const isRequired = requiredSet.has(key);\n const nullable = !isRequired || this.isNullable(typeDef);\n let constraints = nullable ? \"NULL\" : \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${delimiter}${key}${delimiter} >= 0)`;\n }\n\n return `${delimiter}${key}${delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n if (cols.length > 0) {\n return `, ${cols}`;\n } else {\n return \"\";\n }\n }\n\n /**\n * Convert Supabase values to JS values. Ensures numeric strings become numbers where schema says number.\n */\n protected override sqlToJsValue(column: string, value: ValueOptionType): Entity[keyof Entity] {\n const typeDef = this.schema.properties[column as keyof typeof this.schema.properties] as\n | JsonSchema\n | undefined;\n if (typeDef) {\n if (value === null && this.isNullable(typeDef)) {\n return null as Entity[keyof Entity];\n }\n const actualType = this.getNonNullType(typeDef);\n\n // Handle numeric types - Supabase can return them as strings\n if (\n typeof actualType !== \"boolean\" &&\n (actualType.type === \"number\" || actualType.type === \"integer\")\n ) {\n if (typeof value === \"number\") return value as Entity[keyof Entity];\n if (typeof value === \"string\") {\n const parsed = Number(value);\n if (!isNaN(parsed)) return parsed as Entity[keyof Entity];\n }\n }\n }\n return super.sqlToJsValue(column, value);\n }\n\n /**\n * Determines if a field should be treated as unsigned based on schema properties\n * @param typeDef - The schema type definition\n * @returns true if the field should be treated as unsigned\n */\n protected shouldBeUnsigned(typeDef: JsonSchema): boolean {\n // Extract the non-null type using the base class helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return false;\n }\n\n // Check if it's a number type with minimum >= 0\n if (\n (actualType.type === \"number\" || actualType.type === \"integer\") &&\n typeof actualType.minimum === \"number\" &&\n actualType.minimum >= 0\n ) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Stores or updates a row in the database.\n * Uses UPSERT (INSERT ... ON CONFLICT DO UPDATE) for atomic operations.\n *\n * @param entity - The entity to store (may be missing auto-generated keys)\n * @returns The entity with any server-generated fields updated\n * @emits \"put\" event with the updated entity when successful\n */\n async put(entity: InsertType): Promise<Entity> {\n // Handle auto-generated keys\n let entityToInsert = { ...entity };\n\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const entityRecord = entity as Record<string, unknown>;\n const clientProvidedValue = entityRecord[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldOmitKey = false;\n if (this.clientProvidedKeys === \"never\") {\n // Never use client value, let database generate\n shouldOmitKey = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldOmitKey = false;\n } else {\n // \"if-missing\" - omit key if client didn't provide it\n shouldOmitKey = !hasClientValue;\n }\n\n if (shouldOmitKey) {\n // Omit the auto-generated key so Supabase generates it\n delete (entityToInsert as Record<string, unknown>)[keyName];\n }\n }\n\n // Normalize optional fields: convert undefined to null for optional fields\n const normalizedEntity = { ...entityToInsert } as Record<string, unknown>;\n const requiredSet = new Set(this.valueSchema.required ?? []);\n for (const key in this.valueSchema.properties) {\n if (!(key in normalizedEntity) || normalizedEntity[key] === undefined) {\n if (!requiredSet.has(key)) {\n normalizedEntity[key] = null;\n }\n }\n }\n const { data, error } = await this.client\n .from(this.table)\n .upsert(normalizedEntity, { onConflict: this.primaryKeyColumnList() })\n .select()\n .single();\n\n if (error) throw error;\n const updatedEntity = data as Entity;\n\n // Convert all columns from SQL to JS values\n const updatedRecord = updatedEntity as Record<string, unknown>;\n for (const key in this.schema.properties) {\n updatedRecord[key] = this.sqlToJsValue(key, updatedRecord[key] as ValueOptionType);\n }\n\n this.events.emit(\"put\", updatedEntity);\n return updatedEntity;\n }\n\n /**\n * Stores multiple rows in the database in a bulk operation.\n * Uses individual put calls to ensure auto-generated keys are handled correctly.\n *\n * @param entities - Array of entities to store (may be missing auto-generated keys)\n * @returns Array of entities with any server-generated fields updated\n * @emits \"put\" event for each entity stored\n */\n async putBulk(entities: InsertType[]): Promise<Entity[]> {\n if (entities.length === 0) return [];\n\n // Use individual put calls to ensure auto-generated keys are handled correctly\n return await Promise.all(entities.map((entity) => this.put(entity)));\n }\n\n /**\n * Retrieves a value from the database by its primary key.\n *\n * @param key - The primary key object to look up\n * @returns The stored entity or undefined if not found\n * @emits \"get\" event with the key when successful\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n let query = this.client.from(this.table).select(\"*\");\n\n // Build the where clause from primary key\n const keyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), keyRecord[String(pkName)]);\n }\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n // Not found\n this.events.emit(\"get\", key, undefined);\n return undefined;\n }\n throw error;\n }\n\n const val = data as Entity | undefined;\n if (val) {\n // Convert all columns from SQL to JS values\n const valRecord = val as Record<string, unknown>;\n for (const key in this.schema.properties) {\n valRecord[key] = this.sqlToJsValue(key, valRecord[key] as ValueOptionType);\n }\n }\n this.events.emit(\"get\", key, val);\n return val;\n }\n\n /**\n * Deletes a row from the database.\n *\n * @param value - The primary key object or entity to delete\n * @emits \"delete\" event with the key when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n\n let query = this.client.from(this.table).delete();\n\n // Build the where clause from primary key\n const deleteKeyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), deleteKeyRecord[String(pkName)]);\n }\n\n const { error } = await query;\n\n if (error) throw error;\n this.events.emit(\"delete\", key as keyof Entity);\n }\n\n /**\n * Retrieves all entries from the database table, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Promise resolving to an array of entries or undefined if not found\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n let query = this.client.from(this.table).select(\"*\");\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length) {\n // Convert all columns from SQL to JS values\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n return data as Entity[];\n }\n return undefined;\n }\n\n /**\n * Deletes all rows from the database table.\n * @emits \"clearall\" event when successful\n */\n async deleteAll(): Promise<void> {\n // Use the first primary key column for the delete condition\n const firstPkColumn = this.primaryKeyNames[0];\n const { error } = await this.client.from(this.table).delete().neq(String(firstPkColumn), null); // Delete all rows by using a condition that's always true\n\n if (error) throw error;\n this.events.emit(\"clearall\");\n }\n\n /**\n * Returns the total number of rows in the database.\n *\n * @returns Promise resolving to the count of stored items\n */\n async size(): Promise<number> {\n const { count, error } = await this.client\n .from(this.table)\n .select(\"*\", { count: \"exact\", head: true });\n\n if (error) throw error;\n return count ?? 0;\n }\n\n /**\n * Fetches a page of records from the repository.\n * @param offset - Number of records to skip\n * @param limit - Maximum number of records to return\n * @returns Array of entities or undefined if no records found\n */\n async getBulk(offset: number, limit: number): Promise<Entity[] | undefined> {\n // Build the base query\n let query = this.client.from(this.table).select(\"*\");\n\n // Ensure deterministic ordering for pagination by ordering on primary key column(s)\n for (const pkName of this.primaryKeyNames) {\n query = query.order(String(pkName));\n }\n\n const { data, error } = await query.range(offset, offset + limit - 1);\n\n if (error) throw error;\n\n if (!data || data.length === 0) {\n return undefined;\n }\n\n // Convert all columns from SQL to JS values (consistent with getAll)\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n\n return data as Entity[];\n }\n\n /**\n * Applies criteria to a Supabase filter builder. Typed as `any` because the\n * `PostgrestFilterBuilder` generics are deep enough to trip TS2589.\n */\n private applyCriteriaToFilter<Q>(query: Q, criteria: SearchCriteria<Entity>): Q {\n let q = query as any;\n for (const column of Object.keys(criteria) as Array<keyof Entity>) {\n const criterion = criteria[column];\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n switch (operator) {\n case \"=\":\n q = q.eq(String(column), value);\n break;\n case \"<\":\n q = q.lt(String(column), value);\n break;\n case \"<=\":\n q = q.lte(String(column), value);\n break;\n case \">\":\n q = q.gt(String(column), value);\n break;\n case \">=\":\n q = q.gte(String(column), value);\n break;\n }\n }\n return q as Q;\n }\n\n /**\n * Counts rows matching the specified search criteria.\n */\n override async count(criteria?: SearchCriteria<Entity>): Promise<number> {\n if (!criteria || Object.keys(criteria).length === 0) {\n return await this.size();\n }\n\n this.validateQueryParams(criteria);\n const query = this.applyCriteriaToFilter(\n this.client.from(this.table).select(\"*\", { count: \"exact\", head: true }),\n criteria\n );\n\n const { count, error } = await query;\n if (error) throw error;\n return count ?? 0;\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Supports multiple columns with optional comparison operators.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n */\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaKeys.length === 0) {\n return;\n }\n\n let query = this.client.from(this.table).delete();\n\n for (const column of criteriaKeys) {\n if (!(column in this.schema.properties)) {\n throw new Error(`Schema must have a ${String(column)} field to use deleteSearch`);\n }\n\n const criterion = criteria[column];\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n switch (operator) {\n case \"=\":\n query = query.eq(String(column), value);\n break;\n case \"<\":\n query = query.lt(String(column), value);\n break;\n case \"<=\":\n query = query.lte(String(column), value);\n break;\n case \">\":\n query = query.gt(String(column), value);\n break;\n case \">=\":\n query = query.gte(String(column), value);\n break;\n }\n }\n\n const { error } = await query;\n\n if (error) throw error;\n this.events.emit(\"delete\", criteriaKeys[0] as keyof Entity);\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering, limit, and offset.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of matching entities or undefined if no matches found\n */\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n this.validateQueryParams(criteria, options);\n\n let query = this.applyCriteriaToFilter(this.client.from(this.table).select(\"*\"), criteria);\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n } else if (options?.limit !== undefined) {\n query = query.limit(options.limit);\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length > 0) {\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, data as Entity[]);\n return data as Entity[];\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n this.validateSelect(options);\n this.validateQueryParams(criteria, options);\n\n const registered = this.indexes.map((cols, i) => {\n const cs = Array.isArray(cols) ? (cols as string[]) : [cols as string];\n return { name: `idx_${i}`, keyPath: cs };\n });\n\n pickCoveringIndex({\n table: this.table,\n indexes: registered,\n criteriaColumns: Object.keys(criteria),\n orderByColumns: (options.orderBy ?? []).map((o) => ({\n column: String(o.column),\n direction: o.direction,\n })),\n selectColumns: options.select.map(String),\n primaryKeyColumns: this.primaryKeyNames.map(String),\n });\n\n const colList = options.select.map(String).join(\",\");\n let q = this.applyCriteriaToFilter(this.client.from(this.table).select(colList), criteria);\n\n if (options.orderBy) {\n for (const { column, direction } of options.orderBy) {\n q = q.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n if (options.offset !== undefined && options.limit === undefined) {\n throw new StorageValidationError(\"queryIndex with offset requires limit (no implicit cap)\");\n }\n if (options.offset !== undefined || options.limit !== undefined) {\n const start = options.offset ?? 0;\n if (options.limit !== undefined) {\n q = q.range(start, start + options.limit - 1);\n }\n }\n\n const { data, error } = await q;\n if (error) throw error;\n if (!data) return [];\n\n const rows = data as unknown as Record<string, unknown>[];\n const sel = new Set(options.select.map(String));\n for (const row of rows) {\n for (const key of Object.keys(row)) {\n if (sel.has(key)) {\n row[key] = this.sqlToJsValue(key, row[key] as ValueOptionType);\n }\n }\n }\n return rows as unknown as Pick<Entity, K>[];\n }\n\n /**\n * Converts a row from Supabase realtime payload to an Entity with proper type conversions.\n *\n * @param row - The raw row data from Supabase realtime\n * @returns The converted entity\n */\n private convertRealtimeRow(row: Record<string, unknown>): Entity {\n const entity = { ...row } as Entity;\n const record = entity as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, row[key] as ValueOptionType);\n }\n return entity;\n }\n\n /**\n * Subscribes to changes in the repository using Supabase realtime.\n * Receives notifications for INSERT, UPDATE, and DELETE operations from any source.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (not used for Supabase realtime)\n * @returns Unsubscribe function\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Create a unique channel name\n const channelName = `tabular-${this.table}-${Date.now()}`;\n\n this.realtimeChannel = this.client\n .channel(channelName)\n .on(\n \"postgres_changes\",\n {\n event: \"*\",\n schema: \"public\",\n table: this.table,\n },\n (payload) => {\n const change: TabularChangePayload<Entity> = {\n type: payload.eventType.toUpperCase() as TabularChangeType,\n old:\n payload.old && Object.keys(payload.old).length > 0\n ? this.convertRealtimeRow(payload.old)\n : undefined,\n new:\n payload.new && Object.keys(payload.new).length > 0\n ? this.convertRealtimeRow(payload.new)\n : undefined,\n };\n callback(change);\n }\n )\n .subscribe();\n\n return () => {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n };\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n public override destroy(): void {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n }\n}\n",
37
37
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { BaseTabularStorage, ClientProvidedKeysOption } from \"./BaseTabularStorage\";\nimport {\n AutoGeneratedKeys,\n InsertEntity,\n SimplifyPrimaryKey,\n ValueOptionType,\n} from \"./ITabularStorage\";\n\n// BaseTabularStorage is a tabular store that uses SQLite and Postgres use as common code\n\n/**\n * Base class for SQL-based tabular repositories that implements common functionality\n * for both SQLite and PostgreSQL database implementations.\n *\n * @template Schema - The schema definition for the entity using JSON Schema\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport abstract class BaseSqlTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n /**\n * Creates a new instance of BaseSqlTabularStorage\n * @param table - The name of the database table to use for storage\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n /** Caches for computed column definition strings, keyed by delimiter */\n private readonly _pkColsCache = new Map<string, string>();\n private readonly _valColsCache = new Map<string, string>();\n private readonly _pkColListCache = new Map<string, string>();\n private readonly _valColListCache = new Map<string, string>();\n\n constructor(\n protected readonly table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.validateTableAndSchema();\n }\n\n /**\n * Maps JavaScript/TypeScript types to their corresponding SQL type\n * Must be implemented by derived classes for specific SQL dialects\n */\n protected abstract mapTypeToSQL(typeDef: JsonSchema): string;\n\n /**\n * Generates the SQL column definitions for primary key fields\n * @returns SQL string containing primary key column definitions\n */\n protected constructPrimaryKeyColumns($delimiter: string = \"\"): string {\n let cached = this._pkColsCache.get($delimiter);\n if (cached === undefined) {\n cached = Object.entries<JsonSchema>(this.primaryKeySchema.properties)\n .map(([key, typeDef]) => {\n const sqlType = this.mapTypeToSQL(typeDef);\n return `${$delimiter}${key}${$delimiter} ${sqlType} NOT NULL`;\n })\n .join(\", \");\n this._pkColsCache.set($delimiter, cached);\n }\n return cached;\n }\n\n /**\n * Generates the SQL column definitions for value fields\n * @returns SQL string containing value column definitions\n */\n protected constructValueColumns($delimiter: string = \"\"): string {\n let cached = this._valColsCache.get($delimiter);\n if (cached === undefined) {\n const requiredSet = new Set(this.valueSchema.required ?? []);\n const cols = Object.entries<JsonSchema>(this.valueSchema.properties)\n .map(([key, typeDef]) => {\n const sqlType = this.mapTypeToSQL(typeDef);\n const isRequired = requiredSet.has(key);\n const nullable = !isRequired || this.isNullable(typeDef);\n return `${$delimiter}${key}${$delimiter} ${sqlType}${nullable ? \" NULL\" : \" NOT NULL\"}`;\n })\n .join(\", \");\n cached = cols.length > 0 ? `, ${cols}` : \"\";\n this._valColsCache.set($delimiter, cached);\n }\n return cached;\n }\n\n /**\n * Determines if a schema type allows null values\n * @param typeDef - The schema type definition\n * @returns true if the type allows null values\n */\n protected isNullable(typeDef: JsonSchema): boolean {\n if (typeof typeDef === \"boolean\") return typeDef;\n\n // Check for direct null type\n if (typeDef.type === \"null\") {\n return true;\n }\n\n // Check for type as an array that includes null (e.g., type: [\"null\", \"string\"])\n if (Array.isArray(typeDef.type)) {\n return typeDef.type.includes(\"null\");\n }\n\n // Check for union types that include null (anyOf)\n if (typeDef.anyOf && Array.isArray(typeDef.anyOf)) {\n return typeDef.anyOf.some((type: any) => type.type === \"null\");\n }\n\n // Check for union types that include null (oneOf)\n if (typeDef.oneOf && Array.isArray(typeDef.oneOf)) {\n return typeDef.oneOf.some((type: any) => type.type === \"null\");\n }\n\n return false;\n }\n\n /**\n * Returns a comma-separated list of primary key column names\n * @returns Formatted string of primary key column names\n */\n protected primaryKeyColumnList($delimiter: string = \"\"): string {\n let cached = this._pkColListCache.get($delimiter);\n if (cached === undefined) {\n cached =\n $delimiter + this.primaryKeyColumns().join(`${$delimiter}, ${$delimiter}`) + $delimiter;\n this._pkColListCache.set($delimiter, cached);\n }\n return cached;\n }\n\n /**\n * Returns a comma-separated list of value column names\n * @returns Formatted string of value column names\n */\n protected valueColumnList($delimiter: string = \"\"): string {\n let cached = this._valColListCache.get($delimiter);\n if (cached === undefined) {\n cached = $delimiter + this.valueColumns().join(`${$delimiter}, ${$delimiter}`) + $delimiter;\n this._valColListCache.set($delimiter, cached);\n }\n return cached;\n }\n\n /**\n * Gets the real underlying type from possibly union types\n * For example, for a union with null, this extracts the non-null type\n * @param typeDef - The schema to extract from\n * @returns The non-null type from the schema\n */\n protected getNonNullType(typeDef: JsonSchema): JsonSchema {\n if (typeof typeDef === \"boolean\") return typeDef;\n\n if (typeDef.anyOf && Array.isArray(typeDef.anyOf)) {\n const nonNullType = typeDef.anyOf.find((t: any) => t.type !== \"null\");\n if (nonNullType) {\n return nonNullType;\n }\n }\n if (typeDef.oneOf && Array.isArray(typeDef.oneOf)) {\n const nonNullType = typeDef.oneOf.find((t: any) => t.type !== \"null\");\n if (nonNullType) {\n return nonNullType;\n }\n }\n return typeDef;\n }\n\n /**\n * Converts a value object into an ordered array based on the valueSchema\n * This ensures consistent parameter ordering for SQL queries\n * @param value - The value object to convert\n * @returns Array of values ordered according to the schema\n * @throws Error if a required field is missing\n */\n protected getValueAsOrderedArray(value: Value): ValueOptionType[] {\n const orderedParams: ValueOptionType[] = [];\n const valueAsRecord = value as Record<string, Entity[keyof Entity]>;\n const requiredSet = new Set(this.valueSchema.required ?? []);\n for (const key in this.valueSchema.properties) {\n if (Object.prototype.hasOwnProperty.call(valueAsRecord, key)) {\n const val = valueAsRecord[key];\n // Convert undefined to null for optional fields\n if (val === undefined && !requiredSet.has(key)) {\n orderedParams.push(null);\n } else {\n orderedParams.push(this.jsToSqlValue(key, val));\n }\n } else {\n // If the field is required, throw an error\n if (requiredSet.has(key)) {\n throw new Error(`Missing required value field: ${key}`);\n }\n // If the field is optional, use null\n orderedParams.push(null);\n }\n }\n return orderedParams;\n }\n\n /**\n * Converts a primary key object into an ordered array based on the schema\n * This ensures consistent parameter ordering for storage operations\n * @param key - The primary key object to convert\n * @returns Array of key values ordered according to the schema\n */\n protected override getPrimaryKeyAsOrderedArray(key: PrimaryKey): ValueOptionType[] {\n const orderedParams: ValueOptionType[] = [];\n const keyObj = key as Record<string, Entity[keyof Entity]>;\n for (const k of Object.keys(this.primaryKeySchema.properties)) {\n if (k in keyObj) {\n const value = keyObj[k];\n if (value === null) {\n throw new Error(`Primary key field ${k} cannot be null`);\n }\n orderedParams.push(this.jsToSqlValue(k, value));\n } else {\n throw new Error(`Missing required primary key field: ${k}`);\n }\n }\n return orderedParams;\n }\n\n protected jsToSqlValue(column: string, value: Entity[keyof Entity]): ValueOptionType {\n const typeDef = this.schema.properties[column];\n if (!typeDef) {\n return value as ValueOptionType;\n }\n\n // Handle null values for nullable columns\n if (value === null && this.isNullable(typeDef)) {\n return null;\n }\n\n // Extract the non-null type for proper handling\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return value as ValueOptionType;\n }\n\n if (actualType.contentEncoding === \"blob\") {\n if (value instanceof Uint8Array) {\n return value;\n }\n if (typeof Buffer !== \"undefined\" && value instanceof Buffer) {\n return new Uint8Array(value);\n }\n if (Array.isArray(value)) {\n return new Uint8Array(value);\n }\n return value as ValueOptionType;\n } else if (value instanceof Date) {\n // Convert all Date objects to ISO string regardless of type definition\n return value.toISOString();\n } else {\n return value as ValueOptionType;\n }\n }\n\n protected sqlToJsValue(column: string, value: ValueOptionType): Entity[keyof Entity] {\n // Get the type definition\n const typeDef = this.schema.properties[column];\n if (!typeDef) {\n return value as Entity[keyof Entity];\n }\n\n // Handle null values\n if (value === null && this.isNullable(typeDef)) {\n return null as Entity[keyof Entity];\n }\n\n // Extract the non-null type for proper handling\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return value as Entity[keyof Entity];\n }\n\n if (actualType.contentEncoding === \"blob\") {\n if (typeof Buffer !== \"undefined\" && value instanceof Buffer) {\n return new Uint8Array(value) as Entity[keyof Entity];\n }\n if (value instanceof Uint8Array) {\n return value as Entity[keyof Entity];\n }\n return value as Entity[keyof Entity];\n } else {\n return value as Entity[keyof Entity];\n }\n }\n\n /**\n * Validates table name and schema configurations\n * Checks for:\n * 1. Valid table name format\n * 2. Valid schema key names\n * 3. No duplicate keys between primary key and value schemas\n * This is a sanity check to make sure the table and schema are valid,\n * and to prevent dumb mistakes and mischevious behavior.\n * @throws Error if validation fails\n */\n protected validateTableAndSchema(): void {\n // Validate table name\n if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(this.table)) {\n throw new Error(\n \"Table name must start with a letter and contain only letters, digits, and underscores, got: \" +\n this.table\n );\n }\n\n // Validate schema keys\n const validateSchemaKeys = (schema: DataPortSchemaObject) => {\n for (const key in schema.properties) {\n if (!/^[a-zA-Z][a-zA-Z0-9_]*$/.test(key)) {\n throw new Error(\n \"Schema keys must start with a letter and contain only letters, digits, and underscores, got: \" +\n key\n );\n }\n }\n };\n\n validateSchemaKeys(this.primaryKeySchema);\n validateSchemaKeys(this.valueSchema);\n\n // Check for key name collisions between schemas\n const primaryKeys = new Set(Object.keys(this.primaryKeySchema.properties));\n const valueKeys = Object.keys(this.valueSchema.properties);\n const duplicates = valueKeys.filter((key) => primaryKeys.has(key));\n if (duplicates.length > 0) {\n throw new Error(`Duplicate keys found in schemas: ${duplicates.join(\", \")}`);\n }\n }\n}\n",
38
38
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { JsonSchema } from \"@workglow/util/schema\";\nimport { createServiceToken } from \"@workglow/util\";\nimport { IndexedDbTabularStorage } from \"../tabular/IndexedDbTabularStorage\";\nimport { DefaultKeyValueKey, DefaultKeyValueSchema, IKvStorage } from \"./IKvStorage\";\nimport { KvViaTabularStorage } from \"./KvViaTabularStorage\";\n\nexport const IDB_KV_REPOSITORY = createServiceToken<IKvStorage<string, any, any>>(\n \"storage.kvRepository.indexedDb\"\n);\n\n/**\n * A key-value repository implementation that uses IndexedDB for persistent storage in the browser.\n * Leverages a tabular repository abstraction for IndexedDB operations.\n *\n * @template Key - The type of the primary key\n * @template Value - The type of the value being stored\n * @template Combined - Combined type of Key & Value\n */\nexport class IndexedDbKvStorage extends KvViaTabularStorage {\n public tabularRepository: IndexedDbTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >;\n\n /**\n * Creates a new KvStorage instance\n */\n constructor(\n public dbName: string,\n keySchema: JsonSchema = { type: \"string\" },\n valueSchema: JsonSchema = {}\n ) {\n super(keySchema, valueSchema);\n this.tabularRepository = new IndexedDbTabularStorage(\n dbName,\n DefaultKeyValueSchema,\n DefaultKeyValueKey\n );\n }\n}\n",
39
39
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken } from \"@workglow/util\";\nimport { JsonSchema } from \"@workglow/util/schema\";\nimport { SupabaseTabularStorage } from \"../tabular/SupabaseTabularStorage\";\nimport { DefaultKeyValueKey, DefaultKeyValueSchema, IKvStorage } from \"./IKvStorage\";\nimport { KvViaTabularStorage } from \"./KvViaTabularStorage\";\n\nexport const SUPABASE_KV_REPOSITORY = createServiceToken<IKvStorage<string, any, any>>(\n \"storage.kvRepository.supabase\"\n);\n\n/**\n * A key-value repository implementation that uses Supabase for persistent storage.\n * Leverages a tabular repository abstraction for Supabase operations.\n *\n * @template Key - The type of the primary key\n * @template Value - The type of the value being stored\n * @template Combined - Combined type of Key & Value\n */\nexport class SupabaseKvStorage extends KvViaTabularStorage {\n public tabularRepository: SupabaseTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >;\n\n /**\n * Creates a new SupabaseKvStorage instance\n *\n * @param client - Supabase client instance\n * @param tableName - Name of the table to store data\n * @param keySchema - Schema for the key type (defaults to string)\n * @param valueSchema - Schema for the value type (defaults to any)\n */\n constructor(\n public client: unknown,\n public tableName: string,\n keySchema: JsonSchema = { type: \"string\" },\n valueSchema: JsonSchema = {},\n tabularRepository?: SupabaseTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >\n ) {\n super(keySchema, valueSchema);\n this.tabularRepository =\n tabularRepository ??\n new SupabaseTabularStorage(client, tableName, DefaultKeyValueSchema, DefaultKeyValueKey);\n }\n}\n",
40
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken, deepEqual, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport { HybridSubscriptionManager } from \"../util/HybridSubscriptionManager\";\nimport {\n ensureIndexedDbTable,\n ExpectedIndexDefinition,\n MigrationOptions,\n} from \"../util/IndexedDbTable\";\nimport {\n IQueueStorage,\n JobStatus,\n JobStorageFormat,\n PrefixColumn,\n QueueChangePayload,\n QueueStorageOptions,\n QueueSubscribeOptions,\n} from \"./IQueueStorage\";\n\nexport const INDEXED_DB_QUEUE_STORAGE = createServiceToken<IQueueStorage<any, any>>(\n \"jobqueue.storage.indexedDb\"\n);\n\n/**\n * Extended options for IndexedDB queue storage including prefix support\n */\nexport interface IndexedDbQueueStorageOptions extends QueueStorageOptions, MigrationOptions {\n /** Enable BroadcastChannel notifications (default: true) */\n readonly useBroadcastChannel?: boolean;\n /** Backup polling interval in ms (default: 5000, 0 to disable) */\n readonly backupPollingIntervalMs?: number;\n}\n\n/**\n * IndexedDB implementation of a job queue storage.\n * Provides storage and retrieval for job execution states using IndexedDB.\n */\nexport class IndexedDbQueueStorage<Input, Output> implements IQueueStorage<Input, Output> {\n private db: IDBDatabase | undefined;\n private readonly tableName: string;\n private readonly migrationOptions: MigrationOptions;\n /** The prefix column definitions */\n protected readonly prefixes: readonly PrefixColumn[];\n /** The prefix values for filtering */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n /** Shared hybrid subscription manager */\n private hybridManager: HybridSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n > | null = null;\n /** Hybrid subscription options */\n private readonly hybridOptions: {\n readonly useBroadcastChannel: boolean;\n readonly backupPollingIntervalMs: number;\n };\n\n constructor(\n public readonly queueName: string,\n options: IndexedDbQueueStorageOptions = {}\n ) {\n this.migrationOptions = options;\n this.prefixes = options.prefixes ?? [];\n this.prefixValues = options.prefixValues ?? {};\n this.hybridOptions = {\n useBroadcastChannel: options.useBroadcastChannel ?? true,\n backupPollingIntervalMs: options.backupPollingIntervalMs ?? 5000,\n };\n // Generate table name based on prefix configuration to avoid conflicts\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.tableName = `jobs_${prefixNames}`;\n } else {\n this.tableName = \"jobs\";\n }\n }\n\n /**\n * Gets prefix column names for use in indexes\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Checks if a job matches the current prefix values\n */\n private matchesPrefixes(job: JobStorageFormat<Input, Output> & Record<string, unknown>): boolean {\n for (const [key, value] of Object.entries(this.prefixValues)) {\n if (job[key] !== value) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Gets prefix values as an array in column order for index key construction\n */\n private getPrefixKeyValues(): Array<string | number> {\n return this.prefixes.map((p) => this.prefixValues[p.name]);\n }\n\n private async getDb(): Promise<IDBDatabase> {\n if (this.db) return this.db;\n await this.setupDatabase();\n return this.db!;\n }\n\n /**\n * Sets up the IndexedDB database table with the required schema and indexes.\n * Must be called before using any other methods.\n */\n public async setupDatabase(): Promise<void> {\n const prefixColumnNames = this.getPrefixColumnNames();\n\n // Build index key paths with prefixes prepended\n const buildKeyPath = (basePath: string[]): string[] => {\n return [...prefixColumnNames, ...basePath];\n };\n\n const expectedIndexes: ExpectedIndexDefinition[] = [\n {\n name: \"queue_status\",\n keyPath: buildKeyPath([\"queue\", \"status\"]),\n options: { unique: false },\n },\n {\n name: \"queue_status_run_after\",\n keyPath: buildKeyPath([\"queue\", \"status\", \"run_after\"]),\n options: { unique: false },\n },\n {\n name: \"queue_job_run_id\",\n keyPath: buildKeyPath([\"queue\", \"job_run_id\"]),\n options: { unique: false },\n },\n {\n name: \"queue_fingerprint_status\",\n keyPath: buildKeyPath([\"queue\", \"fingerprint\", \"status\"]),\n options: { unique: false },\n },\n ];\n\n this.db = await ensureIndexedDbTable(\n this.tableName,\n \"id\",\n expectedIndexes,\n this.migrationOptions\n );\n }\n\n /**\n * Adds a job to the queue.\n * @param job - The job to add to the queue.\n * @returns A promise that resolves to the job id.\n */\n public async add(job: JobStorageFormat<Input, Output>): Promise<unknown> {\n const db = await this.getDb();\n const now = new Date().toISOString();\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n jobWithPrefixes.id = jobWithPrefixes.id ?? uuid4();\n jobWithPrefixes.job_run_id = jobWithPrefixes.job_run_id ?? uuid4();\n jobWithPrefixes.queue = this.queueName;\n jobWithPrefixes.fingerprint = await makeFingerprint(jobWithPrefixes.input);\n jobWithPrefixes.status = JobStatus.PENDING;\n jobWithPrefixes.progress = 0;\n jobWithPrefixes.progress_message = \"\";\n jobWithPrefixes.progress_details = null;\n jobWithPrefixes.created_at = now;\n jobWithPrefixes.run_after = now;\n\n // Add prefix values to the job\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n\n return new Promise((resolve, reject) => {\n const request = store.add(jobWithPrefixes);\n\n // Don't resolve until transaction is complete\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve(jobWithPrefixes.id);\n };\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Retrieves a job from the queue by its id.\n * @param id - The id of the job to retrieve.\n * @returns A promise that resolves to the job or undefined if the job is not found.\n */\n async get(id: unknown): Promise<JobStorageFormat<Input, Output> | undefined> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const request = store.get(id as string);\n return new Promise((resolve, reject) => {\n request.onsuccess = () => {\n const job = request.result as\n | (JobStorageFormat<Input, Output> & Record<string, unknown>)\n | undefined;\n // Filter by queue name and prefix values to ensure job belongs to this queue\n if (job && job.queue === this.queueName && this.matchesPrefixes(job)) {\n resolve(job);\n } else {\n resolve(undefined);\n }\n };\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Retrieves a slice of jobs from the queue.\n * @param status - The status of the jobs to retrieve.\n * @param num - The number of jobs to retrieve.\n * @returns A promise that resolves to an array of jobs.\n */\n public async peek(\n status: JobStatus = JobStatus.PENDING,\n num: number = 100\n ): Promise<JobStorageFormat<Input, Output>[]> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status_run_after\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n const ret = new Map<unknown, JobStorageFormat<Input, Output>>();\n // Create a key range for the compound index: from [prefixes..., queue, status, \"\"] to [prefixes..., queue, status, \"\\uffff\"]\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, this.queueName, status, \"\"],\n [...prefixKeyValues, this.queueName, status, \"\\uffff\"]\n );\n const cursorRequest = index.openCursor(keyRange);\n\n const handleCursor = (e: Event) => {\n const cursor = (e.target as IDBRequest<IDBCursorWithValue>).result;\n if (!cursor || ret.size >= num) {\n resolve(Array.from(ret.values()));\n return;\n }\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Verify prefix match and use Map to ensure no duplicates by job ID\n if (this.matchesPrefixes(job)) {\n ret.set(cursor.value.id, cursor.value);\n }\n cursor.continue();\n };\n\n cursorRequest.onsuccess = handleCursor;\n cursorRequest.onerror = () => reject(cursorRequest.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Retrieves the next job from the queue using optimistic locking. In case multiple workers\n * claim the same job, the first worker to claim it will process it and the other workers will return undefined.\n * This ONLY happens if workers are running in multiple tabs.\n *\n * IndexedDB uses snapshot isolation, so concurrent transactions can both see the same\n * PENDING job. To prevent processing the same job multiple times, this method:\n * 1. Claims a job by setting it to PROCESSING with a unique claim token\n * 2. After the transaction completes, re-reads the job to verify the claim succeeded\n * 3. If another worker claimed it first (different claim token), returns undefined\n *\n * @param workerId - Worker ID to associate with the job (required)\n * @returns A promise that resolves to the next job or undefined if the queue is empty.\n */\n public async next(workerId: string): Promise<JobStorageFormat<Input, Output> | undefined> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status_run_after\");\n const now = new Date().toISOString();\n const prefixKeyValues = this.getPrefixKeyValues();\n\n // This ensures we can verify that we actually won the race to claim this job\n const claimToken = workerId;\n\n const jobToReturn = await new Promise<JobStorageFormat<Input, Output> | undefined>(\n (resolve, reject) => {\n const cursorRequest = index.openCursor(\n IDBKeyRange.bound(\n [...prefixKeyValues, this.queueName, JobStatus.PENDING, \"\"],\n [...prefixKeyValues, this.queueName, JobStatus.PENDING, now],\n false,\n false\n )\n );\n\n let claimedJob: JobStorageFormat<Input, Output> | undefined;\n let cursorStopped = false;\n\n cursorRequest.onsuccess = (e) => {\n const cursor = (e.target as IDBRequest<IDBCursorWithValue>).result;\n if (!cursor) {\n // Cursor exhausted - resolve with whatever we found (or undefined)\n return;\n }\n\n // If we already found and updated a job, stop iterating\n if (cursorStopped) {\n return;\n }\n\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Verify the job belongs to this queue, matches prefixes, and is still in PENDING state\n if (\n job.queue !== this.queueName ||\n job.status !== JobStatus.PENDING ||\n !this.matchesPrefixes(job)\n ) {\n cursor.continue();\n return;\n }\n\n // Claim the job with our unique token\n job.status = JobStatus.PROCESSING;\n job.last_ran_at = now;\n job.worker_id = claimToken;\n\n try {\n const updateRequest = store.put(job);\n updateRequest.onsuccess = () => {\n claimedJob = job;\n cursorStopped = true;\n // Stop cursor iteration - we've claimed a job\n };\n updateRequest.onerror = (err) => {\n console.error(\"Failed to update job status:\", err);\n cursor.continue();\n };\n } catch (err) {\n console.error(\"Error updating job:\", err);\n cursor.continue();\n }\n };\n\n cursorRequest.onerror = () => reject(cursorRequest.error);\n\n // Wait for transaction to complete before resolving\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n if (claimedJob) {\n this.hybridManager?.notifyLocalChange();\n }\n resolve(claimedJob);\n };\n tx.onerror = () => reject(tx.error);\n }\n );\n\n // If we didn't find any job to claim, return undefined\n if (!jobToReturn) {\n return undefined;\n }\n\n // Verify we actually won the race by re-reading the job\n // This is the optimistic locking check - if another worker claimed it first,\n // their claim token will be there instead of ours\n const verifiedJob = await this.get(jobToReturn.id);\n\n if (!verifiedJob) {\n // Job was deleted - we lost the race\n return undefined;\n }\n\n if (verifiedJob.worker_id !== claimToken) {\n // Another worker claimed this job - we lost the race\n return undefined;\n }\n\n if (verifiedJob.status !== JobStatus.PROCESSING) {\n // Job status changed (e.g., another worker completed it already) - we lost the race\n return undefined;\n }\n\n // We successfully claimed the job\n return verifiedJob;\n }\n\n /**\n * Retrieves the number of jobs in the queue.\n * Returns the count of jobs in the queue.\n */\n public async size(status = JobStatus.PENDING): Promise<number> {\n const db = await this.getDb();\n const prefixKeyValues = this.getPrefixKeyValues();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status\");\n const keyRange = IDBKeyRange.only([...prefixKeyValues, this.queueName, status]);\n const request = index.count(keyRange);\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Marks a job as complete with its output or error.\n */\n public async complete(job: JobStorageFormat<Input, Output>): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n\n return new Promise((resolve, reject) => {\n const getReq = store.get(job.id as string);\n getReq.onsuccess = () => {\n const existing = getReq.result as\n | (JobStorageFormat<Input, Output> & Record<string, unknown>)\n | undefined;\n // Verify job belongs to this queue and matches prefixes\n if (!existing || existing.queue !== this.queueName || !this.matchesPrefixes(existing)) {\n reject(\n new Error(`Job ${job.id} not found or does not belong to queue ${this.queueName}`)\n );\n return;\n }\n const currentAttempts = existing.run_attempts ?? 0;\n job.run_attempts = currentAttempts + 1;\n // Ensure queue is set correctly\n job.queue = this.queueName;\n\n // Ensure prefix values are preserved\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n\n const putReq = store.put(jobWithPrefixes);\n putReq.onsuccess = () => {};\n putReq.onerror = () => reject(putReq.error);\n };\n getReq.onerror = () => reject(getReq.error);\n\n // Don't resolve until transaction is complete\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Releases a claimed job without consuming a retry attempt.\n */\n public async release(id: unknown): Promise<void> {\n const job = await this.get(id);\n if (!job) return;\n\n job.status = JobStatus.PENDING;\n job.worker_id = null;\n job.progress = 0;\n job.progress_message = \"\";\n job.progress_details = null;\n\n await this.put(job);\n }\n\n /**\n * Aborts a job in the queue.\n */\n public async abort(id: unknown): Promise<void> {\n const job = await this.get(id);\n if (!job) return;\n\n job.status = JobStatus.ABORTING;\n await this.complete(job);\n }\n\n /**\n * Gets jobs by their run ID.\n */\n public async getByRunId(job_run_id: string): Promise<JobStorageFormat<Input, Output>[]> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_job_run_id\");\n const prefixKeyValues = this.getPrefixKeyValues();\n const keyRange = IDBKeyRange.only([...prefixKeyValues, this.queueName, job_run_id]);\n const request = index.getAll(keyRange);\n\n return new Promise((resolve, reject) => {\n request.onsuccess = () => {\n // Filter results to ensure they match prefixes\n const results = (request.result || []).filter(\n (job: JobStorageFormat<Input, Output> & Record<string, unknown>) =>\n this.matchesPrefixes(job)\n );\n resolve(results);\n };\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Deletes all jobs from the queue.\n */\n public async deleteAll(): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n // Use a cursor to iterate through all jobs for this queue with prefix\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, this.queueName, \"\"],\n [...prefixKeyValues, this.queueName, \"\\uffff\"]\n );\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Verify job belongs to this queue and matches prefixes before deleting\n if (job.queue === this.queueName && this.matchesPrefixes(job)) {\n const deleteRequest = cursor.delete();\n deleteRequest.onsuccess = () => {\n cursor.continue();\n };\n deleteRequest.onerror = () => {\n // Continue even if delete fails\n cursor.continue();\n };\n } else {\n cursor.continue();\n }\n }\n };\n\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Gets the output for a given input.\n */\n public async outputForInput(input: Input): Promise<Output | null> {\n const fingerprint = await makeFingerprint(input);\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_fingerprint_status\");\n const prefixKeyValues = this.getPrefixKeyValues();\n const request = index.get([\n ...prefixKeyValues,\n this.queueName,\n fingerprint,\n JobStatus.COMPLETED,\n ]);\n\n return new Promise((resolve, reject) => {\n request.onsuccess = () => {\n const job = request.result as\n | (JobStorageFormat<Input, Output> & Record<string, unknown>)\n | undefined;\n if (job && this.matchesPrefixes(job)) {\n resolve(job.output ?? null);\n } else {\n resolve(null);\n }\n };\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Saves progress updates for a job.\n */\n public async saveProgress(\n id: unknown,\n progress: number,\n message: string,\n details: Record<string, any> | null\n ): Promise<void> {\n const job = await this.get(id);\n if (!job) throw new Error(`Job ${id} not found`);\n\n job.progress = progress;\n job.progress_message = message;\n job.progress_details = details;\n\n await this.put(job);\n }\n\n /**\n * Persists a job to the store without modifying run_attempts or other completion logic.\n */\n private async put(job: JobStorageFormat<Input, Output>): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n\n // Ensure queue is set correctly\n job.queue = this.queueName;\n\n // Ensure prefix values are preserved\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n\n return new Promise((resolve, reject) => {\n const putReq = store.put(jobWithPrefixes);\n putReq.onerror = () => reject(putReq.error);\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Deletes a job by its ID.\n */\n public async delete(id: unknown): Promise<void> {\n const job = await this.get(id);\n if (!job) return;\n\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n const request = store.delete(id as string);\n\n return new Promise((resolve, reject) => {\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Delete jobs with a specific status older than a cutoff date\n * @param status - Status of jobs to delete\n * @param olderThanMs - Delete jobs completed more than this many milliseconds ago\n */\n public async deleteJobsByStatusAndAge(status: JobStatus, olderThanMs: number): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status\");\n const cutoffDate = new Date(Date.now() - olderThanMs).toISOString();\n const prefixKeyValues = this.getPrefixKeyValues();\n const keyRange = IDBKeyRange.only([...prefixKeyValues, this.queueName, status]);\n\n return new Promise((resolve, reject) => {\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Verify job belongs to this queue, matches prefixes, and matches criteria\n if (\n job.queue === this.queueName &&\n this.matchesPrefixes(job) &&\n job.status === status &&\n job.completed_at &&\n job.completed_at <= cutoffDate\n ) {\n cursor.delete();\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Gets all jobs from the queue that match the current prefix values.\n * Used internally for normal polling-based subscriptions (efficient - filters at DB level).\n *\n * @returns A promise that resolves to an array of jobs\n */\n private async getAllJobs(): Promise<Array<JobStorageFormat<Input, Output>>> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n const jobs: Array<JobStorageFormat<Input, Output>> = [];\n // Use a key range that covers all statuses for this queue with prefixes\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, this.queueName, \"\"],\n [...prefixKeyValues, this.queueName, \"\\uffff\"]\n );\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n if (job.queue === this.queueName && this.matchesPrefixes(job)) {\n jobs.push(job);\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => resolve(jobs);\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Gets all jobs from the queue with a custom prefix filter.\n * Used for subscriptions with custom prefix filters (filters at DB level where possible).\n *\n * @param prefixFilter - The prefix values to filter by (empty object = all jobs)\n * @returns A promise that resolves to an array of jobs\n */\n private async getAllJobsWithFilter(\n prefixFilter: Readonly<Record<string, string | number>>\n ): Promise<Array<JobStorageFormat<Input, Output>>> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n\n return new Promise((resolve, reject) => {\n const jobs: Array<JobStorageFormat<Input, Output>> = [];\n const request = store.openCursor();\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Filter by queue name\n if (job.queue !== this.queueName) {\n cursor.continue();\n return;\n }\n // If empty filter, include all jobs for this queue\n if (Object.keys(prefixFilter).length === 0) {\n jobs.push(job);\n } else {\n // Check each filter value\n let matches = true;\n for (const [key, value] of Object.entries(prefixFilter)) {\n if (job[key] !== value) {\n matches = false;\n break;\n }\n }\n if (matches) {\n jobs.push(job);\n }\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => resolve(jobs);\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Checks if a prefix filter is custom (different from instance's prefixes).\n */\n private isCustomPrefixFilter(prefixFilter?: Readonly<Record<string, string | number>>): boolean {\n // No filter specified - use instance prefixes (not custom)\n if (prefixFilter === undefined) {\n return false;\n }\n // Empty filter - receive all (custom)\n if (Object.keys(prefixFilter).length === 0) {\n return true;\n }\n // Check if filter matches instance prefixes exactly\n const instanceKeys = Object.keys(this.prefixValues);\n const filterKeys = Object.keys(prefixFilter);\n if (instanceKeys.length !== filterKeys.length) {\n return true; // Different number of keys = custom\n }\n for (const key of instanceKeys) {\n if (this.prefixValues[key] !== prefixFilter[key]) {\n return true; // Different value = custom\n }\n }\n return false; // Matches instance prefixes exactly\n }\n\n /**\n * Gets or creates the shared hybrid subscription manager for normal subscriptions.\n * This ensures all normal subscriptions share a single manager.\n */\n private getHybridManager(): HybridSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n > {\n if (!this.hybridManager) {\n // Generate unique channel name based on queue name and table name\n const channelName = `indexeddb-queue-${this.tableName}-${this.queueName}`;\n\n this.hybridManager = new HybridSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n >(\n channelName,\n async () => {\n // Fetch jobs with instance's prefix filter (efficient DB-level filtering)\n const jobs = await this.getAllJobs();\n return new Map(jobs.map((j) => [j.id, j]));\n },\n (a, b) => deepEqual(a, b),\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n },\n {\n defaultIntervalMs: 1000,\n useBroadcastChannel: this.hybridOptions.useBroadcastChannel,\n backupPollingIntervalMs: this.hybridOptions.backupPollingIntervalMs,\n }\n );\n }\n return this.hybridManager;\n }\n\n /**\n * Creates a dedicated polling subscription for custom prefix filters.\n * This runs separately from the normal polling manager.\n */\n private subscribeWithCustomPrefixFilter(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n prefixFilter: Readonly<Record<string, string | number>>,\n intervalMs: number\n ): () => void {\n let lastKnownJobs = new Map<unknown, JobStorageFormat<Input, Output>>();\n let cancelled = false;\n\n const poll = async () => {\n if (cancelled) return;\n try {\n const currentJobs = await this.getAllJobsWithFilter(prefixFilter);\n if (cancelled) return;\n const currentMap = new Map(currentJobs.map((j) => [j.id, j]));\n\n // Detect changes\n for (const [id, job] of currentMap) {\n const old = lastKnownJobs.get(id);\n if (!old) {\n callback({ type: \"INSERT\", new: job });\n } else if (!deepEqual(old, job)) {\n callback({ type: \"UPDATE\", old, new: job });\n }\n }\n\n for (const [id, job] of lastKnownJobs) {\n if (!currentMap.has(id)) {\n callback({ type: \"DELETE\", old: job });\n }\n }\n\n lastKnownJobs = currentMap;\n } catch {\n // Ignore polling errors\n }\n };\n\n const intervalId = setInterval(poll, intervalMs);\n poll(); // Initial poll\n\n return () => {\n cancelled = true;\n clearInterval(intervalId);\n };\n }\n\n /**\n * Subscribes to changes in the queue.\n * Uses polling since IndexedDB has no native cross-tab change notifications.\n *\n * Normal subscriptions (no custom prefix filter) share a single polling loop for efficiency.\n * Custom prefix filter subscriptions get their own dedicated polling loop with DB-level filtering.\n *\n * @param callback - Function called when a change occurs\n * @param options - Subscription options including polling interval and prefix filter\n * @returns Unsubscribe function\n */\n public subscribeToChanges(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void {\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n\n // Check if this is a custom prefix filter subscription\n if (this.isCustomPrefixFilter(options?.prefixFilter)) {\n // Custom prefix filter - use dedicated polling with DB-level filtering\n return this.subscribeWithCustomPrefixFilter(callback, options!.prefixFilter!, intervalMs);\n }\n\n // Normal subscription - use shared hybrid manager (efficient)\n const manager = this.getHybridManager();\n return manager.subscribe(callback, { intervalMs });\n }\n\n /**\n * Cleanup method to destroy the hybrid manager\n */\n destroy(): void {\n if (this.hybridManager) {\n this.hybridManager.destroy();\n this.hybridManager = null;\n }\n }\n}\n",
41
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { RealtimeChannel, SupabaseClient } from \"@supabase/supabase-js\";\nimport { createServiceToken, deepEqual, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport { PollingSubscriptionManager } from \"../util/PollingSubscriptionManager\";\nimport {\n IQueueStorage,\n JobStatus,\n JobStorageFormat,\n PrefixColumn,\n QueueChangePayload,\n QueueChangeType,\n QueueStorageOptions,\n QueueSubscribeOptions,\n} from \"./IQueueStorage\";\n\nexport const SUPABASE_QUEUE_STORAGE = createServiceToken<IQueueStorage<any, any>>(\n \"jobqueue.storage.supabase\"\n);\n\n/**\n * Supabase implementation of a job queue.\n * Provides storage and retrieval for job execution states using Supabase.\n */\nexport class SupabaseQueueStorage<Input, Output> implements IQueueStorage<Input, Output> {\n protected readonly client: SupabaseClient;\n protected readonly prefixes: readonly PrefixColumn[];\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n protected readonly tableName: string;\n private realtimeChannel: RealtimeChannel | null = null;\n private pollingManager: PollingSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n > | null = null;\n\n constructor(\n client: SupabaseClient,\n protected readonly queueName: string,\n options?: QueueStorageOptions\n ) {\n this.client = client as SupabaseClient;\n this.prefixes = options?.prefixes ?? [];\n this.prefixValues = options?.prefixValues ?? {};\n // Generate table name based on prefix configuration to avoid column conflicts\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.tableName = `job_queue_${prefixNames}`;\n } else {\n this.tableName = \"job_queue\";\n }\n }\n\n /**\n * Gets the SQL column type for a prefix column (Supabase supports UUID natively)\n */\n private getPrefixColumnType(type: PrefixColumn[\"type\"]): string {\n return type === \"uuid\" ? \"UUID\" : \"INTEGER\";\n }\n\n /**\n * Builds the prefix columns SQL for CREATE TABLE\n */\n private buildPrefixColumnsSql(): string {\n if (this.prefixes.length === 0) return \"\";\n return (\n this.prefixes\n .map((p) => `${p.name} ${this.getPrefixColumnType(p.type)} NOT NULL`)\n .join(\",\\n \") + \",\\n \"\n );\n }\n\n /**\n * Builds prefix column names for use in queries\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Applies prefix filters to a Supabase query builder\n */\n private applyPrefixFilters<T>(query: T): T {\n let result = query as any;\n for (const prefix of this.prefixes) {\n result = result.eq(prefix.name, this.prefixValues[prefix.name]);\n }\n return result as T;\n }\n\n /**\n * Gets prefix values as an object for inserts\n */\n private getPrefixInsertValues(): Record<string, string | number> {\n const values: Record<string, string | number> = {};\n for (const prefix of this.prefixes) {\n values[prefix.name] = this.prefixValues[prefix.name];\n }\n return values;\n }\n\n /**\n * Builds WHERE clause conditions for prefix filtering with inline values (for raw SQL)\n * @returns SQL conditions string with values inlined\n */\n private buildPrefixWhereSql(): string {\n if (this.prefixes.length === 0) {\n return \"\";\n }\n const conditions = this.prefixes\n .map((p) => {\n const value = this.prefixValues[p.name];\n if (p.type === \"uuid\") {\n const validated = this.validateSqlValue(String(value), `prefix \"${p.name}\"`);\n return `${p.name} = '${this.escapeSqlString(validated)}'`;\n }\n const numValue = Number(value ?? 0);\n if (!Number.isFinite(numValue)) {\n throw new Error(`Invalid numeric prefix value for \"${p.name}\": ${value}`);\n }\n return `${p.name} = ${numValue}`;\n })\n .join(\" AND \");\n return \" AND \" + conditions;\n }\n\n /**\n * Regex for validating SQL literal-safe strings.\n * Used for quoted values (e.g. queue names/IDs) and only allows alphanumeric\n * characters, underscores, hyphens, colons, and periods.\n */\n private static readonly SAFE_SQL_VALUE_RE = /^[a-zA-Z0-9_\\-.:]+$/;\n\n /**\n * Validates that a string value is safe for use as a quoted SQL literal.\n * Throws an error if the value contains characters outside SAFE_SQL_VALUE_RE.\n */\n private validateSqlValue(value: string, context: string): string {\n if (!SupabaseQueueStorage.SAFE_SQL_VALUE_RE.test(value)) {\n throw new Error(\n `Unsafe value for ${context}: \"${value}\". Values must match /^[a-zA-Z0-9_\\\\-.:]+$/.`\n );\n }\n return value;\n }\n\n /**\n * Escapes a string value for use in SQL\n */\n private escapeSqlString(value: string): string {\n return value.replace(/'/g, \"''\");\n }\n\n public async setupDatabase(): Promise<void> {\n // Note: For Supabase, table creation should typically be done through migrations\n // This setup assumes the table already exists or uses exec_sql RPC function\n const createTypeSql = `CREATE TYPE job_status AS ENUM (${Object.values(JobStatus)\n .map((v) => `'${v}'`)\n .join(\",\")})`;\n\n const { error: typeError } = await this.client.rpc(\"exec_sql\", { query: createTypeSql });\n // Ignore error if type already exists (code 42710)\n if (typeError && typeError.code !== \"42710\") {\n throw typeError;\n }\n\n const prefixColumnsSql = this.buildPrefixColumnsSql();\n const prefixColumnNames = this.getPrefixColumnNames();\n const prefixIndexPrefix =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const indexSuffix = prefixColumnNames.length > 0 ? \"_\" + prefixColumnNames.join(\"_\") : \"\";\n\n const createTableSql = `\n CREATE TABLE IF NOT EXISTS ${this.tableName} (\n id SERIAL NOT NULL,\n ${prefixColumnsSql}fingerprint text NOT NULL,\n queue text NOT NULL,\n job_run_id text NOT NULL,\n status job_status NOT NULL default 'PENDING',\n input jsonb NOT NULL,\n output jsonb,\n run_attempts integer default 0,\n max_retries integer default 20,\n run_after timestamp with time zone DEFAULT now(),\n last_ran_at timestamp with time zone,\n created_at timestamp with time zone DEFAULT now(),\n deadline_at timestamp with time zone,\n completed_at timestamp with time zone,\n error text,\n error_code text,\n progress real DEFAULT 0,\n progress_message text DEFAULT '',\n progress_details jsonb,\n worker_id text\n )`;\n\n const { error: tableError } = await this.client.rpc(\"exec_sql\", { query: createTableSql });\n if (tableError) {\n // Ignore error if table already exists (code 42P07)\n if (tableError.code !== \"42P07\") {\n throw tableError;\n }\n }\n\n // Create indexes with prefix columns prepended\n const indexes = [\n `CREATE INDEX IF NOT EXISTS job_fetcher${indexSuffix}_idx ON ${this.tableName} (${prefixIndexPrefix}id, status, run_after)`,\n `CREATE INDEX IF NOT EXISTS job_queue_fetcher${indexSuffix}_idx ON ${this.tableName} (${prefixIndexPrefix}queue, status, run_after)`,\n `CREATE INDEX IF NOT EXISTS jobs_fingerprint${indexSuffix}_unique_idx ON ${this.tableName} (${prefixIndexPrefix}queue, fingerprint, status)`,\n ];\n\n for (const indexSql of indexes) {\n await this.client.rpc(\"exec_sql\", { query: indexSql });\n // Ignore index creation errors\n }\n }\n\n /**\n * Adds a new job to the queue.\n * @param job - The job to add\n * @returns The ID of the added job\n */\n public async add(job: JobStorageFormat<Input, Output>): Promise<unknown> {\n const now = new Date().toISOString();\n job.queue = this.queueName;\n job.job_run_id = job.job_run_id ?? uuid4();\n job.fingerprint = await makeFingerprint(job.input);\n job.status = JobStatus.PENDING;\n job.progress = 0;\n job.progress_message = \"\";\n job.progress_details = null;\n job.created_at = now;\n job.run_after = now;\n\n const prefixInsertValues = this.getPrefixInsertValues();\n\n const { data, error } = await this.client\n .from(this.tableName)\n .insert({\n ...prefixInsertValues,\n queue: job.queue,\n fingerprint: job.fingerprint,\n input: job.input,\n run_after: job.run_after,\n created_at: job.created_at,\n deadline_at: job.deadline_at,\n max_retries: job.max_retries,\n job_run_id: job.job_run_id,\n progress: job.progress,\n progress_message: job.progress_message,\n progress_details: job.progress_details,\n })\n .select(\"id\")\n .single();\n\n if (error) throw error;\n if (!data) throw new Error(\"Failed to add to queue\");\n\n job.id = data.id;\n return job.id;\n }\n\n /**\n * Retrieves a job by its ID.\n * @param id - The ID of the job to retrieve\n * @returns The job if found, undefined otherwise\n */\n public async get(id: unknown): Promise<JobStorageFormat<Input, Output> | undefined> {\n let query = this.client\n .from(this.tableName)\n .select(\"*\")\n .eq(\"id\", id)\n .eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") return undefined; // Not found\n throw error;\n }\n\n return data as JobStorageFormat<Input, Output> | undefined;\n }\n\n /**\n * Retrieves a slice of jobs from the queue.\n * @param status - The status to filter by\n * @param num - Maximum number of jobs to return\n * @returns An array of jobs\n */\n public async peek(\n status: JobStatus = JobStatus.PENDING,\n num: number = 100\n ): Promise<JobStorageFormat<Input, Output>[]> {\n num = Number(num) || 100;\n\n let query = this.client\n .from(this.tableName)\n .select(\"*\")\n .eq(\"queue\", this.queueName)\n .eq(\"status\", status);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query.order(\"run_after\", { ascending: true }).limit(num);\n\n if (error) throw error;\n return (data as JobStorageFormat<Input, Output>[]) ?? [];\n }\n\n /**\n * Retrieves the next available job that is ready to be processed.\n * Uses atomic UPDATE with subquery SELECT FOR UPDATE SKIP LOCKED to prevent race conditions.\n * @param workerId - Worker ID to associate with the job (required)\n * @returns The next job or undefined if no job is available\n */\n public async next(workerId: string): Promise<JobStorageFormat<Input, Output> | undefined> {\n const prefixConditions = this.buildPrefixWhereSql();\n const validatedQueueName = this.validateSqlValue(this.queueName, \"queueName\");\n const validatedWorkerId = this.validateSqlValue(workerId, \"workerId\");\n const escapedQueueName = this.escapeSqlString(validatedQueueName);\n const escapedWorkerId = this.escapeSqlString(validatedWorkerId);\n\n // Use the same atomic UPDATE...WHERE id = (SELECT...FOR UPDATE SKIP LOCKED) pattern as PostgresQueueStorage\n const sql = `\n UPDATE ${this.tableName}\n SET status = '${JobStatus.PROCESSING}', last_ran_at = NOW() AT TIME ZONE 'UTC', worker_id = '${escapedWorkerId}'\n WHERE id = (\n SELECT id\n FROM ${this.tableName}\n WHERE queue = '${escapedQueueName}'\n AND status = '${JobStatus.PENDING}'\n ${prefixConditions}\n AND run_after <= NOW() AT TIME ZONE 'UTC'\n ORDER BY run_after ASC\n FOR UPDATE SKIP LOCKED\n LIMIT 1\n )\n RETURNING *`;\n\n const { data, error } = await this.client.rpc(\"exec_sql\", { query: sql });\n\n if (error) throw error;\n\n // exec_sql returns result rows as an array\n if (!data || !Array.isArray(data) || data.length === 0) {\n return undefined;\n }\n\n return data[0] as JobStorageFormat<Input, Output>;\n }\n\n /**\n * Retrieves the number of jobs in the queue with a specific status.\n * @param status - The status of the jobs to count\n * @returns The count of jobs with the specified status\n */\n public async size(status = JobStatus.PENDING): Promise<number> {\n let query = this.client\n .from(this.tableName)\n .select(\"*\", { count: \"exact\", head: true })\n .eq(\"queue\", this.queueName)\n .eq(\"status\", status);\n\n query = this.applyPrefixFilters(query);\n\n const { count, error } = await query;\n\n if (error) throw error;\n return count ?? 0;\n }\n\n /**\n * Gets all jobs from the queue that match the current prefix values.\n * Used internally for polling-based subscriptions.\n *\n * @returns An array of jobs\n */\n private async getAllJobs(): Promise<Array<JobStorageFormat<Input, Output>>> {\n let query = this.client.from(this.tableName).select(\"*\").eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query;\n\n if (error) throw error;\n return (data ?? []) as Array<JobStorageFormat<Input, Output>>;\n }\n\n /**\n * Marks a job as complete with its output or error.\n * Enhanced error handling:\n * - For a retryable error, increments run_attempts and updates run_after.\n * - Marks a job as FAILED immediately for permanent or generic errors.\n */\n public async complete(jobDetails: JobStorageFormat<Input, Output>): Promise<void> {\n const now = new Date().toISOString();\n\n // Handle disabled without changing attempts\n if (jobDetails.status === JobStatus.DISABLED) {\n let query = this.client\n .from(this.tableName)\n .update({\n status: jobDetails.status,\n progress: 100,\n progress_message: \"\",\n progress_details: null,\n completed_at: now,\n last_ran_at: now,\n })\n .eq(\"id\", jobDetails.id)\n .eq(\"queue\", this.queueName);\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n if (error) throw error;\n return;\n }\n\n // Read current attempts to compute next value deterministically\n let getQuery = this.client\n .from(this.tableName)\n .select(\"run_attempts, max_retries\")\n .eq(\"id\", jobDetails.id as number)\n .eq(\"queue\", this.queueName);\n getQuery = this.applyPrefixFilters(getQuery);\n const { data: current, error: getError } = await getQuery.single();\n if (getError) throw getError;\n const currentAttempts = (current?.run_attempts as number | undefined) ?? 0;\n const maxRetries = (current?.max_retries as number | undefined) ?? jobDetails.max_retries ?? 10;\n const nextAttempts = currentAttempts + 1;\n\n if (jobDetails.status === JobStatus.PENDING) {\n // Check if the next attempt would exceed max retries\n if (nextAttempts > maxRetries) {\n // Update to FAILED status instead of rescheduling\n let failQuery = this.client\n .from(this.tableName)\n .update({\n status: JobStatus.FAILED,\n error: \"Max retries reached\",\n error_code: \"MAX_RETRIES_REACHED\",\n progress: 100,\n progress_message: \"\",\n progress_details: null,\n completed_at: now,\n last_ran_at: now,\n })\n .eq(\"id\", jobDetails.id)\n .eq(\"queue\", this.queueName);\n failQuery = this.applyPrefixFilters(failQuery);\n const { error: failError } = await failQuery;\n if (failError) throw failError;\n return;\n }\n\n // Reschedule the job\n let query = this.client\n .from(this.tableName)\n .update({\n error: jobDetails.error ?? null,\n error_code: jobDetails.error_code ?? null,\n status: jobDetails.status,\n run_after: jobDetails.run_after!,\n progress: 0,\n progress_message: \"\",\n progress_details: null,\n run_attempts: nextAttempts,\n last_ran_at: now,\n })\n .eq(\"id\", jobDetails.id)\n .eq(\"queue\", this.queueName);\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n if (error) throw error;\n return;\n }\n\n if (jobDetails.status === JobStatus.COMPLETED || jobDetails.status === JobStatus.FAILED) {\n let query = this.client\n .from(this.tableName)\n .update({\n output: jobDetails.output ?? null,\n error: jobDetails.error ?? null,\n error_code: jobDetails.error_code ?? null,\n status: jobDetails.status,\n progress: 100,\n progress_message: \"\",\n progress_details: null,\n run_attempts: nextAttempts,\n completed_at: now,\n last_ran_at: now,\n })\n .eq(\"id\", jobDetails.id)\n .eq(\"queue\", this.queueName);\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n if (error) throw error;\n return;\n }\n\n // Transitional states: PROCESSING/ABORTING etc - increment attempts like other stores\n let query = this.client\n .from(this.tableName)\n .update({\n status: jobDetails.status,\n output: jobDetails.output ?? null,\n error: jobDetails.error ?? null,\n error_code: jobDetails.error_code ?? null,\n run_after: jobDetails.run_after ?? null,\n run_attempts: nextAttempts,\n last_ran_at: now,\n })\n .eq(\"id\", jobDetails.id)\n .eq(\"queue\", this.queueName);\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n if (error) throw error;\n }\n\n /**\n * Releases a claimed job without consuming a retry attempt.\n */\n public async release(jobId: unknown): Promise<void> {\n let query = this.client\n .from(this.tableName)\n .update({\n status: JobStatus.PENDING,\n worker_id: null,\n progress: 0,\n progress_message: \"\",\n progress_details: null,\n })\n .eq(\"id\", jobId)\n .eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n if (error) throw error;\n }\n\n /**\n * Clears all jobs from the queue.\n */\n public async deleteAll(): Promise<void> {\n let query = this.client.from(this.tableName).delete().eq(\"queue\", this.queueName);\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n\n if (error) throw error;\n }\n\n /**\n * Looks up cached output for a given input\n * Uses input fingerprinting for efficient matching\n * @returns The cached output or null if not found\n */\n public async outputForInput(input: Input): Promise<Output | null> {\n const fingerprint = await makeFingerprint(input);\n\n let query = this.client\n .from(this.tableName)\n .select(\"output\")\n .eq(\"fingerprint\", fingerprint)\n .eq(\"queue\", this.queueName)\n .eq(\"status\", JobStatus.COMPLETED);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null; // Not found\n throw error;\n }\n\n return data?.output ?? null;\n }\n\n /**\n * Aborts a job by setting its status to \"ABORTING\".\n * This method will signal the corresponding AbortController so that\n * the job's execute() method (if it supports an AbortSignal parameter)\n * can clean up and exit.\n */\n public async abort(jobId: unknown): Promise<void> {\n let query = this.client\n .from(this.tableName)\n .update({ status: JobStatus.ABORTING })\n .eq(\"id\", jobId)\n .eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n\n if (error) throw error;\n }\n\n /**\n * Retrieves all jobs for a given job run ID.\n * @param job_run_id - The ID of the job run to retrieve\n * @returns An array of jobs\n */\n public async getByRunId(job_run_id: string): Promise<Array<JobStorageFormat<Input, Output>>> {\n let query = this.client\n .from(this.tableName)\n .select(\"*\")\n .eq(\"job_run_id\", job_run_id)\n .eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n const { data, error } = await query;\n\n if (error) throw error;\n return (data as Array<JobStorageFormat<Input, Output>>) ?? [];\n }\n\n /**\n * Implements the saveProgress method\n */\n public async saveProgress(\n jobId: unknown,\n progress: number,\n message: string,\n details: Record<string, any>\n ): Promise<void> {\n let query = this.client\n .from(this.tableName)\n .update({\n progress,\n progress_message: message,\n progress_details: details,\n })\n .eq(\"id\", jobId)\n .eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n\n if (error) throw error;\n }\n\n /**\n * Deletes a job by its ID\n */\n public async delete(jobId: unknown): Promise<void> {\n let query = this.client\n .from(this.tableName)\n .delete()\n .eq(\"id\", jobId)\n .eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n\n if (error) throw error;\n }\n\n /**\n * Delete jobs with a specific status older than a cutoff date\n * @param status - Status of jobs to delete\n * @param olderThanMs - Delete jobs completed more than this many milliseconds ago\n */\n public async deleteJobsByStatusAndAge(status: JobStatus, olderThanMs: number): Promise<void> {\n const cutoffDate = new Date(Date.now() - olderThanMs).toISOString();\n\n let query = this.client\n .from(this.tableName)\n .delete()\n .eq(\"queue\", this.queueName)\n .eq(\"status\", status)\n .not(\"completed_at\", \"is\", null)\n .lte(\"completed_at\", cutoffDate);\n\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n\n if (error) throw error;\n }\n\n /**\n * Checks if a job from a realtime payload matches the specified prefix filter\n * @param job - The job record from the realtime payload\n * @param prefixFilter - The prefix filter to match against (undefined = use instance prefixes, {} = no filter)\n */\n private matchesPrefixFilter(\n job: Record<string, unknown> | undefined,\n prefixFilter?: Readonly<Record<string, string | number>>\n ): boolean {\n if (!job) return false;\n\n // Check queue name first\n if (job.queue !== this.queueName) {\n return false;\n }\n\n // If prefixFilter is explicitly an empty object, no prefix filtering\n if (prefixFilter && Object.keys(prefixFilter).length === 0) {\n return true;\n }\n\n // Use provided prefixFilter or fall back to instance's prefixValues\n const filterValues = prefixFilter ?? this.prefixValues;\n\n // If no filter values, match all\n if (Object.keys(filterValues).length === 0) {\n return true;\n }\n\n // Check each filter value\n for (const [key, value] of Object.entries(filterValues)) {\n if (job[key] !== value) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Checks if a prefix filter is custom (different from instance's prefixes).\n */\n private isCustomPrefixFilter(prefixFilter?: Readonly<Record<string, string | number>>): boolean {\n // No filter specified - use instance prefixes (not custom)\n if (prefixFilter === undefined) {\n return false;\n }\n // Empty filter - receive all (custom)\n if (Object.keys(prefixFilter).length === 0) {\n return true;\n }\n // Check if filter matches instance prefixes exactly\n const instanceKeys = Object.keys(this.prefixValues);\n const filterKeys = Object.keys(prefixFilter);\n if (instanceKeys.length !== filterKeys.length) {\n return true; // Different number of keys = custom\n }\n for (const key of instanceKeys) {\n if (this.prefixValues[key] !== prefixFilter[key]) {\n return true; // Different value = custom\n }\n }\n return false; // Matches instance prefixes exactly\n }\n\n /**\n * Gets all jobs from the queue with a custom prefix filter.\n * Used for subscriptions with custom prefix filters (filters at DB level).\n *\n * @param prefixFilter - The prefix values to filter by (empty object = all jobs)\n * @returns A promise that resolves to an array of jobs\n */\n private async getAllJobsWithFilter(\n prefixFilter: Readonly<Record<string, string | number>>\n ): Promise<Array<JobStorageFormat<Input, Output>>> {\n let query = this.client.from(this.tableName).select(\"*\").eq(\"queue\", this.queueName);\n\n // Apply the custom prefix filter\n for (const [key, value] of Object.entries(prefixFilter)) {\n query = query.eq(key, value);\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n return (data ?? []) as Array<JobStorageFormat<Input, Output>>;\n }\n\n /**\n * Subscribes to changes in the queue.\n * Uses Supabase realtime by default.\n *\n * @param callback - Function called when a change occurs\n * @param options - Subscription options including prefix filter\n * @returns Unsubscribe function\n */\n public subscribeToChanges(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void {\n return this.subscribeToChangesWithRealtime(callback, options?.prefixFilter);\n }\n\n /**\n * Subscribe using Supabase realtime (protected).\n *\n * @param callback - Function called when a change occurs\n * @param prefixFilter - Optional prefix filter (undefined = use instance prefixes, {} = no filter)\n * @returns Unsubscribe function\n */\n protected subscribeToChangesWithRealtime(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n prefixFilter?: Readonly<Record<string, string | number>>\n ): () => void {\n const channelName = `queue-${this.tableName}-${this.queueName}-${Date.now()}`;\n\n this.realtimeChannel = this.client\n .channel(channelName)\n .on(\n \"postgres_changes\",\n {\n event: \"*\",\n schema: \"public\",\n table: this.tableName,\n filter: `queue=eq.${this.queueName}`,\n },\n (payload) => {\n // Filter by prefix values\n const newJob = payload.new as Record<string, unknown> | undefined;\n const oldJob = payload.old as Record<string, unknown> | undefined;\n\n // Check if either old or new job matches the filter\n const newMatches = this.matchesPrefixFilter(newJob, prefixFilter);\n const oldMatches = this.matchesPrefixFilter(oldJob, prefixFilter);\n\n if (!newMatches && !oldMatches) {\n return;\n }\n\n callback({\n type: payload.eventType.toUpperCase() as QueueChangeType,\n old:\n oldJob && Object.keys(oldJob).length > 0\n ? (oldJob as JobStorageFormat<Input, Output>)\n : undefined,\n new:\n newJob && Object.keys(newJob).length > 0\n ? (newJob as JobStorageFormat<Input, Output>)\n : undefined,\n });\n }\n )\n .subscribe();\n\n return () => {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n };\n }\n\n /**\n * Gets or creates the shared polling subscription manager for normal subscriptions (fallback).\n * This ensures all normal subscriptions share a single polling loop per interval.\n */\n private getPollingManager(): PollingSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n > {\n if (!this.pollingManager) {\n this.pollingManager = new PollingSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n >(\n async () => {\n // Fetch jobs with instance's prefix filter (efficient DB-level filtering)\n const jobs = await this.getAllJobs();\n return new Map(jobs.map((j) => [j.id, j]));\n },\n (a, b) => deepEqual(a, b),\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n }\n );\n }\n return this.pollingManager;\n }\n\n /**\n * Creates a dedicated polling subscription for custom prefix filters (fallback).\n * This runs separately from the normal polling manager with DB-level filtering.\n */\n private subscribeWithCustomPrefixFilterPolling(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n prefixFilter: Readonly<Record<string, string | number>>,\n intervalMs: number\n ): () => void {\n let lastKnownJobs = new Map<unknown, JobStorageFormat<Input, Output>>();\n let cancelled = false;\n\n const poll = async () => {\n if (cancelled) return;\n try {\n const currentJobs = await this.getAllJobsWithFilter(prefixFilter);\n if (cancelled) return;\n const currentMap = new Map(currentJobs.map((j) => [j.id, j]));\n\n // Detect changes\n for (const [id, job] of currentMap) {\n const old = lastKnownJobs.get(id);\n if (!old) {\n callback({ type: \"INSERT\", new: job });\n } else if (!deepEqual(old, job)) {\n callback({ type: \"UPDATE\", old, new: job });\n }\n }\n\n for (const [id, job] of lastKnownJobs) {\n if (!currentMap.has(id)) {\n callback({ type: \"DELETE\", old: job });\n }\n }\n\n lastKnownJobs = currentMap;\n } catch {\n // Ignore polling errors\n }\n };\n\n const intervalId = setInterval(poll, intervalMs);\n poll(); // Initial poll\n\n return () => {\n cancelled = true;\n clearInterval(intervalId);\n };\n }\n\n /**\n * Subscribe using polling (protected, available as fallback).\n *\n * Normal subscriptions (no custom prefix filter) share a single polling loop for efficiency.\n * Custom prefix filter subscriptions get their own dedicated polling loop with DB-level filtering.\n *\n * @param callback - Function called when a change occurs\n * @param options - Subscription options including interval and prefix filter\n * @returns Unsubscribe function\n */\n protected subscribeToChangesWithPolling(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void {\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n\n // Check if this is a custom prefix filter subscription\n if (this.isCustomPrefixFilter(options?.prefixFilter)) {\n // Custom prefix filter - use dedicated polling with DB-level filtering\n return this.subscribeWithCustomPrefixFilterPolling(\n callback,\n options!.prefixFilter!,\n intervalMs\n );\n }\n\n // Normal subscription - use shared polling manager (efficient)\n const manager = this.getPollingManager();\n return manager.subscribe(callback, { intervalMs });\n }\n}\n",
42
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken } from \"@workglow/util\";\nimport {\n ensureIndexedDbTable,\n ExpectedIndexDefinition,\n MigrationOptions,\n} from \"../util/IndexedDbTable\";\nimport type { PrefixColumn } from \"../queue/IQueueStorage\";\nimport { IRateLimiterStorage, RateLimiterStorageOptions } from \"./IRateLimiterStorage\";\n\nexport const INDEXED_DB_RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\n \"ratelimiter.storage.indexedDb\"\n);\n\n/**\n * Extended options for IndexedDB rate limiter storage including prefix support.\n */\nexport interface IndexedDbRateLimiterStorageOptions\n extends RateLimiterStorageOptions, MigrationOptions {}\n\n/**\n * Execution record stored in IndexedDB.\n */\ninterface ExecutionRecord {\n readonly id?: string;\n readonly queue_name: string;\n readonly executed_at: string;\n readonly [key: string]: unknown;\n}\n\n/**\n * Next available record stored in IndexedDB.\n */\ninterface NextAvailableRecord {\n readonly queue_name: string;\n readonly next_available_at: string;\n readonly [key: string]: unknown;\n}\n\n/**\n * IndexedDB implementation of rate limiter storage.\n * Manages execution records and next available times for rate limiting.\n */\nexport class IndexedDbRateLimiterStorage implements IRateLimiterStorage {\n private executionDb: IDBDatabase | undefined;\n private nextAvailableDb: IDBDatabase | undefined;\n private readonly executionTableName: string;\n private readonly nextAvailableTableName: string;\n private readonly migrationOptions: MigrationOptions;\n /** The prefix column definitions */\n protected readonly prefixes: readonly PrefixColumn[];\n /** The prefix values for filtering */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n\n constructor(options: IndexedDbRateLimiterStorageOptions = {}) {\n this.migrationOptions = options;\n this.prefixes = options.prefixes ?? [];\n this.prefixValues = options.prefixValues ?? {};\n\n // Generate table names based on prefix configuration\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.executionTableName = `rate_limit_executions_${prefixNames}`;\n this.nextAvailableTableName = `rate_limit_next_available_${prefixNames}`;\n } else {\n this.executionTableName = \"rate_limit_executions\";\n this.nextAvailableTableName = \"rate_limit_next_available\";\n }\n }\n\n /**\n * Gets prefix column names for use in indexes.\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Checks if a record matches the current prefix values.\n */\n private matchesPrefixes(record: Record<string, unknown>): boolean {\n for (const [key, value] of Object.entries(this.prefixValues)) {\n if (record[key] !== value) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Gets prefix values as an array in column order for index key construction.\n */\n private getPrefixKeyValues(): Array<string | number> {\n return this.prefixes.map((p) => this.prefixValues[p.name]);\n }\n\n private async getExecutionDb(): Promise<IDBDatabase> {\n if (this.executionDb) return this.executionDb;\n await this.setupDatabase();\n return this.executionDb!;\n }\n\n private async getNextAvailableDb(): Promise<IDBDatabase> {\n if (this.nextAvailableDb) return this.nextAvailableDb;\n await this.setupDatabase();\n return this.nextAvailableDb!;\n }\n\n public async setupDatabase(): Promise<void> {\n const prefixColumnNames = this.getPrefixColumnNames();\n\n // Build index key paths with prefixes prepended\n const buildKeyPath = (basePath: string[]): string[] => {\n return [...prefixColumnNames, ...basePath];\n };\n\n const executionIndexes: ExpectedIndexDefinition[] = [\n {\n name: \"queue_executed_at\",\n keyPath: buildKeyPath([\"queue_name\", \"executed_at\"]),\n options: { unique: false },\n },\n ];\n\n this.executionDb = await ensureIndexedDbTable(\n this.executionTableName,\n \"id\",\n executionIndexes,\n this.migrationOptions\n );\n\n const nextAvailableIndexes: ExpectedIndexDefinition[] = [\n {\n name: \"queue_name\",\n keyPath: buildKeyPath([\"queue_name\"]),\n options: { unique: true },\n },\n ];\n\n this.nextAvailableDb = await ensureIndexedDbTable(\n this.nextAvailableTableName,\n buildKeyPath([\"queue_name\"]).join(\"_\"),\n nextAvailableIndexes,\n this.migrationOptions\n );\n }\n\n public async recordExecution(queueName: string): Promise<void> {\n const db = await this.getExecutionDb();\n const tx = db.transaction(this.executionTableName, \"readwrite\");\n const store = tx.objectStore(this.executionTableName);\n\n const record: ExecutionRecord = {\n id: crypto.randomUUID(),\n queue_name: queueName,\n executed_at: new Date().toISOString(),\n };\n\n // Add prefix values to the record\n for (const [key, value] of Object.entries(this.prefixValues)) {\n (record as Record<string, unknown>)[key] = value;\n }\n\n return new Promise((resolve, reject) => {\n const request = store.add(record);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n public async getExecutionCount(queueName: string, windowStartTime: string): Promise<number> {\n const db = await this.getExecutionDb();\n const tx = db.transaction(this.executionTableName, \"readonly\");\n const store = tx.objectStore(this.executionTableName);\n const index = store.index(\"queue_executed_at\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n let count = 0;\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, queueName, windowStartTime],\n [...prefixKeyValues, queueName, \"\\uffff\"],\n true, // exclude lower bound (windowStartTime)\n false\n );\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const record = cursor.value as ExecutionRecord;\n if (this.matchesPrefixes(record)) {\n count++;\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => resolve(count);\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n public async getOldestExecutionAtOffset(\n queueName: string,\n offset: number\n ): Promise<string | undefined> {\n const db = await this.getExecutionDb();\n const tx = db.transaction(this.executionTableName, \"readonly\");\n const store = tx.objectStore(this.executionTableName);\n const index = store.index(\"queue_executed_at\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n const executions: string[] = [];\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, queueName, \"\"],\n [...prefixKeyValues, queueName, \"\\uffff\"]\n );\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const record = cursor.value as ExecutionRecord;\n if (this.matchesPrefixes(record)) {\n executions.push(record.executed_at);\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => {\n // Sort by executed_at ascending\n executions.sort();\n resolve(executions[offset]);\n };\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n public async getNextAvailableTime(queueName: string): Promise<string | undefined> {\n const db = await this.getNextAvailableDb();\n const tx = db.transaction(this.nextAvailableTableName, \"readonly\");\n const store = tx.objectStore(this.nextAvailableTableName);\n const prefixKeyValues = this.getPrefixKeyValues();\n const key = [...prefixKeyValues, queueName].join(\"_\");\n\n return new Promise((resolve, reject) => {\n const request = store.get(key);\n request.onsuccess = () => {\n const record = request.result as NextAvailableRecord | undefined;\n if (record && this.matchesPrefixes(record)) {\n resolve(record.next_available_at);\n } else {\n resolve(undefined);\n }\n };\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n public async setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void> {\n const db = await this.getNextAvailableDb();\n const tx = db.transaction(this.nextAvailableTableName, \"readwrite\");\n const store = tx.objectStore(this.nextAvailableTableName);\n const prefixKeyValues = this.getPrefixKeyValues();\n const key = [...prefixKeyValues, queueName].join(\"_\");\n\n const record: NextAvailableRecord & { [key: string]: unknown } = {\n queue_name: queueName,\n next_available_at: nextAvailableAt,\n };\n\n // Add prefix values to the record\n for (const [k, value] of Object.entries(this.prefixValues)) {\n record[k] = value;\n }\n\n // Set the key field\n (record as Record<string, unknown>)[\n this.getPrefixColumnNames().concat([\"queue_name\"]).join(\"_\")\n ] = key;\n\n return new Promise((resolve, reject) => {\n const request = store.put(record);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n public async clear(queueName: string): Promise<void> {\n // Clear executions\n const execDb = await this.getExecutionDb();\n const execTx = execDb.transaction(this.executionTableName, \"readwrite\");\n const execStore = execTx.objectStore(this.executionTableName);\n const execIndex = execStore.index(\"queue_executed_at\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n await new Promise<void>((resolve, reject) => {\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, queueName, \"\"],\n [...prefixKeyValues, queueName, \"\\uffff\"]\n );\n const request = execIndex.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const record = cursor.value as ExecutionRecord;\n if (this.matchesPrefixes(record)) {\n cursor.delete();\n }\n cursor.continue();\n }\n };\n\n execTx.oncomplete = () => resolve();\n execTx.onerror = () => reject(execTx.error);\n request.onerror = () => reject(request.error);\n });\n\n // Clear next available\n const nextDb = await this.getNextAvailableDb();\n const nextTx = nextDb.transaction(this.nextAvailableTableName, \"readwrite\");\n const nextStore = nextTx.objectStore(this.nextAvailableTableName);\n const key = [...prefixKeyValues, queueName].join(\"_\");\n\n await new Promise<void>((resolve, reject) => {\n const request = nextStore.delete(key);\n nextTx.oncomplete = () => resolve();\n nextTx.onerror = () => reject(nextTx.error);\n request.onerror = () => reject(request.error);\n });\n }\n}\n",
43
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { SupabaseClient } from \"@supabase/supabase-js\";\nimport { createServiceToken } from \"@workglow/util\";\nimport type { PrefixColumn } from \"../queue/IQueueStorage\";\nimport { IRateLimiterStorage, RateLimiterStorageOptions } from \"./IRateLimiterStorage\";\n\nexport const SUPABASE_RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\n \"ratelimiter.storage.supabase\"\n);\n\n/**\n * Supabase implementation of rate limiter storage.\n * Manages execution records and next available times for rate limiting.\n */\nexport class SupabaseRateLimiterStorage implements IRateLimiterStorage {\n protected readonly client: SupabaseClient;\n protected readonly prefixes: readonly PrefixColumn[];\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n protected readonly executionTableName: string;\n protected readonly nextAvailableTableName: string;\n\n constructor(client: unknown, options?: RateLimiterStorageOptions) {\n this.client = client as SupabaseClient;\n this.prefixes = options?.prefixes ?? [];\n this.prefixValues = options?.prefixValues ?? {};\n\n // Generate table names based on prefix configuration\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.executionTableName = `rate_limit_executions_${prefixNames}`;\n this.nextAvailableTableName = `rate_limit_next_available_${prefixNames}`;\n } else {\n this.executionTableName = \"rate_limit_executions\";\n this.nextAvailableTableName = \"rate_limit_next_available\";\n }\n }\n\n /**\n * Gets the SQL column type for a prefix column (Supabase supports UUID natively).\n */\n private getPrefixColumnType(type: PrefixColumn[\"type\"]): string {\n return type === \"uuid\" ? \"UUID\" : \"INTEGER\";\n }\n\n /**\n * Builds the prefix columns SQL for CREATE TABLE.\n */\n private buildPrefixColumnsSql(): string {\n if (this.prefixes.length === 0) return \"\";\n return (\n this.prefixes\n .map((p) => `${p.name} ${this.getPrefixColumnType(p.type)} NOT NULL`)\n .join(\",\\n \") + \",\\n \"\n );\n }\n\n /**\n * Builds prefix column names for use in queries.\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Applies prefix filters to a Supabase query builder.\n */\n private applyPrefixFilters<T>(query: T): T {\n let result = query as any;\n for (const prefix of this.prefixes) {\n result = result.eq(prefix.name, this.prefixValues[prefix.name]);\n }\n return result as T;\n }\n\n /**\n * Gets prefix values as an object for inserts.\n */\n private getPrefixInsertValues(): Record<string, string | number> {\n const values: Record<string, string | number> = {};\n for (const prefix of this.prefixes) {\n values[prefix.name] = this.prefixValues[prefix.name];\n }\n return values;\n }\n\n public async setupDatabase(): Promise<void> {\n const prefixColumnsSql = this.buildPrefixColumnsSql();\n const prefixColumnNames = this.getPrefixColumnNames();\n const prefixIndexPrefix =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const indexSuffix = prefixColumnNames.length > 0 ? \"_\" + prefixColumnNames.join(\"_\") : \"\";\n\n // Create execution tracking table\n const createExecTableSql = `\n CREATE TABLE IF NOT EXISTS ${this.executionTableName} (\n id SERIAL PRIMARY KEY,\n ${prefixColumnsSql}queue_name TEXT NOT NULL,\n executed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n )\n `;\n\n const { error: execTableError } = await this.client.rpc(\"exec_sql\", {\n query: createExecTableSql,\n });\n if (execTableError && execTableError.code !== \"42P07\") {\n throw execTableError;\n }\n\n // Create index on execution table\n const createExecIndexSql = `\n CREATE INDEX IF NOT EXISTS rate_limit_exec_queue${indexSuffix}_idx \n ON ${this.executionTableName} (${prefixIndexPrefix}queue_name, executed_at)\n `;\n await this.client.rpc(\"exec_sql\", { query: createExecIndexSql });\n\n // Build primary key columns\n const primaryKeyColumns =\n prefixColumnNames.length > 0 ? `${prefixColumnNames.join(\", \")}, queue_name` : \"queue_name\";\n\n // Create next available table\n const createNextTableSql = `\n CREATE TABLE IF NOT EXISTS ${this.nextAvailableTableName} (\n ${prefixColumnsSql}queue_name TEXT NOT NULL,\n next_available_at TIMESTAMP WITH TIME ZONE,\n PRIMARY KEY (${primaryKeyColumns})\n )\n `;\n\n const { error: nextTableError } = await this.client.rpc(\"exec_sql\", {\n query: createNextTableSql,\n });\n if (nextTableError && nextTableError.code !== \"42P07\") {\n throw nextTableError;\n }\n }\n\n public async recordExecution(queueName: string): Promise<void> {\n const prefixInsertValues = this.getPrefixInsertValues();\n\n const { error } = await this.client.from(this.executionTableName).insert({\n ...prefixInsertValues,\n queue_name: queueName,\n });\n\n if (error) throw error;\n }\n\n public async getExecutionCount(queueName: string, windowStartTime: string): Promise<number> {\n let query = this.client\n .from(this.executionTableName)\n .select(\"*\", { count: \"exact\", head: true })\n .eq(\"queue_name\", queueName)\n .gt(\"executed_at\", windowStartTime);\n\n query = this.applyPrefixFilters(query);\n\n const { count, error } = await query;\n\n if (error) throw error;\n return count ?? 0;\n }\n\n public async getOldestExecutionAtOffset(\n queueName: string,\n offset: number\n ): Promise<string | undefined> {\n let query = this.client\n .from(this.executionTableName)\n .select(\"executed_at\")\n .eq(\"queue_name\", queueName);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query\n .order(\"executed_at\", { ascending: true })\n .range(offset, offset);\n\n if (error) throw error;\n if (!data || data.length === 0) return undefined;\n return new Date(data[0].executed_at).toISOString();\n }\n\n public async getNextAvailableTime(queueName: string): Promise<string | undefined> {\n let query = this.client\n .from(this.nextAvailableTableName)\n .select(\"next_available_at\")\n .eq(\"queue_name\", queueName);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") return undefined; // Not found\n throw error;\n }\n\n if (!data?.next_available_at) return undefined;\n return new Date(data.next_available_at).toISOString();\n }\n\n public async setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void> {\n const prefixInsertValues = this.getPrefixInsertValues();\n\n const { error } = await this.client.from(this.nextAvailableTableName).upsert(\n {\n ...prefixInsertValues,\n queue_name: queueName,\n next_available_at: nextAvailableAt,\n },\n {\n onConflict:\n this.prefixes.length > 0\n ? `${this.getPrefixColumnNames().join(\",\")},queue_name`\n : \"queue_name\",\n }\n );\n\n if (error) throw error;\n }\n\n public async clear(queueName: string): Promise<void> {\n let execQuery = this.client.from(this.executionTableName).delete().eq(\"queue_name\", queueName);\n execQuery = this.applyPrefixFilters(execQuery);\n const { error: execError } = await execQuery;\n if (execError) throw execError;\n\n let nextQuery = this.client\n .from(this.nextAvailableTableName)\n .delete()\n .eq(\"queue_name\", queueName);\n nextQuery = this.applyPrefixFilters(nextQuery);\n const { error: nextError } = await nextQuery;\n if (nextError) throw nextError;\n }\n}\n",
40
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken, deepEqual, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport { HybridSubscriptionManager } from \"../util/HybridSubscriptionManager\";\nimport {\n ensureIndexedDbTable,\n ExpectedIndexDefinition,\n MigrationOptions,\n} from \"../util/IndexedDbTable\";\nimport {\n IQueueStorage,\n JobStatus,\n JobStorageFormat,\n PrefixColumn,\n QueueChangePayload,\n QueueStorageOptions,\n QueueSubscribeOptions,\n} from \"./IQueueStorage\";\n\nexport const INDEXED_DB_QUEUE_STORAGE = createServiceToken<IQueueStorage<any, any>>(\n \"jobqueue.storage.indexedDb\"\n);\n\n/**\n * Extended options for IndexedDB queue storage including prefix support\n */\nexport interface IndexedDbQueueStorageOptions extends QueueStorageOptions, MigrationOptions {\n /** Enable BroadcastChannel notifications (default: true) */\n readonly useBroadcastChannel?: boolean;\n /** Backup polling interval in ms (default: 5000, 0 to disable) */\n readonly backupPollingIntervalMs?: number;\n}\n\n/**\n * IndexedDB implementation of a job queue storage.\n * Provides storage and retrieval for job execution states using IndexedDB.\n */\nexport class IndexedDbQueueStorage<Input, Output> implements IQueueStorage<Input, Output> {\n public readonly scope = \"process\" as const;\n private db: IDBDatabase | undefined;\n private readonly tableName: string;\n private readonly migrationOptions: MigrationOptions;\n /** The prefix column definitions */\n protected readonly prefixes: readonly PrefixColumn[];\n /** The prefix values for filtering */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n /** Shared hybrid subscription manager */\n private hybridManager: HybridSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n > | null = null;\n /** Hybrid subscription options */\n private readonly hybridOptions: {\n readonly useBroadcastChannel: boolean;\n readonly backupPollingIntervalMs: number;\n };\n\n constructor(\n public readonly queueName: string,\n options: IndexedDbQueueStorageOptions = {}\n ) {\n this.migrationOptions = options;\n this.prefixes = options.prefixes ?? [];\n this.prefixValues = options.prefixValues ?? {};\n this.hybridOptions = {\n useBroadcastChannel: options.useBroadcastChannel ?? true,\n backupPollingIntervalMs: options.backupPollingIntervalMs ?? 5000,\n };\n // Generate table name based on prefix configuration to avoid conflicts\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.tableName = `jobs_${prefixNames}`;\n } else {\n this.tableName = \"jobs\";\n }\n }\n\n /**\n * Gets prefix column names for use in indexes\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Checks if a job matches the current prefix values\n */\n private matchesPrefixes(job: JobStorageFormat<Input, Output> & Record<string, unknown>): boolean {\n for (const [key, value] of Object.entries(this.prefixValues)) {\n if (job[key] !== value) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Gets prefix values as an array in column order for index key construction\n */\n private getPrefixKeyValues(): Array<string | number> {\n return this.prefixes.map((p) => this.prefixValues[p.name]);\n }\n\n private async getDb(): Promise<IDBDatabase> {\n if (this.db) return this.db;\n await this.setupDatabase();\n return this.db!;\n }\n\n /**\n * Sets up the IndexedDB database table with the required schema and indexes.\n * Must be called before using any other methods.\n */\n public async setupDatabase(): Promise<void> {\n const prefixColumnNames = this.getPrefixColumnNames();\n\n // Build index key paths with prefixes prepended\n const buildKeyPath = (basePath: string[]): string[] => {\n return [...prefixColumnNames, ...basePath];\n };\n\n const expectedIndexes: ExpectedIndexDefinition[] = [\n {\n name: \"queue_status\",\n keyPath: buildKeyPath([\"queue\", \"status\"]),\n options: { unique: false },\n },\n {\n name: \"queue_status_run_after\",\n keyPath: buildKeyPath([\"queue\", \"status\", \"run_after\"]),\n options: { unique: false },\n },\n {\n name: \"queue_job_run_id\",\n keyPath: buildKeyPath([\"queue\", \"job_run_id\"]),\n options: { unique: false },\n },\n {\n name: \"queue_fingerprint_status\",\n keyPath: buildKeyPath([\"queue\", \"fingerprint\", \"status\"]),\n options: { unique: false },\n },\n ];\n\n this.db = await ensureIndexedDbTable(\n this.tableName,\n \"id\",\n expectedIndexes,\n this.migrationOptions\n );\n }\n\n /**\n * Adds a job to the queue.\n * @param job - The job to add to the queue.\n * @returns A promise that resolves to the job id.\n */\n public async add(job: JobStorageFormat<Input, Output>): Promise<unknown> {\n const db = await this.getDb();\n const now = new Date().toISOString();\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n jobWithPrefixes.id = jobWithPrefixes.id ?? uuid4();\n jobWithPrefixes.job_run_id = jobWithPrefixes.job_run_id ?? uuid4();\n jobWithPrefixes.queue = this.queueName;\n jobWithPrefixes.fingerprint = await makeFingerprint(jobWithPrefixes.input);\n jobWithPrefixes.status = JobStatus.PENDING;\n jobWithPrefixes.progress = 0;\n jobWithPrefixes.progress_message = \"\";\n jobWithPrefixes.progress_details = null;\n jobWithPrefixes.created_at = now;\n jobWithPrefixes.run_after = now;\n\n // Add prefix values to the job\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n\n return new Promise((resolve, reject) => {\n const request = store.add(jobWithPrefixes);\n\n // Don't resolve until transaction is complete\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve(jobWithPrefixes.id);\n };\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Retrieves a job from the queue by its id.\n * @param id - The id of the job to retrieve.\n * @returns A promise that resolves to the job or undefined if the job is not found.\n */\n async get(id: unknown): Promise<JobStorageFormat<Input, Output> | undefined> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const request = store.get(id as string);\n return new Promise((resolve, reject) => {\n request.onsuccess = () => {\n const job = request.result as\n | (JobStorageFormat<Input, Output> & Record<string, unknown>)\n | undefined;\n // Filter by queue name and prefix values to ensure job belongs to this queue\n if (job && job.queue === this.queueName && this.matchesPrefixes(job)) {\n resolve(job);\n } else {\n resolve(undefined);\n }\n };\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Retrieves a slice of jobs from the queue.\n * @param status - The status of the jobs to retrieve.\n * @param num - The number of jobs to retrieve.\n * @returns A promise that resolves to an array of jobs.\n */\n public async peek(\n status: JobStatus = JobStatus.PENDING,\n num: number = 100\n ): Promise<JobStorageFormat<Input, Output>[]> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status_run_after\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n const ret = new Map<unknown, JobStorageFormat<Input, Output>>();\n // Create a key range for the compound index: from [prefixes..., queue, status, \"\"] to [prefixes..., queue, status, \"\\uffff\"]\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, this.queueName, status, \"\"],\n [...prefixKeyValues, this.queueName, status, \"\\uffff\"]\n );\n const cursorRequest = index.openCursor(keyRange);\n\n const handleCursor = (e: Event) => {\n const cursor = (e.target as IDBRequest<IDBCursorWithValue>).result;\n if (!cursor || ret.size >= num) {\n resolve(Array.from(ret.values()));\n return;\n }\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Verify prefix match and use Map to ensure no duplicates by job ID\n if (this.matchesPrefixes(job)) {\n ret.set(cursor.value.id, cursor.value);\n }\n cursor.continue();\n };\n\n cursorRequest.onsuccess = handleCursor;\n cursorRequest.onerror = () => reject(cursorRequest.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Retrieves the next job from the queue using optimistic locking. In case multiple workers\n * claim the same job, the first worker to claim it will process it and the other workers will return undefined.\n * This ONLY happens if workers are running in multiple tabs.\n *\n * IndexedDB uses snapshot isolation, so concurrent transactions can both see the same\n * PENDING job. To prevent processing the same job multiple times, this method:\n * 1. Claims a job by setting it to PROCESSING with a unique claim token\n * 2. After the transaction completes, re-reads the job to verify the claim succeeded\n * 3. If another worker claimed it first (different claim token), returns undefined\n *\n * @param workerId - Worker ID to associate with the job (required)\n * @returns A promise that resolves to the next job or undefined if the queue is empty.\n */\n public async next(workerId: string): Promise<JobStorageFormat<Input, Output> | undefined> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status_run_after\");\n const now = new Date().toISOString();\n const prefixKeyValues = this.getPrefixKeyValues();\n\n // This ensures we can verify that we actually won the race to claim this job\n const claimToken = workerId;\n\n const jobToReturn = await new Promise<JobStorageFormat<Input, Output> | undefined>(\n (resolve, reject) => {\n const cursorRequest = index.openCursor(\n IDBKeyRange.bound(\n [...prefixKeyValues, this.queueName, JobStatus.PENDING, \"\"],\n [...prefixKeyValues, this.queueName, JobStatus.PENDING, now],\n false,\n false\n )\n );\n\n let claimedJob: JobStorageFormat<Input, Output> | undefined;\n let cursorStopped = false;\n\n cursorRequest.onsuccess = (e) => {\n const cursor = (e.target as IDBRequest<IDBCursorWithValue>).result;\n if (!cursor) {\n // Cursor exhausted - resolve with whatever we found (or undefined)\n return;\n }\n\n // If we already found and updated a job, stop iterating\n if (cursorStopped) {\n return;\n }\n\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Verify the job belongs to this queue, matches prefixes, and is still in PENDING state\n if (\n job.queue !== this.queueName ||\n job.status !== JobStatus.PENDING ||\n !this.matchesPrefixes(job)\n ) {\n cursor.continue();\n return;\n }\n\n // Claim the job with our unique token\n job.status = JobStatus.PROCESSING;\n job.last_ran_at = now;\n job.worker_id = claimToken;\n\n try {\n const updateRequest = store.put(job);\n updateRequest.onsuccess = () => {\n claimedJob = job;\n cursorStopped = true;\n // Stop cursor iteration - we've claimed a job\n };\n updateRequest.onerror = (err) => {\n console.error(\"Failed to update job status:\", err);\n cursor.continue();\n };\n } catch (err) {\n console.error(\"Error updating job:\", err);\n cursor.continue();\n }\n };\n\n cursorRequest.onerror = () => reject(cursorRequest.error);\n\n // Wait for transaction to complete before resolving\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n if (claimedJob) {\n this.hybridManager?.notifyLocalChange();\n }\n resolve(claimedJob);\n };\n tx.onerror = () => reject(tx.error);\n }\n );\n\n // If we didn't find any job to claim, return undefined\n if (!jobToReturn) {\n return undefined;\n }\n\n // Verify we actually won the race by re-reading the job\n // This is the optimistic locking check - if another worker claimed it first,\n // their claim token will be there instead of ours\n const verifiedJob = await this.get(jobToReturn.id);\n\n if (!verifiedJob) {\n // Job was deleted - we lost the race\n return undefined;\n }\n\n if (verifiedJob.worker_id !== claimToken) {\n // Another worker claimed this job - we lost the race\n return undefined;\n }\n\n if (verifiedJob.status !== JobStatus.PROCESSING) {\n // Job status changed (e.g., another worker completed it already) - we lost the race\n return undefined;\n }\n\n // We successfully claimed the job\n return verifiedJob;\n }\n\n /**\n * Retrieves the number of jobs in the queue.\n * Returns the count of jobs in the queue.\n */\n public async size(status = JobStatus.PENDING): Promise<number> {\n const db = await this.getDb();\n const prefixKeyValues = this.getPrefixKeyValues();\n return new Promise((resolve, reject) => {\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status\");\n const keyRange = IDBKeyRange.only([...prefixKeyValues, this.queueName, status]);\n const request = index.count(keyRange);\n\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Marks a job as complete with its output or error.\n */\n public async complete(job: JobStorageFormat<Input, Output>): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n\n return new Promise((resolve, reject) => {\n const getReq = store.get(job.id as string);\n getReq.onsuccess = () => {\n const existing = getReq.result as\n | (JobStorageFormat<Input, Output> & Record<string, unknown>)\n | undefined;\n // Verify job belongs to this queue and matches prefixes\n if (!existing || existing.queue !== this.queueName || !this.matchesPrefixes(existing)) {\n reject(\n new Error(`Job ${job.id} not found or does not belong to queue ${this.queueName}`)\n );\n return;\n }\n const currentAttempts = existing.run_attempts ?? 0;\n job.run_attempts = currentAttempts + 1;\n // Ensure queue is set correctly\n job.queue = this.queueName;\n\n // Ensure prefix values are preserved\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n\n const putReq = store.put(jobWithPrefixes);\n putReq.onsuccess = () => {};\n putReq.onerror = () => reject(putReq.error);\n };\n getReq.onerror = () => reject(getReq.error);\n\n // Don't resolve until transaction is complete\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Releases a claimed job without consuming a retry attempt.\n */\n public async release(id: unknown): Promise<void> {\n const job = await this.get(id);\n if (!job) return;\n\n job.status = JobStatus.PENDING;\n job.worker_id = null;\n job.progress = 0;\n job.progress_message = \"\";\n job.progress_details = null;\n\n await this.put(job);\n }\n\n /**\n * Aborts a job in the queue.\n */\n public async abort(id: unknown): Promise<void> {\n const job = await this.get(id);\n if (!job) return;\n\n job.status = JobStatus.ABORTING;\n await this.complete(job);\n }\n\n /**\n * Gets jobs by their run ID.\n */\n public async getByRunId(job_run_id: string): Promise<JobStorageFormat<Input, Output>[]> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_job_run_id\");\n const prefixKeyValues = this.getPrefixKeyValues();\n const keyRange = IDBKeyRange.only([...prefixKeyValues, this.queueName, job_run_id]);\n const request = index.getAll(keyRange);\n\n return new Promise((resolve, reject) => {\n request.onsuccess = () => {\n // Filter results to ensure they match prefixes\n const results = (request.result || []).filter(\n (job: JobStorageFormat<Input, Output> & Record<string, unknown>) =>\n this.matchesPrefixes(job)\n );\n resolve(results);\n };\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Deletes all jobs from the queue.\n */\n public async deleteAll(): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n // Use a cursor to iterate through all jobs for this queue with prefix\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, this.queueName, \"\"],\n [...prefixKeyValues, this.queueName, \"\\uffff\"]\n );\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Verify job belongs to this queue and matches prefixes before deleting\n if (job.queue === this.queueName && this.matchesPrefixes(job)) {\n const deleteRequest = cursor.delete();\n deleteRequest.onsuccess = () => {\n cursor.continue();\n };\n deleteRequest.onerror = () => {\n // Continue even if delete fails\n cursor.continue();\n };\n } else {\n cursor.continue();\n }\n }\n };\n\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Gets the output for a given input.\n */\n public async outputForInput(input: Input): Promise<Output | null> {\n const fingerprint = await makeFingerprint(input);\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_fingerprint_status\");\n const prefixKeyValues = this.getPrefixKeyValues();\n const request = index.get([\n ...prefixKeyValues,\n this.queueName,\n fingerprint,\n JobStatus.COMPLETED,\n ]);\n\n return new Promise((resolve, reject) => {\n request.onsuccess = () => {\n const job = request.result as\n | (JobStorageFormat<Input, Output> & Record<string, unknown>)\n | undefined;\n if (job && this.matchesPrefixes(job)) {\n resolve(job.output ?? null);\n } else {\n resolve(null);\n }\n };\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Saves progress updates for a job.\n */\n public async saveProgress(\n id: unknown,\n progress: number,\n message: string,\n details: Record<string, any> | null\n ): Promise<void> {\n const job = await this.get(id);\n if (!job) throw new Error(`Job ${id} not found`);\n\n job.progress = progress;\n job.progress_message = message;\n job.progress_details = details;\n\n await this.put(job);\n }\n\n /**\n * Persists a job to the store without modifying run_attempts or other completion logic.\n */\n private async put(job: JobStorageFormat<Input, Output>): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n\n // Ensure queue is set correctly\n job.queue = this.queueName;\n\n // Ensure prefix values are preserved\n const jobWithPrefixes = job as JobStorageFormat<Input, Output> & Record<string, unknown>;\n for (const [key, value] of Object.entries(this.prefixValues)) {\n jobWithPrefixes[key] = value;\n }\n\n return new Promise((resolve, reject) => {\n const putReq = store.put(jobWithPrefixes);\n putReq.onerror = () => reject(putReq.error);\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Deletes a job by its ID.\n */\n public async delete(id: unknown): Promise<void> {\n const job = await this.get(id);\n if (!job) return;\n\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n const request = store.delete(id as string);\n\n return new Promise((resolve, reject) => {\n request.onsuccess = () => resolve();\n request.onerror = () => reject(request.error);\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n };\n tx.onerror = () => reject(tx.error);\n });\n }\n\n /**\n * Delete jobs with a specific status older than a cutoff date\n * @param status - Status of jobs to delete\n * @param olderThanMs - Delete jobs completed more than this many milliseconds ago\n */\n public async deleteJobsByStatusAndAge(status: JobStatus, olderThanMs: number): Promise<void> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readwrite\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status\");\n const cutoffDate = new Date(Date.now() - olderThanMs).toISOString();\n const prefixKeyValues = this.getPrefixKeyValues();\n const keyRange = IDBKeyRange.only([...prefixKeyValues, this.queueName, status]);\n\n return new Promise((resolve, reject) => {\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Verify job belongs to this queue, matches prefixes, and matches criteria\n if (\n job.queue === this.queueName &&\n this.matchesPrefixes(job) &&\n job.status === status &&\n job.completed_at &&\n job.completed_at <= cutoffDate\n ) {\n cursor.delete();\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => {\n // Notify hybrid manager of local change\n this.hybridManager?.notifyLocalChange();\n resolve();\n };\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Gets all jobs from the queue that match the current prefix values.\n * Used internally for normal polling-based subscriptions (efficient - filters at DB level).\n *\n * @returns A promise that resolves to an array of jobs\n */\n private async getAllJobs(): Promise<Array<JobStorageFormat<Input, Output>>> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n const index = store.index(\"queue_status\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n const jobs: Array<JobStorageFormat<Input, Output>> = [];\n // Use a key range that covers all statuses for this queue with prefixes\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, this.queueName, \"\"],\n [...prefixKeyValues, this.queueName, \"\\uffff\"]\n );\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n if (job.queue === this.queueName && this.matchesPrefixes(job)) {\n jobs.push(job);\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => resolve(jobs);\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Gets all jobs from the queue with a custom prefix filter.\n * Used for subscriptions with custom prefix filters (filters at DB level where possible).\n *\n * @param prefixFilter - The prefix values to filter by (empty object = all jobs)\n * @returns A promise that resolves to an array of jobs\n */\n private async getAllJobsWithFilter(\n prefixFilter: Readonly<Record<string, string | number>>\n ): Promise<Array<JobStorageFormat<Input, Output>>> {\n const db = await this.getDb();\n const tx = db.transaction(this.tableName, \"readonly\");\n const store = tx.objectStore(this.tableName);\n\n return new Promise((resolve, reject) => {\n const jobs: Array<JobStorageFormat<Input, Output>> = [];\n const request = store.openCursor();\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const job = cursor.value as JobStorageFormat<Input, Output> & Record<string, unknown>;\n // Filter by queue name\n if (job.queue !== this.queueName) {\n cursor.continue();\n return;\n }\n // If empty filter, include all jobs for this queue\n if (Object.keys(prefixFilter).length === 0) {\n jobs.push(job);\n } else {\n // Check each filter value\n let matches = true;\n for (const [key, value] of Object.entries(prefixFilter)) {\n if (job[key] !== value) {\n matches = false;\n break;\n }\n }\n if (matches) {\n jobs.push(job);\n }\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => resolve(jobs);\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n /**\n * Checks if a prefix filter is custom (different from instance's prefixes).\n */\n private isCustomPrefixFilter(prefixFilter?: Readonly<Record<string, string | number>>): boolean {\n // No filter specified - use instance prefixes (not custom)\n if (prefixFilter === undefined) {\n return false;\n }\n // Empty filter - receive all (custom)\n if (Object.keys(prefixFilter).length === 0) {\n return true;\n }\n // Check if filter matches instance prefixes exactly\n const instanceKeys = Object.keys(this.prefixValues);\n const filterKeys = Object.keys(prefixFilter);\n if (instanceKeys.length !== filterKeys.length) {\n return true; // Different number of keys = custom\n }\n for (const key of instanceKeys) {\n if (this.prefixValues[key] !== prefixFilter[key]) {\n return true; // Different value = custom\n }\n }\n return false; // Matches instance prefixes exactly\n }\n\n /**\n * Gets or creates the shared hybrid subscription manager for normal subscriptions.\n * This ensures all normal subscriptions share a single manager.\n */\n private getHybridManager(): HybridSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n > {\n if (!this.hybridManager) {\n // Generate unique channel name based on queue name and table name\n const channelName = `indexeddb-queue-${this.tableName}-${this.queueName}`;\n\n this.hybridManager = new HybridSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n >(\n channelName,\n async () => {\n // Fetch jobs with instance's prefix filter (efficient DB-level filtering)\n const jobs = await this.getAllJobs();\n return new Map(jobs.map((j) => [j.id, j]));\n },\n (a, b) => deepEqual(a, b),\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n },\n {\n defaultIntervalMs: 1000,\n useBroadcastChannel: this.hybridOptions.useBroadcastChannel,\n backupPollingIntervalMs: this.hybridOptions.backupPollingIntervalMs,\n }\n );\n }\n return this.hybridManager;\n }\n\n /**\n * Creates a dedicated polling subscription for custom prefix filters.\n * This runs separately from the normal polling manager.\n */\n private subscribeWithCustomPrefixFilter(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n prefixFilter: Readonly<Record<string, string | number>>,\n intervalMs: number\n ): () => void {\n let lastKnownJobs = new Map<unknown, JobStorageFormat<Input, Output>>();\n let cancelled = false;\n\n const poll = async () => {\n if (cancelled) return;\n try {\n const currentJobs = await this.getAllJobsWithFilter(prefixFilter);\n if (cancelled) return;\n const currentMap = new Map(currentJobs.map((j) => [j.id, j]));\n\n // Detect changes\n for (const [id, job] of currentMap) {\n const old = lastKnownJobs.get(id);\n if (!old) {\n callback({ type: \"INSERT\", new: job });\n } else if (!deepEqual(old, job)) {\n callback({ type: \"UPDATE\", old, new: job });\n }\n }\n\n for (const [id, job] of lastKnownJobs) {\n if (!currentMap.has(id)) {\n callback({ type: \"DELETE\", old: job });\n }\n }\n\n lastKnownJobs = currentMap;\n } catch {\n // Ignore polling errors\n }\n };\n\n const intervalId = setInterval(poll, intervalMs);\n poll(); // Initial poll\n\n return () => {\n cancelled = true;\n clearInterval(intervalId);\n };\n }\n\n /**\n * Subscribes to changes in the queue.\n * Uses polling since IndexedDB has no native cross-tab change notifications.\n *\n * Normal subscriptions (no custom prefix filter) share a single polling loop for efficiency.\n * Custom prefix filter subscriptions get their own dedicated polling loop with DB-level filtering.\n *\n * @param callback - Function called when a change occurs\n * @param options - Subscription options including polling interval and prefix filter\n * @returns Unsubscribe function\n */\n public subscribeToChanges(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void {\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n\n // Check if this is a custom prefix filter subscription\n if (this.isCustomPrefixFilter(options?.prefixFilter)) {\n // Custom prefix filter - use dedicated polling with DB-level filtering\n return this.subscribeWithCustomPrefixFilter(callback, options!.prefixFilter!, intervalMs);\n }\n\n // Normal subscription - use shared hybrid manager (efficient)\n const manager = this.getHybridManager();\n return manager.subscribe(callback, { intervalMs });\n }\n\n /**\n * Cleanup method to destroy the hybrid manager\n */\n destroy(): void {\n if (this.hybridManager) {\n this.hybridManager.destroy();\n this.hybridManager = null;\n }\n }\n}\n",
41
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { RealtimeChannel, SupabaseClient } from \"@supabase/supabase-js\";\nimport { createServiceToken, deepEqual, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport { PollingSubscriptionManager } from \"../util/PollingSubscriptionManager\";\nimport {\n IQueueStorage,\n JobStatus,\n JobStorageFormat,\n PrefixColumn,\n QueueChangePayload,\n QueueChangeType,\n QueueStorageOptions,\n QueueSubscribeOptions,\n} from \"./IQueueStorage\";\n\nexport const SUPABASE_QUEUE_STORAGE = createServiceToken<IQueueStorage<any, any>>(\n \"jobqueue.storage.supabase\"\n);\n\n/**\n * Supabase implementation of a job queue.\n * Provides storage and retrieval for job execution states using Supabase.\n */\nexport class SupabaseQueueStorage<Input, Output> implements IQueueStorage<Input, Output> {\n public readonly scope = \"cluster\" as const;\n protected readonly client: SupabaseClient;\n protected readonly prefixes: readonly PrefixColumn[];\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n protected readonly tableName: string;\n private realtimeChannel: RealtimeChannel | null = null;\n private pollingManager: PollingSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n > | null = null;\n\n constructor(\n client: SupabaseClient,\n protected readonly queueName: string,\n options?: QueueStorageOptions\n ) {\n this.client = client as SupabaseClient;\n this.prefixes = options?.prefixes ?? [];\n this.prefixValues = options?.prefixValues ?? {};\n // Generate table name based on prefix configuration to avoid column conflicts\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.tableName = `job_queue_${prefixNames}`;\n } else {\n this.tableName = \"job_queue\";\n }\n }\n\n /**\n * Gets the SQL column type for a prefix column (Supabase supports UUID natively)\n */\n private getPrefixColumnType(type: PrefixColumn[\"type\"]): string {\n return type === \"uuid\" ? \"UUID\" : \"INTEGER\";\n }\n\n /**\n * Builds the prefix columns SQL for CREATE TABLE\n */\n private buildPrefixColumnsSql(): string {\n if (this.prefixes.length === 0) return \"\";\n return (\n this.prefixes\n .map((p) => `${p.name} ${this.getPrefixColumnType(p.type)} NOT NULL`)\n .join(\",\\n \") + \",\\n \"\n );\n }\n\n /**\n * Builds prefix column names for use in queries\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Applies prefix filters to a Supabase query builder\n */\n private applyPrefixFilters<T>(query: T): T {\n let result = query as any;\n for (const prefix of this.prefixes) {\n result = result.eq(prefix.name, this.prefixValues[prefix.name]);\n }\n return result as T;\n }\n\n /**\n * Gets prefix values as an object for inserts\n */\n private getPrefixInsertValues(): Record<string, string | number> {\n const values: Record<string, string | number> = {};\n for (const prefix of this.prefixes) {\n values[prefix.name] = this.prefixValues[prefix.name];\n }\n return values;\n }\n\n /**\n * Builds WHERE clause conditions for prefix filtering with inline values (for raw SQL)\n * @returns SQL conditions string with values inlined\n */\n private buildPrefixWhereSql(): string {\n if (this.prefixes.length === 0) {\n return \"\";\n }\n const conditions = this.prefixes\n .map((p) => {\n const value = this.prefixValues[p.name];\n if (p.type === \"uuid\") {\n const validated = this.validateSqlValue(String(value), `prefix \"${p.name}\"`);\n return `${p.name} = '${this.escapeSqlString(validated)}'`;\n }\n const numValue = Number(value ?? 0);\n if (!Number.isFinite(numValue)) {\n throw new Error(`Invalid numeric prefix value for \"${p.name}\": ${value}`);\n }\n return `${p.name} = ${numValue}`;\n })\n .join(\" AND \");\n return \" AND \" + conditions;\n }\n\n /**\n * Regex for validating SQL literal-safe strings.\n * Used for quoted values (e.g. queue names/IDs) and only allows alphanumeric\n * characters, underscores, hyphens, colons, and periods.\n */\n private static readonly SAFE_SQL_VALUE_RE = /^[a-zA-Z0-9_\\-.:]+$/;\n\n /**\n * Validates that a string value is safe for use as a quoted SQL literal.\n * Throws an error if the value contains characters outside SAFE_SQL_VALUE_RE.\n */\n private validateSqlValue(value: string, context: string): string {\n if (!SupabaseQueueStorage.SAFE_SQL_VALUE_RE.test(value)) {\n throw new Error(\n `Unsafe value for ${context}: \"${value}\". Values must match /^[a-zA-Z0-9_\\\\-.:]+$/.`\n );\n }\n return value;\n }\n\n /**\n * Escapes a string value for use in SQL\n */\n private escapeSqlString(value: string): string {\n return value.replace(/'/g, \"''\");\n }\n\n public async setupDatabase(): Promise<void> {\n // Note: For Supabase, table creation should typically be done through migrations\n // This setup assumes the table already exists or uses exec_sql RPC function\n const createTypeSql = `CREATE TYPE job_status AS ENUM (${Object.values(JobStatus)\n .map((v) => `'${v}'`)\n .join(\",\")})`;\n\n const { error: typeError } = await this.client.rpc(\"exec_sql\", { query: createTypeSql });\n // Ignore error if type already exists (code 42710)\n if (typeError && typeError.code !== \"42710\") {\n throw typeError;\n }\n\n const prefixColumnsSql = this.buildPrefixColumnsSql();\n const prefixColumnNames = this.getPrefixColumnNames();\n const prefixIndexPrefix =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const indexSuffix = prefixColumnNames.length > 0 ? \"_\" + prefixColumnNames.join(\"_\") : \"\";\n\n const createTableSql = `\n CREATE TABLE IF NOT EXISTS ${this.tableName} (\n id SERIAL NOT NULL,\n ${prefixColumnsSql}fingerprint text NOT NULL,\n queue text NOT NULL,\n job_run_id text NOT NULL,\n status job_status NOT NULL default 'PENDING',\n input jsonb NOT NULL,\n output jsonb,\n run_attempts integer default 0,\n max_retries integer default 20,\n run_after timestamp with time zone DEFAULT now(),\n last_ran_at timestamp with time zone,\n created_at timestamp with time zone DEFAULT now(),\n deadline_at timestamp with time zone,\n completed_at timestamp with time zone,\n error text,\n error_code text,\n progress real DEFAULT 0,\n progress_message text DEFAULT '',\n progress_details jsonb,\n worker_id text\n )`;\n\n const { error: tableError } = await this.client.rpc(\"exec_sql\", { query: createTableSql });\n if (tableError) {\n // Ignore error if table already exists (code 42P07)\n if (tableError.code !== \"42P07\") {\n throw tableError;\n }\n }\n\n // Create indexes with prefix columns prepended\n const indexes = [\n `CREATE INDEX IF NOT EXISTS job_fetcher${indexSuffix}_idx ON ${this.tableName} (${prefixIndexPrefix}id, status, run_after)`,\n `CREATE INDEX IF NOT EXISTS job_queue_fetcher${indexSuffix}_idx ON ${this.tableName} (${prefixIndexPrefix}queue, status, run_after)`,\n `CREATE INDEX IF NOT EXISTS jobs_fingerprint${indexSuffix}_unique_idx ON ${this.tableName} (${prefixIndexPrefix}queue, fingerprint, status)`,\n ];\n\n for (const indexSql of indexes) {\n await this.client.rpc(\"exec_sql\", { query: indexSql });\n // Ignore index creation errors\n }\n }\n\n /**\n * Adds a new job to the queue.\n * @param job - The job to add\n * @returns The ID of the added job\n */\n public async add(job: JobStorageFormat<Input, Output>): Promise<unknown> {\n const now = new Date().toISOString();\n job.queue = this.queueName;\n job.job_run_id = job.job_run_id ?? uuid4();\n job.fingerprint = await makeFingerprint(job.input);\n job.status = JobStatus.PENDING;\n job.progress = 0;\n job.progress_message = \"\";\n job.progress_details = null;\n job.created_at = now;\n job.run_after = now;\n\n const prefixInsertValues = this.getPrefixInsertValues();\n\n const { data, error } = await this.client\n .from(this.tableName)\n .insert({\n ...prefixInsertValues,\n queue: job.queue,\n fingerprint: job.fingerprint,\n input: job.input,\n run_after: job.run_after,\n created_at: job.created_at,\n deadline_at: job.deadline_at,\n max_retries: job.max_retries,\n job_run_id: job.job_run_id,\n progress: job.progress,\n progress_message: job.progress_message,\n progress_details: job.progress_details,\n })\n .select(\"id\")\n .single();\n\n if (error) throw error;\n if (!data) throw new Error(\"Failed to add to queue\");\n\n job.id = data.id;\n return job.id;\n }\n\n /**\n * Retrieves a job by its ID.\n * @param id - The ID of the job to retrieve\n * @returns The job if found, undefined otherwise\n */\n public async get(id: unknown): Promise<JobStorageFormat<Input, Output> | undefined> {\n let query = this.client\n .from(this.tableName)\n .select(\"*\")\n .eq(\"id\", id)\n .eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") return undefined; // Not found\n throw error;\n }\n\n return data as JobStorageFormat<Input, Output> | undefined;\n }\n\n /**\n * Retrieves a slice of jobs from the queue.\n * @param status - The status to filter by\n * @param num - Maximum number of jobs to return\n * @returns An array of jobs\n */\n public async peek(\n status: JobStatus = JobStatus.PENDING,\n num: number = 100\n ): Promise<JobStorageFormat<Input, Output>[]> {\n num = Number(num) || 100;\n\n let query = this.client\n .from(this.tableName)\n .select(\"*\")\n .eq(\"queue\", this.queueName)\n .eq(\"status\", status);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query.order(\"run_after\", { ascending: true }).limit(num);\n\n if (error) throw error;\n return (data as JobStorageFormat<Input, Output>[]) ?? [];\n }\n\n /**\n * Retrieves the next available job that is ready to be processed.\n * Uses atomic UPDATE with subquery SELECT FOR UPDATE SKIP LOCKED to prevent race conditions.\n * @param workerId - Worker ID to associate with the job (required)\n * @returns The next job or undefined if no job is available\n */\n public async next(workerId: string): Promise<JobStorageFormat<Input, Output> | undefined> {\n const prefixConditions = this.buildPrefixWhereSql();\n const validatedQueueName = this.validateSqlValue(this.queueName, \"queueName\");\n const validatedWorkerId = this.validateSqlValue(workerId, \"workerId\");\n const escapedQueueName = this.escapeSqlString(validatedQueueName);\n const escapedWorkerId = this.escapeSqlString(validatedWorkerId);\n\n // Use the same atomic UPDATE...WHERE id = (SELECT...FOR UPDATE SKIP LOCKED) pattern as PostgresQueueStorage\n const sql = `\n UPDATE ${this.tableName}\n SET status = '${JobStatus.PROCESSING}', last_ran_at = NOW() AT TIME ZONE 'UTC', worker_id = '${escapedWorkerId}'\n WHERE id = (\n SELECT id\n FROM ${this.tableName}\n WHERE queue = '${escapedQueueName}'\n AND status = '${JobStatus.PENDING}'\n ${prefixConditions}\n AND run_after <= NOW() AT TIME ZONE 'UTC'\n ORDER BY run_after ASC\n FOR UPDATE SKIP LOCKED\n LIMIT 1\n )\n RETURNING *`;\n\n const { data, error } = await this.client.rpc(\"exec_sql\", { query: sql });\n\n if (error) throw error;\n\n // exec_sql returns result rows as an array\n if (!data || !Array.isArray(data) || data.length === 0) {\n return undefined;\n }\n\n return data[0] as JobStorageFormat<Input, Output>;\n }\n\n /**\n * Retrieves the number of jobs in the queue with a specific status.\n * @param status - The status of the jobs to count\n * @returns The count of jobs with the specified status\n */\n public async size(status = JobStatus.PENDING): Promise<number> {\n let query = this.client\n .from(this.tableName)\n .select(\"*\", { count: \"exact\", head: true })\n .eq(\"queue\", this.queueName)\n .eq(\"status\", status);\n\n query = this.applyPrefixFilters(query);\n\n const { count, error } = await query;\n\n if (error) throw error;\n return count ?? 0;\n }\n\n /**\n * Gets all jobs from the queue that match the current prefix values.\n * Used internally for polling-based subscriptions.\n *\n * @returns An array of jobs\n */\n private async getAllJobs(): Promise<Array<JobStorageFormat<Input, Output>>> {\n let query = this.client.from(this.tableName).select(\"*\").eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query;\n\n if (error) throw error;\n return (data ?? []) as Array<JobStorageFormat<Input, Output>>;\n }\n\n /**\n * Marks a job as complete with its output or error.\n * Enhanced error handling:\n * - For a retryable error, increments run_attempts and updates run_after.\n * - Marks a job as FAILED immediately for permanent or generic errors.\n */\n public async complete(jobDetails: JobStorageFormat<Input, Output>): Promise<void> {\n const now = new Date().toISOString();\n\n // Handle disabled without changing attempts\n if (jobDetails.status === JobStatus.DISABLED) {\n let query = this.client\n .from(this.tableName)\n .update({\n status: jobDetails.status,\n progress: 100,\n progress_message: \"\",\n progress_details: null,\n completed_at: now,\n last_ran_at: now,\n })\n .eq(\"id\", jobDetails.id)\n .eq(\"queue\", this.queueName);\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n if (error) throw error;\n return;\n }\n\n // Read current attempts to compute next value deterministically\n let getQuery = this.client\n .from(this.tableName)\n .select(\"run_attempts, max_retries\")\n .eq(\"id\", jobDetails.id as number)\n .eq(\"queue\", this.queueName);\n getQuery = this.applyPrefixFilters(getQuery);\n const { data: current, error: getError } = await getQuery.single();\n if (getError) throw getError;\n const currentAttempts = (current?.run_attempts as number | undefined) ?? 0;\n const maxRetries = (current?.max_retries as number | undefined) ?? jobDetails.max_retries ?? 10;\n const nextAttempts = currentAttempts + 1;\n\n if (jobDetails.status === JobStatus.PENDING) {\n // Check if the next attempt would exceed max retries\n if (nextAttempts > maxRetries) {\n // Update to FAILED status instead of rescheduling\n let failQuery = this.client\n .from(this.tableName)\n .update({\n status: JobStatus.FAILED,\n error: \"Max retries reached\",\n error_code: \"MAX_RETRIES_REACHED\",\n progress: 100,\n progress_message: \"\",\n progress_details: null,\n completed_at: now,\n last_ran_at: now,\n })\n .eq(\"id\", jobDetails.id)\n .eq(\"queue\", this.queueName);\n failQuery = this.applyPrefixFilters(failQuery);\n const { error: failError } = await failQuery;\n if (failError) throw failError;\n return;\n }\n\n // Reschedule the job\n let query = this.client\n .from(this.tableName)\n .update({\n error: jobDetails.error ?? null,\n error_code: jobDetails.error_code ?? null,\n status: jobDetails.status,\n run_after: jobDetails.run_after!,\n progress: 0,\n progress_message: \"\",\n progress_details: null,\n run_attempts: nextAttempts,\n last_ran_at: now,\n })\n .eq(\"id\", jobDetails.id)\n .eq(\"queue\", this.queueName);\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n if (error) throw error;\n return;\n }\n\n if (jobDetails.status === JobStatus.COMPLETED || jobDetails.status === JobStatus.FAILED) {\n let query = this.client\n .from(this.tableName)\n .update({\n output: jobDetails.output ?? null,\n error: jobDetails.error ?? null,\n error_code: jobDetails.error_code ?? null,\n status: jobDetails.status,\n progress: 100,\n progress_message: \"\",\n progress_details: null,\n run_attempts: nextAttempts,\n completed_at: now,\n last_ran_at: now,\n })\n .eq(\"id\", jobDetails.id)\n .eq(\"queue\", this.queueName);\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n if (error) throw error;\n return;\n }\n\n // Transitional states: PROCESSING/ABORTING etc - increment attempts like other stores\n let query = this.client\n .from(this.tableName)\n .update({\n status: jobDetails.status,\n output: jobDetails.output ?? null,\n error: jobDetails.error ?? null,\n error_code: jobDetails.error_code ?? null,\n run_after: jobDetails.run_after ?? null,\n run_attempts: nextAttempts,\n last_ran_at: now,\n })\n .eq(\"id\", jobDetails.id)\n .eq(\"queue\", this.queueName);\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n if (error) throw error;\n }\n\n /**\n * Releases a claimed job without consuming a retry attempt.\n */\n public async release(jobId: unknown): Promise<void> {\n let query = this.client\n .from(this.tableName)\n .update({\n status: JobStatus.PENDING,\n worker_id: null,\n progress: 0,\n progress_message: \"\",\n progress_details: null,\n })\n .eq(\"id\", jobId)\n .eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n if (error) throw error;\n }\n\n /**\n * Clears all jobs from the queue.\n */\n public async deleteAll(): Promise<void> {\n let query = this.client.from(this.tableName).delete().eq(\"queue\", this.queueName);\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n\n if (error) throw error;\n }\n\n /**\n * Looks up cached output for a given input\n * Uses input fingerprinting for efficient matching\n * @returns The cached output or null if not found\n */\n public async outputForInput(input: Input): Promise<Output | null> {\n const fingerprint = await makeFingerprint(input);\n\n let query = this.client\n .from(this.tableName)\n .select(\"output\")\n .eq(\"fingerprint\", fingerprint)\n .eq(\"queue\", this.queueName)\n .eq(\"status\", JobStatus.COMPLETED);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") return null; // Not found\n throw error;\n }\n\n return data?.output ?? null;\n }\n\n /**\n * Aborts a job by setting its status to \"ABORTING\".\n * This method will signal the corresponding AbortController so that\n * the job's execute() method (if it supports an AbortSignal parameter)\n * can clean up and exit.\n */\n public async abort(jobId: unknown): Promise<void> {\n let query = this.client\n .from(this.tableName)\n .update({ status: JobStatus.ABORTING })\n .eq(\"id\", jobId)\n .eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n\n if (error) throw error;\n }\n\n /**\n * Retrieves all jobs for a given job run ID.\n * @param job_run_id - The ID of the job run to retrieve\n * @returns An array of jobs\n */\n public async getByRunId(job_run_id: string): Promise<Array<JobStorageFormat<Input, Output>>> {\n let query = this.client\n .from(this.tableName)\n .select(\"*\")\n .eq(\"job_run_id\", job_run_id)\n .eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n const { data, error } = await query;\n\n if (error) throw error;\n return (data as Array<JobStorageFormat<Input, Output>>) ?? [];\n }\n\n /**\n * Implements the saveProgress method\n */\n public async saveProgress(\n jobId: unknown,\n progress: number,\n message: string,\n details: Record<string, any>\n ): Promise<void> {\n let query = this.client\n .from(this.tableName)\n .update({\n progress,\n progress_message: message,\n progress_details: details,\n })\n .eq(\"id\", jobId)\n .eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n\n if (error) throw error;\n }\n\n /**\n * Deletes a job by its ID\n */\n public async delete(jobId: unknown): Promise<void> {\n let query = this.client\n .from(this.tableName)\n .delete()\n .eq(\"id\", jobId)\n .eq(\"queue\", this.queueName);\n\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n\n if (error) throw error;\n }\n\n /**\n * Delete jobs with a specific status older than a cutoff date\n * @param status - Status of jobs to delete\n * @param olderThanMs - Delete jobs completed more than this many milliseconds ago\n */\n public async deleteJobsByStatusAndAge(status: JobStatus, olderThanMs: number): Promise<void> {\n const cutoffDate = new Date(Date.now() - olderThanMs).toISOString();\n\n let query = this.client\n .from(this.tableName)\n .delete()\n .eq(\"queue\", this.queueName)\n .eq(\"status\", status)\n .not(\"completed_at\", \"is\", null)\n .lte(\"completed_at\", cutoffDate);\n\n query = this.applyPrefixFilters(query);\n const { error } = await query;\n\n if (error) throw error;\n }\n\n /**\n * Checks if a job from a realtime payload matches the specified prefix filter\n * @param job - The job record from the realtime payload\n * @param prefixFilter - The prefix filter to match against (undefined = use instance prefixes, {} = no filter)\n */\n private matchesPrefixFilter(\n job: Record<string, unknown> | undefined,\n prefixFilter?: Readonly<Record<string, string | number>>\n ): boolean {\n if (!job) return false;\n\n // Check queue name first\n if (job.queue !== this.queueName) {\n return false;\n }\n\n // If prefixFilter is explicitly an empty object, no prefix filtering\n if (prefixFilter && Object.keys(prefixFilter).length === 0) {\n return true;\n }\n\n // Use provided prefixFilter or fall back to instance's prefixValues\n const filterValues = prefixFilter ?? this.prefixValues;\n\n // If no filter values, match all\n if (Object.keys(filterValues).length === 0) {\n return true;\n }\n\n // Check each filter value\n for (const [key, value] of Object.entries(filterValues)) {\n if (job[key] !== value) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Checks if a prefix filter is custom (different from instance's prefixes).\n */\n private isCustomPrefixFilter(prefixFilter?: Readonly<Record<string, string | number>>): boolean {\n // No filter specified - use instance prefixes (not custom)\n if (prefixFilter === undefined) {\n return false;\n }\n // Empty filter - receive all (custom)\n if (Object.keys(prefixFilter).length === 0) {\n return true;\n }\n // Check if filter matches instance prefixes exactly\n const instanceKeys = Object.keys(this.prefixValues);\n const filterKeys = Object.keys(prefixFilter);\n if (instanceKeys.length !== filterKeys.length) {\n return true; // Different number of keys = custom\n }\n for (const key of instanceKeys) {\n if (this.prefixValues[key] !== prefixFilter[key]) {\n return true; // Different value = custom\n }\n }\n return false; // Matches instance prefixes exactly\n }\n\n /**\n * Gets all jobs from the queue with a custom prefix filter.\n * Used for subscriptions with custom prefix filters (filters at DB level).\n *\n * @param prefixFilter - The prefix values to filter by (empty object = all jobs)\n * @returns A promise that resolves to an array of jobs\n */\n private async getAllJobsWithFilter(\n prefixFilter: Readonly<Record<string, string | number>>\n ): Promise<Array<JobStorageFormat<Input, Output>>> {\n let query = this.client.from(this.tableName).select(\"*\").eq(\"queue\", this.queueName);\n\n // Apply the custom prefix filter\n for (const [key, value] of Object.entries(prefixFilter)) {\n query = query.eq(key, value);\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n return (data ?? []) as Array<JobStorageFormat<Input, Output>>;\n }\n\n /**\n * Subscribes to changes in the queue.\n * Uses Supabase realtime by default.\n *\n * @param callback - Function called when a change occurs\n * @param options - Subscription options including prefix filter\n * @returns Unsubscribe function\n */\n public subscribeToChanges(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void {\n return this.subscribeToChangesWithRealtime(callback, options?.prefixFilter);\n }\n\n /**\n * Subscribe using Supabase realtime (protected).\n *\n * @param callback - Function called when a change occurs\n * @param prefixFilter - Optional prefix filter (undefined = use instance prefixes, {} = no filter)\n * @returns Unsubscribe function\n */\n protected subscribeToChangesWithRealtime(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n prefixFilter?: Readonly<Record<string, string | number>>\n ): () => void {\n const channelName = `queue-${this.tableName}-${this.queueName}-${Date.now()}`;\n\n this.realtimeChannel = this.client\n .channel(channelName)\n .on(\n \"postgres_changes\",\n {\n event: \"*\",\n schema: \"public\",\n table: this.tableName,\n filter: `queue=eq.${this.queueName}`,\n },\n (payload) => {\n // Filter by prefix values\n const newJob = payload.new as Record<string, unknown> | undefined;\n const oldJob = payload.old as Record<string, unknown> | undefined;\n\n // Check if either old or new job matches the filter\n const newMatches = this.matchesPrefixFilter(newJob, prefixFilter);\n const oldMatches = this.matchesPrefixFilter(oldJob, prefixFilter);\n\n if (!newMatches && !oldMatches) {\n return;\n }\n\n callback({\n type: payload.eventType.toUpperCase() as QueueChangeType,\n old:\n oldJob && Object.keys(oldJob).length > 0\n ? (oldJob as JobStorageFormat<Input, Output>)\n : undefined,\n new:\n newJob && Object.keys(newJob).length > 0\n ? (newJob as JobStorageFormat<Input, Output>)\n : undefined,\n });\n }\n )\n .subscribe();\n\n return () => {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n };\n }\n\n /**\n * Gets or creates the shared polling subscription manager for normal subscriptions (fallback).\n * This ensures all normal subscriptions share a single polling loop per interval.\n */\n private getPollingManager(): PollingSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n > {\n if (!this.pollingManager) {\n this.pollingManager = new PollingSubscriptionManager<\n JobStorageFormat<Input, Output>,\n unknown,\n QueueChangePayload<Input, Output>\n >(\n async () => {\n // Fetch jobs with instance's prefix filter (efficient DB-level filtering)\n const jobs = await this.getAllJobs();\n return new Map(jobs.map((j) => [j.id, j]));\n },\n (a, b) => deepEqual(a, b),\n {\n insert: (item) => ({ type: \"INSERT\" as const, new: item }),\n update: (oldItem, newItem) => ({ type: \"UPDATE\" as const, old: oldItem, new: newItem }),\n delete: (item) => ({ type: \"DELETE\" as const, old: item }),\n }\n );\n }\n return this.pollingManager;\n }\n\n /**\n * Creates a dedicated polling subscription for custom prefix filters (fallback).\n * This runs separately from the normal polling manager with DB-level filtering.\n */\n private subscribeWithCustomPrefixFilterPolling(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n prefixFilter: Readonly<Record<string, string | number>>,\n intervalMs: number\n ): () => void {\n let lastKnownJobs = new Map<unknown, JobStorageFormat<Input, Output>>();\n let cancelled = false;\n\n const poll = async () => {\n if (cancelled) return;\n try {\n const currentJobs = await this.getAllJobsWithFilter(prefixFilter);\n if (cancelled) return;\n const currentMap = new Map(currentJobs.map((j) => [j.id, j]));\n\n // Detect changes\n for (const [id, job] of currentMap) {\n const old = lastKnownJobs.get(id);\n if (!old) {\n callback({ type: \"INSERT\", new: job });\n } else if (!deepEqual(old, job)) {\n callback({ type: \"UPDATE\", old, new: job });\n }\n }\n\n for (const [id, job] of lastKnownJobs) {\n if (!currentMap.has(id)) {\n callback({ type: \"DELETE\", old: job });\n }\n }\n\n lastKnownJobs = currentMap;\n } catch {\n // Ignore polling errors\n }\n };\n\n const intervalId = setInterval(poll, intervalMs);\n poll(); // Initial poll\n\n return () => {\n cancelled = true;\n clearInterval(intervalId);\n };\n }\n\n /**\n * Subscribe using polling (protected, available as fallback).\n *\n * Normal subscriptions (no custom prefix filter) share a single polling loop for efficiency.\n * Custom prefix filter subscriptions get their own dedicated polling loop with DB-level filtering.\n *\n * @param callback - Function called when a change occurs\n * @param options - Subscription options including interval and prefix filter\n * @returns Unsubscribe function\n */\n protected subscribeToChangesWithPolling(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void {\n const intervalMs = options?.pollingIntervalMs ?? 1000;\n\n // Check if this is a custom prefix filter subscription\n if (this.isCustomPrefixFilter(options?.prefixFilter)) {\n // Custom prefix filter - use dedicated polling with DB-level filtering\n return this.subscribeWithCustomPrefixFilterPolling(\n callback,\n options!.prefixFilter!,\n intervalMs\n );\n }\n\n // Normal subscription - use shared polling manager (efficient)\n const manager = this.getPollingManager();\n return manager.subscribe(callback, { intervalMs });\n }\n}\n",
42
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken } from \"@workglow/util\";\nimport {\n ensureIndexedDbTable,\n ExpectedIndexDefinition,\n MigrationOptions,\n} from \"../util/IndexedDbTable\";\nimport type { PrefixColumn } from \"../queue/IQueueStorage\";\nimport {\n IRateLimiterStorage,\n RateLimiterStorageOptions,\n RateLimiterStorageScope,\n} from \"./IRateLimiterStorage\";\n\nexport const INDEXED_DB_RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\n \"ratelimiter.storage.indexedDb\"\n);\n\n/**\n * Extended options for IndexedDB rate limiter storage including prefix support.\n */\nexport interface IndexedDbRateLimiterStorageOptions\n extends RateLimiterStorageOptions, MigrationOptions {}\n\n/**\n * Execution record stored in IndexedDB.\n */\ninterface ExecutionRecord {\n readonly id?: string;\n readonly queue_name: string;\n readonly executed_at: string;\n readonly [key: string]: unknown;\n}\n\n/**\n * Next available record stored in IndexedDB.\n */\ninterface NextAvailableRecord {\n readonly queue_name: string;\n readonly next_available_at: string;\n readonly [key: string]: unknown;\n}\n\n/**\n * IndexedDB implementation of rate limiter storage.\n * Manages execution records and next available times for rate limiting.\n *\n * Atomicity is `\"process\"`-scoped (browser tab) and the `next_available_at`\n * pre-check inside {@link tryReserveExecution} runs in a separate IDB\n * transaction from the count-and-insert. See {@link tryReserveExecution} for\n * the full caveat — do not assume cross-store atomicity.\n */\nexport class IndexedDbRateLimiterStorage implements IRateLimiterStorage {\n /**\n * `\"process\"` — IndexedDB is per-origin and shared across tabs but not across\n * processes (different machines, server processes). Within a single tab the\n * `readwrite` transaction below provides atomicity.\n */\n public readonly scope: RateLimiterStorageScope = \"process\";\n private executionDb: IDBDatabase | undefined;\n private nextAvailableDb: IDBDatabase | undefined;\n private readonly executionTableName: string;\n private readonly nextAvailableTableName: string;\n private readonly migrationOptions: MigrationOptions;\n /** The prefix column definitions */\n protected readonly prefixes: readonly PrefixColumn[];\n /** The prefix values for filtering */\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n\n constructor(options: IndexedDbRateLimiterStorageOptions = {}) {\n this.migrationOptions = options;\n this.prefixes = options.prefixes ?? [];\n this.prefixValues = options.prefixValues ?? {};\n\n // Generate table names based on prefix configuration\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.executionTableName = `rate_limit_executions_${prefixNames}`;\n this.nextAvailableTableName = `rate_limit_next_available_${prefixNames}`;\n } else {\n this.executionTableName = \"rate_limit_executions\";\n this.nextAvailableTableName = \"rate_limit_next_available\";\n }\n }\n\n /**\n * Gets prefix column names for use in indexes.\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Checks if a record matches the current prefix values.\n */\n private matchesPrefixes(record: Record<string, unknown>): boolean {\n for (const [key, value] of Object.entries(this.prefixValues)) {\n if (record[key] !== value) {\n return false;\n }\n }\n return true;\n }\n\n /**\n * Gets prefix values as an array in column order for index key construction.\n */\n private getPrefixKeyValues(): Array<string | number> {\n return this.prefixes.map((p) => this.prefixValues[p.name]);\n }\n\n private async getExecutionDb(): Promise<IDBDatabase> {\n if (this.executionDb) return this.executionDb;\n await this.setupDatabase();\n return this.executionDb!;\n }\n\n private async getNextAvailableDb(): Promise<IDBDatabase> {\n if (this.nextAvailableDb) return this.nextAvailableDb;\n await this.setupDatabase();\n return this.nextAvailableDb!;\n }\n\n public async setupDatabase(): Promise<void> {\n const prefixColumnNames = this.getPrefixColumnNames();\n\n // Build index key paths with prefixes prepended\n const buildKeyPath = (basePath: string[]): string[] => {\n return [...prefixColumnNames, ...basePath];\n };\n\n const executionIndexes: ExpectedIndexDefinition[] = [\n {\n name: \"queue_executed_at\",\n keyPath: buildKeyPath([\"queue_name\", \"executed_at\"]),\n options: { unique: false },\n },\n ];\n\n this.executionDb = await ensureIndexedDbTable(\n this.executionTableName,\n \"id\",\n executionIndexes,\n this.migrationOptions\n );\n\n const nextAvailableIndexes: ExpectedIndexDefinition[] = [\n {\n name: \"queue_name\",\n keyPath: buildKeyPath([\"queue_name\"]),\n options: { unique: true },\n },\n ];\n\n this.nextAvailableDb = await ensureIndexedDbTable(\n this.nextAvailableTableName,\n buildKeyPath([\"queue_name\"]).join(\"_\"),\n nextAvailableIndexes,\n this.migrationOptions\n );\n }\n\n /**\n * Atomically reserves an execution slot in IndexedDB.\n *\n * Atomicity caveat: this implementation only serializes the `count + insert`\n * pair (under a single `readwrite` IDB transaction over the executions\n * store). The `next_available_at` lookup is a soft pre-check performed\n * BEFORE the tx, because the executions and next-available object stores\n * live in separate `IDBDatabase` instances by design (one\n * `ensureIndexedDbTable` call each) and IDB transaction scope cannot cross\n * databases. This is acceptable for IndexedDB's `\"process\"` scope: rate-\n * limit overshoot from a stale next-available read is bounded by single-\n * tab serial execution, and the stricter count check is what protects the\n * primary maxExecutions invariant.\n */\n public async tryReserveExecution(\n queueName: string,\n maxExecutions: number,\n windowMs: number\n ): Promise<unknown | null> {\n // Soft pre-check against external backoff. Done before opening the tx\n // because next-available lives in a separate IDBDatabase.\n const nextIso = await this.getNextAvailableTime(queueName);\n if (nextIso && new Date(nextIso).getTime() > Date.now()) {\n return null;\n }\n\n const execDb = await this.getExecutionDb();\n const prefixKeyValues = this.getPrefixKeyValues();\n const windowStartIso = new Date(Date.now() - windowMs).toISOString();\n const execTx = execDb.transaction(this.executionTableName, \"readwrite\");\n const execStore = execTx.objectStore(this.executionTableName);\n const insertedId = crypto.randomUUID();\n\n return new Promise<unknown | null>((resolve, reject) => {\n let liveCount = 0;\n let didInsert = false;\n const liveRange = IDBKeyRange.bound(\n [...prefixKeyValues, queueName, windowStartIso],\n [...prefixKeyValues, queueName, \"￿\"],\n true,\n false\n );\n const cursorReq = execStore.index(\"queue_executed_at\").openCursor(liveRange);\n\n cursorReq.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const record = cursor.value as ExecutionRecord;\n if (this.matchesPrefixes(record)) {\n liveCount++;\n }\n cursor.continue();\n return;\n }\n\n if (liveCount >= maxExecutions) {\n // Aborting fires execTx.onabort below, which resolves with `false`.\n // No INSERT happened, so capacity is preserved.\n execTx.abort();\n return;\n }\n\n const record: ExecutionRecord = {\n id: insertedId,\n queue_name: queueName,\n executed_at: new Date().toISOString(),\n };\n for (const [k, v] of Object.entries(this.prefixValues)) {\n (record as Record<string, unknown>)[k] = v;\n }\n const addReq = execStore.add(record);\n didInsert = true;\n addReq.onerror = () => {\n try {\n execTx.abort();\n } catch {\n // already aborted\n }\n reject(addReq.error);\n };\n };\n\n cursorReq.onerror = () => reject(cursorReq.error);\n execTx.oncomplete = () => resolve(didInsert ? insertedId : null);\n execTx.onerror = () => reject(execTx.error);\n execTx.onabort = () => resolve(null);\n });\n }\n\n public async releaseExecution(queueName: string, token: unknown): Promise<void> {\n if (token === null || token === undefined) return;\n const db = await this.getExecutionDb();\n const tx = db.transaction(this.executionTableName, \"readwrite\");\n const store = tx.objectStore(this.executionTableName);\n return new Promise<void>((resolve, reject) => {\n // Delete by id — NEVER by recency. Two concurrent acquirers can hold\n // tokens for different rows; deleting \"the most recent\" would release\n // the other worker's slot.\n const req = store.delete(token as IDBValidKey);\n req.onerror = () => reject(req.error);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n });\n }\n\n public async recordExecution(queueName: string): Promise<void> {\n const db = await this.getExecutionDb();\n const tx = db.transaction(this.executionTableName, \"readwrite\");\n const store = tx.objectStore(this.executionTableName);\n\n const record: ExecutionRecord = {\n id: crypto.randomUUID(),\n queue_name: queueName,\n executed_at: new Date().toISOString(),\n };\n\n // Add prefix values to the record\n for (const [key, value] of Object.entries(this.prefixValues)) {\n (record as Record<string, unknown>)[key] = value;\n }\n\n return new Promise((resolve, reject) => {\n const request = store.add(record);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n public async getExecutionCount(queueName: string, windowStartTime: string): Promise<number> {\n const db = await this.getExecutionDb();\n const tx = db.transaction(this.executionTableName, \"readonly\");\n const store = tx.objectStore(this.executionTableName);\n const index = store.index(\"queue_executed_at\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n let count = 0;\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, queueName, windowStartTime],\n [...prefixKeyValues, queueName, \"\\uffff\"],\n true, // exclude lower bound (windowStartTime)\n false\n );\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const record = cursor.value as ExecutionRecord;\n if (this.matchesPrefixes(record)) {\n count++;\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => resolve(count);\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n public async getOldestExecutionAtOffset(\n queueName: string,\n offset: number\n ): Promise<string | undefined> {\n const db = await this.getExecutionDb();\n const tx = db.transaction(this.executionTableName, \"readonly\");\n const store = tx.objectStore(this.executionTableName);\n const index = store.index(\"queue_executed_at\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n return new Promise((resolve, reject) => {\n const executions: string[] = [];\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, queueName, \"\"],\n [...prefixKeyValues, queueName, \"\\uffff\"]\n );\n const request = index.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const record = cursor.value as ExecutionRecord;\n if (this.matchesPrefixes(record)) {\n executions.push(record.executed_at);\n }\n cursor.continue();\n }\n };\n\n tx.oncomplete = () => {\n // Sort by executed_at ascending\n executions.sort();\n resolve(executions[offset]);\n };\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n public async getNextAvailableTime(queueName: string): Promise<string | undefined> {\n const db = await this.getNextAvailableDb();\n const tx = db.transaction(this.nextAvailableTableName, \"readonly\");\n const store = tx.objectStore(this.nextAvailableTableName);\n const prefixKeyValues = this.getPrefixKeyValues();\n const key = [...prefixKeyValues, queueName].join(\"_\");\n\n return new Promise((resolve, reject) => {\n const request = store.get(key);\n request.onsuccess = () => {\n const record = request.result as NextAvailableRecord | undefined;\n if (record && this.matchesPrefixes(record)) {\n resolve(record.next_available_at);\n } else {\n resolve(undefined);\n }\n };\n request.onerror = () => reject(request.error);\n tx.onerror = () => reject(tx.error);\n });\n }\n\n public async setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void> {\n const db = await this.getNextAvailableDb();\n const tx = db.transaction(this.nextAvailableTableName, \"readwrite\");\n const store = tx.objectStore(this.nextAvailableTableName);\n const prefixKeyValues = this.getPrefixKeyValues();\n const key = [...prefixKeyValues, queueName].join(\"_\");\n\n const record: NextAvailableRecord & { [key: string]: unknown } = {\n queue_name: queueName,\n next_available_at: nextAvailableAt,\n };\n\n // Add prefix values to the record\n for (const [k, value] of Object.entries(this.prefixValues)) {\n record[k] = value;\n }\n\n // Set the key field\n (record as Record<string, unknown>)[\n this.getPrefixColumnNames().concat([\"queue_name\"]).join(\"_\")\n ] = key;\n\n return new Promise((resolve, reject) => {\n const request = store.put(record);\n tx.oncomplete = () => resolve();\n tx.onerror = () => reject(tx.error);\n request.onerror = () => reject(request.error);\n });\n }\n\n public async clear(queueName: string): Promise<void> {\n // Clear executions\n const execDb = await this.getExecutionDb();\n const execTx = execDb.transaction(this.executionTableName, \"readwrite\");\n const execStore = execTx.objectStore(this.executionTableName);\n const execIndex = execStore.index(\"queue_executed_at\");\n const prefixKeyValues = this.getPrefixKeyValues();\n\n await new Promise<void>((resolve, reject) => {\n const keyRange = IDBKeyRange.bound(\n [...prefixKeyValues, queueName, \"\"],\n [...prefixKeyValues, queueName, \"\\uffff\"]\n );\n const request = execIndex.openCursor(keyRange);\n\n request.onsuccess = (event) => {\n const cursor = (event.target as IDBRequest<IDBCursorWithValue>).result;\n if (cursor) {\n const record = cursor.value as ExecutionRecord;\n if (this.matchesPrefixes(record)) {\n cursor.delete();\n }\n cursor.continue();\n }\n };\n\n execTx.oncomplete = () => resolve();\n execTx.onerror = () => reject(execTx.error);\n request.onerror = () => reject(request.error);\n });\n\n // Clear next available\n const nextDb = await this.getNextAvailableDb();\n const nextTx = nextDb.transaction(this.nextAvailableTableName, \"readwrite\");\n const nextStore = nextTx.objectStore(this.nextAvailableTableName);\n const key = [...prefixKeyValues, queueName].join(\"_\");\n\n await new Promise<void>((resolve, reject) => {\n const request = nextStore.delete(key);\n nextTx.oncomplete = () => resolve();\n nextTx.onerror = () => reject(nextTx.error);\n request.onerror = () => reject(request.error);\n });\n }\n}\n",
43
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { SupabaseClient } from \"@supabase/supabase-js\";\nimport { createServiceToken } from \"@workglow/util\";\nimport type { PrefixColumn } from \"../queue/IQueueStorage\";\nimport {\n IRateLimiterStorage,\n RateLimiterStorageOptions,\n RateLimiterStorageScope,\n} from \"./IRateLimiterStorage\";\n\nexport const SUPABASE_RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\n \"ratelimiter.storage.supabase\"\n);\n\n/**\n * Supabase implementation of rate limiter storage.\n * Manages execution records and next available times for rate limiting.\n */\nexport class SupabaseRateLimiterStorage implements IRateLimiterStorage {\n public readonly scope: RateLimiterStorageScope = \"cluster\";\n protected readonly client: SupabaseClient;\n protected readonly prefixes: readonly PrefixColumn[];\n protected readonly prefixValues: Readonly<Record<string, string | number>>;\n protected readonly executionTableName: string;\n protected readonly nextAvailableTableName: string;\n\n constructor(client: unknown, options?: RateLimiterStorageOptions) {\n this.client = client as SupabaseClient;\n this.prefixes = options?.prefixes ?? [];\n this.prefixValues = options?.prefixValues ?? {};\n\n // Generate table names based on prefix configuration\n if (this.prefixes.length > 0) {\n const prefixNames = this.prefixes.map((p) => p.name).join(\"_\");\n this.executionTableName = `rate_limit_executions_${prefixNames}`;\n this.nextAvailableTableName = `rate_limit_next_available_${prefixNames}`;\n } else {\n this.executionTableName = \"rate_limit_executions\";\n this.nextAvailableTableName = \"rate_limit_next_available\";\n }\n }\n\n /**\n * Gets the SQL column type for a prefix column (Supabase supports UUID natively).\n */\n private getPrefixColumnType(type: PrefixColumn[\"type\"]): string {\n return type === \"uuid\" ? \"UUID\" : \"INTEGER\";\n }\n\n /**\n * Builds the prefix columns SQL for CREATE TABLE.\n */\n private buildPrefixColumnsSql(): string {\n if (this.prefixes.length === 0) return \"\";\n return (\n this.prefixes\n .map((p) => `${p.name} ${this.getPrefixColumnType(p.type)} NOT NULL`)\n .join(\",\\n \") + \",\\n \"\n );\n }\n\n /**\n * Builds prefix column names for use in queries.\n */\n private getPrefixColumnNames(): string[] {\n return this.prefixes.map((p) => p.name);\n }\n\n /**\n * Applies prefix filters to a Supabase query builder.\n */\n private applyPrefixFilters<T>(query: T): T {\n let result = query as any;\n for (const prefix of this.prefixes) {\n result = result.eq(prefix.name, this.prefixValues[prefix.name]);\n }\n return result as T;\n }\n\n /**\n * Gets prefix values as an object for inserts.\n */\n private getPrefixInsertValues(): Record<string, string | number> {\n const values: Record<string, string | number> = {};\n for (const prefix of this.prefixes) {\n values[prefix.name] = this.prefixValues[prefix.name];\n }\n return values;\n }\n\n public async setupDatabase(): Promise<void> {\n const prefixColumnsSql = this.buildPrefixColumnsSql();\n const prefixColumnNames = this.getPrefixColumnNames();\n const prefixIndexPrefix =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const indexSuffix = prefixColumnNames.length > 0 ? \"_\" + prefixColumnNames.join(\"_\") : \"\";\n\n // Create execution tracking table\n const createExecTableSql = `\n CREATE TABLE IF NOT EXISTS ${this.executionTableName} (\n id SERIAL PRIMARY KEY,\n ${prefixColumnsSql}queue_name TEXT NOT NULL,\n executed_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\n )\n `;\n\n const { error: execTableError } = await this.client.rpc(\"exec_sql\", {\n query: createExecTableSql,\n });\n if (execTableError && execTableError.code !== \"42P07\") {\n throw execTableError;\n }\n\n // Create index on execution table\n const createExecIndexSql = `\n CREATE INDEX IF NOT EXISTS rate_limit_exec_queue${indexSuffix}_idx \n ON ${this.executionTableName} (${prefixIndexPrefix}queue_name, executed_at)\n `;\n await this.client.rpc(\"exec_sql\", { query: createExecIndexSql });\n\n // Build primary key columns\n const primaryKeyColumns =\n prefixColumnNames.length > 0 ? `${prefixColumnNames.join(\", \")}, queue_name` : \"queue_name\";\n\n // Create next available table\n const createNextTableSql = `\n CREATE TABLE IF NOT EXISTS ${this.nextAvailableTableName} (\n ${prefixColumnsSql}queue_name TEXT NOT NULL,\n next_available_at TIMESTAMP WITH TIME ZONE,\n PRIMARY KEY (${primaryKeyColumns})\n )\n `;\n\n const { error: nextTableError } = await this.client.rpc(\"exec_sql\", {\n query: createNextTableSql,\n });\n if (nextTableError && nextTableError.code !== \"42P07\") {\n throw nextTableError;\n }\n\n // Install the atomic reserve function. The function takes the queue name,\n // window-start cutoff, and max executions; returns true iff a row was\n // inserted. Advisory xact lock keyed on (table, prefixes, queue) ensures\n // concurrent acquirers serialize without contending on unrelated buckets.\n const fnName = this.atomicReserveFunctionName();\n const prefixSig = this.prefixes\n .map((p) => `${p.name} ${this.getPrefixColumnType(p.type)}`)\n .join(\", \");\n const prefixSigPrefix = prefixSig ? prefixSig + \", \" : \"\";\n const prefixWhere =\n this.prefixes.length > 0\n ? \" AND \" + this.prefixes.map((p) => `${p.name} = _${p.name}`).join(\" AND \")\n : \"\";\n const prefixInsertCols =\n this.prefixes.length > 0 ? this.prefixes.map((p) => p.name).join(\", \") + \", \" : \"\";\n const prefixInsertVals =\n this.prefixes.length > 0 ? this.prefixes.map((p) => `_${p.name}`).join(\", \") + \", \" : \"\";\n const lockKeyParts = [`'${this.executionTableName}'`, ...this.prefixes.map((p) => `_${p.name}::text`), `_queue_name::text`];\n const lockKeyExpr = `hashtextextended(${lockKeyParts.join(\" || '|' || \")}, 0)`;\n\n const createFnSql = `\n CREATE OR REPLACE FUNCTION ${fnName}(\n ${prefixSigPrefix}_queue_name TEXT, _window_start TIMESTAMPTZ, _max_exec INT\n ) RETURNS BIGINT AS $fn$\n DECLARE\n _count INT;\n _next TIMESTAMPTZ;\n _new_id BIGINT;\n BEGIN\n PERFORM pg_advisory_xact_lock(${lockKeyExpr});\n SELECT COUNT(*) INTO _count FROM ${this.executionTableName}\n WHERE queue_name = _queue_name AND executed_at > _window_start${prefixWhere};\n IF _count >= _max_exec THEN RETURN NULL; END IF;\n SELECT next_available_at INTO _next FROM ${this.nextAvailableTableName}\n WHERE queue_name = _queue_name${prefixWhere};\n IF _next IS NOT NULL AND _next > NOW() THEN RETURN NULL; END IF;\n INSERT INTO ${this.executionTableName} (${prefixInsertCols}queue_name)\n VALUES (${prefixInsertVals}_queue_name)\n RETURNING id INTO _new_id;\n RETURN _new_id;\n END;\n $fn$ LANGUAGE plpgsql;\n `;\n const { error: fnError } = await this.client.rpc(\"exec_sql\", { query: createFnSql });\n if (fnError) {\n throw fnError;\n }\n }\n\n /** Stable function name derived from table name (Postgres identifiers ≤63 chars). */\n private atomicReserveFunctionName(): string {\n return `${this.executionTableName}_try_reserve`.slice(0, 63);\n }\n\n public async tryReserveExecution(\n queueName: string,\n maxExecutions: number,\n windowMs: number\n ): Promise<unknown | null> {\n const args: Record<string, unknown> = {\n _queue_name: queueName,\n _window_start: new Date(Date.now() - windowMs).toISOString(),\n _max_exec: maxExecutions,\n };\n for (const p of this.prefixes) {\n args[`_${p.name}`] = this.prefixValues[p.name];\n }\n // The PL/pgSQL function returns the inserted id BIGINT on success and\n // NULL when capacity is reached or external backoff is active.\n const { data, error } = await this.client.rpc(this.atomicReserveFunctionName(), args);\n if (error) throw error;\n // The function now returns the inserted row id BIGINT (or NULL when\n // capacity is reached). Real Supabase RPC returns the scalar directly;\n // the pglite-backed mock executes `SELECT * FROM fn()` and returns a row\n // array — accept both shapes.\n if (data === null || data === undefined) return null;\n if (Array.isArray(data)) {\n if (data.length === 0) return null;\n const first = Object.values(data[0] as Record<string, unknown>)[0];\n return first ?? null;\n }\n // Supabase RPC returns BIGINTs as either numbers or strings depending on\n // size; both are valid as opaque tokens.\n return data;\n }\n\n public async releaseExecution(queueName: string, token: unknown): Promise<void> {\n if (token === null || token === undefined) return;\n // Delete by id — NEVER by recency. Two concurrent acquirers can hold\n // tokens for different rows; deleting \"the most recent\" would release the\n // other worker's slot.\n let del = this.client\n .from(this.executionTableName)\n .delete()\n .eq(\"id\", token as number | string)\n .eq(\"queue_name\", queueName);\n del = this.applyPrefixFilters(del);\n const { error: delError } = await del;\n if (delError) throw delError;\n }\n\n public async recordExecution(queueName: string): Promise<void> {\n const prefixInsertValues = this.getPrefixInsertValues();\n\n const { error } = await this.client.from(this.executionTableName).insert({\n ...prefixInsertValues,\n queue_name: queueName,\n });\n\n if (error) throw error;\n }\n\n public async getExecutionCount(queueName: string, windowStartTime: string): Promise<number> {\n let query = this.client\n .from(this.executionTableName)\n .select(\"*\", { count: \"exact\", head: true })\n .eq(\"queue_name\", queueName)\n .gt(\"executed_at\", windowStartTime);\n\n query = this.applyPrefixFilters(query);\n\n const { count, error } = await query;\n\n if (error) throw error;\n return count ?? 0;\n }\n\n public async getOldestExecutionAtOffset(\n queueName: string,\n offset: number\n ): Promise<string | undefined> {\n let query = this.client\n .from(this.executionTableName)\n .select(\"executed_at\")\n .eq(\"queue_name\", queueName);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query\n .order(\"executed_at\", { ascending: true })\n .range(offset, offset);\n\n if (error) throw error;\n if (!data || data.length === 0) return undefined;\n return new Date(data[0].executed_at).toISOString();\n }\n\n public async getNextAvailableTime(queueName: string): Promise<string | undefined> {\n let query = this.client\n .from(this.nextAvailableTableName)\n .select(\"next_available_at\")\n .eq(\"queue_name\", queueName);\n\n query = this.applyPrefixFilters(query);\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") return undefined; // Not found\n throw error;\n }\n\n if (!data?.next_available_at) return undefined;\n return new Date(data.next_available_at).toISOString();\n }\n\n public async setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void> {\n const prefixInsertValues = this.getPrefixInsertValues();\n\n const { error } = await this.client.from(this.nextAvailableTableName).upsert(\n {\n ...prefixInsertValues,\n queue_name: queueName,\n next_available_at: nextAvailableAt,\n },\n {\n onConflict:\n this.prefixes.length > 0\n ? `${this.getPrefixColumnNames().join(\",\")},queue_name`\n : \"queue_name\",\n }\n );\n\n if (error) throw error;\n }\n\n public async clear(queueName: string): Promise<void> {\n let execQuery = this.client.from(this.executionTableName).delete().eq(\"queue_name\", queueName);\n execQuery = this.applyPrefixFilters(execQuery);\n const { error: execError } = await execQuery;\n if (execError) throw execError;\n\n let nextQuery = this.client\n .from(this.nextAvailableTableName)\n .delete()\n .eq(\"queue_name\", queueName);\n nextQuery = this.applyPrefixFilters(nextQuery);\n const { error: nextError } = await nextQuery;\n if (nextError) throw nextError;\n }\n}\n",
44
44
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken } from \"@workglow/util\";\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArrayConstructor,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { cosineSimilarity } from \"@workglow/util/schema\";\nimport type { ClientProvidedKeysOption } from \"../tabular/BaseTabularStorage\";\nimport { IndexedDbTabularStorage } from \"../tabular/IndexedDbTabularStorage\";\nimport type { MigrationOptions } from \"../util/IndexedDbTable\";\nimport type {\n AnyVectorStorage,\n HybridSearchOptions,\n IVectorStorage,\n VectorSearchOptions,\n} from \"./IVectorStorage\";\nimport { getMetadataProperty, getVectorProperty } from \"./IVectorStorage\";\n\nexport const IDB_VECTOR_REPOSITORY = createServiceToken<AnyVectorStorage>(\n \"storage.vectorRepository.indexedDb\"\n);\n\n/**\n * Check if metadata matches filter\n */\nfunction matchesFilter<Metadata>(metadata: Metadata, filter: Partial<Metadata>): boolean {\n for (const [key, value] of Object.entries(filter)) {\n if (metadata[key as keyof Metadata] !== value) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Simple full-text search scoring (keyword matching)\n */\nfunction textRelevance(text: string, query: string): number {\n const textLower = text.toLowerCase();\n const queryLower = query.toLowerCase();\n const queryWords = queryLower.split(/\\s+/).filter((w) => w.length > 0);\n if (queryWords.length === 0) {\n return 0;\n }\n let matches = 0;\n for (const word of queryWords) {\n if (textLower.includes(word)) {\n matches++;\n }\n }\n return matches / queryWords.length;\n}\n\n/**\n * IndexedDB vector storage implementation.\n * Extends IndexedDbTabularStorage for storage.\n * Suitable for browser applications that need persistent vector storage.\n * No vector serialization needed since IndexedDB supports TypedArrays\n * natively via structured clone.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - The primary key names\n * @template Metadata - The metadata type for the vector\n * @template VectorCtor - Constructor for stored vectors (default {@link typeof Float32Array})\n * @template Entity - The entity type\n */\nexport class IndexedDbVectorStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n Metadata extends Record<string, unknown> = Record<string, unknown>,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n>\n extends IndexedDbTabularStorage<Schema, PrimaryKeyNames, Entity>\n implements IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames>\n{\n private vectorDimensions: number;\n private vectorPropertyName: keyof Entity;\n private metadataPropertyName: keyof Entity | undefined;\n\n /**\n * Creates a new IndexedDB vector storage\n * @param table - The name of the IndexedDB store (defaults to 'vectors')\n * @param schema - The schema definition for the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable\n * @param dimensions - The number of dimensions of the vector\n * @param _vectorCtor - TypedArray constructor (unused, IndexedDB stores typed arrays natively)\n * @param migrationOptions - Options for handling database schema migrations\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n table: string = \"vectors\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n dimensions: number,\n _vectorCtor: TypedArrayConstructor = Float32Array,\n migrationOptions: MigrationOptions = {},\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, migrationOptions, clientProvidedKeys);\n\n this.vectorDimensions = dimensions;\n\n // Cache vector and metadata property names from schema\n const vectorProp = getVectorProperty(schema);\n if (!vectorProp) {\n throw new Error(\"Schema must have a property with type array and format TypedArray\");\n }\n this.vectorPropertyName = vectorProp as keyof Entity;\n this.metadataPropertyName = getMetadataProperty(schema) as keyof Entity | undefined;\n }\n\n /**\n * Get the vector dimensions\n * @returns The vector dimensions\n */\n getVectorDimensions(): number {\n return this.vectorDimensions;\n }\n\n async similaritySearch(\n query: TypedArray,\n options: VectorSearchOptions<Record<string, unknown>> = {}\n ) {\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n const results: Array<Entity & { score: number }> = [];\n\n const allEntities = (await this.getAll()) || [];\n\n for (const entity of allEntities) {\n // IndexedDB stores TypedArrays natively via structured clone (no deserialization needed)\n const vector = entity[this.vectorPropertyName] as TypedArray;\n const metadata = this.metadataPropertyName\n ? (entity[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n // Apply filter if provided\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n // Calculate similarity\n const score = cosineSimilarity(query, vector);\n\n // Apply threshold\n if (score < scoreThreshold) {\n continue;\n }\n\n results.push({\n ...entity,\n score,\n } as Entity & { score: number });\n }\n\n // Sort by score descending and take top K\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\n }\n\n async hybridSearch(query: TypedArray, options: HybridSearchOptions<Record<string, unknown>>) {\n const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;\n\n if (!textQuery || textQuery.trim().length === 0) {\n // Fall back to regular vector search if no text query\n return this.similaritySearch(query, { topK, filter, scoreThreshold });\n }\n\n const results: Array<Entity & { score: number }> = [];\n const allEntities = (await this.getAll()) || [];\n\n for (const entity of allEntities) {\n // IndexedDB stores TypedArrays natively via structured clone (no deserialization needed)\n const vector = entity[this.vectorPropertyName] as TypedArray;\n const metadata = this.metadataPropertyName\n ? (entity[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n // Apply filter if provided\n if (filter && !matchesFilter(metadata, filter)) {\n continue;\n }\n\n // Calculate vector similarity\n const vectorScore = cosineSimilarity(query, vector);\n\n // Calculate text relevance (simple keyword matching)\n const metadataText = Object.values(metadata).join(\" \").toLowerCase();\n const textScore = textRelevance(metadataText, textQuery);\n\n // Combine scores\n const combinedScore = vectorWeight * vectorScore + (1 - vectorWeight) * textScore;\n\n // Apply threshold\n if (combinedScore < scoreThreshold) {\n continue;\n }\n\n results.push({\n ...entity,\n score: combinedScore,\n } as Entity & { score: number });\n }\n\n // Sort by combined score descending and take top K\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\n }\n}\n"
45
45
  ],
46
- "mappings": ";AAMA;;;ACoHO,SAAS,iBAAoB,CAAC,OAA6C;AAAA,EAChF,OACE,OAAO,UAAU,YACjB,UAAU,QACV,WAAW,SACX,cAAc,SACd,OAAQ,MAA6B,aAAa;AAAA;;;AC1HtD;AAAA;AAEO,MAAM,qBAAqB,UAAU;AAAA,SACjB,OAAe;AAC1C;AAAA;AAEO,MAAM,+BAA+B,aAAa;AAAA,SAC9B,OAAe;AAC1C;AAAA;AAEO,MAAM,kCAAkC,uBAAuB;AAAA,SAC3C,OAAe;AAAA,EACxC,WAAW,GAAG;AAAA,IACZ,MAAM,yEAAyE;AAAA;AAEnF;AAAA;AAEO,MAAM,iCAAiC,uBAAuB;AAAA,SAC1C,OAAe;AAAA,EACxC,WAAW,CAAC,OAAe;AAAA,IACzB,MAAM,2CAA2C,OAAO;AAAA;AAE5D;AAAA;AAEO,MAAM,kCAAkC,uBAAuB;AAAA,SAC3C,OAAe;AAAA,EACxC,WAAW,CAAC,QAAgB;AAAA,IAC1B,MAAM,WAAW,sCAAsC;AAAA;AAE3D;AAAA;AAEO,MAAM,gCAAgC,aAAa;AAAA,SAC/B,OAAe;AAAA,EACxC,WAAW,CAAC,WAAmB,SAAiB;AAAA,IAC9C,MAAM,GAAG,kCAAkC,SAAS;AAAA;AAExD;;;AClCO,MAAM,kCAAkC,aAAa;AAAA,SACjC,OAAe;AAAA,EAExB;AAAA,EACA;AAAA,EACA;AAAA,EAEhB,WAAW,CACT,OACA,iBACA,mBACA;AAAA,IACA,MAAM,YAAY,kBAAkB,IAAI,CAAC,SAAS,IAAI,KAAK,KAAK,IAAI,IAAI,EAAE,KAAK,IAAI;AAAA,IACnF,MACE,gCAAgC,aAC9B,sBAAsB,gBAAgB,KAAK,IAAI,SAC/C,uBAAuB,aAAa,WACxC;AAAA,IACA,KAAK,QAAQ;AAAA,IACb,KAAK,kBAAkB;AAAA,IACvB,KAAK,oBAAoB;AAAA;AAE7B;;;AHKO,IAAM,qBAAqB,mBAChC,2BACF;AAAA;AAqBO,MAAe,mBAQgE;AAAA,EAwBxE;AAAA,EACA;AAAA,EAvBF,SAAS,IAAI;AAAA,EAEb;AAAA,EACA;AAAA,EACA;AAAA,EAGA,uBAA4C;AAAA,EAE5C,2BAAyD;AAAA,EAEzD;AAAA,EAUV,WAAW,CACC,QACA,iBACV,UAAmF,CAAC,GACpF,qBAA+C,cAC/C;AAAA,IAJU;AAAA,IACA;AAAA,IAIV,KAAK,qBAAqB;AAAA,IAC1B,MAAM,kBAAuC,CAAC;AAAA,IAC9C,MAAM,aAAkC,CAAC;AAAA,IACzC,MAAM,gBAAgB,IAAI,IAAI,eAAe;AAAA,IAG7C,YAAY,KAAK,YAAY,OAAO,QAAQ,OAAO,UAAU,GAAG;AAAA,MAC9D,IAAI,cAAc,IAAI,GAAiC,GAAG;AAAA,QACxD,gBAAgB,OAAO,OAAO,OAAO,CAAC,GAAG,OAAO;AAAA,MAClD,EAAO;AAAA,QACL,WAAW,OAAO,OAAO,OAAO,CAAC,GAAG,OAAO;AAAA;AAAA,IAE/C;AAAA,IAGA,MAAM,qBACJ,OAAO,UAAU,OAAO,CAAC,QAAQ,cAAc,IAAI,GAAiC,CAAC,KAAK,CAAC;AAAA,IAE7F,MAAM,gBACJ,OAAO,UAAU,OAAO,CAAC,QAAQ,CAAC,cAAc,IAAI,GAAiC,CAAC,KAAK,CAAC;AAAA,IAE9F,KAAK,mBAAmB;AAAA,MACtB,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,sBAAsB;AAAA,IACxB;AAAA,IACA,KAAK,cAAc;AAAA,MACjB,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,UAAU;AAAA,MACV,sBAAsB;AAAA,IACxB;AAAA,IAGA,MAAM,kBAAkB,CAAC,GAAG,KAAK,kBAAkB,GAAG,GAAG,KAAK,aAAa,CAAC;AAAA,IAC5E,WAAW,UAAU,iBAAiB;AAAA,MACpC,IAAI,OAAO,WAAW,UAAU;AAAA,QAC9B,MAAM,IAAI,MAAM,8BAA8B;AAAA,MAChD;AAAA,MACA,IAAI,CAAC,0BAA0B,KAAK,MAAM,GAAG;AAAA,QAC3C,MAAM,IAAI,MACR,yFACF;AAAA,MACF;AAAA,IACF;AAAA,IAGA,KAAK,UAAU,QAAQ,IAAI,CAAC,SAAU,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI,CAAE;AAAA,IAO1E,KAAK,UAAU,KAAK,mBAClB,KAAK,kBAAkB,GACvB,KAAK,OACP;AAAA,IAGA,WAAW,iBAAiB,KAAK,SAAS;AAAA,MACxC,WAAW,UAAU,eAAe;AAAA,QAClC,IACE,EAAE,UAAU,KAAK,iBAAiB,eAClC,EAAE,UAAU,KAAK,YAAY,aAC7B;AAAA,UACA,MAAM,IAAI,MACR,qBAAqB,OAAO,MAAM,oDACpC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAIA,MAAM,oBAA8B,CAAC;AAAA,IACrC,WAAW,OAAO,iBAAiB;AAAA,MACjC,MAAM,SAAS,OAAO,GAAG;AAAA,MACzB,MAAM,UAAW,OAAO,WAAmB;AAAA,MAC3C,IAAI,WAAW,OAAO,YAAY,YAAY,sBAAsB,SAAS;AAAA,QAC3E,IAAI,QAAQ,wBAAwB,MAAM;AAAA,UACxC,kBAAkB,KAAK,MAAM;AAAA,QAC/B;AAAA,MACF;AAAA,IACF;AAAA,IAEA,IAAI,kBAAkB,SAAS,GAAG;AAAA,MAChC,MAAM,IAAI,MACR,0CAA0C,kBAAkB,KAAK,IAAI,QACnE,uDACJ;AAAA,IACF;AAAA,IAEA,IAAI,kBAAkB,SAAS,GAAG;AAAA,MAChC,MAAM,iBAAiB,kBAAkB;AAAA,MAEzC,KAAK,uBAAuB;AAAA,MAC5B,KAAK,2BAA2B,KAAK,4BACnC,gBACA,OAAO,WAAW,eACpB;AAAA,IACF;AAAA;AAAA,EAGQ,kBAAkB,CAC1B,YACA,eACuB;AAAA,IAEvB,MAAM,WAAW,CAAC,QAA6B,QAAsC;AAAA,MACnF,IAAI,OAAO,SAAS,IAAI;AAAA,QAAQ,OAAO;AAAA,MACvC,OAAO,OAAO,MAAM,CAAC,KAAK,UAAU,QAAQ,IAAI,MAAM;AAAA;AAAA,IAIxD,cAAc,KAAK,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,MAAM;AAAA,IAEhD,IAAI,eAAsC,CAAC;AAAA,IAE3C,SAAS,IAAI,EAAG,IAAI,cAAc,QAAQ,KAAK;AAAA,MAC7C,IAAI,MAAM,cAAc;AAAA,MAExB,IAAI,SAAS,KAAK,UAAU;AAAA,QAAG;AAAA,MAG/B,IAAI,IAAI,WAAW,GAAG;AAAA,QACpB,aAAa,KAAK,GAAG;AAAA,QACrB;AAAA,MACF;AAAA,MAGA,IAAI,cAAc,cAAc,KAAK,CAAC,UAAU,MAAM,IAAI,KAAK,SAAS,KAAK,QAAQ,CAAC;AAAA,MAEtF,IAAI,CAAC,aAAa;AAAA,QAChB,aAAa,KAAK,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,IAEA,OAAO;AAAA;AAAA,EAQT,EAAkC,CAChC,MACA,IACA;AAAA,IACA,KAAK,OAAO,GAAG,MAAM,EAAE;AAAA;AAAA,EAQzB,GAAmC,CACjC,MACA,IACA;AAAA,IACA,KAAK,OAAO,IAAI,MAAM,EAAE;AAAA;AAAA,EAQ1B,IAAoC,CAClC,MACA,IACA;AAAA,IACA,KAAK,OAAO,KAAK,MAAM,EAAE;AAAA;AAAA,EAQ3B,IAAoC,CAClC,SACG,MACH;AAAA,IACA,KAAK,OAAO,KAAK,MAAM,GAAG,IAAI;AAAA;AAAA,EAQhC,MAAsC,CACpC,MAC4D;AAAA,IAC5D,OAAO,KAAK,OAAO,OAAO,IAAI;AAAA;AAAA,OAkB1B,MAAK,CAAC,UAAoD;AAAA,IAC9D,IAAI,CAAC,YAAY,OAAO,KAAK,QAAQ,EAAE,WAAW,GAAG;AAAA,MACnD,OAAO,MAAM,KAAK,KAAK;AAAA,IACzB;AAAA,IACA,MAAM,WAAW,MAAM,KAAK,MAAM,QAAQ;AAAA,IAC1C,OAAO,UAAU,UAAU;AAAA;AAAA,EAgC7B,UAA2C,CACzC,UACA,SAC4B;AAAA,IAC5B,KAAK,eAAe,OAAO;AAAA,IAC3B,MAAM,kBAAkB;AAAA,MACtB,GAAG,OAAO,KAAK,QAAQ;AAAA,MACvB,IAAI,QAAQ,WAAW,CAAC,GAAG,IAAI,CAAC,MAAM,OAAO,EAAE,MAAM,CAAC;AAAA,MACtD,GAAG,QAAQ,OAAO,IAAI,MAAM;AAAA,IAC9B;AAAA,IACA,MAAM,IAAI,0BAA0B,KAAK,YAAY,MAAM,iBAAiB,CAAC,CAAC;AAAA;AAAA,SAiBzE,OAAO,CAAC,WAAmB,KAA8C;AAAA,IAC9E,IAAI,YAAY,GAAG;AAAA,MACjB,MAAM,IAAI,WAAW,wCAAwC,UAAU;AAAA,IACzE;AAAA,IACA,IAAI,SAAS;AAAA,IACb,OAAO,MAAM;AAAA,MACX,MAAM,OAAO,MAAM,KAAK,QAAQ,QAAQ,QAAQ;AAAA,MAChD,IAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAAA,QAC9B;AAAA,MACF;AAAA,MACA,WAAW,UAAU,MAAM;AAAA,QACzB,MAAM;AAAA,MACR;AAAA,MACA,IAAI,KAAK,SAAS,UAAU;AAAA,QAC1B;AAAA,MACF;AAAA,MACA,UAAU;AAAA,IACZ;AAAA;AAAA,SASK,KAAK,CAAC,WAAmB,KAAgD;AAAA,IAC9E,IAAI,YAAY,GAAG;AAAA,MACjB,MAAM,IAAI,WAAW,wCAAwC,UAAU;AAAA,IACzE;AAAA,IACA,IAAI,SAAS;AAAA,IACb,OAAO,MAAM;AAAA,MACX,MAAM,OAAO,MAAM,KAAK,QAAQ,QAAQ,QAAQ;AAAA,MAChD,IAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAAA,QAC9B;AAAA,MACF;AAAA,MACA,MAAM;AAAA,MACN,IAAI,KAAK,SAAS,UAAU;AAAA,QAC1B;AAAA,MACF;AAAA,MACA,UAAU;AAAA,IACZ;AAAA;AAAA,EAYK,kBAAkB,CACvB,WACA,UACY;AAAA,IACZ,MAAM,IAAI,MACR,6CAA6C,KAAK,YAAY,WAC5D,sEACJ;AAAA;AAAA,EAUQ,mBAAmB,CAC3B,UACA,SACM;AAAA,IACN,MAAM,eAAe,OAAO,KAAK,QAAQ;AAAA,IAEzC,IAAI,aAAa,WAAW,GAAG;AAAA,MAC7B,MAAM,IAAI;AAAA,IACZ;AAAA,IAEA,IAAI,SAAS,UAAU,aAAa,QAAQ,SAAS,GAAG;AAAA,MACtD,MAAM,IAAI,yBAAyB,QAAQ,KAAK;AAAA,IAClD;AAAA,IAEA,IAAI,SAAS,WAAW,aAAa,QAAQ,SAAS,GAAG;AAAA,MACvD,MAAM,IAAI,uBAAuB,0CAA0C,QAAQ,QAAQ;AAAA,IAC7F;AAAA,IAGA,WAAW,UAAU,cAAc;AAAA,MACjC,IAAI,EAAE,UAAU,KAAK,OAAO,aAAa;AAAA,QACvC,MAAM,IAAI,0BAA0B,OAAO,MAAM,CAAC;AAAA,MACpD;AAAA,MAEA,MAAM,YAAY,SAAS;AAAA,MAC3B,IAAI,kBAAkB,SAAS,GAAG;AAAA,QAChC,MAAM,iBAAiB,CAAC,KAAK,KAAK,MAAM,KAAK,IAAI;AAAA,QACjD,IAAI,CAAC,eAAe,SAAS,UAAU,QAAQ,GAAG;AAAA,UAChD,MAAM,IAAI,uBACR,qBAAqB,UAAU,8BAA8B,eAAe,KAAK,IAAI,GACvF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAGA,IAAI,SAAS,SAAS;AAAA,MACpB,MAAM,kBAAkB,CAAC,OAAO,MAAM;AAAA,MACtC,aAAa,QAAQ,eAAe,QAAQ,SAAS;AAAA,QACnD,IAAI,EAAE,UAAU,KAAK,OAAO,aAAa;AAAA,UACvC,MAAM,IAAI,0BAA0B,OAAO,MAAM,CAAC;AAAA,QACpD;AAAA,QACA,IAAI,CAAC,gBAAgB,SAAS,SAAS,GAAG;AAAA,UACxC,MAAM,IAAI,uBACR,2BAA2B,qCAC7B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA;AAAA,EAMQ,qBAAqB,CAAC,SAAsC;AAAA,IACpE,IAAI,CAAC;AAAA,MAAS;AAAA,IAEd,IAAI,QAAQ,UAAU,aAAa,QAAQ,SAAS,GAAG;AAAA,MACrD,MAAM,IAAI,yBAAyB,QAAQ,KAAK;AAAA,IAClD;AAAA,IAEA,IAAI,QAAQ,WAAW,aAAa,QAAQ,SAAS,GAAG;AAAA,MACtD,MAAM,IAAI,uBAAuB,0CAA0C,QAAQ,QAAQ;AAAA,IAC7F;AAAA,IAEA,IAAI,QAAQ,SAAS;AAAA,MACnB,MAAM,kBAAkB,CAAC,OAAO,MAAM;AAAA,MACtC,aAAa,QAAQ,eAAe,QAAQ,SAAS;AAAA,QACnD,IAAI,EAAE,UAAU,KAAK,OAAO,aAAa;AAAA,UACvC,MAAM,IAAI,0BAA0B,OAAO,MAAM,CAAC;AAAA,QACpD;AAAA,QACA,IAAI,CAAC,gBAAgB,SAAS,SAAS,GAAG;AAAA,UACxC,MAAM,IAAI,uBACR,2BAA2B,qCAC7B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA;AAAA,EAQQ,cAA+C,CACvD,SACM;AAAA,IACN,IAAI,CAAC,QAAQ,UAAU,QAAQ,OAAO,WAAW,GAAG;AAAA,MAClD,MAAM,IAAI,uBAAuB,8CAA8C;AAAA,IACjF;AAAA,IACA,MAAM,cAAc,OAAO,KAAK,KAAK,OAAO,UAAU;AAAA,IACtD,WAAW,OAAO,QAAQ,QAAQ;AAAA,MAChC,MAAM,SAAS,OAAO,GAAG;AAAA,MACzB,IAAI,CAAC,YAAY,SAAS,MAAM,GAAG;AAAA,QACjC,MAAM,IAAI,uBAAuB,6BAA6B,0BAA0B;AAAA,MAC1F;AAAA,IACF;AAAA;AAAA,EAGQ,iBAAiB,GAA4B;AAAA,IACrD,MAAM,UAAmC,CAAC;AAAA,IAC1C,WAAW,OAAO,OAAO,KAAK,KAAK,iBAAiB,UAAU,GAAG;AAAA,MAC/D,QAAQ,KAAK,GAAuB;AAAA,IACtC;AAAA,IACA,OAAO;AAAA;AAAA,EAGC,YAAY,GAAuB;AAAA,IAC3C,MAAM,UAA8B,CAAC;AAAA,IACrC,WAAW,OAAO,OAAO,KAAK,KAAK,YAAY,UAAU,GAAG;AAAA,MAC1D,QAAQ,KAAK,GAAkB;AAAA,IACjC;AAAA,IACA,OAAO;AAAA;AAAA,EASC,4BAA4B,CAAC,KAAgD;AAAA,IACrF,IAAI,QAAQ,MAAM;AAAA,MAChB,QAAQ,KAAK,aAAa;AAAA,MAC1B,OAAO,EAAE,OAAO,CAAC,GAAY,KAAK,CAAC,EAAgB;AAAA,IACrD;AAAA,IACA,IAAI,OAAO,QAAQ,UAAU;AAAA,MAC3B,QAAQ,KAAK,yBAAyB;AAAA,MACtC,OAAO,EAAE,OAAO,CAAC,GAAY,KAAK,CAAC,EAAgB;AAAA,IACrD;AAAA,IACA,MAAM,kBAAkB,KAAK,kBAAkB;AAAA,IAC/C,MAAM,aAAa,KAAK,aAAa;AAAA,IACrC,MAAM,QAAwB,CAAC;AAAA,IAC/B,MAAM,MAA2B,CAAC;AAAA,IAClC,MAAM,YAAY;AAAA,IAClB,WAAW,KAAK,iBAAiB;AAAA,MAC9B,IAAgC,KAAe,UAAU;AAAA,IAC5D;AAAA,IACA,WAAW,KAAK,YAAY;AAAA,MACzB,MAAkC,KAAe,UAAU;AAAA,IAC9D;AAAA,IAEA,OAAO,EAAE,OAAuB,IAAuB;AAAA;AAAA,OASzC,iBAAgB,CAAC,KAAkC;AAAA,IACjE,OAAO,MAAM,gBAAgB,GAAG;AAAA;AAAA,EASxB,2BAA2B,CAAC,KAAoC;AAAA,IACxE,MAAM,gBAAmC,CAAC;AAAA,IAC1C,MAAM,SAAS;AAAA,IACf,WAAW,KAAK,KAAK,iBAAiB,YAAY;AAAA,MAChD,IAAI,KAAK,QAAQ;AAAA,QACf,cAAc,KAAK,OAAO,EAAE;AAAA,MAC9B,EAAO;AAAA,QACL,MAAM,IAAI,MAAM,uCAAuC,GAAG;AAAA;AAAA,IAE9D;AAAA,IACA,OAAO;AAAA;AAAA,EAQF,qBAAqB,CAC1B,oBACiC;AAAA,IACjC,IAAI,CAAC,mBAAmB;AAAA,MAAQ;AAAA,IAEhC,MAAM,UAAiC;AAAA,MACrC,KAAK,kBAAkB;AAAA,MACvB,GAAI,KAAK;AAAA,IACX;AAAA,IAEA,MAAM,eAAe,IAAI,IAAI,kBAAkB;AAAA,IAE/C,MAAM,oBAAoB,CAAC,UAAwC;AAAA,MAEjE,OAAO,MAAM,SAAS,KAAK,aAAa,IAAI,MAAM,EAAE;AAAA;AAAA,IAGtD,IAAI;AAAA,IACJ,IAAI,iBAAiB;AAAA,IAErB,WAAW,SAAS,SAAS;AAAA,MAC3B,IAAI,kBAAkB,KAAK,GAAG;AAAA,QAE5B,IAAI,QAAQ;AAAA,QACZ,WAAW,OAAO,OAAO;AAAA,UACvB,IAAI,CAAC,aAAa,IAAI,GAAG;AAAA,YAAG;AAAA,UAC5B;AAAA,QACF;AAAA,QAEA,IAAI,QAAQ,gBAAgB;AAAA,UAC1B,YAAY;AAAA,UACZ,iBAAiB;AAAA,QACnB;AAAA,MACF;AAAA,IACF;AAAA,IAEA,OAAO;AAAA;AAAA,EAOC,mBAAmB,GAAY;AAAA,IACvC,OAAO,KAAK,yBAAyB;AAAA;AAAA,EAQ7B,kBAAkB,CAAC,MAAuB;AAAA,IAClD,OAAO,KAAK,yBAAyB,QAAQ,OAAO,KAAK,oBAAoB,MAAM;AAAA;AAAA,EAS3E,2BAA2B,CAAC,YAAoB,SAAqC;AAAA,IAE7F,IAAI,aAAa;AAAA,IACjB,IAAI,WAAW,OAAO,YAAY,UAAU;AAAA,MAC1C,IAAI,QAAQ,SAAS,MAAM,QAAQ,QAAQ,KAAK,GAAG;AAAA,QACjD,aAAa,QAAQ,MAAM,KAAK,CAAC,MAAW,EAAE,SAAS,MAAM,KAAK;AAAA,MACpE,EAAO,SAAI,QAAQ,SAAS,MAAM,QAAQ,QAAQ,KAAK,GAAG;AAAA,QACxD,aAAa,QAAQ,MAAM,KAAK,CAAC,MAAW,EAAE,SAAS,MAAM,KAAK;AAAA,MACpE;AAAA,IACF;AAAA,IAEA,IAAI,OAAO,eAAe,UAAU;AAAA,MAClC,OAAO;AAAA,IACT;AAAA,IAGA,IAAI,WAAW,SAAS,WAAW;AAAA,MACjC,OAAO;AAAA,IACT;AAAA,IAGA,OAAO;AAAA;AAAA,EAWC,gBAAgB,CACxB,YACA,UAC4C;AAAA,IAC5C,MAAM,IAAI,MACR,wCAAwC,KAAK,YAAY,WACvD,WAAW,yBAAyB,UACxC;AAAA;AAAA,OAQI,cAAa,GAAkB;AAAA,EAOrC,OAAO,GAAS;AAAA,QAIT,OAAO,aAAa,GAAkB;AAAA,IAC3C,KAAK,QAAQ;AAAA;AAAA,GAGd,OAAO,QAAQ,GAAS;AAAA,IACvB,KAAK,QAAQ;AAAA;AAEjB;;AIzuBA,+BAAS;;;ACAT,+BAAS,wCAAoB;;;ACkCtB,SAAS,iBAAiB,CAAC,OAA4C;AAAA,EAC5E,QAAQ,OAAO,SAAS,iBAAiB,gBAAgB,eAAe,sBACtE;AAAA,EACF,MAAM,WAAW,cAAc;AAAA,IAC7B,GAAG;AAAA,IACH,GAAG,eAAe,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,IACrC,GAAG;AAAA,EACL,CAAC;AAAA,EACD,MAAM,QAAQ,IAAI,IAAI,iBAAiB;AAAA,EAEvC,WAAW,OAAO,SAAS;AAAA,IACzB,MAAM,MAAM,YAAY,KAAK,iBAAiB,gBAAgB,eAAe,KAAK;AAAA,IAClF,IAAI,QAAQ,WAAW;AAAA,MACrB,OAAO,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,SAAS,kBAAkB,IAAI,iBAAiB;AAAA,IACxF;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,0BACR,OACA,UACA,QAAQ,IAAI,CAAC,MAAM,EAAE,OAAO,CAC9B;AAAA;AAGF,SAAS,WAAW,CAClB,OACA,UACA,SACA,QACA,OAC2C;AAAA,EAC3C,MAAM,UAAU,MAAM;AAAA,EACtB,MAAM,cAAc,IAAI,IAAI,QAAQ;AAAA,EAEpC,IAAI,SAAS,SAAS,QAAQ;AAAA,IAAQ;AAAA,EACtC,SAAS,IAAI,EAAG,IAAI,SAAS,QAAQ,KAAK;AAAA,IACxC,IAAI,CAAC,YAAY,IAAI,QAAQ,EAAE;AAAA,MAAG;AAAA,EACpC;AAAA,EAEA,IAAI,mBAAmB;AAAA,EACvB,IAAI,QAAQ,SAAS,GAAG;AAAA,IACtB,MAAM,QAAQ,SAAS;AAAA,IACvB,IAAI,QAAQ,QAAQ,SAAS,QAAQ;AAAA,MAAQ;AAAA,IAC7C,SAAS,IAAI,EAAG,IAAI,QAAQ,QAAQ,KAAK;AAAA,MACvC,IAAI,QAAQ,QAAQ,OAAO,QAAQ,GAAG;AAAA,QAAQ;AAAA,IAChD;AAAA,IACA,MAAM,UAAU,QAAQ,MAAM,CAAC,MAAM,EAAE,cAAc,MAAM;AAAA,IAC3D,MAAM,SAAS,QAAQ,MAAM,CAAC,MAAM,EAAE,cAAc,KAAK;AAAA,IACzD,IAAI;AAAA,MAAS,mBAAmB;AAAA,IAC3B,SAAI,CAAC;AAAA,MAAQ;AAAA,EACpB;AAAA,EAEA,MAAM,aAAa,IAAI,IAAI,OAAO;AAAA,EAClC,WAAW,OAAO,QAAQ;AAAA,IACxB,IAAI,CAAC,WAAW,IAAI,GAAG,KAAK,CAAC,MAAM,IAAI,GAAG;AAAA,MAAG;AAAA,EAC/C;AAAA,EAEA,OAAO,EAAE,iBAAiB;AAAA;AAG5B,SAAS,aAAa,CAAC,MAAmC;AAAA,EACxD,OAAO,MAAM,KAAK,IAAI,IAAI,IAAI,CAAC;AAAA;;;AD1E1B,IAAM,4BAA4B,oBACvC,oCACF;AAAA;AASO,MAAM,+BAWH,mBAAmF;AAAA,EAE3F,SAAS,IAAI;AAAA,EAEL,uBAAuB;AAAA,EAEvB,oBAAoB;AAAA,EAU5B,WAAW,CACT,QACA,iBACA,UAAmF,CAAC,GACpF,qBAA+C,cAC/C;AAAA,IACA,MAAM,QAAQ,iBAAiB,SAAS,kBAAkB;AAAA;AAAA,OAM7C,cAAa,GAAkB;AAAA,EAU3B,gBAAgB,CACjC,YACA,UACiB;AAAA,IACjB,IAAI,aAAa,iBAAiB;AAAA,MAChC,OAAO,EAAE,KAAK;AAAA,IAChB,EAAO;AAAA,MACL,OAAO,MAAM;AAAA;AAAA;AAAA,OAUX,IAAG,CAAC,OAAoC;AAAA,IAC5C,IAAI,gBAAgB;AAAA,IACpB,MAAM,eAAe,KAAK;AAAA,IAE1B,IAAI;AAAA,MAEF,IAAI,KAAK,oBAAoB,KAAK,KAAK,sBAAsB;AAAA,QAC3D,MAAM,UAAU,KAAK;AAAA,QACrB,MAAM,sBAAuB,MAAkC;AAAA,QAC/D,MAAM,iBAAiB,wBAAwB,aAAa,wBAAwB;AAAA,QAEpF,IAAI,iBAAiB;AAAA,QACrB,IAAI,KAAK,uBAAuB,SAAS;AAAA,UACvC,iBAAiB;AAAA,QACnB,EAAO,SAAI,KAAK,uBAAuB,UAAU;AAAA,UAC/C,IAAI,CAAC,gBAAgB;AAAA,YACnB,MAAM,IAAI,MACR,uBAAuB,0DACzB;AAAA,UACF;AAAA,UACA,iBAAiB;AAAA,QACnB,EAAO;AAAA,UACL,iBAAiB,CAAC;AAAA;AAAA,QAGpB,IAAI,gBAAgB;AAAA,UAClB,MAAM,iBAAiB,KAAK,iBAAiB,SAAS,KAAK,wBAAyB;AAAA,UACpF,gBAAgB,KAAK,QAAQ,UAAU,eAAe;AAAA,QACxD;AAAA,MACF;AAAA,MAEA,QAAQ,QAAQ,KAAK,6BAA6B,aAAa;AAAA,MAC/D,MAAM,KAAK,MAAM,iBAAgB,GAAG;AAAA,MACpC,KAAK,oBAAoB,CAAC,KAAK,OAAO,IAAI,EAAE;AAAA,MAC5C,KAAK,OAAO,IAAI,IAAI,aAAa;AAAA,MACjC,OAAO,GAAG;AAAA,MACV,KAAK,uBAAuB;AAAA,MAC5B,MAAM;AAAA;AAAA,IAGR,KAAK,OAAO,KAAK,OAAO,aAAa;AAAA,IACrC,OAAO;AAAA;AAAA,OASH,QAAO,CAAC,QAAyC;AAAA,IACrD,OAAO,MAAM,QAAQ,IAAI,OAAO,IAAI,OAAO,UAAU,KAAK,IAAI,KAAK,CAAC,CAAC;AAAA;AAAA,OASjE,IAAG,CAAC,KAA8C;AAAA,IACtD,MAAM,KAAK,MAAM,iBAAgB,GAAG;AAAA,IACpC,MAAM,MAAM,KAAK,OAAO,IAAI,EAAE;AAAA,IAC9B,KAAK,OAAO,KAAK,OAAO,KAAK,GAAG;AAAA,IAChC,OAAO;AAAA;AAAA,OAQH,OAAM,CAAC,OAA2C;AAAA,IACtD,QAAQ,QAAQ,KAAK,6BAA6B,KAAe;AAAA,IACjE,MAAM,KAAK,MAAM,iBAAgB,GAAG;AAAA,IACpC,KAAK,OAAO,OAAO,EAAE;AAAA,IACrB,KAAK,OAAO,KAAK,UAAU,GAAmB;AAAA;AAAA,OAO1C,UAAS,GAAkB;AAAA,IAC/B,KAAK,OAAO,MAAM;AAAA,IAClB,KAAK,OAAO,KAAK,UAAU;AAAA;AAAA,OAQvB,OAAM,CAAC,SAA+D;AAAA,IAC1E,KAAK,sBAAsB,OAAO;AAAA,IAClC,IAAI,MAAM,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAAA,IAEzC,IAAI,SAAS,WAAW,QAAQ,QAAQ,SAAS,GAAG;AAAA,MAClD,IAAI,KAAK,CAAC,GAAG,MAAM;AAAA,QACjB,aAAa,QAAQ,eAAe,QAAQ,SAAU;AAAA,UACpD,MAAM,OAAO,EAAE;AAAA,UACf,MAAM,OAAO,EAAE;AAAA,UACf,IAAI,QAAQ,QAAQ,QAAQ;AAAA,YAAM;AAAA,UAClC,IAAI,QAAQ;AAAA,YAAM,OAAO,cAAc,QAAQ,KAAK;AAAA,UACpD,IAAI,QAAQ;AAAA,YAAM,OAAO,cAAc,QAAQ,IAAI;AAAA,UACnD,IAAI,OAAO;AAAA,YAAM,OAAO,cAAc,QAAQ,KAAK;AAAA,UACnD,IAAI,OAAO;AAAA,YAAM,OAAO,cAAc,QAAQ,IAAI;AAAA,QACpD;AAAA,QACA,OAAO;AAAA,OACR;AAAA,IACH;AAAA,IAEA,IAAI,SAAS,WAAW,WAAW;AAAA,MACjC,MAAM,IAAI,MAAM,QAAQ,MAAM;AAAA,IAChC;AAAA,IAEA,IAAI,SAAS,UAAU,WAAW;AAAA,MAChC,MAAM,IAAI,MAAM,GAAG,QAAQ,KAAK;AAAA,IAClC;AAAA,IAEA,OAAO,IAAI,SAAS,IAAI,MAAM;AAAA;AAAA,OAO1B,KAAI,GAAoB;AAAA,IAC5B,OAAO,KAAK,OAAO;AAAA;AAAA,OASf,QAAO,CAAC,QAAgB,OAA8C;AAAA,IAC1E,MAAM,MAAM,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAAA,IAG3C,IAAI,KAAK,CAAC,GAAG,MAAM;AAAA,MACjB,WAAW,OAAO,KAAK,iBAAiB;AAAA,QACtC,MAAM,OAAQ,EAAsC;AAAA,QACpD,MAAM,OAAQ,EAAsC;AAAA,QACpD,IAAI,OAAO;AAAA,UAAM,OAAO;AAAA,QACxB,IAAI,OAAO;AAAA,UAAM,OAAO;AAAA,MAC1B;AAAA,MACA,OAAO;AAAA,KACR;AAAA,IAED,MAAM,OAAO,IAAI,MAAM,QAAQ,SAAS,KAAK;AAAA,IAC7C,OAAO,KAAK,SAAS,IAAI,OAAO;AAAA;AAAA,OAS5B,aAAY,CAAC,UAAuD;AAAA,IACxE,MAAM,eAAe,OAAO,KAAK,QAAQ;AAAA,IACzC,IAAI,aAAa,WAAW,GAAG;AAAA,MAC7B;AAAA,IACF;AAAA,IAGA,MAAM,UAAU,MAAM,KAAK,KAAK,OAAO,QAAQ,CAAC;AAAA,IAEhD,MAAM,kBAAkB,QAAQ,OAAO,EAAE,GAAG,YAAY;AAAA,MAEtD,WAAW,UAAU,cAAc;AAAA,QACjC,MAAM,YAAY,SAAS;AAAA,QAC3B,MAAM,cAAc,OAAO;AAAA,QAE3B,IAAI,kBAAkB,SAAS,GAAG;AAAA,UAChC,QAAQ,OAAO,aAAa;AAAA,UAE5B,MAAM,IAAI;AAAA,UACV,MAAM,KAAK;AAAA,UACX,QAAQ;AAAA,iBACD;AAAA,cACH,IAAI,OAAO;AAAA,gBAAG,OAAO;AAAA,cACrB;AAAA,iBACG;AAAA,cACH,IAAI,OAAO,QAAQ,OAAO,aAAa,EAAE,KAAK;AAAA,gBAAI,OAAO;AAAA,cACzD;AAAA,iBACG;AAAA,cACH,IAAI,OAAO,QAAQ,OAAO,aAAa,EAAE,MAAM;AAAA,gBAAI,OAAO;AAAA,cAC1D;AAAA,iBACG;AAAA,cACH,IAAI,OAAO,QAAQ,OAAO,aAAa,EAAE,KAAK;AAAA,gBAAI,OAAO;AAAA,cACzD;AAAA,iBACG;AAAA,cACH,IAAI,OAAO,QAAQ,OAAO,aAAa,EAAE,MAAM;AAAA,gBAAI,OAAO;AAAA,cAC1D;AAAA;AAAA,cAEA,OAAO;AAAA;AAAA,QAEb,EAAO;AAAA,UAEL,IAAI,gBAAgB;AAAA,YAAW,OAAO;AAAA;AAAA,MAE1C;AAAA,MACA,OAAO;AAAA,KACR;AAAA,IAGD,YAAY,IAAI,WAAW,iBAAiB;AAAA,MAC1C,KAAK,OAAO,OAAO,EAAE;AAAA,MACrB,QAAQ,QAAQ,KAAK,6BAA6B,MAAM;AAAA,MACxD,KAAK,OAAO,KAAK,UAAU,GAAmB;AAAA,IAChD;AAAA;AAAA,OAUI,MAAK,CACT,UACA,SAC+B;AAAA,IAC/B,KAAK,oBAAoB,UAAU,OAAO;AAAA,IAE1C,MAAM,eAAe,OAAO,KAAK,QAAQ;AAAA,IAEzC,IAAI,UAAoB,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC,EAAE,OAAO,CAAC,WAAW;AAAA,MAC1E,WAAW,UAAU,cAAc;AAAA,QACjC,MAAM,YAAY,SAAS;AAAA,QAC3B,MAAM,cAAc,OAAO;AAAA,QAE3B,IAAI,kBAAkB,SAAS,GAAG;AAAA,UAChC,QAAQ,OAAO,aAAa;AAAA,UAC5B,MAAM,IAAI;AAAA,UACV,MAAM,KAAK;AAAA,UACX,QAAQ;AAAA,iBACD;AAAA,cACH,IAAI,OAAO;AAAA,gBAAG,OAAO;AAAA,cACrB;AAAA,iBACG;AAAA,cACH,IAAI,OAAO,QAAQ,OAAO,aAAa,EAAE,KAAK;AAAA,gBAAI,OAAO;AAAA,cACzD;AAAA,iBACG;AAAA,cACH,IAAI,OAAO,QAAQ,OAAO,aAAa,EAAE,MAAM;AAAA,gBAAI,OAAO;AAAA,cAC1D;AAAA,iBACG;AAAA,cACH,IAAI,OAAO,QAAQ,OAAO,aAAa,EAAE,KAAK;AAAA,gBAAI,OAAO;AAAA,cACzD;AAAA,iBACG;AAAA,cACH,IAAI,OAAO,QAAQ,OAAO,aAAa,EAAE,MAAM;AAAA,gBAAI,OAAO;AAAA,cAC1D;AAAA;AAAA,cAEA,OAAO;AAAA;AAAA,QAEb,EAAO;AAAA,UACL,IAAI,gBAAgB;AAAA,YAAW,OAAO;AAAA;AAAA,MAE1C;AAAA,MACA,OAAO;AAAA,KACR;AAAA,IAED,IAAI,SAAS,WAAW,QAAQ,QAAQ,SAAS,GAAG;AAAA,MAClD,QAAQ,KAAK,CAAC,GAAG,MAAM;AAAA,QACrB,aAAa,QAAQ,eAAe,QAAQ,SAAU;AAAA,UACpD,MAAM,OAAO,EAAE;AAAA,UACf,MAAM,OAAO,EAAE;AAAA,UACf,IAAI,QAAQ,QAAQ,QAAQ;AAAA,YAAM;AAAA,UAClC,IAAI,QAAQ;AAAA,YAAM,OAAO,cAAc,QAAQ,KAAK;AAAA,UACpD,IAAI,QAAQ;AAAA,YAAM,OAAO,cAAc,QAAQ,IAAI;AAAA,UACnD,IAAI,OAAO;AAAA,YAAM,OAAO,cAAc,QAAQ,KAAK;AAAA,UACnD,IAAI,OAAO;AAAA,YAAM,OAAO,cAAc,QAAQ,IAAI;AAAA,QACpD;AAAA,QACA,OAAO;AAAA,OACR;AAAA,IACH;AAAA,IAEA,IAAI,SAAS,WAAW,WAAW;AAAA,MACjC,UAAU,QAAQ,MAAM,QAAQ,MAAM;AAAA,IACxC;AAAA,IAEA,IAAI,SAAS,UAAU,WAAW;AAAA,MAChC,UAAU,QAAQ,MAAM,GAAG,QAAQ,KAAK;AAAA,IAC1C;AAAA,IAEA,MAAM,SAAS,QAAQ,SAAS,IAAI,UAAU;AAAA,IAC9C,KAAK,OAAO,KAAK,SAAS,UAA6B,MAAM;AAAA,IAC7D,OAAO;AAAA;AAAA,OAQM,WAA2C,CACxD,UACA,SAC4B;AAAA,IAC5B,KAAK,eAAe,OAAO;AAAA,IAC3B,KAAK,oBAAoB,UAAU,OAAO;AAAA,IAE1C,MAAM,aAAa,KAAK,QAAQ,IAAI,CAAC,MAAM,OAAO;AAAA,MAChD,MAAM,OAAO;AAAA,MACb,SAAS;AAAA,IACX,EAAE;AAAA,IAEF,kBAAkB;AAAA,MAChB,OAAO;AAAA,MACP,SAAS;AAAA,MACT,iBAAiB,OAAO,KAAK,QAAQ;AAAA,MACrC,iBAAiB,QAAQ,WAAW,CAAC,GAAG,IAAI,CAAC,OAAO;AAAA,QAClD,QAAQ,OAAO,EAAE,MAAM;AAAA,QACvB,WAAW,EAAE;AAAA,MACf,EAAE;AAAA,MACF,eAAe,QAAQ,OAAO,IAAI,MAAM;AAAA,MACxC,mBAAmB,KAAK,gBAAgB,IAAI,MAAM;AAAA,IACpD,CAAC;AAAA,IAGD,MAAM,OAAO,MAAM,KAAK,MAAM,UAAU;AAAA,MACtC,SAAS,QAAQ;AAAA,MACjB,OAAO,QAAQ;AAAA,MACf,QAAQ,QAAQ;AAAA,IAClB,CAAC;AAAA,IACD,IAAI,CAAC;AAAA,MAAM,OAAO,CAAC;AAAA,IACnB,OAAO,KAAK,IAAI,CAAC,QAAQ;AAAA,MACvB,MAAM,MAAM,CAAC;AAAA,MACb,WAAW,KAAK,QAAQ;AAAA,QAAQ,IAAI,KAAK,IAAI;AAAA,MAC7C,OAAO;AAAA,KACR;AAAA;AAAA,EAWa,kBAAkB,CAChC,UACA,SACY;AAAA,IACZ,MAAM,YAAY,CAAC,WAAmB;AAAA,MACpC,SAAS,EAAE,MAAM,KAAK,oBAAoB,WAAW,UAAU,KAAK,OAAO,CAAC;AAAA;AAAA,IAG9E,MAAM,eAAe,CAAC,SAAuB;AAAA,MAC3C,SAAS,EAAE,MAAM,SAAS,CAAC;AAAA;AAAA,IAG7B,MAAM,iBAAiB,MAAM;AAAA,MAC3B,SAAS,EAAE,MAAM,SAAS,CAAC;AAAA;AAAA,IAG7B,KAAK,OAAO,GAAG,OAAO,SAAS;AAAA,IAC/B,KAAK,OAAO,GAAG,UAAU,YAAY;AAAA,IACrC,KAAK,OAAO,GAAG,YAAY,cAAc;AAAA,IAEzC,OAAO,MAAM;AAAA,MACX,KAAK,OAAO,IAAI,OAAO,SAAS;AAAA,MAChC,KAAK,OAAO,IAAI,UAAU,YAAY;AAAA,MACtC,KAAK,OAAO,IAAI,YAAY,cAAc;AAAA;AAAA;AAAA,EAO9B,OAAO,GAAS;AAAA,IAC9B,KAAK,OAAO,MAAM;AAAA;AAEtB;;;AD5cO,IAAM,4BAA4B,oBACvC,kCACF;AAAA;AAUO,MAAM,6BAWH,mBAAmF;AAAA,EAC3E;AAAA,EACR;AAAA,EACA,mBAAmB;AAAA,EACnB,mBAAyC;AAAA,EAajD,WAAW,CACT,SACA,OACA,QACA,iBACA,SACA,qBAA+C,cAC/C;AAAA,IAIA,IAAI,CAAC,UAAU,CAAC,iBAAiB;AAAA,MAC/B,MAAM,IAAI,MACR,gFACF;AAAA,IACF;AAAA,IAEA,MAAM,QAAQ,iBAAiB,WAAW,CAAC,GAAG,kBAAkB;AAAA,IAChE,KAAK,UAAU;AAAA,IAGf,IAAI,OAAO;AAAA,MACT,KAAK,QAAQ;AAAA,IACf,EAAO;AAAA,MACL,KAAK,QAAQ,IAAI,uBACf,QACA,iBACA,WAAW,CAAC,GACZ,kBACF;AAAA;AAAA,IAIF,KAAK,qBAAqB;AAAA;AAAA,EAMpB,oBAAoB,GAAS;AAAA,IAEnC,KAAK,MAAM,GAAG,OAAO,CAAC,WAAW;AAAA,MAC/B,KAAK,OAAO,KAAK,OAAO,MAAM;AAAA,KAC/B;AAAA,IACD,KAAK,MAAM,GAAG,OAAO,CAAC,KAAK,WAAW;AAAA,MACpC,KAAK,OAAO,KAAK,OAAO,KAAK,MAAM;AAAA,KACpC;AAAA,IACD,KAAK,MAAM,GAAG,SAAS,CAAC,KAAK,aAAa;AAAA,MACxC,KAAK,OAAO,KAAK,SAAS,KAAK,QAAQ;AAAA,KACxC;AAAA,IACD,KAAK,MAAM,GAAG,UAAU,CAAC,QAAQ;AAAA,MAC/B,KAAK,OAAO,KAAK,UAAU,GAAG;AAAA,KAC/B;AAAA,IACD,KAAK,MAAM,GAAG,YAAY,MAAM;AAAA,MAC9B,KAAK,OAAO,KAAK,UAAU;AAAA,KAC5B;AAAA;AAAA,OAOW,gBAAe,GAAkB;AAAA,IAC7C,IAAI,KAAK;AAAA,MAAkB;AAAA,IAE3B,IAAI,KAAK,kBAAkB;AAAA,MACzB,OAAO,KAAK;AAAA,IACd;AAAA,IAEA,KAAK,oBAAoB,YAAY;AAAA,MACnC,IAAI;AAAA,QACF,MAAM,MAAM,MAAM,KAAK,QAAQ,OAAO;AAAA,QACtC,IAAI,OAAO,IAAI,SAAS,GAAG;AAAA,UACzB,MAAM,KAAK,MAAM,QAAQ,GAAG;AAAA,QAC9B;AAAA,QACA,KAAK,mBAAmB;AAAA,QACxB,OAAO,OAAO;AAAA,QACd,UAAU,EAAE,KAAK,uDAAuD,EAAE,MAAM,CAAC;AAAA,gBAEjF;AAAA,QACA,KAAK,mBAAmB;AAAA;AAAA,OAEzB;AAAA,IAEH,OAAO,KAAK;AAAA;AAAA,OASR,IAAG,CAAC,OAAoC;AAAA,IAC5C,MAAM,KAAK,gBAAgB;AAAA,IAG3B,MAAM,SAAS,MAAM,KAAK,QAAQ,IAAI,KAAK;AAAA,IAG3C,MAAM,KAAK,MAAM,IAAI,MAAM;AAAA,IAE3B,OAAO;AAAA;AAAA,OASH,QAAO,CAAC,QAAyC;AAAA,IACrD,MAAM,KAAK,gBAAgB;AAAA,IAG3B,MAAM,UAAU,MAAM,KAAK,QAAQ,QAAQ,MAAM;AAAA,IAGjD,MAAM,KAAK,MAAM,QAAQ,OAAO;AAAA,IAEhC,OAAO;AAAA;AAAA,OASH,IAAG,CAAC,KAA8C;AAAA,IACtD,MAAM,KAAK,gBAAgB;AAAA,IAG3B,IAAI,SAAS,MAAM,KAAK,MAAM,IAAI,GAAG;AAAA,IAGrC,IAAI,WAAW,WAAW;AAAA,MACxB,SAAS,MAAM,KAAK,QAAQ,IAAI,GAAG;AAAA,MACnC,IAAI,QAAQ;AAAA,QACV,MAAM,KAAK,MAAM,IAAI,MAAM;AAAA,MAC7B;AAAA,IACF;AAAA,IAEA,OAAO;AAAA;AAAA,OAQH,OAAM,CAAC,OAA2C;AAAA,IACtD,MAAM,KAAK,gBAAgB;AAAA,IAG3B,MAAM,KAAK,QAAQ,OAAO,KAAK;AAAA,IAG/B,MAAM,KAAK,MAAM,OAAO,KAAK;AAAA;AAAA,OAOzB,UAAS,GAAkB;AAAA,IAC/B,MAAM,KAAK,gBAAgB;AAAA,IAG3B,MAAM,KAAK,QAAQ,UAAU;AAAA,IAG7B,MAAM,KAAK,MAAM,UAAU;AAAA;AAAA,OAQvB,OAAM,CAAC,SAA+D;AAAA,IAC1E,MAAM,KAAK,gBAAgB;AAAA,IAG3B,IAAI,UAAU,MAAM,KAAK,MAAM,OAAO;AAAA,IAGtC,IAAI,CAAC,WAAW,QAAQ,WAAW,GAAG;AAAA,MACpC,UAAU,MAAM,KAAK,QAAQ,OAAO;AAAA,MACpC,IAAI,WAAW,QAAQ,SAAS,GAAG;AAAA,QACjC,MAAM,KAAK,MAAM,QAAQ,OAAO;AAAA,MAClC;AAAA,IACF;AAAA,IAGA,IAAI,WAAW,WAAW,QAAQ,SAAS,GAAG;AAAA,MAC5C,OAAO,MAAM,KAAK,MAAM,OAAO,OAAO;AAAA,IACxC;AAAA,IAEA,OAAO;AAAA;AAAA,OAOH,KAAI,GAAoB;AAAA,IAC5B,MAAM,KAAK,gBAAgB;AAAA,IAG3B,OAAO,MAAM,KAAK,QAAQ,KAAK;AAAA;AAAA,OAS3B,QAAO,CAAC,QAAgB,OAA8C;AAAA,IAC1E,MAAM,KAAK,gBAAgB;AAAA,IAG3B,OAAO,MAAM,KAAK,QAAQ,QAAQ,QAAQ,KAAK;AAAA;AAAA,OAY3C,MAAK,CACT,UACA,SAC+B;AAAA,IAC/B,MAAM,KAAK,gBAAgB;AAAA,IAC3B,OAAO,MAAM,KAAK,MAAM,MAAM,UAAU,OAAO;AAAA;AAAA,OAGlC,WAA2C,CACxD,UACA,SAC4B;AAAA,IAC5B,MAAM,KAAK,gBAAgB;AAAA,IAC3B,OAAO,MAAM,KAAK,MAAM,WAAW,UAAU,OAAO;AAAA;AAAA,OAShD,aAAY,CAAC,UAAuD;AAAA,IACxE,MAAM,KAAK,gBAAgB;AAAA,IAG3B,MAAM,KAAK,QAAQ,aAAa,QAAQ;AAAA,IAGxC,MAAM,KAAK,MAAM,aAAa,QAAQ;AAAA;AAAA,OAMlC,gBAAe,GAAkB;AAAA,IACrC,MAAM,KAAK,MAAM,UAAU;AAAA,IAC3B,KAAK,mBAAmB;AAAA;AAAA,OAMpB,aAAY,GAAkB;AAAA,IAClC,MAAM,KAAK,MAAM,UAAU;AAAA,IAC3B,KAAK,mBAAmB;AAAA,IACxB,MAAM,KAAK,gBAAgB;AAAA;AAAA,EAYpB,kBAAkB,CACzB,UACA,SACY;AAAA,IAEZ,OAAO,KAAK,QAAQ,mBAAmB,OAAO,WAAW;AAAA,MAEvD,IAAI,OAAO,SAAS,YAAY,OAAO,SAAS,UAAU;AAAA,QACxD,IAAI,OAAO,KAAK;AAAA,UACd,MAAM,KAAK,MAAM,IAAI,OAAO,GAAG;AAAA,QACjC;AAAA,MACF,EAAO,SAAI,OAAO,SAAS,UAAU;AAAA,QACnC,IAAI,OAAO,KAAK;AAAA,UACd,MAAM,KAAK,MAAM,OAAO,OAAO,GAAG;AAAA,QACpC;AAAA,MACF;AAAA,MAGA,SAAS,MAAM;AAAA,OACd,OAAO;AAAA;AAAA,EAMH,OAAO,GAAS;AAAA,IACvB,KAAK,QAAQ,QAAQ;AAAA,IACrB,KAAK,MAAM,QAAQ;AAAA;AAEvB;;AG3XA,+BAAS;AAiBF,IAAM,wBAAwB,oBACnC,uCACF;AAAA;AA2DO,MAAM,kCAWH,mBAAmF;AAAA,EAC1E;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAWjB,WAAW,CACT,SACA,QACA,OACA,QACA,iBACA,SACA;AAAA,IACA,MACE,QACA,iBACC,SAAS,WAAW,CAAC,GAItB,OACF;AAAA,IACA,KAAK,UAAU;AAAA,IACf,KAAK,SAAS;AAAA,IACd,KAAK,QAAQ;AAAA,IACb,KAAK,QAAQ,SAAS;AAAA,IACtB,KAAK,UAAU,SAAS,WAAW;AAAA;AAAA,cAaxB,YAAyB,CACpC,SACA,QACA,OACA,SAGA;AAAA,IACA,MAAM,UAAU,SAAS,WAAW;AAAA,IACpC,MAAM,QAAQ,SAAS;AAAA,IAGvB,MAAM,MAAM,IAAI,IAAI,GAAG,oBAAoB;AAAA,IAC3C,IAAI,aAAa,IAAI,WAAW,OAAO;AAAA,IACvC,IAAI,aAAa,IAAI,UAAU,MAAM;AAAA,IACrC,IAAI,aAAa,IAAI,SAAS,KAAK;AAAA,IAEnC,MAAM,UAAkC,CAAC;AAAA,IACzC,IAAI,OAAO;AAAA,MACT,QAAQ,mBAAmB,UAAU;AAAA,IACvC;AAAA,IAEA,MAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG,EAAE,QAAQ,CAAC;AAAA,IACxD,IAAI,CAAC,SAAS,IAAI;AAAA,MAChB,MAAM,IAAI,MACR,qCAAqC,SAAS,UAAU,SAAS,YACnE;AAAA,IACF;AAAA,IAEA,MAAM,OAA4B,MAAM,SAAS,KAAK;AAAA,IAGtD,MAAM,aAAkC,CAAC;AAAA,IACzC,MAAM,WAAqB,CAAC;AAAA,IAG5B,WAAW,aAAa,EAAE,MAAM,WAAW,oBAAoB,KAAK;AAAA,IACpE,SAAS,KAAK,SAAS;AAAA,IAEvB,WAAW,WAAW,KAAK,UAAU;AAAA,MACnC,MAAM,aAAa,sBAAsB,QAAQ,IAAI;AAAA,MACrD,WAAW,QAAQ,QAAQ;AAAA,MAE3B,SAAS,KAAK,QAAQ,IAAI;AAAA,IAC5B;AAAA,IAEA,MAAM,SAA+B;AAAA,MACnC,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,sBAAsB;AAAA,IACxB;AAAA,IAEA,OAAO,IAAI,0BACT,SACA,QACA,OACA,QACA,CAAC,SAAS,GACV,OACF;AAAA;AAAA,OAMa,cAAa,GAAkB;AAAA,IAE5C,MAAM,OAAO,MAAM,KAAK,SAA8B,eAAe,CAAC,CAAC;AAAA,IAGvE,MAAM,gBAAgB,OAAO,KAAK,KAAK,OAAO,UAAU;AAAA,IACxD,MAAM,YAAY,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA,IAGjD,MAAM,YAAY,cAAc,SAAS,SAAS;AAAA,IAElD,IAAI,CAAC,WAAW;AAAA,MAEd,WAAW,UAAU,eAAe;AAAA,QAClC,IAAI,CAAC,UAAU,SAAS,MAAM,KAAK,CAAC,KAAK,gBAAgB,SAAS,MAAa,GAAG;AAAA,UAChF,MAAM,IAAI,MAAM,kBAAkB,mDAAmD;AAAA,QACvF;AAAA,MACF;AAAA,IACF;AAAA;AAAA,OAMI,IAAG,CAAC,KAA8C;AAAA,IACtD,MAAM,SAAS,KAAK,6BAA6B,KAAK,IAAI,CAAQ,EAAE;AAAA,IACpE,MAAM,kBAA4B,CAAC;AAAA,IAEnC,YAAY,GAAG,MAAM,OAAO,QAAQ,MAA6B,GAAG;AAAA,MAClE,IAAI,OAAO,MAAM,UAAU;AAAA,QAEzB,MAAM,UAAU,EAAE,QAAQ,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAK;AAAA,QAC5D,gBAAgB,KAAK,GAAG,MAAM,UAAU;AAAA,MAC1C,EAAO;AAAA,QACL,gBAAgB,KAAK,GAAG,KAAK,GAAG;AAAA;AAAA,IAEpC;AAAA,IAEA,MAAM,QAAQ,gBAAgB,KAAK,OAAO;AAAA,IAC1C,MAAM,OAAO,MAAM,KAAK,SAA2B,WAAW,EAAE,OAAO,OAAO,IAAI,CAAC;AAAA,IAEnF,IAAI,KAAK,KAAK,SAAS,GAAG;AAAA,MACxB,MAAM,SAAS,KAAK,YAAY,KAAK,KAAK,EAAE;AAAA,MAC5C,KAAK,OAAO,KAAK,OAAO,KAAK,MAAM;AAAA,MACnC,OAAO;AAAA,IACT;AAAA,IAEA,KAAK,OAAO,KAAK,OAAO,KAAK,SAAS;AAAA,IACtC;AAAA;AAAA,OAMI,OAAM,CAAC,SAA+D;AAAA,IAC1E,KAAK,sBAAsB,OAAO;AAAA,IAElC,MAAM,cAAwB,CAAC;AAAA,IAC/B,IAAI,SAAS;AAAA,IACb,MAAM,WAAW;AAAA,IAEjB,OAAO,MAAM;AAAA,MACX,MAAM,OAAO,MAAM,KAAK,QAAQ,QAAQ,QAAQ;AAAA,MAEhD,IAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAAA,QAC9B;AAAA,MACF;AAAA,MAEA,YAAY,KAAK,GAAG,IAAI;AAAA,MACxB,UAAU,KAAK;AAAA,MAGf,IAAI,KAAK,SAAS,UAAU;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAAA,IAEA,IAAI,YAAY,WAAW;AAAA,MAAG;AAAA,IAE9B,IAAI,UAAU;AAAA,IAGd,IAAI,SAAS,WAAW,QAAQ,QAAQ,SAAS,GAAG;AAAA,MAClD,UAAU,CAAC,GAAG,OAAO;AAAA,MACrB,QAAQ,KAAK,CAAC,GAAG,MAAM;AAAA,QACrB,aAAa,QAAQ,eAAe,QAAQ,SAAU;AAAA,UACpD,MAAM,OAAO,EAAE;AAAA,UACf,MAAM,OAAO,EAAE;AAAA,UACf,IAAI,QAAQ,QAAQ,QAAQ;AAAA,YAAM;AAAA,UAClC,IAAI,QAAQ;AAAA,YAAM,OAAO,cAAc,QAAQ,KAAK;AAAA,UACpD,IAAI,QAAQ;AAAA,YAAM,OAAO,cAAc,QAAQ,IAAI;AAAA,UACnD,IAAI,OAAO;AAAA,YAAM,OAAO,cAAc,QAAQ,KAAK;AAAA,UACnD,IAAI,OAAO;AAAA,YAAM,OAAO,cAAc,QAAQ,IAAI;AAAA,QACpD;AAAA,QACA,OAAO;AAAA,OACR;AAAA,IACH;AAAA,IAGA,IAAI,SAAS,WAAW,WAAW;AAAA,MACjC,UAAU,QAAQ,MAAM,QAAQ,MAAM;AAAA,IACxC;AAAA,IAGA,IAAI,SAAS,UAAU,WAAW;AAAA,MAChC,UAAU,QAAQ,MAAM,GAAG,QAAQ,KAAK;AAAA,IAC1C;AAAA,IAEA,OAAO,QAAQ,SAAS,IAAI,UAAU;AAAA;AAAA,OASlC,QAAO,CAAC,QAAgB,OAA8C;AAAA,IAC1E,MAAM,OAAO,MAAM,KAAK,SAAyB,SAAS;AAAA,MACxD,QAAQ,OAAO,SAAS;AAAA,MACxB,QAAQ,KAAK,IAAI,OAAO,GAAG,EAAE,SAAS;AAAA,IACxC,CAAC;AAAA,IAED,IAAI,KAAK,KAAK,WAAW,GAAG;AAAA,MAC1B;AAAA,IACF;AAAA,IAEA,MAAM,WAAqB,CAAC;AAAA,IAC5B,WAAW,OAAO,KAAK,MAAM;AAAA,MAC3B,SAAS,KAAK,KAAK,YAAY,GAAG,CAAC;AAAA,IACrC;AAAA,IAEA,OAAO;AAAA;AAAA,OAMH,KAAI,GAAoB;AAAA,IAC5B,MAAM,OAAO,MAAM,KAAK,SAAyB,SAAS,CAAC,CAAC;AAAA,IAC5D,OAAO,KAAK,KAAK;AAAA;AAAA,OAMb,IAAG,CAAC,QAAqC;AAAA,IAC7C,MAAM,IAAI,MAAM,uCAAuC;AAAA;AAAA,OAMnD,QAAO,CAAC,SAA0C;AAAA,IACtD,MAAM,IAAI,MAAM,uCAAuC;AAAA;AAAA,OAMnD,OAAM,CAAC,QAA4C;AAAA,IACvD,MAAM,IAAI,MAAM,uCAAuC;AAAA;AAAA,OAMnD,UAAS,GAAkB;AAAA,IAC/B,MAAM,IAAI,MAAM,uCAAuC;AAAA;AAAA,OAWnD,MAAK,CACT,UACA,SAC+B;AAAA,IAC/B,KAAK,oBAAoB,UAAU,OAAO;AAAA,IAG1C,MAAM,kBAA4B,CAAC;AAAA,IACnC,YAAY,GAAG,MAAM,OAAO,QAAQ,QAAQ,GAAG;AAAA,MAC7C,IAAI,MAAM,aAAa,MAAM;AAAA,QAAM;AAAA,MACnC,IAAI,kBAAkB,CAAC,GAAG;AAAA,QACxB,IAAI,EAAE,aAAa,KAAK;AAAA,UACtB,MAAM,IAAI,wBACR,aAAa,EAAE,sBACf,2BACF;AAAA,QACF;AAAA,QACA,MAAM,MAAM,EAAE;AAAA,QACd,IAAI,OAAO,QAAQ,UAAU;AAAA,UAC3B,MAAM,UAAU,IAAI,QAAQ,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAK;AAAA,UAC9D,gBAAgB,KAAK,GAAG,MAAM,UAAU;AAAA,QAC1C,EAAO;AAAA,UACL,gBAAgB,KAAK,GAAG,KAAK,KAAK;AAAA;AAAA,MAEtC,EAAO;AAAA,QACL,IAAI,OAAO,MAAM,UAAU;AAAA,UACzB,MAAM,UAAU,EAAE,QAAQ,OAAO,MAAM,EAAE,QAAQ,MAAM,KAAK;AAAA,UAC5D,gBAAgB,KAAK,GAAG,MAAM,UAAU;AAAA,QAC1C,EAAO;AAAA,UACL,gBAAgB,KAAK,GAAG,KAAK,GAAG;AAAA;AAAA;AAAA,IAGtC;AAAA,IAEA,IAAI,gBAAgB,WAAW,GAAG;AAAA,MAChC;AAAA,IACF;AAAA,IAEA,MAAM,QAAQ,gBAAgB,KAAK,OAAO;AAAA,IAC1C,MAAM,cAAwB,CAAC;AAAA,IAC/B,IAAI,cAAc;AAAA,IAClB,MAAM,aAAa;AAAA,IAEnB,OAAO,MAAM;AAAA,MACX,MAAM,OAAO,MAAM,KAAK,SAA2B,WAAW;AAAA,QAC5D;AAAA,QACA,QAAQ,YAAY,SAAS;AAAA,QAC7B,OAAO,WAAW,SAAS;AAAA,MAC7B,CAAC;AAAA,MAED,WAAW,OAAO,KAAK,MAAM;AAAA,QAC3B,YAAY,KAAK,KAAK,YAAY,GAAG,CAAC;AAAA,MACxC;AAAA,MAEA,eAAe,KAAK,KAAK;AAAA,MAEzB,IAAI,eAAe,KAAK,kBAAkB,KAAK,KAAK,SAAS,YAAY;AAAA,QACvE;AAAA,MACF;AAAA,IACF;AAAA,IAEA,IAAI,UAAU;AAAA,IAGd,IAAI,SAAS,WAAW,QAAQ,QAAQ,SAAS,GAAG;AAAA,MAClD,QAAQ,KAAK,CAAC,GAAG,MAAM;AAAA,QACrB,aAAa,QAAQ,eAAe,QAAQ,SAAU;AAAA,UACpD,MAAM,OAAO,EAAE;AAAA,UACf,MAAM,OAAO,EAAE;AAAA,UACf,IAAI,QAAQ,QAAQ,QAAQ;AAAA,YAAM;AAAA,UAClC,IAAI,QAAQ;AAAA,YAAM,OAAO,cAAc,QAAQ,KAAK;AAAA,UACpD,IAAI,QAAQ;AAAA,YAAM,OAAO,cAAc,QAAQ,IAAI;AAAA,UACnD,IAAI,OAAO;AAAA,YAAM,OAAO,cAAc,QAAQ,KAAK;AAAA,UACnD,IAAI,OAAO;AAAA,YAAM,OAAO,cAAc,QAAQ,IAAI;AAAA,QACpD;AAAA,QACA,OAAO;AAAA,OACR;AAAA,IACH;AAAA,IAGA,IAAI,SAAS,WAAW,WAAW;AAAA,MACjC,UAAU,QAAQ,MAAM,QAAQ,MAAM;AAAA,IACxC;AAAA,IAGA,IAAI,SAAS,UAAU,WAAW;AAAA,MAChC,UAAU,QAAQ,MAAM,GAAG,QAAQ,KAAK;AAAA,IAC1C;AAAA,IAEA,IAAI,QAAQ,SAAS,GAAG;AAAA,MACtB,KAAK,OAAO,KAAK,SAAS,UAA6B,OAAO;AAAA,MAC9D,OAAO;AAAA,IACT,EAAO;AAAA,MACL,KAAK,OAAO,KAAK,SAAS,UAA6B,SAAS;AAAA,MAChE;AAAA;AAAA;AAAA,OAOE,aAAY,CAAC,WAAwD;AAAA,IACzE,MAAM,IAAI,MAAM,uCAAuC;AAAA;AAAA,EAMhD,kBAAkB,CACzB,WACA,UACY;AAAA,IACZ,MAAM,IAAI,MAAM,0DAA0D;AAAA;AAAA,EAMnE,OAAO,GAAS;AAAA,OAOX,SAAW,CAAC,UAAkB,QAA4C;AAAA,IACtF,MAAM,MAAM,IAAI,IAAI,GAAG,KAAK,UAAU,UAAU;AAAA,IAChD,IAAI,aAAa,IAAI,WAAW,KAAK,OAAO;AAAA,IAC5C,IAAI,aAAa,IAAI,UAAU,KAAK,MAAM;AAAA,IAC1C,IAAI,aAAa,IAAI,SAAS,KAAK,KAAK;AAAA,IAExC,YAAY,KAAK,UAAU,OAAO,QAAQ,MAAM,GAAG;AAAA,MACjD,IAAI,UAAU,WAAW;AAAA,QACvB,IAAI,aAAa,IAAI,KAAK,KAAK;AAAA,MACjC;AAAA,IACF;AAAA,IAEA,MAAM,UAAkC,CAAC;AAAA,IACzC,IAAI,KAAK,OAAO;AAAA,MACd,QAAQ,mBAAmB,UAAU,KAAK;AAAA,IAC5C;AAAA,IAEA,MAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG,EAAE,QAAQ,CAAC;AAAA,IACxD,IAAI,CAAC,SAAS,IAAI;AAAA,MAChB,MAAM,IAAI,MAAM,0BAA0B,SAAS,UAAU,SAAS,YAAY;AAAA,IACpF;AAAA,IAEA,OAAO,MAAM,SAAS,KAAK;AAAA;AAAA,EAMrB,WAAW,CAAC,KAA4D;AAAA,IAC9E,OAAO,EAAE,SAAS,IAAI,YAAY,IAAI,IAAI;AAAA;AAE9C;AAKA,SAAS,qBAAqB,CAAC,SAAmB;AAAA,EAEhD,IAAI,QAAQ,UAAU,SAAS;AAAA,IAC7B,QAAQ,QAAQ;AAAA,WACT;AAAA,QACH,OAAO,EAAE,MAAM,SAAS;AAAA,WACrB;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,WACA;AAAA,QACH,OAAO,EAAE,MAAM,UAAU;AAAA,WACtB;AAAA,WACA;AAAA,WACA;AAAA,QACH,OAAO,EAAE,MAAM,SAAS;AAAA,WACrB;AAAA,QACH,OAAO,EAAE,MAAM,UAAU;AAAA;AAAA,QAEzB,OAAO,CAAC;AAAA;AAAA,EAEd;AAAA,EAGA,IAAI,QAAQ,UAAU,cAAc;AAAA,IAClC,OAAO,EAAE,MAAM,UAAU;AAAA,EAC3B;AAAA,EAGA,IAAI,QAAQ,UAAU,YAAY;AAAA,IAChC,OAAO;AAAA,MACL,MAAM;AAAA,MACN,OAAO,sBAAsB,QAAQ,OAAO;AAAA,IAC9C;AAAA,EACF;AAAA,EAGA,OAAO,CAAC;AAAA;;ACzkBV;AAAA,wBACE;AAAA;AAAA;AAAA;AAAA;AAYK,IAAM,uBAAuB,oBAClC,8BACF;AAGA,sBAAsB,iBACpB,sBACA,MAAsC,IAAI,KAC1C,IACF;AAMO,SAAS,4BAA4B,GAAmC;AAAA,EAC7E,OAAO,sBAAsB,IAAI,oBAAoB;AAAA;AAQhD,SAAS,yBAAyB,CAAC,IAAY,YAAqC;AAAA,EACzF,MAAM,QAAQ,6BAA6B;AAAA,EAC3C,MAAM,IAAI,IAAI,UAAU;AAAA;AAQnB,SAAS,oBAAoB,CAAC,IAA2C;AAAA,EAC9E,OAAO,6BAA6B,EAAE,IAAI,EAAE;AAAA;AAO9C,SAAS,6BAA6B,CACpC,IACA,QACA,UACmB;AAAA,EACnB,MAAM,QAAQ,SAAS,IAAI,oBAAoB,IAC3C,SAAS,IAAI,oBAAoB,IACjC,6BAA6B;AAAA,EACjC,MAAM,OAAO,MAAM,IAAI,EAAE;AAAA,EACzB,IAAI,CAAC,MAAM;AAAA,IACT,MAAM,IAAI,MAAM,oBAAoB,2BAA2B;AAAA,EACjE;AAAA,EACA,OAAO;AAAA;AAIT,sBAAsB,mBAAmB,6BAA6B;AAGtE,uBAAuB,mBAAmB,CAAC,OAAO,SAAS,aAAa;AAAA,EACtE,MAAM,QAAQ,SAAS,IAAI,oBAAoB,IAC3C,SAAS,IAAI,oBAAoB,IACjC,6BAA6B;AAAA,EAEjC,YAAY,IAAI,SAAS,OAAO;AAAA,IAC9B,IAAI,SAAS;AAAA,MAAO,OAAO;AAAA,EAC7B;AAAA,EACA;AAAA,CACD;;ACnFD;AAKA,eAAsB,MAAS,CAC7B,UACA,aACA,IACY;AAAA,EACZ,MAAM,YAAY,qBAAqB;AAAA,EACvC,IAAI,CAAC,UAAU;AAAA,IAAW,OAAO,GAAG;AAAA,EACpC,MAAM,OAAO,UAAU,UAAU,UAAU;AAAA,IACzC,YAAY,EAAE,yBAAyB,YAAY;AAAA,EACrD,CAAC;AAAA,EACD,IAAI;AAAA,IACF,MAAM,SAAS,MAAM,GAAG;AAAA,IACxB,KAAK,UAAU,eAAe,EAAE;AAAA,IAChC,OAAO;AAAA,IACP,OAAO,KAAK;AAAA,IACZ,KAAK,UAAU,eAAe,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,IACrF,MAAM;AAAA,YACN;AAAA,IACA,KAAK,IAAI;AAAA;AAAA;;;ACGN,MAAM,wBAMyE;AAAA,EAE/D;AAAA,EACA;AAAA,EAFrB,WAAW,CACU,aACA,OAOnB;AAAA,IARmB;AAAA,IACA;AAAA;AAAA,EASrB,GAAG,CAAC,OAAoC;AAAA,IACtC,OAAO,OAAO,gCAAgC,KAAK,aAAa,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC;AAAA;AAAA,EAG7F,OAAO,CAAC,QAAyC;AAAA,IAC/C,OAAO,OAAO,oCAAoC,KAAK,aAAa,MAClE,KAAK,MAAM,QAAQ,MAAM,CAC3B;AAAA;AAAA,EAGF,GAAG,CAAC,KAA8C;AAAA,IAChD,OAAO,OAAO,gCAAgC,KAAK,aAAa,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC;AAAA;AAAA,EAG3F,MAAM,CAAC,KAAyC;AAAA,IAC9C,OAAO,OAAO,mCAAmC,KAAK,aAAa,MACjE,KAAK,MAAM,OAAO,GAAG,CACvB;AAAA;AAAA,EAGF,MAAM,CAAC,SAA+D;AAAA,IACpE,OAAO,OAAO,mCAAmC,KAAK,aAAa,MACjE,KAAK,MAAM,OAAO,OAAO,CAC3B;AAAA;AAAA,EAGF,SAAS,GAAkB;AAAA,IACzB,OAAO,OAAO,sCAAsC,KAAK,aAAa,MACpE,KAAK,MAAM,UAAU,CACvB;AAAA;AAAA,EAGF,IAAI,GAAoB;AAAA,IACtB,OAAO,OAAO,iCAAiC,KAAK,aAAa,MAAM,KAAK,MAAM,KAAK,CAAC;AAAA;AAAA,EAG1F,KAAK,CAAC,UAAoD;AAAA,IACxD,OAAO,OAAO,kCAAkC,KAAK,aAAa,MAChE,KAAK,MAAM,MAAM,QAAQ,CAC3B;AAAA;AAAA,EAGF,YAAY,CAAC,UAAuD;AAAA,IAClE,OAAO,OAAO,yCAAyC,KAAK,aAAa,MACvE,KAAK,MAAM,aAAa,QAAQ,CAClC;AAAA;AAAA,EAGF,OAAO,CAAC,QAAgB,OAA8C;AAAA,IACpE,OAAO,OAAO,oCAAoC,KAAK,aAAa,MAClE,KAAK,MAAM,QAAQ,QAAQ,KAAK,CAClC;AAAA;AAAA,EAGF,KAAK,CACH,UACA,SAC+B;AAAA,IAC/B,OAAO,OAAO,kCAAkC,KAAK,aAAa,MAChE,KAAK,MAAM,MAAM,UAAU,OAAO,CACpC;AAAA;AAAA,EAGF,UAA2C,CACzC,UACA,SAC4B;AAAA,IAC5B,OAAO,OAAO,uCAAuC,KAAK,aAAa,MACrE,KAAK,MAAM,WAAW,UAAU,OAAO,CACzC;AAAA;AAAA,EAIF,OAAO,CAAC,UAA4D;AAAA,IAClE,OAAO,KAAK,MAAM,QAAQ,QAAQ;AAAA;AAAA,EAGpC,KAAK,CAAC,UAA8D;AAAA,IAClE,OAAO,KAAK,MAAM,MAAM,QAAQ;AAAA;AAAA,EAGlC,kBAAkB,CAChB,UACA,SACY;AAAA,IACZ,OAAO,KAAK,MAAM,mBAAmB,UAAU,OAAO;AAAA;AAAA,EAGxD,aAAa,GAAkB;AAAA,IAC7B,OAAO,KAAK,MAAM,cAAc;AAAA;AAAA,EAGlC,OAAO,GAAS;AAAA,IACd,OAAO,KAAK,MAAM,QAAQ;AAAA;AAAA,GAG3B,OAAO,QAAQ,GAAS;AAAA,IACvB,OAAO,KAAK,MAAM,OAAO,SAAS;AAAA;AAAA,GAGnC,OAAO,aAAa,GAAkB;AAAA,IACrC,OAAO,KAAK,MAAM,OAAO,cAAc;AAAA;AAAA,EAIzC,EAAkC,CAChC,MACA,IACM;AAAA,IACN,KAAK,MAAM,GAAG,MAAM,EAAE;AAAA;AAAA,EAGxB,GAAmC,CACjC,MACA,IACM;AAAA,IACN,KAAK,MAAM,IAAI,MAAM,EAAE;AAAA;AAAA,EAGzB,IAAoC,CAClC,SACG,MACG;AAAA,IACN,KAAK,MAAM,KAAK,MAAM,GAAG,IAAI;AAAA;AAAA,EAG/B,IAAoC,CAClC,MACA,IACM;AAAA,IACN,KAAK,MAAM,KAAK,MAAM,EAAE;AAAA;AAAA,EAG1B,MAAsC,CACpC,MAC4D;AAAA,IAC5D,OAAO,KAAK,MAAM,OAAO,IAAI;AAAA;AAEjC;;AC/KO,IAAM,wBAAwB;AAAA,EACnC,MAAM;AAAA,EACN,YAAY;AAAA,IACV,KAAK,EAAE,MAAM,SAAS;AAAA,IACtB,OAAO,CAAC;AAAA,EACV;AAAA,EACA,sBAAsB;AACxB;AACO,IAAM,qBAAqB,CAAC,KAAK;;ACdxC,+BAAS;;;ACAT,+BAAS,qCAAoB,kCAAc;AAUpC,IAAM,gBAAgB,oBAA8C,sBAAsB;AAAA;AAU1F,MAAe,UAIwB;AAAA,EAQnC;AAAA,EACA;AAAA,EAPC,SAAS,IAAI;AAAA,EAKvB,WAAW,CACF,YAAwB,EAAE,MAAM,SAAS,GACzC,cAA0B,CAAC,GAClC;AAAA,IAFO;AAAA,IACA;AAAA;AAAA,OAsDI,oBAAmB,CAAC,QAAoC;AAAA,IACnE,OAAO,MAAM,iBAAgB,MAAM;AAAA;AAAA,EAQrC,EAA6B,CAAC,MAAa,IAAkD;AAAA,IAC3F,KAAK,OAAO,GAAG,MAAM,EAAE;AAAA;AAAA,EAQzB,GAA8B,CAAC,MAAa,IAAkD;AAAA,IAC5F,KAAK,OAAO,IAAI,MAAM,EAAE;AAAA;AAAA,EAQ1B,IAA+B,CAAC,MAAa,IAAkD;AAAA,IAC7F,KAAK,OAAO,KAAK,MAAM,EAAE;AAAA;AAAA,EAQ3B,IAA+B,CAC7B,SACG,MACH;AAAA,IACA,KAAK,OAAO,KAAK,MAAM,GAAG,IAAI;AAAA;AAAA,EAQhC,MAAiC,CAC/B,MACyD;AAAA,IACzD,OAAO,KAAK,OAAO,OAAO,IAAI;AAAA;AAElC;;;AChIA,IAAM,yBAAyB,IAAI,IAAI,CAAC,UAAU,WAAW,UAAU,MAAM,CAAC;AAAA;AAEvE,MAAe,4BAIZ,UAAgC;AAAA,MAO5B,sBAAsB,GAAY;AAAA,IAC5C,IAAI,KAAK,4BAA4B,WAAW;AAAA,MAC9C,MAAM,aACJ,OAAO,KAAK,gBAAgB,YAC5B,KAAK,gBAAgB,QACrB,UAAU,KAAK,cACX,KAAK,YAAY,OACjB;AAAA,MACN,KAAK,0BAA0B,CAAC,uBAAuB,IAAI,UAAoB;AAAA,IACjF;AAAA,IACA,OAAO,KAAK;AAAA;AAAA,EAEN;AAAA,OAMK,cAAa,GAAkB;AAAA,IAC1C,MAAM,KAAK,kBAAkB,gBAAgB;AAAA;AAAA,OAQlC,IAAG,CAAC,KAAU,OAA6B;AAAA,IACtD,IAAI,KAAK,wBAAwB;AAAA,MAC/B,QAAQ,KAAK,UAAU,KAAK;AAAA,IAC9B;AAAA,IACA,MAAM,KAAK,kBAAkB,IAAI,EAAE,KAAK,MAAM,CAAC;AAAA;AAAA,OAOpC,QAAO,CAAC,OAAyD;AAAA,IAC5E,MAAM,WAAW,KAAK,yBAClB,MAAM,IAAI,GAAG,KAAK,aAAa,EAAE,KAAK,OAAO,KAAK,UAAU,KAAK,EAAW,EAAE,IAC9E;AAAA,IAEJ,MAAM,KAAK,kBAAkB,QAAQ,QAAQ;AAAA;AAAA,OAUlC,IAAG,CAAC,KAAsC;AAAA,IACrD,MAAM,SAAS,MAAM,KAAK,kBAAkB,IAAI,EAAE,IAAI,CAAC;AAAA,IACvD,IAAI,CAAC;AAAA,MAAQ;AAAA,IAEb,IAAI,KAAK,wBAAwB;AAAA,MAC/B,IAAI;AAAA,QACF,OAAO,KAAK,MAAM,OAAO,KAA0B;AAAA,QACnD,OAAO,GAAG;AAAA,QACV,OAAO,OAAO;AAAA;AAAA,IAElB;AAAA,IACA,OAAO,OAAO;AAAA;AAAA,OAOH,OAAM,CAAC,KAAyB;AAAA,IAC3C,OAAO,MAAM,KAAK,kBAAkB,OAAO,EAAE,IAAI,CAAC;AAAA;AAAA,OAOvC,OAAM,GAAoC;AAAA,IACrD,MAAM,SAAS,MAAM,KAAK,kBAAkB,OAAO;AAAA,IACnD,IAAI,QAAQ;AAAA,MACV,OAAO,OAAO,IACZ,CAAC,WACE;AAAA,QACC,KAAK,MAAM;AAAA,QACX,QAAQ,MAAM;AAAA,UACZ,IAAI,KAAK,0BAA0B,OAAO,MAAM,UAAU,UAAU;AAAA,YAClE,IAAI;AAAA,cACF,OAAO,KAAK,MAAM,MAAM,KAAK;AAAA,cAC7B,OAAO,GAAG;AAAA,cACV,OAAO,MAAM;AAAA;AAAA,UAEjB;AAAA,UACA,OAAO,MAAM;AAAA,WACZ;AAAA,MACL,EACJ;AAAA,IACF;AAAA;AAAA,OAMW,UAAS,GAAkB;AAAA,IACtC,OAAO,MAAM,KAAK,kBAAkB,UAAU;AAAA;AAAA,OAOnC,KAAI,GAAoB;AAAA,IACnC,OAAO,MAAM,KAAK,kBAAkB,KAAK;AAAA;AAAA,EAM3C,OAAO,GAAS;AAAA,IACd,KAAK,kBAAkB,QAAQ;AAAA;AAEnC;;;AF9IO,IAAM,uBAAuB,oBAClC,+BACF;AAAA;AAUO,MAAM,0BAA0B,oBAAoB;AAAA,EAClD;AAAA,EAQP,WAAW,CAAC,YAAwB,EAAE,MAAM,SAAS,GAAG,cAA0B,CAAC,GAAG;AAAA,IACpF,MAAM,WAAW,WAAW;AAAA,IAC5B,KAAK,oBAAoB,IAAI,uBAAuB,uBAAuB,kBAAkB;AAAA;AAEjG;;AGvBO,MAAM,mBAIiC;AAAA,EAEzB;AAAA,EACA;AAAA,EAFnB,WAAW,CACQ,aACA,OACjB;AAAA,IAFiB;AAAA,IACA;AAAA;AAAA,EAGnB,GAAG,CAAC,KAAU,OAA6B;AAAA,IACzC,OAAO,OAAO,2BAA2B,KAAK,aAAa,MAAM,KAAK,MAAM,IAAI,KAAK,KAAK,CAAC;AAAA;AAAA,EAE7F,OAAO,CAAC,OAAyD;AAAA,IAC/D,OAAO,OAAO,+BAA+B,KAAK,aAAa,MAAM,KAAK,MAAM,QAAQ,KAAK,CAAC;AAAA;AAAA,EAEhG,GAAG,CAAC,KAAsC;AAAA,IACxC,OAAO,OAAO,2BAA2B,KAAK,aAAa,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC;AAAA;AAAA,EAEtF,MAAM,CAAC,KAAyB;AAAA,IAC9B,OAAO,OAAO,8BAA8B,KAAK,aAAa,MAAM,KAAK,MAAM,OAAO,GAAG,CAAC;AAAA;AAAA,EAE5F,MAAM,GAAoC;AAAA,IACxC,OAAO,OAAO,8BAA8B,KAAK,aAAa,MAAM,KAAK,MAAM,OAAO,CAAC;AAAA;AAAA,EAEzF,SAAS,GAAkB;AAAA,IACzB,OAAO,OAAO,iCAAiC,KAAK,aAAa,MAAM,KAAK,MAAM,UAAU,CAAC;AAAA;AAAA,EAE/F,IAAI,GAAoB;AAAA,IACtB,OAAO,OAAO,4BAA4B,KAAK,aAAa,MAAM,KAAK,MAAM,KAAK,CAAC;AAAA;AAAA,EAErF,mBAAmB,CAAC,QAAoC;AAAA,IACtD,OAAO,KAAK,MAAM,oBAAoB,MAAM;AAAA;AAAA,EAI9C,EAA6B,CAAC,MAAa,IAAkD;AAAA,IAC3F,KAAK,MAAM,GAAG,MAAM,EAAE;AAAA;AAAA,EAExB,GAA8B,CAAC,MAAa,IAAkD;AAAA,IAC5F,KAAK,MAAM,IAAI,MAAM,EAAE;AAAA;AAAA,EAEzB,IAA+B,CAC7B,SACG,MACH;AAAA,IACA,KAAK,MAAM,KAAK,MAAM,GAAG,IAAI;AAAA;AAAA,EAE/B,IAA+B,CAAC,MAAa,IAAkD;AAAA,IAC7F,KAAK,MAAM,KAAK,MAAM,EAAE;AAAA;AAAA,EAE1B,MAAiC,CAC/B,MACyD;AAAA,IACzD,OAAO,KAAK,MAAM,OAAO,IAAI;AAAA;AAEjC;;AChEA;AAAA,wBACE;AAAA,kBACA;AAAA,eACA;AAAA,qBACA;AAAA;AAAA,WAEA;AAAA;;;ACNF,+BAAS;AAEF,IAAM,gBAAgB,oBAA4C,kBAAkB;AA4BpF,IAAM,YAAY;AAAA,EACvB,SAAS;AAAA,EACT,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,UAAU;AAAA,EACV,QAAQ;AAAA,EACR,UAAU;AACZ;;;ADbO,IAAM,0BAA0B,oBACrC,2BACF;AAAA;AAMO,MAAM,qBAA4E;AAAA,EAYrE;AAAA,EAVC;AAAA,EAEA,SAAS,IAAI;AAAA,EAOhC,WAAW,CACO,WAChB,SACA;AAAA,IAFgB;AAAA,IAGhB,KAAK,WAAW,CAAC;AAAA,IACjB,KAAK,eAAe,SAAS,gBAAgB,CAAC;AAAA;AAAA,EAIzC;AAAA,EAKC,eAAe,CAAC,KAAyE;AAAA,IAC/F,YAAY,KAAK,UAAU,OAAO,QAAQ,KAAK,YAAY,GAAG;AAAA,MAC5D,IAAI,IAAI,SAAS,OAAO;AAAA,QACtB,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,EAOD,YAAY,GAAqE;AAAA,IACvF,MAAM,MAAM,IAAI,KAAK,EAAE,YAAY;AAAA,IACnC,OAAO,KAAK,SACT,OAAO,CAAC,QAAQ,KAAK,gBAAgB,GAAG,CAAC,EACzC,OAAO,CAAC,QAAQ,IAAI,WAAW,UAAU,OAAO,EAChD,OAAO,CAAC,QAAQ,CAAC,IAAI,aAAa,IAAI,aAAa,GAAG,EACtD,KAAK,CAAC,GAAG,OAAO,EAAE,aAAa,IAAI,cAAc,EAAE,aAAa,EAAE,CAAC;AAAA;AAAA,OAO3D,IAAG,CAAC,KAAwD;AAAA,IACvE,MAAM,MAAM,CAAC;AAAA,IACb,MAAM,MAAM,IAAI,KAAK,EAAE,YAAY;AAAA,IACnC,MAAM,kBAAkB;AAAA,IACxB,gBAAgB,KAAK,gBAAgB,MAAM,OAAM;AAAA,IACjD,gBAAgB,aAAa,gBAAgB,cAAc,OAAM;AAAA,IACjE,gBAAgB,QAAQ,KAAK;AAAA,IAC7B,gBAAgB,cAAc,MAAM,iBAAgB,gBAAgB,KAAK;AAAA,IACzE,gBAAgB,SAAS,UAAU;AAAA,IACnC,gBAAgB,WAAW;AAAA,IAC3B,gBAAgB,mBAAmB;AAAA,IACnC,gBAAgB,mBAAmB;AAAA,IACnC,gBAAgB,aAAa;AAAA,IAC7B,gBAAgB,YAAY;AAAA,IAG5B,YAAY,KAAK,UAAU,OAAO,QAAQ,KAAK,YAAY,GAAG;AAAA,MAC5D,gBAAgB,OAAO;AAAA,IACzB;AAAA,IAEA,KAAK,SAAS,KAAK,eAAe;AAAA,IAClC,KAAK,OAAO,KAAK,UAAU,EAAE,MAAM,UAAU,KAAK,gBAAgB,CAAC;AAAA,IACnE,OAAO,gBAAgB;AAAA;AAAA,OAQZ,IAAG,CAAC,IAAmE;AAAA,IAClF,MAAM,MAAM,CAAC;AAAA,IACb,MAAM,MAAM,KAAK,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAAA,IACjD,IAAI,OAAO,KAAK,gBAAgB,GAAG,GAAG;AAAA,MACpC,OAAO;AAAA,IACT;AAAA,IACA;AAAA;AAAA,OASW,KAAI,CACf,SAAoB,UAAU,SAC9B,MAAc,KACmC;AAAA,IACjD,MAAM,MAAM,CAAC;AAAA,IACb,MAAM,OAAO,GAAG,KAAK;AAAA,IACrB,OAAO,KAAK,SACT,OAAO,CAAC,MAAM,KAAK,gBAAgB,CAAC,CAAC,EACrC,KAAK,CAAC,GAAG,OAAO,EAAE,aAAa,IAAI,cAAc,EAAE,aAAa,EAAE,CAAC,EACnE,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM,EACjC,MAAM,GAAG,GAAG;AAAA;AAAA,OASJ,KAAI,CAAC,UAAwE;AAAA,IACxF,MAAM,MAAM,CAAC;AAAA,IACb,MAAM,MAAM,KAAK,aAAa;AAAA,IAE9B,MAAM,MAAM,IAAI;AAAA,IAChB,IAAI,KAAK;AAAA,MACP,MAAM,SAAS,KAAK,IAAI;AAAA,MACxB,IAAI,SAAS,UAAU;AAAA,MACvB,IAAI,cAAc,IAAI,KAAK,EAAE,YAAY;AAAA,MACzC,IAAI,YAAY;AAAA,MAChB,KAAK,OAAO,KAAK,UAAU,EAAE,MAAM,UAAU,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,MACpE,OAAO;AAAA,IACT;AAAA;AAAA,OAQW,KAAI,CAAC,SAAS,UAAU,SAA0B;AAAA,IAC7D,MAAM,MAAM,CAAC;AAAA,IACb,OAAO,KAAK,SAAS,OAAO,CAAC,MAAM,KAAK,gBAAgB,CAAC,KAAK,EAAE,WAAW,MAAM,EAAE;AAAA;AAAA,OAUxE,aAAY,CACvB,IACA,UACA,SACA,SACe;AAAA,IACf,MAAM,MAAM,CAAC;AAAA,IACb,MAAM,MAAM,KAAK,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,KAAK,gBAAgB,CAAC,CAAC;AAAA,IAC5E,IAAI,CAAC,KAAK;AAAA,MAGR,MAAM,mBAAmB,KAAK,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AAAA,MAC9D,WAAU,EAAE,KAAK,qCAAqC;AAAA,QACpD;AAAA,QACA,QAAQ,mBAAmB,oBAAoB;AAAA,QAC/C,gBAAgB,kBAAkB;AAAA,QAClC,WAAW,KAAK;AAAA,QAChB,cAAc,KAAK;AAAA,MACrB,CAAC;AAAA,MACD;AAAA,IACF;AAAA,IAIA,IAAI,IAAI,WAAW,UAAU,aAAa,IAAI,WAAW,UAAU,QAAQ;AAAA,MACzE,WAAU,EAAE,KAAK,uDAAuD;AAAA,QACtE;AAAA,QACA,QAAQ,IAAI;AAAA,QACZ,aAAa,IAAI;AAAA,QACjB,OAAO,IAAI;AAAA,MACb,CAAC;AAAA,MACD;AAAA,IACF;AAAA,IAEA,MAAM,SAAS,KAAK,IAAI;AAAA,IACxB,IAAI,WAAW;AAAA,IACf,IAAI,mBAAmB;AAAA,IACvB,IAAI,mBAAmB;AAAA,IACvB,KAAK,OAAO,KAAK,UAAU,EAAE,MAAM,UAAU,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA;AAAA,OAUzD,SAAQ,CAAC,KAAsC;AAAA,IAC1D,MAAM,MAAM,CAAC;AAAA,IACb,MAAM,kBAAkB;AAAA,IACxB,MAAM,QAAQ,KAAK,SAAS,UAAU,CAAC,MAAM,EAAE,OAAO,IAAI,MAAM,KAAK,gBAAgB,CAAC,CAAC;AAAA,IACvF,IAAI,UAAU,IAAI;AAAA,MAChB,MAAM,WAAW,KAAK,SAAS;AAAA,MAC/B,MAAM,kBAAkB,UAAU,gBAAgB;AAAA,MAClD,gBAAgB,eAAe,kBAAkB;AAAA,MAEjD,YAAY,KAAK,UAAU,OAAO,QAAQ,KAAK,YAAY,GAAG;AAAA,QAC5D,gBAAgB,OAAO;AAAA,MACzB;AAAA,MACA,KAAK,SAAS,SAAS;AAAA,MACvB,KAAK,OAAO,KAAK,UAAU,EAAE,MAAM,UAAU,KAAK,UAAU,KAAK,gBAAgB,CAAC;AAAA,IACpF;AAAA;AAAA,OAOW,QAAO,CAAC,IAA4B;AAAA,IAC/C,MAAM,MAAM,CAAC;AAAA,IACb,MAAM,MAAM,KAAK,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,KAAK,gBAAgB,CAAC,CAAC;AAAA,IAC5E,IAAI,KAAK;AAAA,MACP,MAAM,SAAS,KAAK,IAAI;AAAA,MACxB,IAAI,SAAS,UAAU;AAAA,MACvB,IAAI,YAAY;AAAA,MAChB,IAAI,WAAW;AAAA,MACf,IAAI,mBAAmB;AAAA,MACvB,IAAI,mBAAmB;AAAA,MACvB,KAAK,OAAO,KAAK,UAAU,EAAE,MAAM,UAAU,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,IACtE;AAAA;AAAA,OAOW,MAAK,CAAC,IAA4B;AAAA,IAC7C,MAAM,MAAM,CAAC;AAAA,IACb,MAAM,MAAM,KAAK,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,KAAK,gBAAgB,CAAC,CAAC;AAAA,IAC5E,IAAI,KAAK;AAAA,MACP,MAAM,SAAS,KAAK,IAAI;AAAA,MACxB,IAAI,SAAS,UAAU;AAAA,MACvB,KAAK,OAAO,KAAK,UAAU,EAAE,MAAM,UAAU,KAAK,QAAQ,KAAK,IAAI,CAAC;AAAA,IACtE;AAAA;AAAA,OAQW,WAAU,CAAC,OAAgE;AAAA,IACtF,MAAM,MAAM,CAAC;AAAA,IACb,OAAO,KAAK,SAAS,OAAO,CAAC,QAAQ,KAAK,gBAAgB,GAAG,KAAK,IAAI,eAAe,KAAK;AAAA;AAAA,OAM/E,UAAS,GAAkB;AAAA,IACtC,MAAM,MAAM,CAAC;AAAA,IACb,MAAM,cAAc,KAAK,SAAS,OAAO,CAAC,QAAQ,KAAK,gBAAgB,GAAG,CAAC;AAAA,IAC3E,KAAK,WAAW,KAAK,SAAS,OAAO,CAAC,QAAQ,CAAC,KAAK,gBAAgB,GAAG,CAAC;AAAA,IACxE,WAAW,OAAO,aAAa;AAAA,MAC7B,KAAK,OAAO,KAAK,UAAU,EAAE,MAAM,UAAU,KAAK,IAAI,CAAC;AAAA,IACzD;AAAA;AAAA,OASW,eAAc,CAAC,OAAsC;AAAA,IAChE,MAAM,MAAM,CAAC;AAAA,IACb,MAAM,cAAc,MAAM,iBAAgB,KAAK;AAAA,IAC/C,OACE,KAAK,SAAS,KACZ,CAAC,MACC,KAAK,gBAAgB,CAAC,KACtB,EAAE,gBAAgB,eAClB,EAAE,WAAW,UAAU,SAC3B,GAAG,UAAU;AAAA;AAAA,OAOJ,OAAM,CAAC,IAA4B;AAAA,IAC9C,MAAM,MAAM,CAAC;AAAA,IACb,MAAM,aAAa,KAAK,SAAS,KAAK,CAAC,QAAQ,IAAI,OAAO,MAAM,KAAK,gBAAgB,GAAG,CAAC;AAAA,IACzF,KAAK,WAAW,KAAK,SAAS,OAAO,CAAC,QAAQ,EAAE,IAAI,OAAO,MAAM,KAAK,gBAAgB,GAAG,EAAE;AAAA,IAC3F,IAAI,YAAY;AAAA,MACd,KAAK,OAAO,KAAK,UAAU,EAAE,MAAM,UAAU,KAAK,WAAW,CAAC;AAAA,IAChE;AAAA;AAAA,OAQW,yBAAwB,CAAC,QAAmB,aAAoC;AAAA,IAC3F,MAAM,MAAM,CAAC;AAAA,IACb,MAAM,aAAa,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW,EAAE,YAAY;AAAA,IAClE,MAAM,cAAc,KAAK,SAAS,OAChC,CAAC,QACC,KAAK,gBAAgB,GAAG,KACxB,IAAI,WAAW,UACf,IAAI,gBACJ,IAAI,gBAAgB,UACxB;AAAA,IACA,KAAK,WAAW,KAAK,SAAS,OAC5B,CAAC,QACC,CAAC,KAAK,gBAAgB,GAAG,KACzB,IAAI,WAAW,UACf,CAAC,IAAI,gBACL,IAAI,eAAe,UACvB;AAAA,IACA,WAAW,OAAO,aAAa;AAAA,MAC7B,KAAK,OAAO,KAAK,UAAU,EAAE,MAAM,UAAU,KAAK,IAAI,CAAC;AAAA,IACzD;AAAA;AAAA,OAOW,cAAa,GAAkB;AAAA,EASpC,mBAAmB,CACzB,KACA,cACS;AAAA,IAET,IAAI,gBAAgB,OAAO,KAAK,YAAY,EAAE,WAAW,GAAG;AAAA,MAC1D,OAAO;AAAA,IACT;AAAA,IAGA,MAAM,eAAe,gBAAgB,KAAK;AAAA,IAG1C,IAAI,OAAO,KAAK,YAAY,EAAE,WAAW,GAAG;AAAA,MAC1C,OAAO;AAAA,IACT;AAAA,IAGA,MAAM,kBAAkB;AAAA,IACxB,YAAY,KAAK,UAAU,OAAO,QAAQ,YAAY,GAAG;AAAA,MACvD,IAAI,gBAAgB,SAAS,OAAO;AAAA,QAClC,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,EAWF,kBAAkB,CACvB,UACA,SACY;AAAA,IACZ,MAAM,eAAe,SAAS;AAAA,IAG9B,MAAM,mBAAmB,CAAC,WAA8C;AAAA,MAEtE,MAAM,aAAa,OAAO,MAAM,KAAK,oBAAoB,OAAO,KAAK,YAAY,IAAI;AAAA,MACrF,MAAM,aAAa,OAAO,MAAM,KAAK,oBAAoB,OAAO,KAAK,YAAY,IAAI;AAAA,MAErF,IAAI,CAAC,cAAc,CAAC,YAAY;AAAA,QAC9B;AAAA,MACF;AAAA,MAEA,SAAS,MAAM;AAAA;AAAA,IAGjB,OAAO,KAAK,OAAO,UAAU,UAAU,gBAAgB;AAAA;AAE3D;;AE5ZO,MAAM,sBAA6E;AAAA,EAErE;AAAA,EACA;AAAA,EAFnB,WAAW,CACQ,aACA,OACjB;AAAA,IAFiB;AAAA,IACA;AAAA;AAAA,EAGnB,GAAG,CAAC,KAAwD;AAAA,IAC1D,OAAO,OAAO,8BAA8B,KAAK,aAAa,MAAM,KAAK,MAAM,IAAI,GAAG,CAAC;AAAA;AAAA,EAEzF,GAAG,CAAC,IAAmE;AAAA,IACrE,OAAO,OAAO,8BAA8B,KAAK,aAAa,MAAM,KAAK,MAAM,IAAI,EAAE,CAAC;AAAA;AAAA,EAExF,IAAI,CAAC,UAAwE;AAAA,IAC3E,OAAO,OAAO,+BAA+B,KAAK,aAAa,MAAM,KAAK,MAAM,KAAK,QAAQ,CAAC;AAAA;AAAA,EAEhG,IAAI,CAAC,QAAoB,KAA+D;AAAA,IACtF,OAAO,OAAO,+BAA+B,KAAK,aAAa,MAC7D,KAAK,MAAM,KAAK,QAAQ,GAAG,CAC7B;AAAA;AAAA,EAEF,IAAI,CAAC,QAAqC;AAAA,IACxC,OAAO,OAAO,+BAA+B,KAAK,aAAa,MAAM,KAAK,MAAM,KAAK,MAAM,CAAC;AAAA;AAAA,EAE9F,QAAQ,CAAC,KAAqD;AAAA,IAC5D,OAAO,OAAO,mCAAmC,KAAK,aAAa,MACjE,KAAK,MAAM,SAAS,GAAG,CACzB;AAAA;AAAA,EAEF,OAAO,CAAC,IAA4B;AAAA,IAClC,OAAO,OAAO,kCAAkC,KAAK,aAAa,MAAM,KAAK,MAAM,QAAQ,EAAE,CAAC;AAAA;AAAA,EAEhG,SAAS,GAAkB;AAAA,IACzB,OAAO,OAAO,oCAAoC,KAAK,aAAa,MAClE,KAAK,MAAM,UAAU,CACvB;AAAA;AAAA,EAEF,cAAc,CAAC,OAAsC;AAAA,IACnD,OAAO,OAAO,yCAAyC,KAAK,aAAa,MACvE,KAAK,MAAM,eAAe,KAAK,CACjC;AAAA;AAAA,EAEF,KAAK,CAAC,IAA4B;AAAA,IAChC,OAAO,OAAO,gCAAgC,KAAK,aAAa,MAAM,KAAK,MAAM,MAAM,EAAE,CAAC;AAAA;AAAA,EAE5F,UAAU,CAAC,OAAgE;AAAA,IACzE,OAAO,OAAO,qCAAqC,KAAK,aAAa,MACnE,KAAK,MAAM,WAAW,KAAK,CAC7B;AAAA;AAAA,EAEF,YAAY,CACV,IACA,UACA,SACA,SACe;AAAA,IACf,OAAO,OAAO,uCAAuC,KAAK,aAAa,MACrE,KAAK,MAAM,aAAa,IAAI,UAAU,SAAS,OAAO,CACxD;AAAA;AAAA,EAEF,MAAM,CAAC,IAA4B;AAAA,IACjC,OAAO,OAAO,iCAAiC,KAAK,aAAa,MAAM,KAAK,MAAM,OAAO,EAAE,CAAC;AAAA;AAAA,EAE9F,wBAAwB,CAAC,QAAmB,aAAoC;AAAA,IAC9E,OAAO,OAAO,mDAAmD,KAAK,aAAa,MACjF,KAAK,MAAM,yBAAyB,QAAQ,WAAW,CACzD;AAAA;AAAA,EAEF,aAAa,GAAkB;AAAA,IAC7B,OAAO,KAAK,MAAM,cAAc;AAAA;AAAA,EAElC,kBAAkB,CAChB,UACA,SACY;AAAA,IACZ,OAAO,KAAK,MAAM,mBAAmB,UAAU,OAAO;AAAA;AAE1D;;ACzFA,+BAAS,+BAAoB;AAGtB,IAAM,iCAAiC,qBAC5C,8BACF;AAAA;AAcO,MAAM,2BAA0D;AAAA,EAElD;AAAA,EAGF,aAA4C,IAAI;AAAA,EAGhD,qBAAwC,IAAI;AAAA,EAE7D,WAAW,CAAC,SAAqC;AAAA,IAC/C,KAAK,eAAe,SAAS,gBAAgB,CAAC;AAAA;AAAA,EAMxC,OAAO,CAAC,WAA2B;AAAA,IACzC,MAAM,aAAa,OAAO,QAAQ,KAAK,YAAY,EAChD,KAAK,EAAE,KAAK,OAAO,EAAE,cAAc,CAAC,CAAC,EACrC,IAAI,EAAE,GAAG,OAAO,GAAG,KAAK,GAAG,EAC3B,KAAK,GAAG;AAAA,IACX,OAAO,aAAa,GAAG,cAAc,cAAc;AAAA;AAAA,OAGxC,cAAa,GAAkB;AAAA,OAI/B,gBAAe,CAAC,WAAkC;AAAA,IAC7D,MAAM,OAAM,CAAC;AAAA,IACb,MAAM,MAAM,KAAK,QAAQ,SAAS;AAAA,IAClC,MAAM,aAAa,KAAK,WAAW,IAAI,GAAG,KAAK,CAAC;AAAA,IAChD,WAAW,KAAK;AAAA,MACd;AAAA,MACA,YAAY,IAAI;AAAA,IAClB,CAAC;AAAA,IACD,KAAK,WAAW,IAAI,KAAK,UAAU;AAAA;AAAA,OAGxB,kBAAiB,CAAC,WAAmB,iBAA0C;AAAA,IAC1F,MAAM,OAAM,CAAC;AAAA,IACb,MAAM,MAAM,KAAK,QAAQ,SAAS;AAAA,IAClC,MAAM,aAAa,KAAK,WAAW,IAAI,GAAG,KAAK,CAAC;AAAA,IAChD,MAAM,cAAc,IAAI,KAAK,eAAe;AAAA,IAC5C,OAAO,WAAW,OAAO,CAAC,MAAM,EAAE,aAAa,WAAW,EAAE;AAAA;AAAA,OAGjD,2BAA0B,CACrC,WACA,QAC6B;AAAA,IAC7B,MAAM,OAAM,CAAC;AAAA,IACb,MAAM,MAAM,KAAK,QAAQ,SAAS;AAAA,IAClC,MAAM,aAAa,KAAK,WAAW,IAAI,GAAG,KAAK,CAAC;AAAA,IAChD,MAAM,SAAS,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,WAAW,QAAQ,IAAI,EAAE,WAAW,QAAQ,CAAC;AAAA,IAC7F,MAAM,YAAY,OAAO;AAAA,IACzB,OAAO,WAAW,WAAW,YAAY;AAAA;AAAA,OAG9B,qBAAoB,CAAC,WAAgD;AAAA,IAChF,MAAM,OAAM,CAAC;AAAA,IACb,MAAM,MAAM,KAAK,QAAQ,SAAS;AAAA,IAClC,MAAM,OAAO,KAAK,mBAAmB,IAAI,GAAG;AAAA,IAC5C,OAAO,MAAM,YAAY;AAAA;AAAA,OAGd,qBAAoB,CAAC,WAAmB,iBAAwC;AAAA,IAC3F,MAAM,OAAM,CAAC;AAAA,IACb,MAAM,MAAM,KAAK,QAAQ,SAAS;AAAA,IAClC,KAAK,mBAAmB,IAAI,KAAK,IAAI,KAAK,eAAe,CAAC;AAAA;AAAA,OAG/C,MAAK,CAAC,WAAkC;AAAA,IACnD,MAAM,OAAM,CAAC;AAAA,IACb,MAAM,MAAM,KAAK,QAAQ,SAAS;AAAA,IAClC,KAAK,WAAW,OAAO,GAAG;AAAA,IAC1B,KAAK,mBAAmB,OAAO,GAAG;AAAA;AAEtC;;AClGA,+BAAS;AAGF,IAAM,uBAAuB,qBAAwC,qBAAqB;;ACyD1F,MAAM,0BAAoD;AAAA,EAE9C,cAAc,IAAI;AAAA,EAG3B,iBAAiB,IAAI;AAAA,EAGrB,cAAc;AAAA,EAGd,UAAmC;AAAA,EAGnC,0BAAiE;AAAA,EAGxD;AAAA,EAGA;AAAA,EAGA;AAAA,EAGA;AAAA,EAGA;AAAA,EAWjB,WAAW,CACT,aACA,YACA,cACA,gBACA,SACA;AAAA,IACA,KAAK,aAAa;AAAA,IAClB,KAAK,eAAe;AAAA,IACpB,KAAK,iBAAiB;AAAA,IAEtB,KAAK,UAAU;AAAA,MACb,mBAAmB,SAAS,qBAAqB;AAAA,MACjD,yBAAyB,SAAS,2BAA2B;AAAA,MAC7D,qBAAqB,SAAS,uBAAuB;AAAA,MACrD,sBAAsB,SAAS,wBAAwB;AAAA,IACzD;AAAA,IAEA,KAAK,sBACH,KAAK,QAAQ,uBAAuB,OAAO,qBAAqB;AAAA,IAElE,IAAI,KAAK,qBAAqB;AAAA,MAC5B,KAAK,2BAA2B;AAAA,IAClC;AAAA;AAAA,EAMM,0BAA0B,GAAS;AAAA,IACzC,IAAI;AAAA,MACF,KAAK,UAAU,IAAI,iBAAiB,KAAK,QAAQ,oBAAoB;AAAA,MACrE,KAAK,QAAQ,YAAY,CAAC,UAA0C;AAAA,QAClE,KAAK,uBAAuB,MAAM,IAAI;AAAA;AAAA,MAExC,OAAO,OAAO;AAAA,MACd,QAAQ,MAAM,0CAA0C,KAAK;AAAA,MAC7D,KAAK,UAAU;AAAA;AAAA;AAAA,OAOL,uBAAsB,CAAC,SAA0C;AAAA,IAC7E,IAAI,QAAQ,SAAS,UAAU;AAAA,MAE7B,MAAM,KAAK,cAAc;AAAA,IAC3B;AAAA;AAAA,EAQF,iBAAiB,GAAS;AAAA,IAExB,KAAK,cAAc;AAAA,IAGnB,IAAI,KAAK,SAAS;AAAA,MAChB,IAAI;AAAA,QACF,KAAK,QAAQ,YAAY,EAAE,MAAM,SAAS,CAAqB;AAAA,QAC/D,OAAO,OAAO;AAAA,IAGlB;AAAA;AAAA,EAUF,SAAS,CACP,UACA,SACY;AAAA,IACZ,MAAM,WAAW,SAAS,cAAc,KAAK,QAAQ;AAAA,IACrD,MAAM,eAA4C;AAAA,MAChD;AAAA,MACA,YAAY;AAAA,IACd;AAAA,IAEA,MAAM,oBAAoB,KAAK,YAAY,SAAS;AAAA,IACpD,KAAK,YAAY,IAAI,YAAY;AAAA,IAEjC,IAAI,mBAAmB;AAAA,MAErB,IAAI,CAAC,KAAK,aAAa;AAAA,QACrB,KAAK,cAAc;AAAA,QAEd,KAAK,cAAc,YAAY;AAAA,MACtC,EAAO;AAAA,QAEL,KAAK,+BAA+B,YAAY;AAAA;AAAA,MAMlD,IAAI,KAAK,QAAQ,0BAA0B,GAAG;AAAA,QAC5C,KAAK,mBAAmB;AAAA,MAC1B;AAAA,IACF,EAAO;AAAA,MACL,KAAK,+BAA+B,YAAY;AAAA;AAAA,IAGlD,OAAO,MAAM;AAAA,MACX,KAAK,YAAY,OAAO,YAAY;AAAA,MAGpC,IAAI,KAAK,YAAY,SAAS,GAAG;AAAA,QAC/B,KAAK,kBAAkB;AAAA,MACzB;AAAA;AAAA;AAAA,OAOU,cAAa,CAAC,cAA0D;AAAA,IACpF,IAAI;AAAA,MACF,KAAK,iBAAiB,MAAM,KAAK,WAAW;AAAA,MAE5C,cAAc,SAAS,KAAK,gBAAgB;AAAA,QAC1C,MAAM,UAAU,KAAK,eAAe,OAAO,IAAI;AAAA,QAC/C,IAAI;AAAA,UACF,aAAa,SAAS,OAAO;AAAA,UAC7B,MAAM;AAAA,MAGV;AAAA,MACA,MAAM;AAAA;AAAA,EAQF,8BAA8B,CAAC,cAAiD;AAAA,IAEtF,cAAc,SAAS,KAAK,gBAAgB;AAAA,MAC1C,MAAM,UAAU,KAAK,eAAe,OAAO,IAAI;AAAA,MAC/C,IAAI;AAAA,QACF,aAAa,SAAS,OAAO;AAAA,QAC7B,MAAM;AAAA,IAGV;AAAA;AAAA,OAMY,cAAa,GAAkB;AAAA,IAC3C,IAAI,KAAK,YAAY,SAAS;AAAA,MAAG;AAAA,IAEjC,IAAI;AAAA,MACF,MAAM,eAAe,MAAM,KAAK,WAAW;AAAA,MAC3C,MAAM,UAA2B,CAAC;AAAA,MAGlC,YAAY,KAAK,SAAS,cAAc;AAAA,QACtC,MAAM,UAAU,KAAK,eAAe,IAAI,GAAG;AAAA,QAC3C,IAAI,CAAC,SAAS;AAAA,UACZ,QAAQ,KAAK,KAAK,eAAe,OAAO,IAAI,CAAC;AAAA,QAC/C,EAAO,SAAI,CAAC,KAAK,aAAa,SAAS,IAAI,GAAG;AAAA,UAC5C,QAAQ,KAAK,KAAK,eAAe,OAAO,SAAS,IAAI,CAAC;AAAA,QACxD;AAAA,MACF;AAAA,MAGA,YAAY,KAAK,SAAS,KAAK,gBAAgB;AAAA,QAC7C,IAAI,CAAC,aAAa,IAAI,GAAG,GAAG;AAAA,UAC1B,QAAQ,KAAK,KAAK,eAAe,OAAO,IAAI,CAAC;AAAA,QAC/C;AAAA,MACF;AAAA,MAGA,KAAK,iBAAiB;AAAA,MAGtB,WAAW,UAAU,SAAS;AAAA,QAC5B,WAAW,OAAO,KAAK,aAAa;AAAA,UAClC,IAAI;AAAA,YACF,IAAI,SAAS,MAAM;AAAA,YACnB,MAAM;AAAA,QAGV;AAAA,MACF;AAAA,MACA,MAAM;AAAA;AAAA,EAQF,kBAAkB,GAAS;AAAA,IACjC,IAAI,KAAK;AAAA,MAAyB;AAAA,IAElC,KAAK,0BAA0B,YAC7B,MAAM,KAAK,cAAc,GACzB,KAAK,QAAQ,uBACf;AAAA;AAAA,EAMM,iBAAiB,GAAS;AAAA,IAChC,IAAI,KAAK,yBAAyB;AAAA,MAChC,cAAc,KAAK,uBAAuB;AAAA,MAC1C,KAAK,0BAA0B;AAAA,IACjC;AAAA;AAAA,MAME,iBAAiB,GAAW;AAAA,IAC9B,OAAO,KAAK,YAAY;AAAA;AAAA,MAMtB,gBAAgB,GAAY;AAAA,IAC9B,OAAO,KAAK,YAAY,OAAO;AAAA;AAAA,MAM7B,wBAAwB,GAAY;AAAA,IACtC,OAAO,KAAK,YAAY;AAAA;AAAA,EAM1B,OAAO,GAAS;AAAA,IACd,KAAK,kBAAkB;AAAA,IACvB,IAAI,KAAK,SAAS;AAAA,MAChB,KAAK,QAAQ,MAAM;AAAA,MACnB,KAAK,UAAU;AAAA,IACjB;AAAA,IACA,KAAK,YAAY,MAAM;AAAA,IACvB,KAAK,eAAe,MAAM;AAAA,IAC1B,KAAK,cAAc;AAAA;AAEvB;;ACtSO,MAAM,2BAAqD;AAAA,EAE/C,YAAY,IAAI;AAAA,EASzB,iBAAiB,IAAI;AAAA,EAGrB,cAAc;AAAA,EAGd,eAAe;AAAA,EAGN;AAAA,EAGA;AAAA,EAGA;AAAA,EAGA;AAAA,EAUjB,WAAW,CACT,YACA,cACA,gBACA,SACA;AAAA,IACA,KAAK,aAAa;AAAA,IAClB,KAAK,eAAe;AAAA,IACpB,KAAK,iBAAiB;AAAA,IACtB,KAAK,oBAAoB,SAAS,qBAAqB;AAAA;AAAA,EAUzD,SAAS,CACP,UACA,SACY;AAAA,IACZ,MAAM,WAAW,SAAS,cAAc,KAAK;AAAA,IAC7C,MAAM,eAA4C;AAAA,MAChD;AAAA,MACA,YAAY;AAAA,IACd;AAAA,IAEA,IAAI,gBAAgB,KAAK,UAAU,IAAI,QAAQ;AAAA,IAC/C,IAAI,CAAC,eAAe;AAAA,MAElB,MAAM,cAAc,IAAI;AAAA,MACxB,MAAM,aAAa,YAAY,MAAM,KAAK,KAAK,WAAW,GAAG,QAAQ;AAAA,MAErE,gBAAgB,EAAE,YAAY,YAAY;AAAA,MAC1C,KAAK,UAAU,IAAI,UAAU,aAAa;AAAA,MAG1C,IAAI,CAAC,KAAK,aAAa;AAAA,QACrB,KAAK,cAAc;AAAA,QACnB,KAAK,eAAe;AAAA,QACpB,KAAK,YAAY,YAAY;AAAA,MAC/B,EAAO;AAAA,QAEL,KAAK,qBAAqB,YAAY;AAAA;AAAA,IAE1C,EAAO;AAAA,MAEL,KAAK,qBAAqB,YAAY;AAAA;AAAA,IAGxC,cAAc,YAAY,IAAI,YAAY;AAAA,IAE1C,OAAO,MAAM;AAAA,MACX,MAAM,QAAQ,KAAK,UAAU,IAAI,QAAQ;AAAA,MACzC,IAAI,OAAO;AAAA,QACT,MAAM,YAAY,OAAO,YAAY;AAAA,QAGrC,IAAI,MAAM,YAAY,SAAS,GAAG;AAAA,UAChC,cAAc,MAAM,UAAU;AAAA,UAC9B,KAAK,UAAU,OAAO,QAAQ;AAAA,QAChC;AAAA,MACF;AAAA;AAAA;AAAA,OAOU,YAAW,CAAC,iBAA6D;AAAA,IACrF,IAAI;AAAA,MACF,KAAK,iBAAiB,MAAM,KAAK,WAAW;AAAA,MAE5C,cAAc,SAAS,KAAK,gBAAgB;AAAA,QAC1C,MAAM,UAAU,KAAK,eAAe,OAAO,IAAI;AAAA,QAC/C,IAAI;AAAA,UACF,gBAAgB,SAAS,OAAO;AAAA,UAChC,MAAM;AAAA,MAGV;AAAA,MACA,MAAM,WAEN;AAAA,MACA,KAAK,eAAe;AAAA;AAAA;AAAA,EAOhB,oBAAoB,CAAC,cAAiD;AAAA,IAE5E,cAAc,SAAS,KAAK,gBAAgB;AAAA,MAC1C,MAAM,UAAU,KAAK,eAAe,OAAO,IAAI;AAAA,MAC/C,IAAI;AAAA,QACF,aAAa,SAAS,OAAO;AAAA,QAC7B,MAAM;AAAA,IAGV;AAAA;AAAA,OAMY,KAAI,CAAC,aAA8D;AAAA,IAC/E,IAAI,YAAY,SAAS;AAAA,MAAG;AAAA,IAE5B,IAAI,KAAK;AAAA,MAAc;AAAA,IAEvB,IAAI;AAAA,MACF,MAAM,eAAe,MAAM,KAAK,WAAW;AAAA,MAC3C,MAAM,UAA2B,CAAC;AAAA,MAGlC,YAAY,KAAK,SAAS,cAAc;AAAA,QACtC,MAAM,UAAU,KAAK,eAAe,IAAI,GAAG;AAAA,QAC3C,IAAI,CAAC,SAAS;AAAA,UACZ,QAAQ,KAAK,KAAK,eAAe,OAAO,IAAI,CAAC;AAAA,QAC/C,EAAO,SAAI,CAAC,KAAK,aAAa,SAAS,IAAI,GAAG;AAAA,UAC5C,QAAQ,KAAK,KAAK,eAAe,OAAO,SAAS,IAAI,CAAC;AAAA,QACxD;AAAA,MACF;AAAA,MAGA,YAAY,KAAK,SAAS,KAAK,gBAAgB;AAAA,QAC7C,IAAI,CAAC,aAAa,IAAI,GAAG,GAAG;AAAA,UAC1B,QAAQ,KAAK,KAAK,eAAe,OAAO,IAAI,CAAC;AAAA,QAC/C;AAAA,MACF;AAAA,MAGA,KAAK,iBAAiB;AAAA,MAGtB,WAAW,UAAU,SAAS;AAAA,QAC5B,WAAW,OAAO,aAAa;AAAA,UAC7B,IAAI;AAAA,YACF,IAAI,SAAS,MAAM;AAAA,YACnB,MAAM;AAAA,QAGV;AAAA,MACF;AAAA,MACA,MAAM;AAAA;AAAA,MAQN,iBAAiB,GAAW;AAAA,IAC9B,IAAI,QAAQ;AAAA,IACZ,WAAW,SAAS,KAAK,UAAU,OAAO,GAAG;AAAA,MAC3C,SAAS,MAAM,YAAY;AAAA,IAC7B;AAAA,IACA,OAAO;AAAA;AAAA,MAML,gBAAgB,GAAY;AAAA,IAC9B,OAAO,KAAK,UAAU,OAAO;AAAA;AAAA,EAM/B,OAAO,GAAS;AAAA,IACd,WAAW,SAAS,KAAK,UAAU,OAAO,GAAG;AAAA,MAC3C,cAAc,MAAM,UAAU;AAAA,IAChC;AAAA,IACA,KAAK,UAAU,MAAM;AAAA,IACrB,KAAK,eAAe,MAAM;AAAA,IAC1B,KAAK,cAAc;AAAA,IACnB,KAAK,eAAe;AAAA;AAExB;;ACrRA;;;ACiHO,SAAS,iBAAsD,CACpE,QACwC;AAAA,EACxC,YAAY,KAAK,UAAU,OAAO,QAAoB,OAAO,UAAU,GAAG;AAAA,IACxE,IACE,OAAO,UAAU,aACjB,MAAM,SAAS,YACd,MAAM,WAAW,gBAAgB,MAAM,QAAQ,WAAW,aAAa,IACxE;AAAA,MACA,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA;AAAA;AAMK,SAAS,mBAAwD,CACtE,QACwC;AAAA,EACxC,YAAY,KAAK,UAAU,OAAO,QAAoB,OAAO,UAAU,GAAG;AAAA,IACxE,IAAI,OAAO,UAAU,aAAa,MAAM,SAAS,YAAY,MAAM,WAAW,YAAY;AAAA,MACxF,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA;AAAA;;;ADnIF,SAAS,aAAuB,CAAC,UAAoB,QAAoC;AAAA,EACvF,YAAY,KAAK,UAAU,OAAO,QAAQ,MAAM,GAAG;AAAA,IACjD,IAAI,SAAS,SAA2B,OAAO;AAAA,MAC7C,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAMT,SAAS,aAAa,CAAC,MAAc,OAAuB;AAAA,EAC1D,MAAM,YAAY,KAAK,YAAY;AAAA,EACnC,MAAM,aAAa,MAAM,YAAY;AAAA,EACrC,MAAM,aAAa,WAAW,MAAM,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAAA,EACrE,IAAI,WAAW,WAAW,GAAG;AAAA,IAC3B,OAAO;AAAA,EACT;AAAA,EACA,IAAI,UAAU;AAAA,EACd,WAAW,QAAQ,YAAY;AAAA,IAC7B,IAAI,UAAU,SAAS,IAAI,GAAG;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO,UAAU,WAAW;AAAA;AAAA;AAYvB,MAAM,8BAMH,uBAEV;AAAA,EACU;AAAA,EACA;AAAA,EACA;AAAA,EAUR,WAAW,CACT,QACA,iBACA,UAAmF,CAAC,GACpF,YACA,cAAqC,cACrC;AAAA,IACA,MAAM,QAAQ,iBAAiB,OAAO;AAAA,IAEtC,KAAK,mBAAmB;AAAA,IAGxB,MAAM,aAAa,kBAAkB,MAAM;AAAA,IAC3C,IAAI,CAAC,YAAY;AAAA,MACf,MAAM,IAAI,MAAM,mEAAmE;AAAA,IACrF;AAAA,IACA,KAAK,qBAAqB;AAAA,IAC1B,KAAK,uBAAuB,oBAAoB,MAAM;AAAA;AAAA,EAOxD,mBAAmB,GAAW;AAAA,IAC5B,OAAO,KAAK;AAAA;AAAA,OAGR,iBAAgB,CACpB,OACA,UAAwD,CAAC,GACzD;AAAA,IACA,QAAQ,OAAO,IAAI,QAAQ,iBAAiB,MAAM;AAAA,IAClD,MAAM,UAA6C,CAAC;AAAA,IAEpD,MAAM,cAAe,MAAM,KAAK,OAAO,KAAM,CAAC;AAAA,IAE9C,WAAW,UAAU,aAAa;AAAA,MAChC,MAAM,SAAS,OAAO,KAAK;AAAA,MAC3B,MAAM,WAAW,KAAK,uBACjB,OAAO,KAAK,wBACZ,CAAC;AAAA,MAGN,IAAI,UAAU,CAAC,cAAc,UAAU,MAAM,GAAG;AAAA,QAC9C;AAAA,MACF;AAAA,MAGA,MAAM,QAAQ,iBAAiB,OAAO,MAAM;AAAA,MAG5C,IAAI,QAAQ,gBAAgB;AAAA,QAC1B;AAAA,MACF;AAAA,MAEA,QAAQ,KAAK;AAAA,WACR;AAAA,QACH;AAAA,MACF,CAA+B;AAAA,IACjC;AAAA,IAGA,QAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAAA,IACxC,MAAM,aAAa,QAAQ,MAAM,GAAG,IAAI;AAAA,IAExC,OAAO;AAAA;AAAA,OAGH,aAAY,CAAC,OAAmB,SAAuD;AAAA,IAC3F,QAAQ,OAAO,IAAI,QAAQ,iBAAiB,GAAG,WAAW,eAAe,QAAQ;AAAA,IAEjF,IAAI,CAAC,aAAa,UAAU,KAAK,EAAE,WAAW,GAAG;AAAA,MAE/C,OAAO,KAAK,iBAAiB,OAAO,EAAE,MAAM,QAAQ,eAAe,CAAC;AAAA,IACtE;AAAA,IAEA,MAAM,UAA6C,CAAC;AAAA,IACpD,MAAM,cAAe,MAAM,KAAK,OAAO,KAAM,CAAC;AAAA,IAE9C,WAAW,UAAU,aAAa;AAAA,MAEhC,MAAM,SAAS,OAAO,KAAK;AAAA,MAC3B,MAAM,WAAW,KAAK,uBACjB,OAAO,KAAK,wBACZ,CAAC;AAAA,MAGN,IAAI,UAAU,CAAC,cAAc,UAAU,MAAM,GAAG;AAAA,QAC9C;AAAA,MACF;AAAA,MAGA,MAAM,cAAc,iBAAiB,OAAO,MAAM;AAAA,MAGlD,MAAM,eAAe,OAAO,OAAO,YAAY,CAAC,CAAC,EAC9C,KAAK,GAAG,EACR,YAAY;AAAA,MACf,MAAM,YAAY,cAAc,cAAc,SAAS;AAAA,MAGvD,MAAM,gBAAgB,eAAe,eAAe,IAAI,gBAAgB;AAAA,MAGxE,IAAI,gBAAgB,gBAAgB;AAAA,QAClC;AAAA,MACF;AAAA,MAEA,QAAQ,KAAK;AAAA,WACR;AAAA,QACH,OAAO;AAAA,MACT,CAA+B;AAAA,IACjC;AAAA,IAGA,QAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAAA,IACxC,MAAM,aAAa,QAAQ,MAAM,GAAG,IAAI;AAAA,IAExC,OAAO;AAAA;AAEX;;AE/KO,MAAM,+BAUH,wBAEV;AAAA,EACmB;AAAA,EASjB,WAAW,CACT,aACA,OACA;AAAA,IACA,MAAM,aAAa,KAAK;AAAA,IACxB,KAAK,cAAc;AAAA;AAAA,EAGrB,mBAAmB,GAAW;AAAA,IAC5B,OAAO,KAAK,YAAY,oBAAoB;AAAA;AAAA,EAG9C,gBAAgB,CACd,OACA,SACyC;AAAA,IACzC,OAAO,OAAO,4CAA4C,KAAK,aAAa,MAC1E,KAAK,YAAY,iBAAiB,OAAO,OAAO,CAClD;AAAA;AAAA,EAGF,YAAY,CACV,OACA,SACyC;AAAA,IACzC,IAAI,CAAC,KAAK,YAAY,cAAc;AAAA,MAClC,MAAM,IAAI,MAAM,wEAAwE;AAAA,IAC1F;AAAA,IACA,OAAO,OAAO,wCAAwC,KAAK,aAAa,MACtE,KAAK,YAAY,aAAc,OAAO,OAAO,CAC/C;AAAA;AAEJ;;ACxEA;AAAA;AAkCO,MAAM,2BAAuD;AAAA,EAK/C;AAAA,EACA;AAAA,EAJF,WAAW,IAAI;AAAA,EAEhC,WAAW,CACQ,IACA,YACjB;AAAA,IAFiB;AAAA,IACA;AAAA,IAEjB,IAAI,CAAC,YAAY;AAAA,MACf,MAAM,IAAI,MAAM,6DAA6D;AAAA,IAC/E;AAAA;AAAA,OAGI,IAAG,CAAC,KAA0C;AAAA,IAClD,MAAM,MAAO,MAAM,KAAK,GAAG,IAAI,GAAG;AAAA,IAClC,IAAI,CAAC;AAAA,MAAK;AAAA,IAEV,IAAI,IAAI,aAAa,IAAI,KAAK,IAAI,SAAS,KAAK,IAAI,MAAQ;AAAA,MAC1D,MAAM,KAAK,GAAG,OAAO,GAAG;AAAA,MACxB;AAAA,IACF;AAAA,IAEA,OAAO,QAAQ,IAAI,WAAW,IAAI,IAAI,KAAK,YAAY,KAAK,QAAQ;AAAA;AAAA,OAGhE,IAAG,CAAC,KAAa,OAAe,SAA+C;AAAA,IACnF,MAAM,MAAM,IAAI;AAAA,IAChB,MAAM,WAAY,MAAM,KAAK,GAAG,IAAI,GAAG;AAAA,IAEvC,QAAQ,WAAW,OAAO,MAAM,QAAQ,OAAO,KAAK,YAAY,KAAK,QAAQ;AAAA,IAE7E,MAAM,SAA2B;AAAA,MAC/B;AAAA,MACA;AAAA,MACA,OAAO,SAAS,SAAS,UAAU;AAAA,MACnC,UAAU,SAAS,YAAY,UAAU;AAAA,MACzC,WAAW,UAAU,aAAa,IAAI,YAAY;AAAA,MAClD,WAAW,IAAI,YAAY;AAAA,MAC3B,WAAW,SAAS,YAAY,QAAQ,UAAU,YAAY,IAAI,UAAU;AAAA,IAC9E;AAAA,IAEA,MAAM,KAAK,GAAG,IAAI,KAAK,MAAM;AAAA;AAAA,OAGzB,OAAM,CAAC,KAA+B;AAAA,IAC1C,MAAM,SAAU,MAAM,KAAK,GAAG,IAAI,GAAG,MAAO;AAAA,IAC5C,IAAI,QAAQ;AAAA,MACV,MAAM,KAAK,GAAG,OAAO,GAAG;AAAA,IAC1B;AAAA,IACA,OAAO;AAAA;AAAA,OAGH,IAAG,CAAC,KAA+B;AAAA,IACvC,MAAM,MAAO,MAAM,KAAK,GAAG,IAAI,GAAG;AAAA,IAClC,IAAI,CAAC;AAAA,MAAK,OAAO;AAAA,IAEjB,IAAI,IAAI,aAAa,IAAI,KAAK,IAAI,SAAS,KAAK,IAAI,MAAQ;AAAA,MAC1D,MAAM,KAAK,GAAG,OAAO,GAAG;AAAA,MACxB,OAAO;AAAA,IACT;AAAA,IACA,OAAO;AAAA;AAAA,OAGH,KAAI,GAA+B;AAAA,IACvC,MAAM,MAAM,MAAM,KAAK,GAAG,OAAO;AAAA,IACjC,IAAI,CAAC;AAAA,MAAK,OAAO,CAAC;AAAA,IAElB,MAAM,MAAM,IAAI;AAAA,IAChB,MAAM,SAAmB,CAAC;AAAA,IAC1B,WAAW,SAAS,KAAK;AAAA,MACvB,IAAI,MAAM,MAAM,aAAa,IAAI,KAAK,MAAM,MAAM,SAAS,KAAK,KAAK;AAAA,QACnE,MAAM,KAAK,GAAG,OAAO,MAAM,GAAG;AAAA,QAC9B;AAAA,MACF;AAAA,MACA,OAAO,KAAK,MAAM,GAAG;AAAA,IACvB;AAAA,IACA,OAAO;AAAA;AAAA,OAGH,UAAS,GAAkB;AAAA,IAC/B,MAAM,KAAK,GAAG,UAAU;AAAA;AAE5B;;ACrFO,MAAM,6BAAyD;AAAA,EAGvC;AAAA,EAFrB;AAAA,EAER,WAAW,CAAkB,IAAiC;AAAA,IAAjC;AAAA;AAAA,MAKzB,UAAU,GAAY;AAAA,IACxB,OAAO,KAAK,UAAU;AAAA;AAAA,EASxB,MAAM,CAAC,YAA0B;AAAA,IAC/B,KAAK,QAAQ,IAAI,2BAA2B,KAAK,IAA+B,UAAU;AAAA;AAAA,EAO5F,IAAI,GAAS;AAAA,IACX,KAAK,QAAQ;AAAA;AAAA,OAGT,IAAG,CAAC,KAA0C;AAAA,IAClD,IAAI,CAAC,KAAK;AAAA,MAAO;AAAA,IACjB,OAAO,KAAK,MAAM,IAAI,GAAG;AAAA;AAAA,OAGrB,IAAG,CAAC,KAAa,OAAe,SAA+C;AAAA,IACnF,IAAI,CAAC,KAAK,OAAO;AAAA,MACf,MAAM,IAAI,MAAM,uEAAuE;AAAA,IACzF;AAAA,IACA,OAAO,KAAK,MAAM,IAAI,KAAK,OAAO,OAAO;AAAA;AAAA,OAGrC,OAAM,CAAC,KAA+B;AAAA,IAC1C,IAAI,CAAC,KAAK;AAAA,MAAO,OAAO;AAAA,IACxB,OAAO,KAAK,MAAM,OAAO,GAAG;AAAA;AAAA,OAGxB,IAAG,CAAC,KAA+B;AAAA,IACvC,IAAI,CAAC,KAAK;AAAA,MAAO,OAAO;AAAA,IACxB,OAAO,KAAK,MAAM,IAAI,GAAG;AAAA;AAAA,OAGrB,KAAI,GAA+B;AAAA,IACvC,IAAI,CAAC,KAAK;AAAA,MAAO,OAAO,CAAC;AAAA,IACzB,OAAO,KAAK,MAAM,KAAK;AAAA;AAAA,OAGnB,UAAS,GAAkB;AAAA,IAC/B,IAAI,CAAC,KAAK;AAAA,MAAO;AAAA,IACjB,OAAO,KAAK,MAAM,UAAU;AAAA;AAEhC;;AC7FA,+BAAS,mCAAoB,+BAAW,2BAAiB;;;ACIzD;AAuCA,IAAM,sBAAsB;AAK5B,eAAe,kBAAkB,CAC/B,IACA,WACA,UACe;AAAA,EACf,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,IACtC,IAAI;AAAA,MACF,MAAM,cAAc,GAAG,YAAY,qBAAqB,WAAW;AAAA,MACnE,MAAM,QAAQ,YAAY,YAAY,mBAAmB;AAAA,MACzD,MAAM,UAAU,MAAM,IAAI,KAAK,UAAU,UAAU,GAAG,SAAS;AAAA,MAE/D,QAAQ,YAAY,MAAM,QAAQ;AAAA,MAClC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,YAAY,UAAU,MAAM,OAAO,YAAY,KAAK;AAAA,MACpD,OAAO,KAAK;AAAA,MAEZ,QAAQ;AAAA;AAAA,GAEX;AAAA;AAMH,eAAe,kBAAkB,CAC/B,WACA,SACA,uBACsB;AAAA,EACtB,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,IACtC,MAAM,cAAc,UAAU,KAAK,WAAW,OAAO;AAAA,IAErD,YAAY,YAAY,CAAC,UAAU;AAAA,MACjC,MAAM,KAAM,MAAM,OAA4B;AAAA,MAG9C,GAAG,kBAAkB,MAAM;AAAA,QACzB,GAAG,MAAM;AAAA;AAAA,MAGX,QAAQ,EAAE;AAAA;AAAA,IAGZ,YAAY,kBAAkB,CAAC,UAAU;AAAA,MACvC,IAAI,uBAAuB;AAAA,QACzB,sBAAsB,KAAK;AAAA,MAC7B;AAAA;AAAA,IAGF,YAAY,UAAU,MAAM;AAAA,MAC1B,MAAM,QAAQ,YAAY;AAAA,MAE1B,IAAI,SAAS,MAAM,SAAS,gBAAgB;AAAA,QAC1C,OACE,IAAI,MACF,YAAY,gEAAgE,WAAW,YACzF,CACF;AAAA,MACF,EAAO;AAAA,QACL,OAAO,KAAK;AAAA;AAAA;AAAA,IAGhB,YAAY,YAAY,MAAM;AAAA,MAC5B,OACE,IAAI,MAAM,YAAY,iEAAiE,CACzF;AAAA;AAAA,GAEH;AAAA;AAMH,eAAe,oBAAoB,CAAC,WAAkC;AAAA,EACpE,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,IACtC,MAAM,gBAAgB,UAAU,eAAe,SAAS;AAAA,IAExD,cAAc,YAAY,MAAM,QAAQ;AAAA,IACxC,cAAc,UAAU,MAAM,OAAO,cAAc,KAAK;AAAA,IACxD,cAAc,YAAY,MAAM;AAAA,MAC9B,OACE,IAAI,MAAM,0BAA0B,sDAAsD,CAC5F;AAAA;AAAA,GAEH;AAAA;AAcH,SAAS,cAAc,CACrB,OACA,oBACA,iBACY;AAAA,EACZ,MAAM,OAAmB;AAAA,IACvB,cAAc,CAAC;AAAA,IACf,iBAAiB,CAAC;AAAA,IAClB,iBAAiB,CAAC;AAAA,IAClB,mBAAmB;AAAA,IACnB,4BAA4B;AAAA,EAC9B;AAAA,EAGA,MAAM,gBAAgB,MAAM;AAAA,EAC5B,MAAM,qBAAqB,MAAM,QAAQ,kBAAkB,IACvD,qBACA;AAAA,EACJ,MAAM,mBAAmB,MAAM,QAAQ,aAAa,IAAI,gBAAgB;AAAA,EAExE,IAAI,CAAC,UAAU,oBAAoB,gBAAgB,GAAG;AAAA,IACpD,KAAK,oBAAoB;AAAA,IACzB,KAAK,6BAA6B;AAAA,IAClC,OAAO;AAAA,EACT;AAAA,EAGA,MAAM,kBAAkB,IAAI;AAAA,EAC5B,SAAS,IAAI,EAAG,IAAI,MAAM,WAAW,QAAQ,KAAK;AAAA,IAChD,MAAM,YAAY,MAAM,WAAW;AAAA,IACnC,gBAAgB,IAAI,WAAW,MAAM,MAAM,SAAS,CAAC;AAAA,EACvD;AAAA,EAGA,WAAW,eAAe,iBAAiB;AAAA,IACzC,MAAM,cAAc,gBAAgB,IAAI,YAAY,IAAI;AAAA,IAExD,IAAI,CAAC,aAAa;AAAA,MAChB,KAAK,aAAa,KAAK,WAAW;AAAA,IACpC,EAAO;AAAA,MAEL,MAAM,kBAAkB,MAAM,QAAQ,YAAY,OAAO,IACrD,YAAY,UACZ,CAAC,YAAY,OAAO;AAAA,MACxB,MAAM,iBAAgB,MAAM,QAAQ,YAAY,OAAO,IACnD,YAAY,UACZ,CAAC,YAAY,OAAO;AAAA,MAExB,MAAM,iBAAiB,CAAC,UAAU,iBAAiB,cAAa;AAAA,MAChE,MAAM,gBAAgB,YAAY,YAAY,YAAY,SAAS,UAAU;AAAA,MAC7E,MAAM,oBACJ,YAAY,gBAAgB,YAAY,SAAS,cAAc;AAAA,MAEjE,IAAI,kBAAkB,iBAAiB,mBAAmB;AAAA,QACxD,KAAK,gBAAgB,KAAK,WAAW;AAAA,MACvC;AAAA,MAEA,gBAAgB,OAAO,YAAY,IAAI;AAAA;AAAA,EAE3C;AAAA,EAGA,KAAK,kBAAkB,MAAM,KAAK,gBAAgB,KAAK,CAAC;AAAA,EAExD,OAAO;AAAA;AAMT,eAAe,WAAW,CAAC,OAAuC;AAAA,EAChE,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,IACtC,MAAM,UAAU,MAAM,OAAO;AAAA,IAC7B,QAAQ,YAAY,MAAM,QAAQ,QAAQ,UAAU,CAAC,CAAC;AAAA,IACtD,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,GAC7C;AAAA;AAMH,eAAe,2BAA2B,CACxC,IACA,WACA,MACA,UAA4B,CAAC,GACP;AAAA,EACtB,MAAM,iBAAiB,GAAG;AAAA,EAC1B,MAAM,aAAa,iBAAiB;AAAA,EAEpC,GAAG,MAAM;AAAA,EAET,QAAQ,sBACN,aAAa,0BAA0B,qBAAqB,iBAC5D,CACF;AAAA,EAEA,OAAO,mBAAmB,WAAW,YAAY,CAAC,UAAiC;AAAA,IACjF,MAAM,cAAe,MAAM,OAA4B;AAAA,IACvD,MAAM,QAAQ,YAAY,YAAY,SAAS;AAAA,IAG/C,WAAW,aAAa,KAAK,iBAAiB;AAAA,MAC5C,QAAQ,sBAAsB,mBAAmB,aAAa,GAAG;AAAA,MACjE,MAAM,YAAY,SAAS;AAAA,IAC7B;AAAA,IAGA,WAAW,YAAY,KAAK,iBAAiB;AAAA,MAC3C,QAAQ,sBAAsB,mBAAmB,SAAS,QAAQ,GAAG;AAAA,MACrE,IAAI,MAAM,WAAW,SAAS,SAAS,IAAI,GAAG;AAAA,QAC5C,MAAM,YAAY,SAAS,IAAI;AAAA,MACjC;AAAA,MACA,MAAM,YAAY,SAAS,MAAM,SAAS,SAAS,SAAS,OAAO;AAAA,IACrE;AAAA,IAGA,WAAW,YAAY,KAAK,cAAc;AAAA,MACxC,QAAQ,sBAAsB,iBAAiB,SAAS,QAAQ,GAAG;AAAA,MACnE,MAAM,YAAY,SAAS,MAAM,SAAS,SAAS,SAAS,OAAO;AAAA,IACrE;AAAA,IAEA,QAAQ,sBAAsB,sBAAsB,CAAG;AAAA,GACxD;AAAA;AAOH,eAAe,2BAA2B,CACxC,IACA,WACA,YACA,iBACA,UAA4B,CAAC,GAC7B,gBAAyB,OACH;AAAA,EACtB,IAAI,CAAC,QAAQ,2BAA2B;AAAA,IACtC,MAAM,IAAI,MACR,sCAAsC,gCACpC,4FACA,+CACJ;AAAA,EACF;AAAA,EAEA,MAAM,iBAAiB,GAAG;AAAA,EAC1B,MAAM,aAAa,iBAAiB;AAAA,EAEpC,QAAQ,sBACN,uCAAuC,uCACvC,CACF;AAAA,EAGA,IAAI,eAAsB,CAAC;AAAA,EAC3B,IAAI;AAAA,IACF,MAAM,cAAc,GAAG,YAAY,WAAW,UAAU;AAAA,IACxD,MAAM,QAAQ,YAAY,YAAY,SAAS;AAAA,IAC/C,eAAe,MAAM,YAAY,KAAK;AAAA,IACtC,QAAQ,sBAAsB,QAAQ,aAAa,kBAAkB,GAAG;AAAA,IACxE,OAAO,KAAK;AAAA,IACZ,QAAQ,qBACN,kDAAkD,OAClD,GACF;AAAA;AAAA,EAGF,GAAG,MAAM;AAAA,EAGT,IAAI,QAAQ,mBAAmB,aAAa,SAAS,GAAG;AAAA,IACtD,QAAQ,sBAAsB,gBAAgB,aAAa,qBAAqB,GAAG;AAAA,IACnF,IAAI;AAAA,MACF,MAAM,cAAc,CAAC;AAAA,MACrB,SAAS,IAAI,EAAG,IAAI,aAAa,QAAQ,KAAK;AAAA,QAC5C,MAAM,SAAS,aAAa;AAAA,QAC5B,MAAM,oBAAoB,MAAM,QAAQ,gBAAgB,MAAM;AAAA,QAC9D,IAAI,sBAAsB,aAAa,sBAAsB,MAAM;AAAA,UACjE,YAAY,KAAK,iBAAiB;AAAA,QACpC;AAAA,QACA,IAAI,IAAI,QAAQ,GAAG;AAAA,UACjB,QAAQ,sBACN,eAAe,KAAK,aAAa,kBACjC,MAAO,IAAI,aAAa,SAAU,GACpC;AAAA,QACF;AAAA,MACF;AAAA,MACA,eAAe;AAAA,MACf,QAAQ,sBAAsB,4BAA4B,aAAa,kBAAkB,GAAG;AAAA,MAC5F,OAAO,KAAK;AAAA,MACZ,QAAQ,qBACN,+BAA+B,+BAC/B,GACF;AAAA,MACA,eAAe,CAAC;AAAA;AAAA,EAEpB;AAAA,EAGA,QAAQ,sBAAsB,8BAA8B,IAAI;AAAA,EAEhE,MAAM,QAAQ,MAAM,mBAAmB,WAAW,YAAY,CAAC,UAAiC;AAAA,IAC9F,MAAM,MAAM,MAAM,OAA4B;AAAA,IAG9C,IAAI,IAAG,iBAAiB,SAAS,SAAS,GAAG;AAAA,MAC3C,IAAG,kBAAkB,SAAS;AAAA,IAChC;AAAA,IAGA,MAAM,QAAQ,IAAG,kBAAkB,WAAW,EAAE,SAAS,YAAY,cAAc,CAAC;AAAA,IAGpF,WAAW,OAAO,iBAAiB;AAAA,MACjC,MAAM,YAAY,IAAI,MAAM,IAAI,SAAS,IAAI,OAAO;AAAA,IACtD;AAAA,IAGA,IAAI,aAAa,SAAS,GAAG;AAAA,MAC3B,QAAQ,sBAAsB,aAAa,aAAa,qBAAqB,GAAG;AAAA,MAEhF,WAAW,UAAU,cAAc;AAAA,QACjC,IAAI;AAAA,UACF,MAAM,IAAI,MAAM;AAAA,UAChB,OAAO,KAAK;AAAA,UACZ,QAAQ,qBAAqB,6BAA6B,OAAO,GAAY;AAAA;AAAA,MAEjF;AAAA,IACF;AAAA,GACD;AAAA,EAED,QAAQ,sBAAsB,kCAAkC,CAAG;AAAA,EAEnE,OAAO;AAAA;AAMT,eAAe,iBAAiB,CAC9B,WACA,YACA,iBACA,UAA4B,CAAC,GAC7B,gBAAyB,OACH;AAAA,EACtB,QAAQ,sBAAsB,0BAA0B,aAAa,CAAC;AAAA,EAGtE,IAAI;AAAA,IACF,MAAM,qBAAqB,SAAS;AAAA,IAEpC,MAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,IACtD,OAAO,KAAK;AAAA,EAId,MAAM,UAAU;AAAA,EAEhB,MAAM,KAAK,MAAM,mBAAmB,WAAW,SAAS,CAAC,UAAiC;AAAA,IACxF,MAAM,MAAM,MAAM,OAA4B;AAAA,IAG9C,IAAI,CAAC,IAAG,iBAAiB,SAAS,mBAAmB,GAAG;AAAA,MACtD,IAAG,kBAAkB,qBAAqB,EAAE,SAAS,YAAY,CAAC;AAAA,IACpE;AAAA,IAGA,MAAM,QAAQ,IAAG,kBAAkB,WAAW,EAAE,SAAS,YAAY,cAAc,CAAC;AAAA,IAGpF,WAAW,OAAO,iBAAiB;AAAA,MACjC,MAAM,YAAY,IAAI,MAAM,IAAI,SAAS,IAAI,OAAO;AAAA,IACtD;AAAA,GACD;AAAA,EAGD,MAAM,WAA2B;AAAA,IAC/B,SAAS,GAAG;AAAA,IACZ;AAAA,IACA,SAAS;AAAA,IACT,aAAa;AAAA,IACb,WAAW,KAAK,IAAI;AAAA,EACtB;AAAA,EAEA,MAAM,mBAAmB,IAAI,WAAW,QAAQ;AAAA,EAEhD,QAAQ,sBAAsB,iCAAiC,CAAG;AAAA,EAElE,OAAO;AAAA;AAOT,eAAsB,oBAAoB,CACxC,WACA,YACA,kBAA6C,CAAC,GAC9C,UAA4B,CAAC,GAC7B,gBAAyB,OACH;AAAA,EACtB,IAAI;AAAA,IAEF,IAAI;AAAA,IACJ,IAAI,iBAAiB;AAAA,IACrB,IAAI;AAAA,MAEF,KAAK,MAAM,mBAAmB,SAAS;AAAA,MAIvC,IAAI,GAAG,YAAY,KAAK,CAAC,GAAG,iBAAiB,SAAS,SAAS,GAAG;AAAA,QAChE,iBAAiB;AAAA,QACjB,GAAG,MAAM;AAAA,MACX;AAAA,MACA,OAAO,KAAU;AAAA,MAGjB,QAAQ,sBACN,YAAY,iEACZ,CACF;AAAA,MACA,OAAO,MAAM,kBACX,WACA,YACA,iBACA,SACA,aACF;AAAA;AAAA,IAMF,IAAI,gBAAgB;AAAA,MAClB,QAAQ,sBAAsB,0BAA0B,aAAa,CAAC;AAAA,MAEtE,IAAI;AAAA,QACF,MAAM,qBAAqB,SAAS;AAAA,QACpC,MAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,QACtD,OAAO,KAAK;AAAA,MAKd,KAAK,MAAM,mBAAmB,WAAW,GAAG,CAAC,UAAiC;AAAA,QAC5E,MAAM,MAAM,MAAM,OAA4B;AAAA,QAG9C,IAAI,CAAC,IAAG,iBAAiB,SAAS,mBAAmB,GAAG;AAAA,UACtD,IAAG,kBAAkB,qBAAqB,EAAE,SAAS,YAAY,CAAC;AAAA,QACpE;AAAA,QAGA,MAAM,SAAQ,IAAG,kBAAkB,WAAW,EAAE,SAAS,YAAY,cAAc,CAAC;AAAA,QAGpF,WAAW,OAAO,iBAAiB;AAAA,UACjC,OAAM,YAAY,IAAI,MAAM,IAAI,SAAS,IAAI,OAAO;AAAA,QACtD;AAAA,OACD;AAAA,MAGD,MAAM,YAA2B;AAAA,QAC/B,SAAS,GAAG;AAAA,QACZ;AAAA,QACA,SAAS;AAAA,QACT,aAAa;AAAA,QACb,WAAW,KAAK,IAAI;AAAA,MACtB;AAAA,MACA,MAAM,mBAAmB,IAAI,WAAW,SAAQ;AAAA,MAEhD,QAAQ,sBAAsB,iCAAiC,CAAG;AAAA,MAClE,OAAO;AAAA,IACT;AAAA,IAGA,IAAI,CAAC,GAAG,iBAAiB,SAAS,mBAAmB,GAAG;AAAA,MACtD,MAAM,iBAAiB,GAAG;AAAA,MAC1B,GAAG,MAAM;AAAA,MAET,KAAK,MAAM,mBACT,WACA,iBAAiB,GACjB,CAAC,UAAiC;AAAA,QAChC,MAAM,MAAM,MAAM,OAA4B;AAAA,QAC9C,IAAI,CAAC,IAAG,iBAAiB,SAAS,mBAAmB,GAAG;AAAA,UACtD,IAAG,kBAAkB,qBAAqB,EAAE,SAAS,YAAY,CAAC;AAAA,QACpE;AAAA,OAEJ;AAAA,IACF;AAAA,IAGA,IAAI,CAAC,GAAG,iBAAiB,SAAS,SAAS,GAAG;AAAA,MAE5C,QAAQ,sBAAsB,gBAAgB,yCAAyC,CAAC;AAAA,MACxF,GAAG,MAAM;AAAA,MACT,OAAO,MAAM,kBACX,WACA,YACA,iBACA,SACA,aACF;AAAA,IACF;AAAA,IAGA,MAAM,cAAc,GAAG,YAAY,WAAW,UAAU;AAAA,IACxD,MAAM,QAAQ,YAAY,YAAY,SAAS;AAAA,IAC/C,MAAM,OAAO,eAAe,OAAO,YAAY,eAAe;AAAA,IAE9D,MAAM,IAAI,QAAc,CAAC,YAAY;AAAA,MACnC,YAAY,aAAa,MAAM,QAAQ;AAAA,MACvC,YAAY,UAAU,MAAM,QAAQ;AAAA,KACrC;AAAA,IAGD,MAAM,iBACJ,KAAK,aAAa,SAAS,KAC3B,KAAK,gBAAgB,SAAS,KAC9B,KAAK,gBAAgB,SAAS,KAC9B,KAAK;AAAA,IAEP,IAAI,CAAC,gBAAgB;AAAA,MAEnB,QAAQ,sBAAsB,cAAc,2BAA2B,CAAG;AAAA,MAG1E,MAAM,YAA2B;AAAA,QAC/B,SAAS,GAAG;AAAA,QACZ;AAAA,QACA,SAAS;AAAA,QACT,WAAW,KAAK,IAAI;AAAA,MACtB;AAAA,MACA,MAAM,mBAAmB,IAAI,WAAW,SAAQ;AAAA,MAEhD,OAAO;AAAA,IACT;AAAA,IAGA,IAAI,KAAK,4BAA4B;AAAA,MACnC,QAAQ,sBACN,sDAAsD,aACtD,CACF;AAAA,MACA,KAAK,MAAM,4BACT,IACA,WACA,YACA,iBACA,SACA,aACF;AAAA,IACF,EAAO;AAAA,MACL,QAAQ,sBAAsB,wCAAwC,aAAa,CAAC;AAAA,MACpF,KAAK,MAAM,4BAA4B,IAAI,WAAW,MAAM,OAAO;AAAA;AAAA,IAIrE,MAAM,WAA2B;AAAA,MAC/B,SAAS,GAAG;AAAA,MACZ;AAAA,MACA,SAAS;AAAA,MACT,WAAW,KAAK,IAAI;AAAA,IACtB;AAAA,IACA,MAAM,mBAAmB,IAAI,WAAW,QAAQ;AAAA,IAEhD,OAAO;AAAA,IACP,OAAO,KAAK;AAAA,IACZ,QAAQ,qBAAqB,wBAAwB,cAAc,OAAO,GAAY;AAAA,IACtF,MAAM;AAAA;AAAA;AAOV,eAAsB,kBAAkB,CAAC,WAAkC;AAAA,EACzE,OAAO,qBAAqB,SAAS;AAAA;;;ADvlBhC,IAAM,yBAAyB,qBACpC,qCACF;AAiBA,SAAS,wBAA2B,CAAC,GAAM,GAAe;AAAA,EACxD,MAAM,KAAM,GAAgC;AAAA,EAC5C,MAAM,KAAM,GAAgC;AAAA,EAC5C,IAAI,OAAO,OAAO,YAAY,OAAO,OAAO,UAAU;AAAA,IACpD,OAAO,OAAO;AAAA,EAChB;AAAA,EACA,OAAO,WAAU,GAAG,CAAC;AAAA;AAAA;AAShB,MAAM,gCAWH,mBAAmF;AAAA,EAsClF;AAAA,EApCD;AAAA,EAEA,eAA4C;AAAA,EAE5C;AAAA,EAEA,gBAIG;AAAA,EAEM;AAAA,EAWT;AAAA,EAYR,WAAW,CACF,QAAgB,iBACvB,QACA,iBACA,UAAmF,CAAC,GACpF,mBAGI,CAAC,GACL,qBAA+C,cAC/C;AAAA,IACA,MAAM,QAAQ,iBAAiB,SAAS,kBAAkB;AAAA,IAVnD;AAAA,IAWP,KAAK,mBAAmB;AAAA,IACxB,KAAK,gBAAgB;AAAA,MACnB,qBAAqB,iBAAiB,uBAAuB;AAAA,MAC7D,yBAAyB,iBAAiB,2BAA2B;AAAA,IACvE;AAAA;AAAA,OAOY,MAAK,GAAyB;AAAA,IAC1C,IAAI,KAAK;AAAA,MAAI,OAAO,KAAK;AAAA,IACzB,MAAM,KAAK,cAAc;AAAA,IACzB,OAAO,KAAK;AAAA;AAAA,OAOQ,cAAa,GAAkB;AAAA,IACnD,IAAI,KAAK;AAAA,MAAI;AAAA,IACb,IAAI,KAAK,cAAc;AAAA,MACrB,MAAM,KAAK;AAAA,MACX;AAAA,IACF;AAAA,IAEA,KAAK,eAAe,KAAK,aAAa;AAAA,IACtC,IAAI;AAAA,MACF,KAAK,KAAK,MAAM,KAAK;AAAA,cACrB;AAAA,MACA,KAAK,eAAe;AAAA;AAAA;AAAA,OAOV,aAAY,GAAyB;AAAA,IACjD,MAAM,YAAY,MAAM,kBAAkB;AAAA,IAG1C,MAAM,kBAA6C,CAAC;AAAA,IAEpD,WAAW,QAAQ,KAAK,SAAS;AAAA,MAE/B,MAAM,UAAU;AAAA,MAEhB,IAAI,QAAQ,UAAU,UAAU,QAAQ;AAAA,QACtC,MAAM,aAAa,QAAQ,MAAM,CAAC,KAAK,QAAQ,QAAQ,UAAU,IAAI;AAAA,QACrE,IAAI;AAAA,UAAY;AAAA,MAClB;AAAA,MAGA,MAAM,cAAc,QAAQ,IAAI,CAAC,QAAQ,OAAO,GAAG,CAAC;AAAA,MACpD,MAAM,YAAY,YAAY,KAAK,GAAG;AAAA,MACtC,gBAAgB,KAAK;AAAA,QACnB,MAAM;AAAA,QACN,SAAS,YAAY,WAAW,IAAI,YAAY,KAAK;AAAA,QACrD,SAAS,EAAE,QAAQ,MAAM;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,aAAa,UAAU,WAAW,IAAI,UAAU,KAAK;AAAA,IAI3D,MAAM,mBACJ,KAAK,oBAAoB,KACzB,KAAK,6BAA6B,mBAClC,UAAU,WAAW;AAAA,IAGvB,OAAO,MAAM,qBACX,KAAK,OACL,YACA,iBACA,KAAK,kBACL,gBACF;AAAA;AAAA,EAUiB,gBAAgB,CACjC,YACA,UACiB;AAAA,IACjB,IAAI,aAAa,QAAQ;AAAA,MACvB,OAAO,OAAM;AAAA,IACf;AAAA,IAEA,MAAM,IAAI,MACR,wFAAwF,YAC1F;AAAA;AAAA,OASI,IAAG,CAAC,QAAqC;AAAA,IAC7C,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,IAAI,gBAAgB;AAAA,IAGpB,IAAI,KAAK,oBAAoB,KAAK,KAAK,sBAAsB;AAAA,MAC3D,MAAM,UAAU,OAAO,KAAK,oBAAoB;AAAA,MAChD,MAAM,sBAAuB,OAAmC;AAAA,MAChE,MAAM,iBAAiB,wBAAwB,aAAa,wBAAwB;AAAA,MAEpF,IAAI,KAAK,6BAA6B,QAAQ;AAAA,QAE5C,IAAI,iBAAiB;AAAA,QACrB,IAAI,KAAK,uBAAuB,SAAS;AAAA,UACvC,iBAAiB;AAAA,QACnB,EAAO,SAAI,KAAK,uBAAuB,UAAU;AAAA,UAC/C,IAAI,CAAC,gBAAgB;AAAA,YACnB,MAAM,IAAI,MACR,uBAAuB,0DACzB;AAAA,UACF;AAAA,UACA,iBAAiB;AAAA,QACnB,EAAO;AAAA,UAEL,iBAAiB,CAAC;AAAA;AAAA,QAGpB,IAAI,gBAAgB;AAAA,UAClB,MAAM,iBAAiB,KAAK,iBAAiB,SAAS,MAAM;AAAA,UAC5D,gBAAgB,KAAK,SAAS,UAAU,eAAe;AAAA,QACzD;AAAA,MACF,EAAO,SAAI,KAAK,6BAA6B,iBAAiB;AAAA,QAG5D,IAAI,KAAK,uBAAuB,YAAY,CAAC,gBAAgB;AAAA,UAC3D,MAAM,IAAI,MACR,uBAAuB,0DACzB;AAAA,QACF;AAAA,QAEA,IAAI,KAAK,uBAAuB,SAAS;AAAA,UACvC,SAAS,UAAU,MAAM,SAAS;AAAA,UAClC,gBAAgB;AAAA,QAClB;AAAA,MAEF;AAAA,IACF;AAAA,IAGA,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,cAAc,GAAG,YAAY,KAAK,OAAO,WAAW;AAAA,MAC1D,MAAM,QAAQ,YAAY,YAAY,KAAK,KAAK;AAAA,MAChD,MAAM,UAAU,MAAM,IAAI,aAAa;AAAA,MACvC,QAAQ,UAAU,MAAM;AAAA,QACtB,OAAO,QAAQ,KAAK;AAAA;AAAA,MAEtB,QAAQ,YAAY,MAAM;AAAA,QAExB,IACE,KAAK,oBAAoB,KACzB,KAAK,wBACL,KAAK,6BAA6B,iBAClC;AAAA,UACA,MAAM,UAAU,OAAO,KAAK,oBAAoB;AAAA,UAChD,IAAI,cAAc,aAA6B,WAAW;AAAA,YAExD,gBAAgB,KAAK,gBAAgB,UAAU,QAAQ,OAAO;AAAA,UAChE;AAAA,QACF;AAAA,QACA,KAAK,OAAO,KAAK,OAAO,aAAa;AAAA,QACrC,QAAQ,aAAa;AAAA;AAAA,MAEvB,YAAY,aAAa,MAAM;AAAA,QAE7B,KAAK,eAAe,kBAAkB;AAAA;AAAA,KAEzC;AAAA;AAAA,OASG,QAAO,CAAC,SAA0C;AAAA,IAEtD,OAAO,MAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,WAAW,KAAK,IAAI,MAAM,CAAC,CAAC;AAAA;AAAA,EAGjD,2BAA2B,CAAC,KAAiB;AAAA,IAC9D,OAAO,MACJ,4BAA4B,GAAG,EAC/B,IAAI,CAAC,UAAW,OAAO,UAAU,WAAW,MAAM,SAAS,IAAI,KAAM;AAAA;AAAA,EAGlE,aAAa,CAAC,KAAsB;AAAA,IAC1C,MAAM,OAAO,MACV,4BAA4B,GAAG,EAC/B,IAAI,CAAC,UAAW,OAAO,UAAU,WAAW,MAAM,SAAS,IAAI,KAAM;AAAA,IACxE,OAAO,KAAK,WAAW,IAAI,KAAK,KAAK;AAAA;AAAA,OASjC,IAAG,CAAC,KAA8C;AAAA,IACtD,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,cAAc,GAAG,YAAY,KAAK,OAAO,UAAU;AAAA,MACzD,MAAM,QAAQ,YAAY,YAAY,KAAK,KAAK;AAAA,MAChD,MAAM,UAAU,MAAM,IAAI,KAAK,cAAc,GAAG,CAAC;AAAA,MACjD,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,QAAQ,YAAY,MAAM;AAAA,QACxB,IAAI,CAAC,QAAQ,QAAQ;AAAA,UACnB,KAAK,OAAO,KAAK,OAAO,KAAK,SAAS;AAAA,UACtC,QAAQ,SAAS;AAAA,UACjB;AAAA,QACF;AAAA,QACA,KAAK,OAAO,KAAK,OAAO,KAAK,QAAQ,MAAM;AAAA,QAC3C,QAAQ,QAAQ,MAAM;AAAA;AAAA,KAEzB;AAAA;AAAA,OAQG,OAAM,CAAC,SAA+D;AAAA,IAC1E,KAAK,sBAAsB,OAAO;AAAA,IAClC,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,cAAc,GAAG,YAAY,KAAK,OAAO,UAAU;AAAA,IACzD,MAAM,QAAQ,YAAY,YAAY,KAAK,KAAK;AAAA,IAChD,MAAM,UAAU,MAAM,OAAO;AAAA,IAC7B,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,QAAQ,YAAY,MAAM;AAAA,QACxB,IAAI,SAAmB,QAAQ;AAAA,QAC/B,IAAI,OAAO,WAAW,GAAG;AAAA,UACvB,QAAQ,SAAS;AAAA,UACjB;AAAA,QACF;AAAA,QAEA,IAAI,SAAS,WAAW,QAAQ,QAAQ,SAAS,GAAG;AAAA,UAClD,OAAO,KAAK,CAAC,GAAG,MAAM;AAAA,YACpB,aAAa,QAAQ,eAAe,QAAQ,SAAU;AAAA,cACpD,MAAM,OAAO,EAAE;AAAA,cACf,MAAM,OAAO,EAAE;AAAA,cACf,IAAI,QAAQ,QAAQ,QAAQ;AAAA,gBAAM;AAAA,cAClC,IAAI,QAAQ;AAAA,gBAAM,OAAO,cAAc,QAAQ,KAAK;AAAA,cACpD,IAAI,QAAQ;AAAA,gBAAM,OAAO,cAAc,QAAQ,IAAI;AAAA,cACnD,IAAI,OAAO;AAAA,gBAAM,OAAO,cAAc,QAAQ,KAAK;AAAA,cACnD,IAAI,OAAO;AAAA,gBAAM,OAAO,cAAc,QAAQ,IAAI;AAAA,YACpD;AAAA,YACA,OAAO;AAAA,WACR;AAAA,QACH;AAAA,QAEA,IAAI,SAAS,WAAW,WAAW;AAAA,UACjC,SAAS,OAAO,MAAM,QAAQ,MAAM;AAAA,QACtC;AAAA,QAEA,IAAI,SAAS,UAAU,WAAW;AAAA,UAChC,SAAS,OAAO,MAAM,GAAG,QAAQ,KAAK;AAAA,QACxC;AAAA,QAEA,QAAQ,OAAO,SAAS,IAAI,SAAS,SAAS;AAAA;AAAA,KAEjD;AAAA;AAAA,OAOG,OAAM,CAAC,KAAgC;AAAA,IAC3C,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,cAAc,GAAG,YAAY,KAAK,OAAO,WAAW;AAAA,MAC1D,MAAM,QAAQ,YAAY,YAAY,KAAK,KAAK;AAAA,MAChD,MAAM,UAAU,MAAM,OAAO,KAAK,cAAc,GAAG,CAAC;AAAA,MACpD,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,QAAQ,YAAY,MAAM;AAAA,QACxB,KAAK,OAAO,KAAK,UAAU,GAAmB;AAAA,QAC9C,QAAQ;AAAA;AAAA,MAEV,YAAY,aAAa,MAAM;AAAA,QAE7B,KAAK,eAAe,kBAAkB;AAAA;AAAA,KAEzC;AAAA;AAAA,OAOG,UAAS,GAAkB;AAAA,IAC/B,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,cAAc,GAAG,YAAY,KAAK,OAAO,WAAW;AAAA,MAC1D,MAAM,QAAQ,YAAY,YAAY,KAAK,KAAK;AAAA,MAChD,MAAM,UAAU,MAAM,MAAM;AAAA,MAC5B,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,QAAQ,YAAY,MAAM;AAAA,QACxB,KAAK,OAAO,KAAK,UAAU;AAAA,QAC3B,QAAQ;AAAA;AAAA,MAEV,YAAY,aAAa,MAAM;AAAA,QAE7B,KAAK,eAAe,kBAAkB;AAAA;AAAA,KAEzC;AAAA;AAAA,OAOG,KAAI,GAAoB;AAAA,IAC5B,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,cAAc,GAAG,YAAY,KAAK,OAAO,UAAU;AAAA,MACzD,MAAM,QAAQ,YAAY,YAAY,KAAK,KAAK;AAAA,MAChD,MAAM,UAAU,MAAM,MAAM;AAAA,MAC5B,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,QAAQ,YAAY,MAAM,QAAQ,QAAQ,MAAM;AAAA,KACjD;AAAA;AAAA,EAUK,oBAAoB,GAA+B;AAAA,IACzD,IAAI,KAAK;AAAA,MAAmB,OAAO,KAAK;AAAA,IACxC,MAAM,WAAW,IAAI,IAAI,KAAK,OAAO,YAAY,CAAC,CAAC;AAAA,IACnD,KAAK,oBAAoB,KAAK,QAAQ,OAAO,CAAC,YAC5C,QAAQ,MAAM,CAAC,WAAW,SAAS,IAAI,OAAO,MAAM,CAAC,CAAC,CACxD;AAAA,IACA,OAAO,KAAK;AAAA;AAAA,EAcN,kBAAkB,CACxB,OACA,UAOY;AAAA,IACZ,MAAM,kBAAkB,OAAO,KAAK,QAAQ;AAAA,IAC5C,IAAI,gBAAgB,WAAW;AAAA,MAAG;AAAA,IAElC,IAAI;AAAA,IASJ,WAAW,gBAAgB,KAAK,qBAAqB,GAAG;AAAA,MACtD,MAAM,eAA0B,CAAC;AAAA,MACjC,WAAW,UAAU,cAAc;AAAA,QACjC,MAAM,QAAQ,KAAK,0BAA0B,UAAU,MAAM;AAAA,QAC7D,IAAI,UAAU;AAAA,UAAW;AAAA,QACzB,aAAa,KAAK,KAAK;AAAA,MACzB;AAAA,MAEA,IAAI,aAAa,WAAW;AAAA,QAAG;AAAA,MAE/B,MAAM,gBAAgB,aAAa,MAAM,GAAG,aAAa,MAAM;AAAA,MAC/D,MAAM,iBAAiB,gBAAgB,MAAM,CAAC,WAAW,cAAc,SAAS,MAAM,CAAC;AAAA,MAEvF,MAAM,SACJ,CAAC,QACA,kBAAkB,CAAC,KAAK,kBACxB,mBAAmB,KAAK,kBAAkB,aAAa,SAAS,KAAK,aAAa;AAAA,MAErF,IAAI,QAAQ;AAAA,QACV,OAAO;AAAA,UACL,WAAW,aAAa,IAAI,CAAC,WAAW,OAAO,MAAM,CAAC,EAAE,KAAK,GAAG;AAAA,UAChE;AAAA,UACA,WAAW,aAAa,WAAW,aAAa;AAAA,UAChD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,IAAI,CAAC;AAAA,MAAM;AAAA,IAEX,MAAM,QAAQ,KAAK,YACf,YAAY,KAAK,KAAK,aAAa,WAAW,IAAI,KAAK,aAAa,KAAK,KAAK,YAAY,IAC1F,YAAY,MAAM,KAAK,cAAc,CAAC,GAAG,KAAK,cAAc,CAAC,CAAC,CAAC;AAAA,IAEnE,OAAO;AAAA,MACL,QAAQ,MAAM,MAAM,KAAK,SAAS;AAAA,MAClC;AAAA,MACA,gBAAgB,KAAK;AAAA,IACvB;AAAA;AAAA,OAWa,MAAK,CAAC,UAAoD;AAAA,IACvE,IAAI,CAAC,YAAY,OAAO,KAAK,QAAQ,EAAE,WAAW,GAAG;AAAA,MACnD,OAAO,MAAM,KAAK,KAAK;AAAA,IACzB;AAAA,IAEA,KAAK,oBAAoB,QAAQ;AAAA,IACjC,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAE5B,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,cAAc,GAAG,YAAY,KAAK,OAAO,UAAU;AAAA,MACzD,MAAM,QAAQ,YAAY,YAAY,KAAK,KAAK;AAAA,MAChD,MAAM,OAAO,KAAK,mBAAmB,OAAO,QAAQ;AAAA,MAEpD,IAAI,MAAM,gBAAgB;AAAA,QACxB,MAAM,WAAU,KAAK,OAAO,MAAM,KAAK,KAAK;AAAA,QAC5C,SAAQ,UAAU,MAAM,OAAO,SAAQ,KAAK;AAAA,QAC5C,SAAQ,YAAY,MAAM,QAAQ,SAAQ,MAAM;AAAA,QAChD;AAAA,MACF;AAAA,MAEA,MAAM,SAAS,MAAM,UAAU;AAAA,MAC/B,MAAM,QAAQ,MAAM;AAAA,MACpB,IAAI,QAAQ;AAAA,MACZ,MAAM,UAAU,OAAO,WAAW,KAAK;AAAA,MACvC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,QAAQ,YAAY,MAAM;AAAA,QACxB,MAAM,SAAS,QAAQ;AAAA,QACvB,IAAI,CAAC,QAAQ;AAAA,UACX,QAAQ,KAAK;AAAA,UACb;AAAA,QACF;AAAA,QACA,IAAI,KAAK,gBAAgB,OAAO,OAAiB,QAAQ,GAAG;AAAA,UAC1D,SAAS;AAAA,QACX;AAAA,QACA,OAAO,SAAS;AAAA;AAAA,KAEnB;AAAA;AAAA,OASG,QAAO,CAAC,QAAgB,OAA8C;AAAA,IAC1E,IAAI,SAAS,GAAG;AAAA,MACd,MAAM,IAAI,WAAW,oCAAoC,QAAQ;AAAA,IACnE;AAAA,IACA,IAAI,SAAS,GAAG;AAAA,MACd;AAAA,IACF;AAAA,IAEA,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,cAAc,GAAG,YAAY,KAAK,OAAO,UAAU;AAAA,MACzD,MAAM,QAAQ,YAAY,YAAY,KAAK,KAAK;AAAA,MAChD,MAAM,UAAU,MAAM,WAAW;AAAA,MACjC,MAAM,WAAqB,CAAC;AAAA,MAC5B,IAAI,UAAU;AAAA,MAEd,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,QAAQ,YAAY,MAAM;AAAA,QACxB,MAAM,SAAS,QAAQ;AAAA,QACvB,IAAI,QAAQ;AAAA,UAEV,IAAI,CAAC,WAAW,SAAS,GAAG;AAAA,YAC1B,UAAU;AAAA,YACV,OAAO,QAAQ,MAAM;AAAA,YACrB;AAAA,UACF;AAAA,UAGA,SAAS,KAAK,OAAO,KAAK;AAAA,UAC1B,IAAI,SAAS,WAAW,OAAO;AAAA,YAC7B,QAAQ,QAAQ;AAAA,YAChB;AAAA,UACF;AAAA,UACA,OAAO,SAAS;AAAA,QAClB,EAAO;AAAA,UAEL,QAAQ,SAAS,SAAS,IAAI,WAAW,SAAS;AAAA;AAAA;AAAA,KAGvD;AAAA;AAAA,EASK,eAAe,CAAC,QAAgB,UAAiD;AAAA,IACvF,WAAW,UAAU,OAAO,KAAK,QAAQ,GAA0B;AAAA,MACjE,MAAM,YAAY,SAAS;AAAA,MAC3B,MAAM,cAAc,OAAO;AAAA,MAE3B,IAAI,WAA2B;AAAA,MAC/B,IAAI;AAAA,MAEJ,IAAI,kBAAkB,SAAS,GAAG;AAAA,QAChC,WAAW,UAAU;AAAA,QACrB,QAAQ,UAAU;AAAA,MACpB,EAAO;AAAA,QACL,QAAQ;AAAA;AAAA,MAIV,IAAI,aAAa,QAAQ,gBAAgB,QAAQ,gBAAgB,YAAY;AAAA,QAC3E,OAAO;AAAA,MACT;AAAA,MAEA,QAAQ;AAAA,aACD;AAAA,UACH,IAAI,gBAAgB;AAAA,YAAO,OAAO;AAAA,UAClC;AAAA,aACG;AAAA,UACH,IAAI,EAAE,cAAc;AAAA,YAAQ,OAAO;AAAA,UACnC;AAAA,aACG;AAAA,UACH,IAAI,EAAE,eAAe;AAAA,YAAQ,OAAO;AAAA,UACpC;AAAA,aACG;AAAA,UACH,IAAI,EAAE,cAAc;AAAA,YAAQ,OAAO;AAAA,UACnC;AAAA,aACG;AAAA,UACH,IAAI,EAAE,eAAe;AAAA,YAAQ,OAAO;AAAA,UACpC;AAAA;AAAA,UAEA,OAAO;AAAA;AAAA,IAEb;AAAA,IACA,OAAO;AAAA;AAAA,OASH,aAAY,CAAC,UAAuD;AAAA,IACxE,MAAM,eAAe,OAAO,KAAK,QAAQ;AAAA,IACzC,IAAI,aAAa,WAAW,GAAG;AAAA,MAC7B;AAAA,IACF;AAAA,IAEA,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAE5B,OAAO,IAAI,QAAQ,OAAO,SAAS,WAAW;AAAA,MAC5C,IAAI;AAAA,QACF,MAAM,cAAc,GAAG,YAAY,KAAK,OAAO,WAAW;AAAA,QAC1D,MAAM,QAAQ,YAAY,YAAY,KAAK,KAAK;AAAA,QAGhD,YAAY,aAAa,MAAM;AAAA,UAC7B,KAAK,OAAO,KAAK,UAAU,aAAa,EAAkB;AAAA,UAE1D,KAAK,eAAe,kBAAkB;AAAA,UACtC,QAAQ;AAAA;AAAA,QAGV,YAAY,UAAU,MAAM;AAAA,UAC1B,OAAO,YAAY,KAAK;AAAA;AAAA,QAI1B,MAAM,gBAAgB,MAAM,OAAO;AAAA,QAEnC,cAAc,YAAY,MAAM;AAAA,UAC9B,MAAM,aAAuB,cAAc;AAAA,UAG3C,MAAM,kBAAkB,WAAW,OAAO,CAAC,WACzC,KAAK,gBAAgB,QAAQ,QAAQ,CACvC;AAAA,UAEA,IAAI,gBAAgB,WAAW,GAAG;AAAA,YAEhC;AAAA,UACF;AAAA,UAGA,WAAW,UAAU,iBAAiB;AAAA,YAEpC,MAAM,aAAa,KAAK,kBAAkB,EAAE,OAAO,CAAC,KAAK,QAAQ;AAAA,cAE/D,IAAI,OAAO,OAAO;AAAA,cAClB,OAAO;AAAA,eACN,CAAC,CAAe;AAAA,YAGnB,MAAM,UAAU,MAAM,OAAO,KAAK,cAAc,UAAU,CAAC;AAAA,YAE3D,QAAQ,UAAU,MAAM;AAAA,cACtB,QAAQ,MAAM,0BAA0B,QAAQ,KAAK;AAAA;AAAA,UAEzD;AAAA;AAAA,QAGF,cAAc,UAAU,MAAM;AAAA,UAC5B,OAAO,cAAc,KAAK;AAAA;AAAA,QAE5B,OAAO,OAAO;AAAA,QACd,OAAO,KAAK;AAAA;AAAA,KAEf;AAAA;AAAA,EAGK,yBAAyB,CAC/B,UACA,QACkC;AAAA,IAClC,MAAM,YAAY,SAAS;AAAA,IAC3B,IAAI,cAAc;AAAA,MAAW;AAAA,IAC7B,IAAI,kBAAkB,SAAS,GAAG;AAAA,MAChC,OAAO,UAAU,aAAa,MAAO,UAAU,QAAiC;AAAA,IAClF;AAAA,IACA,OAAO;AAAA;AAAA,EAGD,cAAc,CAAC,GAAW,GAAW,SAAwC;AAAA,IACnF,IAAI,CAAC,SAAS;AAAA,MAAS,OAAO;AAAA,IAC9B,aAAa,QAAQ,eAAe,QAAQ,SAAS;AAAA,MACnD,MAAM,OAAO,EAAE;AAAA,MACf,MAAM,OAAO,EAAE;AAAA,MACf,IAAI,QAAQ,QAAQ,QAAQ;AAAA,QAAM;AAAA,MAClC,IAAI,QAAQ;AAAA,QAAM,OAAO,cAAc,QAAQ,KAAK;AAAA,MACpD,IAAI,QAAQ;AAAA,QAAM,OAAO,cAAc,QAAQ,IAAI;AAAA,MACnD,IAAI,OAAO;AAAA,QAAM,OAAO,cAAc,QAAQ,KAAK;AAAA,MACnD,IAAI,OAAO;AAAA,QAAM,OAAO,cAAc,QAAQ,IAAI;AAAA,IACpD;AAAA,IACA,OAAO;AAAA;AAAA,EAGD,kBAAkB,CACxB,OACA,UACA,SASA;AAAA,IACA,MAAM,UAAU,SAAS,WAAW,CAAC;AAAA,IACrC,IAAI;AAAA,IAUJ,WAAW,gBAAgB,KAAK,qBAAqB,GAAG;AAAA,MACtD,MAAM,eAA0B,CAAC;AAAA,MACjC,WAAW,UAAU,cAAc;AAAA,QACjC,MAAM,QAAQ,KAAK,0BAA0B,UAAU,MAAM;AAAA,QAC7D,IAAI,UAAU;AAAA,UAAW;AAAA,QACzB,aAAa,KAAK,KAAK;AAAA,MACzB;AAAA,MAEA,IAAI,aAAa,WAAW;AAAA,QAAG;AAAA,MAE/B,MAAM,mBAAmB,aAAa,MAAM,aAAa,MAAM;AAAA,MAC/D,IAAI,6BAA6B;AAAA,MACjC,OACE,6BAA6B,QAAQ,UACrC,6BAA6B,aAAa,UAC1C,QAAQ,6BAA6B,WAAW,aAAa,6BAC7D;AAAA,QACA;AAAA,MACF;AAAA,MACA,MAAM,oBAAoB,QAAQ,MAAM,0BAA0B;AAAA,MAClE,MAAM,iBACJ,kBAAkB,WAAW,KAC5B,kBAAkB,UAAU,iBAAiB,UAC5C,kBAAkB,MAAM,CAAC,OAAO,UAAU,MAAM,WAAW,iBAAiB,MAAM,KAClF,QAAQ,MAAM,CAAC,UAAU,MAAM,cAAc,QAAQ,IAAI,SAAS;AAAA,MAEtE,IAAI,CAAC,kBAAkB;AAAA,QAAM;AAAA,MAE7B,IACE,CAAC,QACA,kBAAkB,CAAC,KAAK,kBACzB,aAAa,SAAS,KAAK,aAAa,QACxC;AAAA,QACA,OAAO;AAAA,UACL,WAAW,aAAa,IAAI,CAAC,WAAW,OAAO,MAAM,CAAC,EAAE,KAAK,GAAG;AAAA,UAChE;AAAA,UACA,WAAW,aAAa,WAAW,aAAa;AAAA,UAChD;AAAA,UACA,WAAW,QAAQ,IAAI,cAAc,SAAS,SAAS;AAAA,QACzD;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,eAAe,QAAQ,MAAM,kBAAkB,SAAS,UAAU,SAAS;AAAA,IACjF,MAAM,gBAAgB,QAAQ,MAAM,kBAAkB,SAAS,WAAW,SAAS;AAAA,IAEnF,IAAI,CAAC,MAAM;AAAA,MACT,OAAO;AAAA,QACL,QAAQ;AAAA,QACR,OAAO;AAAA,QACP,WAAW,QAAQ,IAAI,cAAc,SAAS,SAAS;AAAA,QACvD,gBAAgB;AAAA,QAChB,cAAc;AAAA,QACd,eAAe;AAAA,QACf,eAAe;AAAA,MACjB;AAAA,IACF;AAAA,IAEA,MAAM,SAAS,MAAM,MAAM,KAAK,SAAS;AAAA,IAEzC,MAAM,WAAW,KAAK,YAClB,YAAY,KAAK,KAAK,aAAa,WAAW,IAAI,KAAK,aAAa,KAAK,KAAK,YAAY,IAC1F,YAAY,MAAM,KAAK,cAAc,CAAC,GAAG,KAAK,cAAc,CAAC,CAAC,CAAC;AAAA,IAEnE,OAAO;AAAA,MACL;AAAA,MACA,OAAO;AAAA,MACP,WAAW,KAAK;AAAA,MAChB,gBAAgB,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,MACA,eAAe,gBAAiB,SAAS,UAAU,IAAK;AAAA,IAC1D;AAAA;AAAA,OAUI,MAAK,CACT,UACA,SAC+B;AAAA,IAC/B,KAAK,oBAAoB,UAAU,OAAO;AAAA,IAC1C,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAE5B,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,cAAc,GAAG,YAAY,KAAK,OAAO,UAAU;AAAA,MACzD,MAAM,QAAQ,YAAY,YAAY,KAAK,KAAK;AAAA,MAChD,MAAM,eAAe,KAAK,mBAAmB,OAAO,UAAU,OAAO;AAAA,MACrE,MAAM,UAAoB,CAAC;AAAA,MAC3B,MAAM,UAAU,aAAa,OAAO,WAAW,aAAa,OAAO,aAAa,SAAS;AAAA,MAEzF,QAAQ,YAAY,MAAM;AAAA,QACxB,MAAM,SAAS,QAAQ;AAAA,QACvB,IAAI,CAAC,QAAQ;AAAA,UACX,IAAI,eAAe;AAAA,UAEnB,IAAI,CAAC,aAAa,kBAAkB,SAAS,WAAW,QAAQ,QAAQ,SAAS,GAAG;AAAA,YAClF,eAAe,CAAC,GAAG,YAAY,EAAE,KAAK,CAAC,GAAG,MAAM,KAAK,eAAe,GAAG,GAAG,OAAO,CAAC;AAAA,UACpF;AAAA,UAEA,IAAI,CAAC,aAAa,iBAAiB,SAAS,WAAW,WAAW;AAAA,YAChE,eAAe,aAAa,MAAM,QAAQ,MAAM;AAAA,UAClD;AAAA,UAEA,IAAI,CAAC,aAAa,gBAAgB,SAAS,UAAU,WAAW;AAAA,YAC9D,eAAe,aAAa,MAAM,GAAG,QAAQ,KAAK;AAAA,UACpD;AAAA,UAEA,MAAM,SAAS,aAAa,SAAS,IAAI,eAAe;AAAA,UACxD,KAAK,OAAO,KAAK,SAAS,UAA6B,MAAM;AAAA,UAC7D,QAAQ,MAAM;AAAA,UACd;AAAA,QACF;AAAA,QAEA,MAAM,SAAS,OAAO;AAAA,QACtB,IAAI,KAAK,gBAAgB,QAAQ,QAAQ,GAAG;AAAA,UAC1C,IAAI,aAAa,gBAAgB,GAAG;AAAA,YAClC,aAAa,iBAAiB;AAAA,UAChC,EAAO;AAAA,YACL,QAAQ,KAAK,MAAM;AAAA,YACnB,IAAI,aAAa,gBAAgB,QAAQ,WAAW,SAAS,OAAO;AAAA,cAClE,MAAM,SAAS,QAAQ,SAAS,IAAI,UAAU;AAAA,cAC9C,KAAK,OAAO,KAAK,SAAS,UAA6B,MAAM;AAAA,cAC7D,QAAQ,MAAM;AAAA,cACd;AAAA,YACF;AAAA;AAAA,QAEJ;AAAA,QAEA,OAAO,SAAS;AAAA;AAAA,MAGlB,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA;AAAA,OAWY,WAA2C,CACxD,UACA,SAC4B;AAAA,IAC5B,KAAK,eAAe,OAAO;AAAA,IAC3B,KAAK,oBAAoB,UAAU,OAAO;AAAA,IAE1C,MAAM,aAAa,KAAK,QAAQ,IAAI,CAAC,SAAS;AAAA,MAC5C,MAAM,KAAK,MAAM,QAAQ,IAAI,IAAK,OAAoB,CAAC,IAAc;AAAA,MACrE,OAAO,EAAE,MAAM,GAAG,KAAK,GAAG,GAAG,SAAS,GAAG;AAAA,KAC1C;AAAA,IAED,MAAM,SAAS,kBAAkB;AAAA,MAC/B,OAAO,KAAK;AAAA,MACZ,SAAS;AAAA,MACT,iBAAiB,OAAO,KAAK,QAAQ;AAAA,MACrC,iBAAiB,QAAQ,WAAW,CAAC,GAAG,IAAI,CAAC,OAAO;AAAA,QAClD,QAAQ,OAAO,EAAE,MAAM;AAAA,QACvB,WAAW,EAAE;AAAA,MACf,EAAE;AAAA,MACF,eAAe,QAAQ,OAAO,IAAI,MAAM;AAAA,MACxC,mBAAmB,KAAK,kBAAkB,EAAE,IAAI,MAAM;AAAA,IACxD,CAAC;AAAA,IAED,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,KAAK,GAAG,YAAY,KAAK,OAAO,UAAU;AAAA,MAChD,MAAM,QAAQ,GAAG,YAAY,KAAK,KAAK;AAAA,MACvC,MAAM,MAAM,MAAM,MAAM,OAAO,IAAI;AAAA,MAMnC,MAAM,SAAoB,CAAC;AAAA,MAC3B,WAAW,OAAO,OAAO,SAAS;AAAA,QAChC,MAAM,IAAK,SAAqC;AAAA,QAChD,IAAI,MAAM,aAAa,EAAE,OAAQ;AAAA,UAAuC;AAAA,QACxE,IAAI,kBAAkB,CAAC,GAAG;AAAA,UACxB,IAAI,EAAE,aAAa;AAAA,YAAK;AAAA,UACxB,OAAO,KAAK,EAAE,KAAK;AAAA,QACrB,EAAO;AAAA,UACL,OAAO,KAAK,CAAC;AAAA;AAAA,MAEjB;AAAA,MAGA,MAAM,QACJ,OAAO,WAAW,IACd,YACA,OAAO,WAAW,OAAO,QAAQ,SAC/B,YAAY,KAAK,OAAO,WAAW,IAAI,OAAO,KAAK,MAAM,IACzD,YAAY,MAAM,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC;AAAA,MAEjD,MAAM,YAAgC,OAAO,mBAAmB,SAAS;AAAA,MAEzE,MAAM,UAAU,IAAI,cAAc,OAAO,SAAS;AAAA,MAClD,MAAM,MAAyB,CAAC;AAAA,MAChC,IAAI,SAAS,QAAQ,UAAU;AAAA,MAG/B,MAAM,mBAAmB,IAAI;AAAA,MAC7B,OAAO,QAAQ,QAAQ,CAAC,KAAK,MAAM,iBAAiB,IAAI,KAAK,CAAC,CAAC;AAAA,MAE/D,MAAM,SAAS,KAAK,kBAAkB,EAAE,IAAI,MAAM;AAAA,MAClD,MAAM,cAAc,IAAI;AAAA,MACxB,OAAO,QAAQ,CAAC,KAAK,MAAM,YAAY,IAAI,KAAK,CAAC,CAAC;AAAA,MAElD,QAAQ,YAAY,MAAM;AAAA,QACxB,MAAM,SAAS,QAAQ;AAAA,QACvB,IAAI,CAAC,QAAQ;AAAA,UACX,QAAQ,GAAG;AAAA,UACX;AAAA,QACF;AAAA,QAEA,MAAM,MAAM,OAAO;AAAA,QAGnB,MAAM,MAAM,CAAC;AAAA,QACb,WAAW,OAAO,QAAQ,QAAQ;AAAA,UAChC,MAAM,SAAS,OAAO,GAAG;AAAA,UACzB,MAAM,MAAM,iBAAiB,IAAI,MAAM;AAAA,UACvC,IAAI,QAAQ,WAAW;AAAA,YAErB,IAAI,UAAU,MAAM,QAAQ,GAAG,IAAI,IAAI,OAAO;AAAA,UAChD,EAAO;AAAA,YAEL,IAAI,OAAO,WAAW,KAAK,WAAW,OAAO,IAAI;AAAA,cAC/C,IAAI,UAAU,OAAO;AAAA,YACvB,EAAO;AAAA,cACL,MAAM,QAAQ,YAAY,IAAI,MAAM;AAAA,cACpC,IAAI,UAAU,WAAW;AAAA,gBACvB,IAAI,UAAU,MAAM,QAAQ,OAAO,UAAU,IACxC,OAAO,WAAyB,SACjC,OAAO;AAAA,cACb;AAAA;AAAA;AAAA,QAGN;AAAA,QAGA,IAAI,UAAU;AAAA,QACd,YAAY,KAAK,SAAS,OAAO,QAAQ,QAAmC,GAAG;AAAA,UAC7E,IAAI,CAAC,kBAAkB,IAAI;AAAA,YAAG;AAAA,UAC9B,MAAM,MAAM,iBAAiB,IAAI,GAAG;AAAA,UACpC,IAAI,QAAQ;AAAA,YAAW;AAAA,UACvB,MAAM,aAAa,MAAM,QAAQ,GAAG,IAAK,IAAkB,OAAO;AAAA,UAClE,IAAI,CAAC,oBAAoB,YAAY,KAAK,UAAU,KAAK,KAAK,GAAG;AAAA,YAC/D,UAAU;AAAA,YACV;AAAA,UACF;AAAA,QACF;AAAA,QAEA,IAAI,SAAS;AAAA,UACX,IAAI,SAAS,GAAG;AAAA,YACd,UAAU;AAAA,UACZ,EAAO;AAAA,YACL,IAAI,KAAK,GAAsB;AAAA,YAC/B,IAAI,QAAQ,UAAU,aAAa,IAAI,UAAU,QAAQ,OAAO;AAAA,cAC9D,QAAQ,GAAG;AAAA,cACX;AAAA,YACF;AAAA;AAAA,QAEJ;AAAA,QAEA,OAAO,SAAS;AAAA;AAAA,MAGlB,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA;AAAA,EAOK,gBAAgB,GAItB;AAAA,IACA,IAAI,CAAC,KAAK,eAAe;AAAA,MAEvB,MAAM,cAAc,qBAAqB,KAAK;AAAA,MAE9C,KAAK,gBAAgB,IAAI,0BAKvB,aACA,YAAY;AAAA,QAEV,MAAM,WAAY,MAAM,KAAK,OAAO,KAAM,CAAC;AAAA,QAC3C,MAAM,MAAM,IAAI;AAAA,QAChB,WAAW,UAAU,UAAU;AAAA,UAC7B,QAAQ,QAAQ,KAAK,6BAA6B,MAAM;AAAA,UACxD,MAAM,cAAc,MAAM,iBAAgB,GAAG;AAAA,UAC7C,IAAI,IAAI,aAAa,MAAM;AAAA,QAC7B;AAAA,QACA,OAAO;AAAA,SAET,0BACA;AAAA,QACE,QAAQ,CAAC,UAAU,EAAE,MAAM,UAAmB,KAAK,KAAK;AAAA,QACxD,QAAQ,CAAC,SAAS,aAAa,EAAE,MAAM,UAAmB,KAAK,SAAS,KAAK,QAAQ;AAAA,QACrF,QAAQ,CAAC,UAAU,EAAE,MAAM,UAAmB,KAAK,KAAK;AAAA,MAC1D,GACA;AAAA,QACE,mBAAmB;AAAA,QACnB,qBAAqB,KAAK,cAAc;AAAA,QACxC,yBAAyB,KAAK,cAAc;AAAA,MAC9C,CACF;AAAA,IACF;AAAA,IACA,OAAO,KAAK;AAAA;AAAA,EAWE,kBAAkB,CAChC,UACA,SACY;AAAA,IAGZ,MAAM,aAAa,SAAS,qBAAqB;AAAA,IACjD,MAAM,UAAU,KAAK,iBAAiB;AAAA,IACtC,OAAO,QAAQ,UAAU,UAAU,EAAE,WAAW,CAAC;AAAA;AAAA,EAMnC,OAAO,GAAS;AAAA,IAC9B,IAAI,KAAK,eAAe;AAAA,MACtB,KAAK,cAAc,QAAQ;AAAA,MAC3B,KAAK,gBAAgB;AAAA,IACvB;AAAA,IACA,KAAK,IAAI,MAAM;AAAA;AAEnB;AAMA,SAAS,mBAAmB,CAAC,GAAY,IAAoB,GAAqB;AAAA,EAChF,MAAM,KAAK;AAAA,EACX,MAAM,KAAK;AAAA,EACX,QAAQ;AAAA,SACD;AAAA,MACH,OAAO,OAAO;AAAA,SACX;AAAA,MACH,OAAO,OAAO,QAAQ,OAAO,aAAa,KAAK;AAAA,SAC5C;AAAA,MACH,OAAO,OAAO,QAAQ,OAAO,aAAa,MAAM;AAAA,SAC7C;AAAA,MACH,OAAO,OAAO,QAAQ,OAAO,aAAa,KAAK;AAAA,SAC5C;AAAA,MACH,OAAO,OAAO,QAAQ,OAAO,aAAa,MAAM;AAAA;AAAA;;AE/qCtD,+BAAS;AAcF,IAAM,sCAAsC,qBACjD,0CACF;AAEA,IAAM,eAAe;AACrB,IAAM,uBAAuB;AAAA;AAsBtB,MAAM,qCAWH,mBAAmF;AAAA,EACnF,UAAmC;AAAA,EACnC;AAAA,EACA;AAAA,EACA,gBAAgB;AAAA,EAChB,iBAAiB;AAAA,EACjB,kBAAsC,CAAC;AAAA,EAW/C,WAAW,CACT,cAAsB,iBACtB,QACA,iBACA,UAAmF,CAAC,GACpF,qBAA+C,cAC/C;AAAA,IACA,MAAM,QAAQ,iBAAiB,SAAS,kBAAkB;AAAA,IAC1D,KAAK,cAAc;AAAA,IACnB,KAAK,eAAe,IAAI,uBACtB,QACA,iBACA,SACA,kBACF;AAAA,IAEA,KAAK,qBAAqB;AAAA,IAE1B,KAAK,2BAA2B;AAAA;AAAA,EAM1B,2BAA2B,GAAY;AAAA,IAC7C,OAAO,OAAO,qBAAqB;AAAA;AAAA,EAM7B,0BAA0B,GAAS;AAAA,IACzC,IAAI,CAAC,KAAK,4BAA4B,GAAG;AAAA,MACvC,QAAQ,KAAK,uEAAuE;AAAA,MACpF;AAAA,IACF;AAAA,IAEA,IAAI;AAAA,MACF,KAAK,UAAU,IAAI,iBAAiB,KAAK,WAAW;AAAA,MACpD,KAAK,QAAQ,YAAY,CAAC,UAA0C;AAAA,QAClE,KAAK,uBAAuB,MAAM,IAAI;AAAA;AAAA,MAIxC,KAAK,kBAAkB;AAAA,MACvB,OAAO,OAAO;AAAA,MACd,QAAQ,MAAM,0CAA0C,KAAK;AAAA;AAAA;AAAA,EAOzD,oBAAoB,GAAS;AAAA,IACnC,KAAK,aAAa,GAAG,OAAO,CAAC,WAAW;AAAA,MACtC,KAAK,OAAO,KAAK,OAAO,MAAM;AAAA,KAC/B;AAAA,IACD,KAAK,aAAa,GAAG,OAAO,CAAC,KAAK,WAAW;AAAA,MAC3C,KAAK,OAAO,KAAK,OAAO,KAAK,MAAM;AAAA,KACpC;AAAA,IACD,KAAK,aAAa,GAAG,SAAS,CAAC,KAAK,aAAa;AAAA,MAC/C,KAAK,OAAO,KAAK,SAAS,KAAK,QAAQ;AAAA,KACxC;AAAA,IACD,KAAK,aAAa,GAAG,UAAU,CAAC,QAAQ;AAAA,MACtC,KAAK,OAAO,KAAK,UAAU,GAAG;AAAA,KAC/B;AAAA,IACD,KAAK,aAAa,GAAG,YAAY,MAAM;AAAA,MACrC,KAAK,OAAO,KAAK,UAAU;AAAA,KAC5B;AAAA;AAAA,OAMW,uBAAsB,CAAC,SAA0C;AAAA,IAC7E,IAAI,KAAK,kBAAkB,QAAQ,SAAS,iBAAiB;AAAA,MAE3D,IAAI,KAAK,gBAAgB,SAAS,sBAAsB;AAAA,QACtD,KAAK,gBAAgB,KAAK,OAAO;AAAA,MACnC;AAAA,MACA;AAAA,IACF;AAAA,IAEA,QAAQ,QAAQ;AAAA,WACT;AAAA,QAEH,MAAM,MAAM,MAAM,KAAK,aAAa,OAAO;AAAA,QAC3C,IAAI,KAAK,WAAW,KAAK;AAAA,UACvB,KAAK,QAAQ,YAAY;AAAA,YACvB,MAAM;AAAA,YACN,MAAM;AAAA,UACR,CAAqB;AAAA,QACvB;AAAA,QACA;AAAA,WAEG;AAAA,QAEH,IAAI,QAAQ,QAAQ,MAAM,QAAQ,QAAQ,IAAI,GAAG;AAAA,UAC/C,MAAM,KAAK,kBAAkB,QAAQ,IAAI;AAAA,QAC3C;AAAA,QACA,KAAK,iBAAiB;AAAA,QACtB,MAAM,KAAK,qBAAqB;AAAA,QAChC;AAAA,WAEG;AAAA,QAEH,MAAM,KAAK,aAAa,IAAI,QAAQ,MAAM;AAAA,QAC1C;AAAA,WAEG;AAAA,QAEH,MAAM,KAAK,aAAa,QAAQ,QAAQ,QAAQ;AAAA,QAChD;AAAA,WAEG;AAAA,QAEH,MAAM,KAAK,aAAa,OAAO,QAAQ,GAAG;AAAA,QAC1C;AAAA,WAEG;AAAA,QAEH,MAAM,KAAK,aAAa,UAAU;AAAA,QAClC;AAAA,WAEG;AAAA,QAEH,MAAM,KAAK,aAAa,aAAa,QAAQ,QAAwC;AAAA,QACrF;AAAA;AAAA;AAAA,OASQ,qBAAoB,GAAkB;AAAA,IAClD,OAAO,CAAC,KAAK,kBAAkB,KAAK,gBAAgB,SAAS,GAAG;AAAA,MAC9D,MAAM,WAAW,KAAK;AAAA,MACtB,KAAK,kBAAkB,CAAC;AAAA,MACxB,WAAW,WAAW,UAAU;AAAA,QAC9B,MAAM,KAAK,uBAAuB,OAAO;AAAA,QACzC,IAAI,KAAK,gBAAgB;AAAA,UACvB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA;AAAA,EAMM,iBAAiB,GAAS;AAAA,IAChC,IAAI,CAAC,KAAK;AAAA,MAAS;AAAA,IAEnB,KAAK,iBAAiB;AAAA,IACtB,KAAK,QAAQ,YAAY,EAAE,MAAM,eAAe,CAAqB;AAAA,IAGrE,WAAW,MAAM;AAAA,MACf,IAAI,KAAK,gBAAgB;AAAA,QACvB,KAAK,iBAAiB;AAAA,QACjB,KAAK,qBAAqB,EAAE,MAAM,CAAC,UAAU;AAAA,UAChD,QAAQ,MAAM,uDAAuD,KAAK;AAAA,SAC3E;AAAA,MACH;AAAA,OACC,YAAY;AAAA;AAAA,OAMH,kBAAiB,CAAC,UAAmC;AAAA,IACjE,IAAI,SAAS,WAAW;AAAA,MAAG;AAAA,IAG3B,MAAM,KAAK,aAAa,UAAU;AAAA,IAGlC,MAAM,KAAK,aAAa,QAAQ,QAAQ;AAAA;AAAA,EAMlC,SAAS,CAAC,SAAiC;AAAA,IACjD,IAAI,KAAK,SAAS;AAAA,MAChB,KAAK,QAAQ,YAAY,OAAO;AAAA,IAClC;AAAA;AAAA,OAMoB,cAAa,GAAkB;AAAA,IACnD,IAAI,KAAK;AAAA,MAAe;AAAA,IACxB,KAAK,gBAAgB;AAAA,IACrB,MAAM,KAAK,kBAAkB;AAAA;AAAA,OASlB,IAAG,CAAC,OAAoC;AAAA,IACnD,MAAM,SAAS,MAAM,KAAK,aAAa,IAAI,KAAK;AAAA,IAChD,KAAK,UAAU,EAAE,MAAM,OAAO,QAAQ,OAAO,CAAC;AAAA,IAC9C,OAAO;AAAA;AAAA,OASI,QAAO,CAAC,QAAyC;AAAA,IAC5D,MAAM,SAAS,MAAM,KAAK,aAAa,QAAQ,MAAM;AAAA,IACrD,KAAK,UAAU,EAAE,MAAM,YAAY,UAAU,OAAO,CAAC;AAAA,IACrD,OAAO;AAAA;AAAA,OASH,IAAG,CAAC,KAA8C;AAAA,IACtD,OAAO,MAAM,KAAK,aAAa,IAAI,GAAG;AAAA;AAAA,OAQlC,OAAM,CAAC,OAA2C;AAAA,IACtD,MAAM,KAAK,aAAa,OAAO,KAAK;AAAA,IACpC,QAAQ,QAAQ,KAAK,6BAA6B,KAAe;AAAA,IACjE,KAAK,UAAU,EAAE,MAAM,UAAU,IAAI,CAAC;AAAA;AAAA,OAOlC,UAAS,GAAkB;AAAA,IAC/B,MAAM,KAAK,aAAa,UAAU;AAAA,IAClC,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAAA;AAAA,OAQjC,OAAM,CAAC,SAA+D;AAAA,IAC1E,OAAO,MAAM,KAAK,aAAa,OAAO,OAAO;AAAA;AAAA,OAOzC,KAAI,GAAoB;AAAA,IAC5B,OAAO,MAAM,KAAK,aAAa,KAAK;AAAA;AAAA,OAShC,QAAO,CAAC,QAAgB,OAA8C;AAAA,IAC1E,OAAO,MAAM,KAAK,aAAa,QAAQ,QAAQ,KAAK;AAAA;AAAA,OAUhD,MAAK,CACT,UACA,SAC+B;AAAA,IAC/B,OAAO,MAAM,KAAK,aAAa,MAAM,UAAU,OAAO;AAAA;AAAA,OASlD,aAAY,CAAC,UAAuD;AAAA,IACxE,MAAM,KAAK,aAAa,aAAa,QAAQ;AAAA,IAC7C,KAAK,UAAU;AAAA,MACb,MAAM;AAAA,MACN;AAAA,IACF,CAAC;AAAA;AAAA,EAYa,kBAAkB,CAChC,UACA,SACY;AAAA,IACZ,OAAO,KAAK,aAAa,mBAAmB,UAAU,OAAO;AAAA;AAAA,EAM/C,OAAO,GAAS;AAAA,IAC9B,IAAI,KAAK,SAAS;AAAA,MAChB,KAAK,QAAQ,MAAM;AAAA,MACnB,KAAK,UAAU;AAAA,IACjB;AAAA,IACA,KAAK,aAAa,QAAQ;AAAA;AAE9B;;ACpZA,+BAAS;;;ACsBF,MAAe,8BAWZ,mBAAmF;AAAA,EAiBtE;AAAA,EANJ,eAAe,IAAI;AAAA,EACnB,gBAAgB,IAAI;AAAA,EACpB,kBAAkB,IAAI;AAAA,EACtB,mBAAmB,IAAI;AAAA,EAExC,WAAW,CACU,QAAgB,iBACnC,QACA,iBACA,UAAmF,CAAC,GACpF,qBAA+C,cAC/C;AAAA,IACA,MAAM,QAAQ,iBAAiB,SAAS,kBAAkB;AAAA,IANvC;AAAA,IAOnB,KAAK,uBAAuB;AAAA;AAAA,EAapB,0BAA0B,CAAC,aAAqB,IAAY;AAAA,IACpE,IAAI,SAAS,KAAK,aAAa,IAAI,UAAU;AAAA,IAC7C,IAAI,WAAW,WAAW;AAAA,MACxB,SAAS,OAAO,QAAoB,KAAK,iBAAiB,UAAU,EACjE,IAAI,EAAE,KAAK,aAAa;AAAA,QACvB,MAAM,UAAU,KAAK,aAAa,OAAO;AAAA,QACzC,OAAO,GAAG,aAAa,MAAM,cAAc;AAAA,OAC5C,EACA,KAAK,IAAI;AAAA,MACZ,KAAK,aAAa,IAAI,YAAY,MAAM;AAAA,IAC1C;AAAA,IACA,OAAO;AAAA;AAAA,EAOC,qBAAqB,CAAC,aAAqB,IAAY;AAAA,IAC/D,IAAI,SAAS,KAAK,cAAc,IAAI,UAAU;AAAA,IAC9C,IAAI,WAAW,WAAW;AAAA,MACxB,MAAM,cAAc,IAAI,IAAI,KAAK,YAAY,YAAY,CAAC,CAAC;AAAA,MAC3D,MAAM,OAAO,OAAO,QAAoB,KAAK,YAAY,UAAU,EAChE,IAAI,EAAE,KAAK,aAAa;AAAA,QACvB,MAAM,UAAU,KAAK,aAAa,OAAO;AAAA,QACzC,MAAM,aAAa,YAAY,IAAI,GAAG;AAAA,QACtC,MAAM,WAAW,CAAC,cAAc,KAAK,WAAW,OAAO;AAAA,QACvD,OAAO,GAAG,aAAa,MAAM,cAAc,UAAU,WAAW,UAAU;AAAA,OAC3E,EACA,KAAK,IAAI;AAAA,MACZ,SAAS,KAAK,SAAS,IAAI,KAAK,SAAS;AAAA,MACzC,KAAK,cAAc,IAAI,YAAY,MAAM;AAAA,IAC3C;AAAA,IACA,OAAO;AAAA;AAAA,EAQC,UAAU,CAAC,SAA8B;AAAA,IACjD,IAAI,OAAO,YAAY;AAAA,MAAW,OAAO;AAAA,IAGzC,IAAI,QAAQ,SAAS,QAAQ;AAAA,MAC3B,OAAO;AAAA,IACT;AAAA,IAGA,IAAI,MAAM,QAAQ,QAAQ,IAAI,GAAG;AAAA,MAC/B,OAAO,QAAQ,KAAK,SAAS,MAAM;AAAA,IACrC;AAAA,IAGA,IAAI,QAAQ,SAAS,MAAM,QAAQ,QAAQ,KAAK,GAAG;AAAA,MACjD,OAAO,QAAQ,MAAM,KAAK,CAAC,SAAc,KAAK,SAAS,MAAM;AAAA,IAC/D;AAAA,IAGA,IAAI,QAAQ,SAAS,MAAM,QAAQ,QAAQ,KAAK,GAAG;AAAA,MACjD,OAAO,QAAQ,MAAM,KAAK,CAAC,SAAc,KAAK,SAAS,MAAM;AAAA,IAC/D;AAAA,IAEA,OAAO;AAAA;AAAA,EAOC,oBAAoB,CAAC,aAAqB,IAAY;AAAA,IAC9D,IAAI,SAAS,KAAK,gBAAgB,IAAI,UAAU;AAAA,IAChD,IAAI,WAAW,WAAW;AAAA,MACxB,SACE,aAAa,KAAK,kBAAkB,EAAE,KAAK,GAAG,eAAe,YAAY,IAAI;AAAA,MAC/E,KAAK,gBAAgB,IAAI,YAAY,MAAM;AAAA,IAC7C;AAAA,IACA,OAAO;AAAA;AAAA,EAOC,eAAe,CAAC,aAAqB,IAAY;AAAA,IACzD,IAAI,SAAS,KAAK,iBAAiB,IAAI,UAAU;AAAA,IACjD,IAAI,WAAW,WAAW;AAAA,MACxB,SAAS,aAAa,KAAK,aAAa,EAAE,KAAK,GAAG,eAAe,YAAY,IAAI;AAAA,MACjF,KAAK,iBAAiB,IAAI,YAAY,MAAM;AAAA,IAC9C;AAAA,IACA,OAAO;AAAA;AAAA,EASC,cAAc,CAAC,SAAiC;AAAA,IACxD,IAAI,OAAO,YAAY;AAAA,MAAW,OAAO;AAAA,IAEzC,IAAI,QAAQ,SAAS,MAAM,QAAQ,QAAQ,KAAK,GAAG;AAAA,MACjD,MAAM,cAAc,QAAQ,MAAM,KAAK,CAAC,MAAW,EAAE,SAAS,MAAM;AAAA,MACpE,IAAI,aAAa;AAAA,QACf,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,IAAI,QAAQ,SAAS,MAAM,QAAQ,QAAQ,KAAK,GAAG;AAAA,MACjD,MAAM,cAAc,QAAQ,MAAM,KAAK,CAAC,MAAW,EAAE,SAAS,MAAM;AAAA,MACpE,IAAI,aAAa;AAAA,QACf,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,EAUC,sBAAsB,CAAC,OAAiC;AAAA,IAChE,MAAM,gBAAmC,CAAC;AAAA,IAC1C,MAAM,gBAAgB;AAAA,IACtB,MAAM,cAAc,IAAI,IAAI,KAAK,YAAY,YAAY,CAAC,CAAC;AAAA,IAC3D,WAAW,OAAO,KAAK,YAAY,YAAY;AAAA,MAC7C,IAAI,OAAO,UAAU,eAAe,KAAK,eAAe,GAAG,GAAG;AAAA,QAC5D,MAAM,MAAM,cAAc;AAAA,QAE1B,IAAI,QAAQ,aAAa,CAAC,YAAY,IAAI,GAAG,GAAG;AAAA,UAC9C,cAAc,KAAK,IAAI;AAAA,QACzB,EAAO;AAAA,UACL,cAAc,KAAK,KAAK,aAAa,KAAK,GAAG,CAAC;AAAA;AAAA,MAElD,EAAO;AAAA,QAEL,IAAI,YAAY,IAAI,GAAG,GAAG;AAAA,UACxB,MAAM,IAAI,MAAM,iCAAiC,KAAK;AAAA,QACxD;AAAA,QAEA,cAAc,KAAK,IAAI;AAAA;AAAA,IAE3B;AAAA,IACA,OAAO;AAAA;AAAA,EASU,2BAA2B,CAAC,KAAoC;AAAA,IACjF,MAAM,gBAAmC,CAAC;AAAA,IAC1C,MAAM,SAAS;AAAA,IACf,WAAW,KAAK,OAAO,KAAK,KAAK,iBAAiB,UAAU,GAAG;AAAA,MAC7D,IAAI,KAAK,QAAQ;AAAA,QACf,MAAM,QAAQ,OAAO;AAAA,QACrB,IAAI,UAAU,MAAM;AAAA,UAClB,MAAM,IAAI,MAAM,qBAAqB,kBAAkB;AAAA,QACzD;AAAA,QACA,cAAc,KAAK,KAAK,aAAa,GAAG,KAAK,CAAC;AAAA,MAChD,EAAO;AAAA,QACL,MAAM,IAAI,MAAM,uCAAuC,GAAG;AAAA;AAAA,IAE9D;AAAA,IACA,OAAO;AAAA;AAAA,EAGC,YAAY,CAAC,QAAgB,OAA8C;AAAA,IACnF,MAAM,UAAU,KAAK,OAAO,WAAW;AAAA,IACvC,IAAI,CAAC,SAAS;AAAA,MACZ,OAAO;AAAA,IACT;AAAA,IAGA,IAAI,UAAU,QAAQ,KAAK,WAAW,OAAO,GAAG;AAAA,MAC9C,OAAO;AAAA,IACT;AAAA,IAGA,MAAM,aAAa,KAAK,eAAe,OAAO;AAAA,IAC9C,IAAI,OAAO,eAAe,WAAW;AAAA,MACnC,OAAO;AAAA,IACT;AAAA,IAEA,IAAI,WAAW,oBAAoB,QAAQ;AAAA,MACzC,IAAI,iBAAiB,YAAY;AAAA,QAC/B,OAAO;AAAA,MACT;AAAA,MACA,IAAI,OAAO,WAAW,eAAe,iBAAiB,QAAQ;AAAA,QAC5D,OAAO,IAAI,WAAW,KAAK;AAAA,MAC7B;AAAA,MACA,IAAI,MAAM,QAAQ,KAAK,GAAG;AAAA,QACxB,OAAO,IAAI,WAAW,KAAK;AAAA,MAC7B;AAAA,MACA,OAAO;AAAA,IACT,EAAO,SAAI,iBAAiB,MAAM;AAAA,MAEhC,OAAO,MAAM,YAAY;AAAA,IAC3B,EAAO;AAAA,MACL,OAAO;AAAA;AAAA;AAAA,EAID,YAAY,CAAC,QAAgB,OAA8C;AAAA,IAEnF,MAAM,UAAU,KAAK,OAAO,WAAW;AAAA,IACvC,IAAI,CAAC,SAAS;AAAA,MACZ,OAAO;AAAA,IACT;AAAA,IAGA,IAAI,UAAU,QAAQ,KAAK,WAAW,OAAO,GAAG;AAAA,MAC9C,OAAO;AAAA,IACT;AAAA,IAGA,MAAM,aAAa,KAAK,eAAe,OAAO;AAAA,IAC9C,IAAI,OAAO,eAAe,WAAW;AAAA,MACnC,OAAO;AAAA,IACT;AAAA,IAEA,IAAI,WAAW,oBAAoB,QAAQ;AAAA,MACzC,IAAI,OAAO,WAAW,eAAe,iBAAiB,QAAQ;AAAA,QAC5D,OAAO,IAAI,WAAW,KAAK;AAAA,MAC7B;AAAA,MACA,IAAI,iBAAiB,YAAY;AAAA,QAC/B,OAAO;AAAA,MACT;AAAA,MACA,OAAO;AAAA,IACT,EAAO;AAAA,MACL,OAAO;AAAA;AAAA;AAAA,EAcD,sBAAsB,GAAS;AAAA,IAEvC,IAAI,CAAC,0BAA0B,KAAK,KAAK,KAAK,GAAG;AAAA,MAC/C,MAAM,IAAI,MACR,iGACE,KAAK,KACT;AAAA,IACF;AAAA,IAGA,MAAM,qBAAqB,CAAC,WAAiC;AAAA,MAC3D,WAAW,OAAO,OAAO,YAAY;AAAA,QACnC,IAAI,CAAC,0BAA0B,KAAK,GAAG,GAAG;AAAA,UACxC,MAAM,IAAI,MACR,kGACE,GACJ;AAAA,QACF;AAAA,MACF;AAAA;AAAA,IAGF,mBAAmB,KAAK,gBAAgB;AAAA,IACxC,mBAAmB,KAAK,WAAW;AAAA,IAGnC,MAAM,cAAc,IAAI,IAAI,OAAO,KAAK,KAAK,iBAAiB,UAAU,CAAC;AAAA,IACzE,MAAM,YAAY,OAAO,KAAK,KAAK,YAAY,UAAU;AAAA,IACzD,MAAM,aAAa,UAAU,OAAO,CAAC,QAAQ,YAAY,IAAI,GAAG,CAAC;AAAA,IACjE,IAAI,WAAW,SAAS,GAAG;AAAA,MACzB,MAAM,IAAI,MAAM,oCAAoC,WAAW,KAAK,IAAI,GAAG;AAAA,IAC7E;AAAA;AAEJ;;;ADpUO,IAAM,8BAA8B,qBACzC,oCACF;AAAA;AAUO,MAAM,+BAWH,sBAAsF;AAAA,EAC3E;AAAA,EACX,kBAA0C;AAAA,EAalD,WAAW,CACT,QACA,QAAgB,iBAChB,QACA,iBACA,UAAmF,CAAC,GACpF,qBAA+C,cAC/C;AAAA,IACA,MAAM,OAAO,QAAQ,iBAAiB,SAAS,kBAAkB;AAAA,IACjE,KAAK,SAAS;AAAA;AAAA,OAQM,cAAa,GAAkB;AAAA,IACnD,MAAM,MAAM;AAAA,oCACoB,KAAK;AAAA,UAC/B,KAAK,2BAA2B,GAAG,KAAK,KAAK,sBAAsB,GAAG;AAAA,uBACzD,KAAK,qBAAqB;AAAA;AAAA;AAAA,IAG7C,QAAQ,UAAU,MAAM,KAAK,OAAO,IAAI,YAAY,EAAE,OAAO,IAAI,CAAC;AAAA,IAClE,IAAI,SAAS,CAAC,MAAM,QAAQ,SAAS,gBAAgB,GAAG;AAAA,MACtD,MAAM;AAAA,IACR;AAAA,IAGA,MAAM,YAAY,KAAK,kBAAkB;AAAA,IAGzC,MAAM,iBAAiB,IAAI;AAAA,IAE3B,WAAW,WAAW,KAAK,SAAS;AAAA,MAElC,IAAI,QAAQ,UAAU,UAAU,QAAQ;AAAA,QAEtC,MAAM,aAAa,QAAQ,MAAM,CAAC,KAAK,QAAQ,QAAQ,UAAU,IAAI;AAAA,QACrE,IAAI;AAAA,UAAY;AAAA,MAClB;AAAA,MAGA,MAAM,YAAY,GAAG,KAAK,SAAS,QAAQ,KAAK,GAAG;AAAA,MACnD,MAAM,aAAa,QAAQ,IAAI,CAAC,QAAQ,IAAI,OAAO,GAAG,IAAI,EAAE,KAAK,IAAI;AAAA,MAGrE,MAAM,YAAY,QAAQ,KAAK,GAAG;AAAA,MAClC,IAAI,eAAe,IAAI,SAAS;AAAA,QAAG;AAAA,MAGnC,MAAM,cAAc,MAAM,KAAK,cAAc,EAAE,KAAK,CAAC,aAAa;AAAA,QAChE,MAAM,eAAe,SAAS,MAAM,GAAG;AAAA,QACvC,OACE,aAAa,UAAU,QAAQ,UAC/B,QAAQ,MAAM,CAAC,KAAK,QAAQ,QAAQ,aAAa,IAAI;AAAA,OAExD;AAAA,MAED,IAAI,CAAC,aAAa;AAAA,QAChB,MAAM,WAAW,+BAA+B,kBAAkB,KAAK,WAAW;AAAA,QAClF,QAAQ,OAAO,eAAe,MAAM,KAAK,OAAO,IAAI,YAAY,EAAE,OAAO,SAAS,CAAC;AAAA,QACnF,IAAI,cAAc,CAAC,WAAW,QAAQ,SAAS,gBAAgB,GAAG;AAAA,UAEhE,QAAQ,KAAK,0BAA0B,cAAc,UAAU;AAAA,QACjE;AAAA,QACA,eAAe,IAAI,SAAS;AAAA,MAC9B;AAAA,IACF;AAAA;AAAA,EAWiB,YAAY,CAAC,SAA6B;AAAA,IAE3D,MAAM,aAAa,KAAK,eAAe,OAAO;AAAA,IAC9C,IAAI,OAAO,eAAe,WAAW;AAAA,MACnC,OAAO;AAAA,IACT;AAAA,IAGA,IAAI,WAAW,oBAAoB;AAAA,MAAQ,OAAO;AAAA,IAElD,QAAQ,WAAW;AAAA,WACZ;AAAA,QAEH,IAAI,WAAW,WAAW;AAAA,UAAa,OAAO;AAAA,QAC9C,IAAI,WAAW,WAAW;AAAA,UAAQ,OAAO;AAAA,QACzC,IAAI,WAAW,WAAW;AAAA,UAAS,OAAO;AAAA,QAC1C,IAAI,WAAW,WAAW;AAAA,UAAO,OAAO;AAAA,QACxC,IAAI,WAAW,WAAW;AAAA,UAAQ,OAAO;AAAA,QAGzC,IAAI,OAAO,WAAW,cAAc,UAAU;AAAA,UAC5C,OAAO,WAAW,WAAW;AAAA,QAC/B;AAAA,QAGA,OAAO;AAAA,WAEJ;AAAA,WACA;AAAA,QAEH,IAAI,WAAW,eAAe,KAAK,WAAW,SAAS,WAAW;AAAA,UAEhE,IAAI,OAAO,WAAW,YAAY,UAAU;AAAA,YAC1C,IAAI,WAAW,WAAW,GAAG;AAAA,cAE3B,IAAI,OAAO,WAAW,YAAY,UAAU;AAAA,gBAC1C,IAAI,WAAW,WAAW;AAAA,kBAAO,OAAO;AAAA,gBACxC,IAAI,WAAW,WAAW;AAAA,kBAAY,OAAO;AAAA,cAC/C;AAAA,cACA,OAAO;AAAA,YACT;AAAA,UACF;AAAA,UAGA,OAAO;AAAA,QACT;AAAA,QAGA,IAAI,WAAW,WAAW;AAAA,UAAS,OAAO;AAAA,QAC1C,IAAI,WAAW,WAAW;AAAA,UAAU,OAAO;AAAA,QAG3C,IAAI,OAAO,WAAW,eAAe,UAAU;AAAA,UAC7C,MAAM,gBAAgB,OAAO,WAAW,UAAU,EAAE,MAAM,GAAG,EAAE,IAAI,UAAU;AAAA,UAC7E,IAAI,gBAAgB,GAAG;AAAA,YACrB,OAAO,eAAe;AAAA,UACxB;AAAA,QACF;AAAA,QAEA,OAAO;AAAA,WAEJ;AAAA,QACH,OAAO;AAAA,WAEJ;AAAA,QAEH,IACE,WAAW,SACX,OAAO,WAAW,UAAU,YAC5B,CAAC,MAAM,QAAQ,WAAW,KAAK,GAC/B;AAAA,UACA,MAAM,WAAW,KAAK,aAAa,WAAW,KAAmB;AAAA,UAIjE,MAAM,6BAA6B;AAAA,YACjC;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UAGA,MAAM,cAAc,2BAA2B,KAC7C,CAAC,SAAS,aAAa,QAAS,SAAS,WAAW,OAAO,GAAG,KAAK,SAAS,SAC9E;AAAA,UAEA,IAAI,aAAa;AAAA,YACf,OAAO,GAAG;AAAA,UACZ,EAAO;AAAA,YACL,OAAO;AAAA;AAAA,QAEX;AAAA,QACA,OAAO;AAAA,WAEJ;AAAA,QACH,OAAO;AAAA;AAAA,QAGP,OAAO;AAAA;AAAA;AAAA,EASM,0BAA0B,CAAC,aAAqB,IAAY;AAAA,IAC7E,MAAM,OAAO,OAAO,QAAoB,KAAK,iBAAiB,UAAU,EACrE,IAAI,EAAE,KAAK,aAAa;AAAA,MAEvB,IAAI,KAAK,mBAAmB,GAAG,GAAG;AAAA,QAChC,IAAI,KAAK,6BAA6B,iBAAiB;AAAA,UAErD,MAAM,WAAU,KAAK,aAAa,OAAO;AAAA,UACzC,MAAM,aAAa,SAAQ,SAAS,UAAU;AAAA,UAC9C,MAAM,WAAW,SAAQ,SAAS,QAAQ;AAAA,UAC1C,MAAM,aAAa,WAAW,cAAc,aAAa,gBAAgB;AAAA,UACzE,OAAO,GAAG,aAAa,MAAM,cAAc;AAAA,QAC7C,EAAO,SAAI,KAAK,6BAA6B,QAAQ;AAAA,UAEnD,OAAO,GAAG,aAAa,MAAM;AAAA,QAC/B;AAAA,MACF;AAAA,MAEA,MAAM,UAAU,KAAK,aAAa,OAAO;AAAA,MACzC,IAAI,cAAc;AAAA,MAGlB,IAAI,KAAK,iBAAiB,OAAO,GAAG;AAAA,QAClC,eAAe,WAAW,aAAa,MAAM;AAAA,MAC/C;AAAA,MAEA,OAAO,GAAG,aAAa,MAAM,cAAc,WAAW;AAAA,KACvD,EACA,KAAK,IAAI;AAAA,IACZ,OAAO;AAAA;AAAA,EAOU,qBAAqB,CAAC,aAAqB,IAAY;AAAA,IACxE,MAAM,YAAY,cAAc;AAAA,IAChC,MAAM,cAAc,IAAI,IAAI,KAAK,YAAY,YAAY,CAAC,CAAC;AAAA,IAC3D,MAAM,OAAO,OAAO,QAAoB,KAAK,YAAY,UAAU,EAChE,IAAI,EAAE,KAAK,aAAa;AAAA,MACvB,MAAM,UAAU,KAAK,aAAa,OAAO;AAAA,MACzC,MAAM,aAAa,YAAY,IAAI,GAAG;AAAA,MACtC,MAAM,WAAW,CAAC,cAAc,KAAK,WAAW,OAAO;AAAA,MACvD,IAAI,cAAc,WAAW,SAAS;AAAA,MAGtC,IAAI,KAAK,iBAAiB,OAAO,GAAG;AAAA,QAClC,eAAe,WAAW,YAAY,MAAM;AAAA,MAC9C;AAAA,MAEA,OAAO,GAAG,YAAY,MAAM,aAAa,WAAW;AAAA,KACrD,EACA,KAAK,IAAI;AAAA,IACZ,IAAI,KAAK,SAAS,GAAG;AAAA,MACnB,OAAO,KAAK;AAAA,IACd,EAAO;AAAA,MACL,OAAO;AAAA;AAAA;AAAA,EAOQ,YAAY,CAAC,QAAgB,OAA8C;AAAA,IAC5F,MAAM,UAAU,KAAK,OAAO,WAAW;AAAA,IAGvC,IAAI,SAAS;AAAA,MACX,IAAI,UAAU,QAAQ,KAAK,WAAW,OAAO,GAAG;AAAA,QAC9C,OAAO;AAAA,MACT;AAAA,MACA,MAAM,aAAa,KAAK,eAAe,OAAO;AAAA,MAG9C,IACE,OAAO,eAAe,cACrB,WAAW,SAAS,YAAY,WAAW,SAAS,YACrD;AAAA,QACA,IAAI,OAAO,UAAU;AAAA,UAAU,OAAO;AAAA,QACtC,IAAI,OAAO,UAAU,UAAU;AAAA,UAC7B,MAAM,SAAS,OAAO,KAAK;AAAA,UAC3B,IAAI,CAAC,MAAM,MAAM;AAAA,YAAG,OAAO;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAAA,IACA,OAAO,MAAM,aAAa,QAAQ,KAAK;AAAA;AAAA,EAQ/B,gBAAgB,CAAC,SAA8B;AAAA,IAEvD,MAAM,aAAa,KAAK,eAAe,OAAO;AAAA,IAC9C,IAAI,OAAO,eAAe,WAAW;AAAA,MACnC,OAAO;AAAA,IACT;AAAA,IAGA,KACG,WAAW,SAAS,YAAY,WAAW,SAAS,cACrD,OAAO,WAAW,YAAY,YAC9B,WAAW,WAAW,GACtB;AAAA,MACA,OAAO;AAAA,IACT;AAAA,IAEA,OAAO;AAAA;AAAA,OAWH,IAAG,CAAC,QAAqC;AAAA,IAE7C,IAAI,iBAAiB,KAAK,OAAO;AAAA,IAEjC,IAAI,KAAK,oBAAoB,KAAK,KAAK,sBAAsB;AAAA,MAC3D,MAAM,UAAU,OAAO,KAAK,oBAAoB;AAAA,MAChD,MAAM,eAAe;AAAA,MACrB,MAAM,sBAAsB,aAAa;AAAA,MACzC,MAAM,iBAAiB,wBAAwB,aAAa,wBAAwB;AAAA,MAEpF,IAAI,gBAAgB;AAAA,MACpB,IAAI,KAAK,uBAAuB,SAAS;AAAA,QAEvC,gBAAgB;AAAA,MAClB,EAAO,SAAI,KAAK,uBAAuB,UAAU;AAAA,QAC/C,IAAI,CAAC,gBAAgB;AAAA,UACnB,MAAM,IAAI,MACR,uBAAuB,0DACzB;AAAA,QACF;AAAA,QACA,gBAAgB;AAAA,MAClB,EAAO;AAAA,QAEL,gBAAgB,CAAC;AAAA;AAAA,MAGnB,IAAI,eAAe;AAAA,QAEjB,OAAQ,eAA2C;AAAA,MACrD;AAAA,IACF;AAAA,IAGA,MAAM,mBAAmB,KAAK,eAAe;AAAA,IAC7C,MAAM,cAAc,IAAI,IAAI,KAAK,YAAY,YAAY,CAAC,CAAC;AAAA,IAC3D,WAAW,OAAO,KAAK,YAAY,YAAY;AAAA,MAC7C,IAAI,EAAE,OAAO,qBAAqB,iBAAiB,SAAS,WAAW;AAAA,QACrE,IAAI,CAAC,YAAY,IAAI,GAAG,GAAG;AAAA,UACzB,iBAAiB,OAAO;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAAA,IACA,QAAQ,MAAM,UAAU,MAAM,KAAK,OAChC,KAAK,KAAK,KAAK,EACf,OAAO,kBAAkB,EAAE,YAAY,KAAK,qBAAqB,EAAE,CAAC,EACpE,OAAO,EACP,OAAO;AAAA,IAEV,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,MAAM,gBAAgB;AAAA,IAGtB,MAAM,gBAAgB;AAAA,IACtB,WAAW,OAAO,KAAK,OAAO,YAAY;AAAA,MACxC,cAAc,OAAO,KAAK,aAAa,KAAK,cAAc,IAAuB;AAAA,IACnF;AAAA,IAEA,KAAK,OAAO,KAAK,OAAO,aAAa;AAAA,IACrC,OAAO;AAAA;AAAA,OAWH,QAAO,CAAC,UAA2C;AAAA,IACvD,IAAI,SAAS,WAAW;AAAA,MAAG,OAAO,CAAC;AAAA,IAGnC,OAAO,MAAM,QAAQ,IAAI,SAAS,IAAI,CAAC,WAAW,KAAK,IAAI,MAAM,CAAC,CAAC;AAAA;AAAA,OAU/D,IAAG,CAAC,KAA8C;AAAA,IACtD,IAAI,QAAQ,KAAK,OAAO,KAAK,KAAK,KAAK,EAAE,OAAO,GAAG;AAAA,IAGnD,MAAM,YAAY;AAAA,IAClB,WAAW,UAAU,KAAK,iBAAiB;AAAA,MACzC,QAAQ,MAAM,GAAG,OAAO,MAAM,GAAG,UAAU,OAAO,MAAM,EAAE;AAAA,IAC5D;AAAA,IAEA,QAAQ,MAAM,UAAU,MAAM,MAAM,OAAO;AAAA,IAE3C,IAAI,OAAO;AAAA,MACT,IAAI,MAAM,SAAS,YAAY;AAAA,QAE7B,KAAK,OAAO,KAAK,OAAO,KAAK,SAAS;AAAA,QACtC;AAAA,MACF;AAAA,MACA,MAAM;AAAA,IACR;AAAA,IAEA,MAAM,MAAM;AAAA,IACZ,IAAI,KAAK;AAAA,MAEP,MAAM,YAAY;AAAA,MAClB,WAAW,QAAO,KAAK,OAAO,YAAY;AAAA,QACxC,UAAU,QAAO,KAAK,aAAa,MAAK,UAAU,KAAuB;AAAA,MAC3E;AAAA,IACF;AAAA,IACA,KAAK,OAAO,KAAK,OAAO,KAAK,GAAG;AAAA,IAChC,OAAO;AAAA;AAAA,OASH,OAAM,CAAC,OAA2C;AAAA,IACtD,QAAQ,QAAQ,KAAK,6BAA6B,KAAe;AAAA,IAEjE,IAAI,QAAQ,KAAK,OAAO,KAAK,KAAK,KAAK,EAAE,OAAO;AAAA,IAGhD,MAAM,kBAAkB;AAAA,IACxB,WAAW,UAAU,KAAK,iBAAiB;AAAA,MACzC,QAAQ,MAAM,GAAG,OAAO,MAAM,GAAG,gBAAgB,OAAO,MAAM,EAAE;AAAA,IAClE;AAAA,IAEA,QAAQ,UAAU,MAAM;AAAA,IAExB,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,KAAK,OAAO,KAAK,UAAU,GAAmB;AAAA;AAAA,OAQ1C,OAAM,CAAC,SAA+D;AAAA,IAC1E,KAAK,sBAAsB,OAAO;AAAA,IAClC,IAAI,QAAQ,KAAK,OAAO,KAAK,KAAK,KAAK,EAAE,OAAO,GAAG;AAAA,IAEnD,IAAI,SAAS,SAAS;AAAA,MACpB,aAAa,QAAQ,eAAe,QAAQ,SAAS;AAAA,QACnD,QAAQ,MAAM,MAAM,OAAO,MAAM,GAAG,EAAE,WAAW,cAAc,MAAM,CAAC;AAAA,MACxE;AAAA,IACF;AAAA,IAEA,IAAI,SAAS,WAAW,aAAa,SAAS,UAAU,WAAW;AAAA,MACjE,MAAM,QAAQ,SAAS,UAAU;AAAA,MACjC,IAAI,SAAS,UAAU,WAAW;AAAA,QAChC,QAAQ,MAAM,MAAM,OAAO,QAAQ,QAAQ,QAAQ,CAAC;AAAA,MACtD,EAAO,SAAI,SAAS,WAAW,WAAW;AAAA,QACxC,QAAQ,MAAM,MAAM,OAAO,QAAQ,MAAM;AAAA,MAC3C;AAAA,IACF;AAAA,IAEA,QAAQ,MAAM,UAAU,MAAM;AAAA,IAE9B,IAAI;AAAA,MAAO,MAAM;AAAA,IAEjB,IAAI,QAAQ,KAAK,QAAQ;AAAA,MAEvB,WAAW,OAAO,MAAM;AAAA,QACtB,MAAM,SAAS;AAAA,QACf,WAAW,OAAO,KAAK,OAAO,YAAY;AAAA,UACxC,OAAO,OAAO,KAAK,aAAa,KAAK,OAAO,IAAuB;AAAA,QACrE;AAAA,MACF;AAAA,MACA,OAAO;AAAA,IACT;AAAA,IACA;AAAA;AAAA,OAOI,UAAS,GAAkB;AAAA,IAE/B,MAAM,gBAAgB,KAAK,gBAAgB;AAAA,IAC3C,QAAQ,UAAU,MAAM,KAAK,OAAO,KAAK,KAAK,KAAK,EAAE,OAAO,EAAE,IAAI,OAAO,aAAa,GAAG,IAAI;AAAA,IAE7F,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,KAAK,OAAO,KAAK,UAAU;AAAA;AAAA,OAQvB,KAAI,GAAoB;AAAA,IAC5B,QAAQ,OAAO,UAAU,MAAM,KAAK,OACjC,KAAK,KAAK,KAAK,EACf,OAAO,KAAK,EAAE,OAAO,SAAS,MAAM,KAAK,CAAC;AAAA,IAE7C,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,OAAO,SAAS;AAAA;AAAA,OASZ,QAAO,CAAC,QAAgB,OAA8C;AAAA,IAE1E,IAAI,QAAQ,KAAK,OAAO,KAAK,KAAK,KAAK,EAAE,OAAO,GAAG;AAAA,IAGnD,WAAW,UAAU,KAAK,iBAAiB;AAAA,MACzC,QAAQ,MAAM,MAAM,OAAO,MAAM,CAAC;AAAA,IACpC;AAAA,IAEA,QAAQ,MAAM,UAAU,MAAM,MAAM,MAAM,QAAQ,SAAS,QAAQ,CAAC;AAAA,IAEpE,IAAI;AAAA,MAAO,MAAM;AAAA,IAEjB,IAAI,CAAC,QAAQ,KAAK,WAAW,GAAG;AAAA,MAC9B;AAAA,IACF;AAAA,IAGA,WAAW,OAAO,MAAM;AAAA,MACtB,MAAM,SAAS;AAAA,MACf,WAAW,OAAO,KAAK,OAAO,YAAY;AAAA,QACxC,OAAO,OAAO,KAAK,aAAa,KAAK,OAAO,IAAuB;AAAA,MACrE;AAAA,IACF;AAAA,IAEA,OAAO;AAAA;AAAA,EAOD,qBAAwB,CAAC,OAAU,UAAqC;AAAA,IAC9E,IAAI,IAAI;AAAA,IACR,WAAW,UAAU,OAAO,KAAK,QAAQ,GAA0B;AAAA,MACjE,MAAM,YAAY,SAAS;AAAA,MAC3B,IAAI,WAA2B;AAAA,MAC/B,IAAI;AAAA,MAEJ,IAAI,kBAAkB,SAAS,GAAG;AAAA,QAChC,WAAW,UAAU;AAAA,QACrB,QAAQ,UAAU;AAAA,MACpB,EAAO;AAAA,QACL,QAAQ;AAAA;AAAA,MAGV,QAAQ;AAAA,aACD;AAAA,UACH,IAAI,EAAE,GAAG,OAAO,MAAM,GAAG,KAAK;AAAA,UAC9B;AAAA,aACG;AAAA,UACH,IAAI,EAAE,GAAG,OAAO,MAAM,GAAG,KAAK;AAAA,UAC9B;AAAA,aACG;AAAA,UACH,IAAI,EAAE,IAAI,OAAO,MAAM,GAAG,KAAK;AAAA,UAC/B;AAAA,aACG;AAAA,UACH,IAAI,EAAE,GAAG,OAAO,MAAM,GAAG,KAAK;AAAA,UAC9B;AAAA,aACG;AAAA,UACH,IAAI,EAAE,IAAI,OAAO,MAAM,GAAG,KAAK;AAAA,UAC/B;AAAA;AAAA,IAEN;AAAA,IACA,OAAO;AAAA;AAAA,OAMM,MAAK,CAAC,UAAoD;AAAA,IACvE,IAAI,CAAC,YAAY,OAAO,KAAK,QAAQ,EAAE,WAAW,GAAG;AAAA,MACnD,OAAO,MAAM,KAAK,KAAK;AAAA,IACzB;AAAA,IAEA,KAAK,oBAAoB,QAAQ;AAAA,IACjC,MAAM,QAAQ,KAAK,sBACjB,KAAK,OAAO,KAAK,KAAK,KAAK,EAAE,OAAO,KAAK,EAAE,OAAO,SAAS,MAAM,KAAK,CAAC,GACvE,QACF;AAAA,IAEA,QAAQ,OAAO,UAAU,MAAM;AAAA,IAC/B,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,OAAO,SAAS;AAAA;AAAA,OASZ,aAAY,CAAC,UAAuD;AAAA,IACxE,MAAM,eAAe,OAAO,KAAK,QAAQ;AAAA,IACzC,IAAI,aAAa,WAAW,GAAG;AAAA,MAC7B;AAAA,IACF;AAAA,IAEA,IAAI,QAAQ,KAAK,OAAO,KAAK,KAAK,KAAK,EAAE,OAAO;AAAA,IAEhD,WAAW,UAAU,cAAc;AAAA,MACjC,IAAI,EAAE,UAAU,KAAK,OAAO,aAAa;AAAA,QACvC,MAAM,IAAI,MAAM,sBAAsB,OAAO,MAAM,6BAA6B;AAAA,MAClF;AAAA,MAEA,MAAM,YAAY,SAAS;AAAA,MAC3B,IAAI,WAA2B;AAAA,MAC/B,IAAI;AAAA,MAEJ,IAAI,kBAAkB,SAAS,GAAG;AAAA,QAChC,WAAW,UAAU;AAAA,QACrB,QAAQ,UAAU;AAAA,MACpB,EAAO;AAAA,QACL,QAAQ;AAAA;AAAA,MAGV,QAAQ;AAAA,aACD;AAAA,UACH,QAAQ,MAAM,GAAG,OAAO,MAAM,GAAG,KAAK;AAAA,UACtC;AAAA,aACG;AAAA,UACH,QAAQ,MAAM,GAAG,OAAO,MAAM,GAAG,KAAK;AAAA,UACtC;AAAA,aACG;AAAA,UACH,QAAQ,MAAM,IAAI,OAAO,MAAM,GAAG,KAAK;AAAA,UACvC;AAAA,aACG;AAAA,UACH,QAAQ,MAAM,GAAG,OAAO,MAAM,GAAG,KAAK;AAAA,UACtC;AAAA,aACG;AAAA,UACH,QAAQ,MAAM,IAAI,OAAO,MAAM,GAAG,KAAK;AAAA,UACvC;AAAA;AAAA,IAEN;AAAA,IAEA,QAAQ,UAAU,MAAM;AAAA,IAExB,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,KAAK,OAAO,KAAK,UAAU,aAAa,EAAkB;AAAA;AAAA,OAUtD,MAAK,CACT,UACA,SAC+B;AAAA,IAC/B,KAAK,oBAAoB,UAAU,OAAO;AAAA,IAE1C,IAAI,QAAQ,KAAK,sBAAsB,KAAK,OAAO,KAAK,KAAK,KAAK,EAAE,OAAO,GAAG,GAAG,QAAQ;AAAA,IAEzF,IAAI,SAAS,SAAS;AAAA,MACpB,aAAa,QAAQ,eAAe,QAAQ,SAAS;AAAA,QACnD,QAAQ,MAAM,MAAM,OAAO,MAAM,GAAG,EAAE,WAAW,cAAc,MAAM,CAAC;AAAA,MACxE;AAAA,IACF;AAAA,IAEA,IAAI,SAAS,WAAW,aAAa,SAAS,UAAU,WAAW;AAAA,MACjE,MAAM,QAAQ,SAAS,UAAU;AAAA,MACjC,IAAI,SAAS,UAAU,WAAW;AAAA,QAChC,QAAQ,MAAM,MAAM,OAAO,QAAQ,QAAQ,QAAQ,CAAC;AAAA,MACtD,EAAO,SAAI,SAAS,WAAW,WAAW;AAAA,QACxC,QAAQ,MAAM,MAAM,OAAO,QAAQ,MAAM;AAAA,MAC3C;AAAA,IACF,EAAO,SAAI,SAAS,UAAU,WAAW;AAAA,MACvC,QAAQ,MAAM,MAAM,QAAQ,KAAK;AAAA,IACnC;AAAA,IAEA,QAAQ,MAAM,UAAU,MAAM;AAAA,IAE9B,IAAI;AAAA,MAAO,MAAM;AAAA,IAEjB,IAAI,QAAQ,KAAK,SAAS,GAAG;AAAA,MAC3B,WAAW,OAAO,MAAM;AAAA,QACtB,MAAM,SAAS;AAAA,QACf,WAAW,OAAO,KAAK,OAAO,YAAY;AAAA,UACxC,OAAO,OAAO,KAAK,aAAa,KAAK,OAAO,IAAuB;AAAA,QACrE;AAAA,MACF;AAAA,MACA,KAAK,OAAO,KAAK,SAAS,UAA6B,IAAgB;AAAA,MACvE,OAAO;AAAA,IACT;AAAA,IACA,KAAK,OAAO,KAAK,SAAS,UAA6B,SAAS;AAAA,IAChE;AAAA;AAAA,OAGa,WAA2C,CACxD,UACA,SAC4B;AAAA,IAC5B,KAAK,eAAe,OAAO;AAAA,IAC3B,KAAK,oBAAoB,UAAU,OAAO;AAAA,IAE1C,MAAM,aAAa,KAAK,QAAQ,IAAI,CAAC,MAAM,MAAM;AAAA,MAC/C,MAAM,KAAK,MAAM,QAAQ,IAAI,IAAK,OAAoB,CAAC,IAAc;AAAA,MACrE,OAAO,EAAE,MAAM,OAAO,KAAK,SAAS,GAAG;AAAA,KACxC;AAAA,IAED,kBAAkB;AAAA,MAChB,OAAO,KAAK;AAAA,MACZ,SAAS;AAAA,MACT,iBAAiB,OAAO,KAAK,QAAQ;AAAA,MACrC,iBAAiB,QAAQ,WAAW,CAAC,GAAG,IAAI,CAAC,OAAO;AAAA,QAClD,QAAQ,OAAO,EAAE,MAAM;AAAA,QACvB,WAAW,EAAE;AAAA,MACf,EAAE;AAAA,MACF,eAAe,QAAQ,OAAO,IAAI,MAAM;AAAA,MACxC,mBAAmB,KAAK,gBAAgB,IAAI,MAAM;AAAA,IACpD,CAAC;AAAA,IAED,MAAM,UAAU,QAAQ,OAAO,IAAI,MAAM,EAAE,KAAK,GAAG;AAAA,IACnD,IAAI,IAAI,KAAK,sBAAsB,KAAK,OAAO,KAAK,KAAK,KAAK,EAAE,OAAO,OAAO,GAAG,QAAQ;AAAA,IAEzF,IAAI,QAAQ,SAAS;AAAA,MACnB,aAAa,QAAQ,eAAe,QAAQ,SAAS;AAAA,QACnD,IAAI,EAAE,MAAM,OAAO,MAAM,GAAG,EAAE,WAAW,cAAc,MAAM,CAAC;AAAA,MAChE;AAAA,IACF;AAAA,IACA,IAAI,QAAQ,WAAW,aAAa,QAAQ,UAAU,WAAW;AAAA,MAC/D,MAAM,IAAI,uBAAuB,yDAAyD;AAAA,IAC5F;AAAA,IACA,IAAI,QAAQ,WAAW,aAAa,QAAQ,UAAU,WAAW;AAAA,MAC/D,MAAM,QAAQ,QAAQ,UAAU;AAAA,MAChC,IAAI,QAAQ,UAAU,WAAW;AAAA,QAC/B,IAAI,EAAE,MAAM,OAAO,QAAQ,QAAQ,QAAQ,CAAC;AAAA,MAC9C;AAAA,IACF;AAAA,IAEA,QAAQ,MAAM,UAAU,MAAM;AAAA,IAC9B,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,IAAI,CAAC;AAAA,MAAM,OAAO,CAAC;AAAA,IAEnB,MAAM,OAAO;AAAA,IACb,MAAM,MAAM,IAAI,IAAI,QAAQ,OAAO,IAAI,MAAM,CAAC;AAAA,IAC9C,WAAW,OAAO,MAAM;AAAA,MACtB,WAAW,OAAO,OAAO,KAAK,GAAG,GAAG;AAAA,QAClC,IAAI,IAAI,IAAI,GAAG,GAAG;AAAA,UAChB,IAAI,OAAO,KAAK,aAAa,KAAK,IAAI,IAAuB;AAAA,QAC/D;AAAA,MACF;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,EASD,kBAAkB,CAAC,KAAsC;AAAA,IAC/D,MAAM,SAAS,KAAK,IAAI;AAAA,IACxB,MAAM,SAAS;AAAA,IACf,WAAW,OAAO,KAAK,OAAO,YAAY;AAAA,MACxC,OAAO,OAAO,KAAK,aAAa,KAAK,IAAI,IAAuB;AAAA,IAClE;AAAA,IACA,OAAO;AAAA;AAAA,EAWO,kBAAkB,CAChC,UACA,SACY;AAAA,IAEZ,MAAM,cAAc,WAAW,KAAK,SAAS,KAAK,IAAI;AAAA,IAEtD,KAAK,kBAAkB,KAAK,OACzB,QAAQ,WAAW,EACnB,GACC,oBACA;AAAA,MACE,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO,KAAK;AAAA,IACd,GACA,CAAC,YAAY;AAAA,MACX,MAAM,SAAuC;AAAA,QAC3C,MAAM,QAAQ,UAAU,YAAY;AAAA,QACpC,KACE,QAAQ,OAAO,OAAO,KAAK,QAAQ,GAAG,EAAE,SAAS,IAC7C,KAAK,mBAAmB,QAAQ,GAAG,IACnC;AAAA,QACN,KACE,QAAQ,OAAO,OAAO,KAAK,QAAQ,GAAG,EAAE,SAAS,IAC7C,KAAK,mBAAmB,QAAQ,GAAG,IACnC;AAAA,MACR;AAAA,MACA,SAAS,MAAM;AAAA,KAEnB,EACC,UAAU;AAAA,IAEb,OAAO,MAAM;AAAA,MACX,IAAI,KAAK,iBAAiB;AAAA,QACxB,KAAK,OAAO,cAAc,KAAK,eAAe;AAAA,QAC9C,KAAK,kBAAkB;AAAA,MACzB;AAAA;AAAA;AAAA,EAOY,OAAO,GAAS;AAAA,IAC9B,IAAI,KAAK,iBAAiB;AAAA,MACxB,KAAK,OAAO,cAAc,KAAK,eAAe;AAAA,MAC9C,KAAK,kBAAkB;AAAA,IACzB;AAAA;AAEJ;;AEt5BA,+BAAS;AAKF,IAAM,oBAAoB,qBAC/B,gCACF;AAAA;AAUO,MAAM,2BAA2B,oBAAoB;AAAA,EAUjD;AAAA,EATF;AAAA,EAQP,WAAW,CACF,QACP,YAAwB,EAAE,MAAM,SAAS,GACzC,cAA0B,CAAC,GAC3B;AAAA,IACA,MAAM,WAAW,WAAW;AAAA,IAJrB;AAAA,IAKP,KAAK,oBAAoB,IAAI,wBAC3B,QACA,uBACA,kBACF;AAAA;AAEJ;;ACvCA,+BAAS;AAMF,IAAM,yBAAyB,qBACpC,+BACF;AAAA;AAUO,MAAM,0BAA0B,oBAAoB;AAAA,EAehD;AAAA,EACA;AAAA,EAfF;AAAA,EAaP,WAAW,CACF,QACA,WACP,YAAwB,EAAE,MAAM,SAAS,GACzC,cAA0B,CAAC,GAC3B,mBAIA;AAAA,IACA,MAAM,WAAW,WAAW;AAAA,IATrB;AAAA,IACA;AAAA,IASP,KAAK,oBACH,qBACA,IAAI,uBAAuB,QAAQ,WAAW,uBAAuB,kBAAkB;AAAA;AAE7F;;AC/CA,+BAAS,mCAAoB,+BAAW,2BAAiB;AAiBlD,IAAM,2BAA2B,qBACtC,4BACF;AAAA;AAgBO,MAAM,sBAA6E;AAAA,EAqBtE;AAAA,EApBV;AAAA,EACS;AAAA,EACA;AAAA,EAEE;AAAA,EAEA;AAAA,EAEX,gBAIG;AAAA,EAEM;AAAA,EAKjB,WAAW,CACO,WAChB,UAAwC,CAAC,GACzC;AAAA,IAFgB;AAAA,IAGhB,KAAK,mBAAmB;AAAA,IACxB,KAAK,WAAW,QAAQ,YAAY,CAAC;AAAA,IACrC,KAAK,eAAe,QAAQ,gBAAgB,CAAC;AAAA,IAC7C,KAAK,gBAAgB;AAAA,MACnB,qBAAqB,QAAQ,uBAAuB;AAAA,MACpD,yBAAyB,QAAQ,2BAA2B;AAAA,IAC9D;AAAA,IAEA,IAAI,KAAK,SAAS,SAAS,GAAG;AAAA,MAC5B,MAAM,cAAc,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG;AAAA,MAC7D,KAAK,YAAY,QAAQ;AAAA,IAC3B,EAAO;AAAA,MACL,KAAK,YAAY;AAAA;AAAA;AAAA,EAOb,oBAAoB,GAAa;AAAA,IACvC,OAAO,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA;AAAA,EAMhC,eAAe,CAAC,KAAyE;AAAA,IAC/F,YAAY,KAAK,UAAU,OAAO,QAAQ,KAAK,YAAY,GAAG;AAAA,MAC5D,IAAI,IAAI,SAAS,OAAO;AAAA,QACtB,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,EAMD,kBAAkB,GAA2B;AAAA,IACnD,OAAO,KAAK,SAAS,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE,KAAK;AAAA;AAAA,OAG7C,MAAK,GAAyB;AAAA,IAC1C,IAAI,KAAK;AAAA,MAAI,OAAO,KAAK;AAAA,IACzB,MAAM,KAAK,cAAc;AAAA,IACzB,OAAO,KAAK;AAAA;AAAA,OAOD,cAAa,GAAkB;AAAA,IAC1C,MAAM,oBAAoB,KAAK,qBAAqB;AAAA,IAGpD,MAAM,eAAe,CAAC,aAAiC;AAAA,MACrD,OAAO,CAAC,GAAG,mBAAmB,GAAG,QAAQ;AAAA;AAAA,IAG3C,MAAM,kBAA6C;AAAA,MACjD;AAAA,QACE,MAAM;AAAA,QACN,SAAS,aAAa,CAAC,SAAS,QAAQ,CAAC;AAAA,QACzC,SAAS,EAAE,QAAQ,MAAM;AAAA,MAC3B;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,SAAS,aAAa,CAAC,SAAS,UAAU,WAAW,CAAC;AAAA,QACtD,SAAS,EAAE,QAAQ,MAAM;AAAA,MAC3B;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,SAAS,aAAa,CAAC,SAAS,YAAY,CAAC;AAAA,QAC7C,SAAS,EAAE,QAAQ,MAAM;AAAA,MAC3B;AAAA,MACA;AAAA,QACE,MAAM;AAAA,QACN,SAAS,aAAa,CAAC,SAAS,eAAe,QAAQ,CAAC;AAAA,QACxD,SAAS,EAAE,QAAQ,MAAM;AAAA,MAC3B;AAAA,IACF;AAAA,IAEA,KAAK,KAAK,MAAM,qBACd,KAAK,WACL,MACA,iBACA,KAAK,gBACP;AAAA;AAAA,OAQW,IAAG,CAAC,KAAwD;AAAA,IACvE,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,MAAM,IAAI,KAAK,EAAE,YAAY;AAAA,IACnC,MAAM,kBAAkB;AAAA,IACxB,gBAAgB,KAAK,gBAAgB,MAAM,OAAM;AAAA,IACjD,gBAAgB,aAAa,gBAAgB,cAAc,OAAM;AAAA,IACjE,gBAAgB,QAAQ,KAAK;AAAA,IAC7B,gBAAgB,cAAc,MAAM,iBAAgB,gBAAgB,KAAK;AAAA,IACzE,gBAAgB,SAAS,UAAU;AAAA,IACnC,gBAAgB,WAAW;AAAA,IAC3B,gBAAgB,mBAAmB;AAAA,IACnC,gBAAgB,mBAAmB;AAAA,IACnC,gBAAgB,aAAa;AAAA,IAC7B,gBAAgB,YAAY;AAAA,IAG5B,YAAY,KAAK,UAAU,OAAO,QAAQ,KAAK,YAAY,GAAG;AAAA,MAC5D,gBAAgB,OAAO;AAAA,IACzB;AAAA,IAEA,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,WAAW;AAAA,IACrD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAE3C,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,UAAU,MAAM,IAAI,eAAe;AAAA,MAGzC,GAAG,aAAa,MAAM;AAAA,QAEpB,KAAK,eAAe,kBAAkB;AAAA,QACtC,QAAQ,gBAAgB,EAAE;AAAA;AAAA,MAE5B,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,MAClC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA;AAAA,OAQG,IAAG,CAAC,IAAmE;AAAA,IAC3E,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,UAAU;AAAA,IACpD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAC3C,MAAM,UAAU,MAAM,IAAI,EAAY;AAAA,IACtC,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,QAAQ,YAAY,MAAM;AAAA,QACxB,MAAM,MAAM,QAAQ;AAAA,QAIpB,IAAI,OAAO,IAAI,UAAU,KAAK,aAAa,KAAK,gBAAgB,GAAG,GAAG;AAAA,UACpE,QAAQ,GAAG;AAAA,QACb,EAAO;AAAA,UACL,QAAQ,SAAS;AAAA;AAAA;AAAA,MAGrB,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,KACnC;AAAA;AAAA,OASU,KAAI,CACf,SAAoB,UAAU,SAC9B,MAAc,KAC8B;AAAA,IAC5C,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,UAAU;AAAA,IACpD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAC3C,MAAM,QAAQ,MAAM,MAAM,wBAAwB;AAAA,IAClD,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAEhD,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,MAAM,IAAI;AAAA,MAEhB,MAAM,WAAW,YAAY,MAC3B,CAAC,GAAG,iBAAiB,KAAK,WAAW,QAAQ,EAAE,GAC/C,CAAC,GAAG,iBAAiB,KAAK,WAAW,QAAQ,GAAQ,CACvD;AAAA,MACA,MAAM,gBAAgB,MAAM,WAAW,QAAQ;AAAA,MAE/C,MAAM,eAAe,CAAC,MAAa;AAAA,QACjC,MAAM,SAAU,EAAE,OAA0C;AAAA,QAC5D,IAAI,CAAC,UAAU,IAAI,QAAQ,KAAK;AAAA,UAC9B,QAAQ,MAAM,KAAK,IAAI,OAAO,CAAC,CAAC;AAAA,UAChC;AAAA,QACF;AAAA,QACA,MAAM,MAAM,OAAO;AAAA,QAEnB,IAAI,KAAK,gBAAgB,GAAG,GAAG;AAAA,UAC7B,IAAI,IAAI,OAAO,MAAM,IAAI,OAAO,KAAK;AAAA,QACvC;AAAA,QACA,OAAO,SAAS;AAAA;AAAA,MAGlB,cAAc,YAAY;AAAA,MAC1B,cAAc,UAAU,MAAM,OAAO,cAAc,KAAK;AAAA,MACxD,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,KACnC;AAAA;AAAA,OAiBU,KAAI,CAAC,UAAwE;AAAA,IACxF,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,WAAW;AAAA,IACrD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAC3C,MAAM,QAAQ,MAAM,MAAM,wBAAwB;AAAA,IAClD,MAAM,MAAM,IAAI,KAAK,EAAE,YAAY;AAAA,IACnC,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAGhD,MAAM,aAAa;AAAA,IAEnB,MAAM,cAAc,MAAM,IAAI,QAC5B,CAAC,SAAS,WAAW;AAAA,MACnB,MAAM,gBAAgB,MAAM,WAC1B,YAAY,MACV,CAAC,GAAG,iBAAiB,KAAK,WAAW,UAAU,SAAS,EAAE,GAC1D,CAAC,GAAG,iBAAiB,KAAK,WAAW,UAAU,SAAS,GAAG,GAC3D,OACA,KACF,CACF;AAAA,MAEA,IAAI;AAAA,MACJ,IAAI,gBAAgB;AAAA,MAEpB,cAAc,YAAY,CAAC,MAAM;AAAA,QAC/B,MAAM,SAAU,EAAE,OAA0C;AAAA,QAC5D,IAAI,CAAC,QAAQ;AAAA,UAEX;AAAA,QACF;AAAA,QAGA,IAAI,eAAe;AAAA,UACjB;AAAA,QACF;AAAA,QAEA,MAAM,MAAM,OAAO;AAAA,QAEnB,IACE,IAAI,UAAU,KAAK,aACnB,IAAI,WAAW,UAAU,WACzB,CAAC,KAAK,gBAAgB,GAAG,GACzB;AAAA,UACA,OAAO,SAAS;AAAA,UAChB;AAAA,QACF;AAAA,QAGA,IAAI,SAAS,UAAU;AAAA,QACvB,IAAI,cAAc;AAAA,QAClB,IAAI,YAAY;AAAA,QAEhB,IAAI;AAAA,UACF,MAAM,gBAAgB,MAAM,IAAI,GAAG;AAAA,UACnC,cAAc,YAAY,MAAM;AAAA,YAC9B,aAAa;AAAA,YACb,gBAAgB;AAAA;AAAA,UAGlB,cAAc,UAAU,CAAC,QAAQ;AAAA,YAC/B,QAAQ,MAAM,gCAAgC,GAAG;AAAA,YACjD,OAAO,SAAS;AAAA;AAAA,UAElB,OAAO,KAAK;AAAA,UACZ,QAAQ,MAAM,uBAAuB,GAAG;AAAA,UACxC,OAAO,SAAS;AAAA;AAAA;AAAA,MAIpB,cAAc,UAAU,MAAM,OAAO,cAAc,KAAK;AAAA,MAGxD,GAAG,aAAa,MAAM;AAAA,QAEpB,IAAI,YAAY;AAAA,UACd,KAAK,eAAe,kBAAkB;AAAA,QACxC;AAAA,QACA,QAAQ,UAAU;AAAA;AAAA,MAEpB,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,KAEtC;AAAA,IAGA,IAAI,CAAC,aAAa;AAAA,MAChB;AAAA,IACF;AAAA,IAKA,MAAM,cAAc,MAAM,KAAK,IAAI,YAAY,EAAE;AAAA,IAEjD,IAAI,CAAC,aAAa;AAAA,MAEhB;AAAA,IACF;AAAA,IAEA,IAAI,YAAY,cAAc,YAAY;AAAA,MAExC;AAAA,IACF;AAAA,IAEA,IAAI,YAAY,WAAW,UAAU,YAAY;AAAA,MAE/C;AAAA,IACF;AAAA,IAGA,OAAO;AAAA;AAAA,OAOI,KAAI,CAAC,SAAS,UAAU,SAA0B;AAAA,IAC7D,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAChD,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,UAAU;AAAA,MACpD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,MAC3C,MAAM,QAAQ,MAAM,MAAM,cAAc;AAAA,MACxC,MAAM,WAAW,YAAY,KAAK,CAAC,GAAG,iBAAiB,KAAK,WAAW,MAAM,CAAC;AAAA,MAC9E,MAAM,UAAU,MAAM,MAAM,QAAQ;AAAA,MAEpC,QAAQ,YAAY,MAAM,QAAQ,QAAQ,MAAM;AAAA,MAChD,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,KACnC;AAAA;AAAA,OAMU,SAAQ,CAAC,KAAqD;AAAA,IACzE,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,WAAW;AAAA,IACrD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAE3C,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,SAAS,MAAM,IAAI,IAAI,EAAY;AAAA,MACzC,OAAO,YAAY,MAAM;AAAA,QACvB,MAAM,WAAW,OAAO;AAAA,QAIxB,IAAI,CAAC,YAAY,SAAS,UAAU,KAAK,aAAa,CAAC,KAAK,gBAAgB,QAAQ,GAAG;AAAA,UACrF,OACE,IAAI,MAAM,OAAO,IAAI,4CAA4C,KAAK,WAAW,CACnF;AAAA,UACA;AAAA,QACF;AAAA,QACA,MAAM,kBAAkB,SAAS,gBAAgB;AAAA,QACjD,IAAI,eAAe,kBAAkB;AAAA,QAErC,IAAI,QAAQ,KAAK;AAAA,QAGjB,MAAM,kBAAkB;AAAA,QACxB,YAAY,KAAK,UAAU,OAAO,QAAQ,KAAK,YAAY,GAAG;AAAA,UAC5D,gBAAgB,OAAO;AAAA,QACzB;AAAA,QAEA,MAAM,SAAS,MAAM,IAAI,eAAe;AAAA,QACxC,OAAO,YAAY,MAAM;AAAA,QACzB,OAAO,UAAU,MAAM,OAAO,OAAO,KAAK;AAAA;AAAA,MAE5C,OAAO,UAAU,MAAM,OAAO,OAAO,KAAK;AAAA,MAG1C,GAAG,aAAa,MAAM;AAAA,QAEpB,KAAK,eAAe,kBAAkB;AAAA,QACtC,QAAQ;AAAA;AAAA,MAEV,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,KACnC;AAAA;AAAA,OAMU,QAAO,CAAC,IAA4B;AAAA,IAC/C,MAAM,MAAM,MAAM,KAAK,IAAI,EAAE;AAAA,IAC7B,IAAI,CAAC;AAAA,MAAK;AAAA,IAEV,IAAI,SAAS,UAAU;AAAA,IACvB,IAAI,YAAY;AAAA,IAChB,IAAI,WAAW;AAAA,IACf,IAAI,mBAAmB;AAAA,IACvB,IAAI,mBAAmB;AAAA,IAEvB,MAAM,KAAK,IAAI,GAAG;AAAA;AAAA,OAMP,MAAK,CAAC,IAA4B;AAAA,IAC7C,MAAM,MAAM,MAAM,KAAK,IAAI,EAAE;AAAA,IAC7B,IAAI,CAAC;AAAA,MAAK;AAAA,IAEV,IAAI,SAAS,UAAU;AAAA,IACvB,MAAM,KAAK,SAAS,GAAG;AAAA;AAAA,OAMZ,WAAU,CAAC,YAAgE;AAAA,IACtF,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,UAAU;AAAA,IACpD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAC3C,MAAM,QAAQ,MAAM,MAAM,kBAAkB;AAAA,IAC5C,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAChD,MAAM,WAAW,YAAY,KAAK,CAAC,GAAG,iBAAiB,KAAK,WAAW,UAAU,CAAC;AAAA,IAClF,MAAM,UAAU,MAAM,OAAO,QAAQ;AAAA,IAErC,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,QAAQ,YAAY,MAAM;AAAA,QAExB,MAAM,WAAW,QAAQ,UAAU,CAAC,GAAG,OACrC,CAAC,QACC,KAAK,gBAAgB,GAAG,CAC5B;AAAA,QACA,QAAQ,OAAO;AAAA;AAAA,MAEjB,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,KACnC;AAAA;AAAA,OAMU,UAAS,GAAkB;AAAA,IACtC,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,WAAW;AAAA,IACrD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAC3C,MAAM,QAAQ,MAAM,MAAM,cAAc;AAAA,IACxC,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAEhD,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MAEtC,MAAM,WAAW,YAAY,MAC3B,CAAC,GAAG,iBAAiB,KAAK,WAAW,EAAE,GACvC,CAAC,GAAG,iBAAiB,KAAK,WAAW,GAAQ,CAC/C;AAAA,MACA,MAAM,UAAU,MAAM,WAAW,QAAQ;AAAA,MAEzC,QAAQ,YAAY,CAAC,UAAU;AAAA,QAC7B,MAAM,SAAU,MAAM,OAA0C;AAAA,QAChE,IAAI,QAAQ;AAAA,UACV,MAAM,MAAM,OAAO;AAAA,UAEnB,IAAI,IAAI,UAAU,KAAK,aAAa,KAAK,gBAAgB,GAAG,GAAG;AAAA,YAC7D,MAAM,gBAAgB,OAAO,OAAO;AAAA,YACpC,cAAc,YAAY,MAAM;AAAA,cAC9B,OAAO,SAAS;AAAA;AAAA,YAElB,cAAc,UAAU,MAAM;AAAA,cAE5B,OAAO,SAAS;AAAA;AAAA,UAEpB,EAAO;AAAA,YACL,OAAO,SAAS;AAAA;AAAA,QAEpB;AAAA;AAAA,MAGF,GAAG,aAAa,MAAM;AAAA,QAEpB,KAAK,eAAe,kBAAkB;AAAA,QACtC,QAAQ;AAAA;AAAA,MAEV,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,MAClC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA;AAAA,OAMU,eAAc,CAAC,OAAsC;AAAA,IAChE,MAAM,cAAc,MAAM,iBAAgB,KAAK;AAAA,IAC/C,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,UAAU;AAAA,IACpD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAC3C,MAAM,QAAQ,MAAM,MAAM,0BAA0B;AAAA,IACpD,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAChD,MAAM,UAAU,MAAM,IAAI;AAAA,MACxB,GAAG;AAAA,MACH,KAAK;AAAA,MACL;AAAA,MACA,UAAU;AAAA,IACZ,CAAC;AAAA,IAED,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,QAAQ,YAAY,MAAM;AAAA,QACxB,MAAM,MAAM,QAAQ;AAAA,QAGpB,IAAI,OAAO,KAAK,gBAAgB,GAAG,GAAG;AAAA,UACpC,QAAQ,IAAI,UAAU,IAAI;AAAA,QAC5B,EAAO;AAAA,UACL,QAAQ,IAAI;AAAA;AAAA;AAAA,MAGhB,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,KACnC;AAAA;AAAA,OAMU,aAAY,CACvB,IACA,UACA,SACA,SACe;AAAA,IACf,MAAM,MAAM,MAAM,KAAK,IAAI,EAAE;AAAA,IAC7B,IAAI,CAAC;AAAA,MAAK,MAAM,IAAI,MAAM,OAAO,cAAc;AAAA,IAE/C,IAAI,WAAW;AAAA,IACf,IAAI,mBAAmB;AAAA,IACvB,IAAI,mBAAmB;AAAA,IAEvB,MAAM,KAAK,IAAI,GAAG;AAAA;AAAA,OAMN,IAAG,CAAC,KAAqD;AAAA,IACrE,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,WAAW;AAAA,IACrD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAG3C,IAAI,QAAQ,KAAK;AAAA,IAGjB,MAAM,kBAAkB;AAAA,IACxB,YAAY,KAAK,UAAU,OAAO,QAAQ,KAAK,YAAY,GAAG;AAAA,MAC5D,gBAAgB,OAAO;AAAA,IACzB;AAAA,IAEA,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,SAAS,MAAM,IAAI,eAAe;AAAA,MACxC,OAAO,UAAU,MAAM,OAAO,OAAO,KAAK;AAAA,MAC1C,GAAG,aAAa,MAAM;AAAA,QAEpB,KAAK,eAAe,kBAAkB;AAAA,QACtC,QAAQ;AAAA;AAAA,MAEV,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,KACnC;AAAA;AAAA,OAMU,OAAM,CAAC,IAA4B;AAAA,IAC9C,MAAM,MAAM,MAAM,KAAK,IAAI,EAAE;AAAA,IAC7B,IAAI,CAAC;AAAA,MAAK;AAAA,IAEV,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,WAAW;AAAA,IACrD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAC3C,MAAM,UAAU,MAAM,OAAO,EAAY;AAAA,IAEzC,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,QAAQ,YAAY,MAAM,QAAQ;AAAA,MAClC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,GAAG,aAAa,MAAM;AAAA,QAEpB,KAAK,eAAe,kBAAkB;AAAA;AAAA,MAExC,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,KACnC;AAAA;AAAA,OAQU,yBAAwB,CAAC,QAAmB,aAAoC;AAAA,IAC3F,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,WAAW;AAAA,IACrD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAC3C,MAAM,QAAQ,MAAM,MAAM,cAAc;AAAA,IACxC,MAAM,aAAa,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW,EAAE,YAAY;AAAA,IAClE,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAChD,MAAM,WAAW,YAAY,KAAK,CAAC,GAAG,iBAAiB,KAAK,WAAW,MAAM,CAAC;AAAA,IAE9E,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,UAAU,MAAM,WAAW,QAAQ;AAAA,MAEzC,QAAQ,YAAY,CAAC,UAAU;AAAA,QAC7B,MAAM,SAAU,MAAM,OAA0C;AAAA,QAChE,IAAI,QAAQ;AAAA,UACV,MAAM,MAAM,OAAO;AAAA,UAEnB,IACE,IAAI,UAAU,KAAK,aACnB,KAAK,gBAAgB,GAAG,KACxB,IAAI,WAAW,UACf,IAAI,gBACJ,IAAI,gBAAgB,YACpB;AAAA,YACA,OAAO,OAAO;AAAA,UAChB;AAAA,UACA,OAAO,SAAS;AAAA,QAClB;AAAA;AAAA,MAGF,GAAG,aAAa,MAAM;AAAA,QAEpB,KAAK,eAAe,kBAAkB;AAAA,QACtC,QAAQ;AAAA;AAAA,MAEV,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,MAClC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA;AAAA,OASW,WAAU,GAAoD;AAAA,IAC1E,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,UAAU;AAAA,IACpD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAC3C,MAAM,QAAQ,MAAM,MAAM,cAAc;AAAA,IACxC,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAEhD,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,OAA+C,CAAC;AAAA,MAEtD,MAAM,WAAW,YAAY,MAC3B,CAAC,GAAG,iBAAiB,KAAK,WAAW,EAAE,GACvC,CAAC,GAAG,iBAAiB,KAAK,WAAW,GAAQ,CAC/C;AAAA,MACA,MAAM,UAAU,MAAM,WAAW,QAAQ;AAAA,MAEzC,QAAQ,YAAY,CAAC,UAAU;AAAA,QAC7B,MAAM,SAAU,MAAM,OAA0C;AAAA,QAChE,IAAI,QAAQ;AAAA,UACV,MAAM,MAAM,OAAO;AAAA,UACnB,IAAI,IAAI,UAAU,KAAK,aAAa,KAAK,gBAAgB,GAAG,GAAG;AAAA,YAC7D,KAAK,KAAK,GAAG;AAAA,UACf;AAAA,UACA,OAAO,SAAS;AAAA,QAClB;AAAA;AAAA,MAGF,GAAG,aAAa,MAAM,QAAQ,IAAI;AAAA,MAClC,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,MAClC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA;AAAA,OAUW,qBAAoB,CAChC,cACiD;AAAA,IACjD,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,IAC5B,MAAM,KAAK,GAAG,YAAY,KAAK,WAAW,UAAU;AAAA,IACpD,MAAM,QAAQ,GAAG,YAAY,KAAK,SAAS;AAAA,IAE3C,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,OAA+C,CAAC;AAAA,MACtD,MAAM,UAAU,MAAM,WAAW;AAAA,MAEjC,QAAQ,YAAY,CAAC,UAAU;AAAA,QAC7B,MAAM,SAAU,MAAM,OAA0C;AAAA,QAChE,IAAI,QAAQ;AAAA,UACV,MAAM,MAAM,OAAO;AAAA,UAEnB,IAAI,IAAI,UAAU,KAAK,WAAW;AAAA,YAChC,OAAO,SAAS;AAAA,YAChB;AAAA,UACF;AAAA,UAEA,IAAI,OAAO,KAAK,YAAY,EAAE,WAAW,GAAG;AAAA,YAC1C,KAAK,KAAK,GAAG;AAAA,UACf,EAAO;AAAA,YAEL,IAAI,UAAU;AAAA,YACd,YAAY,KAAK,UAAU,OAAO,QAAQ,YAAY,GAAG;AAAA,cACvD,IAAI,IAAI,SAAS,OAAO;AAAA,gBACtB,UAAU;AAAA,gBACV;AAAA,cACF;AAAA,YACF;AAAA,YACA,IAAI,SAAS;AAAA,cACX,KAAK,KAAK,GAAG;AAAA,YACf;AAAA;AAAA,UAEF,OAAO,SAAS;AAAA,QAClB;AAAA;AAAA,MAGF,GAAG,aAAa,MAAM,QAAQ,IAAI;AAAA,MAClC,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,MAClC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA;AAAA,EAMK,oBAAoB,CAAC,cAAmE;AAAA,IAE9F,IAAI,iBAAiB,WAAW;AAAA,MAC9B,OAAO;AAAA,IACT;AAAA,IAEA,IAAI,OAAO,KAAK,YAAY,EAAE,WAAW,GAAG;AAAA,MAC1C,OAAO;AAAA,IACT;AAAA,IAEA,MAAM,eAAe,OAAO,KAAK,KAAK,YAAY;AAAA,IAClD,MAAM,aAAa,OAAO,KAAK,YAAY;AAAA,IAC3C,IAAI,aAAa,WAAW,WAAW,QAAQ;AAAA,MAC7C,OAAO;AAAA,IACT;AAAA,IACA,WAAW,OAAO,cAAc;AAAA,MAC9B,IAAI,KAAK,aAAa,SAAS,aAAa,MAAM;AAAA,QAChD,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,EAOD,gBAAgB,GAItB;AAAA,IACA,IAAI,CAAC,KAAK,eAAe;AAAA,MAEvB,MAAM,cAAc,mBAAmB,KAAK,aAAa,KAAK;AAAA,MAE9D,KAAK,gBAAgB,IAAI,0BAKvB,aACA,YAAY;AAAA,QAEV,MAAM,OAAO,MAAM,KAAK,WAAW;AAAA,QACnC,OAAO,IAAI,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAAA,SAE3C,CAAC,GAAG,MAAM,WAAU,GAAG,CAAC,GACxB;AAAA,QACE,QAAQ,CAAC,UAAU,EAAE,MAAM,UAAmB,KAAK,KAAK;AAAA,QACxD,QAAQ,CAAC,SAAS,aAAa,EAAE,MAAM,UAAmB,KAAK,SAAS,KAAK,QAAQ;AAAA,QACrF,QAAQ,CAAC,UAAU,EAAE,MAAM,UAAmB,KAAK,KAAK;AAAA,MAC1D,GACA;AAAA,QACE,mBAAmB;AAAA,QACnB,qBAAqB,KAAK,cAAc;AAAA,QACxC,yBAAyB,KAAK,cAAc;AAAA,MAC9C,CACF;AAAA,IACF;AAAA,IACA,OAAO,KAAK;AAAA;AAAA,EAON,+BAA+B,CACrC,UACA,cACA,YACY;AAAA,IACZ,IAAI,gBAAgB,IAAI;AAAA,IACxB,IAAI,YAAY;AAAA,IAEhB,MAAM,OAAO,YAAY;AAAA,MACvB,IAAI;AAAA,QAAW;AAAA,MACf,IAAI;AAAA,QACF,MAAM,cAAc,MAAM,KAAK,qBAAqB,YAAY;AAAA,QAChE,IAAI;AAAA,UAAW;AAAA,QACf,MAAM,aAAa,IAAI,IAAI,YAAY,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAAA,QAG5D,YAAY,IAAI,QAAQ,YAAY;AAAA,UAClC,MAAM,MAAM,cAAc,IAAI,EAAE;AAAA,UAChC,IAAI,CAAC,KAAK;AAAA,YACR,SAAS,EAAE,MAAM,UAAU,KAAK,IAAI,CAAC;AAAA,UACvC,EAAO,SAAI,CAAC,WAAU,KAAK,GAAG,GAAG;AAAA,YAC/B,SAAS,EAAE,MAAM,UAAU,KAAK,KAAK,IAAI,CAAC;AAAA,UAC5C;AAAA,QACF;AAAA,QAEA,YAAY,IAAI,QAAQ,eAAe;AAAA,UACrC,IAAI,CAAC,WAAW,IAAI,EAAE,GAAG;AAAA,YACvB,SAAS,EAAE,MAAM,UAAU,KAAK,IAAI,CAAC;AAAA,UACvC;AAAA,QACF;AAAA,QAEA,gBAAgB;AAAA,QAChB,MAAM;AAAA;AAAA,IAKV,MAAM,aAAa,YAAY,MAAM,UAAU;AAAA,IAC/C,KAAK;AAAA,IAEL,OAAO,MAAM;AAAA,MACX,YAAY;AAAA,MACZ,cAAc,UAAU;AAAA;AAAA;AAAA,EAerB,kBAAkB,CACvB,UACA,SACY;AAAA,IACZ,MAAM,aAAa,SAAS,qBAAqB;AAAA,IAGjD,IAAI,KAAK,qBAAqB,SAAS,YAAY,GAAG;AAAA,MAEpD,OAAO,KAAK,gCAAgC,UAAU,QAAS,cAAe,UAAU;AAAA,IAC1F;AAAA,IAGA,MAAM,UAAU,KAAK,iBAAiB;AAAA,IACtC,OAAO,QAAQ,UAAU,UAAU,EAAE,WAAW,CAAC;AAAA;AAAA,EAMnD,OAAO,GAAS;AAAA,IACd,IAAI,KAAK,eAAe;AAAA,MACtB,KAAK,cAAc,QAAQ;AAAA,MAC3B,KAAK,gBAAgB;AAAA,IACvB;AAAA;AAEJ;;ACz7BA,+BAAS,mCAAoB,+BAAW,2BAAiB;AAalD,IAAM,yBAAyB,qBACpC,2BACF;AAAA;AAMO,MAAM,qBAA4E;AAAA,EAclE;AAAA,EAbF;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACX,kBAA0C;AAAA,EAC1C,iBAIG;AAAA,EAEX,WAAW,CACT,QACmB,WACnB,SACA;AAAA,IAFmB;AAAA,IAGnB,KAAK,SAAS;AAAA,IACd,KAAK,WAAW,SAAS,YAAY,CAAC;AAAA,IACtC,KAAK,eAAe,SAAS,gBAAgB,CAAC;AAAA,IAE9C,IAAI,KAAK,SAAS,SAAS,GAAG;AAAA,MAC5B,MAAM,cAAc,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG;AAAA,MAC7D,KAAK,YAAY,aAAa;AAAA,IAChC,EAAO;AAAA,MACL,KAAK,YAAY;AAAA;AAAA;AAAA,EAOb,mBAAmB,CAAC,MAAoC;AAAA,IAC9D,OAAO,SAAS,SAAS,SAAS;AAAA;AAAA,EAM5B,qBAAqB,GAAW;AAAA,IACtC,IAAI,KAAK,SAAS,WAAW;AAAA,MAAG,OAAO;AAAA,IACvC,OACE,KAAK,SACF,IAAI,CAAC,MAAM,GAAG,EAAE,QAAQ,KAAK,oBAAoB,EAAE,IAAI,YAAY,EACnE,KAAK;AAAA,OAAW,IAAI;AAAA;AAAA;AAAA,EAOnB,oBAAoB,GAAa;AAAA,IACvC,OAAO,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA;AAAA,EAMhC,kBAAqB,CAAC,OAAa;AAAA,IACzC,IAAI,SAAS;AAAA,IACb,WAAW,UAAU,KAAK,UAAU;AAAA,MAClC,SAAS,OAAO,GAAG,OAAO,MAAM,KAAK,aAAa,OAAO,KAAK;AAAA,IAChE;AAAA,IACA,OAAO;AAAA;AAAA,EAMD,qBAAqB,GAAoC;AAAA,IAC/D,MAAM,SAA0C,CAAC;AAAA,IACjD,WAAW,UAAU,KAAK,UAAU;AAAA,MAClC,OAAO,OAAO,QAAQ,KAAK,aAAa,OAAO;AAAA,IACjD;AAAA,IACA,OAAO;AAAA;AAAA,EAOD,mBAAmB,GAAW;AAAA,IACpC,IAAI,KAAK,SAAS,WAAW,GAAG;AAAA,MAC9B,OAAO;AAAA,IACT;AAAA,IACA,MAAM,aAAa,KAAK,SACrB,IAAI,CAAC,MAAM;AAAA,MACV,MAAM,QAAQ,KAAK,aAAa,EAAE;AAAA,MAClC,IAAI,EAAE,SAAS,QAAQ;AAAA,QACrB,MAAM,YAAY,KAAK,iBAAiB,OAAO,KAAK,GAAG,WAAW,EAAE,OAAO;AAAA,QAC3E,OAAO,GAAG,EAAE,WAAW,KAAK,gBAAgB,SAAS;AAAA,MACvD;AAAA,MACA,MAAM,WAAW,OAAO,SAAS,CAAC;AAAA,MAClC,IAAI,CAAC,OAAO,SAAS,QAAQ,GAAG;AAAA,QAC9B,MAAM,IAAI,MAAM,qCAAqC,EAAE,UAAU,OAAO;AAAA,MAC1E;AAAA,MACA,OAAO,GAAG,EAAE,UAAU;AAAA,KACvB,EACA,KAAK,OAAO;AAAA,IACf,OAAO,UAAU;AAAA;AAAA,SAQK,oBAAoB;AAAA,EAMpC,gBAAgB,CAAC,OAAe,SAAyB;AAAA,IAC/D,IAAI,CAAC,qBAAqB,kBAAkB,KAAK,KAAK,GAAG;AAAA,MACvD,MAAM,IAAI,MACR,oBAAoB,aAAa,mDACnC;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,EAMD,eAAe,CAAC,OAAuB;AAAA,IAC7C,OAAO,MAAM,QAAQ,MAAM,IAAI;AAAA;AAAA,OAGpB,cAAa,GAAkB;AAAA,IAG1C,MAAM,gBAAgB,mCAAmC,OAAO,OAAO,SAAS,EAC7E,IAAI,CAAC,MAAM,IAAI,IAAI,EACnB,KAAK,GAAG;AAAA,IAEX,QAAQ,OAAO,cAAc,MAAM,KAAK,OAAO,IAAI,YAAY,EAAE,OAAO,cAAc,CAAC;AAAA,IAEvF,IAAI,aAAa,UAAU,SAAS,SAAS;AAAA,MAC3C,MAAM;AAAA,IACR;AAAA,IAEA,MAAM,mBAAmB,KAAK,sBAAsB;AAAA,IACpD,MAAM,oBAAoB,KAAK,qBAAqB;AAAA,IACpD,MAAM,oBACJ,kBAAkB,SAAS,IAAI,kBAAkB,KAAK,IAAI,IAAI,OAAO;AAAA,IACvE,MAAM,cAAc,kBAAkB,SAAS,IAAI,MAAM,kBAAkB,KAAK,GAAG,IAAI;AAAA,IAEvF,MAAM,iBAAiB;AAAA,iCACM,KAAK;AAAA;AAAA,QAE9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAqBJ,QAAQ,OAAO,eAAe,MAAM,KAAK,OAAO,IAAI,YAAY,EAAE,OAAO,eAAe,CAAC;AAAA,IACzF,IAAI,YAAY;AAAA,MAEd,IAAI,WAAW,SAAS,SAAS;AAAA,QAC/B,MAAM;AAAA,MACR;AAAA,IACF;AAAA,IAGA,MAAM,UAAU;AAAA,MACd,yCAAyC,sBAAsB,KAAK,cAAc;AAAA,MAClF,+CAA+C,sBAAsB,KAAK,cAAc;AAAA,MACxF,8CAA8C,6BAA6B,KAAK,cAAc;AAAA,IAChG;AAAA,IAEA,WAAW,YAAY,SAAS;AAAA,MAC9B,MAAM,KAAK,OAAO,IAAI,YAAY,EAAE,OAAO,SAAS,CAAC;AAAA,IAEvD;AAAA;AAAA,OAQW,IAAG,CAAC,KAAwD;AAAA,IACvE,MAAM,MAAM,IAAI,KAAK,EAAE,YAAY;AAAA,IACnC,IAAI,QAAQ,KAAK;AAAA,IACjB,IAAI,aAAa,IAAI,cAAc,OAAM;AAAA,IACzC,IAAI,cAAc,MAAM,iBAAgB,IAAI,KAAK;AAAA,IACjD,IAAI,SAAS,UAAU;AAAA,IACvB,IAAI,WAAW;AAAA,IACf,IAAI,mBAAmB;AAAA,IACvB,IAAI,mBAAmB;AAAA,IACvB,IAAI,aAAa;AAAA,IACjB,IAAI,YAAY;AAAA,IAEhB,MAAM,qBAAqB,KAAK,sBAAsB;AAAA,IAEtD,QAAQ,MAAM,UAAU,MAAM,KAAK,OAChC,KAAK,KAAK,SAAS,EACnB,OAAO;AAAA,SACH;AAAA,MACH,OAAO,IAAI;AAAA,MACX,aAAa,IAAI;AAAA,MACjB,OAAO,IAAI;AAAA,MACX,WAAW,IAAI;AAAA,MACf,YAAY,IAAI;AAAA,MAChB,aAAa,IAAI;AAAA,MACjB,aAAa,IAAI;AAAA,MACjB,YAAY,IAAI;AAAA,MAChB,UAAU,IAAI;AAAA,MACd,kBAAkB,IAAI;AAAA,MACtB,kBAAkB,IAAI;AAAA,IACxB,CAAC,EACA,OAAO,IAAI,EACX,OAAO;AAAA,IAEV,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,IAAI,CAAC;AAAA,MAAM,MAAM,IAAI,MAAM,wBAAwB;AAAA,IAEnD,IAAI,KAAK,KAAK;AAAA,IACd,OAAO,IAAI;AAAA;AAAA,OAQA,IAAG,CAAC,IAAmE;AAAA,IAClF,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO,GAAG,EACV,GAAG,MAAM,EAAE,EACX,GAAG,SAAS,KAAK,SAAS;AAAA,IAE7B,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IAErC,QAAQ,MAAM,UAAU,MAAM,MAAM,OAAO;AAAA,IAE3C,IAAI,OAAO;AAAA,MACT,IAAI,MAAM,SAAS;AAAA,QAAY;AAAA,MAC/B,MAAM;AAAA,IACR;AAAA,IAEA,OAAO;AAAA;AAAA,OASI,KAAI,CACf,SAAoB,UAAU,SAC9B,MAAc,KAC8B;AAAA,IAC5C,MAAM,OAAO,GAAG,KAAK;AAAA,IAErB,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO,GAAG,EACV,GAAG,SAAS,KAAK,SAAS,EAC1B,GAAG,UAAU,MAAM;AAAA,IAEtB,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IAErC,QAAQ,MAAM,UAAU,MAAM,MAAM,MAAM,aAAa,EAAE,WAAW,KAAK,CAAC,EAAE,MAAM,GAAG;AAAA,IAErF,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,OAAQ,QAA8C,CAAC;AAAA;AAAA,OAS5C,KAAI,CAAC,UAAwE;AAAA,IACxF,MAAM,mBAAmB,KAAK,oBAAoB;AAAA,IAClD,MAAM,qBAAqB,KAAK,iBAAiB,KAAK,WAAW,WAAW;AAAA,IAC5E,MAAM,oBAAoB,KAAK,iBAAiB,UAAU,UAAU;AAAA,IACpE,MAAM,mBAAmB,KAAK,gBAAgB,kBAAkB;AAAA,IAChE,MAAM,kBAAkB,KAAK,gBAAgB,iBAAiB;AAAA,IAG9D,MAAM,MAAM;AAAA,eACD,KAAK;AAAA,sBACE,UAAU,qEAAqE;AAAA;AAAA;AAAA,eAGtF,KAAK;AAAA,yBACK;AAAA,wBACD,UAAU;AAAA,UACxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQN,QAAQ,MAAM,UAAU,MAAM,KAAK,OAAO,IAAI,YAAY,EAAE,OAAO,IAAI,CAAC;AAAA,IAExE,IAAI;AAAA,MAAO,MAAM;AAAA,IAGjB,IAAI,CAAC,QAAQ,CAAC,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW,GAAG;AAAA,MACtD;AAAA,IACF;AAAA,IAEA,OAAO,KAAK;AAAA;AAAA,OAQD,KAAI,CAAC,SAAS,UAAU,SAA0B;AAAA,IAC7D,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO,KAAK,EAAE,OAAO,SAAS,MAAM,KAAK,CAAC,EAC1C,GAAG,SAAS,KAAK,SAAS,EAC1B,GAAG,UAAU,MAAM;AAAA,IAEtB,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IAErC,QAAQ,OAAO,UAAU,MAAM;AAAA,IAE/B,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,OAAO,SAAS;AAAA;AAAA,OASJ,WAAU,GAAoD;AAAA,IAC1E,IAAI,QAAQ,KAAK,OAAO,KAAK,KAAK,SAAS,EAAE,OAAO,GAAG,EAAE,GAAG,SAAS,KAAK,SAAS;AAAA,IAEnF,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IAErC,QAAQ,MAAM,UAAU,MAAM;AAAA,IAE9B,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,OAAQ,QAAQ,CAAC;AAAA;AAAA,OASN,SAAQ,CAAC,YAA4D;AAAA,IAChF,MAAM,MAAM,IAAI,KAAK,EAAE,YAAY;AAAA,IAGnC,IAAI,WAAW,WAAW,UAAU,UAAU;AAAA,MAC5C,IAAI,SAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO;AAAA,QACN,QAAQ,WAAW;AAAA,QACnB,UAAU;AAAA,QACV,kBAAkB;AAAA,QAClB,kBAAkB;AAAA,QAClB,cAAc;AAAA,QACd,aAAa;AAAA,MACf,CAAC,EACA,GAAG,MAAM,WAAW,EAAE,EACtB,GAAG,SAAS,KAAK,SAAS;AAAA,MAC7B,SAAQ,KAAK,mBAAmB,MAAK;AAAA,MACrC,QAAQ,kBAAU,MAAM;AAAA,MACxB,IAAI;AAAA,QAAO,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,IAGA,IAAI,WAAW,KAAK,OACjB,KAAK,KAAK,SAAS,EACnB,OAAO,2BAA2B,EAClC,GAAG,MAAM,WAAW,EAAY,EAChC,GAAG,SAAS,KAAK,SAAS;AAAA,IAC7B,WAAW,KAAK,mBAAmB,QAAQ;AAAA,IAC3C,QAAQ,MAAM,SAAS,OAAO,aAAa,MAAM,SAAS,OAAO;AAAA,IACjE,IAAI;AAAA,MAAU,MAAM;AAAA,IACpB,MAAM,kBAAmB,SAAS,gBAAuC;AAAA,IACzE,MAAM,aAAc,SAAS,eAAsC,WAAW,eAAe;AAAA,IAC7F,MAAM,eAAe,kBAAkB;AAAA,IAEvC,IAAI,WAAW,WAAW,UAAU,SAAS;AAAA,MAE3C,IAAI,eAAe,YAAY;AAAA,QAE7B,IAAI,YAAY,KAAK,OAClB,KAAK,KAAK,SAAS,EACnB,OAAO;AAAA,UACN,QAAQ,UAAU;AAAA,UAClB,OAAO;AAAA,UACP,YAAY;AAAA,UACZ,UAAU;AAAA,UACV,kBAAkB;AAAA,UAClB,kBAAkB;AAAA,UAClB,cAAc;AAAA,UACd,aAAa;AAAA,QACf,CAAC,EACA,GAAG,MAAM,WAAW,EAAE,EACtB,GAAG,SAAS,KAAK,SAAS;AAAA,QAC7B,YAAY,KAAK,mBAAmB,SAAS;AAAA,QAC7C,QAAQ,OAAO,cAAc,MAAM;AAAA,QACnC,IAAI;AAAA,UAAW,MAAM;AAAA,QACrB;AAAA,MACF;AAAA,MAGA,IAAI,SAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO;AAAA,QACN,OAAO,WAAW,SAAS;AAAA,QAC3B,YAAY,WAAW,cAAc;AAAA,QACrC,QAAQ,WAAW;AAAA,QACnB,WAAW,WAAW;AAAA,QACtB,UAAU;AAAA,QACV,kBAAkB;AAAA,QAClB,kBAAkB;AAAA,QAClB,cAAc;AAAA,QACd,aAAa;AAAA,MACf,CAAC,EACA,GAAG,MAAM,WAAW,EAAE,EACtB,GAAG,SAAS,KAAK,SAAS;AAAA,MAC7B,SAAQ,KAAK,mBAAmB,MAAK;AAAA,MACrC,QAAQ,kBAAU,MAAM;AAAA,MACxB,IAAI;AAAA,QAAO,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,IAEA,IAAI,WAAW,WAAW,UAAU,aAAa,WAAW,WAAW,UAAU,QAAQ;AAAA,MACvF,IAAI,SAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO;AAAA,QACN,QAAQ,WAAW,UAAU;AAAA,QAC7B,OAAO,WAAW,SAAS;AAAA,QAC3B,YAAY,WAAW,cAAc;AAAA,QACrC,QAAQ,WAAW;AAAA,QACnB,UAAU;AAAA,QACV,kBAAkB;AAAA,QAClB,kBAAkB;AAAA,QAClB,cAAc;AAAA,QACd,cAAc;AAAA,QACd,aAAa;AAAA,MACf,CAAC,EACA,GAAG,MAAM,WAAW,EAAE,EACtB,GAAG,SAAS,KAAK,SAAS;AAAA,MAC7B,SAAQ,KAAK,mBAAmB,MAAK;AAAA,MACrC,QAAQ,kBAAU,MAAM;AAAA,MACxB,IAAI;AAAA,QAAO,MAAM;AAAA,MACjB;AAAA,IACF;AAAA,IAGA,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO;AAAA,MACN,QAAQ,WAAW;AAAA,MACnB,QAAQ,WAAW,UAAU;AAAA,MAC7B,OAAO,WAAW,SAAS;AAAA,MAC3B,YAAY,WAAW,cAAc;AAAA,MACrC,WAAW,WAAW,aAAa;AAAA,MACnC,cAAc;AAAA,MACd,aAAa;AAAA,IACf,CAAC,EACA,GAAG,MAAM,WAAW,EAAE,EACtB,GAAG,SAAS,KAAK,SAAS;AAAA,IAC7B,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IACrC,QAAQ,UAAU,MAAM;AAAA,IACxB,IAAI;AAAA,MAAO,MAAM;AAAA;AAAA,OAMN,QAAO,CAAC,OAA+B;AAAA,IAClD,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO;AAAA,MACN,QAAQ,UAAU;AAAA,MAClB,WAAW;AAAA,MACX,UAAU;AAAA,MACV,kBAAkB;AAAA,MAClB,kBAAkB;AAAA,IACpB,CAAC,EACA,GAAG,MAAM,KAAK,EACd,GAAG,SAAS,KAAK,SAAS;AAAA,IAE7B,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IACrC,QAAQ,UAAU,MAAM;AAAA,IACxB,IAAI;AAAA,MAAO,MAAM;AAAA;AAAA,OAMN,UAAS,GAAkB;AAAA,IACtC,IAAI,QAAQ,KAAK,OAAO,KAAK,KAAK,SAAS,EAAE,OAAO,EAAE,GAAG,SAAS,KAAK,SAAS;AAAA,IAChF,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IACrC,QAAQ,UAAU,MAAM;AAAA,IAExB,IAAI;AAAA,MAAO,MAAM;AAAA;AAAA,OAQN,eAAc,CAAC,OAAsC;AAAA,IAChE,MAAM,cAAc,MAAM,iBAAgB,KAAK;AAAA,IAE/C,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO,QAAQ,EACf,GAAG,eAAe,WAAW,EAC7B,GAAG,SAAS,KAAK,SAAS,EAC1B,GAAG,UAAU,UAAU,SAAS;AAAA,IAEnC,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IAErC,QAAQ,MAAM,UAAU,MAAM,MAAM,OAAO;AAAA,IAE3C,IAAI,OAAO;AAAA,MACT,IAAI,MAAM,SAAS;AAAA,QAAY,OAAO;AAAA,MACtC,MAAM;AAAA,IACR;AAAA,IAEA,OAAO,MAAM,UAAU;AAAA;AAAA,OASZ,MAAK,CAAC,OAA+B;AAAA,IAChD,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO,EAAE,QAAQ,UAAU,SAAS,CAAC,EACrC,GAAG,MAAM,KAAK,EACd,GAAG,SAAS,KAAK,SAAS;AAAA,IAE7B,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IACrC,QAAQ,UAAU,MAAM;AAAA,IAExB,IAAI;AAAA,MAAO,MAAM;AAAA;AAAA,OAQN,WAAU,CAAC,YAAqE;AAAA,IAC3F,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO,GAAG,EACV,GAAG,cAAc,UAAU,EAC3B,GAAG,SAAS,KAAK,SAAS;AAAA,IAE7B,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IACrC,QAAQ,MAAM,UAAU,MAAM;AAAA,IAE9B,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,OAAQ,QAAmD,CAAC;AAAA;AAAA,OAMjD,aAAY,CACvB,OACA,UACA,SACA,SACe;AAAA,IACf,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO;AAAA,MACN;AAAA,MACA,kBAAkB;AAAA,MAClB,kBAAkB;AAAA,IACpB,CAAC,EACA,GAAG,MAAM,KAAK,EACd,GAAG,SAAS,KAAK,SAAS;AAAA,IAE7B,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IACrC,QAAQ,UAAU,MAAM;AAAA,IAExB,IAAI;AAAA,MAAO,MAAM;AAAA;AAAA,OAMN,OAAM,CAAC,OAA+B;AAAA,IACjD,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO,EACP,GAAG,MAAM,KAAK,EACd,GAAG,SAAS,KAAK,SAAS;AAAA,IAE7B,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IACrC,QAAQ,UAAU,MAAM;AAAA,IAExB,IAAI;AAAA,MAAO,MAAM;AAAA;AAAA,OAQN,yBAAwB,CAAC,QAAmB,aAAoC;AAAA,IAC3F,MAAM,aAAa,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW,EAAE,YAAY;AAAA,IAElE,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO,EACP,GAAG,SAAS,KAAK,SAAS,EAC1B,GAAG,UAAU,MAAM,EACnB,IAAI,gBAAgB,MAAM,IAAI,EAC9B,IAAI,gBAAgB,UAAU;AAAA,IAEjC,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IACrC,QAAQ,UAAU,MAAM;AAAA,IAExB,IAAI;AAAA,MAAO,MAAM;AAAA;AAAA,EAQX,mBAAmB,CACzB,KACA,cACS;AAAA,IACT,IAAI,CAAC;AAAA,MAAK,OAAO;AAAA,IAGjB,IAAI,IAAI,UAAU,KAAK,WAAW;AAAA,MAChC,OAAO;AAAA,IACT;AAAA,IAGA,IAAI,gBAAgB,OAAO,KAAK,YAAY,EAAE,WAAW,GAAG;AAAA,MAC1D,OAAO;AAAA,IACT;AAAA,IAGA,MAAM,eAAe,gBAAgB,KAAK;AAAA,IAG1C,IAAI,OAAO,KAAK,YAAY,EAAE,WAAW,GAAG;AAAA,MAC1C,OAAO;AAAA,IACT;AAAA,IAGA,YAAY,KAAK,UAAU,OAAO,QAAQ,YAAY,GAAG;AAAA,MACvD,IAAI,IAAI,SAAS,OAAO;AAAA,QACtB,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,EAMD,oBAAoB,CAAC,cAAmE;AAAA,IAE9F,IAAI,iBAAiB,WAAW;AAAA,MAC9B,OAAO;AAAA,IACT;AAAA,IAEA,IAAI,OAAO,KAAK,YAAY,EAAE,WAAW,GAAG;AAAA,MAC1C,OAAO;AAAA,IACT;AAAA,IAEA,MAAM,eAAe,OAAO,KAAK,KAAK,YAAY;AAAA,IAClD,MAAM,aAAa,OAAO,KAAK,YAAY;AAAA,IAC3C,IAAI,aAAa,WAAW,WAAW,QAAQ;AAAA,MAC7C,OAAO;AAAA,IACT;AAAA,IACA,WAAW,OAAO,cAAc;AAAA,MAC9B,IAAI,KAAK,aAAa,SAAS,aAAa,MAAM;AAAA,QAChD,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,OAUK,qBAAoB,CAChC,cACiD;AAAA,IACjD,IAAI,QAAQ,KAAK,OAAO,KAAK,KAAK,SAAS,EAAE,OAAO,GAAG,EAAE,GAAG,SAAS,KAAK,SAAS;AAAA,IAGnF,YAAY,KAAK,UAAU,OAAO,QAAQ,YAAY,GAAG;AAAA,MACvD,QAAQ,MAAM,GAAG,KAAK,KAAK;AAAA,IAC7B;AAAA,IAEA,QAAQ,MAAM,UAAU,MAAM;AAAA,IAE9B,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,OAAQ,QAAQ,CAAC;AAAA;AAAA,EAWZ,kBAAkB,CACvB,UACA,SACY;AAAA,IACZ,OAAO,KAAK,+BAA+B,UAAU,SAAS,YAAY;AAAA;AAAA,EAUlE,8BAA8B,CACtC,UACA,cACY;AAAA,IACZ,MAAM,cAAc,SAAS,KAAK,aAAa,KAAK,aAAa,KAAK,IAAI;AAAA,IAE1E,KAAK,kBAAkB,KAAK,OACzB,QAAQ,WAAW,EACnB,GACC,oBACA;AAAA,MACE,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,OAAO,KAAK;AAAA,MACZ,QAAQ,YAAY,KAAK;AAAA,IAC3B,GACA,CAAC,YAAY;AAAA,MAEX,MAAM,SAAS,QAAQ;AAAA,MACvB,MAAM,SAAS,QAAQ;AAAA,MAGvB,MAAM,aAAa,KAAK,oBAAoB,QAAQ,YAAY;AAAA,MAChE,MAAM,aAAa,KAAK,oBAAoB,QAAQ,YAAY;AAAA,MAEhE,IAAI,CAAC,cAAc,CAAC,YAAY;AAAA,QAC9B;AAAA,MACF;AAAA,MAEA,SAAS;AAAA,QACP,MAAM,QAAQ,UAAU,YAAY;AAAA,QACpC,KACE,UAAU,OAAO,KAAK,MAAM,EAAE,SAAS,IAClC,SACD;AAAA,QACN,KACE,UAAU,OAAO,KAAK,MAAM,EAAE,SAAS,IAClC,SACD;AAAA,MACR,CAAC;AAAA,KAEL,EACC,UAAU;AAAA,IAEb,OAAO,MAAM;AAAA,MACX,IAAI,KAAK,iBAAiB;AAAA,QACxB,KAAK,OAAO,cAAc,KAAK,eAAe;AAAA,QAC9C,KAAK,kBAAkB;AAAA,MACzB;AAAA;AAAA;AAAA,EAQI,iBAAiB,GAIvB;AAAA,IACA,IAAI,CAAC,KAAK,gBAAgB;AAAA,MACxB,KAAK,iBAAiB,IAAI,2BAKxB,YAAY;AAAA,QAEV,MAAM,OAAO,MAAM,KAAK,WAAW;AAAA,QACnC,OAAO,IAAI,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAAA,SAE3C,CAAC,GAAG,MAAM,WAAU,GAAG,CAAC,GACxB;AAAA,QACE,QAAQ,CAAC,UAAU,EAAE,MAAM,UAAmB,KAAK,KAAK;AAAA,QACxD,QAAQ,CAAC,SAAS,aAAa,EAAE,MAAM,UAAmB,KAAK,SAAS,KAAK,QAAQ;AAAA,QACrF,QAAQ,CAAC,UAAU,EAAE,MAAM,UAAmB,KAAK,KAAK;AAAA,MAC1D,CACF;AAAA,IACF;AAAA,IACA,OAAO,KAAK;AAAA;AAAA,EAON,sCAAsC,CAC5C,UACA,cACA,YACY;AAAA,IACZ,IAAI,gBAAgB,IAAI;AAAA,IACxB,IAAI,YAAY;AAAA,IAEhB,MAAM,OAAO,YAAY;AAAA,MACvB,IAAI;AAAA,QAAW;AAAA,MACf,IAAI;AAAA,QACF,MAAM,cAAc,MAAM,KAAK,qBAAqB,YAAY;AAAA,QAChE,IAAI;AAAA,UAAW;AAAA,QACf,MAAM,aAAa,IAAI,IAAI,YAAY,IAAI,CAAC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;AAAA,QAG5D,YAAY,IAAI,QAAQ,YAAY;AAAA,UAClC,MAAM,MAAM,cAAc,IAAI,EAAE;AAAA,UAChC,IAAI,CAAC,KAAK;AAAA,YACR,SAAS,EAAE,MAAM,UAAU,KAAK,IAAI,CAAC;AAAA,UACvC,EAAO,SAAI,CAAC,WAAU,KAAK,GAAG,GAAG;AAAA,YAC/B,SAAS,EAAE,MAAM,UAAU,KAAK,KAAK,IAAI,CAAC;AAAA,UAC5C;AAAA,QACF;AAAA,QAEA,YAAY,IAAI,QAAQ,eAAe;AAAA,UACrC,IAAI,CAAC,WAAW,IAAI,EAAE,GAAG;AAAA,YACvB,SAAS,EAAE,MAAM,UAAU,KAAK,IAAI,CAAC;AAAA,UACvC;AAAA,QACF;AAAA,QAEA,gBAAgB;AAAA,QAChB,MAAM;AAAA;AAAA,IAKV,MAAM,aAAa,YAAY,MAAM,UAAU;AAAA,IAC/C,KAAK;AAAA,IAEL,OAAO,MAAM;AAAA,MACX,YAAY;AAAA,MACZ,cAAc,UAAU;AAAA;AAAA;AAAA,EAclB,6BAA6B,CACrC,UACA,SACY;AAAA,IACZ,MAAM,aAAa,SAAS,qBAAqB;AAAA,IAGjD,IAAI,KAAK,qBAAqB,SAAS,YAAY,GAAG;AAAA,MAEpD,OAAO,KAAK,uCACV,UACA,QAAS,cACT,UACF;AAAA,IACF;AAAA,IAGA,MAAM,UAAU,KAAK,kBAAkB;AAAA,IACvC,OAAO,QAAQ,UAAU,UAAU,EAAE,WAAW,CAAC;AAAA;AAErD;;ACv7BA,+BAAS;AASF,IAAM,kCAAkC,qBAC7C,+BACF;AAAA;AA+BO,MAAM,4BAA2D;AAAA,EAC9D;AAAA,EACA;AAAA,EACS;AAAA,EACA;AAAA,EACA;AAAA,EAEE;AAAA,EAEA;AAAA,EAEnB,WAAW,CAAC,UAA8C,CAAC,GAAG;AAAA,IAC5D,KAAK,mBAAmB;AAAA,IACxB,KAAK,WAAW,QAAQ,YAAY,CAAC;AAAA,IACrC,KAAK,eAAe,QAAQ,gBAAgB,CAAC;AAAA,IAG7C,IAAI,KAAK,SAAS,SAAS,GAAG;AAAA,MAC5B,MAAM,cAAc,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG;AAAA,MAC7D,KAAK,qBAAqB,yBAAyB;AAAA,MACnD,KAAK,yBAAyB,6BAA6B;AAAA,IAC7D,EAAO;AAAA,MACL,KAAK,qBAAqB;AAAA,MAC1B,KAAK,yBAAyB;AAAA;AAAA;AAAA,EAO1B,oBAAoB,GAAa;AAAA,IACvC,OAAO,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA;AAAA,EAMhC,eAAe,CAAC,QAA0C;AAAA,IAChE,YAAY,KAAK,UAAU,OAAO,QAAQ,KAAK,YAAY,GAAG;AAAA,MAC5D,IAAI,OAAO,SAAS,OAAO;AAAA,QACzB,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAAA,EAMD,kBAAkB,GAA2B;AAAA,IACnD,OAAO,KAAK,SAAS,IAAI,CAAC,MAAM,KAAK,aAAa,EAAE,KAAK;AAAA;AAAA,OAG7C,eAAc,GAAyB;AAAA,IACnD,IAAI,KAAK;AAAA,MAAa,OAAO,KAAK;AAAA,IAClC,MAAM,KAAK,cAAc;AAAA,IACzB,OAAO,KAAK;AAAA;AAAA,OAGA,mBAAkB,GAAyB;AAAA,IACvD,IAAI,KAAK;AAAA,MAAiB,OAAO,KAAK;AAAA,IACtC,MAAM,KAAK,cAAc;AAAA,IACzB,OAAO,KAAK;AAAA;AAAA,OAGD,cAAa,GAAkB;AAAA,IAC1C,MAAM,oBAAoB,KAAK,qBAAqB;AAAA,IAGpD,MAAM,eAAe,CAAC,aAAiC;AAAA,MACrD,OAAO,CAAC,GAAG,mBAAmB,GAAG,QAAQ;AAAA;AAAA,IAG3C,MAAM,mBAA8C;AAAA,MAClD;AAAA,QACE,MAAM;AAAA,QACN,SAAS,aAAa,CAAC,cAAc,aAAa,CAAC;AAAA,QACnD,SAAS,EAAE,QAAQ,MAAM;AAAA,MAC3B;AAAA,IACF;AAAA,IAEA,KAAK,cAAc,MAAM,qBACvB,KAAK,oBACL,MACA,kBACA,KAAK,gBACP;AAAA,IAEA,MAAM,uBAAkD;AAAA,MACtD;AAAA,QACE,MAAM;AAAA,QACN,SAAS,aAAa,CAAC,YAAY,CAAC;AAAA,QACpC,SAAS,EAAE,QAAQ,KAAK;AAAA,MAC1B;AAAA,IACF;AAAA,IAEA,KAAK,kBAAkB,MAAM,qBAC3B,KAAK,wBACL,aAAa,CAAC,YAAY,CAAC,EAAE,KAAK,GAAG,GACrC,sBACA,KAAK,gBACP;AAAA;AAAA,OAGW,gBAAe,CAAC,WAAkC;AAAA,IAC7D,MAAM,KAAK,MAAM,KAAK,eAAe;AAAA,IACrC,MAAM,KAAK,GAAG,YAAY,KAAK,oBAAoB,WAAW;AAAA,IAC9D,MAAM,QAAQ,GAAG,YAAY,KAAK,kBAAkB;AAAA,IAEpD,MAAM,SAA0B;AAAA,MAC9B,IAAI,OAAO,WAAW;AAAA,MACtB,YAAY;AAAA,MACZ,aAAa,IAAI,KAAK,EAAE,YAAY;AAAA,IACtC;AAAA,IAGA,YAAY,KAAK,UAAU,OAAO,QAAQ,KAAK,YAAY,GAAG;AAAA,MAC3D,OAAmC,OAAO;AAAA,IAC7C;AAAA,IAEA,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,UAAU,MAAM,IAAI,MAAM;AAAA,MAChC,GAAG,aAAa,MAAM,QAAQ;AAAA,MAC9B,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,MAClC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA;AAAA,OAGU,kBAAiB,CAAC,WAAmB,iBAA0C;AAAA,IAC1F,MAAM,KAAK,MAAM,KAAK,eAAe;AAAA,IACrC,MAAM,KAAK,GAAG,YAAY,KAAK,oBAAoB,UAAU;AAAA,IAC7D,MAAM,QAAQ,GAAG,YAAY,KAAK,kBAAkB;AAAA,IACpD,MAAM,QAAQ,MAAM,MAAM,mBAAmB;AAAA,IAC7C,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAEhD,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,IAAI,QAAQ;AAAA,MACZ,MAAM,WAAW,YAAY,MAC3B,CAAC,GAAG,iBAAiB,WAAW,eAAe,GAC/C,CAAC,GAAG,iBAAiB,WAAW,GAAQ,GACxC,MACA,KACF;AAAA,MACA,MAAM,UAAU,MAAM,WAAW,QAAQ;AAAA,MAEzC,QAAQ,YAAY,CAAC,UAAU;AAAA,QAC7B,MAAM,SAAU,MAAM,OAA0C;AAAA,QAChE,IAAI,QAAQ;AAAA,UACV,MAAM,SAAS,OAAO;AAAA,UACtB,IAAI,KAAK,gBAAgB,MAAM,GAAG;AAAA,YAChC;AAAA,UACF;AAAA,UACA,OAAO,SAAS;AAAA,QAClB;AAAA;AAAA,MAGF,GAAG,aAAa,MAAM,QAAQ,KAAK;AAAA,MACnC,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,MAClC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA;AAAA,OAGU,2BAA0B,CACrC,WACA,QAC6B;AAAA,IAC7B,MAAM,KAAK,MAAM,KAAK,eAAe;AAAA,IACrC,MAAM,KAAK,GAAG,YAAY,KAAK,oBAAoB,UAAU;AAAA,IAC7D,MAAM,QAAQ,GAAG,YAAY,KAAK,kBAAkB;AAAA,IACpD,MAAM,QAAQ,MAAM,MAAM,mBAAmB;AAAA,IAC7C,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAEhD,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,aAAuB,CAAC;AAAA,MAC9B,MAAM,WAAW,YAAY,MAC3B,CAAC,GAAG,iBAAiB,WAAW,EAAE,GAClC,CAAC,GAAG,iBAAiB,WAAW,GAAQ,CAC1C;AAAA,MACA,MAAM,UAAU,MAAM,WAAW,QAAQ;AAAA,MAEzC,QAAQ,YAAY,CAAC,UAAU;AAAA,QAC7B,MAAM,SAAU,MAAM,OAA0C;AAAA,QAChE,IAAI,QAAQ;AAAA,UACV,MAAM,SAAS,OAAO;AAAA,UACtB,IAAI,KAAK,gBAAgB,MAAM,GAAG;AAAA,YAChC,WAAW,KAAK,OAAO,WAAW;AAAA,UACpC;AAAA,UACA,OAAO,SAAS;AAAA,QAClB;AAAA;AAAA,MAGF,GAAG,aAAa,MAAM;AAAA,QAEpB,WAAW,KAAK;AAAA,QAChB,QAAQ,WAAW,OAAO;AAAA;AAAA,MAE5B,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,MAClC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA;AAAA,OAGU,qBAAoB,CAAC,WAAgD;AAAA,IAChF,MAAM,KAAK,MAAM,KAAK,mBAAmB;AAAA,IACzC,MAAM,KAAK,GAAG,YAAY,KAAK,wBAAwB,UAAU;AAAA,IACjE,MAAM,QAAQ,GAAG,YAAY,KAAK,sBAAsB;AAAA,IACxD,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAChD,MAAM,MAAM,CAAC,GAAG,iBAAiB,SAAS,EAAE,KAAK,GAAG;AAAA,IAEpD,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,UAAU,MAAM,IAAI,GAAG;AAAA,MAC7B,QAAQ,YAAY,MAAM;AAAA,QACxB,MAAM,SAAS,QAAQ;AAAA,QACvB,IAAI,UAAU,KAAK,gBAAgB,MAAM,GAAG;AAAA,UAC1C,QAAQ,OAAO,iBAAiB;AAAA,QAClC,EAAO;AAAA,UACL,QAAQ,SAAS;AAAA;AAAA;AAAA,MAGrB,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,MAC5C,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,KACnC;AAAA;AAAA,OAGU,qBAAoB,CAAC,WAAmB,iBAAwC;AAAA,IAC3F,MAAM,KAAK,MAAM,KAAK,mBAAmB;AAAA,IACzC,MAAM,KAAK,GAAG,YAAY,KAAK,wBAAwB,WAAW;AAAA,IAClE,MAAM,QAAQ,GAAG,YAAY,KAAK,sBAAsB;AAAA,IACxD,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAChD,MAAM,MAAM,CAAC,GAAG,iBAAiB,SAAS,EAAE,KAAK,GAAG;AAAA,IAEpD,MAAM,SAA2D;AAAA,MAC/D,YAAY;AAAA,MACZ,mBAAmB;AAAA,IACrB;AAAA,IAGA,YAAY,GAAG,UAAU,OAAO,QAAQ,KAAK,YAAY,GAAG;AAAA,MAC1D,OAAO,KAAK;AAAA,IACd;AAAA,IAGC,OACC,KAAK,qBAAqB,EAAE,OAAO,CAAC,YAAY,CAAC,EAAE,KAAK,GAAG,KACzD;AAAA,IAEJ,OAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AAAA,MACtC,MAAM,UAAU,MAAM,IAAI,MAAM;AAAA,MAChC,GAAG,aAAa,MAAM,QAAQ;AAAA,MAC9B,GAAG,UAAU,MAAM,OAAO,GAAG,KAAK;AAAA,MAClC,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA;AAAA,OAGU,MAAK,CAAC,WAAkC;AAAA,IAEnD,MAAM,SAAS,MAAM,KAAK,eAAe;AAAA,IACzC,MAAM,SAAS,OAAO,YAAY,KAAK,oBAAoB,WAAW;AAAA,IACtE,MAAM,YAAY,OAAO,YAAY,KAAK,kBAAkB;AAAA,IAC5D,MAAM,YAAY,UAAU,MAAM,mBAAmB;AAAA,IACrD,MAAM,kBAAkB,KAAK,mBAAmB;AAAA,IAEhD,MAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAAA,MAC3C,MAAM,WAAW,YAAY,MAC3B,CAAC,GAAG,iBAAiB,WAAW,EAAE,GAClC,CAAC,GAAG,iBAAiB,WAAW,GAAQ,CAC1C;AAAA,MACA,MAAM,UAAU,UAAU,WAAW,QAAQ;AAAA,MAE7C,QAAQ,YAAY,CAAC,UAAU;AAAA,QAC7B,MAAM,SAAU,MAAM,OAA0C;AAAA,QAChE,IAAI,QAAQ;AAAA,UACV,MAAM,SAAS,OAAO;AAAA,UACtB,IAAI,KAAK,gBAAgB,MAAM,GAAG;AAAA,YAChC,OAAO,OAAO;AAAA,UAChB;AAAA,UACA,OAAO,SAAS;AAAA,QAClB;AAAA;AAAA,MAGF,OAAO,aAAa,MAAM,QAAQ;AAAA,MAClC,OAAO,UAAU,MAAM,OAAO,OAAO,KAAK;AAAA,MAC1C,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA,IAGD,MAAM,SAAS,MAAM,KAAK,mBAAmB;AAAA,IAC7C,MAAM,SAAS,OAAO,YAAY,KAAK,wBAAwB,WAAW;AAAA,IAC1E,MAAM,YAAY,OAAO,YAAY,KAAK,sBAAsB;AAAA,IAChE,MAAM,MAAM,CAAC,GAAG,iBAAiB,SAAS,EAAE,KAAK,GAAG;AAAA,IAEpD,MAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAAA,MAC3C,MAAM,UAAU,UAAU,OAAO,GAAG;AAAA,MACpC,OAAO,aAAa,MAAM,QAAQ;AAAA,MAClC,OAAO,UAAU,MAAM,OAAO,OAAO,KAAK;AAAA,MAC1C,QAAQ,UAAU,MAAM,OAAO,QAAQ,KAAK;AAAA,KAC7C;AAAA;AAEL;;AClVA,+BAAS;AAIF,IAAM,gCAAgC,qBAC3C,8BACF;AAAA;AAMO,MAAM,2BAA0D;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEnB,WAAW,CAAC,QAAiB,SAAqC;AAAA,IAChE,KAAK,SAAS;AAAA,IACd,KAAK,WAAW,SAAS,YAAY,CAAC;AAAA,IACtC,KAAK,eAAe,SAAS,gBAAgB,CAAC;AAAA,IAG9C,IAAI,KAAK,SAAS,SAAS,GAAG;AAAA,MAC5B,MAAM,cAAc,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI,EAAE,KAAK,GAAG;AAAA,MAC7D,KAAK,qBAAqB,yBAAyB;AAAA,MACnD,KAAK,yBAAyB,6BAA6B;AAAA,IAC7D,EAAO;AAAA,MACL,KAAK,qBAAqB;AAAA,MAC1B,KAAK,yBAAyB;AAAA;AAAA;AAAA,EAO1B,mBAAmB,CAAC,MAAoC;AAAA,IAC9D,OAAO,SAAS,SAAS,SAAS;AAAA;AAAA,EAM5B,qBAAqB,GAAW;AAAA,IACtC,IAAI,KAAK,SAAS,WAAW;AAAA,MAAG,OAAO;AAAA,IACvC,OACE,KAAK,SACF,IAAI,CAAC,MAAM,GAAG,EAAE,QAAQ,KAAK,oBAAoB,EAAE,IAAI,YAAY,EACnE,KAAK;AAAA,SAAa,IAAI;AAAA;AAAA;AAAA,EAOrB,oBAAoB,GAAa;AAAA,IACvC,OAAO,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI;AAAA;AAAA,EAMhC,kBAAqB,CAAC,OAAa;AAAA,IACzC,IAAI,SAAS;AAAA,IACb,WAAW,UAAU,KAAK,UAAU;AAAA,MAClC,SAAS,OAAO,GAAG,OAAO,MAAM,KAAK,aAAa,OAAO,KAAK;AAAA,IAChE;AAAA,IACA,OAAO;AAAA;AAAA,EAMD,qBAAqB,GAAoC;AAAA,IAC/D,MAAM,SAA0C,CAAC;AAAA,IACjD,WAAW,UAAU,KAAK,UAAU;AAAA,MAClC,OAAO,OAAO,QAAQ,KAAK,aAAa,OAAO;AAAA,IACjD;AAAA,IACA,OAAO;AAAA;AAAA,OAGI,cAAa,GAAkB;AAAA,IAC1C,MAAM,mBAAmB,KAAK,sBAAsB;AAAA,IACpD,MAAM,oBAAoB,KAAK,qBAAqB;AAAA,IACpD,MAAM,oBACJ,kBAAkB,SAAS,IAAI,kBAAkB,KAAK,IAAI,IAAI,OAAO;AAAA,IACvE,MAAM,cAAc,kBAAkB,SAAS,IAAI,MAAM,kBAAkB,KAAK,GAAG,IAAI;AAAA,IAGvF,MAAM,qBAAqB;AAAA,mCACI,KAAK;AAAA;AAAA,UAE9B;AAAA;AAAA;AAAA;AAAA,IAKN,QAAQ,OAAO,mBAAmB,MAAM,KAAK,OAAO,IAAI,YAAY;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,IACD,IAAI,kBAAkB,eAAe,SAAS,SAAS;AAAA,MACrD,MAAM;AAAA,IACR;AAAA,IAGA,MAAM,qBAAqB;AAAA,wDACyB;AAAA,aAC3C,KAAK,uBAAuB;AAAA;AAAA,IAErC,MAAM,KAAK,OAAO,IAAI,YAAY,EAAE,OAAO,mBAAmB,CAAC;AAAA,IAG/D,MAAM,oBACJ,kBAAkB,SAAS,IAAI,GAAG,kBAAkB,KAAK,IAAI,kBAAkB;AAAA,IAGjF,MAAM,qBAAqB;AAAA,mCACI,KAAK;AAAA,UAC9B;AAAA;AAAA,uBAEa;AAAA;AAAA;AAAA,IAInB,QAAQ,OAAO,mBAAmB,MAAM,KAAK,OAAO,IAAI,YAAY;AAAA,MAClE,OAAO;AAAA,IACT,CAAC;AAAA,IACD,IAAI,kBAAkB,eAAe,SAAS,SAAS;AAAA,MACrD,MAAM;AAAA,IACR;AAAA;AAAA,OAGW,gBAAe,CAAC,WAAkC;AAAA,IAC7D,MAAM,qBAAqB,KAAK,sBAAsB;AAAA,IAEtD,QAAQ,UAAU,MAAM,KAAK,OAAO,KAAK,KAAK,kBAAkB,EAAE,OAAO;AAAA,SACpE;AAAA,MACH,YAAY;AAAA,IACd,CAAC;AAAA,IAED,IAAI;AAAA,MAAO,MAAM;AAAA;AAAA,OAGN,kBAAiB,CAAC,WAAmB,iBAA0C;AAAA,IAC1F,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,kBAAkB,EAC5B,OAAO,KAAK,EAAE,OAAO,SAAS,MAAM,KAAK,CAAC,EAC1C,GAAG,cAAc,SAAS,EAC1B,GAAG,eAAe,eAAe;AAAA,IAEpC,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IAErC,QAAQ,OAAO,UAAU,MAAM;AAAA,IAE/B,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,OAAO,SAAS;AAAA;AAAA,OAGL,2BAA0B,CACrC,WACA,QAC6B;AAAA,IAC7B,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,kBAAkB,EAC5B,OAAO,aAAa,EACpB,GAAG,cAAc,SAAS;AAAA,IAE7B,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IAErC,QAAQ,MAAM,UAAU,MAAM,MAC3B,MAAM,eAAe,EAAE,WAAW,KAAK,CAAC,EACxC,MAAM,QAAQ,MAAM;AAAA,IAEvB,IAAI;AAAA,MAAO,MAAM;AAAA,IACjB,IAAI,CAAC,QAAQ,KAAK,WAAW;AAAA,MAAG;AAAA,IAChC,OAAO,IAAI,KAAK,KAAK,GAAG,WAAW,EAAE,YAAY;AAAA;AAAA,OAGtC,qBAAoB,CAAC,WAAgD;AAAA,IAChF,IAAI,QAAQ,KAAK,OACd,KAAK,KAAK,sBAAsB,EAChC,OAAO,mBAAmB,EAC1B,GAAG,cAAc,SAAS;AAAA,IAE7B,QAAQ,KAAK,mBAAmB,KAAK;AAAA,IAErC,QAAQ,MAAM,UAAU,MAAM,MAAM,OAAO;AAAA,IAE3C,IAAI,OAAO;AAAA,MACT,IAAI,MAAM,SAAS;AAAA,QAAY;AAAA,MAC/B,MAAM;AAAA,IACR;AAAA,IAEA,IAAI,CAAC,MAAM;AAAA,MAAmB;AAAA,IAC9B,OAAO,IAAI,KAAK,KAAK,iBAAiB,EAAE,YAAY;AAAA;AAAA,OAGzC,qBAAoB,CAAC,WAAmB,iBAAwC;AAAA,IAC3F,MAAM,qBAAqB,KAAK,sBAAsB;AAAA,IAEtD,QAAQ,UAAU,MAAM,KAAK,OAAO,KAAK,KAAK,sBAAsB,EAAE,OACpE;AAAA,SACK;AAAA,MACH,YAAY;AAAA,MACZ,mBAAmB;AAAA,IACrB,GACA;AAAA,MACE,YACE,KAAK,SAAS,SAAS,IACnB,GAAG,KAAK,qBAAqB,EAAE,KAAK,GAAG,iBACvC;AAAA,IACR,CACF;AAAA,IAEA,IAAI;AAAA,MAAO,MAAM;AAAA;AAAA,OAGN,MAAK,CAAC,WAAkC;AAAA,IACnD,IAAI,YAAY,KAAK,OAAO,KAAK,KAAK,kBAAkB,EAAE,OAAO,EAAE,GAAG,cAAc,SAAS;AAAA,IAC7F,YAAY,KAAK,mBAAmB,SAAS;AAAA,IAC7C,QAAQ,OAAO,cAAc,MAAM;AAAA,IACnC,IAAI;AAAA,MAAW,MAAM;AAAA,IAErB,IAAI,YAAY,KAAK,OAClB,KAAK,KAAK,sBAAsB,EAChC,OAAO,EACP,GAAG,cAAc,SAAS;AAAA,IAC7B,YAAY,KAAK,mBAAmB,SAAS;AAAA,IAC7C,QAAQ,OAAO,cAAc,MAAM;AAAA,IACnC,IAAI;AAAA,MAAW,MAAM;AAAA;AAEzB;;AC1OA,+BAAS;AAQT,6BAAS;AAYF,IAAM,wBAAwB,qBACnC,oCACF;AAKA,SAAS,cAAuB,CAAC,UAAoB,QAAoC;AAAA,EACvF,YAAY,KAAK,UAAU,OAAO,QAAQ,MAAM,GAAG;AAAA,IACjD,IAAI,SAAS,SAA2B,OAAO;AAAA,MAC7C,OAAO;AAAA,IACT;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAMT,SAAS,cAAa,CAAC,MAAc,OAAuB;AAAA,EAC1D,MAAM,YAAY,KAAK,YAAY;AAAA,EACnC,MAAM,aAAa,MAAM,YAAY;AAAA,EACrC,MAAM,aAAa,WAAW,MAAM,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,CAAC;AAAA,EACrE,IAAI,WAAW,WAAW,GAAG;AAAA,IAC3B,OAAO;AAAA,EACT;AAAA,EACA,IAAI,UAAU;AAAA,EACd,WAAW,QAAQ,YAAY;AAAA,IAC7B,IAAI,UAAU,SAAS,IAAI,GAAG;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO,UAAU,WAAW;AAAA;AAAA;AAgBvB,MAAM,+BAMH,wBAEV;AAAA,EACU;AAAA,EACA;AAAA,EACA;AAAA,EAaR,WAAW,CACT,QAAgB,WAChB,QACA,iBACA,UAAmF,CAAC,GACpF,YACA,cAAqC,cACrC,mBAAqC,CAAC,GACtC,qBAA+C,cAC/C;AAAA,IACA,MAAM,OAAO,QAAQ,iBAAiB,SAAS,kBAAkB,kBAAkB;AAAA,IAEnF,KAAK,mBAAmB;AAAA,IAGxB,MAAM,aAAa,kBAAkB,MAAM;AAAA,IAC3C,IAAI,CAAC,YAAY;AAAA,MACf,MAAM,IAAI,MAAM,mEAAmE;AAAA,IACrF;AAAA,IACA,KAAK,qBAAqB;AAAA,IAC1B,KAAK,uBAAuB,oBAAoB,MAAM;AAAA;AAAA,EAOxD,mBAAmB,GAAW;AAAA,IAC5B,OAAO,KAAK;AAAA;AAAA,OAGR,iBAAgB,CACpB,OACA,UAAwD,CAAC,GACzD;AAAA,IACA,QAAQ,OAAO,IAAI,QAAQ,iBAAiB,MAAM;AAAA,IAClD,MAAM,UAA6C,CAAC;AAAA,IAEpD,MAAM,cAAe,MAAM,KAAK,OAAO,KAAM,CAAC;AAAA,IAE9C,WAAW,UAAU,aAAa;AAAA,MAEhC,MAAM,SAAS,OAAO,KAAK;AAAA,MAC3B,MAAM,WAAW,KAAK,uBACjB,OAAO,KAAK,wBACZ,CAAC;AAAA,MAGN,IAAI,UAAU,CAAC,eAAc,UAAU,MAAM,GAAG;AAAA,QAC9C;AAAA,MACF;AAAA,MAGA,MAAM,QAAQ,kBAAiB,OAAO,MAAM;AAAA,MAG5C,IAAI,QAAQ,gBAAgB;AAAA,QAC1B;AAAA,MACF;AAAA,MAEA,QAAQ,KAAK;AAAA,WACR;AAAA,QACH;AAAA,MACF,CAA+B;AAAA,IACjC;AAAA,IAGA,QAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAAA,IACxC,MAAM,aAAa,QAAQ,MAAM,GAAG,IAAI;AAAA,IAExC,OAAO;AAAA;AAAA,OAGH,aAAY,CAAC,OAAmB,SAAuD;AAAA,IAC3F,QAAQ,OAAO,IAAI,QAAQ,iBAAiB,GAAG,WAAW,eAAe,QAAQ;AAAA,IAEjF,IAAI,CAAC,aAAa,UAAU,KAAK,EAAE,WAAW,GAAG;AAAA,MAE/C,OAAO,KAAK,iBAAiB,OAAO,EAAE,MAAM,QAAQ,eAAe,CAAC;AAAA,IACtE;AAAA,IAEA,MAAM,UAA6C,CAAC;AAAA,IACpD,MAAM,cAAe,MAAM,KAAK,OAAO,KAAM,CAAC;AAAA,IAE9C,WAAW,UAAU,aAAa;AAAA,MAEhC,MAAM,SAAS,OAAO,KAAK;AAAA,MAC3B,MAAM,WAAW,KAAK,uBACjB,OAAO,KAAK,wBACZ,CAAC;AAAA,MAGN,IAAI,UAAU,CAAC,eAAc,UAAU,MAAM,GAAG;AAAA,QAC9C;AAAA,MACF;AAAA,MAGA,MAAM,cAAc,kBAAiB,OAAO,MAAM;AAAA,MAGlD,MAAM,eAAe,OAAO,OAAO,QAAQ,EAAE,KAAK,GAAG,EAAE,YAAY;AAAA,MACnE,MAAM,YAAY,eAAc,cAAc,SAAS;AAAA,MAGvD,MAAM,gBAAgB,eAAe,eAAe,IAAI,gBAAgB;AAAA,MAGxE,IAAI,gBAAgB,gBAAgB;AAAA,QAClC;AAAA,MACF;AAAA,MAEA,QAAQ,KAAK;AAAA,WACR;AAAA,QACH,OAAO;AAAA,MACT,CAA+B;AAAA,IACjC;AAAA,IAGA,QAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAAA,IACxC,MAAM,aAAa,QAAQ,MAAM,GAAG,IAAI;AAAA,IAExC,OAAO;AAAA;AAEX;",
47
- "debugId": "2583E6527A9527C764756E2164756E21",
46
+ "mappings": "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",
47
+ "debugId": "E2D716C3197417F164756E2164756E21",
48
48
  "names": []
49
49
  }