@workglow/postgres 0.2.34 → 0.2.35

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 (39) hide show
  1. package/README.md +51 -0
  2. package/dist/job-queue/browser.d.ts.map +1 -1
  3. package/dist/job-queue/browser.js +11 -1
  4. package/dist/job-queue/browser.js.map +3 -3
  5. package/dist/job-queue/bun.d.ts.map +1 -1
  6. package/dist/job-queue/common.d.ts.map +1 -1
  7. package/dist/job-queue/node.d.ts.map +1 -1
  8. package/dist/job-queue/node.js +11 -1
  9. package/dist/job-queue/node.js.map +3 -3
  10. package/dist/migrations/PostgresMigrationRunner.d.ts +7 -3
  11. package/dist/migrations/PostgresMigrationRunner.d.ts.map +1 -1
  12. package/dist/migrations/common.d.ts.map +1 -1
  13. package/dist/storage/PostgresTabularStorage.d.ts +14 -2
  14. package/dist/storage/PostgresTabularStorage.d.ts.map +1 -1
  15. package/dist/storage/PostgresVectorStorage.d.ts +1 -5
  16. package/dist/storage/PostgresVectorStorage.d.ts.map +1 -1
  17. package/dist/storage/browser.d.ts.map +1 -1
  18. package/dist/storage/browser.js +50 -106
  19. package/dist/storage/browser.js.map +4 -4
  20. package/dist/storage/bun.d.ts.map +1 -1
  21. package/dist/storage/common.d.ts.map +1 -1
  22. package/dist/storage/node.d.ts.map +1 -1
  23. package/dist/storage/node.js +60 -106
  24. package/dist/storage/node.js.map +5 -5
  25. package/dist/text/PostgresFtsTextIndex.d.ts +108 -0
  26. package/dist/text/PostgresFtsTextIndex.d.ts.map +1 -0
  27. package/dist/text/browser.d.ts +7 -0
  28. package/dist/text/browser.d.ts.map +1 -0
  29. package/dist/text/browser.js +185 -0
  30. package/dist/text/browser.js.map +10 -0
  31. package/dist/text/bun.d.ts +7 -0
  32. package/dist/text/bun.d.ts.map +1 -0
  33. package/dist/text/common.d.ts +7 -0
  34. package/dist/text/common.d.ts.map +1 -0
  35. package/dist/text/node.d.ts +7 -0
  36. package/dist/text/node.d.ts.map +1 -0
  37. package/dist/text/node.js +185 -0
  38. package/dist/text/node.js.map +10 -0
  39. package/package.json +25 -9
package/README.md CHANGED
@@ -6,6 +6,7 @@ Postgres backends for @workglow/storage and @workglow/job-queue.
6
6
 
7
7
  - Postgres implementation of `@workglow/storage` interfaces
8
8
  - Postgres implementation of `@workglow/job-queue` interfaces
9
+ - Postgres-native `ITextIndex` for `@workglow/knowledge-base` hybrid search
9
10
  - Persistent storage for tasks, vectors, and queues
10
11
 
11
12
  ## Installation
@@ -28,6 +29,56 @@ const storage = new PostgresTabularStorage(connectionConfig);
28
29
  const queue = new PostgresQueueStorage(connectionConfig);
