@cipherstash/stack 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (64) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -2
  3. package/dist/bin/stash.js +63 -45
  4. package/dist/bin/stash.js.map +1 -1
  5. package/dist/{chunk-5G4F4JJG.js → chunk-JLI27P46.js} +1 -1
  6. package/dist/chunk-JLI27P46.js.map +1 -0
  7. package/dist/{chunk-LHZ6KZIG.js → chunk-MW6D52V2.js} +42 -31
  8. package/dist/chunk-MW6D52V2.js.map +1 -0
  9. package/dist/{chunk-5DCT6YU2.js → chunk-OAPLZLR5.js} +7 -3
  10. package/dist/{chunk-5DCT6YU2.js.map → chunk-OAPLZLR5.js.map} +1 -1
  11. package/dist/{chunk-7XRPN2KX.js → chunk-TBAIVO6T.js} +26 -23
  12. package/dist/chunk-TBAIVO6T.js.map +1 -0
  13. package/dist/{client-D-ZH8SB2.d.cts → client-Bf0Xw2xo.d.cts} +19 -16
  14. package/dist/{client-BV9pXC-d.d.ts → client-Kfp8OsPB.d.ts} +19 -16
  15. package/dist/client.cjs +25 -22
  16. package/dist/client.cjs.map +1 -1
  17. package/dist/client.d.cts +2 -2
  18. package/dist/client.d.ts +2 -2
  19. package/dist/client.js +5 -5
  20. package/dist/drizzle/index.cjs +19 -16
  21. package/dist/drizzle/index.cjs.map +1 -1
  22. package/dist/drizzle/index.d.cts +5 -5
  23. package/dist/drizzle/index.d.ts +5 -5
  24. package/dist/drizzle/index.js +2 -2
  25. package/dist/drizzle/index.js.map +1 -1
  26. package/dist/dynamodb/index.cjs.map +1 -1
  27. package/dist/dynamodb/index.d.cts +10 -10
  28. package/dist/dynamodb/index.d.ts +10 -10
  29. package/dist/dynamodb/index.js.map +1 -1
  30. package/dist/identity/index.cjs +6 -2
  31. package/dist/identity/index.cjs.map +1 -1
  32. package/dist/identity/index.js +1 -1
  33. package/dist/index.cjs +67 -49
  34. package/dist/index.cjs.map +1 -1
  35. package/dist/index.d.cts +3 -3
  36. package/dist/index.d.ts +3 -3
  37. package/dist/index.js +7 -7
  38. package/dist/schema/index.cjs +31 -28
  39. package/dist/schema/index.cjs.map +1 -1
  40. package/dist/schema/index.d.cts +1 -1
  41. package/dist/schema/index.d.ts +1 -1
  42. package/dist/schema/index.js +11 -11
  43. package/dist/secrets/index.cjs +63 -45
  44. package/dist/secrets/index.cjs.map +1 -1
  45. package/dist/secrets/index.d.cts +1 -1
  46. package/dist/secrets/index.d.ts +1 -1
  47. package/dist/secrets/index.js +4 -4
  48. package/dist/secrets/index.js.map +1 -1
  49. package/dist/supabase/index.cjs +7 -7
  50. package/dist/supabase/index.cjs.map +1 -1
  51. package/dist/supabase/index.d.cts +3 -3
  52. package/dist/supabase/index.d.ts +3 -3
  53. package/dist/supabase/index.js +3 -3
  54. package/dist/supabase/index.js.map +1 -1
  55. package/dist/{types-public-Dfg-hkuQ.d.cts → types-public-0CzBV45X.d.cts} +70 -52
  56. package/dist/{types-public-Dfg-hkuQ.d.ts → types-public-0CzBV45X.d.ts} +70 -52
  57. package/dist/types-public.cjs.map +1 -1
  58. package/dist/types-public.d.cts +1 -1
  59. package/dist/types-public.d.ts +1 -1
  60. package/dist/types-public.js +1 -1
  61. package/package.json +1 -1
  62. package/dist/chunk-5G4F4JJG.js.map +0 -1
  63. package/dist/chunk-7XRPN2KX.js.map +0 -1
  64. package/dist/chunk-LHZ6KZIG.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/supabase/helpers.ts","../../src/supabase/query-builder.ts","../../src/supabase/index.ts"],"sourcesContent":["import type { ProtectColumn, ProtectTable, ProtectTableColumn } 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: ProtectTable<ProtectTableColumn>,\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 * 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\n for (const char of input) {\n if (char === '(') {\n depth++\n current += char\n } else if (char === ')') {\n depth--\n current += char\n } else if (char === ',' && depth === 0) {\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 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\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 return String(value)\n}\n","import type { EncryptionClient } from '@/encryption/ffi'\nimport type { AuditConfig } from '@/encryption/ffi/operations/base-operation'\nimport {\n bulkModelsToEncryptedPgComposites,\n modelToEncryptedPgComposites,\n} from '@/encryption/helpers'\nimport type { LockContext } from '@/identity'\nimport type { ProtectTable, ProtectTableColumn } from '@/schema'\nimport { ProtectColumn } from '@/schema'\nimport type { ScalarQueryTerm } from '@/types'\nimport type { JsPlaintext } from '@cipherstash/protect-ffi'\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 private tableName: string\n private schema: ProtectTable<ProtectTableColumn>\n private encryptionClient: EncryptionClient\n private supabaseClient: SupabaseClientLike\n private encryptedColumnNames: string[]\n\n // Recorded operations\n private mutation: MutationOp | null = null\n private selectColumns: string | null = null\n private selectOptions:\n | { head?: boolean; count?: 'exact' | 'planned' | 'estimated' }\n | undefined = undefined\n private filters: PendingFilter[] = []\n private orFilters: PendingOrFilter[] = []\n private matchFilters: PendingMatchFilter[] = []\n private notFilters: PendingNotFilter[] = []\n private rawFilters: PendingRawFilter[] = []\n private transforms: TransformOp[] = []\n private resultMode: ResultMode = 'array'\n private shouldThrowOnError = false\n\n // Encryption-specific state\n private lockContext: LockContext | null = null\n private auditConfig: AuditConfig | null = null\n\n constructor(\n tableName: string,\n schema: ProtectTable<ProtectTableColumn>,\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 private async execute(): Promise<EncryptedSupabaseResponse<T[]>> {\n try {\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 error: EncryptedSupabaseError = {\n message: err instanceof Error ? err.message : String(err),\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 private 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 throw new EncryptionFailedError(\n `Failed to encrypt models: ${result.failure.message}`,\n result.failure,\n )\n }\n\n return bulkModelsToEncryptedPgComposites(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 throw new EncryptionFailedError(\n `Failed to encrypt model: ${result.failure.message}`,\n result.failure,\n )\n }\n\n return modelToEncryptedPgComposites(result.data)\n }\n\n // ---------------------------------------------------------------------------\n // Step 2: Build select string with casts\n // ---------------------------------------------------------------------------\n\n private 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 private 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 // `is` is used for null/boolean checks — don't encrypt\n continue\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 // 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 throw new EncryptionFailedError(\n `Failed to encrypt query terms: ${result.failure.message}`,\n result.failure,\n )\n }\n\n return { encryptedValues: result.data, termMap }\n }\n\n // ---------------------------------------------------------------------------\n // Step 4: Build and execute real Supabase query\n // ---------------------------------------------------------------------------\n\n private 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 private 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 switch (f.op) {\n case 'eq':\n q = q.eq(f.column, value)\n break\n case 'neq':\n q = q.neq(f.column, value)\n break\n case 'gt':\n q = q.gt(f.column, value)\n break\n case 'gte':\n q = q.gte(f.column, value)\n break\n case 'lt':\n q = q.lt(f.column, value)\n break\n case 'lte':\n q = q.lte(f.column, value)\n break\n case 'like':\n q = q.like(f.column, value as string)\n break\n case 'ilike':\n q = q.ilike(f.column, value as string)\n break\n case 'is':\n q = q.is(f.column, value)\n break\n case 'in':\n q = q.in(f.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[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 value = notValueMap.has(i) ? notValueMap.get(i) : nf.value\n q = q.not(nf.column, nf.op, value)\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 let hasEncrypted = false\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 hasEncrypted = true\n }\n }\n\n if (hasEncrypted) {\n q = q.or(rebuildOrString(parsed), {\n referencedTable: of_.referencedTable,\n })\n } else {\n q = q.or(of_.value, { referencedTable: of_.referencedTable })\n }\n } else {\n // Structured: convert to string\n const conditions = of_.conditions.map((cond, j) => {\n const key = `${i}:${j}`\n if (orStructuredConditionMap.has(key)) {\n return { ...cond, value: orStructuredConditionMap.get(key) }\n }\n return cond\n })\n\n q = q.or(rebuildOrString(conditions))\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(rf.column, rf.operator, value)\n }\n\n return q\n }\n\n // ---------------------------------------------------------------------------\n // Step 5: Decrypt results\n // ---------------------------------------------------------------------------\n\n private 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 throw new EncryptionFailedError(\n `Failed to decrypt model: ${decrypted.failure.message}`,\n decrypted.failure,\n )\n }\n\n return {\n data: decrypted.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 // 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 throw new EncryptionFailedError(\n `Failed to decrypt models: ${decrypted.failure.message}`,\n decrypted.failure,\n )\n }\n\n return {\n data: decrypted.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 // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n private getColumnMap(): Record<string, ProtectColumn> {\n const map: Record<string, ProtectColumn> = {}\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 ProtectColumn) {\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\nclass 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/ffi'\nimport type { ProtectTable, ProtectTableColumn } from '@/schema'\nimport { EncryptedQueryBuilderImpl } from './query-builder'\nimport type {\n EncryptedSupabaseConfig,\n EncryptedSupabaseInstance,\n SupabaseClientLike,\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: ProtectTable<ProtectTableColumn>,\n ) {\n return new EncryptedQueryBuilderImpl<T>(\n tableName,\n schema,\n encryptionClient,\n supabaseClient,\n )\n },\n }\n}\n\nexport type {\n EncryptedSupabaseConfig,\n EncryptedSupabaseInstance,\n EncryptedSupabaseResponse,\n EncryptedSupabaseError,\n EncryptedQueryBuilder,\n PendingOrCondition,\n SupabaseClientLike,\n} from './types'\n"],"mappings":"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","names":["baseOp","op","result","decrypted"]}
1
+ {"version":3,"sources":["../../src/supabase/helpers.ts","../../src/supabase/query-builder.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 * 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\n for (const char of input) {\n if (char === '(') {\n depth++\n current += char\n } else if (char === ')') {\n depth--\n current += char\n } else if (char === ',' && depth === 0) {\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 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\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 return String(value)\n}\n","import type { EncryptionClient } from '@/encryption'\nimport type { AuditConfig } from '@/encryption/operations/base-operation'\nimport {\n bulkModelsToEncryptedPgComposites,\n modelToEncryptedPgComposites,\n} from '@/encryption/helpers'\nimport type { LockContext } from '@/identity'\nimport type { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport { EncryptedColumn } from '@/schema'\nimport type { ScalarQueryTerm } from '@/types'\nimport type { JsPlaintext } from '@cipherstash/protect-ffi'\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 private tableName: string\n private schema: EncryptedTable<EncryptedTableColumn>\n private encryptionClient: EncryptionClient\n private supabaseClient: SupabaseClientLike\n private encryptedColumnNames: string[]\n\n // Recorded operations\n private mutation: MutationOp | null = null\n private selectColumns: string | null = null\n private selectOptions:\n | { head?: boolean; count?: 'exact' | 'planned' | 'estimated' }\n | undefined = undefined\n private filters: PendingFilter[] = []\n private orFilters: PendingOrFilter[] = []\n private matchFilters: PendingMatchFilter[] = []\n private notFilters: PendingNotFilter[] = []\n private rawFilters: PendingRawFilter[] = []\n private transforms: TransformOp[] = []\n private resultMode: ResultMode = 'array'\n private shouldThrowOnError = false\n\n // Encryption-specific state\n private lockContext: LockContext | null = null\n private 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 private async execute(): Promise<EncryptedSupabaseResponse<T[]>> {\n try {\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 error: EncryptedSupabaseError = {\n message: err instanceof Error ? err.message : String(err),\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 private 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 throw new EncryptionFailedError(\n `Failed to encrypt models: ${result.failure.message}`,\n result.failure,\n )\n }\n\n return bulkModelsToEncryptedPgComposites(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 throw new EncryptionFailedError(\n `Failed to encrypt model: ${result.failure.message}`,\n result.failure,\n )\n }\n\n return modelToEncryptedPgComposites(result.data)\n }\n\n // ---------------------------------------------------------------------------\n // Step 2: Build select string with casts\n // ---------------------------------------------------------------------------\n\n private 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 private 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 // `is` is used for null/boolean checks — don't encrypt\n continue\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 // 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 throw new EncryptionFailedError(\n `Failed to encrypt query terms: ${result.failure.message}`,\n result.failure,\n )\n }\n\n return { encryptedValues: result.data, termMap }\n }\n\n // ---------------------------------------------------------------------------\n // Step 4: Build and execute real Supabase query\n // ---------------------------------------------------------------------------\n\n private 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 private 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 switch (f.op) {\n case 'eq':\n q = q.eq(f.column, value)\n break\n case 'neq':\n q = q.neq(f.column, value)\n break\n case 'gt':\n q = q.gt(f.column, value)\n break\n case 'gte':\n q = q.gte(f.column, value)\n break\n case 'lt':\n q = q.lt(f.column, value)\n break\n case 'lte':\n q = q.lte(f.column, value)\n break\n case 'like':\n q = q.like(f.column, value as string)\n break\n case 'ilike':\n q = q.ilike(f.column, value as string)\n break\n case 'is':\n q = q.is(f.column, value)\n break\n case 'in':\n q = q.in(f.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[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 value = notValueMap.has(i) ? notValueMap.get(i) : nf.value\n q = q.not(nf.column, nf.op, value)\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 let hasEncrypted = false\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 hasEncrypted = true\n }\n }\n\n if (hasEncrypted) {\n q = q.or(rebuildOrString(parsed), {\n referencedTable: of_.referencedTable,\n })\n } else {\n q = q.or(of_.value, { referencedTable: of_.referencedTable })\n }\n } else {\n // Structured: convert to string\n const conditions = of_.conditions.map((cond, j) => {\n const key = `${i}:${j}`\n if (orStructuredConditionMap.has(key)) {\n return { ...cond, value: orStructuredConditionMap.get(key) }\n }\n return cond\n })\n\n q = q.or(rebuildOrString(conditions))\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(rf.column, rf.operator, value)\n }\n\n return q\n }\n\n // ---------------------------------------------------------------------------\n // Step 5: Decrypt results\n // ---------------------------------------------------------------------------\n\n private 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 throw new EncryptionFailedError(\n `Failed to decrypt model: ${decrypted.failure.message}`,\n decrypted.failure,\n )\n }\n\n return {\n data: decrypted.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 // 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 throw new EncryptionFailedError(\n `Failed to decrypt models: ${decrypted.failure.message}`,\n decrypted.failure,\n )\n }\n\n return {\n data: decrypted.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 // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n private getColumnMap(): Record<string, EncryptedColumn> {\n const map: Record<string, EncryptedColumn> = {}\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\nclass 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 { EncryptedTable, EncryptedTableColumn } from '@/schema'\nimport { EncryptedQueryBuilderImpl } from './query-builder'\nimport type {\n EncryptedSupabaseConfig,\n EncryptedSupabaseInstance,\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\nexport type {\n EncryptedSupabaseConfig,\n EncryptedSupabaseInstance,\n EncryptedSupabaseResponse,\n EncryptedSupabaseError,\n EncryptedQueryBuilder,\n PendingOrCondition,\n SupabaseClientLike,\n} from './types'\n"],"mappings":"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","names":["baseOp","op","result","decrypted"]}
@@ -61,20 +61,26 @@ type ClientConfig = {
61
61
  };
62
62
  type AtLeastOneCsTable<T> = [T, ...T[]];
63
63
  type EncryptionClientConfig = {
64
- schemas: AtLeastOneCsTable<ProtectTable<ProtectTableColumn>>;
64
+ schemas: AtLeastOneCsTable<EncryptedTable<EncryptedTableColumn>>;
65
65
  config?: ClientConfig;
66
66
  logging?: LoggingConfig;
67
67
  };
68
+ /**
69
+ * Options for single-value encrypt operations.
70
+ * Use a column from your table schema (from {@link encryptedColumn}) or a nested
71
+ * field (from {@link encryptedField}) as the target for encryption.
72
+ */
68
73
  type EncryptOptions = {
69
- column: ProtectColumn | ProtectValue;
70
- table: ProtectTable<ProtectTableColumn>;
74
+ /** The column or nested field to encrypt into. From {@link EncryptedColumn} or {@link EncryptedField}. */
75
+ column: EncryptedColumn | EncryptedField;
76
+ table: EncryptedTable<EncryptedTableColumn>;
71
77
  };
72
78
  /** Format for encrypted query/search term return values */
73
79
  type EncryptedReturnType = 'eql' | 'composite-literal' | 'escaped-composite-literal';
74
80
  type SearchTerm = {
75
81
  value: JsPlaintext;
76
- column: ProtectColumn;
77
- table: ProtectTable<ProtectTableColumn>;
82
+ column: EncryptedColumn;
83
+ table: EncryptedTable<EncryptedTableColumn>;
78
84
  returnType?: EncryptedReturnType;
79
85
  };
80
86
  /** Encrypted search term result: EQL object or composite literal string */
@@ -98,7 +104,7 @@ type Decrypted<T> = OtherFields<T> & DecryptedFields<T>;
98
104
  * Fields whose keys match columns defined in `S` become `Encrypted`;
99
105
  * all other fields retain their original types from `T`.
100
106
  *
101
- * When `S` is the widened `ProtectTableColumn` (e.g. when a user passes an
107
+ * When `S` is the widened `EncryptedTableColumn` (e.g. when a user passes an
102
108
  * explicit `<User>` type argument without specifying `S`), the type degrades
103
109
  * gracefully to `T` — preserving backward compatibility.
104
110
  *
@@ -109,12 +115,12 @@ type Decrypted<T> = OtherFields<T> & DecryptedFields<T>;
109
115
  * ```typescript
110
116
  * type User = { id: string; email: string }
111
117
  * // With a schema that defines `email`:
112
- * type Encrypted = EncryptedFromSchema<User, { email: ProtectColumn }>
118
+ * type Encrypted = EncryptedFromSchema<User, { email: EncryptedColumn }>
113
119
  * // => { id: string; email: Encrypted }
114
120
  * ```
115
121
  */
116
- type EncryptedFromSchema<T, S extends ProtectTableColumn> = {
117
- [K in keyof T]: [K] extends [keyof S] ? [S[K & keyof S]] extends [ProtectColumn | ProtectValue] ? Encrypted : T[K] : T[K];
122
+ type EncryptedFromSchema<T, S extends EncryptedTableColumn> = {
123
+ [K in keyof T]: [K] extends [keyof S] ? [S[K & keyof S]] extends [EncryptedColumn | EncryptedField] ? Encrypted : T[K] : T[K];
118
124
  };
119
125
  type BulkEncryptPayload = Array<{
120
126
  id?: string;
@@ -166,8 +172,8 @@ declare const queryTypes: {
166
172
  };
167
173
  /** @internal */
168
174
  type QueryTermBase = {
169
- column: ProtectColumn;
170
- table: ProtectTable<ProtectTableColumn>;
175
+ column: EncryptedColumn;
176
+ table: EncryptedTable<EncryptedTableColumn>;
171
177
  queryType?: QueryTypeName;
172
178
  returnType?: EncryptedReturnType;
173
179
  };
@@ -729,35 +735,44 @@ type SteVecIndexOpts = z.infer<typeof steVecIndexOptsSchema>;
729
735
  type UniqueIndexOpts = z.infer<typeof uniqueIndexOptsSchema>;
730
736
  type OreIndexOpts = z.infer<typeof oreIndexOptsSchema>;
731
737
  type ColumnSchema = z.infer<typeof columnSchema>;
732
- type ProtectTableColumn = {
733
- [key: string]: ProtectColumn | {
734
- [key: string]: ProtectValue | {
735
- [key: string]: ProtectValue | {
736
- [key: string]: ProtectValue;
738
+ /**
739
+ * Shape of table columns: either top-level {@link EncryptedColumn} or nested
740
+ * objects whose leaves are {@link EncryptedField}. Used with {@link encryptedTable}.
741
+ */
742
+ type EncryptedTableColumn = {
743
+ [key: string]: EncryptedColumn | {
744
+ [key: string]: EncryptedField | {
745
+ [key: string]: EncryptedField | {
746
+ [key: string]: EncryptedField;
737
747
  };
738
748
  };
739
749
  };
740
750
  };
741
751
  type EncryptConfig = z.infer<typeof encryptConfigSchema>;
742
- declare class ProtectValue {
752
+ /**
753
+ * Builder for a nested encrypted field (encrypted but not searchable).
754
+ * Create with {@link encryptedField}. Use inside nested objects in {@link encryptedTable};
755
+ * supports `.dataType()` for plaintext type. No index methods (equality, orderAndRange, etc.).
756
+ */
757
+ declare class EncryptedField {
743
758
  private valueName;
744
759
  private castAsValue;
745
760
  constructor(valueName: string);
746
761
  /**
747
- * Set or override the plaintext data type for this value.
762
+ * Set or override the plaintext data type for this field.
748
763
  *
749
764
  * By default all values are treated as `'string'`. Use this method to specify
750
765
  * a different type so the encryption layer knows how to encode the plaintext
751
766
  * before encrypting.
752
767
  *
753
768
  * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
754
- * @returns This `ProtectValue` instance for method chaining.
769
+ * @returns This `EncryptedField` instance for method chaining.
755
770
  *
756
771
  * @example
757
772
  * ```typescript
758
- * import { encryptedValue } from "@cipherstash/stack/schema"
773
+ * import { encryptedField } from "@cipherstash/stack/schema"
759
774
  *
760
- * const age = encryptedValue("age").dataType("number")
775
+ * const age = encryptedField("age").dataType("number")
761
776
  * ```
762
777
  */
763
778
  dataType(castAs: CastAs): this;
@@ -767,7 +782,7 @@ declare class ProtectValue {
767
782
  };
768
783
  getName(): string;
769
784
  }
770
- declare class ProtectColumn {
785
+ declare class EncryptedColumn {
771
786
  private columnName;
772
787
  private castAsValue;
773
788
  private indexesValue;
@@ -780,7 +795,7 @@ declare class ProtectColumn {
780
795
  * before encrypting.
781
796
  *
782
797
  * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
783
- * @returns This `ProtectColumn` instance for method chaining.
798
+ * @returns This `EncryptedColumn` instance for method chaining.
784
799
  *
785
800
  * @example
786
801
  * ```typescript
@@ -796,7 +811,7 @@ declare class ProtectColumn {
796
811
  * ORE allows sorting, comparison, and range queries on encrypted data.
797
812
  * Use with `encryptQuery` and `queryType: 'orderAndRange'`.
798
813
  *
799
- * @returns This `ProtectColumn` instance for method chaining.
814
+ * @returns This `EncryptedColumn` instance for method chaining.
800
815
  *
801
816
  * @example
802
817
  * ```typescript
@@ -816,7 +831,7 @@ declare class ProtectColumn {
816
831
  *
817
832
  * @param tokenFilters - Optional array of token filters (e.g. `[{ kind: 'downcase' }]`).
818
833
  * When omitted, no token filters are applied.
819
- * @returns This `ProtectColumn` instance for method chaining.
834
+ * @returns This `EncryptedColumn` instance for method chaining.
820
835
  *
821
836
  * @example
822
837
  * ```typescript
@@ -836,7 +851,7 @@ declare class ProtectColumn {
836
851
  *
837
852
  * @param opts - Optional match index configuration. Defaults to 3-character ngram
838
853
  * tokenization with a downcase filter, `k=6`, `m=2048`, and `include_original=true`.
839
- * @returns This `ProtectColumn` instance for method chaining.
854
+ * @returns This `EncryptedColumn` instance for method chaining.
840
855
  *
841
856
  * @example
842
857
  * ```typescript
@@ -868,7 +883,7 @@ declare class ProtectColumn {
868
883
  * the plaintext type: strings become selector queries, objects/arrays become
869
884
  * containment queries.
870
885
  *
871
- * @returns This `ProtectColumn` instance for method chaining.
886
+ * @returns This `EncryptedColumn` instance for method chaining.
872
887
  *
873
888
  * @example
874
889
  * ```typescript
@@ -895,9 +910,11 @@ interface TableDefinition {
895
910
  tableName: string;
896
911
  columns: Record<string, ColumnSchema>;
897
912
  }
898
- declare class ProtectTable<T extends ProtectTableColumn> {
913
+ declare class EncryptedTable<T extends EncryptedTableColumn> {
899
914
  readonly tableName: string;
900
915
  private readonly columnBuilders;
916
+ /** @internal Type-level brand so TypeScript can infer `T` from `EncryptedTable<T>`. */
917
+ readonly _columnType: T;
901
918
  constructor(tableName: string, columnBuilders: T);
902
919
  /**
903
920
  * Compile this table schema into a `TableDefinition` used internally by the encryption client.
@@ -921,7 +938,7 @@ declare class ProtectTable<T extends ProtectTableColumn> {
921
938
  build(): TableDefinition;
922
939
  }
923
940
  /**
924
- * Infer the plaintext (decrypted) type from a ProtectTable schema.
941
+ * Infer the plaintext (decrypted) type from a EncryptedTable schema.
925
942
  *
926
943
  * @example
927
944
  * ```typescript
@@ -934,11 +951,11 @@ declare class ProtectTable<T extends ProtectTableColumn> {
934
951
  * // => { email: string; name: string }
935
952
  * ```
936
953
  */
937
- type InferPlaintext<T extends ProtectTable<any>> = T extends ProtectTable<infer C> ? {
938
- [K in keyof C as C[K] extends ProtectColumn | ProtectValue ? K : never]: string;
954
+ type InferPlaintext<T extends EncryptedTable<any>> = T extends EncryptedTable<infer C> ? {
955
+ [K in keyof C as C[K] extends EncryptedColumn | EncryptedField ? K : never]: string;
939
956
  } : never;
940
957
  /**
941
- * Infer the encrypted type from a ProtectTable schema.
958
+ * Infer the encrypted type from a EncryptedTable schema.
942
959
  *
943
960
  * @example
944
961
  * ```typescript
@@ -950,13 +967,13 @@ type InferPlaintext<T extends ProtectTable<any>> = T extends ProtectTable<infer
950
967
  * // => { email: Encrypted }
951
968
  * ```
952
969
  */
953
- type InferEncrypted<T extends ProtectTable<any>> = T extends ProtectTable<infer C> ? {
954
- [K in keyof C as C[K] extends ProtectColumn | ProtectValue ? K : never]: Encrypted;
970
+ type InferEncrypted<T extends EncryptedTable<any>> = T extends EncryptedTable<infer C> ? {
971
+ [K in keyof C as C[K] extends EncryptedColumn | EncryptedField ? K : never]: Encrypted;
955
972
  } : never;
956
973
  /**
957
974
  * Define an encrypted table schema.
958
975
  *
959
- * Creates a `ProtectTable` that maps a database table name to a set of encrypted
976
+ * Creates a `EncryptedTable` that maps a database table name to a set of encrypted
960
977
  * column definitions. Pass the resulting object to `Encryption({ schemas: [...] })`
961
978
  * when initializing the client.
962
979
  *
@@ -966,8 +983,9 @@ type InferEncrypted<T extends ProtectTable<any>> = T extends ProtectTable<infer
966
983
  *
967
984
  * @param tableName - The name of the database table this schema represents.
968
985
  * @param columns - An object whose keys are logical column names and values are
969
- * `ProtectColumn` instances created with {@link encryptedColumn}.
970
- * @returns A `ProtectTable<T> & T` that can be used as both a schema definition
986
+ * {@link EncryptedColumn} from {@link encryptedColumn}, or nested objects whose
987
+ * leaves are {@link EncryptedField} from {@link encryptedField}.
988
+ * @returns A `EncryptedTable<T> & T` that can be used as both a schema definition
971
989
  * and a column accessor.
972
990
  *
973
991
  * @example
@@ -986,17 +1004,17 @@ type InferEncrypted<T extends ProtectTable<any>> = T extends ProtectTable<infer
986
1004
  * await client.encrypt("hello@example.com", { column: users.email, table: users })
987
1005
  * ```
988
1006
  */
989
- declare function encryptedTable<T extends ProtectTableColumn>(tableName: string, columns: T): ProtectTable<T> & T;
1007
+ declare function encryptedTable<T extends EncryptedTableColumn>(tableName: string, columns: T): EncryptedTable<T> & T;
990
1008
  /**
991
1009
  * Define an encrypted column within a table schema.
992
1010
  *
993
- * Creates a `ProtectColumn` builder for the given column name. Chain index
1011
+ * Creates a `EncryptedColumn` builder for the given column name. Chain index
994
1012
  * methods (`.equality()`, `.freeTextSearch()`, `.orderAndRange()`,
995
1013
  * `.searchableJson()`) and/or `.dataType()` to configure searchable encryption
996
1014
  * and the plaintext data type.
997
1015
  *
998
1016
  * @param columnName - The name of the database column to encrypt.
999
- * @returns A new `ProtectColumn` builder.
1017
+ * @returns A new `EncryptedColumn` builder.
1000
1018
  *
1001
1019
  * @example
1002
1020
  * ```typescript
@@ -1007,31 +1025,31 @@ declare function encryptedTable<T extends ProtectTableColumn>(tableName: string,
1007
1025
  * })
1008
1026
  * ```
1009
1027
  */
1010
- declare function encryptedColumn(columnName: string): ProtectColumn;
1028
+ declare function encryptedColumn(columnName: string): EncryptedColumn;
1011
1029
  /**
1012
- * Define an encrypted value for use in nested or structured schemas.
1030
+ * Define an encrypted field for use in nested or structured schemas.
1013
1031
  *
1014
- * `encryptedValue` is similar to {@link encryptedColumn} but creates a `ProtectValue`
1015
- * intended for nested fields within a table schema. It supports `.dataType()`
1016
- * for specifying the plaintext type.
1032
+ * `encryptedField` is similar to {@link encryptedColumn} but creates an {@link EncryptedField}
1033
+ * for nested fields that are encrypted but not searchable (no indexes). Use `.dataType()`
1034
+ * to specify the plaintext type.
1017
1035
  *
1018
1036
  * @param valueName - The name of the value field.
1019
- * @returns A new `ProtectValue` builder.
1037
+ * @returns A new `EncryptedField` builder.
1020
1038
  *
1021
1039
  * @example
1022
1040
  * ```typescript
1023
- * import { encryptedTable, encryptedValue } from "@cipherstash/stack/schema"
1041
+ * import { encryptedTable, encryptedField } from "@cipherstash/stack/schema"
1024
1042
  *
1025
1043
  * const orders = encryptedTable("orders", {
1026
1044
  * details: {
1027
- * amount: encryptedValue("amount").dataType("number"),
1028
- * currency: encryptedValue("currency"),
1045
+ * amount: encryptedField("amount").dataType("number"),
1046
+ * currency: encryptedField("currency"),
1029
1047
  * },
1030
1048
  * })
1031
1049
  * ```
1032
1050
  */
1033
- declare function encryptedValue(valueName: string): ProtectValue;
1051
+ declare function encryptedField(valueName: string): EncryptedField;
1034
1052
  /** @internal */
1035
- declare function buildEncryptConfig(...protectTables: Array<ProtectTable<ProtectTableColumn>>): EncryptConfig;
1053
+ declare function buildEncryptConfig(...protectTables: Array<EncryptedTable<EncryptedTableColumn>>): EncryptConfig;
1036
1054
 
1037
- export { type SearchTerm as A, type BulkDecryptedData as B, type CastAs as C, type Decrypted as D, type EncryptionClientConfig as E, type EncryptedSearchTerm as F, type EncryptedFields as G, type OtherFields as H, type InferPlaintext as I, type DecryptedFields as J, type KeysetIdentifier as K, type DecryptionResult as L, type MatchIndexOpts as M, type LoggingConfig as N, type OreIndexOpts as O, ProtectColumn as P, type QueryTypeName as Q, queryTypes as R, type ScalarQueryTerm as S, type TokenFilter as T, type UniqueIndexOpts as U, encryptedColumn as a, encryptedValue as b, type InferEncrypted as c, ProtectTable as d, encryptedTable as e, type ProtectTableColumn as f, ProtectValue as g, type EncryptedFromSchema as h, type Encrypted as i, type EncryptedValue as j, type EncryptedQueryResult as k, type Client as l, type BulkDecryptPayload as m, type BulkEncryptedData as n, type BulkEncryptPayload as o, type EncryptOptions as p, type EncryptQueryOptions as q, type EncryptedReturnType as r, type EncryptConfig as s, castAsEnum as t, encryptConfigSchema as u, type SteVecIndexOpts as v, type ColumnSchema as w, buildEncryptConfig as x, type EncryptPayload as y, type ClientConfig as z };
1055
+ export { type ClientConfig as A, type BulkDecryptedData as B, type CastAs as C, type Decrypted as D, type EncryptionClientConfig as E, type SearchTerm as F, type EncryptedSearchTerm as G, type EncryptedFields as H, type InferPlaintext as I, type OtherFields as J, type KeysetIdentifier as K, type DecryptedFields as L, type MatchIndexOpts as M, type DecryptionResult as N, type OreIndexOpts as O, type LoggingConfig as P, type QueryTypeName as Q, queryTypes as R, type ScalarQueryTerm as S, type TokenFilter as T, type UniqueIndexOpts as U, encryptedColumn as a, encryptedField as b, type InferEncrypted as c, EncryptedColumn as d, encryptedTable as e, EncryptedTable as f, type EncryptedTableColumn as g, EncryptedField as h, type EncryptedFromSchema as i, type Encrypted as j, type EncryptedValue as k, type EncryptedQueryResult as l, type Client as m, type BulkDecryptPayload as n, type BulkEncryptedData as o, type BulkEncryptPayload as p, type EncryptOptions as q, type EncryptQueryOptions as r, type EncryptedReturnType as s, type EncryptConfig as t, castAsEnum as u, encryptConfigSchema as v, type SteVecIndexOpts as w, type ColumnSchema as x, buildEncryptConfig as y, type EncryptPayload as z };