@cipherstash/stack 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE.md +21 -0
  3. package/README.md +670 -0
  4. package/dist/bin/stash.js +5049 -0
  5. package/dist/bin/stash.js.map +1 -0
  6. package/dist/chunk-2GZMIJFO.js +2400 -0
  7. package/dist/chunk-2GZMIJFO.js.map +1 -0
  8. package/dist/chunk-5DCT6YU2.js +138 -0
  9. package/dist/chunk-5DCT6YU2.js.map +1 -0
  10. package/dist/chunk-7XRPN2KX.js +336 -0
  11. package/dist/chunk-7XRPN2KX.js.map +1 -0
  12. package/dist/chunk-SJ7JO4ME.js +28 -0
  13. package/dist/chunk-SJ7JO4ME.js.map +1 -0
  14. package/dist/chunk-SUYMGQBY.js +67 -0
  15. package/dist/chunk-SUYMGQBY.js.map +1 -0
  16. package/dist/client-BxJG56Ey.d.cts +647 -0
  17. package/dist/client-DtGq9dJp.d.ts +647 -0
  18. package/dist/client.cjs +347 -0
  19. package/dist/client.cjs.map +1 -0
  20. package/dist/client.d.cts +7 -0
  21. package/dist/client.d.ts +7 -0
  22. package/dist/client.js +11 -0
  23. package/dist/client.js.map +1 -0
  24. package/dist/drizzle/index.cjs +1528 -0
  25. package/dist/drizzle/index.cjs.map +1 -0
  26. package/dist/drizzle/index.d.cts +350 -0
  27. package/dist/drizzle/index.d.ts +350 -0
  28. package/dist/drizzle/index.js +1212 -0
  29. package/dist/drizzle/index.js.map +1 -0
  30. package/dist/dynamodb/index.cjs +382 -0
  31. package/dist/dynamodb/index.cjs.map +1 -0
  32. package/dist/dynamodb/index.d.cts +125 -0
  33. package/dist/dynamodb/index.d.ts +125 -0
  34. package/dist/dynamodb/index.js +355 -0
  35. package/dist/dynamodb/index.js.map +1 -0
  36. package/dist/identity/index.cjs +271 -0
  37. package/dist/identity/index.cjs.map +1 -0
  38. package/dist/identity/index.d.cts +3 -0
  39. package/dist/identity/index.d.ts +3 -0
  40. package/dist/identity/index.js +117 -0
  41. package/dist/identity/index.js.map +1 -0
  42. package/dist/index-9-Ya3fDK.d.cts +169 -0
  43. package/dist/index-9-Ya3fDK.d.ts +169 -0
  44. package/dist/index.cjs +2915 -0
  45. package/dist/index.cjs.map +1 -0
  46. package/dist/index.d.cts +22 -0
  47. package/dist/index.d.ts +22 -0
  48. package/dist/index.js +23 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/schema/index.cjs +368 -0
  51. package/dist/schema/index.cjs.map +1 -0
  52. package/dist/schema/index.d.cts +4 -0
  53. package/dist/schema/index.d.ts +4 -0
  54. package/dist/schema/index.js +23 -0
  55. package/dist/schema/index.js.map +1 -0
  56. package/dist/secrets/index.cjs +3207 -0
  57. package/dist/secrets/index.cjs.map +1 -0
  58. package/dist/secrets/index.d.cts +227 -0
  59. package/dist/secrets/index.d.ts +227 -0
  60. package/dist/secrets/index.js +323 -0
  61. package/dist/secrets/index.js.map +1 -0
  62. package/dist/supabase/index.cjs +1113 -0
  63. package/dist/supabase/index.cjs.map +1 -0
  64. package/dist/supabase/index.d.cts +144 -0
  65. package/dist/supabase/index.d.ts +144 -0
  66. package/dist/supabase/index.js +864 -0
  67. package/dist/supabase/index.js.map +1 -0
  68. package/dist/types-public-BCj1L4fi.d.cts +1013 -0
  69. package/dist/types-public-BCj1L4fi.d.ts +1013 -0
  70. package/dist/types-public.cjs +40 -0
  71. package/dist/types-public.cjs.map +1 -0
  72. package/dist/types-public.d.cts +4 -0
  73. package/dist/types-public.d.ts +4 -0
  74. package/dist/types-public.js +7 -0
  75. package/dist/types-public.js.map +1 -0
  76. package/package.json +202 -0
