@cipherstash/stack 0.15.3 → 0.18.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 (65) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/dist/{chunk-6FD7OBGM.js → chunk-LLCCNKDL.js} +3 -3
  3. package/dist/chunk-LLCCNKDL.js.map +1 -0
  4. package/dist/{chunk-MD6742R6.js → chunk-VPOTNP4K.js} +1 -1
  5. package/dist/chunk-VPOTNP4K.js.map +1 -0
  6. package/dist/{chunk-4RNBI3UH.js → chunk-XWPGAHBZ.js} +1 -1
  7. package/dist/chunk-XWPGAHBZ.js.map +1 -0
  8. package/dist/{chunk-GNLU3I27.js → chunk-YWQXTZ5M.js} +4 -2
  9. package/dist/chunk-YWQXTZ5M.js.map +1 -0
  10. package/dist/{chunk-46S3YFRK.js → chunk-ZYOZHZMJ.js} +170 -54
  11. package/dist/chunk-ZYOZHZMJ.js.map +1 -0
  12. package/dist/{client-Dv60lAyy.d.ts → client-CIsfZ2zg.d.ts} +17 -22
  13. package/dist/{client-DQyqn0oT.d.cts → client-Dt98Rugc.d.cts} +17 -22
  14. package/dist/client.cjs +2 -0
  15. package/dist/client.cjs.map +1 -1
  16. package/dist/client.d.cts +2 -2
  17. package/dist/client.d.ts +2 -2
  18. package/dist/client.js +1 -1
  19. package/dist/drizzle/index.cjs +6 -3
  20. package/dist/drizzle/index.cjs.map +1 -1
  21. package/dist/drizzle/index.d.cts +2 -2
  22. package/dist/drizzle/index.d.ts +2 -2
  23. package/dist/drizzle/index.js +6 -5
  24. package/dist/drizzle/index.js.map +1 -1
  25. package/dist/dynamodb/index.cjs +14 -4
  26. package/dist/dynamodb/index.cjs.map +1 -1
  27. package/dist/dynamodb/index.d.cts +12 -12
  28. package/dist/dynamodb/index.d.ts +12 -12
  29. package/dist/dynamodb/index.js +9 -3
  30. package/dist/dynamodb/index.js.map +1 -1
  31. package/dist/encryption/index.cjs +178 -52
  32. package/dist/encryption/index.cjs.map +1 -1
  33. package/dist/encryption/index.d.cts +2 -2
  34. package/dist/encryption/index.d.ts +2 -2
  35. package/dist/encryption/index.js +25 -5
  36. package/dist/identity/index.cjs +2 -2
  37. package/dist/identity/index.cjs.map +1 -1
  38. package/dist/identity/index.js +3 -3
  39. package/dist/index.cjs +160 -52
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +3 -3
  42. package/dist/index.d.ts +3 -3
  43. package/dist/index.js +5 -5
  44. package/dist/schema/index.cjs +3 -1
  45. package/dist/schema/index.cjs.map +1 -1
  46. package/dist/schema/index.d.cts +1 -1
  47. package/dist/schema/index.d.ts +1 -1
  48. package/dist/schema/index.js +1 -1
  49. package/dist/supabase/index.cjs +2 -2
  50. package/dist/supabase/index.cjs.map +1 -1
  51. package/dist/supabase/index.d.cts +2 -2
  52. package/dist/supabase/index.d.ts +2 -2
  53. package/dist/supabase/index.js +3 -3
  54. package/dist/{types-public-DX3mGqoi.d.ts → types-public-BTxqjmtv.d.cts} +96 -81
  55. package/dist/{types-public-DX3mGqoi.d.cts → types-public-BTxqjmtv.d.ts} +96 -81
  56. package/dist/types-public.cjs.map +1 -1
  57. package/dist/types-public.d.cts +1 -1
  58. package/dist/types-public.d.ts +1 -1
  59. package/dist/types-public.js +1 -1
  60. package/package.json +16 -16
  61. package/dist/chunk-46S3YFRK.js.map +0 -1
  62. package/dist/chunk-4RNBI3UH.js.map +0 -1
  63. package/dist/chunk-6FD7OBGM.js.map +0 -1
  64. package/dist/chunk-GNLU3I27.js.map +0 -1
  65. package/dist/chunk-MD6742R6.js.map +0 -1
