@cipherstash/stack 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -1
  3. package/dist/bin/stash.js +46 -141
  4. package/dist/bin/stash.js.map +1 -1
  5. package/dist/{chunk-SUYMGQBY.js → chunk-4RNBI3UH.js} +1 -7
  6. package/dist/chunk-4RNBI3UH.js.map +1 -0
  7. package/dist/{chunk-JLI27P46.js → chunk-KOU2MHXJ.js} +1 -1
  8. package/dist/chunk-KOU2MHXJ.js.map +1 -0
  9. package/dist/{chunk-MW6D52V2.js → chunk-WUZGKTMG.js} +45 -134
  10. package/dist/chunk-WUZGKTMG.js.map +1 -0
  11. package/dist/{chunk-TBAIVO6T.js → chunk-Y35W4WFN.js} +6 -6
  12. package/dist/chunk-Y35W4WFN.js.map +1 -0
  13. package/dist/{client-Bf0Xw2xo.d.cts → client-CUGXheRq.d.cts} +15 -16
  14. package/dist/{client-Kfp8OsPB.d.ts → client-CrGQnSlk.d.ts} +15 -16
  15. package/dist/client.cjs +5 -5
  16. package/dist/client.cjs.map +1 -1
  17. package/dist/client.d.cts +2 -2
  18. package/dist/client.d.ts +2 -2
  19. package/dist/client.js +1 -1
  20. package/dist/drizzle/index.cjs +5 -5
  21. package/dist/drizzle/index.cjs.map +1 -1
  22. package/dist/drizzle/index.d.cts +2 -2
  23. package/dist/drizzle/index.d.ts +2 -2
  24. package/dist/drizzle/index.js +2 -2
  25. package/dist/dynamodb/index.d.cts +2 -2
  26. package/dist/dynamodb/index.d.ts +2 -2
  27. package/dist/index.cjs +46 -141
  28. package/dist/index.cjs.map +1 -1
  29. package/dist/index.d.cts +3 -3
  30. package/dist/index.d.ts +3 -3
  31. package/dist/index.js +4 -4
  32. package/dist/schema/index.cjs +5 -5
  33. package/dist/schema/index.cjs.map +1 -1
  34. package/dist/schema/index.d.cts +1 -1
  35. package/dist/schema/index.d.ts +1 -1
  36. package/dist/schema/index.js +1 -1
  37. package/dist/secrets/index.cjs +46 -141
  38. package/dist/secrets/index.cjs.map +1 -1
  39. package/dist/secrets/index.d.cts +1 -1
  40. package/dist/secrets/index.d.ts +1 -1
  41. package/dist/secrets/index.js +4 -4
  42. package/dist/supabase/index.cjs +2 -2
  43. package/dist/supabase/index.cjs.map +1 -1
  44. package/dist/supabase/index.d.cts +2 -2
  45. package/dist/supabase/index.d.ts +2 -2
  46. package/dist/supabase/index.js +2 -2
  47. package/dist/{types-public-0CzBV45X.d.cts → types-public-Wj6tB_ux.d.cts} +47 -26
  48. package/dist/{types-public-0CzBV45X.d.ts → types-public-Wj6tB_ux.d.ts} +47 -26
  49. package/dist/types-public.cjs.map +1 -1
  50. package/dist/types-public.d.cts +1 -1
  51. package/dist/types-public.d.ts +1 -1
  52. package/dist/types-public.js +1 -1
  53. package/package.json +2 -2
  54. package/dist/chunk-JLI27P46.js.map +0 -1
  55. package/dist/chunk-MW6D52V2.js.map +0 -1
  56. package/dist/chunk-SUYMGQBY.js.map +0 -1
  57. package/dist/chunk-TBAIVO6T.js.map +0 -1
@@ -5,15 +5,9 @@ function encryptedToPgComposite(obj) {
5
5
  };
6
6
  }
7
7
  function encryptedToCompositeLiteral(obj) {
8
- if (obj === null) {
9
- throw new Error("encryptedToCompositeLiteral: obj cannot be null");
10
- }
11
8
  return `(${JSON.stringify(JSON.stringify(obj))})`;
12
9
  }
13
10
  function encryptedToEscapedCompositeLiteral(obj) {
14
- if (obj === null) {
15
- throw new Error("encryptedToEscapedCompositeLiteral: obj cannot be null");
16
- }
17
11
  return JSON.stringify(encryptedToCompositeLiteral(obj));
18
12
  }
