@workglow/supabase 0.2.33 → 0.2.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/job-queue/browser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/job-queue/browser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,UAAU,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/job-queue/bun.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/job-queue/bun.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,UAAU,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/job-queue/common.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/job-queue/common.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,wBAAwB,CAAC;AACvC,cAAc,8BAA8B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/job-queue/node.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/job-queue/node.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,UAAU,CAAC"}
@@ -149,12 +149,14 @@ export declare class SupabaseTabularStorage<Schema extends DataPortSchemaObject,
149
149
  */
150
150
  size(): Promise<number>;
151
151
  /**
152
- * Fetches a page of records from the repository.
152
+ * Fetches a page of records from the repository using offset-based paging.
153
153
  * @param offset - Number of records to skip
154
154
  * @param limit - Maximum number of records to return
155
155
  * @returns Array of entities or undefined if no records found
156
+ * @deprecated Offset-based paging is unstable under concurrent writes.
157
+ * Use {@link getPage} for stable, keyset-based pagination.
156
158
  */
157
- getBulk(offset: number, limit: number): Promise<Entity[] | undefined>;
159
+ getOffsetPage(offset: number, limit: number): Promise<Entity[] | undefined>;
158
160
  /**
159
161
  * Applies criteria to a Supabase filter builder. Typed as `any` because the
160
162
  * `PostgrestFilterBuilder` generics are deep enough to trip TS2589.
@@ -1 +1 @@
1
- {"version":3,"file":"SupabaseTabularStorage.d.ts","sourceRoot":"","sources":["../../src/storage/SupabaseTabularStorage.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SupabaseTabularStorage.d.ts","sourceRoot":"","sources":["../../src/storage/SupabaseTabularStorage.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/storage/browser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/storage/browser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,UAAU,CAAC"}
@@ -395,7 +395,7 @@ class SupabaseTabularStorage extends BaseSqlTabularStorage {
395
395
  throw error;
396
396
  return count ?? 0;
397
397
  }
398
- async getBulk(offset, limit) {
398
+ async getOffsetPage(offset, limit) {
399
399
  let query = this.client.from(this.table).select("*");
400
400
  for (const pkName of this.primaryKeyNames) {
401
401
  query = query.order(String(pkName));
@@ -735,4 +735,4 @@ export {
735
735
  SUPABASE_KV_REPOSITORY
736
736
  };
737
737
 
738
- //# debugId=AAD23751886988C864756E2164756E21
738
+ //# debugId=A507CF4158D891DC64756E2164756E21
@@ -3,9 +3,9 @@
3
3
  "sources": ["../../src/storage/SupabaseKvStorage.ts", "../../src/storage/SupabaseTabularStorage.ts"],
4
4
  "sourcesContent": [
5
5
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken } from \"@workglow/util\";\nimport { JsonSchema } from \"@workglow/util/schema\";\nimport { SupabaseTabularStorage } from \"./SupabaseTabularStorage\";\nimport {\n DefaultKeyValueKey,\n DefaultKeyValueSchema,\n IKvStorage,\n KvViaTabularStorage,\n} from \"@workglow/storage\";\n\nexport const SUPABASE_KV_REPOSITORY = createServiceToken<IKvStorage<string, any, any>>(\n \"storage.kvRepository.supabase\"\n);\n\n/**\n * A key-value repository implementation that uses Supabase for persistent storage.\n * Leverages a tabular repository abstraction for Supabase operations.\n *\n * @template Key - The type of the primary key\n * @template Value - The type of the value being stored\n * @template Combined - Combined type of Key & Value\n */\nexport class SupabaseKvStorage extends KvViaTabularStorage {\n public tabularRepository: SupabaseTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >;\n\n /**\n * Creates a new SupabaseKvStorage instance\n *\n * @param client - Supabase client instance\n * @param tableName - Name of the table to store data\n * @param keySchema - Schema for the key type (defaults to string)\n * @param valueSchema - Schema for the value type (defaults to any)\n */\n constructor(\n public client: unknown,\n public tableName: string,\n keySchema: JsonSchema = { type: \"string\" },\n valueSchema: JsonSchema = {},\n tabularRepository?: SupabaseTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >\n ) {\n super(keySchema, valueSchema);\n this.tabularRepository =\n tabularRepository ??\n new SupabaseTabularStorage(client, tableName, DefaultKeyValueSchema, DefaultKeyValueKey);\n }\n}\n",
6
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { RealtimeChannel, SupabaseClient } from \"@supabase/supabase-js\";\nimport { createServiceToken, uuid4 } from \"@workglow/util\";\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport {\n BaseSqlTabularStorage,\n ClientProvidedKeysOption,\n AnyTabularStorage,\n AutoGeneratedKeys,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n Page,\n PageRequest,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularChangeType,\n TabularSubscribeOptions,\n ValueOptionType,\n pickCoveringIndex,\n StorageValidationError,\n assertCursorMatches,\n decodeCursor,\n} from \"@workglow/storage\";\n\n/**\n * Quotes a value for inclusion in a PostgREST filter expression.\n *\n * PostgREST treats commas, periods, parentheses, colons, double-quotes,\n * and whitespace as filter syntax delimiters; values containing any of\n * these need to be wrapped in double-quotes (with embedded `\"` and `\\`\n * escaped). ISO timestamps contain dots, so most non-trivial values need\n * quoting. We err on the side of quoting anything that isn't a clean\n * integer or boolean — false positives are cheap; false negatives produce\n * malformed filters that PostgREST silently mis-parses.\n */\nfunction escapePostgrest(value: string | number | boolean | null): string {\n if (value === null) return \"null\";\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\";\n if (typeof value === \"number\" && Number.isInteger(value)) return String(value);\n const s = String(value);\n return `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\nexport const SUPABASE_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.supabase\"\n);\n\n/**\n * A Supabase-based tabular repository implementation that extends BaseSqlTabularStorage.\n * This class provides persistent storage for data in a Supabase database,\n * making it suitable for multi-user scenarios.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class SupabaseTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseSqlTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n protected readonly client: SupabaseClient;\n private realtimeChannel: RealtimeChannel | null = null;\n\n /**\n * Creates a new SupabaseTabularStorage instance.\n *\n * @param client - Supabase client instance\n * @param table - Name of the table to store data (defaults to \"tabular_store\")\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n client: unknown,\n table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.client = client as SupabaseClient;\n }\n\n /**\n * Initializes the database table with the required schema.\n * Creates the table if it doesn't exist with primary key and value columns.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n const sql = `\n CREATE TABLE IF NOT EXISTS \"${this.table}\" (\n ${this.constructPrimaryKeyColumns('\"')} ${this.constructValueColumns('\"')},\n PRIMARY KEY (${this.primaryKeyColumnList()}) \n )\n `;\n const { error } = await this.client.rpc(\"exec_sql\", { query: sql });\n if (error && !error.message.includes(\"already exists\")) {\n throw error;\n }\n\n // Get primary key columns to avoid creating redundant indexes\n const pkColumns = this.primaryKeyColumns();\n\n // Track created indexes to avoid duplicates and redundant indexes\n const createdIndexes = new Set<string>();\n\n for (const columns of this.indexes) {\n // Skip if this is just the primary key or a prefix of it\n if (columns.length <= pkColumns.length) {\n // @ts-ignore\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n\n // Create index name and column list\n const indexName = `${this.table}_${columns.join(\"_\")}`;\n const columnList = columns.map((col) => `\"${String(col)}\"`).join(\", \");\n\n // Skip if we've already created this index or if it's redundant\n const columnKey = columns.join(\",\");\n if (createdIndexes.has(columnKey)) continue;\n\n // Check if this index would be redundant with an existing one\n const isRedundant = Array.from(createdIndexes).some((existing) => {\n const existingCols = existing.split(\",\");\n return (\n existingCols.length >= columns.length &&\n columns.every((col, idx) => col === existingCols[idx])\n );\n });\n\n if (!isRedundant) {\n const indexSql = `CREATE INDEX IF NOT EXISTS \"${indexName}\" ON \"${this.table}\" (${columnList})`;\n const { error: indexError } = await this.client.rpc(\"exec_sql\", { query: indexSql });\n if (indexError && !indexError.message.includes(\"already exists\")) {\n // Index creation errors are not critical, log and continue\n console.warn(`Failed to create index ${indexName}:`, indexError);\n }\n createdIndexes.add(columnKey);\n }\n }\n }\n\n /**\n * Maps TypeScript/JavaScript types to corresponding PostgreSQL data types.\n * Uses additional schema information like minimum/maximum values, nullable status,\n * and string lengths to create more optimized column types.\n *\n * @param typeDef - The TypeScript/JavaScript type to map\n * @returns The corresponding PostgreSQL data type\n */\n protected override mapTypeToSQL(typeDef: JsonSchema): string {\n // Extract the actual non-null type using base helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return \"TEXT /* boolean schema */\";\n }\n\n // Handle BLOB type\n if (actualType.contentEncoding === \"blob\") return \"BYTEA\";\n\n switch (actualType.type) {\n case \"string\":\n // Handle special string formats\n if (actualType.format === \"date-time\") return \"TIMESTAMP\";\n if (actualType.format === \"date\") return \"DATE\";\n if (actualType.format === \"email\") return \"VARCHAR(255)\";\n if (actualType.format === \"uri\") return \"VARCHAR(2048)\";\n if (actualType.format === \"uuid\") return \"UUID\";\n\n // Use a VARCHAR with maxLength if specified\n if (typeof actualType.maxLength === \"number\") {\n return `VARCHAR(${actualType.maxLength})`;\n }\n\n // Default to TEXT for strings without constraints\n return \"TEXT\";\n\n case \"number\":\n case \"integer\":\n // Handle integer vs floating point\n if (actualType.multipleOf === 1 || actualType.type === \"integer\") {\n // Use PostgreSQL's numeric range types based on min/max values\n if (typeof actualType.minimum === \"number\") {\n if (actualType.minimum >= 0) {\n // For unsigned integers\n if (typeof actualType.maximum === \"number\") {\n if (actualType.maximum <= 32767) return \"SMALLINT\";\n if (actualType.maximum <= 2147483647) return \"INTEGER\";\n }\n return \"BIGINT\";\n }\n }\n\n // Default integer type\n return \"INTEGER\";\n }\n\n // For floating point numbers with precision requirements\n if (actualType.format === \"float\") return \"REAL\";\n if (actualType.format === \"double\") return \"DOUBLE PRECISION\";\n\n // Use NUMERIC with precision/scale if specified\n if (typeof actualType.multipleOf === \"number\") {\n const decimalPlaces = String(actualType.multipleOf).split(\".\")[1]?.length || 0;\n if (decimalPlaces > 0) {\n return `NUMERIC(38, ${decimalPlaces})`;\n }\n }\n\n return \"NUMERIC\";\n\n case \"boolean\":\n return \"BOOLEAN\";\n\n case \"array\":\n // Handle array types (if items type is specified)\n if (\n actualType.items &&\n typeof actualType.items === \"object\" &&\n !Array.isArray(actualType.items)\n ) {\n const itemType = this.mapTypeToSQL(actualType.items as JsonSchema);\n\n // Only use native PostgreSQL arrays for simple scalar types\n // List of types that work well as native PostgreSQL arrays\n const supportedArrayElementTypes = [\n \"TEXT\",\n \"VARCHAR\",\n \"CHAR\",\n \"INTEGER\",\n \"SMALLINT\",\n \"BIGINT\",\n \"REAL\",\n \"DOUBLE PRECISION\",\n \"NUMERIC\",\n \"BOOLEAN\",\n \"UUID\",\n \"DATE\",\n \"TIMESTAMP\",\n ];\n\n // Check if the item type is in our supported list (either exact match or starts with for VARCHAR types)\n const isSupported = supportedArrayElementTypes.some(\n (type) => itemType === type || (itemType.startsWith(type + \"(\") && type !== \"VARCHAR\") // Handle things like VARCHAR(255)\n );\n\n if (isSupported) {\n return `${itemType}[]`;\n } else {\n return \"JSONB /* complex array */\";\n }\n }\n return \"JSONB /* generic array */\";\n\n case \"object\":\n return \"JSONB /* object */\";\n\n default:\n return \"TEXT /* unknown type */\";\n }\n }\n\n /**\n * Generates the SQL column definitions for primary key fields with constraints\n * Handles auto-generated keys using SERIAL for integers and UUID DEFAULT for strings\n * @returns SQL string containing primary key column definitions\n */\n protected override constructPrimaryKeyColumns($delimiter: string = \"\"): string {\n const cols = Object.entries<JsonSchema>(this.primaryKeySchema.properties)\n .map(([key, typeDef]) => {\n // Check if this is an auto-generated key\n if (this.isAutoGeneratedKey(key)) {\n if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // Use SERIAL or BIGSERIAL for auto-increment\n const sqlType = this.mapTypeToSQL(typeDef);\n const isSmallInt = sqlType.includes(\"SMALLINT\");\n const isBigInt = sqlType.includes(\"BIGINT\");\n const serialType = isBigInt ? \"BIGSERIAL\" : isSmallInt ? \"SMALLSERIAL\" : \"SERIAL\";\n return `${$delimiter}${key}${$delimiter} ${serialType}`;\n } else if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // Use UUID with DEFAULT gen_random_uuid()\n return `${$delimiter}${key}${$delimiter} UUID DEFAULT gen_random_uuid()`;\n }\n }\n\n const sqlType = this.mapTypeToSQL(typeDef);\n let constraints = \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${$delimiter}${key}${$delimiter} >= 0)`;\n }\n\n return `${$delimiter}${key}${$delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n return cols;\n }\n\n /**\n * Generates the SQL column definitions for value fields with constraints\n * @returns SQL string containing value column definitions\n */\n protected override constructValueColumns($delimiter: string = \"\"): string {\n const delimiter = $delimiter || '\"';\n const requiredSet = new Set(this.valueSchema.required ?? []);\n const cols = Object.entries<JsonSchema>(this.valueSchema.properties)\n .map(([key, typeDef]) => {\n const sqlType = this.mapTypeToSQL(typeDef);\n const isRequired = requiredSet.has(key);\n const nullable = !isRequired || this.isNullable(typeDef);\n let constraints = nullable ? \"NULL\" : \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${delimiter}${key}${delimiter} >= 0)`;\n }\n\n return `${delimiter}${key}${delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n if (cols.length > 0) {\n return `, ${cols}`;\n } else {\n return \"\";\n }\n }\n\n /**\n * Convert Supabase values to JS values. Ensures numeric strings become numbers where schema says number.\n */\n protected override sqlToJsValue(column: string, value: ValueOptionType): Entity[keyof Entity] {\n const typeDef = this.schema.properties[column as keyof typeof this.schema.properties] as\n | JsonSchema\n | undefined;\n if (typeDef) {\n if (value === null && this.isNullable(typeDef)) {\n return null as Entity[keyof Entity];\n }\n const actualType = this.getNonNullType(typeDef);\n\n // Handle numeric types - Supabase can return them as strings\n if (\n typeof actualType !== \"boolean\" &&\n (actualType.type === \"number\" || actualType.type === \"integer\")\n ) {\n if (typeof value === \"number\") return value as Entity[keyof Entity];\n if (typeof value === \"string\") {\n const parsed = Number(value);\n if (!isNaN(parsed)) return parsed as Entity[keyof Entity];\n }\n }\n }\n return super.sqlToJsValue(column, value);\n }\n\n /**\n * Determines if a field should be treated as unsigned based on schema properties\n * @param typeDef - The schema type definition\n * @returns true if the field should be treated as unsigned\n */\n protected shouldBeUnsigned(typeDef: JsonSchema): boolean {\n // Extract the non-null type using the base class helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return false;\n }\n\n // Check if it's a number type with minimum >= 0\n if (\n (actualType.type === \"number\" || actualType.type === \"integer\") &&\n typeof actualType.minimum === \"number\" &&\n actualType.minimum >= 0\n ) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Stores or updates a row in the database.\n * Uses UPSERT (INSERT ... ON CONFLICT DO UPDATE) for atomic operations.\n *\n * @param entity - The entity to store (may be missing auto-generated keys)\n * @returns The entity with any server-generated fields updated\n * @emits \"put\" event with the updated entity when successful\n */\n /**\n * Apply the auto-generated-key policy and the optional-field-to-null\n * normalization that Supabase's REST upsert expects. Shared by {@link put}\n * and {@link putBulk} so a row goes over the wire identically regardless of\n * whether it was inserted alone or as part of a batch.\n *\n * For UUID-strategy auto-gen keys we generate the UUID client-side rather\n * than letting `gen_random_uuid()` fill it server-side. Otherwise the input\n * row has no primary key, and {@link putBulk}'s ordering-preservation step\n * (re-keying the response by PK) cannot work — `result[i]` would no longer\n * be guaranteed to correspond to `values[i]`. SQLite's UUID path uses the\n * same trick.\n */\n private normalizeForUpsert(entity: InsertType): Record<string, unknown> {\n const entityToInsert = { ...entity } as Record<string, unknown>;\n\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const clientProvidedValue = entityToInsert[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldFillKey = false;\n if (this.clientProvidedKeys === \"never\") {\n shouldFillKey = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldFillKey = false;\n } else {\n shouldFillKey = !hasClientValue;\n }\n\n if (shouldFillKey) {\n if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // Generate client-side so the input carries a PK and the bulk\n // response can be re-aligned to input order.\n entityToInsert[keyName] = uuid4();\n } else {\n // Autoincrement integer keys cannot be generated client-side; let\n // Postgres fill via SERIAL. putBulk falls back to response order in\n // this case (and Postgres preserves INSERT ... RETURNING order in\n // practice).\n delete entityToInsert[keyName];\n }\n }\n }\n\n // Normalize optional fields: convert undefined to null for optional fields\n const requiredSet = new Set(this.valueSchema.required ?? []);\n for (const key in this.valueSchema.properties) {\n if (!(key in entityToInsert) || entityToInsert[key] === undefined) {\n if (!requiredSet.has(key)) {\n entityToInsert[key] = null;\n }\n }\n }\n\n return entityToInsert;\n }\n\n /** Hydrate a row returned by Supabase 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 async put(entity: InsertType): Promise<Entity> {\n const normalizedEntity = this.normalizeForUpsert(entity);\n const { data, error } = await this.client\n .from(this.table)\n .upsert(normalizedEntity, { onConflict: this.primaryKeyColumnList() })\n .select()\n .single();\n\n if (error) throw error;\n const updatedEntity = this.hydrateRow(data);\n\n this.events.emit(\"put\", updatedEntity);\n return updatedEntity;\n }\n\n /**\n * Stores multiple rows by issuing a single PostgREST `upsert` carrying every\n * row in one request. PostgREST runs the underlying `INSERT ... ON CONFLICT`\n * inside one server-side transaction, so this is both atomic and a single\n * round trip — far cheaper than `Promise.all` fanning out one HTTPS request\n * per row.\n *\n * **Ordering:** {@link normalizeForUpsert} fills UUID auto-gen keys\n * client-side, so for the common UUID case every input row carries a PK\n * and the response is re-aligned to input order by primary-key match. The\n * only remaining case where ordering relies on Postgres's `INSERT ...\n * RETURNING` row order (stable in practice but not formally contracted) is\n * autoincrement-integer auto-gen keys, where the database has to assign\n * the key.\n *\n * `put` events are deferred until after the upsert resolves so listeners do\n * not see rows from a request that ultimately failed.\n */\n async putBulk(entities: InsertType[]): Promise<Entity[]> {\n if (entities.length === 0) return [];\n\n const normalizedEntities = entities.map((entity) => this.normalizeForUpsert(entity));\n const { data, error } = await this.client\n .from(this.table)\n .upsert(normalizedEntities, { onConflict: this.primaryKeyColumnList() })\n .select();\n\n if (error) throw error;\n if (!data) return [];\n\n const returnedRows = (data as unknown[]).map((row) => this.hydrateRow(row));\n\n // Reorder by primary key when every input row carries its full PK. With an\n // auto-generated key omitted from the input, we have no key to match on,\n // so trust the response order (Postgres's INSERT ... RETURNING preserves\n // VALUES order in practice).\n const orderedEntities = this.alignBulkResponseToInputOrder(normalizedEntities, returnedRows);\n\n for (const entity of orderedEntities) {\n this.events.emit(\"put\", entity);\n }\n return orderedEntities;\n }\n\n /**\n * If every input row supplies its full primary key, build a PK index over\n * the response and emit rows in input order. Otherwise return the response\n * as-is — there is no key to match on, so we have to trust the backend.\n */\n private alignBulkResponseToInputOrder(\n inputs: ReadonlyArray<Record<string, unknown>>,\n responseRows: Entity[]\n ): Entity[] {\n if (inputs.length !== responseRows.length) {\n // Server returned a different cardinality (e.g. dedup); fall back to as-is.\n return responseRows;\n }\n const pkColumns = this.primaryKeyColumns().map(String);\n for (const input of inputs) {\n for (const col of pkColumns) {\n if (input[col] === undefined || input[col] === null) {\n return responseRows;\n }\n }\n }\n\n const fingerprint = (row: Record<string, unknown>): string =>\n pkColumns.map((c) => String(row[c])).join(\"\u0000\");\n\n const responseByPk = new Map<string, Entity>();\n for (const row of responseRows) {\n responseByPk.set(fingerprint(row as unknown as Record<string, unknown>), row);\n }\n\n const ordered: Entity[] = [];\n for (const input of inputs) {\n const match = responseByPk.get(fingerprint(input));\n if (!match) return responseRows; // unexpected; fall back\n ordered.push(match);\n }\n return ordered;\n }\n\n /**\n * Retrieves a value from the database by its primary key.\n *\n * @param key - The primary key object to look up\n * @returns The stored entity or undefined if not found\n * @emits \"get\" event with the key when successful\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n let query = this.client.from(this.table).select(\"*\");\n\n // Build the where clause from primary key\n const keyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), keyRecord[String(pkName)]);\n }\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n // Not found\n this.events.emit(\"get\", key, undefined);\n return undefined;\n }\n throw error;\n }\n\n const val = data as Entity | undefined;\n if (val) {\n // Convert all columns from SQL to JS values\n const valRecord = val as Record<string, unknown>;\n for (const key in this.schema.properties) {\n valRecord[key] = this.sqlToJsValue(key, valRecord[key] as ValueOptionType);\n }\n }\n this.events.emit(\"get\", key, val);\n return val;\n }\n\n /**\n * Deletes a row from the database.\n *\n * @param value - The primary key object or entity to delete\n * @emits \"delete\" event with the key when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n\n let query = this.client.from(this.table).delete();\n\n // Build the where clause from primary key\n const deleteKeyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), deleteKeyRecord[String(pkName)]);\n }\n\n const { error } = await query;\n\n if (error) throw error;\n this.events.emit(\"delete\", key as keyof Entity);\n }\n\n /**\n * Retrieves all entries from the database table, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Promise resolving to an array of entries or undefined if not found\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n let query = this.client.from(this.table).select(\"*\");\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length) {\n // Convert all columns from SQL to JS values\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n return data as Entity[];\n }\n return undefined;\n }\n\n /**\n * Deletes all rows from the database table.\n * @emits \"clearall\" event when successful\n */\n async deleteAll(): Promise<void> {\n // Use the first primary key column for the delete condition\n const firstPkColumn = this.primaryKeyNames[0];\n const { error } = await this.client.from(this.table).delete().neq(String(firstPkColumn), null); // Delete all rows by using a condition that's always true\n\n if (error) throw error;\n this.events.emit(\"clearall\");\n }\n\n /**\n * Returns the total number of rows in the database.\n *\n * @returns Promise resolving to the count of stored items\n */\n async size(): Promise<number> {\n const { count, error } = await this.client\n .from(this.table)\n .select(\"*\", { count: \"exact\", head: true });\n\n if (error) throw error;\n return count ?? 0;\n }\n\n /**\n * Fetches a page of records from the repository.\n * @param offset - Number of records to skip\n * @param limit - Maximum number of records to return\n * @returns Array of entities or undefined if no records found\n */\n async getBulk(offset: number, limit: number): Promise<Entity[] | undefined> {\n // Build the base query\n let query = this.client.from(this.table).select(\"*\");\n\n // Ensure deterministic ordering for pagination by ordering on primary key column(s)\n for (const pkName of this.primaryKeyNames) {\n query = query.order(String(pkName));\n }\n\n const { data, error } = await query.range(offset, offset + limit - 1);\n\n if (error) throw error;\n\n if (!data || data.length === 0) {\n return undefined;\n }\n\n // Convert all columns from SQL to JS values (consistent with getAll)\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n\n return data as Entity[];\n }\n\n /**\n * Applies criteria to a Supabase filter builder. Typed as `any` because the\n * `PostgrestFilterBuilder` generics are deep enough to trip TS2589.\n */\n private applyCriteriaToFilter<Q>(query: Q, criteria: SearchCriteria<Entity>): Q {\n let q = query as any;\n for (const column of Object.keys(criteria) as Array<keyof Entity>) {\n const criterion = criteria[column];\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n switch (operator) {\n case \"=\":\n q = q.eq(String(column), value);\n break;\n case \"<\":\n q = q.lt(String(column), value);\n break;\n case \"<=\":\n q = q.lte(String(column), value);\n break;\n case \">\":\n q = q.gt(String(column), value);\n break;\n case \">=\":\n q = q.gte(String(column), value);\n break;\n }\n }\n return q as Q;\n }\n\n /**\n * Counts rows matching the specified search criteria.\n */\n override async count(criteria?: SearchCriteria<Entity>): Promise<number> {\n if (!criteria || Object.keys(criteria).length === 0) {\n return await this.size();\n }\n\n this.validateQueryParams(criteria);\n const query = this.applyCriteriaToFilter(\n this.client.from(this.table).select(\"*\", { count: \"exact\", head: true }),\n criteria\n );\n\n const { count, error } = await query;\n if (error) throw error;\n return count ?? 0;\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Supports multiple columns with optional comparison operators.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n */\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaKeys.length === 0) {\n return;\n }\n\n let query = this.client.from(this.table).delete();\n\n for (const column of criteriaKeys) {\n if (!(column in this.schema.properties)) {\n throw new Error(`Schema must have a ${String(column)} field to use deleteSearch`);\n }\n\n const criterion = criteria[column];\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n switch (operator) {\n case \"=\":\n query = query.eq(String(column), value);\n break;\n case \"<\":\n query = query.lt(String(column), value);\n break;\n case \"<=\":\n query = query.lte(String(column), value);\n break;\n case \">\":\n query = query.gt(String(column), value);\n break;\n case \">=\":\n query = query.gte(String(column), value);\n break;\n }\n }\n\n const { error } = await query;\n\n if (error) throw error;\n this.events.emit(\"delete\", criteriaKeys[0] as keyof Entity);\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering, limit, and offset.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of matching entities or undefined if no matches found\n */\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n this.validateQueryParams(criteria, options);\n\n let query = this.applyCriteriaToFilter(this.client.from(this.table).select(\"*\"), criteria);\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n } else if (options?.limit !== undefined) {\n query = query.limit(options.limit);\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length > 0) {\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, data as Entity[]);\n return data as Entity[];\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n\n /**\n * Cursor-paginated read pushed into PostgREST. Builds a keyset OR-of-AND\n * filter via Supabase's `.or()` plus per-column `.order()` with explicit\n * `nullsFirst` so iteration semantics match the rest of the package\n * (NULLs sort before non-null for ASC, after for DESC). The pushdown\n * makes memory and wire traffic O(pageSize) regardless of table size,\n * unlike the in-memory base-class fallback which would full-table-scan.\n */\n override async getPage(request: PageRequest<Entity> = {}): Promise<Page<Entity>> {\n return this.runSupabasePage(undefined, request);\n }\n\n override async queryPage(\n criteria: SearchCriteria<Entity>,\n request: PageRequest<Entity> = {}\n ): Promise<Page<Entity>> {\n this.validateQueryParams(criteria, undefined);\n return this.runSupabasePage(criteria, request);\n }\n\n private async runSupabasePage(\n criteria: SearchCriteria<Entity> | undefined,\n request: PageRequest<Entity>\n ): Promise<Page<Entity>> {\n // Validate before we send column names through PostgREST filters or\n // ORDER BY — caller is the trust boundary for orderBy contents.\n this.validatePageRequest(request);\n const limit = request.limit ?? 100;\n const pkColumns = this.primaryKeyColumns() as unknown as Array<keyof Entity>;\n const orderBy = request.orderBy;\n const effectiveOrderBy = this.buildEffectiveOrderBy(orderBy, pkColumns);\n const effectiveOrderForCursor = effectiveOrderBy.map((o) => ({\n column: String(o.column),\n direction: o.direction,\n }));\n\n let cursorPayload;\n if (request.cursor !== undefined) {\n cursorPayload = decodeCursor(request.cursor);\n assertCursorMatches(cursorPayload, effectiveOrderForCursor);\n }\n\n let query: any = this.client.from(this.table).select(\"*\");\n if (criteria && Object.keys(criteria).length > 0) {\n query = this.applyCriteriaToFilter(query, criteria);\n }\n\n if (cursorPayload) {\n const filter = this.buildSupabaseKeysetFilter(effectiveOrderBy, cursorPayload.c);\n // `null` is the keyset builder's signal for \"no rows possible\" — e.g.\n // a DESC cursor parked on a NULL leading column; nothing comes after\n // a NULLs-last trailer. Short-circuit instead of issuing the query.\n if (filter === null) {\n return { items: [], nextCursor: undefined };\n }\n query = query.or(filter);\n }\n\n for (const { column, direction } of effectiveOrderBy) {\n query = query.order(String(column), {\n ascending: direction === \"ASC\",\n nullsFirst: direction === \"ASC\",\n });\n }\n query = query.limit(limit);\n\n const { data, error } = await query;\n if (error) throw error;\n\n const items = (data ?? []) as Entity[];\n for (const row of items) {\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\n const nextCursor =\n items.length === limit\n ? this.buildCursor(items[items.length - 1], effectiveOrderBy)\n : undefined;\n return { items, nextCursor };\n }\n\n /**\n * Builds a PostgREST OR-of-AND filter string for keyset pagination.\n * See {@link BaseSqlTabularStorage.buildKeysetWhere} for the canonical\n * description of the OR-of-AND form and NULL semantics; this is the\n * same logic translated to PostgREST's filter grammar.\n *\n * Returns `null` when *every* OR-clause is unreachable, which means the\n * caller can skip the round-trip — the page is unconditionally empty.\n * The common trigger is a single-column DESC orderBy parked on a NULL\n * cursor (no row comes after a NULLs-last trailer); compound orderings\n * with later tiebreaker columns will still produce reachable clauses\n * even when the leading cursor value is NULL.\n */\n private buildSupabaseKeysetFilter(\n orderBy: ReadonlyArray<{ column: keyof Entity; direction: \"ASC\" | \"DESC\" }>,\n cursorValues: ReadonlyArray<string | number | boolean | null>\n ): string | null {\n const orClauses: string[] = [];\n for (let i = 0; i < orderBy.length; i++) {\n const andParts: string[] = [];\n // Equality on preceding columns; collapse to `is.null` for null cursors\n // because PostgREST `eq.null` doesn't exist (and SQL semantics agree\n // that `col = NULL` is never true).\n for (let j = 0; j < i; j++) {\n const col = String(orderBy[j].column);\n const v = cursorValues[j];\n andParts.push(v === null ? `${col}.is.null` : `${col}.eq.${escapePostgrest(v)}`);\n }\n const col = String(orderBy[i].column);\n const v = cursorValues[i];\n const dir = orderBy[i].direction;\n let cmp: string;\n if (v === null) {\n if (dir === \"ASC\") {\n // ASC NULLS-FIRST: rows strictly after NULL on this column are\n // any non-null value.\n cmp = `${col}.not.is.null`;\n } else {\n // DESC NULLS-LAST: nothing comes strictly after a NULL on this\n // column. The i-th OR-clause contributes no rows — drop it. We\n // can't `return null`, because subsequent clauses (i+1, i+2, …)\n // can still produce matches via equality on the NULL preceding\n // columns plus a tiebreaker on a later column. Mirrors the\n // `1 = 0` predicate in `BaseSqlTabularStorage.buildKeysetWhere`.\n continue;\n }\n } else {\n if (dir === \"ASC\") {\n cmp = `${col}.gt.${escapePostgrest(v)}`;\n } else {\n // Smaller than the cursor, then NULLs-last trailer.\n cmp = `or(${col}.lt.${escapePostgrest(v)},${col}.is.null)`;\n }\n }\n andParts.push(cmp);\n orClauses.push(andParts.length === 1 ? andParts[0] : `and(${andParts.join(\",\")})`);\n }\n if (orClauses.length === 0) return null;\n return orClauses.join(\",\");\n }\n\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n this.validateSelect(options);\n this.validateQueryParams(criteria, options);\n\n const registered = this.indexes.map((cols, i) => {\n const cs = Array.isArray(cols) ? (cols as string[]) : [cols as string];\n return { name: `idx_${i}`, keyPath: cs };\n });\n\n pickCoveringIndex({\n table: this.table,\n indexes: registered,\n criteriaColumns: Object.keys(criteria),\n orderByColumns: (options.orderBy ?? []).map((o) => ({\n column: String(o.column),\n direction: o.direction,\n })),\n selectColumns: options.select.map(String),\n primaryKeyColumns: this.primaryKeyNames.map(String),\n });\n\n const colList = options.select.map(String).join(\",\");\n let q = this.applyCriteriaToFilter(this.client.from(this.table).select(colList), criteria);\n\n if (options.orderBy) {\n for (const { column, direction } of options.orderBy) {\n q = q.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n if (options.offset !== undefined && options.limit === undefined) {\n throw new StorageValidationError(\"queryIndex with offset requires limit (no implicit cap)\");\n }\n if (options.offset !== undefined || options.limit !== undefined) {\n const start = options.offset ?? 0;\n if (options.limit !== undefined) {\n q = q.range(start, start + options.limit - 1);\n }\n }\n\n const { data, error } = await q;\n if (error) throw error;\n if (!data) return [];\n\n const rows = data as unknown as Record<string, unknown>[];\n const sel = new Set(options.select.map(String));\n for (const row of rows) {\n for (const key of Object.keys(row)) {\n if (sel.has(key)) {\n row[key] = this.sqlToJsValue(key, row[key] as ValueOptionType);\n }\n }\n }\n return rows as unknown as Pick<Entity, K>[];\n }\n\n /**\n * Converts a row from Supabase realtime payload to an Entity with proper type conversions.\n *\n * @param row - The raw row data from Supabase realtime\n * @returns The converted entity\n */\n private convertRealtimeRow(row: Record<string, unknown>): Entity {\n const entity = { ...row } as Entity;\n const record = entity as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, row[key] as ValueOptionType);\n }\n return entity;\n }\n\n /**\n * Subscribes to changes in the repository using Supabase realtime.\n * Receives notifications for INSERT, UPDATE, and DELETE operations from any source.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (not used for Supabase realtime)\n * @returns Unsubscribe function\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Create a unique channel name\n const channelName = `tabular-${this.table}-${Date.now()}`;\n\n this.realtimeChannel = this.client\n .channel(channelName)\n .on(\n \"postgres_changes\",\n {\n event: \"*\",\n schema: \"public\",\n table: this.table,\n },\n (payload) => {\n const change: TabularChangePayload<Entity> = {\n type: payload.eventType.toUpperCase() as TabularChangeType,\n old:\n payload.old && Object.keys(payload.old).length > 0\n ? this.convertRealtimeRow(payload.old)\n : undefined,\n new:\n payload.new && Object.keys(payload.new).length > 0\n ? this.convertRealtimeRow(payload.new)\n : undefined,\n };\n callback(change);\n }\n )\n .subscribe();\n\n return () => {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n };\n }\n\n /**\n * **Best-effort, non-atomic.** Supabase exposes PostgREST, not a session-\n * level transaction surface this client can drive — there is no\n * `BEGIN`/`COMMIT`/`ROLLBACK` over the wire. The override exists only to\n * make the no-rollback semantics explicit instead of inheriting the base\n * default silently: `fn` runs to completion against `this`, the result\n * propagates, and any partial writes survive a thrown `fn`. Use a\n * stored-procedure / RPC if you need true atomicity on Supabase.\n */\n public override async withTransaction<T>(fn: (tx: this) => Promise<T>): Promise<T> {\n return fn(this);\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n public override destroy(): void {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n }\n}\n"
6
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { RealtimeChannel, SupabaseClient } from \"@supabase/supabase-js\";\nimport { createServiceToken, uuid4 } from \"@workglow/util\";\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport {\n BaseSqlTabularStorage,\n ClientProvidedKeysOption,\n AnyTabularStorage,\n AutoGeneratedKeys,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n Page,\n PageRequest,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularChangeType,\n TabularSubscribeOptions,\n ValueOptionType,\n pickCoveringIndex,\n StorageValidationError,\n assertCursorMatches,\n decodeCursor,\n} from \"@workglow/storage\";\n\n/**\n * Quotes a value for inclusion in a PostgREST filter expression.\n *\n * PostgREST treats commas, periods, parentheses, colons, double-quotes,\n * and whitespace as filter syntax delimiters; values containing any of\n * these need to be wrapped in double-quotes (with embedded `\"` and `\\`\n * escaped). ISO timestamps contain dots, so most non-trivial values need\n * quoting. We err on the side of quoting anything that isn't a clean\n * integer or boolean — false positives are cheap; false negatives produce\n * malformed filters that PostgREST silently mis-parses.\n */\nfunction escapePostgrest(value: string | number | boolean | null): string {\n if (value === null) return \"null\";\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\";\n if (typeof value === \"number\" && Number.isInteger(value)) return String(value);\n const s = String(value);\n return `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\nexport const SUPABASE_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.supabase\"\n);\n\n/**\n * A Supabase-based tabular repository implementation that extends BaseSqlTabularStorage.\n * This class provides persistent storage for data in a Supabase database,\n * making it suitable for multi-user scenarios.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class SupabaseTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseSqlTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n protected readonly client: SupabaseClient;\n private realtimeChannel: RealtimeChannel | null = null;\n\n /**\n * Creates a new SupabaseTabularStorage instance.\n *\n * @param client - Supabase client instance\n * @param table - Name of the table to store data (defaults to \"tabular_store\")\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n client: unknown,\n table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.client = client as SupabaseClient;\n }\n\n /**\n * Initializes the database table with the required schema.\n * Creates the table if it doesn't exist with primary key and value columns.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n const sql = `\n CREATE TABLE IF NOT EXISTS \"${this.table}\" (\n ${this.constructPrimaryKeyColumns('\"')} ${this.constructValueColumns('\"')},\n PRIMARY KEY (${this.primaryKeyColumnList()}) \n )\n `;\n const { error } = await this.client.rpc(\"exec_sql\", { query: sql });\n if (error && !error.message.includes(\"already exists\")) {\n throw error;\n }\n\n // Get primary key columns to avoid creating redundant indexes\n const pkColumns = this.primaryKeyColumns();\n\n // Track created indexes to avoid duplicates and redundant indexes\n const createdIndexes = new Set<string>();\n\n for (const columns of this.indexes) {\n // Skip if this is just the primary key or a prefix of it\n if (columns.length <= pkColumns.length) {\n // @ts-ignore\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n\n // Create index name and column list\n const indexName = `${this.table}_${columns.join(\"_\")}`;\n const columnList = columns.map((col) => `\"${String(col)}\"`).join(\", \");\n\n // Skip if we've already created this index or if it's redundant\n const columnKey = columns.join(\",\");\n if (createdIndexes.has(columnKey)) continue;\n\n // Check if this index would be redundant with an existing one\n const isRedundant = Array.from(createdIndexes).some((existing) => {\n const existingCols = existing.split(\",\");\n return (\n existingCols.length >= columns.length &&\n columns.every((col, idx) => col === existingCols[idx])\n );\n });\n\n if (!isRedundant) {\n const indexSql = `CREATE INDEX IF NOT EXISTS \"${indexName}\" ON \"${this.table}\" (${columnList})`;\n const { error: indexError } = await this.client.rpc(\"exec_sql\", { query: indexSql });\n if (indexError && !indexError.message.includes(\"already exists\")) {\n // Index creation errors are not critical, log and continue\n console.warn(`Failed to create index ${indexName}:`, indexError);\n }\n createdIndexes.add(columnKey);\n }\n }\n }\n\n /**\n * Maps TypeScript/JavaScript types to corresponding PostgreSQL data types.\n * Uses additional schema information like minimum/maximum values, nullable status,\n * and string lengths to create more optimized column types.\n *\n * @param typeDef - The TypeScript/JavaScript type to map\n * @returns The corresponding PostgreSQL data type\n */\n protected override mapTypeToSQL(typeDef: JsonSchema): string {\n // Extract the actual non-null type using base helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return \"TEXT /* boolean schema */\";\n }\n\n // Handle BLOB type\n if (actualType.contentEncoding === \"blob\") return \"BYTEA\";\n\n switch (actualType.type) {\n case \"string\":\n // Handle special string formats\n if (actualType.format === \"date-time\") return \"TIMESTAMP\";\n if (actualType.format === \"date\") return \"DATE\";\n if (actualType.format === \"email\") return \"VARCHAR(255)\";\n if (actualType.format === \"uri\") return \"VARCHAR(2048)\";\n if (actualType.format === \"uuid\") return \"UUID\";\n\n // Use a VARCHAR with maxLength if specified\n if (typeof actualType.maxLength === \"number\") {\n return `VARCHAR(${actualType.maxLength})`;\n }\n\n // Default to TEXT for strings without constraints\n return \"TEXT\";\n\n case \"number\":\n case \"integer\":\n // Handle integer vs floating point\n if (actualType.multipleOf === 1 || actualType.type === \"integer\") {\n // Use PostgreSQL's numeric range types based on min/max values\n if (typeof actualType.minimum === \"number\") {\n if (actualType.minimum >= 0) {\n // For unsigned integers\n if (typeof actualType.maximum === \"number\") {\n if (actualType.maximum <= 32767) return \"SMALLINT\";\n if (actualType.maximum <= 2147483647) return \"INTEGER\";\n }\n return \"BIGINT\";\n }\n }\n\n // Default integer type\n return \"INTEGER\";\n }\n\n // For floating point numbers with precision requirements\n if (actualType.format === \"float\") return \"REAL\";\n if (actualType.format === \"double\") return \"DOUBLE PRECISION\";\n\n // Use NUMERIC with precision/scale if specified\n if (typeof actualType.multipleOf === \"number\") {\n const decimalPlaces = String(actualType.multipleOf).split(\".\")[1]?.length || 0;\n if (decimalPlaces > 0) {\n return `NUMERIC(38, ${decimalPlaces})`;\n }\n }\n\n return \"NUMERIC\";\n\n case \"boolean\":\n return \"BOOLEAN\";\n\n case \"array\":\n // Handle array types (if items type is specified)\n if (\n actualType.items &&\n typeof actualType.items === \"object\" &&\n !Array.isArray(actualType.items)\n ) {\n const itemType = this.mapTypeToSQL(actualType.items as JsonSchema);\n\n // Only use native PostgreSQL arrays for simple scalar types\n // List of types that work well as native PostgreSQL arrays\n const supportedArrayElementTypes = [\n \"TEXT\",\n \"VARCHAR\",\n \"CHAR\",\n \"INTEGER\",\n \"SMALLINT\",\n \"BIGINT\",\n \"REAL\",\n \"DOUBLE PRECISION\",\n \"NUMERIC\",\n \"BOOLEAN\",\n \"UUID\",\n \"DATE\",\n \"TIMESTAMP\",\n ];\n\n // Check if the item type is in our supported list (either exact match or starts with for VARCHAR types)\n const isSupported = supportedArrayElementTypes.some(\n (type) => itemType === type || (itemType.startsWith(type + \"(\") && type !== \"VARCHAR\") // Handle things like VARCHAR(255)\n );\n\n if (isSupported) {\n return `${itemType}[]`;\n } else {\n return \"JSONB /* complex array */\";\n }\n }\n return \"JSONB /* generic array */\";\n\n case \"object\":\n return \"JSONB /* object */\";\n\n default:\n return \"TEXT /* unknown type */\";\n }\n }\n\n /**\n * Generates the SQL column definitions for primary key fields with constraints\n * Handles auto-generated keys using SERIAL for integers and UUID DEFAULT for strings\n * @returns SQL string containing primary key column definitions\n */\n protected override constructPrimaryKeyColumns($delimiter: string = \"\"): string {\n const cols = Object.entries<JsonSchema>(this.primaryKeySchema.properties)\n .map(([key, typeDef]) => {\n // Check if this is an auto-generated key\n if (this.isAutoGeneratedKey(key)) {\n if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // Use SERIAL or BIGSERIAL for auto-increment\n const sqlType = this.mapTypeToSQL(typeDef);\n const isSmallInt = sqlType.includes(\"SMALLINT\");\n const isBigInt = sqlType.includes(\"BIGINT\");\n const serialType = isBigInt ? \"BIGSERIAL\" : isSmallInt ? \"SMALLSERIAL\" : \"SERIAL\";\n return `${$delimiter}${key}${$delimiter} ${serialType}`;\n } else if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // Use UUID with DEFAULT gen_random_uuid()\n return `${$delimiter}${key}${$delimiter} UUID DEFAULT gen_random_uuid()`;\n }\n }\n\n const sqlType = this.mapTypeToSQL(typeDef);\n let constraints = \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${$delimiter}${key}${$delimiter} >= 0)`;\n }\n\n return `${$delimiter}${key}${$delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n return cols;\n }\n\n /**\n * Generates the SQL column definitions for value fields with constraints\n * @returns SQL string containing value column definitions\n */\n protected override constructValueColumns($delimiter: string = \"\"): string {\n const delimiter = $delimiter || '\"';\n const requiredSet = new Set(this.valueSchema.required ?? []);\n const cols = Object.entries<JsonSchema>(this.valueSchema.properties)\n .map(([key, typeDef]) => {\n const sqlType = this.mapTypeToSQL(typeDef);\n const isRequired = requiredSet.has(key);\n const nullable = !isRequired || this.isNullable(typeDef);\n let constraints = nullable ? \"NULL\" : \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${delimiter}${key}${delimiter} >= 0)`;\n }\n\n return `${delimiter}${key}${delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n if (cols.length > 0) {\n return `, ${cols}`;\n } else {\n return \"\";\n }\n }\n\n /**\n * Convert Supabase values to JS values. Ensures numeric strings become numbers where schema says number.\n */\n protected override sqlToJsValue(column: string, value: ValueOptionType): Entity[keyof Entity] {\n const typeDef = this.schema.properties[column as keyof typeof this.schema.properties] as\n | JsonSchema\n | undefined;\n if (typeDef) {\n if (value === null && this.isNullable(typeDef)) {\n return null as Entity[keyof Entity];\n }\n const actualType = this.getNonNullType(typeDef);\n\n // Handle numeric types - Supabase can return them as strings\n if (\n typeof actualType !== \"boolean\" &&\n (actualType.type === \"number\" || actualType.type === \"integer\")\n ) {\n if (typeof value === \"number\") return value as Entity[keyof Entity];\n if (typeof value === \"string\") {\n const parsed = Number(value);\n if (!isNaN(parsed)) return parsed as Entity[keyof Entity];\n }\n }\n }\n return super.sqlToJsValue(column, value);\n }\n\n /**\n * Determines if a field should be treated as unsigned based on schema properties\n * @param typeDef - The schema type definition\n * @returns true if the field should be treated as unsigned\n */\n protected shouldBeUnsigned(typeDef: JsonSchema): boolean {\n // Extract the non-null type using the base class helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return false;\n }\n\n // Check if it's a number type with minimum >= 0\n if (\n (actualType.type === \"number\" || actualType.type === \"integer\") &&\n typeof actualType.minimum === \"number\" &&\n actualType.minimum >= 0\n ) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Stores or updates a row in the database.\n * Uses UPSERT (INSERT ... ON CONFLICT DO UPDATE) for atomic operations.\n *\n * @param entity - The entity to store (may be missing auto-generated keys)\n * @returns The entity with any server-generated fields updated\n * @emits \"put\" event with the updated entity when successful\n */\n /**\n * Apply the auto-generated-key policy and the optional-field-to-null\n * normalization that Supabase's REST upsert expects. Shared by {@link put}\n * and {@link putBulk} so a row goes over the wire identically regardless of\n * whether it was inserted alone or as part of a batch.\n *\n * For UUID-strategy auto-gen keys we generate the UUID client-side rather\n * than letting `gen_random_uuid()` fill it server-side. Otherwise the input\n * row has no primary key, and {@link putBulk}'s ordering-preservation step\n * (re-keying the response by PK) cannot work — `result[i]` would no longer\n * be guaranteed to correspond to `values[i]`. SQLite's UUID path uses the\n * same trick.\n */\n private normalizeForUpsert(entity: InsertType): Record<string, unknown> {\n const entityToInsert = { ...entity } as Record<string, unknown>;\n\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const clientProvidedValue = entityToInsert[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldFillKey = false;\n if (this.clientProvidedKeys === \"never\") {\n shouldFillKey = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldFillKey = false;\n } else {\n shouldFillKey = !hasClientValue;\n }\n\n if (shouldFillKey) {\n if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // Generate client-side so the input carries a PK and the bulk\n // response can be re-aligned to input order.\n entityToInsert[keyName] = uuid4();\n } else {\n // Autoincrement integer keys cannot be generated client-side; let\n // Postgres fill via SERIAL. putBulk falls back to response order in\n // this case (and Postgres preserves INSERT ... RETURNING order in\n // practice).\n delete entityToInsert[keyName];\n }\n }\n }\n\n // Normalize optional fields: convert undefined to null for optional fields\n const requiredSet = new Set(this.valueSchema.required ?? []);\n for (const key in this.valueSchema.properties) {\n if (!(key in entityToInsert) || entityToInsert[key] === undefined) {\n if (!requiredSet.has(key)) {\n entityToInsert[key] = null;\n }\n }\n }\n\n return entityToInsert;\n }\n\n /** Hydrate a row returned by Supabase 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 async put(entity: InsertType): Promise<Entity> {\n const normalizedEntity = this.normalizeForUpsert(entity);\n const { data, error } = await this.client\n .from(this.table)\n .upsert(normalizedEntity, { onConflict: this.primaryKeyColumnList() })\n .select()\n .single();\n\n if (error) throw error;\n const updatedEntity = this.hydrateRow(data);\n\n this.events.emit(\"put\", updatedEntity);\n return updatedEntity;\n }\n\n /**\n * Stores multiple rows by issuing a single PostgREST `upsert` carrying every\n * row in one request. PostgREST runs the underlying `INSERT ... ON CONFLICT`\n * inside one server-side transaction, so this is both atomic and a single\n * round trip — far cheaper than `Promise.all` fanning out one HTTPS request\n * per row.\n *\n * **Ordering:** {@link normalizeForUpsert} fills UUID auto-gen keys\n * client-side, so for the common UUID case every input row carries a PK\n * and the response is re-aligned to input order by primary-key match. The\n * only remaining case where ordering relies on Postgres's `INSERT ...\n * RETURNING` row order (stable in practice but not formally contracted) is\n * autoincrement-integer auto-gen keys, where the database has to assign\n * the key.\n *\n * `put` events are deferred until after the upsert resolves so listeners do\n * not see rows from a request that ultimately failed.\n */\n async putBulk(entities: InsertType[]): Promise<Entity[]> {\n if (entities.length === 0) return [];\n\n const normalizedEntities = entities.map((entity) => this.normalizeForUpsert(entity));\n const { data, error } = await this.client\n .from(this.table)\n .upsert(normalizedEntities, { onConflict: this.primaryKeyColumnList() })\n .select();\n\n if (error) throw error;\n if (!data) return [];\n\n const returnedRows = (data as unknown[]).map((row) => this.hydrateRow(row));\n\n // Reorder by primary key when every input row carries its full PK. With an\n // auto-generated key omitted from the input, we have no key to match on,\n // so trust the response order (Postgres's INSERT ... RETURNING preserves\n // VALUES order in practice).\n const orderedEntities = this.alignBulkResponseToInputOrder(normalizedEntities, returnedRows);\n\n for (const entity of orderedEntities) {\n this.events.emit(\"put\", entity);\n }\n return orderedEntities;\n }\n\n /**\n * If every input row supplies its full primary key, build a PK index over\n * the response and emit rows in input order. Otherwise return the response\n * as-is — there is no key to match on, so we have to trust the backend.\n */\n private alignBulkResponseToInputOrder(\n inputs: ReadonlyArray<Record<string, unknown>>,\n responseRows: Entity[]\n ): Entity[] {\n if (inputs.length !== responseRows.length) {\n // Server returned a different cardinality (e.g. dedup); fall back to as-is.\n return responseRows;\n }\n const pkColumns = this.primaryKeyColumns().map(String);\n for (const input of inputs) {\n for (const col of pkColumns) {\n if (input[col] === undefined || input[col] === null) {\n return responseRows;\n }\n }\n }\n\n const fingerprint = (row: Record<string, unknown>): string =>\n pkColumns.map((c) => String(row[c])).join(\"\u0000\");\n\n const responseByPk = new Map<string, Entity>();\n for (const row of responseRows) {\n responseByPk.set(fingerprint(row as unknown as Record<string, unknown>), row);\n }\n\n const ordered: Entity[] = [];\n for (const input of inputs) {\n const match = responseByPk.get(fingerprint(input));\n if (!match) return responseRows; // unexpected; fall back\n ordered.push(match);\n }\n return ordered;\n }\n\n /**\n * Retrieves a value from the database by its primary key.\n *\n * @param key - The primary key object to look up\n * @returns The stored entity or undefined if not found\n * @emits \"get\" event with the key when successful\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n let query = this.client.from(this.table).select(\"*\");\n\n // Build the where clause from primary key\n const keyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), keyRecord[String(pkName)]);\n }\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n // Not found\n this.events.emit(\"get\", key, undefined);\n return undefined;\n }\n throw error;\n }\n\n const val = data as Entity | undefined;\n if (val) {\n // Convert all columns from SQL to JS values\n const valRecord = val as Record<string, unknown>;\n for (const key in this.schema.properties) {\n valRecord[key] = this.sqlToJsValue(key, valRecord[key] as ValueOptionType);\n }\n }\n this.events.emit(\"get\", key, val);\n return val;\n }\n\n /**\n * Deletes a row from the database.\n *\n * @param value - The primary key object or entity to delete\n * @emits \"delete\" event with the key when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n\n let query = this.client.from(this.table).delete();\n\n // Build the where clause from primary key\n const deleteKeyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), deleteKeyRecord[String(pkName)]);\n }\n\n const { error } = await query;\n\n if (error) throw error;\n this.events.emit(\"delete\", key as keyof Entity);\n }\n\n /**\n * Retrieves all entries from the database table, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Promise resolving to an array of entries or undefined if not found\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n let query = this.client.from(this.table).select(\"*\");\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length) {\n // Convert all columns from SQL to JS values\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n return data as Entity[];\n }\n return undefined;\n }\n\n /**\n * Deletes all rows from the database table.\n * @emits \"clearall\" event when successful\n */\n async deleteAll(): Promise<void> {\n // Use the first primary key column for the delete condition\n const firstPkColumn = this.primaryKeyNames[0];\n const { error } = await this.client.from(this.table).delete().neq(String(firstPkColumn), null); // Delete all rows by using a condition that's always true\n\n if (error) throw error;\n this.events.emit(\"clearall\");\n }\n\n /**\n * Returns the total number of rows in the database.\n *\n * @returns Promise resolving to the count of stored items\n */\n async size(): Promise<number> {\n const { count, error } = await this.client\n .from(this.table)\n .select(\"*\", { count: \"exact\", head: true });\n\n if (error) throw error;\n return count ?? 0;\n }\n\n /**\n * Fetches a page of records from the repository using offset-based paging.\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 * @deprecated Offset-based paging is unstable under concurrent writes.\n * Use {@link getPage} for stable, keyset-based pagination.\n */\n async getOffsetPage(offset: number, limit: number): Promise<Entity[] | undefined> {\n // Build the base query\n let query = this.client.from(this.table).select(\"*\");\n\n // Ensure deterministic ordering for pagination by ordering on primary key column(s)\n for (const pkName of this.primaryKeyNames) {\n query = query.order(String(pkName));\n }\n\n const { data, error } = await query.range(offset, offset + limit - 1);\n\n if (error) throw error;\n\n if (!data || data.length === 0) {\n return undefined;\n }\n\n // Convert all columns from SQL to JS values (consistent with getAll)\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n\n return data as Entity[];\n }\n\n /**\n * Applies criteria to a Supabase filter builder. Typed as `any` because the\n * `PostgrestFilterBuilder` generics are deep enough to trip TS2589.\n */\n private applyCriteriaToFilter<Q>(query: Q, criteria: SearchCriteria<Entity>): Q {\n let q = query as any;\n for (const column of Object.keys(criteria) as Array<keyof Entity>) {\n const criterion = criteria[column];\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n switch (operator) {\n case \"=\":\n q = q.eq(String(column), value);\n break;\n case \"<\":\n q = q.lt(String(column), value);\n break;\n case \"<=\":\n q = q.lte(String(column), value);\n break;\n case \">\":\n q = q.gt(String(column), value);\n break;\n case \">=\":\n q = q.gte(String(column), value);\n break;\n }\n }\n return q as Q;\n }\n\n /**\n * Counts rows matching the specified search criteria.\n */\n override async count(criteria?: SearchCriteria<Entity>): Promise<number> {\n if (!criteria || Object.keys(criteria).length === 0) {\n return await this.size();\n }\n\n this.validateQueryParams(criteria);\n const query = this.applyCriteriaToFilter(\n this.client.from(this.table).select(\"*\", { count: \"exact\", head: true }),\n criteria\n );\n\n const { count, error } = await query;\n if (error) throw error;\n return count ?? 0;\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Supports multiple columns with optional comparison operators.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n */\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaKeys.length === 0) {\n return;\n }\n\n let query = this.client.from(this.table).delete();\n\n for (const column of criteriaKeys) {\n if (!(column in this.schema.properties)) {\n throw new Error(`Schema must have a ${String(column)} field to use deleteSearch`);\n }\n\n const criterion = criteria[column];\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n switch (operator) {\n case \"=\":\n query = query.eq(String(column), value);\n break;\n case \"<\":\n query = query.lt(String(column), value);\n break;\n case \"<=\":\n query = query.lte(String(column), value);\n break;\n case \">\":\n query = query.gt(String(column), value);\n break;\n case \">=\":\n query = query.gte(String(column), value);\n break;\n }\n }\n\n const { error } = await query;\n\n if (error) throw error;\n this.events.emit(\"delete\", criteriaKeys[0] as keyof Entity);\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering, limit, and offset.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of matching entities or undefined if no matches found\n */\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n this.validateQueryParams(criteria, options);\n\n let query = this.applyCriteriaToFilter(this.client.from(this.table).select(\"*\"), criteria);\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n } else if (options?.limit !== undefined) {\n query = query.limit(options.limit);\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length > 0) {\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, data as Entity[]);\n return data as Entity[];\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n\n /**\n * Cursor-paginated read pushed into PostgREST. Builds a keyset OR-of-AND\n * filter via Supabase's `.or()` plus per-column `.order()` with explicit\n * `nullsFirst` so iteration semantics match the rest of the package\n * (NULLs sort before non-null for ASC, after for DESC). The pushdown\n * makes memory and wire traffic O(pageSize) regardless of table size,\n * unlike the in-memory base-class fallback which would full-table-scan.\n */\n override async getPage(request: PageRequest<Entity> = {}): Promise<Page<Entity>> {\n return this.runSupabasePage(undefined, request);\n }\n\n override async queryPage(\n criteria: SearchCriteria<Entity>,\n request: PageRequest<Entity> = {}\n ): Promise<Page<Entity>> {\n this.validateQueryParams(criteria, undefined);\n return this.runSupabasePage(criteria, request);\n }\n\n private async runSupabasePage(\n criteria: SearchCriteria<Entity> | undefined,\n request: PageRequest<Entity>\n ): Promise<Page<Entity>> {\n // Validate before we send column names through PostgREST filters or\n // ORDER BY — caller is the trust boundary for orderBy contents.\n this.validatePageRequest(request);\n const limit = request.limit ?? 100;\n const pkColumns = this.primaryKeyColumns() as unknown as Array<keyof Entity>;\n const orderBy = request.orderBy;\n const effectiveOrderBy = this.buildEffectiveOrderBy(orderBy, pkColumns);\n const effectiveOrderForCursor = effectiveOrderBy.map((o) => ({\n column: String(o.column),\n direction: o.direction,\n }));\n\n let cursorPayload;\n if (request.cursor !== undefined) {\n cursorPayload = decodeCursor(request.cursor);\n assertCursorMatches(cursorPayload, effectiveOrderForCursor);\n }\n\n let query: any = this.client.from(this.table).select(\"*\");\n if (criteria && Object.keys(criteria).length > 0) {\n query = this.applyCriteriaToFilter(query, criteria);\n }\n\n if (cursorPayload) {\n const filter = this.buildSupabaseKeysetFilter(effectiveOrderBy, cursorPayload.c);\n // `null` is the keyset builder's signal for \"no rows possible\" — e.g.\n // a DESC cursor parked on a NULL leading column; nothing comes after\n // a NULLs-last trailer. Short-circuit instead of issuing the query.\n if (filter === null) {\n return { items: [], nextCursor: undefined };\n }\n query = query.or(filter);\n }\n\n for (const { column, direction } of effectiveOrderBy) {\n query = query.order(String(column), {\n ascending: direction === \"ASC\",\n nullsFirst: direction === \"ASC\",\n });\n }\n query = query.limit(limit);\n\n const { data, error } = await query;\n if (error) throw error;\n\n const items = (data ?? []) as Entity[];\n for (const row of items) {\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\n const nextCursor =\n items.length === limit\n ? this.buildCursor(items[items.length - 1], effectiveOrderBy)\n : undefined;\n return { items, nextCursor };\n }\n\n /**\n * Builds a PostgREST OR-of-AND filter string for keyset pagination.\n * See {@link BaseSqlTabularStorage.buildKeysetWhere} for the canonical\n * description of the OR-of-AND form and NULL semantics; this is the\n * same logic translated to PostgREST's filter grammar.\n *\n * Returns `null` when *every* OR-clause is unreachable, which means the\n * caller can skip the round-trip — the page is unconditionally empty.\n * The common trigger is a single-column DESC orderBy parked on a NULL\n * cursor (no row comes after a NULLs-last trailer); compound orderings\n * with later tiebreaker columns will still produce reachable clauses\n * even when the leading cursor value is NULL.\n */\n private buildSupabaseKeysetFilter(\n orderBy: ReadonlyArray<{ column: keyof Entity; direction: \"ASC\" | \"DESC\" }>,\n cursorValues: ReadonlyArray<string | number | boolean | null>\n ): string | null {\n const orClauses: string[] = [];\n for (let i = 0; i < orderBy.length; i++) {\n const andParts: string[] = [];\n // Equality on preceding columns; collapse to `is.null` for null cursors\n // because PostgREST `eq.null` doesn't exist (and SQL semantics agree\n // that `col = NULL` is never true).\n for (let j = 0; j < i; j++) {\n const col = String(orderBy[j].column);\n const v = cursorValues[j];\n andParts.push(v === null ? `${col}.is.null` : `${col}.eq.${escapePostgrest(v)}`);\n }\n const col = String(orderBy[i].column);\n const v = cursorValues[i];\n const dir = orderBy[i].direction;\n let cmp: string;\n if (v === null) {\n if (dir === \"ASC\") {\n // ASC NULLS-FIRST: rows strictly after NULL on this column are\n // any non-null value.\n cmp = `${col}.not.is.null`;\n } else {\n // DESC NULLS-LAST: nothing comes strictly after a NULL on this\n // column. The i-th OR-clause contributes no rows — drop it. We\n // can't `return null`, because subsequent clauses (i+1, i+2, …)\n // can still produce matches via equality on the NULL preceding\n // columns plus a tiebreaker on a later column. Mirrors the\n // `1 = 0` predicate in `BaseSqlTabularStorage.buildKeysetWhere`.\n continue;\n }\n } else {\n if (dir === \"ASC\") {\n cmp = `${col}.gt.${escapePostgrest(v)}`;\n } else {\n // Smaller than the cursor, then NULLs-last trailer.\n cmp = `or(${col}.lt.${escapePostgrest(v)},${col}.is.null)`;\n }\n }\n andParts.push(cmp);\n orClauses.push(andParts.length === 1 ? andParts[0] : `and(${andParts.join(\",\")})`);\n }\n if (orClauses.length === 0) return null;\n return orClauses.join(\",\");\n }\n\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n this.validateSelect(options);\n this.validateQueryParams(criteria, options);\n\n const registered = this.indexes.map((cols, i) => {\n const cs = Array.isArray(cols) ? (cols as string[]) : [cols as string];\n return { name: `idx_${i}`, keyPath: cs };\n });\n\n pickCoveringIndex({\n table: this.table,\n indexes: registered,\n criteriaColumns: Object.keys(criteria),\n orderByColumns: (options.orderBy ?? []).map((o) => ({\n column: String(o.column),\n direction: o.direction,\n })),\n selectColumns: options.select.map(String),\n primaryKeyColumns: this.primaryKeyNames.map(String),\n });\n\n const colList = options.select.map(String).join(\",\");\n let q = this.applyCriteriaToFilter(this.client.from(this.table).select(colList), criteria);\n\n if (options.orderBy) {\n for (const { column, direction } of options.orderBy) {\n q = q.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n if (options.offset !== undefined && options.limit === undefined) {\n throw new StorageValidationError(\"queryIndex with offset requires limit (no implicit cap)\");\n }\n if (options.offset !== undefined || options.limit !== undefined) {\n const start = options.offset ?? 0;\n if (options.limit !== undefined) {\n q = q.range(start, start + options.limit - 1);\n }\n }\n\n const { data, error } = await q;\n if (error) throw error;\n if (!data) return [];\n\n const rows = data as unknown as Record<string, unknown>[];\n const sel = new Set(options.select.map(String));\n for (const row of rows) {\n for (const key of Object.keys(row)) {\n if (sel.has(key)) {\n row[key] = this.sqlToJsValue(key, row[key] as ValueOptionType);\n }\n }\n }\n return rows as unknown as Pick<Entity, K>[];\n }\n\n /**\n * Converts a row from Supabase realtime payload to an Entity with proper type conversions.\n *\n * @param row - The raw row data from Supabase realtime\n * @returns The converted entity\n */\n private convertRealtimeRow(row: Record<string, unknown>): Entity {\n const entity = { ...row } as Entity;\n const record = entity as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, row[key] as ValueOptionType);\n }\n return entity;\n }\n\n /**\n * Subscribes to changes in the repository using Supabase realtime.\n * Receives notifications for INSERT, UPDATE, and DELETE operations from any source.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (not used for Supabase realtime)\n * @returns Unsubscribe function\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Create a unique channel name\n const channelName = `tabular-${this.table}-${Date.now()}`;\n\n this.realtimeChannel = this.client\n .channel(channelName)\n .on(\n \"postgres_changes\",\n {\n event: \"*\",\n schema: \"public\",\n table: this.table,\n },\n (payload) => {\n const change: TabularChangePayload<Entity> = {\n type: payload.eventType.toUpperCase() as TabularChangeType,\n old:\n payload.old && Object.keys(payload.old).length > 0\n ? this.convertRealtimeRow(payload.old)\n : undefined,\n new:\n payload.new && Object.keys(payload.new).length > 0\n ? this.convertRealtimeRow(payload.new)\n : undefined,\n };\n callback(change);\n }\n )\n .subscribe();\n\n return () => {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n };\n }\n\n /**\n * **Best-effort, non-atomic.** Supabase exposes PostgREST, not a session-\n * level transaction surface this client can drive — there is no\n * `BEGIN`/`COMMIT`/`ROLLBACK` over the wire. The override exists only to\n * make the no-rollback semantics explicit instead of inheriting the base\n * default silently: `fn` runs to completion against `this`, the result\n * propagates, and any partial writes survive a thrown `fn`. Use a\n * stored-procedure / RPC if you need true atomicity on Supabase.\n */\n public override async withTransaction<T>(fn: (tx: this) => Promise<T>): Promise<T> {\n return fn(this);\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n public override destroy(): void {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n }\n}\n"
7
7
  ],
8
- "mappings": "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",
9
- "debugId": "AAD23751886988C864756E2164756E21",
8
+ "mappings": "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",
9
+ "debugId": "A507CF4158D891DC64756E2164756E21",
10
10
  "names": []
11
11
  }
@@ -1 +1 @@
1
- {"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/storage/bun.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/storage/bun.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,UAAU,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/storage/common.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/storage/common.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,qBAAqB,CAAC;AACpC,cAAc,0BAA0B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/storage/node.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/storage/node.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,cAAc,UAAU,CAAC"}
@@ -395,7 +395,7 @@ class SupabaseTabularStorage extends BaseSqlTabularStorage {
395
395
  throw error;
396
396
  return count ?? 0;
397
397
  }
398
- async getBulk(offset, limit) {
398
+ async getOffsetPage(offset, limit) {
399
399
  let query = this.client.from(this.table).select("*");
400
400
  for (const pkName of this.primaryKeyNames) {
401
401
  query = query.order(String(pkName));
@@ -735,4 +735,4 @@ export {
735
735
  SUPABASE_KV_REPOSITORY
736
736
  };
737
737
 
738
- //# debugId=A7D3C92DD87268E764756E2164756E21
738
+ //# debugId=65D57CB2936568C964756E2164756E21
@@ -3,9 +3,9 @@
3
3
  "sources": ["../../src/storage/SupabaseKvStorage.ts", "../../src/storage/SupabaseTabularStorage.ts"],
4
4
  "sourcesContent": [
5
5
  "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { createServiceToken } from \"@workglow/util\";\nimport { JsonSchema } from \"@workglow/util/schema\";\nimport { SupabaseTabularStorage } from \"./SupabaseTabularStorage\";\nimport {\n DefaultKeyValueKey,\n DefaultKeyValueSchema,\n IKvStorage,\n KvViaTabularStorage,\n} from \"@workglow/storage\";\n\nexport const SUPABASE_KV_REPOSITORY = createServiceToken<IKvStorage<string, any, any>>(\n \"storage.kvRepository.supabase\"\n);\n\n/**\n * A key-value repository implementation that uses Supabase for persistent storage.\n * Leverages a tabular repository abstraction for Supabase operations.\n *\n * @template Key - The type of the primary key\n * @template Value - The type of the value being stored\n * @template Combined - Combined type of Key & Value\n */\nexport class SupabaseKvStorage extends KvViaTabularStorage {\n public tabularRepository: SupabaseTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >;\n\n /**\n * Creates a new SupabaseKvStorage instance\n *\n * @param client - Supabase client instance\n * @param tableName - Name of the table to store data\n * @param keySchema - Schema for the key type (defaults to string)\n * @param valueSchema - Schema for the value type (defaults to any)\n */\n constructor(\n public client: unknown,\n public tableName: string,\n keySchema: JsonSchema = { type: \"string\" },\n valueSchema: JsonSchema = {},\n tabularRepository?: SupabaseTabularStorage<\n typeof DefaultKeyValueSchema,\n typeof DefaultKeyValueKey\n >\n ) {\n super(keySchema, valueSchema);\n this.tabularRepository =\n tabularRepository ??\n new SupabaseTabularStorage(client, tableName, DefaultKeyValueSchema, DefaultKeyValueKey);\n }\n}\n",
6
- "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { RealtimeChannel, SupabaseClient } from \"@supabase/supabase-js\";\nimport { createServiceToken, uuid4 } from \"@workglow/util\";\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport {\n BaseSqlTabularStorage,\n ClientProvidedKeysOption,\n AnyTabularStorage,\n AutoGeneratedKeys,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n Page,\n PageRequest,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularChangeType,\n TabularSubscribeOptions,\n ValueOptionType,\n pickCoveringIndex,\n StorageValidationError,\n assertCursorMatches,\n decodeCursor,\n} from \"@workglow/storage\";\n\n/**\n * Quotes a value for inclusion in a PostgREST filter expression.\n *\n * PostgREST treats commas, periods, parentheses, colons, double-quotes,\n * and whitespace as filter syntax delimiters; values containing any of\n * these need to be wrapped in double-quotes (with embedded `\"` and `\\`\n * escaped). ISO timestamps contain dots, so most non-trivial values need\n * quoting. We err on the side of quoting anything that isn't a clean\n * integer or boolean — false positives are cheap; false negatives produce\n * malformed filters that PostgREST silently mis-parses.\n */\nfunction escapePostgrest(value: string | number | boolean | null): string {\n if (value === null) return \"null\";\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\";\n if (typeof value === \"number\" && Number.isInteger(value)) return String(value);\n const s = String(value);\n return `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\nexport const SUPABASE_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.supabase\"\n);\n\n/**\n * A Supabase-based tabular repository implementation that extends BaseSqlTabularStorage.\n * This class provides persistent storage for data in a Supabase database,\n * making it suitable for multi-user scenarios.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class SupabaseTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseSqlTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n protected readonly client: SupabaseClient;\n private realtimeChannel: RealtimeChannel | null = null;\n\n /**\n * Creates a new SupabaseTabularStorage instance.\n *\n * @param client - Supabase client instance\n * @param table - Name of the table to store data (defaults to \"tabular_store\")\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n client: unknown,\n table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.client = client as SupabaseClient;\n }\n\n /**\n * Initializes the database table with the required schema.\n * Creates the table if it doesn't exist with primary key and value columns.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n const sql = `\n CREATE TABLE IF NOT EXISTS \"${this.table}\" (\n ${this.constructPrimaryKeyColumns('\"')} ${this.constructValueColumns('\"')},\n PRIMARY KEY (${this.primaryKeyColumnList()}) \n )\n `;\n const { error } = await this.client.rpc(\"exec_sql\", { query: sql });\n if (error && !error.message.includes(\"already exists\")) {\n throw error;\n }\n\n // Get primary key columns to avoid creating redundant indexes\n const pkColumns = this.primaryKeyColumns();\n\n // Track created indexes to avoid duplicates and redundant indexes\n const createdIndexes = new Set<string>();\n\n for (const columns of this.indexes) {\n // Skip if this is just the primary key or a prefix of it\n if (columns.length <= pkColumns.length) {\n // @ts-ignore\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n\n // Create index name and column list\n const indexName = `${this.table}_${columns.join(\"_\")}`;\n const columnList = columns.map((col) => `\"${String(col)}\"`).join(\", \");\n\n // Skip if we've already created this index or if it's redundant\n const columnKey = columns.join(\",\");\n if (createdIndexes.has(columnKey)) continue;\n\n // Check if this index would be redundant with an existing one\n const isRedundant = Array.from(createdIndexes).some((existing) => {\n const existingCols = existing.split(\",\");\n return (\n existingCols.length >= columns.length &&\n columns.every((col, idx) => col === existingCols[idx])\n );\n });\n\n if (!isRedundant) {\n const indexSql = `CREATE INDEX IF NOT EXISTS \"${indexName}\" ON \"${this.table}\" (${columnList})`;\n const { error: indexError } = await this.client.rpc(\"exec_sql\", { query: indexSql });\n if (indexError && !indexError.message.includes(\"already exists\")) {\n // Index creation errors are not critical, log and continue\n console.warn(`Failed to create index ${indexName}:`, indexError);\n }\n createdIndexes.add(columnKey);\n }\n }\n }\n\n /**\n * Maps TypeScript/JavaScript types to corresponding PostgreSQL data types.\n * Uses additional schema information like minimum/maximum values, nullable status,\n * and string lengths to create more optimized column types.\n *\n * @param typeDef - The TypeScript/JavaScript type to map\n * @returns The corresponding PostgreSQL data type\n */\n protected override mapTypeToSQL(typeDef: JsonSchema): string {\n // Extract the actual non-null type using base helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return \"TEXT /* boolean schema */\";\n }\n\n // Handle BLOB type\n if (actualType.contentEncoding === \"blob\") return \"BYTEA\";\n\n switch (actualType.type) {\n case \"string\":\n // Handle special string formats\n if (actualType.format === \"date-time\") return \"TIMESTAMP\";\n if (actualType.format === \"date\") return \"DATE\";\n if (actualType.format === \"email\") return \"VARCHAR(255)\";\n if (actualType.format === \"uri\") return \"VARCHAR(2048)\";\n if (actualType.format === \"uuid\") return \"UUID\";\n\n // Use a VARCHAR with maxLength if specified\n if (typeof actualType.maxLength === \"number\") {\n return `VARCHAR(${actualType.maxLength})`;\n }\n\n // Default to TEXT for strings without constraints\n return \"TEXT\";\n\n case \"number\":\n case \"integer\":\n // Handle integer vs floating point\n if (actualType.multipleOf === 1 || actualType.type === \"integer\") {\n // Use PostgreSQL's numeric range types based on min/max values\n if (typeof actualType.minimum === \"number\") {\n if (actualType.minimum >= 0) {\n // For unsigned integers\n if (typeof actualType.maximum === \"number\") {\n if (actualType.maximum <= 32767) return \"SMALLINT\";\n if (actualType.maximum <= 2147483647) return \"INTEGER\";\n }\n return \"BIGINT\";\n }\n }\n\n // Default integer type\n return \"INTEGER\";\n }\n\n // For floating point numbers with precision requirements\n if (actualType.format === \"float\") return \"REAL\";\n if (actualType.format === \"double\") return \"DOUBLE PRECISION\";\n\n // Use NUMERIC with precision/scale if specified\n if (typeof actualType.multipleOf === \"number\") {\n const decimalPlaces = String(actualType.multipleOf).split(\".\")[1]?.length || 0;\n if (decimalPlaces > 0) {\n return `NUMERIC(38, ${decimalPlaces})`;\n }\n }\n\n return \"NUMERIC\";\n\n case \"boolean\":\n return \"BOOLEAN\";\n\n case \"array\":\n // Handle array types (if items type is specified)\n if (\n actualType.items &&\n typeof actualType.items === \"object\" &&\n !Array.isArray(actualType.items)\n ) {\n const itemType = this.mapTypeToSQL(actualType.items as JsonSchema);\n\n // Only use native PostgreSQL arrays for simple scalar types\n // List of types that work well as native PostgreSQL arrays\n const supportedArrayElementTypes = [\n \"TEXT\",\n \"VARCHAR\",\n \"CHAR\",\n \"INTEGER\",\n \"SMALLINT\",\n \"BIGINT\",\n \"REAL\",\n \"DOUBLE PRECISION\",\n \"NUMERIC\",\n \"BOOLEAN\",\n \"UUID\",\n \"DATE\",\n \"TIMESTAMP\",\n ];\n\n // Check if the item type is in our supported list (either exact match or starts with for VARCHAR types)\n const isSupported = supportedArrayElementTypes.some(\n (type) => itemType === type || (itemType.startsWith(type + \"(\") && type !== \"VARCHAR\") // Handle things like VARCHAR(255)\n );\n\n if (isSupported) {\n return `${itemType}[]`;\n } else {\n return \"JSONB /* complex array */\";\n }\n }\n return \"JSONB /* generic array */\";\n\n case \"object\":\n return \"JSONB /* object */\";\n\n default:\n return \"TEXT /* unknown type */\";\n }\n }\n\n /**\n * Generates the SQL column definitions for primary key fields with constraints\n * Handles auto-generated keys using SERIAL for integers and UUID DEFAULT for strings\n * @returns SQL string containing primary key column definitions\n */\n protected override constructPrimaryKeyColumns($delimiter: string = \"\"): string {\n const cols = Object.entries<JsonSchema>(this.primaryKeySchema.properties)\n .map(([key, typeDef]) => {\n // Check if this is an auto-generated key\n if (this.isAutoGeneratedKey(key)) {\n if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // Use SERIAL or BIGSERIAL for auto-increment\n const sqlType = this.mapTypeToSQL(typeDef);\n const isSmallInt = sqlType.includes(\"SMALLINT\");\n const isBigInt = sqlType.includes(\"BIGINT\");\n const serialType = isBigInt ? \"BIGSERIAL\" : isSmallInt ? \"SMALLSERIAL\" : \"SERIAL\";\n return `${$delimiter}${key}${$delimiter} ${serialType}`;\n } else if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // Use UUID with DEFAULT gen_random_uuid()\n return `${$delimiter}${key}${$delimiter} UUID DEFAULT gen_random_uuid()`;\n }\n }\n\n const sqlType = this.mapTypeToSQL(typeDef);\n let constraints = \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${$delimiter}${key}${$delimiter} >= 0)`;\n }\n\n return `${$delimiter}${key}${$delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n return cols;\n }\n\n /**\n * Generates the SQL column definitions for value fields with constraints\n * @returns SQL string containing value column definitions\n */\n protected override constructValueColumns($delimiter: string = \"\"): string {\n const delimiter = $delimiter || '\"';\n const requiredSet = new Set(this.valueSchema.required ?? []);\n const cols = Object.entries<JsonSchema>(this.valueSchema.properties)\n .map(([key, typeDef]) => {\n const sqlType = this.mapTypeToSQL(typeDef);\n const isRequired = requiredSet.has(key);\n const nullable = !isRequired || this.isNullable(typeDef);\n let constraints = nullable ? \"NULL\" : \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${delimiter}${key}${delimiter} >= 0)`;\n }\n\n return `${delimiter}${key}${delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n if (cols.length > 0) {\n return `, ${cols}`;\n } else {\n return \"\";\n }\n }\n\n /**\n * Convert Supabase values to JS values. Ensures numeric strings become numbers where schema says number.\n */\n protected override sqlToJsValue(column: string, value: ValueOptionType): Entity[keyof Entity] {\n const typeDef = this.schema.properties[column as keyof typeof this.schema.properties] as\n | JsonSchema\n | undefined;\n if (typeDef) {\n if (value === null && this.isNullable(typeDef)) {\n return null as Entity[keyof Entity];\n }\n const actualType = this.getNonNullType(typeDef);\n\n // Handle numeric types - Supabase can return them as strings\n if (\n typeof actualType !== \"boolean\" &&\n (actualType.type === \"number\" || actualType.type === \"integer\")\n ) {\n if (typeof value === \"number\") return value as Entity[keyof Entity];\n if (typeof value === \"string\") {\n const parsed = Number(value);\n if (!isNaN(parsed)) return parsed as Entity[keyof Entity];\n }\n }\n }\n return super.sqlToJsValue(column, value);\n }\n\n /**\n * Determines if a field should be treated as unsigned based on schema properties\n * @param typeDef - The schema type definition\n * @returns true if the field should be treated as unsigned\n */\n protected shouldBeUnsigned(typeDef: JsonSchema): boolean {\n // Extract the non-null type using the base class helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return false;\n }\n\n // Check if it's a number type with minimum >= 0\n if (\n (actualType.type === \"number\" || actualType.type === \"integer\") &&\n typeof actualType.minimum === \"number\" &&\n actualType.minimum >= 0\n ) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Stores or updates a row in the database.\n * Uses UPSERT (INSERT ... ON CONFLICT DO UPDATE) for atomic operations.\n *\n * @param entity - The entity to store (may be missing auto-generated keys)\n * @returns The entity with any server-generated fields updated\n * @emits \"put\" event with the updated entity when successful\n */\n /**\n * Apply the auto-generated-key policy and the optional-field-to-null\n * normalization that Supabase's REST upsert expects. Shared by {@link put}\n * and {@link putBulk} so a row goes over the wire identically regardless of\n * whether it was inserted alone or as part of a batch.\n *\n * For UUID-strategy auto-gen keys we generate the UUID client-side rather\n * than letting `gen_random_uuid()` fill it server-side. Otherwise the input\n * row has no primary key, and {@link putBulk}'s ordering-preservation step\n * (re-keying the response by PK) cannot work — `result[i]` would no longer\n * be guaranteed to correspond to `values[i]`. SQLite's UUID path uses the\n * same trick.\n */\n private normalizeForUpsert(entity: InsertType): Record<string, unknown> {\n const entityToInsert = { ...entity } as Record<string, unknown>;\n\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const clientProvidedValue = entityToInsert[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldFillKey = false;\n if (this.clientProvidedKeys === \"never\") {\n shouldFillKey = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldFillKey = false;\n } else {\n shouldFillKey = !hasClientValue;\n }\n\n if (shouldFillKey) {\n if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // Generate client-side so the input carries a PK and the bulk\n // response can be re-aligned to input order.\n entityToInsert[keyName] = uuid4();\n } else {\n // Autoincrement integer keys cannot be generated client-side; let\n // Postgres fill via SERIAL. putBulk falls back to response order in\n // this case (and Postgres preserves INSERT ... RETURNING order in\n // practice).\n delete entityToInsert[keyName];\n }\n }\n }\n\n // Normalize optional fields: convert undefined to null for optional fields\n const requiredSet = new Set(this.valueSchema.required ?? []);\n for (const key in this.valueSchema.properties) {\n if (!(key in entityToInsert) || entityToInsert[key] === undefined) {\n if (!requiredSet.has(key)) {\n entityToInsert[key] = null;\n }\n }\n }\n\n return entityToInsert;\n }\n\n /** Hydrate a row returned by Supabase 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 async put(entity: InsertType): Promise<Entity> {\n const normalizedEntity = this.normalizeForUpsert(entity);\n const { data, error } = await this.client\n .from(this.table)\n .upsert(normalizedEntity, { onConflict: this.primaryKeyColumnList() })\n .select()\n .single();\n\n if (error) throw error;\n const updatedEntity = this.hydrateRow(data);\n\n this.events.emit(\"put\", updatedEntity);\n return updatedEntity;\n }\n\n /**\n * Stores multiple rows by issuing a single PostgREST `upsert` carrying every\n * row in one request. PostgREST runs the underlying `INSERT ... ON CONFLICT`\n * inside one server-side transaction, so this is both atomic and a single\n * round trip — far cheaper than `Promise.all` fanning out one HTTPS request\n * per row.\n *\n * **Ordering:** {@link normalizeForUpsert} fills UUID auto-gen keys\n * client-side, so for the common UUID case every input row carries a PK\n * and the response is re-aligned to input order by primary-key match. The\n * only remaining case where ordering relies on Postgres's `INSERT ...\n * RETURNING` row order (stable in practice but not formally contracted) is\n * autoincrement-integer auto-gen keys, where the database has to assign\n * the key.\n *\n * `put` events are deferred until after the upsert resolves so listeners do\n * not see rows from a request that ultimately failed.\n */\n async putBulk(entities: InsertType[]): Promise<Entity[]> {\n if (entities.length === 0) return [];\n\n const normalizedEntities = entities.map((entity) => this.normalizeForUpsert(entity));\n const { data, error } = await this.client\n .from(this.table)\n .upsert(normalizedEntities, { onConflict: this.primaryKeyColumnList() })\n .select();\n\n if (error) throw error;\n if (!data) return [];\n\n const returnedRows = (data as unknown[]).map((row) => this.hydrateRow(row));\n\n // Reorder by primary key when every input row carries its full PK. With an\n // auto-generated key omitted from the input, we have no key to match on,\n // so trust the response order (Postgres's INSERT ... RETURNING preserves\n // VALUES order in practice).\n const orderedEntities = this.alignBulkResponseToInputOrder(normalizedEntities, returnedRows);\n\n for (const entity of orderedEntities) {\n this.events.emit(\"put\", entity);\n }\n return orderedEntities;\n }\n\n /**\n * If every input row supplies its full primary key, build a PK index over\n * the response and emit rows in input order. Otherwise return the response\n * as-is — there is no key to match on, so we have to trust the backend.\n */\n private alignBulkResponseToInputOrder(\n inputs: ReadonlyArray<Record<string, unknown>>,\n responseRows: Entity[]\n ): Entity[] {\n if (inputs.length !== responseRows.length) {\n // Server returned a different cardinality (e.g. dedup); fall back to as-is.\n return responseRows;\n }\n const pkColumns = this.primaryKeyColumns().map(String);\n for (const input of inputs) {\n for (const col of pkColumns) {\n if (input[col] === undefined || input[col] === null) {\n return responseRows;\n }\n }\n }\n\n const fingerprint = (row: Record<string, unknown>): string =>\n pkColumns.map((c) => String(row[c])).join(\"\u0000\");\n\n const responseByPk = new Map<string, Entity>();\n for (const row of responseRows) {\n responseByPk.set(fingerprint(row as unknown as Record<string, unknown>), row);\n }\n\n const ordered: Entity[] = [];\n for (const input of inputs) {\n const match = responseByPk.get(fingerprint(input));\n if (!match) return responseRows; // unexpected; fall back\n ordered.push(match);\n }\n return ordered;\n }\n\n /**\n * Retrieves a value from the database by its primary key.\n *\n * @param key - The primary key object to look up\n * @returns The stored entity or undefined if not found\n * @emits \"get\" event with the key when successful\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n let query = this.client.from(this.table).select(\"*\");\n\n // Build the where clause from primary key\n const keyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), keyRecord[String(pkName)]);\n }\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n // Not found\n this.events.emit(\"get\", key, undefined);\n return undefined;\n }\n throw error;\n }\n\n const val = data as Entity | undefined;\n if (val) {\n // Convert all columns from SQL to JS values\n const valRecord = val as Record<string, unknown>;\n for (const key in this.schema.properties) {\n valRecord[key] = this.sqlToJsValue(key, valRecord[key] as ValueOptionType);\n }\n }\n this.events.emit(\"get\", key, val);\n return val;\n }\n\n /**\n * Deletes a row from the database.\n *\n * @param value - The primary key object or entity to delete\n * @emits \"delete\" event with the key when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n\n let query = this.client.from(this.table).delete();\n\n // Build the where clause from primary key\n const deleteKeyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), deleteKeyRecord[String(pkName)]);\n }\n\n const { error } = await query;\n\n if (error) throw error;\n this.events.emit(\"delete\", key as keyof Entity);\n }\n\n /**\n * Retrieves all entries from the database table, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Promise resolving to an array of entries or undefined if not found\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n let query = this.client.from(this.table).select(\"*\");\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length) {\n // Convert all columns from SQL to JS values\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n return data as Entity[];\n }\n return undefined;\n }\n\n /**\n * Deletes all rows from the database table.\n * @emits \"clearall\" event when successful\n */\n async deleteAll(): Promise<void> {\n // Use the first primary key column for the delete condition\n const firstPkColumn = this.primaryKeyNames[0];\n const { error } = await this.client.from(this.table).delete().neq(String(firstPkColumn), null); // Delete all rows by using a condition that's always true\n\n if (error) throw error;\n this.events.emit(\"clearall\");\n }\n\n /**\n * Returns the total number of rows in the database.\n *\n * @returns Promise resolving to the count of stored items\n */\n async size(): Promise<number> {\n const { count, error } = await this.client\n .from(this.table)\n .select(\"*\", { count: \"exact\", head: true });\n\n if (error) throw error;\n return count ?? 0;\n }\n\n /**\n * Fetches a page of records from the repository.\n * @param offset - Number of records to skip\n * @param limit - Maximum number of records to return\n * @returns Array of entities or undefined if no records found\n */\n async getBulk(offset: number, limit: number): Promise<Entity[] | undefined> {\n // Build the base query\n let query = this.client.from(this.table).select(\"*\");\n\n // Ensure deterministic ordering for pagination by ordering on primary key column(s)\n for (const pkName of this.primaryKeyNames) {\n query = query.order(String(pkName));\n }\n\n const { data, error } = await query.range(offset, offset + limit - 1);\n\n if (error) throw error;\n\n if (!data || data.length === 0) {\n return undefined;\n }\n\n // Convert all columns from SQL to JS values (consistent with getAll)\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n\n return data as Entity[];\n }\n\n /**\n * Applies criteria to a Supabase filter builder. Typed as `any` because the\n * `PostgrestFilterBuilder` generics are deep enough to trip TS2589.\n */\n private applyCriteriaToFilter<Q>(query: Q, criteria: SearchCriteria<Entity>): Q {\n let q = query as any;\n for (const column of Object.keys(criteria) as Array<keyof Entity>) {\n const criterion = criteria[column];\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n switch (operator) {\n case \"=\":\n q = q.eq(String(column), value);\n break;\n case \"<\":\n q = q.lt(String(column), value);\n break;\n case \"<=\":\n q = q.lte(String(column), value);\n break;\n case \">\":\n q = q.gt(String(column), value);\n break;\n case \">=\":\n q = q.gte(String(column), value);\n break;\n }\n }\n return q as Q;\n }\n\n /**\n * Counts rows matching the specified search criteria.\n */\n override async count(criteria?: SearchCriteria<Entity>): Promise<number> {\n if (!criteria || Object.keys(criteria).length === 0) {\n return await this.size();\n }\n\n this.validateQueryParams(criteria);\n const query = this.applyCriteriaToFilter(\n this.client.from(this.table).select(\"*\", { count: \"exact\", head: true }),\n criteria\n );\n\n const { count, error } = await query;\n if (error) throw error;\n return count ?? 0;\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Supports multiple columns with optional comparison operators.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n */\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaKeys.length === 0) {\n return;\n }\n\n let query = this.client.from(this.table).delete();\n\n for (const column of criteriaKeys) {\n if (!(column in this.schema.properties)) {\n throw new Error(`Schema must have a ${String(column)} field to use deleteSearch`);\n }\n\n const criterion = criteria[column];\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n switch (operator) {\n case \"=\":\n query = query.eq(String(column), value);\n break;\n case \"<\":\n query = query.lt(String(column), value);\n break;\n case \"<=\":\n query = query.lte(String(column), value);\n break;\n case \">\":\n query = query.gt(String(column), value);\n break;\n case \">=\":\n query = query.gte(String(column), value);\n break;\n }\n }\n\n const { error } = await query;\n\n if (error) throw error;\n this.events.emit(\"delete\", criteriaKeys[0] as keyof Entity);\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering, limit, and offset.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of matching entities or undefined if no matches found\n */\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n this.validateQueryParams(criteria, options);\n\n let query = this.applyCriteriaToFilter(this.client.from(this.table).select(\"*\"), criteria);\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n } else if (options?.limit !== undefined) {\n query = query.limit(options.limit);\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length > 0) {\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, data as Entity[]);\n return data as Entity[];\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n\n /**\n * Cursor-paginated read pushed into PostgREST. Builds a keyset OR-of-AND\n * filter via Supabase's `.or()` plus per-column `.order()` with explicit\n * `nullsFirst` so iteration semantics match the rest of the package\n * (NULLs sort before non-null for ASC, after for DESC). The pushdown\n * makes memory and wire traffic O(pageSize) regardless of table size,\n * unlike the in-memory base-class fallback which would full-table-scan.\n */\n override async getPage(request: PageRequest<Entity> = {}): Promise<Page<Entity>> {\n return this.runSupabasePage(undefined, request);\n }\n\n override async queryPage(\n criteria: SearchCriteria<Entity>,\n request: PageRequest<Entity> = {}\n ): Promise<Page<Entity>> {\n this.validateQueryParams(criteria, undefined);\n return this.runSupabasePage(criteria, request);\n }\n\n private async runSupabasePage(\n criteria: SearchCriteria<Entity> | undefined,\n request: PageRequest<Entity>\n ): Promise<Page<Entity>> {\n // Validate before we send column names through PostgREST filters or\n // ORDER BY — caller is the trust boundary for orderBy contents.\n this.validatePageRequest(request);\n const limit = request.limit ?? 100;\n const pkColumns = this.primaryKeyColumns() as unknown as Array<keyof Entity>;\n const orderBy = request.orderBy;\n const effectiveOrderBy = this.buildEffectiveOrderBy(orderBy, pkColumns);\n const effectiveOrderForCursor = effectiveOrderBy.map((o) => ({\n column: String(o.column),\n direction: o.direction,\n }));\n\n let cursorPayload;\n if (request.cursor !== undefined) {\n cursorPayload = decodeCursor(request.cursor);\n assertCursorMatches(cursorPayload, effectiveOrderForCursor);\n }\n\n let query: any = this.client.from(this.table).select(\"*\");\n if (criteria && Object.keys(criteria).length > 0) {\n query = this.applyCriteriaToFilter(query, criteria);\n }\n\n if (cursorPayload) {\n const filter = this.buildSupabaseKeysetFilter(effectiveOrderBy, cursorPayload.c);\n // `null` is the keyset builder's signal for \"no rows possible\" — e.g.\n // a DESC cursor parked on a NULL leading column; nothing comes after\n // a NULLs-last trailer. Short-circuit instead of issuing the query.\n if (filter === null) {\n return { items: [], nextCursor: undefined };\n }\n query = query.or(filter);\n }\n\n for (const { column, direction } of effectiveOrderBy) {\n query = query.order(String(column), {\n ascending: direction === \"ASC\",\n nullsFirst: direction === \"ASC\",\n });\n }\n query = query.limit(limit);\n\n const { data, error } = await query;\n if (error) throw error;\n\n const items = (data ?? []) as Entity[];\n for (const row of items) {\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\n const nextCursor =\n items.length === limit\n ? this.buildCursor(items[items.length - 1], effectiveOrderBy)\n : undefined;\n return { items, nextCursor };\n }\n\n /**\n * Builds a PostgREST OR-of-AND filter string for keyset pagination.\n * See {@link BaseSqlTabularStorage.buildKeysetWhere} for the canonical\n * description of the OR-of-AND form and NULL semantics; this is the\n * same logic translated to PostgREST's filter grammar.\n *\n * Returns `null` when *every* OR-clause is unreachable, which means the\n * caller can skip the round-trip — the page is unconditionally empty.\n * The common trigger is a single-column DESC orderBy parked on a NULL\n * cursor (no row comes after a NULLs-last trailer); compound orderings\n * with later tiebreaker columns will still produce reachable clauses\n * even when the leading cursor value is NULL.\n */\n private buildSupabaseKeysetFilter(\n orderBy: ReadonlyArray<{ column: keyof Entity; direction: \"ASC\" | \"DESC\" }>,\n cursorValues: ReadonlyArray<string | number | boolean | null>\n ): string | null {\n const orClauses: string[] = [];\n for (let i = 0; i < orderBy.length; i++) {\n const andParts: string[] = [];\n // Equality on preceding columns; collapse to `is.null` for null cursors\n // because PostgREST `eq.null` doesn't exist (and SQL semantics agree\n // that `col = NULL` is never true).\n for (let j = 0; j < i; j++) {\n const col = String(orderBy[j].column);\n const v = cursorValues[j];\n andParts.push(v === null ? `${col}.is.null` : `${col}.eq.${escapePostgrest(v)}`);\n }\n const col = String(orderBy[i].column);\n const v = cursorValues[i];\n const dir = orderBy[i].direction;\n let cmp: string;\n if (v === null) {\n if (dir === \"ASC\") {\n // ASC NULLS-FIRST: rows strictly after NULL on this column are\n // any non-null value.\n cmp = `${col}.not.is.null`;\n } else {\n // DESC NULLS-LAST: nothing comes strictly after a NULL on this\n // column. The i-th OR-clause contributes no rows — drop it. We\n // can't `return null`, because subsequent clauses (i+1, i+2, …)\n // can still produce matches via equality on the NULL preceding\n // columns plus a tiebreaker on a later column. Mirrors the\n // `1 = 0` predicate in `BaseSqlTabularStorage.buildKeysetWhere`.\n continue;\n }\n } else {\n if (dir === \"ASC\") {\n cmp = `${col}.gt.${escapePostgrest(v)}`;\n } else {\n // Smaller than the cursor, then NULLs-last trailer.\n cmp = `or(${col}.lt.${escapePostgrest(v)},${col}.is.null)`;\n }\n }\n andParts.push(cmp);\n orClauses.push(andParts.length === 1 ? andParts[0] : `and(${andParts.join(\",\")})`);\n }\n if (orClauses.length === 0) return null;\n return orClauses.join(\",\");\n }\n\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n this.validateSelect(options);\n this.validateQueryParams(criteria, options);\n\n const registered = this.indexes.map((cols, i) => {\n const cs = Array.isArray(cols) ? (cols as string[]) : [cols as string];\n return { name: `idx_${i}`, keyPath: cs };\n });\n\n pickCoveringIndex({\n table: this.table,\n indexes: registered,\n criteriaColumns: Object.keys(criteria),\n orderByColumns: (options.orderBy ?? []).map((o) => ({\n column: String(o.column),\n direction: o.direction,\n })),\n selectColumns: options.select.map(String),\n primaryKeyColumns: this.primaryKeyNames.map(String),\n });\n\n const colList = options.select.map(String).join(\",\");\n let q = this.applyCriteriaToFilter(this.client.from(this.table).select(colList), criteria);\n\n if (options.orderBy) {\n for (const { column, direction } of options.orderBy) {\n q = q.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n if (options.offset !== undefined && options.limit === undefined) {\n throw new StorageValidationError(\"queryIndex with offset requires limit (no implicit cap)\");\n }\n if (options.offset !== undefined || options.limit !== undefined) {\n const start = options.offset ?? 0;\n if (options.limit !== undefined) {\n q = q.range(start, start + options.limit - 1);\n }\n }\n\n const { data, error } = await q;\n if (error) throw error;\n if (!data) return [];\n\n const rows = data as unknown as Record<string, unknown>[];\n const sel = new Set(options.select.map(String));\n for (const row of rows) {\n for (const key of Object.keys(row)) {\n if (sel.has(key)) {\n row[key] = this.sqlToJsValue(key, row[key] as ValueOptionType);\n }\n }\n }\n return rows as unknown as Pick<Entity, K>[];\n }\n\n /**\n * Converts a row from Supabase realtime payload to an Entity with proper type conversions.\n *\n * @param row - The raw row data from Supabase realtime\n * @returns The converted entity\n */\n private convertRealtimeRow(row: Record<string, unknown>): Entity {\n const entity = { ...row } as Entity;\n const record = entity as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, row[key] as ValueOptionType);\n }\n return entity;\n }\n\n /**\n * Subscribes to changes in the repository using Supabase realtime.\n * Receives notifications for INSERT, UPDATE, and DELETE operations from any source.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (not used for Supabase realtime)\n * @returns Unsubscribe function\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Create a unique channel name\n const channelName = `tabular-${this.table}-${Date.now()}`;\n\n this.realtimeChannel = this.client\n .channel(channelName)\n .on(\n \"postgres_changes\",\n {\n event: \"*\",\n schema: \"public\",\n table: this.table,\n },\n (payload) => {\n const change: TabularChangePayload<Entity> = {\n type: payload.eventType.toUpperCase() as TabularChangeType,\n old:\n payload.old && Object.keys(payload.old).length > 0\n ? this.convertRealtimeRow(payload.old)\n : undefined,\n new:\n payload.new && Object.keys(payload.new).length > 0\n ? this.convertRealtimeRow(payload.new)\n : undefined,\n };\n callback(change);\n }\n )\n .subscribe();\n\n return () => {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n };\n }\n\n /**\n * **Best-effort, non-atomic.** Supabase exposes PostgREST, not a session-\n * level transaction surface this client can drive — there is no\n * `BEGIN`/`COMMIT`/`ROLLBACK` over the wire. The override exists only to\n * make the no-rollback semantics explicit instead of inheriting the base\n * default silently: `fn` runs to completion against `this`, the result\n * propagates, and any partial writes survive a thrown `fn`. Use a\n * stored-procedure / RPC if you need true atomicity on Supabase.\n */\n public override async withTransaction<T>(fn: (tx: this) => Promise<T>): Promise<T> {\n return fn(this);\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n public override destroy(): void {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n }\n}\n"
6
+ "/**\n * @license\n * Copyright 2025 Steven Roussey <sroussey@gmail.com>\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport type { RealtimeChannel, SupabaseClient } from \"@supabase/supabase-js\";\nimport { createServiceToken, uuid4 } from \"@workglow/util\";\nimport {\n DataPortSchemaObject,\n FromSchema,\n JsonSchema,\n TypedArraySchemaOptions,\n} from \"@workglow/util/schema\";\nimport {\n BaseSqlTabularStorage,\n ClientProvidedKeysOption,\n AnyTabularStorage,\n AutoGeneratedKeys,\n CoveringIndexQueryOptions,\n DeleteSearchCriteria,\n InsertEntity,\n isSearchCondition,\n Page,\n PageRequest,\n QueryOptions,\n SearchCriteria,\n SearchOperator,\n SimplifyPrimaryKey,\n TabularChangePayload,\n TabularChangeType,\n TabularSubscribeOptions,\n ValueOptionType,\n pickCoveringIndex,\n StorageValidationError,\n assertCursorMatches,\n decodeCursor,\n} from \"@workglow/storage\";\n\n/**\n * Quotes a value for inclusion in a PostgREST filter expression.\n *\n * PostgREST treats commas, periods, parentheses, colons, double-quotes,\n * and whitespace as filter syntax delimiters; values containing any of\n * these need to be wrapped in double-quotes (with embedded `\"` and `\\`\n * escaped). ISO timestamps contain dots, so most non-trivial values need\n * quoting. We err on the side of quoting anything that isn't a clean\n * integer or boolean — false positives are cheap; false negatives produce\n * malformed filters that PostgREST silently mis-parses.\n */\nfunction escapePostgrest(value: string | number | boolean | null): string {\n if (value === null) return \"null\";\n if (typeof value === \"boolean\") return value ? \"true\" : \"false\";\n if (typeof value === \"number\" && Number.isInteger(value)) return String(value);\n const s = String(value);\n return `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\nexport const SUPABASE_TABULAR_REPOSITORY = createServiceToken<AnyTabularStorage>(\n \"storage.tabularRepository.supabase\"\n);\n\n/**\n * A Supabase-based tabular repository implementation that extends BaseSqlTabularStorage.\n * This class provides persistent storage for data in a Supabase database,\n * making it suitable for multi-user scenarios.\n *\n * @template Schema - The schema definition for the entity\n * @template PrimaryKeyNames - Array of property names that form the primary key\n */\nexport class SupabaseTabularStorage<\n Schema extends DataPortSchemaObject,\n PrimaryKeyNames extends ReadonlyArray<keyof Schema[\"properties\"]>,\n // computed types\n Entity = FromSchema<Schema, TypedArraySchemaOptions>,\n PrimaryKey = SimplifyPrimaryKey<Entity, PrimaryKeyNames>,\n Value = Omit<Entity, PrimaryKeyNames[number] & keyof Entity>,\n InsertType extends InsertEntity<Entity, AutoGeneratedKeys<Schema>> = InsertEntity<\n Entity,\n AutoGeneratedKeys<Schema>\n >,\n> extends BaseSqlTabularStorage<Schema, PrimaryKeyNames, Entity, PrimaryKey, Value, InsertType> {\n protected readonly client: SupabaseClient;\n private realtimeChannel: RealtimeChannel | null = null;\n\n /**\n * Creates a new SupabaseTabularStorage instance.\n *\n * @param client - Supabase client instance\n * @param table - Name of the table to store data (defaults to \"tabular_store\")\n * @param schema - Schema defining the structure of the entity\n * @param primaryKeyNames - Array of property names that form the primary key\n * @param indexes - Array of columns or column arrays to make searchable. Each string or single column creates a single-column index,\n * while each array creates a compound index with columns in the specified order.\n * @param clientProvidedKeys - How to handle client-provided values for auto-generated keys\n */\n constructor(\n client: unknown,\n table: string = \"tabular_store\",\n schema: Schema,\n primaryKeyNames: PrimaryKeyNames,\n indexes: readonly (keyof NoInfer<Entity> | readonly (keyof NoInfer<Entity>)[])[] = [],\n clientProvidedKeys: ClientProvidedKeysOption = \"if-missing\"\n ) {\n super(table, schema, primaryKeyNames, indexes, clientProvidedKeys);\n this.client = client as SupabaseClient;\n }\n\n /**\n * Initializes the database table with the required schema.\n * Creates the table if it doesn't exist with primary key and value columns.\n * Must be called before using any other methods.\n */\n public override async setupDatabase(): Promise<void> {\n const sql = `\n CREATE TABLE IF NOT EXISTS \"${this.table}\" (\n ${this.constructPrimaryKeyColumns('\"')} ${this.constructValueColumns('\"')},\n PRIMARY KEY (${this.primaryKeyColumnList()}) \n )\n `;\n const { error } = await this.client.rpc(\"exec_sql\", { query: sql });\n if (error && !error.message.includes(\"already exists\")) {\n throw error;\n }\n\n // Get primary key columns to avoid creating redundant indexes\n const pkColumns = this.primaryKeyColumns();\n\n // Track created indexes to avoid duplicates and redundant indexes\n const createdIndexes = new Set<string>();\n\n for (const columns of this.indexes) {\n // Skip if this is just the primary key or a prefix of it\n if (columns.length <= pkColumns.length) {\n // @ts-ignore\n const isPkPrefix = columns.every((col, idx) => col === pkColumns[idx]);\n if (isPkPrefix) continue;\n }\n\n // Create index name and column list\n const indexName = `${this.table}_${columns.join(\"_\")}`;\n const columnList = columns.map((col) => `\"${String(col)}\"`).join(\", \");\n\n // Skip if we've already created this index or if it's redundant\n const columnKey = columns.join(\",\");\n if (createdIndexes.has(columnKey)) continue;\n\n // Check if this index would be redundant with an existing one\n const isRedundant = Array.from(createdIndexes).some((existing) => {\n const existingCols = existing.split(\",\");\n return (\n existingCols.length >= columns.length &&\n columns.every((col, idx) => col === existingCols[idx])\n );\n });\n\n if (!isRedundant) {\n const indexSql = `CREATE INDEX IF NOT EXISTS \"${indexName}\" ON \"${this.table}\" (${columnList})`;\n const { error: indexError } = await this.client.rpc(\"exec_sql\", { query: indexSql });\n if (indexError && !indexError.message.includes(\"already exists\")) {\n // Index creation errors are not critical, log and continue\n console.warn(`Failed to create index ${indexName}:`, indexError);\n }\n createdIndexes.add(columnKey);\n }\n }\n }\n\n /**\n * Maps TypeScript/JavaScript types to corresponding PostgreSQL data types.\n * Uses additional schema information like minimum/maximum values, nullable status,\n * and string lengths to create more optimized column types.\n *\n * @param typeDef - The TypeScript/JavaScript type to map\n * @returns The corresponding PostgreSQL data type\n */\n protected override mapTypeToSQL(typeDef: JsonSchema): string {\n // Extract the actual non-null type using base helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return \"TEXT /* boolean schema */\";\n }\n\n // Handle BLOB type\n if (actualType.contentEncoding === \"blob\") return \"BYTEA\";\n\n switch (actualType.type) {\n case \"string\":\n // Handle special string formats\n if (actualType.format === \"date-time\") return \"TIMESTAMP\";\n if (actualType.format === \"date\") return \"DATE\";\n if (actualType.format === \"email\") return \"VARCHAR(255)\";\n if (actualType.format === \"uri\") return \"VARCHAR(2048)\";\n if (actualType.format === \"uuid\") return \"UUID\";\n\n // Use a VARCHAR with maxLength if specified\n if (typeof actualType.maxLength === \"number\") {\n return `VARCHAR(${actualType.maxLength})`;\n }\n\n // Default to TEXT for strings without constraints\n return \"TEXT\";\n\n case \"number\":\n case \"integer\":\n // Handle integer vs floating point\n if (actualType.multipleOf === 1 || actualType.type === \"integer\") {\n // Use PostgreSQL's numeric range types based on min/max values\n if (typeof actualType.minimum === \"number\") {\n if (actualType.minimum >= 0) {\n // For unsigned integers\n if (typeof actualType.maximum === \"number\") {\n if (actualType.maximum <= 32767) return \"SMALLINT\";\n if (actualType.maximum <= 2147483647) return \"INTEGER\";\n }\n return \"BIGINT\";\n }\n }\n\n // Default integer type\n return \"INTEGER\";\n }\n\n // For floating point numbers with precision requirements\n if (actualType.format === \"float\") return \"REAL\";\n if (actualType.format === \"double\") return \"DOUBLE PRECISION\";\n\n // Use NUMERIC with precision/scale if specified\n if (typeof actualType.multipleOf === \"number\") {\n const decimalPlaces = String(actualType.multipleOf).split(\".\")[1]?.length || 0;\n if (decimalPlaces > 0) {\n return `NUMERIC(38, ${decimalPlaces})`;\n }\n }\n\n return \"NUMERIC\";\n\n case \"boolean\":\n return \"BOOLEAN\";\n\n case \"array\":\n // Handle array types (if items type is specified)\n if (\n actualType.items &&\n typeof actualType.items === \"object\" &&\n !Array.isArray(actualType.items)\n ) {\n const itemType = this.mapTypeToSQL(actualType.items as JsonSchema);\n\n // Only use native PostgreSQL arrays for simple scalar types\n // List of types that work well as native PostgreSQL arrays\n const supportedArrayElementTypes = [\n \"TEXT\",\n \"VARCHAR\",\n \"CHAR\",\n \"INTEGER\",\n \"SMALLINT\",\n \"BIGINT\",\n \"REAL\",\n \"DOUBLE PRECISION\",\n \"NUMERIC\",\n \"BOOLEAN\",\n \"UUID\",\n \"DATE\",\n \"TIMESTAMP\",\n ];\n\n // Check if the item type is in our supported list (either exact match or starts with for VARCHAR types)\n const isSupported = supportedArrayElementTypes.some(\n (type) => itemType === type || (itemType.startsWith(type + \"(\") && type !== \"VARCHAR\") // Handle things like VARCHAR(255)\n );\n\n if (isSupported) {\n return `${itemType}[]`;\n } else {\n return \"JSONB /* complex array */\";\n }\n }\n return \"JSONB /* generic array */\";\n\n case \"object\":\n return \"JSONB /* object */\";\n\n default:\n return \"TEXT /* unknown type */\";\n }\n }\n\n /**\n * Generates the SQL column definitions for primary key fields with constraints\n * Handles auto-generated keys using SERIAL for integers and UUID DEFAULT for strings\n * @returns SQL string containing primary key column definitions\n */\n protected override constructPrimaryKeyColumns($delimiter: string = \"\"): string {\n const cols = Object.entries<JsonSchema>(this.primaryKeySchema.properties)\n .map(([key, typeDef]) => {\n // Check if this is an auto-generated key\n if (this.isAutoGeneratedKey(key)) {\n if (this.autoGeneratedKeyStrategy === \"autoincrement\") {\n // Use SERIAL or BIGSERIAL for auto-increment\n const sqlType = this.mapTypeToSQL(typeDef);\n const isSmallInt = sqlType.includes(\"SMALLINT\");\n const isBigInt = sqlType.includes(\"BIGINT\");\n const serialType = isBigInt ? \"BIGSERIAL\" : isSmallInt ? \"SMALLSERIAL\" : \"SERIAL\";\n return `${$delimiter}${key}${$delimiter} ${serialType}`;\n } else if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // Use UUID with DEFAULT gen_random_uuid()\n return `${$delimiter}${key}${$delimiter} UUID DEFAULT gen_random_uuid()`;\n }\n }\n\n const sqlType = this.mapTypeToSQL(typeDef);\n let constraints = \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${$delimiter}${key}${$delimiter} >= 0)`;\n }\n\n return `${$delimiter}${key}${$delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n return cols;\n }\n\n /**\n * Generates the SQL column definitions for value fields with constraints\n * @returns SQL string containing value column definitions\n */\n protected override constructValueColumns($delimiter: string = \"\"): string {\n const delimiter = $delimiter || '\"';\n const requiredSet = new Set(this.valueSchema.required ?? []);\n const cols = Object.entries<JsonSchema>(this.valueSchema.properties)\n .map(([key, typeDef]) => {\n const sqlType = this.mapTypeToSQL(typeDef);\n const isRequired = requiredSet.has(key);\n const nullable = !isRequired || this.isNullable(typeDef);\n let constraints = nullable ? \"NULL\" : \"NOT NULL\";\n\n // Add CHECK constraint for unsigned numbers\n if (this.shouldBeUnsigned(typeDef)) {\n constraints += ` CHECK (${delimiter}${key}${delimiter} >= 0)`;\n }\n\n return `${delimiter}${key}${delimiter} ${sqlType} ${constraints}`;\n })\n .join(\", \");\n if (cols.length > 0) {\n return `, ${cols}`;\n } else {\n return \"\";\n }\n }\n\n /**\n * Convert Supabase values to JS values. Ensures numeric strings become numbers where schema says number.\n */\n protected override sqlToJsValue(column: string, value: ValueOptionType): Entity[keyof Entity] {\n const typeDef = this.schema.properties[column as keyof typeof this.schema.properties] as\n | JsonSchema\n | undefined;\n if (typeDef) {\n if (value === null && this.isNullable(typeDef)) {\n return null as Entity[keyof Entity];\n }\n const actualType = this.getNonNullType(typeDef);\n\n // Handle numeric types - Supabase can return them as strings\n if (\n typeof actualType !== \"boolean\" &&\n (actualType.type === \"number\" || actualType.type === \"integer\")\n ) {\n if (typeof value === \"number\") return value as Entity[keyof Entity];\n if (typeof value === \"string\") {\n const parsed = Number(value);\n if (!isNaN(parsed)) return parsed as Entity[keyof Entity];\n }\n }\n }\n return super.sqlToJsValue(column, value);\n }\n\n /**\n * Determines if a field should be treated as unsigned based on schema properties\n * @param typeDef - The schema type definition\n * @returns true if the field should be treated as unsigned\n */\n protected shouldBeUnsigned(typeDef: JsonSchema): boolean {\n // Extract the non-null type using the base class helper\n const actualType = this.getNonNullType(typeDef);\n if (typeof actualType === \"boolean\") {\n return false;\n }\n\n // Check if it's a number type with minimum >= 0\n if (\n (actualType.type === \"number\" || actualType.type === \"integer\") &&\n typeof actualType.minimum === \"number\" &&\n actualType.minimum >= 0\n ) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Stores or updates a row in the database.\n * Uses UPSERT (INSERT ... ON CONFLICT DO UPDATE) for atomic operations.\n *\n * @param entity - The entity to store (may be missing auto-generated keys)\n * @returns The entity with any server-generated fields updated\n * @emits \"put\" event with the updated entity when successful\n */\n /**\n * Apply the auto-generated-key policy and the optional-field-to-null\n * normalization that Supabase's REST upsert expects. Shared by {@link put}\n * and {@link putBulk} so a row goes over the wire identically regardless of\n * whether it was inserted alone or as part of a batch.\n *\n * For UUID-strategy auto-gen keys we generate the UUID client-side rather\n * than letting `gen_random_uuid()` fill it server-side. Otherwise the input\n * row has no primary key, and {@link putBulk}'s ordering-preservation step\n * (re-keying the response by PK) cannot work — `result[i]` would no longer\n * be guaranteed to correspond to `values[i]`. SQLite's UUID path uses the\n * same trick.\n */\n private normalizeForUpsert(entity: InsertType): Record<string, unknown> {\n const entityToInsert = { ...entity } as Record<string, unknown>;\n\n if (this.hasAutoGeneratedKey() && this.autoGeneratedKeyName) {\n const keyName = String(this.autoGeneratedKeyName);\n const clientProvidedValue = entityToInsert[keyName];\n const hasClientValue = clientProvidedValue !== undefined && clientProvidedValue !== null;\n\n let shouldFillKey = false;\n if (this.clientProvidedKeys === \"never\") {\n shouldFillKey = true;\n } else if (this.clientProvidedKeys === \"always\") {\n if (!hasClientValue) {\n throw new Error(\n `Auto-generated key \"${keyName}\" is required when clientProvidedKeys is \"always\"`\n );\n }\n shouldFillKey = false;\n } else {\n shouldFillKey = !hasClientValue;\n }\n\n if (shouldFillKey) {\n if (this.autoGeneratedKeyStrategy === \"uuid\") {\n // Generate client-side so the input carries a PK and the bulk\n // response can be re-aligned to input order.\n entityToInsert[keyName] = uuid4();\n } else {\n // Autoincrement integer keys cannot be generated client-side; let\n // Postgres fill via SERIAL. putBulk falls back to response order in\n // this case (and Postgres preserves INSERT ... RETURNING order in\n // practice).\n delete entityToInsert[keyName];\n }\n }\n }\n\n // Normalize optional fields: convert undefined to null for optional fields\n const requiredSet = new Set(this.valueSchema.required ?? []);\n for (const key in this.valueSchema.properties) {\n if (!(key in entityToInsert) || entityToInsert[key] === undefined) {\n if (!requiredSet.has(key)) {\n entityToInsert[key] = null;\n }\n }\n }\n\n return entityToInsert;\n }\n\n /** Hydrate a row returned by Supabase 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 async put(entity: InsertType): Promise<Entity> {\n const normalizedEntity = this.normalizeForUpsert(entity);\n const { data, error } = await this.client\n .from(this.table)\n .upsert(normalizedEntity, { onConflict: this.primaryKeyColumnList() })\n .select()\n .single();\n\n if (error) throw error;\n const updatedEntity = this.hydrateRow(data);\n\n this.events.emit(\"put\", updatedEntity);\n return updatedEntity;\n }\n\n /**\n * Stores multiple rows by issuing a single PostgREST `upsert` carrying every\n * row in one request. PostgREST runs the underlying `INSERT ... ON CONFLICT`\n * inside one server-side transaction, so this is both atomic and a single\n * round trip — far cheaper than `Promise.all` fanning out one HTTPS request\n * per row.\n *\n * **Ordering:** {@link normalizeForUpsert} fills UUID auto-gen keys\n * client-side, so for the common UUID case every input row carries a PK\n * and the response is re-aligned to input order by primary-key match. The\n * only remaining case where ordering relies on Postgres's `INSERT ...\n * RETURNING` row order (stable in practice but not formally contracted) is\n * autoincrement-integer auto-gen keys, where the database has to assign\n * the key.\n *\n * `put` events are deferred until after the upsert resolves so listeners do\n * not see rows from a request that ultimately failed.\n */\n async putBulk(entities: InsertType[]): Promise<Entity[]> {\n if (entities.length === 0) return [];\n\n const normalizedEntities = entities.map((entity) => this.normalizeForUpsert(entity));\n const { data, error } = await this.client\n .from(this.table)\n .upsert(normalizedEntities, { onConflict: this.primaryKeyColumnList() })\n .select();\n\n if (error) throw error;\n if (!data) return [];\n\n const returnedRows = (data as unknown[]).map((row) => this.hydrateRow(row));\n\n // Reorder by primary key when every input row carries its full PK. With an\n // auto-generated key omitted from the input, we have no key to match on,\n // so trust the response order (Postgres's INSERT ... RETURNING preserves\n // VALUES order in practice).\n const orderedEntities = this.alignBulkResponseToInputOrder(normalizedEntities, returnedRows);\n\n for (const entity of orderedEntities) {\n this.events.emit(\"put\", entity);\n }\n return orderedEntities;\n }\n\n /**\n * If every input row supplies its full primary key, build a PK index over\n * the response and emit rows in input order. Otherwise return the response\n * as-is — there is no key to match on, so we have to trust the backend.\n */\n private alignBulkResponseToInputOrder(\n inputs: ReadonlyArray<Record<string, unknown>>,\n responseRows: Entity[]\n ): Entity[] {\n if (inputs.length !== responseRows.length) {\n // Server returned a different cardinality (e.g. dedup); fall back to as-is.\n return responseRows;\n }\n const pkColumns = this.primaryKeyColumns().map(String);\n for (const input of inputs) {\n for (const col of pkColumns) {\n if (input[col] === undefined || input[col] === null) {\n return responseRows;\n }\n }\n }\n\n const fingerprint = (row: Record<string, unknown>): string =>\n pkColumns.map((c) => String(row[c])).join(\"\u0000\");\n\n const responseByPk = new Map<string, Entity>();\n for (const row of responseRows) {\n responseByPk.set(fingerprint(row as unknown as Record<string, unknown>), row);\n }\n\n const ordered: Entity[] = [];\n for (const input of inputs) {\n const match = responseByPk.get(fingerprint(input));\n if (!match) return responseRows; // unexpected; fall back\n ordered.push(match);\n }\n return ordered;\n }\n\n /**\n * Retrieves a value from the database by its primary key.\n *\n * @param key - The primary key object to look up\n * @returns The stored entity or undefined if not found\n * @emits \"get\" event with the key when successful\n */\n async get(key: PrimaryKey): Promise<Entity | undefined> {\n let query = this.client.from(this.table).select(\"*\");\n\n // Build the where clause from primary key\n const keyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), keyRecord[String(pkName)]);\n }\n\n const { data, error } = await query.single();\n\n if (error) {\n if (error.code === \"PGRST116\") {\n // Not found\n this.events.emit(\"get\", key, undefined);\n return undefined;\n }\n throw error;\n }\n\n const val = data as Entity | undefined;\n if (val) {\n // Convert all columns from SQL to JS values\n const valRecord = val as Record<string, unknown>;\n for (const key in this.schema.properties) {\n valRecord[key] = this.sqlToJsValue(key, valRecord[key] as ValueOptionType);\n }\n }\n this.events.emit(\"get\", key, val);\n return val;\n }\n\n /**\n * Deletes a row from the database.\n *\n * @param value - The primary key object or entity to delete\n * @emits \"delete\" event with the key when successful\n */\n async delete(value: PrimaryKey | Entity): Promise<void> {\n const { key } = this.separateKeyValueFromCombined(value as Entity);\n\n let query = this.client.from(this.table).delete();\n\n // Build the where clause from primary key\n const deleteKeyRecord = key as Record<string, unknown>;\n for (const pkName of this.primaryKeyNames) {\n query = query.eq(String(pkName), deleteKeyRecord[String(pkName)]);\n }\n\n const { error } = await query;\n\n if (error) throw error;\n this.events.emit(\"delete\", key as keyof Entity);\n }\n\n /**\n * Retrieves all entries from the database table, with optional ordering, offset, and limit.\n * @param options - Optional ordering, limit, and offset options\n * @returns Promise resolving to an array of entries or undefined if not found\n */\n async getAll(options?: QueryOptions<Entity>): Promise<Entity[] | undefined> {\n this.validateGetAllOptions(options);\n let query = this.client.from(this.table).select(\"*\");\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length) {\n // Convert all columns from SQL to JS values\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n return data as Entity[];\n }\n return undefined;\n }\n\n /**\n * Deletes all rows from the database table.\n * @emits \"clearall\" event when successful\n */\n async deleteAll(): Promise<void> {\n // Use the first primary key column for the delete condition\n const firstPkColumn = this.primaryKeyNames[0];\n const { error } = await this.client.from(this.table).delete().neq(String(firstPkColumn), null); // Delete all rows by using a condition that's always true\n\n if (error) throw error;\n this.events.emit(\"clearall\");\n }\n\n /**\n * Returns the total number of rows in the database.\n *\n * @returns Promise resolving to the count of stored items\n */\n async size(): Promise<number> {\n const { count, error } = await this.client\n .from(this.table)\n .select(\"*\", { count: \"exact\", head: true });\n\n if (error) throw error;\n return count ?? 0;\n }\n\n /**\n * Fetches a page of records from the repository using offset-based paging.\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 * @deprecated Offset-based paging is unstable under concurrent writes.\n * Use {@link getPage} for stable, keyset-based pagination.\n */\n async getOffsetPage(offset: number, limit: number): Promise<Entity[] | undefined> {\n // Build the base query\n let query = this.client.from(this.table).select(\"*\");\n\n // Ensure deterministic ordering for pagination by ordering on primary key column(s)\n for (const pkName of this.primaryKeyNames) {\n query = query.order(String(pkName));\n }\n\n const { data, error } = await query.range(offset, offset + limit - 1);\n\n if (error) throw error;\n\n if (!data || data.length === 0) {\n return undefined;\n }\n\n // Convert all columns from SQL to JS values (consistent with getAll)\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n\n return data as Entity[];\n }\n\n /**\n * Applies criteria to a Supabase filter builder. Typed as `any` because the\n * `PostgrestFilterBuilder` generics are deep enough to trip TS2589.\n */\n private applyCriteriaToFilter<Q>(query: Q, criteria: SearchCriteria<Entity>): Q {\n let q = query as any;\n for (const column of Object.keys(criteria) as Array<keyof Entity>) {\n const criterion = criteria[column];\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n switch (operator) {\n case \"=\":\n q = q.eq(String(column), value);\n break;\n case \"<\":\n q = q.lt(String(column), value);\n break;\n case \"<=\":\n q = q.lte(String(column), value);\n break;\n case \">\":\n q = q.gt(String(column), value);\n break;\n case \">=\":\n q = q.gte(String(column), value);\n break;\n }\n }\n return q as Q;\n }\n\n /**\n * Counts rows matching the specified search criteria.\n */\n override async count(criteria?: SearchCriteria<Entity>): Promise<number> {\n if (!criteria || Object.keys(criteria).length === 0) {\n return await this.size();\n }\n\n this.validateQueryParams(criteria);\n const query = this.applyCriteriaToFilter(\n this.client.from(this.table).select(\"*\", { count: \"exact\", head: true }),\n criteria\n );\n\n const { count, error } = await query;\n if (error) throw error;\n return count ?? 0;\n }\n\n /**\n * Deletes all entries matching the specified search criteria.\n * Supports multiple columns with optional comparison operators.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n */\n async deleteSearch(criteria: DeleteSearchCriteria<Entity>): Promise<void> {\n const criteriaKeys = Object.keys(criteria) as Array<keyof Entity>;\n if (criteriaKeys.length === 0) {\n return;\n }\n\n let query = this.client.from(this.table).delete();\n\n for (const column of criteriaKeys) {\n if (!(column in this.schema.properties)) {\n throw new Error(`Schema must have a ${String(column)} field to use deleteSearch`);\n }\n\n const criterion = criteria[column];\n let operator: SearchOperator = \"=\";\n let value: Entity[keyof Entity];\n\n if (isSearchCondition(criterion)) {\n operator = criterion.operator;\n value = criterion.value as Entity[keyof Entity];\n } else {\n value = criterion as Entity[keyof Entity];\n }\n\n switch (operator) {\n case \"=\":\n query = query.eq(String(column), value);\n break;\n case \"<\":\n query = query.lt(String(column), value);\n break;\n case \"<=\":\n query = query.lte(String(column), value);\n break;\n case \">\":\n query = query.gt(String(column), value);\n break;\n case \">=\":\n query = query.gte(String(column), value);\n break;\n }\n }\n\n const { error } = await query;\n\n if (error) throw error;\n this.events.emit(\"delete\", criteriaKeys[0] as keyof Entity);\n }\n\n /**\n * Queries entries matching the specified search criteria with optional ordering, limit, and offset.\n *\n * @param criteria - Object with column names as keys and values or SearchConditions\n * @param options - Optional ordering, limit, and offset options\n * @returns Array of matching entities or undefined if no matches found\n */\n async query(\n criteria: SearchCriteria<Entity>,\n options?: QueryOptions<Entity>\n ): Promise<Entity[] | undefined> {\n this.validateQueryParams(criteria, options);\n\n let query = this.applyCriteriaToFilter(this.client.from(this.table).select(\"*\"), criteria);\n\n if (options?.orderBy) {\n for (const { column, direction } of options.orderBy) {\n query = query.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n\n if (options?.offset !== undefined || options?.limit !== undefined) {\n const start = options?.offset ?? 0;\n if (options?.limit !== undefined) {\n query = query.range(start, start + options.limit - 1);\n } else if (options?.offset !== undefined) {\n query = query.range(start, start + 999999);\n }\n } else if (options?.limit !== undefined) {\n query = query.limit(options.limit);\n }\n\n const { data, error } = await query;\n\n if (error) throw error;\n\n if (data && data.length > 0) {\n for (const row of data) {\n const record = row as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, record[key] as ValueOptionType);\n }\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, data as Entity[]);\n return data as Entity[];\n }\n this.events.emit(\"query\", criteria as Partial<Entity>, undefined);\n return undefined;\n }\n\n /**\n * Cursor-paginated read pushed into PostgREST. Builds a keyset OR-of-AND\n * filter via Supabase's `.or()` plus per-column `.order()` with explicit\n * `nullsFirst` so iteration semantics match the rest of the package\n * (NULLs sort before non-null for ASC, after for DESC). The pushdown\n * makes memory and wire traffic O(pageSize) regardless of table size,\n * unlike the in-memory base-class fallback which would full-table-scan.\n */\n override async getPage(request: PageRequest<Entity> = {}): Promise<Page<Entity>> {\n return this.runSupabasePage(undefined, request);\n }\n\n override async queryPage(\n criteria: SearchCriteria<Entity>,\n request: PageRequest<Entity> = {}\n ): Promise<Page<Entity>> {\n this.validateQueryParams(criteria, undefined);\n return this.runSupabasePage(criteria, request);\n }\n\n private async runSupabasePage(\n criteria: SearchCriteria<Entity> | undefined,\n request: PageRequest<Entity>\n ): Promise<Page<Entity>> {\n // Validate before we send column names through PostgREST filters or\n // ORDER BY — caller is the trust boundary for orderBy contents.\n this.validatePageRequest(request);\n const limit = request.limit ?? 100;\n const pkColumns = this.primaryKeyColumns() as unknown as Array<keyof Entity>;\n const orderBy = request.orderBy;\n const effectiveOrderBy = this.buildEffectiveOrderBy(orderBy, pkColumns);\n const effectiveOrderForCursor = effectiveOrderBy.map((o) => ({\n column: String(o.column),\n direction: o.direction,\n }));\n\n let cursorPayload;\n if (request.cursor !== undefined) {\n cursorPayload = decodeCursor(request.cursor);\n assertCursorMatches(cursorPayload, effectiveOrderForCursor);\n }\n\n let query: any = this.client.from(this.table).select(\"*\");\n if (criteria && Object.keys(criteria).length > 0) {\n query = this.applyCriteriaToFilter(query, criteria);\n }\n\n if (cursorPayload) {\n const filter = this.buildSupabaseKeysetFilter(effectiveOrderBy, cursorPayload.c);\n // `null` is the keyset builder's signal for \"no rows possible\" — e.g.\n // a DESC cursor parked on a NULL leading column; nothing comes after\n // a NULLs-last trailer. Short-circuit instead of issuing the query.\n if (filter === null) {\n return { items: [], nextCursor: undefined };\n }\n query = query.or(filter);\n }\n\n for (const { column, direction } of effectiveOrderBy) {\n query = query.order(String(column), {\n ascending: direction === \"ASC\",\n nullsFirst: direction === \"ASC\",\n });\n }\n query = query.limit(limit);\n\n const { data, error } = await query;\n if (error) throw error;\n\n const items = (data ?? []) as Entity[];\n for (const row of items) {\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\n const nextCursor =\n items.length === limit\n ? this.buildCursor(items[items.length - 1], effectiveOrderBy)\n : undefined;\n return { items, nextCursor };\n }\n\n /**\n * Builds a PostgREST OR-of-AND filter string for keyset pagination.\n * See {@link BaseSqlTabularStorage.buildKeysetWhere} for the canonical\n * description of the OR-of-AND form and NULL semantics; this is the\n * same logic translated to PostgREST's filter grammar.\n *\n * Returns `null` when *every* OR-clause is unreachable, which means the\n * caller can skip the round-trip — the page is unconditionally empty.\n * The common trigger is a single-column DESC orderBy parked on a NULL\n * cursor (no row comes after a NULLs-last trailer); compound orderings\n * with later tiebreaker columns will still produce reachable clauses\n * even when the leading cursor value is NULL.\n */\n private buildSupabaseKeysetFilter(\n orderBy: ReadonlyArray<{ column: keyof Entity; direction: \"ASC\" | \"DESC\" }>,\n cursorValues: ReadonlyArray<string | number | boolean | null>\n ): string | null {\n const orClauses: string[] = [];\n for (let i = 0; i < orderBy.length; i++) {\n const andParts: string[] = [];\n // Equality on preceding columns; collapse to `is.null` for null cursors\n // because PostgREST `eq.null` doesn't exist (and SQL semantics agree\n // that `col = NULL` is never true).\n for (let j = 0; j < i; j++) {\n const col = String(orderBy[j].column);\n const v = cursorValues[j];\n andParts.push(v === null ? `${col}.is.null` : `${col}.eq.${escapePostgrest(v)}`);\n }\n const col = String(orderBy[i].column);\n const v = cursorValues[i];\n const dir = orderBy[i].direction;\n let cmp: string;\n if (v === null) {\n if (dir === \"ASC\") {\n // ASC NULLS-FIRST: rows strictly after NULL on this column are\n // any non-null value.\n cmp = `${col}.not.is.null`;\n } else {\n // DESC NULLS-LAST: nothing comes strictly after a NULL on this\n // column. The i-th OR-clause contributes no rows — drop it. We\n // can't `return null`, because subsequent clauses (i+1, i+2, …)\n // can still produce matches via equality on the NULL preceding\n // columns plus a tiebreaker on a later column. Mirrors the\n // `1 = 0` predicate in `BaseSqlTabularStorage.buildKeysetWhere`.\n continue;\n }\n } else {\n if (dir === \"ASC\") {\n cmp = `${col}.gt.${escapePostgrest(v)}`;\n } else {\n // Smaller than the cursor, then NULLs-last trailer.\n cmp = `or(${col}.lt.${escapePostgrest(v)},${col}.is.null)`;\n }\n }\n andParts.push(cmp);\n orClauses.push(andParts.length === 1 ? andParts[0] : `and(${andParts.join(\",\")})`);\n }\n if (orClauses.length === 0) return null;\n return orClauses.join(\",\");\n }\n\n override async queryIndex<K extends keyof Entity & string>(\n criteria: SearchCriteria<Entity>,\n options: CoveringIndexQueryOptions<Entity, K>\n ): Promise<Pick<Entity, K>[]> {\n this.validateSelect(options);\n this.validateQueryParams(criteria, options);\n\n const registered = this.indexes.map((cols, i) => {\n const cs = Array.isArray(cols) ? (cols as string[]) : [cols as string];\n return { name: `idx_${i}`, keyPath: cs };\n });\n\n pickCoveringIndex({\n table: this.table,\n indexes: registered,\n criteriaColumns: Object.keys(criteria),\n orderByColumns: (options.orderBy ?? []).map((o) => ({\n column: String(o.column),\n direction: o.direction,\n })),\n selectColumns: options.select.map(String),\n primaryKeyColumns: this.primaryKeyNames.map(String),\n });\n\n const colList = options.select.map(String).join(\",\");\n let q = this.applyCriteriaToFilter(this.client.from(this.table).select(colList), criteria);\n\n if (options.orderBy) {\n for (const { column, direction } of options.orderBy) {\n q = q.order(String(column), { ascending: direction === \"ASC\" });\n }\n }\n if (options.offset !== undefined && options.limit === undefined) {\n throw new StorageValidationError(\"queryIndex with offset requires limit (no implicit cap)\");\n }\n if (options.offset !== undefined || options.limit !== undefined) {\n const start = options.offset ?? 0;\n if (options.limit !== undefined) {\n q = q.range(start, start + options.limit - 1);\n }\n }\n\n const { data, error } = await q;\n if (error) throw error;\n if (!data) return [];\n\n const rows = data as unknown as Record<string, unknown>[];\n const sel = new Set(options.select.map(String));\n for (const row of rows) {\n for (const key of Object.keys(row)) {\n if (sel.has(key)) {\n row[key] = this.sqlToJsValue(key, row[key] as ValueOptionType);\n }\n }\n }\n return rows as unknown as Pick<Entity, K>[];\n }\n\n /**\n * Converts a row from Supabase realtime payload to an Entity with proper type conversions.\n *\n * @param row - The raw row data from Supabase realtime\n * @returns The converted entity\n */\n private convertRealtimeRow(row: Record<string, unknown>): Entity {\n const entity = { ...row } as Entity;\n const record = entity as Record<string, unknown>;\n for (const key in this.schema.properties) {\n record[key] = this.sqlToJsValue(key, row[key] as ValueOptionType);\n }\n return entity;\n }\n\n /**\n * Subscribes to changes in the repository using Supabase realtime.\n * Receives notifications for INSERT, UPDATE, and DELETE operations from any source.\n *\n * @param callback - Function called when a change occurs\n * @param options - Optional subscription options (not used for Supabase realtime)\n * @returns Unsubscribe function\n */\n public override subscribeToChanges(\n callback: (change: TabularChangePayload<Entity>) => void,\n options?: TabularSubscribeOptions\n ): () => void {\n // Create a unique channel name\n const channelName = `tabular-${this.table}-${Date.now()}`;\n\n this.realtimeChannel = this.client\n .channel(channelName)\n .on(\n \"postgres_changes\",\n {\n event: \"*\",\n schema: \"public\",\n table: this.table,\n },\n (payload) => {\n const change: TabularChangePayload<Entity> = {\n type: payload.eventType.toUpperCase() as TabularChangeType,\n old:\n payload.old && Object.keys(payload.old).length > 0\n ? this.convertRealtimeRow(payload.old)\n : undefined,\n new:\n payload.new && Object.keys(payload.new).length > 0\n ? this.convertRealtimeRow(payload.new)\n : undefined,\n };\n callback(change);\n }\n )\n .subscribe();\n\n return () => {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n };\n }\n\n /**\n * **Best-effort, non-atomic.** Supabase exposes PostgREST, not a session-\n * level transaction surface this client can drive — there is no\n * `BEGIN`/`COMMIT`/`ROLLBACK` over the wire. The override exists only to\n * make the no-rollback semantics explicit instead of inheriting the base\n * default silently: `fn` runs to completion against `this`, the result\n * propagates, and any partial writes survive a thrown `fn`. Use a\n * stored-procedure / RPC if you need true atomicity on Supabase.\n */\n public override async withTransaction<T>(fn: (tx: this) => Promise<T>): Promise<T> {\n return fn(this);\n }\n\n /**\n * Destroys the repository and frees up resources.\n */\n public override destroy(): void {\n if (this.realtimeChannel) {\n this.client.removeChannel(this.realtimeChannel);\n this.realtimeChannel = null;\n }\n }\n}\n"
7
7
  ],
8
- "mappings": "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",
9
- "debugId": "A7D3C92DD87268E764756E2164756E21",
8
+ "mappings": "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",
9
+ "debugId": "65D57CB2936568C964756E2164756E21",
10
10
  "names": []
11
11
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@workglow/supabase",
3
3
  "type": "module",
4
- "version": "0.2.33",
4
+ "version": "0.2.35",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/workglow-dev/libs.git",
@@ -54,12 +54,12 @@
54
54
  }
55
55
  },
56
56
  "dependencies": {
57
- "@supabase/supabase-js": "^2.105.3"
57
+ "@supabase/supabase-js": "^2.105.4"
58
58
  },
59
59
  "peerDependencies": {
60
- "@workglow/job-queue": "0.2.33",
61
- "@workglow/storage": "0.2.33",
62
- "@workglow/util": "0.2.33"
60
+ "@workglow/job-queue": "0.2.35",
61
+ "@workglow/storage": "0.2.35",
62
+ "@workglow/util": "0.2.35"
63
63
  },
64
64
  "peerDependenciesMeta": {
65
65
  "@workglow/job-queue": {
@@ -73,9 +73,9 @@
73
73
  }
74
74
  },
75
75
  "devDependencies": {
76
- "@workglow/job-queue": "0.2.33",
77
- "@workglow/storage": "0.2.33",
78
- "@workglow/util": "0.2.33"
76
+ "@workglow/job-queue": "0.2.35",
77
+ "@workglow/storage": "0.2.35",
78
+ "@workglow/util": "0.2.35"
79
79
  },
80
80
  "files": [
81
81
  "dist",