@workglow/postgres 0.2.34 → 0.2.36

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
@@ -4,11 +4,11 @@
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 type { Pool, PoolConfig } from \"pg\";\n\nexport type { Pool, PoolConfig };\n\nlet _pg: typeof import(\"pg\") | undefined;\n\n/**\n * Dynamically loads the `pg` package (Node.js and Bun). Idempotent; same implementation as\n * {@link Postgres.init} (mirrors {@link Sqlite.init} from `@workglow/sqlite/storage`).\n *\n * Call before using {@link getPostgres} or {@link createPool}.\n */\nexport async function loadPostgres(): Promise<void> {\n if (_pg) {\n return;\n }\n try {\n _pg = await import(\"pg\");\n } catch {\n throw new Error(\n 'The \"pg\" package is required for @workglow/postgres/storage on Node.js or Bun. Install: bun add pg'\n );\n }\n}\n\n/** Resolved `pg` module after {@link Postgres.init} / {@link loadPostgres}. */\nexport function getPostgres(): typeof import(\"pg\") {\n if (!_pg) {\n throw new Error(\n \"Postgres is not ready. Await Postgres.init() before using getPostgres() or Postgres.module.\"\n );\n }\n return _pg;\n}\n\n/** Creates a connection pool after loading `pg`. */\nexport async function createPool(config: PoolConfig): Promise<Pool> {\n await loadPostgres();\n return new _pg!.Pool(config);\n}\n\n/** Namespaced helpers (lazy `pg` load). {@link Postgres.init} matches {@link Sqlite.init}. */\nexport const Postgres = {\n init: loadPostgres,\n load: loadPostgres,\n get module(): typeof import(\"pg\") {\n return getPostgres();\n },\n createPool,\n} as const;\n",
6
6
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { JsonSchema } from \"@workglow/util/schema\";\nimport { createServiceToken } from \"@workglow/util\";\nimport { PostgresTabularStorage } from \"./PostgresTabularStorage\";\nimport {\n DefaultKeyValueKey,\n DefaultKeyValueSchema,\n IKvStorage,\n KvViaTabularStorage,\n} from \"@workglow/storage\";\n\nexport const POSTGRES_KV_REPOSITORY = createServiceToken<IKvStorage<string, any, any>>(\n \"storage.kvRepository.postgres\"\n);\n\n/**\n * A key-value repository implementation that uses PostgreSQL for persistent storage.\n * Leverages a tabular repository abstraction for PostgreSQL operations.\n *\n * @template Key - The type of the primary key\n * @template Value - The type of the value being stored\n * @template Combined - Combined type of Key & Value\n */\nexport class PostgresKvStorage extends KvViaTabularStorage {\n public tabularRepository: PostgresTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >;\n\n /**\n * Creates a new KvStorage instance\n */\n constructor(\n public db: any,\n public dbName: string,\n keySchema: JsonSchema = { type: \"string\" },\n valueSchema: JsonSchema = {}\n ) {\n super(keySchema, valueSchema);\n this.tabularRepository = new PostgresTabularStorage(\n db,\n dbName,\n DefaultKeyValueSchema,\n DefaultKeyValueKey\n );\n }\n}\n",
7
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Pool } from \"@workglow/postgres/storage\";\nimport { createServiceToken } from \"@workglow/util\";\nimport type { TypedArray } from \"@workglow/util/schema\";\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport {\n BaseSqlTabularStorage,\n buildSearchWhere,\n ClientProvidedKeysOption,\n AnyTabularStorage,\n AutoGeneratedKeys,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n ITabularMigration,\n ITabularMigrationApplier,\n MIGRATIONS_TABLE,\n Page,\n PageRequest,\n PostgresDialect,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n SqlTabularMigrationApplier,\n TabularChangePayload,\n TabularSubscribeOptions,\n ValueOptionType,\n type VectorIndexOptions,\n pickCoveringIndex,\n} from \"@workglow/storage\";\n\nexport const POSTGRES_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.postgres\"\n);\n\n/**\n * Validates a vector-index numeric tuning value: undefined is allowed\n * (caller wants the pgvector default), otherwise it must be a finite,\n * positive integer. Throws a clear error rather than splicing `NaN` /\n * `Infinity` / negative numbers / floats into DDL.\n */\nfunction assertPositiveInt(value: number | undefined, label: string): void {\n if (value === undefined) return;\n if (!Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {\n throw new Error(\n `VectorIndexOptions.${label} must be a positive integer; received ${String(value)}`\n );\n }\n}\n\n/**\n * A PostgreSQL-based tabular repository implementation that extends BaseSqlTabularStorage.\n * This class provides persistent storage for data in a PostgreSQL database,\n * making it suitable for multi-user scenarios.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class PostgresTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseSqlTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n protected db: Pool;\n\n /**\n * Creates a new PostgresTabularStorage instance.\n *\n * @param db - PostgreSQL db\n * @param table - Name of the table to store data (defaults to \"tabular_store\")\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n db: Pool,\n table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\",\n tabularMigrations?: ReadonlyArray<ITabularMigration>\n ) {\n super(table, schema, primaryKeyNames, indexes, clientProvidedKeys, tabularMigrations, table);\n this.db = db;\n }\n\n /**\n * Initializes the database table with the required schema.\n * Creates the table if it doesn't exist with primary key and value columns.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n if (this.tabularMigrations && this.tabularMigrations.length > 0) {\n // Probe BEFORE creating so we can tell the orchestrator whether the\n // table existed beforehand. We always create the table at the target\n // schema (idempotent via CREATE TABLE IF NOT EXISTS); the `freshTable`\n // flag lets the orchestrator take the mark-all-applied fast path on a\n // brand-new DB instead of running migration ops against a schema that\n // already matches them.\n const exists = await this.tableExistsAsync();\n await this.createTableAndIndexes();\n await this.applyTabularMigrations({ freshTable: !exists });\n // For pre-existing DBs that ran migrations, re-assert declared indexes\n // (idempotent). On fresh DBs we already did this in createTableAndIndexes.\n if (exists) {\n await this.createDeclaredIndexes();\n }\n return;\n }\n await this.createTableAndIndexes();\n }\n\n private async tableExistsAsync(): Promise<boolean> {\n const r = await this.db.query<{ x: number }, [string]>(\n `SELECT 1 AS x FROM information_schema.tables WHERE table_name = $1 LIMIT 1`,\n [this.table]\n );\n return r.rows.length > 0;\n }\n\n /**\n * Original setupDatabase behavior, extracted so the migrations branch\n * can call it conditionally on a fresh DB.\n */\n private async createTableAndIndexes(): Promise<void> {\n const sql = `\n CREATE TABLE IF NOT EXISTS \"${this.table}\" (\n ${this.constructPrimaryKeyColumns('\"')} ${this.constructValueColumns('\"')},\n PRIMARY KEY (${this.primaryKeyColumnList()})\n )\n `;\n await this.db.query(sql);\n await this.createVectorIndexes();\n await this.createDeclaredIndexes();\n }\n\n /**\n * Index-creation loop extracted so the migration path can re-run it after\n * migrations to ensure idempotence.\n */\n private async createDeclaredIndexes(): Promise<void> {\n const pkColumns = this.primaryKeyColumns();\n const createdIndexes = new Set<string>();\n for (const columns of this.indexes) {\n if (columns.length <= pkColumns.length) {\n // @ts-ignore\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n const indexName = `${this.table}_${columns.join(\"_\")}`;\n const columnList = columns.map((col) => `\"${String(col)}\"`).join(\", \");\n const columnKey = columns.join(\",\");\n if (createdIndexes.has(columnKey)) continue;\n const isRedundant = Array.from(createdIndexes).some((existing) => {\n const existingCols = existing.split(\",\");\n return (\n existingCols.length >= columns.length &&\n columns.every((col, idx) => col === existingCols[idx])\n );\n });\n if (!isRedundant) {\n await this.db.query(\n `CREATE INDEX IF NOT EXISTS \"${indexName}\" ON \"${this.table}\" (${columnList})`\n );\n createdIndexes.add(columnKey);\n }\n }\n }\n\n /**\n * Runs DDL inside the current transaction. Public so the `withTransaction`\n * proxy can route the call to the tx-bound client by overriding `this.db`.\n * Do not call directly; only via the applier's `executeSqlTx`.\n */\n public async runMigrationDdl(sql: string): Promise<void> {\n await this.db.query(sql);\n }\n\n /**\n * Inserts a `(component, version)` row into the bookkeeping table on the\n * current transaction's client. Public for the same reason as\n * {@link runMigrationDdl}.\n */\n public async recordMigrationApplied(\n component: string,\n version: number,\n description: string | null\n ): Promise<void> {\n await this.db.query(\n `INSERT INTO ${MIGRATIONS_TABLE}(component, version, description) VALUES ($1, $2, $3)`,\n [component, version, description]\n );\n }\n\n public override getMigrationApplier(): ITabularMigrationApplier | null {\n return new PostgresTabularMigrationApplierImpl(this);\n }\n\n protected isVectorFormat(format?: string): boolean {\n if (!format) return false;\n return format.startsWith(\"TypedArray:\") || format === \"TypedArray\";\n }\n\n protected getVectorDimensions(typeDef: JsonSchema): number | undefined {\n return undefined;\n }\n\n /**\n * Maps TypeScript/JavaScript types to corresponding PostgreSQL data types.\n * Uses additional schema information like minimum/maximum values, nullable status,\n * and string lengths to create more optimized column types.\n *\n * @param typeDef - The TypeScript/JavaScript type to map\n * @returns The corresponding PostgreSQL data type\n */\n protected mapTypeToSQL(typeDef: JsonSchema): string {\n // Extract the actual non-null type using base helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return \"TEXT /* boolean schema */\";\n }\n\n // Handle BLOB type\n if (actualType.contentEncoding === \"blob\") return \"BYTEA\";\n\n switch (actualType.type) {\n case \"string\":\n // Handle special string formats\n if (actualType.format === \"date-time\") return \"TIMESTAMP\";\n if (actualType.format === \"date\") return \"DATE\";\n if (actualType.format === \"email\") return \"VARCHAR(255)\";\n if (actualType.format === \"uri\") return \"VARCHAR(2048)\";\n if (actualType.format === \"uuid\") return \"UUID\";\n\n // Handle vector format (pgvector extension)\n if (this.isVectorFormat(actualType.format)) {\n const dimension = this.getVectorDimensions(actualType);\n if (typeof dimension === \"number\") {\n return `vector(${dimension})`;\n }\n }\n\n // Use a VARCHAR with maxLength if specified\n if (typeof actualType.maxLength === \"number\") {\n return `VARCHAR(${actualType.maxLength})`;\n }\n\n // Default to TEXT for strings without constraints\n return \"TEXT\";\n\n case \"number\":\n case \"integer\":\n // Handle integer vs floating point\n if (actualType.multipleOf === 1 || actualType.type === \"integer\") {\n // Use PostgreSQL's numeric range types based on min/max values\n if (typeof actualType.minimum === \"number\") {\n if (actualType.minimum >= 0) {\n // For unsigned integers\n if (typeof actualType.maximum === \"number\") {\n if (actualType.maximum <= 32767) return \"SMALLINT\";\n if (actualType.maximum <= 2147483647) return \"INTEGER\";\n }\n return \"BIGINT\";\n }\n }\n\n // Default integer type\n return \"INTEGER\";\n }\n\n // For floating point numbers with precision requirements\n if (actualType.format === \"float\") return \"REAL\";\n if (actualType.format === \"double\") return \"DOUBLE PRECISION\";\n\n // Use NUMERIC with precision/scale if specified\n if (typeof actualType.multipleOf === \"number\") {\n const decimalPlaces = String(actualType.multipleOf).split(\".\")[1]?.length || 0;\n if (decimalPlaces > 0) {\n return `NUMERIC(38, ${decimalPlaces})`;\n }\n }\n\n return \"NUMERIC\";\n\n case \"boolean\":\n return \"BOOLEAN\";\n\n case \"array\":\n // Handle array types (if items type is specified)\n if (\n actualType.items &&\n typeof actualType.items === \"object\" &&\n !Array.isArray(actualType.items)\n ) {\n const itemType = this.mapTypeToSQL(actualType.items as JsonSchema);\n\n // Only use native PostgreSQL arrays for simple scalar types\n // List of types that work well as native PostgreSQL arrays\n const supportedArrayElementTypes = [\n \"TEXT\",\n \"VARCHAR\",\n \"CHAR\",\n \"INTEGER\",\n \"SMALLINT\",\n \"BIGINT\",\n \"REAL\",\n \"DOUBLE PRECISION\",\n \"NUMERIC\",\n \"BOOLEAN\",\n \"UUID\",\n \"DATE\",\n \"TIMESTAMP\",\n ];\n\n // Check if the item type is in our supported list (either exact match or starts with for VARCHAR types)\n const isSupported = supportedArrayElementTypes.some(\n (type) => itemType === type || (itemType.startsWith(type + \"(\") && type !== \"VARCHAR\") // Handle things like VARCHAR(255)\n );\n\n if (isSupported) {\n return `${itemType}[]`;\n } else {\n return \"JSONB /* complex array */\";\n }\n }\n return \"JSONB /* generic array */\";\n\n case \"object\":\n return \"JSONB /* object */\";\n\n default:\n return \"TEXT /* unknown type */\";\n }\n }\n\n /**\n * Generates the SQL column definitions for primary key fields with constraints\n * Handles auto-generated keys using SERIAL for integers and UUID DEFAULT for strings\n * @returns SQL string containing primary key column definitions\n */\n protected override constructPrimaryKeyColumns($delimiter: string = \"\"): string {\n const cols = Object.entries<JsonSchema>(this.primaryKeySchema.properties)\n .map(([key, typeDef]) => {\n // Check if this is an auto-generated key\n if (this.isAutoGeneratedKey(key)) {\n if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // Use SERIAL or BIGSERIAL for auto-increment\n const sqlType = this.mapTypeToSQL(typeDef);\n const isSmallInt = sqlType.includes(\"SMALLINT\");\n const isBigInt = sqlType.includes(\"BIGINT\");\n const serialType = isBigInt ? \"BIGSERIAL\" : isSmallInt ? \"SMALLSERIAL\" : \"SERIAL\";\n return `${$delimiter}${key}${$delimiter} ${serialType}`;\n } else if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // Use UUID with DEFAULT gen_random_uuid()\n return `${$delimiter}${key}${$delimiter} UUID DEFAULT gen_random_uuid()`;\n }\n }\n\n const sqlType = this.mapTypeToSQL(typeDef);\n let constraints = \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${$delimiter}${key}${$delimiter} >= 0)`;\n }\n\n return `${$delimiter}${key}${$delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n return cols;\n }\n\n /**\n * Generates the SQL column definitions for value fields with constraints\n * @returns SQL string containing value column definitions\n */\n protected override constructValueColumns($delimiter: string = \"\"): string {\n const requiredSet = new Set(this.valueSchema.required ?? []);\n const cols = Object.entries<JsonSchema>(this.valueSchema.properties)\n .map(([key, typeDef]) => {\n const sqlType = this.mapTypeToSQL(typeDef);\n const isRequired = requiredSet.has(key);\n const nullable = !isRequired || this.isNullable(typeDef);\n let constraints = nullable ? \"NULL\" : \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${$delimiter}${key}${$delimiter} >= 0)`;\n }\n\n return `${$delimiter}${key}${$delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n if (cols.length > 0) {\n return `, ${cols}`;\n } else {\n return \"\";\n }\n }\n\n /**\n * Convert JavaScript values to PostgreSQL values, including TypedArray to vector string\n */\n protected override jsToSqlValue(column: string, value: Entity[keyof Entity]): ValueOptionType {\n const typeDef = this.schema.properties[column];\n if (typeDef) {\n const actualType = this.getNonNullType(typeDef);\n\n // Handle vector format - convert TypedArray to pgvector string format [1.0, 2.0, ...]\n if (typeof actualType !== \"boolean\" && this.isVectorFormat(actualType.format)) {\n if (value && ArrayBuffer.isView(value) && !(value instanceof DataView)) {\n // It's a TypedArray\n const array = Array.from(value as unknown as TypedArray);\n return `[${array.join(\",\")}]`;\n }\n // If it's already a string (serialized), return as-is\n if (typeof value === \"string\") {\n return value;\n }\n }\n }\n return super.jsToSqlValue(column, value);\n }\n\n /**\n * Convert PostgreSQL values to JS values. Ensures numeric strings become numbers where schema says number.\n */\n protected override sqlToJsValue(column: string, value: ValueOptionType): Entity[keyof Entity] {\n const typeDef = this.schema.properties[column as keyof typeof this.schema.properties] as\n | JsonSchema\n | undefined;\n if (typeDef) {\n if (value === null && this.isNullable(typeDef)) {\n return null as Entity[keyof Entity];\n }\n const actualType = this.getNonNullType(typeDef);\n\n // Handle vector format - convert pgvector string to TypedArray\n if (typeof actualType !== \"boolean\" && this.isVectorFormat(actualType.format)) {\n if (typeof value === \"string\") {\n try {\n // Parse the vector string format [1.0, 2.0, ...] to TypedArray\n const array = JSON.parse(value);\n return new Float32Array(array) as Entity[keyof Entity];\n } catch (e) {\n console.warn(`Failed to parse vector for column ${column}:`, e);\n }\n }\n // If it's already an object/TypedArray, return as-is\n if (value && typeof value === \"object\") {\n return value as Entity[keyof Entity];\n }\n }\n\n // Handle numeric types - PostgreSQL can return them as strings\n if (\n typeof actualType !== \"boolean\" &&\n (actualType.type === \"number\" || actualType.type === \"integer\")\n ) {\n if (typeof value === \"number\") return value as Entity[keyof Entity];\n if (typeof value === \"string\") {\n const parsed = Number(value);\n if (!isNaN(parsed)) return parsed as Entity[keyof Entity];\n }\n }\n }\n return super.sqlToJsValue(column, value);\n }\n\n /**\n * Determines if a field should be treated as unsigned based on schema properties\n * @param typeDef - The schema type definition\n * @returns true if the field should be treated as unsigned\n */\n protected shouldBeUnsigned(typeDef: JsonSchema): boolean {\n // Extract the non-null type using the base class helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return false;\n }\n\n // Check if it's a number type with minimum >= 0\n if (\n (actualType.type === \"number\" || actualType.type === \"integer\") &&\n typeof actualType.minimum === \"number\" &&\n actualType.minimum >= 0\n ) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Gets information about vector columns in the schema\n * @returns Array of objects with column name and dimension\n */\n protected getVectorColumns(): Array<{ column: string; dimension: number }> {\n const vectorColumns: Array<{ column: string; dimension: number }> = [];\n\n // Check all properties in the schema\n for (const [key, typeDef] of Object.entries<JsonSchema>(this.schema.properties)) {\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType !== \"boolean\" && this.isVectorFormat(actualType.format)) {\n const dimension = this.getVectorDimensions(actualType);\n if (typeof dimension === \"number\") {\n vectorColumns.push({ column: key, dimension });\n } else {\n console.warn(`Invalid vector format for column ${key}: ${actualType.format}, skipping`);\n }\n }\n }\n\n return vectorColumns;\n }\n\n /**\n * Subclasses (e.g. {@link PostgresVectorStorage}) override this to tune the\n * index built by {@link createVectorIndexes}. Returning `{}` (the default)\n * requests HNSW with cosine distance and pgvector's built-in `m` /\n * `efConstruction` defaults.\n */\n protected getVectorIndexOptions(): VectorIndexOptions {\n return {};\n }\n\n /**\n * Creates vector-specific indexes for pgvector.\n *\n * Called after table creation if vector columns exist. Honours the options\n * returned by {@link getVectorIndexOptions} — HNSW (default, with optional\n * `m` / `efConstruction` build-time tuning) or IVFFlat (when `lists` is\n * provided). See {@link VectorIndexOptions} for recall/latency trade-offs.\n */\n protected async createVectorIndexes(): Promise<void> {\n const vectorColumns = this.getVectorColumns();\n\n if (vectorColumns.length === 0) {\n return; // No vector columns, nothing to do\n }\n\n const opts = this.getVectorIndexOptions();\n // Validate the option shape up front so a misconfiguration fails before\n // we touch the database (rather than producing surprising SQL errors).\n if (opts.hnsw && opts.ivfflat) {\n throw new Error(\n \"VectorIndexOptions: only one of `hnsw` or `ivfflat` may be set; received both.\"\n );\n }\n assertPositiveInt(opts.hnsw?.m, \"hnsw.m\");\n assertPositiveInt(opts.hnsw?.efConstruction, \"hnsw.efConstruction\");\n assertPositiveInt(opts.hnsw?.efSearch, \"hnsw.efSearch\");\n assertPositiveInt(opts.ivfflat?.lists, \"ivfflat.lists\");\n assertPositiveInt(opts.ivfflat?.probes, \"ivfflat.probes\");\n\n // Try to enable pgvector extension\n try {\n await this.db.query(\"CREATE EXTENSION IF NOT EXISTS vector\");\n } catch (error) {\n console.warn(\n \"pgvector extension not available, vector columns will use TEXT fallback:\",\n error\n );\n return;\n }\n\n const distance = opts.distance ?? \"cosine\";\n const opClass =\n distance === \"l2\"\n ? \"vector_l2_ops\"\n : distance === \"ip\"\n ? \"vector_ip_ops\"\n : \"vector_cosine_ops\";\n\n const tableId = PostgresDialect.quoteId(this.table);\n\n if (opts.ivfflat) {\n // IVFFlat path — explicit `lists` is required.\n const { lists } = opts.ivfflat;\n for (const { column } of vectorColumns) {\n const indexId = PostgresDialect.quoteId(`${this.table}_${column}_ivfflat_idx`);\n const columnId = PostgresDialect.quoteId(column);\n try {\n await this.db.query(`\n CREATE INDEX IF NOT EXISTS ${indexId}\n ON ${tableId}\n USING ivfflat (${columnId} ${opClass})\n WITH (lists = ${lists})\n `);\n } catch (error) {\n console.warn(`Failed to create IVFFlat index on ${column}:`, error);\n }\n }\n return;\n }\n\n // Default: HNSW. `m` and `efConstruction` are build-time; `efSearch` is\n // applied per-session at query time (see PostgresVectorStorage).\n const hnsw = opts.hnsw ?? {};\n const buildParams: string[] = [];\n if (typeof hnsw.m === \"number\") buildParams.push(`m = ${hnsw.m}`);\n if (typeof hnsw.efConstruction === \"number\") {\n buildParams.push(`ef_construction = ${hnsw.efConstruction}`);\n }\n const withClause = buildParams.length > 0 ? ` WITH (${buildParams.join(\", \")})` : \"\";\n\n for (const { column } of vectorColumns) {\n const indexId = PostgresDialect.quoteId(`${this.table}_${column}_hnsw_idx`);\n const columnId = PostgresDialect.quoteId(column);\n try {\n await this.db.query(`\n CREATE INDEX IF NOT EXISTS ${indexId}\n ON ${tableId}\n USING hnsw (${columnId} ${opClass})${withClause}\n `);\n } catch (error) {\n console.warn(`Failed to create HNSW index on ${column}:`, error);\n }\n }\n }\n\n /**\n * Builds the parameterized `INSERT … ON CONFLICT … RETURNING *` SQL for a\n * single entity, applying the auto-generated-key policy. Extracted so\n * {@link put} and {@link putBulk} can share the column/parameter logic\n * while routing the actual query through different connections (the pool\n * vs. a transaction-bound client).\n */\n private buildPutSql(entity: InsertType): { sql: string; params: ValueOptionType[] } {\n // Determine which columns to include in INSERT\n const columnsToInsert: string[] = [];\n const paramsToInsert: ValueOptionType[] = [];\n\n // Handle primary key columns\n const pkColumns = this.primaryKeyColumns();\n const entityRecord = entity as Record<string, unknown>;\n for (const col of pkColumns) {\n const colStr = String(col);\n\n // Check if this is an auto-generated key\n if (this.isAutoGeneratedKey(colStr)) {\n const clientProvidedValue = entityRecord[colStr];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldUseClientValue = false;\n if (this.clientProvidedKeys === \"never\") {\n // Never use client value, let database generate\n shouldUseClientValue = false;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${colStr}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldUseClientValue = true;\n } else {\n // \"if-missing\" - use client value if provided\n shouldUseClientValue = hasClientValue;\n }\n\n if (shouldUseClientValue) {\n columnsToInsert.push(colStr);\n paramsToInsert.push(\n this.jsToSqlValue(colStr, clientProvidedValue as Entity[keyof Entity])\n );\n }\n // Otherwise skip it - let database generate via SERIAL or DEFAULT\n continue;\n }\n\n // Regular primary key column\n columnsToInsert.push(colStr);\n const value = entityRecord[colStr];\n paramsToInsert.push(this.jsToSqlValue(colStr, value as Entity[keyof Entity]));\n }\n\n // Handle value columns\n const valueColumns = this.valueColumns();\n for (const col of valueColumns) {\n const colStr = String(col);\n columnsToInsert.push(colStr);\n const value = entityRecord[colStr];\n paramsToInsert.push(this.jsToSqlValue(colStr, value as Entity[keyof Entity]));\n }\n\n const columnList = columnsToInsert.map((c) => `\"${c}\"`).join(\", \");\n const placeholders = columnsToInsert.map((_, i) => `$${i + 1}`).join(\", \");\n\n // Build ON CONFLICT clause if there are value columns\n const conflictClause =\n valueColumns.length > 0\n ? `\n ON CONFLICT (${this.primaryKeyColumnList('\"')}) DO UPDATE\n SET\n ${(valueColumns as string[])\n .map((col) => {\n const colIdx = columnsToInsert.indexOf(String(col));\n return `\"${col}\" = $${colIdx + 1}`;\n })\n .join(\", \")}\n `\n : \"\";\n\n const sql = `\n INSERT INTO \"${this.table}\" (${columnList})\n VALUES (${placeholders})\n ${conflictClause}\n RETURNING *\n `;\n\n return { sql, params: paramsToInsert };\n }\n\n /** Hydrate a row returned by Postgres back into entity-shaped JS values. */\n private hydrateRow(row: unknown): Entity {\n const entity = row as Entity;\n const record = entity as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n return entity;\n }\n\n /**\n * Acquires a client that BEGIN/COMMIT-style transactions can safely run on.\n *\n * - Real `pg.Pool` exposes `connect()`, which dedicates a client for the\n * transaction duration.\n * - PGlite-style single-connection wrappers (PGLitePool, raw PGlite)\n * serialize every `query()` through one underlying session, so issuing\n * the BEGIN/COMMIT pair directly on `this.db.query` is equivalent.\n * - Anything else — a custom no-`connect()` adapter that fans queries\n * across sessions — would dispatch the BEGIN and the bracketed queries\n * to different sessions, silently breaking atomicity. We refuse to\n * operate on it rather than provide a false guarantee.\n *\n * Whitelist mirrors {@link\n * PostgresRateLimiterStorage.tryReserveExecution}: the rate limiter has\n * the same atomicity requirement, and divergence here would let a pool\n * type be safe in one place and unsafe in another.\n *\n * Caller MUST invoke `release()` on the returned client. The no-op release\n * for single-connection wrappers is safe.\n */\n private async acquireConnection(): Promise<{\n query: Pool[\"query\"];\n release: () => void;\n }> {\n const supportsConnect =\n typeof (this.db as unknown as { connect?: unknown }).connect === \"function\";\n if (supportsConnect) {\n return await (\n this.db as unknown as {\n connect: () => Promise<{ query: Pool[\"query\"]; release: () => void }>;\n }\n ).connect();\n }\n\n // Without connect() we route BEGIN/COMMIT through this.db.query directly.\n // That is only safe if every query funnels through one underlying session.\n // Recognize:\n // - PGLitePool — our own wrapper class; constructor name preserved.\n // - PGlite — third-party, ships minified so `constructor.name` can\n // be obfuscated (observed: \"q\"). Detect via duck-typing on methods\n // PGlite uniquely exposes (`waitReady` Promise + `exec`).\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 `PostgresTabularStorage.putBulk 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 BEGIN and the bracketed INSERTs to different sessions, breaking atomicity.`\n );\n }\n return {\n query: this.db.query.bind(this.db) as Pool[\"query\"],\n release: () => {},\n };\n }\n\n /**\n * Per-instance promise-chain mutex. Only meaningful on single-connection\n * backends (PGlite / PGLitePool) — there `withTransaction` runs on the\n * shared session and we need to keep external callers from slipping into\n * the open transaction. On a real `pg.Pool` (anything exposing\n * `connect()`) the mutex would serialize independent reads/writes that\n * Postgres is happy to fan across separate pool clients, turning the\n * pool's main benefit into a per-instance bottleneck — so we short-circuit\n * to a no-op on that path. Real-pool isolation comes from\n * `withTransaction` dedicating its own client via `pool.connect()`.\n *\n * The Proxy returned by {@link createTxView} routes back to the private\n * `_*Internal` methods directly, so calls made *through* the `tx` handle\n * inside `fn` do not deadlock against the mutex held by `withTransaction`.\n */\n private mutexChain: Promise<void> = Promise.resolve();\n private get serializeOps(): boolean {\n return typeof (this.db as unknown as { connect?: unknown }).connect !== \"function\";\n }\n private async mutex<T>(fn: () => Promise<T>): Promise<T> {\n if (!this.serializeOps) return fn();\n const prev = this.mutexChain;\n let release!: () => void;\n this.mutexChain = new Promise<void>((resolve) => {\n release = resolve;\n });\n await prev;\n try {\n return await fn();\n } finally {\n release();\n }\n }\n\n /**\n * True while the parent instance is between `BEGIN` and `COMMIT`/`ROLLBACK`.\n * Used only to fail fast when `fn` captures the *original* storage instead\n * of the `tx` handle and tries to recursively call `withTransaction` —\n * that would deadlock against its own mutex on the PGlite path. Calls\n * routed through `tx` hit the proxy's `withTransaction` override before\n * reaching here.\n */\n private inTransaction: boolean = false;\n\n /**\n * Emits a `put` event. Overridden on the {@link createTxView} proxy to\n * push into a per-transaction buffer instead, so listeners never observe\n * rows that are about to roll back.\n */\n protected emitPut(entity: Entity): void {\n this.events.emit(\"put\", entity);\n }\n\n /**\n * Stores or updates a row in the database.\n * Uses UPSERT (INSERT ... ON CONFLICT DO UPDATE) for atomic operations.\n *\n * @param entity - The entity to store (may be missing auto-generated keys)\n * @returns The entity with any server-generated fields updated\n * @emits \"put\" event with the updated entity when successful (deferred until\n * commit if inside a {@link withTransaction})\n */\n async put(entity: InsertType): Promise<Entity> {\n return this.mutex(() => this._putInternal(entity));\n }\n\n private async _putInternal(entity: InsertType): Promise<Entity> {\n const { sql, params } = this.buildPutSql(entity);\n const result = await this.db.query(sql, params);\n const updatedEntity = this.hydrateRow(result.rows[0]);\n this.emitPut(updatedEntity);\n return updatedEntity;\n }\n\n /**\n * Stores multiple rows atomically inside a single `BEGIN` / `COMMIT`. All\n * inserts share one connection, which (a) reduces pool churn vs. a\n * `Promise.all` fan-out, (b) gives all-or-nothing semantics, and (c) lets\n * Postgres group the writes into a single commit with one fsync rather than\n * one per row.\n *\n * Per-row UPSERT — instead of a multi-VALUES insert — keeps the\n * auto-generated key policy and `RETURNING *` shape identical to {@link put}\n * and stays correct when a batch mixes rows that include the auto-gen key\n * with rows that omit it.\n *\n * `put` events are deferred until after `COMMIT` so listeners do not see\n * rows that are about to roll back. When this call is nested inside a\n * {@link withTransaction}, deferral extends to that outer commit.\n */\n async putBulk(entities: InsertType[]): Promise<Entity[]> {\n return this.mutex(() => this._putBulkInternal(entities));\n }\n\n private async _putBulkInternal(entities: InsertType[]): Promise<Entity[]> {\n if (entities.length === 0) return [];\n\n // Already inside an outer transaction (called via the `tx` view inside\n // `withTransaction`)? Skip our own BEGIN/COMMIT — Postgres `BEGIN`\n // inside an active transaction is a warning + no-op, and the inner\n // `COMMIT` would commit the OUTER transaction prematurely. Run the\n // inserts directly on `this.db`, which the proxy has already swapped to\n // the transaction-bound client (real pool) or the shared session\n // (PGlite).\n if (this.inTransaction) {\n const updated: Entity[] = [];\n for (const entity of entities) {\n const { sql, params } = this.buildPutSql(entity);\n const result = await this.db.query(sql, params);\n updated.push(this.hydrateRow(result.rows[0]));\n }\n for (const entity of updated) this.emitPut(entity);\n return updated;\n }\n\n const conn = await this.acquireConnection();\n const updatedEntities: Entity[] = [];\n try {\n await conn.query(\"BEGIN\");\n try {\n for (const entity of entities) {\n const { sql, params } = this.buildPutSql(entity);\n const result = await conn.query(sql, params);\n updatedEntities.push(this.hydrateRow(result.rows[0]));\n }\n await conn.query(\"COMMIT\");\n } catch (err) {\n try {\n await conn.query(\"ROLLBACK\");\n } catch {\n // prefer the original error if rollback fails\n }\n throw err;\n }\n } finally {\n conn.release();\n }\n\n for (const entity of updatedEntities) this.emitPut(entity);\n return updatedEntities;\n }\n\n /**\n * Build a Proxy view of `this` for the `withTransaction` callback. The\n * proxy:\n *\n * - Swaps `db` for the transaction-bound handle so every query inside\n * `fn` runs on it: the dedicated client returned by `pool.connect()`\n * for a real `pg.Pool`, or the shared session for PGlite/PGLitePool.\n * - Routes any public method `foo` whose private sibling `_fooInternal`\n * exists to that sibling, so calls made through `tx` bypass the\n * mutex (PGlite path) and do not deadlock. The naming convention is\n * the only sync mechanism — adding a public method with a matching\n * `_fooInternal` is enough; no explicit map to keep in step.\n * - Reports `inTransaction === true`, which is what\n * {@link _putBulkInternal} keys off to skip its own BEGIN/COMMIT\n * and run on the swapped `db` directly.\n * - Overrides {@link emitPut} to queue events on a per-transaction\n * buffer; the outer `withTransaction` flushes that buffer after\n * `COMMIT` (or discards on `ROLLBACK`).\n * - Throws on nested `withTransaction` — Postgres has no autonomous\n * `BEGIN`. Use SAVEPOINT directly for nested rollback boundaries.\n */\n private createTxView(txDb: { query: Pool[\"query\"] }, deferredPutEvents: Entity[]): this {\n const target = this;\n return new Proxy(target, {\n get(t, prop, receiver) {\n if (prop === \"withTransaction\") {\n return () => {\n throw new Error(\n \"PostgresTabularStorage.withTransaction does not support nesting. \" +\n \"Use SAVEPOINT directly or refactor to a single transaction.\"\n );\n };\n }\n if (prop === \"db\") return txDb;\n if (prop === \"inTransaction\") return true;\n if (prop === \"emitPut\") {\n return (entity: Entity) => deferredPutEvents.push(entity);\n }\n if (typeof prop === \"string\") {\n const internal = (t as unknown as Record<string, unknown>)[`_${prop}Internal`];\n if (typeof internal === \"function\") {\n return (...args: unknown[]) =>\n (internal as (...a: unknown[]) => unknown).apply(receiver, args);\n }\n }\n const value = Reflect.get(t, prop, receiver);\n return typeof value === \"function\" ? value.bind(receiver) : value;\n },\n }) as this;\n }\n\n /**\n * Runs `fn` inside a single Postgres transaction.\n *\n * **Real `pg.Pool`** — acquires a dedicated client via `pool.connect()`,\n * runs `BEGIN`/`COMMIT`/`ROLLBACK` on that client, and routes every\n * query inside `fn` through it. The parent storage instance keeps fanning\n * external traffic across the pool, so external callers run *in parallel*\n * with the open transaction (no per-instance mutex). This is the natural\n * Postgres concurrency model.\n *\n * **PGlite / PGLitePool** — single underlying session: the parent's mutex\n * is acquired for the duration of `fn` so external callers queue behind\n * the transaction instead of slipping into it. `BEGIN`/`COMMIT` run on\n * the shared `this.db`.\n *\n * `put` events emitted from inside `fn` (whether via `tx.put`,\n * `tx.putBulk`, or any other writer) are buffered on a per-transaction\n * queue and flushed to the parent's event emitter after `COMMIT`. If `fn`\n * throws, the buffer is discarded along with the rolled-back rows so\n * listeners never observe writes that did not actually commit.\n *\n * Recursive calls — either through the original instance or through `tx`\n * — throw rather than reusing the outer transaction implicitly. Use\n * SAVEPOINT directly for nested rollback boundaries.\n */\n override async withTransaction<T>(fn: (tx: this) => Promise<T>): Promise<T> {\n const supportsConnect =\n typeof (this.db as unknown as { connect?: unknown }).connect === \"function\";\n\n if (supportsConnect) {\n // Real pg.Pool: dedicate a client to this transaction; the parent's\n // pool stays available for external callers, who run in parallel on\n // other clients. We deliberately do NOT set `this.inTransaction` here\n // — it would make external `_putBulkInternal` calls short-circuit\n // their own BEGIN/COMMIT even though they are not actually nested.\n // Nested calls via a captured original `this` simply acquire another\n // pool client and run as an independent transaction; Postgres handles\n // the concurrency, so no nesting guard is required on this path.\n const client = await (\n this.db as unknown as {\n connect: () => Promise<{ query: Pool[\"query\"]; release: () => void }>;\n }\n ).connect();\n try {\n return await this.runInTransaction(fn, { query: client.query.bind(client) });\n } finally {\n client.release();\n }\n }\n\n // PGlite/PGLitePool: single underlying session. Serialize against\n // external callers via the mutex, and set `inTransaction` so that a\n // nested `withTransaction` invoked via the original (rather than `tx`)\n // throws instead of deadlocking on its own mutex.\n if (this.inTransaction) {\n throw new Error(\n \"PostgresTabularStorage.withTransaction does not support nesting. \" +\n \"Use SAVEPOINT directly or refactor to a single transaction.\"\n );\n }\n return this.mutex(async () => {\n this.inTransaction = true;\n try {\n return await this.runInTransaction(fn, { query: this.db.query.bind(this.db) });\n } finally {\n this.inTransaction = false;\n }\n });\n }\n\n private async runInTransaction<T>(\n fn: (tx: this) => Promise<T>,\n txDb: { query: Pool[\"query\"] }\n ): Promise<T> {\n const deferredPutEvents: Entity[] = [];\n await txDb.query(\"BEGIN\");\n let result: T;\n try {\n result = await fn(this.createTxView(txDb, deferredPutEvents));\n await txDb.query(\"COMMIT\");\n } catch (err) {\n try {\n await txDb.query(\"ROLLBACK\");\n } catch {\n // prefer the original error if rollback fails\n }\n throw err;\n }\n // Flush deferred events only on commit success.\n for (const entity of deferredPutEvents) this.events.emit(\"put\", entity);\n return result;\n }\n\n /**\n * Retrieves a value from the database by its primary key.\n *\n * @param key - The primary key object to look up\n * @returns The stored value or undefined if not found\n * @emits \"get\" event with the key when successful\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n return this.mutex(() => this._getInternal(key));\n }\n\n private async _getInternal(key: PrimaryKey): Promise<Entity | undefined> {\n const db = this.db;\n const whereClauses = (this.primaryKeyColumns() as string[])\n .map((discriminatorKey, i) => `\"${discriminatorKey}\" = $${i + 1}`)\n .join(\" AND \");\n\n const sql = `SELECT * FROM \"${this.table}\" WHERE ${whereClauses}`;\n const params = this.getPrimaryKeyAsOrderedArray(key);\n const result = await db.query(sql, params);\n\n let val: Entity | undefined;\n if (result.rows.length > 0) {\n val = result.rows[0] as Entity;\n // Convert all columns according to schema\n const valRecord = val as Record<string, unknown>;\n for (const key in this.schema.properties) {\n valRecord[key] = this.sqlToJsValue(key, valRecord[key] as ValueOptionType);\n }\n } else {\n val = undefined;\n }\n this.events.emit(\"get\", key, val);\n return val;\n }\n\n /**\n * Deletes a row from the database.\n *\n * @param key - The primary key object to delete\n * @emits \"delete\" event with the key when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n return this.mutex(() => this._deleteInternal(value));\n }\n\n private async _deleteInternal(value: PrimaryKey | Entity): Promise<void> {\n const db = this.db;\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n const whereClauses = (this.primaryKeyColumns() as string[])\n .map((key, i) => `${key} = $${i + 1}`)\n .join(\" AND \");\n\n const params = this.getPrimaryKeyAsOrderedArray(key);\n await db.query(`DELETE FROM \"${this.table}\" WHERE ${whereClauses}`, params);\n this.events.emit(\"delete\", key as keyof Entity);\n }\n\n /**\n * Retrieves all entries from the database table, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Promise resolving to an array of entries or undefined if not found\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n return this.mutex(() => this._getAllInternal(options));\n }\n\n private async _getAllInternal(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n const db = this.db;\n let sql = `SELECT * FROM \"${this.table}\"`;\n const params: ValueOptionType[] = [];\n\n if (options?.orderBy && options.orderBy.length > 0) {\n const orderClauses = options.orderBy.map((o) => `\"${String(o.column)}\" ${o.direction}`);\n sql += ` ORDER BY ${orderClauses.join(\", \")}`;\n }\n\n if (options?.limit !== undefined) {\n sql += ` LIMIT $${params.length + 1}`;\n params.push(options.limit);\n }\n\n if (options?.offset !== undefined) {\n sql += ` OFFSET $${params.length + 1}`;\n params.push(options.offset);\n }\n\n const result = params.length > 0 ? await db.query(sql, params) : await db.query(sql);\n\n if (result.rows.length > 0) {\n // Convert all columns according to schema\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n return result.rows;\n }\n return undefined;\n }\n\n /**\n * Deletes all rows from the database table.\n * @emits \"clearall\" event when successful\n */\n async deleteAll(): Promise<void> {\n return this.mutex(() => this._deleteAllInternal());\n }\n\n private async _deleteAllInternal(): Promise<void> {\n const db = this.db;\n await db.query(`DELETE FROM \"${this.table}\"`);\n this.events.emit(\"clearall\");\n }\n\n /**\n * Returns the total number of rows in the database.\n *\n * @returns Promise resolving to the count of stored items\n */\n async size(): Promise<number> {\n return this.mutex(() => this._sizeInternal());\n }\n\n private async _sizeInternal(): Promise<number> {\n const db = this.db;\n const result = await db.query(`SELECT COUNT(*) FROM \"${this.table}\"`);\n return parseInt(result.rows[0].count, 10);\n }\n\n /**\n * Counts rows matching the specified search criteria.\n */\n override async count(criteria?: SearchCriteria<Entity>): Promise<number> {\n return this.mutex(() => this._countInternal(criteria));\n }\n\n private async _countInternal(criteria?: SearchCriteria<Entity>): Promise<number> {\n if (!criteria || Object.keys(criteria).length === 0) {\n return await this._sizeInternal();\n }\n\n this.validateQueryParams(criteria);\n const db = this.db;\n const { whereClause, params } = this.buildDeleteSearchWhere(criteria);\n const result = await db.query<{ count: string }, ValueOptionType[]>(\n `SELECT COUNT(*) FROM \"${this.table}\" WHERE ${whereClause}`,\n params\n );\n return parseInt(result.rows[0].count, 10);\n }\n\n /**\n * Fetches a page of records from the repository.\n * @param offset - Number of records to skip\n * @param limit - Maximum number of records to return\n * @returns Array of entities or undefined if no records found\n */\n async getBulk(offset: number, limit: number): Promise<Entity[] | undefined> {\n return this.mutex(() => this._getBulkInternal(offset, limit));\n }\n\n private async _getBulkInternal(offset: number, limit: number): Promise<Entity[] | undefined> {\n const db = this.db;\n const orderByClause = this.primaryKeyColumns()\n .map((col) => `\"${String(col)}\"`)\n .join(\", \");\n const result = await db.query(\n `SELECT * FROM \"${this.table}\" ORDER BY ${orderByClause} LIMIT $1 OFFSET $2`,\n [limit, offset]\n );\n\n if (!result.rows || result.rows.length === 0) {\n return undefined;\n }\n\n // Convert all columns according to schema (consistent with getAll)\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n\n return result.rows as Entity[];\n }\n\n /**\n * Builds WHERE clause conditions from delete search criteria.\n * @param criteria - The search criteria object\n * @returns Object with whereClause string and params array\n */\n protected buildDeleteSearchWhere(criteria: DeleteSearchCriteria<Entity>): {\n whereClause: string;\n params: ValueOptionType[];\n } {\n // Route through the shared `buildSearchWhere` helper for consistent\n // operator handling, then drop `nextIndex` since deleteSearch callers\n // don't need it. `buildSearchWhereWithIndex` keeps the cursor-pagination\n // contract that does need it.\n const built = buildSearchWhere<Entity>(\n PostgresDialect,\n criteria,\n this.schema.properties as Record<string, unknown>,\n (column, value) => this.jsToSqlValue(column, value)\n );\n return { whereClause: built.whereClause, params: built.params };\n }\n\n /**\n * Cursor-paginated read with keyset predicates pushed into SQL.\n *\n * Goes through {@link mutex} so on the single-connection PGlite path a\n * `getPage` issued while a `withTransaction` is in flight queues behind\n * the transaction's `BEGIN`/`COMMIT` instead of slipping in between them\n * on the shared session. On a real `pg.Pool`, {@link mutex} is a no-op —\n * page reads fan out to other pool clients in parallel as expected. The\n * Proxy returned by {@link createTxView} auto-routes to\n * {@link _getPageInternal} via the `_*Internal` naming convention, so\n * calls made through `tx` bypass the mutex (which the transaction holds)\n * and run on the transaction-bound `db`.\n */\n override async getPage(request: PageRequest<Entity> = {}): Promise<Page<Entity>> {\n return this.mutex(() => this._getPageInternal(request));\n }\n\n private async _getPageInternal(request: PageRequest<Entity>): Promise<Page<Entity>> {\n return this.runSqlPage(undefined, request, this.postgresDialect());\n }\n\n override async queryPage(\n criteria: SearchCriteria<Entity>,\n request: PageRequest<Entity> = {}\n ): Promise<Page<Entity>> {\n return this.mutex(() => this._queryPageInternal(criteria, request));\n }\n\n private async _queryPageInternal(\n criteria: SearchCriteria<Entity>,\n request: PageRequest<Entity>\n ): Promise<Page<Entity>> {\n this.validateQueryParams(criteria, undefined);\n return this.runSqlPage(criteria, request, this.postgresDialect());\n }\n\n private postgresDialect() {\n return {\n quote: '\"',\n placeholder: (index: number) => `$${index}`,\n buildSearchWhere: (criteria: SearchCriteria<Entity>, startIndex: number) =>\n this.buildSearchWhereWithIndex(criteria, startIndex),\n executeSelect: async (sql: string, params: ValueOptionType[]): Promise<Entity[]> => {\n const result = await this.db.query(sql, params as unknown[]);\n const rows = (result.rows ?? []) as Entity[];\n for (const row of rows) {\n const record = row as Record<string, unknown>;\n for (const k in this.schema.properties) {\n record[k] = this.sqlToJsValue(k, record[k] as ValueOptionType);\n }\n }\n return rows;\n },\n };\n }\n\n /**\n * Like {@link buildSearchWhere} but also reports the next free placeholder\n * index — the cursor-pagination machinery needs to chain its own predicates\n * after the criteria block, so it has to know what `$N` to start at.\n */\n private buildSearchWhereWithIndex(\n criteria: SearchCriteria<Entity>,\n startIndex: number\n ): { whereClause: string; params: ValueOptionType[]; nextIndex: number } {\n const built = buildSearchWhere<Entity>(\n PostgresDialect,\n criteria,\n this.schema.properties as Record<string, unknown>,\n (column, value) => this.jsToSqlValue(column, value),\n startIndex\n );\n return {\n whereClause: built.whereClause,\n params: built.params,\n nextIndex: startIndex + built.params.length,\n };\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Supports multiple columns with optional comparison operators.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n */\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n return this.mutex(() => this._deleteSearchInternal(criteria));\n }\n\n private async _deleteSearchInternal(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaKeys.length === 0) {\n return;\n }\n\n const db = this.db;\n const { whereClause, params } = this.buildDeleteSearchWhere(criteria);\n await db.query(`DELETE FROM \"${this.table}\" WHERE ${whereClause}`, params);\n this.events.emit(\"delete\", criteriaKeys[0] as keyof Entity);\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering, limit, and offset.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of matching entities or undefined if no matches found\n */\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n return this.mutex(() => this._queryInternal(criteria, options));\n }\n\n private async _queryInternal(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n this.validateQueryParams(criteria, options);\n const db = this.db;\n\n let sql = `SELECT * FROM \"${this.table}\"`;\n const { whereClause, params } = this.buildDeleteSearchWhere(criteria);\n sql += ` WHERE ${whereClause}`;\n\n if (options?.orderBy && options.orderBy.length > 0) {\n const orderClauses = options.orderBy.map((o) => `\"${String(o.column)}\" ${o.direction}`);\n sql += ` ORDER BY ${orderClauses.join(\", \")}`;\n }\n\n if (options?.limit !== undefined) {\n sql += ` LIMIT $${params.length + 1}`;\n params.push(options.limit);\n }\n\n if (options?.offset !== undefined) {\n sql += ` OFFSET $${params.length + 1}`;\n params.push(options.offset);\n }\n\n const result = await db.query(sql, params);\n\n if (result.rows.length > 0) {\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const k in this.schema.properties) {\n record[k] = this.sqlToJsValue(k, record[k] as ValueOptionType);\n }\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, result.rows as Entity[]);\n return result.rows as Entity[];\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n\n /**\n * Queries entries matching the specified search criteria, returning only the selected columns.\n * Requires a covering index that satisfies the criteria, orderBy, and select columns.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Required select columns plus optional orderBy, limit, and offset\n * @returns Array of partial entities containing only the selected columns\n * @throws {CoveringIndexMissingError} when no registered index covers the query\n */\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n return this.mutex(() => this._queryIndexInternal(criteria, options));\n }\n\n private async _queryIndexInternal<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n this.validateSelect(options);\n this.validateQueryParams(criteria, options);\n\n const registered = this.indexes.map((cols, i) => {\n const cs = Array.isArray(cols) ? (cols as string[]) : [cols as string];\n return { name: `idx_${i}`, keyPath: cs };\n });\n\n pickCoveringIndex({\n table: this.table,\n indexes: registered,\n criteriaColumns: Object.keys(criteria),\n orderByColumns: (options.orderBy ?? []).map((o) => ({\n column: String(o.column),\n direction: o.direction,\n })),\n selectColumns: options.select.map(String),\n primaryKeyColumns: this.primaryKeyNames.map(String),\n });\n\n const cols = options.select.map((c) => `\"${String(c)}\"`).join(\", \");\n let sql = `SELECT ${cols} FROM \"${this.table}\"`;\n const { whereClause, params } = this.buildDeleteSearchWhere(criteria);\n sql += ` WHERE ${whereClause}`;\n\n if (options.orderBy && options.orderBy.length > 0) {\n sql +=\n ` ORDER BY ` +\n options.orderBy.map((o) => `\"${String(o.column)}\" ${o.direction}`).join(\", \");\n }\n if (options.limit !== undefined) {\n sql += ` LIMIT $${params.length + 1}`;\n params.push(options.limit);\n }\n if (options.offset !== undefined) {\n sql += ` OFFSET $${params.length + 1}`;\n params.push(options.offset);\n }\n\n const db = this.db;\n const result = await db.query(sql, params);\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const k of Object.keys(record)) {\n record[k] = this.sqlToJsValue(k, record[k] as ValueOptionType);\n }\n }\n return result.rows as Pick<Entity, K>[];\n }\n\n /**\n * Subscribes to changes in the repository.\n * NOT IMPLEMENTED for PostgreSQL storage.\n *\n * @throws Error always - subscribeToChanges is not supported for PostgreSQL storage\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n throw new Error(\"subscribeToChanges is not supported for PostgresTabularStorage\");\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n public override destroy(): void {\n super.destroy();\n }\n}\n\nclass PostgresTabularMigrationApplierImpl extends SqlTabularMigrationApplier {\n constructor(private readonly host: PostgresTabularStorage<any, any, any, any, any, any>) {\n super();\n }\n protected override dialectName(): \"sqlite\" | \"postgres\" {\n return \"postgres\";\n }\n protected override table(): string {\n return (this.host as unknown as { table: string }).table;\n }\n protected override storage(): AnyTabularStorage {\n return this.host as unknown as AnyTabularStorage;\n }\n protected override mapTypeToSQL(typeDef: JsonSchema): string {\n return (this.host as unknown as { mapTypeToSQL: (t: JsonSchema) => string }).mapTypeToSQL(\n typeDef\n );\n }\n protected override isNullableSchema(typeDef: JsonSchema): boolean {\n return (this.host as unknown as { isNullable: (t: JsonSchema) => boolean }).isNullable(typeDef);\n }\n protected override async executeSql(sql: string): Promise<void> {\n await (this.host as unknown as { db: { query: (sql: string) => Promise<unknown> } }).db.query(\n sql\n );\n }\n protected override async executeSqlTx(sql: string, tx: AnyTabularStorage): Promise<void> {\n await (tx as unknown as { runMigrationDdl: (s: string) => Promise<void> }).runMigrationDdl(sql);\n }\n protected override async recordAppliedTx(\n component: string,\n version: number,\n description: string | undefined,\n tx: AnyTabularStorage\n ): Promise<void> {\n await (\n tx as unknown as {\n recordMigrationApplied: (c: string, v: number, d: string | null) => Promise<void>;\n }\n ).recordMigrationApplied(component, version, description ?? null);\n }\n protected override async recordApplied(\n component: string,\n version: number,\n description: string | undefined\n ): Promise<void> {\n await (\n this.host as unknown as {\n db: {\n query: (sql: string, params: unknown[]) => Promise<unknown>;\n };\n }\n ).db.query(\n `INSERT INTO ${MIGRATIONS_TABLE}(component, version, description) VALUES ($1, $2, $3)`,\n [component, version, description ?? null]\n );\n }\n protected override async queryAppliedVersions(component: string): Promise<Set<number>> {\n const r = await (\n this.host as unknown as {\n db: {\n query: (sql: string, params: unknown[]) => Promise<{ rows: Array<{ version: number }> }>;\n };\n }\n ).db.query(`SELECT version FROM ${MIGRATIONS_TABLE} WHERE component = $1`, [component]);\n return new Set(r.rows.map((row) => Number(row.version)));\n }\n protected override async probeTableExists(): Promise<boolean> {\n const r = await (\n this.host as unknown as {\n db: {\n query: (sql: string, params: unknown[]) => Promise<{ rows: unknown[] }>;\n };\n }\n ).db.query(`SELECT 1 FROM information_schema.tables WHERE table_name = $1 LIMIT 1`, [\n (this.host as unknown as { table: string }).table,\n ]);\n return r.rows.length > 0;\n }\n}\n",
8
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Pool } from \"@workglow/postgres/storage\";\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArrayConstructor,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { cosineSimilarity } from \"@workglow/util/schema\";\nimport { PostgresTabularStorage } from \"./PostgresTabularStorage\";\nimport {\n PostgresDialect,\n StorageValidationError,\n getMetadataProperty,\n getVectorProperty,\n} from \"@workglow/storage\";\nimport type {\n HybridSearchOptions,\n IVectorStorage,\n VectorDistanceMetric,\n VectorIndexOptions,\n VectorSearchOptions,\n} from \"@workglow/storage\";\n\n/**\n * PostgreSQL vector repository implementation using pgvector extension.\n * Extends PostgresTabularStorage for storage.\n * Provides efficient vector similarity search with native database support.\n *\n * Requirements:\n * - PostgreSQL database with pgvector extension installed\n * - CREATE EXTENSION vector;\n *\n * @template Metadata - The metadata type\n * @template VectorCtor - Constructor for stored vectors (default {@link typeof Float32Array})\n */\n/**\n * Regex for validating metadata filter keys to prevent SQL injection.\n * Only allows alphanumeric characters and underscores, starting with a letter or underscore.\n */\nconst SAFE_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\nexport class PostgresVectorStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n Metadata extends Record<string, unknown> = Record<string, unknown>,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n>\n extends PostgresTabularStorage<Schema, PrimaryKeyNames, Entity>\n implements IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames>\n{\n private vectorDimensions: number;\n private readonly vectorCtor: TypedArrayConstructor;\n private vectorPropertyName: keyof Entity;\n private metadataPropertyName: keyof Entity | undefined;\n private readonly indexOptions: VectorIndexOptions;\n\n /**\n * Creates a new PostgreSQL vector repository\n * @param db - PostgreSQL connection pool\n * @param table - The name of the table to use for storage\n * @param schema - The schema definition for the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable\n * @param dimensions - The number of dimensions of the vector\n * @param vectorCtor - TypedArray constructor used when hydrating vectors from SQL text (e.g. {@link Float32Array})\n * @param indexOptions - Tuning for the pgvector index (HNSW vs IVFFlat,\n * distance metric, m / efConstruction / lists / probes).\n * See {@link VectorIndexOptions} for the recall/latency\n * trade-offs. Defaults to HNSW with cosine distance and\n * pgvector's built-in `m=16`, `efConstruction=64` defaults.\n */\n constructor(\n db: Pool,\n table: string,\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n dimensions: number,\n vectorCtor: TypedArrayConstructor = Float32Array,\n indexOptions: VectorIndexOptions = {}\n ) {\n super(db, table, schema, primaryKeyNames, indexes);\n\n this.vectorDimensions = dimensions;\n this.vectorCtor = vectorCtor;\n this.indexOptions = indexOptions;\n\n // Cache vector and metadata property names from schema\n const vectorProp = getVectorProperty(schema);\n if (!vectorProp) {\n throw new Error(\"Schema must have a property with type array and format TypedArray\");\n }\n this.vectorPropertyName = vectorProp as keyof Entity;\n this.metadataPropertyName = getMetadataProperty(schema) as keyof Entity | undefined;\n }\n\n public override getVectorDimensions(): number {\n return this.vectorDimensions;\n }\n\n /** Exposes tuning to {@link PostgresTabularStorage.createVectorIndexes}. */\n protected override getVectorIndexOptions(): VectorIndexOptions {\n return this.indexOptions;\n }\n\n /** Resolved distance metric for this storage (defaults to cosine). */\n private get distance(): VectorDistanceMetric {\n return this.indexOptions.distance ?? \"cosine\";\n }\n\n /**\n * pgvector distance operators per metric:\n * - cosine: `<=>` → cosine distance ∈ [0, 2]\n * - l2 (euclidean): `<->` → L2 distance ∈ [0, ∞)\n * - ip (inner): `<#>` → negative inner product (pgvector negates so\n * smaller = \"more similar\", matching the other ops)\n */\n private get distanceOperator(): string {\n switch (this.distance) {\n case \"l2\":\n return \"<->\";\n case \"ip\":\n return \"<#>\";\n default:\n return \"<=>\";\n }\n }\n\n /**\n * SQL fragment that converts the raw distance from {@link distanceOperator}\n * into a \"higher = more similar\" score that the rest of the API exposes.\n *\n * - cosine: 1 - cosine_distance → similarity in [-1, 1]\n * - l2: 1 / (1 + l2_distance) → ∈ (0, 1], 1 is exact match\n * - ip: -(neg_inner_product) → the actual dot product\n */\n private buildScoreExpr(vectorExpr: string, queryParam: string): string {\n const op = this.distanceOperator;\n switch (this.distance) {\n case \"l2\":\n return `(1.0 / (1.0 + (${vectorExpr} ${op} ${queryParam}::vector)))`;\n case \"ip\":\n return `(-1.0 * (${vectorExpr} ${op} ${queryParam}::vector))`;\n default:\n return `(1 - (${vectorExpr} ${op} ${queryParam}::vector))`;\n }\n }\n\n /**\n * Returns the `efSearch` / `probes` values configured at construction time.\n *\n * NOTE: these are query-time GUCs and must be set on the active session.\n * With a {@link Pool}, a connection is checked out per `pool.query()`, so a\n * standalone `SET hnsw.ef_search = N` issued before a SELECT lands on a\n * different client and has no effect. To apply them, callers should run\n * search queries against a single checked-out client (using `pool.connect()`)\n * inside a transaction with `SET LOCAL`, or set them at the role/database\n * level via `ALTER ROLE ... SET hnsw.ef_search = N`.\n */\n public getQueryTuning(): { efSearch?: number; probes?: number } {\n return {\n efSearch: this.indexOptions.hnsw?.efSearch,\n probes: this.indexOptions.ivfflat?.probes,\n };\n }\n\n public async similaritySearch(\n query: TypedArray,\n options: VectorSearchOptions<Metadata> = {}\n ): Promise<Array<Entity & { score: number }>> {\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n\n try {\n // Try native pgvector search first\n const queryVector = `[${Array.from(query).join(\",\")}]`;\n // Use the raw column name for object-property lookup on result rows,\n // and a quoted form for splicing into SQL identifiers (handles reserved\n // words, mixed case, and any caller-supplied schema).\n const vectorColRaw = String(this.vectorPropertyName);\n const vectorCol = PostgresDialect.quoteId(vectorColRaw);\n const metadataColRaw = this.metadataPropertyName ? String(this.metadataPropertyName) : null;\n const metadataCol = metadataColRaw ? PostgresDialect.quoteId(metadataColRaw) : null;\n const distOp = this.distanceOperator;\n const scoreExpr = this.buildScoreExpr(vectorCol, \"$1\");\n\n let sql = `\n SELECT\n *,\n ${scoreExpr} as score\n FROM \"${this.table}\"\n `;\n\n const params: any[] = [queryVector];\n let paramIndex = 2;\n // Track whether we've actually emitted a WHERE — `filter` alone isn't\n // sufficient because it can be truthy yet contribute zero predicates\n // (empty object, or no metadata column to apply it against).\n let hasWhere = false;\n\n if (filter && Object.keys(filter).length > 0 && metadataCol) {\n const conditions: string[] = [];\n for (const [key, value] of Object.entries(filter)) {\n if (!SAFE_IDENTIFIER_RE.test(key)) {\n throw new StorageValidationError(\n `Invalid metadata filter key: \"${key}\". Keys must match /^[a-zA-Z_][a-zA-Z0-9_]*$/.`\n );\n }\n // The JSON key inside `->>` is already validated above; we still\n // need to quote the column identifier itself to handle non-trivial\n // metadata column names.\n conditions.push(`${metadataCol}->>'${key}' = $${paramIndex}`);\n params.push(String(value));\n paramIndex++;\n }\n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(\" AND \")}`;\n hasWhere = true;\n }\n }\n\n // Always emit the score threshold predicate so behaviour matches the\n // in-memory fallback (`score >= scoreThreshold`) for every metric and\n // every threshold value (including 0 / negative).\n sql += hasWhere ? \" AND\" : \" WHERE\";\n sql += ` ${scoreExpr} >= $${paramIndex}`;\n params.push(scoreThreshold);\n paramIndex++;\n\n // ORDER BY uses the raw distance (smaller = closer) so the configured\n // pgvector index can serve the query directly.\n sql += ` ORDER BY ${vectorCol} ${distOp} $1::vector LIMIT $${paramIndex}`;\n params.push(topK);\n\n const result = await this.db.query(sql, params);\n\n // Fetch vectors separately for each result\n const results: Array<Entity & { score: number }> = [];\n for (const row of result.rows) {\n const vectorResult = await this.db.query(\n `SELECT ${vectorCol}::text FROM \"${this.table}\" WHERE ${this.getPrimaryKeyWhereClause()}`,\n this.getPrimaryKeyValues(row)\n );\n const vectorStr = vectorResult.rows[0]?.[vectorColRaw] || \"[]\";\n const vectorArray = JSON.parse(vectorStr);\n\n results.push({\n ...row,\n [this.vectorPropertyName]: new this.vectorCtor(vectorArray),\n score: parseFloat(row.score),\n } as Entity & { score: number });\n }\n\n return results;\n } catch (error) {\n if (error instanceof StorageValidationError) {\n throw error; // Don't swallow validation errors\n }\n // Fall back to in-memory similarity calculation if pgvector is not available\n console.error(\"pgvector query failed, falling back to in-memory search:\", error);\n return this.searchFallback(query, options);\n }\n }\n\n async hybridSearch(query: TypedArray, options: HybridSearchOptions<Metadata>) {\n const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;\n\n if (!textQuery || textQuery.trim().length === 0) {\n return this.similaritySearch(query, { topK, filter, scoreThreshold });\n }\n\n try {\n // Try native hybrid search with pgvector + full-text\n const queryVector = `[${Array.from(query).join(\",\")}]`;\n // Use plainto_tsquery via parameterized query to avoid tsquery injection\n const tsQueryText = textQuery;\n const vectorColRaw = String(this.vectorPropertyName);\n const vectorCol = PostgresDialect.quoteId(vectorColRaw);\n const metadataColRaw = this.metadataPropertyName ? String(this.metadataPropertyName) : null;\n const metadataCol = metadataColRaw ? PostgresDialect.quoteId(metadataColRaw) : null;\n const vectorScoreExpr = this.buildScoreExpr(vectorCol, \"$1\");\n const combinedScoreExpr = `(\n $2 * ${vectorScoreExpr} +\n $3 * ts_rank(to_tsvector('english', ${metadataCol || \"''\"}::text), plainto_tsquery('english', $4))\n )`;\n\n let sql = `\n SELECT\n *,\n ${combinedScoreExpr} as score\n FROM \"${this.table}\"\n `;\n\n const params: any[] = [queryVector, vectorWeight, 1 - vectorWeight, tsQueryText];\n let paramIndex = 5;\n // Track whether we've actually emitted a WHERE — see similaritySearch\n // for why `filter` alone isn't a sufficient signal.\n let hasWhere = false;\n\n if (filter && Object.keys(filter).length > 0 && metadataCol) {\n const conditions: string[] = [];\n for (const [key, value] of Object.entries(filter)) {\n if (!SAFE_IDENTIFIER_RE.test(key)) {\n throw new StorageValidationError(\n `Invalid metadata filter key: \"${key}\". Keys must match /^[a-zA-Z_][a-zA-Z0-9_]*$/.`\n );\n }\n conditions.push(`${metadataCol}->>'${key}' = $${paramIndex}`);\n params.push(String(value));\n paramIndex++;\n }\n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(\" AND \")}`;\n hasWhere = true;\n }\n }\n\n // Always emit the score threshold predicate (matches the in-memory\n // fallback's `>= scoreThreshold` semantics for every threshold value).\n sql += hasWhere ? \" AND\" : \" WHERE\";\n sql += ` ${combinedScoreExpr} >= $${paramIndex}`;\n params.push(scoreThreshold);\n paramIndex++;\n\n sql += ` ORDER BY score DESC LIMIT $${paramIndex}`;\n params.push(topK);\n\n const result = await this.db.query(sql, params);\n\n // Fetch vectors separately for each result\n const results: Array<Entity & { score: number }> = [];\n for (const row of result.rows) {\n const vectorResult = await this.db.query(\n `SELECT ${vectorCol}::text FROM \"${this.table}\" WHERE ${this.getPrimaryKeyWhereClause()}`,\n this.getPrimaryKeyValues(row)\n );\n const vectorStr = vectorResult.rows[0]?.[vectorColRaw] || \"[]\";\n const vectorArray = JSON.parse(vectorStr);\n\n results.push({\n ...row,\n [this.vectorPropertyName]: new this.vectorCtor(vectorArray),\n score: parseFloat(row.score),\n } as Entity & { score: number });\n }\n\n return results;\n } catch (error) {\n if (error instanceof StorageValidationError) {\n throw error; // Don't swallow validation errors\n }\n // Fall back to in-memory hybrid search\n console.error(\"pgvector hybrid query failed, falling back to in-memory search:\", error);\n return this.hybridSearchFallback(query, options);\n }\n }\n\n /**\n * Throws if the configured distance metric isn't cosine. The in-memory\n * fallback paths below only know how to compute cosine similarity; if\n * pgvector is unavailable for an `l2`/`ip` storage, falling back would\n * silently return wrong scores. Callers using non-cosine distances must\n * keep pgvector working.\n */\n private assertFallbackSupportsDistance(): void {\n if (this.distance !== \"cosine\") {\n throw new Error(\n `PostgresVectorStorage: pgvector is unavailable and the in-memory ` +\n `fallback only supports cosine distance (configured: \"${this.distance}\"). ` +\n `Install pgvector or switch the storage to cosine distance.`\n );\n }\n }\n\n /**\n * Fallback search using in-memory cosine similarity. Only valid for\n * `distance: \"cosine\"`; see {@link assertFallbackSupportsDistance}.\n */\n private async searchFallback(query: TypedArray, options: VectorSearchOptions<Metadata>) {\n this.assertFallbackSupportsDistance();\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n const allRows = (await this.getAll()) || [];\n const results: Array<Entity & { score: number }> = [];\n\n for (const row of allRows) {\n const vector = row[this.vectorPropertyName] as TypedArray;\n const metadata = this.metadataPropertyName\n ? (row[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n if (filter && !this.matchesFilter(metadata, filter)) {\n continue;\n }\n\n const score = cosineSimilarity(query, vector);\n\n if (score >= scoreThreshold) {\n results.push({ ...row, score } as Entity & { score: number });\n }\n }\n\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\n }\n\n /**\n * Fallback hybrid search. Only valid for `distance: \"cosine\"`; see\n * {@link assertFallbackSupportsDistance}.\n */\n private async hybridSearchFallback(query: TypedArray, options: HybridSearchOptions<Metadata>) {\n this.assertFallbackSupportsDistance();\n const { topK = 10, filter, scoreThreshold = 0, textQuery, vectorWeight = 0.7 } = options;\n\n const allRows = (await this.getAll()) || [];\n const results: Array<Entity & { score: number }> = [];\n const queryLower = textQuery.toLowerCase();\n const queryWords = queryLower.split(/\\s+/).filter((w) => w.length > 0);\n\n for (const row of allRows) {\n const vector = row[this.vectorPropertyName] as TypedArray;\n const metadata = this.metadataPropertyName\n ? (row[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n if (filter && !this.matchesFilter(metadata, filter)) {\n continue;\n }\n\n const vectorScore = cosineSimilarity(query, vector);\n const metadataText = Object.values(metadata ?? {})\n .join(\" \")\n .toLowerCase();\n let textScore = 0;\n if (queryWords.length > 0) {\n let matches = 0;\n for (const word of queryWords) {\n if (metadataText.includes(word)) {\n matches++;\n }\n }\n textScore = matches / queryWords.length;\n }\n\n const combinedScore = vectorWeight * vectorScore + (1 - vectorWeight) * textScore;\n\n if (combinedScore >= scoreThreshold) {\n results.push({ ...row, score: combinedScore } as Entity & { score: number });\n }\n }\n\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\n }\n\n private getPrimaryKeyWhereClause(): string {\n const conditions = this.primaryKeyNames.map((key, idx) => `${String(key)} = $${idx + 1}`);\n return conditions.join(\" AND \");\n }\n\n private getPrimaryKeyValues(row: any): any[] {\n return this.primaryKeyNames.map((key) => row[key]);\n }\n\n private matchesFilter(metadata: Metadata, filter: Partial<Metadata>): boolean {\n for (const [key, value] of Object.entries(filter)) {\n if (metadata[key as keyof Metadata] !== value) {\n return false;\n }\n }\n return true;\n }\n}\n",
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 {\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"
7
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Pool } from \"@workglow/postgres/storage\";\nimport { createServiceToken } from \"@workglow/util\";\nimport type { TypedArray } from \"@workglow/util/schema\";\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport {\n BaseSqlTabularStorage,\n buildSearchWhere,\n ClientProvidedKeysOption,\n AnyTabularStorage,\n AutoGeneratedKeys,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n ITabularMigration,\n ITabularMigrationApplier,\n MIGRATIONS_TABLE,\n Page,\n PageRequest,\n PostgresDialect,\n QueryOptions,\n SearchCriteria,\n SimplifyPrimaryKey,\n SqlTabularMigrationApplier,\n TabularChangePayload,\n TabularSubscribeOptions,\n ValueOptionType,\n type VectorIndexOptions,\n pickCoveringIndex,\n} from \"@workglow/storage\";\n\nexport const POSTGRES_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.postgres\"\n);\n\n/**\n * Validates a vector-index numeric tuning value: undefined is allowed\n * (caller wants the pgvector default), otherwise it must be a finite,\n * positive integer. Throws a clear error rather than splicing `NaN` /\n * `Infinity` / negative numbers / floats into DDL.\n */\nfunction assertPositiveInt(value: number | undefined, label: string): void {\n if (value === undefined) return;\n if (!Number.isFinite(value) || !Number.isInteger(value) || value <= 0) {\n throw new Error(\n `VectorIndexOptions.${label} must be a positive integer; received ${String(value)}`\n );\n }\n}\n\n/**\n * A PostgreSQL-based tabular repository implementation that extends BaseSqlTabularStorage.\n * This class provides persistent storage for data in a PostgreSQL database,\n * making it suitable for multi-user scenarios.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class PostgresTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseSqlTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n protected db: Pool;\n\n /**\n * Creates a new PostgresTabularStorage instance.\n *\n * @param db - PostgreSQL db\n * @param table - Name of the table to store data (defaults to \"tabular_store\")\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n db: Pool,\n table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\",\n tabularMigrations?: ReadonlyArray<ITabularMigration>\n ) {\n super(table, schema, primaryKeyNames, indexes, clientProvidedKeys, tabularMigrations, table);\n this.db = db;\n }\n\n /**\n * Initializes the database table with the required schema.\n * Creates the table if it doesn't exist with primary key and value columns.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n if (this.tabularMigrations && this.tabularMigrations.length > 0) {\n // Probe BEFORE creating so we can tell the orchestrator whether the\n // table existed beforehand. We always create the table at the target\n // schema (idempotent via CREATE TABLE IF NOT EXISTS); the `freshTable`\n // flag lets the orchestrator take the mark-all-applied fast path on a\n // brand-new DB instead of running migration ops against a schema that\n // already matches them.\n const exists = await this.tableExistsAsync();\n await this.createTableAndIndexes();\n await this.applyTabularMigrations({ freshTable: !exists });\n // For pre-existing DBs that ran migrations, re-assert declared indexes\n // (idempotent). On fresh DBs we already did this in createTableAndIndexes.\n if (exists) {\n await this.createDeclaredIndexes();\n }\n return;\n }\n await this.createTableAndIndexes();\n }\n\n private async tableExistsAsync(): Promise<boolean> {\n const r = await this.db.query<{ x: number }, [string]>(\n `SELECT 1 AS x FROM information_schema.tables WHERE table_name = $1 LIMIT 1`,\n [this.table]\n );\n return r.rows.length > 0;\n }\n\n /**\n * Original setupDatabase behavior, extracted so the migrations branch\n * can call it conditionally on a fresh DB.\n */\n private async createTableAndIndexes(): Promise<void> {\n const sql = `\n CREATE TABLE IF NOT EXISTS \"${this.table}\" (\n ${this.constructPrimaryKeyColumns('\"')} ${this.constructValueColumns('\"')},\n PRIMARY KEY (${this.primaryKeyColumnList()})\n )\n `;\n await this.db.query(sql);\n await this.createVectorIndexes();\n await this.createDeclaredIndexes();\n }\n\n /**\n * Index-creation loop extracted so the migration path can re-run it after\n * migrations to ensure idempotence.\n */\n private async createDeclaredIndexes(): Promise<void> {\n const pkColumns = this.primaryKeyColumns();\n const createdIndexes = new Set<string>();\n for (const columns of this.indexes) {\n if (columns.length <= pkColumns.length) {\n // @ts-ignore\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n const indexName = `${this.table}_${columns.join(\"_\")}`;\n const columnList = columns.map((col) => `\"${String(col)}\"`).join(\", \");\n const columnKey = columns.join(\",\");\n if (createdIndexes.has(columnKey)) continue;\n const isRedundant = Array.from(createdIndexes).some((existing) => {\n const existingCols = existing.split(\",\");\n return (\n existingCols.length >= columns.length &&\n columns.every((col, idx) => col === existingCols[idx])\n );\n });\n if (!isRedundant) {\n await this.db.query(\n `CREATE INDEX IF NOT EXISTS \"${indexName}\" ON \"${this.table}\" (${columnList})`\n );\n createdIndexes.add(columnKey);\n }\n }\n }\n\n /**\n * Runs DDL inside the current transaction. Public so the `withTransaction`\n * proxy can route the call to the tx-bound client by overriding `this.db`.\n * Do not call directly; only via the applier's `executeSqlTx`.\n */\n public async runMigrationDdl(sql: string): Promise<void> {\n await this.db.query(sql);\n }\n\n /**\n * Inserts a `(component, version)` row into the bookkeeping table on the\n * current transaction's client. Public for the same reason as\n * {@link runMigrationDdl}.\n */\n public async recordMigrationApplied(\n component: string,\n version: number,\n description: string | null\n ): Promise<void> {\n await this.db.query(\n `INSERT INTO ${MIGRATIONS_TABLE}(component, version, description) VALUES ($1, $2, $3)`,\n [component, version, description]\n );\n }\n\n public override getMigrationApplier(): ITabularMigrationApplier | null {\n return new PostgresTabularMigrationApplierImpl(this);\n }\n\n protected isVectorFormat(format?: string): boolean {\n if (!format) return false;\n return format.startsWith(\"TypedArray:\") || format === \"TypedArray\";\n }\n\n protected getVectorDimensions(typeDef: JsonSchema): number | undefined {\n return undefined;\n }\n\n /**\n * Maps TypeScript/JavaScript types to corresponding PostgreSQL data types.\n * Uses additional schema information like minimum/maximum values, nullable status,\n * and string lengths to create more optimized column types.\n *\n * @param typeDef - The TypeScript/JavaScript type to map\n * @returns The corresponding PostgreSQL data type\n */\n protected mapTypeToSQL(typeDef: JsonSchema): string {\n // Extract the actual non-null type using base helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return \"TEXT /* boolean schema */\";\n }\n\n // Handle BLOB type\n if (actualType.contentEncoding === \"blob\") return \"BYTEA\";\n\n switch (actualType.type) {\n case \"string\":\n // Handle special string formats\n if (actualType.format === \"date-time\") return \"TIMESTAMP\";\n if (actualType.format === \"date\") return \"DATE\";\n if (actualType.format === \"email\") return \"VARCHAR(255)\";\n if (actualType.format === \"uri\") return \"VARCHAR(2048)\";\n if (actualType.format === \"uuid\") return \"UUID\";\n\n // Handle vector format (pgvector extension)\n if (this.isVectorFormat(actualType.format)) {\n const dimension = this.getVectorDimensions(actualType);\n if (typeof dimension === \"number\") {\n return `vector(${dimension})`;\n }\n }\n\n // Use a VARCHAR with maxLength if specified\n if (typeof actualType.maxLength === \"number\") {\n return `VARCHAR(${actualType.maxLength})`;\n }\n\n // Default to TEXT for strings without constraints\n return \"TEXT\";\n\n case \"number\":\n case \"integer\":\n // Handle integer vs floating point\n if (actualType.multipleOf === 1 || actualType.type === \"integer\") {\n // Use PostgreSQL's numeric range types based on min/max values\n if (typeof actualType.minimum === \"number\") {\n if (actualType.minimum >= 0) {\n // For unsigned integers\n if (typeof actualType.maximum === \"number\") {\n if (actualType.maximum <= 32767) return \"SMALLINT\";\n if (actualType.maximum <= 2147483647) return \"INTEGER\";\n }\n return \"BIGINT\";\n }\n }\n\n // Default integer type\n return \"INTEGER\";\n }\n\n // For floating point numbers with precision requirements\n if (actualType.format === \"float\") return \"REAL\";\n if (actualType.format === \"double\") return \"DOUBLE PRECISION\";\n\n // Use NUMERIC with precision/scale if specified\n if (typeof actualType.multipleOf === \"number\") {\n const decimalPlaces = String(actualType.multipleOf).split(\".\")[1]?.length || 0;\n if (decimalPlaces > 0) {\n return `NUMERIC(38, ${decimalPlaces})`;\n }\n }\n\n return \"NUMERIC\";\n\n case \"boolean\":\n return \"BOOLEAN\";\n\n case \"array\":\n // Handle array types (if items type is specified)\n if (\n actualType.items &&\n typeof actualType.items === \"object\" &&\n !Array.isArray(actualType.items)\n ) {\n const itemType = this.mapTypeToSQL(actualType.items as JsonSchema);\n\n // Only use native PostgreSQL arrays for simple scalar types\n // List of types that work well as native PostgreSQL arrays\n const supportedArrayElementTypes = [\n \"TEXT\",\n \"VARCHAR\",\n \"CHAR\",\n \"INTEGER\",\n \"SMALLINT\",\n \"BIGINT\",\n \"REAL\",\n \"DOUBLE PRECISION\",\n \"NUMERIC\",\n \"BOOLEAN\",\n \"UUID\",\n \"DATE\",\n \"TIMESTAMP\",\n ];\n\n // Check if the item type is in our supported list (either exact match or starts with for VARCHAR types)\n const isSupported = supportedArrayElementTypes.some(\n (type) => itemType === type || (itemType.startsWith(type + \"(\") && type !== \"VARCHAR\") // Handle things like VARCHAR(255)\n );\n\n if (isSupported) {\n return `${itemType}[]`;\n } else {\n return \"JSONB /* complex array */\";\n }\n }\n return \"JSONB /* generic array */\";\n\n case \"object\":\n return \"JSONB /* object */\";\n\n default:\n return \"TEXT /* unknown type */\";\n }\n }\n\n /**\n * Generates the SQL column definitions for primary key fields with constraints\n * Handles auto-generated keys using SERIAL for integers and UUID DEFAULT for strings\n * @returns SQL string containing primary key column definitions\n */\n protected override constructPrimaryKeyColumns($delimiter: string = \"\"): string {\n const cols = Object.entries<JsonSchema>(this.primaryKeySchema.properties)\n .map(([key, typeDef]) => {\n // Check if this is an auto-generated key\n if (this.isAutoGeneratedKey(key)) {\n if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // Use SERIAL or BIGSERIAL for auto-increment\n const sqlType = this.mapTypeToSQL(typeDef);\n const isSmallInt = sqlType.includes(\"SMALLINT\");\n const isBigInt = sqlType.includes(\"BIGINT\");\n const serialType = isBigInt ? \"BIGSERIAL\" : isSmallInt ? \"SMALLSERIAL\" : \"SERIAL\";\n return `${$delimiter}${key}${$delimiter} ${serialType}`;\n } else if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // Use UUID with DEFAULT gen_random_uuid()\n return `${$delimiter}${key}${$delimiter} UUID DEFAULT gen_random_uuid()`;\n }\n }\n\n const sqlType = this.mapTypeToSQL(typeDef);\n let constraints = \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${$delimiter}${key}${$delimiter} >= 0)`;\n }\n\n return `${$delimiter}${key}${$delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n return cols;\n }\n\n /**\n * Generates the SQL column definitions for value fields with constraints\n * @returns SQL string containing value column definitions\n */\n protected override constructValueColumns($delimiter: string = \"\"): string {\n const requiredSet = new Set(this.valueSchema.required ?? []);\n const cols = Object.entries<JsonSchema>(this.valueSchema.properties)\n .map(([key, typeDef]) => {\n const sqlType = this.mapTypeToSQL(typeDef);\n const isRequired = requiredSet.has(key);\n const nullable = !isRequired || this.isNullable(typeDef);\n let constraints = nullable ? \"NULL\" : \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${$delimiter}${key}${$delimiter} >= 0)`;\n }\n\n return `${$delimiter}${key}${$delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n if (cols.length > 0) {\n return `, ${cols}`;\n } else {\n return \"\";\n }\n }\n\n /**\n * Convert JavaScript values to PostgreSQL values, including TypedArray to vector string\n */\n protected override jsToSqlValue(column: string, value: Entity[keyof Entity]): ValueOptionType {\n const typeDef = this.schema.properties[column];\n if (typeDef) {\n const actualType = this.getNonNullType(typeDef);\n\n // Handle vector format - convert TypedArray to pgvector string format [1.0, 2.0, ...]\n if (typeof actualType !== \"boolean\" && this.isVectorFormat(actualType.format)) {\n if (value && ArrayBuffer.isView(value) && !(value instanceof DataView)) {\n // It's a TypedArray\n const array = Array.from(value as unknown as TypedArray);\n return `[${array.join(\",\")}]`;\n }\n // If it's already a string (serialized), return as-is\n if (typeof value === \"string\") {\n return value;\n }\n }\n }\n return super.jsToSqlValue(column, value);\n }\n\n /**\n * Convert PostgreSQL values to JS values. Ensures numeric strings become numbers where schema says number.\n */\n protected override sqlToJsValue(column: string, value: ValueOptionType): Entity[keyof Entity] {\n const typeDef = this.schema.properties[column as keyof typeof this.schema.properties] as\n | JsonSchema\n | undefined;\n if (typeDef) {\n if (value === null && this.isNullable(typeDef)) {\n return null as Entity[keyof Entity];\n }\n const actualType = this.getNonNullType(typeDef);\n\n // Handle vector format - convert pgvector string to TypedArray\n if (typeof actualType !== \"boolean\" && this.isVectorFormat(actualType.format)) {\n if (typeof value === \"string\") {\n try {\n // Parse the vector string format [1.0, 2.0, ...] to TypedArray\n const array = JSON.parse(value);\n return new Float32Array(array) as Entity[keyof Entity];\n } catch (e) {\n console.warn(`Failed to parse vector for column ${column}:`, e);\n }\n }\n // If it's already an object/TypedArray, return as-is\n if (value && typeof value === \"object\") {\n return value as Entity[keyof Entity];\n }\n }\n\n // Handle numeric types - PostgreSQL can return them as strings\n if (\n typeof actualType !== \"boolean\" &&\n (actualType.type === \"number\" || actualType.type === \"integer\")\n ) {\n if (typeof value === \"number\") return value as Entity[keyof Entity];\n if (typeof value === \"string\") {\n const parsed = Number(value);\n if (!isNaN(parsed)) return parsed as Entity[keyof Entity];\n }\n }\n }\n return super.sqlToJsValue(column, value);\n }\n\n /**\n * Determines if a field should be treated as unsigned based on schema properties\n * @param typeDef - The schema type definition\n * @returns true if the field should be treated as unsigned\n */\n protected shouldBeUnsigned(typeDef: JsonSchema): boolean {\n // Extract the non-null type using the base class helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return false;\n }\n\n // Check if it's a number type with minimum >= 0\n if (\n (actualType.type === \"number\" || actualType.type === \"integer\") &&\n typeof actualType.minimum === \"number\" &&\n actualType.minimum >= 0\n ) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Gets information about vector columns in the schema\n * @returns Array of objects with column name and dimension\n */\n protected getVectorColumns(): Array<{ column: string; dimension: number }> {\n const vectorColumns: Array<{ column: string; dimension: number }> = [];\n\n // Check all properties in the schema\n for (const [key, typeDef] of Object.entries<JsonSchema>(this.schema.properties)) {\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType !== \"boolean\" && this.isVectorFormat(actualType.format)) {\n const dimension = this.getVectorDimensions(actualType);\n if (typeof dimension === \"number\") {\n vectorColumns.push({ column: key, dimension });\n } else {\n console.warn(`Invalid vector format for column ${key}: ${actualType.format}, skipping`);\n }\n }\n }\n\n return vectorColumns;\n }\n\n /**\n * Subclasses (e.g. {@link PostgresVectorStorage}) override this to tune the\n * index built by {@link createVectorIndexes}. Returning `{}` (the default)\n * requests HNSW with cosine distance and pgvector's built-in `m` /\n * `efConstruction` defaults.\n */\n protected getVectorIndexOptions(): VectorIndexOptions {\n return {};\n }\n\n /**\n * Creates vector-specific indexes for pgvector.\n *\n * Called after table creation if vector columns exist. Honours the options\n * returned by {@link getVectorIndexOptions} — HNSW (default, with optional\n * `m` / `efConstruction` build-time tuning) or IVFFlat (when `lists` is\n * provided). See {@link VectorIndexOptions} for recall/latency trade-offs.\n */\n protected async createVectorIndexes(): Promise<void> {\n const vectorColumns = this.getVectorColumns();\n\n if (vectorColumns.length === 0) {\n return; // No vector columns, nothing to do\n }\n\n const opts = this.getVectorIndexOptions();\n // Validate the option shape up front so a misconfiguration fails before\n // we touch the database (rather than producing surprising SQL errors).\n if (opts.hnsw && opts.ivfflat) {\n throw new Error(\n \"VectorIndexOptions: only one of `hnsw` or `ivfflat` may be set; received both.\"\n );\n }\n assertPositiveInt(opts.hnsw?.m, \"hnsw.m\");\n assertPositiveInt(opts.hnsw?.efConstruction, \"hnsw.efConstruction\");\n assertPositiveInt(opts.hnsw?.efSearch, \"hnsw.efSearch\");\n assertPositiveInt(opts.ivfflat?.lists, \"ivfflat.lists\");\n assertPositiveInt(opts.ivfflat?.probes, \"ivfflat.probes\");\n\n // Try to enable pgvector extension\n try {\n await this.db.query(\"CREATE EXTENSION IF NOT EXISTS vector\");\n } catch (error) {\n console.warn(\n \"pgvector extension not available, vector columns will use TEXT fallback:\",\n error\n );\n return;\n }\n\n const distance = opts.distance ?? \"cosine\";\n const opClass =\n distance === \"l2\"\n ? \"vector_l2_ops\"\n : distance === \"ip\"\n ? \"vector_ip_ops\"\n : \"vector_cosine_ops\";\n\n const tableId = PostgresDialect.quoteId(this.table);\n\n if (opts.ivfflat) {\n // IVFFlat path — explicit `lists` is required.\n const { lists } = opts.ivfflat;\n for (const { column } of vectorColumns) {\n const indexId = PostgresDialect.quoteId(`${this.table}_${column}_ivfflat_idx`);\n const columnId = PostgresDialect.quoteId(column);\n try {\n await this.db.query(`\n CREATE INDEX IF NOT EXISTS ${indexId}\n ON ${tableId}\n USING ivfflat (${columnId} ${opClass})\n WITH (lists = ${lists})\n `);\n } catch (error) {\n console.warn(`Failed to create IVFFlat index on ${column}:`, error);\n }\n }\n return;\n }\n\n // Default: HNSW. `m` and `efConstruction` are build-time; `efSearch` is\n // applied per-session at query time (see PostgresVectorStorage).\n const hnsw = opts.hnsw ?? {};\n const buildParams: string[] = [];\n if (typeof hnsw.m === \"number\") buildParams.push(`m = ${hnsw.m}`);\n if (typeof hnsw.efConstruction === \"number\") {\n buildParams.push(`ef_construction = ${hnsw.efConstruction}`);\n }\n const withClause = buildParams.length > 0 ? ` WITH (${buildParams.join(\", \")})` : \"\";\n\n for (const { column } of vectorColumns) {\n const indexId = PostgresDialect.quoteId(`${this.table}_${column}_hnsw_idx`);\n const columnId = PostgresDialect.quoteId(column);\n try {\n await this.db.query(`\n CREATE INDEX IF NOT EXISTS ${indexId}\n ON ${tableId}\n USING hnsw (${columnId} ${opClass})${withClause}\n `);\n } catch (error) {\n console.warn(`Failed to create HNSW index on ${column}:`, error);\n }\n }\n }\n\n /**\n * Builds the parameterized `INSERT … ON CONFLICT … RETURNING *` SQL for a\n * single entity, applying the auto-generated-key policy. Extracted so\n * {@link put} and {@link putBulk} can share the column/parameter logic\n * while routing the actual query through different connections (the pool\n * vs. a transaction-bound client).\n */\n private buildPutSql(entity: InsertType): { sql: string; params: ValueOptionType[] } {\n // Determine which columns to include in INSERT\n const columnsToInsert: string[] = [];\n const paramsToInsert: ValueOptionType[] = [];\n\n // Handle primary key columns\n const pkColumns = this.primaryKeyColumns();\n const entityRecord = entity as Record<string, unknown>;\n for (const col of pkColumns) {\n const colStr = String(col);\n\n // Check if this is an auto-generated key\n if (this.isAutoGeneratedKey(colStr)) {\n const clientProvidedValue = entityRecord[colStr];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldUseClientValue = false;\n if (this.clientProvidedKeys === \"never\") {\n // Never use client value, let database generate\n shouldUseClientValue = false;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${colStr}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldUseClientValue = true;\n } else {\n // \"if-missing\" - use client value if provided\n shouldUseClientValue = hasClientValue;\n }\n\n if (shouldUseClientValue) {\n columnsToInsert.push(colStr);\n paramsToInsert.push(\n this.jsToSqlValue(colStr, clientProvidedValue as Entity[keyof Entity])\n );\n }\n // Otherwise skip it - let database generate via SERIAL or DEFAULT\n continue;\n }\n\n // Regular primary key column\n columnsToInsert.push(colStr);\n const value = entityRecord[colStr];\n paramsToInsert.push(this.jsToSqlValue(colStr, value as Entity[keyof Entity]));\n }\n\n // Handle value columns\n const valueColumns = this.valueColumns();\n for (const col of valueColumns) {\n const colStr = String(col);\n columnsToInsert.push(colStr);\n const value = entityRecord[colStr];\n paramsToInsert.push(this.jsToSqlValue(colStr, value as Entity[keyof Entity]));\n }\n\n const columnList = columnsToInsert.map((c) => `\"${c}\"`).join(\", \");\n const placeholders = columnsToInsert.map((_, i) => `$${i + 1}`).join(\", \");\n\n // Build ON CONFLICT clause if there are value columns\n const conflictClause =\n valueColumns.length > 0\n ? `\n ON CONFLICT (${this.primaryKeyColumnList('\"')}) DO UPDATE\n SET\n ${(valueColumns as string[])\n .map((col) => {\n const colIdx = columnsToInsert.indexOf(String(col));\n return `\"${col}\" = $${colIdx + 1}`;\n })\n .join(\", \")}\n `\n : \"\";\n\n const sql = `\n INSERT INTO \"${this.table}\" (${columnList})\n VALUES (${placeholders})\n ${conflictClause}\n RETURNING *\n `;\n\n return { sql, params: paramsToInsert };\n }\n\n /** Hydrate a row returned by Postgres back into entity-shaped JS values. */\n private hydrateRow(row: unknown): Entity {\n const entity = row as Entity;\n const record = entity as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n return entity;\n }\n\n /**\n * Acquires a client that BEGIN/COMMIT-style transactions can safely run on.\n *\n * - Real `pg.Pool` exposes `connect()`, which dedicates a client for the\n * transaction duration.\n * - PGlite-style single-connection wrappers (PGLitePool, raw PGlite)\n * serialize every `query()` through one underlying session, so issuing\n * the BEGIN/COMMIT pair directly on `this.db.query` is equivalent.\n * - Anything else — a custom no-`connect()` adapter that fans queries\n * across sessions — would dispatch the BEGIN and the bracketed queries\n * to different sessions, silently breaking atomicity. We refuse to\n * operate on it rather than provide a false guarantee.\n *\n * Whitelist mirrors {@link\n * PostgresRateLimiterStorage.tryReserveExecution}: the rate limiter has\n * the same atomicity requirement, and divergence here would let a pool\n * type be safe in one place and unsafe in another.\n *\n * Caller MUST invoke `release()` on the returned client. The no-op release\n * for single-connection wrappers is safe.\n */\n private async acquireConnection(): Promise<{\n query: Pool[\"query\"];\n release: () => void;\n }> {\n const supportsConnect =\n typeof (this.db as unknown as { connect?: unknown }).connect === \"function\";\n if (supportsConnect) {\n return await (\n this.db as unknown as {\n connect: () => Promise<{ query: Pool[\"query\"]; release: () => void }>;\n }\n ).connect();\n }\n\n // Without connect() we route BEGIN/COMMIT through this.db.query directly.\n // That is only safe if every query funnels through one underlying session.\n // Recognize:\n // - PGLitePool — our own wrapper class; constructor name preserved.\n // - PGlite — third-party, ships minified so `constructor.name` can\n // be obfuscated (observed: \"q\"). Detect via duck-typing on methods\n // PGlite uniquely exposes (`waitReady` Promise + `exec`).\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 `PostgresTabularStorage.putBulk 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 BEGIN and the bracketed INSERTs to different sessions, breaking atomicity.`\n );\n }\n return {\n query: this.db.query.bind(this.db) as Pool[\"query\"],\n release: () => {},\n };\n }\n\n /**\n * Per-instance promise-chain mutex. Only meaningful on single-connection\n * backends (PGlite / PGLitePool) — there `withTransaction` runs on the\n * shared session and we need to keep external callers from slipping into\n * the open transaction. On a real `pg.Pool` (anything exposing\n * `connect()`) the mutex would serialize independent reads/writes that\n * Postgres is happy to fan across separate pool clients, turning the\n * pool's main benefit into a per-instance bottleneck — so we short-circuit\n * to a no-op on that path. Real-pool isolation comes from\n * `withTransaction` dedicating its own client via `pool.connect()`.\n *\n * The Proxy returned by {@link createTxView} routes back to the private\n * `_*Internal` methods directly, so calls made *through* the `tx` handle\n * inside `fn` do not deadlock against the mutex held by `withTransaction`.\n */\n private mutexChain: Promise<void> = Promise.resolve();\n private get serializeOps(): boolean {\n return typeof (this.db as unknown as { connect?: unknown }).connect !== \"function\";\n }\n private async mutex<T>(fn: () => Promise<T>): Promise<T> {\n if (!this.serializeOps) return fn();\n const prev = this.mutexChain;\n let release!: () => void;\n this.mutexChain = new Promise<void>((resolve) => {\n release = resolve;\n });\n await prev;\n try {\n return await fn();\n } finally {\n release();\n }\n }\n\n /**\n * True while the parent instance is between `BEGIN` and `COMMIT`/`ROLLBACK`.\n * Used only to fail fast when `fn` captures the *original* storage instead\n * of the `tx` handle and tries to recursively call `withTransaction` —\n * that would deadlock against its own mutex on the PGlite path. Calls\n * routed through `tx` hit the proxy's `withTransaction` override before\n * reaching here.\n */\n private inTransaction: boolean = false;\n\n /**\n * Emits a `put` event. Overridden on the {@link createTxView} proxy to\n * push into a per-transaction buffer instead, so listeners never observe\n * rows that are about to roll back.\n */\n protected emitPut(entity: Entity): void {\n this.events.emit(\"put\", entity);\n }\n\n /**\n * Stores or updates a row in the database.\n * Uses UPSERT (INSERT ... ON CONFLICT DO UPDATE) for atomic operations.\n *\n * @param entity - The entity to store (may be missing auto-generated keys)\n * @returns The entity with any server-generated fields updated\n * @emits \"put\" event with the updated entity when successful (deferred until\n * commit if inside a {@link withTransaction})\n */\n async put(entity: InsertType): Promise<Entity> {\n return this.mutex(() => this._putInternal(entity));\n }\n\n private async _putInternal(entity: InsertType): Promise<Entity> {\n const { sql, params } = this.buildPutSql(entity);\n const result = await this.db.query(sql, params);\n const updatedEntity = this.hydrateRow(result.rows[0]);\n this.emitPut(updatedEntity);\n return updatedEntity;\n }\n\n /**\n * Stores multiple rows atomically inside a single `BEGIN` / `COMMIT`. All\n * inserts share one connection, which (a) reduces pool churn vs. a\n * `Promise.all` fan-out, (b) gives all-or-nothing semantics, and (c) lets\n * Postgres group the writes into a single commit with one fsync rather than\n * one per row.\n *\n * Per-row UPSERT — instead of a multi-VALUES insert — keeps the\n * auto-generated key policy and `RETURNING *` shape identical to {@link put}\n * and stays correct when a batch mixes rows that include the auto-gen key\n * with rows that omit it.\n *\n * `put` events are deferred until after `COMMIT` so listeners do not see\n * rows that are about to roll back. When this call is nested inside a\n * {@link withTransaction}, deferral extends to that outer commit.\n */\n async putBulk(entities: InsertType[]): Promise<Entity[]> {\n return this.mutex(() => this._putBulkInternal(entities));\n }\n\n private async _putBulkInternal(entities: InsertType[]): Promise<Entity[]> {\n if (entities.length === 0) return [];\n\n // Already inside an outer transaction (called via the `tx` view inside\n // `withTransaction`)? Skip our own BEGIN/COMMIT — Postgres `BEGIN`\n // inside an active transaction is a warning + no-op, and the inner\n // `COMMIT` would commit the OUTER transaction prematurely. Run the\n // inserts directly on `this.db`, which the proxy has already swapped to\n // the transaction-bound client (real pool) or the shared session\n // (PGlite).\n if (this.inTransaction) {\n const updated: Entity[] = [];\n for (const entity of entities) {\n const { sql, params } = this.buildPutSql(entity);\n const result = await this.db.query(sql, params);\n updated.push(this.hydrateRow(result.rows[0]));\n }\n for (const entity of updated) this.emitPut(entity);\n return updated;\n }\n\n const conn = await this.acquireConnection();\n const updatedEntities: Entity[] = [];\n try {\n await conn.query(\"BEGIN\");\n try {\n for (const entity of entities) {\n const { sql, params } = this.buildPutSql(entity);\n const result = await conn.query(sql, params);\n updatedEntities.push(this.hydrateRow(result.rows[0]));\n }\n await conn.query(\"COMMIT\");\n } catch (err) {\n try {\n await conn.query(\"ROLLBACK\");\n } catch {\n // prefer the original error if rollback fails\n }\n throw err;\n }\n } finally {\n conn.release();\n }\n\n for (const entity of updatedEntities) this.emitPut(entity);\n return updatedEntities;\n }\n\n /**\n * Build a Proxy view of `this` for the `withTransaction` callback. The\n * proxy:\n *\n * - Swaps `db` for the transaction-bound handle so every query inside\n * `fn` runs on it: the dedicated client returned by `pool.connect()`\n * for a real `pg.Pool`, or the shared session for PGlite/PGLitePool.\n * - Routes any public method `foo` whose private sibling `_fooInternal`\n * exists to that sibling, so calls made through `tx` bypass the\n * mutex (PGlite path) and do not deadlock. The naming convention is\n * the only sync mechanism — adding a public method with a matching\n * `_fooInternal` is enough; no explicit map to keep in step.\n * - Reports `inTransaction === true`, which is what\n * {@link _putBulkInternal} keys off to skip its own BEGIN/COMMIT\n * and run on the swapped `db` directly.\n * - Overrides {@link emitPut} to queue events on a per-transaction\n * buffer; the outer `withTransaction` flushes that buffer after\n * `COMMIT` (or discards on `ROLLBACK`).\n * - Throws on nested `withTransaction` — Postgres has no autonomous\n * `BEGIN`. Use SAVEPOINT directly for nested rollback boundaries.\n */\n private createTxView(txDb: { query: Pool[\"query\"] }, deferredPutEvents: Entity[]): this {\n const target = this;\n return new Proxy(target, {\n get(t, prop, receiver) {\n if (prop === \"withTransaction\") {\n return () => {\n throw new Error(\n \"PostgresTabularStorage.withTransaction does not support nesting. \" +\n \"Use SAVEPOINT directly or refactor to a single transaction.\"\n );\n };\n }\n if (prop === \"db\") return txDb;\n if (prop === \"inTransaction\") return true;\n if (prop === \"emitPut\") {\n return (entity: Entity) => deferredPutEvents.push(entity);\n }\n if (typeof prop === \"string\") {\n const internal = (t as unknown as Record<string, unknown>)[`_${prop}Internal`];\n if (typeof internal === \"function\") {\n return (...args: unknown[]) =>\n (internal as (...a: unknown[]) => unknown).apply(receiver, args);\n }\n }\n const value = Reflect.get(t, prop, receiver);\n return typeof value === \"function\" ? value.bind(receiver) : value;\n },\n }) as this;\n }\n\n /**\n * Runs `fn` inside a single Postgres transaction.\n *\n * **Real `pg.Pool`** — acquires a dedicated client via `pool.connect()`,\n * runs `BEGIN`/`COMMIT`/`ROLLBACK` on that client, and routes every\n * query inside `fn` through it. The parent storage instance keeps fanning\n * external traffic across the pool, so external callers run *in parallel*\n * with the open transaction (no per-instance mutex). This is the natural\n * Postgres concurrency model.\n *\n * **PGlite / PGLitePool** — single underlying session: the parent's mutex\n * is acquired for the duration of `fn` so external callers queue behind\n * the transaction instead of slipping into it. `BEGIN`/`COMMIT` run on\n * the shared `this.db`.\n *\n * `put` events emitted from inside `fn` (whether via `tx.put`,\n * `tx.putBulk`, or any other writer) are buffered on a per-transaction\n * queue and flushed to the parent's event emitter after `COMMIT`. If `fn`\n * throws, the buffer is discarded along with the rolled-back rows so\n * listeners never observe writes that did not actually commit.\n *\n * Recursive calls — either through the original instance or through `tx`\n * — throw rather than reusing the outer transaction implicitly. Use\n * SAVEPOINT directly for nested rollback boundaries.\n */\n override async withTransaction<T>(fn: (tx: this) => Promise<T>): Promise<T> {\n const supportsConnect =\n typeof (this.db as unknown as { connect?: unknown }).connect === \"function\";\n\n if (supportsConnect) {\n // Real pg.Pool: dedicate a client to this transaction; the parent's\n // pool stays available for external callers, who run in parallel on\n // other clients. We deliberately do NOT set `this.inTransaction` here\n // — it would make external `_putBulkInternal` calls short-circuit\n // their own BEGIN/COMMIT even though they are not actually nested.\n // Nested calls via a captured original `this` simply acquire another\n // pool client and run as an independent transaction; Postgres handles\n // the concurrency, so no nesting guard is required on this path.\n const client = await (\n this.db as unknown as {\n connect: () => Promise<{ query: Pool[\"query\"]; release: () => void }>;\n }\n ).connect();\n try {\n return await this.runInTransaction(fn, { query: client.query.bind(client) });\n } finally {\n client.release();\n }\n }\n\n // PGlite/PGLitePool: single underlying session. Serialize against\n // external callers via the mutex, and set `inTransaction` so that a\n // nested `withTransaction` invoked via the original (rather than `tx`)\n // throws instead of deadlocking on its own mutex.\n if (this.inTransaction) {\n throw new Error(\n \"PostgresTabularStorage.withTransaction does not support nesting. \" +\n \"Use SAVEPOINT directly or refactor to a single transaction.\"\n );\n }\n return this.mutex(async () => {\n this.inTransaction = true;\n try {\n return await this.runInTransaction(fn, { query: this.db.query.bind(this.db) });\n } finally {\n this.inTransaction = false;\n }\n });\n }\n\n private async runInTransaction<T>(\n fn: (tx: this) => Promise<T>,\n txDb: { query: Pool[\"query\"] }\n ): Promise<T> {\n const deferredPutEvents: Entity[] = [];\n await txDb.query(\"BEGIN\");\n let result: T;\n try {\n result = await fn(this.createTxView(txDb, deferredPutEvents));\n await txDb.query(\"COMMIT\");\n } catch (err) {\n try {\n await txDb.query(\"ROLLBACK\");\n } catch {\n // prefer the original error if rollback fails\n }\n throw err;\n }\n // Flush deferred events only on commit success.\n for (const entity of deferredPutEvents) this.events.emit(\"put\", entity);\n return result;\n }\n\n /**\n * Retrieves a value from the database by its primary key.\n *\n * @param key - The primary key object to look up\n * @returns The stored value or undefined if not found\n * @emits \"get\" event with the key when successful\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n return this.mutex(() => this._getInternal(key));\n }\n\n private async _getInternal(key: PrimaryKey): Promise<Entity | undefined> {\n const db = this.db;\n const whereClauses = (this.primaryKeyColumns() as string[])\n .map((discriminatorKey, i) => `\"${discriminatorKey}\" = $${i + 1}`)\n .join(\" AND \");\n\n const sql = `SELECT * FROM \"${this.table}\" WHERE ${whereClauses}`;\n const params = this.getPrimaryKeyAsOrderedArray(key);\n const result = await db.query(sql, params);\n\n let val: Entity | undefined;\n if (result.rows.length > 0) {\n val = result.rows[0] as Entity;\n // Convert all columns according to schema\n const valRecord = val as Record<string, unknown>;\n for (const key in this.schema.properties) {\n valRecord[key] = this.sqlToJsValue(key, valRecord[key] as ValueOptionType);\n }\n } else {\n val = undefined;\n }\n this.events.emit(\"get\", key, val);\n return val;\n }\n\n /**\n * Fetch multiple rows by primary key in a single statement. Single-column\n * keys emit `WHERE pk IN ($1,$2,...)`. Compound keys emit\n * `WHERE (pk1,pk2,...) IN (($1,$2,...),($3,$4,...),...)`. Values bind\n * through `jsToSqlValue` for parity with `query()` and `get()`.\n *\n * Postgres caps a single statement at 65535 bind parameters; inputs that\n * would exceed the cap are chunked so each round-trip stays well under\n * it. The same chunking shape is shared with the SQLite backend.\n */\n override async getBulk(keys: readonly PrimaryKey[]): Promise<Entity[]> {\n if (keys.length === 0) return [];\n const pkColCount = this.primaryKeyColumns().length;\n const chunkSize = Math.max(1, Math.floor(30000 / pkColCount));\n let rows: Entity[];\n if (keys.length <= chunkSize) {\n rows = await this.mutex(() => this._getBulkInternal(keys));\n } else {\n rows = [];\n for (let i = 0; i < keys.length; i += chunkSize) {\n const chunk = keys.slice(i, i + chunkSize);\n const chunkRows = await this.mutex(() => this._getBulkInternal(chunk));\n rows.push(...chunkRows);\n }\n }\n this.events.emit(\"getBulk\", keys, rows);\n return rows;\n }\n\n private async _getBulkInternal(keys: readonly PrimaryKey[]): Promise<Entity[]> {\n const db = this.db;\n const pkCols = this.primaryKeyColumns() as string[];\n\n const params: ValueOptionType[] = [];\n const tuples: string[] = [];\n let p = 1;\n for (const key of keys) {\n const ordered = this.getPrimaryKeyAsOrderedArray(key);\n params.push(...ordered);\n const slots: string[] = [];\n for (let i = 0; i < pkCols.length; i++) {\n slots.push(`$${p++}`);\n }\n tuples.push(`(${slots.join(\", \")})`);\n }\n\n const lhs =\n pkCols.length === 1\n ? `\"${pkCols[0]}\"`\n : `(${pkCols.map((c) => `\"${c}\"`).join(\", \")})`;\n\n // Single-column LHS uses a flat list of placeholders for idiomatic SQL.\n // Compound LHS uses row-value tuples.\n const rhs =\n pkCols.length === 1\n ? params.map((_, i) => `$${i + 1}`).join(\", \")\n : tuples.join(\", \");\n\n const sql = `SELECT * FROM \"${this.table}\" WHERE ${lhs} IN (${rhs})`;\n const result = await db.query(sql, params);\n\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n return result.rows as Entity[];\n }\n\n /**\n * Deletes a row from the database.\n *\n * @param key - The primary key object to delete\n * @emits \"delete\" event with the key when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n return this.mutex(() => this._deleteInternal(value));\n }\n\n private async _deleteInternal(value: PrimaryKey | Entity): Promise<void> {\n const db = this.db;\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n const whereClauses = (this.primaryKeyColumns() as string[])\n .map((key, i) => `${key} = $${i + 1}`)\n .join(\" AND \");\n\n const params = this.getPrimaryKeyAsOrderedArray(key);\n await db.query(`DELETE FROM \"${this.table}\" WHERE ${whereClauses}`, params);\n this.events.emit(\"delete\", key as keyof Entity);\n }\n\n /**\n * Retrieves all entries from the database table, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Promise resolving to an array of entries or undefined if not found\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n return this.mutex(() => this._getAllInternal(options));\n }\n\n private async _getAllInternal(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n const db = this.db;\n let sql = `SELECT * FROM \"${this.table}\"`;\n const params: ValueOptionType[] = [];\n\n if (options?.orderBy && options.orderBy.length > 0) {\n const orderClauses = options.orderBy.map((o) => `\"${String(o.column)}\" ${o.direction}`);\n sql += ` ORDER BY ${orderClauses.join(\", \")}`;\n }\n\n if (options?.limit !== undefined) {\n sql += ` LIMIT $${params.length + 1}`;\n params.push(options.limit);\n }\n\n if (options?.offset !== undefined) {\n sql += ` OFFSET $${params.length + 1}`;\n params.push(options.offset);\n }\n\n const result = params.length > 0 ? await db.query(sql, params) : await db.query(sql);\n\n if (result.rows.length > 0) {\n // Convert all columns according to schema\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n return result.rows;\n }\n return undefined;\n }\n\n /**\n * Deletes all rows from the database table.\n * @emits \"clearall\" event when successful\n */\n async deleteAll(): Promise<void> {\n return this.mutex(() => this._deleteAllInternal());\n }\n\n private async _deleteAllInternal(): Promise<void> {\n const db = this.db;\n await db.query(`DELETE FROM \"${this.table}\"`);\n this.events.emit(\"clearall\");\n }\n\n /**\n * Returns the total number of rows in the database.\n *\n * @returns Promise resolving to the count of stored items\n */\n async size(): Promise<number> {\n return this.mutex(() => this._sizeInternal());\n }\n\n private async _sizeInternal(): Promise<number> {\n const db = this.db;\n const result = await db.query(`SELECT COUNT(*) FROM \"${this.table}\"`);\n return parseInt(result.rows[0].count, 10);\n }\n\n /**\n * Counts rows matching the specified search criteria.\n */\n override async count(criteria?: SearchCriteria<Entity>): Promise<number> {\n return this.mutex(() => this._countInternal(criteria));\n }\n\n private async _countInternal(criteria?: SearchCriteria<Entity>): Promise<number> {\n if (!criteria || Object.keys(criteria).length === 0) {\n return await this._sizeInternal();\n }\n\n this.validateQueryParams(criteria);\n const db = this.db;\n const { whereClause, params } = this.buildDeleteSearchWhere(criteria);\n const result = await db.query<{ count: string }, ValueOptionType[]>(\n `SELECT COUNT(*) FROM \"${this.table}\" WHERE ${whereClause}`,\n params\n );\n return parseInt(result.rows[0].count, 10);\n }\n\n /**\n * Fetches a page of records from the repository.\n * @param offset - Number of records to skip\n * @param limit - Maximum number of records to return\n * @returns Array of entities or undefined if no records found\n */\n async getOffsetPage(offset: number, limit: number): Promise<Entity[] | undefined> {\n return this.mutex(() => this._getOffsetPageInternal(offset, limit));\n }\n\n private async _getOffsetPageInternal(offset: number, limit: number): Promise<Entity[] | undefined> {\n const db = this.db;\n const orderByClause = this.primaryKeyColumns()\n .map((col) => `\"${String(col)}\"`)\n .join(\", \");\n const result = await db.query(\n `SELECT * FROM \"${this.table}\" ORDER BY ${orderByClause} LIMIT $1 OFFSET $2`,\n [limit, offset]\n );\n\n if (!result.rows || result.rows.length === 0) {\n return undefined;\n }\n\n // Convert all columns according to schema (consistent with getAll)\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n\n return result.rows as Entity[];\n }\n\n /**\n * Builds WHERE clause conditions from delete search criteria.\n * @param criteria - The search criteria object\n * @returns Object with whereClause string and params array\n */\n protected buildDeleteSearchWhere(criteria: DeleteSearchCriteria<Entity>): {\n whereClause: string;\n params: ValueOptionType[];\n } {\n // Route through the shared `buildSearchWhere` helper for consistent\n // operator handling, then drop `nextIndex` since deleteSearch callers\n // don't need it. `buildSearchWhereWithIndex` keeps the cursor-pagination\n // contract that does need it.\n const built = buildSearchWhere<Entity>(\n PostgresDialect,\n criteria,\n this.schema.properties as Record<string, unknown>,\n (column, value) => this.jsToSqlValue(column, value)\n );\n return { whereClause: built.whereClause, params: built.params };\n }\n\n /**\n * Cursor-paginated read with keyset predicates pushed into SQL.\n *\n * Goes through {@link mutex} so on the single-connection PGlite path a\n * `getPage` issued while a `withTransaction` is in flight queues behind\n * the transaction's `BEGIN`/`COMMIT` instead of slipping in between them\n * on the shared session. On a real `pg.Pool`, {@link mutex} is a no-op —\n * page reads fan out to other pool clients in parallel as expected. The\n * Proxy returned by {@link createTxView} auto-routes to\n * {@link _getPageInternal} via the `_*Internal` naming convention, so\n * calls made through `tx` bypass the mutex (which the transaction holds)\n * and run on the transaction-bound `db`.\n */\n override async getPage(request: PageRequest<Entity> = {}): Promise<Page<Entity>> {\n return this.mutex(() => this._getPageInternal(request));\n }\n\n private async _getPageInternal(request: PageRequest<Entity>): Promise<Page<Entity>> {\n return this.runSqlPage(undefined, request, this.postgresDialect());\n }\n\n override async queryPage(\n criteria: SearchCriteria<Entity>,\n request: PageRequest<Entity> = {}\n ): Promise<Page<Entity>> {\n return this.mutex(() => this._queryPageInternal(criteria, request));\n }\n\n private async _queryPageInternal(\n criteria: SearchCriteria<Entity>,\n request: PageRequest<Entity>\n ): Promise<Page<Entity>> {\n this.validateQueryParams(criteria, undefined);\n return this.runSqlPage(criteria, request, this.postgresDialect());\n }\n\n private postgresDialect() {\n return {\n quote: '\"',\n placeholder: (index: number) => `$${index}`,\n buildSearchWhere: (criteria: SearchCriteria<Entity>, startIndex: number) =>\n this.buildSearchWhereWithIndex(criteria, startIndex),\n executeSelect: async (sql: string, params: ValueOptionType[]): Promise<Entity[]> => {\n const result = await this.db.query(sql, params as unknown[]);\n const rows = (result.rows ?? []) as Entity[];\n for (const row of rows) {\n const record = row as Record<string, unknown>;\n for (const k in this.schema.properties) {\n record[k] = this.sqlToJsValue(k, record[k] as ValueOptionType);\n }\n }\n return rows;\n },\n };\n }\n\n /**\n * Like {@link buildSearchWhere} but also reports the next free placeholder\n * index — the cursor-pagination machinery needs to chain its own predicates\n * after the criteria block, so it has to know what `$N` to start at.\n */\n private buildSearchWhereWithIndex(\n criteria: SearchCriteria<Entity>,\n startIndex: number\n ): { whereClause: string; params: ValueOptionType[]; nextIndex: number } {\n const built = buildSearchWhere<Entity>(\n PostgresDialect,\n criteria,\n this.schema.properties as Record<string, unknown>,\n (column, value) => this.jsToSqlValue(column, value),\n startIndex\n );\n return {\n whereClause: built.whereClause,\n params: built.params,\n nextIndex: startIndex + built.params.length,\n };\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Supports multiple columns with optional comparison operators.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n */\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n return this.mutex(() => this._deleteSearchInternal(criteria));\n }\n\n private async _deleteSearchInternal(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaKeys.length === 0) {\n return;\n }\n\n const db = this.db;\n const { whereClause, params } = this.buildDeleteSearchWhere(criteria);\n await db.query(`DELETE FROM \"${this.table}\" WHERE ${whereClause}`, params);\n this.events.emit(\"delete\", criteriaKeys[0] as keyof Entity);\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering, limit, and offset.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of matching entities or undefined if no matches found\n */\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n return this.mutex(() => this._queryInternal(criteria, options));\n }\n\n private async _queryInternal(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n this.validateQueryParams(criteria, options);\n const db = this.db;\n\n let sql = `SELECT * FROM \"${this.table}\"`;\n const { whereClause, params } = this.buildDeleteSearchWhere(criteria);\n sql += ` WHERE ${whereClause}`;\n\n if (options?.orderBy && options.orderBy.length > 0) {\n const orderClauses = options.orderBy.map((o) => `\"${String(o.column)}\" ${o.direction}`);\n sql += ` ORDER BY ${orderClauses.join(\", \")}`;\n }\n\n if (options?.limit !== undefined) {\n sql += ` LIMIT $${params.length + 1}`;\n params.push(options.limit);\n }\n\n if (options?.offset !== undefined) {\n sql += ` OFFSET $${params.length + 1}`;\n params.push(options.offset);\n }\n\n const result = await db.query(sql, params);\n\n if (result.rows.length > 0) {\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const k in this.schema.properties) {\n record[k] = this.sqlToJsValue(k, record[k] as ValueOptionType);\n }\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, result.rows as Entity[]);\n return result.rows as Entity[];\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n\n /**\n * Queries entries matching the specified search criteria, returning only the selected columns.\n * Requires a covering index that satisfies the criteria, orderBy, and select columns.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Required select columns plus optional orderBy, limit, and offset\n * @returns Array of partial entities containing only the selected columns\n * @throws {CoveringIndexMissingError} when no registered index covers the query\n */\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n return this.mutex(() => this._queryIndexInternal(criteria, options));\n }\n\n private async _queryIndexInternal<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n this.validateSelect(options);\n this.validateQueryParams(criteria, options);\n\n const registered = this.indexes.map((cols, i) => {\n const cs = Array.isArray(cols) ? (cols as string[]) : [cols as string];\n return { name: `idx_${i}`, keyPath: cs };\n });\n\n pickCoveringIndex({\n table: this.table,\n indexes: registered,\n criteriaColumns: Object.keys(criteria),\n orderByColumns: (options.orderBy ?? []).map((o) => ({\n column: String(o.column),\n direction: o.direction,\n })),\n selectColumns: options.select.map(String),\n primaryKeyColumns: this.primaryKeyNames.map(String),\n });\n\n const cols = options.select.map((c) => `\"${String(c)}\"`).join(\", \");\n let sql = `SELECT ${cols} FROM \"${this.table}\"`;\n const { whereClause, params } = this.buildDeleteSearchWhere(criteria);\n sql += ` WHERE ${whereClause}`;\n\n if (options.orderBy && options.orderBy.length > 0) {\n sql +=\n ` ORDER BY ` +\n options.orderBy.map((o) => `\"${String(o.column)}\" ${o.direction}`).join(\", \");\n }\n if (options.limit !== undefined) {\n sql += ` LIMIT $${params.length + 1}`;\n params.push(options.limit);\n }\n if (options.offset !== undefined) {\n sql += ` OFFSET $${params.length + 1}`;\n params.push(options.offset);\n }\n\n const db = this.db;\n const result = await db.query(sql, params);\n for (const row of result.rows) {\n const record = row as Record<string, unknown>;\n for (const k of Object.keys(record)) {\n record[k] = this.sqlToJsValue(k, record[k] as ValueOptionType);\n }\n }\n return result.rows as Pick<Entity, K>[];\n }\n\n /**\n * Subscribes to changes in the repository.\n * NOT IMPLEMENTED for PostgreSQL storage.\n *\n * @throws Error always - subscribeToChanges is not supported for PostgreSQL storage\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n throw new Error(\"subscribeToChanges is not supported for PostgresTabularStorage\");\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n public override destroy(): void {\n super.destroy();\n }\n}\n\nclass PostgresTabularMigrationApplierImpl extends SqlTabularMigrationApplier {\n constructor(private readonly host: PostgresTabularStorage<any, any, any, any, any, any>) {\n super();\n }\n protected override dialectName(): \"sqlite\" | \"postgres\" {\n return \"postgres\";\n }\n protected override table(): string {\n return (this.host as unknown as { table: string }).table;\n }\n protected override storage(): AnyTabularStorage {\n return this.host as unknown as AnyTabularStorage;\n }\n protected override mapTypeToSQL(typeDef: JsonSchema): string {\n return (this.host as unknown as { mapTypeToSQL: (t: JsonSchema) => string }).mapTypeToSQL(\n typeDef\n );\n }\n protected override isNullableSchema(typeDef: JsonSchema): boolean {\n return (this.host as unknown as { isNullable: (t: JsonSchema) => boolean }).isNullable(typeDef);\n }\n protected override async executeSql(sql: string): Promise<void> {\n await (this.host as unknown as { db: { query: (sql: string) => Promise<unknown> } }).db.query(\n sql\n );\n }\n protected override async executeSqlTx(sql: string, tx: AnyTabularStorage): Promise<void> {\n await (tx as unknown as { runMigrationDdl: (s: string) => Promise<void> }).runMigrationDdl(sql);\n }\n protected override async recordAppliedTx(\n component: string,\n version: number,\n description: string | undefined,\n tx: AnyTabularStorage\n ): Promise<void> {\n await (\n tx as unknown as {\n recordMigrationApplied: (c: string, v: number, d: string | null) => Promise<void>;\n }\n ).recordMigrationApplied(component, version, description ?? null);\n }\n protected override async recordApplied(\n component: string,\n version: number,\n description: string | undefined\n ): Promise<void> {\n await (\n this.host as unknown as {\n db: {\n query: (sql: string, params: unknown[]) => Promise<unknown>;\n };\n }\n ).db.query(\n `INSERT INTO ${MIGRATIONS_TABLE}(component, version, description) VALUES ($1, $2, $3)`,\n [component, version, description ?? null]\n );\n }\n protected override async queryAppliedVersions(component: string): Promise<Set<number>> {\n const r = await (\n this.host as unknown as {\n db: {\n query: (sql: string, params: unknown[]) => Promise<{ rows: Array<{ version: number }> }>;\n };\n }\n ).db.query(`SELECT version FROM ${MIGRATIONS_TABLE} WHERE component = $1`, [component]);\n return new Set(r.rows.map((row) => Number(row.version)));\n }\n protected override async probeTableExists(): Promise<boolean> {\n const r = await (\n this.host as unknown as {\n db: {\n query: (sql: string, params: unknown[]) => Promise<{ rows: unknown[] }>;\n };\n }\n ).db.query(`SELECT 1 FROM information_schema.tables WHERE table_name = $1 LIMIT 1`, [\n (this.host as unknown as { table: string }).table,\n ]);\n return r.rows.length > 0;\n }\n}\n",
8
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { Pool } from \"@workglow/postgres/storage\";\nimport type {\n DataPortSchemaObject,\n FromSchema,\n TypedArray,\n TypedArrayConstructor,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport { cosineSimilarity } from \"@workglow/util/schema\";\nimport { PostgresTabularStorage } from \"./PostgresTabularStorage\";\nimport {\n PostgresDialect,\n StorageValidationError,\n getMetadataProperty,\n getVectorProperty,\n} from \"@workglow/storage\";\nimport type {\n IVectorStorage,\n VectorDistanceMetric,\n VectorIndexOptions,\n VectorSearchOptions,\n} from \"@workglow/storage\";\n\n/**\n * PostgreSQL vector repository implementation using pgvector extension.\n * Extends PostgresTabularStorage for storage.\n * Provides efficient vector similarity search with native database support.\n *\n * Requirements:\n * - PostgreSQL database with pgvector extension installed\n * - CREATE EXTENSION vector;\n *\n * @template Metadata - The metadata type\n * @template VectorCtor - Constructor for stored vectors (default {@link typeof Float32Array})\n */\n/**\n * Regex for validating metadata filter keys to prevent SQL injection.\n * Only allows alphanumeric characters and underscores, starting with a letter or underscore.\n */\nconst SAFE_IDENTIFIER_RE = /^[a-zA-Z_][a-zA-Z0-9_]*$/;\n\nexport class PostgresVectorStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n Metadata extends Record<string, unknown> = Record<string, unknown>,\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n>\n extends PostgresTabularStorage<Schema, PrimaryKeyNames, Entity>\n implements IVectorStorage<Metadata, Schema, Entity, PrimaryKeyNames>\n{\n private vectorDimensions: number;\n private readonly vectorCtor: TypedArrayConstructor;\n private vectorPropertyName: keyof Entity;\n private metadataPropertyName: keyof Entity | undefined;\n private readonly indexOptions: VectorIndexOptions;\n\n /**\n * Creates a new PostgreSQL vector repository\n * @param db - PostgreSQL connection pool\n * @param table - The name of the table to use for storage\n * @param schema - The schema definition for the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable\n * @param dimensions - The number of dimensions of the vector\n * @param vectorCtor - TypedArray constructor used when hydrating vectors from SQL text (e.g. {@link Float32Array})\n * @param indexOptions - Tuning for the pgvector index (HNSW vs IVFFlat,\n * distance metric, m / efConstruction / lists / probes).\n * See {@link VectorIndexOptions} for the recall/latency\n * trade-offs. Defaults to HNSW with cosine distance and\n * pgvector's built-in `m=16`, `efConstruction=64` defaults.\n */\n constructor(\n db: Pool,\n table: string,\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n dimensions: number,\n vectorCtor: TypedArrayConstructor = Float32Array,\n indexOptions: VectorIndexOptions = {}\n ) {\n super(db, table, schema, primaryKeyNames, indexes);\n\n this.vectorDimensions = dimensions;\n this.vectorCtor = vectorCtor;\n this.indexOptions = indexOptions;\n\n // Cache vector and metadata property names from schema\n const vectorProp = getVectorProperty(schema);\n if (!vectorProp) {\n throw new Error(\"Schema must have a property with type array and format TypedArray\");\n }\n this.vectorPropertyName = vectorProp as keyof Entity;\n this.metadataPropertyName = getMetadataProperty(schema) as keyof Entity | undefined;\n }\n\n public override getVectorDimensions(): number {\n return this.vectorDimensions;\n }\n\n /** Exposes tuning to {@link PostgresTabularStorage.createVectorIndexes}. */\n protected override getVectorIndexOptions(): VectorIndexOptions {\n return this.indexOptions;\n }\n\n /** Resolved distance metric for this storage (defaults to cosine). */\n private get distance(): VectorDistanceMetric {\n return this.indexOptions.distance ?? \"cosine\";\n }\n\n /**\n * pgvector distance operators per metric:\n * - cosine: `<=>` → cosine distance ∈ [0, 2]\n * - l2 (euclidean): `<->` → L2 distance ∈ [0, ∞)\n * - ip (inner): `<#>` → negative inner product (pgvector negates so\n * smaller = \"more similar\", matching the other ops)\n */\n private get distanceOperator(): string {\n switch (this.distance) {\n case \"l2\":\n return \"<->\";\n case \"ip\":\n return \"<#>\";\n default:\n return \"<=>\";\n }\n }\n\n /**\n * SQL fragment that converts the raw distance from {@link distanceOperator}\n * into a \"higher = more similar\" score that the rest of the API exposes.\n *\n * - cosine: 1 - cosine_distance → similarity in [-1, 1]\n * - l2: 1 / (1 + l2_distance) → ∈ (0, 1], 1 is exact match\n * - ip: -(neg_inner_product) → the actual dot product\n */\n private buildScoreExpr(vectorExpr: string, queryParam: string): string {\n const op = this.distanceOperator;\n switch (this.distance) {\n case \"l2\":\n return `(1.0 / (1.0 + (${vectorExpr} ${op} ${queryParam}::vector)))`;\n case \"ip\":\n return `(-1.0 * (${vectorExpr} ${op} ${queryParam}::vector))`;\n default:\n return `(1 - (${vectorExpr} ${op} ${queryParam}::vector))`;\n }\n }\n\n /**\n * Returns the `efSearch` / `probes` values configured at construction time.\n *\n * NOTE: these are query-time GUCs and must be set on the active session.\n * With a {@link Pool}, a connection is checked out per `pool.query()`, so a\n * standalone `SET hnsw.ef_search = N` issued before a SELECT lands on a\n * different client and has no effect. To apply them, callers should run\n * search queries against a single checked-out client (using `pool.connect()`)\n * inside a transaction with `SET LOCAL`, or set them at the role/database\n * level via `ALTER ROLE ... SET hnsw.ef_search = N`.\n */\n public getQueryTuning(): { efSearch?: number; probes?: number } {\n return {\n efSearch: this.indexOptions.hnsw?.efSearch,\n probes: this.indexOptions.ivfflat?.probes,\n };\n }\n\n public async similaritySearch(\n query: TypedArray,\n options: VectorSearchOptions<Metadata> = {}\n ): Promise<Array<Entity & { score: number }>> {\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n\n try {\n // Try native pgvector search first\n const queryVector = `[${Array.from(query).join(\",\")}]`;\n // Use the raw column name for object-property lookup on result rows,\n // and a quoted form for splicing into SQL identifiers (handles reserved\n // words, mixed case, and any caller-supplied schema).\n const vectorColRaw = String(this.vectorPropertyName);\n const vectorCol = PostgresDialect.quoteId(vectorColRaw);\n const metadataColRaw = this.metadataPropertyName ? String(this.metadataPropertyName) : null;\n const metadataCol = metadataColRaw ? PostgresDialect.quoteId(metadataColRaw) : null;\n const distOp = this.distanceOperator;\n const scoreExpr = this.buildScoreExpr(vectorCol, \"$1\");\n\n let sql = `\n SELECT\n *,\n ${scoreExpr} as score\n FROM \"${this.table}\"\n `;\n\n const params: any[] = [queryVector];\n let paramIndex = 2;\n // Track whether we've actually emitted a WHERE — `filter` alone isn't\n // sufficient because it can be truthy yet contribute zero predicates\n // (empty object, or no metadata column to apply it against).\n let hasWhere = false;\n\n if (filter && Object.keys(filter).length > 0 && metadataCol) {\n const conditions: string[] = [];\n for (const [key, value] of Object.entries(filter)) {\n if (!SAFE_IDENTIFIER_RE.test(key)) {\n throw new StorageValidationError(\n `Invalid metadata filter key: \"${key}\". Keys must match /^[a-zA-Z_][a-zA-Z0-9_]*$/.`\n );\n }\n // The JSON key inside `->>` is already validated above; we still\n // need to quote the column identifier itself to handle non-trivial\n // metadata column names.\n conditions.push(`${metadataCol}->>'${key}' = $${paramIndex}`);\n params.push(String(value));\n paramIndex++;\n }\n if (conditions.length > 0) {\n sql += ` WHERE ${conditions.join(\" AND \")}`;\n hasWhere = true;\n }\n }\n\n // Always emit the score threshold predicate so behaviour matches the\n // in-memory fallback (`score >= scoreThreshold`) for every metric and\n // every threshold value (including 0 / negative).\n sql += hasWhere ? \" AND\" : \" WHERE\";\n sql += ` ${scoreExpr} >= $${paramIndex}`;\n params.push(scoreThreshold);\n paramIndex++;\n\n // ORDER BY uses the raw distance (smaller = closer) so the configured\n // pgvector index can serve the query directly.\n sql += ` ORDER BY ${vectorCol} ${distOp} $1::vector LIMIT $${paramIndex}`;\n params.push(topK);\n\n const result = await this.db.query(sql, params);\n\n // Fetch vectors separately for each result\n const results: Array<Entity & { score: number }> = [];\n for (const row of result.rows) {\n const vectorResult = await this.db.query(\n `SELECT ${vectorCol}::text FROM \"${this.table}\" WHERE ${this.getPrimaryKeyWhereClause()}`,\n this.getPrimaryKeyValues(row)\n );\n const vectorStr = vectorResult.rows[0]?.[vectorColRaw] || \"[]\";\n const vectorArray = JSON.parse(vectorStr);\n\n results.push({\n ...row,\n [this.vectorPropertyName]: new this.vectorCtor(vectorArray),\n score: parseFloat(row.score),\n } as Entity & { score: number });\n }\n\n return results;\n } catch (error) {\n if (error instanceof StorageValidationError) {\n throw error; // Don't swallow validation errors\n }\n // Fall back to in-memory similarity calculation if pgvector is not available\n console.error(\"pgvector query failed, falling back to in-memory search:\", error);\n return this.searchFallback(query, options);\n }\n }\n\n /**\n * Throws if the configured distance metric isn't cosine. The in-memory\n * fallback paths below only know how to compute cosine similarity; if\n * pgvector is unavailable for an `l2`/`ip` storage, falling back would\n * silently return wrong scores. Callers using non-cosine distances must\n * keep pgvector working.\n */\n private assertFallbackSupportsDistance(): void {\n if (this.distance !== \"cosine\") {\n throw new Error(\n `PostgresVectorStorage: pgvector is unavailable and the in-memory ` +\n `fallback only supports cosine distance (configured: \"${this.distance}\"). ` +\n `Install pgvector or switch the storage to cosine distance.`\n );\n }\n }\n\n /**\n * Fallback search using in-memory cosine similarity. Only valid for\n * `distance: \"cosine\"`; see {@link assertFallbackSupportsDistance}.\n */\n private async searchFallback(query: TypedArray, options: VectorSearchOptions<Metadata>) {\n this.assertFallbackSupportsDistance();\n const { topK = 10, filter, scoreThreshold = 0 } = options;\n const allRows = (await this.getAll()) || [];\n const results: Array<Entity & { score: number }> = [];\n\n for (const row of allRows) {\n const vector = row[this.vectorPropertyName] as TypedArray;\n const metadata = this.metadataPropertyName\n ? (row[this.metadataPropertyName] as Metadata)\n : ({} as Metadata);\n\n if (filter && !this.matchesFilter(metadata, filter)) {\n continue;\n }\n\n const score = cosineSimilarity(query, vector);\n\n if (score >= scoreThreshold) {\n results.push({ ...row, score } as Entity & { score: number });\n }\n }\n\n results.sort((a, b) => b.score - a.score);\n const topResults = results.slice(0, topK);\n\n return topResults;\n }\n\n private getPrimaryKeyWhereClause(): string {\n const conditions = this.primaryKeyNames.map((key, idx) => `${String(key)} = $${idx + 1}`);\n return conditions.join(\" AND \");\n }\n\n private getPrimaryKeyValues(row: any): any[] {\n return this.primaryKeyNames.map((key) => row[key]);\n }\n\n private matchesFilter(metadata: Metadata, filter: Partial<Metadata>): boolean {\n for (const [key, value] of Object.entries(filter)) {\n if (metadata[key as keyof Metadata] !== value) {\n return false;\n }\n }\n return true;\n }\n}\n",
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 {\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"
10
10
  ],