29
30
  ```
30
31
 
32
+ ### Postgres-native hybrid search
33
+
34
+ `PostgresFtsTextIndex` is an `ITextIndex` backed by a single side table per
35
+ KB indexed by a GIN `tsvector` (Postgres FTS). Plug it into a
36
+ `KnowledgeBase` to get `kb.hybridSearch()` / `kb.textSearch()` with the
37
+ full-text postings living server-side rather than in the JS heap.
38
+
39
+ Benefits over the in-memory `BM25Index` default for Postgres-backed KBs:
40
+
41
+ - **Durable, server-side index**: postings live in Postgres as a side table
42
+ with a GIN index; the index survives process restarts without a rebuild.
43
+ - **No in-memory BM25 state**: the JS heap doesn't hold the inverted index —
44
+ the database does. Incremental `add` / `remove` writes don't grow heap.
45
+ - **Transactional rebuild**: `beginRebuild` / `commitRebuild` / `abortRebuild`
46
+ wrap the rebuild in a single `BEGIN` / `COMMIT` / `ROLLBACK` so a mid-
47
+ rebuild crash leaves the prior index intact.
48
+
49
+ > **Note**: `KnowledgeBase.reindexText()` still iterates all chunks via
50
+ > `chunkStorage.getAll()` to populate the index. The benefit here is not
51
+ > memory savings on reindex; it's that the *index itself* lives server-
52
+ > side and incremental writes don't grow the JS heap.
53
+
54
+ ```typescript
55
+ import { createKnowledgeBase } from "@workglow/knowledge-base";
56
+ import { PostgresFtsTextIndex } from "@workglow/postgres/text";
57
+
58
+ const textIndex = new PostgresFtsTextIndex(pool, "my_kb_fts");
59
+ // One-time DDL: CREATE TABLE + GIN index, idempotent.
60
+ await textIndex.setupDatabase();
61
+
62
+ const kb = await createKnowledgeBase({
63
+ name: "my-kb",
64
+ vectorDimensions: 768,
65
+ textIndex,
66
+ });
67
+ ```
68
+
69
+ > **Note**: the `table` argument is validated against a strict identifier
70
+ > whitelist — alphanumerics and underscore only, and must start with a
71
+ > letter or underscore (regex: `/^[A-Za-z_][A-Za-z0-9_]*$/`). Schema-
72
+ > qualified names (e.g. `public.chunks_fts`) and names containing dashes
73
+ > are rejected with an `Error` at DDL time. If you need to use a non-
74
+ > default schema, configure it via the Postgres pool's `search_path`
75
+ > instead.
76
+
77
+ `reindexText` wraps the rebuild in a Postgres transaction via the
78
+ `ITextIndex.beginRebuild` / `commitRebuild` / `abortRebuild` hooks, so a
79
+ failed rebuild rolls back atomically. `toJSON` / `fromJSON` are no-ops:
80
+ the table is the snapshot.
81
+
31
82
  ## License
32
83
 
33
84
  Apache 2.0 - See [LICENSE](../../LICENSE) for details.
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/job-queue/browser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/job-queue/browser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,UAAU,CAAC"}
@@ -16,6 +16,7 @@ import {
16
16
  MIGRATIONS_TABLE,
17
17
  sortMigrations
18
18
  } from "@workglow/storage";
19
+ var runLocks = new WeakMap;
19
20
 
20
21
  class PostgresMigrationRunner {
21
22
  db;
@@ -48,6 +49,15 @@ class PostgresMigrationRunner {
48
49
  } };
49
50
  }
50
51
  async run(migrations, options = {}) {
52
+ const key = this.db;
53
+ const prev = runLocks.get(key) ?? Promise.resolve();
54
+ const result = prev.then(() => this.runInternal(migrations, options));
55
+ runLocks.set(key, result.catch(() => {
56
+ return;
57
+ }));
58
+ return result;
59
+ }
60
+ async runInternal(migrations, options) {
51
61
  await this.ensureBookkeepingTable();
52
62
  const sorted = sortMigrations(migrations);
53
63
  const applied = [];
@@ -895,4 +905,4 @@ export {
895
905
  POSTGRES_QUEUE_STORAGE
896
906
  };
897
907
 
898
- //# debugId=9559FE4247FC32D964756E2164756E21
908
+ //# debugId=A07A5231BDAE0A9B64756E2164756E21
@@ -3,12 +3,12 @@
3
3
  "sources": ["../../src/job-queue/PostgresQueueStorage.ts", "../../src/migrations/PostgresMigrationRunner.ts", "../../src/migrations/postgresQueueMigrations.ts", "../../src/job-queue/PostgresRateLimiterStorage.ts", "../../src/migrations/postgresRateLimiterMigrations.ts"],
4
4
  "sourcesContent": [
5
5
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { Pool } from \"@workglow/postgres/storage\";\nimport { createServiceToken, getLogger, makeFingerprint, uuid4 } from \"@workglow/util\";\nimport { JobStatus } from \"@workglow/job-queue\";\nimport type {\n IQueueStorage,\n JobStorageFormat,\n PrefixColumn,\n QueueChangePayload,\n QueueStorageOptions,\n QueueSubscribeOptions,\n} from \"@workglow/job-queue\";\nimport {\n assertPrefixesSafe,\n buildPrefixInsertFragments,\n buildPrefixWhereClause,\n getPrefixColumnNames,\n getPrefixParamValues,\n PostgresDialect,\n} from \"@workglow/storage\";\nimport { PostgresMigrationRunner } from \"../migrations/PostgresMigrationRunner\";\nimport { postgresQueueMigrations } from \"../migrations/postgresQueueMigrations\";\n\nexport const POSTGRES_QUEUE_STORAGE = createServiceToken<IQueueStorage<any, any>>(\n \"jobqueue.storage.postgres\"\n);\n\n/**\n * Subset of pg.PoolClient that {@link PostgresQueueStorage.subscribeToChanges}\n * needs. Typed locally so we don't require `pg` types at the storage layer.\n */\ninterface ListenClient {\n query: (sql: string) => Promise<unknown>;\n release: () => void;\n removeAllListeners?: (event: string) => void;\n on: (event: string, listener: (...args: any[]) => void) => void;\n}\n\n/**\n * PostgreSQL implementation of a job queue.\n * Provides storage and retrieval for job execution states using PostgreSQL.\n */\nexport class PostgresQueueStorage<Input, Output> implements IQueueStorage<Input, Output> {\n public readonly scope = \"cluster\" as const;\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 /** The table name for the job queue */\n protected readonly tableName: string;\n\n constructor(\n protected readonly db: Pool,\n protected readonly queueName: string,\n options?: QueueStorageOptions\n ) {\n this.prefixes = options?.prefixes ?? [];\n this.prefixValues = options?.prefixValues ?? {};\n\n // Validate prefix column names to prevent SQL injection in DDL statements\n assertPrefixesSafe(this.prefixes);\n\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 /** WHERE-clause helper specialized for this instance's dialect + prefix values. */\n private buildPrefixWhereClause(startParam: number) {\n return buildPrefixWhereClause(PostgresDialect, this.prefixes, this.prefixValues, startParam);\n }\n\n /** Returns prefix values in column order. */\n private getPrefixParamValues(): Array<string | number> {\n return getPrefixParamValues(this.prefixes, this.prefixValues);\n }\n\n /**\n * Returns the versioned migrations that this storage's table layout depends\n * on. Callers can compose them with other storages' migrations under a\n * shared {@link PostgresMigrationRunner}; otherwise call {@link migrate}.\n */\n public getMigrations() {\n return postgresQueueMigrations(this.tableName, this.prefixes);\n }\n\n /**\n * Applies any pending migrations for this queue's table. Idempotent —\n * already-applied versions are recorded in `_storage_migrations` and\n * skipped on subsequent calls.\n */\n public async migrate(): Promise<void> {\n await new PostgresMigrationRunner(this.db).run(this.getMigrations());\n }\n\n /**\n * Channel name for this storage's LISTEN/NOTIFY. Mirrors the trigger's\n * computation so subscriber and notifier agree.\n */\n private notifyChannelName(): string {\n // md5() returns 32 hex chars; combined with the 7-char prefix this is well\n // under Postgres's 63-byte identifier limit.\n const tableAndQueue = `${this.tableName}${this.queueName}`;\n const hash = createHash(\"md5\").update(tableAndQueue).digest(\"hex\");\n return `wglw_q_${hash}`;\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 prefixColumnNames = getPrefixColumnNames(this.prefixes);\n const { columns: prefixColumnsInsert, placeholders: prefixParamPlaceholders } =\n buildPrefixInsertFragments(PostgresDialect, this.prefixes, 1);\n const prefixParamValues = this.getPrefixParamValues();\n const baseParamStart = prefixColumnNames.length + 1;\n\n const sql = `\n INSERT INTO ${this.tableName}(\n ${prefixColumnsInsert}queue, \n fingerprint, \n input, \n run_after,\n created_at,\n deadline_at,\n max_retries, \n job_run_id, \n progress, \n progress_message, \n progress_details\n )\n VALUES \n (${prefixParamPlaceholders}$${baseParamStart},$${baseParamStart + 1},$${baseParamStart + 2},$${baseParamStart + 3},$${baseParamStart + 4},$${baseParamStart + 5},$${baseParamStart + 6},$${baseParamStart + 7},$${baseParamStart + 8},$${baseParamStart + 9},$${baseParamStart + 10})\n RETURNING id`;\n const params = [\n ...prefixParamValues,\n job.queue,\n job.fingerprint,\n JSON.stringify(job.input),\n job.run_after,\n job.created_at,\n job.deadline_at,\n job.max_retries,\n job.job_run_id,\n job.progress,\n job.progress_message,\n job.progress_details ? JSON.stringify(job.progress_details) : null,\n ];\n const result = await this.db.query(sql, params);\n\n if (!result) throw new Error(\"Failed to add to queue\");\n job.id = result.rows[0].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 const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(3);\n const result = await this.db.query(\n `SELECT *\n FROM ${this.tableName}\n WHERE id = $1 AND queue = $2${prefixConditions}\n FOR UPDATE SKIP LOCKED\n LIMIT 1`,\n [id, this.queueName, ...prefixParams]\n );\n\n if (!result || result.rows.length === 0) return undefined;\n return result.rows[0];\n }\n\n /**\n * Retrieves a slice of jobs from the queue.\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<Array<JobStorageFormat<Input, Output>>> {\n num = Number(num) || 100; // TS does not validate, so ensure it is a number\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(4);\n const result = await this.db.query<\n JobStorageFormat<Input, Output>,\n Array<string | number | JobStatus>\n >(\n `\n SELECT *\n FROM ${this.tableName}\n WHERE queue = $1\n AND status = $2${prefixConditions}\n ORDER BY run_after ASC\n LIMIT $3\n FOR UPDATE SKIP LOCKED`,\n [this.queueName, status, num, ...prefixParams]\n );\n if (!result) return [];\n return result.rows;\n }\n\n /**\n * Retrieves the next available job that is ready to be processed.\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 // Parameters: $1=status, $2=queue, $3=status, $4=worker_id, $5+=prefix params\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(5);\n const result = await this.db.query<\n JobStorageFormat<Input, Output>,\n Array<string | number | JobStatus | null>\n >(\n `\n UPDATE ${this.tableName} \n SET status = $1, last_ran_at = NOW() AT TIME ZONE 'UTC', worker_id = $4\n WHERE id = (\n SELECT id \n FROM ${this.tableName} \n WHERE queue = $2 \n AND status = $3\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 [JobStatus.PROCESSING, this.queueName, JobStatus.PENDING, workerId, ...prefixParams]\n );\n\n return result?.rows?.[0] ?? undefined;\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 const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(3);\n const result = await this.db.query<{ count: string }, Array<string | number | JobStatus>>(\n `\n SELECT COUNT(*) as count\n FROM ${this.tableName}\n WHERE queue = $1\n AND status = $2${prefixConditions}`,\n [this.queueName, status, ...prefixParams]\n );\n if (!result) return 0;\n return parseInt(result.rows[0].count, 10);\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 prefixParams = this.getPrefixParamValues();\n\n if (jobDetails.status === JobStatus.DISABLED) {\n const { conditions: prefixConditions } = this.buildPrefixWhereClause(4);\n await this.db.query(\n `UPDATE ${this.tableName} \n SET \n status = $1, \n progress = 100,\n progress_message = '',\n progress_details = NULL,\n completed_at = NOW() AT TIME ZONE 'UTC'\n WHERE id = $2 AND queue = $3${prefixConditions}`,\n [jobDetails.status, jobDetails.id, this.queueName, ...prefixParams]\n );\n } else if (jobDetails.status === JobStatus.PENDING) {\n const { conditions: prefixConditions } = this.buildPrefixWhereClause(7);\n await this.db.query(\n `UPDATE ${this.tableName} \n SET \n error = $1, \n error_code = $2,\n status = $3, \n run_after = $4, \n progress = 0,\n progress_message = '',\n progress_details = NULL,\n run_attempts = run_attempts + 1, \n last_ran_at = NOW() AT TIME ZONE 'UTC'\n WHERE id = $5 AND queue = $6${prefixConditions}`,\n [\n jobDetails.error,\n jobDetails.error_code,\n jobDetails.status,\n jobDetails.run_after,\n jobDetails.id,\n this.queueName,\n ...prefixParams,\n ]\n );\n } else {\n const { conditions: prefixConditions } = this.buildPrefixWhereClause(7);\n await this.db.query(\n `\n UPDATE ${this.tableName} \n SET \n output = $1, \n error = $2, \n error_code = $3,\n status = $4, \n progress = 100,\n progress_message = '',\n progress_details = NULL,\n run_attempts = run_attempts + 1, \n completed_at = NOW() AT TIME ZONE 'UTC',\n last_ran_at = NOW() AT TIME ZONE 'UTC'\n WHERE id = $5 AND queue = $6${prefixConditions}`,\n [\n jobDetails.output ? JSON.stringify(jobDetails.output) : null,\n jobDetails.error ?? null,\n jobDetails.error_code ?? null,\n jobDetails.status,\n jobDetails.id,\n this.queueName,\n ...prefixParams,\n ]\n );\n }\n }\n\n /**\n * Clears all jobs from the queue.\n */\n public async deleteAll(): Promise<void> {\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(2);\n await this.db.query(\n `\n DELETE FROM ${this.tableName}\n WHERE queue = $1${prefixConditions}`,\n [this.queueName, ...prefixParams]\n );\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 const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(3);\n const result = await this.db.query(\n `\n SELECT output\n FROM ${this.tableName}\n WHERE fingerprint = $1 AND queue = $2 AND status = 'COMPLETED'${prefixConditions}`,\n [fingerprint, this.queueName, ...prefixParams]\n );\n if (!result || result.rows.length === 0) return null;\n return result.rows[0].output;\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 const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(3);\n await this.db.query(\n `\n UPDATE ${this.tableName} \n SET status = 'ABORTING' \n WHERE id = $1 AND queue = $2${prefixConditions}`,\n [jobId, this.queueName, ...prefixParams]\n );\n }\n\n /**\n * Releases a claimed job back to PENDING without incrementing run_attempts.\n * @param jobId - The id of the claimed job to release.\n */\n public async release(jobId: unknown): Promise<void> {\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(3);\n await this.db.query(\n `\n UPDATE ${this.tableName}\n SET status = 'PENDING',\n worker_id = NULL,\n progress = 0,\n progress_message = '',\n progress_details = NULL\n WHERE id = $1 AND queue = $2${prefixConditions}`,\n [jobId, this.queueName, ...prefixParams]\n );\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 const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(3);\n const result = await this.db.query(\n `\n SELECT * FROM ${this.tableName} WHERE job_run_id = $1 AND queue = $2${prefixConditions}`,\n [job_run_id, this.queueName, ...prefixParams]\n );\n if (!result) return [];\n return result.rows;\n }\n\n /**\n * Implements the abstract saveProgress method from JobQueue\n */\n public async saveProgress(\n jobId: unknown,\n progress: number,\n message: string,\n details: Record<string, any>\n ): Promise<void> {\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(6);\n await this.db.query(\n `\n UPDATE ${this.tableName} \n SET progress = $1,\n progress_message = $2,\n progress_details = $3\n WHERE id = $4 AND queue = $5${prefixConditions}`,\n [\n progress,\n message,\n details ? JSON.stringify(details) : null,\n jobId,\n this.queueName,\n ...prefixParams,\n ]\n );\n }\n\n /**\n * Deletes a job by its ID\n */\n public async delete(jobId: unknown): Promise<void> {\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(3);\n await this.db.query(\n `DELETE FROM ${this.tableName} WHERE id = $1 AND queue = $2${prefixConditions}`,\n [jobId, this.queueName, ...prefixParams]\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 cutoffDate = new Date(Date.now() - olderThanMs).toISOString();\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(4);\n await this.db.query(\n `DELETE FROM ${this.tableName} \n WHERE queue = $1 \n AND status = $2 \n AND completed_at IS NOT NULL \n AND completed_at <= $3${prefixConditions}`,\n [this.queueName, status, cutoffDate, ...prefixParams]\n );\n }\n\n /**\n * Subscribe to INSERT/UPDATE notifications via PostgreSQL LISTEN/NOTIFY.\n * Replaces 100ms-poll fallback for cluster Postgres deployments — workers\n * wake within network-latency of an actual change rather than on a timer.\n *\n * Acquires a dedicated client from the pool (LISTEN occupies a connection\n * for its lifetime). On unsubscribe, runs UNLISTEN and releases the client.\n * On connection loss, attempts to reconnect with bounded backoff and\n * re-LISTEN. After every successful (re)connect — including the initial\n * one — emits a synthetic `{ type: \"RESYNC\" }` event so subscribers can\n * re-poll state and pick up any rows inserted during the disconnect window\n * (or between subscribe and the first NOTIFY landing).\n *\n * Throws synchronously when the underlying pool lacks `connect()`\n * (single-connection wrappers like PGLite) so the caller's try/catch can\n * fall back to polling. JobQueueServer.start does this and logs at debug.\n *\n * `options.prefixFilter` follows {@link QueueSubscribeOptions.prefixFilter}:\n * `undefined` means \"use the storage instance's configured prefixValues\",\n * `{}` means \"receive all changes regardless of prefix\".\n */\n public subscribeToChanges(\n callback: (change: QueueChangePayload<Input, Output>) => void,\n options?: QueueSubscribeOptions\n ): () => void {\n type PoolWithConnect = { connect: () => Promise<ListenClient> };\n const poolMaybe = this.db as unknown as Partial<PoolWithConnect>;\n if (typeof poolMaybe.connect !== \"function\") {\n // Detect synchronously so callers can catch and fall back to polling\n // without leaving a dangling unhandled promise rejection behind.\n throw new Error(\n \"PostgresQueueStorage.subscribeToChanges requires a pg.Pool (got a single-connection wrapper)\"\n );\n }\n const pool = poolMaybe as PoolWithConnect;\n\n const channel = this.notifyChannelName();\n // undefined -> default to instance prefixValues; {} -> no filtering;\n // partial -> filter by the provided subset (matches QueueSubscribeOptions docs).\n const effectivePrefixFilter: Readonly<Record<string, string | number>> | null =\n options?.prefixFilter === undefined\n ? this.prefixes.length > 0\n ? this.prefixValues\n : null\n : Object.keys(options.prefixFilter).length === 0\n ? null\n : options.prefixFilter;\n\n let unsubscribed = false;\n let activeClient: ListenClient | null = null;\n let reconnectTimer: ReturnType<typeof setTimeout> | null = null;\n let backoffMs = 250;\n\n const dispatch = (change: QueueChangePayload<Input, Output>): void => {\n try {\n callback(change);\n } catch (err) {\n // Never let user callbacks tear down the listener loop.\n getLogger().debug(\"PostgresQueueStorage subscribe callback threw\", {\n channel,\n changeType: change.type,\n error: err,\n });\n }\n };\n\n const matchesPrefix = (\n change: QueueChangePayload<Input, Output>,\n filter: Readonly<Record<string, string | number>>\n ): boolean => {\n const row = (change.new ?? change.old) as Record<string, unknown> | undefined;\n if (!row) return false;\n for (const [k, v] of Object.entries(filter)) {\n if (row[k] !== v) return false;\n }\n return true;\n };\n\n // Hydrate the row referenced by a notification. Postgres NOTIFY is capped\n // at 8 KB so we ship only {id, queue, status} in the payload and fetch the\n // full row here — keeps subscriber payloads consistent with other backends\n // (e.g. Supabase realtime, IndexedDb) and lets prefixFilter inspect the\n // prefix columns the row actually has.\n const hydrate = async (id: unknown): Promise<JobStorageFormat<Input, Output> | undefined> => {\n try {\n return await this.get(id);\n } catch {\n return undefined;\n }\n };\n\n const handleNotification = (msg: { channel: string; payload?: string }): void => {\n if (msg.channel !== channel || !msg.payload) return;\n let parsed: { op: string; id: number; queue: string; status: string };\n try {\n parsed = JSON.parse(msg.payload);\n } catch {\n return;\n }\n void (async () => {\n const op = parsed.op;\n const fallback = {\n id: parsed.id,\n queue: parsed.queue,\n status: parsed.status,\n } as unknown as JobStorageFormat<Input, Output>;\n const fullRow = op === \"DELETE\" ? undefined : await hydrate(parsed.id);\n const change: QueueChangePayload<Input, Output> = {\n type: op === \"INSERT\" ? \"INSERT\" : op === \"DELETE\" ? \"DELETE\" : \"UPDATE\",\n new: op === \"DELETE\" ? undefined : (fullRow ?? fallback),\n old: op === \"DELETE\" ? fallback : undefined,\n };\n if (effectivePrefixFilter && !matchesPrefix(change, effectivePrefixFilter)) return;\n dispatch(change);\n })();\n };\n\n const connect = async (): Promise<void> => {\n if (unsubscribed) return;\n try {\n const client = await pool.connect();\n if (unsubscribed) {\n client.release();\n return;\n }\n activeClient = client;\n client.on(\"notification\", handleNotification);\n client.on(\"error\", () => scheduleReconnect());\n await client.query(`LISTEN ${channel}`);\n backoffMs = 250; // reset on successful (re)connect\n // Synthetic resync: any rows inserted between subscribe and LISTEN\n // landing (or during a reconnect window) have no NOTIFY backing.\n // Fire a no-payload event so subscribers can re-poll state.\n dispatch({ type: \"RESYNC\" });\n } catch {\n scheduleReconnect();\n }\n };\n\n const scheduleReconnect = (): void => {\n if (unsubscribed || reconnectTimer) return;\n const c = activeClient;\n activeClient = null;\n try {\n c?.removeAllListeners?.(\"notification\");\n c?.removeAllListeners?.(\"error\");\n c?.release();\n } catch {\n // best-effort\n }\n const delay = Math.min(backoffMs, 30_000);\n backoffMs = Math.min(backoffMs * 2, 30_000);\n reconnectTimer = setTimeout(() => {\n reconnectTimer = null;\n void connect();\n }, delay);\n };\n\n void connect();\n\n return () => {\n unsubscribed = true;\n if (reconnectTimer) {\n clearTimeout(reconnectTimer);\n reconnectTimer = null;\n }\n const c = activeClient;\n activeClient = null;\n if (c) {\n // Best-effort UNLISTEN; ignore errors (connection may already be dead).\n c.query(`UNLISTEN ${channel}`)\n .catch(() => {})\n .finally(() => {\n try {\n c.removeAllListeners?.(\"notification\");\n c.removeAllListeners?.(\"error\");\n c.release();\n } catch {\n // best-effort\n }\n });\n }\n };\n }\n}\n",
6
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Pool } from \"../storage/_postgres/node-bun\";\nimport {\n type IMigration,\n type IMigrationRunner,\n type RunMigrationsOptions,\n MIGRATIONS_TABLE,\n sortMigrations,\n} from \"@workglow/storage\";\n\n/**\n * Minimal \"queryable\" shape implemented by both a checked-out node-postgres\n * client and the PGlite-backed Pool we use in browser/test contexts.\n *\n * The runner programs against this so it can run BEGIN / up() / INSERT /\n * COMMIT through whichever path is available without dragging in pg's full\n * `PoolClient` type.\n */\ninterface PgQueryable {\n query<T = unknown, P extends unknown[] = unknown[]>(\n sql: string,\n params?: P\n ): Promise<{ rows: T[] }>;\n}\n\n/**\n * `Pool.connect()` shape — present on real node-postgres pools, absent on\n * the embedded PGlite pool used in browser/tests. Detected at runtime.\n */\ntype ConnectablePool = Pool & {\n connect?: () => Promise<PgQueryable & { release: () => void }>;\n};\n\n/**\n * Runs versioned migrations against a PostgreSQL pool.\n *\n * Each migration runs inside a single connection's transaction so the\n * bookkeeping INSERT and the migration's DDL commit together. node-postgres\n * pools don't guarantee that two consecutive `pool.query()` calls hit the\n * same client, so we check out a dedicated connection via `pool.connect()`\n * when available. The embedded PGlite pool used in browser/tests has no\n * `connect()` (it is single-client by construction), so we fall back to\n * the raw pool — BEGIN/COMMIT on it still hit the same backing connection.\n *\n * A unique constraint on `(component, version)` makes concurrent runners\n * safe: the loser of a race raises a duplicate-key error (`23505`) and we\n * treat that as \"already applied\".\n */\nexport class PostgresMigrationRunner implements IMigrationRunner<Pool> {\n constructor(private readonly db: Pool) {}\n\n async ensureBookkeepingTable(): Promise<void> {\n await this.db.query(`\n CREATE TABLE IF NOT EXISTS ${MIGRATIONS_TABLE} (\n component TEXT NOT NULL,\n version INTEGER NOT NULL,\n description TEXT,\n applied_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\n PRIMARY KEY (component, version)\n )\n `);\n }\n\n async appliedVersions(component: string): Promise<Set<number>> {\n const result = await this.db.query<{ version: number }, [string]>(\n `SELECT version FROM ${MIGRATIONS_TABLE} WHERE component = $1`,\n [component]\n );\n return new Set(result.rows.map((r) => Number(r.version)));\n }\n\n /**\n * Acquires a transaction-scoped queryable. Returns the raw pool when the\n * underlying driver doesn't expose `connect()` (PGlite); the `release()`\n * callback is then a no-op.\n */\n private async acquireClient(): Promise<{ client: PgQueryable; release: () => void }> {\n const pool = this.db as ConnectablePool;\n if (typeof pool.connect === \"function\") {\n const client = await pool.connect();\n return { client, release: () => client.release() };\n }\n return { client: this.db as unknown as PgQueryable, release: () => undefined };\n }\n\n async run(\n migrations: ReadonlyArray<IMigration<Pool>>,\n options: RunMigrationsOptions = {}\n ): Promise<ReadonlyArray<IMigration<Pool>>> {\n await this.ensureBookkeepingTable();\n const sorted = sortMigrations(migrations);\n const applied: IMigration<Pool>[] = [];\n const cache = new Map<string, Set<number>>();\n const onProgress = options.onProgress;\n\n for (const m of sorted) {\n let seen = cache.get(m.component);\n if (!seen) {\n seen = await this.appliedVersions(m.component);\n cache.set(m.component, seen);\n }\n if (seen.has(m.version)) continue;\n\n onProgress?.({\n component: m.component,\n version: m.version,\n phase: \"starting\",\n description: m.description,\n });\n\n const { client, release } = await this.acquireClient();\n try {\n await client.query(\"BEGIN\");\n // Migrations are written against the `Pool` type but only need a\n // queryable surface. Casting keeps the public signature stable while\n // routing the migration's queries through the dedicated client.\n await m.up(client as unknown as Pool, (fraction) => {\n onProgress?.({\n component: m.component,\n version: m.version,\n phase: \"running\",\n description: m.description,\n fraction,\n });\n });\n await client.query(\n `INSERT INTO ${MIGRATIONS_TABLE}(component, version, description) VALUES ($1, $2, $3)`,\n [m.component, m.version, m.description ?? null]\n );\n await client.query(\"COMMIT\");\n seen.add(m.version);\n applied.push(m);\n onProgress?.({\n component: m.component,\n version: m.version,\n phase: \"completed\",\n description: m.description,\n fraction: 1,\n });\n } catch (err: unknown) {\n await client.query(\"ROLLBACK\").catch(() => undefined);\n // Concurrent runner already inserted — treat as success.\n if ((err as { code?: string })?.code === \"23505\") {\n seen.add(m.version);\n onProgress?.({\n component: m.component,\n version: m.version,\n phase: \"completed\",\n description: m.description,\n fraction: 1,\n });\n continue;\n }\n onProgress?.({\n component: m.component,\n version: m.version,\n phase: \"failed\",\n description: m.description,\n error: err,\n });\n throw err;\n } finally {\n release();\n }\n }\n\n return applied;\n }\n}\n",
6
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Pool } from \"../storage/_postgres/node-bun\";\nimport {\n type IMigration,\n type IMigrationRunner,\n type RunMigrationsOptions,\n MIGRATIONS_TABLE,\n sortMigrations,\n} from \"@workglow/storage\";\n\n/**\n * Minimal \"queryable\" shape implemented by both a checked-out node-postgres\n * client and the PGlite-backed Pool we use in browser/test contexts.\n *\n * The runner programs against this so it can run BEGIN / up() / INSERT /\n * COMMIT through whichever path is available without dragging in pg's full\n * `PoolClient` type.\n */\ninterface PgQueryable {\n query<T = unknown, P extends unknown[] = unknown[]>(\n sql: string,\n params?: P\n ): Promise<{ rows: T[] }>;\n}\n\n/**\n * `Pool.connect()` shape — present on real node-postgres pools, absent on\n * the embedded PGlite pool used in browser/tests. Detected at runtime.\n */\ntype ConnectablePool = Pool & {\n connect?: () => Promise<PgQueryable & { release: () => void }>;\n};\n\n/**\n * In-process serialization of `run()` calls per `Pool` wrapper. Keyed by\n * the wrapper object (not the underlying database), so two separate pools\n * pointing at the same database — or runners in different processes — do\n * not contend through this map. Cross-instance races are handled by the\n * bookkeeping PK check below (a 23505 from a concurrent INSERT is caught\n * and treated as \"already applied\"). Without this in-process mutex,\n * multiple runners sharing one pool would each invoke `up()` before the\n * 23505 was raised. The map is a WeakMap so disposing the pool releases\n * the entry.\n */\nconst runLocks = new WeakMap<object, Promise<unknown>>();\n\n/**\n * Runs versioned migrations against a PostgreSQL pool.\n *\n * Each migration runs inside a single connection's transaction so the\n * bookkeeping INSERT and the migration's DDL commit together. node-postgres\n * pools don't guarantee that two consecutive `pool.query()` calls hit the\n * same client, so we check out a dedicated connection via `pool.connect()`\n * when available. The embedded PGlite pool used in browser/tests has no\n * `connect()` (it is single-client by construction), so we fall back to\n * the raw pool — BEGIN/COMMIT on it still hit the same backing connection.\n *\n * Concurrent `run()` calls against the same pool are serialized through a\n * JS-layer mutex so racing runners see each others' bookkeeping rows before\n * deciding to invoke `up()`. The unique constraint on `(component, version)`\n * remains a defense-in-depth check a 23505 from a separate process (or a\n * different pool instance backed by the same database) is still treated as\n * \"already applied\".\n */\nexport class PostgresMigrationRunner implements IMigrationRunner<Pool> {\n constructor(private readonly db: Pool) {}\n\n async ensureBookkeepingTable(): Promise<void> {\n await this.db.query(`\n CREATE TABLE IF NOT EXISTS ${MIGRATIONS_TABLE} (\n component TEXT NOT NULL,\n version INTEGER NOT NULL,\n description TEXT,\n applied_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(),\n PRIMARY KEY (component, version)\n )\n `);\n }\n\n async appliedVersions(component: string): Promise<Set<number>> {\n const result = await this.db.query<{ version: number }, [string]>(\n `SELECT version FROM ${MIGRATIONS_TABLE} WHERE component = $1`,\n [component]\n );\n return new Set(result.rows.map((r) => Number(r.version)));\n }\n\n /**\n * Acquires a transaction-scoped queryable. Returns the raw pool when the\n * underlying driver doesn't expose `connect()` (PGlite); the `release()`\n * callback is then a no-op.\n */\n private async acquireClient(): Promise<{ client: PgQueryable; release: () => void }> {\n const pool = this.db as ConnectablePool;\n if (typeof pool.connect === \"function\") {\n const client = await pool.connect();\n return { client, release: () => client.release() };\n }\n return { client: this.db as unknown as PgQueryable, release: () => undefined };\n }\n\n async run(\n migrations: ReadonlyArray<IMigration<Pool>>,\n options: RunMigrationsOptions = {}\n ): Promise<ReadonlyArray<IMigration<Pool>>> {\n const key = this.db as unknown as object;\n const prev = runLocks.get(key) ?? Promise.resolve();\n const result = prev.then(() => this.runInternal(migrations, options));\n runLocks.set(\n key,\n result.catch(() => undefined)\n );\n return result;\n }\n\n private async runInternal(\n migrations: ReadonlyArray<IMigration<Pool>>,\n options: RunMigrationsOptions\n ): Promise<ReadonlyArray<IMigration<Pool>>> {\n await this.ensureBookkeepingTable();\n const sorted = sortMigrations(migrations);\n const applied: IMigration<Pool>[] = [];\n const cache = new Map<string, Set<number>>();\n const onProgress = options.onProgress;\n\n for (const m of sorted) {\n let seen = cache.get(m.component);\n if (!seen) {\n seen = await this.appliedVersions(m.component);\n cache.set(m.component, seen);\n }\n if (seen.has(m.version)) continue;\n\n onProgress?.({\n component: m.component,\n version: m.version,\n phase: \"starting\",\n description: m.description,\n });\n\n const { client, release } = await this.acquireClient();\n try {\n await client.query(\"BEGIN\");\n // Migrations are written against the `Pool` type but only need a\n // queryable surface. Casting keeps the public signature stable while\n // routing the migration's queries through the dedicated client.\n await m.up(client as unknown as Pool, (fraction) => {\n onProgress?.({\n component: m.component,\n version: m.version,\n phase: \"running\",\n description: m.description,\n fraction,\n });\n });\n await client.query(\n `INSERT INTO ${MIGRATIONS_TABLE}(component, version, description) VALUES ($1, $2, $3)`,\n [m.component, m.version, m.description ?? null]\n );\n await client.query(\"COMMIT\");\n seen.add(m.version);\n applied.push(m);\n onProgress?.({\n component: m.component,\n version: m.version,\n phase: \"completed\",\n description: m.description,\n fraction: 1,\n });\n } catch (err: unknown) {\n await client.query(\"ROLLBACK\").catch(() => undefined);\n // Concurrent runner already inserted — treat as success.\n if ((err as { code?: string })?.code === \"23505\") {\n seen.add(m.version);\n onProgress?.({\n component: m.component,\n version: m.version,\n phase: \"completed\",\n description: m.description,\n fraction: 1,\n });\n continue;\n }\n onProgress?.({\n component: m.component,\n version: m.version,\n phase: \"failed\",\n description: m.description,\n error: err,\n });\n throw err;\n } finally {\n release();\n }\n }\n\n return applied;\n }\n}\n",
7
7
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Pool } from \"../storage/_postgres/node-bun\";\nimport { JobStatus, type PrefixColumn } from \"@workglow/job-queue\";\nimport {\n buildPrefixColumnsSql,\n getPrefixIndexPrefix,\n getPrefixIndexSuffix,\n type IMigration,\n PostgresDialect,\n} from \"@workglow/storage\";\n\n/**\n * Frozen v1 set of `job_status` enum values, captured at migration creation\n * time. Migration bodies are historical artifacts and MUST NOT read the\n * mutable {@link JobStatus} const directly: a fresh DB created after a value\n * is added to the const would receive the new value, while a DB already at v1\n * would not — silently producing version-skewed enums and runtime errors on\n * insert. Adding a status requires a NEW migration that runs\n * `ALTER TYPE job_status ADD VALUE IF NOT EXISTS '...'`.\n */\nconst JOB_STATUS_V1: readonly string[] = [\n \"PENDING\",\n \"PROCESSING\",\n \"COMPLETED\",\n \"ABORTING\",\n \"FAILED\",\n \"DISABLED\",\n];\n\n/**\n * Sanity check: if a developer adds a status to {@link JobStatus} without\n * also writing a follow-up migration that ALTER TYPE-adds it, queries that\n * insert the new status will fail at runtime against any DB still on v1.\n *\n * Run lazily from {@link postgresQueueMigrations} (NOT at module import) so\n * that consumers re-exporting this module via barrel files don't crash on\n * import when they have no intention of running migrations.\n */\nfunction assertJobStatusMatchesV1(): void {\n const current = new Set(Object.values(JobStatus));\n for (const v of JOB_STATUS_V1) {\n if (!current.has(v as JobStatus)) {\n throw new Error(\n `JobStatus const is missing v1 enum value \"${v}\"; v1 migration values are frozen.`\n );\n }\n }\n for (const v of current) {\n if (!JOB_STATUS_V1.includes(v)) {\n throw new Error(\n `JobStatus contains \"${v}\" which is not in JOB_STATUS_V1. ` +\n `Add a new migration that runs \"ALTER TYPE job_status ADD VALUE IF NOT EXISTS '${v}'\" ` +\n `instead of mutating the v1 enum literal.`\n );\n }\n }\n}\n\n/**\n * Initial migration set for the Postgres queue table identified by `tableName`.\n *\n * Component name is `queue:postgres:<tableName>` so two queues with different\n * table names get tracked independently in `_storage_migrations`. The v1\n * payload covers schema + indexes + LISTEN/NOTIFY plumbing; the trigger is\n * idempotent (`CREATE OR REPLACE FUNCTION` + `DROP TRIGGER IF EXISTS`).\n */\nexport function postgresQueueMigrations(\n tableName: string,\n prefixes: readonly PrefixColumn[]\n): IMigration<Pool>[] {\n assertJobStatusMatchesV1();\n const component = `queue:postgres:${tableName}`;\n const prefixColumnsSql = buildPrefixColumnsSql(PostgresDialect, prefixes);\n const prefixIndexPrefix = getPrefixIndexPrefix(prefixes);\n const indexSuffix = getPrefixIndexSuffix(prefixes);\n\n return [\n {\n component,\n version: 1,\n description: \"Create job_status enum + queue table + indexes + notify trigger\",\n async up(db: Pool) {\n // Enum literal is the frozen v1 set, NOT Object.values(JobStatus).\n // See JOB_STATUS_V1 for why.\n const enumLiteral = JOB_STATUS_V1.map((v) => `'${v}'`).join(\",\");\n // DO block so the existence check + CREATE TYPE happen in one\n // statement. A bare `CREATE TYPE ...` raising duplicate_object inside\n // a transaction would leave it aborted (Postgres state 25P02), and\n // the runner's BEGIN/COMMIT would reject every subsequent statement.\n await db.query(`\n DO $$\n BEGIN\n IF NOT EXISTS (SELECT 1 FROM pg_type WHERE typname = 'job_status') THEN\n CREATE TYPE job_status AS ENUM (${enumLiteral});\n END IF;\n END $$;\n `);\n\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${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\n await db.query(`\n CREATE INDEX IF NOT EXISTS job_fetcher${indexSuffix}_idx\n ON ${tableName} (${prefixIndexPrefix}id, status, run_after)\n `);\n await db.query(`\n CREATE INDEX IF NOT EXISTS job_queue_fetcher${indexSuffix}_idx\n ON ${tableName} (${prefixIndexPrefix}queue, status, run_after)\n `);\n await db.query(`\n CREATE INDEX IF NOT EXISTS jobs_fingerprint${indexSuffix}_unique_idx\n ON ${tableName} (${prefixIndexPrefix}queue, fingerprint, status)\n `);\n\n // Install LISTEN/NOTIFY plumbing so subscribers can wake on\n // INSERT/UPDATE without polling. Best-effort: in-process\n // Postgres-compatible engines like PGLite may not implement pg_notify\n // or plpgsql. Skip trigger installation in that case — the queue's\n // subscribeToChanges throws synchronously for those engines anyway.\n //\n // Wrapped in a SAVEPOINT because this migration runs inside the\n // runner's BEGIN/COMMIT. Without the savepoint, any error in the\n // trigger DDL would put the outer transaction into aborted state\n // (Postgres 25P02), poisoning the runner's bookkeeping INSERT and\n // failing the whole migration — even though the trigger itself is\n // optional. ROLLBACK TO SAVEPOINT lets us discard just the failed\n // trigger work and keep the rest of the migration committable.\n const fnName = `${tableName}_notify`;\n const trgName = `${tableName}_notify_trg`;\n await db.query(\"SAVEPOINT install_notify_trigger\");\n try {\n await db.query(`\n CREATE OR REPLACE FUNCTION ${fnName}() RETURNS trigger AS $fn$\n DECLARE\n channel TEXT := 'wglw_q_' || md5('${tableName}' || COALESCE(NEW.queue, OLD.queue));\n payload TEXT;\n BEGIN\n payload := json_build_object(\n 'op', TG_OP,\n 'id', COALESCE(NEW.id, OLD.id),\n 'queue', COALESCE(NEW.queue, OLD.queue),\n 'status', COALESCE(NEW.status::text, OLD.status::text)\n )::text;\n PERFORM pg_notify(channel, payload);\n RETURN NULL;\n END;\n $fn$ LANGUAGE plpgsql;\n `);\n await db.query(`DROP TRIGGER IF EXISTS ${trgName} ON ${tableName}`);\n await db.query(`\n CREATE TRIGGER ${trgName}\n AFTER INSERT OR UPDATE ON ${tableName}\n FOR EACH ROW EXECUTE FUNCTION ${fnName}();\n `);\n await db.query(\"RELEASE SAVEPOINT install_notify_trigger\");\n } catch {\n // Engine doesn't support LISTEN/NOTIFY; rewind to the savepoint so\n // the outer transaction stays usable, and let subscribers fall\n // back to polling.\n await db.query(\"ROLLBACK TO SAVEPOINT install_notify_trigger\").catch(() => undefined);\n await db.query(\"RELEASE SAVEPOINT install_notify_trigger\").catch(() => undefined);\n }\n },\n },\n ];\n}\n",
8
8
  "/**\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 { Pool } from \"@workglow/postgres/storage\";\nimport type { PrefixColumn } from \"@workglow/job-queue\";\nimport type {\n IRateLimiterStorage,\n RateLimiterStorageOptions,\n RateLimiterStorageScope,\n} from \"@workglow/job-queue\";\nimport {\n assertPrefixesSafe,\n buildPrefixWhereClause,\n getPrefixColumnNames,\n getPrefixParamValues,\n PostgresDialect,\n} from \"@workglow/storage\";\nimport { PostgresMigrationRunner } from \"../migrations/PostgresMigrationRunner\";\nimport { postgresRateLimiterMigrations } from \"../migrations/postgresRateLimiterMigrations\";\n\nexport const POSTGRES_RATE_LIMITER_STORAGE = createServiceToken<IRateLimiterStorage>(\n \"ratelimiter.storage.postgres\"\n);\n\n/**\n * PostgreSQL implementation of rate limiter storage.\n * Manages execution records and next available times for rate limiting.\n */\nexport class PostgresRateLimiterStorage implements IRateLimiterStorage {\n public readonly scope: RateLimiterStorageScope = \"cluster\";\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 /** The table name for execution tracking */\n protected readonly executionTableName: string;\n /** The table name for next available times */\n protected readonly nextAvailableTableName: string;\n\n constructor(\n protected readonly db: Pool,\n options?: RateLimiterStorageOptions\n ) {\n this.prefixes = options?.prefixes ?? [];\n this.prefixValues = options?.prefixValues ?? {};\n // Validate prefix column names before deriving table names from them.\n assertPrefixesSafe(this.prefixes);\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 /** WHERE-clause helper specialized for the Postgres dialect. */\n private buildPrefixWhereClause(startParam: number) {\n return buildPrefixWhereClause(PostgresDialect, this.prefixes, this.prefixValues, startParam);\n }\n\n /** Returns prefix values in column order. */\n private getPrefixParamValues(): Array<string | number> {\n return getPrefixParamValues(this.prefixes, this.prefixValues);\n }\n\n /**\n * Returns the versioned migrations that this storage's tables depend on.\n * Callers can compose them with other storages' migrations under a shared\n * {@link PostgresMigrationRunner}; otherwise call {@link migrate}.\n */\n public getMigrations() {\n return postgresRateLimiterMigrations(\n this.executionTableName,\n this.nextAvailableTableName,\n this.prefixes\n );\n }\n\n /** Applies any pending migrations for this rate limiter's tables. */\n public async migrate(): Promise<void> {\n await new PostgresMigrationRunner(this.db).run(this.getMigrations());\n }\n\n public async tryReserveExecution(\n queueName: string,\n maxExecutions: number,\n windowMs: number\n ): Promise<unknown | null> {\n const prefixColumnNames = getPrefixColumnNames(this.prefixes);\n const prefixParamValues = this.getPrefixParamValues();\n const prefixCount = prefixColumnNames.length;\n\n // Parameter layout:\n // $1..$N prefix values (used in lock-key, count, next-available, and INSERT)\n // $(N+1) queueName\n // $(N+2) windowStart timestamp\n // $(N+3) maxExecutions\n const queueParam = `$${prefixCount + 1}`;\n const windowStartParam = `$${prefixCount + 2}`;\n\n // For the advisory lock we hash table-name + prefix values + queue-name into a bigint.\n // Use hashtextextended which returns int8 (advisory_xact_lock takes bigint).\n const lockKeyParts: string[] = [`'${this.executionTableName}'`];\n for (let i = 0; i < prefixCount; i++) {\n lockKeyParts.push(`$${i + 1}::text`);\n }\n lockKeyParts.push(`${queueParam}::text`);\n const lockKeyExpr = `hashtextextended(${lockKeyParts.join(\" || '|' || \")}, 0)`;\n\n const prefixWhere =\n prefixCount > 0\n ? \" AND \" + prefixColumnNames.map((p, i) => `${p} = $${i + 1}`).join(\" AND \")\n : \"\";\n\n const prefixInsertCols = prefixCount > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const prefixInsertPlaceholders =\n prefixCount > 0 ? prefixColumnNames.map((_, i) => `$${i + 1}`).join(\", \") + \", \" : \"\";\n\n const windowStart = new Date(Date.now() - windowMs).toISOString();\n\n // Use a dedicated client when the pool supports connect() (real pg.Pool)\n // — the advisory xact lock + transaction MUST run on the same connection\n // for atomicity. Without connect(), only known single-connection wrappers\n // (PGLitePool, raw PGlite) are safe, since they implicitly serialize all\n // queries through one underlying connection. Anything else (e.g. a custom\n // multi-connection adapter without connect()) would dispatch the lock and\n // the INSERT to different sessions, defeating the lock entirely.\n const supportsConnect =\n typeof (this.db as unknown as { connect?: unknown }).connect === \"function\";\n if (!supportsConnect) {\n // Without connect() we run BEGIN/advisory_lock/INSERT/COMMIT directly on\n // `db.query`. That's only safe if `db` is a single-connection wrapper\n // (every query goes through the same underlying session). Recognize:\n // - PGLitePool — our own wrapper class; constructor name preserved.\n // - PGlite — third-party, ships minified so `constructor.name`\n // can be obfuscated (observed: \"q\"). Detect via duck-typing on\n // methods PGlite uniquely exposes (`waitReady` Promise + `exec`).\n // Any other no-connect() pool would dispatch the lock and the INSERT\n // to potentially different sessions, breaking atomicity.\n const dbAny = this.db as unknown as {\n waitReady?: unknown;\n exec?: unknown;\n constructor?: { name?: string };\n };\n const ctorName = dbAny.constructor?.name;\n const looksLikePGlite = typeof dbAny.exec === \"function\" && dbAny.waitReady !== undefined;\n const looksLikePGLitePool = ctorName === \"PGLitePool\";\n if (!looksLikePGlite && !looksLikePGLitePool) {\n throw new Error(\n `PostgresRateLimiterStorage.tryReserveExecution requires a pg.Pool with connect() or a known single-connection wrapper (PGLitePool, PGlite); got ${ctorName ?? typeof this.db}. A multi-connection pool without connect() would dispatch the advisory lock and the INSERT to different sessions, breaking atomicity.`\n );\n }\n }\n const conn = supportsConnect\n ? await (\n this.db as unknown as {\n connect: () => Promise<{\n query: Pool[\"query\"];\n release: () => void;\n }>;\n }\n ).connect()\n : { query: this.db.query.bind(this.db), release: () => {} };\n\n try {\n await conn.query(\"BEGIN\");\n try {\n await conn.query(`SELECT pg_advisory_xact_lock(${lockKeyExpr})`, [\n ...prefixParamValues,\n queueName,\n ]);\n\n const countResult = await conn.query(\n `\n SELECT COUNT(*)::int AS n\n FROM ${this.executionTableName}\n WHERE queue_name = ${queueParam} AND executed_at > ${windowStartParam}${prefixWhere}\n `,\n [...prefixParamValues, queueName, windowStart]\n );\n const n: number = countResult.rows[0]?.n ?? 0;\n if (n >= maxExecutions) {\n await conn.query(\"COMMIT\");\n return null;\n }\n\n const naResult = await conn.query(\n `\n SELECT next_available_at\n FROM ${this.nextAvailableTableName}\n WHERE queue_name = ${queueParam}${prefixWhere}\n `,\n [...prefixParamValues, queueName]\n );\n const nextAvailableAt: Date | null = naResult.rows[0]?.next_available_at ?? null;\n if (nextAvailableAt && new Date(nextAvailableAt).getTime() > Date.now()) {\n await conn.query(\"COMMIT\");\n return null;\n }\n\n const insertResult = await conn.query(\n `\n INSERT INTO ${this.executionTableName} (${prefixInsertCols}queue_name)\n VALUES (${prefixInsertPlaceholders}${queueParam})\n RETURNING id\n `,\n [...prefixParamValues, queueName]\n );\n await conn.query(\"COMMIT\");\n return insertResult.rows[0]?.id ?? null;\n } catch (err) {\n try {\n await conn.query(\"ROLLBACK\");\n } catch {\n // best-effort\n }\n throw err;\n }\n } finally {\n conn.release();\n }\n }\n\n public async releaseExecution(queueName: string, token: unknown): Promise<void> {\n if (token === null || token === undefined) return;\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(3);\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 await this.db.query(\n `DELETE FROM ${this.executionTableName} WHERE id = $1 AND queue_name = $2${prefixConditions}`,\n [token as string | number, queueName, ...prefixParams]\n );\n }\n\n public async recordExecution(queueName: string): Promise<void> {\n const prefixColumnNames = getPrefixColumnNames(this.prefixes);\n const prefixColumnsInsert =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const prefixParamValues = this.getPrefixParamValues();\n const prefixParamPlaceholders =\n prefixColumnNames.length > 0\n ? prefixColumnNames.map((_, i) => `$${i + 1}`).join(\", \") + \", \"\n : \"\";\n const queueParamNum = prefixColumnNames.length + 1;\n\n await this.db.query(\n `\n INSERT INTO ${this.executionTableName} (${prefixColumnsInsert}queue_name)\n VALUES (${prefixParamPlaceholders}$${queueParamNum})\n `,\n [...prefixParamValues, queueName]\n );\n }\n\n public async getExecutionCount(queueName: string, windowStartTime: string): Promise<number> {\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(3);\n\n const result = await this.db.query(\n `\n SELECT COUNT(*) AS count\n FROM ${this.executionTableName}\n WHERE queue_name = $1 AND executed_at > $2${prefixConditions}\n `,\n [queueName, windowStartTime, ...prefixParams]\n );\n\n return parseInt(result.rows[0]?.count ?? \"0\", 10);\n }\n\n public async getOldestExecutionAtOffset(\n queueName: string,\n offset: number\n ): Promise<string | undefined> {\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(3);\n\n const result = await this.db.query(\n `\n SELECT executed_at\n FROM ${this.executionTableName}\n WHERE queue_name = $1${prefixConditions}\n ORDER BY executed_at ASC\n LIMIT 1 OFFSET $2\n `,\n [queueName, offset, ...prefixParams]\n );\n\n const executedAt = result.rows[0]?.executed_at;\n if (!executedAt) return undefined;\n return new Date(executedAt).toISOString();\n }\n\n public async getNextAvailableTime(queueName: string): Promise<string | undefined> {\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(2);\n\n const result = await this.db.query(\n `\n SELECT next_available_at\n FROM ${this.nextAvailableTableName}\n WHERE queue_name = $1${prefixConditions}\n `,\n [queueName, ...prefixParams]\n );\n\n const nextAvailableAt = result.rows[0]?.next_available_at;\n if (!nextAvailableAt) return undefined;\n return new Date(nextAvailableAt).toISOString();\n }\n\n public async setNextAvailableTime(queueName: string, nextAvailableAt: string): Promise<void> {\n const prefixColumnNames = getPrefixColumnNames(this.prefixes);\n const prefixColumnsInsert =\n prefixColumnNames.length > 0 ? prefixColumnNames.join(\", \") + \", \" : \"\";\n const prefixParamValues = this.getPrefixParamValues();\n const prefixParamPlaceholders =\n prefixColumnNames.length > 0\n ? prefixColumnNames.map((_, i) => `$${i + 1}`).join(\", \") + \", \"\n : \"\";\n const baseParamStart = prefixColumnNames.length + 1;\n\n // Build the conflict columns for upsert\n const conflictColumns =\n prefixColumnNames.length > 0 ? `${prefixColumnNames.join(\", \")}, queue_name` : \"queue_name\";\n\n await this.db.query(\n `\n INSERT INTO ${this.nextAvailableTableName} (${prefixColumnsInsert}queue_name, next_available_at)\n VALUES (${prefixParamPlaceholders}$${baseParamStart}, $${baseParamStart + 1})\n ON CONFLICT (${conflictColumns})\n DO UPDATE SET next_available_at = EXCLUDED.next_available_at\n `,\n [...prefixParamValues, queueName, nextAvailableAt]\n );\n }\n\n public async clear(queueName: string): Promise<void> {\n const { conditions: prefixConditions, params: prefixParams } = this.buildPrefixWhereClause(2);\n\n await this.db.query(\n `DELETE FROM ${this.executionTableName} WHERE queue_name = $1${prefixConditions}`,\n [queueName, ...prefixParams]\n );\n await this.db.query(\n `DELETE FROM ${this.nextAvailableTableName} WHERE queue_name = $1${prefixConditions}`,\n [queueName, ...prefixParams]\n );\n }\n}\n",