package/dist/index.cjs CHANGED
@@ -292,6 +292,8 @@ var EncryptedTable = class {
292
292
  this.tableName = tableName;
293
293
  this.columnBuilders = columnBuilders;
294
294
  }
295
+ tableName;
296
+ columnBuilders;
295
297
  /**
296
298
  * Compile this table schema into a `TableDefinition` used internally by the encryption client.
297
299
  *
@@ -368,7 +370,7 @@ function encryptedField(valueName) {
368
370
  }
369
371
  function buildEncryptConfig(...protectTables) {
370
372
  const config = {
371
- v: 2,
373
+ v: 1,
372
374
  tables: {}
373
375
  };
374
376
  for (const tb of protectTables) {
@@ -387,7 +389,7 @@ var EncryptionErrorTypes = {
387
389
  CtsTokenError: "CtsTokenError"
388
390
  };
389
391
 
390
- // ../../node_modules/.pnpm/evlog@1.9.0/node_modules/evlog/dist/utils.mjs
392
+ // ../../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/dist/utils.mjs
391
393
  function formatDuration(ms) {
392
394
  if (ms < 1e3) return `${Math.round(ms)}ms`;
393
395
  return `${(ms / 1e3).toFixed(2)}s`;
@@ -443,7 +445,7 @@ function matchesPattern(path, pattern) {
443
445
  return new RegExp(`^${regexPattern}$`).test(path);
444
446
  }
445
447
 
446
- // ../../node_modules/.pnpm/evlog@1.9.0/node_modules/evlog/dist/logger.mjs
448
+ // ../../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/dist/logger.mjs
447
449
  function isPlainObject(val) {
448
450
  return val !== null && typeof val === "object" && !Array.isArray(val);
449
451
  }
@@ -750,7 +752,15 @@ var logger = {
750
752
  // src/encryption/index.ts
751
753
  var import_result11 = require("@byteslice/result");
752
754
  var import_protect_ffi9 = require("@cipherstash/protect-ffi");
753
- var import_uuid = require("uuid");
755
+
756
+ // ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/regex.js
757
+ var regex_default = /^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$/i;
758
+
759
+ // ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/validate.js
760
+ function validate(uuid) {
761
+ return typeof uuid === "string" && regex_default.test(uuid);
762
+ }
763
+ var validate_default = validate;
754
764
 
755
765
  // src/encryption/helpers/index.ts
756
766
  function encryptedToPgComposite(obj) {
@@ -944,6 +954,15 @@ var EncryptionOperation = class {
944
954
  };
945
955
 
946
956
  // src/encryption/operations/batch-encrypt-query.ts
957
+ function filterNullTerms(terms) {
958
+ const nonNullTerms = [];
959
+ terms.forEach((term, index) => {
960
+ if (term.value !== null && term.value !== void 0) {
961
+ nonNullTerms.push({ term, originalIndex: index });
962
+ }
963
+ });
964
+ return { nonNullTerms };
965
+ }
947
966
  function buildQueryPayload(term, lockContext) {
948
967
  assertValidNumericValue(term.value);
949
968
  const { indexType, queryOp } = resolveIndexType(
@@ -964,10 +983,15 @@ function buildQueryPayload(term, lockContext) {
964
983
  }
965
984
  return payload;
966
985
  }
967
- function assembleResults(terms, encryptedValues) {
968
- return terms.map(
969
- (term, i) => formatEncryptedResult(encryptedValues[i], term.returnType)
970
- );
986
+ function assembleResults(totalLength, encryptedValues, nonNullTerms) {
987
+ const results = new Array(totalLength).fill(null);
988
+ nonNullTerms.forEach(({ term, originalIndex }, i) => {
989
+ results[originalIndex] = formatEncryptedResult(
990
+ encryptedValues[i],
991
+ term.returnType
992
+ );
993
+ });
994
+ return results;
971
995
  }
972
996
  var BatchEncryptQueryOperation = class extends EncryptionOperation {
973
997
  constructor(client, terms) {
@@ -975,6 +999,8 @@ var BatchEncryptQueryOperation = class extends EncryptionOperation {
975
999
  this.client = client;
976
1000
  this.terms = terms;
977
1001
  }
1002
+ client;
1003
+ terms;
978
1004
  withLockContext(lockContext) {
979
1005
  return new BatchEncryptQueryOperationWithLockContext(
980
1006
  this.client,
@@ -994,18 +1020,23 @@ var BatchEncryptQueryOperation = class extends EncryptionOperation {
994
1020
  log.emit();
995
1021
  return { data: [] };
996
1022
  }
1023
+ const { nonNullTerms } = filterNullTerms(this.terms);
1024
+ if (nonNullTerms.length === 0) {
1025
+ log.emit();
1026
+ return { data: this.terms.map(() => null) };
1027
+ }
997
1028
  const result = await (0, import_result.withResult)(
998
1029
  async () => {
999
1030
  if (!this.client) throw noClientError();
1000
1031
  const { metadata } = this.getAuditData();
1001
- const queries = this.terms.map(
1002
- (term) => buildQueryPayload(term)
1032
+ const queries = nonNullTerms.map(
1033
+ ({ term }) => buildQueryPayload(term)
1003
1034
  );
1004
1035
  const encrypted = await (0, import_protect_ffi2.encryptQueryBulk)(this.client, {
1005
1036
  queries,
1006
1037
  unverifiedContext: metadata
1007
1038
  });
1008
- return assembleResults(this.terms, encrypted);
1039
+ return assembleResults(this.terms.length, encrypted, nonNullTerms);
1009
1040
  },
1010
1041
  (error) => {
1011
1042
  log.set({ errorCode: getErrorCode(error) ?? "unknown" });
@@ -1028,6 +1059,9 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
1028
1059
  this.lockContext = lockContext;
1029
1060
  this.auditMetadata = auditMetadata;
1030
1061
  }
1062
+ client;
1063
+ terms;
1064
+ lockContext;
1031
1065
  async execute() {
1032
1066
  const log = createRequestLogger();
1033
1067
  log.set({
@@ -1039,6 +1073,11 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
1039
1073
  log.emit();
1040
1074
  return { data: [] };
1041
1075
  }
1076
+ const { nonNullTerms } = filterNullTerms(this.terms);
1077
+ if (nonNullTerms.length === 0) {
1078
+ log.emit();
1079
+ return { data: this.terms.map(() => null) };
1080
+ }
1042
1081
  const lockContextResult = await this.lockContext.getLockContext();
1043
1082
  if (lockContextResult.failure) {
1044
1083
  log.emit();
@@ -1049,15 +1088,15 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
1049
1088
  async () => {
1050
1089
  if (!this.client) throw noClientError();
1051
1090
  const { metadata } = this.getAuditData();
1052
- const queries = this.terms.map(
1053
- (term) => buildQueryPayload(term, context)
1091
+ const queries = nonNullTerms.map(
1092
+ ({ term }) => buildQueryPayload(term, context)
1054
1093
  );
1055
1094
  const encrypted = await (0, import_protect_ffi2.encryptQueryBulk)(this.client, {
1056
1095
  queries,
1057
1096
  serviceToken: ctsToken,
1058
1097
  unverifiedContext: metadata
1059
1098
  });
1060
- return assembleResults(this.terms, encrypted);
1099
+ return assembleResults(this.terms.length, encrypted, nonNullTerms);
1061
1100
  },
1062
1101
  (error) => {
1063
1102
  log.set({ errorCode: getErrorCode(error) ?? "unknown" });
@@ -1077,25 +1116,30 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
1077
1116
  var import_result2 = require("@byteslice/result");
1078
1117
  var import_protect_ffi3 = require("@cipherstash/protect-ffi");
1079
1118
  var createDecryptPayloads = (encryptedPayloads, lockContext) => {
1080
- return encryptedPayloads.map(({ id, data }) => ({
1119
+ return encryptedPayloads.filter(({ data }) => data !== null).map(({ id, data }) => ({
1081
1120
  id,
1082
1121
  ciphertext: data,
1083
1122
  ...lockContext && { lockContext }
1084
1123
  }));
1085
1124
  };
1125
+ var createNullResult = (encryptedPayloads) => encryptedPayloads.map(({ id }) => ({ id, data: null }));
1086
1126
  var mapDecryptedDataToResult = (encryptedPayloads, decryptedData) => {
1087
- return decryptedData.map((decryptResult, i) => {
1088
- if ("error" in decryptResult) {
1089
- return {
1090
- id: encryptedPayloads[i].id,
1091
- error: decryptResult.error
1092
- };
1127
+ const result = new Array(encryptedPayloads.length);
1128
+ let decryptedIndex = 0;
1129
+ for (let i = 0; i < encryptedPayloads.length; i++) {
1130
+ if (encryptedPayloads[i].data === null) {
1131
+ result[i] = { id: encryptedPayloads[i].id, data: null };
1132
+ } else {
1133
+ const decryptResult = decryptedData[decryptedIndex];
1134
+ if ("error" in decryptResult) {
1135
+ result[i] = { id: encryptedPayloads[i].id, error: decryptResult.error };
1136
+ } else {
1137
+ result[i] = { id: encryptedPayloads[i].id, data: decryptResult.data };
1138
+ }
1139
+ decryptedIndex++;
1093
1140
  }
1094
- return {
1095
- id: encryptedPayloads[i].id,
1096
- data: decryptResult.data
1097
- };
1098
- });
1141
+ }
1142
+ return result;
1099
1143
  };
1100
1144
  var BulkDecryptOperation = class extends EncryptionOperation {
1101
1145
  client;
@@ -1120,10 +1164,13 @@ var BulkDecryptOperation = class extends EncryptionOperation {
1120
1164
  if (!this.client) throw noClientError();
1121
1165
  if (!this.encryptedPayloads || this.encryptedPayloads.length === 0)
1122
1166
  return [];
1123
- const payloads = createDecryptPayloads(this.encryptedPayloads);
1167
+ const nonNullPayloads = createDecryptPayloads(this.encryptedPayloads);
1168
+ if (nonNullPayloads.length === 0) {
1169
+ return createNullResult(this.encryptedPayloads);
1170
+ }
1124
1171
  const { metadata } = this.getAuditData();
1125
1172
  const decryptedData = await (0, import_protect_ffi3.decryptBulkFallible)(this.client, {
1126
- ciphertexts: payloads,
1173
+ ciphertexts: nonNullPayloads,
1127
1174
  unverifiedContext: metadata
1128
1175
  });
1129
1176
  return mapDecryptedDataToResult(this.encryptedPayloads, decryptedData);
@@ -1175,13 +1222,16 @@ var BulkDecryptOperationWithLockContext = class extends EncryptionOperation {
1175
1222
  if (context.failure) {
1176
1223
  throw new Error(`[encryption]: ${context.failure.message}`);
1177
1224
  }
1178
- const payloads = createDecryptPayloads(
1225
+ const nonNullPayloads = createDecryptPayloads(
1179
1226
  encryptedPayloads,
1180
1227
  context.data.context
1181
1228
  );
1229
+ if (nonNullPayloads.length === 0) {
1230
+ return createNullResult(encryptedPayloads);
1231
+ }
1182
1232
  const { metadata } = this.getAuditData();
1183
1233
  const decryptedData = await (0, import_protect_ffi3.decryptBulkFallible)(client, {
1184
- ciphertexts: payloads,
1234
+ ciphertexts: nonNullPayloads,
1185
1235
  serviceToken: context.data.ctsToken,
1186
1236
  unverifiedContext: metadata
1187
1237
  });
@@ -1820,7 +1870,7 @@ var BulkDecryptModelsOperationWithLockContext = class extends EncryptionOperatio
1820
1870
  var import_result4 = require("@byteslice/result");
1821
1871
  var import_protect_ffi5 = require("@cipherstash/protect-ffi");
1822
1872
  var createEncryptPayloads = (plaintexts, column, table, lockContext) => {
1823
- return plaintexts.map(({ id, plaintext }) => ({
1873
+ return plaintexts.filter(({ plaintext }) => plaintext !== null).map(({ id, plaintext }) => ({
1824
1874
  id,
1825
1875
  plaintext,
1826
1876
  column: column.getName(),
@@ -1828,6 +1878,20 @@ var createEncryptPayloads = (plaintexts, column, table, lockContext) => {
1828
1878
  ...lockContext && { lockContext }
1829
1879
  }));
1830
1880
  };
1881
+ var createNullResult2 = (plaintexts) => plaintexts.map(({ id }) => ({ id, data: null }));
1882
+ var mapEncryptedDataToResult = (plaintexts, encryptedData) => {
1883
+ const result = new Array(plaintexts.length);
1884
+ let encryptedIndex = 0;
1885
+ for (let i = 0; i < plaintexts.length; i++) {
1886
+ if (plaintexts[i].plaintext === null) {
1887
+ result[i] = { id: plaintexts[i].id, data: null };
1888
+ } else {
1889
+ result[i] = { id: plaintexts[i].id, data: encryptedData[encryptedIndex] };
1890
+ encryptedIndex++;
1891
+ }
1892
+ }
1893
+ return result;
1894
+ };
1831
1895
  var BulkEncryptOperation = class extends EncryptionOperation {
1832
1896
  client;
1833
1897
  plaintexts;
@@ -1860,20 +1924,20 @@ var BulkEncryptOperation = class extends EncryptionOperation {
1860
1924
  if (!this.plaintexts || this.plaintexts.length === 0) {
1861
1925
  return [];
1862
1926
  }
1863
- const payloads = createEncryptPayloads(
1927
+ const nonNullPayloads = createEncryptPayloads(
1864
1928
  this.plaintexts,
1865
1929
  this.column,
1866
1930
  this.table
1867
1931
  );
1932
+ if (nonNullPayloads.length === 0) {
1933
+ return createNullResult2(this.plaintexts);
1934
+ }
1868
1935
  const { metadata } = this.getAuditData();
1869
1936
  const encryptedData = await (0, import_protect_ffi5.encryptBulk)(this.client, {
1870
- plaintexts: payloads,
1937
+ plaintexts: nonNullPayloads,
1871
1938
  unverifiedContext: metadata
1872
1939
  });
1873
- return encryptedData.map((data, i) => ({
1874
- id: this.plaintexts[i].id,
1875
- data
1876
- }));
1940
+ return mapEncryptedDataToResult(this.plaintexts, encryptedData);
1877
1941
  },
1878
1942
  (error) => {
1879
1943
  log.set({ errorCode: getErrorCode(error) ?? "unknown" });
@@ -1930,22 +1994,22 @@ var BulkEncryptOperationWithLockContext = class extends EncryptionOperation {
1930
1994
  if (context.failure) {
1931
1995
  throw new Error(`[encryption]: ${context.failure.message}`);
1932
1996
  }
1933
- const payloads = createEncryptPayloads(
1997
+ const nonNullPayloads = createEncryptPayloads(
1934
1998
  plaintexts,
1935
1999
  column,
1936
2000
  table,
1937
2001
  context.data.context
1938
2002
  );
2003
+ if (nonNullPayloads.length === 0) {
2004
+ return createNullResult2(plaintexts);
2005
+ }
1939
2006
  const { metadata } = this.getAuditData();
1940
2007
  const encryptedData = await (0, import_protect_ffi5.encryptBulk)(client, {
1941
- plaintexts: payloads,
2008
+ plaintexts: nonNullPayloads,
1942
2009
  serviceToken: context.data.ctsToken,
1943
2010
  unverifiedContext: metadata
1944
2011
  });
1945
- return encryptedData.map((data, i) => ({
1946
- id: plaintexts[i].id,
1947
- data
1948
- }));
2012
+ return mapEncryptedDataToResult(plaintexts, encryptedData);
1949
2013
  },
1950
2014
  (error) => {
1951
2015
  log.set({ errorCode: getErrorCode(error) ?? "unknown" });
@@ -2075,6 +2139,10 @@ var import_result6 = require("@byteslice/result");
2075
2139
  var import_protect_ffi6 = require("@cipherstash/protect-ffi");
2076
2140
  var DecryptOperation = class extends EncryptionOperation {
2077
2141
  client;
2142
+ // Internally widened to allow null so the runtime guard below can
2143
+ // short-circuit on legacy / manually-NULLed rows. The public
2144
+ // `Encryption.decrypt()` signature still rejects null at the type
2145
+ // layer; this is defense in depth for direct construction.
2078
2146
  encryptedData;
2079
2147
  constructor(client, encryptedData) {
2080
2148
  super();
@@ -2095,6 +2163,9 @@ var DecryptOperation = class extends EncryptionOperation {
2095
2163
  if (!this.client) {
2096
2164
  throw noClientError();
2097
2165
  }
2166
+ if (this.encryptedData === null) {
2167
+ return null;
2168
+ }
2098
2169
  const { metadata } = this.getAuditData();
2099
2170
  return await (0, import_protect_ffi6.decrypt)(this.client, {
2100
2171
  ciphertext: this.encryptedData,
@@ -2145,6 +2216,9 @@ var DecryptOperationWithLockContext = class extends EncryptionOperation {
2145
2216
  if (!client) {
2146
2217
  throw noClientError();
2147
2218
  }
2219
+ if (encryptedData === null) {
2220
+ return null;
2221
+ }
2148
2222
  const { metadata } = this.getAuditData();
2149
2223
  const context = await this.lockContext.getLockContext();
2150
2224
  if (context.failure) {
@@ -2272,6 +2346,10 @@ var import_result8 = require("@byteslice/result");
2272
2346
  var import_protect_ffi7 = require("@cipherstash/protect-ffi");
2273
2347
  var EncryptOperation = class extends EncryptionOperation {
2274
2348
  client;
2349
+ // Internally widened to allow null so the runtime guard below can
2350
+ // short-circuit. The public `Encryption.encrypt()` signature still
2351
+ // rejects null at the type layer; this is defense in depth for callers
2352
+ // that reach this class through casts or dynamic field walking.
2275
2353
  plaintext;
2276
2354
  column;
2277
2355
  table;
@@ -2298,6 +2376,9 @@ var EncryptOperation = class extends EncryptionOperation {
2298
2376
  if (!this.client) {
2299
2377
  throw noClientError();
2300
2378
  }
2379
+ if (this.plaintext === null) {
2380
+ return null;
2381
+ }
2301
2382
  if (typeof this.plaintext === "number" && Number.isNaN(this.plaintext)) {
2302
2383
  throw new Error("[encryption]: Cannot encrypt NaN value");
2303
2384
  }
@@ -2359,6 +2440,9 @@ var EncryptOperationWithLockContext = class extends EncryptionOperation {
2359
2440
  if (!client) {
2360
2441
  throw noClientError();
2361
2442
  }
2443
+ if (plaintext === null) {
2444
+ return null;
2445
+ }
2362
2446
  const { metadata } = this.getAuditData();
2363
2447
  const context = await this.lockContext.getLockContext();
2364
2448
  if (context.failure) {
@@ -2504,6 +2588,9 @@ var EncryptQueryOperation = class extends EncryptionOperation {
2504
2588
  this.plaintext = plaintext;
2505
2589
  this.opts = opts;
2506
2590
  }
2591
+ client;
2592
+ plaintext;
2593
+ opts;
2507
2594
  withLockContext(lockContext) {
2508
2595
  return new EncryptQueryOperationWithLockContext(
2509
2596
  this.client,
@@ -2522,7 +2609,12 @@ var EncryptQueryOperation = class extends EncryptionOperation {
2522
2609
  queryType: this.opts.queryType,
2523
2610
  lockContext: false
2524
2611
  });
2525
- const validationError = validateNumericValue(this.plaintext);
2612
+ if (this.plaintext === null || this.plaintext === void 0) {
2613
+ log.emit();
2614
+ return { data: null };
2615
+ }
2616
+ const plaintext = this.plaintext;
2617
+ const validationError = validateNumericValue(plaintext);
2526
2618
  if (validationError?.failure) {
2527
2619
  log.emit();
2528
2620
  return { failure: validationError.failure };
@@ -2534,15 +2626,15 @@ var EncryptQueryOperation = class extends EncryptionOperation {
2534
2626
  const { indexType, queryOp } = resolveIndexType(
2535
2627
  this.opts.column,
2536
2628
  this.opts.queryType,
2537
- this.plaintext
2629
+ plaintext
2538
2630
  );
2539
2631
  assertValueIndexCompatibility(
2540
- this.plaintext,
2632
+ plaintext,
2541
2633
  indexType,
2542
2634
  this.opts.column.getName()
2543
2635
  );
2544
2636
  const encrypted = await (0, import_protect_ffi8.encryptQuery)(this.client, {
2545
- plaintext: this.plaintext,
2637
+ plaintext,
2546
2638
  column: this.opts.column.getName(),
2547
2639
  table: this.opts.table.tableName,
2548
2640
  indexType,
@@ -2576,6 +2668,10 @@ var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
2576
2668
  this.lockContext = lockContext;
2577
2669
  this.auditMetadata = auditMetadata;
2578
2670
  }
2671
+ client;
2672
+ plaintext;
2673
+ opts;
2674
+ lockContext;
2579
2675
  async execute() {
2580
2676
  const log = createRequestLogger();
2581
2677
  log.set({
@@ -2585,7 +2681,12 @@ var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
2585
2681
  queryType: this.opts.queryType,
2586
2682
  lockContext: true
2587
2683
  });
2588
- const validationError = validateNumericValue(this.plaintext);
2684
+ if (this.plaintext === null || this.plaintext === void 0) {
2685
+ log.emit();
2686
+ return { data: null };
2687
+ }
2688
+ const plaintext = this.plaintext;
2689
+ const validationError = validateNumericValue(plaintext);
2589
2690
  if (validationError?.failure) {
2590
2691
  log.emit();
2591
2692
  return { failure: validationError.failure };
@@ -2603,15 +2704,15 @@ var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
2603
2704
  const { indexType, queryOp } = resolveIndexType(
2604
2705
  this.opts.column,
2605
2706
  this.opts.queryType,
2606
- this.plaintext
2707
+ plaintext
2607
2708
  );
2608
2709
  assertValueIndexCompatibility(
2609
- this.plaintext,
2710
+ plaintext,
2610
2711
  indexType,
2611
2712
  this.opts.column.getName()
2612
2713
  );
2613
2714
  const encrypted = await (0, import_protect_ffi8.encryptQuery)(this.client, {
2614
- plaintext: this.plaintext,
2715
+ plaintext,
2615
2716
  column: this.opts.column.getName(),
2616
2717
  table: this.opts.table.tableName,
2617
2718
  indexType,
@@ -2807,6 +2908,13 @@ var EncryptionClient = class {
2807
2908
  * .withLockContext(lockContext)
2808
2909
  * ```
2809
2910
  *
2911
+ * @remarks
2912
+ * The public input type rejects null, but at runtime `decrypt` will
2913
+ * short-circuit and return null when given a null ciphertext
2914
+ * (defense in depth for legacy / manually-NULLed DB rows reached via
2915
+ * casts or dynamic field walking). The narrow return type holds for
2916
+ * any caller that respects the input contract.
2917
+ *
2810
2918
  * @see {@link LockContext}
2811
2919
  * @see {@link DecryptOperation}
2812
2920
  */
@@ -3068,7 +3176,7 @@ var Encryption = async (config) => {
3068
3176
  "[encryption]: At least one encryptedTable must be provided to initialize the encryption client"
3069
3177
  );
3070
3178
  }
3071
- if (clientConfig?.keyset && "id" in clientConfig.keyset && !(0, import_uuid.validate)(clientConfig.keyset.id)) {
3179
+ if (clientConfig?.keyset && "id" in clientConfig.keyset && !validate_default(clientConfig.keyset.id)) {
3072
3180
  throw new Error(
3073
3181
  "[encryption]: Invalid UUID provided for keyset id. Must be a valid UUID."
3074
3182
  );