11
- "mappings": "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",
12
- "debugId": "1C3E72F1BE3B8A0064756E2164756E21",
11
+ "mappings": ";;;;AAUA,IAAI;AAQJ,eAAsB,YAAY,GAAkB;AAAA,EAClD,IAAI,KAAK;AAAA,IACP;AAAA,EACF;AAAA,EACA,IAAI;AAAA,IACF,MAAM,MAAa;AAAA,IACnB,MAAM;AAAA,IACN,MAAM,IAAI,MACR,oGACF;AAAA;AAAA;AAKG,SAAS,WAAW,GAAwB;AAAA,EACjD,IAAI,CAAC,KAAK;AAAA,IACR,MAAM,IAAI,MACR,6FACF;AAAA,EACF;AAAA,EACA,OAAO;AAAA;AAIT,eAAsB,UAAU,CAAC,QAAmC;AAAA,EAClE,MAAM,aAAa;AAAA,EACnB,OAAO,IAAI,IAAK,KAAK,MAAM;AAAA;AAItB,IAAM,WAAW;AAAA,EACtB,MAAM;AAAA,EACN,MAAM;AAAA,MACF,MAAM,GAAwB;AAAA,IAChC,OAAO,YAAY;AAAA;AAAA,EAErB;AACF;;AChDA,+BAAS;;;ACAT;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA0BO,IAAM,8BAA8B,mBACzC,oCACF;AAQA,SAAS,iBAAiB,CAAC,OAA2B,OAAqB;AAAA,EACzE,IAAI,UAAU;AAAA,IAAW;AAAA,EACzB,IAAI,CAAC,OAAO,SAAS,KAAK,KAAK,CAAC,OAAO,UAAU,KAAK,KAAK,SAAS,GAAG;AAAA,IACrE,MAAM,IAAI,MACR,sBAAsB,8CAA8C,OAAO,KAAK,GAClF;AAAA,EACF;AAAA;AAAA;AAWK,MAAM,+BAWH,sBAAsF;AAAA,EACpF;AAAA,EAaV,WAAW,CACT,IACA,QAAgB,iBAChB,QACA,iBACA,UAAmF,CAAC,GACpF,qBAA+C,cAC/C,mBACA;AAAA,IACA,MAAM,OAAO,QAAQ,iBAAiB,SAAS,oBAAoB,mBAAmB,KAAK;AAAA,IAC3F,KAAK,KAAK;AAAA;AAAA,OAQU,cAAa,GAAkB;AAAA,IACnD,IAAI,KAAK,qBAAqB,KAAK,kBAAkB,SAAS,GAAG;AAAA,MAO/D,MAAM,SAAS,MAAM,KAAK,iBAAiB;AAAA,MAC3C,MAAM,KAAK,sBAAsB;AAAA,MACjC,MAAM,KAAK,uBAAuB,EAAE,YAAY,CAAC,OAAO,CAAC;AAAA,MAGzD,IAAI,QAAQ;AAAA,QACV,MAAM,KAAK,sBAAsB;AAAA,MACnC;AAAA,MACA;AAAA,IACF;AAAA,IACA,MAAM,KAAK,sBAAsB;AAAA;AAAA,OAGrB,iBAAgB,GAAqB;AAAA,IACjD,MAAM,IAAI,MAAM,KAAK,GAAG,MACtB,8EACA,CAAC,KAAK,KAAK,CACb;AAAA,IACA,OAAO,EAAE,KAAK,SAAS;AAAA;AAAA,OAOX,sBAAqB,GAAkB;AAAA,IACnD,MAAM,MAAM;AAAA,oCACoB,KAAK;AAAA,UAC/B,KAAK,2BAA2B,GAAG,KAAK,KAAK,sBAAsB,GAAG;AAAA,uBACzD,KAAK,qBAAqB;AAAA;AAAA;AAAA,IAG7C,MAAM,KAAK,GAAG,MAAM,GAAG;AAAA,IACvB,MAAM,KAAK,oBAAoB;AAAA,IAC/B,MAAM,KAAK,sBAAsB;AAAA;AAAA,OAOrB,sBAAqB,GAAkB;AAAA,IACnD,MAAM,YAAY,KAAK,kBAAkB;AAAA,IACzC,MAAM,iBAAiB,IAAI;AAAA,IAC3B,WAAW,WAAW,KAAK,SAAS;AAAA,MAClC,IAAI,QAAQ,UAAU,UAAU,QAAQ;AAAA,QAEtC,MAAM,aAAa,QAAQ,MAAM,CAAC,KAAK,QAAQ,QAAQ,UAAU,IAAI;AAAA,QACrE,IAAI;AAAA,UAAY;AAAA,MAClB;AAAA,MACA,MAAM,YAAY,GAAG,KAAK,SAAS,QAAQ,KAAK,GAAG;AAAA,MACnD,MAAM,aAAa,QAAQ,IAAI,CAAC,QAAQ,IAAI,OAAO,GAAG,IAAI,EAAE,KAAK,IAAI;AAAA,MACrE,MAAM,YAAY,QAAQ,KAAK,GAAG;AAAA,MAClC,IAAI,eAAe,IAAI,SAAS;AAAA,QAAG;AAAA,MACnC,MAAM,cAAc,MAAM,KAAK,cAAc,EAAE,KAAK,CAAC,aAAa;AAAA,QAChE,MAAM,eAAe,SAAS,MAAM,GAAG;AAAA,QACvC,OACE,aAAa,UAAU,QAAQ,UAC/B,QAAQ,MAAM,CAAC,KAAK,QAAQ,QAAQ,aAAa,IAAI;AAAA,OAExD;AAAA,MACD,IAAI,CAAC,aAAa;AAAA,QAChB,MAAM,KAAK,GAAG,MACZ,+BAA+B,kBAAkB,KAAK,WAAW,aACnE;AAAA,QACA,eAAe,IAAI,SAAS;AAAA,MAC9B;AAAA,IACF;AAAA;AAAA,OAQW,gBAAe,CAAC,KAA4B;AAAA,IACvD,MAAM,KAAK,GAAG,MAAM,GAAG;AAAA;AAAA,OAQZ,uBAAsB,CACjC,WACA,SACA,aACe;AAAA,IACf,MAAM,KAAK,GAAG,MACZ,eAAe,yEACf,CAAC,WAAW,SAAS,WAAW,CAClC;AAAA;AAAA,EAGc,mBAAmB,GAAoC;AAAA,IACrE,OAAO,IAAI,oCAAoC,IAAI;AAAA;AAAA,EAG3C,cAAc,CAAC,QAA0B;AAAA,IACjD,IAAI,CAAC;AAAA,MAAQ,OAAO;AAAA,IACpB,OAAO,OAAO,WAAW,aAAa,KAAK,WAAW;AAAA;AAAA,EAG9C,mBAAmB,CAAC,SAAyC;AAAA,IACrE;AAAA;AAAA,EAWQ,YAAY,CAAC,SAA6B;AAAA,IAElD,MAAM,aAAa,KAAK,eAAe,OAAO;AAAA,IAC9C,IAAI,OAAO,eAAe,WAAW;AAAA,MACnC,OAAO;AAAA,IACT;AAAA,IAGA,IAAI,WAAW,oBAAoB;AAAA,MAAQ,OAAO;AAAA,IAElD,QAAQ,WAAW;AAAA,WACZ;AAAA,QAEH,IAAI,WAAW,WAAW;AAAA,UAAa,OAAO;AAAA,QAC9C,IAAI,WAAW,WAAW;AAAA,UAAQ,OAAO;AAAA,QACzC,IAAI,WAAW,WAAW;AAAA,UAAS,OAAO;AAAA,QAC1C,IAAI,WAAW,WAAW;AAAA,UAAO,OAAO;AAAA,QACxC,IAAI,WAAW,WAAW;AAAA,UAAQ,OAAO;AAAA,QAGzC,IAAI,KAAK,eAAe,WAAW,MAAM,GAAG;AAAA,UAC1C,MAAM,YAAY,KAAK,oBAAoB,UAAU;AAAA,UACrD,IAAI,OAAO,cAAc,UAAU;AAAA,YACjC,OAAO,UAAU;AAAA,UACnB;AAAA,QACF;AAAA,QAGA,IAAI,OAAO,WAAW,cAAc,UAAU;AAAA,UAC5C,OAAO,WAAW,WAAW;AAAA,QAC/B;AAAA,QAGA,OAAO;AAAA,WAEJ;AAAA,WACA;AAAA,QAEH,IAAI,WAAW,eAAe,KAAK,WAAW,SAAS,WAAW;AAAA,UAEhE,IAAI,OAAO,WAAW,YAAY,UAAU;AAAA,YAC1C,IAAI,WAAW,WAAW,GAAG;AAAA,cAE3B,IAAI,OAAO,WAAW,YAAY,UAAU;AAAA,gBAC1C,IAAI,WAAW,WAAW;AAAA,kBAAO,OAAO;AAAA,gBACxC,IAAI,WAAW,WAAW;AAAA,kBAAY,OAAO;AAAA,cAC/C;AAAA,cACA,OAAO;AAAA,YACT;AAAA,UACF;AAAA,UAGA,OAAO;AAAA,QACT;AAAA,QAGA,IAAI,WAAW,WAAW;AAAA,UAAS,OAAO;AAAA,QAC1C,IAAI,WAAW,WAAW;AAAA,UAAU,OAAO;AAAA,QAG3C,IAAI,OAAO,WAAW,eAAe,UAAU;AAAA,UAC7C,MAAM,gBAAgB,OAAO,WAAW,UAAU,EAAE,MAAM,GAAG,EAAE,IAAI,UAAU;AAAA,UAC7E,IAAI,gBAAgB,GAAG;AAAA,YACrB,OAAO,eAAe;AAAA,UACxB;AAAA,QACF;AAAA,QAEA,OAAO;AAAA,WAEJ;AAAA,QACH,OAAO;AAAA,WAEJ;AAAA,QAEH,IACE,WAAW,SACX,OAAO,WAAW,UAAU,YAC5B,CAAC,MAAM,QAAQ,WAAW,KAAK,GAC/B;AAAA,UACA,MAAM,WAAW,KAAK,aAAa,WAAW,KAAmB;AAAA,UAIjE,MAAM,6BAA6B;AAAA,YACjC;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,UAGA,MAAM,cAAc,2BAA2B,KAC7C,CAAC,SAAS,aAAa,QAAS,SAAS,WAAW,OAAO,GAAG,KAAK,SAAS,SAC9E;AAAA,UAEA,IAAI,aAAa;AAAA,YACf,OAAO,GAAG;AAAA,UACZ,EAAO;AAAA,YACL,OAAO;AAAA;AAAA,QAEX;AAAA,QACA,OAAO;AAAA,WAEJ;AAAA,QACH,OAAO;AAAA;AAAA,QAGP,OAAO;AAAA;AAAA;AAAA,EASM,0BAA0B,CAAC,aAAqB,IAAY;AAAA,IAC7E,MAAM,OAAO,OAAO,QAAoB,KAAK,iBAAiB,UAAU,EACrE,IAAI,EAAE,KAAK,aAAa;AAAA,MAEvB,IAAI,KAAK,mBAAmB,GAAG,GAAG;AAAA,QAChC,IAAI,KAAK,6BAA6B,iBAAiB;AAAA,UAErD,MAAM,WAAU,KAAK,aAAa,OAAO;AAAA,UACzC,MAAM,aAAa,SAAQ,SAAS,UAAU;AAAA,UAC9C,MAAM,WAAW,SAAQ,SAAS,QAAQ;AAAA,UAC1C,MAAM,aAAa,WAAW,cAAc,aAAa,gBAAgB;AAAA,UACzE,OAAO,GAAG,aAAa,MAAM,cAAc;AAAA,QAC7C,EAAO,SAAI,KAAK,6BAA6B,QAAQ;AAAA,UAEnD,OAAO,GAAG,aAAa,MAAM;AAAA,QAC/B;AAAA,MACF;AAAA,MAEA,MAAM,UAAU,KAAK,aAAa,OAAO;AAAA,MACzC,IAAI,cAAc;AAAA,MAGlB,IAAI,KAAK,iBAAiB,OAAO,GAAG;AAAA,QAClC,eAAe,WAAW,aAAa,MAAM;AAAA,MAC/C;AAAA,MAEA,OAAO,GAAG,aAAa,MAAM,cAAc,WAAW;AAAA,KACvD,EACA,KAAK,IAAI;AAAA,IACZ,OAAO;AAAA;AAAA,EAOU,qBAAqB,CAAC,aAAqB,IAAY;AAAA,IACxE,MAAM,cAAc,IAAI,IAAI,KAAK,YAAY,YAAY,CAAC,CAAC;AAAA,IAC3D,MAAM,OAAO,OAAO,QAAoB,KAAK,YAAY,UAAU,EAChE,IAAI,EAAE,KAAK,aAAa;AAAA,MACvB,MAAM,UAAU,KAAK,aAAa,OAAO;AAAA,MACzC,MAAM,aAAa,YAAY,IAAI,GAAG;AAAA,MACtC,MAAM,WAAW,CAAC,cAAc,KAAK,WAAW,OAAO;AAAA,MACvD,IAAI,cAAc,WAAW,SAAS;AAAA,MAGtC,IAAI,KAAK,iBAAiB,OAAO,GAAG;AAAA,QAClC,eAAe,WAAW,aAAa,MAAM;AAAA,MAC/C;AAAA,MAEA,OAAO,GAAG,aAAa,MAAM,cAAc,WAAW;AAAA,KACvD,EACA,KAAK,IAAI;AAAA,IACZ,IAAI,KAAK,SAAS,GAAG;AAAA,MACnB,OAAO,KAAK;AAAA,IACd,EAAO;AAAA,MACL,OAAO;AAAA;AAAA;AAAA,EAOQ,YAAY,CAAC,QAAgB,OAA8C;AAAA,IAC5F,MAAM,UAAU,KAAK,OAAO,WAAW;AAAA,IACvC,IAAI,SAAS;AAAA,MACX,MAAM,aAAa,KAAK,eAAe,OAAO;AAAA,MAG9C,IAAI,OAAO,eAAe,aAAa,KAAK,eAAe,WAAW,MAAM,GAAG;AAAA,QAC7E,IAAI,SAAS,YAAY,OAAO,KAAK,KAAK,EAAE,iBAAiB,WAAW;AAAA,UAEtE,MAAM,QAAQ,MAAM,KAAK,KAA8B;AAAA,UACvD,OAAO,IAAI,MAAM,KAAK,GAAG;AAAA,QAC3B;AAAA,QAEA,IAAI,OAAO,UAAU,UAAU;AAAA,UAC7B,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,IACA,OAAO,MAAM,aAAa,QAAQ,KAAK;AAAA;AAAA,EAMtB,YAAY,CAAC,QAAgB,OAA8C;AAAA,IAC5F,MAAM,UAAU,KAAK,OAAO,WAAW;AAAA,IAGvC,IAAI,SAAS;AAAA,MACX,IAAI,UAAU,QAAQ,KAAK,WAAW,OAAO,GAAG;AAAA,QAC9C,OAAO;AAAA,MACT;AAAA,MACA,MAAM,aAAa,KAAK,eAAe,OAAO;AAAA,MAG9C,IAAI,OAAO,eAAe,aAAa,KAAK,eAAe,WAAW,MAAM,GAAG;AAAA,QAC7E,IAAI,OAAO,UAAU,UAAU;AAAA,UAC7B,IAAI;AAAA,YAEF,MAAM,QAAQ,KAAK,MAAM,KAAK;AAAA,YAC9B,OAAO,IAAI,aAAa,KAAK;AAAA,YAC7B,OAAO,GAAG;AAAA,YACV,QAAQ,KAAK,qCAAqC,WAAW,CAAC;AAAA;AAAA,QAElE;AAAA,QAEA,IAAI,SAAS,OAAO,UAAU,UAAU;AAAA,UACtC,OAAO;AAAA,QACT;AAAA,MACF;AAAA,MAGA,IACE,OAAO,eAAe,cACrB,WAAW,SAAS,YAAY,WAAW,SAAS,YACrD;AAAA,QACA,IAAI,OAAO,UAAU;AAAA,UAAU,OAAO;AAAA,QACtC,IAAI,OAAO,UAAU,UAAU;AAAA,UAC7B,MAAM,SAAS,OAAO,KAAK;AAAA,UAC3B,IAAI,CAAC,MAAM,MAAM;AAAA,YAAG,OAAO;AAAA,QAC7B;AAAA,MACF;AAAA,IACF;AAAA,IACA,OAAO,MAAM,aAAa,QAAQ,KAAK;AAAA;AAAA,EAQ/B,gBAAgB,CAAC,SAA8B;AAAA,IAEvD,MAAM,aAAa,KAAK,eAAe,OAAO;AAAA,IAC9C,IAAI,OAAO,eAAe,WAAW;AAAA,MACnC,OAAO;AAAA,IACT;AAAA,IAGA,KACG,WAAW,SAAS,YAAY,WAAW,SAAS,cACrD,OAAO,WAAW,YAAY,YAC9B,WAAW,WAAW,GACtB;AAAA,MACA,OAAO;AAAA,IACT;AAAA,IAEA,OAAO;AAAA;AAAA,EAOC,gBAAgB,GAAiD;AAAA,IACzE,MAAM,gBAA8D,CAAC;AAAA,IAGrE,YAAY,KAAK,YAAY,OAAO,QAAoB,KAAK,OAAO,UAAU,GAAG;AAAA,MAC/E,MAAM,aAAa,KAAK,eAAe,OAAO;AAAA,MAC9C,IAAI,OAAO,eAAe,aAAa,KAAK,eAAe,WAAW,MAAM,GAAG;AAAA,QAC7E,MAAM,YAAY,KAAK,oBAAoB,UAAU;AAAA,QACrD,IAAI,OAAO,cAAc,UAAU;AAAA,UACjC,cAAc,KAAK,EAAE,QAAQ,KAAK,UAAU,CAAC;AAAA,QAC/C,EAAO;AAAA,UACL,QAAQ,KAAK,oCAAoC,QAAQ,WAAW,kBAAkB;AAAA;AAAA,MAE1F;AAAA,IACF;AAAA,IAEA,OAAO;AAAA;AAAA,EASC,qBAAqB,GAAuB;AAAA,IACpD,OAAO,CAAC;AAAA;AAAA,OAWM,oBAAmB,GAAkB;AAAA,IACnD,MAAM,gBAAgB,KAAK,iBAAiB;AAAA,IAE5C,IAAI,cAAc,WAAW,GAAG;AAAA,MAC9B;AAAA,IACF;AAAA,IAEA,MAAM,OAAO,KAAK,sBAAsB;AAAA,IAGxC,IAAI,KAAK,QAAQ,KAAK,SAAS;AAAA,MAC7B,MAAM,IAAI,MACR,gFACF;AAAA,IACF;AAAA,IACA,kBAAkB,KAAK,MAAM,GAAG,QAAQ;AAAA,IACxC,kBAAkB,KAAK,MAAM,gBAAgB,qBAAqB;AAAA,IAClE,kBAAkB,KAAK,MAAM,UAAU,eAAe;AAAA,IACtD,kBAAkB,KAAK,SAAS,OAAO,eAAe;AAAA,IACtD,kBAAkB,KAAK,SAAS,QAAQ,gBAAgB;AAAA,IAGxD,IAAI;AAAA,MACF,MAAM,KAAK,GAAG,MAAM,uCAAuC;AAAA,MAC3D,OAAO,OAAO;AAAA,MACd,QAAQ,KACN,4EACA,KACF;AAAA,MACA;AAAA;AAAA,IAGF,MAAM,WAAW,KAAK,YAAY;AAAA,IAClC,MAAM,UACJ,aAAa,OACT,kBACA,aAAa,OACX,kBACA;AAAA,IAER,MAAM,UAAU,gBAAgB,QAAQ,KAAK,KAAK;AAAA,IAElD,IAAI,KAAK,SAAS;AAAA,MAEhB,QAAQ,UAAU,KAAK;AAAA,MACvB,aAAa,YAAY,eAAe;AAAA,QACtC,MAAM,UAAU,gBAAgB,QAAQ,GAAG,KAAK,SAAS,oBAAoB;AAAA,QAC7E,MAAM,WAAW,gBAAgB,QAAQ,MAAM;AAAA,QAC/C,IAAI;AAAA,UACF,MAAM,KAAK,GAAG,MAAM;AAAA,yCACW;AAAA,iBACxB;AAAA,6BACY,YAAY;AAAA,4BACb;AAAA,WACjB;AAAA,UACD,OAAO,OAAO;AAAA,UACd,QAAQ,KAAK,qCAAqC,WAAW,KAAK;AAAA;AAAA,MAEtE;AAAA,MACA;AAAA,IACF;AAAA,IAIA,MAAM,OAAO,KAAK,QAAQ,CAAC;AAAA,IAC3B,MAAM,cAAwB,CAAC;AAAA,IAC/B,IAAI,OAAO,KAAK,MAAM;AAAA,MAAU,YAAY,KAAK,OAAO,KAAK,GAAG;AAAA,IAChE,IAAI,OAAO,KAAK,mBAAmB,UAAU;AAAA,MAC3C,YAAY,KAAK,qBAAqB,KAAK,gBAAgB;AAAA,IAC7D;AAAA,IACA,MAAM,aAAa,YAAY,SAAS,IAAI,UAAU,YAAY,KAAK,IAAI,OAAO;AAAA,IAElF,aAAa,YAAY,eAAe;AAAA,MACtC,MAAM,UAAU,gBAAgB,QAAQ,GAAG,KAAK,SAAS,iBAAiB;AAAA,MAC1E,MAAM,WAAW,gBAAgB,QAAQ,MAAM;AAAA,MAC/C,IAAI;AAAA,QACF,MAAM,KAAK,GAAG,MAAM;AAAA,uCACW;AAAA,eACxB;AAAA,wBACS,YAAY,WAAW;AAAA,SACtC;AAAA,QACD,OAAO,OAAO;AAAA,QACd,QAAQ,KAAK,kCAAkC,WAAW,KAAK;AAAA;AAAA,IAEnE;AAAA;AAAA,EAUM,WAAW,CAAC,QAAgE;AAAA,IAElF,MAAM,kBAA4B,CAAC;AAAA,IACnC,MAAM,iBAAoC,CAAC;AAAA,IAG3C,MAAM,YAAY,KAAK,kBAAkB;AAAA,IACzC,MAAM,eAAe;AAAA,IACrB,WAAW,OAAO,WAAW;AAAA,MAC3B,MAAM,SAAS,OAAO,GAAG;AAAA,MAGzB,IAAI,KAAK,mBAAmB,MAAM,GAAG;AAAA,QACnC,MAAM,sBAAsB,aAAa;AAAA,QACzC,MAAM,iBAAiB,wBAAwB,aAAa,wBAAwB;AAAA,QAEpF,IAAI,uBAAuB;AAAA,QAC3B,IAAI,KAAK,uBAAuB,SAAS;AAAA,UAEvC,uBAAuB;AAAA,QACzB,EAAO,SAAI,KAAK,uBAAuB,UAAU;AAAA,UAC/C,IAAI,CAAC,gBAAgB;AAAA,YACnB,MAAM,IAAI,MACR,uBAAuB,yDACzB;AAAA,UACF;AAAA,UACA,uBAAuB;AAAA,QACzB,EAAO;AAAA,UAEL,uBAAuB;AAAA;AAAA,QAGzB,IAAI,sBAAsB;AAAA,UACxB,gBAAgB,KAAK,MAAM;AAAA,UAC3B,eAAe,KACb,KAAK,aAAa,QAAQ,mBAA2C,CACvE;AAAA,QACF;AAAA,QAEA;AAAA,MACF;AAAA,MAGA,gBAAgB,KAAK,MAAM;AAAA,MAC3B,MAAM,QAAQ,aAAa;AAAA,MAC3B,eAAe,KAAK,KAAK,aAAa,QAAQ,KAA6B,CAAC;AAAA,IAC9E;AAAA,IAGA,MAAM,eAAe,KAAK,aAAa;AAAA,IACvC,WAAW,OAAO,cAAc;AAAA,MAC9B,MAAM,SAAS,OAAO,GAAG;AAAA,MACzB,gBAAgB,KAAK,MAAM;AAAA,MAC3B,MAAM,QAAQ,aAAa;AAAA,MAC3B,eAAe,KAAK,KAAK,aAAa,QAAQ,KAA6B,CAAC;AAAA,IAC9E;AAAA,IAEA,MAAM,aAAa,gBAAgB,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,IAAI;AAAA,IACjE,MAAM,eAAe,gBAAgB,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,GAAG,EAAE,KAAK,IAAI;AAAA,IAGzE,MAAM,iBACJ,aAAa,SAAS,IAClB;AAAA,qBACW,KAAK,qBAAqB,GAAG;AAAA;AAAA,QAEzC,aACA,IAAI,CAAC,QAAQ;AAAA,MACZ,MAAM,SAAS,gBAAgB,QAAQ,OAAO,GAAG,CAAC;AAAA,MAClD,OAAO,IAAI,WAAW,SAAS;AAAA,KAChC,EACA,KAAK,IAAI;AAAA,UAER;AAAA,IAEN,MAAM,MAAM;AAAA,qBACK,KAAK,WAAW;AAAA,gBACrB;AAAA,QACR;AAAA;AAAA;AAAA,IAIJ,OAAO,EAAE,KAAK,QAAQ,eAAe;AAAA;AAAA,EAI/B,UAAU,CAAC,KAAsB;AAAA,IACvC,MAAM,SAAS;AAAA,IACf,MAAM,SAAS;AAAA,IACf,WAAW,OAAO,KAAK,OAAO,YAAY;AAAA,MACxC,OAAO,OAAO,KAAK,aAAa,KAAK,OAAO,IAAuB;AAAA,IACrE;AAAA,IACA,OAAO;AAAA;AAAA,OAwBK,kBAAiB,GAG5B;AAAA,IACD,MAAM,kBACJ,OAAQ,KAAK,GAAwC,YAAY;AAAA,IACnE,IAAI,iBAAiB;AAAA,MACnB,OAAO,MACL,KAAK,GAGL,QAAQ;AAAA,IACZ;AAAA,IASA,MAAM,QAAQ,KAAK;AAAA,IAKnB,MAAM,WAAW,MAAM,aAAa;AAAA,IACpC,MAAM,kBAAkB,OAAO,MAAM,SAAS,cAAc,MAAM,cAAc;AAAA,IAChF,MAAM,sBAAsB,aAAa;AAAA,IACzC,IAAI,CAAC,mBAAmB,CAAC,qBAAqB;AAAA,MAC5C,MAAM,IAAI,MACR,mIAAmI,YAAY,OAAO,KAAK,yIAC7J;AAAA,IACF;AAAA,IACA,OAAO;AAAA,MACL,OAAO,KAAK,GAAG,MAAM,KAAK,KAAK,EAAE;AAAA,MACjC,SAAS,MAAM;AAAA,IACjB;AAAA;AAAA,EAkBM,aAA4B,QAAQ,QAAQ;AAAA,MACxC,YAAY,GAAY;AAAA,IAClC,OAAO,OAAQ,KAAK,GAAwC,YAAY;AAAA;AAAA,OAE5D,MAAQ,CAAC,IAAkC;AAAA,IACvD,IAAI,CAAC,KAAK;AAAA,MAAc,OAAO,GAAG;AAAA,IAClC,MAAM,OAAO,KAAK;AAAA,IAClB,IAAI;AAAA,IACJ,KAAK,aAAa,IAAI,QAAc,CAAC,YAAY;AAAA,MAC/C,UAAU;AAAA,KACX;AAAA,IACD,MAAM;AAAA,IACN,IAAI;AAAA,MACF,OAAO,MAAM,GAAG;AAAA,cAChB;AAAA,MACA,QAAQ;AAAA;AAAA;AAAA,EAYJ,gBAAyB;AAAA,EAOvB,OAAO,CAAC,QAAsB;AAAA,IACtC,KAAK,OAAO,KAAK,OAAO,MAAM;AAAA;AAAA,OAY1B,IAAG,CAAC,QAAqC;AAAA,IAC7C,OAAO,KAAK,MAAM,MAAM,KAAK,aAAa,MAAM,CAAC;AAAA;AAAA,OAGrC,aAAY,CAAC,QAAqC;AAAA,IAC9D,QAAQ,KAAK,WAAW,KAAK,YAAY,MAAM;AAAA,IAC/C,MAAM,SAAS,MAAM,KAAK,GAAG,MAAM,KAAK,MAAM;AAAA,IAC9C,MAAM,gBAAgB,KAAK,WAAW,OAAO,KAAK,EAAE;AAAA,IACpD,KAAK,QAAQ,aAAa;AAAA,IAC1B,OAAO;AAAA;AAAA,OAmBH,QAAO,CAAC,UAA2C;AAAA,IACvD,OAAO,KAAK,MAAM,MAAM,KAAK,iBAAiB,QAAQ,CAAC;AAAA;AAAA,OAG3C,iBAAgB,CAAC,UAA2C;AAAA,IACxE,IAAI,SAAS,WAAW;AAAA,MAAG,OAAO,CAAC;AAAA,IASnC,IAAI,KAAK,eAAe;AAAA,MACtB,MAAM,UAAoB,CAAC;AAAA,MAC3B,WAAW,UAAU,UAAU;AAAA,QAC7B,QAAQ,KAAK,WAAW,KAAK,YAAY,MAAM;AAAA,QAC/C,MAAM,SAAS,MAAM,KAAK,GAAG,MAAM,KAAK,MAAM;AAAA,QAC9C,QAAQ,KAAK,KAAK,WAAW,OAAO,KAAK,EAAE,CAAC;AAAA,MAC9C;AAAA,MACA,WAAW,UAAU;AAAA,QAAS,KAAK,QAAQ,MAAM;AAAA,MACjD,OAAO;AAAA,IACT;AAAA,IAEA,MAAM,OAAO,MAAM,KAAK,kBAAkB;AAAA,IAC1C,MAAM,kBAA4B,CAAC;AAAA,IACnC,IAAI;AAAA,MACF,MAAM,KAAK,MAAM,OAAO;AAAA,MACxB,IAAI;AAAA,QACF,WAAW,UAAU,UAAU;AAAA,UAC7B,QAAQ,KAAK,WAAW,KAAK,YAAY,MAAM;AAAA,UAC/C,MAAM,SAAS,MAAM,KAAK,MAAM,KAAK,MAAM;AAAA,UAC3C,gBAAgB,KAAK,KAAK,WAAW,OAAO,KAAK,EAAE,CAAC;AAAA,QACtD;AAAA,QACA,MAAM,KAAK,MAAM,QAAQ;AAAA,QACzB,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,IAGf,WAAW,UAAU;AAAA,MAAiB,KAAK,QAAQ,MAAM;AAAA,IACzD,OAAO;AAAA;AAAA,EAwBD,YAAY,CAAC,MAAgC,mBAAmC;AAAA,IACtF,MAAM,SAAS;AAAA,IACf,OAAO,IAAI,MAAM,QAAQ;AAAA,MACvB,GAAG,CAAC,GAAG,MAAM,UAAU;AAAA,QACrB,IAAI,SAAS,mBAAmB;AAAA,UAC9B,OAAO,MAAM;AAAA,YACX,MAAM,IAAI,MACR,sEACE,6DACJ;AAAA;AAAA,QAEJ;AAAA,QACA,IAAI,SAAS;AAAA,UAAM,OAAO;AAAA,QAC1B,IAAI,SAAS;AAAA,UAAiB,OAAO;AAAA,QACrC,IAAI,SAAS,WAAW;AAAA,UACtB,OAAO,CAAC,WAAmB,kBAAkB,KAAK,MAAM;AAAA,QAC1D;AAAA,QACA,IAAI,OAAO,SAAS,UAAU;AAAA,UAC5B,MAAM,WAAY,EAAyC,IAAI;AAAA,UAC/D,IAAI,OAAO,aAAa,YAAY;AAAA,YAClC,OAAO,IAAI,SACR,SAA0C,MAAM,UAAU,IAAI;AAAA,UACnE;AAAA,QACF;AAAA,QACA,MAAM,QAAQ,QAAQ,IAAI,GAAG,MAAM,QAAQ;AAAA,QAC3C,OAAO,OAAO,UAAU,aAAa,MAAM,KAAK,QAAQ,IAAI;AAAA;AAAA,IAEhE,CAAC;AAAA;AAAA,OA4BY,gBAAkB,CAAC,IAA0C;AAAA,IAC1E,MAAM,kBACJ,OAAQ,KAAK,GAAwC,YAAY;AAAA,IAEnE,IAAI,iBAAiB;AAAA,MASnB,MAAM,SAAS,MACb,KAAK,GAGL,QAAQ;AAAA,MACV,IAAI;AAAA,QACF,OAAO,MAAM,KAAK,iBAAiB,IAAI,EAAE,OAAO,OAAO,MAAM,KAAK,MAAM,EAAE,CAAC;AAAA,gBAC3E;AAAA,QACA,OAAO,QAAQ;AAAA;AAAA,IAEnB;AAAA,IAMA,IAAI,KAAK,eAAe;AAAA,MACtB,MAAM,IAAI,MACR,sEACE,6DACJ;AAAA,IACF;AAAA,IACA,OAAO,KAAK,MAAM,YAAY;AAAA,MAC5B,KAAK,gBAAgB;AAAA,MACrB,IAAI;AAAA,QACF,OAAO,MAAM,KAAK,iBAAiB,IAAI,EAAE,OAAO,KAAK,GAAG,MAAM,KAAK,KAAK,EAAE,EAAE,CAAC;AAAA,gBAC7E;AAAA,QACA,KAAK,gBAAgB;AAAA;AAAA,KAExB;AAAA;AAAA,OAGW,iBAAmB,CAC/B,IACA,MACY;AAAA,IACZ,MAAM,oBAA8B,CAAC;AAAA,IACrC,MAAM,KAAK,MAAM,OAAO;AAAA,IACxB,IAAI;AAAA,IACJ,IAAI;AAAA,MACF,SAAS,MAAM,GAAG,KAAK,aAAa,MAAM,iBAAiB,CAAC;AAAA,MAC5D,MAAM,KAAK,MAAM,QAAQ;AAAA,MACzB,OAAO,KAAK;AAAA,MACZ,IAAI;AAAA,QACF,MAAM,KAAK,MAAM,UAAU;AAAA,QAC3B,MAAM;AAAA,MAGR,MAAM;AAAA;AAAA,IAGR,WAAW,UAAU;AAAA,MAAmB,KAAK,OAAO,KAAK,OAAO,MAAM;AAAA,IACtE,OAAO;AAAA;AAAA,OAUH,IAAG,CAAC,KAA8C;AAAA,IACtD,OAAO,KAAK,MAAM,MAAM,KAAK,aAAa,GAAG,CAAC;AAAA;AAAA,OAGlC,aAAY,CAAC,KAA8C;AAAA,IACvE,MAAM,KAAK,KAAK;AAAA,IAChB,MAAM,eAAgB,KAAK,kBAAkB,EAC1C,IAAI,CAAC,kBAAkB,MAAM,IAAI,wBAAwB,IAAI,GAAG,EAChE,KAAK,OAAO;AAAA,IAEf,MAAM,MAAM,kBAAkB,KAAK,gBAAgB;AAAA,IACnD,MAAM,SAAS,KAAK,4BAA4B,GAAG;AAAA,IACnD,MAAM,SAAS,MAAM,GAAG,MAAM,KAAK,MAAM;AAAA,IAEzC,IAAI;AAAA,IACJ,IAAI,OAAO,KAAK,SAAS,GAAG;AAAA,MAC1B,MAAM,OAAO,KAAK;AAAA,MAElB,MAAM,YAAY;AAAA,MAClB,WAAW,QAAO,KAAK,OAAO,YAAY;AAAA,QACxC,UAAU,QAAO,KAAK,aAAa,MAAK,UAAU,KAAuB;AAAA,MAC3E;AAAA,IACF,EAAO;AAAA,MACL,MAAM;AAAA;AAAA,IAER,KAAK,OAAO,KAAK,OAAO,KAAK,GAAG;AAAA,IAChC,OAAO;AAAA;AAAA,OAaM,QAAO,CAAC,MAAgD;AAAA,IACrE,IAAI,KAAK,WAAW;AAAA,MAAG,OAAO,CAAC;AAAA,IAC/B,MAAM,aAAa,KAAK,kBAAkB,EAAE;AAAA,IAC5C,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,UAAU,CAAC;AAAA,IAC5D,IAAI;AAAA,IACJ,IAAI,KAAK,UAAU,WAAW;AAAA,MAC5B,OAAO,MAAM,KAAK,MAAM,MAAM,KAAK,iBAAiB,IAAI,CAAC;AAAA,IAC3D,EAAO;AAAA,MACL,OAAO,CAAC;AAAA,MACR,SAAS,IAAI,EAAG,IAAI,KAAK,QAAQ,KAAK,WAAW;AAAA,QAC/C,MAAM,QAAQ,KAAK,MAAM,GAAG,IAAI,SAAS;AAAA,QACzC,MAAM,YAAY,MAAM,KAAK,MAAM,MAAM,KAAK,iBAAiB,KAAK,CAAC;AAAA,QACrE,KAAK,KAAK,GAAG,SAAS;AAAA,MACxB;AAAA;AAAA,IAEF,KAAK,OAAO,KAAK,WAAW,MAAM,IAAI;AAAA,IACtC,OAAO;AAAA;AAAA,OAGK,iBAAgB,CAAC,MAAgD;AAAA,IAC7E,MAAM,KAAK,KAAK;AAAA,IAChB,MAAM,SAAS,KAAK,kBAAkB;AAAA,IAEtC,MAAM,SAA4B,CAAC;AAAA,IACnC,MAAM,SAAmB,CAAC;AAAA,IAC1B,IAAI,IAAI;AAAA,IACR,WAAW,OAAO,MAAM;AAAA,MACtB,MAAM,UAAU,KAAK,4BAA4B,GAAG;AAAA,MACpD,OAAO,KAAK,GAAG,OAAO;AAAA,MACtB,MAAM,QAAkB,CAAC;AAAA,MACzB,SAAS,IAAI,EAAG,IAAI,OAAO,QAAQ,KAAK;AAAA,QACtC,MAAM,KAAK,IAAI,KAAK;AAAA,MACtB;AAAA,MACA,OAAO,KAAK,IAAI,MAAM,KAAK,IAAI,IAAI;AAAA,IACrC;AAAA,IAEA,MAAM,MACJ,OAAO,WAAW,IACd,IAAI,OAAO,QACX,IAAI,OAAO,IAAI,CAAC,MAAM,IAAI,IAAI,EAAE,KAAK,IAAI;AAAA,IAI/C,MAAM,MACJ,OAAO,WAAW,IACd,OAAO,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,GAAG,EAAE,KAAK,IAAI,IAC3C,OAAO,KAAK,IAAI;AAAA,IAEtB,MAAM,MAAM,kBAAkB,KAAK,gBAAgB,WAAW;AAAA,IAC9D,MAAM,SAAS,MAAM,GAAG,MAAM,KAAK,MAAM;AAAA,IAEzC,WAAW,OAAO,OAAO,MAAM;AAAA,MAC7B,MAAM,SAAS;AAAA,MACf,WAAW,OAAO,KAAK,OAAO,YAAY;AAAA,QACxC,OAAO,OAAO,KAAK,aAAa,KAAK,OAAO,IAAuB;AAAA,MACrE;AAAA,IACF;AAAA,IACA,OAAO,OAAO;AAAA;AAAA,OASV,OAAM,CAAC,OAA2C;AAAA,IACtD,OAAO,KAAK,MAAM,MAAM,KAAK,gBAAgB,KAAK,CAAC;AAAA;AAAA,OAGvC,gBAAe,CAAC,OAA2C;AAAA,IACvE,MAAM,KAAK,KAAK;AAAA,IAChB,QAAQ,QAAQ,KAAK,6BAA6B,KAAe;AAAA,IACjE,MAAM,eAAgB,KAAK,kBAAkB,EAC1C,IAAI,CAAC,MAAK,MAAM,GAAG,WAAU,IAAI,GAAG,EACpC,KAAK,OAAO;AAAA,IAEf,MAAM,SAAS,KAAK,4BAA4B,GAAG;AAAA,IACnD,MAAM,GAAG,MAAM,gBAAgB,KAAK,gBAAgB,gBAAgB,MAAM;AAAA,IAC1E,KAAK,OAAO,KAAK,UAAU,GAAmB;AAAA;AAAA,OAQ1C,OAAM,CAAC,SAA+D;AAAA,IAC1E,OAAO,KAAK,MAAM,MAAM,KAAK,gBAAgB,OAAO,CAAC;AAAA;AAAA,OAGzC,gBAAe,CAAC,SAA+D;AAAA,IAC3F,KAAK,sBAAsB,OAAO;AAAA,IAClC,MAAM,KAAK,KAAK;AAAA,IAChB,IAAI,MAAM,kBAAkB,KAAK;AAAA,IACjC,MAAM,SAA4B,CAAC;AAAA,IAEnC,IAAI,SAAS,WAAW,QAAQ,QAAQ,SAAS,GAAG;AAAA,MAClD,MAAM,eAAe,QAAQ,QAAQ,IAAI,CAAC,MAAM,IAAI,OAAO,EAAE,MAAM,MAAM,EAAE,WAAW;AAAA,MACtF,OAAO,aAAa,aAAa,KAAK,IAAI;AAAA,IAC5C;AAAA,IAEA,IAAI,SAAS,UAAU,WAAW;AAAA,MAChC,OAAO,WAAW,OAAO,SAAS;AAAA,MAClC,OAAO,KAAK,QAAQ,KAAK;AAAA,IAC3B;AAAA,IAEA,IAAI,SAAS,WAAW,WAAW;AAAA,MACjC,OAAO,YAAY,OAAO,SAAS;AAAA,MACnC,OAAO,KAAK,QAAQ,MAAM;AAAA,IAC5B;AAAA,IAEA,MAAM,SAAS,OAAO,SAAS,IAAI,MAAM,GAAG,MAAM,KAAK,MAAM,IAAI,MAAM,GAAG,MAAM,GAAG;AAAA,IAEnF,IAAI,OAAO,KAAK,SAAS,GAAG;AAAA,MAE1B,WAAW,OAAO,OAAO,MAAM;AAAA,QAC7B,MAAM,SAAS;AAAA,QACf,WAAW,OAAO,KAAK,OAAO,YAAY;AAAA,UACxC,OAAO,OAAO,KAAK,aAAa,KAAK,OAAO,IAAuB;AAAA,QACrE;AAAA,MACF;AAAA,MACA,OAAO,OAAO;AAAA,IAChB;AAAA,IACA;AAAA;AAAA,OAOI,UAAS,GAAkB;AAAA,IAC/B,OAAO,KAAK,MAAM,MAAM,KAAK,mBAAmB,CAAC;AAAA;AAAA,OAGrC,mBAAkB,GAAkB;AAAA,IAChD,MAAM,KAAK,KAAK;AAAA,IAChB,MAAM,GAAG,MAAM,gBAAgB,KAAK,QAAQ;AAAA,IAC5C,KAAK,OAAO,KAAK,UAAU;AAAA;AAAA,OAQvB,KAAI,GAAoB;AAAA,IAC5B,OAAO,KAAK,MAAM,MAAM,KAAK,cAAc,CAAC;AAAA;AAAA,OAGhC,cAAa,GAAoB;AAAA,IAC7C,MAAM,KAAK,KAAK;AAAA,IAChB,MAAM,SAAS,MAAM,GAAG,MAAM,yBAAyB,KAAK,QAAQ;AAAA,IACpE,OAAO,SAAS,OAAO,KAAK,GAAG,OAAO,EAAE;AAAA;AAAA,OAM3B,MAAK,CAAC,UAAoD;AAAA,IACvE,OAAO,KAAK,MAAM,MAAM,KAAK,eAAe,QAAQ,CAAC;AAAA;AAAA,OAGzC,eAAc,CAAC,UAAoD;AAAA,IAC/E,IAAI,CAAC,YAAY,OAAO,KAAK,QAAQ,EAAE,WAAW,GAAG;AAAA,MACnD,OAAO,MAAM,KAAK,cAAc;AAAA,IAClC;AAAA,IAEA,KAAK,oBAAoB,QAAQ;AAAA,IACjC,MAAM,KAAK,KAAK;AAAA,IAChB,QAAQ,aAAa,WAAW,KAAK,uBAAuB,QAAQ;AAAA,IACpE,MAAM,SAAS,MAAM,GAAG,MACtB,yBAAyB,KAAK,gBAAgB,eAC9C,MACF;AAAA,IACA,OAAO,SAAS,OAAO,KAAK,GAAG,OAAO,EAAE;AAAA;AAAA,OASpC,cAAa,CAAC,QAAgB,OAA8C;AAAA,IAChF,OAAO,KAAK,MAAM,MAAM,KAAK,uBAAuB,QAAQ,KAAK,CAAC;AAAA;AAAA,OAGtD,uBAAsB,CAAC,QAAgB,OAA8C;AAAA,IACjG,MAAM,KAAK,KAAK;AAAA,IAChB,MAAM,gBAAgB,KAAK,kBAAkB,EAC1C,IAAI,CAAC,QAAQ,IAAI,OAAO,GAAG,IAAI,EAC/B,KAAK,IAAI;AAAA,IACZ,MAAM,SAAS,MAAM,GAAG,MACtB,kBAAkB,KAAK,mBAAmB,oCAC1C,CAAC,OAAO,MAAM,CAChB;AAAA,IAEA,IAAI,CAAC,OAAO,QAAQ,OAAO,KAAK,WAAW,GAAG;AAAA,MAC5C;AAAA,IACF;AAAA,IAGA,WAAW,OAAO,OAAO,MAAM;AAAA,MAC7B,MAAM,SAAS;AAAA,MACf,WAAW,OAAO,KAAK,OAAO,YAAY;AAAA,QACxC,OAAO,OAAO,KAAK,aAAa,KAAK,OAAO,IAAuB;AAAA,MACrE;AAAA,IACF;AAAA,IAEA,OAAO,OAAO;AAAA;AAAA,EAQN,sBAAsB,CAAC,UAG/B;AAAA,IAKA,MAAM,QAAQ,iBACZ,iBACA,UACA,KAAK,OAAO,YACZ,CAAC,QAAQ,UAAU,KAAK,aAAa,QAAQ,KAAK,CACpD;AAAA,IACA,OAAO,EAAE,aAAa,MAAM,aAAa,QAAQ,MAAM,OAAO;AAAA;AAAA,OAgBjD,QAAO,CAAC,UAA+B,CAAC,GAA0B;AAAA,IAC/E,OAAO,KAAK,MAAM,MAAM,KAAK,iBAAiB,OAAO,CAAC;AAAA;AAAA,OAG1C,iBAAgB,CAAC,SAAqD;AAAA,IAClF,OAAO,KAAK,WAAW,WAAW,SAAS,KAAK,gBAAgB,CAAC;AAAA;AAAA,OAGpD,UAAS,CACtB,UACA,UAA+B,CAAC,GACT;AAAA,IACvB,OAAO,KAAK,MAAM,MAAM,KAAK,mBAAmB,UAAU,OAAO,CAAC;AAAA;AAAA,OAGtD,mBAAkB,CAC9B,UACA,SACuB;AAAA,IACvB,KAAK,oBAAoB,UAAU,SAAS;AAAA,IAC5C,OAAO,KAAK,WAAW,UAAU,SAAS,KAAK,gBAAgB,CAAC;AAAA;AAAA,EAG1D,eAAe,GAAG;AAAA,IACxB,OAAO;AAAA,MACL,OAAO;AAAA,MACP,aAAa,CAAC,UAAkB,IAAI;AAAA,MACpC,kBAAkB,CAAC,UAAkC,eACnD,KAAK,0BAA0B,UAAU,UAAU;AAAA,MACrD,eAAe,OAAO,KAAa,WAAiD;AAAA,QAClF,MAAM,SAAS,MAAM,KAAK,GAAG,MAAM,KAAK,MAAmB;AAAA,QAC3D,MAAM,OAAQ,OAAO,QAAQ,CAAC;AAAA,QAC9B,WAAW,OAAO,MAAM;AAAA,UACtB,MAAM,SAAS;AAAA,UACf,WAAW,KAAK,KAAK,OAAO,YAAY;AAAA,YACtC,OAAO,KAAK,KAAK,aAAa,GAAG,OAAO,EAAqB;AAAA,UAC/D;AAAA,QACF;AAAA,QACA,OAAO;AAAA;AAAA,IAEX;AAAA;AAAA,EAQM,yBAAyB,CAC/B,UACA,YACuE;AAAA,IACvE,MAAM,QAAQ,iBACZ,iBACA,UACA,KAAK,OAAO,YACZ,CAAC,QAAQ,UAAU,KAAK,aAAa,QAAQ,KAAK,GAClD,UACF;AAAA,IACA,OAAO;AAAA,MACL,aAAa,MAAM;AAAA,MACnB,QAAQ,MAAM;AAAA,MACd,WAAW,aAAa,MAAM,OAAO;AAAA,IACvC;AAAA;AAAA,OASI,aAAY,CAAC,UAAuD;AAAA,IACxE,OAAO,KAAK,MAAM,MAAM,KAAK,sBAAsB,QAAQ,CAAC;AAAA;AAAA,OAGhD,sBAAqB,CAAC,UAAuD;AAAA,IACzF,MAAM,eAAe,OAAO,KAAK,QAAQ;AAAA,IACzC,IAAI,aAAa,WAAW,GAAG;AAAA,MAC7B;AAAA,IACF;AAAA,IAEA,MAAM,KAAK,KAAK;AAAA,IAChB,QAAQ,aAAa,WAAW,KAAK,uBAAuB,QAAQ;AAAA,IACpE,MAAM,GAAG,MAAM,gBAAgB,KAAK,gBAAgB,eAAe,MAAM;AAAA,IACzE,KAAK,OAAO,KAAK,UAAU,aAAa,EAAkB;AAAA;AAAA,OAUtD,MAAK,CACT,UACA,SAC+B;AAAA,IAC/B,OAAO,KAAK,MAAM,MAAM,KAAK,eAAe,UAAU,OAAO,CAAC;AAAA;AAAA,OAGlD,eAAc,CAC1B,UACA,SAC+B;AAAA,IAC/B,KAAK,oBAAoB,UAAU,OAAO;AAAA,IAC1C,MAAM,KAAK,KAAK;AAAA,IAEhB,IAAI,MAAM,kBAAkB,KAAK;AAAA,IACjC,QAAQ,aAAa,WAAW,KAAK,uBAAuB,QAAQ;AAAA,IACpE,OAAO,UAAU;AAAA,IAEjB,IAAI,SAAS,WAAW,QAAQ,QAAQ,SAAS,GAAG;AAAA,MAClD,MAAM,eAAe,QAAQ,QAAQ,IAAI,CAAC,MAAM,IAAI,OAAO,EAAE,MAAM,MAAM,EAAE,WAAW;AAAA,MACtF,OAAO,aAAa,aAAa,KAAK,IAAI;AAAA,IAC5C;AAAA,IAEA,IAAI,SAAS,UAAU,WAAW;AAAA,MAChC,OAAO,WAAW,OAAO,SAAS;AAAA,MAClC,OAAO,KAAK,QAAQ,KAAK;AAAA,IAC3B;AAAA,IAEA,IAAI,SAAS,WAAW,WAAW;AAAA,MACjC,OAAO,YAAY,OAAO,SAAS;AAAA,MACnC,OAAO,KAAK,QAAQ,MAAM;AAAA,IAC5B;AAAA,IAEA,MAAM,SAAS,MAAM,GAAG,MAAM,KAAK,MAAM;AAAA,IAEzC,IAAI,OAAO,KAAK,SAAS,GAAG;AAAA,MAC1B,WAAW,OAAO,OAAO,MAAM;AAAA,QAC7B,MAAM,SAAS;AAAA,QACf,WAAW,KAAK,KAAK,OAAO,YAAY;AAAA,UACtC,OAAO,KAAK,KAAK,aAAa,GAAG,OAAO,EAAqB;AAAA,QAC/D;AAAA,MACF;AAAA,MACA,KAAK,OAAO,KAAK,SAAS,UAA6B,OAAO,IAAgB;AAAA,MAC9E,OAAO,OAAO;AAAA,IAChB;AAAA,IACA,KAAK,OAAO,KAAK,SAAS,UAA6B,SAAS;AAAA,IAChE;AAAA;AAAA,OAYa,WAA2C,CACxD,UACA,SAC4B;AAAA,IAC5B,OAAO,KAAK,MAAM,MAAM,KAAK,oBAAoB,UAAU,OAAO,CAAC;AAAA;AAAA,OAGvD,oBAAoD,CAChE,UACA,SAC4B;AAAA,IAC5B,KAAK,eAAe,OAAO;AAAA,IAC3B,KAAK,oBAAoB,UAAU,OAAO;AAAA,IAE1C,MAAM,aAAa,KAAK,QAAQ,IAAI,CAAC,OAAM,MAAM;AAAA,MAC/C,MAAM,KAAK,MAAM,QAAQ,KAAI,IAAK,QAAoB,CAAC,KAAc;AAAA,MACrE,OAAO,EAAE,MAAM,OAAO,KAAK,SAAS,GAAG;AAAA,KACxC;AAAA,IAED,kBAAkB;AAAA,MAChB,OAAO,KAAK;AAAA,MACZ,SAAS;AAAA,MACT,iBAAiB,OAAO,KAAK,QAAQ;AAAA,MACrC,iBAAiB,QAAQ,WAAW,CAAC,GAAG,IAAI,CAAC,OAAO;AAAA,QAClD,QAAQ,OAAO,EAAE,MAAM;AAAA,QACvB,WAAW,EAAE;AAAA,MACf,EAAE;AAAA,MACF,eAAe,QAAQ,OAAO,IAAI,MAAM;AAAA,MACxC,mBAAmB,KAAK,gBAAgB,IAAI,MAAM;AAAA,IACpD,CAAC;AAAA,IAED,MAAM,OAAO,QAAQ,OAAO,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,EAAE,KAAK,IAAI;AAAA,IAClE,IAAI,MAAM,UAAU,cAAc,KAAK;AAAA,IACvC,QAAQ,aAAa,WAAW,KAAK,uBAAuB,QAAQ;AAAA,IACpE,OAAO,UAAU;AAAA,IAEjB,IAAI,QAAQ,WAAW,QAAQ,QAAQ,SAAS,GAAG;AAAA,MACjD,OACE,eACA,QAAQ,QAAQ,IAAI,CAAC,MAAM,IAAI,OAAO,EAAE,MAAM,MAAM,EAAE,WAAW,EAAE,KAAK,IAAI;AAAA,IAChF;AAAA,IACA,IAAI,QAAQ,UAAU,WAAW;AAAA,MAC/B,OAAO,WAAW,OAAO,SAAS;AAAA,MAClC,OAAO,KAAK,QAAQ,KAAK;AAAA,IAC3B;AAAA,IACA,IAAI,QAAQ,WAAW,WAAW;AAAA,MAChC,OAAO,YAAY,OAAO,SAAS;AAAA,MACnC,OAAO,KAAK,QAAQ,MAAM;AAAA,IAC5B;AAAA,IAEA,MAAM,KAAK,KAAK;AAAA,IAChB,MAAM,SAAS,MAAM,GAAG,MAAM,KAAK,MAAM;AAAA,IACzC,WAAW,OAAO,OAAO,MAAM;AAAA,MAC7B,MAAM,SAAS;AAAA,MACf,WAAW,KAAK,OAAO,KAAK,MAAM,GAAG;AAAA,QACnC,OAAO,KAAK,KAAK,aAAa,GAAG,OAAO,EAAqB;AAAA,MAC/D;AAAA,IACF;AAAA,IACA,OAAO,OAAO;AAAA;AAAA,EASA,kBAAkB,CAChC,UACA,SACY;AAAA,IACZ,MAAM,IAAI,MAAM,gEAAgE;AAAA;AAAA,EAMlE,OAAO,GAAS;AAAA,IAC9B,MAAM,QAAQ;AAAA;AAElB;AAAA;AAEA,MAAM,4CAA4C,2BAA2B;AAAA,EAC9C;AAAA,EAA7B,WAAW,CAAkB,MAA4D;AAAA,IACvF,MAAM;AAAA,IADqB;AAAA;AAAA,EAGV,WAAW,GAA0B;AAAA,IACtD,OAAO;AAAA;AAAA,EAEU,KAAK,GAAW;AAAA,IACjC,OAAQ,KAAK,KAAsC;AAAA;AAAA,EAElC,OAAO,GAAsB;AAAA,IAC9C,OAAO,KAAK;AAAA;AAAA,EAEK,YAAY,CAAC,SAA6B;AAAA,IAC3D,OAAQ,KAAK,KAAgE,aAC3E,OACF;AAAA;AAAA,EAEiB,gBAAgB,CAAC,SAA8B;AAAA,IAChE,OAAQ,KAAK,KAA+D,WAAW,OAAO;AAAA;AAAA,OAEvE,WAAU,CAAC,KAA4B;AAAA,IAC9D,MAAO,KAAK,KAAyE,GAAG,MACtF,GACF;AAAA;AAAA,OAEuB,aAAY,CAAC,KAAa,IAAsC;AAAA,IACvF,MAAO,GAAoE,gBAAgB,GAAG;AAAA;AAAA,OAEvE,gBAAe,CACtC,WACA,SACA,aACA,IACe;AAAA,IACf,MACE,GAGA,uBAAuB,WAAW,SAAS,eAAe,IAAI;AAAA;AAAA,OAEzC,cAAa,CACpC,WACA,SACA,aACe;AAAA,IACf,MACE,KAAK,KAKL,GAAG,MACH,eAAe,yEACf,CAAC,WAAW,SAAS,eAAe,IAAI,CAC1C;AAAA;AAAA,OAEuB,qBAAoB,CAAC,WAAyC;AAAA,IACrF,MAAM,IAAI,MACR,KAAK,KAKL,GAAG,MAAM,uBAAuB,yCAAyC,CAAC,SAAS,CAAC;AAAA,IACtF,OAAO,IAAI,IAAI,EAAE,KAAK,IAAI,CAAC,QAAQ,OAAO,IAAI,OAAO,CAAC,CAAC;AAAA;AAAA,OAEhC,iBAAgB,GAAqB;AAAA,IAC5D,MAAM,IAAI,MACR,KAAK,KAKL,GAAG,MAAM,yEAAyE;AAAA,MACjF,KAAK,KAAsC;AAAA,IAC9C,CAAC;AAAA,IACD,OAAO,EAAE,KAAK,SAAS;AAAA;AAE3B;;;ADzpDA;AAAA;AAAA;AAAA;AAAA;AAOO,IAAM,yBAAyB,oBACpC,+BACF;AAAA;AAUO,MAAM,0BAA0B,oBAAoB;AAAA,EAUhD;AAAA,EACA;AAAA,EAVF;AAAA,EAQP,WAAW,CACF,IACA,QACP,YAAwB,EAAE,MAAM,SAAS,GACzC,cAA0B,CAAC,GAC3B;AAAA,IACA,MAAM,WAAW,WAAW;AAAA,IALrB;AAAA,IACA;AAAA,IAKP,KAAK,oBAAoB,IAAI,uBAC3B,IACA,QACA,uBACA,kBACF;AAAA;AAEJ;;AErCA;AAEA;AAAA,qBACE;AAAA;AAAA;AAAA;AAAA;AA4BF,IAAM,qBAAqB;AAAA;AAEpB,MAAM,8BAMH,uBAEV;AAAA,EACU;AAAA,EACS;AAAA,EACT;AAAA,EACA;AAAA,EACS;AAAA,EAiBjB,WAAW,CACT,IACA,OACA,QACA,iBACA,UAAmF,CAAC,GACpF,YACA,aAAoC,cACpC,eAAmC,CAAC,GACpC;AAAA,IACA,MAAM,IAAI,OAAO,QAAQ,iBAAiB,OAAO;AAAA,IAEjD,KAAK,mBAAmB;AAAA,IACxB,KAAK,aAAa;AAAA,IAClB,KAAK,eAAe;AAAA,IAGpB,MAAM,aAAa,kBAAkB,MAAM;AAAA,IAC3C,IAAI,CAAC,YAAY;AAAA,MACf,MAAM,IAAI,MAAM,mEAAmE;AAAA,IACrF;AAAA,IACA,KAAK,qBAAqB;AAAA,IAC1B,KAAK,uBAAuB,oBAAoB,MAAM;AAAA;AAAA,EAGxC,mBAAmB,GAAW;AAAA,IAC5C,OAAO,KAAK;AAAA;AAAA,EAIK,qBAAqB,GAAuB;AAAA,IAC7D,OAAO,KAAK;AAAA;AAAA,MAIF,QAAQ,GAAyB;AAAA,IAC3C,OAAO,KAAK,aAAa,YAAY;AAAA;AAAA,MAU3B,gBAAgB,GAAW;AAAA,IACrC,QAAQ,KAAK;AAAA,WACN;AAAA,QACH,OAAO;AAAA,WACJ;AAAA,QACH,OAAO;AAAA;AAAA,QAEP,OAAO;AAAA;AAAA;AAAA,EAYL,cAAc,CAAC,YAAoB,YAA4B;AAAA,IACrE,MAAM,KAAK,KAAK;AAAA,IAChB,QAAQ,KAAK;AAAA,WACN;AAAA,QACH,OAAO,kBAAkB,cAAc,MAAM;AAAA,WAC1C;AAAA,QACH,OAAO,YAAY,cAAc,MAAM;AAAA;AAAA,QAEvC,OAAO,SAAS,cAAc,MAAM;AAAA;AAAA;AAAA,EAenC,cAAc,GAA2C;AAAA,IAC9D,OAAO;AAAA,MACL,UAAU,KAAK,aAAa,MAAM;AAAA,MAClC,QAAQ,KAAK,aAAa,SAAS;AAAA,IACrC;AAAA;AAAA,OAGW,iBAAgB,CAC3B,OACA,UAAyC,CAAC,GACE;AAAA,IAC5C,QAAQ,OAAO,IAAI,QAAQ,iBAAiB,MAAM;AAAA,IAElD,IAAI;AAAA,MAEF,MAAM,cAAc,IAAI,MAAM,KAAK,KAAK,EAAE,KAAK,GAAG;AAAA,MAIlD,MAAM,eAAe,OAAO,KAAK,kBAAkB;AAAA,MACnD,MAAM,YAAY,iBAAgB,QAAQ,YAAY;AAAA,MACtD,MAAM,iBAAiB,KAAK,uBAAuB,OAAO,KAAK,oBAAoB,IAAI;AAAA,MACvF,MAAM,cAAc,iBAAiB,iBAAgB,QAAQ,cAAc,IAAI;AAAA,MAC/E,MAAM,SAAS,KAAK;AAAA,MACpB,MAAM,YAAY,KAAK,eAAe,WAAW,IAAI;AAAA,MAErD,IAAI,MAAM;AAAA;AAAA;AAAA,YAGJ;AAAA,gBACI,KAAK;AAAA;AAAA,MAGf,MAAM,SAAgB,CAAC,WAAW;AAAA,MAClC,IAAI,aAAa;AAAA,MAIjB,IAAI,WAAW;AAAA,MAEf,IAAI,UAAU,OAAO,KAAK,MAAM,EAAE,SAAS,KAAK,aAAa;AAAA,QAC3D,MAAM,aAAuB,CAAC;AAAA,QAC9B,YAAY,KAAK,UAAU,OAAO,QAAQ,MAAM,GAAG;AAAA,UACjD,IAAI,CAAC,mBAAmB,KAAK,GAAG,GAAG;AAAA,YACjC,MAAM,IAAI,uBACR,iCAAiC,mDACnC;AAAA,UACF;AAAA,UAIA,WAAW,KAAK,GAAG,kBAAkB,WAAW,YAAY;AAAA,UAC5D,OAAO,KAAK,OAAO,KAAK,CAAC;AAAA,UACzB;AAAA,QACF;AAAA,QACA,IAAI,WAAW,SAAS,GAAG;AAAA,UACzB,OAAO,UAAU,WAAW,KAAK,OAAO;AAAA,UACxC,WAAW;AAAA,QACb;AAAA,MACF;AAAA,MAKA,OAAO,WAAW,SAAS;AAAA,MAC3B,OAAO,IAAI,iBAAiB;AAAA,MAC5B,OAAO,KAAK,cAAc;AAAA,MAC1B;AAAA,MAIA,OAAO,aAAa,aAAa,4BAA4B;AAAA,MAC7D,OAAO,KAAK,IAAI;AAAA,MAEhB,MAAM,SAAS,MAAM,KAAK,GAAG,MAAM,KAAK,MAAM;AAAA,MAG9C,MAAM,UAA6C,CAAC;AAAA,MACpD,WAAW,OAAO,OAAO,MAAM;AAAA,QAC7B,MAAM,eAAe,MAAM,KAAK,GAAG,MACjC,UAAU,yBAAyB,KAAK,gBAAgB,KAAK,yBAAyB,KACtF,KAAK,oBAAoB,GAAG,CAC9B;AAAA,QACA,MAAM,YAAY,aAAa,KAAK,KAAK,iBAAiB;AAAA,QAC1D,MAAM,cAAc,KAAK,MAAM,SAAS;AAAA,QAExC,QAAQ,KAAK;AAAA,aACR;AAAA,WACF,KAAK,qBAAqB,IAAI,KAAK,WAAW,WAAW;AAAA,UAC1D,OAAO,WAAW,IAAI,KAAK;AAAA,QAC7B,CAA+B;AAAA,MACjC;AAAA,MAEA,OAAO;AAAA,MACP,OAAO,OAAO;AAAA,MACd,IAAI,iBAAiB,wBAAwB;AAAA,QAC3C,MAAM;AAAA,MACR;AAAA,MAEA,QAAQ,MAAM,4DAA4D,KAAK;AAAA,MAC/E,OAAO,KAAK,eAAe,OAAO,OAAO;AAAA;AAAA;AAAA,EAWrC,8BAA8B,GAAS;AAAA,IAC7C,IAAI,KAAK,aAAa,UAAU;AAAA,MAC9B,MAAM,IAAI,MACR,sEACE,wDAAwD,KAAK,iBAC7D,4DACJ;AAAA,IACF;AAAA;AAAA,OAOY,eAAc,CAAC,OAAmB,SAAwC;AAAA,IACtF,KAAK,+BAA+B;AAAA,IACpC,QAAQ,OAAO,IAAI,QAAQ,iBAAiB,MAAM;AAAA,IAClD,MAAM,UAAW,MAAM,KAAK,OAAO,KAAM,CAAC;AAAA,IAC1C,MAAM,UAA6C,CAAC;AAAA,IAEpD,WAAW,OAAO,SAAS;AAAA,MACzB,MAAM,SAAS,IAAI,KAAK;AAAA,MACxB,MAAM,WAAW,KAAK,uBACjB,IAAI,KAAK,wBACT,CAAC;AAAA,MAEN,IAAI,UAAU,CAAC,KAAK,cAAc,UAAU,MAAM,GAAG;AAAA,QACnD;AAAA,MACF;AAAA,MAEA,MAAM,QAAQ,iBAAiB,OAAO,MAAM;AAAA,MAE5C,IAAI,SAAS,gBAAgB;AAAA,QAC3B,QAAQ,KAAK,KAAK,KAAK,MAAM,CAA+B;AAAA,MAC9D;AAAA,IACF;AAAA,IAEA,QAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;AAAA,IACxC,MAAM,aAAa,QAAQ,MAAM,GAAG,IAAI;AAAA,IAExC,OAAO;AAAA;AAAA,EAGD,wBAAwB,GAAW;AAAA,IACzC,MAAM,aAAa,KAAK,gBAAgB,IAAI,CAAC,KAAK,QAAQ,GAAG,OAAO,GAAG,QAAQ,MAAM,GAAG;AAAA,IACxF,OAAO,WAAW,KAAK,OAAO;AAAA;AAAA,EAGxB,mBAAmB,CAAC,KAAiB;AAAA,IAC3C,OAAO,KAAK,gBAAgB,IAAI,CAAC,QAAQ,IAAI,IAAI;AAAA;AAAA,EAG3C,aAAa,CAAC,UAAoB,QAAoC;AAAA,IAC5E,YAAY,KAAK,UAAU,OAAO,QAAQ,MAAM,GAAG;AAAA,MACjD,IAAI,SAAS,SAA2B,OAAO;AAAA,QAC7C,OAAO;AAAA,MACT;AAAA,IACF;AAAA,IACA,OAAO;AAAA;AAEX;;ACzUA;AAAA,sBAIE;AAAA;AAAA;AAsCF,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,0CACvB,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,0EACf,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;",
12
+ "debugId": "31CB72E3014C272564756E2164756E21",
13
13
  "names": []
14
14
  }