9
9
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Pool } from \"../storage/_postgres/node-bun\";\nimport type { PrefixColumn } from \"@workglow/job-queue\";\nimport {\n buildPrefixColumnsSql,\n getPrefixColumnNames,\n getPrefixIndexPrefix,\n getPrefixIndexSuffix,\n type IMigration,\n PostgresDialect,\n} from \"@workglow/storage\";\n\n/** Initial migration set for the Postgres rate-limiter tables. */\nexport function postgresRateLimiterMigrations(\n executionTableName: string,\n nextAvailableTableName: string,\n prefixes: readonly PrefixColumn[]\n): IMigration<Pool>[] {\n const component = `rate-limiter:postgres:${executionTableName}`;\n const prefixColumnsSql = buildPrefixColumnsSql(PostgresDialect, prefixes);\n const prefixColumnNames = getPrefixColumnNames(prefixes);\n const prefixIndexPrefix = getPrefixIndexPrefix(prefixes);\n const indexSuffix = getPrefixIndexSuffix(prefixes);\n const primaryKeyColumns =\n prefixColumnNames.length > 0 ? `${prefixColumnNames.join(\", \")}, queue_name` : \"queue_name\";\n\n return [\n {\n component,\n version: 1,\n description: \"Create rate-limiter execution + next_available tables\",\n async up(db: Pool) {\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${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 await db.query(`\n CREATE INDEX IF NOT EXISTS rate_limit_exec_queue${indexSuffix}_idx\n ON ${executionTableName} (${prefixIndexPrefix}queue_name, executed_at)\n `);\n await db.query(`\n CREATE TABLE IF NOT EXISTS ${nextAvailableTableName} (\n ${prefixColumnsSql}queue_name TEXT NOT NULL,\n next_available_at TIMESTAMP WITH TIME ZONE,\n PRIMARY KEY (${primaryKeyColumns})\n )\n `);\n },\n },\n ];\n}\n"
10
10
  ],