19
13
  function formatEncryptedResult(encrypted, returnType) {
@@ -64,4 +58,4 @@ export {
64
58
  toFfiKeysetIdentifier,
65
59
  isEncryptedPayload
66
60
  };
67
- //# sourceMappingURL=chunk-SUYMGQBY.js.map
61
+ //# sourceMappingURL=chunk-4RNBI3UH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/encryption/helpers/index.ts"],"sourcesContent":["import type { Encrypted, EncryptedQueryResult, KeysetIdentifier } from '@/types'\nimport type {\n Encrypted as CipherStashEncrypted,\n KeysetIdentifier as KeysetIdentifierFfi,\n} from '@cipherstash/protect-ffi'\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: CipherStashEncrypted): 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: CipherStashEncrypted,\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: CipherStashEncrypted,\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"],"mappings":";AAcO,SAAS,uBAAuB,KAAsC;AAC3E,SAAO;AAAA,IACL,MAAM;AAAA,EACR;AACF;AAYO,SAAS,4BAA4B,KAAmC;AAC7E,SAAO,IAAI,KAAK,UAAU,KAAK,UAAU,GAAG,CAAC,CAAC;AAChD;AAWO,SAAS,mCACd,KACQ;AACR,SAAO,KAAK,UAAU,4BAA4B,GAAG,CAAC;AACxD;AASO,SAAS,sBACd,WACA,YACsB;AACtB,MAAI,eAAe,qBAAqB;AACtC,WAAO,4BAA4B,SAAS;AAAA,EAC9C;AACA,MAAI,eAAe,6BAA6B;AAC9C,WAAO,mCAAmC,SAAS;AAAA,EACrD;AACA,SAAO;AACT;AAKO,SAAS,6BACd,OACG;AACH,QAAM,SAAkC,CAAC;AAEzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,mBAAmB,KAAK,GAAG;AAC7B,aAAO,GAAG,IAAI,uBAAuB,KAAK;AAAA,IAC5C,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,kCAEd,QAAkB;AAClB,SAAO,OAAO,IAAI,CAAC,UAAU,6BAA6B,KAAK,CAAC;AAClE;AAEO,SAAS,sBACd,QACiC;AACjC,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI,UAAU,QAAQ;AACpB,WAAO,EAAE,MAAM,OAAO,KAAK;AAAA,EAC7B;AAEA,SAAO,EAAE,MAAM,OAAO,GAAG;AAC3B;AAKO,SAAS,mBAAmB,OAAoC;AACrE,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,OAAO,UAAU,SAAU,QAAO;AAEtC,QAAM,MAAM;AAGZ,MAAI,EAAE,OAAO,QAAQ,OAAO,IAAI,MAAM,SAAU,QAAO;AAGvD,MAAI,EAAE,OAAO,QAAQ,OAAO,IAAI,MAAM,SAAU,QAAO;AAGvD,MAAI,EAAE,OAAO,QAAQ,EAAE,QAAQ,KAAM,QAAO;AAE5C,SAAO;AACT;","names":[]}
@@ -25,4 +25,4 @@ export {
25
25
  queryTypeToFfi,
26
26
  queryTypeToQueryOp
27
27
  };
28
- //# sourceMappingURL=chunk-JLI27P46.js.map
28
+ //# sourceMappingURL=chunk-KOU2MHXJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type {\n EncryptedColumn,\n EncryptedTable,\n EncryptedTableColumn,\n EncryptedField,\n} from '@/schema'\nimport type { LoggingConfig } from '@/utils/logger'\nimport type {\n Encrypted as CipherStashEncrypted,\n JsPlaintext,\n QueryOpName,\n newClient,\n} from '@cipherstash/protect-ffi'\n\n// ---------------------------------------------------------------------------\n// Branded type utilities\n// ---------------------------------------------------------------------------\n\n/** Brand symbol for nominal typing */\ndeclare const __brand: unique symbol\n\n/** Creates a branded type that is structurally incompatible with the base type */\ntype Brand<T, B extends string> = T & { readonly [__brand]: B }\n\n// ---------------------------------------------------------------------------\n// Core types\n// ---------------------------------------------------------------------------\n\nexport type Client = Awaited<ReturnType<typeof newClient>> | undefined\n\n/** A branded type representing encrypted data. Cannot be accidentally used as plaintext. */\nexport type EncryptedValue = Brand<CipherStashEncrypted, 'encrypted'>\n\n/** Structural type representing encrypted data. See also `EncryptedValue` for branded nominal typing. */\nexport type Encrypted = CipherStashEncrypted\n\n// ---------------------------------------------------------------------------\n// Client configuration\n// ---------------------------------------------------------------------------\n\nexport type KeysetIdentifier = { name: string } | { id: string }\n\nexport type ClientConfig = {\n /**\n * The CipherStash workspace CRN (Cloud Resource Name).\n * Format: `crn:<region>.aws:<workspace-id>`.\n * Can also be set via the `CS_WORKSPACE_CRN` environment variable.\n * If omitted, the SDK reads from the environment or TOML config files.\n */\n workspaceCrn?: string\n\n /**\n * The API access key used for authenticating with the CipherStash API.\n * Can also be set via the `CS_CLIENT_ACCESS_KEY` environment variable.\n * Obtain this from the CipherStash dashboard after creating a workspace.\n */\n accessKey?: string\n\n /**\n * The client identifier used to authenticate with CipherStash services.\n * Can also be set via the `CS_CLIENT_ID` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientId?: string\n\n /**\n * The client key material used in combination with ZeroKMS for encryption operations.\n * Can also be set via the `CS_CLIENT_KEY` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientKey?: string\n\n /**\n * An optional keyset identifier for multi-tenant encryption.\n * Each keyset provides cryptographic isolation, giving each tenant its own keyspace.\n * Specify by name (`{ name: \"tenant-a\" }`) or UUID (`{ id: \"...\" }`).\n * Keysets are created and managed in the CipherStash dashboard.\n */\n keyset?: KeysetIdentifier\n}\n\ntype AtLeastOneCsTable<T> = [T, ...T[]]\n\nexport type EncryptionClientConfig = {\n schemas: AtLeastOneCsTable<EncryptedTable<EncryptedTableColumn>>\n config?: ClientConfig\n logging?: LoggingConfig\n}\n\n// ---------------------------------------------------------------------------\n// Encrypt / decrypt operation options and results\n// ---------------------------------------------------------------------------\n\n/**\n * Options for single-value encrypt operations.\n * Use a column from your table schema (from {@link encryptedColumn}) or a nested\n * field (from {@link encryptedField}) as the target for encryption.\n */\nexport type EncryptOptions = {\n /** The column or nested field to encrypt into. From {@link EncryptedColumn} or {@link EncryptedField}. */\n column: EncryptedColumn | EncryptedField\n table: EncryptedTable<EncryptedTableColumn>\n}\n\n/** Format for encrypted query/search term return values */\nexport type EncryptedReturnType =\n | 'eql'\n | 'composite-literal'\n | 'escaped-composite-literal'\n\nexport type SearchTerm = {\n value: JsPlaintext\n column: EncryptedColumn\n table: EncryptedTable<EncryptedTableColumn>\n returnType?: EncryptedReturnType\n}\n\n/** Encrypted search term result: EQL object or composite literal string */\nexport type EncryptedSearchTerm = Encrypted | string\n\n/** Result of encryptQuery (single or batch): EQL or composite literal string */\nexport type EncryptedQueryResult = Encrypted | string\n\n// ---------------------------------------------------------------------------\n// Model field types (encrypted vs decrypted views)\n// ---------------------------------------------------------------------------\n\nexport type EncryptedFields<T> = {\n [K in keyof T as NonNullable<T[K]> extends Encrypted ? K : never]: T[K]\n}\n\nexport type OtherFields<T> = {\n [K in keyof T as NonNullable<T[K]> extends Encrypted ? never : K]: T[K]\n}\n\nexport type DecryptedFields<T> = {\n [K in keyof T as NonNullable<T[K]> extends Encrypted ? K : never]:\n null extends T[K] ? string | null : string\n}\n\n/** Model with encrypted fields replaced by plaintext (decrypted) values */\nexport type Decrypted<T> = OtherFields<T> & DecryptedFields<T>\n\n/**\n * Maps a plaintext model type to its encrypted form using the table schema.\n *\n * Fields whose keys match columns defined in `S` become `Encrypted`;\n * all other fields retain their original types from `T`.\n *\n * When `S` is the widened `EncryptedTableColumn` (e.g. when a user passes an\n * explicit `<User>` type argument without specifying `S`), the type degrades\n * gracefully to `T` — preserving backward compatibility.\n *\n * @typeParam T - The plaintext model type (e.g. `{ id: string; email: string }`)\n * @typeParam S - The table schema column definition, inferred from the `table` argument\n *\n * @example\n * ```typescript\n * type User = { id: string; email: string }\n * // With a schema that defines `email`:\n * type Encrypted = EncryptedFromSchema<User, { email: EncryptedColumn }>\n * // => { id: string; email: Encrypted }\n * ```\n */\nexport type EncryptedFromSchema<T, S extends EncryptedTableColumn> = {\n [K in keyof T]: [K] extends [keyof S]\n ? [S[K & keyof S]] extends [EncryptedColumn | EncryptedField]\n ? null extends T[K] ? Encrypted | null : Encrypted\n : T[K]\n : T[K]\n}\n\n// ---------------------------------------------------------------------------\n// Bulk operations\n// ---------------------------------------------------------------------------\n\nexport type BulkEncryptPayload = Array<{\n id?: string\n plaintext: JsPlaintext\n}>\n\nexport type BulkEncryptedData = Array<{ id?: string; data: Encrypted }>\nexport type BulkDecryptPayload = Array<{ id?: string; data: Encrypted }>\nexport type BulkDecryptedData = Array<DecryptionResult<JsPlaintext>>\n\ntype DecryptionSuccess<T> = { error?: never; data: T; id?: string }\ntype DecryptionError<T> = { error: T; id?: string; data?: never }\n\n/**\n * Result type for individual items in bulk decrypt operations.\n * Uses `error`/`data` fields (not `failure`/`data`) since bulk operations\n * can have per-item failures.\n */\nexport type DecryptionResult<T> = DecryptionSuccess<T> | DecryptionError<T>\n\n// ---------------------------------------------------------------------------\n// Query types (for searchable encryption / encryptQuery)\n// ---------------------------------------------------------------------------\n\n/**\n * User-facing query type names for encrypting query values.\n *\n * - `'equality'`: Exact match. [Exact Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/exact)\n * - `'freeTextSearch'`: Text search. [Match Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/match)\n * - `'orderAndRange'`: Comparison and range. [Range Queries](https://cipherstash.com/docs/platform/searchable-encryption/supported-queries/range)\n * - `'steVecSelector'`: JSONPath selector (e.g. `'$.user.email'`)\n * - `'steVecTerm'`: Containment (e.g. `{ role: 'admin' }`)\n * - `'searchableJson'`: Auto-infers selector or term from plaintext type (recommended)\n */\nexport type QueryTypeName =\n | 'orderAndRange'\n | 'freeTextSearch'\n | 'equality'\n | 'steVecSelector'\n | 'steVecTerm'\n | 'searchableJson'\n\n/** @internal */\nexport type FfiIndexTypeName = 'ore' | 'match' | 'unique' | 'ste_vec'\n\nexport const queryTypes = {\n orderAndRange: 'orderAndRange',\n freeTextSearch: 'freeTextSearch',\n equality: 'equality',\n steVecSelector: 'steVecSelector',\n steVecTerm: 'steVecTerm',\n searchableJson: 'searchableJson',\n} as const satisfies Record<string, QueryTypeName>\n\n/** @internal */\nexport const queryTypeToFfi: Record<QueryTypeName, FfiIndexTypeName> = {\n orderAndRange: 'ore',\n freeTextSearch: 'match',\n equality: 'unique',\n steVecSelector: 'ste_vec',\n steVecTerm: 'ste_vec',\n searchableJson: 'ste_vec',\n}\n\n/** @internal */\nexport const queryTypeToQueryOp: Partial<Record<QueryTypeName, QueryOpName>> = {\n steVecSelector: 'ste_vec_selector',\n steVecTerm: 'ste_vec_term',\n}\n\n/** @internal */\nexport type QueryTermBase = {\n column: EncryptedColumn\n table: EncryptedTable<EncryptedTableColumn>\n queryType?: QueryTypeName\n returnType?: EncryptedReturnType\n}\n\nexport type EncryptQueryOptions = QueryTermBase\n\nexport type ScalarQueryTerm = QueryTermBase & {\n value: JsPlaintext\n}\n"],"mappings":";AA4NO,IAAM,aAAa;AAAA,EACxB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,gBAAgB;AAClB;AAGO,IAAM,iBAA0D;AAAA,EACrE,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,gBAAgB;AAClB;AAGO,IAAM,qBAAkE;AAAA,EAC7E,gBAAgB;AAAA,EAChB,YAAY;AACd;","names":[]}
@@ -2,11 +2,11 @@ import {
2
2
  formatEncryptedResult,
3
3
  isEncryptedPayload,
4
4
  toFfiKeysetIdentifier
5
- } from "./chunk-SUYMGQBY.js";
5
+ } from "./chunk-4RNBI3UH.js";
6
6
  import {
7
7
  queryTypeToFfi,
8
8
  queryTypeToQueryOp
9
- } from "./chunk-JLI27P46.js";
9
+ } from "./chunk-KOU2MHXJ.js";
10
10
  import {
11
11
  EncryptionErrorTypes,
12
12
  createRequestLogger,
@@ -17,7 +17,7 @@ import {
17
17
  import {
18
18
  buildEncryptConfig,
19
19
  encryptConfigSchema
20
- } from "./chunk-TBAIVO6T.js";
20
+ } from "./chunk-Y35W4WFN.js";
21
21
 
22
22
  // src/encryption/index.ts
23
23
  import { withResult as withResult11 } from "@byteslice/result";
@@ -167,18 +167,6 @@ var EncryptionOperation = class {
167
167
  };
168
168
 
169
169
  // src/encryption/operations/batch-encrypt-query.ts
170
- function filterNullTerms(terms) {
171
- const nullIndices = /* @__PURE__ */ new Set();
172
- const nonNullTerms = [];
173
- terms.forEach((term, index) => {
174
- if (term.value === null || term.value === void 0) {
175
- nullIndices.add(index);
176
- } else {
177
- nonNullTerms.push({ term, originalIndex: index });
178
- }
179
- });
180
- return { nullIndices, nonNullTerms };
181
- }
182
170
  function buildQueryPayload(term, lockContext) {
183
171
  assertValidNumericValue(term.value);
184
172
  const { indexType, queryOp } = resolveIndexType(
@@ -199,13 +187,10 @@ function buildQueryPayload(term, lockContext) {
199
187
  }
200
188
  return payload;
201
189
  }
202
- function assembleResults(totalLength, encryptedValues, nonNullTerms) {
203
- const results = new Array(totalLength).fill(null);
204
- nonNullTerms.forEach(({ term, originalIndex }, i) => {
205
- const encrypted = encryptedValues[i];
206
- results[originalIndex] = formatEncryptedResult(encrypted, term.returnType);
207
- });
208
- return results;
190
+ function assembleResults(terms, encryptedValues) {
191
+ return terms.map(
192
+ (term, i) => formatEncryptedResult(encryptedValues[i], term.returnType)
193
+ );
209
194
  }
210
195
  var BatchEncryptQueryOperation = class extends EncryptionOperation {
211
196
  constructor(client, terms) {
@@ -232,23 +217,18 @@ var BatchEncryptQueryOperation = class extends EncryptionOperation {
232
217
  log.emit();
233
218
  return { data: [] };
234
219
  }
235
- const { nullIndices, nonNullTerms } = filterNullTerms(this.terms);
236
- if (nonNullTerms.length === 0) {
237
- log.emit();
238
- return { data: this.terms.map(() => null) };
239
- }
240
220
  const result = await withResult(
241
221
  async () => {
242
222
  if (!this.client) throw noClientError();
243
223
  const { metadata } = this.getAuditData();
244
- const queries = nonNullTerms.map(
245
- ({ term }) => buildQueryPayload(term)
224
+ const queries = this.terms.map(
225
+ (term) => buildQueryPayload(term)
246
226
  );
247
227
  const encrypted = await ffiEncryptQueryBulk(this.client, {
248
228
  queries,
249
229
  unverifiedContext: metadata
250
230
  });
251
- return assembleResults(this.terms.length, encrypted, nonNullTerms);
231
+ return assembleResults(this.terms, encrypted);
252
232
  },
253
233
  (error) => {
254
234
  log.set({ errorCode: getErrorCode(error) ?? "unknown" });
@@ -282,11 +262,6 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
282
262
  log.emit();
283
263
  return { data: [] };
284
264
  }
285
- const { nullIndices, nonNullTerms } = filterNullTerms(this.terms);
286
- if (nonNullTerms.length === 0) {
287
- log.emit();
288
- return { data: this.terms.map(() => null) };
289
- }
290
265
  const lockContextResult = await this.lockContext.getLockContext();
291
266
  if (lockContextResult.failure) {
292
267
  log.emit();
@@ -297,15 +272,15 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
297
272
  async () => {
298
273
  if (!this.client) throw noClientError();
299
274
  const { metadata } = this.getAuditData();
300
- const queries = nonNullTerms.map(
301
- ({ term }) => buildQueryPayload(term, context)
275
+ const queries = this.terms.map(
276
+ (term) => buildQueryPayload(term, context)
302
277
  );
303
278
  const encrypted = await ffiEncryptQueryBulk(this.client, {
304
279
  queries,
305
280
  serviceToken: ctsToken,
306
281
  unverifiedContext: metadata
307
282
  });
308
- return assembleResults(this.terms.length, encrypted, nonNullTerms);
283
+ return assembleResults(this.terms, encrypted);
309
284
  },
310
285
  (error) => {
311
286
  log.set({ errorCode: getErrorCode(error) ?? "unknown" });
@@ -327,42 +302,25 @@ import {
327
302
  decryptBulkFallible
328
303
  } from "@cipherstash/protect-ffi";
329
304
  var createDecryptPayloads = (encryptedPayloads, lockContext) => {
330
- return encryptedPayloads.map((item, index) => ({ ...item, originalIndex: index })).filter(({ data }) => data !== null).map(({ id, data, originalIndex }) => ({
305
+ return encryptedPayloads.map(({ id, data }) => ({
331
306
  id,
332
307
  ciphertext: data,
333
- originalIndex,
334
308
  ...lockContext && { lockContext }
335
309
  }));
336
310
  };
337
- var createNullResult = (encryptedPayloads) => {
338
- return encryptedPayloads.map(({ id }) => ({
339
- id,
340
- data: null
341
- }));
342
- };
343
311
  var mapDecryptedDataToResult = (encryptedPayloads, decryptedData) => {
344
- const result = new Array(encryptedPayloads.length);
345
- let decryptedIndex = 0;
346
- for (let i = 0; i < encryptedPayloads.length; i++) {
347
- if (encryptedPayloads[i].data === null) {
348
- result[i] = { id: encryptedPayloads[i].id, data: null };
349
- } else {
350
- const decryptResult = decryptedData[decryptedIndex];
351
- if ("error" in decryptResult) {
352
- result[i] = {
353
- id: encryptedPayloads[i].id,
354
- error: decryptResult.error
355
- };
356
- } else {
357
- result[i] = {
358
- id: encryptedPayloads[i].id,
359
- data: decryptResult.data
360
- };
361
- }
362
- decryptedIndex++;
312
+ return decryptedData.map((decryptResult, i) => {
313
+ if ("error" in decryptResult) {
314
+ return {
315
+ id: encryptedPayloads[i].id,
316
+ error: decryptResult.error
317
+ };
363
318
  }
364
- }
365
- return result;
319
+ return {
320
+ id: encryptedPayloads[i].id,
321
+ data: decryptResult.data
322
+ };
323
+ });
366
324
  };
367
325
  var BulkDecryptOperation = class extends EncryptionOperation {
368
326
  client;
@@ -387,13 +345,10 @@ var BulkDecryptOperation = class extends EncryptionOperation {
387
345
  if (!this.client) throw noClientError();
388
346
  if (!this.encryptedPayloads || this.encryptedPayloads.length === 0)
389
347
  return [];
390
- const nonNullPayloads = createDecryptPayloads(this.encryptedPayloads);
391
- if (nonNullPayloads.length === 0) {
392
- return createNullResult(this.encryptedPayloads);
393
- }
348
+ const payloads = createDecryptPayloads(this.encryptedPayloads);
394
349
  const { metadata } = this.getAuditData();
395
350
  const decryptedData = await decryptBulkFallible(this.client, {
396
- ciphertexts: nonNullPayloads,
351
+ ciphertexts: payloads,
397
352
  unverifiedContext: metadata
398
353
  });
399
354
  return mapDecryptedDataToResult(this.encryptedPayloads, decryptedData);
@@ -445,16 +400,13 @@ var BulkDecryptOperationWithLockContext = class extends EncryptionOperation {
445
400
  if (context.failure) {
446
401
  throw new Error(`[encryption]: ${context.failure.message}`);
447
402
  }
448
- const nonNullPayloads = createDecryptPayloads(
403
+ const payloads = createDecryptPayloads(
449
404
  encryptedPayloads,
450
405
  context.data.context
451
406
  );
452
- if (nonNullPayloads.length === 0) {
453
- return createNullResult(encryptedPayloads);
454
- }
455
407
  const { metadata } = this.getAuditData();
456
408
  const decryptedData = await decryptBulkFallible(client, {
457
- ciphertexts: nonNullPayloads,
409
+ ciphertexts: payloads,
458
410
  serviceToken: context.data.ctsToken,
459
411
  unverifiedContext: metadata
460
412
  });
@@ -1096,34 +1048,14 @@ var BulkDecryptModelsOperationWithLockContext = class extends EncryptionOperatio
1096
1048
  import { withResult as withResult4 } from "@byteslice/result";
1097
1049
  import { encryptBulk as encryptBulk2 } from "@cipherstash/protect-ffi";
1098
1050
  var createEncryptPayloads = (plaintexts, column, table, lockContext) => {
1099
- return plaintexts.map((item, index) => ({ ...item, originalIndex: index })).filter(({ plaintext }) => plaintext !== null).map(({ id, plaintext, originalIndex }) => ({
1051
+ return plaintexts.map(({ id, plaintext }) => ({
1100
1052
  id,
1101
1053
  plaintext,
1102
1054
  column: column.getName(),
1103
1055
  table: table.tableName,
1104
- originalIndex,
1105
1056
  ...lockContext && { lockContext }
1106
1057
  }));
1107
1058
  };
1108
- var createNullResult2 = (plaintexts) => {
1109
- return plaintexts.map(({ id }) => ({ id, data: null }));
1110
- };
1111
- var mapEncryptedDataToResult = (plaintexts, encryptedData) => {
1112
- const result = new Array(plaintexts.length);
1113
- let encryptedIndex = 0;
1114
- for (let i = 0; i < plaintexts.length; i++) {
1115
- if (plaintexts[i].plaintext === null) {
1116
- result[i] = { id: plaintexts[i].id, data: null };
1117
- } else {
1118
- result[i] = {
1119
- id: plaintexts[i].id,
1120
- data: encryptedData[encryptedIndex]
1121
- };
1122
- encryptedIndex++;
1123
- }
1124
- }
1125
- return result;
1126
- };
1127
1059
  var BulkEncryptOperation = class extends EncryptionOperation {
1128
1060
  client;
1129
1061
  plaintexts;
@@ -1156,20 +1088,20 @@ var BulkEncryptOperation = class extends EncryptionOperation {
1156
1088
  if (!this.plaintexts || this.plaintexts.length === 0) {
1157
1089
  return [];
1158
1090
  }
1159
- const nonNullPayloads = createEncryptPayloads(
1091
+ const payloads = createEncryptPayloads(
1160
1092
  this.plaintexts,
1161
1093
  this.column,
1162
1094
  this.table
1163
1095
  );
1164
- if (nonNullPayloads.length === 0) {
1165
- return createNullResult2(this.plaintexts);
1166
- }
1167
1096
  const { metadata } = this.getAuditData();
1168
1097
  const encryptedData = await encryptBulk2(this.client, {
1169
- plaintexts: nonNullPayloads,
1098
+ plaintexts: payloads,
1170
1099
  unverifiedContext: metadata
1171
1100
  });
1172
- return mapEncryptedDataToResult(this.plaintexts, encryptedData);
1101
+ return encryptedData.map((data, i) => ({
1102
+ id: this.plaintexts[i].id,
1103
+ data
1104
+ }));
1173
1105
  },
1174
1106
  (error) => {
1175
1107
  log.set({ errorCode: getErrorCode(error) ?? "unknown" });
@@ -1226,22 +1158,22 @@ var BulkEncryptOperationWithLockContext = class extends EncryptionOperation {
1226
1158
  if (context.failure) {
1227
1159
  throw new Error(`[encryption]: ${context.failure.message}`);
1228
1160
  }
1229
- const nonNullPayloads = createEncryptPayloads(
1161
+ const payloads = createEncryptPayloads(
1230
1162
  plaintexts,
1231
1163
  column,
1232
1164
  table,
1233
1165
  context.data.context
1234
1166
  );
1235
- if (nonNullPayloads.length === 0) {
1236
- return createNullResult2(plaintexts);
1237
- }
1238
1167
  const { metadata } = this.getAuditData();
1239
1168
  const encryptedData = await encryptBulk2(client, {
1240
- plaintexts: nonNullPayloads,
1169
+ plaintexts: payloads,
1241
1170
  serviceToken: context.data.ctsToken,
1242
1171
  unverifiedContext: metadata
1243
1172
  });
1244
- return mapEncryptedDataToResult(plaintexts, encryptedData);
1173
+ return encryptedData.map((data, i) => ({
1174
+ id: plaintexts[i].id,
1175
+ data
1176
+ }));
1245
1177
  },
1246
1178
  (error) => {
1247
1179
  log.set({ errorCode: getErrorCode(error) ?? "unknown" });
@@ -1393,9 +1325,6 @@ var DecryptOperation = class extends EncryptionOperation {
1393
1325
  if (!this.client) {
1394
1326
  throw noClientError();
1395
1327
  }
1396
- if (this.encryptedData === null) {
1397
- return null;
1398
- }
1399
1328
  const { metadata } = this.getAuditData();
1400
1329
  return await ffiDecrypt(this.client, {
1401
1330
  ciphertext: this.encryptedData,
@@ -1446,9 +1375,6 @@ var DecryptOperationWithLockContext = class extends EncryptionOperation {
1446
1375
  if (!client) {
1447
1376
  throw noClientError();
1448
1377
  }
1449
- if (encryptedData === null) {
1450
- return null;
1451
- }
1452
1378
  const { metadata } = this.getAuditData();
1453
1379
  const context = await this.lockContext.getLockContext();
1454
1380
  if (context.failure) {
@@ -1604,9 +1530,6 @@ var EncryptOperation = class extends EncryptionOperation {
1604
1530
  if (!this.client) {
1605
1531
  throw noClientError();
1606
1532
  }
1607
- if (this.plaintext === null) {
1608
- return null;
1609
- }
1610
1533
  if (typeof this.plaintext === "number" && Number.isNaN(this.plaintext)) {
1611
1534
  throw new Error("[encryption]: Cannot encrypt NaN value");
1612
1535
  }
@@ -1668,9 +1591,6 @@ var EncryptOperationWithLockContext = class extends EncryptionOperation {
1668
1591
  if (!client) {
1669
1592
  throw noClientError();
1670
1593
  }
1671
- if (plaintext === null) {
1672
- return null;
1673
- }
1674
1594
  const { metadata } = this.getAuditData();
1675
1595
  const context = await this.lockContext.getLockContext();
1676
1596
  if (context.failure) {
@@ -1836,10 +1756,6 @@ var EncryptQueryOperation = class extends EncryptionOperation {
1836
1756
  queryType: this.opts.queryType,
1837
1757
  lockContext: false
1838
1758
  });
1839
- if (this.plaintext === null || this.plaintext === void 0) {
1840
- log.emit();
1841
- return { data: null };
1842
- }
1843
1759
  const validationError = validateNumericValue(this.plaintext);
1844
1760
  if (validationError?.failure) {
1845
1761
  log.emit();
@@ -1903,10 +1819,6 @@ var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
1903
1819
  queryType: this.opts.queryType,
1904
1820
  lockContext: true
1905
1821
  });
1906
- if (this.plaintext === null || this.plaintext === void 0) {
1907
- log.emit();
1908
- return { data: null };
1909
- }
1910
1822
  const validationError = validateNumericValue(this.plaintext);
1911
1823
  if (validationError?.failure) {
1912
1824
  log.emit();
@@ -2011,7 +1923,7 @@ var EncryptionClient = class {
2011
1923
  /**
2012
1924
  * Encrypt a value - returns a promise which resolves to an encrypted value.
2013
1925
  *
2014
- * @param plaintext - The plaintext value to be encrypted. Can be null.
1926
+ * @param plaintext - The plaintext value to be encrypted.
2015
1927
  * @param opts - Options specifying the column (or nested field) and table for encryption. See {@link EncryptOptions}.
2016
1928
  * @returns An EncryptOperation that can be awaited or chained with additional methods.
2017
1929
  *
@@ -2312,7 +2224,7 @@ var EncryptionClient = class {
2312
2224
  *
2313
2225
  * Each value is encrypted with its own unique key via a single call to ZeroKMS.
2314
2226
  * Values can include optional `id` fields for correlating results back to
2315
- * your application data. Null plaintext values are preserved as null.
2227
+ * your application data.
2316
2228
  *
2317
2229
  * @param plaintexts - An array of objects with `plaintext` (and optional `id`) fields.
2318
2230
  * @param opts - Options specifying the target column (or nested {@link encryptedField}) and table. See {@link EncryptOptions}.
@@ -2333,7 +2245,6 @@ var EncryptionClient = class {
2333
2245
  * [
2334
2246
  * { id: "u1", plaintext: "alice@example.com" },
2335
2247
  * { id: "u2", plaintext: "bob@example.com" },
2336
- * { id: "u3", plaintext: null },
2337
2248
  * ],
2338
2249
  * { column: users.email, table: users },
2339
2250
  * )
@@ -2423,4 +2334,4 @@ var Encryption = async (config) => {
2423
2334
  export {
2424
2335
  Encryption
2425
2336
  };
2426
- //# sourceMappingURL=chunk-MW6D52V2.js.map
2337
+ //# sourceMappingURL=chunk-WUZGKTMG.js.map