@cipherstash/stack 0.19.0 → 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +596 -0
- package/README.md +376 -276
- package/dist/adapter-kit.cjs +1002 -0
- package/dist/adapter-kit.cjs.map +1 -0
- package/dist/adapter-kit.d.cts +120 -0
- package/dist/adapter-kit.d.ts +120 -0
- package/dist/adapter-kit.js +122 -0
- package/dist/adapter-kit.js.map +1 -0
- package/dist/base-operation-AOAIvsSB.d.cts +32 -0
- package/dist/base-operation-FXEzUXIq.d.ts +32 -0
- package/dist/{chunk-4AVL4VZD.js → chunk-3B5ZX3IS.js} +3 -1
- package/dist/chunk-3B5ZX3IS.js.map +1 -0
- package/dist/{chunk-U66S7VIF.js → chunk-6SGN52W6.js} +166 -107
- package/dist/chunk-6SGN52W6.js.map +1 -0
- package/dist/chunk-7333ZC6L.js +48 -0
- package/dist/chunk-7333ZC6L.js.map +1 -0
- package/dist/{chunk-MP3SSDNN.js → chunk-CLM7E4I6.js} +15 -15
- package/dist/{chunk-MP3SSDNN.js.map → chunk-CLM7E4I6.js.map} +1 -1
- package/dist/{chunk-OFQ555AX.js → chunk-IDKP6ABU.js} +2 -2
- package/dist/{chunk-36AA7IBJ.js → chunk-L7ISHSG7.js} +53 -20
- package/dist/chunk-L7ISHSG7.js.map +1 -0
- package/dist/{chunk-LBMC4D6D.js → chunk-NVKK7UDN.js} +1 -1
- package/dist/chunk-NVKK7UDN.js.map +1 -0
- package/dist/chunk-X3JRXEIB.js +98 -0
- package/dist/chunk-X3JRXEIB.js.map +1 -0
- package/dist/client.cjs +29 -12
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +3 -2
- package/dist/client.d.ts +3 -2
- package/dist/client.js +2 -2
- package/dist/{table-CIH7jZ2h.d.ts → columns-0lbT9stl.d.ts} +157 -138
- package/dist/{table-DihEAlxG.d.cts → columns-Bxv7Oo9o.d.cts} +157 -138
- package/dist/dynamodb/index.d.cts +3 -2
- package/dist/dynamodb/index.d.ts +3 -2
- package/dist/encryption/index.cjs +54 -16
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.d.cts +807 -6
- package/dist/encryption/index.d.ts +807 -6
- package/dist/encryption/index.js +6 -6
- package/dist/encryption/v3.cjs +1078 -973
- package/dist/encryption/v3.cjs.map +1 -1
- package/dist/encryption/v3.d.cts +15 -12
- package/dist/encryption/v3.d.ts +15 -12
- package/dist/encryption/v3.js +50 -22
- package/dist/encryption/v3.js.map +1 -1
- package/dist/eql/v3/index.cjs +130 -79
- package/dist/eql/v3/index.cjs.map +1 -1
- package/dist/eql/v3/index.d.cts +115 -13
- package/dist/eql/v3/index.d.ts +115 -13
- package/dist/eql/v3/index.js +16 -6
- package/dist/errors/index.cjs.map +1 -1
- package/dist/errors/index.d.cts +5 -5
- package/dist/errors/index.d.ts +5 -5
- package/dist/errors/index.js +1 -1
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.js +2 -2
- package/dist/index-BquA71_Y.d.ts +24 -0
- package/dist/index-fhWTOV0K.d.cts +24 -0
- package/dist/index.cjs +79 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -17
- package/dist/index.d.ts +5 -17
- package/dist/index.js +6 -6
- package/dist/schema/index.cjs +29 -12
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.cts +1 -1
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema/index.js +2 -2
- package/dist/{types-public-CpS5KjwX.d.ts → types-public-QMjYNfQO.d.cts} +765 -726
- package/dist/{types-public-CpS5KjwX.d.cts → types-public-QMjYNfQO.d.ts} +765 -726
- package/dist/types-public.cjs.map +1 -1
- package/dist/types-public.d.cts +1 -1
- package/dist/types-public.d.ts +1 -1
- package/dist/types-public.js +1 -1
- package/dist/wasm-inline.d.ts +779 -405
- package/dist/wasm-inline.js +606 -299
- package/dist/wasm-inline.js.map +1 -1
- package/package.json +25 -53
- package/dist/chunk-36AA7IBJ.js.map +0 -1
- package/dist/chunk-4AVL4VZD.js.map +0 -1
- package/dist/chunk-IADZCZEA.js +0 -23
- package/dist/chunk-IADZCZEA.js.map +0 -1
- package/dist/chunk-IBSK6P33.js +0 -209
- package/dist/chunk-IBSK6P33.js.map +0 -1
- package/dist/chunk-LBMC4D6D.js.map +0 -1
- package/dist/chunk-U66S7VIF.js.map +0 -1
- package/dist/client-DSGHBN-g.d.cts +0 -834
- package/dist/client-DfCrlHXh.d.ts +0 -834
- package/dist/drizzle/index.cjs +0 -5617
- package/dist/drizzle/index.cjs.map +0 -1
- package/dist/drizzle/index.d.cts +0 -358
- package/dist/drizzle/index.d.ts +0 -358
- package/dist/drizzle/index.js +0 -1220
- package/dist/drizzle/index.js.map +0 -1
- package/dist/supabase/index.cjs +0 -5951
- package/dist/supabase/index.cjs.map +0 -1
- package/dist/supabase/index.d.cts +0 -223
- package/dist/supabase/index.d.ts +0 -223
- package/dist/supabase/index.js +0 -1217
- package/dist/supabase/index.js.map +0 -1
- /package/dist/{chunk-OFQ555AX.js.map → chunk-IDKP6ABU.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/supabase/helpers.ts","../../src/supabase/query-builder.ts","../../src/supabase/query-builder-v3.ts","../../src/supabase/index.ts"],"sourcesContent":["import type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport type { QueryTypeName } from '@/types'\nimport type { FilterOp, PendingOrCondition } from './types'\n\n/**\n * Get the names of all encrypted columns defined in a table schema.\n */\nexport function getEncryptedColumnNames(\n schema: EncryptedTable<EncryptedTableColumn>,\n): string[] {\n const built = schema.build()\n return Object.keys(built.columns)\n}\n\n/**\n * Check whether a column name refers to an encrypted column in the schema.\n */\nexport function isEncryptedColumn(\n columnName: string,\n encryptedColumnNames: string[],\n): boolean {\n return encryptedColumnNames.includes(columnName)\n}\n\n/**\n * Parse a Supabase select string and add `::jsonb` casts to encrypted columns.\n *\n * Input: `'id, email, name'`\n * Output: `'id, email::jsonb, name::jsonb'` (if email and name are encrypted)\n *\n * Handles whitespace, already-cast columns, and embedded functions.\n */\nexport function addJsonbCasts(\n columns: string,\n encryptedColumnNames: string[],\n): string {\n return columns\n .split(',')\n .map((col) => {\n const trimmed = col.trim()\n\n // Skip empty segments\n if (!trimmed) return col\n\n // If it already has a cast (e.g. `email::jsonb`), skip\n if (trimmed.includes('::')) return col\n\n // If it contains parens (function call) or dots (foreign table), skip\n if (trimmed.includes('(') || trimmed.includes('.')) return col\n\n // Check if the column name (possibly with alias) is encrypted\n // Handle `column_name` or `column_name as alias`\n const parts = trimmed.split(/\\s+/)\n const colName = parts[0]\n\n if (isEncryptedColumn(colName, encryptedColumnNames)) {\n // Preserve original whitespace before the column\n const leadingWhitespace = col.match(/^(\\s*)/)?.[1] ?? ''\n if (parts.length > 1) {\n // Has alias: `email as e` -> `email::jsonb as e`\n return `${leadingWhitespace}${colName}::jsonb ${parts.slice(1).join(' ')}`\n }\n return `${leadingWhitespace}${colName}::jsonb`\n }\n\n return col\n })\n .join(',')\n}\n\n/**\n * Parse a Supabase select string and add `::jsonb` casts to encrypted EQL v3\n * columns, resolving JS property names to DB column names via PostgREST\n * aliasing.\n *\n * Input: `'id, email, createdAt'` with `{ email: 'email', createdAt: 'created_at' }`\n * Output: `'id, email::jsonb, createdAt:created_at::jsonb'`\n *\n * - A property whose DB name differs is emitted as `prop:db_name::jsonb`\n * (PostgREST rename syntax), so result rows come back keyed by the JS\n * property name.\n * - A DB column name used directly is cast in place (`db_name::jsonb`).\n * - Tokens that already carry a cast, or contain parens/dots (functions,\n * foreign tables), are left untouched — same rules as the v2 helper.\n *\n * Besides the rewritten select string, returns `keyToDb`: every result-row\n * key this select produces for an encrypted column, mapped to its DB column\n * name — including user-chosen PostgREST aliases (`ts:created_at` → rows\n * keyed `ts`). The v3 builder uses it to reconstruct `Date` values on keys\n * the static property↔DB map cannot see.\n */\nexport function addJsonbCastsV3(\n columns: string,\n propToDb: Record<string, string>,\n): { select: string; keyToDb: Record<string, string> } {\n const dbNames = new Set(Object.values(propToDb))\n const keyToDb: Record<string, string> = {}\n\n const select = columns\n .split(',')\n .map((col) => {\n const trimmed = col.trim()\n\n if (!trimmed) return col\n if (trimmed.includes('::')) return col\n if (trimmed.includes('(') || trimmed.includes('.')) return col\n\n const leadingWhitespace = col.match(/^(\\s*)/)?.[1] ?? ''\n\n // Already-aliased token: `alias:column`\n const aliasMatch = trimmed.match(\n /^([A-Za-z_][A-Za-z0-9_]*):([A-Za-z_][A-Za-z0-9_]*)$/,\n )\n if (aliasMatch) {\n const [, alias, name] = aliasMatch\n const db = propToDb[name] ?? (dbNames.has(name) ? name : undefined)\n if (db !== undefined) {\n keyToDb[alias] = db\n return `${leadingWhitespace}${alias}:${db}::jsonb`\n }\n return col\n }\n\n const db = propToDb[trimmed]\n if (db !== undefined) {\n keyToDb[trimmed] = db\n return db === trimmed\n ? `${leadingWhitespace}${trimmed}::jsonb`\n : `${leadingWhitespace}${trimmed}:${db}::jsonb`\n }\n\n if (dbNames.has(trimmed)) {\n keyToDb[trimmed] = trimmed\n return `${leadingWhitespace}${trimmed}::jsonb`\n }\n\n return col\n })\n .join(',')\n\n return { select, keyToDb }\n}\n\n/**\n * Map a Supabase filter operation to a CipherStash query type.\n */\nexport function mapFilterOpToQueryType(op: FilterOp): QueryTypeName {\n switch (op) {\n case 'eq':\n case 'neq':\n case 'in':\n case 'is':\n return 'equality'\n case 'like':\n case 'ilike':\n return 'freeTextSearch'\n case 'gt':\n case 'gte':\n case 'lt':\n case 'lte':\n return 'orderAndRange'\n default:\n return 'equality'\n }\n}\n\n/**\n * Parse a Supabase `.or()` filter string into structured conditions.\n *\n * Input: `'email.eq.john@example.com,name.ilike.%john%'`\n * Output: `[{ column: 'email', op: 'eq', value: 'john@example.com' }, { column: 'name', op: 'ilike', value: '%john%' }]`\n */\nexport function parseOrString(orString: string): PendingOrCondition[] {\n const conditions: PendingOrCondition[] = []\n // Split on commas that are not inside parentheses (nested or/and)\n const parts = splitOrString(orString)\n\n for (const part of parts) {\n const trimmed = part.trim()\n if (!trimmed) continue\n\n // Format: column.op.value\n const firstDot = trimmed.indexOf('.')\n if (firstDot === -1) continue\n\n const column = trimmed.slice(0, firstDot)\n const rest = trimmed.slice(firstDot + 1)\n\n const secondDot = rest.indexOf('.')\n if (secondDot === -1) continue\n\n const op = rest.slice(0, secondDot) as FilterOp\n const value = rest.slice(secondDot + 1)\n\n // Handle special value formats\n const parsedValue = parseOrValue(value)\n\n conditions.push({ column, op, value: parsedValue })\n }\n\n return conditions\n}\n\n/**\n * Rebuild an `.or()` string from structured conditions.\n */\nexport function rebuildOrString(conditions: PendingOrCondition[]): string {\n return conditions\n .map((c) => {\n const value = formatOrValue(c.value)\n return `${c.column}.${c.op}.${value}`\n })\n .join(',')\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\nfunction splitOrString(input: string): string[] {\n const parts: string[] = []\n let current = ''\n let depth = 0\n let inQuotes = false\n\n for (const char of input) {\n if (char === '\"' && depth === 0) {\n inQuotes = !inQuotes\n current += char\n } else if (char === '(' && !inQuotes) {\n depth++\n current += char\n } else if (char === ')' && !inQuotes) {\n depth--\n current += char\n } else if (char === ',' && depth === 0 && !inQuotes) {\n parts.push(current)\n current = ''\n } else {\n current += char\n }\n }\n\n if (current) {\n parts.push(current)\n }\n\n return parts\n}\n\nfunction parseOrValue(value: string): unknown {\n // Handle double-quoted values (PostgREST quoting for reserved characters)\n if (value.startsWith('\"') && value.endsWith('\"')) {\n return value.slice(1, -1)\n }\n\n // Handle parenthesized lists: (val1,val2,val3)\n if (value.startsWith('(') && value.endsWith(')')) {\n return value\n .slice(1, -1)\n .split(',')\n .map((v) => v.trim())\n }\n\n // Handle booleans\n if (value === 'true') return true\n if (value === 'false') return false\n\n // Handle null\n if (value === 'null') return null\n\n return value\n}\n\n/**\n * PostgREST reserved characters that require double-quoting in filter values.\n * See: https://docs.postgrest.org/en/latest/references/api/tables_views.html\n */\nconst POSTGREST_RESERVED = /[,().]/\n\nfunction formatOrValue(value: unknown): string {\n if (Array.isArray(value)) {\n return `(${value.join(',')})`\n }\n if (value === null) return 'null'\n if (value === true) return 'true'\n if (value === false) return 'false'\n\n const str = String(value)\n\n // Wrap in double quotes if the value contains reserved characters.\n // This is required for encrypted values (JSON with commas, braces, etc.)\n // and is safe for all string values per PostgREST spec.\n if (POSTGREST_RESERVED.test(str)) {\n return `\"${str}\"`\n }\n\n return str\n}\n","import type { JsPlaintext } from '@cipherstash/protect-ffi'\nimport type { EncryptionClient } from '@/encryption'\nimport {\n bulkModelsToEncryptedPgComposites,\n modelToEncryptedPgComposites,\n} from '@/encryption/helpers'\nimport type { AuditConfig } from '@/encryption/operations/base-operation'\nimport type { LockContext } from '@/identity'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport { EncryptedColumn } from '@/schema'\nimport type { BuildableQueryColumn, ScalarQueryTerm } from '@/types'\nimport { logger } from '@/utils/logger'\nimport {\n addJsonbCasts,\n getEncryptedColumnNames,\n isEncryptedColumn,\n mapFilterOpToQueryType,\n parseOrString,\n rebuildOrString,\n} from './helpers'\nimport type {\n EncryptedSupabaseError,\n EncryptedSupabaseResponse,\n FilterOp,\n MutationOp,\n PendingFilter,\n PendingMatchFilter,\n PendingNotFilter,\n PendingOrCondition,\n PendingOrFilter,\n PendingRawFilter,\n ResultMode,\n SupabaseClientLike,\n SupabaseQueryBuilder,\n TransformOp,\n} from './types'\n\n/**\n * A deferred query builder that wraps Supabase's query builder to automatically\n * handle encryption and decryption of data.\n *\n * All chained operations are recorded synchronously. When the builder is awaited,\n * it encrypts mutation data, adds `::jsonb` casts, batch-encrypts filter values,\n * executes the real Supabase query, and decrypts results.\n */\nexport class EncryptedQueryBuilderImpl<\n T extends Record<string, unknown> = Record<string, unknown>,\n> {\n protected tableName: string\n protected schema: EncryptedTable<EncryptedTableColumn>\n protected encryptionClient: EncryptionClient\n protected supabaseClient: SupabaseClientLike\n protected encryptedColumnNames: string[]\n\n // Recorded operations\n protected mutation: MutationOp | null = null\n protected selectColumns: string | null = null\n protected selectOptions:\n | { head?: boolean; count?: 'exact' | 'planned' | 'estimated' }\n | undefined = undefined\n protected filters: PendingFilter[] = []\n protected orFilters: PendingOrFilter[] = []\n protected matchFilters: PendingMatchFilter[] = []\n protected notFilters: PendingNotFilter[] = []\n protected rawFilters: PendingRawFilter[] = []\n protected transforms: TransformOp[] = []\n protected resultMode: ResultMode = 'array'\n protected shouldThrowOnError = false\n\n // Encryption-specific state\n protected lockContext: LockContext | null = null\n protected auditConfig: AuditConfig | null = null\n\n constructor(\n tableName: string,\n schema: EncryptedTable<EncryptedTableColumn>,\n encryptionClient: EncryptionClient,\n supabaseClient: SupabaseClientLike,\n ) {\n this.tableName = tableName\n this.schema = schema\n this.encryptionClient = encryptionClient\n this.supabaseClient = supabaseClient\n this.encryptedColumnNames = getEncryptedColumnNames(schema)\n }\n\n // ---------------------------------------------------------------------------\n // Mutation methods\n // ---------------------------------------------------------------------------\n\n select(\n columns: string,\n options?: { head?: boolean; count?: 'exact' | 'planned' | 'estimated' },\n ): this {\n if (columns === '*') {\n throw new Error(\n \"encryptedSupabase does not support select('*'). Please list columns explicitly so that encrypted columns can be cast with ::jsonb.\",\n )\n }\n this.selectColumns = columns\n this.selectOptions = options\n return this\n }\n\n insert(\n data: Partial<T> | Partial<T>[],\n options?: {\n count?: 'exact' | 'planned' | 'estimated'\n defaultToNull?: boolean\n onConflict?: string\n },\n ): this {\n this.mutation = {\n kind: 'insert',\n data: data as Record<string, unknown> | Record<string, unknown>[],\n options,\n }\n return this\n }\n\n update(\n data: Partial<T>,\n options?: { count?: 'exact' | 'planned' | 'estimated' },\n ): this {\n this.mutation = {\n kind: 'update',\n data: data as Record<string, unknown>,\n options,\n }\n return this\n }\n\n upsert(\n data: Partial<T> | Partial<T>[],\n options?: {\n count?: 'exact' | 'planned' | 'estimated'\n onConflict?: string\n ignoreDuplicates?: boolean\n defaultToNull?: boolean\n },\n ): this {\n this.mutation = {\n kind: 'upsert',\n data: data as Record<string, unknown> | Record<string, unknown>[],\n options,\n }\n return this\n }\n\n delete(options?: { count?: 'exact' | 'planned' | 'estimated' }): this {\n this.mutation = { kind: 'delete', options }\n return this\n }\n\n // ---------------------------------------------------------------------------\n // Filter methods\n // ---------------------------------------------------------------------------\n\n eq(column: string, value: unknown): this {\n this.filters.push({ op: 'eq', column, value })\n return this\n }\n\n neq(column: string, value: unknown): this {\n this.filters.push({ op: 'neq', column, value })\n return this\n }\n\n gt(column: string, value: unknown): this {\n this.filters.push({ op: 'gt', column, value })\n return this\n }\n\n gte(column: string, value: unknown): this {\n this.filters.push({ op: 'gte', column, value })\n return this\n }\n\n lt(column: string, value: unknown): this {\n this.filters.push({ op: 'lt', column, value })\n return this\n }\n\n lte(column: string, value: unknown): this {\n this.filters.push({ op: 'lte', column, value })\n return this\n }\n\n like(column: string, pattern: string): this {\n this.filters.push({ op: 'like', column, value: pattern })\n return this\n }\n\n ilike(column: string, pattern: string): this {\n this.filters.push({ op: 'ilike', column, value: pattern })\n return this\n }\n\n is(column: string, value: null | boolean): this {\n this.filters.push({ op: 'is', column, value })\n return this\n }\n\n in(column: string, values: unknown[]): this {\n this.filters.push({ op: 'in', column, value: values })\n return this\n }\n\n filter(column: string, operator: string, value: unknown): this {\n this.rawFilters.push({ column, operator, value })\n return this\n }\n\n not(column: string, operator: string, value: unknown): this {\n this.notFilters.push({ column, op: operator as FilterOp, value })\n return this\n }\n\n or(\n filtersOrConditions: string | PendingOrCondition[],\n options?: { referencedTable?: string; foreignTable?: string },\n ): this {\n if (typeof filtersOrConditions === 'string') {\n this.orFilters.push({\n kind: 'string',\n value: filtersOrConditions,\n referencedTable: options?.referencedTable ?? options?.foreignTable,\n })\n } else {\n this.orFilters.push({\n kind: 'structured',\n conditions: filtersOrConditions,\n })\n }\n return this\n }\n\n match(query: Record<string, unknown>): this {\n this.matchFilters.push({ query })\n return this\n }\n\n // ---------------------------------------------------------------------------\n // Transform methods (passthrough)\n // ---------------------------------------------------------------------------\n\n order(\n column: string,\n options?: {\n ascending?: boolean\n nullsFirst?: boolean\n referencedTable?: string\n foreignTable?: string\n },\n ): this {\n this.transforms.push({ kind: 'order', column, options })\n return this\n }\n\n limit(\n count: number,\n options?: { referencedTable?: string; foreignTable?: string },\n ): this {\n this.transforms.push({ kind: 'limit', count, options })\n return this\n }\n\n range(\n from: number,\n to: number,\n options?: { referencedTable?: string; foreignTable?: string },\n ): this {\n this.transforms.push({ kind: 'range', from, to, options })\n return this\n }\n\n single(): this {\n this.resultMode = 'single'\n this.transforms.push({ kind: 'single' })\n return this\n }\n\n maybeSingle(): this {\n this.resultMode = 'maybeSingle'\n this.transforms.push({ kind: 'maybeSingle' })\n return this\n }\n\n csv(): this {\n this.transforms.push({ kind: 'csv' })\n return this\n }\n\n abortSignal(signal: AbortSignal): this {\n this.transforms.push({ kind: 'abortSignal', signal })\n return this\n }\n\n throwOnError(): this {\n this.shouldThrowOnError = true\n this.transforms.push({ kind: 'throwOnError' })\n return this\n }\n\n returns<U extends Record<string, unknown>>(): EncryptedQueryBuilderImpl<U> {\n // Type-level cast only; builder state is preserved\n return this as unknown as EncryptedQueryBuilderImpl<U>\n }\n\n // ---------------------------------------------------------------------------\n // Encryption-specific methods\n // ---------------------------------------------------------------------------\n\n withLockContext(lockContext: LockContext): this {\n this.lockContext = lockContext\n return this\n }\n\n audit(config: AuditConfig): this {\n this.auditConfig = config\n return this\n }\n\n // ---------------------------------------------------------------------------\n // PromiseLike implementation (deferred execution)\n // ---------------------------------------------------------------------------\n\n then<TResult1 = EncryptedSupabaseResponse<T[]>, TResult2 = never>(\n onfulfilled?:\n | ((\n value: EncryptedSupabaseResponse<T[]>,\n ) => TResult1 | PromiseLike<TResult1>)\n | null,\n onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,\n ): Promise<TResult1 | TResult2> {\n return this.execute().then(onfulfilled, onrejected)\n }\n\n // ---------------------------------------------------------------------------\n // Core execution\n // ---------------------------------------------------------------------------\n\n protected async execute(): Promise<EncryptedSupabaseResponse<T[]>> {\n try {\n logger.debug(`Supabase encrypted query on table \"${this.tableName}\".`)\n\n // 1. Encrypt mutation data\n const encryptedMutation = await this.encryptMutationData()\n\n // 2. Build select string with ::jsonb casts\n const selectString = this.buildSelectString()\n\n // 3. Batch-encrypt filter values\n const encryptedFilters = await this.encryptFilterValues()\n\n // 4. Build and execute real Supabase query\n const result = await this.buildAndExecuteQuery(\n encryptedMutation,\n selectString,\n encryptedFilters,\n )\n\n // 5. Decrypt results\n return await this.decryptResults(result)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n logger.error(\n `Supabase encrypted query failed on table \"${this.tableName}\": ${message}`,\n )\n\n const error: EncryptedSupabaseError = {\n message,\n encryptionError: undefined,\n }\n\n if (this.shouldThrowOnError) {\n throw err\n }\n\n return {\n data: null,\n error,\n count: null,\n status: 500,\n statusText: 'Encryption Error',\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Step 1: Encrypt mutation data\n // ---------------------------------------------------------------------------\n\n protected async encryptMutationData(): Promise<\n Record<string, unknown> | Record<string, unknown>[] | null\n > {\n if (!this.mutation) return null\n\n if (this.mutation.kind === 'delete') return null\n\n const data = this.mutation.data\n\n if (Array.isArray(data)) {\n // Bulk encrypt\n const baseOp = this.encryptionClient.bulkEncryptModels(data, this.schema)\n const op = this.lockContext\n ? baseOp.withLockContext(this.lockContext)\n : baseOp\n if (this.auditConfig) op.audit(this.auditConfig)\n\n const result = await op\n if (result.failure) {\n logger.error(\n `Supabase: failed to encrypt models for table \"${this.tableName}\"`,\n )\n\n throw new EncryptionFailedError(\n `Failed to encrypt models: ${result.failure.message}`,\n result.failure,\n )\n }\n\n return this.transformEncryptedMutationModels(result.data)\n }\n\n // Single model\n const baseOp = this.encryptionClient.encryptModel(data, this.schema)\n const op = this.lockContext\n ? baseOp.withLockContext(this.lockContext)\n : baseOp\n if (this.auditConfig) op.audit(this.auditConfig)\n\n const result = await op\n if (result.failure) {\n logger.error(\n `Supabase: failed to encrypt model for table \"${this.tableName}\"`,\n )\n\n throw new EncryptionFailedError(\n `Failed to encrypt model: ${result.failure.message}`,\n result.failure,\n )\n }\n\n return this.transformEncryptedMutationModel(result.data)\n }\n\n /**\n * Encode an encrypted model for the Supabase request body. v2 wraps each\n * encrypted value in the `{ data: ... }` object expected by the\n * `eql_v2_encrypted` composite type. The v3 dialect overrides this — native\n * `eql_v3.*` domains are plain jsonb, so the raw payload is sent instead\n * (keyed by DB column name).\n */\n protected transformEncryptedMutationModel(\n model: Record<string, unknown>,\n ): Record<string, unknown> {\n return modelToEncryptedPgComposites(model)\n }\n\n protected transformEncryptedMutationModels(\n models: Record<string, unknown>[],\n ): Record<string, unknown>[] {\n return bulkModelsToEncryptedPgComposites(models)\n }\n\n // ---------------------------------------------------------------------------\n // Step 2: Build select string with casts\n // ---------------------------------------------------------------------------\n\n protected buildSelectString(): string | null {\n if (this.selectColumns === null) return null\n return addJsonbCasts(this.selectColumns, this.encryptedColumnNames)\n }\n\n // ---------------------------------------------------------------------------\n // Step 3: Encrypt filter values\n // ---------------------------------------------------------------------------\n\n protected async encryptFilterValues(): Promise<EncryptedFilterState> {\n // Collect all terms that need encryption\n const terms: ScalarQueryTerm[] = []\n const termMap: TermMapping[] = []\n\n const tableColumns = this.getColumnMap()\n\n // Regular filters\n for (let i = 0; i < this.filters.length; i++) {\n const f = this.filters[i]\n if (!isEncryptedColumn(f.column, this.encryptedColumnNames)) continue\n\n const column = tableColumns[f.column]\n if (!column) continue\n\n if (f.op === 'in' && Array.isArray(f.value)) {\n // For `in` filters, encrypt each value separately\n for (let j = 0; j < f.value.length; j++) {\n terms.push({\n value: f.value[j] as JsPlaintext,\n column,\n table: this.schema,\n queryType: mapFilterOpToQueryType(f.op),\n returnType: 'composite-literal',\n })\n termMap.push({ source: 'filter', filterIndex: i, inIndex: j })\n }\n } else if (f.op === 'is') {\n } else {\n terms.push({\n value: f.value as JsPlaintext,\n column,\n table: this.schema,\n queryType: mapFilterOpToQueryType(f.op),\n returnType: 'composite-literal',\n })\n termMap.push({ source: 'filter', filterIndex: i })\n }\n }\n\n // Match filters\n for (let i = 0; i < this.matchFilters.length; i++) {\n const mf = this.matchFilters[i]\n for (const [colName, value] of Object.entries(mf.query)) {\n if (!isEncryptedColumn(colName, this.encryptedColumnNames)) continue\n const column = tableColumns[colName]\n if (!column) continue\n\n terms.push({\n value: value as JsPlaintext,\n column,\n table: this.schema,\n queryType: 'equality',\n returnType: 'composite-literal',\n })\n termMap.push({ source: 'match', matchIndex: i, column: colName })\n }\n }\n\n // Not filters\n for (let i = 0; i < this.notFilters.length; i++) {\n const nf = this.notFilters[i]\n if (!isEncryptedColumn(nf.column, this.encryptedColumnNames)) continue\n const column = tableColumns[nf.column]\n if (!column) continue\n\n terms.push({\n value: nf.value as JsPlaintext,\n column,\n table: this.schema,\n queryType: mapFilterOpToQueryType(nf.op),\n returnType: 'composite-literal',\n })\n termMap.push({ source: 'not', notIndex: i })\n }\n\n // Or filters (string form parsed into conditions)\n for (let i = 0; i < this.orFilters.length; i++) {\n const of_ = this.orFilters[i]\n if (of_.kind === 'string') {\n const parsed = parseOrString(of_.value)\n for (let j = 0; j < parsed.length; j++) {\n const cond = parsed[j]\n if (!isEncryptedColumn(cond.column, this.encryptedColumnNames))\n continue\n const column = tableColumns[cond.column]\n if (!column) continue\n\n terms.push({\n value: cond.value as JsPlaintext,\n column,\n table: this.schema,\n queryType: mapFilterOpToQueryType(cond.op),\n returnType: 'composite-literal',\n })\n termMap.push({ source: 'or-string', orIndex: i, conditionIndex: j })\n }\n } else {\n for (let j = 0; j < of_.conditions.length; j++) {\n const cond = of_.conditions[j]\n if (!isEncryptedColumn(cond.column, this.encryptedColumnNames))\n continue\n const column = tableColumns[cond.column]\n if (!column) continue\n\n terms.push({\n value: cond.value as JsPlaintext,\n column,\n table: this.schema,\n queryType: mapFilterOpToQueryType(cond.op),\n returnType: 'composite-literal',\n })\n termMap.push({\n source: 'or-structured',\n orIndex: i,\n conditionIndex: j,\n })\n }\n }\n }\n\n // Raw filters\n for (let i = 0; i < this.rawFilters.length; i++) {\n const rf = this.rawFilters[i]\n if (!isEncryptedColumn(rf.column, this.encryptedColumnNames)) continue\n const column = tableColumns[rf.column]\n if (!column) continue\n\n terms.push({\n value: rf.value as JsPlaintext,\n column,\n table: this.schema,\n queryType: 'equality',\n returnType: 'composite-literal',\n })\n termMap.push({ source: 'raw', rawIndex: i })\n }\n\n if (terms.length === 0) {\n return { encryptedValues: [], termMap: [] }\n }\n\n const encryptedValues = await this.encryptCollectedTerms(terms)\n return { encryptedValues, termMap }\n }\n\n /**\n * Encrypt the collected filter terms, returning one encoded value per term\n * (in order). v2 batch-encrypts via `encryptQuery` with the\n * `composite-literal` return type — the `(\"json\")` string the\n * `eql_v2_encrypted` composite operators compare. The v3 dialect overrides\n * this to produce full-envelope jsonb operands instead.\n */\n protected async encryptCollectedTerms(\n terms: ScalarQueryTerm[],\n ): Promise<unknown[]> {\n // Batch encrypt all terms in one call\n const baseOp = this.encryptionClient.encryptQuery(terms)\n const op = this.lockContext\n ? baseOp.withLockContext(this.lockContext)\n : baseOp\n if (this.auditConfig) op.audit(this.auditConfig)\n\n const result = await op\n if (result.failure) {\n logger.error(\n `Supabase: failed to encrypt query terms for table \"${this.tableName}\"`,\n )\n\n throw new EncryptionFailedError(\n `Failed to encrypt query terms: ${result.failure.message}`,\n result.failure,\n )\n }\n\n return result.data\n }\n\n // ---------------------------------------------------------------------------\n // Step 4: Build and execute real Supabase query\n // ---------------------------------------------------------------------------\n\n protected async buildAndExecuteQuery(\n encryptedMutation:\n | Record<string, unknown>\n | Record<string, unknown>[]\n | null,\n selectString: string | null,\n encryptedFilters: EncryptedFilterState,\n ): Promise<RawSupabaseResult> {\n let query: SupabaseQueryBuilder = this.supabaseClient.from(this.tableName)\n\n // Apply mutation\n if (this.mutation) {\n switch (this.mutation.kind) {\n case 'insert':\n query = query.insert(encryptedMutation!, this.mutation.options)\n break\n case 'update':\n query = query.update(encryptedMutation!, this.mutation.options)\n break\n case 'upsert':\n query = query.upsert(encryptedMutation!, this.mutation.options)\n break\n case 'delete':\n query = query.delete(this.mutation.options)\n break\n }\n }\n\n // Apply select\n if (selectString !== null) {\n query = query.select(selectString, this.selectOptions)\n } else if (!this.mutation) {\n // Default select without explicit columns - shouldn't happen but fallback\n query = query.select('*', this.selectOptions)\n }\n\n // Apply resolved filters\n query = this.applyFilters(query, encryptedFilters)\n\n // Apply transforms\n for (const t of this.transforms) {\n switch (t.kind) {\n case 'order':\n query = query.order(t.column, t.options)\n break\n case 'limit':\n query = query.limit(t.count, t.options)\n break\n case 'range':\n query = query.range(t.from, t.to, t.options)\n break\n case 'single':\n query = query.single()\n break\n case 'maybeSingle':\n query = query.maybeSingle()\n break\n case 'csv':\n query = query.csv()\n break\n case 'abortSignal':\n query = query.abortSignal(t.signal)\n break\n case 'throwOnError':\n query = query.throwOnError()\n break\n }\n }\n\n const result = (await query) as unknown as RawSupabaseResult\n return result\n }\n\n // ---------------------------------------------------------------------------\n // Apply filters with encrypted values substituted\n // ---------------------------------------------------------------------------\n\n protected applyFilters(\n query: SupabaseQueryBuilder,\n encryptedFilters: EncryptedFilterState,\n ): SupabaseQueryBuilder {\n let q = query\n\n // Build lookup maps for quick access to encrypted values\n const filterValueMap = new Map<number, unknown>()\n const filterInMap = new Map<string, unknown>() // \"filterIndex:inIndex\" -> value\n const matchValueMap = new Map<string, unknown>() // \"matchIndex:column\" -> value\n const notValueMap = new Map<number, unknown>()\n const rawValueMap = new Map<number, unknown>()\n const orStringConditionMap = new Map<string, unknown>() // \"orIndex:condIndex\" -> value\n const orStructuredConditionMap = new Map<string, unknown>()\n\n for (let i = 0; i < encryptedFilters.termMap.length; i++) {\n const mapping = encryptedFilters.termMap[i]\n const encValue = encryptedFilters.encryptedValues[i]\n\n switch (mapping.source) {\n case 'filter':\n if (mapping.inIndex !== undefined) {\n filterInMap.set(\n `${mapping.filterIndex}:${mapping.inIndex}`,\n encValue,\n )\n } else {\n filterValueMap.set(mapping.filterIndex, encValue)\n }\n break\n case 'match':\n matchValueMap.set(`${mapping.matchIndex}:${mapping.column}`, encValue)\n break\n case 'not':\n notValueMap.set(mapping.notIndex, encValue)\n break\n case 'raw':\n rawValueMap.set(mapping.rawIndex, encValue)\n break\n case 'or-string':\n orStringConditionMap.set(\n `${mapping.orIndex}:${mapping.conditionIndex}`,\n encValue,\n )\n break\n case 'or-structured':\n orStructuredConditionMap.set(\n `${mapping.orIndex}:${mapping.conditionIndex}`,\n encValue,\n )\n break\n }\n }\n\n // Apply regular filters\n for (let i = 0; i < this.filters.length; i++) {\n const f = this.filters[i]\n let value = f.value\n\n if (filterValueMap.has(i)) {\n value = filterValueMap.get(i)\n } else if (f.op === 'in' && Array.isArray(f.value)) {\n // Reconstruct array with encrypted values substituted\n value = f.value.map((v, j) => {\n const key = `${i}:${j}`\n return filterInMap.has(key) ? filterInMap.get(key) : v\n })\n }\n\n const column = this.filterColumnName(f.column)\n const wasEncrypted = filterValueMap.has(i)\n\n switch (f.op) {\n case 'eq':\n q = q.eq(column, value)\n break\n case 'neq':\n q = q.neq(column, value)\n break\n case 'gt':\n q = q.gt(column, value)\n break\n case 'gte':\n q = q.gte(column, value)\n break\n case 'lt':\n q = q.lt(column, value)\n break\n case 'lte':\n q = q.lte(column, value)\n break\n case 'like':\n case 'ilike':\n q = this.applyPatternFilter(q, column, f.op, value, wasEncrypted)\n break\n case 'is':\n q = q.is(column, value)\n break\n case 'in':\n q = q.in(column, value as unknown[])\n break\n }\n }\n\n // Apply match filters\n for (let i = 0; i < this.matchFilters.length; i++) {\n const mf = this.matchFilters[i]\n const resolvedQuery: Record<string, unknown> = {}\n\n for (const [colName, originalValue] of Object.entries(mf.query)) {\n const key = `${i}:${colName}`\n resolvedQuery[this.filterColumnName(colName)] = matchValueMap.has(key)\n ? matchValueMap.get(key)\n : originalValue\n }\n\n q = q.match(resolvedQuery)\n }\n\n // Apply not filters\n for (let i = 0; i < this.notFilters.length; i++) {\n const nf = this.notFilters[i]\n const wasEncrypted = notValueMap.has(i)\n const value = wasEncrypted ? notValueMap.get(i) : nf.value\n q = q.not(\n this.filterColumnName(nf.column),\n this.notFilterOperator(nf.op, wasEncrypted),\n value,\n )\n }\n\n // Apply or filters\n for (let i = 0; i < this.orFilters.length; i++) {\n const of_ = this.orFilters[i]\n\n if (of_.kind === 'string') {\n const parsed = parseOrString(of_.value)\n const encryptedIndexes = new Set<number>()\n\n for (let j = 0; j < parsed.length; j++) {\n const key = `${i}:${j}`\n if (orStringConditionMap.has(key)) {\n parsed[j] = { ...parsed[j], value: orStringConditionMap.get(key) }\n encryptedIndexes.add(j)\n }\n }\n\n if (encryptedIndexes.size > 0) {\n q = q.or(\n rebuildOrString(\n this.transformOrConditions(parsed, encryptedIndexes),\n ),\n {\n referencedTable: of_.referencedTable,\n },\n )\n } else {\n q = q.or(of_.value, { referencedTable: of_.referencedTable })\n }\n } else {\n // Structured: convert to string\n const encryptedIndexes = new Set<number>()\n const conditions = of_.conditions.map((cond, j) => {\n const key = `${i}:${j}`\n if (orStructuredConditionMap.has(key)) {\n encryptedIndexes.add(j)\n return { ...cond, value: orStructuredConditionMap.get(key) }\n }\n return cond\n })\n\n q = q.or(\n rebuildOrString(\n this.transformOrConditions(conditions, encryptedIndexes),\n ),\n )\n }\n }\n\n // Apply raw filters\n for (let i = 0; i < this.rawFilters.length; i++) {\n const rf = this.rawFilters[i]\n const value = rawValueMap.has(i) ? rawValueMap.get(i) : rf.value\n q = q.filter(this.filterColumnName(rf.column), rf.operator, value)\n }\n\n return q\n }\n\n // ---------------------------------------------------------------------------\n // Dialect seams — every default preserves the v2 behaviour byte-for-byte.\n // The v3 builder (see ./query-builder-v3) overrides these for native\n // `eql_v3.*` domain columns.\n // ---------------------------------------------------------------------------\n\n /**\n * Map a filter's column name to the DB column name PostgREST must see.\n * v2 schemas key columns by their DB name already, so this is the identity;\n * the v3 dialect resolves a JS property name to its DB name.\n */\n protected filterColumnName(column: string): string {\n return column\n }\n\n /**\n * Apply a `like`/`ilike` filter. v2 relies on the `~~` operator defined on\n * `eql_v2_encrypted`; the v3 dialect overrides this for encrypted columns\n * because the `eql_v3.*` domains expose free-text match via `@>`\n * (PostgREST `cs`) rather than a LIKE operator.\n */\n protected applyPatternFilter(\n q: SupabaseQueryBuilder,\n column: string,\n op: 'like' | 'ilike',\n value: unknown,\n _wasEncrypted: boolean,\n ): SupabaseQueryBuilder {\n return op === 'like'\n ? q.like(column, value as string)\n : q.ilike(column, value as string)\n }\n\n /**\n * The PostgREST operator to use for a `.not()` filter. The v3 dialect maps\n * `like`/`ilike` on encrypted columns to `cs` (see applyPatternFilter).\n */\n protected notFilterOperator(op: FilterOp, _wasEncrypted: boolean): string {\n return op\n }\n\n /**\n * Transform `.or()` conditions before the or-string is rebuilt. The v3\n * dialect maps property names to DB names and `like`/`ilike` on encrypted\n * conditions to `cs`.\n */\n protected transformOrConditions(\n conditions: PendingOrCondition[],\n _encryptedIndexes: Set<number>,\n ): PendingOrCondition[] {\n return conditions\n }\n\n /**\n * Post-process a decrypted result row. The v3 dialect reconstructs `Date`\n * values from the encrypt-config `cast_as`; v2 returns rows unchanged.\n */\n protected postprocessDecryptedRow(\n row: Record<string, unknown>,\n ): Record<string, unknown> {\n return row\n }\n\n // ---------------------------------------------------------------------------\n // Step 5: Decrypt results\n // ---------------------------------------------------------------------------\n\n protected async decryptResults(\n result: RawSupabaseResult,\n ): Promise<EncryptedSupabaseResponse<T[]>> {\n // If there's an error from Supabase, pass it through\n if (result.error) {\n return {\n data: null,\n error: {\n message: result.error.message,\n details: result.error.details,\n hint: result.error.hint,\n code: result.error.code,\n },\n count: result.count ?? null,\n status: result.status,\n statusText: result.statusText,\n }\n }\n\n // No data to decrypt\n if (result.data === null || result.data === undefined) {\n return {\n data: null,\n error: null,\n count: result.count ?? null,\n status: result.status,\n statusText: result.statusText,\n }\n }\n\n // Determine if we need to decrypt\n const hasSelect = this.selectColumns !== null\n const hasMutationWithReturning = this.mutation !== null && hasSelect\n\n if (!hasSelect && !hasMutationWithReturning) {\n // No select means no data to decrypt (e.g., insert without .select())\n return {\n data: result.data as T[],\n error: null,\n count: result.count ?? null,\n status: result.status,\n statusText: result.statusText,\n }\n }\n\n // Decrypt based on result mode\n if (this.resultMode === 'single' || this.resultMode === 'maybeSingle') {\n if (result.data === null) {\n return {\n data: null,\n error: null,\n count: result.count ?? null,\n status: result.status,\n statusText: result.statusText,\n }\n }\n\n // Single result — decrypt one model\n const baseDecryptOp = this.encryptionClient.decryptModel(\n result.data as Record<string, unknown>,\n )\n const decryptOp = this.lockContext\n ? baseDecryptOp.withLockContext(this.lockContext)\n : baseDecryptOp\n if (this.auditConfig) decryptOp.audit(this.auditConfig)\n\n const decrypted = await decryptOp\n if (decrypted.failure) {\n logger.error(\n `Supabase: failed to decrypt model for table \"${this.tableName}\"`,\n )\n\n throw new EncryptionFailedError(\n `Failed to decrypt model: ${decrypted.failure.message}`,\n decrypted.failure,\n )\n }\n\n return {\n data: this.postprocessDecryptedRow(\n decrypted.data as Record<string, unknown>,\n ) as unknown as T[],\n error: null,\n count: result.count ?? null,\n status: result.status,\n statusText: result.statusText,\n }\n }\n\n // Array result — bulk decrypt\n const dataArray = result.data as Record<string, unknown>[]\n if (dataArray.length === 0) {\n return {\n data: [] as unknown as T[],\n error: null,\n count: result.count ?? null,\n status: result.status,\n statusText: result.statusText,\n }\n }\n\n const baseBulkDecryptOp = this.encryptionClient.bulkDecryptModels(dataArray)\n const bulkDecryptOp = this.lockContext\n ? baseBulkDecryptOp.withLockContext(this.lockContext)\n : baseBulkDecryptOp\n if (this.auditConfig) bulkDecryptOp.audit(this.auditConfig)\n\n const decrypted = await bulkDecryptOp\n if (decrypted.failure) {\n logger.error(\n `Supabase: failed to decrypt models for table \"${this.tableName}\"`,\n )\n\n throw new EncryptionFailedError(\n `Failed to decrypt models: ${decrypted.failure.message}`,\n decrypted.failure,\n )\n }\n\n return {\n data: decrypted.data.map((row) =>\n this.postprocessDecryptedRow(row as Record<string, unknown>),\n ) as unknown as T[],\n error: null,\n count: result.count ?? null,\n status: result.status,\n statusText: result.statusText,\n }\n }\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n protected getColumnMap(): Record<string, BuildableQueryColumn> {\n const map: Record<string, BuildableQueryColumn> = {}\n const schema = this.schema as unknown as Record<string, unknown>\n\n for (const colName of this.encryptedColumnNames) {\n const col = schema[colName]\n if (col instanceof EncryptedColumn) {\n map[colName] = col\n }\n }\n\n return map\n }\n}\n\n// ---------------------------------------------------------------------------\n// Internal types\n// ---------------------------------------------------------------------------\n\ntype TermMapping =\n | { source: 'filter'; filterIndex: number; inIndex?: number }\n | { source: 'match'; matchIndex: number; column: string }\n | { source: 'not'; notIndex: number }\n | { source: 'raw'; rawIndex: number }\n | { source: 'or-string'; orIndex: number; conditionIndex: number }\n | { source: 'or-structured'; orIndex: number; conditionIndex: number }\n\ntype EncryptedFilterState = {\n encryptedValues: unknown[]\n termMap: TermMapping[]\n}\n\ntype RawSupabaseResult = {\n data: unknown\n error: {\n message: string\n details?: string\n hint?: string\n code?: string\n } | null\n count?: number | null\n status: number\n statusText: string\n}\n\nexport class EncryptionFailedError extends Error {\n public encryptionError: unknown\n\n constructor(message: string, encryptionError: unknown) {\n super(message)\n this.name = 'EncryptionFailedError'\n this.encryptionError = encryptionError\n }\n}\n","import type { EncryptionClient } from '@/encryption'\nimport type { AnyV3Table } from '@/eql/v3'\nimport { EncryptedV3Column } from '@/eql/v3/columns'\nimport type {\n ColumnSchema,\n EncryptedTable,\n EncryptedTableColumn,\n} from '@/schema'\nimport type { BuildableQueryColumn, ScalarQueryTerm } from '@/types'\nimport { logger } from '@/utils/logger'\nimport { addJsonbCastsV3 } from './helpers'\nimport {\n EncryptedQueryBuilderImpl,\n EncryptionFailedError,\n} from './query-builder'\nimport type {\n FilterOp,\n PendingOrCondition,\n SupabaseClientLike,\n SupabaseQueryBuilder,\n} from './types'\n\n/**\n * The subset of a v3 column builder the dialect relies on. Structural rather\n * than the concrete class union so the runtime `instanceof EncryptedV3Column`\n * gate and this type stay independent.\n *\n * Deliberately NOT `BuildableQueryColumn`'s `BuildableV3QueryableColumn` arm,\n * despite the overlapping members: that type pins `isQueryable(): true`, and\n * this map intentionally retains storage-only columns (whose `isQueryable()`\n * is `false`) so a filter on one produces a precise error instead of passing\n * through unencrypted.\n */\ntype V3ColumnLike = {\n getName(): string\n getEqlType(): string\n getQueryCapabilities(): {\n equality: boolean\n orderAndRange: boolean\n freeTextSearch: boolean\n }\n build(): ColumnSchema\n}\n\n/**\n * EQL v3 dialect of {@link EncryptedQueryBuilderImpl} for native `eql_v3.*`\n * domain columns. The query mechanism is v2's — direct EQL operators over\n * PostgREST — with four narrow forks:\n *\n * - **Column recognition / naming** — v3 columns are `EncryptedV3Column`\n * builders and may map a JS property name to a different DB column name\n * (`buildColumnKeyMap`). Filters, select casts, and mutations resolve\n * property → DB name; select casts alias the DB column back to the property\n * (`prop:db_name::jsonb`) so result rows keep property keys.\n * - **Mutation encoding** — the raw encrypted payload object is sent (the\n * `eql_v3.*` domains are `DOMAIN … AS jsonb`), not v2's `{ data: … }`\n * composite wrap.\n * - **Query-term encoding (INTERIM — tracked as CIP-3402)** — every filter\n * operand is the FULL storage envelope from `encrypt()`, serialized as\n * jsonb text. Why it is required today: each `eql_v3.*` domain CHECK\n * requires the storage keys (`v`/`i`/`c` plus the domain's index terms),\n * the SQL operator functions coerce their jsonb operand into the domain,\n * and protect-ffi has no v3 scalar query wire shape (`encryptQuery` throws\n * `EQL_V3_QUERY_UNSUPPORTED` on a v3 client) — so a term-only operand is\n * impossible for EVERY domain, not just `text_search`. The full envelope\n * satisfies the CHECK by construction and the operators extract the term\n * they need (`eq_term`/`ord_term`/`match_term`). Caveat: operands carry a\n * real ciphertext plus ALL index terms through PostgREST GET query strings\n * (URL logs/proxies). Replaced by the EQL-side term-only scalar query\n * envelope when it ships — see {@link encryptCollectedTerms}, the single\n * swap point.\n * - **`like`/`ilike`** — the v3 domains define no LIKE operator; free-text\n * match is `@>` on the bloom filter. Encrypted pattern filters are emitted\n * as PostgREST `cs` instead. (Match is tokenized + downcased, so `like` and\n * `ilike` behave identically. For substring patterns to match, the column's\n * match index should set `include_original: false` — with the default\n * `true`, the full-envelope operand's bloom carries the whole pattern as an\n * extra token that only matches when the pattern equals the stored value.)\n *\n * Decrypted rows additionally get `Date` reconstruction from the\n * encrypt-config `cast_as`, mirroring the typed v3 client.\n */\nexport class EncryptedQueryBuilderV3Impl<\n T extends Record<string, unknown> = Record<string, unknown>,\n> extends EncryptedQueryBuilderImpl<T> {\n private v3Table: AnyV3Table\n /** JS property name → DB column name, for every encrypted column. */\n private propToDb: Record<string, string>\n /** Built column schemas keyed by DB column name (for `cast_as`). */\n private columnSchemas: Record<string, ColumnSchema>\n /** Column builders keyed by BOTH property name and DB name. */\n private v3Columns: Record<string, V3ColumnLike>\n /**\n * Result-row key → DB column name for the columns the current select\n * produces, including user-chosen PostgREST aliases (`ts:created_at` keys\n * rows by `ts`). Populated by {@link buildSelectString}; consumed by\n * {@link postprocessDecryptedRow} so aliased date columns still get `Date`\n * reconstruction.\n */\n private selectKeyToDb: Record<string, string> = {}\n\n constructor(\n tableName: string,\n table: AnyV3Table,\n encryptionClient: EncryptionClient,\n supabaseClient: SupabaseClientLike,\n ) {\n super(\n tableName,\n // The base class only ever calls BuildableTable members on the schema\n // (build / encryptModel plumbing); every v2-specific behaviour is\n // overridden below.\n table as unknown as EncryptedTable<EncryptedTableColumn>,\n encryptionClient,\n supabaseClient,\n )\n\n this.v3Table = table\n this.propToDb = table.buildColumnKeyMap()\n this.columnSchemas = table.build().columns\n\n this.v3Columns = {}\n for (const [property, builder] of Object.entries(table.columnBuilders)) {\n if (builder instanceof EncryptedV3Column) {\n const col = builder as unknown as V3ColumnLike\n this.v3Columns[property] = col\n this.v3Columns[col.getName()] = col\n }\n }\n\n // The base class derives encrypted column names from build(), which v3\n // keys by DB name. Filters and select strings address columns by JS\n // property name, so recognition must cover both.\n this.encryptedColumnNames = Object.keys(this.v3Columns)\n }\n\n // ---------------------------------------------------------------------------\n // Dialect overrides\n // ---------------------------------------------------------------------------\n\n protected override getColumnMap(): Record<string, BuildableQueryColumn> {\n return this.v3Columns as unknown as Record<string, BuildableQueryColumn>\n }\n\n protected override filterColumnName(column: string): string {\n return this.propToDb[column] ?? column\n }\n\n protected override buildSelectString(): string | null {\n if (this.selectColumns === null) return null\n const { select, keyToDb } = addJsonbCastsV3(\n this.selectColumns,\n this.propToDb,\n )\n this.selectKeyToDb = keyToDb\n return select\n }\n\n /** v3 domains are plain jsonb — send the raw payload, keyed by DB name. */\n protected override transformEncryptedMutationModel(\n model: Record<string, unknown>,\n ): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n for (const [key, value] of Object.entries(model)) {\n out[this.propToDb[key] ?? key] = value\n }\n return out\n }\n\n protected override transformEncryptedMutationModels(\n models: Record<string, unknown>[],\n ): Record<string, unknown>[] {\n return models.map((model) => this.transformEncryptedMutationModel(model))\n }\n\n /**\n * Encrypt every filter operand as a full storage envelope (see the class\n * doc for why `encryptQuery` terms cannot be used), serialized to jsonb\n * text for the PostgREST filter value.\n *\n * INTERIM + single swap point. The full-envelope operand is a tracked\n * workaround (Linear CIP-3402), not the design: it carries a real\n * decryptable ciphertext `c` plus ALL of the column's index terms, and\n * PostgREST filters travel in GET query strings — so operands can land in\n * URL logs, proxies, and Supabase request logs (query terms are meant to\n * be index-terms-only). When the EQL term-only scalar query envelope (the\n * scalar analog of `eql_v3.jsonb_query`) ships, swapping the encryption\n * call inside THIS method — and its `JSON.stringify` wire encoding — must\n * be the ONLY change needed: every consuming seam (filter application,\n * `or`/`not` transforms, the wire-operator remap) treats the returned\n * operand as an opaque, already-encoded string and is encoding-agnostic.\n * Do not let operand-encoding knowledge leak out of this method.\n */\n protected override async encryptCollectedTerms(\n terms: ScalarQueryTerm[],\n ): Promise<unknown[]> {\n return Promise.all(\n terms.map(async (term) => {\n const column = term.column as unknown as V3ColumnLike\n const queryType = term.queryType ?? 'equality'\n const capabilities = column.getQueryCapabilities()\n\n // encrypt(null) short-circuits to null, which JSON.stringify would\n // turn into the literal string \"null\" — a silently-wrong operand.\n if (term.value == null) {\n throw new Error(\n `[supabase v3]: cannot encrypt a null filter value for column \"${column.getName()}\" — use .is('${column.getName()}', null) for NULL checks`,\n )\n }\n\n if (\n queryType !== 'equality' &&\n queryType !== 'orderAndRange' &&\n queryType !== 'freeTextSearch'\n ) {\n throw new Error(\n `[supabase v3]: query type \"${queryType}\" is not supported on scalar eql_v3 columns`,\n )\n }\n\n if (!capabilities[queryType]) {\n throw new Error(\n `[supabase v3]: column \"${column.getName()}\" (${column.getEqlType()}) does not support ${queryType} queries — declare the column with a domain that carries that capability`,\n )\n }\n\n const baseOp = this.encryptionClient.encrypt(term.value, {\n column,\n table: this.v3Table,\n })\n const op = this.lockContext\n ? baseOp.withLockContext(this.lockContext)\n : baseOp\n if (this.auditConfig) op.audit(this.auditConfig)\n\n const result = await op\n if (result.failure) {\n logger.error(\n `Supabase: failed to encrypt query terms for table \"${this.tableName}\"`,\n )\n\n throw new EncryptionFailedError(\n `Failed to encrypt query terms: ${result.failure.message}`,\n result.failure,\n )\n }\n\n return JSON.stringify(result.data)\n }),\n )\n }\n\n /**\n * The single source of the encrypted wire-operator remap: `like`/`ilike`\n * on an encrypted column become PostgREST `cs` (bloom-filter `@>`) — the\n * `eql_v3.*` domains define no LIKE operator. Every pattern-bearing seam\n * (`applyPatternFilter`, `notFilterOperator`, `transformOrConditions`)\n * derives its operator here so they cannot drift apart.\n */\n private encryptedFilterOp(op: string, wasEncrypted: boolean): string {\n return wasEncrypted && (op === 'like' || op === 'ilike') ? 'cs' : op\n }\n\n /** Encrypted pattern filters go through the bloom-filter `@>` (`cs`). */\n protected override applyPatternFilter(\n q: SupabaseQueryBuilder,\n column: string,\n op: 'like' | 'ilike',\n value: unknown,\n wasEncrypted: boolean,\n ): SupabaseQueryBuilder {\n const wireOp = this.encryptedFilterOp(op, wasEncrypted)\n if (wireOp !== op) {\n return q.filter(column, wireOp, value)\n }\n return super.applyPatternFilter(q, column, op, value, wasEncrypted)\n }\n\n protected override notFilterOperator(\n op: FilterOp,\n wasEncrypted: boolean,\n ): string {\n return this.encryptedFilterOp(op, wasEncrypted)\n }\n\n protected override transformOrConditions(\n conditions: PendingOrCondition[],\n encryptedIndexes: Set<number>,\n ): PendingOrCondition[] {\n return conditions.map((cond, j) => ({\n ...cond,\n column: this.filterColumnName(cond.column),\n op: this.encryptedFilterOp(cond.op, encryptedIndexes.has(j)) as FilterOp,\n }))\n }\n\n /** Rebuild `Date` values from the encrypt-config `cast_as`, mirroring the\n * typed v3 client's decrypt-model path. */\n protected override postprocessDecryptedRow(\n row: Record<string, unknown>,\n ): Record<string, unknown> {\n // Row key → DB column name for every key an encrypted column can appear\n // under: the select's actual keys (including user-chosen aliases like\n // `ts:created_at`) plus the static property/DB names as a fallback for\n // paths with no recorded select.\n const keyToDb: Record<string, string> = { ...this.selectKeyToDb }\n for (const [property, dbName] of Object.entries(this.propToDb)) {\n keyToDb[property] ??= dbName\n keyToDb[dbName] ??= dbName\n }\n\n const out: Record<string, unknown> = { ...row }\n for (const [key, dbName] of Object.entries(keyToDb)) {\n // Both 'date' and 'timestamp' columns decrypt to a JS `Date`.\n const castAs = this.columnSchemas[dbName]?.cast_as\n if (castAs !== 'date' && castAs !== 'timestamp') continue\n const value = out[key]\n if (value == null || value instanceof Date) continue\n if (typeof value === 'string' || typeof value === 'number') {\n out[key] = new Date(value)\n }\n }\n return out\n }\n}\n","import type { AnyV3Table, InferPlaintext } from '@/eql/v3'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport { EncryptedQueryBuilderImpl } from './query-builder'\nimport { EncryptedQueryBuilderV3Impl } from './query-builder-v3'\nimport type {\n EncryptedQueryBuilderV3,\n EncryptedSupabaseConfig,\n EncryptedSupabaseInstance,\n EncryptedSupabaseV3Config,\n EncryptedSupabaseV3Instance,\n} from './types'\n\n/**\n * Create an encrypted Supabase wrapper that transparently handles encryption\n * and decryption for queries on encrypted columns.\n *\n * @param config - Configuration containing the encryption client and Supabase client.\n * @returns An object with a `from()` method that mirrors `supabase.from()` but\n * auto-encrypts mutations, adds `::jsonb` casts, encrypts filter values, and\n * decrypts results.\n *\n * @example\n * ```typescript\n * import { Encryption } from '@cipherstash/stack'\n * import { encryptedSupabase } from '@cipherstash/stack/supabase'\n * import { encryptedTable, encryptedColumn } from '@cipherstash/stack/schema'\n *\n * const users = encryptedTable('users', {\n * name: encryptedColumn('name').freeTextSearch().equality(),\n * email: encryptedColumn('email').freeTextSearch().equality(),\n * })\n *\n * const client = await Encryption({ schemas: [users] })\n * const eSupabase = encryptedSupabase({ encryptionClient: client, supabaseClient: supabase })\n *\n * // INSERT - auto-encrypts, auto-converts to PG composite\n * await eSupabase.from('users', users)\n * .insert({ name: 'John', email: 'john@example.com', age: 30 })\n *\n * // SELECT with filter - auto-casts ::jsonb, auto-encrypts search term, auto-decrypts\n * const { data } = await eSupabase.from('users', users)\n * .select('id, email, name')\n * .eq('email', 'john@example.com')\n * ```\n */\nexport function encryptedSupabase(\n config: EncryptedSupabaseConfig,\n): EncryptedSupabaseInstance {\n const { encryptionClient, supabaseClient } = config\n\n return {\n from<T extends Record<string, unknown> = Record<string, unknown>>(\n tableName: string,\n schema: EncryptedTable<EncryptedTableColumn>,\n ) {\n return new EncryptedQueryBuilderImpl<T>(\n tableName,\n schema,\n encryptionClient,\n supabaseClient,\n )\n },\n }\n}\n\n/**\n * Create an encrypted Supabase wrapper for **EQL v3** schemas — tables\n * authored with `@cipherstash/stack/eql/v3` whose columns are native\n * `eql_v3.*` domains.\n *\n * The public surface and call shape are identical to {@link encryptedSupabase}\n * (`.eq/.neq/.in/.gt/.gte/.lt/.lte/.like/.ilike/.match/.or/.not/.filter`,\n * `withLockContext`, `audit`); only the schema type and the wire encoding\n * differ. The same Supabase caveats carry over: the `eql_v3` schema must be\n * added to the project's **Exposed schemas** and granted to the Supabase\n * roles for the operators to resolve, and encrypted `ORDER BY` is\n * unsupported (range *filtering* works).\n *\n * @example\n * ```typescript\n * import { Encryption } from '@cipherstash/stack'\n * import { encryptedTable, types } from '@cipherstash/stack/eql/v3'\n * import { encryptedSupabaseV3 } from '@cipherstash/stack/supabase'\n *\n * const users = encryptedTable('users', {\n * email: types.TextSearch('email'), // eql_v3.text_search\n * amount: types.IntegerOrd('amount'), // eql_v3.integer_ord\n * })\n *\n * const client = await Encryption({ schemas: [users] })\n * const es = encryptedSupabaseV3({ encryptionClient: client, supabaseClient: supabase })\n *\n * await es.from('users', users).insert({ email: 'a@b.com', amount: 30 })\n * await es.from('users', users).select('id, email, amount').eq('email', 'a@b.com')\n * await es.from('users', users).select('id, amount').gte('amount', 10).lte('amount', 100)\n * ```\n */\nexport function encryptedSupabaseV3(\n config: EncryptedSupabaseV3Config,\n): EncryptedSupabaseV3Instance {\n const { encryptionClient, supabaseClient } = config\n\n return {\n from<\n Table extends AnyV3Table,\n Row extends Record<string, unknown> = InferPlaintext<Table>,\n >(tableName: string, table: Table) {\n return new EncryptedQueryBuilderV3Impl<Row>(\n tableName,\n table,\n encryptionClient,\n supabaseClient,\n ) as unknown as EncryptedQueryBuilderV3<Table, Row>\n },\n }\n}\n\nexport type {\n EncryptedQueryBuilder,\n EncryptedQueryBuilderV3,\n EncryptedSupabaseConfig,\n EncryptedSupabaseError,\n EncryptedSupabaseInstance,\n EncryptedSupabaseResponse,\n EncryptedSupabaseV3Config,\n EncryptedSupabaseV3Instance,\n PendingOrCondition,\n SupabaseClientLike,\n V3FilterableKeys,\n} from './types'\n"],"mappings":"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","names":["db","baseOp","op","result","decrypted"]}
|
|
File without changes
|