11
- "mappings": ";AAMA;AAEA;AACA,sBAAS;AAST;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAME;AAAA;;;ACjBF;AAAA;AAAA;AAAA;AAAA;AA8CO,MAAM,wBAA0D;AAAA,EACxC;AAAA,EAA7B,WAAW,CAAkB,IAAU;AAAA,IAAV;AAAA;AAAA,OAEvB,uBAAsB,GAAkB;AAAA,IAC5C,MAAM,KAAK,GAAG,MAAM;AAAA,mCACW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAO9B;AAAA;AAAA,OAGG,gBAAe,CAAC,WAAyC;AAAA,IAC7D,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B,uBAAuB,yCACvB,CAAC,SAAS,CACZ;AAAA,IACA,OAAO,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,OAAO,EAAE,OAAO,CAAC,CAAC;AAAA;AAAA,OAQ5C,cAAa,GAA0D;AAAA,IACnF,MAAM,OAAO,KAAK;AAAA,IAClB,IAAI,OAAO,KAAK,YAAY,YAAY;AAAA,MACtC,MAAM,SAAS,MAAM,KAAK,QAAQ;AAAA,MAClC,OAAO,EAAE,QAAQ,SAAS,MAAM,OAAO,QAAQ,EAAE;AAAA,IACnD;AAAA,IACA,OAAO,EAAE,QAAQ,KAAK,IAA8B,SAAS,MAAG;AAAA,MAAG;AAAA,MAAU;AAAA;AAAA,OAGzE,IAAG,CACP,YACA,UAAgC,CAAC,GACS;AAAA,IAC1C,MAAM,KAAK,uBAAuB;AAAA,IAClC,MAAM,SAAS,eAAe,UAAU;AAAA,IACxC,MAAM,UAA8B,CAAC;AAAA,IACrC,MAAM,QAAQ,IAAI;AAAA,IAClB,MAAM,aAAa,QAAQ;AAAA,IAE3B,WAAW,KAAK,QAAQ;AAAA,MACtB,IAAI,OAAO,MAAM,IAAI,EAAE,SAAS;AAAA,MAChC,IAAI,CAAC,MAAM;AAAA,QACT,OAAO,MAAM,KAAK,gBAAgB,EAAE,SAAS;AAAA,QAC7C,MAAM,IAAI,EAAE,WAAW,IAAI;AAAA,MAC7B;AAAA,MACA,IAAI,KAAK,IAAI,EAAE,OAAO;AAAA,QAAG;AAAA,MAEzB,aAAa;AAAA,QACX,WAAW,EAAE;AAAA,QACb,SAAS,EAAE;AAAA,QACX,OAAO;AAAA,QACP,aAAa,EAAE;AAAA,MACjB,CAAC;AAAA,MAED,QAAQ,QAAQ,YAAY,MAAM,KAAK,cAAc;AAAA,MACrD,IAAI;AAAA,QACF,MAAM,OAAO,MAAM,OAAO;AAAA,QAI1B,MAAM,EAAE,GAAG,QAA2B,CAAC,aAAa;AAAA,UAClD,aAAa;AAAA,YACX,WAAW,EAAE;AAAA,YACb,SAAS,EAAE;AAAA,YACX,OAAO;AAAA,YACP,aAAa,EAAE;AAAA,YACf;AAAA,UACF,CAAC;AAAA,SACF;AAAA,QACD,MAAM,OAAO,MACX,eAAe,yEACf,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,IAAI,CAChD;AAAA,QACA,MAAM,OAAO,MAAM,QAAQ;AAAA,QAC3B,KAAK,IAAI,EAAE,OAAO;AAAA,QAClB,QAAQ,KAAK,CAAC;AAAA,QACd,aAAa;AAAA,UACX,WAAW,EAAE;AAAA,UACb,SAAS,EAAE;AAAA,UACX,OAAO;AAAA,UACP,aAAa,EAAE;AAAA,UACf,UAAU;AAAA,QACZ,CAAC;AAAA,QACD,OAAO,KAAc;AAAA,QACrB,MAAM,OAAO,MAAM,UAAU,EAAE,MAAM,MAAG;AAAA,UAAG;AAAA,SAAS;AAAA,QAEpD,IAAK,KAA2B,SAAS,SAAS;AAAA,UAChD,KAAK,IAAI,EAAE,OAAO;AAAA,UAClB,aAAa;AAAA,YACX,WAAW,EAAE;AAAA,YACb,SAAS,EAAE;AAAA,YACX,OAAO;AAAA,YACP,aAAa,EAAE;AAAA,YACf,UAAU;AAAA,UACZ,CAAC;AAAA,UACD;AAAA,QACF;AAAA,QACA,aAAa;AAAA,UACX,WAAW,EAAE;AAAA,UACb,SAAS,EAAE;AAAA,UACX,OAAO;AAAA,UACP,aAAa,EAAE;AAAA,UACf,OAAO;AAAA,QACT,CAAC;AAAA,QACD,MAAM;AAAA,gBACN;AAAA,QACA,QAAQ;AAAA;AAAA,IAEZ;AAAA,IAEA,OAAO;AAAA;AAEX;;;ACtKA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,IAAM,gBAAmC;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAWA,SAAS,wBAAwB,GAAS;AAAA,EACxC,MAAM,UAAU,IAAI,IAAI,OAAO,OAAO,SAAS,CAAC;AAAA,EAChD,WAAW,KAAK,eAAe;AAAA,IAC7B,IAAI,CAAC,QAAQ,IAAI,CAAc,GAAG;AAAA,MAChC,MAAM,IAAI,MACR,6CAA6C,qCAC/C;AAAA,IACF;AAAA,EACF;AAAA,EACA,WAAW,KAAK,SAAS;AAAA,IACvB,IAAI,CAAC,cAAc,SAAS,CAAC,GAAG;AAAA,MAC9B,MAAM,IAAI,MACR,uBAAuB,uCACrB,iFAAiF,SACjF,0CACJ;AAAA,IACF;AAAA,EACF;AAAA;AAWK,SAAS,uBAAuB,CACrC,WACA,UACoB;AAAA,EACpB,yBAAyB;AAAA,EACzB,MAAM,YAAY,kBAAkB;AAAA,EACpC,MAAM,mBAAmB,sBAAsB,iBAAiB,QAAQ;AAAA,EACxE,MAAM,oBAAoB,qBAAqB,QAAQ;AAAA,EACvD,MAAM,cAAc,qBAAqB,QAAQ;AAAA,EAEjD,OAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA,SAAS;AAAA,MACT,aAAa;AAAA,WACP,GAAE,CAAC,IAAU;AAAA,QAGjB,MAAM,cAAc,cAAc,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,GAAG;AAAA,QAK/D,MAAM,GAAG,MAAM;AAAA;AAAA;AAAA;AAAA,gDAIyB;AAAA;AAAA;AAAA,SAGvC;AAAA,QAED,MAAM,GAAG,MAAM;AAAA,uCACgB;AAAA;AAAA,cAEzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAoBL;AAAA,QAED,MAAM,GAAG,MAAM;AAAA,kDAC2B;AAAA,iBACjC,cAAc;AAAA,SACtB;AAAA,QACD,MAAM,GAAG,MAAM;AAAA,wDACiC;AAAA,iBACvC,cAAc;AAAA,SACtB;AAAA,QACD,MAAM,GAAG,MAAM;AAAA,uDACgC;AAAA,iBACtC,cAAc;AAAA,SACtB;AAAA,QAeD,MAAM,SAAS,GAAG;AAAA,QAClB,MAAM,UAAU,GAAG;AAAA,QACnB,MAAM,GAAG,MAAM,kCAAkC;AAAA,QACjD,IAAI;AAAA,UACF,MAAM,GAAG,MAAM;AAAA,yCACgB;AAAA;AAAA,kDAES;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAavC;AAAA,UACD,MAAM,GAAG,MAAM,0BAA0B,cAAc,WAAW;AAAA,UAClE,MAAM,GAAG,MAAM;AAAA,6BACI;AAAA,0CACa;AAAA,8CACI;AAAA,WACnC;AAAA,UACD,MAAM,GAAG,MAAM,0CAA0C;AAAA,UACzD,MAAM;AAAA,UAIN,MAAM,GAAG,MAAM,8CAA8C,EAAE,MAAM,MAAG;AAAA,YAAG;AAAA,WAAS;AAAA,UACpF,MAAM,GAAG,MAAM,0CAA0C,EAAE,MAAM,MAAG;AAAA,YAAG;AAAA,WAAS;AAAA;AAAA;AAAA,IAGtF;AAAA,EACF;AAAA;;;AFlKK,IAAM,yBAAyB,mBACpC,2BACF;AAAA;AAiBO,MAAM,qBAA4E;AAAA,EAUlE;AAAA,EACA;AAAA,EAVL,QAAQ;AAAA,EAEL;AAAA,EAEA;AAAA,EAEA;AAAA,EAEnB,WAAW,CACU,IACA,WACnB,SACA;AAAA,IAHmB;AAAA,IACA;AAAA,IAGnB,KAAK,WAAW,SAAS,YAAY,CAAC;AAAA,IACtC,KAAK,eAAe,SAAS,gBAAgB,CAAC;AAAA,IAG9C,mBAAmB,KAAK,QAAQ;AAAA,IAGhC,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,EAKb,sBAAsB,CAAC,YAAoB;AAAA,IACjD,OAAO,uBAAuB,kBAAiB,KAAK,UAAU,KAAK,cAAc,UAAU;AAAA;AAAA,EAIrF,oBAAoB,GAA2B;AAAA,IACrD,OAAO,qBAAqB,KAAK,UAAU,KAAK,YAAY;AAAA;AAAA,EAQvD,aAAa,GAAG;AAAA,IACrB,OAAO,wBAAwB,KAAK,WAAW,KAAK,QAAQ;AAAA;AAAA,OAQjD,QAAO,GAAkB;AAAA,IACpC,MAAM,IAAI,wBAAwB,KAAK,EAAE,EAAE,IAAI,KAAK,cAAc,CAAC;AAAA;AAAA,EAO7D,iBAAiB,GAAW;AAAA,IAGlC,MAAM,gBAAgB,GAAG,KAAK,YAAY,KAAK;AAAA,IAC/C,MAAM,OAAO,WAAW,KAAK,EAAE,OAAO,aAAa,EAAE,OAAO,KAAK;AAAA,IACjE,OAAO,UAAU;AAAA;AAAA,OAQN,IAAG,CAAC,KAAwD;AAAA,IACvE,MAAM,MAAM,IAAI,KAAK,EAAE,YAAY;AAAA,IACnC,IAAI,QAAQ,KAAK;AAAA,IACjB,IAAI,aAAa,IAAI,cAAc,MAAM;AAAA,IACzC,IAAI,cAAc,MAAM,gBAAgB,IAAI,KAAK;AAAA,IACjD,IAAI,SAAS,WAAU;AAAA,IACvB,IAAI,WAAW;AAAA,IACf,IAAI,mBAAmB;AAAA,IACvB,IAAI,mBAAmB;AAAA,IACvB,IAAI,aAAa;AAAA,IACjB,IAAI,YAAY;AAAA,IAEhB,MAAM,oBAAoB,qBAAqB,KAAK,QAAQ;AAAA,IAC5D,QAAQ,SAAS,qBAAqB,cAAc,4BAClD,2BAA2B,kBAAiB,KAAK,UAAU,CAAC;AAAA,IAC9D,MAAM,oBAAoB,KAAK,qBAAqB;AAAA,IACpD,MAAM,iBAAiB,kBAAkB,SAAS;AAAA,IAElD,MAAM,MAAM;AAAA,oBACI,KAAK;AAAA,UACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAaC,2BAA2B,mBAAmB,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB;AAAA;AAAA,IAErR,MAAM,SAAS;AAAA,MACb,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,KAAK,UAAU,IAAI,KAAK;AAAA,MACxB,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI,mBAAmB,KAAK,UAAU,IAAI,gBAAgB,IAAI;AAAA,IAChE;AAAA,IACA,MAAM,SAAS,MAAM,KAAK,GAAG,MAAM,KAAK,MAAM;AAAA,IAE9C,IAAI,CAAC;AAAA,MAAQ,MAAM,IAAI,MAAM,wBAAwB;AAAA,IACrD,IAAI,KAAK,OAAO,KAAK,GAAG;AAAA,IACxB,OAAO,IAAI;AAAA;AAAA,OAQA,IAAG,CAAC,IAAmE;AAAA,IAClF,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA,eACS,KAAK;AAAA,sCACkB;AAAA;AAAA,kBAGhC,CAAC,IAAI,KAAK,WAAW,GAAG,YAAY,CACtC;AAAA,IAEA,IAAI,CAAC,UAAU,OAAO,KAAK,WAAW;AAAA,MAAG;AAAA,IACzC,OAAO,OAAO,KAAK;AAAA;AAAA,OAQR,KAAI,CACf,SAAoB,WAAU,SAC9B,MAAc,KACmC;AAAA,IACjD,MAAM,OAAO,GAAG,KAAK;AAAA,IACrB,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAI3B;AAAA;AAAA,eAES,KAAK;AAAA;AAAA,yBAEK;AAAA;AAAA;AAAA,iCAInB,CAAC,KAAK,WAAW,QAAQ,KAAK,GAAG,YAAY,CAC/C;AAAA,IACA,IAAI,CAAC;AAAA,MAAQ,OAAO,CAAC;AAAA,IACrB,OAAO,OAAO;AAAA;AAAA,OAQH,KAAI,CAAC,UAAwE;AAAA,IAExF,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAI3B;AAAA,eACS,KAAK;AAAA;AAAA;AAAA;AAAA,eAIL,KAAK;AAAA;AAAA;AAAA,UAGV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAOJ,CAAC,WAAU,YAAY,KAAK,WAAW,WAAU,SAAS,UAAU,GAAG,YAAY,CACrF;AAAA,IAEA,OAAO,QAAQ,OAAO,MAAM;AAAA;AAAA,OAQjB,KAAI,CAAC,SAAS,WAAU,SAA0B;AAAA,IAC7D,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA;AAAA,eAES,KAAK;AAAA;AAAA,yBAEK,oBACnB,CAAC,KAAK,WAAW,QAAQ,GAAG,YAAY,CAC1C;AAAA,IACA,IAAI,CAAC;AAAA,MAAQ,OAAO;AAAA,IACpB,OAAO,SAAS,OAAO,KAAK,GAAG,OAAO,EAAE;AAAA;AAAA,OAS7B,SAAQ,CAAC,YAA4D;AAAA,IAChF,MAAM,eAAe,KAAK,qBAAqB;AAAA,IAE/C,IAAI,WAAW,WAAW,WAAU,UAAU;AAAA,MAC5C,QAAQ,YAAY,qBAAqB,KAAK,uBAAuB,CAAC;AAAA,MACtE,MAAM,KAAK,GAAG,MACZ,UAAU,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAOiB,oBAChC,CAAC,WAAW,QAAQ,WAAW,IAAI,KAAK,WAAW,GAAG,YAAY,CACpE;AAAA,IACF,EAAO,SAAI,WAAW,WAAW,WAAU,SAAS;AAAA,MAClD,QAAQ,YAAY,qBAAqB,KAAK,uBAAuB,CAAC;AAAA,MACtE,MAAM,KAAK,GAAG,MACZ,UAAU,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAWiB,oBAChC;AAAA,QACE,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,QACX,KAAK;AAAA,QACL,GAAG;AAAA,MACL,CACF;AAAA,IACF,EAAO;AAAA,MACL,QAAQ,YAAY,qBAAqB,KAAK,uBAAuB,CAAC;AAAA,MACtE,MAAM,KAAK,GAAG,MACZ;AAAA,mBACW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAYgB,oBAChC;AAAA,QACE,WAAW,SAAS,KAAK,UAAU,WAAW,MAAM,IAAI;AAAA,QACxD,WAAW,SAAS;AAAA,QACpB,WAAW,cAAc;AAAA,QACzB,WAAW;AAAA,QACX,WAAW;AAAA,QACX,KAAK;AAAA,QACL,GAAG;AAAA,MACL,CACF;AAAA;AAAA;AAAA,OAOS,UAAS,GAAkB;AAAA,IACtC,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,KAAK,GAAG,MACZ;AAAA,oBACc,KAAK;AAAA,0BACC,oBACpB,CAAC,KAAK,WAAW,GAAG,YAAY,CAClC;AAAA;AAAA,OAQW,eAAc,CAAC,OAAsC;AAAA,IAChE,MAAM,cAAc,MAAM,gBAAgB,KAAK;AAAA,IAC/C,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA;AAAA,eAES,KAAK;AAAA,wEACoD,oBAClE,CAAC,aAAa,KAAK,WAAW,GAAG,YAAY,CAC/C;AAAA,IACA,IAAI,CAAC,UAAU,OAAO,KAAK,WAAW;AAAA,MAAG,OAAO;AAAA,IAChD,OAAO,OAAO,KAAK,GAAG;AAAA;AAAA,OASX,MAAK,CAAC,OAA+B;AAAA,IAChD,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,KAAK,GAAG,MACZ;AAAA,eACS,KAAK;AAAA;AAAA,oCAEgB,oBAC9B,CAAC,OAAO,KAAK,WAAW,GAAG,YAAY,CACzC;AAAA;AAAA,OAOW,QAAO,CAAC,OAA+B;AAAA,IAClD,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,KAAK,GAAG,MACZ;AAAA,eACS,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAMkB,oBAChC,CAAC,OAAO,KAAK,WAAW,GAAG,YAAY,CACzC;AAAA;AAAA,OAQW,WAAU,CAAC,YAAqE;AAAA,IAC3F,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA,sBACgB,KAAK,iDAAiD,oBACtE,CAAC,YAAY,KAAK,WAAW,GAAG,YAAY,CAC9C;AAAA,IACA,IAAI,CAAC;AAAA,MAAQ,OAAO,CAAC;AAAA,IACrB,OAAO,OAAO;AAAA;AAAA,OAMH,aAAY,CACvB,OACA,UACA,SACA,SACe;AAAA,IACf,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,KAAK,GAAG,MACZ;AAAA,eACS,KAAK;AAAA;AAAA;AAAA;AAAA,oCAIgB,oBAC9B;AAAA,MACE;AAAA,MACA;AAAA,MACA,UAAU,KAAK,UAAU,OAAO,IAAI;AAAA,MACpC;AAAA,MACA,KAAK;AAAA,MACL,GAAG;AAAA,IACL,CACF;AAAA;AAAA,OAMW,OAAM,CAAC,OAA+B;AAAA,IACjD,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,KAAK,GAAG,MACZ,eAAe,KAAK,yCAAyC,oBAC7D,CAAC,OAAO,KAAK,WAAW,GAAG,YAAY,CACzC;AAAA;AAAA,OAQW,yBAAwB,CAAC,QAAmB,aAAoC;AAAA,IAC3F,MAAM,aAAa,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW,EAAE,YAAY;AAAA,IAClE,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,KAAK,GAAG,MACZ,eAAe,KAAK;AAAA;AAAA;AAAA;AAAA,+BAIK,oBACzB,CAAC,KAAK,WAAW,QAAQ,YAAY,GAAG,YAAY,CACtD;AAAA;AAAA,EAwBK,kBAAkB,CACvB,UACA,SACY;AAAA,IAEZ,MAAM,YAAY,KAAK;AAAA,IACvB,IAAI,OAAO,UAAU,YAAY,YAAY;AAAA,MAG3C,MAAM,IAAI,MACR,8FACF;AAAA,IACF;AAAA,IACA,MAAM,OAAO;AAAA,IAEb,MAAM,UAAU,KAAK,kBAAkB;AAAA,IAGvC,MAAM,wBACJ,SAAS,iBAAiB,YACtB,KAAK,SAAS,SAAS,IACrB,KAAK,eACL,OACF,OAAO,KAAK,QAAQ,YAAY,EAAE,WAAW,IAC3C,OACA,QAAQ;AAAA,IAEhB,IAAI,eAAe;AAAA,IACnB,IAAI,eAAoC;AAAA,IACxC,IAAI,iBAAuD;AAAA,IAC3D,IAAI,YAAY;AAAA,IAEhB,MAAM,WAAW,CAAC,WAAoD;AAAA,MACpE,IAAI;AAAA,QACF,SAAS,MAAM;AAAA,QACf,OAAO,KAAK;AAAA,QAEZ,UAAU,EAAE,MAAM,iDAAiD;AAAA,UACjE;AAAA,UACA,YAAY,OAAO;AAAA,UACnB,OAAO;AAAA,QACT,CAAC;AAAA;AAAA;AAAA,IAIL,MAAM,gBAAgB,CACpB,QACA,WACY;AAAA,MACZ,MAAM,MAAO,OAAO,OAAO,OAAO;AAAA,MAClC,IAAI,CAAC;AAAA,QAAK,OAAO;AAAA,MACjB,YAAY,GAAG,MAAM,OAAO,QAAQ,MAAM,GAAG;AAAA,QAC3C,IAAI,IAAI,OAAO;AAAA,UAAG,OAAO;AAAA,MAC3B;AAAA,MACA,OAAO;AAAA;AAAA,IAQT,MAAM,UAAU,OAAO,OAAsE;AAAA,MAC3F,IAAI;AAAA,QACF,OAAO,MAAM,KAAK,IAAI,EAAE;AAAA,QACxB,MAAM;AAAA,QACN;AAAA;AAAA;AAAA,IAIJ,MAAM,qBAAqB,CAAC,QAAqD;AAAA,MAC/E,IAAI,IAAI,YAAY,WAAW,CAAC,IAAI;AAAA,QAAS;AAAA,MAC7C,IAAI;AAAA,MACJ,IAAI;AAAA,QACF,SAAS,KAAK,MAAM,IAAI,OAAO;AAAA,QAC/B,MAAM;AAAA,QACN;AAAA;AAAA,OAEI,YAAY;AAAA,QAChB,MAAM,KAAK,OAAO;AAAA,QAClB,MAAM,WAAW;AAAA,UACf,IAAI,OAAO;AAAA,UACX,OAAO,OAAO;AAAA,UACd,QAAQ,OAAO;AAAA,QACjB;AAAA,QACA,MAAM,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,EAAE;AAAA,QACrE,MAAM,SAA4C;AAAA,UAChD,MAAM,OAAO,WAAW,WAAW,OAAO,WAAW,WAAW;AAAA,UAChE,KAAK,OAAO,WAAW,YAAa,WAAW;AAAA,UAC/C,KAAK,OAAO,WAAW,WAAW;AAAA,QACpC;AAAA,QACA,IAAI,yBAAyB,CAAC,cAAc,QAAQ,qBAAqB;AAAA,UAAG;AAAA,QAC5E,SAAS,MAAM;AAAA,SACd;AAAA;AAAA,IAGL,MAAM,UAAU,YAA2B;AAAA,MACzC,IAAI;AAAA,QAAc;AAAA,MAClB,IAAI;AAAA,QACF,MAAM,SAAS,MAAM,KAAK,QAAQ;AAAA,QAClC,IAAI,cAAc;AAAA,UAChB,OAAO,QAAQ;AAAA,UACf;AAAA,QACF;AAAA,QACA,eAAe;AAAA,QACf,OAAO,GAAG,gBAAgB,kBAAkB;AAAA,QAC5C,OAAO,GAAG,SAAS,MAAM,kBAAkB,CAAC;AAAA,QAC5C,MAAM,OAAO,MAAM,UAAU,SAAS;AAAA,QACtC,YAAY;AAAA,QAIZ,SAAS,EAAE,MAAM,SAAS,CAAC;AAAA,QAC3B,MAAM;AAAA,QACN,kBAAkB;AAAA;AAAA;AAAA,IAItB,MAAM,oBAAoB,MAAY;AAAA,MACpC,IAAI,gBAAgB;AAAA,QAAgB;AAAA,MACpC,MAAM,IAAI;AAAA,MACV,eAAe;AAAA,MACf,IAAI;AAAA,QACF,GAAG,qBAAqB,cAAc;AAAA,QACtC,GAAG,qBAAqB,OAAO;AAAA,QAC/B,GAAG,QAAQ;AAAA,QACX,MAAM;AAAA,MAGR,MAAM,QAAQ,KAAK,IAAI,WAAW,KAAM;AAAA,MACxC,YAAY,KAAK,IAAI,YAAY,GAAG,KAAM;AAAA,MAC1C,iBAAiB,WAAW,MAAM;AAAA,QAChC,iBAAiB;AAAA,QACZ,QAAQ;AAAA,SACZ,KAAK;AAAA;AAAA,IAGL,QAAQ;AAAA,IAEb,OAAO,MAAM;AAAA,MACX,eAAe;AAAA,MACf,IAAI,gBAAgB;AAAA,QAClB,aAAa,cAAc;AAAA,QAC3B,iBAAiB;AAAA,MACnB;AAAA,MACA,MAAM,IAAI;AAAA,MACV,eAAe;AAAA,MACf,IAAI,GAAG;AAAA,QAEL,EAAE,MAAM,YAAY,SAAS,EAC1B,MAAM,MAAM,EAAE,EACd,QAAQ,MAAM;AAAA,UACb,IAAI;AAAA,YACF,EAAE,qBAAqB,cAAc;AAAA,YACrC,EAAE,qBAAqB,OAAO;AAAA,YAC9B,EAAE,QAAQ;AAAA,YACV,MAAM;AAAA,SAGT;AAAA,MACL;AAAA;AAAA;AAGN;;AGnqBA,+BAAS;AAQT;AAAA,wBACE;AAAA,4BACA;AAAA,0BACA;AAAA,0BACA;AAAA,qBACA;AAAA;;;ACXF;AAAA,2BACE;AAAA,0BACA;AAAA,0BACA;AAAA,0BACA;AAAA,qBAEA;AAAA;AAIK,SAAS,6BAA6B,CAC3C,oBACA,wBACA,UACoB;AAAA,EACpB,MAAM,YAAY,yBAAyB;AAAA,EAC3C,MAAM,mBAAmB,uBAAsB,kBAAiB,QAAQ;AAAA,EACxE,MAAM,oBAAoB,sBAAqB,QAAQ;AAAA,EACvD,MAAM,oBAAoB,sBAAqB,QAAQ;AAAA,EACvD,MAAM,cAAc,sBAAqB,QAAQ;AAAA,EACjD,MAAM,oBACJ,kBAAkB,SAAS,IAAI,GAAG,kBAAkB,KAAK,IAAI,kBAAkB;AAAA,EAEjF,OAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA,SAAS;AAAA,MACT,aAAa;AAAA,WACP,GAAE,CAAC,IAAU;AAAA,QACjB,MAAM,GAAG,MAAM;AAAA,uCACgB;AAAA;AAAA,cAEzB;AAAA;AAAA;AAAA,SAGL;AAAA,QACD,MAAM,GAAG,MAAM;AAAA,4DACqC;AAAA,iBAC3C,uBAAuB;AAAA,SAC/B;AAAA,QACD,MAAM,GAAG,MAAM;AAAA,uCACgB;AAAA,cACzB;AAAA;AAAA,2BAEa;AAAA;AAAA,SAElB;AAAA;AAAA,IAEL;AAAA,EACF;AAAA;;;ADjCK,IAAM,gCAAgC,oBAC3C,8BACF;AAAA;AAMO,MAAM,2BAA0D;AAAA,EAYhD;AAAA,EAXL,QAAiC;AAAA,EAE9B;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,EAEnB,WAAW,CACU,IACnB,SACA;AAAA,IAFmB;AAAA,IAGnB,KAAK,WAAW,SAAS,YAAY,CAAC;AAAA,IACtC,KAAK,eAAe,SAAS,gBAAgB,CAAC;AAAA,IAE9C,oBAAmB,KAAK,QAAQ;AAAA,IAGhC,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,EAK1B,sBAAsB,CAAC,YAAoB;AAAA,IACjD,OAAO,wBAAuB,kBAAiB,KAAK,UAAU,KAAK,cAAc,UAAU;AAAA;AAAA,EAIrF,oBAAoB,GAA2B;AAAA,IACrD,OAAO,sBAAqB,KAAK,UAAU,KAAK,YAAY;AAAA;AAAA,EAQvD,aAAa,GAAG;AAAA,IACrB,OAAO,8BACL,KAAK,oBACL,KAAK,wBACL,KAAK,QACP;AAAA;AAAA,OAIW,QAAO,GAAkB;AAAA,IACpC,MAAM,IAAI,wBAAwB,KAAK,EAAE,EAAE,IAAI,KAAK,cAAc,CAAC;AAAA;AAAA,OAGxD,oBAAmB,CAC9B,WACA,eACA,UACyB;AAAA,IACzB,MAAM,oBAAoB,sBAAqB,KAAK,QAAQ;AAAA,IAC5D,MAAM,oBAAoB,KAAK,qBAAqB;AAAA,IACpD,MAAM,cAAc,kBAAkB;AAAA,IAOtC,MAAM,aAAa,IAAI,cAAc;AAAA,IACrC,MAAM,mBAAmB,IAAI,cAAc;AAAA,IAI3C,MAAM,eAAyB,CAAC,IAAI,KAAK,qBAAqB;AAAA,IAC9D,SAAS,IAAI,EAAG,IAAI,aAAa,KAAK;AAAA,MACpC,aAAa,KAAK,IAAI,IAAI,SAAS;AAAA,IACrC;AAAA,IACA,aAAa,KAAK,GAAG,kBAAkB;AAAA,IACvC,MAAM,cAAc,oBAAoB,aAAa,KAAK,aAAa;AAAA,IAEvE,MAAM,cACJ,cAAc,IACV,UAAU,kBAAkB,IAAI,CAAC,GAAG,MAAM,GAAG,QAAQ,IAAI,GAAG,EAAE,KAAK,OAAO,IAC1E;AAAA,IAEN,MAAM,mBAAmB,cAAc,IAAI,kBAAkB,KAAK,IAAI,IAAI,OAAO;AAAA,IACjF,MAAM,2BACJ,cAAc,IAAI,kBAAkB,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,GAAG,EAAE,KAAK,IAAI,IAAI,OAAO;AAAA,IAErF,MAAM,cAAc,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ,EAAE,YAAY;AAAA,IAShE,MAAM,kBACJ,OAAQ,KAAK,GAAwC,YAAY;AAAA,IACnE,IAAI,CAAC,iBAAiB;AAAA,MAUpB,MAAM,QAAQ,KAAK;AAAA,MAKnB,MAAM,WAAW,MAAM,aAAa;AAAA,MACpC,MAAM,kBAAkB,OAAO,MAAM,SAAS,cAAc,MAAM,cAAc;AAAA,MAChF,MAAM,sBAAsB,aAAa;AAAA,MACzC,IAAI,CAAC,mBAAmB,CAAC,qBAAqB;AAAA,QAC5C,MAAM,IAAI,MACR,mJAAmJ,YAAY,OAAO,KAAK,0IAC7K;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,OAAO,kBACT,MACE,KAAK,GAML,QAAQ,IACV,EAAE,OAAO,KAAK,GAAG,MAAM,KAAK,KAAK,EAAE,GAAG,SAAS,MAAM,GAAG;AAAA,IAE5D,IAAI;AAAA,MACF,MAAM,KAAK,MAAM,OAAO;AAAA,MACxB,IAAI;AAAA,QACF,MAAM,KAAK,MAAM,gCAAgC,gBAAgB;AAAA,UAC/D,GAAG;AAAA,UACH;AAAA,QACF,CAAC;AAAA,QAED,MAAM,cAAc,MAAM,KAAK,MAC7B;AAAA;AAAA,iBAEO,KAAK;AAAA,+BACS,gCAAgC,mBAAmB;AAAA,aAExE,CAAC,GAAG,mBAAmB,WAAW,WAAW,CAC/C;AAAA,QACA,MAAM,IAAY,YAAY,KAAK,IAAI,KAAK;AAAA,QAC5C,IAAI,KAAK,eAAe;AAAA,UACtB,MAAM,KAAK,MAAM,QAAQ;AAAA,UACzB,OAAO;AAAA,QACT;AAAA,QAEA,MAAM,WAAW,MAAM,KAAK,MAC1B;AAAA;AAAA,iBAEO,KAAK;AAAA,+BACS,aAAa;AAAA,aAElC,CAAC,GAAG,mBAAmB,SAAS,CAClC;AAAA,QACA,MAAM,kBAA+B,SAAS,KAAK,IAAI,qBAAqB;AAAA,QAC5E,IAAI,mBAAmB,IAAI,KAAK,eAAe,EAAE,QAAQ,IAAI,KAAK,IAAI,GAAG;AAAA,UACvE,MAAM,KAAK,MAAM,QAAQ;AAAA,UACzB,OAAO;AAAA,QACT;AAAA,QAEA,MAAM,eAAe,MAAM,KAAK,MAC9B;AAAA,wBACc,KAAK,uBAAuB;AAAA,oBAChC,2BAA2B;AAAA;AAAA,aAGrC,CAAC,GAAG,mBAAmB,SAAS,CAClC;AAAA,QACA,MAAM,KAAK,MAAM,QAAQ;AAAA,QACzB,OAAO,aAAa,KAAK,IAAI,MAAM;AAAA,QACnC,OAAO,KAAK;AAAA,QACZ,IAAI;AAAA,UACF,MAAM,KAAK,MAAM,UAAU;AAAA,UAC3B,MAAM;AAAA,QAGR,MAAM;AAAA;AAAA,cAER;AAAA,MACA,KAAK,QAAQ;AAAA;AAAA;AAAA,OAIJ,iBAAgB,CAAC,WAAmB,OAA+B;AAAA,IAC9E,IAAI,UAAU,QAAQ,UAAU;AAAA,MAAW;AAAA,IAC3C,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAI5F,MAAM,KAAK,GAAG,MACZ,eAAe,KAAK,uDAAuD,oBAC3E,CAAC,OAA0B,WAAW,GAAG,YAAY,CACvD;AAAA;AAAA,OAGW,gBAAe,CAAC,WAAkC;AAAA,IAC7D,MAAM,oBAAoB,sBAAqB,KAAK,QAAQ;AAAA,IAC5D,MAAM,sBACJ,kBAAkB,SAAS,IAAI,kBAAkB,KAAK,IAAI,IAAI,OAAO;AAAA,IACvE,MAAM,oBAAoB,KAAK,qBAAqB;AAAA,IACpD,MAAM,0BACJ,kBAAkB,SAAS,IACvB,kBAAkB,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,GAAG,EAAE,KAAK,IAAI,IAAI,OAC1D;AAAA,IACN,MAAM,gBAAgB,kBAAkB,SAAS;AAAA,IAEjD,MAAM,KAAK,GAAG,MACZ;AAAA,oBACc,KAAK,uBAAuB;AAAA,gBAChC,2BAA2B;AAAA,OAErC,CAAC,GAAG,mBAAmB,SAAS,CAClC;AAAA;AAAA,OAGW,kBAAiB,CAAC,WAAmB,iBAA0C;AAAA,IAC1F,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAE5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA;AAAA,aAEO,KAAK;AAAA,kDACgC;AAAA,OAE5C,CAAC,WAAW,iBAAiB,GAAG,YAAY,CAC9C;AAAA,IAEA,OAAO,SAAS,OAAO,KAAK,IAAI,SAAS,KAAK,EAAE;AAAA;AAAA,OAGrC,2BAA0B,CACrC,WACA,QAC6B;AAAA,IAC7B,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAE5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA;AAAA,aAEO,KAAK;AAAA,6BACW;AAAA;AAAA;AAAA,OAIvB,CAAC,WAAW,QAAQ,GAAG,YAAY,CACrC;AAAA,IAEA,MAAM,aAAa,OAAO,KAAK,IAAI;AAAA,IACnC,IAAI,CAAC;AAAA,MAAY;AAAA,IACjB,OAAO,IAAI,KAAK,UAAU,EAAE,YAAY;AAAA;AAAA,OAG7B,qBAAoB,CAAC,WAAgD;AAAA,IAChF,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAE5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA;AAAA,aAEO,KAAK;AAAA,6BACW;AAAA,OAEvB,CAAC,WAAW,GAAG,YAAY,CAC7B;AAAA,IAEA,MAAM,kBAAkB,OAAO,KAAK,IAAI;AAAA,IACxC,IAAI,CAAC;AAAA,MAAiB;AAAA,IACtB,OAAO,IAAI,KAAK,eAAe,EAAE,YAAY;AAAA;AAAA,OAGlC,qBAAoB,CAAC,WAAmB,iBAAwC;AAAA,IAC3F,MAAM,oBAAoB,sBAAqB,KAAK,QAAQ;AAAA,IAC5D,MAAM,sBACJ,kBAAkB,SAAS,IAAI,kBAAkB,KAAK,IAAI,IAAI,OAAO;AAAA,IACvE,MAAM,oBAAoB,KAAK,qBAAqB;AAAA,IACpD,MAAM,0BACJ,kBAAkB,SAAS,IACvB,kBAAkB,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,GAAG,EAAE,KAAK,IAAI,IAAI,OAC1D;AAAA,IACN,MAAM,iBAAiB,kBAAkB,SAAS;AAAA,IAGlD,MAAM,kBACJ,kBAAkB,SAAS,IAAI,GAAG,kBAAkB,KAAK,IAAI,kBAAkB;AAAA,IAEjF,MAAM,KAAK,GAAG,MACZ;AAAA,oBACc,KAAK,2BAA2B;AAAA,gBACpC,2BAA2B,oBAAoB,iBAAiB;AAAA,qBAC3D;AAAA;AAAA,OAGf,CAAC,GAAG,mBAAmB,WAAW,eAAe,CACnD;AAAA;AAAA,OAGW,MAAK,CAAC,WAAkC;AAAA,IACnD,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAE5F,MAAM,KAAK,GAAG,MACZ,eAAe,KAAK,2CAA2C,oBAC/D,CAAC,WAAW,GAAG,YAAY,CAC7B;AAAA,IACA,MAAM,KAAK,GAAG,MACZ,eAAe,KAAK,+CAA+C,oBACnE,CAAC,WAAW,GAAG,YAAY,CAC7B;AAAA;AAEJ;",
12
- "debugId": "9559FE4247FC32D964756E2164756E21",
11
+ "mappings": ";AAMA;AAEA;AACA,sBAAS;AAST;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAME;AAAA;;;ACjBF;AAAA;AAAA;AAAA;AA0CA,IAAM,WAAW,IAAI;AAAA;AAoBd,MAAM,wBAA0D;AAAA,EACxC;AAAA,EAA7B,WAAW,CAAkB,IAAU;AAAA,IAAV;AAAA;AAAA,OAEvB,uBAAsB,GAAkB;AAAA,IAC5C,MAAM,KAAK,GAAG,MAAM;AAAA,mCACW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAO9B;AAAA;AAAA,OAGG,gBAAe,CAAC,WAAyC;AAAA,IAC7D,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B,uBAAuB,yCACvB,CAAC,SAAS,CACZ;AAAA,IACA,OAAO,IAAI,IAAI,OAAO,KAAK,IAAI,CAAC,MAAM,OAAO,EAAE,OAAO,CAAC,CAAC;AAAA;AAAA,OAQ5C,cAAa,GAA0D;AAAA,IACnF,MAAM,OAAO,KAAK;AAAA,IAClB,IAAI,OAAO,KAAK,YAAY,YAAY;AAAA,MACtC,MAAM,SAAS,MAAM,KAAK,QAAQ;AAAA,MAClC,OAAO,EAAE,QAAQ,SAAS,MAAM,OAAO,QAAQ,EAAE;AAAA,IACnD;AAAA,IACA,OAAO,EAAE,QAAQ,KAAK,IAA8B,SAAS,MAAG;AAAA,MAAG;AAAA,MAAU;AAAA;AAAA,OAGzE,IAAG,CACP,YACA,UAAgC,CAAC,GACS;AAAA,IAC1C,MAAM,MAAM,KAAK;AAAA,IACjB,MAAM,OAAO,SAAS,IAAI,GAAG,KAAK,QAAQ,QAAQ;AAAA,IAClD,MAAM,SAAS,KAAK,KAAK,MAAM,KAAK,YAAY,YAAY,OAAO,CAAC;AAAA,IACpE,SAAS,IACP,KACA,OAAO,MAAM,MAAG;AAAA,MAAG;AAAA,KAAS,CAC9B;AAAA,IACA,OAAO;AAAA;AAAA,OAGK,YAAW,CACvB,YACA,SAC0C;AAAA,IAC1C,MAAM,KAAK,uBAAuB;AAAA,IAClC,MAAM,SAAS,eAAe,UAAU;AAAA,IACxC,MAAM,UAA8B,CAAC;AAAA,IACrC,MAAM,QAAQ,IAAI;AAAA,IAClB,MAAM,aAAa,QAAQ;AAAA,IAE3B,WAAW,KAAK,QAAQ;AAAA,MACtB,IAAI,OAAO,MAAM,IAAI,EAAE,SAAS;AAAA,MAChC,IAAI,CAAC,MAAM;AAAA,QACT,OAAO,MAAM,KAAK,gBAAgB,EAAE,SAAS;AAAA,QAC7C,MAAM,IAAI,EAAE,WAAW,IAAI;AAAA,MAC7B;AAAA,MACA,IAAI,KAAK,IAAI,EAAE,OAAO;AAAA,QAAG;AAAA,MAEzB,aAAa;AAAA,QACX,WAAW,EAAE;AAAA,QACb,SAAS,EAAE;AAAA,QACX,OAAO;AAAA,QACP,aAAa,EAAE;AAAA,MACjB,CAAC;AAAA,MAED,QAAQ,QAAQ,YAAY,MAAM,KAAK,cAAc;AAAA,MACrD,IAAI;AAAA,QACF,MAAM,OAAO,MAAM,OAAO;AAAA,QAI1B,MAAM,EAAE,GAAG,QAA2B,CAAC,aAAa;AAAA,UAClD,aAAa;AAAA,YACX,WAAW,EAAE;AAAA,YACb,SAAS,EAAE;AAAA,YACX,OAAO;AAAA,YACP,aAAa,EAAE;AAAA,YACf;AAAA,UACF,CAAC;AAAA,SACF;AAAA,QACD,MAAM,OAAO,MACX,eAAe,yEACf,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,eAAe,IAAI,CAChD;AAAA,QACA,MAAM,OAAO,MAAM,QAAQ;AAAA,QAC3B,KAAK,IAAI,EAAE,OAAO;AAAA,QAClB,QAAQ,KAAK,CAAC;AAAA,QACd,aAAa;AAAA,UACX,WAAW,EAAE;AAAA,UACb,SAAS,EAAE;AAAA,UACX,OAAO;AAAA,UACP,aAAa,EAAE;AAAA,UACf,UAAU;AAAA,QACZ,CAAC;AAAA,QACD,OAAO,KAAc;AAAA,QACrB,MAAM,OAAO,MAAM,UAAU,EAAE,MAAM,MAAG;AAAA,UAAG;AAAA,SAAS;AAAA,QAEpD,IAAK,KAA2B,SAAS,SAAS;AAAA,UAChD,KAAK,IAAI,EAAE,OAAO;AAAA,UAClB,aAAa;AAAA,YACX,WAAW,EAAE;AAAA,YACb,SAAS,EAAE;AAAA,YACX,OAAO;AAAA,YACP,aAAa,EAAE;AAAA,YACf,UAAU;AAAA,UACZ,CAAC;AAAA,UACD;AAAA,QACF;AAAA,QACA,aAAa;AAAA,UACX,WAAW,EAAE;AAAA,UACb,SAAS,EAAE;AAAA,UACX,OAAO;AAAA,UACP,aAAa,EAAE;AAAA,UACf,OAAO;AAAA,QACT,CAAC;AAAA,QACD,MAAM;AAAA,gBACN;AAAA,QACA,QAAQ;AAAA;AAAA,IAEZ;AAAA,IAEA,OAAO;AAAA;AAEX;;;ACpMA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,IAAM,gBAAmC;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAWA,SAAS,wBAAwB,GAAS;AAAA,EACxC,MAAM,UAAU,IAAI,IAAI,OAAO,OAAO,SAAS,CAAC;AAAA,EAChD,WAAW,KAAK,eAAe;AAAA,IAC7B,IAAI,CAAC,QAAQ,IAAI,CAAc,GAAG;AAAA,MAChC,MAAM,IAAI,MACR,6CAA6C,qCAC/C;AAAA,IACF;AAAA,EACF;AAAA,EACA,WAAW,KAAK,SAAS;AAAA,IACvB,IAAI,CAAC,cAAc,SAAS,CAAC,GAAG;AAAA,MAC9B,MAAM,IAAI,MACR,uBAAuB,uCACrB,iFAAiF,SACjF,0CACJ;AAAA,IACF;AAAA,EACF;AAAA;AAWK,SAAS,uBAAuB,CACrC,WACA,UACoB;AAAA,EACpB,yBAAyB;AAAA,EACzB,MAAM,YAAY,kBAAkB;AAAA,EACpC,MAAM,mBAAmB,sBAAsB,iBAAiB,QAAQ;AAAA,EACxE,MAAM,oBAAoB,qBAAqB,QAAQ;AAAA,EACvD,MAAM,cAAc,qBAAqB,QAAQ;AAAA,EAEjD,OAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA,SAAS;AAAA,MACT,aAAa;AAAA,WACP,GAAE,CAAC,IAAU;AAAA,QAGjB,MAAM,cAAc,cAAc,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,GAAG;AAAA,QAK/D,MAAM,GAAG,MAAM;AAAA;AAAA;AAAA;AAAA,gDAIyB;AAAA;AAAA;AAAA,SAGvC;AAAA,QAED,MAAM,GAAG,MAAM;AAAA,uCACgB;AAAA;AAAA,cAEzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAoBL;AAAA,QAED,MAAM,GAAG,MAAM;AAAA,kDAC2B;AAAA,iBACjC,cAAc;AAAA,SACtB;AAAA,QACD,MAAM,GAAG,MAAM;AAAA,wDACiC;AAAA,iBACvC,cAAc;AAAA,SACtB;AAAA,QACD,MAAM,GAAG,MAAM;AAAA,uDACgC;AAAA,iBACtC,cAAc;AAAA,SACtB;AAAA,QAeD,MAAM,SAAS,GAAG;AAAA,QAClB,MAAM,UAAU,GAAG;AAAA,QACnB,MAAM,GAAG,MAAM,kCAAkC;AAAA,QACjD,IAAI;AAAA,UACF,MAAM,GAAG,MAAM;AAAA,yCACgB;AAAA;AAAA,kDAES;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAavC;AAAA,UACD,MAAM,GAAG,MAAM,0BAA0B,cAAc,WAAW;AAAA,UAClE,MAAM,GAAG,MAAM;AAAA,6BACI;AAAA,0CACa;AAAA,8CACI;AAAA,WACnC;AAAA,UACD,MAAM,GAAG,MAAM,0CAA0C;AAAA,UACzD,MAAM;AAAA,UAIN,MAAM,GAAG,MAAM,8CAA8C,EAAE,MAAM,MAAG;AAAA,YAAG;AAAA,WAAS;AAAA,UACpF,MAAM,GAAG,MAAM,0CAA0C,EAAE,MAAM,MAAG;AAAA,YAAG;AAAA,WAAS;AAAA;AAAA;AAAA,IAGtF;AAAA,EACF;AAAA;;;AFlKK,IAAM,yBAAyB,mBACpC,2BACF;AAAA;AAiBO,MAAM,qBAA4E;AAAA,EAUlE;AAAA,EACA;AAAA,EAVL,QAAQ;AAAA,EAEL;AAAA,EAEA;AAAA,EAEA;AAAA,EAEnB,WAAW,CACU,IACA,WACnB,SACA;AAAA,IAHmB;AAAA,IACA;AAAA,IAGnB,KAAK,WAAW,SAAS,YAAY,CAAC;AAAA,IACtC,KAAK,eAAe,SAAS,gBAAgB,CAAC;AAAA,IAG9C,mBAAmB,KAAK,QAAQ;AAAA,IAGhC,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,EAKb,sBAAsB,CAAC,YAAoB;AAAA,IACjD,OAAO,uBAAuB,kBAAiB,KAAK,UAAU,KAAK,cAAc,UAAU;AAAA;AAAA,EAIrF,oBAAoB,GAA2B;AAAA,IACrD,OAAO,qBAAqB,KAAK,UAAU,KAAK,YAAY;AAAA;AAAA,EAQvD,aAAa,GAAG;AAAA,IACrB,OAAO,wBAAwB,KAAK,WAAW,KAAK,QAAQ;AAAA;AAAA,OAQjD,QAAO,GAAkB;AAAA,IACpC,MAAM,IAAI,wBAAwB,KAAK,EAAE,EAAE,IAAI,KAAK,cAAc,CAAC;AAAA;AAAA,EAO7D,iBAAiB,GAAW;AAAA,IAGlC,MAAM,gBAAgB,GAAG,KAAK,YAAY,KAAK;AAAA,IAC/C,MAAM,OAAO,WAAW,KAAK,EAAE,OAAO,aAAa,EAAE,OAAO,KAAK;AAAA,IACjE,OAAO,UAAU;AAAA;AAAA,OAQN,IAAG,CAAC,KAAwD;AAAA,IACvE,MAAM,MAAM,IAAI,KAAK,EAAE,YAAY;AAAA,IACnC,IAAI,QAAQ,KAAK;AAAA,IACjB,IAAI,aAAa,IAAI,cAAc,MAAM;AAAA,IACzC,IAAI,cAAc,MAAM,gBAAgB,IAAI,KAAK;AAAA,IACjD,IAAI,SAAS,WAAU;AAAA,IACvB,IAAI,WAAW;AAAA,IACf,IAAI,mBAAmB;AAAA,IACvB,IAAI,mBAAmB;AAAA,IACvB,IAAI,aAAa;AAAA,IACjB,IAAI,YAAY;AAAA,IAEhB,MAAM,oBAAoB,qBAAqB,KAAK,QAAQ;AAAA,IAC5D,QAAQ,SAAS,qBAAqB,cAAc,4BAClD,2BAA2B,kBAAiB,KAAK,UAAU,CAAC;AAAA,IAC9D,MAAM,oBAAoB,KAAK,qBAAqB;AAAA,IACpD,MAAM,iBAAiB,kBAAkB,SAAS;AAAA,IAElD,MAAM,MAAM;AAAA,oBACI,KAAK;AAAA,UACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAaC,2BAA2B,mBAAmB,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB,MAAM,iBAAiB;AAAA;AAAA,IAErR,MAAM,SAAS;AAAA,MACb,GAAG;AAAA,MACH,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,KAAK,UAAU,IAAI,KAAK;AAAA,MACxB,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI;AAAA,MACJ,IAAI,mBAAmB,KAAK,UAAU,IAAI,gBAAgB,IAAI;AAAA,IAChE;AAAA,IACA,MAAM,SAAS,MAAM,KAAK,GAAG,MAAM,KAAK,MAAM;AAAA,IAE9C,IAAI,CAAC;AAAA,MAAQ,MAAM,IAAI,MAAM,wBAAwB;AAAA,IACrD,IAAI,KAAK,OAAO,KAAK,GAAG;AAAA,IACxB,OAAO,IAAI;AAAA;AAAA,OAQA,IAAG,CAAC,IAAmE;AAAA,IAClF,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA,eACS,KAAK;AAAA,sCACkB;AAAA;AAAA,kBAGhC,CAAC,IAAI,KAAK,WAAW,GAAG,YAAY,CACtC;AAAA,IAEA,IAAI,CAAC,UAAU,OAAO,KAAK,WAAW;AAAA,MAAG;AAAA,IACzC,OAAO,OAAO,KAAK;AAAA;AAAA,OAQR,KAAI,CACf,SAAoB,WAAU,SAC9B,MAAc,KACmC;AAAA,IACjD,MAAM,OAAO,GAAG,KAAK;AAAA,IACrB,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAI3B;AAAA;AAAA,eAES,KAAK;AAAA;AAAA,yBAEK;AAAA;AAAA;AAAA,iCAInB,CAAC,KAAK,WAAW,QAAQ,KAAK,GAAG,YAAY,CAC/C;AAAA,IACA,IAAI,CAAC;AAAA,MAAQ,OAAO,CAAC;AAAA,IACrB,OAAO,OAAO;AAAA;AAAA,OAQH,KAAI,CAAC,UAAwE;AAAA,IAExF,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAI3B;AAAA,eACS,KAAK;AAAA;AAAA;AAAA;AAAA,eAIL,KAAK;AAAA;AAAA;AAAA,UAGV;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAOJ,CAAC,WAAU,YAAY,KAAK,WAAW,WAAU,SAAS,UAAU,GAAG,YAAY,CACrF;AAAA,IAEA,OAAO,QAAQ,OAAO,MAAM;AAAA;AAAA,OAQjB,KAAI,CAAC,SAAS,WAAU,SAA0B;AAAA,IAC7D,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA;AAAA,eAES,KAAK;AAAA;AAAA,yBAEK,oBACnB,CAAC,KAAK,WAAW,QAAQ,GAAG,YAAY,CAC1C;AAAA,IACA,IAAI,CAAC;AAAA,MAAQ,OAAO;AAAA,IACpB,OAAO,SAAS,OAAO,KAAK,GAAG,OAAO,EAAE;AAAA;AAAA,OAS7B,SAAQ,CAAC,YAA4D;AAAA,IAChF,MAAM,eAAe,KAAK,qBAAqB;AAAA,IAE/C,IAAI,WAAW,WAAW,WAAU,UAAU;AAAA,MAC5C,QAAQ,YAAY,qBAAqB,KAAK,uBAAuB,CAAC;AAAA,MACtE,MAAM,KAAK,GAAG,MACZ,UAAU,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAOiB,oBAChC,CAAC,WAAW,QAAQ,WAAW,IAAI,KAAK,WAAW,GAAG,YAAY,CACpE;AAAA,IACF,EAAO,SAAI,WAAW,WAAW,WAAU,SAAS;AAAA,MAClD,QAAQ,YAAY,qBAAqB,KAAK,uBAAuB,CAAC;AAAA,MACtE,MAAM,KAAK,GAAG,MACZ,UAAU,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAWiB,oBAChC;AAAA,QACE,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,QACX,WAAW;AAAA,QACX,KAAK;AAAA,QACL,GAAG;AAAA,MACL,CACF;AAAA,IACF,EAAO;AAAA,MACL,QAAQ,YAAY,qBAAqB,KAAK,uBAAuB,CAAC;AAAA,MACtE,MAAM,KAAK,GAAG,MACZ;AAAA,mBACW,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wCAYgB,oBAChC;AAAA,QACE,WAAW,SAAS,KAAK,UAAU,WAAW,MAAM,IAAI;AAAA,QACxD,WAAW,SAAS;AAAA,QACpB,WAAW,cAAc;AAAA,QACzB,WAAW;AAAA,QACX,WAAW;AAAA,QACX,KAAK;AAAA,QACL,GAAG;AAAA,MACL,CACF;AAAA;AAAA;AAAA,OAOS,UAAS,GAAkB;AAAA,IACtC,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,KAAK,GAAG,MACZ;AAAA,oBACc,KAAK;AAAA,0BACC,oBACpB,CAAC,KAAK,WAAW,GAAG,YAAY,CAClC;AAAA;AAAA,OAQW,eAAc,CAAC,OAAsC;AAAA,IAChE,MAAM,cAAc,MAAM,gBAAgB,KAAK;AAAA,IAC/C,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA;AAAA,eAES,KAAK;AAAA,wEACoD,oBAClE,CAAC,aAAa,KAAK,WAAW,GAAG,YAAY,CAC/C;AAAA,IACA,IAAI,CAAC,UAAU,OAAO,KAAK,WAAW;AAAA,MAAG,OAAO;AAAA,IAChD,OAAO,OAAO,KAAK,GAAG;AAAA;AAAA,OASX,MAAK,CAAC,OAA+B;AAAA,IAChD,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,KAAK,GAAG,MACZ;AAAA,eACS,KAAK;AAAA;AAAA,oCAEgB,oBAC9B,CAAC,OAAO,KAAK,WAAW,GAAG,YAAY,CACzC;AAAA;AAAA,OAOW,QAAO,CAAC,OAA+B;AAAA,IAClD,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,KAAK,GAAG,MACZ;AAAA,eACS,KAAK;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,sCAMkB,oBAChC,CAAC,OAAO,KAAK,WAAW,GAAG,YAAY,CACzC;AAAA;AAAA,OAQW,WAAU,CAAC,YAAqE;AAAA,IAC3F,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA,sBACgB,KAAK,iDAAiD,oBACtE,CAAC,YAAY,KAAK,WAAW,GAAG,YAAY,CAC9C;AAAA,IACA,IAAI,CAAC;AAAA,MAAQ,OAAO,CAAC;AAAA,IACrB,OAAO,OAAO;AAAA;AAAA,OAMH,aAAY,CACvB,OACA,UACA,SACA,SACe;AAAA,IACf,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,KAAK,GAAG,MACZ;AAAA,eACS,KAAK;AAAA;AAAA;AAAA;AAAA,oCAIgB,oBAC9B;AAAA,MACE;AAAA,MACA;AAAA,MACA,UAAU,KAAK,UAAU,OAAO,IAAI;AAAA,MACpC;AAAA,MACA,KAAK;AAAA,MACL,GAAG;AAAA,IACL,CACF;AAAA;AAAA,OAMW,OAAM,CAAC,OAA+B;AAAA,IACjD,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,KAAK,GAAG,MACZ,eAAe,KAAK,yCAAyC,oBAC7D,CAAC,OAAO,KAAK,WAAW,GAAG,YAAY,CACzC;AAAA;AAAA,OAQW,yBAAwB,CAAC,QAAmB,aAAoC;AAAA,IAC3F,MAAM,aAAa,IAAI,KAAK,KAAK,IAAI,IAAI,WAAW,EAAE,YAAY;AAAA,IAClE,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAC5F,MAAM,KAAK,GAAG,MACZ,eAAe,KAAK;AAAA;AAAA;AAAA;AAAA,+BAIK,oBACzB,CAAC,KAAK,WAAW,QAAQ,YAAY,GAAG,YAAY,CACtD;AAAA;AAAA,EAwBK,kBAAkB,CACvB,UACA,SACY;AAAA,IAEZ,MAAM,YAAY,KAAK;AAAA,IACvB,IAAI,OAAO,UAAU,YAAY,YAAY;AAAA,MAG3C,MAAM,IAAI,MACR,8FACF;AAAA,IACF;AAAA,IACA,MAAM,OAAO;AAAA,IAEb,MAAM,UAAU,KAAK,kBAAkB;AAAA,IAGvC,MAAM,wBACJ,SAAS,iBAAiB,YACtB,KAAK,SAAS,SAAS,IACrB,KAAK,eACL,OACF,OAAO,KAAK,QAAQ,YAAY,EAAE,WAAW,IAC3C,OACA,QAAQ;AAAA,IAEhB,IAAI,eAAe;AAAA,IACnB,IAAI,eAAoC;AAAA,IACxC,IAAI,iBAAuD;AAAA,IAC3D,IAAI,YAAY;AAAA,IAEhB,MAAM,WAAW,CAAC,WAAoD;AAAA,MACpE,IAAI;AAAA,QACF,SAAS,MAAM;AAAA,QACf,OAAO,KAAK;AAAA,QAEZ,UAAU,EAAE,MAAM,iDAAiD;AAAA,UACjE;AAAA,UACA,YAAY,OAAO;AAAA,UACnB,OAAO;AAAA,QACT,CAAC;AAAA;AAAA;AAAA,IAIL,MAAM,gBAAgB,CACpB,QACA,WACY;AAAA,MACZ,MAAM,MAAO,OAAO,OAAO,OAAO;AAAA,MAClC,IAAI,CAAC;AAAA,QAAK,OAAO;AAAA,MACjB,YAAY,GAAG,MAAM,OAAO,QAAQ,MAAM,GAAG;AAAA,QAC3C,IAAI,IAAI,OAAO;AAAA,UAAG,OAAO;AAAA,MAC3B;AAAA,MACA,OAAO;AAAA;AAAA,IAQT,MAAM,UAAU,OAAO,OAAsE;AAAA,MAC3F,IAAI;AAAA,QACF,OAAO,MAAM,KAAK,IAAI,EAAE;AAAA,QACxB,MAAM;AAAA,QACN;AAAA;AAAA;AAAA,IAIJ,MAAM,qBAAqB,CAAC,QAAqD;AAAA,MAC/E,IAAI,IAAI,YAAY,WAAW,CAAC,IAAI;AAAA,QAAS;AAAA,MAC7C,IAAI;AAAA,MACJ,IAAI;AAAA,QACF,SAAS,KAAK,MAAM,IAAI,OAAO;AAAA,QAC/B,MAAM;AAAA,QACN;AAAA;AAAA,OAEI,YAAY;AAAA,QAChB,MAAM,KAAK,OAAO;AAAA,QAClB,MAAM,WAAW;AAAA,UACf,IAAI,OAAO;AAAA,UACX,OAAO,OAAO;AAAA,UACd,QAAQ,OAAO;AAAA,QACjB;AAAA,QACA,MAAM,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,EAAE;AAAA,QACrE,MAAM,SAA4C;AAAA,UAChD,MAAM,OAAO,WAAW,WAAW,OAAO,WAAW,WAAW;AAAA,UAChE,KAAK,OAAO,WAAW,YAAa,WAAW;AAAA,UAC/C,KAAK,OAAO,WAAW,WAAW;AAAA,QACpC;AAAA,QACA,IAAI,yBAAyB,CAAC,cAAc,QAAQ,qBAAqB;AAAA,UAAG;AAAA,QAC5E,SAAS,MAAM;AAAA,SACd;AAAA;AAAA,IAGL,MAAM,UAAU,YAA2B;AAAA,MACzC,IAAI;AAAA,QAAc;AAAA,MAClB,IAAI;AAAA,QACF,MAAM,SAAS,MAAM,KAAK,QAAQ;AAAA,QAClC,IAAI,cAAc;AAAA,UAChB,OAAO,QAAQ;AAAA,UACf;AAAA,QACF;AAAA,QACA,eAAe;AAAA,QACf,OAAO,GAAG,gBAAgB,kBAAkB;AAAA,QAC5C,OAAO,GAAG,SAAS,MAAM,kBAAkB,CAAC;AAAA,QAC5C,MAAM,OAAO,MAAM,UAAU,SAAS;AAAA,QACtC,YAAY;AAAA,QAIZ,SAAS,EAAE,MAAM,SAAS,CAAC;AAAA,QAC3B,MAAM;AAAA,QACN,kBAAkB;AAAA;AAAA;AAAA,IAItB,MAAM,oBAAoB,MAAY;AAAA,MACpC,IAAI,gBAAgB;AAAA,QAAgB;AAAA,MACpC,MAAM,IAAI;AAAA,MACV,eAAe;AAAA,MACf,IAAI;AAAA,QACF,GAAG,qBAAqB,cAAc;AAAA,QACtC,GAAG,qBAAqB,OAAO;AAAA,QAC/B,GAAG,QAAQ;AAAA,QACX,MAAM;AAAA,MAGR,MAAM,QAAQ,KAAK,IAAI,WAAW,KAAM;AAAA,MACxC,YAAY,KAAK,IAAI,YAAY,GAAG,KAAM;AAAA,MAC1C,iBAAiB,WAAW,MAAM;AAAA,QAChC,iBAAiB;AAAA,QACZ,QAAQ;AAAA,SACZ,KAAK;AAAA;AAAA,IAGL,QAAQ;AAAA,IAEb,OAAO,MAAM;AAAA,MACX,eAAe;AAAA,MACf,IAAI,gBAAgB;AAAA,QAClB,aAAa,cAAc;AAAA,QAC3B,iBAAiB;AAAA,MACnB;AAAA,MACA,MAAM,IAAI;AAAA,MACV,eAAe;AAAA,MACf,IAAI,GAAG;AAAA,QAEL,EAAE,MAAM,YAAY,SAAS,EAC1B,MAAM,MAAM,EAAE,EACd,QAAQ,MAAM;AAAA,UACb,IAAI;AAAA,YACF,EAAE,qBAAqB,cAAc;AAAA,YACrC,EAAE,qBAAqB,OAAO;AAAA,YAC9B,EAAE,QAAQ;AAAA,YACV,MAAM;AAAA,SAGT;AAAA,MACL;AAAA;AAAA;AAGN;;AGnqBA,+BAAS;AAQT;AAAA,wBACE;AAAA,4BACA;AAAA,0BACA;AAAA,0BACA;AAAA,qBACA;AAAA;;;ACXF;AAAA,2BACE;AAAA,0BACA;AAAA,0BACA;AAAA,0BACA;AAAA,qBAEA;AAAA;AAIK,SAAS,6BAA6B,CAC3C,oBACA,wBACA,UACoB;AAAA,EACpB,MAAM,YAAY,yBAAyB;AAAA,EAC3C,MAAM,mBAAmB,uBAAsB,kBAAiB,QAAQ;AAAA,EACxE,MAAM,oBAAoB,sBAAqB,QAAQ;AAAA,EACvD,MAAM,oBAAoB,sBAAqB,QAAQ;AAAA,EACvD,MAAM,cAAc,sBAAqB,QAAQ;AAAA,EACjD,MAAM,oBACJ,kBAAkB,SAAS,IAAI,GAAG,kBAAkB,KAAK,IAAI,kBAAkB;AAAA,EAEjF,OAAO;AAAA,IACL;AAAA,MACE;AAAA,MACA,SAAS;AAAA,MACT,aAAa;AAAA,WACP,GAAE,CAAC,IAAU;AAAA,QACjB,MAAM,GAAG,MAAM;AAAA,uCACgB;AAAA;AAAA,cAEzB;AAAA;AAAA;AAAA,SAGL;AAAA,QACD,MAAM,GAAG,MAAM;AAAA,4DACqC;AAAA,iBAC3C,uBAAuB;AAAA,SAC/B;AAAA,QACD,MAAM,GAAG,MAAM;AAAA,uCACgB;AAAA,cACzB;AAAA;AAAA,2BAEa;AAAA;AAAA,SAElB;AAAA;AAAA,IAEL;AAAA,EACF;AAAA;;;ADjCK,IAAM,gCAAgC,oBAC3C,8BACF;AAAA;AAMO,MAAM,2BAA0D;AAAA,EAYhD;AAAA,EAXL,QAAiC;AAAA,EAE9B;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,EAEnB,WAAW,CACU,IACnB,SACA;AAAA,IAFmB;AAAA,IAGnB,KAAK,WAAW,SAAS,YAAY,CAAC;AAAA,IACtC,KAAK,eAAe,SAAS,gBAAgB,CAAC;AAAA,IAE9C,oBAAmB,KAAK,QAAQ;AAAA,IAGhC,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,EAK1B,sBAAsB,CAAC,YAAoB;AAAA,IACjD,OAAO,wBAAuB,kBAAiB,KAAK,UAAU,KAAK,cAAc,UAAU;AAAA;AAAA,EAIrF,oBAAoB,GAA2B;AAAA,IACrD,OAAO,sBAAqB,KAAK,UAAU,KAAK,YAAY;AAAA;AAAA,EAQvD,aAAa,GAAG;AAAA,IACrB,OAAO,8BACL,KAAK,oBACL,KAAK,wBACL,KAAK,QACP;AAAA;AAAA,OAIW,QAAO,GAAkB;AAAA,IACpC,MAAM,IAAI,wBAAwB,KAAK,EAAE,EAAE,IAAI,KAAK,cAAc,CAAC;AAAA;AAAA,OAGxD,oBAAmB,CAC9B,WACA,eACA,UACyB;AAAA,IACzB,MAAM,oBAAoB,sBAAqB,KAAK,QAAQ;AAAA,IAC5D,MAAM,oBAAoB,KAAK,qBAAqB;AAAA,IACpD,MAAM,cAAc,kBAAkB;AAAA,IAOtC,MAAM,aAAa,IAAI,cAAc;AAAA,IACrC,MAAM,mBAAmB,IAAI,cAAc;AAAA,IAI3C,MAAM,eAAyB,CAAC,IAAI,KAAK,qBAAqB;AAAA,IAC9D,SAAS,IAAI,EAAG,IAAI,aAAa,KAAK;AAAA,MACpC,aAAa,KAAK,IAAI,IAAI,SAAS;AAAA,IACrC;AAAA,IACA,aAAa,KAAK,GAAG,kBAAkB;AAAA,IACvC,MAAM,cAAc,oBAAoB,aAAa,KAAK,aAAa;AAAA,IAEvE,MAAM,cACJ,cAAc,IACV,UAAU,kBAAkB,IAAI,CAAC,GAAG,MAAM,GAAG,QAAQ,IAAI,GAAG,EAAE,KAAK,OAAO,IAC1E;AAAA,IAEN,MAAM,mBAAmB,cAAc,IAAI,kBAAkB,KAAK,IAAI,IAAI,OAAO;AAAA,IACjF,MAAM,2BACJ,cAAc,IAAI,kBAAkB,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,GAAG,EAAE,KAAK,IAAI,IAAI,OAAO;AAAA,IAErF,MAAM,cAAc,IAAI,KAAK,KAAK,IAAI,IAAI,QAAQ,EAAE,YAAY;AAAA,IAShE,MAAM,kBACJ,OAAQ,KAAK,GAAwC,YAAY;AAAA,IACnE,IAAI,CAAC,iBAAiB;AAAA,MAUpB,MAAM,QAAQ,KAAK;AAAA,MAKnB,MAAM,WAAW,MAAM,aAAa;AAAA,MACpC,MAAM,kBAAkB,OAAO,MAAM,SAAS,cAAc,MAAM,cAAc;AAAA,MAChF,MAAM,sBAAsB,aAAa;AAAA,MACzC,IAAI,CAAC,mBAAmB,CAAC,qBAAqB;AAAA,QAC5C,MAAM,IAAI,MACR,mJAAmJ,YAAY,OAAO,KAAK,0IAC7K;AAAA,MACF;AAAA,IACF;AAAA,IACA,MAAM,OAAO,kBACT,MACE,KAAK,GAML,QAAQ,IACV,EAAE,OAAO,KAAK,GAAG,MAAM,KAAK,KAAK,EAAE,GAAG,SAAS,MAAM,GAAG;AAAA,IAE5D,IAAI;AAAA,MACF,MAAM,KAAK,MAAM,OAAO;AAAA,MACxB,IAAI;AAAA,QACF,MAAM,KAAK,MAAM,gCAAgC,gBAAgB;AAAA,UAC/D,GAAG;AAAA,UACH;AAAA,QACF,CAAC;AAAA,QAED,MAAM,cAAc,MAAM,KAAK,MAC7B;AAAA;AAAA,iBAEO,KAAK;AAAA,+BACS,gCAAgC,mBAAmB;AAAA,aAExE,CAAC,GAAG,mBAAmB,WAAW,WAAW,CAC/C;AAAA,QACA,MAAM,IAAY,YAAY,KAAK,IAAI,KAAK;AAAA,QAC5C,IAAI,KAAK,eAAe;AAAA,UACtB,MAAM,KAAK,MAAM,QAAQ;AAAA,UACzB,OAAO;AAAA,QACT;AAAA,QAEA,MAAM,WAAW,MAAM,KAAK,MAC1B;AAAA;AAAA,iBAEO,KAAK;AAAA,+BACS,aAAa;AAAA,aAElC,CAAC,GAAG,mBAAmB,SAAS,CAClC;AAAA,QACA,MAAM,kBAA+B,SAAS,KAAK,IAAI,qBAAqB;AAAA,QAC5E,IAAI,mBAAmB,IAAI,KAAK,eAAe,EAAE,QAAQ,IAAI,KAAK,IAAI,GAAG;AAAA,UACvE,MAAM,KAAK,MAAM,QAAQ;AAAA,UACzB,OAAO;AAAA,QACT;AAAA,QAEA,MAAM,eAAe,MAAM,KAAK,MAC9B;AAAA,wBACc,KAAK,uBAAuB;AAAA,oBAChC,2BAA2B;AAAA;AAAA,aAGrC,CAAC,GAAG,mBAAmB,SAAS,CAClC;AAAA,QACA,MAAM,KAAK,MAAM,QAAQ;AAAA,QACzB,OAAO,aAAa,KAAK,IAAI,MAAM;AAAA,QACnC,OAAO,KAAK;AAAA,QACZ,IAAI;AAAA,UACF,MAAM,KAAK,MAAM,UAAU;AAAA,UAC3B,MAAM;AAAA,QAGR,MAAM;AAAA;AAAA,cAER;AAAA,MACA,KAAK,QAAQ;AAAA;AAAA;AAAA,OAIJ,iBAAgB,CAAC,WAAmB,OAA+B;AAAA,IAC9E,IAAI,UAAU,QAAQ,UAAU;AAAA,MAAW;AAAA,IAC3C,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAI5F,MAAM,KAAK,GAAG,MACZ,eAAe,KAAK,uDAAuD,oBAC3E,CAAC,OAA0B,WAAW,GAAG,YAAY,CACvD;AAAA;AAAA,OAGW,gBAAe,CAAC,WAAkC;AAAA,IAC7D,MAAM,oBAAoB,sBAAqB,KAAK,QAAQ;AAAA,IAC5D,MAAM,sBACJ,kBAAkB,SAAS,IAAI,kBAAkB,KAAK,IAAI,IAAI,OAAO;AAAA,IACvE,MAAM,oBAAoB,KAAK,qBAAqB;AAAA,IACpD,MAAM,0BACJ,kBAAkB,SAAS,IACvB,kBAAkB,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,GAAG,EAAE,KAAK,IAAI,IAAI,OAC1D;AAAA,IACN,MAAM,gBAAgB,kBAAkB,SAAS;AAAA,IAEjD,MAAM,KAAK,GAAG,MACZ;AAAA,oBACc,KAAK,uBAAuB;AAAA,gBAChC,2BAA2B;AAAA,OAErC,CAAC,GAAG,mBAAmB,SAAS,CAClC;AAAA;AAAA,OAGW,kBAAiB,CAAC,WAAmB,iBAA0C;AAAA,IAC1F,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAE5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA;AAAA,aAEO,KAAK;AAAA,kDACgC;AAAA,OAE5C,CAAC,WAAW,iBAAiB,GAAG,YAAY,CAC9C;AAAA,IAEA,OAAO,SAAS,OAAO,KAAK,IAAI,SAAS,KAAK,EAAE;AAAA;AAAA,OAGrC,2BAA0B,CACrC,WACA,QAC6B;AAAA,IAC7B,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAE5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA;AAAA,aAEO,KAAK;AAAA,6BACW;AAAA;AAAA;AAAA,OAIvB,CAAC,WAAW,QAAQ,GAAG,YAAY,CACrC;AAAA,IAEA,MAAM,aAAa,OAAO,KAAK,IAAI;AAAA,IACnC,IAAI,CAAC;AAAA,MAAY;AAAA,IACjB,OAAO,IAAI,KAAK,UAAU,EAAE,YAAY;AAAA;AAAA,OAG7B,qBAAoB,CAAC,WAAgD;AAAA,IAChF,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAE5F,MAAM,SAAS,MAAM,KAAK,GAAG,MAC3B;AAAA;AAAA,aAEO,KAAK;AAAA,6BACW;AAAA,OAEvB,CAAC,WAAW,GAAG,YAAY,CAC7B;AAAA,IAEA,MAAM,kBAAkB,OAAO,KAAK,IAAI;AAAA,IACxC,IAAI,CAAC;AAAA,MAAiB;AAAA,IACtB,OAAO,IAAI,KAAK,eAAe,EAAE,YAAY;AAAA;AAAA,OAGlC,qBAAoB,CAAC,WAAmB,iBAAwC;AAAA,IAC3F,MAAM,oBAAoB,sBAAqB,KAAK,QAAQ;AAAA,IAC5D,MAAM,sBACJ,kBAAkB,SAAS,IAAI,kBAAkB,KAAK,IAAI,IAAI,OAAO;AAAA,IACvE,MAAM,oBAAoB,KAAK,qBAAqB;AAAA,IACpD,MAAM,0BACJ,kBAAkB,SAAS,IACvB,kBAAkB,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,GAAG,EAAE,KAAK,IAAI,IAAI,OAC1D;AAAA,IACN,MAAM,iBAAiB,kBAAkB,SAAS;AAAA,IAGlD,MAAM,kBACJ,kBAAkB,SAAS,IAAI,GAAG,kBAAkB,KAAK,IAAI,kBAAkB;AAAA,IAEjF,MAAM,KAAK,GAAG,MACZ;AAAA,oBACc,KAAK,2BAA2B;AAAA,gBACpC,2BAA2B,oBAAoB,iBAAiB;AAAA,qBAC3D;AAAA;AAAA,OAGf,CAAC,GAAG,mBAAmB,WAAW,eAAe,CACnD;AAAA;AAAA,OAGW,MAAK,CAAC,WAAkC;AAAA,IACnD,QAAQ,YAAY,kBAAkB,QAAQ,iBAAiB,KAAK,uBAAuB,CAAC;AAAA,IAE5F,MAAM,KAAK,GAAG,MACZ,eAAe,KAAK,2CAA2C,oBAC/D,CAAC,WAAW,GAAG,YAAY,CAC7B;AAAA,IACA,MAAM,KAAK,GAAG,MACZ,eAAe,KAAK,+CAA+C,oBACnE,CAAC,WAAW,GAAG,YAAY,CAC7B;AAAA;AAEJ;",
12
+ "debugId": "A07A5231BDAE0A9B64756E2164756E21",
13
13
  "names": []
