@cipherstash/stack 0.19.0 → 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +596 -0
- package/README.md +376 -276
- package/dist/adapter-kit.cjs +1002 -0
- package/dist/adapter-kit.cjs.map +1 -0
- package/dist/adapter-kit.d.cts +120 -0
- package/dist/adapter-kit.d.ts +120 -0
- package/dist/adapter-kit.js +122 -0
- package/dist/adapter-kit.js.map +1 -0
- package/dist/base-operation-AOAIvsSB.d.cts +32 -0
- package/dist/base-operation-FXEzUXIq.d.ts +32 -0
- package/dist/{chunk-4AVL4VZD.js → chunk-3B5ZX3IS.js} +3 -1
- package/dist/chunk-3B5ZX3IS.js.map +1 -0
- package/dist/{chunk-U66S7VIF.js → chunk-6SGN52W6.js} +166 -107
- package/dist/chunk-6SGN52W6.js.map +1 -0
- package/dist/chunk-7333ZC6L.js +48 -0
- package/dist/chunk-7333ZC6L.js.map +1 -0
- package/dist/{chunk-MP3SSDNN.js → chunk-CLM7E4I6.js} +15 -15
- package/dist/{chunk-MP3SSDNN.js.map → chunk-CLM7E4I6.js.map} +1 -1
- package/dist/{chunk-OFQ555AX.js → chunk-IDKP6ABU.js} +2 -2
- package/dist/{chunk-36AA7IBJ.js → chunk-L7ISHSG7.js} +53 -20
- package/dist/chunk-L7ISHSG7.js.map +1 -0
- package/dist/{chunk-LBMC4D6D.js → chunk-NVKK7UDN.js} +1 -1
- package/dist/chunk-NVKK7UDN.js.map +1 -0
- package/dist/chunk-X3JRXEIB.js +98 -0
- package/dist/chunk-X3JRXEIB.js.map +1 -0
- package/dist/client.cjs +29 -12
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +3 -2
- package/dist/client.d.ts +3 -2
- package/dist/client.js +2 -2
- package/dist/{table-CIH7jZ2h.d.ts → columns-0lbT9stl.d.ts} +157 -138
- package/dist/{table-DihEAlxG.d.cts → columns-Bxv7Oo9o.d.cts} +157 -138
- package/dist/dynamodb/index.d.cts +3 -2
- package/dist/dynamodb/index.d.ts +3 -2
- package/dist/encryption/index.cjs +54 -16
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.d.cts +807 -6
- package/dist/encryption/index.d.ts +807 -6
- package/dist/encryption/index.js +6 -6
- package/dist/encryption/v3.cjs +1078 -973
- package/dist/encryption/v3.cjs.map +1 -1
- package/dist/encryption/v3.d.cts +15 -12
- package/dist/encryption/v3.d.ts +15 -12
- package/dist/encryption/v3.js +50 -22
- package/dist/encryption/v3.js.map +1 -1
- package/dist/eql/v3/index.cjs +130 -79
- package/dist/eql/v3/index.cjs.map +1 -1
- package/dist/eql/v3/index.d.cts +115 -13
- package/dist/eql/v3/index.d.ts +115 -13
- package/dist/eql/v3/index.js +16 -6
- package/dist/errors/index.cjs.map +1 -1
- package/dist/errors/index.d.cts +5 -5
- package/dist/errors/index.d.ts +5 -5
- package/dist/errors/index.js +1 -1
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.js +2 -2
- package/dist/index-BquA71_Y.d.ts +24 -0
- package/dist/index-fhWTOV0K.d.cts +24 -0
- package/dist/index.cjs +79 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -17
- package/dist/index.d.ts +5 -17
- package/dist/index.js +6 -6
- package/dist/schema/index.cjs +29 -12
- package/dist/schema/index.cjs.map +1 -1
- package/dist/schema/index.d.cts +1 -1
- package/dist/schema/index.d.ts +1 -1
- package/dist/schema/index.js +2 -2
- package/dist/{types-public-CpS5KjwX.d.ts → types-public-QMjYNfQO.d.cts} +765 -726
- package/dist/{types-public-CpS5KjwX.d.cts → types-public-QMjYNfQO.d.ts} +765 -726
- package/dist/types-public.cjs.map +1 -1
- package/dist/types-public.d.cts +1 -1
- package/dist/types-public.d.ts +1 -1
- package/dist/types-public.js +1 -1
- package/dist/wasm-inline.d.ts +779 -405
- package/dist/wasm-inline.js +606 -299
- package/dist/wasm-inline.js.map +1 -1
- package/package.json +25 -53
- package/dist/chunk-36AA7IBJ.js.map +0 -1
- package/dist/chunk-4AVL4VZD.js.map +0 -1
- package/dist/chunk-IADZCZEA.js +0 -23
- package/dist/chunk-IADZCZEA.js.map +0 -1
- package/dist/chunk-IBSK6P33.js +0 -209
- package/dist/chunk-IBSK6P33.js.map +0 -1
- package/dist/chunk-LBMC4D6D.js.map +0 -1
- package/dist/chunk-U66S7VIF.js.map +0 -1
- package/dist/client-DSGHBN-g.d.cts +0 -834
- package/dist/client-DfCrlHXh.d.ts +0 -834
- package/dist/drizzle/index.cjs +0 -5617
- package/dist/drizzle/index.cjs.map +0 -1
- package/dist/drizzle/index.d.cts +0 -358
- package/dist/drizzle/index.d.ts +0 -358
- package/dist/drizzle/index.js +0 -1220
- package/dist/drizzle/index.js.map +0 -1
- package/dist/supabase/index.cjs +0 -5951
- package/dist/supabase/index.cjs.map +0 -1
- package/dist/supabase/index.d.cts +0 -223
- package/dist/supabase/index.d.ts +0 -223
- package/dist/supabase/index.js +0 -1217
- package/dist/supabase/index.js.map +0 -1
- /package/dist/{chunk-OFQ555AX.js.map → chunk-IDKP6ABU.js.map} +0 -0
package/dist/encryption/v3.cjs
CHANGED
|
@@ -30,6 +30,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/encryption/v3.ts
|
|
31
31
|
var v3_exports = {};
|
|
32
32
|
__export(v3_exports, {
|
|
33
|
+
EncryptedBigintColumn: () => EncryptedBigintColumn,
|
|
34
|
+
EncryptedBigintEqColumn: () => EncryptedBigintEqColumn,
|
|
35
|
+
EncryptedBigintOrdColumn: () => EncryptedBigintOrdColumn,
|
|
36
|
+
EncryptedBigintOrdOreColumn: () => EncryptedBigintOrdOreColumn,
|
|
33
37
|
EncryptedBooleanColumn: () => EncryptedBooleanColumn,
|
|
34
38
|
EncryptedDateColumn: () => EncryptedDateColumn,
|
|
35
39
|
EncryptedDateEqColumn: () => EncryptedDateEqColumn,
|
|
@@ -43,6 +47,7 @@ __export(v3_exports, {
|
|
|
43
47
|
EncryptedIntegerEqColumn: () => EncryptedIntegerEqColumn,
|
|
44
48
|
EncryptedIntegerOrdColumn: () => EncryptedIntegerOrdColumn,
|
|
45
49
|
EncryptedIntegerOrdOreColumn: () => EncryptedIntegerOrdOreColumn,
|
|
50
|
+
EncryptedJsonColumn: () => EncryptedJsonColumn,
|
|
46
51
|
EncryptedNumericColumn: () => EncryptedNumericColumn,
|
|
47
52
|
EncryptedNumericEqColumn: () => EncryptedNumericEqColumn,
|
|
48
53
|
EncryptedNumericOrdColumn: () => EncryptedNumericOrdColumn,
|
|
@@ -75,6 +80,408 @@ __export(v3_exports, {
|
|
|
75
80
|
});
|
|
76
81
|
module.exports = __toCommonJS(v3_exports);
|
|
77
82
|
|
|
83
|
+
// src/schema/match-defaults.ts
|
|
84
|
+
function defaultMatchOpts() {
|
|
85
|
+
return {
|
|
86
|
+
tokenizer: { kind: "ngram", token_length: 3 },
|
|
87
|
+
token_filters: [{ kind: "downcase" }],
|
|
88
|
+
k: 6,
|
|
89
|
+
m: 2048,
|
|
90
|
+
include_original: true
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// src/eql/v3/columns.ts
|
|
95
|
+
var DATE_LIKE_CASTS = ["date", "timestamp"];
|
|
96
|
+
var STORAGE_ONLY = {
|
|
97
|
+
equality: false,
|
|
98
|
+
orderAndRange: false,
|
|
99
|
+
freeTextSearch: false
|
|
100
|
+
};
|
|
101
|
+
var EQUALITY_ONLY = {
|
|
102
|
+
equality: true,
|
|
103
|
+
orderAndRange: false,
|
|
104
|
+
freeTextSearch: false
|
|
105
|
+
};
|
|
106
|
+
var ORDER_AND_RANGE = {
|
|
107
|
+
equality: true,
|
|
108
|
+
orderAndRange: true,
|
|
109
|
+
freeTextSearch: false
|
|
110
|
+
};
|
|
111
|
+
var MATCH_ONLY = {
|
|
112
|
+
equality: false,
|
|
113
|
+
orderAndRange: false,
|
|
114
|
+
freeTextSearch: true
|
|
115
|
+
};
|
|
116
|
+
var TEXT_SEARCH = {
|
|
117
|
+
equality: true,
|
|
118
|
+
orderAndRange: true,
|
|
119
|
+
freeTextSearch: true
|
|
120
|
+
};
|
|
121
|
+
var TEXT_SEARCH_EQL_TYPE = "public.eql_v3_text_search";
|
|
122
|
+
var INTEGER = {
|
|
123
|
+
eqlType: "public.eql_v3_integer",
|
|
124
|
+
castAs: "number",
|
|
125
|
+
capabilities: STORAGE_ONLY
|
|
126
|
+
};
|
|
127
|
+
var INTEGER_EQ = {
|
|
128
|
+
eqlType: "public.eql_v3_integer_eq",
|
|
129
|
+
castAs: "number",
|
|
130
|
+
capabilities: EQUALITY_ONLY
|
|
131
|
+
};
|
|
132
|
+
var INTEGER_ORD_ORE = {
|
|
133
|
+
eqlType: "public.eql_v3_integer_ord_ore",
|
|
134
|
+
castAs: "number",
|
|
135
|
+
capabilities: ORDER_AND_RANGE
|
|
136
|
+
};
|
|
137
|
+
var INTEGER_ORD = {
|
|
138
|
+
eqlType: "public.eql_v3_integer_ord",
|
|
139
|
+
castAs: "number",
|
|
140
|
+
capabilities: ORDER_AND_RANGE
|
|
141
|
+
};
|
|
142
|
+
var SMALLINT = {
|
|
143
|
+
eqlType: "public.eql_v3_smallint",
|
|
144
|
+
castAs: "number",
|
|
145
|
+
capabilities: STORAGE_ONLY
|
|
146
|
+
};
|
|
147
|
+
var SMALLINT_EQ = {
|
|
148
|
+
eqlType: "public.eql_v3_smallint_eq",
|
|
149
|
+
castAs: "number",
|
|
150
|
+
capabilities: EQUALITY_ONLY
|
|
151
|
+
};
|
|
152
|
+
var SMALLINT_ORD_ORE = {
|
|
153
|
+
eqlType: "public.eql_v3_smallint_ord_ore",
|
|
154
|
+
castAs: "number",
|
|
155
|
+
capabilities: ORDER_AND_RANGE
|
|
156
|
+
};
|
|
157
|
+
var SMALLINT_ORD = {
|
|
158
|
+
eqlType: "public.eql_v3_smallint_ord",
|
|
159
|
+
castAs: "number",
|
|
160
|
+
capabilities: ORDER_AND_RANGE
|
|
161
|
+
};
|
|
162
|
+
var BIGINT = {
|
|
163
|
+
eqlType: "public.eql_v3_bigint",
|
|
164
|
+
castAs: "bigint",
|
|
165
|
+
capabilities: STORAGE_ONLY
|
|
166
|
+
};
|
|
167
|
+
var BIGINT_EQ = {
|
|
168
|
+
eqlType: "public.eql_v3_bigint_eq",
|
|
169
|
+
castAs: "bigint",
|
|
170
|
+
capabilities: EQUALITY_ONLY
|
|
171
|
+
};
|
|
172
|
+
var BIGINT_ORD_ORE = {
|
|
173
|
+
eqlType: "public.eql_v3_bigint_ord_ore",
|
|
174
|
+
castAs: "bigint",
|
|
175
|
+
capabilities: ORDER_AND_RANGE
|
|
176
|
+
};
|
|
177
|
+
var BIGINT_ORD = {
|
|
178
|
+
eqlType: "public.eql_v3_bigint_ord",
|
|
179
|
+
castAs: "bigint",
|
|
180
|
+
capabilities: ORDER_AND_RANGE
|
|
181
|
+
};
|
|
182
|
+
var DATE = {
|
|
183
|
+
eqlType: "public.eql_v3_date",
|
|
184
|
+
castAs: "date",
|
|
185
|
+
capabilities: STORAGE_ONLY
|
|
186
|
+
};
|
|
187
|
+
var DATE_EQ = {
|
|
188
|
+
eqlType: "public.eql_v3_date_eq",
|
|
189
|
+
castAs: "date",
|
|
190
|
+
capabilities: EQUALITY_ONLY
|
|
191
|
+
};
|
|
192
|
+
var DATE_ORD_ORE = {
|
|
193
|
+
eqlType: "public.eql_v3_date_ord_ore",
|
|
194
|
+
castAs: "date",
|
|
195
|
+
capabilities: ORDER_AND_RANGE
|
|
196
|
+
};
|
|
197
|
+
var DATE_ORD = {
|
|
198
|
+
eqlType: "public.eql_v3_date_ord",
|
|
199
|
+
castAs: "date",
|
|
200
|
+
capabilities: ORDER_AND_RANGE
|
|
201
|
+
};
|
|
202
|
+
var TIMESTAMP = {
|
|
203
|
+
eqlType: "public.eql_v3_timestamp",
|
|
204
|
+
castAs: "timestamp",
|
|
205
|
+
capabilities: STORAGE_ONLY
|
|
206
|
+
};
|
|
207
|
+
var TIMESTAMP_EQ = {
|
|
208
|
+
eqlType: "public.eql_v3_timestamp_eq",
|
|
209
|
+
castAs: "timestamp",
|
|
210
|
+
capabilities: EQUALITY_ONLY
|
|
211
|
+
};
|
|
212
|
+
var TIMESTAMP_ORD_ORE = {
|
|
213
|
+
eqlType: "public.eql_v3_timestamp_ord_ore",
|
|
214
|
+
castAs: "timestamp",
|
|
215
|
+
capabilities: ORDER_AND_RANGE
|
|
216
|
+
};
|
|
217
|
+
var TIMESTAMP_ORD = {
|
|
218
|
+
eqlType: "public.eql_v3_timestamp_ord",
|
|
219
|
+
castAs: "timestamp",
|
|
220
|
+
capabilities: ORDER_AND_RANGE
|
|
221
|
+
};
|
|
222
|
+
var NUMERIC = {
|
|
223
|
+
eqlType: "public.eql_v3_numeric",
|
|
224
|
+
castAs: "number",
|
|
225
|
+
capabilities: STORAGE_ONLY
|
|
226
|
+
};
|
|
227
|
+
var NUMERIC_EQ = {
|
|
228
|
+
eqlType: "public.eql_v3_numeric_eq",
|
|
229
|
+
castAs: "number",
|
|
230
|
+
capabilities: EQUALITY_ONLY
|
|
231
|
+
};
|
|
232
|
+
var NUMERIC_ORD_ORE = {
|
|
233
|
+
eqlType: "public.eql_v3_numeric_ord_ore",
|
|
234
|
+
castAs: "number",
|
|
235
|
+
capabilities: ORDER_AND_RANGE
|
|
236
|
+
};
|
|
237
|
+
var NUMERIC_ORD = {
|
|
238
|
+
eqlType: "public.eql_v3_numeric_ord",
|
|
239
|
+
castAs: "number",
|
|
240
|
+
capabilities: ORDER_AND_RANGE
|
|
241
|
+
};
|
|
242
|
+
var TEXT = {
|
|
243
|
+
eqlType: "public.eql_v3_text",
|
|
244
|
+
castAs: "string",
|
|
245
|
+
capabilities: STORAGE_ONLY
|
|
246
|
+
};
|
|
247
|
+
var TEXT_EQ = {
|
|
248
|
+
eqlType: "public.eql_v3_text_eq",
|
|
249
|
+
castAs: "string",
|
|
250
|
+
capabilities: EQUALITY_ONLY
|
|
251
|
+
};
|
|
252
|
+
var TEXT_MATCH = {
|
|
253
|
+
eqlType: "public.eql_v3_text_match",
|
|
254
|
+
castAs: "string",
|
|
255
|
+
capabilities: MATCH_ONLY
|
|
256
|
+
};
|
|
257
|
+
var TEXT_ORD_ORE = {
|
|
258
|
+
eqlType: "public.eql_v3_text_ord_ore",
|
|
259
|
+
castAs: "string",
|
|
260
|
+
capabilities: ORDER_AND_RANGE
|
|
261
|
+
};
|
|
262
|
+
var TEXT_ORD = {
|
|
263
|
+
eqlType: "public.eql_v3_text_ord",
|
|
264
|
+
castAs: "string",
|
|
265
|
+
capabilities: ORDER_AND_RANGE
|
|
266
|
+
};
|
|
267
|
+
var BOOLEAN = {
|
|
268
|
+
eqlType: "public.eql_v3_boolean",
|
|
269
|
+
castAs: "boolean",
|
|
270
|
+
capabilities: STORAGE_ONLY
|
|
271
|
+
};
|
|
272
|
+
var REAL = {
|
|
273
|
+
eqlType: "public.eql_v3_real",
|
|
274
|
+
castAs: "number",
|
|
275
|
+
capabilities: STORAGE_ONLY
|
|
276
|
+
};
|
|
277
|
+
var REAL_EQ = {
|
|
278
|
+
eqlType: "public.eql_v3_real_eq",
|
|
279
|
+
castAs: "number",
|
|
280
|
+
capabilities: EQUALITY_ONLY
|
|
281
|
+
};
|
|
282
|
+
var REAL_ORD_ORE = {
|
|
283
|
+
eqlType: "public.eql_v3_real_ord_ore",
|
|
284
|
+
castAs: "number",
|
|
285
|
+
capabilities: ORDER_AND_RANGE
|
|
286
|
+
};
|
|
287
|
+
var REAL_ORD = {
|
|
288
|
+
eqlType: "public.eql_v3_real_ord",
|
|
289
|
+
castAs: "number",
|
|
290
|
+
capabilities: ORDER_AND_RANGE
|
|
291
|
+
};
|
|
292
|
+
var DOUBLE = {
|
|
293
|
+
eqlType: "public.eql_v3_double",
|
|
294
|
+
castAs: "number",
|
|
295
|
+
capabilities: STORAGE_ONLY
|
|
296
|
+
};
|
|
297
|
+
var DOUBLE_EQ = {
|
|
298
|
+
eqlType: "public.eql_v3_double_eq",
|
|
299
|
+
castAs: "number",
|
|
300
|
+
capabilities: EQUALITY_ONLY
|
|
301
|
+
};
|
|
302
|
+
var DOUBLE_ORD_ORE = {
|
|
303
|
+
eqlType: "public.eql_v3_double_ord_ore",
|
|
304
|
+
castAs: "number",
|
|
305
|
+
capabilities: ORDER_AND_RANGE
|
|
306
|
+
};
|
|
307
|
+
var DOUBLE_ORD = {
|
|
308
|
+
eqlType: "public.eql_v3_double_ord",
|
|
309
|
+
castAs: "number",
|
|
310
|
+
capabilities: ORDER_AND_RANGE
|
|
311
|
+
};
|
|
312
|
+
function indexesForCapabilities(capabilities, castAs, ordering) {
|
|
313
|
+
const indexes = {};
|
|
314
|
+
if (capabilities.equality && (!capabilities.orderAndRange || castAs === "string")) {
|
|
315
|
+
indexes.unique = { token_filters: [] };
|
|
316
|
+
}
|
|
317
|
+
if (capabilities.orderAndRange) {
|
|
318
|
+
indexes[ordering] = {};
|
|
319
|
+
}
|
|
320
|
+
if (capabilities.freeTextSearch) {
|
|
321
|
+
indexes.match = { ...defaultMatchOpts(), include_original: false };
|
|
322
|
+
}
|
|
323
|
+
if (capabilities.searchableJson) {
|
|
324
|
+
indexes.ste_vec = {
|
|
325
|
+
prefix: "enabled",
|
|
326
|
+
array_index_mode: { item: true, wildcard: true, position: false },
|
|
327
|
+
mode: "compat"
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
return indexes;
|
|
331
|
+
}
|
|
332
|
+
function orderingForEqlType(eqlType) {
|
|
333
|
+
return eqlType.endsWith("_ord_ore") ? "ore" : "ope";
|
|
334
|
+
}
|
|
335
|
+
function isQueryableCapabilities(capabilities) {
|
|
336
|
+
return capabilities.equality || capabilities.orderAndRange || capabilities.freeTextSearch || (capabilities.searchableJson ?? false);
|
|
337
|
+
}
|
|
338
|
+
var EncryptedV3Column = class {
|
|
339
|
+
constructor(columnName, definition) {
|
|
340
|
+
this.columnName = columnName;
|
|
341
|
+
this.definition = definition;
|
|
342
|
+
}
|
|
343
|
+
columnName;
|
|
344
|
+
definition;
|
|
345
|
+
getName() {
|
|
346
|
+
return this.columnName;
|
|
347
|
+
}
|
|
348
|
+
/** The concrete EQL v3 domain name. Metadata only; not emitted by `build()`. */
|
|
349
|
+
getEqlType() {
|
|
350
|
+
return this.definition.eqlType;
|
|
351
|
+
}
|
|
352
|
+
/** The semantic query capabilities this domain exposes. Metadata only. */
|
|
353
|
+
getQueryCapabilities() {
|
|
354
|
+
return this.definition.capabilities;
|
|
355
|
+
}
|
|
356
|
+
/** `true` when this domain can produce at least one kind of query term. */
|
|
357
|
+
isQueryable() {
|
|
358
|
+
return isQueryableCapabilities(
|
|
359
|
+
this.definition.capabilities
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
/** Emit the encrypt-config column: `cast_as` plus capability-derived indexes. */
|
|
363
|
+
build() {
|
|
364
|
+
return {
|
|
365
|
+
cast_as: this.definition.castAs,
|
|
366
|
+
indexes: indexesForCapabilities(
|
|
367
|
+
this.definition.capabilities,
|
|
368
|
+
this.definition.castAs,
|
|
369
|
+
orderingForEqlType(this.definition.eqlType)
|
|
370
|
+
)
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
};
|
|
374
|
+
var TEXT_SEARCH_DOMAIN = {
|
|
375
|
+
eqlType: TEXT_SEARCH_EQL_TYPE,
|
|
376
|
+
castAs: "string",
|
|
377
|
+
capabilities: TEXT_SEARCH
|
|
378
|
+
};
|
|
379
|
+
var EncryptedTextSearchColumn = class extends EncryptedV3Column {
|
|
380
|
+
constructor(columnName) {
|
|
381
|
+
super(columnName, TEXT_SEARCH_DOMAIN);
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
var EncryptedIntegerColumn = class extends EncryptedV3Column {
|
|
385
|
+
};
|
|
386
|
+
var EncryptedIntegerEqColumn = class extends EncryptedV3Column {
|
|
387
|
+
};
|
|
388
|
+
var EncryptedIntegerOrdOreColumn = class extends EncryptedV3Column {
|
|
389
|
+
};
|
|
390
|
+
var EncryptedIntegerOrdColumn = class extends EncryptedV3Column {
|
|
391
|
+
};
|
|
392
|
+
var EncryptedSmallintColumn = class extends EncryptedV3Column {
|
|
393
|
+
};
|
|
394
|
+
var EncryptedSmallintEqColumn = class extends EncryptedV3Column {
|
|
395
|
+
};
|
|
396
|
+
var EncryptedSmallintOrdOreColumn = class extends EncryptedV3Column {
|
|
397
|
+
};
|
|
398
|
+
var EncryptedSmallintOrdColumn = class extends EncryptedV3Column {
|
|
399
|
+
};
|
|
400
|
+
var EncryptedBigintColumn = class extends EncryptedV3Column {
|
|
401
|
+
};
|
|
402
|
+
var EncryptedBigintEqColumn = class extends EncryptedV3Column {
|
|
403
|
+
};
|
|
404
|
+
var EncryptedBigintOrdOreColumn = class extends EncryptedV3Column {
|
|
405
|
+
};
|
|
406
|
+
var EncryptedBigintOrdColumn = class extends EncryptedV3Column {
|
|
407
|
+
};
|
|
408
|
+
var EncryptedDateColumn = class extends EncryptedV3Column {
|
|
409
|
+
};
|
|
410
|
+
var EncryptedDateEqColumn = class extends EncryptedV3Column {
|
|
411
|
+
};
|
|
412
|
+
var EncryptedDateOrdOreColumn = class extends EncryptedV3Column {
|
|
413
|
+
};
|
|
414
|
+
var EncryptedDateOrdColumn = class extends EncryptedV3Column {
|
|
415
|
+
};
|
|
416
|
+
var EncryptedTimestampColumn = class extends EncryptedV3Column {
|
|
417
|
+
};
|
|
418
|
+
var EncryptedTimestampEqColumn = class extends EncryptedV3Column {
|
|
419
|
+
};
|
|
420
|
+
var EncryptedTimestampOrdOreColumn = class extends EncryptedV3Column {
|
|
421
|
+
};
|
|
422
|
+
var EncryptedTimestampOrdColumn = class extends EncryptedV3Column {
|
|
423
|
+
};
|
|
424
|
+
var EncryptedNumericColumn = class extends EncryptedV3Column {
|
|
425
|
+
};
|
|
426
|
+
var EncryptedNumericEqColumn = class extends EncryptedV3Column {
|
|
427
|
+
};
|
|
428
|
+
var EncryptedNumericOrdOreColumn = class extends EncryptedV3Column {
|
|
429
|
+
};
|
|
430
|
+
var EncryptedNumericOrdColumn = class extends EncryptedV3Column {
|
|
431
|
+
};
|
|
432
|
+
var EncryptedTextColumn = class extends EncryptedV3Column {
|
|
433
|
+
};
|
|
434
|
+
var EncryptedTextEqColumn = class extends EncryptedV3Column {
|
|
435
|
+
};
|
|
436
|
+
var EncryptedTextMatchColumn = class extends EncryptedV3Column {
|
|
437
|
+
};
|
|
438
|
+
var EncryptedTextOrdOreColumn = class extends EncryptedV3Column {
|
|
439
|
+
};
|
|
440
|
+
var EncryptedTextOrdColumn = class extends EncryptedV3Column {
|
|
441
|
+
};
|
|
442
|
+
var EncryptedBooleanColumn = class extends EncryptedV3Column {
|
|
443
|
+
};
|
|
444
|
+
var EncryptedRealColumn = class extends EncryptedV3Column {
|
|
445
|
+
};
|
|
446
|
+
var EncryptedRealEqColumn = class extends EncryptedV3Column {
|
|
447
|
+
};
|
|
448
|
+
var EncryptedRealOrdOreColumn = class extends EncryptedV3Column {
|
|
449
|
+
};
|
|
450
|
+
var EncryptedRealOrdColumn = class extends EncryptedV3Column {
|
|
451
|
+
};
|
|
452
|
+
var EncryptedDoubleColumn = class extends EncryptedV3Column {
|
|
453
|
+
};
|
|
454
|
+
var EncryptedDoubleEqColumn = class extends EncryptedV3Column {
|
|
455
|
+
};
|
|
456
|
+
var EncryptedDoubleOrdOreColumn = class extends EncryptedV3Column {
|
|
457
|
+
};
|
|
458
|
+
var EncryptedDoubleOrdColumn = class extends EncryptedV3Column {
|
|
459
|
+
};
|
|
460
|
+
var JSON_DOMAIN = {
|
|
461
|
+
eqlType: "public.eql_v3_json",
|
|
462
|
+
castAs: "json",
|
|
463
|
+
capabilities: {
|
|
464
|
+
equality: false,
|
|
465
|
+
orderAndRange: false,
|
|
466
|
+
freeTextSearch: false,
|
|
467
|
+
searchableJson: true
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
var EncryptedJsonColumn = class extends EncryptedV3Column {
|
|
471
|
+
constructor(columnName) {
|
|
472
|
+
super(columnName, JSON_DOMAIN);
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
// src/errors/index.ts
|
|
477
|
+
var EncryptionErrorTypes = {
|
|
478
|
+
ClientInitError: "ClientInitError",
|
|
479
|
+
EncryptionError: "EncryptionError",
|
|
480
|
+
DecryptionError: "DecryptionError",
|
|
481
|
+
LockContextError: "LockContextError",
|
|
482
|
+
CtsTokenError: "CtsTokenError"
|
|
483
|
+
};
|
|
484
|
+
|
|
78
485
|
// ../../node_modules/.pnpm/@byteslice+result@0.2.0/node_modules/@byteslice/result/dist/result.mjs
|
|
79
486
|
function ensureError(ex) {
|
|
80
487
|
return ex instanceof Error ? ex : new Error("Something went wrong");
|
|
@@ -100,15 +507,6 @@ function validate(uuid) {
|
|
|
100
507
|
}
|
|
101
508
|
var validate_default = validate;
|
|
102
509
|
|
|
103
|
-
// src/errors/index.ts
|
|
104
|
-
var EncryptionErrorTypes = {
|
|
105
|
-
ClientInitError: "ClientInitError",
|
|
106
|
-
EncryptionError: "EncryptionError",
|
|
107
|
-
DecryptionError: "DecryptionError",
|
|
108
|
-
LockContextError: "LockContextError",
|
|
109
|
-
CtsTokenError: "CtsTokenError"
|
|
110
|
-
};
|
|
111
|
-
|
|
112
510
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
|
|
113
511
|
var external_exports = {};
|
|
114
512
|
__export(external_exports, {
|
|
@@ -4150,24 +4548,6 @@ var coerce = {
|
|
|
4150
4548
|
};
|
|
4151
4549
|
var NEVER = INVALID;
|
|
4152
4550
|
|
|
4153
|
-
// src/schema/match-defaults.ts
|
|
4154
|
-
function defaultMatchOpts() {
|
|
4155
|
-
return {
|
|
4156
|
-
tokenizer: { kind: "ngram", token_length: 3 },
|
|
4157
|
-
token_filters: [{ kind: "downcase" }],
|
|
4158
|
-
k: 6,
|
|
4159
|
-
m: 2048,
|
|
4160
|
-
include_original: true
|
|
4161
|
-
};
|
|
4162
|
-
}
|
|
4163
|
-
function cloneMatchOpts(opts) {
|
|
4164
|
-
return {
|
|
4165
|
-
...opts,
|
|
4166
|
-
tokenizer: { ...opts.tokenizer },
|
|
4167
|
-
token_filters: opts.token_filters.map((f) => ({ ...f }))
|
|
4168
|
-
};
|
|
4169
|
-
}
|
|
4170
|
-
|
|
4171
4551
|
// src/schema/index.ts
|
|
4172
4552
|
var eqlCastAsEnum = external_exports.enum([
|
|
4173
4553
|
"text",
|
|
@@ -4204,6 +4584,7 @@ var tokenizerSchema = external_exports.union([
|
|
|
4204
4584
|
})
|
|
4205
4585
|
]).default({ kind: "ngram", token_length: 3 }).optional();
|
|
4206
4586
|
var oreIndexOptsSchema = external_exports.object({});
|
|
4587
|
+
var opeIndexOptsSchema = external_exports.object({});
|
|
4207
4588
|
var uniqueIndexOptsSchema = external_exports.object({
|
|
4208
4589
|
token_filters: external_exports.array(tokenFilterSchema).default([]).optional()
|
|
4209
4590
|
});
|
|
@@ -4225,10 +4606,12 @@ var arrayIndexModeSchema = external_exports.union([
|
|
|
4225
4606
|
]);
|
|
4226
4607
|
var steVecIndexOptsSchema = external_exports.object({
|
|
4227
4608
|
prefix: external_exports.string(),
|
|
4228
|
-
array_index_mode: arrayIndexModeSchema.optional()
|
|
4609
|
+
array_index_mode: arrayIndexModeSchema.optional(),
|
|
4610
|
+
mode: external_exports.enum(["compat", "standard"]).optional()
|
|
4229
4611
|
});
|
|
4230
4612
|
var indexesSchema = external_exports.object({
|
|
4231
4613
|
ore: oreIndexOptsSchema.optional(),
|
|
4614
|
+
ope: opeIndexOptsSchema.optional(),
|
|
4232
4615
|
unique: uniqueIndexOptsSchema.optional(),
|
|
4233
4616
|
match: matchIndexOptsSchema.optional(),
|
|
4234
4617
|
ste_vec: steVecIndexOptsSchema.optional()
|
|
@@ -4840,6 +5223,8 @@ var LockContext = class {
|
|
|
4840
5223
|
|
|
4841
5224
|
// src/types.ts
|
|
4842
5225
|
var queryTypeToFfi = {
|
|
5226
|
+
// v3 `_ord` domains carry `ope` instead — `resolveIndexType` swaps this
|
|
5227
|
+
// static default for the ordering index the column actually configures.
|
|
4843
5228
|
orderAndRange: "ore",
|
|
4844
5229
|
freeTextSearch: "match",
|
|
4845
5230
|
equality: "unique",
|
|
@@ -4862,6 +5247,7 @@ function inferIndexType(column) {
|
|
|
4862
5247
|
if (indexes.unique) return "unique";
|
|
4863
5248
|
if (indexes.match) return "match";
|
|
4864
5249
|
if (indexes.ore) return "ore";
|
|
5250
|
+
if (indexes.ope) return "ope";
|
|
4865
5251
|
if (indexes.ste_vec) return "ste_vec";
|
|
4866
5252
|
throw new Error(
|
|
4867
5253
|
`Column "${column.getName()}" has no suitable index for queries`
|
|
@@ -4883,6 +5269,7 @@ function validateIndexType(column, indexType) {
|
|
|
4883
5269
|
unique: !!indexes.unique,
|
|
4884
5270
|
match: !!indexes.match,
|
|
4885
5271
|
ore: !!indexes.ore,
|
|
5272
|
+
ope: !!indexes.ope,
|
|
4886
5273
|
ste_vec: !!indexes.ste_vec
|
|
4887
5274
|
};
|
|
4888
5275
|
if (!indexMap[indexType]) {
|
|
@@ -4891,17 +5278,25 @@ function validateIndexType(column, indexType) {
|
|
|
4891
5278
|
);
|
|
4892
5279
|
}
|
|
4893
5280
|
}
|
|
4894
|
-
function
|
|
4895
|
-
if (!("getQueryCapabilities" in column)) return
|
|
4896
|
-
if (!column.getQueryCapabilities().equality) return
|
|
5281
|
+
function equalityOrderingIndex(column) {
|
|
5282
|
+
if (!("getQueryCapabilities" in column)) return null;
|
|
5283
|
+
if (!column.getQueryCapabilities().equality) return null;
|
|
4897
5284
|
const indexes = column.build().indexes ?? {};
|
|
4898
|
-
|
|
5285
|
+
if (indexes.unique) return null;
|
|
5286
|
+
if (indexes.ore) return "ore";
|
|
5287
|
+
if (indexes.ope) return "ope";
|
|
5288
|
+
return null;
|
|
4899
5289
|
}
|
|
4900
5290
|
function resolveIndexType(column, queryType, plaintext) {
|
|
4901
|
-
|
|
5291
|
+
let indexType = queryType ? queryTypeToFfi[queryType] : inferIndexType(column);
|
|
4902
5292
|
if (queryType) {
|
|
4903
|
-
if (queryType === "equality"
|
|
4904
|
-
|
|
5293
|
+
if (queryType === "equality") {
|
|
5294
|
+
const ordering = equalityOrderingIndex(column);
|
|
5295
|
+
if (ordering) return { indexType: ordering };
|
|
5296
|
+
}
|
|
5297
|
+
if (queryType === "orderAndRange" && indexType === "ore") {
|
|
5298
|
+
const indexes = column.build().indexes ?? {};
|
|
5299
|
+
if (!indexes.ore && indexes.ope) indexType = "ope";
|
|
4905
5300
|
}
|
|
4906
5301
|
validateIndexType(column, indexType);
|
|
4907
5302
|
if (queryType === "searchableJson") {
|
|
@@ -4922,6 +5317,11 @@ function resolveIndexType(column, queryType, plaintext) {
|
|
|
4922
5317
|
}
|
|
4923
5318
|
|
|
4924
5319
|
// src/encryption/helpers/validation.ts
|
|
5320
|
+
var INT64_MIN = -9223372036854775808n;
|
|
5321
|
+
var INT64_MAX = 9223372036854775807n;
|
|
5322
|
+
function isBigintOutOfInt64Range(value) {
|
|
5323
|
+
return typeof value === "bigint" && (value < INT64_MIN || value > INT64_MAX);
|
|
5324
|
+
}
|
|
4925
5325
|
function validateNumericValue(value) {
|
|
4926
5326
|
if (typeof value === "number" && Number.isNaN(value)) {
|
|
4927
5327
|
return {
|
|
@@ -4939,6 +5339,14 @@ function validateNumericValue(value) {
|
|
|
4939
5339
|
}
|
|
4940
5340
|
};
|
|
4941
5341
|
}
|
|
5342
|
+
if (isBigintOutOfInt64Range(value)) {
|
|
5343
|
+
return {
|
|
5344
|
+
failure: {
|
|
5345
|
+
type: EncryptionErrorTypes.EncryptionError,
|
|
5346
|
+
message: "[encryption]: Cannot encrypt bigint value out of int64 range"
|
|
5347
|
+
}
|
|
5348
|
+
};
|
|
5349
|
+
}
|
|
4942
5350
|
return void 0;
|
|
4943
5351
|
}
|
|
4944
5352
|
function assertValidNumericValue(value) {
|
|
@@ -4948,9 +5356,14 @@ function assertValidNumericValue(value) {
|
|
|
4948
5356
|
if (typeof value === "number" && !Number.isFinite(value)) {
|
|
4949
5357
|
throw new Error("[encryption]: Cannot encrypt Infinity value");
|
|
4950
5358
|
}
|
|
5359
|
+
if (isBigintOutOfInt64Range(value)) {
|
|
5360
|
+
throw new Error(
|
|
5361
|
+
"[encryption]: Cannot encrypt bigint value out of int64 range"
|
|
5362
|
+
);
|
|
5363
|
+
}
|
|
4951
5364
|
}
|
|
4952
5365
|
function assertValueIndexCompatibility(value, indexType, columnName) {
|
|
4953
|
-
if (typeof value === "number" && indexType === "match") {
|
|
5366
|
+
if ((typeof value === "number" || typeof value === "bigint") && indexType === "match") {
|
|
4954
5367
|
throw new Error(
|
|
4955
5368
|
`[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.`
|
|
4956
5369
|
);
|
|
@@ -5383,6 +5796,7 @@ function prepareFieldsForEncryption(model, table) {
|
|
|
5383
5796
|
);
|
|
5384
5797
|
}
|
|
5385
5798
|
} else if (columnPaths2.includes(fullKey)) {
|
|
5799
|
+
assertValidNumericValue(value);
|
|
5386
5800
|
const id = index.toString();
|
|
5387
5801
|
keyMap[id] = fullKey;
|
|
5388
5802
|
operationFields[fullKey] = value;
|
|
@@ -5561,6 +5975,7 @@ function prepareBulkModelsForOperation(models, table) {
|
|
|
5561
5975
|
);
|
|
5562
5976
|
}
|
|
5563
5977
|
} else if (columnPaths.includes(fullKey)) {
|
|
5978
|
+
assertValidNumericValue(value);
|
|
5564
5979
|
const id = index.toString();
|
|
5565
5980
|
keyMap[id] = { modelIndex, fieldKey: fullKey };
|
|
5566
5981
|
modelOperationFields[fullKey] = value;
|
|
@@ -5872,13 +6287,16 @@ var BulkDecryptModelsOperationWithLockContext = class extends EncryptionOperatio
|
|
|
5872
6287
|
// src/encryption/operations/bulk-encrypt.ts
|
|
5873
6288
|
var import_protect_ffi5 = require("@cipherstash/protect-ffi");
|
|
5874
6289
|
var createEncryptPayloads = (plaintexts, column, table, lockContext) => {
|
|
5875
|
-
return plaintexts.filter(({ plaintext }) => plaintext !== null).map(({ id, plaintext }) =>
|
|
5876
|
-
|
|
5877
|
-
|
|
5878
|
-
|
|
5879
|
-
|
|
5880
|
-
|
|
5881
|
-
|
|
6290
|
+
return plaintexts.filter(({ plaintext }) => plaintext !== null).map(({ id, plaintext }) => {
|
|
6291
|
+
assertValidNumericValue(plaintext);
|
|
6292
|
+
return {
|
|
6293
|
+
id,
|
|
6294
|
+
plaintext,
|
|
6295
|
+
column: column.getName(),
|
|
6296
|
+
table: table.tableName,
|
|
6297
|
+
...lockContext && { lockContext }
|
|
6298
|
+
};
|
|
6299
|
+
});
|
|
5882
6300
|
};
|
|
5883
6301
|
var createNullResult2 = (plaintexts) => plaintexts.map(({ id }) => ({ id, data: null }));
|
|
5884
6302
|
var mapEncryptedDataToResult = (plaintexts, encryptedData) => {
|
|
@@ -6602,956 +7020,600 @@ var EncryptQueryOperation = class extends EncryptionOperation {
|
|
|
6602
7020
|
this.opts.queryType,
|
|
6603
7021
|
plaintext
|
|
6604
7022
|
);
|
|
6605
|
-
assertValueIndexCompatibility(
|
|
6606
|
-
plaintext,
|
|
6607
|
-
indexType,
|
|
6608
|
-
this.opts.column.getName()
|
|
6609
|
-
);
|
|
6610
|
-
const encrypted = await (0, import_protect_ffi8.encryptQuery)(this.client, {
|
|
6611
|
-
// `Plaintext` widens the FFI `JsPlaintext` with `Date` (serialized via
|
|
6612
|
-
// `toJSON` at the boundary); cast until the upstream input union is
|
|
6613
|
-
// corrected to include it.
|
|
6614
|
-
plaintext,
|
|
6615
|
-
column: this.opts.column.getName(),
|
|
6616
|
-
table: this.opts.table.tableName,
|
|
6617
|
-
indexType,
|
|
6618
|
-
queryOp,
|
|
6619
|
-
unverifiedContext: metadata
|
|
6620
|
-
});
|
|
6621
|
-
return formatEncryptedResult(encrypted, this.opts.returnType);
|
|
6622
|
-
},
|
|
6623
|
-
(error) => {
|
|
6624
|
-
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
6625
|
-
return {
|
|
6626
|
-
type: EncryptionErrorTypes.EncryptionError,
|
|
6627
|
-
message: error.message,
|
|
6628
|
-
code: getErrorCode(error)
|
|
6629
|
-
};
|
|
6630
|
-
}
|
|
6631
|
-
);
|
|
6632
|
-
log.emit();
|
|
6633
|
-
return result;
|
|
6634
|
-
}
|
|
6635
|
-
getOperation() {
|
|
6636
|
-
return { client: this.client, plaintext: this.plaintext, ...this.opts };
|
|
6637
|
-
}
|
|
6638
|
-
};
|
|
6639
|
-
var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
|
|
6640
|
-
constructor(client, plaintext, opts, lockContext, auditMetadata) {
|
|
6641
|
-
super();
|
|
6642
|
-
this.client = client;
|
|
6643
|
-
this.plaintext = plaintext;
|
|
6644
|
-
this.opts = opts;
|
|
6645
|
-
this.lockContext = lockContext;
|
|
6646
|
-
this.auditMetadata = auditMetadata;
|
|
6647
|
-
}
|
|
6648
|
-
client;
|
|
6649
|
-
plaintext;
|
|
6650
|
-
opts;
|
|
6651
|
-
lockContext;
|
|
6652
|
-
async execute() {
|
|
6653
|
-
const log = createRequestLogger();
|
|
6654
|
-
log.set({
|
|
6655
|
-
op: "encryptQuery",
|
|
6656
|
-
table: this.opts.table.tableName,
|
|
6657
|
-
column: this.opts.column.getName(),
|
|
6658
|
-
queryType: this.opts.queryType,
|
|
6659
|
-
lockContext: true
|
|
6660
|
-
});
|
|
6661
|
-
if (this.plaintext === null || this.plaintext === void 0) {
|
|
6662
|
-
log.emit();
|
|
6663
|
-
return { data: null };
|
|
6664
|
-
}
|
|
6665
|
-
const plaintext = this.plaintext;
|
|
6666
|
-
const validationError = validateNumericValue(plaintext);
|
|
6667
|
-
if (validationError?.failure) {
|
|
6668
|
-
log.emit();
|
|
6669
|
-
return { failure: validationError.failure };
|
|
6670
|
-
}
|
|
6671
|
-
const result = await withResult(
|
|
6672
|
-
async () => {
|
|
6673
|
-
if (!this.client) throw noClientError();
|
|
6674
|
-
const context = resolveLockContext(this.lockContext);
|
|
6675
|
-
const { metadata } = this.getAuditData();
|
|
6676
|
-
const { indexType, queryOp } = resolveIndexType(
|
|
6677
|
-
this.opts.column,
|
|
6678
|
-
this.opts.queryType,
|
|
6679
|
-
plaintext
|
|
6680
|
-
);
|
|
6681
|
-
assertValueIndexCompatibility(
|
|
6682
|
-
plaintext,
|
|
6683
|
-
indexType,
|
|
6684
|
-
this.opts.column.getName()
|
|
6685
|
-
);
|
|
6686
|
-
const encrypted = await (0, import_protect_ffi8.encryptQuery)(this.client, {
|
|
6687
|
-
// `Plaintext` widens the FFI `JsPlaintext` with `Date` (serialized via
|
|
6688
|
-
// `toJSON` at the boundary); cast until the upstream input union is
|
|
6689
|
-
// corrected to include it.
|
|
6690
|
-
plaintext,
|
|
6691
|
-
column: this.opts.column.getName(),
|
|
6692
|
-
table: this.opts.table.tableName,
|
|
6693
|
-
indexType,
|
|
6694
|
-
queryOp,
|
|
6695
|
-
lockContext: context,
|
|
6696
|
-
unverifiedContext: metadata
|
|
6697
|
-
});
|
|
6698
|
-
return formatEncryptedResult(encrypted, this.opts.returnType);
|
|
6699
|
-
},
|
|
6700
|
-
(error) => {
|
|
6701
|
-
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
6702
|
-
return {
|
|
6703
|
-
type: EncryptionErrorTypes.EncryptionError,
|
|
6704
|
-
message: error.message,
|
|
6705
|
-
code: getErrorCode(error)
|
|
6706
|
-
};
|
|
6707
|
-
}
|
|
6708
|
-
);
|
|
6709
|
-
log.emit();
|
|
6710
|
-
return result;
|
|
6711
|
-
}
|
|
6712
|
-
};
|
|
6713
|
-
|
|
6714
|
-
// src/encryption/index.ts
|
|
6715
|
-
var noClientError = () => new Error(
|
|
6716
|
-
"The Encryption client has not been initialized. Please call init() before using the client."
|
|
6717
|
-
);
|
|
6718
|
-
function resolveEqlVersion(schemas, explicit) {
|
|
6719
|
-
const v3Count = schemas.filter(
|
|
6720
|
-
(schema) => typeof schema.buildColumnKeyMap === "function"
|
|
6721
|
-
).length;
|
|
6722
|
-
if (v3Count > 0 && v3Count < schemas.length) {
|
|
6723
|
-
throw new Error(
|
|
6724
|
-
"[encryption]: cannot mix EQL v2 and EQL v3 tables in one client \u2014 one client emits exactly one wire format. Create separate clients for the v2 and v3 schemas."
|
|
6725
|
-
);
|
|
6726
|
-
}
|
|
6727
|
-
if (explicit !== void 0) {
|
|
6728
|
-
return explicit;
|
|
6729
|
-
}
|
|
6730
|
-
return v3Count === 0 ? void 0 : 3;
|
|
6731
|
-
}
|
|
6732
|
-
var EncryptionClient = class {
|
|
6733
|
-
client;
|
|
6734
|
-
encryptConfig;
|
|
6735
|
-
/**
|
|
6736
|
-
* Initializes the EncryptionClient with the provided configuration.
|
|
6737
|
-
* @internal
|
|
6738
|
-
* @param config - The configuration object for initializing the client.
|
|
6739
|
-
* @returns A promise that resolves to a {@link Result} containing the initialized EncryptionClient or an {@link EncryptionError}.
|
|
6740
|
-
**/
|
|
6741
|
-
async init(config) {
|
|
6742
|
-
return await withResult(
|
|
6743
|
-
async () => {
|
|
6744
|
-
const validated = encryptConfigSchema.parse(
|
|
6745
|
-
config.encryptConfig
|
|
6746
|
-
);
|
|
6747
|
-
logger.debug(
|
|
6748
|
-
"Initializing the Encryption client with the following config:",
|
|
6749
|
-
{
|
|
6750
|
-
encryptConfig: validated
|
|
6751
|
-
}
|
|
7023
|
+
assertValueIndexCompatibility(
|
|
7024
|
+
plaintext,
|
|
7025
|
+
indexType,
|
|
7026
|
+
this.opts.column.getName()
|
|
6752
7027
|
);
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
|
|
6756
|
-
|
|
6757
|
-
|
|
6758
|
-
|
|
6759
|
-
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
eqlVersion: config.eqlVersion
|
|
7028
|
+
const encrypted = await (0, import_protect_ffi8.encryptQuery)(this.client, {
|
|
7029
|
+
// `Plaintext` widens the FFI `JsPlaintext` with `Date` (serialized via
|
|
7030
|
+
// `toJSON` at the boundary); cast until the upstream input union is
|
|
7031
|
+
// corrected to include it.
|
|
7032
|
+
plaintext,
|
|
7033
|
+
column: this.opts.column.getName(),
|
|
7034
|
+
table: this.opts.table.tableName,
|
|
7035
|
+
indexType,
|
|
7036
|
+
queryOp,
|
|
7037
|
+
unverifiedContext: metadata
|
|
6764
7038
|
});
|
|
6765
|
-
this.
|
|
6766
|
-
logger.debug("Successfully initialized the Encryption client.");
|
|
6767
|
-
return this;
|
|
7039
|
+
return formatEncryptedResult(encrypted, this.opts.returnType);
|
|
6768
7040
|
},
|
|
6769
|
-
(error) =>
|
|
6770
|
-
|
|
6771
|
-
|
|
6772
|
-
|
|
7041
|
+
(error) => {
|
|
7042
|
+
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
7043
|
+
return {
|
|
7044
|
+
type: EncryptionErrorTypes.EncryptionError,
|
|
7045
|
+
message: error.message,
|
|
7046
|
+
code: getErrorCode(error)
|
|
7047
|
+
};
|
|
7048
|
+
}
|
|
6773
7049
|
);
|
|
7050
|
+
log.emit();
|
|
7051
|
+
return result;
|
|
6774
7052
|
}
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
*
|
|
6778
|
-
* @param plaintext - The plaintext value to be encrypted.
|
|
6779
|
-
* @param opts - Options specifying the column (or nested field) and table for encryption. See {@link EncryptOptions}.
|
|
6780
|
-
* @returns An EncryptOperation that can be awaited or chained with additional methods.
|
|
6781
|
-
*
|
|
6782
|
-
* @example
|
|
6783
|
-
* The following example demonstrates how to encrypt a value using the Encryption client.
|
|
6784
|
-
* It includes defining an encryption schema with {@link encryptedTable} and {@link encryptedColumn},
|
|
6785
|
-
* initializing the client with {@link Encryption}, and performing the encryption.
|
|
6786
|
-
*
|
|
6787
|
-
* `encrypt` returns an {@link EncryptOperation} which can be awaited to get a {@link Result}
|
|
6788
|
-
* which can either be the encrypted value or an {@link EncryptionError}.
|
|
6789
|
-
*
|
|
6790
|
-
* ```typescript
|
|
6791
|
-
* // Define encryption schema
|
|
6792
|
-
* import { Encryption } from "@cipherstash/stack"
|
|
6793
|
-
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
6794
|
-
* const userSchema = encryptedTable("users", {
|
|
6795
|
-
* email: encryptedColumn("email"),
|
|
6796
|
-
* });
|
|
6797
|
-
*
|
|
6798
|
-
* // Initialize Encryption client
|
|
6799
|
-
* const client = await Encryption({ schemas: [userSchema] })
|
|
6800
|
-
*
|
|
6801
|
-
* // Encrypt a value
|
|
6802
|
-
* const encryptedResult = await client.encrypt(
|
|
6803
|
-
* "person@example.com",
|
|
6804
|
-
* { column: userSchema.email, table: userSchema }
|
|
6805
|
-
* )
|
|
6806
|
-
*
|
|
6807
|
-
* // Handle encryption result
|
|
6808
|
-
* if (encryptedResult.failure) {
|
|
6809
|
-
* throw new Error(`Encryption failed: ${encryptedResult.failure.message}`);
|
|
6810
|
-
* }
|
|
6811
|
-
*
|
|
6812
|
-
* console.log("Encrypted data:", encryptedResult.data);
|
|
6813
|
-
* ```
|
|
6814
|
-
*
|
|
6815
|
-
* @example
|
|
6816
|
-
* When encrypting data, a {@link LockContext} can be provided to tie the encryption to a specific user or session.
|
|
6817
|
-
* This ensures that the same lock context is required for decryption.
|
|
6818
|
-
*
|
|
6819
|
-
* The following example demonstrates how to create a lock context using a user's JWT token
|
|
6820
|
-
* and use it during encryption.
|
|
6821
|
-
*
|
|
6822
|
-
* ```typescript
|
|
6823
|
-
* // Define encryption schema and initialize client as above
|
|
6824
|
-
*
|
|
6825
|
-
* // Create a lock for the user's `sub` claim from their JWT
|
|
6826
|
-
* const lc = new LockContext();
|
|
6827
|
-
* const lockContext = await lc.identify(userJwt);
|
|
6828
|
-
*
|
|
6829
|
-
* if (lockContext.failure) {
|
|
6830
|
-
* // Handle the failure
|
|
6831
|
-
* }
|
|
6832
|
-
*
|
|
6833
|
-
* // Encrypt a value with the lock context
|
|
6834
|
-
* // Decryption will then require the same lock context
|
|
6835
|
-
* const encryptedResult = await client.encrypt(
|
|
6836
|
-
* "person@example.com",
|
|
6837
|
-
* { column: userSchema.email, table: userSchema }
|
|
6838
|
-
* )
|
|
6839
|
-
* .withLockContext(lockContext)
|
|
6840
|
-
* ```
|
|
6841
|
-
*
|
|
6842
|
-
* @see {@link EncryptOptions}
|
|
6843
|
-
* @see {@link Result}
|
|
6844
|
-
* @see {@link encryptedTable}
|
|
6845
|
-
* @see {@link encryptedColumn}
|
|
6846
|
-
* @see {@link encryptedField}
|
|
6847
|
-
* @see {@link LockContext}
|
|
6848
|
-
* @see {@link EncryptOperation}
|
|
6849
|
-
*/
|
|
6850
|
-
encrypt(plaintext, opts) {
|
|
6851
|
-
return new EncryptOperation(this.client, plaintext, opts);
|
|
6852
|
-
}
|
|
6853
|
-
encryptQuery(plaintextOrTerms, opts) {
|
|
6854
|
-
if (!opts && isScalarQueryTermArray(plaintextOrTerms)) {
|
|
6855
|
-
return new BatchEncryptQueryOperation(this.client, plaintextOrTerms);
|
|
6856
|
-
}
|
|
6857
|
-
if (Array.isArray(plaintextOrTerms) && plaintextOrTerms.length === 0 && !opts) {
|
|
6858
|
-
return new BatchEncryptQueryOperation(
|
|
6859
|
-
this.client,
|
|
6860
|
-
[]
|
|
6861
|
-
);
|
|
6862
|
-
}
|
|
6863
|
-
if (!opts) {
|
|
6864
|
-
throw new Error("EncryptQueryOptions are required");
|
|
6865
|
-
}
|
|
6866
|
-
return new EncryptQueryOperation(
|
|
6867
|
-
this.client,
|
|
6868
|
-
plaintextOrTerms,
|
|
6869
|
-
opts
|
|
6870
|
-
);
|
|
7053
|
+
getOperation() {
|
|
7054
|
+
return { client: this.client, plaintext: this.plaintext, ...this.opts };
|
|
6871
7055
|
}
|
|
6872
|
-
|
|
6873
|
-
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
*
|
|
6882
|
-
* ```typescript
|
|
6883
|
-
* const encryptedData = await client.encrypt(
|
|
6884
|
-
* "person@example.com",
|
|
6885
|
-
* { column: "email", table: "users" }
|
|
6886
|
-
* )
|
|
6887
|
-
* const decryptResult = await client.decrypt(encryptedData)
|
|
6888
|
-
* if (decryptResult.failure) {
|
|
6889
|
-
* throw new Error(`Decryption failed: ${decryptResult.failure.message}`);
|
|
6890
|
-
* }
|
|
6891
|
-
* console.log("Decrypted data:", decryptResult.data);
|
|
6892
|
-
* ```
|
|
6893
|
-
*
|
|
6894
|
-
* @example
|
|
6895
|
-
* Provide a lock context when decrypting:
|
|
6896
|
-
* ```typescript
|
|
6897
|
-
* await client.decrypt(encryptedData)
|
|
6898
|
-
* .withLockContext(lockContext)
|
|
6899
|
-
* ```
|
|
6900
|
-
*
|
|
6901
|
-
* @remarks
|
|
6902
|
-
* The public input type rejects null, but at runtime `decrypt` will
|
|
6903
|
-
* short-circuit and return null when given a null ciphertext
|
|
6904
|
-
* (defense in depth for legacy / manually-NULLed DB rows reached via
|
|
6905
|
-
* casts or dynamic field walking). The narrow return type holds for
|
|
6906
|
-
* any caller that respects the input contract.
|
|
6907
|
-
*
|
|
6908
|
-
* @see {@link LockContext}
|
|
6909
|
-
* @see {@link DecryptOperation}
|
|
6910
|
-
*/
|
|
6911
|
-
decrypt(encryptedData) {
|
|
6912
|
-
return new DecryptOperation(this.client, encryptedData);
|
|
7056
|
+
};
|
|
7057
|
+
var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
|
|
7058
|
+
constructor(client, plaintext, opts, lockContext, auditMetadata) {
|
|
7059
|
+
super();
|
|
7060
|
+
this.client = client;
|
|
7061
|
+
this.plaintext = plaintext;
|
|
7062
|
+
this.opts = opts;
|
|
7063
|
+
this.lockContext = lockContext;
|
|
7064
|
+
this.auditMetadata = auditMetadata;
|
|
6913
7065
|
}
|
|
6914
|
-
|
|
6915
|
-
|
|
6916
|
-
|
|
6917
|
-
|
|
6918
|
-
|
|
6919
|
-
|
|
6920
|
-
|
|
6921
|
-
|
|
6922
|
-
|
|
6923
|
-
|
|
6924
|
-
|
|
6925
|
-
|
|
6926
|
-
|
|
6927
|
-
|
|
6928
|
-
|
|
6929
|
-
|
|
6930
|
-
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
|
|
6959
|
-
|
|
6960
|
-
|
|
6961
|
-
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
7066
|
+
client;
|
|
7067
|
+
plaintext;
|
|
7068
|
+
opts;
|
|
7069
|
+
lockContext;
|
|
7070
|
+
async execute() {
|
|
7071
|
+
const log = createRequestLogger();
|
|
7072
|
+
log.set({
|
|
7073
|
+
op: "encryptQuery",
|
|
7074
|
+
table: this.opts.table.tableName,
|
|
7075
|
+
column: this.opts.column.getName(),
|
|
7076
|
+
queryType: this.opts.queryType,
|
|
7077
|
+
lockContext: true
|
|
7078
|
+
});
|
|
7079
|
+
if (this.plaintext === null || this.plaintext === void 0) {
|
|
7080
|
+
log.emit();
|
|
7081
|
+
return { data: null };
|
|
7082
|
+
}
|
|
7083
|
+
const plaintext = this.plaintext;
|
|
7084
|
+
const validationError = validateNumericValue(plaintext);
|
|
7085
|
+
if (validationError?.failure) {
|
|
7086
|
+
log.emit();
|
|
7087
|
+
return { failure: validationError.failure };
|
|
7088
|
+
}
|
|
7089
|
+
const result = await withResult(
|
|
7090
|
+
async () => {
|
|
7091
|
+
if (!this.client) throw noClientError();
|
|
7092
|
+
const context = resolveLockContext(this.lockContext);
|
|
7093
|
+
const { metadata } = this.getAuditData();
|
|
7094
|
+
const { indexType, queryOp } = resolveIndexType(
|
|
7095
|
+
this.opts.column,
|
|
7096
|
+
this.opts.queryType,
|
|
7097
|
+
plaintext
|
|
7098
|
+
);
|
|
7099
|
+
assertValueIndexCompatibility(
|
|
7100
|
+
plaintext,
|
|
7101
|
+
indexType,
|
|
7102
|
+
this.opts.column.getName()
|
|
7103
|
+
);
|
|
7104
|
+
const encrypted = await (0, import_protect_ffi8.encryptQuery)(this.client, {
|
|
7105
|
+
// `Plaintext` widens the FFI `JsPlaintext` with `Date` (serialized via
|
|
7106
|
+
// `toJSON` at the boundary); cast until the upstream input union is
|
|
7107
|
+
// corrected to include it.
|
|
7108
|
+
plaintext,
|
|
7109
|
+
column: this.opts.column.getName(),
|
|
7110
|
+
table: this.opts.table.tableName,
|
|
7111
|
+
indexType,
|
|
7112
|
+
queryOp,
|
|
7113
|
+
lockContext: context,
|
|
7114
|
+
unverifiedContext: metadata
|
|
7115
|
+
});
|
|
7116
|
+
return formatEncryptedResult(encrypted, this.opts.returnType);
|
|
7117
|
+
},
|
|
7118
|
+
(error) => {
|
|
7119
|
+
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
7120
|
+
return {
|
|
7121
|
+
type: EncryptionErrorTypes.EncryptionError,
|
|
7122
|
+
message: error.message,
|
|
7123
|
+
code: getErrorCode(error)
|
|
7124
|
+
};
|
|
7125
|
+
}
|
|
6965
7126
|
);
|
|
7127
|
+
log.emit();
|
|
7128
|
+
return result;
|
|
6966
7129
|
}
|
|
6967
|
-
|
|
6968
|
-
|
|
6969
|
-
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6973
|
-
|
|
6974
|
-
|
|
6975
|
-
|
|
6976
|
-
|
|
6977
|
-
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
* // Decrypt a previously encrypted model
|
|
6981
|
-
* const decrypted = await client.decryptModel<User>(encryptedUser)
|
|
6982
|
-
*
|
|
6983
|
-
* if (decrypted.failure) {
|
|
6984
|
-
* console.error(decrypted.failure.message)
|
|
6985
|
-
* } else {
|
|
6986
|
-
* console.log(decrypted.data.email) // "alice@example.com"
|
|
6987
|
-
* }
|
|
6988
|
-
*
|
|
6989
|
-
* // With a lock context
|
|
6990
|
-
* const decrypted = await client
|
|
6991
|
-
* .decryptModel<User>(encryptedUser)
|
|
6992
|
-
* .withLockContext(lockContext)
|
|
6993
|
-
* ```
|
|
6994
|
-
*/
|
|
6995
|
-
decryptModel(input) {
|
|
6996
|
-
return new DecryptModelOperation(this.client, input);
|
|
6997
|
-
}
|
|
6998
|
-
/**
|
|
6999
|
-
* Encrypt multiple models (objects) in a single bulk operation.
|
|
7000
|
-
*
|
|
7001
|
-
* Performs a single call to ZeroKMS regardless of the number of models,
|
|
7002
|
-
* while still using a unique key for each encrypted value. Only fields
|
|
7003
|
-
* matching the table schema are encrypted; other fields pass through unchanged.
|
|
7004
|
-
*
|
|
7005
|
-
* The return type is **schema-aware**: fields matching the table schema are
|
|
7006
|
-
* typed as `Encrypted`, while other fields retain their original types. For
|
|
7007
|
-
* best results, let TypeScript infer the type parameters from the arguments.
|
|
7008
|
-
*
|
|
7009
|
-
* @param input - An array of model objects with plaintext values to encrypt.
|
|
7010
|
-
* @param table - The table schema defining which fields to encrypt.
|
|
7011
|
-
* @returns A `BulkEncryptModelsOperation` that can be awaited to get a `Result`
|
|
7012
|
-
* containing an array of models with schema-defined fields typed as `Encrypted`,
|
|
7013
|
-
* or an `EncryptionError`.
|
|
7014
|
-
*
|
|
7015
|
-
* @example
|
|
7016
|
-
* ```typescript
|
|
7017
|
-
* import { Encryption } from "@cipherstash/stack"
|
|
7018
|
-
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
7019
|
-
*
|
|
7020
|
-
* type User = { id: string; email: string }
|
|
7021
|
-
*
|
|
7022
|
-
* const usersSchema = encryptedTable("users", {
|
|
7023
|
-
* email: encryptedColumn("email"),
|
|
7024
|
-
* })
|
|
7025
|
-
*
|
|
7026
|
-
* const client = await Encryption({ schemas: [usersSchema] })
|
|
7027
|
-
*
|
|
7028
|
-
* // Let TypeScript infer the return type from the schema.
|
|
7029
|
-
* // Each item's email is typed as `Encrypted`, id stays `string`.
|
|
7030
|
-
* const result = await client.bulkEncryptModels(
|
|
7031
|
-
* [
|
|
7032
|
-
* { id: "1", email: "alice@example.com" },
|
|
7033
|
-
* { id: "2", email: "bob@example.com" },
|
|
7034
|
-
* ],
|
|
7035
|
-
* usersSchema,
|
|
7036
|
-
* )
|
|
7037
|
-
*
|
|
7038
|
-
* if (!result.failure) {
|
|
7039
|
-
* console.log(result.data) // array of models with encrypted email fields
|
|
7040
|
-
* }
|
|
7041
|
-
* ```
|
|
7042
|
-
*/
|
|
7043
|
-
bulkEncryptModels(input, table) {
|
|
7044
|
-
return new BulkEncryptModelsOperation(
|
|
7045
|
-
this.client,
|
|
7046
|
-
input,
|
|
7047
|
-
table
|
|
7130
|
+
};
|
|
7131
|
+
|
|
7132
|
+
// src/encryption/index.ts
|
|
7133
|
+
var noClientError = () => new Error(
|
|
7134
|
+
"The Encryption client has not been initialized. Please call init() before using the client."
|
|
7135
|
+
);
|
|
7136
|
+
function resolveEqlVersion(schemas, explicit) {
|
|
7137
|
+
const v3Count = schemas.filter(
|
|
7138
|
+
(schema) => typeof schema.buildColumnKeyMap === "function"
|
|
7139
|
+
).length;
|
|
7140
|
+
if (v3Count > 0 && v3Count < schemas.length) {
|
|
7141
|
+
throw new Error(
|
|
7142
|
+
"[encryption]: cannot mix EQL v2 and EQL v3 tables in one client \u2014 one client emits exactly one wire format. Create separate clients for the v2 and v3 schemas."
|
|
7048
7143
|
);
|
|
7049
7144
|
}
|
|
7050
|
-
|
|
7051
|
-
|
|
7052
|
-
*
|
|
7053
|
-
* Performs a single call to ZeroKMS regardless of the number of models,
|
|
7054
|
-
* restoring all encrypted fields to their original plaintext values.
|
|
7055
|
-
*
|
|
7056
|
-
* @param input - An array of model objects with encrypted field values.
|
|
7057
|
-
* @returns A `BulkDecryptModelsOperation<T>` that can be awaited to get a `Result`
|
|
7058
|
-
* containing an array of models with decrypted plaintext fields, or an `EncryptionError`.
|
|
7059
|
-
*
|
|
7060
|
-
* @example
|
|
7061
|
-
* ```typescript
|
|
7062
|
-
* const encryptedUsers = encryptedResult.data // from bulkEncryptModels
|
|
7063
|
-
*
|
|
7064
|
-
* const result = await client.bulkDecryptModels<User>(encryptedUsers)
|
|
7065
|
-
*
|
|
7066
|
-
* if (!result.failure) {
|
|
7067
|
-
* for (const user of result.data) {
|
|
7068
|
-
* console.log(user.email) // plaintext email
|
|
7069
|
-
* }
|
|
7070
|
-
* }
|
|
7071
|
-
*
|
|
7072
|
-
* // With a lock context
|
|
7073
|
-
* const result = await client
|
|
7074
|
-
* .bulkDecryptModels<User>(encryptedUsers)
|
|
7075
|
-
* .withLockContext(lockContext)
|
|
7076
|
-
* ```
|
|
7077
|
-
*/
|
|
7078
|
-
bulkDecryptModels(input) {
|
|
7079
|
-
return new BulkDecryptModelsOperation(this.client, input);
|
|
7145
|
+
if (explicit !== void 0) {
|
|
7146
|
+
return explicit;
|
|
7080
7147
|
}
|
|
7148
|
+
return v3Count === 0 ? void 0 : 3;
|
|
7149
|
+
}
|
|
7150
|
+
var EncryptionClient = class {
|
|
7151
|
+
client;
|
|
7152
|
+
encryptConfig;
|
|
7081
7153
|
/**
|
|
7082
|
-
*
|
|
7083
|
-
*
|
|
7084
|
-
*
|
|
7085
|
-
*
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
|
|
7089
|
-
|
|
7090
|
-
|
|
7091
|
-
|
|
7092
|
-
|
|
7093
|
-
|
|
7094
|
-
|
|
7095
|
-
|
|
7096
|
-
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7109
|
-
|
|
7110
|
-
|
|
7111
|
-
|
|
7112
|
-
|
|
7113
|
-
|
|
7114
|
-
|
|
7115
|
-
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7154
|
+
* Initializes the EncryptionClient with the provided configuration.
|
|
7155
|
+
* @internal
|
|
7156
|
+
* @param config - The configuration object for initializing the client.
|
|
7157
|
+
* @returns A promise that resolves to a {@link Result} containing the initialized EncryptionClient or an {@link EncryptionError}.
|
|
7158
|
+
**/
|
|
7159
|
+
async init(config) {
|
|
7160
|
+
return await withResult(
|
|
7161
|
+
async () => {
|
|
7162
|
+
const validated = encryptConfigSchema.parse(
|
|
7163
|
+
config.encryptConfig
|
|
7164
|
+
);
|
|
7165
|
+
logger.debug(
|
|
7166
|
+
"Initializing the Encryption client with the following config:",
|
|
7167
|
+
{
|
|
7168
|
+
encryptConfig: validated
|
|
7169
|
+
}
|
|
7170
|
+
);
|
|
7171
|
+
this.client = await (0, import_protect_ffi9.newClient)({
|
|
7172
|
+
encryptConfig: validated,
|
|
7173
|
+
clientOpts: {
|
|
7174
|
+
workspaceCrn: config.workspaceCrn,
|
|
7175
|
+
accessKey: config.accessKey,
|
|
7176
|
+
clientId: config.clientId,
|
|
7177
|
+
clientKey: config.clientKey,
|
|
7178
|
+
keyset: toFfiKeysetIdentifier(config.keyset)
|
|
7179
|
+
},
|
|
7180
|
+
strategy: config.authStrategy,
|
|
7181
|
+
eqlVersion: config.eqlVersion
|
|
7182
|
+
});
|
|
7183
|
+
this.encryptConfig = validated;
|
|
7184
|
+
logger.debug("Successfully initialized the Encryption client.");
|
|
7185
|
+
return this;
|
|
7186
|
+
},
|
|
7187
|
+
(error) => ({
|
|
7188
|
+
type: EncryptionErrorTypes.ClientInitError,
|
|
7189
|
+
message: error.message
|
|
7190
|
+
})
|
|
7191
|
+
);
|
|
7119
7192
|
}
|
|
7120
7193
|
/**
|
|
7121
|
-
*
|
|
7122
|
-
*
|
|
7123
|
-
* Performs a single call to ZeroKMS to decrypt all values. The result uses
|
|
7124
|
-
* a multi-status pattern: each item in the returned array has either a `data`
|
|
7125
|
-
* field (success) or an `error` field (failure), allowing graceful handling
|
|
7126
|
-
* of partial failures.
|
|
7194
|
+
* Encrypt a value - returns a promise which resolves to an encrypted value.
|
|
7127
7195
|
*
|
|
7128
|
-
* @param
|
|
7129
|
-
* @
|
|
7130
|
-
*
|
|
7131
|
-
* or an `EncryptionError` if the entire operation fails.
|
|
7196
|
+
* @param plaintext - The plaintext value to be encrypted.
|
|
7197
|
+
* @param opts - Options specifying the column (or nested field) and table for encryption. See {@link EncryptOptions}.
|
|
7198
|
+
* @returns An EncryptOperation that can be awaited or chained with additional methods.
|
|
7132
7199
|
*
|
|
7133
7200
|
* @example
|
|
7134
|
-
*
|
|
7135
|
-
*
|
|
7136
|
-
*
|
|
7137
|
-
* const result = await client.bulkDecrypt(encrypted.data)
|
|
7201
|
+
* The following example demonstrates how to encrypt a value using the Encryption client.
|
|
7202
|
+
* It includes defining an encryption schema with {@link encryptedTable} and {@link encryptedColumn},
|
|
7203
|
+
* initializing the client with {@link Encryption}, and performing the encryption.
|
|
7138
7204
|
*
|
|
7139
|
-
*
|
|
7140
|
-
*
|
|
7141
|
-
* if ("data" in item) {
|
|
7142
|
-
* console.log(`${item.id}: ${item.data}`)
|
|
7143
|
-
* } else {
|
|
7144
|
-
* console.error(`${item.id} failed: ${item.error}`)
|
|
7145
|
-
* }
|
|
7146
|
-
* }
|
|
7147
|
-
* }
|
|
7148
|
-
* ```
|
|
7149
|
-
*/
|
|
7150
|
-
bulkDecrypt(encryptedPayloads) {
|
|
7151
|
-
return new BulkDecryptOperation(this.client, encryptedPayloads);
|
|
7152
|
-
}
|
|
7153
|
-
/**
|
|
7154
|
-
* Get the encrypt config object.
|
|
7205
|
+
* `encrypt` returns an {@link EncryptOperation} which can be awaited to get a {@link Result}
|
|
7206
|
+
* which can either be the encrypted value or an {@link EncryptionError}.
|
|
7155
7207
|
*
|
|
7156
|
-
*
|
|
7157
|
-
|
|
7158
|
-
|
|
7159
|
-
|
|
7160
|
-
|
|
7161
|
-
|
|
7162
|
-
|
|
7163
|
-
|
|
7164
|
-
|
|
7165
|
-
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7173
|
-
|
|
7174
|
-
|
|
7175
|
-
|
|
7176
|
-
|
|
7177
|
-
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7182
|
-
|
|
7183
|
-
|
|
7184
|
-
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7192
|
-
|
|
7193
|
-
|
|
7194
|
-
|
|
7195
|
-
|
|
7196
|
-
|
|
7197
|
-
|
|
7198
|
-
|
|
7199
|
-
|
|
7200
|
-
|
|
7201
|
-
|
|
7202
|
-
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
|
|
7208
|
-
|
|
7209
|
-
|
|
7210
|
-
|
|
7211
|
-
}
|
|
7212
|
-
|
|
7213
|
-
|
|
7214
|
-
|
|
7215
|
-
|
|
7216
|
-
|
|
7217
|
-
|
|
7218
|
-
equality: false,
|
|
7219
|
-
orderAndRange: false,
|
|
7220
|
-
freeTextSearch: true
|
|
7221
|
-
};
|
|
7222
|
-
var TEXT_SEARCH = {
|
|
7223
|
-
equality: true,
|
|
7224
|
-
orderAndRange: true,
|
|
7225
|
-
freeTextSearch: true
|
|
7226
|
-
};
|
|
7227
|
-
var TEXT_SEARCH_EQL_TYPE = "eql_v3.text_search";
|
|
7228
|
-
var INTEGER = {
|
|
7229
|
-
eqlType: "eql_v3.integer",
|
|
7230
|
-
castAs: "number",
|
|
7231
|
-
capabilities: STORAGE_ONLY
|
|
7232
|
-
};
|
|
7233
|
-
var INTEGER_EQ = {
|
|
7234
|
-
eqlType: "eql_v3.integer_eq",
|
|
7235
|
-
castAs: "number",
|
|
7236
|
-
capabilities: EQUALITY_ONLY
|
|
7237
|
-
};
|
|
7238
|
-
var INTEGER_ORD_ORE = {
|
|
7239
|
-
eqlType: "eql_v3.integer_ord_ore",
|
|
7240
|
-
castAs: "number",
|
|
7241
|
-
capabilities: ORDER_AND_RANGE
|
|
7242
|
-
};
|
|
7243
|
-
var INTEGER_ORD = {
|
|
7244
|
-
eqlType: "eql_v3.integer_ord",
|
|
7245
|
-
castAs: "number",
|
|
7246
|
-
capabilities: ORDER_AND_RANGE
|
|
7247
|
-
};
|
|
7248
|
-
var SMALLINT = {
|
|
7249
|
-
eqlType: "eql_v3.smallint",
|
|
7250
|
-
castAs: "number",
|
|
7251
|
-
capabilities: STORAGE_ONLY
|
|
7252
|
-
};
|
|
7253
|
-
var SMALLINT_EQ = {
|
|
7254
|
-
eqlType: "eql_v3.smallint_eq",
|
|
7255
|
-
castAs: "number",
|
|
7256
|
-
capabilities: EQUALITY_ONLY
|
|
7257
|
-
};
|
|
7258
|
-
var SMALLINT_ORD_ORE = {
|
|
7259
|
-
eqlType: "eql_v3.smallint_ord_ore",
|
|
7260
|
-
castAs: "number",
|
|
7261
|
-
capabilities: ORDER_AND_RANGE
|
|
7262
|
-
};
|
|
7263
|
-
var SMALLINT_ORD = {
|
|
7264
|
-
eqlType: "eql_v3.smallint_ord",
|
|
7265
|
-
castAs: "number",
|
|
7266
|
-
capabilities: ORDER_AND_RANGE
|
|
7267
|
-
};
|
|
7268
|
-
var DATE = {
|
|
7269
|
-
eqlType: "eql_v3.date",
|
|
7270
|
-
castAs: "date",
|
|
7271
|
-
capabilities: STORAGE_ONLY
|
|
7272
|
-
};
|
|
7273
|
-
var DATE_EQ = {
|
|
7274
|
-
eqlType: "eql_v3.date_eq",
|
|
7275
|
-
castAs: "date",
|
|
7276
|
-
capabilities: EQUALITY_ONLY
|
|
7277
|
-
};
|
|
7278
|
-
var DATE_ORD_ORE = {
|
|
7279
|
-
eqlType: "eql_v3.date_ord_ore",
|
|
7280
|
-
castAs: "date",
|
|
7281
|
-
capabilities: ORDER_AND_RANGE
|
|
7282
|
-
};
|
|
7283
|
-
var DATE_ORD = {
|
|
7284
|
-
eqlType: "eql_v3.date_ord",
|
|
7285
|
-
castAs: "date",
|
|
7286
|
-
capabilities: ORDER_AND_RANGE
|
|
7287
|
-
};
|
|
7288
|
-
var TIMESTAMP = {
|
|
7289
|
-
eqlType: "eql_v3.timestamp",
|
|
7290
|
-
castAs: "timestamp",
|
|
7291
|
-
capabilities: STORAGE_ONLY
|
|
7292
|
-
};
|
|
7293
|
-
var TIMESTAMP_EQ = {
|
|
7294
|
-
eqlType: "eql_v3.timestamp_eq",
|
|
7295
|
-
castAs: "timestamp",
|
|
7296
|
-
capabilities: EQUALITY_ONLY
|
|
7297
|
-
};
|
|
7298
|
-
var TIMESTAMP_ORD_ORE = {
|
|
7299
|
-
eqlType: "eql_v3.timestamp_ord_ore",
|
|
7300
|
-
castAs: "timestamp",
|
|
7301
|
-
capabilities: ORDER_AND_RANGE
|
|
7302
|
-
};
|
|
7303
|
-
var TIMESTAMP_ORD = {
|
|
7304
|
-
eqlType: "eql_v3.timestamp_ord",
|
|
7305
|
-
castAs: "timestamp",
|
|
7306
|
-
capabilities: ORDER_AND_RANGE
|
|
7307
|
-
};
|
|
7308
|
-
var NUMERIC = {
|
|
7309
|
-
eqlType: "eql_v3.numeric",
|
|
7310
|
-
castAs: "number",
|
|
7311
|
-
capabilities: STORAGE_ONLY
|
|
7312
|
-
};
|
|
7313
|
-
var NUMERIC_EQ = {
|
|
7314
|
-
eqlType: "eql_v3.numeric_eq",
|
|
7315
|
-
castAs: "number",
|
|
7316
|
-
capabilities: EQUALITY_ONLY
|
|
7317
|
-
};
|
|
7318
|
-
var NUMERIC_ORD_ORE = {
|
|
7319
|
-
eqlType: "eql_v3.numeric_ord_ore",
|
|
7320
|
-
castAs: "number",
|
|
7321
|
-
capabilities: ORDER_AND_RANGE
|
|
7322
|
-
};
|
|
7323
|
-
var NUMERIC_ORD = {
|
|
7324
|
-
eqlType: "eql_v3.numeric_ord",
|
|
7325
|
-
castAs: "number",
|
|
7326
|
-
capabilities: ORDER_AND_RANGE
|
|
7327
|
-
};
|
|
7328
|
-
var TEXT = {
|
|
7329
|
-
eqlType: "eql_v3.text",
|
|
7330
|
-
castAs: "string",
|
|
7331
|
-
capabilities: STORAGE_ONLY
|
|
7332
|
-
};
|
|
7333
|
-
var TEXT_EQ = {
|
|
7334
|
-
eqlType: "eql_v3.text_eq",
|
|
7335
|
-
castAs: "string",
|
|
7336
|
-
capabilities: EQUALITY_ONLY
|
|
7337
|
-
};
|
|
7338
|
-
var TEXT_MATCH = {
|
|
7339
|
-
eqlType: "eql_v3.text_match",
|
|
7340
|
-
castAs: "string",
|
|
7341
|
-
capabilities: MATCH_ONLY
|
|
7342
|
-
};
|
|
7343
|
-
var TEXT_ORD_ORE = {
|
|
7344
|
-
eqlType: "eql_v3.text_ord_ore",
|
|
7345
|
-
castAs: "string",
|
|
7346
|
-
capabilities: ORDER_AND_RANGE
|
|
7347
|
-
};
|
|
7348
|
-
var TEXT_ORD = {
|
|
7349
|
-
eqlType: "eql_v3.text_ord",
|
|
7350
|
-
castAs: "string",
|
|
7351
|
-
capabilities: ORDER_AND_RANGE
|
|
7352
|
-
};
|
|
7353
|
-
var BOOLEAN = {
|
|
7354
|
-
eqlType: "eql_v3.boolean",
|
|
7355
|
-
castAs: "boolean",
|
|
7356
|
-
capabilities: STORAGE_ONLY
|
|
7357
|
-
};
|
|
7358
|
-
var REAL = {
|
|
7359
|
-
eqlType: "eql_v3.real",
|
|
7360
|
-
castAs: "number",
|
|
7361
|
-
capabilities: STORAGE_ONLY
|
|
7362
|
-
};
|
|
7363
|
-
var REAL_EQ = {
|
|
7364
|
-
eqlType: "eql_v3.real_eq",
|
|
7365
|
-
castAs: "number",
|
|
7366
|
-
capabilities: EQUALITY_ONLY
|
|
7367
|
-
};
|
|
7368
|
-
var REAL_ORD_ORE = {
|
|
7369
|
-
eqlType: "eql_v3.real_ord_ore",
|
|
7370
|
-
castAs: "number",
|
|
7371
|
-
capabilities: ORDER_AND_RANGE
|
|
7372
|
-
};
|
|
7373
|
-
var REAL_ORD = {
|
|
7374
|
-
eqlType: "eql_v3.real_ord",
|
|
7375
|
-
castAs: "number",
|
|
7376
|
-
capabilities: ORDER_AND_RANGE
|
|
7377
|
-
};
|
|
7378
|
-
var DOUBLE = {
|
|
7379
|
-
eqlType: "eql_v3.double",
|
|
7380
|
-
castAs: "number",
|
|
7381
|
-
capabilities: STORAGE_ONLY
|
|
7382
|
-
};
|
|
7383
|
-
var DOUBLE_EQ = {
|
|
7384
|
-
eqlType: "eql_v3.double_eq",
|
|
7385
|
-
castAs: "number",
|
|
7386
|
-
capabilities: EQUALITY_ONLY
|
|
7387
|
-
};
|
|
7388
|
-
var DOUBLE_ORD_ORE = {
|
|
7389
|
-
eqlType: "eql_v3.double_ord_ore",
|
|
7390
|
-
castAs: "number",
|
|
7391
|
-
capabilities: ORDER_AND_RANGE
|
|
7392
|
-
};
|
|
7393
|
-
var DOUBLE_ORD = {
|
|
7394
|
-
eqlType: "eql_v3.double_ord",
|
|
7395
|
-
castAs: "number",
|
|
7396
|
-
capabilities: ORDER_AND_RANGE
|
|
7397
|
-
};
|
|
7398
|
-
function indexesForCapabilities(capabilities, castAs) {
|
|
7399
|
-
const indexes = {};
|
|
7400
|
-
if (capabilities.equality && (!capabilities.orderAndRange || castAs === "string")) {
|
|
7401
|
-
indexes.unique = { token_filters: [] };
|
|
7402
|
-
}
|
|
7403
|
-
if (capabilities.orderAndRange) {
|
|
7404
|
-
indexes.ore = {};
|
|
7405
|
-
}
|
|
7406
|
-
if (capabilities.freeTextSearch) {
|
|
7407
|
-
indexes.match = defaultMatchOpts();
|
|
7208
|
+
* ```typescript
|
|
7209
|
+
* // Define encryption schema
|
|
7210
|
+
* import { Encryption } from "@cipherstash/stack"
|
|
7211
|
+
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
7212
|
+
* const userSchema = encryptedTable("users", {
|
|
7213
|
+
* email: encryptedColumn("email"),
|
|
7214
|
+
* });
|
|
7215
|
+
*
|
|
7216
|
+
* // Initialize Encryption client
|
|
7217
|
+
* const client = await Encryption({ schemas: [userSchema] })
|
|
7218
|
+
*
|
|
7219
|
+
* // Encrypt a value
|
|
7220
|
+
* const encryptedResult = await client.encrypt(
|
|
7221
|
+
* "person@example.com",
|
|
7222
|
+
* { column: userSchema.email, table: userSchema }
|
|
7223
|
+
* )
|
|
7224
|
+
*
|
|
7225
|
+
* // Handle encryption result
|
|
7226
|
+
* if (encryptedResult.failure) {
|
|
7227
|
+
* throw new Error(`Encryption failed: ${encryptedResult.failure.message}`);
|
|
7228
|
+
* }
|
|
7229
|
+
*
|
|
7230
|
+
* console.log("Encrypted data:", encryptedResult.data);
|
|
7231
|
+
* ```
|
|
7232
|
+
*
|
|
7233
|
+
* @example
|
|
7234
|
+
* When encrypting data, a {@link LockContext} can be provided to tie the encryption to a specific user or session.
|
|
7235
|
+
* This ensures that the same lock context is required for decryption.
|
|
7236
|
+
*
|
|
7237
|
+
* The following example demonstrates how to create a lock context using a user's JWT token
|
|
7238
|
+
* and use it during encryption.
|
|
7239
|
+
*
|
|
7240
|
+
* ```typescript
|
|
7241
|
+
* // Define encryption schema and initialize client as above
|
|
7242
|
+
*
|
|
7243
|
+
* // Create a lock for the user's `sub` claim from their JWT
|
|
7244
|
+
* const lc = new LockContext();
|
|
7245
|
+
* const lockContext = await lc.identify(userJwt);
|
|
7246
|
+
*
|
|
7247
|
+
* if (lockContext.failure) {
|
|
7248
|
+
* // Handle the failure
|
|
7249
|
+
* }
|
|
7250
|
+
*
|
|
7251
|
+
* // Encrypt a value with the lock context
|
|
7252
|
+
* // Decryption will then require the same lock context
|
|
7253
|
+
* const encryptedResult = await client.encrypt(
|
|
7254
|
+
* "person@example.com",
|
|
7255
|
+
* { column: userSchema.email, table: userSchema }
|
|
7256
|
+
* )
|
|
7257
|
+
* .withLockContext(lockContext)
|
|
7258
|
+
* ```
|
|
7259
|
+
*
|
|
7260
|
+
* @see {@link EncryptOptions}
|
|
7261
|
+
* @see {@link Result}
|
|
7262
|
+
* @see {@link encryptedTable}
|
|
7263
|
+
* @see {@link encryptedColumn}
|
|
7264
|
+
* @see {@link encryptedField}
|
|
7265
|
+
* @see {@link LockContext}
|
|
7266
|
+
* @see {@link EncryptOperation}
|
|
7267
|
+
*/
|
|
7268
|
+
encrypt(plaintext, opts) {
|
|
7269
|
+
return new EncryptOperation(this.client, plaintext, opts);
|
|
7408
7270
|
}
|
|
7409
|
-
|
|
7410
|
-
|
|
7411
|
-
|
|
7412
|
-
|
|
7413
|
-
|
|
7414
|
-
|
|
7415
|
-
|
|
7416
|
-
|
|
7417
|
-
|
|
7271
|
+
encryptQuery(plaintextOrTerms, opts) {
|
|
7272
|
+
if (!opts && isScalarQueryTermArray(plaintextOrTerms)) {
|
|
7273
|
+
return new BatchEncryptQueryOperation(this.client, plaintextOrTerms);
|
|
7274
|
+
}
|
|
7275
|
+
if (Array.isArray(plaintextOrTerms) && plaintextOrTerms.length === 0 && !opts) {
|
|
7276
|
+
return new BatchEncryptQueryOperation(
|
|
7277
|
+
this.client,
|
|
7278
|
+
[]
|
|
7279
|
+
);
|
|
7280
|
+
}
|
|
7281
|
+
if (!opts) {
|
|
7282
|
+
throw new Error("EncryptQueryOptions are required");
|
|
7283
|
+
}
|
|
7284
|
+
return new EncryptQueryOperation(
|
|
7285
|
+
this.client,
|
|
7286
|
+
plaintextOrTerms,
|
|
7287
|
+
opts
|
|
7288
|
+
);
|
|
7418
7289
|
}
|
|
7419
|
-
|
|
7420
|
-
|
|
7421
|
-
|
|
7422
|
-
|
|
7290
|
+
/**
|
|
7291
|
+
* Decryption - returns a promise which resolves to a decrypted value.
|
|
7292
|
+
*
|
|
7293
|
+
* @param encryptedData - The encrypted data to be decrypted.
|
|
7294
|
+
* @returns A DecryptOperation that can be awaited or chained with additional methods.
|
|
7295
|
+
*
|
|
7296
|
+
* @example
|
|
7297
|
+
* The following example demonstrates how to decrypt a value that was previously encrypted using the {@link encrypt} method.
|
|
7298
|
+
* It includes encrypting a value first, then decrypting it, and handling the result.
|
|
7299
|
+
*
|
|
7300
|
+
* ```typescript
|
|
7301
|
+
* const encryptedData = await client.encrypt(
|
|
7302
|
+
* "person@example.com",
|
|
7303
|
+
* { column: "email", table: "users" }
|
|
7304
|
+
* )
|
|
7305
|
+
* const decryptResult = await client.decrypt(encryptedData)
|
|
7306
|
+
* if (decryptResult.failure) {
|
|
7307
|
+
* throw new Error(`Decryption failed: ${decryptResult.failure.message}`);
|
|
7308
|
+
* }
|
|
7309
|
+
* console.log("Decrypted data:", decryptResult.data);
|
|
7310
|
+
* ```
|
|
7311
|
+
*
|
|
7312
|
+
* @example
|
|
7313
|
+
* Provide a lock context when decrypting:
|
|
7314
|
+
* ```typescript
|
|
7315
|
+
* await client.decrypt(encryptedData)
|
|
7316
|
+
* .withLockContext(lockContext)
|
|
7317
|
+
* ```
|
|
7318
|
+
*
|
|
7319
|
+
* @remarks
|
|
7320
|
+
* The public input type rejects null, but at runtime `decrypt` will
|
|
7321
|
+
* short-circuit and return null when given a null ciphertext
|
|
7322
|
+
* (defense in depth for legacy / manually-NULLed DB rows reached via
|
|
7323
|
+
* casts or dynamic field walking). The narrow return type holds for
|
|
7324
|
+
* any caller that respects the input contract.
|
|
7325
|
+
*
|
|
7326
|
+
* @see {@link LockContext}
|
|
7327
|
+
* @see {@link DecryptOperation}
|
|
7328
|
+
*/
|
|
7329
|
+
decrypt(encryptedData) {
|
|
7330
|
+
return new DecryptOperation(this.client, encryptedData);
|
|
7423
7331
|
}
|
|
7424
|
-
/**
|
|
7425
|
-
|
|
7426
|
-
|
|
7332
|
+
/**
|
|
7333
|
+
* Encrypt a model (object) based on the table schema.
|
|
7334
|
+
*
|
|
7335
|
+
* Only fields whose keys match columns defined in the table schema are encrypted.
|
|
7336
|
+
* All other fields are passed through unchanged. Returns a thenable operation
|
|
7337
|
+
* that supports `.withLockContext()` for identity-aware encryption.
|
|
7338
|
+
*
|
|
7339
|
+
* The return type is **schema-aware**: fields matching the table schema are
|
|
7340
|
+
* typed as `Encrypted`, while other fields retain their original types. For
|
|
7341
|
+
* best results, let TypeScript infer the type parameters from the arguments
|
|
7342
|
+
* rather than providing an explicit type argument.
|
|
7343
|
+
*
|
|
7344
|
+
* @param input - The model object with plaintext values to encrypt.
|
|
7345
|
+
* @param table - The table schema defining which fields to encrypt.
|
|
7346
|
+
* @returns An `EncryptModelOperation` that can be awaited to get a `Result`
|
|
7347
|
+
* containing the model with schema-defined fields typed as `Encrypted`,
|
|
7348
|
+
* or an `EncryptionError`.
|
|
7349
|
+
*
|
|
7350
|
+
* @example
|
|
7351
|
+
* ```typescript
|
|
7352
|
+
* import { Encryption } from "@cipherstash/stack"
|
|
7353
|
+
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
7354
|
+
*
|
|
7355
|
+
* type User = { id: string; email: string; createdAt: Date }
|
|
7356
|
+
*
|
|
7357
|
+
* const usersSchema = encryptedTable("users", {
|
|
7358
|
+
* email: encryptedColumn("email").equality(),
|
|
7359
|
+
* })
|
|
7360
|
+
*
|
|
7361
|
+
* const client = await Encryption({ schemas: [usersSchema] })
|
|
7362
|
+
*
|
|
7363
|
+
* // Let TypeScript infer the return type from the schema.
|
|
7364
|
+
* // result.data.email is typed as `Encrypted`, result.data.id stays `string`.
|
|
7365
|
+
* const result = await client.encryptModel(
|
|
7366
|
+
* { id: "user_123", email: "alice@example.com", createdAt: new Date() },
|
|
7367
|
+
* usersSchema,
|
|
7368
|
+
* )
|
|
7369
|
+
*
|
|
7370
|
+
* if (result.failure) {
|
|
7371
|
+
* console.error(result.failure.message)
|
|
7372
|
+
* } else {
|
|
7373
|
+
* console.log(result.data.id) // string
|
|
7374
|
+
* console.log(result.data.email) // Encrypted
|
|
7375
|
+
* }
|
|
7376
|
+
* ```
|
|
7377
|
+
*/
|
|
7378
|
+
encryptModel(input, table) {
|
|
7379
|
+
return new EncryptModelOperation(
|
|
7380
|
+
this.client,
|
|
7381
|
+
input,
|
|
7382
|
+
table
|
|
7383
|
+
);
|
|
7427
7384
|
}
|
|
7428
|
-
/**
|
|
7429
|
-
|
|
7430
|
-
|
|
7385
|
+
/**
|
|
7386
|
+
* Decrypt a model (object) whose fields contain encrypted values.
|
|
7387
|
+
*
|
|
7388
|
+
* Identifies encrypted fields automatically and decrypts them, returning the
|
|
7389
|
+
* model with plaintext values. Returns a thenable operation that supports
|
|
7390
|
+
* `.withLockContext()` for identity-aware decryption.
|
|
7391
|
+
*
|
|
7392
|
+
* @param input - The model object with encrypted field values.
|
|
7393
|
+
* @returns A `DecryptModelOperation<T>` that can be awaited to get a `Result`
|
|
7394
|
+
* containing the model with decrypted plaintext fields, or an `EncryptionError`.
|
|
7395
|
+
*
|
|
7396
|
+
* @example
|
|
7397
|
+
* ```typescript
|
|
7398
|
+
* // Decrypt a previously encrypted model
|
|
7399
|
+
* const decrypted = await client.decryptModel<User>(encryptedUser)
|
|
7400
|
+
*
|
|
7401
|
+
* if (decrypted.failure) {
|
|
7402
|
+
* console.error(decrypted.failure.message)
|
|
7403
|
+
* } else {
|
|
7404
|
+
* console.log(decrypted.data.email) // "alice@example.com"
|
|
7405
|
+
* }
|
|
7406
|
+
*
|
|
7407
|
+
* // With a lock context
|
|
7408
|
+
* const decrypted = await client
|
|
7409
|
+
* .decryptModel<User>(encryptedUser)
|
|
7410
|
+
* .withLockContext(lockContext)
|
|
7411
|
+
* ```
|
|
7412
|
+
*/
|
|
7413
|
+
decryptModel(input) {
|
|
7414
|
+
return new DecryptModelOperation(this.client, input);
|
|
7431
7415
|
}
|
|
7432
|
-
/**
|
|
7433
|
-
|
|
7434
|
-
|
|
7435
|
-
|
|
7416
|
+
/**
|
|
7417
|
+
* Encrypt multiple models (objects) in a single bulk operation.
|
|
7418
|
+
*
|
|
7419
|
+
* Performs a single call to ZeroKMS regardless of the number of models,
|
|
7420
|
+
* while still using a unique key for each encrypted value. Only fields
|
|
7421
|
+
* matching the table schema are encrypted; other fields pass through unchanged.
|
|
7422
|
+
*
|
|
7423
|
+
* The return type is **schema-aware**: fields matching the table schema are
|
|
7424
|
+
* typed as `Encrypted`, while other fields retain their original types. For
|
|
7425
|
+
* best results, let TypeScript infer the type parameters from the arguments.
|
|
7426
|
+
*
|
|
7427
|
+
* @param input - An array of model objects with plaintext values to encrypt.
|
|
7428
|
+
* @param table - The table schema defining which fields to encrypt.
|
|
7429
|
+
* @returns A `BulkEncryptModelsOperation` that can be awaited to get a `Result`
|
|
7430
|
+
* containing an array of models with schema-defined fields typed as `Encrypted`,
|
|
7431
|
+
* or an `EncryptionError`.
|
|
7432
|
+
*
|
|
7433
|
+
* @example
|
|
7434
|
+
* ```typescript
|
|
7435
|
+
* import { Encryption } from "@cipherstash/stack"
|
|
7436
|
+
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
7437
|
+
*
|
|
7438
|
+
* type User = { id: string; email: string }
|
|
7439
|
+
*
|
|
7440
|
+
* const usersSchema = encryptedTable("users", {
|
|
7441
|
+
* email: encryptedColumn("email"),
|
|
7442
|
+
* })
|
|
7443
|
+
*
|
|
7444
|
+
* const client = await Encryption({ schemas: [usersSchema] })
|
|
7445
|
+
*
|
|
7446
|
+
* // Let TypeScript infer the return type from the schema.
|
|
7447
|
+
* // Each item's email is typed as `Encrypted`, id stays `string`.
|
|
7448
|
+
* const result = await client.bulkEncryptModels(
|
|
7449
|
+
* [
|
|
7450
|
+
* { id: "1", email: "alice@example.com" },
|
|
7451
|
+
* { id: "2", email: "bob@example.com" },
|
|
7452
|
+
* ],
|
|
7453
|
+
* usersSchema,
|
|
7454
|
+
* )
|
|
7455
|
+
*
|
|
7456
|
+
* if (!result.failure) {
|
|
7457
|
+
* console.log(result.data) // array of models with encrypted email fields
|
|
7458
|
+
* }
|
|
7459
|
+
* ```
|
|
7460
|
+
*/
|
|
7461
|
+
bulkEncryptModels(input, table) {
|
|
7462
|
+
return new BulkEncryptModelsOperation(
|
|
7463
|
+
this.client,
|
|
7464
|
+
input,
|
|
7465
|
+
table
|
|
7436
7466
|
);
|
|
7437
7467
|
}
|
|
7438
|
-
/**
|
|
7439
|
-
|
|
7440
|
-
|
|
7441
|
-
|
|
7442
|
-
|
|
7443
|
-
|
|
7444
|
-
|
|
7445
|
-
|
|
7446
|
-
|
|
7468
|
+
/**
|
|
7469
|
+
* Decrypt multiple models (objects) in a single bulk operation.
|
|
7470
|
+
*
|
|
7471
|
+
* Performs a single call to ZeroKMS regardless of the number of models,
|
|
7472
|
+
* restoring all encrypted fields to their original plaintext values.
|
|
7473
|
+
*
|
|
7474
|
+
* @param input - An array of model objects with encrypted field values.
|
|
7475
|
+
* @returns A `BulkDecryptModelsOperation<T>` that can be awaited to get a `Result`
|
|
7476
|
+
* containing an array of models with decrypted plaintext fields, or an `EncryptionError`.
|
|
7477
|
+
*
|
|
7478
|
+
* @example
|
|
7479
|
+
* ```typescript
|
|
7480
|
+
* const encryptedUsers = encryptedResult.data // from bulkEncryptModels
|
|
7481
|
+
*
|
|
7482
|
+
* const result = await client.bulkDecryptModels<User>(encryptedUsers)
|
|
7483
|
+
*
|
|
7484
|
+
* if (!result.failure) {
|
|
7485
|
+
* for (const user of result.data) {
|
|
7486
|
+
* console.log(user.email) // plaintext email
|
|
7487
|
+
* }
|
|
7488
|
+
* }
|
|
7489
|
+
*
|
|
7490
|
+
* // With a lock context
|
|
7491
|
+
* const result = await client
|
|
7492
|
+
* .bulkDecryptModels<User>(encryptedUsers)
|
|
7493
|
+
* .withLockContext(lockContext)
|
|
7494
|
+
* ```
|
|
7495
|
+
*/
|
|
7496
|
+
bulkDecryptModels(input) {
|
|
7497
|
+
return new BulkDecryptModelsOperation(this.client, input);
|
|
7447
7498
|
}
|
|
7448
|
-
|
|
7449
|
-
|
|
7450
|
-
|
|
7451
|
-
|
|
7452
|
-
|
|
7453
|
-
|
|
7454
|
-
|
|
7455
|
-
|
|
7456
|
-
|
|
7457
|
-
|
|
7458
|
-
|
|
7499
|
+
/**
|
|
7500
|
+
* Encrypt multiple plaintext values in a single bulk operation.
|
|
7501
|
+
*
|
|
7502
|
+
* Each value is encrypted with its own unique key via a single call to ZeroKMS.
|
|
7503
|
+
* Values can include optional `id` fields for correlating results back to
|
|
7504
|
+
* your application data.
|
|
7505
|
+
*
|
|
7506
|
+
* @param plaintexts - An array of objects with `plaintext` (and optional `id`) fields.
|
|
7507
|
+
* @param opts - Options specifying the target column (or nested {@link encryptedField}) and table. See {@link EncryptOptions}.
|
|
7508
|
+
* @returns A `BulkEncryptOperation` that can be awaited to get a `Result`
|
|
7509
|
+
* containing an array of `{ id?, data: Encrypted }` objects, or an `EncryptionError`.
|
|
7510
|
+
*
|
|
7511
|
+
* @example
|
|
7512
|
+
* ```typescript
|
|
7513
|
+
* import { Encryption } from "@cipherstash/stack"
|
|
7514
|
+
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
7515
|
+
*
|
|
7516
|
+
* const users = encryptedTable("users", {
|
|
7517
|
+
* email: encryptedColumn("email"),
|
|
7518
|
+
* })
|
|
7519
|
+
* const client = await Encryption({ schemas: [users] })
|
|
7520
|
+
*
|
|
7521
|
+
* const result = await client.bulkEncrypt(
|
|
7522
|
+
* [
|
|
7523
|
+
* { id: "u1", plaintext: "alice@example.com" },
|
|
7524
|
+
* { id: "u2", plaintext: "bob@example.com" },
|
|
7525
|
+
* ],
|
|
7526
|
+
* { column: users.email, table: users },
|
|
7527
|
+
* )
|
|
7528
|
+
*
|
|
7529
|
+
* if (!result.failure) {
|
|
7530
|
+
* // result.data = [{ id: "u1", data: Encrypted }, { id: "u2", data: Encrypted }, ...]
|
|
7531
|
+
* console.log(result.data)
|
|
7532
|
+
* }
|
|
7533
|
+
* ```
|
|
7534
|
+
*/
|
|
7535
|
+
bulkEncrypt(plaintexts, opts) {
|
|
7536
|
+
return new BulkEncryptOperation(this.client, plaintexts, opts);
|
|
7459
7537
|
}
|
|
7460
7538
|
/**
|
|
7461
|
-
*
|
|
7462
|
-
*
|
|
7463
|
-
*
|
|
7539
|
+
* Decrypt multiple encrypted values in a single bulk operation.
|
|
7540
|
+
*
|
|
7541
|
+
* Performs a single call to ZeroKMS to decrypt all values. The result uses
|
|
7542
|
+
* a multi-status pattern: each item in the returned array has either a `data`
|
|
7543
|
+
* field (success) or an `error` field (failure), allowing graceful handling
|
|
7544
|
+
* of partial failures.
|
|
7545
|
+
*
|
|
7546
|
+
* @param encryptedPayloads - An array of objects with `data` (encrypted payload) and optional `id` fields.
|
|
7547
|
+
* @returns A `BulkDecryptOperation` that can be awaited to get a `Result`
|
|
7548
|
+
* containing an array of `{ id?, data: plaintext }` or `{ id?, error: string }` objects,
|
|
7549
|
+
* or an `EncryptionError` if the entire operation fails.
|
|
7550
|
+
*
|
|
7551
|
+
* @example
|
|
7552
|
+
* ```typescript
|
|
7553
|
+
* const encrypted = await client.bulkEncrypt(plaintexts, { column: users.email, table: users })
|
|
7554
|
+
*
|
|
7555
|
+
* const result = await client.bulkDecrypt(encrypted.data)
|
|
7556
|
+
*
|
|
7557
|
+
* if (!result.failure) {
|
|
7558
|
+
* for (const item of result.data) {
|
|
7559
|
+
* if ("data" in item) {
|
|
7560
|
+
* console.log(`${item.id}: ${item.data}`)
|
|
7561
|
+
* } else {
|
|
7562
|
+
* console.error(`${item.id} failed: ${item.error}`)
|
|
7563
|
+
* }
|
|
7564
|
+
* }
|
|
7565
|
+
* }
|
|
7566
|
+
* ```
|
|
7464
7567
|
*/
|
|
7465
|
-
|
|
7466
|
-
|
|
7467
|
-
this.matchOpts = cloneMatchOpts({
|
|
7468
|
-
tokenizer: opts?.tokenizer ?? defaults.tokenizer,
|
|
7469
|
-
token_filters: opts?.token_filters ?? defaults.token_filters,
|
|
7470
|
-
k: opts?.k ?? defaults.k,
|
|
7471
|
-
m: opts?.m ?? defaults.m,
|
|
7472
|
-
include_original: opts?.include_original ?? defaults.include_original
|
|
7473
|
-
});
|
|
7474
|
-
return this;
|
|
7568
|
+
bulkDecrypt(encryptedPayloads) {
|
|
7569
|
+
return new BulkDecryptOperation(this.client, encryptedPayloads);
|
|
7475
7570
|
}
|
|
7476
|
-
/**
|
|
7477
|
-
|
|
7478
|
-
|
|
7479
|
-
|
|
7480
|
-
|
|
7481
|
-
|
|
7482
|
-
|
|
7483
|
-
match: cloneMatchOpts(this.matchOpts)
|
|
7484
|
-
}
|
|
7485
|
-
};
|
|
7571
|
+
/**
|
|
7572
|
+
* Get the encrypt config object.
|
|
7573
|
+
*
|
|
7574
|
+
* @returns The encrypt config object.
|
|
7575
|
+
*/
|
|
7576
|
+
getEncryptConfig() {
|
|
7577
|
+
return this.encryptConfig;
|
|
7486
7578
|
}
|
|
7487
7579
|
};
|
|
7488
|
-
var
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7493
|
-
|
|
7494
|
-
|
|
7495
|
-
}
|
|
7496
|
-
var
|
|
7497
|
-
};
|
|
7498
|
-
|
|
7499
|
-
|
|
7500
|
-
|
|
7501
|
-
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
|
|
7505
|
-
|
|
7506
|
-
|
|
7507
|
-
}
|
|
7508
|
-
|
|
7509
|
-
|
|
7510
|
-
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
|
|
7522
|
-
|
|
7523
|
-
}
|
|
7524
|
-
|
|
7525
|
-
};
|
|
7526
|
-
var EncryptedNumericOrdColumn = class extends EncryptedV3Column {
|
|
7527
|
-
};
|
|
7528
|
-
var EncryptedTextColumn = class extends EncryptedV3Column {
|
|
7529
|
-
};
|
|
7530
|
-
var EncryptedTextEqColumn = class extends EncryptedV3Column {
|
|
7531
|
-
};
|
|
7532
|
-
var EncryptedTextMatchColumn = class extends EncryptedV3Column {
|
|
7533
|
-
};
|
|
7534
|
-
var EncryptedTextOrdOreColumn = class extends EncryptedV3Column {
|
|
7535
|
-
};
|
|
7536
|
-
var EncryptedTextOrdColumn = class extends EncryptedV3Column {
|
|
7537
|
-
};
|
|
7538
|
-
var EncryptedBooleanColumn = class extends EncryptedV3Column {
|
|
7539
|
-
};
|
|
7540
|
-
var EncryptedRealColumn = class extends EncryptedV3Column {
|
|
7541
|
-
};
|
|
7542
|
-
var EncryptedRealEqColumn = class extends EncryptedV3Column {
|
|
7543
|
-
};
|
|
7544
|
-
var EncryptedRealOrdOreColumn = class extends EncryptedV3Column {
|
|
7545
|
-
};
|
|
7546
|
-
var EncryptedRealOrdColumn = class extends EncryptedV3Column {
|
|
7547
|
-
};
|
|
7548
|
-
var EncryptedDoubleColumn = class extends EncryptedV3Column {
|
|
7549
|
-
};
|
|
7550
|
-
var EncryptedDoubleEqColumn = class extends EncryptedV3Column {
|
|
7551
|
-
};
|
|
7552
|
-
var EncryptedDoubleOrdOreColumn = class extends EncryptedV3Column {
|
|
7553
|
-
};
|
|
7554
|
-
var EncryptedDoubleOrdColumn = class extends EncryptedV3Column {
|
|
7580
|
+
var warnedStrategyDeprecated = false;
|
|
7581
|
+
function warnStrategyDeprecated() {
|
|
7582
|
+
if (warnedStrategyDeprecated) return;
|
|
7583
|
+
warnedStrategyDeprecated = true;
|
|
7584
|
+
console.warn(
|
|
7585
|
+
"[encryption]: `config.strategy` is deprecated and will be removed in a future release \u2014 use `config.authStrategy` instead."
|
|
7586
|
+
);
|
|
7587
|
+
}
|
|
7588
|
+
var Encryption = async (config) => {
|
|
7589
|
+
const { schemas, config: clientConfig } = config;
|
|
7590
|
+
if (!schemas.length) {
|
|
7591
|
+
throw new Error(
|
|
7592
|
+
"[encryption]: At least one encryptedTable must be provided to initialize the encryption client"
|
|
7593
|
+
);
|
|
7594
|
+
}
|
|
7595
|
+
if (clientConfig?.keyset && "id" in clientConfig.keyset && !validate_default(clientConfig.keyset.id)) {
|
|
7596
|
+
throw new Error(
|
|
7597
|
+
"[encryption]: Invalid UUID provided for keyset id. Must be a valid UUID."
|
|
7598
|
+
);
|
|
7599
|
+
}
|
|
7600
|
+
if (clientConfig?.strategy) {
|
|
7601
|
+
warnStrategyDeprecated();
|
|
7602
|
+
}
|
|
7603
|
+
const authStrategy = clientConfig?.authStrategy ?? clientConfig?.strategy;
|
|
7604
|
+
const client = new EncryptionClient();
|
|
7605
|
+
const encryptConfig = buildEncryptConfig(...schemas);
|
|
7606
|
+
const eqlVersion = resolveEqlVersion(schemas, clientConfig?.eqlVersion);
|
|
7607
|
+
const result = await client.init({
|
|
7608
|
+
encryptConfig,
|
|
7609
|
+
...clientConfig,
|
|
7610
|
+
authStrategy,
|
|
7611
|
+
eqlVersion
|
|
7612
|
+
});
|
|
7613
|
+
if (result.failure) {
|
|
7614
|
+
throw new Error(`[encryption]: ${result.failure.message}`);
|
|
7615
|
+
}
|
|
7616
|
+
return result.data;
|
|
7555
7617
|
};
|
|
7556
7618
|
|
|
7557
7619
|
// src/eql/v3/table.ts
|
|
@@ -7563,7 +7625,7 @@ var EncryptedTable = class {
|
|
|
7563
7625
|
tableName;
|
|
7564
7626
|
columnBuilders;
|
|
7565
7627
|
build() {
|
|
7566
|
-
const builtColumns =
|
|
7628
|
+
const builtColumns = /* @__PURE__ */ Object.create(null);
|
|
7567
7629
|
for (const builder of Object.values(this.columnBuilders)) {
|
|
7568
7630
|
const name = builder.getName();
|
|
7569
7631
|
if (Object.hasOwn(builtColumns, name)) {
|
|
@@ -7584,9 +7646,19 @@ var EncryptedTable = class {
|
|
|
7584
7646
|
* encrypt config and FFI by DB name — `build()` keys columns by DB name, so
|
|
7585
7647
|
* the two only agree when property == name. This recovers the mapping that
|
|
7586
7648
|
* `build()` discards.
|
|
7649
|
+
*
|
|
7650
|
+
* NULL PROTOTYPE — load-bearing. Callers index this map by a column name that
|
|
7651
|
+
* ultimately comes from the database (`addJsonbCastsV3`, `filterColumnName`,
|
|
7652
|
+
* the mutation transform). On a plain object literal, a column named
|
|
7653
|
+
* `constructor` / `toString` / `valueOf` / `__proto__` resolves to an
|
|
7654
|
+
* inherited `Object.prototype` member, which is truthy — so a *plaintext*
|
|
7655
|
+
* column with such a name would be mistaken for a mapped encrypted column and
|
|
7656
|
+
* its `Object.prototype` value interpolated into the emitted select string.
|
|
7657
|
+
* `encryptedTable()` rejects such names as JS *properties*, but nothing
|
|
7658
|
+
* constrains the DB column names a table may contain.
|
|
7587
7659
|
*/
|
|
7588
7660
|
buildColumnKeyMap() {
|
|
7589
|
-
const map =
|
|
7661
|
+
const map = /* @__PURE__ */ Object.create(null);
|
|
7590
7662
|
for (const [property, builder] of Object.entries(this.columnBuilders)) {
|
|
7591
7663
|
map[property] = builder.getName();
|
|
7592
7664
|
}
|
|
@@ -7648,6 +7720,12 @@ var types = {
|
|
|
7648
7720
|
SmallintEq: (name) => new EncryptedSmallintEqColumn(name, SMALLINT_EQ),
|
|
7649
7721
|
SmallintOrdOre: (name) => new EncryptedSmallintOrdOreColumn(name, SMALLINT_ORD_ORE),
|
|
7650
7722
|
SmallintOrd: (name) => new EncryptedSmallintOrdColumn(name, SMALLINT_ORD),
|
|
7723
|
+
// bigint (int8) — plaintext is a JS `bigint`, round-tripped losslessly by
|
|
7724
|
+
// the native protect-ffi boundary (see ./columns)
|
|
7725
|
+
Bigint: (name) => new EncryptedBigintColumn(name, BIGINT),
|
|
7726
|
+
BigintEq: (name) => new EncryptedBigintEqColumn(name, BIGINT_EQ),
|
|
7727
|
+
BigintOrdOre: (name) => new EncryptedBigintOrdOreColumn(name, BIGINT_ORD_ORE),
|
|
7728
|
+
BigintOrd: (name) => new EncryptedBigintOrdColumn(name, BIGINT_ORD),
|
|
7651
7729
|
// date
|
|
7652
7730
|
Date: (name) => new EncryptedDateColumn(name, DATE),
|
|
7653
7731
|
DateEq: (name) => new EncryptedDateEqColumn(name, DATE_EQ),
|
|
@@ -7681,7 +7759,14 @@ var types = {
|
|
|
7681
7759
|
Double: (name) => new EncryptedDoubleColumn(name, DOUBLE),
|
|
7682
7760
|
DoubleEq: (name) => new EncryptedDoubleEqColumn(name, DOUBLE_EQ),
|
|
7683
7761
|
DoubleOrdOre: (name) => new EncryptedDoubleOrdOreColumn(name, DOUBLE_ORD_ORE),
|
|
7684
|
-
DoubleOrd: (name) => new EncryptedDoubleOrdColumn(name, DOUBLE_ORD)
|
|
7762
|
+
DoubleOrd: (name) => new EncryptedDoubleOrdColumn(name, DOUBLE_ORD),
|
|
7763
|
+
// json (encrypted JSONB document, ste_vec containment)
|
|
7764
|
+
Json: (name) => new EncryptedJsonColumn(name)
|
|
7765
|
+
// `satisfies` is load-bearing, not decoration: `DOMAIN_REGISTRY` derives itself
|
|
7766
|
+
// by calling every value here at module load. A non-factory export would throw
|
|
7767
|
+
// during module evaluation and take the supabase introspect/schema-build/verify
|
|
7768
|
+
// path down with it. This turns that into a compile error at the offending line.
|
|
7769
|
+
// `as const` applies first, so literal key inference is preserved.
|
|
7685
7770
|
};
|
|
7686
7771
|
|
|
7687
7772
|
// src/encryption/v3.ts
|
|
@@ -7690,7 +7775,7 @@ function rowReconstructor(table) {
|
|
|
7690
7775
|
const propToDb = table.buildColumnKeyMap();
|
|
7691
7776
|
const dateProperties = Object.entries(propToDb).filter(([, dbName]) => {
|
|
7692
7777
|
const castAs = columns[dbName]?.cast_as;
|
|
7693
|
-
return castAs
|
|
7778
|
+
return DATE_LIKE_CASTS.includes(castAs);
|
|
7694
7779
|
}).map(([property]) => property);
|
|
7695
7780
|
return (row) => {
|
|
7696
7781
|
const out = { ...row };
|
|
@@ -7702,24 +7787,40 @@ function rowReconstructor(table) {
|
|
|
7702
7787
|
return out;
|
|
7703
7788
|
};
|
|
7704
7789
|
}
|
|
7705
|
-
function typedClient(client, ...
|
|
7790
|
+
function typedClient(client, ...schemas) {
|
|
7791
|
+
const reconstructors = /* @__PURE__ */ new Map();
|
|
7792
|
+
for (const table of schemas) {
|
|
7793
|
+
reconstructors.set(table.tableName, rowReconstructor(table));
|
|
7794
|
+
}
|
|
7795
|
+
const unknownTableFailure = {
|
|
7796
|
+
failure: {
|
|
7797
|
+
type: EncryptionErrorTypes.DecryptionError,
|
|
7798
|
+
message: "[eql/v3]: decryptModel received a table this client was not initialized with \u2014 pass a table given to EncryptionV3/typedClient"
|
|
7799
|
+
}
|
|
7800
|
+
};
|
|
7801
|
+
function encryptQuery(plaintextOrTerms, opts) {
|
|
7802
|
+
return client.encryptQuery(plaintextOrTerms, opts);
|
|
7803
|
+
}
|
|
7706
7804
|
return {
|
|
7707
7805
|
encrypt: (plaintext, opts) => client.encrypt(plaintext, opts),
|
|
7708
|
-
encryptQuery
|
|
7806
|
+
encryptQuery,
|
|
7709
7807
|
encryptModel: (input, table) => client.encryptModel(input, table),
|
|
7710
7808
|
bulkEncryptModels: (input, table) => client.bulkEncryptModels(input, table),
|
|
7711
7809
|
decrypt: (encrypted) => client.decrypt(encrypted),
|
|
7712
7810
|
decryptModel: async (input, table, lockContext) => {
|
|
7811
|
+
const reconstruct = reconstructors.get(table.tableName);
|
|
7812
|
+
if (!reconstruct) return unknownTableFailure;
|
|
7713
7813
|
const op = client.decryptModel(input);
|
|
7714
7814
|
const result = await (lockContext ? op.withLockContext(lockContext) : op);
|
|
7715
7815
|
if (result.failure) return result;
|
|
7716
|
-
return { data:
|
|
7816
|
+
return { data: reconstruct(result.data) };
|
|
7717
7817
|
},
|
|
7718
7818
|
bulkDecryptModels: async (input, table, lockContext) => {
|
|
7819
|
+
const reconstruct = reconstructors.get(table.tableName);
|
|
7820
|
+
if (!reconstruct) return unknownTableFailure;
|
|
7719
7821
|
const op = client.bulkDecryptModels(input);
|
|
7720
7822
|
const result = await (lockContext ? op.withLockContext(lockContext) : op);
|
|
7721
7823
|
if (result.failure) return result;
|
|
7722
|
-
const reconstruct = rowReconstructor(table);
|
|
7723
7824
|
return {
|
|
7724
7825
|
data: result.data.map(
|
|
7725
7826
|
(row) => reconstruct(row)
|
|
@@ -7734,17 +7835,20 @@ function typedClient(client, ..._schemas) {
|
|
|
7734
7835
|
async function EncryptionV3(config) {
|
|
7735
7836
|
const client = await Encryption({
|
|
7736
7837
|
schemas: config.schemas,
|
|
7737
|
-
//
|
|
7738
|
-
//
|
|
7739
|
-
//
|
|
7740
|
-
//
|
|
7741
|
-
|
|
7742
|
-
config: { ...config.config, eqlVersion: config.config?.eqlVersion ?? 3 }
|
|
7838
|
+
// Force the v3 EQL wire format. protect-ffi's newClient defaults to
|
|
7839
|
+
// eqlVersion 2; a v2-mode client cannot resolve v3 concrete-type columns
|
|
7840
|
+
// and fails every encrypt with "Cannot convert undefined or null to
|
|
7841
|
+
// object". This is a v3-only invariant, so it overrides any user value.
|
|
7842
|
+
config: { ...config.config, eqlVersion: 3 }
|
|
7743
7843
|
});
|
|
7744
7844
|
return typedClient(client, ...config.schemas);
|
|
7745
7845
|
}
|
|
7746
7846
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7747
7847
|
0 && (module.exports = {
|
|
7848
|
+
EncryptedBigintColumn,
|
|
7849
|
+
EncryptedBigintEqColumn,
|
|
7850
|
+
EncryptedBigintOrdColumn,
|
|
7851
|
+
EncryptedBigintOrdOreColumn,
|
|
7748
7852
|
EncryptedBooleanColumn,
|
|
7749
7853
|
EncryptedDateColumn,
|
|
7750
7854
|
EncryptedDateEqColumn,
|
|
@@ -7758,6 +7862,7 @@ async function EncryptionV3(config) {
|
|
|
7758
7862
|
EncryptedIntegerEqColumn,
|
|
7759
7863
|
EncryptedIntegerOrdColumn,
|
|
7760
7864
|
EncryptedIntegerOrdOreColumn,
|
|
7865
|
+
EncryptedJsonColumn,
|
|
7761
7866
|
EncryptedNumericColumn,
|
|
7762
7867
|
EncryptedNumericEqColumn,
|
|
7763
7868
|
EncryptedNumericOrdColumn,
|