@cipherstash/stack 0.19.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.
Files changed (90) hide show
  1. package/CHANGELOG.md +531 -0
  2. package/README.md +95 -77
  3. package/dist/adapter-kit.cjs +923 -0
  4. package/dist/adapter-kit.cjs.map +1 -0
  5. package/dist/adapter-kit.d.cts +82 -0
  6. package/dist/adapter-kit.d.ts +82 -0
  7. package/dist/adapter-kit.js +47 -0
  8. package/dist/adapter-kit.js.map +1 -0
  9. package/dist/base-operation-AOAIvsSB.d.cts +32 -0
  10. package/dist/base-operation-FXEzUXIq.d.ts +32 -0
  11. package/dist/{chunk-4AVL4VZD.js → chunk-3B5ZX3IS.js} +3 -1
  12. package/dist/chunk-3B5ZX3IS.js.map +1 -0
  13. package/dist/chunk-7333ZC6L.js +48 -0
  14. package/dist/chunk-7333ZC6L.js.map +1 -0
  15. package/dist/{chunk-MP3SSDNN.js → chunk-CLM7E4I6.js} +15 -15
  16. package/dist/{chunk-MP3SSDNN.js.map → chunk-CLM7E4I6.js.map} +1 -1
  17. package/dist/{chunk-U66S7VIF.js → chunk-V2Q3NYIH.js} +166 -107
  18. package/dist/chunk-V2Q3NYIH.js.map +1 -0
  19. package/dist/chunk-X3JRXEIB.js +98 -0
  20. package/dist/chunk-X3JRXEIB.js.map +1 -0
  21. package/dist/{chunk-36AA7IBJ.js → chunk-ZTP5QJ27.js} +51 -18
  22. package/dist/chunk-ZTP5QJ27.js.map +1 -0
  23. package/dist/client.cjs +29 -12
  24. package/dist/client.cjs.map +1 -1
  25. package/dist/client.d.cts +3 -2
  26. package/dist/client.d.ts +3 -2
  27. package/dist/client.js +2 -2
  28. package/dist/{table-DihEAlxG.d.cts → columns-D2_YzrCX.d.cts} +155 -136
  29. package/dist/{table-CIH7jZ2h.d.ts → columns-rZc7fQHI.d.ts} +155 -136
  30. package/dist/dynamodb/index.d.cts +3 -2
  31. package/dist/dynamodb/index.d.ts +3 -2
  32. package/dist/encryption/index.cjs +54 -16
  33. package/dist/encryption/index.cjs.map +1 -1
  34. package/dist/encryption/index.d.cts +807 -6
  35. package/dist/encryption/index.d.ts +807 -6
  36. package/dist/encryption/index.js +4 -4
  37. package/dist/encryption/v3.cjs +1078 -973
  38. package/dist/encryption/v3.cjs.map +1 -1
  39. package/dist/encryption/v3.d.cts +15 -12
  40. package/dist/encryption/v3.d.ts +15 -12
  41. package/dist/encryption/v3.js +49 -21
  42. package/dist/encryption/v3.js.map +1 -1
  43. package/dist/eql/v3/index.cjs +130 -79
  44. package/dist/eql/v3/index.cjs.map +1 -1
  45. package/dist/eql/v3/index.d.cts +115 -13
  46. package/dist/eql/v3/index.d.ts +115 -13
  47. package/dist/eql/v3/index.js +16 -6
  48. package/dist/index-BquA71_Y.d.ts +24 -0
  49. package/dist/index-fhWTOV0K.d.cts +24 -0
  50. package/dist/index.cjs +79 -27
  51. package/dist/index.cjs.map +1 -1
  52. package/dist/index.d.cts +5 -17
  53. package/dist/index.d.ts +5 -17
  54. package/dist/index.js +4 -4
  55. package/dist/schema/index.cjs +29 -12
  56. package/dist/schema/index.cjs.map +1 -1
  57. package/dist/schema/index.d.cts +1 -1
  58. package/dist/schema/index.d.ts +1 -1
  59. package/dist/schema/index.js +2 -2
  60. package/dist/{types-public-CpS5KjwX.d.ts → types-public-QMjYNfQO.d.cts} +765 -726
  61. package/dist/{types-public-CpS5KjwX.d.cts → types-public-QMjYNfQO.d.ts} +765 -726
  62. package/dist/types-public.cjs.map +1 -1
  63. package/dist/types-public.d.cts +1 -1
  64. package/dist/types-public.d.ts +1 -1
  65. package/dist/types-public.js +1 -1
  66. package/dist/wasm-inline.d.ts +779 -405
  67. package/dist/wasm-inline.js +606 -299
  68. package/dist/wasm-inline.js.map +1 -1
  69. package/package.json +25 -53
  70. package/dist/chunk-36AA7IBJ.js.map +0 -1
  71. package/dist/chunk-4AVL4VZD.js.map +0 -1
  72. package/dist/chunk-IADZCZEA.js +0 -23
  73. package/dist/chunk-IADZCZEA.js.map +0 -1
  74. package/dist/chunk-IBSK6P33.js +0 -209
  75. package/dist/chunk-IBSK6P33.js.map +0 -1
  76. package/dist/chunk-U66S7VIF.js.map +0 -1
  77. package/dist/client-DSGHBN-g.d.cts +0 -834
  78. package/dist/client-DfCrlHXh.d.ts +0 -834
  79. package/dist/drizzle/index.cjs +0 -5617
  80. package/dist/drizzle/index.cjs.map +0 -1
  81. package/dist/drizzle/index.d.cts +0 -358
  82. package/dist/drizzle/index.d.ts +0 -358
  83. package/dist/drizzle/index.js +0 -1220
  84. package/dist/drizzle/index.js.map +0 -1
  85. package/dist/supabase/index.cjs +0 -5951
  86. package/dist/supabase/index.cjs.map +0 -1
  87. package/dist/supabase/index.d.cts +0 -223
  88. package/dist/supabase/index.d.ts +0 -223
  89. package/dist/supabase/index.js +0 -1217
  90. package/dist/supabase/index.js.map +0 -1
