@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
@@ -20,6 +20,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/encryption/index.ts
21
21
  var encryption_exports = {};
22
22
  __export(encryption_exports, {
23
+ BatchEncryptQueryOperation: () => BatchEncryptQueryOperation,
24
+ BulkDecryptModelsOperation: () => BulkDecryptModelsOperation,
25
+ BulkDecryptOperation: () => BulkDecryptOperation,
26
+ BulkEncryptModelsOperation: () => BulkEncryptModelsOperation,
27
+ BulkEncryptOperation: () => BulkEncryptOperation,
28
+ DecryptModelOperation: () => DecryptModelOperation,
29
+ DecryptOperation: () => DecryptOperation,
30
+ EncryptModelOperation: () => EncryptModelOperation,
31
+ EncryptOperation: () => EncryptOperation,
32
+ EncryptQueryOperation: () => EncryptQueryOperation,
23
33
  Encryption: () => Encryption,
24
34
  EncryptionClient: () => EncryptionClient,
25
35
  noClientError: () => noClientError
@@ -103,7 +113,7 @@ var encryptConfigSchema = import_zod.z.object({
103
113
  });
104
114
  function buildEncryptConfig(...protectTables) {
105
115
  const config = {
106
- v: 2,
116
+ v: 1,
107
117
  tables: {}
108
118
  };
109
119
  for (const tb of protectTables) {
@@ -113,7 +123,7 @@ function buildEncryptConfig(...protectTables) {
113
123
  return config;
114
124
  }
115
125
 
116
- // ../../node_modules/.pnpm/evlog@1.9.0/node_modules/evlog/dist/utils.mjs
126
+ // ../../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
117
127
  function formatDuration(ms) {
118
128
  if (ms < 1e3) return `${Math.round(ms)}ms`;
119
129
  return `${(ms / 1e3).toFixed(2)}s`;
@@ -169,7 +179,7 @@ function matchesPattern(path, pattern) {
169
179
  return new RegExp(`^${regexPattern}$`).test(path);
170
180
  }
171
181
 
172
- // ../../node_modules/.pnpm/evlog@1.9.0/node_modules/evlog/dist/logger.mjs
182
+ // ../../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
173
183
  function isPlainObject(val) {
174
184
  return val !== null && typeof val === "object" && !Array.isArray(val);
175
185
  }
@@ -476,7 +486,15 @@ var logger = {
476
486
  // src/encryption/index.ts
477
487
  var import_result11 = require("@byteslice/result");
478
488
  var import_protect_ffi9 = require("@cipherstash/protect-ffi");
479
- var import_uuid = require("uuid");
489
+
490
+ // ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/regex.js
491
+ 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;
492
+
493
+ // ../../node_modules/.pnpm/uuid@14.0.0/node_modules/uuid/dist-node/validate.js
494
+ function validate(uuid) {
495
+ return typeof uuid === "string" && regex_default.test(uuid);
496
+ }
497
+ var validate_default = validate;
480
498
 
481
499
  // src/encryption/helpers/index.ts
482
500
  function encryptedToCompositeLiteral(obj) {
@@ -665,6 +683,15 @@ var EncryptionOperation = class {
665
683
  };
666
684
 
667
685
  // src/encryption/operations/batch-encrypt-query.ts
686
+ function filterNullTerms(terms) {
687
+ const nonNullTerms = [];
688
+ terms.forEach((term, index) => {
689
+ if (term.value !== null && term.value !== void 0) {
690
+ nonNullTerms.push({ term, originalIndex: index });
691
+ }
692
+ });
693
+ return { nonNullTerms };
694
+ }
668
695
  function buildQueryPayload(term, lockContext) {
669
696
  assertValidNumericValue(term.value);
670
697
  const { indexType, queryOp } = resolveIndexType(
@@ -685,10 +712,15 @@ function buildQueryPayload(term, lockContext) {
685
712
  }
686
713
  return payload;
687
714
  }
688
- function assembleResults(terms, encryptedValues) {
689
- return terms.map(
690
- (term, i) => formatEncryptedResult(encryptedValues[i], term.returnType)
691
- );
715
+ function assembleResults(totalLength, encryptedValues, nonNullTerms) {
716
+ const results = new Array(totalLength).fill(null);
717
+ nonNullTerms.forEach(({ term, originalIndex }, i) => {
718
+ results[originalIndex] = formatEncryptedResult(
719
+ encryptedValues[i],
720
+ term.returnType
721
+ );
722
+ });
723
+ return results;
692
724
  }
693
725
  var BatchEncryptQueryOperation = class extends EncryptionOperation {
694
726
  constructor(client, terms) {
@@ -696,6 +728,8 @@ var BatchEncryptQueryOperation = class extends EncryptionOperation {
696
728
  this.client = client;
697
729
  this.terms = terms;
698
730
  }
731
+ client;
732
+ terms;
699
733
  withLockContext(lockContext) {
700
734
  return new BatchEncryptQueryOperationWithLockContext(
701
735
  this.client,
@@ -715,18 +749,23 @@ var BatchEncryptQueryOperation = class extends EncryptionOperation {
715
749
  log.emit();
716
750
  return { data: [] };
717
751
  }
752
+ const { nonNullTerms } = filterNullTerms(this.terms);
753
+ if (nonNullTerms.length === 0) {
754
+ log.emit();
755
+ return { data: this.terms.map(() => null) };
756
+ }
718
757
  const result = await (0, import_result.withResult)(
719
758
  async () => {
720
759
  if (!this.client) throw noClientError();
721
760
  const { metadata } = this.getAuditData();
722
- const queries = this.terms.map(
723
- (term) => buildQueryPayload(term)
761
+ const queries = nonNullTerms.map(
762
+ ({ term }) => buildQueryPayload(term)
724
763
  );
725
764
  const encrypted = await (0, import_protect_ffi2.encryptQueryBulk)(this.client, {
726
765
  queries,
727
766
  unverifiedContext: metadata
728
767
  });
729
- return assembleResults(this.terms, encrypted);
768
+ return assembleResults(this.terms.length, encrypted, nonNullTerms);
730
769
  },
731
770
  (error) => {
732
771
  log.set({ errorCode: getErrorCode(error) ?? "unknown" });
@@ -749,6 +788,9 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
749
788
  this.lockContext = lockContext;
750
789
  this.auditMetadata = auditMetadata;
751
790
  }
791
+ client;
792
+ terms;
793
+ lockContext;
752
794
  async execute() {
753
795
  const log = createRequestLogger();
754
796
  log.set({
@@ -760,6 +802,11 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
760
802
  log.emit();
761
803
  return { data: [] };
762
804
  }
805
+ const { nonNullTerms } = filterNullTerms(this.terms);
806
+ if (nonNullTerms.length === 0) {
807
+ log.emit();
808
+ return { data: this.terms.map(() => null) };
809
+ }
763
810
  const lockContextResult = await this.lockContext.getLockContext();
764
811
  if (lockContextResult.failure) {
765
812
  log.emit();
@@ -770,15 +817,15 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
770
817
  async () => {
771
818
  if (!this.client) throw noClientError();
772
819
  const { metadata } = this.getAuditData();
773
- const queries = this.terms.map(
774
- (term) => buildQueryPayload(term, context)
820
+ const queries = nonNullTerms.map(
821
+ ({ term }) => buildQueryPayload(term, context)
775
822
  );
776
823
  const encrypted = await (0, import_protect_ffi2.encryptQueryBulk)(this.client, {
777
824
  queries,
778
825
  serviceToken: ctsToken,
779
826
  unverifiedContext: metadata
780
827
  });
781
- return assembleResults(this.terms, encrypted);
828
+ return assembleResults(this.terms.length, encrypted, nonNullTerms);
782
829
  },
783
830
  (error) => {
784
831
  log.set({ errorCode: getErrorCode(error) ?? "unknown" });
@@ -798,25 +845,30 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
798
845
  var import_result2 = require("@byteslice/result");
799
846
  var import_protect_ffi3 = require("@cipherstash/protect-ffi");
800
847
  var createDecryptPayloads = (encryptedPayloads, lockContext) => {
801
- return encryptedPayloads.map(({ id, data }) => ({
848
+ return encryptedPayloads.filter(({ data }) => data !== null).map(({ id, data }) => ({
802
849
  id,
803
850
  ciphertext: data,
804
851
  ...lockContext && { lockContext }
805
852
  }));
806
853
  };
854
+ var createNullResult = (encryptedPayloads) => encryptedPayloads.map(({ id }) => ({ id, data: null }));
807
855
  var mapDecryptedDataToResult = (encryptedPayloads, decryptedData) => {
808
- return decryptedData.map((decryptResult, i) => {
809
- if ("error" in decryptResult) {
810
- return {
811
- id: encryptedPayloads[i].id,
812
- error: decryptResult.error
813
- };
856
+ const result = new Array(encryptedPayloads.length);
857
+ let decryptedIndex = 0;
858
+ for (let i = 0; i < encryptedPayloads.length; i++) {
859
+ if (encryptedPayloads[i].data === null) {
860
+ result[i] = { id: encryptedPayloads[i].id, data: null };
861
+ } else {
862
+ const decryptResult = decryptedData[decryptedIndex];
863
+ if ("error" in decryptResult) {
864
+ result[i] = { id: encryptedPayloads[i].id, error: decryptResult.error };
865
+ } else {
866
+ result[i] = { id: encryptedPayloads[i].id, data: decryptResult.data };
867
+ }
868
+ decryptedIndex++;
814
869
  }
815
- return {
816
- id: encryptedPayloads[i].id,
817
- data: decryptResult.data
818
- };
819
- });
870
+ }
871
+ return result;
820
872
  };
821
873
  var BulkDecryptOperation = class extends EncryptionOperation {
822
874
  client;
@@ -841,10 +893,13 @@ var BulkDecryptOperation = class extends EncryptionOperation {
841
893
  if (!this.client) throw noClientError();
842
894
  if (!this.encryptedPayloads || this.encryptedPayloads.length === 0)
843
895
  return [];
844
- const payloads = createDecryptPayloads(this.encryptedPayloads);
896
+ const nonNullPayloads = createDecryptPayloads(this.encryptedPayloads);
897
+ if (nonNullPayloads.length === 0) {
898
+ return createNullResult(this.encryptedPayloads);
899
+ }
845
900
  const { metadata } = this.getAuditData();
846
901
  const decryptedData = await (0, import_protect_ffi3.decryptBulkFallible)(this.client, {
847
- ciphertexts: payloads,
902
+ ciphertexts: nonNullPayloads,
848
903
  unverifiedContext: metadata
849
904
  });
850
905
  return mapDecryptedDataToResult(this.encryptedPayloads, decryptedData);
@@ -896,13 +951,16 @@ var BulkDecryptOperationWithLockContext = class extends EncryptionOperation {
896
951
  if (context.failure) {
897
952
  throw new Error(`[encryption]: ${context.failure.message}`);
898
953
  }
899
- const payloads = createDecryptPayloads(
954
+ const nonNullPayloads = createDecryptPayloads(
900
955
  encryptedPayloads,
901
956
  context.data.context
902
957
  );
958
+ if (nonNullPayloads.length === 0) {
959
+ return createNullResult(encryptedPayloads);
960
+ }
903
961
  const { metadata } = this.getAuditData();
904
962
  const decryptedData = await (0, import_protect_ffi3.decryptBulkFallible)(client, {
905
- ciphertexts: payloads,
963
+ ciphertexts: nonNullPayloads,
906
964
  serviceToken: context.data.ctsToken,
907
965
  unverifiedContext: metadata
908
966
  });
@@ -1541,7 +1599,7 @@ var BulkDecryptModelsOperationWithLockContext = class extends EncryptionOperatio
1541
1599
  var import_result4 = require("@byteslice/result");
1542
1600
  var import_protect_ffi5 = require("@cipherstash/protect-ffi");
1543
1601
  var createEncryptPayloads = (plaintexts, column, table, lockContext) => {
1544
- return plaintexts.map(({ id, plaintext }) => ({
1602
+ return plaintexts.filter(({ plaintext }) => plaintext !== null).map(({ id, plaintext }) => ({
1545
1603
  id,
1546
1604
  plaintext,
1547
1605
  column: column.getName(),
@@ -1549,6 +1607,20 @@ var createEncryptPayloads = (plaintexts, column, table, lockContext) => {
1549
1607
  ...lockContext && { lockContext }
1550
1608
  }));
1551
1609
  };
1610
+ var createNullResult2 = (plaintexts) => plaintexts.map(({ id }) => ({ id, data: null }));
1611
+ var mapEncryptedDataToResult = (plaintexts, encryptedData) => {
1612
+ const result = new Array(plaintexts.length);
1613
+ let encryptedIndex = 0;
1614
+ for (let i = 0; i < plaintexts.length; i++) {
1615
+ if (plaintexts[i].plaintext === null) {
1616
+ result[i] = { id: plaintexts[i].id, data: null };
1617
+ } else {
1618
+ result[i] = { id: plaintexts[i].id, data: encryptedData[encryptedIndex] };
1619
+ encryptedIndex++;
1620
+ }
1621
+ }
1622
+ return result;
1623
+ };
1552
1624
  var BulkEncryptOperation = class extends EncryptionOperation {
1553
1625
  client;
1554
1626
  plaintexts;
@@ -1581,20 +1653,20 @@ var BulkEncryptOperation = class extends EncryptionOperation {
1581
1653
  if (!this.plaintexts || this.plaintexts.length === 0) {
1582
1654
  return [];
1583
1655
  }
1584
- const payloads = createEncryptPayloads(
1656
+ const nonNullPayloads = createEncryptPayloads(
1585
1657
  this.plaintexts,
1586
1658
  this.column,
1587
1659
  this.table
1588
1660
  );
1661
+ if (nonNullPayloads.length === 0) {
1662
+ return createNullResult2(this.plaintexts);
1663
+ }
1589
1664
  const { metadata } = this.getAuditData();
1590
1665
  const encryptedData = await (0, import_protect_ffi5.encryptBulk)(this.client, {
1591
- plaintexts: payloads,
1666
+ plaintexts: nonNullPayloads,
1592
1667
  unverifiedContext: metadata
1593
1668
  });
1594
- return encryptedData.map((data, i) => ({
1595
- id: this.plaintexts[i].id,
1596
- data
1597
- }));
1669
+ return mapEncryptedDataToResult(this.plaintexts, encryptedData);
1598
1670
  },
1599
1671
  (error) => {
1600
1672
  log.set({ errorCode: getErrorCode(error) ?? "unknown" });
@@ -1651,22 +1723,22 @@ var BulkEncryptOperationWithLockContext = class extends EncryptionOperation {
1651
1723
  if (context.failure) {
1652
1724
  throw new Error(`[encryption]: ${context.failure.message}`);
1653
1725
  }
1654
- const payloads = createEncryptPayloads(
1726
+ const nonNullPayloads = createEncryptPayloads(
1655
1727
  plaintexts,
1656
1728
  column,
1657
1729
  table,
1658
1730
  context.data.context
1659
1731
  );
1732
+ if (nonNullPayloads.length === 0) {
1733
+ return createNullResult2(plaintexts);
1734
+ }
1660
1735
  const { metadata } = this.getAuditData();
1661
1736
  const encryptedData = await (0, import_protect_ffi5.encryptBulk)(client, {
1662
- plaintexts: payloads,
1737
+ plaintexts: nonNullPayloads,
1663
1738
  serviceToken: context.data.ctsToken,
1664
1739
  unverifiedContext: metadata
1665
1740
  });
1666
- return encryptedData.map((data, i) => ({
1667
- id: plaintexts[i].id,
1668
- data
1669
- }));
1741
+ return mapEncryptedDataToResult(plaintexts, encryptedData);
1670
1742
  },
1671
1743
  (error) => {
1672
1744
  log.set({ errorCode: getErrorCode(error) ?? "unknown" });
@@ -1796,6 +1868,10 @@ var import_result6 = require("@byteslice/result");
1796
1868
  var import_protect_ffi6 = require("@cipherstash/protect-ffi");
1797
1869
  var DecryptOperation = class extends EncryptionOperation {
1798
1870
  client;
1871
+ // Internally widened to allow null so the runtime guard below can
1872
+ // short-circuit on legacy / manually-NULLed rows. The public
1873
+ // `Encryption.decrypt()` signature still rejects null at the type
1874
+ // layer; this is defense in depth for direct construction.
1799
1875
  encryptedData;
1800
1876
  constructor(client, encryptedData) {
1801
1877
  super();
@@ -1816,6 +1892,9 @@ var DecryptOperation = class extends EncryptionOperation {
1816
1892
  if (!this.client) {
1817
1893
  throw noClientError();
1818
1894
  }
1895
+ if (this.encryptedData === null) {
1896
+ return null;
1897
+ }
1819
1898
  const { metadata } = this.getAuditData();
1820
1899
  return await (0, import_protect_ffi6.decrypt)(this.client, {
1821
1900
  ciphertext: this.encryptedData,
@@ -1866,6 +1945,9 @@ var DecryptOperationWithLockContext = class extends EncryptionOperation {
1866
1945
  if (!client) {
1867
1946
  throw noClientError();
1868
1947
  }
1948
+ if (encryptedData === null) {
1949
+ return null;
1950
+ }
1869
1951
  const { metadata } = this.getAuditData();
1870
1952
  const context = await this.lockContext.getLockContext();
1871
1953
  if (context.failure) {
@@ -1993,6 +2075,10 @@ var import_result8 = require("@byteslice/result");
1993
2075
  var import_protect_ffi7 = require("@cipherstash/protect-ffi");
1994
2076
  var EncryptOperation = class extends EncryptionOperation {
1995
2077
  client;
2078
+ // Internally widened to allow null so the runtime guard below can
2079
+ // short-circuit. The public `Encryption.encrypt()` signature still
2080
+ // rejects null at the type layer; this is defense in depth for callers
2081
+ // that reach this class through casts or dynamic field walking.
1996
2082
  plaintext;
1997
2083
  column;
1998
2084
  table;
@@ -2019,6 +2105,9 @@ var EncryptOperation = class extends EncryptionOperation {
2019
2105
  if (!this.client) {
2020
2106
  throw noClientError();
2021
2107
  }
2108
+ if (this.plaintext === null) {
2109
+ return null;
2110
+ }
2022
2111
  if (typeof this.plaintext === "number" && Number.isNaN(this.plaintext)) {
2023
2112
  throw new Error("[encryption]: Cannot encrypt NaN value");
2024
2113
  }
@@ -2080,6 +2169,9 @@ var EncryptOperationWithLockContext = class extends EncryptionOperation {
2080
2169
  if (!client) {
2081
2170
  throw noClientError();
2082
2171
  }
2172
+ if (plaintext === null) {
2173
+ return null;
2174
+ }
2083
2175
  const { metadata } = this.getAuditData();
2084
2176
  const context = await this.lockContext.getLockContext();
2085
2177
  if (context.failure) {
@@ -2225,6 +2317,9 @@ var EncryptQueryOperation = class extends EncryptionOperation {
2225
2317
  this.plaintext = plaintext;
2226
2318
  this.opts = opts;
2227
2319
  }
2320
+ client;
2321
+ plaintext;
2322
+ opts;
2228
2323
  withLockContext(lockContext) {
2229
2324
  return new EncryptQueryOperationWithLockContext(
2230
2325
  this.client,
@@ -2243,7 +2338,12 @@ var EncryptQueryOperation = class extends EncryptionOperation {
2243
2338
  queryType: this.opts.queryType,
2244
2339
  lockContext: false
2245
2340
  });
2246
- const validationError = validateNumericValue(this.plaintext);
2341
+ if (this.plaintext === null || this.plaintext === void 0) {
2342
+ log.emit();
2343
+ return { data: null };
2344
+ }
2345
+ const plaintext = this.plaintext;
2346
+ const validationError = validateNumericValue(plaintext);
2247
2347
  if (validationError?.failure) {
2248
2348
  log.emit();
2249
2349
  return { failure: validationError.failure };
@@ -2255,15 +2355,15 @@ var EncryptQueryOperation = class extends EncryptionOperation {
2255
2355
  const { indexType, queryOp } = resolveIndexType(
2256
2356
  this.opts.column,
2257
2357
  this.opts.queryType,
2258
- this.plaintext
2358
+ plaintext
2259
2359
  );
2260
2360
  assertValueIndexCompatibility(
2261
- this.plaintext,
2361
+ plaintext,
2262
2362
  indexType,
2263
2363
  this.opts.column.getName()
2264
2364
  );
2265
2365
  const encrypted = await (0, import_protect_ffi8.encryptQuery)(this.client, {
2266
- plaintext: this.plaintext,
2366
+ plaintext,
2267
2367
  column: this.opts.column.getName(),
2268
2368
  table: this.opts.table.tableName,
2269
2369
  indexType,
@@ -2297,6 +2397,10 @@ var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
2297
2397
  this.lockContext = lockContext;
2298
2398
  this.auditMetadata = auditMetadata;
2299
2399
  }
2400
+ client;
2401
+ plaintext;
2402
+ opts;
2403
+ lockContext;
2300
2404
  async execute() {
2301
2405
  const log = createRequestLogger();
2302
2406
  log.set({
@@ -2306,7 +2410,12 @@ var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
2306
2410
  queryType: this.opts.queryType,
2307
2411
  lockContext: true
2308
2412
  });
2309
- const validationError = validateNumericValue(this.plaintext);
2413
+ if (this.plaintext === null || this.plaintext === void 0) {
2414
+ log.emit();
2415
+ return { data: null };
2416
+ }
2417
+ const plaintext = this.plaintext;
2418
+ const validationError = validateNumericValue(plaintext);
2310
2419
  if (validationError?.failure) {
2311
2420
  log.emit();
2312
2421
  return { failure: validationError.failure };
@@ -2324,15 +2433,15 @@ var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
2324
2433
  const { indexType, queryOp } = resolveIndexType(
2325
2434
  this.opts.column,
2326
2435
  this.opts.queryType,
2327
- this.plaintext
2436
+ plaintext
2328
2437
  );
2329
2438
  assertValueIndexCompatibility(
2330
- this.plaintext,
2439
+ plaintext,
2331
2440
  indexType,
2332
2441
  this.opts.column.getName()
2333
2442
  );
2334
2443
  const encrypted = await (0, import_protect_ffi8.encryptQuery)(this.client, {
2335
- plaintext: this.plaintext,
2444
+ plaintext,
2336
2445
  column: this.opts.column.getName(),
2337
2446
  table: this.opts.table.tableName,
2338
2447
  indexType,
@@ -2528,6 +2637,13 @@ var EncryptionClient = class {
2528
2637
  * .withLockContext(lockContext)
2529
2638
  * ```
2530
2639
  *
2640
+ * @remarks
2641
+ * The public input type rejects null, but at runtime `decrypt` will
2642
+ * short-circuit and return null when given a null ciphertext
2643
+ * (defense in depth for legacy / manually-NULLed DB rows reached via
2644
+ * casts or dynamic field walking). The narrow return type holds for
2645
+ * any caller that respects the input contract.
2646
+ *
2531
2647
  * @see {@link LockContext}
2532
2648
  * @see {@link DecryptOperation}
2533
2649
  */
@@ -2789,7 +2905,7 @@ var Encryption = async (config) => {
2789
2905
  "[encryption]: At least one encryptedTable must be provided to initialize the encryption client"
2790
2906
  );
2791
2907
  }
2792
- if (clientConfig?.keyset && "id" in clientConfig.keyset && !(0, import_uuid.validate)(clientConfig.keyset.id)) {
2908
+ if (clientConfig?.keyset && "id" in clientConfig.keyset && !validate_default(clientConfig.keyset.id)) {
2793
2909
  throw new Error(
2794
2910
  "[encryption]: Invalid UUID provided for keyset id. Must be a valid UUID."
2795
2911
  );
@@ -2807,6 +2923,16 @@ var Encryption = async (config) => {
2807
2923
  };
2808
2924
  // Annotate the CommonJS export names for ESM import in node:
2809
2925
  0 && (module.exports = {
2926
+ BatchEncryptQueryOperation,
2927
+ BulkDecryptModelsOperation,
2928
+ BulkDecryptOperation,
2929
+ BulkEncryptModelsOperation,
2930
+ BulkEncryptOperation,
2931
+ DecryptModelOperation,
2932
+ DecryptOperation,
2933
+ EncryptModelOperation,
2934
+ EncryptOperation,
2935
+ EncryptQueryOperation,
2810
2936
  Encryption,
2811
2937
  EncryptionClient,
2812
2938
  noClientError