14
14
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/job-queue/bun.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/job-queue/bun.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,UAAU,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/job-queue/common.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAK7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,uCAAuC,CAAC;AACtD,cAAc,6CAA6C,CAAC"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/job-queue/common.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC;AAK7C,cAAc,uCAAuC,CAAC;AACtD,cAAc,uCAAuC,CAAC;AACtD,cAAc,6CAA6C,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/job-queue/node.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/job-queue/node.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,UAAU,CAAC"}
@@ -16,6 +16,7 @@ import {
16
16
  MIGRATIONS_TABLE,
17
17
  sortMigrations
18
18
  } from "@workglow/storage";
19
+ var runLocks = new WeakMap;
19
20
 
20
21
  class PostgresMigrationRunner {
21
22
  db;
@@ -48,6 +49,15 @@ class PostgresMigrationRunner {
48
49
  } };
49
50
  }
50
51
  async run(migrations, options = {}) {
52
+ const key = this.db;
53
+ const prev = runLocks.get(key) ?? Promise.resolve();
54
+ const result = prev.then(() => this.runInternal(migrations, options));
55
+ runLocks.set(key, result.catch(() => {
56
+ return;
57
+ }));
58
+ return result;
59
+ }
60
+ async runInternal(migrations, options) {
51
61
  await this.ensureBookkeepingTable();
52
62
  const sorted = sortMigrations(migrations);
53
63
  const applied = [];
@@ -895,4 +905,4 @@ export {
895
905
  POSTGRES_QUEUE_STORAGE
896
906
  };
897
907
 
898
- //# debugId=2ED5372BB2A9B7BA64756E2164756E21
908
+ //# debugId=4374150EC82279E664756E2164756E21