@@ -0,0 +1,350 @@
1
+ import * as drizzle_orm_pg_core from 'drizzle-orm/pg-core';
2
+ import { PgTable } from 'drizzle-orm/pg-core';
3
+ import { e as encryptedTable, C as CastAs, M as MatchIndexOpts, T as TokenFilter } from '../types-public-BCj1L4fi.js';
4
+ import { E as EncryptionClient } from '../client-DtGq9dJp.js';
5
+ import { SQLWrapper, SQL, exists, notExists, isNull, isNotNull, not, arrayContains, arrayContained, arrayOverlaps } from 'drizzle-orm';
6
+ import 'zod';
7
+ import 'evlog';
8
+ import '@cipherstash/protect-ffi';
9
+ import '../index-9-Ya3fDK.js';
10
+ import '@byteslice/result';
11
+
12
+ /**
13
+ * Extracts an encryption schema from a Drizzle table definition.
14
+ * This function identifies columns created with `encryptedType` and
15
+ * builds a corresponding `ProtectTable` with `encryptedColumn` definitions.
16
+ *
17
+ * @param table - The Drizzle table definition
18
+ * @returns A ProtectTable that can be used with encryption client initialization
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * const drizzleUsersTable = pgTable('users', {
23
+ * email: encryptedType('email', { freeTextSearch: true, equality: true }),
24
+ * age: encryptedType('age', { dataType: 'number', orderAndRange: true }),
25
+ * })
26
+ *
27
+ * const encryptionSchema = extractEncryptionSchema(drizzleUsersTable)
28
+ * const client = await createEncryptionClient({ schemas: [encryptionSchema.build()] })
29
+ * ```
30
+ */
31
+ declare function extractEncryptionSchema<T extends PgTable<any>>(table: T): ReturnType<typeof encryptedTable<Record<string, ProtectColumn>>>;
32
+
33
+ /**
34
+ * Custom error types for better debugging
35
+ */
36
+ declare class EncryptionOperatorError extends Error {
37
+ readonly context?: {
38
+ tableName?: string;
39
+ columnName?: string;
40
+ operator?: string;
41
+ } | undefined;
42
+ constructor(message: string, context?: {
43
+ tableName?: string;
44
+ columnName?: string;
45
+ operator?: string;
46
+ } | undefined);
47
+ }
48
+ declare class EncryptionConfigError extends EncryptionOperatorError {
49
+ constructor(message: string, context?: EncryptionOperatorError['context']);
50
+ }
51
+ /**
52
+ * Creates a set of encryption-aware operators that automatically encrypt values
53
+ * for encrypted columns before using them with Drizzle operators.
54
+ *
55
+ * For equality and text search operators (eq, ne, like, ilike, inArray, etc.):
56
+ * Values are encrypted and then passed to regular Drizzle operators, which use
57
+ * PostgreSQL's built-in operators for eql_v2_encrypted types.
58
+ *
59
+ * For order and range operators (gt, gte, lt, lte, between, notBetween):
60
+ * Values are encrypted and then use eql_v2.* functions (eql_v2.gt(), eql_v2.gte(), etc.)
61
+ * which are required for ORE (Order-Revealing Encryption) comparisons.
62
+ *
63
+ * @param encryptionClient - The EncryptionClient instance
64
+ * @returns An object with all Drizzle operators wrapped for encrypted columns
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * // Initialize operators
69
+ * const ops = createEncryptionOperators(encryptionClient)
70
+ *
71
+ * // Equality search - automatically encrypts and uses PostgreSQL operators
72
+ * const results = await db
73
+ * .select()
74
+ * .from(usersTable)
75
+ * .where(await ops.eq(usersTable.email, 'user@example.com'))
76
+ *
77
+ * // Range query - automatically encrypts and uses eql_v2.gte()
78
+ * const olderUsers = await db
79
+ * .select()
80
+ * .from(usersTable)
81
+ * .where(await ops.gte(usersTable.age, 25))
82
+ * ```
83
+ */
84
+ declare function createEncryptionOperators(encryptionClient: EncryptionClient): {
85
+ /**
86
+ * Equality operator - encrypts value for encrypted columns.
87
+ * Requires either `equality` or `orderAndRange` to be set on {@link EncryptedColumnConfig}.
88
+ *
89
+ * @example
90
+ * Select users with a specific email address.
91
+ * ```ts
92
+ * const condition = await ops.eq(usersTable.email, 'user@example.com')
93
+ * const results = await db.select().from(usersTable).where(condition)
94
+ * ```
95
+ */
96
+ eq: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL;
97
+ /**
98
+ * Not equal operator - encrypts value for encrypted columns.
99
+ * Requires either `equality` or `orderAndRange` to be set on {@link EncryptedColumnConfig}.
100
+ *
101
+ * @example
102
+ * Select users whose email address is not a specific value.
103
+ * ```ts
104
+ * const condition = await ops.ne(usersTable.email, 'user@example.com')
105
+ * const results = await db.select().from(usersTable).where(condition)
106
+ * ```
107
+ */
108
+ ne: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL;
109
+ /**
110
+ * Greater than operator for encrypted columns with ORE index.
111
+ * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.
112
+ *
113
+ * @example
114
+ * Select users older than a specific age.
115
+ * ```ts
116
+ * const condition = await ops.gt(usersTable.age, 30)
117
+ * const results = await db.select().from(usersTable).where(condition)
118
+ * ```
119
+ */
120
+ gt: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL;
121
+ /**
122
+ * Greater than or equal operator for encrypted columns with ORE index.
123
+ * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.
124
+ *
125
+ * @example
126
+ * Select users older than or equal to a specific age.
127
+ * ```ts
128
+ * const condition = await ops.gte(usersTable.age, 30)
129
+ * const results = await db.select().from(usersTable).where(condition)
130
+ * ```
131
+ */
132
+ gte: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL;
133
+ /**
134
+ * Less than operator for encrypted columns with ORE index.
135
+ * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.
136
+ *
137
+ * @example
138
+ * Select users younger than a specific age.
139
+ * ```ts
140
+ * const condition = await ops.lt(usersTable.age, 30)
141
+ * const results = await db.select().from(usersTable).where(condition)
142
+ * ```
143
+ */
144
+ lt: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL;
145
+ /**
146
+ * Less than or equal operator for encrypted columns with ORE index.
147
+ * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.
148
+ *
149
+ * @example
150
+ * Select users younger than or equal to a specific age.
151
+ * ```ts
152
+ * const condition = await ops.lte(usersTable.age, 30)
153
+ * const results = await db.select().from(usersTable).where(condition)
154
+ * ```
155
+ */
156
+ lte: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL;
157
+ /**
158
+ * Between operator for encrypted columns with ORE index.
159
+ * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.
160
+ *
161
+ * @example
162
+ * Select users within a specific age range.
163
+ * ```ts
164
+ * const condition = await ops.between(usersTable.age, 20, 30)
165
+ * const results = await db.select().from(usersTable).where(condition)
166
+ * ```
167
+ */
168
+ between: (left: SQLWrapper, min: unknown, max: unknown) => Promise<SQL> | SQL;
169
+ /**
170
+ * Not between operator for encrypted columns with ORE index.
171
+ * Requires `orderAndRange` to be set on {@link EncryptedColumnConfig}.
172
+ *
173
+ * @example
174
+ * Select users outside a specific age range.
175
+ * ```ts
176
+ * const condition = await ops.notBetween(usersTable.age, 20, 30)
177
+ * const results = await db.select().from(usersTable).where(condition)
178
+ * ```
179
+ */
180
+ notBetween: (left: SQLWrapper, min: unknown, max: unknown) => Promise<SQL> | SQL;
181
+ /**
182
+ * Like operator for encrypted columns with free text search.
183
+ * Requires `freeTextSearch` to be set on {@link EncryptedColumnConfig}.
184
+ *
185
+ * > [!IMPORTANT]
186
+ * > Case sensitivity on encrypted columns depends on the {@link EncryptedColumnConfig}.
187
+ * > Ensure that the column is configured for case-insensitive search if needed.
188
+ *
189
+ * @example
190
+ * Select users with email addresses matching a pattern.
191
+ * ```ts
192
+ * const condition = await ops.like(usersTable.email, '%@example.com')
193
+ * const results = await db.select().from(usersTable).where(condition)
194
+ * ```
195
+ */
196
+ like: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL;
197
+ /**
198
+ * ILike operator for encrypted columns with free text search.
199
+ * Requires `freeTextSearch` to be set on {@link EncryptedColumnConfig}.
200
+ *
201
+ * > [!IMPORTANT]
202
+ * > Case sensitivity on encrypted columns depends on the {@link EncryptedColumnConfig}.
203
+ * > Ensure that the column is configured for case-insensitive search if needed.
204
+ *
205
+ * @example
206
+ * Select users with email addresses matching a pattern (case-insensitive).
207
+ * ```ts
208
+ * const condition = await ops.ilike(usersTable.email, '%@example.com')
209
+ * const results = await db.select().from(usersTable).where(condition)
210
+ * ```
211
+ */
212
+ ilike: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL;
213
+ notIlike: (left: SQLWrapper, right: unknown) => Promise<SQL> | SQL;
214
+ /**
215
+ * JSONB path query first operator for encrypted columns with searchable JSON.
216
+ * Requires `searchableJson` to be set on {@link EncryptedColumnConfig}.
217
+ *
218
+ * Encrypts the JSON path selector and calls `eql_v2.jsonb_path_query_first()`,
219
+ * casting the parameter to `eql_v2_encrypted`.
220
+ *
221
+ * @throws {EncryptionOperatorError} If the column does not have `searchableJson` enabled.
222
+ */
223
+ jsonbPathQueryFirst: (left: SQLWrapper, right: unknown) => Promise<SQL>;
224
+ /**
225
+ * JSONB get operator for encrypted columns with searchable JSON.
226
+ * Requires `searchableJson` to be set on {@link EncryptedColumnConfig}.
227
+ *
228
+ * Encrypts the JSON path selector and uses the `->` operator,
229
+ * casting the parameter to `eql_v2_encrypted`.
230
+ *
231
+ * @throws {EncryptionOperatorError} If the column does not have `searchableJson` enabled.
232
+ */
233
+ jsonbGet: (left: SQLWrapper, right: unknown) => Promise<SQL>;
234
+ /**
235
+ * JSONB path exists operator for encrypted columns with searchable JSON.
236
+ * Requires `searchableJson` to be set on {@link EncryptedColumnConfig}.
237
+ *
238
+ * Encrypts the JSON path selector and calls `eql_v2.jsonb_path_exists()`,
239
+ * casting the parameter to `eql_v2_encrypted`.
240
+ *
241
+ * @throws {EncryptionOperatorError} If the column does not have `searchableJson` enabled.
242
+ */
243
+ jsonbPathExists: (left: SQLWrapper, right: unknown) => Promise<SQL>;
244
+ inArray: (left: SQLWrapper, right: unknown[] | SQLWrapper) => Promise<SQL>;
245
+ notInArray: (left: SQLWrapper, right: unknown[] | SQLWrapper) => Promise<SQL>;
246
+ asc: (column: SQLWrapper) => SQL;
247
+ desc: (column: SQLWrapper) => SQL;
248
+ and: (...conditions: (SQL | SQLWrapper | Promise<SQL> | undefined)[]) => Promise<SQL>;
249
+ or: (...conditions: (SQL | SQLWrapper | Promise<SQL> | undefined)[]) => Promise<SQL>;
250
+ exists: typeof exists;
251
+ notExists: typeof notExists;
252
+ isNull: typeof isNull;
253
+ isNotNull: typeof isNotNull;
254
+ not: typeof not;
255
+ arrayContains: typeof arrayContains;
256
+ arrayContained: typeof arrayContained;
257
+ arrayOverlaps: typeof arrayOverlaps;
258
+ };
259
+
260
+ /**
261
+ * Configuration for encrypted column indexes and data types
262
+ */
263
+ type EncryptedColumnConfig = {
264
+ /**
265
+ * Data type for the column (default: 'string')
266
+ */
267
+ dataType?: CastAs;
268
+ /**
269
+ * Enable free text search. Can be a boolean for default options, or an object for custom configuration.
270
+ */
271
+ freeTextSearch?: boolean | MatchIndexOpts;
272
+ /**
273
+ * Enable equality index. Can be a boolean for default options, or an array of token filters.
274
+ */
275
+ equality?: boolean | TokenFilter[];
276
+ /**
277
+ * Enable order and range index for sorting and range queries.
278
+ */
279
+ orderAndRange?: boolean;
280
+ /**
281
+ * Enable searchable JSON index for JSONB path queries.
282
+ * Requires dataType: 'json'.
283
+ */
284
+ searchableJson?: boolean;
285
+ };
286
+ /**
287
+ * Creates an encrypted column type for Drizzle ORM with configurable searchable encryption options.
288
+ *
289
+ * When data is encrypted, the actual stored value is an [EQL v2](/docs/reference/eql) encrypted composite type which includes any searchable encryption indexes defined for the column.
290
+ * Importantly, the original data type is not known until it is decrypted. Therefore, this function allows specifying
291
+ * the original data type via the `dataType` option in the configuration.
292
+ * This ensures that when data is decrypted, it can be correctly interpreted as the intended TypeScript type.
293
+ *
294
+ * @typeParam TData - The TypeScript type of the data stored in the column
295
+ * @param name - The column name in the database
296
+ * @param config - Optional configuration for data type and searchable encryption indexes
297
+ * @returns A Drizzle column type that can be used in pgTable definitions
298
+ *
299
+ * ## Searchable Encryption Options
300
+ *
301
+ * - `dataType`: Specifies the original data type of the column (e.g., 'string', 'number', 'json'). Default is 'string'.
302
+ * - `freeTextSearch`: Enables free text search index. Can be a boolean for default options, or an object for custom configuration.
303
+ * - `equality`: Enables equality index. Can be a boolean for default options, or an array of token filters.
304
+ * - `orderAndRange`: Enables order and range index for sorting and range queries.
305
+ * - `searchableJson`: Enables searchable JSON index for JSONB path queries on encrypted JSON columns.
306
+ *
307
+ * See {@link EncryptedColumnConfig}.
308
+ *
309
+ * @example
310
+ * Defining a drizzle table schema for postgres table with encrypted columns.
311
+ *
312
+ * ```typescript
313
+ * import { pgTable, integer, timestamp } from 'drizzle-orm/pg-core'
314
+ * import { encryptedType } from '@cipherstash/stack/drizzle'
315
+ *
316
+ * const users = pgTable('users', {
317
+ * email: encryptedType('email', {
318
+ * freeTextSearch: true,
319
+ * equality: true,
320
+ * orderAndRange: true,
321
+ * }),
322
+ * age: encryptedType('age', {
323
+ * dataType: 'number',
324
+ * equality: true,
325
+ * orderAndRange: true,
326
+ * }),
327
+ * profile: encryptedType('profile', {
328
+ * dataType: 'json',
329
+ * }),
330
+ * })
331
+ * ```
332
+ */
333
+ declare const encryptedType: <TData>(name: string, config?: EncryptedColumnConfig) => drizzle_orm_pg_core.PgCustomColumnBuilder<{
334
+ name: string;
335
+ dataType: "custom";
336
+ columnType: "PgCustomColumn";
337
+ data: TData;
338
+ driverParam: string;
339
+ enumValues: undefined;
340
+ }>;
341
+ /**
342
+ * Get configuration for an encrypted column by checking if it's an encrypted type
343
+ * and looking up the config by column name
344
+ * @internal
345
+ */
346
+ declare function getEncryptedColumnConfig(columnName: string, column: unknown): (EncryptedColumnConfig & {
347
+ name: string;
348
+ }) | undefined;
349
+
350
+ export { CastAs, type EncryptedColumnConfig, EncryptionConfigError, EncryptionOperatorError, MatchIndexOpts, TokenFilter, createEncryptionOperators, encryptedType, extractEncryptionSchema, getEncryptedColumnConfig };