@@ -1,10 +1,13 @@
1
1
  import {
2
2
  EncryptedTable,
3
3
  buildEncryptConfig,
4
- encryptedTable,
5
- types
6
- } from "../../chunk-IBSK6P33.js";
4
+ encryptedTable
5
+ } from "../../chunk-X3JRXEIB.js";
7
6
  import {
7
+ EncryptedBigintColumn,
8
+ EncryptedBigintEqColumn,
9
+ EncryptedBigintOrdColumn,
10
+ EncryptedBigintOrdOreColumn,
8
11
  EncryptedBooleanColumn,
9
12
  EncryptedDateColumn,
10
13
  EncryptedDateEqColumn,
@@ -18,6 +21,7 @@ import {
18
21
  EncryptedIntegerEqColumn,
19
22
  EncryptedIntegerOrdColumn,
20
23
  EncryptedIntegerOrdOreColumn,
24
+ EncryptedJsonColumn,
21
25
  EncryptedNumericColumn,
22
26
  EncryptedNumericEqColumn,
23
27
  EncryptedNumericOrdColumn,
@@ -40,11 +44,16 @@ import {
40
44
  EncryptedTimestampEqColumn,
41
45
  EncryptedTimestampOrdColumn,
42
46
  EncryptedTimestampOrdOreColumn,
43
- TEXT_SEARCH_EQL_TYPE
44
- } from "../../chunk-U66S7VIF.js";
45
- import "../../chunk-IADZCZEA.js";
47
+ TEXT_SEARCH_EQL_TYPE,
48
+ types
49
+ } from "../../chunk-V2Q3NYIH.js";
50
+ import "../../chunk-7333ZC6L.js";
46
51
  import "../../chunk-PZ5AY32C.js";
47
52
  export {
53
+ EncryptedBigintColumn,
54
+ EncryptedBigintEqColumn,
55
+ EncryptedBigintOrdColumn,
56
+ EncryptedBigintOrdOreColumn,
48
57
  EncryptedBooleanColumn,
49
58
  EncryptedDateColumn,
50
59
  EncryptedDateEqColumn,
@@ -58,6 +67,7 @@ export {
58
67
  EncryptedIntegerEqColumn,
59
68
  EncryptedIntegerOrdColumn,
60
69
  EncryptedIntegerOrdOreColumn,
70
+ EncryptedJsonColumn,
61
71
  EncryptedNumericColumn,
62
72
  EncryptedNumericEqColumn,
63
73
  EncryptedNumericOrdColumn,
@@ -0,0 +1,24 @@
1
+ import { p as Encrypted } from './types-public-QMjYNfQO.js';
2
+
3
+ type EncryptedPgComposite = {
4
+ data: Encrypted;
5
+ };
6
+ /**
7
+ * Helper function to transform an encrypted payload into a PostgreSQL composite type.
8
+ * Use this when inserting data via Supabase or similar clients.
9
+ */
10
+ declare function encryptedToPgComposite(obj: Encrypted): EncryptedPgComposite;
11
+ /**
12
+ * Helper function to transform a model's encrypted fields into PostgreSQL composite types
13
+ */
14
+ declare function modelToEncryptedPgComposites<T extends Record<string, unknown>>(model: T): T;
15
+ /**
16
+ * Helper function to transform multiple models' encrypted fields into PostgreSQL composite types
17
+ */
18
+ declare function bulkModelsToEncryptedPgComposites<T extends Record<string, unknown>>(models: T[]): T[];
19
+ /**
20
+ * Helper function to check if a value is an encrypted payload
21
+ */
22
+ declare function isEncryptedPayload(value: unknown): value is Encrypted;
23
+
24
+ export { bulkModelsToEncryptedPgComposites as b, encryptedToPgComposite as e, isEncryptedPayload as i, modelToEncryptedPgComposites as m };
@@ -0,0 +1,24 @@
1
+ import { p as Encrypted } from './types-public-QMjYNfQO.cjs';
2
+
3
+ type EncryptedPgComposite = {
4
+ data: Encrypted;
5
+ };
6
+ /**
7
+ * Helper function to transform an encrypted payload into a PostgreSQL composite type.
8
+ * Use this when inserting data via Supabase or similar clients.
9
+ */
10
+ declare function encryptedToPgComposite(obj: Encrypted): EncryptedPgComposite;
11
+ /**
12
+ * Helper function to transform a model's encrypted fields into PostgreSQL composite types
13
+ */
14
+ declare function modelToEncryptedPgComposites<T extends Record<string, unknown>>(model: T): T;
15
+ /**
16
+ * Helper function to transform multiple models' encrypted fields into PostgreSQL composite types
17
+ */
18
+ declare function bulkModelsToEncryptedPgComposites<T extends Record<string, unknown>>(models: T[]): T[];
19
+ /**
20
+ * Helper function to check if a value is an encrypted payload
21
+ */
22
+ declare function isEncryptedPayload(value: unknown): value is Encrypted;
23
+
24
+ export { bulkModelsToEncryptedPgComposites as b, encryptedToPgComposite as e, isEncryptedPayload as i, modelToEncryptedPgComposites as m };
package/dist/index.cjs CHANGED
@@ -4128,6 +4128,23 @@ function defaultMatchOpts() {
4128
4128
  include_original: true
4129
4129
  };
4130
4130
  }
4131
+ function cloneMatchOpts(opts) {
4132
+ return {
4133
+ ...opts,
4134
+ tokenizer: { ...opts.tokenizer },
4135
+ token_filters: opts.token_filters.map((f) => ({ ...f }))
4136
+ };
4137
+ }
4138
+ function resolveMatchOpts(opts) {
4139
+ const defaults = defaultMatchOpts();
4140
+ return cloneMatchOpts({
4141
+ tokenizer: opts?.tokenizer ?? defaults.tokenizer,
4142
+ token_filters: opts?.token_filters ?? defaults.token_filters,
4143
+ k: opts?.k ?? defaults.k,
4144
+ m: opts?.m ?? defaults.m,
4145
+ include_original: opts?.include_original ?? defaults.include_original
4146
+ });
4147
+ }
4131
4148
 
4132
4149
  // src/schema/index.ts
4133
4150
  var eqlCastAsEnum = external_exports.enum([
@@ -4165,6 +4182,7 @@ var tokenizerSchema = external_exports.union([
4165
4182
  })
4166
4183
  ]).default({ kind: "ngram", token_length: 3 }).optional();
4167
4184
  var oreIndexOptsSchema = external_exports.object({});
4185
+ var opeIndexOptsSchema = external_exports.object({});
4168
4186
  var uniqueIndexOptsSchema = external_exports.object({
4169
4187
  token_filters: external_exports.array(tokenFilterSchema).default([]).optional()
4170
4188
  });
@@ -4186,10 +4204,12 @@ var arrayIndexModeSchema = external_exports.union([
4186
4204
  ]);
4187
4205
  var steVecIndexOptsSchema = external_exports.object({
4188
4206
  prefix: external_exports.string(),
4189
- array_index_mode: arrayIndexModeSchema.optional()
4207
+ array_index_mode: arrayIndexModeSchema.optional(),
4208
+ mode: external_exports.enum(["compat", "standard"]).optional()
4190
4209
  });
4191
4210
  var indexesSchema = external_exports.object({
4192
4211
  ore: oreIndexOptsSchema.optional(),
4212
+ ope: opeIndexOptsSchema.optional(),
4193
4213
  unique: uniqueIndexOptsSchema.optional(),
4194
4214
  match: matchIndexOptsSchema.optional(),
4195
4215
  ste_vec: steVecIndexOptsSchema.optional()
@@ -4218,7 +4238,7 @@ var EncryptedField = class {
4218
4238
  * a different type so the encryption layer knows how to encode the plaintext
4219
4239
  * before encrypting.
4220
4240
  *
4221
- * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'text'`, `'bigint'`, or `'json'`.
4241
+ * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'timestamp'`, `'text'`, `'bigint'`, or `'json'`. Use `'timestamp'` (not `'date'`) to preserve time-of-day — `'date'` truncates to midnight.
4222
4242
  * @returns This `EncryptedField` instance for method chaining.
4223
4243
  *
4224
4244
  * @example
@@ -4257,7 +4277,7 @@ var EncryptedColumn = class {
4257
4277
  * a different type so the encryption layer knows how to encode the plaintext
4258
4278
  * before encrypting.
4259
4279
  *
4260
- * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
4280
+ * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'timestamp'`, `'text'`, `'bigint'`, or `'json'`. Use `'timestamp'` (not `'date'`) to preserve time-of-day — `'date'` truncates to midnight.
4261
4281
  * @returns This `EncryptedColumn` instance for method chaining.
4262
4282
  *
4263
4283
  * @example
@@ -4346,14 +4366,7 @@ var EncryptedColumn = class {
4346
4366
  * ```
4347
4367
  */
4348
4368
  freeTextSearch(opts) {
4349
- const defaults = defaultMatchOpts();
4350
- this.indexesValue.match = {
4351
- tokenizer: opts?.tokenizer ?? defaults.tokenizer,
4352
- token_filters: opts?.token_filters ?? defaults.token_filters,
4353
- k: opts?.k ?? defaults.k,
4354
- m: opts?.m ?? defaults.m,
4355
- include_original: opts?.include_original ?? defaults.include_original
4356
- };
4369
+ this.indexesValue.match = resolveMatchOpts(opts);
4357
4370
  return this;
4358
4371
  }
4359
4372
  /**
@@ -4380,7 +4393,11 @@ var EncryptedColumn = class {
4380
4393
  */
4381
4394
  searchableJson() {
4382
4395
  this.castAsValue = "json";
4383
- this.indexesValue.ste_vec = { prefix: "enabled", array_index_mode: "all" };
4396
+ this.indexesValue.ste_vec = {
4397
+ prefix: "enabled",
4398
+ array_index_mode: "all",
4399
+ mode: "standard"
4400
+ };
4384
4401
  return this;
4385
4402
  }
4386
4403
  build() {
@@ -5076,6 +5093,8 @@ var LockContext = class {
5076
5093
 
5077
5094
  // src/types.ts
5078
5095
  var queryTypeToFfi = {
5096
+ // v3 `_ord` domains carry `ope` instead — `resolveIndexType` swaps this
5097
+ // static default for the ordering index the column actually configures.
5079
5098
  orderAndRange: "ore",
5080
5099
  freeTextSearch: "match",
5081
5100
  equality: "unique",
@@ -5098,6 +5117,7 @@ function inferIndexType(column) {
5098
5117
  if (indexes.unique) return "unique";
5099
5118
  if (indexes.match) return "match";
5100
5119
  if (indexes.ore) return "ore";
5120
+ if (indexes.ope) return "ope";
5101
5121
  if (indexes.ste_vec) return "ste_vec";
5102
5122
  throw new Error(
5103
5123
  `Column "${column.getName()}" has no suitable index for queries`
@@ -5119,6 +5139,7 @@ function validateIndexType(column, indexType) {
5119
5139
  unique: !!indexes.unique,
5120
5140
  match: !!indexes.match,
5121
5141
  ore: !!indexes.ore,
5142
+ ope: !!indexes.ope,
5122
5143
  ste_vec: !!indexes.ste_vec
5123
5144
  };
5124
5145
  if (!indexMap[indexType]) {
@@ -5127,17 +5148,25 @@ function validateIndexType(column, indexType) {
5127
5148
  );
5128
5149
  }
5129
5150
  }
5130
- function resolvesEqualityViaOre(column) {
5131
- if (!("getQueryCapabilities" in column)) return false;
5132
- if (!column.getQueryCapabilities().equality) return false;
5151
+ function equalityOrderingIndex(column) {
5152
+ if (!("getQueryCapabilities" in column)) return null;
5153
+ if (!column.getQueryCapabilities().equality) return null;
5133
5154
  const indexes = column.build().indexes ?? {};
5134
- return !indexes.unique && !!indexes.ore;
5155
+ if (indexes.unique) return null;
5156
+ if (indexes.ore) return "ore";
5157
+ if (indexes.ope) return "ope";
5158
+ return null;
5135
5159
  }
5136
5160
  function resolveIndexType(column, queryType, plaintext) {
5137
- const indexType = queryType ? queryTypeToFfi[queryType] : inferIndexType(column);
5161
+ let indexType = queryType ? queryTypeToFfi[queryType] : inferIndexType(column);
5138
5162
  if (queryType) {
5139
- if (queryType === "equality" && resolvesEqualityViaOre(column)) {
5140
- return { indexType: "ore" };
5163
+ if (queryType === "equality") {
5164
+ const ordering = equalityOrderingIndex(column);
5165
+ if (ordering) return { indexType: ordering };
5166
+ }
5167
+ if (queryType === "orderAndRange" && indexType === "ore") {
5168
+ const indexes = column.build().indexes ?? {};
5169
+ if (!indexes.ore && indexes.ope) indexType = "ope";
5141
5170
  }
5142
5171
  validateIndexType(column, indexType);
5143
5172
  if (queryType === "searchableJson") {
@@ -5158,6 +5187,11 @@ function resolveIndexType(column, queryType, plaintext) {
5158
5187
  }
5159
5188
 
5160
5189
  // src/encryption/helpers/validation.ts
5190
+ var INT64_MIN = -9223372036854775808n;
5191
+ var INT64_MAX = 9223372036854775807n;
5192
+ function isBigintOutOfInt64Range(value) {
5193
+ return typeof value === "bigint" && (value < INT64_MIN || value > INT64_MAX);
5194
+ }
5161
5195
  function validateNumericValue(value) {
5162
5196
  if (typeof value === "number" && Number.isNaN(value)) {
5163
5197
  return {
@@ -5175,6 +5209,14 @@ function validateNumericValue(value) {
5175
5209
  }
5176
5210
  };
5177
5211
  }
5212
+ if (isBigintOutOfInt64Range(value)) {
5213
+ return {
5214
+ failure: {
5215
+ type: EncryptionErrorTypes.EncryptionError,
5216
+ message: "[encryption]: Cannot encrypt bigint value out of int64 range"
5217
+ }
5218
+ };
5219
+ }
5178
5220
  return void 0;
5179
5221
  }
5180
5222
  function assertValidNumericValue(value) {
@@ -5184,9 +5226,14 @@ function assertValidNumericValue(value) {
5184
5226
  if (typeof value === "number" && !Number.isFinite(value)) {
5185
5227
  throw new Error("[encryption]: Cannot encrypt Infinity value");
5186
5228
  }
5229
+ if (isBigintOutOfInt64Range(value)) {
5230
+ throw new Error(
5231
+ "[encryption]: Cannot encrypt bigint value out of int64 range"
5232
+ );
5233
+ }
5187
5234
  }
5188
5235
  function assertValueIndexCompatibility(value, indexType, columnName) {
5189
- if (typeof value === "number" && indexType === "match") {
5236
+ if ((typeof value === "number" || typeof value === "bigint") && indexType === "match") {
5190
5237
  throw new Error(
5191
5238
  `[encryption]: Cannot use 'match' index with numeric value on column "${columnName}". The 'freeTextSearch' index only supports string values. Configure the column with 'orderAndRange()' or 'equality()' for numeric queries.`
5192
5239
  );
@@ -5619,6 +5666,7 @@ function prepareFieldsForEncryption(model, table) {
5619
5666
  );
5620
5667
  }
5621
5668
  } else if (columnPaths2.includes(fullKey)) {
5669
+ assertValidNumericValue(value);
5622
5670
  const id = index.toString();
5623
5671
  keyMap[id] = fullKey;
5624
5672
  operationFields[fullKey] = value;
@@ -5797,6 +5845,7 @@ function prepareBulkModelsForOperation(models, table) {
5797
5845
  );
5798
5846
  }
5799
5847
  } else if (columnPaths.includes(fullKey)) {
5848
+ assertValidNumericValue(value);
5800
5849
  const id = index.toString();
5801
5850
  keyMap[id] = { modelIndex, fieldKey: fullKey };
5802
5851
  modelOperationFields[fullKey] = value;
@@ -6108,13 +6157,16 @@ var BulkDecryptModelsOperationWithLockContext = class extends EncryptionOperatio
6108
6157
  // src/encryption/operations/bulk-encrypt.ts
6109
6158
  var import_protect_ffi5 = require("@cipherstash/protect-ffi");
6110
6159
  var createEncryptPayloads = (plaintexts, column, table, lockContext) => {
6111
- return plaintexts.filter(({ plaintext }) => plaintext !== null).map(({ id, plaintext }) => ({
6112
- id,
6113
- plaintext,
6114
- column: column.getName(),
6115
- table: table.tableName,
6116
- ...lockContext && { lockContext }
6117
- }));
6160
+ return plaintexts.filter(({ plaintext }) => plaintext !== null).map(({ id, plaintext }) => {
6161
+ assertValidNumericValue(plaintext);
6162
+ return {
6163
+ id,
6164
+ plaintext,
6165
+ column: column.getName(),
6166
+ table: table.tableName,
6167
+ ...lockContext && { lockContext }
6168
+ };
6169
+ });
6118
6170
  };
6119
6171
  var createNullResult2 = (plaintexts) => plaintexts.map(({ id }) => ({ id, data: null }));
6120
6172
  var mapEncryptedDataToResult = (plaintexts, encryptedData) => {