@cipherstash/stack 0.18.0 → 1.0.0-rc.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.
- package/CHANGELOG.md +704 -0
- package/README.md +97 -79
- package/dist/adapter-kit.cjs +923 -0
- package/dist/adapter-kit.cjs.map +1 -0
- package/dist/adapter-kit.d.cts +82 -0
- package/dist/adapter-kit.d.ts +82 -0
- package/dist/adapter-kit.js +47 -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-VPOTNP4K.js → chunk-3B5ZX3IS.js} +3 -1
- package/dist/chunk-3B5ZX3IS.js.map +1 -0
- package/dist/chunk-7333ZC6L.js +48 -0
- package/dist/chunk-7333ZC6L.js.map +1 -0
- package/dist/{chunk-XWPGAHBZ.js → chunk-BNO32ZMV.js} +1 -1
- package/dist/chunk-BNO32ZMV.js.map +1 -0
- package/dist/chunk-CLM7E4I6.js +4439 -0
- package/dist/chunk-CLM7E4I6.js.map +1 -0
- package/dist/{chunk-LLCCNKDL.js → chunk-HQANMV7R.js} +3 -3
- package/dist/{chunk-LLCCNKDL.js.map → chunk-HQANMV7R.js.map} +1 -1
- package/dist/chunk-JSG2AMDI.js +17 -0
- package/dist/chunk-JSG2AMDI.js.map +1 -0
- package/dist/chunk-OFQ555AX.js +191 -0
- package/dist/chunk-OFQ555AX.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-V2Q3NYIH.js +494 -0
- package/dist/chunk-V2Q3NYIH.js.map +1 -0
- package/dist/chunk-X3JRXEIB.js +98 -0
- package/dist/chunk-X3JRXEIB.js.map +1 -0
- package/dist/{chunk-ZYOZHZMJ.js → chunk-ZTP5QJ27.js} +193 -169
- package/dist/chunk-ZTP5QJ27.js.map +1 -0
- package/dist/client.cjs +4124 -49
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +6 -5
- package/dist/client.d.ts +6 -5
- package/dist/client.js +3 -1
- package/dist/columns-D2_YzrCX.d.cts +622 -0
- package/dist/columns-rZc7fQHI.d.ts +622 -0
- package/dist/dynamodb/index.cjs +19 -12
- package/dist/dynamodb/index.cjs.map +1 -1
- package/dist/dynamodb/index.d.cts +3 -2
- package/dist/dynamodb/index.d.ts +3 -2
- package/dist/dynamodb/index.js +8 -10
- package/dist/dynamodb/index.js.map +1 -1
- package/dist/encryption/index.cjs +4496 -222
- 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 +15 -7
- package/dist/encryption/v3.cjs +7896 -0
- package/dist/encryption/v3.cjs.map +1 -0
- package/dist/encryption/v3.d.cts +103 -0
- package/dist/encryption/v3.d.ts +103 -0
- package/dist/encryption/v3.js +189 -0
- package/dist/encryption/v3.js.map +1 -0
- package/dist/eql/v3/index.cjs +663 -0
- package/dist/eql/v3/index.cjs.map +1 -0
- package/dist/eql/v3/index.d.cts +173 -0
- package/dist/eql/v3/index.d.ts +173 -0
- package/dist/eql/v3/index.js +99 -0
- package/dist/eql/v3/index.js.map +1 -0
- package/dist/errors/index.js +1 -0
- package/dist/identity/index.cjs +55 -35
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.d.cts +54 -30
- package/dist/identity/index.d.ts +54 -30
- package/dist/identity/index.js +9 -177
- package/dist/identity/index.js.map +1 -1
- package/dist/index-BquA71_Y.d.ts +24 -0
- package/dist/index-fhWTOV0K.d.cts +24 -0
- package/dist/index.cjs +4547 -243
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -19
- package/dist/index.d.ts +18 -19
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/dist/schema/index.cjs +4128 -49
- 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 +3 -1
- package/dist/{types-public-BTxqjmtv.d.cts → types-public-QMjYNfQO.d.cts} +448 -251
- package/dist/{types-public-BTxqjmtv.d.ts → types-public-QMjYNfQO.d.ts} +448 -251
- package/dist/types-public.cjs.map +1 -1
- package/dist/types-public.d.cts +2 -2
- package/dist/types-public.d.ts +2 -2
- package/dist/types-public.js +2 -1
- package/dist/wasm-inline.d.ts +1643 -0
- package/dist/wasm-inline.js +4901 -0
- package/dist/wasm-inline.js.map +1 -0
- package/package.json +74 -52
- package/dist/chunk-VPOTNP4K.js.map +0 -1
- package/dist/chunk-XWPGAHBZ.js.map +0 -1
- package/dist/chunk-YWQXTZ5M.js +0 -383
- package/dist/chunk-YWQXTZ5M.js.map +0 -1
- package/dist/chunk-ZYOZHZMJ.js.map +0 -1
- package/dist/client-CIsfZ2zg.d.ts +0 -692
- package/dist/client-Dt98Rugc.d.cts +0 -692
- package/dist/drizzle/index.cjs +0 -1558
- 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 -1215
- package/dist/drizzle/index.js.map +0 -1
- package/dist/supabase/index.cjs +0 -1526
- package/dist/supabase/index.cjs.map +0 -1
- package/dist/supabase/index.d.cts +0 -144
- package/dist/supabase/index.d.ts +0 -144
- package/dist/supabase/index.js +0 -899
- package/dist/supabase/index.js.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/supabase/index.ts","../../src/encryption/helpers/index.ts","../../src/schema/index.ts","../../../../node_modules/.pnpm/evlog@1.11.0_next@15.5.10_react-dom@19.2.3_react@19.2.3__react@19.2.3__react@19.2.3/node_modules/evlog/src/utils.ts","../../../../node_modules/.pnpm/evlog@1.11.0_next@15.5.10_react-dom@19.2.3_react@19.2.3__react@19.2.3__react@19.2.3/node_modules/evlog/src/logger.ts","../../src/utils/logger/index.ts","../../src/supabase/helpers.ts","../../src/supabase/query-builder.ts"],"sourcesContent":["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","import type { Encrypted, EncryptedQueryResult, KeysetIdentifier } from '@/types'\nimport type {\n Encrypted as CipherStashEncrypted,\n EncryptedQuery as CipherStashEncryptedQuery,\n KeysetIdentifier as KeysetIdentifierFfi,\n} from '@cipherstash/protect-ffi'\n\n/**\n * The shape `encryptQuery` / `encryptQueryBulk` can return: a full storage\n * payload (returned for `ste_vec_term` containment queries) or a query-only\n * payload with no ciphertext (scalar `unique`/`match`/`ore` lookups and\n * `ste_vec_selector` path queries).\n *\n * TODO: duplicated in `@cipherstash/protect` — see\n * `packages/protect/src/helpers/index.ts`. Both copies should be removed once\n * `@cipherstash/protect-ffi` exports a named alias for the `encryptQuery`\n * return type (https://github.com/cipherstash/stack/pull/473).\n */\ntype EncryptedQueryTerm = CipherStashEncrypted | CipherStashEncryptedQuery\n\nexport type EncryptedPgComposite = {\n data: Encrypted\n}\n\n/**\n * Helper function to transform an encrypted payload into a PostgreSQL composite type.\n * Use this when inserting data via Supabase or similar clients.\n */\nexport function encryptedToPgComposite(obj: Encrypted): EncryptedPgComposite {\n return {\n data: obj,\n }\n}\n\n/**\n * Helper function to transform an encrypted payload into a PostgreSQL composite literal string.\n * Use this when querying with `.eq()` or similar equality operations in Supabase.\n *\n * @example\n * ```typescript\n * const literal = encryptedToCompositeLiteral(encrypted)\n * await supabase.from('table').select().eq('column', literal)\n * ```\n */\nexport function encryptedToCompositeLiteral(obj: EncryptedQueryTerm): string {\n return `(${JSON.stringify(JSON.stringify(obj))})`\n}\n\n/**\n * Helper function to transform an encrypted payload into an escaped PostgreSQL composite literal string.\n * Use this when you need the composite literal format to be escaped as a string value.\n *\n * @example\n * ```typescript\n * const escapedLiteral = encryptedToEscapedCompositeLiteral(encrypted)\n * ```\n */\nexport function encryptedToEscapedCompositeLiteral(\n obj: EncryptedQueryTerm,\n): string {\n return JSON.stringify(encryptedToCompositeLiteral(obj))\n}\n\n/**\n * Format an encrypted result based on the requested return type.\n *\n * - `'composite-literal'` → PostgreSQL composite literal string `(\"json\")`\n * - `'escaped-composite-literal'` → escaped variant `\"(\\\"json\\\")\"`\n * - default (`'eql'` or omitted) → raw encrypted object\n */\nexport function formatEncryptedResult(\n encrypted: EncryptedQueryTerm,\n returnType?: string,\n): EncryptedQueryResult {\n if (returnType === 'composite-literal') {\n return encryptedToCompositeLiteral(encrypted)\n }\n if (returnType === 'escaped-composite-literal') {\n return encryptedToEscapedCompositeLiteral(encrypted)\n }\n return encrypted\n}\n\n/**\n * Helper function to transform a model's encrypted fields into PostgreSQL composite types\n */\nexport function modelToEncryptedPgComposites<T extends Record<string, unknown>>(\n model: T,\n): T {\n const result: Record<string, unknown> = {}\n\n for (const [key, value] of Object.entries(model)) {\n if (isEncryptedPayload(value)) {\n result[key] = encryptedToPgComposite(value)\n } else {\n result[key] = value\n }\n }\n\n return result as T\n}\n\n/**\n * Helper function to transform multiple models' encrypted fields into PostgreSQL composite types\n */\nexport function bulkModelsToEncryptedPgComposites<\n T extends Record<string, unknown>,\n>(models: T[]): T[] {\n return models.map((model) => modelToEncryptedPgComposites(model))\n}\n\nexport function toFfiKeysetIdentifier(\n keyset: KeysetIdentifier | undefined,\n): KeysetIdentifierFfi | undefined {\n if (!keyset) return undefined\n\n if ('name' in keyset) {\n return { Name: keyset.name }\n }\n\n return { Uuid: keyset.id }\n}\n\n/**\n * Helper function to check if a value is an encrypted payload\n */\nexport function isEncryptedPayload(value: unknown): value is Encrypted {\n if (value === null) return false\n if (typeof value !== 'object') return false\n\n const obj = value as Record<string, unknown>\n\n // Must have version field (number)\n if (!('v' in obj) || typeof obj.v !== 'number') return false\n\n // Must have index field (object)\n if (!('i' in obj) || typeof obj.i !== 'object') return false\n\n // Must have either ciphertext (c) or searchable vector (sv)\n if (!('c' in obj) && !('sv' in obj)) return false\n\n return true\n}\n\nexport {\n toJsonPath,\n buildNestedObject,\n parseJsonbPath,\n} from './jsonb'\n","import type { Encrypted } from '@/types'\nimport { z } from 'zod'\n\n// ------------------------\n// Zod schemas\n// ------------------------\n\n/**\n * Allowed cast types for CipherStash schema fields.\n *\n * **Possible values:**\n * - `\"bigint\"`\n * - `\"boolean\"`\n * - `\"date\"`\n * - `\"number\"`\n * - `\"string\"`\n * - `\"json\"`\n * - `\"text\"`\n *\n * @remarks\n * This is a Zod enum used at runtime to validate schema definitions.\n * Use {@link CastAs} when typing your own code.\n *\n * @internal\n */\n/**\n * EQL cast types — the PostgreSQL-aligned types that EQL actually accepts.\n * These are stored in the `cast_as` field of the EncryptConfig.\n */\nexport const eqlCastAsEnum = z\n .enum([\n 'text',\n 'int',\n 'small_int',\n 'big_int',\n 'real',\n 'double',\n 'boolean',\n 'date',\n 'jsonb',\n ])\n .default('text')\n\n/**\n * SDK-facing data types — developer-friendly aliases accepted by `dataType()`.\n */\nexport const castAsEnum = z\n .enum(['bigint', 'boolean', 'date', 'number', 'string', 'json', 'text'])\n .default('text')\n\n/**\n * Map SDK-facing data types to EQL `cast_as` values.\n *\n * The SDK accepts developer-friendly types like `'string'` and `'number'`,\n * but EQL expects PostgreSQL-aligned types like `'text'` and `'double'`.\n */\nexport function toEqlCastAs(value: CastAs): EqlCastAs {\n switch (value) {\n case 'string':\n return 'text'\n case 'text':\n return 'text'\n case 'number':\n return 'double'\n case 'bigint':\n return 'big_int'\n case 'boolean':\n return 'boolean'\n case 'date':\n return 'date'\n case 'json':\n return 'jsonb'\n }\n}\n\nconst tokenFilterSchema = z.object({\n kind: z.literal('downcase'),\n})\n\nconst tokenizerSchema = z\n .union([\n z.object({\n kind: z.literal('standard'),\n }),\n z.object({\n kind: z.literal('ngram'),\n token_length: z.number(),\n }),\n ])\n .default({ kind: 'ngram', token_length: 3 })\n .optional()\n\nconst oreIndexOptsSchema = z.object({})\n\nconst uniqueIndexOptsSchema = z.object({\n token_filters: z.array(tokenFilterSchema).default([]).optional(),\n})\n\nconst matchIndexOptsSchema = z.object({\n tokenizer: tokenizerSchema,\n token_filters: z.array(tokenFilterSchema).default([]).optional(),\n k: z.number().default(6).optional(),\n m: z.number().default(2048).optional(),\n include_original: z.boolean().default(false).optional(),\n})\n\nconst arrayIndexModeSchema = z.union([\n z.literal('all'),\n z.literal('none'),\n z.object({\n item: z.boolean().optional(),\n wildcard: z.boolean().optional(),\n position: z.boolean().optional(),\n }),\n])\n\nconst steVecIndexOptsSchema = z.object({\n prefix: z.string(),\n array_index_mode: arrayIndexModeSchema.optional(),\n})\n\nconst indexesSchema = z\n .object({\n ore: oreIndexOptsSchema.optional(),\n unique: uniqueIndexOptsSchema.optional(),\n match: matchIndexOptsSchema.optional(),\n ste_vec: steVecIndexOptsSchema.optional(),\n })\n .default({})\n\nconst columnSchema = z\n .object({\n cast_as: castAsEnum,\n indexes: indexesSchema,\n })\n .default({})\n\nconst tableSchema = z.record(columnSchema).default({})\n\nconst tablesSchema = z.record(tableSchema).default({})\n\n/** @internal */\nexport const encryptConfigSchema = z.object({\n v: z.number(),\n tables: tablesSchema,\n})\n\n// ------------------------\n// Type definitions\n// ------------------------\n\n/**\n * Type-safe alias for {@link castAsEnum} used to specify the *unencrypted* data type of a column or value.\n * This is important because once encrypted, all data is stored as binary blobs.\n *\n * @see {@link castAsEnum} for possible values.\n */\nexport type CastAs = z.infer<typeof castAsEnum>\nexport type EqlCastAs = z.infer<typeof eqlCastAsEnum>\nexport type TokenFilter = z.infer<typeof tokenFilterSchema>\nexport type MatchIndexOpts = z.infer<typeof matchIndexOptsSchema>\nexport type SteVecIndexOpts = z.infer<typeof steVecIndexOptsSchema>\nexport type UniqueIndexOpts = z.infer<typeof uniqueIndexOptsSchema>\nexport type OreIndexOpts = z.infer<typeof oreIndexOptsSchema>\nexport type ColumnSchema = z.infer<typeof columnSchema>\n\n/**\n * Shape of table columns: either top-level {@link EncryptedColumn} or nested\n * objects whose leaves are {@link EncryptedField}. Used with {@link encryptedTable}.\n */\nexport type EncryptedTableColumn = {\n [key: string]:\n | EncryptedColumn\n | {\n [key: string]:\n | EncryptedField\n | {\n [key: string]:\n | EncryptedField\n | {\n [key: string]: EncryptedField\n }\n }\n }\n}\nexport type EncryptConfig = z.infer<typeof encryptConfigSchema>\n\n// ------------------------\n// Interface definitions\n// ------------------------\n\n/**\n * Builder for a nested encrypted field (encrypted but not searchable).\n * Create with {@link encryptedField}. Use inside nested objects in {@link encryptedTable};\n * supports `.dataType()` for plaintext type. No index methods (equality, orderAndRange, etc.).\n */\nexport class EncryptedField {\n private valueName: string\n private castAsValue: CastAs\n\n constructor(valueName: string) {\n this.valueName = valueName\n this.castAsValue = 'string'\n }\n\n /**\n * Set or override the plaintext data type for this field.\n *\n * By default all values are treated as `'string'`. Use this method to specify\n * a different type so the encryption layer knows how to encode the plaintext\n * before encrypting.\n *\n * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'text'`, `'bigint'`, or `'json'`.\n * @returns This `EncryptedField` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedField } from \"@cipherstash/stack/schema\"\n *\n * const age = encryptedField(\"age\").dataType(\"number\")\n * ```\n */\n dataType(castAs: CastAs) {\n this.castAsValue = castAs\n return this\n }\n\n build() {\n return {\n cast_as: this.castAsValue,\n indexes: {},\n }\n }\n\n getName() {\n return this.valueName\n }\n}\n\nexport class EncryptedColumn {\n private columnName: string\n private castAsValue: CastAs\n private indexesValue: {\n ore?: OreIndexOpts\n unique?: UniqueIndexOpts\n match?: Required<MatchIndexOpts>\n ste_vec?: SteVecIndexOpts\n } = {}\n\n constructor(columnName: string) {\n this.columnName = columnName\n this.castAsValue = 'string'\n }\n\n /**\n * Set or override the plaintext data type for this column.\n *\n * By default all columns are treated as `'string'`. Use this method to specify\n * a different type so the encryption layer knows how to encode the plaintext\n * before encrypting.\n *\n * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const dateOfBirth = encryptedColumn(\"date_of_birth\").dataType(\"date\")\n * ```\n */\n dataType(castAs: CastAs) {\n this.castAsValue = castAs\n return this\n }\n\n /**\n * Enable Order-Revealing Encryption (ORE) indexing on this column.\n *\n * ORE allows sorting, comparison, and range queries on encrypted data.\n * Use with `encryptQuery` and `queryType: 'orderAndRange'`.\n *\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").orderAndRange(),\n * })\n * ```\n */\n orderAndRange() {\n this.indexesValue.ore = {}\n return this\n }\n\n /**\n * Enable an exact-match (unique) index on this column.\n *\n * Allows equality queries on encrypted data. Use with `encryptQuery`\n * and `queryType: 'equality'`.\n *\n * @param tokenFilters - Optional array of token filters (e.g. `[{ kind: 'downcase' }]`).\n * When omitted, no token filters are applied.\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n * ```\n */\n equality(tokenFilters?: TokenFilter[]) {\n this.indexesValue.unique = {\n token_filters: tokenFilters ?? [],\n }\n return this\n }\n\n /**\n * Enable a full-text / fuzzy search (match) index on this column.\n *\n * Uses n-gram tokenization by default for substring and fuzzy matching.\n * Use with `encryptQuery` and `queryType: 'freeTextSearch'`.\n *\n * @param opts - Optional match index configuration. Defaults to 3-character ngram\n * tokenization with a downcase filter, `k=6`, `m=2048`, and `include_original=true`.\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").freeTextSearch(),\n * })\n *\n * // With custom options\n * const posts = encryptedTable(\"posts\", {\n * body: encryptedColumn(\"body\").freeTextSearch({\n * tokenizer: { kind: \"ngram\", token_length: 4 },\n * k: 8,\n * m: 4096,\n * }),\n * })\n * ```\n */\n freeTextSearch(opts?: MatchIndexOpts) {\n // Provide defaults\n this.indexesValue.match = {\n tokenizer: opts?.tokenizer ?? { kind: 'ngram', token_length: 3 },\n token_filters: opts?.token_filters ?? [\n {\n kind: 'downcase',\n },\n ],\n k: opts?.k ?? 6,\n m: opts?.m ?? 2048,\n include_original: opts?.include_original ?? true,\n }\n return this\n }\n\n /**\n * Configure this column for searchable encrypted JSON (STE-Vec).\n *\n * Enables encrypted JSONPath selector queries (e.g. `'$.user.email'`) and\n * containment queries (e.g. `{ role: 'admin' }`). Automatically sets the\n * data type to `'json'`.\n *\n * When used with `encryptQuery`, the query operation is auto-inferred from\n * the plaintext type: strings become selector queries, objects/arrays become\n * containment queries.\n *\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const documents = encryptedTable(\"documents\", {\n * metadata: encryptedColumn(\"metadata\").searchableJson(),\n * })\n * ```\n */\n searchableJson() {\n this.castAsValue = 'json'\n this.indexesValue.ste_vec = { prefix: 'enabled', array_index_mode: 'all' }\n return this\n }\n\n build() {\n return {\n cast_as: this.castAsValue,\n indexes: this.indexesValue,\n }\n }\n\n getName() {\n return this.columnName\n }\n}\n\ninterface TableDefinition {\n tableName: string\n columns: Record<string, ColumnSchema>\n}\n\nexport class EncryptedTable<T extends EncryptedTableColumn> {\n /** @internal Type-level brand so TypeScript can infer `T` from `EncryptedTable<T>`. */\n declare readonly _columnType: T\n\n constructor(\n public readonly tableName: string,\n public readonly columnBuilders: T,\n ) {}\n\n /**\n * Compile this table schema into a `TableDefinition` used internally by the encryption client.\n *\n * Iterates over all column builders, calls `.build()` on each, and assembles\n * the final `{ tableName, columns }` structure. For `searchableJson()` columns,\n * the STE-Vec prefix is automatically set to `\"<tableName>/<columnName>\"`.\n *\n * @returns A `TableDefinition` containing the table name and built column configs.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * const definition = users.build()\n * // { tableName: \"users\", columns: { email: { cast_as: \"string\", indexes: { unique: ... } } } }\n * ```\n */\n build(): TableDefinition {\n const builtColumns: Record<string, ColumnSchema> = {}\n\n const processColumn = (\n builder:\n | EncryptedColumn\n | Record<\n string,\n | EncryptedField\n | Record<\n string,\n | EncryptedField\n | Record<\n string,\n EncryptedField | Record<string, EncryptedField>\n >\n >\n >,\n colName: string,\n ) => {\n if (builder instanceof EncryptedColumn) {\n const builtColumn = builder.build()\n\n // Hanlde building the ste_vec index for JSON columns so users don't have to pass the prefix.\n if (\n builtColumn.cast_as === 'json' &&\n builtColumn.indexes.ste_vec?.prefix === 'enabled'\n ) {\n builtColumns[colName] = {\n ...builtColumn,\n indexes: {\n ...builtColumn.indexes,\n ste_vec: {\n ...builtColumn.indexes.ste_vec,\n prefix: `${this.tableName}/${colName}`,\n },\n },\n }\n } else {\n builtColumns[colName] = builtColumn\n }\n } else {\n for (const [key, value] of Object.entries(builder)) {\n if (value instanceof EncryptedField) {\n builtColumns[value.getName()] = value.build()\n } else {\n processColumn(value, key)\n }\n }\n }\n }\n\n for (const [colName, builder] of Object.entries(this.columnBuilders)) {\n processColumn(builder, colName)\n }\n\n return {\n tableName: this.tableName,\n columns: builtColumns,\n }\n }\n}\n\n// ------------------------\n// Schema type inference helpers\n// ------------------------\n\n/**\n * Infer the plaintext (decrypted) type from a EncryptedTable schema.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * name: encryptedColumn(\"name\"),\n * })\n *\n * type UserPlaintext = InferPlaintext<typeof users>\n * // => { email: string; name: string }\n * ```\n */\nexport type InferPlaintext<T extends EncryptedTable<any>> =\n T extends EncryptedTable<infer C>\n ? {\n [K in keyof C as C[K] extends EncryptedColumn | EncryptedField\n ? K\n : never]: string\n }\n : never\n\n/**\n * Infer the encrypted type from a EncryptedTable schema.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * type UserEncrypted = InferEncrypted<typeof users>\n * // => { email: Encrypted }\n * ```\n */\nexport type InferEncrypted<T extends EncryptedTable<any>> =\n T extends EncryptedTable<infer C>\n ? {\n [K in keyof C as C[K] extends EncryptedColumn | EncryptedField\n ? K\n : never]: Encrypted\n }\n : never\n\n// ------------------------\n// User facing functions\n// ------------------------\n\n/**\n * Define an encrypted table schema.\n *\n * Creates a `EncryptedTable` that maps a database table name to a set of encrypted\n * column definitions. Pass the resulting object to `Encryption({ schemas: [...] })`\n * when initializing the client.\n *\n * The returned object is also a proxy that exposes each column builder directly,\n * so you can reference columns as `users.email` when calling `encrypt`, `decrypt`,\n * and `encryptQuery`.\n *\n * @param tableName - The name of the database table this schema represents.\n * @param columns - An object whose keys are logical column names and values are\n * {@link EncryptedColumn} from {@link encryptedColumn}, or nested objects whose\n * leaves are {@link EncryptedField} from {@link encryptedField}.\n * @returns A `EncryptedTable<T> & T` that can be used as both a schema definition\n * and a column accessor.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality().freeTextSearch(),\n * address: encryptedColumn(\"address\"),\n * })\n *\n * // Use as schema\n * const client = await Encryption({ schemas: [users] })\n *\n * // Use as column accessor\n * await client.encrypt(\"hello@example.com\", { column: users.email, table: users })\n * ```\n */\nexport function encryptedTable<T extends EncryptedTableColumn>(\n tableName: string,\n columns: T,\n): EncryptedTable<T> & T {\n const tableBuilder = new EncryptedTable(\n tableName,\n columns,\n ) as EncryptedTable<T> & T\n\n for (const [colName, colBuilder] of Object.entries(columns)) {\n ;(tableBuilder as EncryptedTableColumn)[colName] = colBuilder\n }\n\n return tableBuilder\n}\n\n/**\n * Define an encrypted column within a table schema.\n *\n * Creates a `EncryptedColumn` builder for the given column name. Chain index\n * methods (`.equality()`, `.freeTextSearch()`, `.orderAndRange()`,\n * `.searchableJson()`) and/or `.dataType()` to configure searchable encryption\n * and the plaintext data type.\n *\n * @param columnName - The name of the database column to encrypt.\n * @returns A new `EncryptedColumn` builder.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality().freeTextSearch().orderAndRange(),\n * })\n * ```\n */\nexport function encryptedColumn(columnName: string) {\n return new EncryptedColumn(columnName)\n}\n\n/**\n * Define an encrypted field for use in nested or structured schemas.\n *\n * `encryptedField` is similar to {@link encryptedColumn} but creates an {@link EncryptedField}\n * for nested fields that are encrypted but not searchable (no indexes). Use `.dataType()`\n * to specify the plaintext type.\n *\n * @param valueName - The name of the value field.\n * @returns A new `EncryptedField` builder.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedField } from \"@cipherstash/stack/schema\"\n *\n * const orders = encryptedTable(\"orders\", {\n * details: {\n * amount: encryptedField(\"amount\").dataType(\"number\"),\n * currency: encryptedField(\"currency\"),\n * },\n * })\n * ```\n */\nexport function encryptedField(valueName: string) {\n return new EncryptedField(valueName)\n}\n\n/**\n * Build an encrypt config from a list of encrypted tables.\n *\n * @param protectTables - The list of encrypted tables to build the config from.\n * @returns An encrypt config object.\n *\n * @example\n * ```typescript\n * import { buildEncryptConfig } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * const orders = encryptedTable(\"orders\", {\n * amount: encryptedColumn(\"amount\").dataType(\"number\"),\n * })\n *\n * const config = buildEncryptConfig(users, orders)\n * console.log(config)\n * ```\n */\nexport function buildEncryptConfig(\n ...protectTables: Array<EncryptedTable<EncryptedTableColumn>>\n): EncryptConfig {\n const config: EncryptConfig = {\n v: 1,\n tables: {},\n }\n\n for (const tb of protectTables) {\n const tableDef = tb.build()\n config.tables[tableDef.tableName] = tableDef.columns\n }\n\n return config\n}\n","import type { EnvironmentContext, LogLevel } from './types'\n\nexport function formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${Math.round(ms)}ms`\n }\n return `${(ms / 1000).toFixed(2)}s`\n}\n\nexport function isServer(): boolean {\n return typeof window === 'undefined'\n}\n\nexport function isClient(): boolean {\n return typeof window !== 'undefined'\n}\n\nexport function isDev(): boolean {\n if (typeof process !== 'undefined') {\n return process.env.NODE_ENV !== 'production'\n }\n if (typeof window !== 'undefined') {\n return true\n }\n return false\n}\n\nexport function detectEnvironment(): Partial<EnvironmentContext> {\n const env = typeof process !== 'undefined' ? process.env : {}\n const defaultEnvironment = isDev() ? 'development' : 'production'\n\n return {\n environment: env.NODE_ENV || defaultEnvironment,\n service: env.SERVICE_NAME || 'app',\n version: env.APP_VERSION,\n commitHash: env.COMMIT_SHA\n || env.GITHUB_SHA\n || env.VERCEL_GIT_COMMIT_SHA\n || env.CF_PAGES_COMMIT_SHA,\n region: env.VERCEL_REGION\n || env.AWS_REGION\n || env.FLY_REGION\n || env.CF_REGION,\n }\n}\n\nexport function getConsoleMethod(level: LogLevel): LogLevel {\n return level\n}\n\nexport const colors = {\n reset: '\\x1B[0m',\n bold: '\\x1B[1m',\n dim: '\\x1B[2m',\n red: '\\x1B[31m',\n green: '\\x1B[32m',\n yellow: '\\x1B[33m',\n blue: '\\x1B[34m',\n magenta: '\\x1B[35m',\n cyan: '\\x1B[36m',\n white: '\\x1B[37m',\n gray: '\\x1B[90m',\n} as const\n\nexport function getLevelColor(level: string): string {\n switch (level) {\n case 'error':\n return colors.red\n case 'warn':\n return colors.yellow\n case 'info':\n return colors.cyan\n case 'debug':\n return colors.gray\n default:\n return colors.white\n }\n}\n\n/** Headers that should never be passed to hooks for security */\nexport const SENSITIVE_HEADERS = [\n 'authorization',\n 'cookie',\n 'set-cookie',\n 'x-api-key',\n 'x-auth-token',\n 'proxy-authorization',\n]\n\nexport function filterSafeHeaders(headers: Record<string, string>): Record<string, string> {\n const safeHeaders: Record<string, string> = {}\n\n for (const [key, value] of Object.entries(headers)) {\n if (!SENSITIVE_HEADERS.includes(key.toLowerCase())) {\n safeHeaders[key] = value\n }\n }\n\n return safeHeaders\n}\n\n/**\n * Match a path against a glob pattern.\n * Supports * (any chars except /) and ** (any chars including /).\n */\nexport function matchesPattern(path: string, pattern: string): boolean {\n const regexPattern = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&') // Escape special regex chars except * and ?\n .replace(/\\*\\*/g, '{{GLOBSTAR}}') // Temp placeholder for **\n .replace(/\\*/g, '[^/]*') // * matches anything except /\n .replace(/{{GLOBSTAR}}/g, '.*') // ** matches anything including /\n .replace(/\\?/g, '[^/]') // ? matches single char except /\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(path)\n}\n","import type { DrainContext, EnvironmentContext, FieldContext, Log, LogLevel, LoggerConfig, RequestLogger, RequestLoggerOptions, SamplingConfig, TailSamplingContext, WideEvent } from './types'\nimport { colors, detectEnvironment, formatDuration, getConsoleMethod, getLevelColor, isDev, matchesPattern } from './utils'\n\nfunction isPlainObject(val: unknown): val is Record<string, unknown> {\n return val !== null && typeof val === 'object' && !Array.isArray(val)\n}\n\nfunction deepDefaults(base: Record<string, unknown>, defaults: Record<string, unknown>): Record<string, unknown> {\n const result = { ...base }\n for (const key in defaults) {\n const baseVal = result[key]\n const defaultVal = defaults[key]\n if (baseVal === undefined || baseVal === null) {\n result[key] = defaultVal\n } else if (isPlainObject(baseVal) && isPlainObject(defaultVal)) {\n result[key] = deepDefaults(baseVal, defaultVal)\n }\n }\n return result\n}\n\nlet globalEnv: EnvironmentContext = {\n service: 'app',\n environment: 'development',\n}\n\nlet globalPretty = isDev()\nlet globalSampling: SamplingConfig = {}\nlet globalStringify = true\nlet globalDrain: ((ctx: DrainContext) => void | Promise<void>) | undefined\nlet globalEnabled = true\n\n/**\n * Initialize the logger with configuration.\n * Call this once at application startup.\n */\nexport function initLogger(config: LoggerConfig = {}): void {\n globalEnabled = config.enabled ?? true\n const detected = detectEnvironment()\n\n globalEnv = {\n service: config.env?.service ?? detected.service ?? 'app',\n environment: config.env?.environment ?? detected.environment ?? 'development',\n version: config.env?.version ?? detected.version,\n commitHash: config.env?.commitHash ?? detected.commitHash,\n region: config.env?.region ?? detected.region,\n }\n\n globalPretty = config.pretty ?? isDev()\n globalSampling = config.sampling ?? {}\n globalStringify = config.stringify ?? true\n globalDrain = config.drain\n}\n\n/**\n * Check if logging is globally enabled.\n */\nexport function isEnabled(): boolean {\n return globalEnabled\n}\n\n/**\n * Determine if a log at the given level should be emitted based on sampling config.\n * Error level defaults to 100% (always logged) unless explicitly configured otherwise.\n */\nfunction shouldSample(level: LogLevel): boolean {\n const { rates } = globalSampling\n if (!rates) {\n return true // No sampling configured, log everything\n }\n\n // Error defaults to 100% unless explicitly set\n const percentage = level === 'error' && rates.error === undefined\n ? 100\n : rates[level] ?? 100\n\n // 0% = never log, 100% = always log\n if (percentage <= 0) return false\n if (percentage >= 100) return true\n\n return Math.random() * 100 < percentage\n}\n\n/**\n * Evaluate tail sampling conditions to determine if a log should be force-kept.\n * Returns true if ANY condition matches (OR logic).\n */\nexport function shouldKeep(ctx: TailSamplingContext): boolean {\n const { keep } = globalSampling\n if (!keep?.length) return false\n\n return keep.some((condition) => {\n if (condition.status !== undefined && ctx.status !== undefined && ctx.status >= condition.status) {\n return true\n }\n if (condition.duration !== undefined && ctx.duration !== undefined && ctx.duration >= condition.duration) {\n return true\n }\n if (condition.path && ctx.path && matchesPattern(ctx.path, condition.path)) {\n return true\n }\n return false\n })\n}\n\nfunction emitWideEvent(level: LogLevel, event: Record<string, unknown>, skipSamplingCheck = false): WideEvent | null {\n if (!globalEnabled) return null\n\n if (!skipSamplingCheck && !shouldSample(level)) {\n return null\n }\n\n const formatted: WideEvent = {\n timestamp: new Date().toISOString(),\n level,\n ...globalEnv,\n ...event,\n }\n\n if (globalPretty) {\n prettyPrintWideEvent(formatted)\n } else if (globalStringify) {\n console[getConsoleMethod(level)](JSON.stringify(formatted))\n } else {\n console[getConsoleMethod(level)](formatted)\n }\n\n if (globalDrain) {\n Promise.resolve(globalDrain({ event: formatted })).catch((err) => {\n console.error('[evlog] drain failed:', err)\n })\n }\n\n return formatted\n}\n\nfunction emitTaggedLog(level: LogLevel, tag: string, message: string): void {\n if (!globalEnabled) return\n\n if (globalPretty) {\n if (!shouldSample(level)) {\n return\n }\n const color = getLevelColor(level)\n const timestamp = new Date().toISOString().slice(11, 23)\n console.log(`${colors.dim}${timestamp}${colors.reset} ${color}[${tag}]${colors.reset} ${message}`)\n return\n }\n emitWideEvent(level, { tag, message })\n}\n\nfunction formatValue(value: unknown): string {\n if (value === null || value === undefined) {\n return String(value)\n }\n if (typeof value === 'object') {\n // Flatten object to key=value pairs\n const pairs: string[] = []\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n if (v !== undefined && v !== null) {\n if (typeof v === 'object') {\n // For nested objects, show as JSON\n pairs.push(`${k}=${JSON.stringify(v)}`)\n } else {\n pairs.push(`${k}=${v}`)\n }\n }\n }\n return pairs.join(' ')\n }\n return String(value)\n}\n\nfunction prettyPrintWideEvent(event: Record<string, unknown>): void {\n const { timestamp, level, service, environment, version, ...rest } = event\n const levelColor = getLevelColor(level as string)\n const ts = (timestamp as string).slice(11, 23)\n\n let header = `${colors.dim}${ts}${colors.reset} ${levelColor}${(level as string).toUpperCase()}${colors.reset}`\n header += ` ${colors.cyan}[${service}]${colors.reset}`\n\n if (rest.method && rest.path) {\n header += ` ${rest.method} ${rest.path}`\n delete rest.method\n delete rest.path\n }\n\n if (rest.status) {\n const statusColor = (rest.status as number) >= 400 ? colors.red : colors.green\n header += ` ${statusColor}${rest.status}${colors.reset}`\n delete rest.status\n }\n\n if (rest.duration) {\n header += ` ${colors.dim}in ${rest.duration}${colors.reset}`\n delete rest.duration\n }\n\n console.log(header)\n\n const entries = Object.entries(rest).filter(([_, v]) => v !== undefined)\n const lastIndex = entries.length - 1\n\n entries.forEach(([key, value], index) => {\n const isLast = index === lastIndex\n const prefix = isLast ? '└─' : '├─'\n const formatted = formatValue(value)\n console.log(` ${colors.dim}${prefix}${colors.reset} ${colors.cyan}${key}:${colors.reset} ${formatted}`)\n })\n}\n\nfunction createLogMethod(level: LogLevel) {\n return function logMethod(tagOrEvent: string | Record<string, unknown>, message?: string): void {\n if (typeof tagOrEvent === 'string' && message !== undefined) {\n emitTaggedLog(level, tagOrEvent, message)\n } else if (typeof tagOrEvent === 'object') {\n emitWideEvent(level, tagOrEvent)\n } else {\n emitTaggedLog(level, 'log', String(tagOrEvent))\n }\n }\n}\n\n/**\n * Simple logging API - as easy as console.log\n *\n * @example\n * ```ts\n * log.info('auth', 'User logged in')\n * log.error({ action: 'payment', error: 'failed' })\n * ```\n */\nconst _log: Log = {\n info: createLogMethod('info'),\n error: createLogMethod('error'),\n warn: createLogMethod('warn'),\n debug: createLogMethod('debug'),\n}\n\nexport { _log as log }\n\nconst noopLogger: RequestLogger = {\n set() {},\n error() {},\n info() {},\n warn() {},\n emit() {\n return null\n },\n getContext() {\n return {}\n },\n}\n\n/**\n * Create a request-scoped logger for building wide events.\n *\n * @example\n * ```ts\n * const log = createRequestLogger({ method: 'POST', path: '/checkout' })\n * log.set({ user: { id: '123' } })\n * log.set({ cart: { items: 3 } })\n * log.emit()\n * ```\n */\nexport function createRequestLogger<T extends object = Record<string, unknown>>(options: RequestLoggerOptions = {}): RequestLogger<T> {\n if (!globalEnabled) return noopLogger as RequestLogger<T>\n\n const startTime = Date.now()\n let context: Record<string, unknown> = {\n method: options.method,\n path: options.path,\n requestId: options.requestId,\n }\n let hasError = false\n let hasWarn = false\n\n function addRequestLog(level: 'info' | 'warn', message: string): void {\n const entry = {\n level,\n message,\n timestamp: new Date().toISOString(),\n }\n\n const requestLogs = Array.isArray(context.requestLogs)\n ? [...context.requestLogs, entry]\n : [entry]\n\n context = {\n ...context,\n requestLogs,\n }\n }\n\n return {\n set(data: FieldContext<T>): void {\n context = deepDefaults(data as Record<string, unknown>, context) as Record<string, unknown>\n },\n\n error(error: Error | string, errorContext?: FieldContext<T>): void {\n hasError = true\n const err = typeof error === 'string' ? new Error(error) : error\n\n const errorData = {\n ...(errorContext as Record<string, unknown>),\n error: {\n name: err.name,\n message: err.message,\n stack: err.stack,\n ...('status' in err && { status: (err as Record<string, unknown>).status }),\n ...('statusText' in err && { statusText: (err as Record<string, unknown>).statusText }),\n ...('statusCode' in err && { statusCode: (err as Record<string, unknown>).statusCode }),\n ...('statusMessage' in err && { statusMessage: (err as Record<string, unknown>).statusMessage }),\n ...('data' in err && { data: (err as Record<string, unknown>).data }),\n ...('cause' in err && { cause: (err as unknown as Record<string, unknown>).cause }),\n },\n }\n context = deepDefaults(errorData, context) as Record<string, unknown>\n },\n\n info(message: string, infoContext?: FieldContext<T>): void {\n addRequestLog('info', message)\n if (infoContext) {\n const { requestLogs: _, ...rest } = infoContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n warn(message: string, warnContext?: FieldContext<T>): void {\n hasWarn = true\n addRequestLog('warn', message)\n if (warnContext) {\n const { requestLogs: _, ...rest } = warnContext as Record<string, unknown>\n context = deepDefaults(rest, context) as Record<string, unknown>\n }\n },\n\n emit(overrides?: FieldContext<T> & { _forceKeep?: boolean }): WideEvent | null {\n const durationMs = Date.now() - startTime\n const duration = formatDuration(durationMs)\n const level: LogLevel = hasError ? 'error' : hasWarn ? 'warn' : 'info'\n\n // Extract _forceKeep from overrides (set by evlog:emit:keep hook)\n const { _forceKeep, ...restOverrides } = (overrides ?? {}) as Record<string, unknown> & { _forceKeep?: boolean }\n\n // Build tail sampling context\n const tailCtx: TailSamplingContext = {\n status: (context.status ?? restOverrides.status) as number | undefined,\n duration: durationMs,\n path: context.path as string | undefined,\n method: context.method as string | undefined,\n context: { ...context, ...restOverrides },\n }\n\n // Tail sampling: force keep if hook or built-in conditions match\n const forceKeep = _forceKeep || shouldKeep(tailCtx)\n\n // Apply head sampling only if not force-kept\n if (!forceKeep && !shouldSample(level)) {\n return null\n }\n\n return emitWideEvent(level, {\n ...context,\n ...restOverrides,\n duration,\n }, true)\n },\n\n getContext(): FieldContext<T> & Record<string, unknown> {\n return { ...context }\n },\n }\n}\n\n/**\n * Get the current environment context.\n */\nexport function getEnvironment(): EnvironmentContext {\n return { ...globalEnv }\n}\n","import { createRequestLogger, initLogger } from 'evlog'\n\n/**\n * Log level for the Stack logger.\n *\n * Configured via the `STASH_STACK_LOG` environment variable.\n *\n * - `'error'` — Only errors (default when `STASH_STACK_LOG` is not set).\n * - `'info'` — Info and errors.\n * - `'debug'` — Debug, info, and errors.\n */\nexport type LogLevel = 'debug' | 'info' | 'error'\n\nconst validLevels: readonly LogLevel[] = ['debug', 'info', 'error'] as const\n\nfunction levelFromEnv(): LogLevel {\n const env = process.env.STASH_STACK_LOG\n if (env && validLevels.includes(env as LogLevel)) return env as LogLevel\n return 'error'\n}\n\nfunction samplingRatesForLevel(level: LogLevel): Record<string, number> {\n // evlog uses sampling rates: 100 = always emit, 0 = never emit\n switch (level) {\n case 'debug':\n return { debug: 100, info: 100, warn: 100, error: 100 }\n case 'info':\n return { debug: 0, info: 100, warn: 100, error: 100 }\n case 'error':\n default:\n return { debug: 0, info: 0, warn: 0, error: 100 }\n }\n}\n\nlet initialized = false\n\n/**\n * Initialize the Stack logger.\n *\n * The log level is read from the `STASH_STACK_LOG` environment variable.\n * When the variable is not set, the default is `'error'` (errors only).\n *\n * @internal\n */\nexport function initStackLogger(): void {\n if (initialized) return\n initialized = true\n\n const level = levelFromEnv()\n const rates = samplingRatesForLevel(level)\n\n initLogger({\n env: { service: '@cipherstash/stack' },\n enabled: true,\n sampling: { rates },\n })\n}\n\n// Auto-init with defaults on first import\ninitStackLogger()\n\nexport { createRequestLogger }\n\n// Stringify only the first arg (the message string); drop subsequent args\n// which may contain sensitive objects (e.g. encryptConfig, plaintext).\nfunction safeMessage(args: unknown[]): string {\n return typeof args[0] === 'string' ? args[0] : ''\n}\n\n// Logger for simple one-off logs used across Stack interfaces.\nexport const logger = {\n debug(...args: unknown[]) {\n const log = createRequestLogger()\n log.set({\n level: 'debug',\n source: '@cipherstash/stack',\n message: safeMessage(args),\n })\n log.emit()\n },\n info(...args: unknown[]) {\n const log = createRequestLogger()\n log.set({ source: '@cipherstash/stack' })\n log.info(safeMessage(args))\n log.emit()\n },\n warn(...args: unknown[]) {\n const log = createRequestLogger()\n log.warn(safeMessage(args))\n log.emit()\n },\n error(...args: unknown[]) {\n const log = createRequestLogger()\n log.error(safeMessage(args))\n log.emit()\n },\n}\n","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 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 { 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 { ScalarQueryTerm } from '@/types'\nimport { logger } from '@/utils/logger'\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 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 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 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 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 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 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 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 { 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 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: 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 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 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"],"mappings":"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","names":["baseOp","op","result","decrypted"]}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { A as AuditConfig, a as EncryptionClient } from '../client-Dt98Rugc.cjs';
|
|
2
|
-
import { EncryptionError } from '../errors/index.cjs';
|
|
3
|
-
import { LockContext } from '../identity/index.cjs';
|
|
4
|
-
import { c as EncryptedTable, d as EncryptedTableColumn } from '../types-public-BTxqjmtv.cjs';
|
|
5
|
-
import '@byteslice/result';
|
|
6
|
-
import '@cipherstash/protect-ffi';
|
|
7
|
-
import 'zod';
|
|
8
|
-
|
|
9
|
-
type EncryptedSupabaseConfig = {
|
|
10
|
-
encryptionClient: EncryptionClient;
|
|
11
|
-
supabaseClient: SupabaseClientLike;
|
|
12
|
-
};
|
|
13
|
-
interface EncryptedSupabaseInstance {
|
|
14
|
-
from<T extends Record<string, unknown> = Record<string, unknown>>(tableName: string, schema: EncryptedTable<EncryptedTableColumn>): EncryptedQueryBuilder<T>;
|
|
15
|
-
}
|
|
16
|
-
type EncryptedSupabaseResponse<T> = {
|
|
17
|
-
data: T | null;
|
|
18
|
-
error: EncryptedSupabaseError | null;
|
|
19
|
-
count: number | null;
|
|
20
|
-
status: number;
|
|
21
|
-
statusText: string;
|
|
22
|
-
};
|
|
23
|
-
type EncryptedSupabaseError = {
|
|
24
|
-
message: string;
|
|
25
|
-
details?: string;
|
|
26
|
-
hint?: string;
|
|
27
|
-
code?: string;
|
|
28
|
-
encryptionError?: EncryptionError;
|
|
29
|
-
};
|
|
30
|
-
type FilterOp = 'eq' | 'neq' | 'like' | 'ilike' | 'in' | 'gt' | 'gte' | 'lt' | 'lte' | 'is';
|
|
31
|
-
type PendingOrCondition = {
|
|
32
|
-
column: string;
|
|
33
|
-
op: FilterOp;
|
|
34
|
-
value: unknown;
|
|
35
|
-
};
|
|
36
|
-
interface SupabaseClientLike {
|
|
37
|
-
from(table: string): any;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Helper to extract string keys from T */
|
|
41
|
-
type StringKeyOf<T> = Extract<keyof T, string>;
|
|
42
|
-
interface EncryptedQueryBuilder<T extends Record<string, unknown> = Record<string, unknown>> extends PromiseLike<EncryptedSupabaseResponse<T[]>> {
|
|
43
|
-
select(columns: string, options?: {
|
|
44
|
-
head?: boolean;
|
|
45
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
46
|
-
}): EncryptedQueryBuilder<T>;
|
|
47
|
-
insert(data: Partial<T> | Partial<T>[], options?: {
|
|
48
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
49
|
-
defaultToNull?: boolean;
|
|
50
|
-
onConflict?: string;
|
|
51
|
-
}): EncryptedQueryBuilder<T>;
|
|
52
|
-
update(data: Partial<T>, options?: {
|
|
53
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
54
|
-
}): EncryptedQueryBuilder<T>;
|
|
55
|
-
upsert(data: Partial<T> | Partial<T>[], options?: {
|
|
56
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
57
|
-
onConflict?: string;
|
|
58
|
-
ignoreDuplicates?: boolean;
|
|
59
|
-
defaultToNull?: boolean;
|
|
60
|
-
}): EncryptedQueryBuilder<T>;
|
|
61
|
-
delete(options?: {
|
|
62
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
63
|
-
}): EncryptedQueryBuilder<T>;
|
|
64
|
-
eq<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
|
|
65
|
-
neq<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
|
|
66
|
-
gt<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
|
|
67
|
-
gte<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
|
|
68
|
-
lt<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
|
|
69
|
-
lte<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
|
|
70
|
-
like<K extends StringKeyOf<T>>(column: K, pattern: string): EncryptedQueryBuilder<T>;
|
|
71
|
-
ilike<K extends StringKeyOf<T>>(column: K, pattern: string): EncryptedQueryBuilder<T>;
|
|
72
|
-
is<K extends StringKeyOf<T>>(column: K, value: null | boolean): EncryptedQueryBuilder<T>;
|
|
73
|
-
in<K extends StringKeyOf<T>>(column: K, values: T[K][]): EncryptedQueryBuilder<T>;
|
|
74
|
-
filter<K extends StringKeyOf<T>>(column: K, operator: string, value: T[K]): EncryptedQueryBuilder<T>;
|
|
75
|
-
not<K extends StringKeyOf<T>>(column: K, operator: string, value: T[K]): EncryptedQueryBuilder<T>;
|
|
76
|
-
or(filters: string, options?: {
|
|
77
|
-
referencedTable?: string;
|
|
78
|
-
foreignTable?: string;
|
|
79
|
-
}): EncryptedQueryBuilder<T>;
|
|
80
|
-
or(conditions: PendingOrCondition[], options?: {
|
|
81
|
-
referencedTable?: string;
|
|
82
|
-
foreignTable?: string;
|
|
83
|
-
}): EncryptedQueryBuilder<T>;
|
|
84
|
-
match(query: Partial<T>): EncryptedQueryBuilder<T>;
|
|
85
|
-
order<K extends StringKeyOf<T>>(column: K, options?: {
|
|
86
|
-
ascending?: boolean;
|
|
87
|
-
nullsFirst?: boolean;
|
|
88
|
-
referencedTable?: string;
|
|
89
|
-
foreignTable?: string;
|
|
90
|
-
}): EncryptedQueryBuilder<T>;
|
|
91
|
-
limit(count: number, options?: {
|
|
92
|
-
referencedTable?: string;
|
|
93
|
-
foreignTable?: string;
|
|
94
|
-
}): EncryptedQueryBuilder<T>;
|
|
95
|
-
range(from: number, to: number, options?: {
|
|
96
|
-
referencedTable?: string;
|
|
97
|
-
foreignTable?: string;
|
|
98
|
-
}): EncryptedQueryBuilder<T>;
|
|
99
|
-
single(): EncryptedQueryBuilder<T>;
|
|
100
|
-
maybeSingle(): EncryptedQueryBuilder<T>;
|
|
101
|
-
csv(): EncryptedQueryBuilder<T>;
|
|
102
|
-
abortSignal(signal: AbortSignal): EncryptedQueryBuilder<T>;
|
|
103
|
-
throwOnError(): EncryptedQueryBuilder<T>;
|
|
104
|
-
returns<U extends Record<string, unknown>>(): EncryptedQueryBuilder<U>;
|
|
105
|
-
withLockContext(lockContext: LockContext): EncryptedQueryBuilder<T>;
|
|
106
|
-
audit(config: AuditConfig): EncryptedQueryBuilder<T>;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Create an encrypted Supabase wrapper that transparently handles encryption
|
|
111
|
-
* and decryption for queries on encrypted columns.
|
|
112
|
-
*
|
|
113
|
-
* @param config - Configuration containing the encryption client and Supabase client.
|
|
114
|
-
* @returns An object with a `from()` method that mirrors `supabase.from()` but
|
|
115
|
-
* auto-encrypts mutations, adds `::jsonb` casts, encrypts filter values, and
|
|
116
|
-
* decrypts results.
|
|
117
|
-
*
|
|
118
|
-
* @example
|
|
119
|
-
* ```typescript
|
|
120
|
-
* import { Encryption } from '@cipherstash/stack'
|
|
121
|
-
* import { encryptedSupabase } from '@cipherstash/stack/supabase'
|
|
122
|
-
* import { encryptedTable, encryptedColumn } from '@cipherstash/stack/schema'
|
|
123
|
-
*
|
|
124
|
-
* const users = encryptedTable('users', {
|
|
125
|
-
* name: encryptedColumn('name').freeTextSearch().equality(),
|
|
126
|
-
* email: encryptedColumn('email').freeTextSearch().equality(),
|
|
127
|
-
* })
|
|
128
|
-
*
|
|
129
|
-
* const client = await Encryption({ schemas: [users] })
|
|
130
|
-
* const eSupabase = encryptedSupabase({ encryptionClient: client, supabaseClient: supabase })
|
|
131
|
-
*
|
|
132
|
-
* // INSERT - auto-encrypts, auto-converts to PG composite
|
|
133
|
-
* await eSupabase.from('users', users)
|
|
134
|
-
* .insert({ name: 'John', email: 'john@example.com', age: 30 })
|
|
135
|
-
*
|
|
136
|
-
* // SELECT with filter - auto-casts ::jsonb, auto-encrypts search term, auto-decrypts
|
|
137
|
-
* const { data } = await eSupabase.from('users', users)
|
|
138
|
-
* .select('id, email, name')
|
|
139
|
-
* .eq('email', 'john@example.com')
|
|
140
|
-
* ```
|
|
141
|
-
*/
|
|
142
|
-
declare function encryptedSupabase(config: EncryptedSupabaseConfig): EncryptedSupabaseInstance;
|
|
143
|
-
|
|
144
|
-
export { type EncryptedQueryBuilder, type EncryptedSupabaseConfig, type EncryptedSupabaseError, type EncryptedSupabaseInstance, type EncryptedSupabaseResponse, type PendingOrCondition, type SupabaseClientLike, encryptedSupabase };
|
package/dist/supabase/index.d.ts
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { A as AuditConfig, a as EncryptionClient } from '../client-CIsfZ2zg.js';
|
|
2
|
-
import { EncryptionError } from '../errors/index.js';
|
|
3
|
-
import { LockContext } from '../identity/index.js';
|
|
4
|
-
import { c as EncryptedTable, d as EncryptedTableColumn } from '../types-public-BTxqjmtv.js';
|
|
5
|
-
import '@byteslice/result';
|
|
6
|
-
import '@cipherstash/protect-ffi';
|
|
7
|
-
import 'zod';
|
|
8
|
-
|
|
9
|
-
type EncryptedSupabaseConfig = {
|
|
10
|
-
encryptionClient: EncryptionClient;
|
|
11
|
-
supabaseClient: SupabaseClientLike;
|
|
12
|
-
};
|
|
13
|
-
interface EncryptedSupabaseInstance {
|
|
14
|
-
from<T extends Record<string, unknown> = Record<string, unknown>>(tableName: string, schema: EncryptedTable<EncryptedTableColumn>): EncryptedQueryBuilder<T>;
|
|
15
|
-
}
|
|
16
|
-
type EncryptedSupabaseResponse<T> = {
|
|
17
|
-
data: T | null;
|
|
18
|
-
error: EncryptedSupabaseError | null;
|
|
19
|
-
count: number | null;
|
|
20
|
-
status: number;
|
|
21
|
-
statusText: string;
|
|
22
|
-
};
|
|
23
|
-
type EncryptedSupabaseError = {
|
|
24
|
-
message: string;
|
|
25
|
-
details?: string;
|
|
26
|
-
hint?: string;
|
|
27
|
-
code?: string;
|
|
28
|
-
encryptionError?: EncryptionError;
|
|
29
|
-
};
|
|
30
|
-
type FilterOp = 'eq' | 'neq' | 'like' | 'ilike' | 'in' | 'gt' | 'gte' | 'lt' | 'lte' | 'is';
|
|
31
|
-
type PendingOrCondition = {
|
|
32
|
-
column: string;
|
|
33
|
-
op: FilterOp;
|
|
34
|
-
value: unknown;
|
|
35
|
-
};
|
|
36
|
-
interface SupabaseClientLike {
|
|
37
|
-
from(table: string): any;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** Helper to extract string keys from T */
|
|
41
|
-
type StringKeyOf<T> = Extract<keyof T, string>;
|
|
42
|
-
interface EncryptedQueryBuilder<T extends Record<string, unknown> = Record<string, unknown>> extends PromiseLike<EncryptedSupabaseResponse<T[]>> {
|
|
43
|
-
select(columns: string, options?: {
|
|
44
|
-
head?: boolean;
|
|
45
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
46
|
-
}): EncryptedQueryBuilder<T>;
|
|
47
|
-
insert(data: Partial<T> | Partial<T>[], options?: {
|
|
48
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
49
|
-
defaultToNull?: boolean;
|
|
50
|
-
onConflict?: string;
|
|
51
|
-
}): EncryptedQueryBuilder<T>;
|
|
52
|
-
update(data: Partial<T>, options?: {
|
|
53
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
54
|
-
}): EncryptedQueryBuilder<T>;
|
|
55
|
-
upsert(data: Partial<T> | Partial<T>[], options?: {
|
|
56
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
57
|
-
onConflict?: string;
|
|
58
|
-
ignoreDuplicates?: boolean;
|
|
59
|
-
defaultToNull?: boolean;
|
|
60
|
-
}): EncryptedQueryBuilder<T>;
|
|
61
|
-
delete(options?: {
|
|
62
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
63
|
-
}): EncryptedQueryBuilder<T>;
|
|
64
|
-
eq<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
|
|
65
|
-
neq<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
|
|
66
|
-
gt<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
|
|
67
|
-
gte<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
|
|
68
|
-
lt<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
|
|
69
|
-
lte<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
|
|
70
|
-
like<K extends StringKeyOf<T>>(column: K, pattern: string): EncryptedQueryBuilder<T>;
|
|
71
|
-
ilike<K extends StringKeyOf<T>>(column: K, pattern: string): EncryptedQueryBuilder<T>;
|
|
72
|
-
is<K extends StringKeyOf<T>>(column: K, value: null | boolean): EncryptedQueryBuilder<T>;
|
|
73
|
-
in<K extends StringKeyOf<T>>(column: K, values: T[K][]): EncryptedQueryBuilder<T>;
|
|
74
|
-
filter<K extends StringKeyOf<T>>(column: K, operator: string, value: T[K]): EncryptedQueryBuilder<T>;
|
|
75
|
-
not<K extends StringKeyOf<T>>(column: K, operator: string, value: T[K]): EncryptedQueryBuilder<T>;
|
|
76
|
-
or(filters: string, options?: {
|
|
77
|
-
referencedTable?: string;
|
|
78
|
-
foreignTable?: string;
|
|
79
|
-
}): EncryptedQueryBuilder<T>;
|
|
80
|
-
or(conditions: PendingOrCondition[], options?: {
|
|
81
|
-
referencedTable?: string;
|
|
82
|
-
foreignTable?: string;
|
|
83
|
-
}): EncryptedQueryBuilder<T>;
|
|
84
|
-
match(query: Partial<T>): EncryptedQueryBuilder<T>;
|
|
85
|
-
order<K extends StringKeyOf<T>>(column: K, options?: {
|
|
86
|
-
ascending?: boolean;
|
|
87
|
-
nullsFirst?: boolean;
|
|
88
|
-
referencedTable?: string;
|
|
89
|
-
foreignTable?: string;
|
|
90
|
-
}): EncryptedQueryBuilder<T>;
|
|
91
|
-
limit(count: number, options?: {
|
|
92
|
-
referencedTable?: string;
|
|
93
|
-
foreignTable?: string;
|
|
94
|
-
}): EncryptedQueryBuilder<T>;
|
|
95
|
-
range(from: number, to: number, options?: {
|
|
96
|
-
referencedTable?: string;
|
|
97
|
-
foreignTable?: string;
|
|
98
|
-
}): EncryptedQueryBuilder<T>;
|
|
99
|
-
single(): EncryptedQueryBuilder<T>;
|
|
100
|
-
maybeSingle(): EncryptedQueryBuilder<T>;
|
|
101
|
-
csv(): EncryptedQueryBuilder<T>;
|
|
102
|
-
abortSignal(signal: AbortSignal): EncryptedQueryBuilder<T>;
|
|
103
|
-
throwOnError(): EncryptedQueryBuilder<T>;
|
|
104
|
-
returns<U extends Record<string, unknown>>(): EncryptedQueryBuilder<U>;
|
|
105
|
-
withLockContext(lockContext: LockContext): EncryptedQueryBuilder<T>;
|
|
106
|
-
audit(config: AuditConfig): EncryptedQueryBuilder<T>;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* Create an encrypted Supabase wrapper that transparently handles encryption
|
|
111
|
-
* and decryption for queries on encrypted columns.
|
|
112
|
-
*
|
|
113
|
-
* @param config - Configuration containing the encryption client and Supabase client.
|
|
114
|
-
* @returns An object with a `from()` method that mirrors `supabase.from()` but
|
|
115
|
-
* auto-encrypts mutations, adds `::jsonb` casts, encrypts filter values, and
|
|
116
|
-
* decrypts results.
|
|
117
|
-
*
|
|
118
|
-
* @example
|
|
119
|
-
* ```typescript
|
|
120
|
-
* import { Encryption } from '@cipherstash/stack'
|
|
121
|
-
* import { encryptedSupabase } from '@cipherstash/stack/supabase'
|
|
122
|
-
* import { encryptedTable, encryptedColumn } from '@cipherstash/stack/schema'
|
|
123
|
-
*
|
|
124
|
-
* const users = encryptedTable('users', {
|
|
125
|
-
* name: encryptedColumn('name').freeTextSearch().equality(),
|
|
126
|
-
* email: encryptedColumn('email').freeTextSearch().equality(),
|
|
127
|
-
* })
|
|
128
|
-
*
|
|
129
|
-
* const client = await Encryption({ schemas: [users] })
|
|
130
|
-
* const eSupabase = encryptedSupabase({ encryptionClient: client, supabaseClient: supabase })
|
|
131
|
-
*
|
|
132
|
-
* // INSERT - auto-encrypts, auto-converts to PG composite
|
|
133
|
-
* await eSupabase.from('users', users)
|
|
134
|
-
* .insert({ name: 'John', email: 'john@example.com', age: 30 })
|
|
135
|
-
*
|
|
136
|
-
* // SELECT with filter - auto-casts ::jsonb, auto-encrypts search term, auto-decrypts
|
|
137
|
-
* const { data } = await eSupabase.from('users', users)
|
|
138
|
-
* .select('id, email, name')
|
|
139
|
-
* .eq('email', 'john@example.com')
|
|
140
|
-
* ```
|
|
141
|
-
*/
|
|
142
|
-
declare function encryptedSupabase(config: EncryptedSupabaseConfig): EncryptedSupabaseInstance;
|
|
143
|
-
|
|
144
|
-
export { type EncryptedQueryBuilder, type EncryptedSupabaseConfig, type EncryptedSupabaseError, type EncryptedSupabaseInstance, type EncryptedSupabaseResponse, type PendingOrCondition, type SupabaseClientLike, encryptedSupabase };
|