@cipherstash/stack 0.19.0 → 1.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +531 -0
- package/README.md +95 -77
- package/dist/adapter-kit.cjs +923 -0
- package/dist/adapter-kit.cjs.map +1 -0
- package/dist/adapter-kit.d.cts +82 -0
- package/dist/adapter-kit.d.ts +82 -0
- package/dist/adapter-kit.js +47 -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-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-U66S7VIF.js → chunk-V2Q3NYIH.js} +166 -107
- package/dist/chunk-V2Q3NYIH.js.map +1 -0
- package/dist/chunk-X3JRXEIB.js +98 -0
- package/dist/chunk-X3JRXEIB.js.map +1 -0
- package/dist/{chunk-36AA7IBJ.js → chunk-ZTP5QJ27.js} +51 -18
- package/dist/chunk-ZTP5QJ27.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-DihEAlxG.d.cts → columns-D2_YzrCX.d.cts} +155 -136
- package/dist/{table-CIH7jZ2h.d.ts → columns-rZc7fQHI.d.ts} +155 -136
- 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 +4 -4
- 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 +49 -21
- 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/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 +4 -4
- 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-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
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { A as AuditConfig, e as EncryptionClient } from '../client-DSGHBN-g.cjs';
|
|
2
|
-
import { A as AnyV3Table, a as QueryTypesForColumn, W as InferPlaintext } from '../table-DihEAlxG.cjs';
|
|
3
|
-
import { EncryptionError } from '../errors/index.cjs';
|
|
4
|
-
import { LockContext } from '../identity/index.cjs';
|
|
5
|
-
import { g as EncryptedTable, h as EncryptedTableColumn } from '../types-public-CpS5KjwX.cjs';
|
|
6
|
-
import '@byteslice/result';
|
|
7
|
-
import '@cipherstash/protect-ffi';
|
|
8
|
-
import 'zod';
|
|
9
|
-
|
|
10
|
-
type EncryptedSupabaseConfig = {
|
|
11
|
-
encryptionClient: EncryptionClient;
|
|
12
|
-
supabaseClient: SupabaseClientLike;
|
|
13
|
-
};
|
|
14
|
-
interface EncryptedSupabaseInstance {
|
|
15
|
-
from<T extends Record<string, unknown> = Record<string, unknown>>(tableName: string, schema: EncryptedTable<EncryptedTableColumn>): EncryptedQueryBuilder<T>;
|
|
16
|
-
}
|
|
17
|
-
type EncryptedSupabaseV3Config = {
|
|
18
|
-
encryptionClient: EncryptionClient;
|
|
19
|
-
supabaseClient: SupabaseClientLike;
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* The column builders declared on a v3 table, recovered from the table's
|
|
23
|
-
* type-level `_columnType` brand.
|
|
24
|
-
*/
|
|
25
|
-
type V3ColumnsOfTable<Table> = Table extends {
|
|
26
|
-
readonly _columnType: infer C;
|
|
27
|
-
} ? C : never;
|
|
28
|
-
/**
|
|
29
|
-
* JS property names of a v3 table's storage-only columns — those whose domain
|
|
30
|
-
* exposes no query capability (e.g. `types.Bool`, `types.Text`). Excluded from
|
|
31
|
-
* the filterable keys so a filter on one is a type error, matching the runtime
|
|
32
|
-
* guard in the v3 term encryption path.
|
|
33
|
-
*/
|
|
34
|
-
type NonQueryableV3Keys<Table extends AnyV3Table> = {
|
|
35
|
-
[K in Extract<keyof V3ColumnsOfTable<Table>, string>]: [
|
|
36
|
-
QueryTypesForColumn<V3ColumnsOfTable<Table>[K]>
|
|
37
|
-
] extends [never] ? K : never;
|
|
38
|
-
}[Extract<keyof V3ColumnsOfTable<Table>, string>];
|
|
39
|
-
/**
|
|
40
|
-
* Row keys a v3 builder accepts in filter methods: every row key except the
|
|
41
|
-
* table's storage-only encrypted columns. Plaintext (non-schema) columns pass
|
|
42
|
-
* through untouched, exactly as in v2.
|
|
43
|
-
*/
|
|
44
|
-
type V3FilterableKeys<Table extends AnyV3Table, Row extends Record<string, unknown>> = Exclude<Extract<keyof Row, string>, NonQueryableV3Keys<Table>>;
|
|
45
|
-
/**
|
|
46
|
-
* The v3 builder type: the shared {@link EncryptedQueryBuilder} surface with
|
|
47
|
-
* filter methods narrowed to {@link V3FilterableKeys}.
|
|
48
|
-
*/
|
|
49
|
-
type EncryptedQueryBuilderV3<Table extends AnyV3Table, Row extends Record<string, unknown>> = EncryptedQueryBuilder<Row, V3FilterableKeys<Table, Row> & StringKeyOf<Row>>;
|
|
50
|
-
interface EncryptedSupabaseV3Instance {
|
|
51
|
-
/**
|
|
52
|
-
* `Row` defaults to exactly the table's inferred plaintext shape — NOT
|
|
53
|
-
* widened with an index signature. Widening would collapse
|
|
54
|
-
* {@link V3FilterableKeys} to `string` and silently disable the
|
|
55
|
-
* storage-only-column filter guard. The trade-off: with the default `Row`,
|
|
56
|
-
* plaintext passthrough columns (`id`, `created_at`, …) are not filterable
|
|
57
|
-
* or insertable at the type level — pass an explicit `Row` that includes
|
|
58
|
-
* them (`es.from<typeof users, UserRow>(…)`).
|
|
59
|
-
*/
|
|
60
|
-
from<Table extends AnyV3Table, Row extends Record<string, unknown> = InferPlaintext<Table>>(tableName: string, table: Table): EncryptedQueryBuilderV3<Table, Row>;
|
|
61
|
-
}
|
|
62
|
-
type EncryptedSupabaseResponse<T> = {
|
|
63
|
-
data: T | null;
|
|
64
|
-
error: EncryptedSupabaseError | null;
|
|
65
|
-
count: number | null;
|
|
66
|
-
status: number;
|
|
67
|
-
statusText: string;
|
|
68
|
-
};
|
|
69
|
-
type EncryptedSupabaseError = {
|
|
70
|
-
message: string;
|
|
71
|
-
details?: string;
|
|
72
|
-
hint?: string;
|
|
73
|
-
code?: string;
|
|
74
|
-
encryptionError?: EncryptionError;
|
|
75
|
-
};
|
|
76
|
-
type FilterOp = 'eq' | 'neq' | 'like' | 'ilike' | 'in' | 'gt' | 'gte' | 'lt' | 'lte' | 'is';
|
|
77
|
-
type PendingOrCondition = {
|
|
78
|
-
column: string;
|
|
79
|
-
op: FilterOp;
|
|
80
|
-
value: unknown;
|
|
81
|
-
};
|
|
82
|
-
interface SupabaseClientLike {
|
|
83
|
-
from(table: string): any;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** Helper to extract string keys from T */
|
|
87
|
-
type StringKeyOf<T> = Extract<keyof T, string>;
|
|
88
|
-
interface EncryptedQueryBuilder<T extends Record<string, unknown> = Record<string, unknown>, FK extends StringKeyOf<T> = StringKeyOf<T>> extends PromiseLike<EncryptedSupabaseResponse<T[]>> {
|
|
89
|
-
select(columns: string, options?: {
|
|
90
|
-
head?: boolean;
|
|
91
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
92
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
93
|
-
insert(data: Partial<T> | Partial<T>[], options?: {
|
|
94
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
95
|
-
defaultToNull?: boolean;
|
|
96
|
-
onConflict?: string;
|
|
97
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
98
|
-
update(data: Partial<T>, options?: {
|
|
99
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
100
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
101
|
-
upsert(data: Partial<T> | Partial<T>[], options?: {
|
|
102
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
103
|
-
onConflict?: string;
|
|
104
|
-
ignoreDuplicates?: boolean;
|
|
105
|
-
defaultToNull?: boolean;
|
|
106
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
107
|
-
delete(options?: {
|
|
108
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
109
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
110
|
-
eq<K extends FK>(column: K, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
111
|
-
neq<K extends FK>(column: K, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
112
|
-
gt<K extends FK>(column: K, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
113
|
-
gte<K extends FK>(column: K, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
114
|
-
lt<K extends FK>(column: K, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
115
|
-
lte<K extends FK>(column: K, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
116
|
-
like<K extends FK>(column: K, pattern: string): EncryptedQueryBuilder<T, FK>;
|
|
117
|
-
ilike<K extends FK>(column: K, pattern: string): EncryptedQueryBuilder<T, FK>;
|
|
118
|
-
is<K extends FK>(column: K, value: null | boolean): EncryptedQueryBuilder<T, FK>;
|
|
119
|
-
in<K extends FK>(column: K, values: T[K][]): EncryptedQueryBuilder<T, FK>;
|
|
120
|
-
filter<K extends FK>(column: K, operator: string, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
121
|
-
not<K extends FK>(column: K, operator: string, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
122
|
-
or(filters: string, options?: {
|
|
123
|
-
referencedTable?: string;
|
|
124
|
-
foreignTable?: string;
|
|
125
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
126
|
-
or(conditions: PendingOrCondition[], options?: {
|
|
127
|
-
referencedTable?: string;
|
|
128
|
-
foreignTable?: string;
|
|
129
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
130
|
-
match(query: Partial<Pick<T, FK>>): EncryptedQueryBuilder<T, FK>;
|
|
131
|
-
order<K extends StringKeyOf<T>>(column: K, options?: {
|
|
132
|
-
ascending?: boolean;
|
|
133
|
-
nullsFirst?: boolean;
|
|
134
|
-
referencedTable?: string;
|
|
135
|
-
foreignTable?: string;
|
|
136
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
137
|
-
limit(count: number, options?: {
|
|
138
|
-
referencedTable?: string;
|
|
139
|
-
foreignTable?: string;
|
|
140
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
141
|
-
range(from: number, to: number, options?: {
|
|
142
|
-
referencedTable?: string;
|
|
143
|
-
foreignTable?: string;
|
|
144
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
145
|
-
single(): EncryptedQueryBuilder<T, FK>;
|
|
146
|
-
maybeSingle(): EncryptedQueryBuilder<T, FK>;
|
|
147
|
-
csv(): EncryptedQueryBuilder<T, FK>;
|
|
148
|
-
abortSignal(signal: AbortSignal): EncryptedQueryBuilder<T, FK>;
|
|
149
|
-
throwOnError(): EncryptedQueryBuilder<T, FK>;
|
|
150
|
-
returns<U extends Record<string, unknown>>(): EncryptedQueryBuilder<U>;
|
|
151
|
-
withLockContext(lockContext: LockContext): EncryptedQueryBuilder<T, FK>;
|
|
152
|
-
audit(config: AuditConfig): EncryptedQueryBuilder<T, FK>;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Create an encrypted Supabase wrapper that transparently handles encryption
|
|
157
|
-
* and decryption for queries on encrypted columns.
|
|
158
|
-
*
|
|
159
|
-
* @param config - Configuration containing the encryption client and Supabase client.
|
|
160
|
-
* @returns An object with a `from()` method that mirrors `supabase.from()` but
|
|
161
|
-
* auto-encrypts mutations, adds `::jsonb` casts, encrypts filter values, and
|
|
162
|
-
* decrypts results.
|
|
163
|
-
*
|
|
164
|
-
* @example
|
|
165
|
-
* ```typescript
|
|
166
|
-
* import { Encryption } from '@cipherstash/stack'
|
|
167
|
-
* import { encryptedSupabase } from '@cipherstash/stack/supabase'
|
|
168
|
-
* import { encryptedTable, encryptedColumn } from '@cipherstash/stack/schema'
|
|
169
|
-
*
|
|
170
|
-
* const users = encryptedTable('users', {
|
|
171
|
-
* name: encryptedColumn('name').freeTextSearch().equality(),
|
|
172
|
-
* email: encryptedColumn('email').freeTextSearch().equality(),
|
|
173
|
-
* })
|
|
174
|
-
*
|
|
175
|
-
* const client = await Encryption({ schemas: [users] })
|
|
176
|
-
* const eSupabase = encryptedSupabase({ encryptionClient: client, supabaseClient: supabase })
|
|
177
|
-
*
|
|
178
|
-
* // INSERT - auto-encrypts, auto-converts to PG composite
|
|
179
|
-
* await eSupabase.from('users', users)
|
|
180
|
-
* .insert({ name: 'John', email: 'john@example.com', age: 30 })
|
|
181
|
-
*
|
|
182
|
-
* // SELECT with filter - auto-casts ::jsonb, auto-encrypts search term, auto-decrypts
|
|
183
|
-
* const { data } = await eSupabase.from('users', users)
|
|
184
|
-
* .select('id, email, name')
|
|
185
|
-
* .eq('email', 'john@example.com')
|
|
186
|
-
* ```
|
|
187
|
-
*/
|
|
188
|
-
declare function encryptedSupabase(config: EncryptedSupabaseConfig): EncryptedSupabaseInstance;
|
|
189
|
-
/**
|
|
190
|
-
* Create an encrypted Supabase wrapper for **EQL v3** schemas — tables
|
|
191
|
-
* authored with `@cipherstash/stack/eql/v3` whose columns are native
|
|
192
|
-
* `eql_v3.*` domains.
|
|
193
|
-
*
|
|
194
|
-
* The public surface and call shape are identical to {@link encryptedSupabase}
|
|
195
|
-
* (`.eq/.neq/.in/.gt/.gte/.lt/.lte/.like/.ilike/.match/.or/.not/.filter`,
|
|
196
|
-
* `withLockContext`, `audit`); only the schema type and the wire encoding
|
|
197
|
-
* differ. The same Supabase caveats carry over: the `eql_v3` schema must be
|
|
198
|
-
* added to the project's **Exposed schemas** and granted to the Supabase
|
|
199
|
-
* roles for the operators to resolve, and encrypted `ORDER BY` is
|
|
200
|
-
* unsupported (range *filtering* works).
|
|
201
|
-
*
|
|
202
|
-
* @example
|
|
203
|
-
* ```typescript
|
|
204
|
-
* import { Encryption } from '@cipherstash/stack'
|
|
205
|
-
* import { encryptedTable, types } from '@cipherstash/stack/eql/v3'
|
|
206
|
-
* import { encryptedSupabaseV3 } from '@cipherstash/stack/supabase'
|
|
207
|
-
*
|
|
208
|
-
* const users = encryptedTable('users', {
|
|
209
|
-
* email: types.TextSearch('email'), // eql_v3.text_search
|
|
210
|
-
* amount: types.IntegerOrd('amount'), // eql_v3.integer_ord
|
|
211
|
-
* })
|
|
212
|
-
*
|
|
213
|
-
* const client = await Encryption({ schemas: [users] })
|
|
214
|
-
* const es = encryptedSupabaseV3({ encryptionClient: client, supabaseClient: supabase })
|
|
215
|
-
*
|
|
216
|
-
* await es.from('users', users).insert({ email: 'a@b.com', amount: 30 })
|
|
217
|
-
* await es.from('users', users).select('id, email, amount').eq('email', 'a@b.com')
|
|
218
|
-
* await es.from('users', users).select('id, amount').gte('amount', 10).lte('amount', 100)
|
|
219
|
-
* ```
|
|
220
|
-
*/
|
|
221
|
-
declare function encryptedSupabaseV3(config: EncryptedSupabaseV3Config): EncryptedSupabaseV3Instance;
|
|
222
|
-
|
|
223
|
-
export { type EncryptedQueryBuilder, type EncryptedQueryBuilderV3, type EncryptedSupabaseConfig, type EncryptedSupabaseError, type EncryptedSupabaseInstance, type EncryptedSupabaseResponse, type EncryptedSupabaseV3Config, type EncryptedSupabaseV3Instance, type PendingOrCondition, type SupabaseClientLike, type V3FilterableKeys, encryptedSupabase, encryptedSupabaseV3 };
|
package/dist/supabase/index.d.ts
DELETED
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
import { A as AuditConfig, e as EncryptionClient } from '../client-DfCrlHXh.js';
|
|
2
|
-
import { A as AnyV3Table, a as QueryTypesForColumn, W as InferPlaintext } from '../table-CIH7jZ2h.js';
|
|
3
|
-
import { EncryptionError } from '../errors/index.js';
|
|
4
|
-
import { LockContext } from '../identity/index.js';
|
|
5
|
-
import { g as EncryptedTable, h as EncryptedTableColumn } from '../types-public-CpS5KjwX.js';
|
|
6
|
-
import '@byteslice/result';
|
|
7
|
-
import '@cipherstash/protect-ffi';
|
|
8
|
-
import 'zod';
|
|
9
|
-
|
|
10
|
-
type EncryptedSupabaseConfig = {
|
|
11
|
-
encryptionClient: EncryptionClient;
|
|
12
|
-
supabaseClient: SupabaseClientLike;
|
|
13
|
-
};
|
|
14
|
-
interface EncryptedSupabaseInstance {
|
|
15
|
-
from<T extends Record<string, unknown> = Record<string, unknown>>(tableName: string, schema: EncryptedTable<EncryptedTableColumn>): EncryptedQueryBuilder<T>;
|
|
16
|
-
}
|
|
17
|
-
type EncryptedSupabaseV3Config = {
|
|
18
|
-
encryptionClient: EncryptionClient;
|
|
19
|
-
supabaseClient: SupabaseClientLike;
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* The column builders declared on a v3 table, recovered from the table's
|
|
23
|
-
* type-level `_columnType` brand.
|
|
24
|
-
*/
|
|
25
|
-
type V3ColumnsOfTable<Table> = Table extends {
|
|
26
|
-
readonly _columnType: infer C;
|
|
27
|
-
} ? C : never;
|
|
28
|
-
/**
|
|
29
|
-
* JS property names of a v3 table's storage-only columns — those whose domain
|
|
30
|
-
* exposes no query capability (e.g. `types.Bool`, `types.Text`). Excluded from
|
|
31
|
-
* the filterable keys so a filter on one is a type error, matching the runtime
|
|
32
|
-
* guard in the v3 term encryption path.
|
|
33
|
-
*/
|
|
34
|
-
type NonQueryableV3Keys<Table extends AnyV3Table> = {
|
|
35
|
-
[K in Extract<keyof V3ColumnsOfTable<Table>, string>]: [
|
|
36
|
-
QueryTypesForColumn<V3ColumnsOfTable<Table>[K]>
|
|
37
|
-
] extends [never] ? K : never;
|
|
38
|
-
}[Extract<keyof V3ColumnsOfTable<Table>, string>];
|
|
39
|
-
/**
|
|
40
|
-
* Row keys a v3 builder accepts in filter methods: every row key except the
|
|
41
|
-
* table's storage-only encrypted columns. Plaintext (non-schema) columns pass
|
|
42
|
-
* through untouched, exactly as in v2.
|
|
43
|
-
*/
|
|
44
|
-
type V3FilterableKeys<Table extends AnyV3Table, Row extends Record<string, unknown>> = Exclude<Extract<keyof Row, string>, NonQueryableV3Keys<Table>>;
|
|
45
|
-
/**
|
|
46
|
-
* The v3 builder type: the shared {@link EncryptedQueryBuilder} surface with
|
|
47
|
-
* filter methods narrowed to {@link V3FilterableKeys}.
|
|
48
|
-
*/
|
|
49
|
-
type EncryptedQueryBuilderV3<Table extends AnyV3Table, Row extends Record<string, unknown>> = EncryptedQueryBuilder<Row, V3FilterableKeys<Table, Row> & StringKeyOf<Row>>;
|
|
50
|
-
interface EncryptedSupabaseV3Instance {
|
|
51
|
-
/**
|
|
52
|
-
* `Row` defaults to exactly the table's inferred plaintext shape — NOT
|
|
53
|
-
* widened with an index signature. Widening would collapse
|
|
54
|
-
* {@link V3FilterableKeys} to `string` and silently disable the
|
|
55
|
-
* storage-only-column filter guard. The trade-off: with the default `Row`,
|
|
56
|
-
* plaintext passthrough columns (`id`, `created_at`, …) are not filterable
|
|
57
|
-
* or insertable at the type level — pass an explicit `Row` that includes
|
|
58
|
-
* them (`es.from<typeof users, UserRow>(…)`).
|
|
59
|
-
*/
|
|
60
|
-
from<Table extends AnyV3Table, Row extends Record<string, unknown> = InferPlaintext<Table>>(tableName: string, table: Table): EncryptedQueryBuilderV3<Table, Row>;
|
|
61
|
-
}
|
|
62
|
-
type EncryptedSupabaseResponse<T> = {
|
|
63
|
-
data: T | null;
|
|
64
|
-
error: EncryptedSupabaseError | null;
|
|
65
|
-
count: number | null;
|
|
66
|
-
status: number;
|
|
67
|
-
statusText: string;
|
|
68
|
-
};
|
|
69
|
-
type EncryptedSupabaseError = {
|
|
70
|
-
message: string;
|
|
71
|
-
details?: string;
|
|
72
|
-
hint?: string;
|
|
73
|
-
code?: string;
|
|
74
|
-
encryptionError?: EncryptionError;
|
|
75
|
-
};
|
|
76
|
-
type FilterOp = 'eq' | 'neq' | 'like' | 'ilike' | 'in' | 'gt' | 'gte' | 'lt' | 'lte' | 'is';
|
|
77
|
-
type PendingOrCondition = {
|
|
78
|
-
column: string;
|
|
79
|
-
op: FilterOp;
|
|
80
|
-
value: unknown;
|
|
81
|
-
};
|
|
82
|
-
interface SupabaseClientLike {
|
|
83
|
-
from(table: string): any;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** Helper to extract string keys from T */
|
|
87
|
-
type StringKeyOf<T> = Extract<keyof T, string>;
|
|
88
|
-
interface EncryptedQueryBuilder<T extends Record<string, unknown> = Record<string, unknown>, FK extends StringKeyOf<T> = StringKeyOf<T>> extends PromiseLike<EncryptedSupabaseResponse<T[]>> {
|
|
89
|
-
select(columns: string, options?: {
|
|
90
|
-
head?: boolean;
|
|
91
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
92
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
93
|
-
insert(data: Partial<T> | Partial<T>[], options?: {
|
|
94
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
95
|
-
defaultToNull?: boolean;
|
|
96
|
-
onConflict?: string;
|
|
97
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
98
|
-
update(data: Partial<T>, options?: {
|
|
99
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
100
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
101
|
-
upsert(data: Partial<T> | Partial<T>[], options?: {
|
|
102
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
103
|
-
onConflict?: string;
|
|
104
|
-
ignoreDuplicates?: boolean;
|
|
105
|
-
defaultToNull?: boolean;
|
|
106
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
107
|
-
delete(options?: {
|
|
108
|
-
count?: 'exact' | 'planned' | 'estimated';
|
|
109
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
110
|
-
eq<K extends FK>(column: K, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
111
|
-
neq<K extends FK>(column: K, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
112
|
-
gt<K extends FK>(column: K, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
113
|
-
gte<K extends FK>(column: K, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
114
|
-
lt<K extends FK>(column: K, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
115
|
-
lte<K extends FK>(column: K, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
116
|
-
like<K extends FK>(column: K, pattern: string): EncryptedQueryBuilder<T, FK>;
|
|
117
|
-
ilike<K extends FK>(column: K, pattern: string): EncryptedQueryBuilder<T, FK>;
|
|
118
|
-
is<K extends FK>(column: K, value: null | boolean): EncryptedQueryBuilder<T, FK>;
|
|
119
|
-
in<K extends FK>(column: K, values: T[K][]): EncryptedQueryBuilder<T, FK>;
|
|
120
|
-
filter<K extends FK>(column: K, operator: string, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
121
|
-
not<K extends FK>(column: K, operator: string, value: T[K]): EncryptedQueryBuilder<T, FK>;
|
|
122
|
-
or(filters: string, options?: {
|
|
123
|
-
referencedTable?: string;
|
|
124
|
-
foreignTable?: string;
|
|
125
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
126
|
-
or(conditions: PendingOrCondition[], options?: {
|
|
127
|
-
referencedTable?: string;
|
|
128
|
-
foreignTable?: string;
|
|
129
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
130
|
-
match(query: Partial<Pick<T, FK>>): EncryptedQueryBuilder<T, FK>;
|
|
131
|
-
order<K extends StringKeyOf<T>>(column: K, options?: {
|
|
132
|
-
ascending?: boolean;
|
|
133
|
-
nullsFirst?: boolean;
|
|
134
|
-
referencedTable?: string;
|
|
135
|
-
foreignTable?: string;
|
|
136
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
137
|
-
limit(count: number, options?: {
|
|
138
|
-
referencedTable?: string;
|
|
139
|
-
foreignTable?: string;
|
|
140
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
141
|
-
range(from: number, to: number, options?: {
|
|
142
|
-
referencedTable?: string;
|
|
143
|
-
foreignTable?: string;
|
|
144
|
-
}): EncryptedQueryBuilder<T, FK>;
|
|
145
|
-
single(): EncryptedQueryBuilder<T, FK>;
|
|
146
|
-
maybeSingle(): EncryptedQueryBuilder<T, FK>;
|
|
147
|
-
csv(): EncryptedQueryBuilder<T, FK>;
|
|
148
|
-
abortSignal(signal: AbortSignal): EncryptedQueryBuilder<T, FK>;
|
|
149
|
-
throwOnError(): EncryptedQueryBuilder<T, FK>;
|
|
150
|
-
returns<U extends Record<string, unknown>>(): EncryptedQueryBuilder<U>;
|
|
151
|
-
withLockContext(lockContext: LockContext): EncryptedQueryBuilder<T, FK>;
|
|
152
|
-
audit(config: AuditConfig): EncryptedQueryBuilder<T, FK>;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Create an encrypted Supabase wrapper that transparently handles encryption
|
|
157
|
-
* and decryption for queries on encrypted columns.
|
|
158
|
-
*
|
|
159
|
-
* @param config - Configuration containing the encryption client and Supabase client.
|
|
160
|
-
* @returns An object with a `from()` method that mirrors `supabase.from()` but
|
|
161
|
-
* auto-encrypts mutations, adds `::jsonb` casts, encrypts filter values, and
|
|
162
|
-
* decrypts results.
|
|
163
|
-
*
|
|
164
|
-
* @example
|
|
165
|
-
* ```typescript
|
|
166
|
-
* import { Encryption } from '@cipherstash/stack'
|
|
167
|
-
* import { encryptedSupabase } from '@cipherstash/stack/supabase'
|
|
168
|
-
* import { encryptedTable, encryptedColumn } from '@cipherstash/stack/schema'
|
|
169
|
-
*
|
|
170
|
-
* const users = encryptedTable('users', {
|
|
171
|
-
* name: encryptedColumn('name').freeTextSearch().equality(),
|
|
172
|
-
* email: encryptedColumn('email').freeTextSearch().equality(),
|
|
173
|
-
* })
|
|
174
|
-
*
|
|
175
|
-
* const client = await Encryption({ schemas: [users] })
|
|
176
|
-
* const eSupabase = encryptedSupabase({ encryptionClient: client, supabaseClient: supabase })
|
|
177
|
-
*
|
|
178
|
-
* // INSERT - auto-encrypts, auto-converts to PG composite
|
|
179
|
-
* await eSupabase.from('users', users)
|
|
180
|
-
* .insert({ name: 'John', email: 'john@example.com', age: 30 })
|
|
181
|
-
*
|
|
182
|
-
* // SELECT with filter - auto-casts ::jsonb, auto-encrypts search term, auto-decrypts
|
|
183
|
-
* const { data } = await eSupabase.from('users', users)
|
|
184
|
-
* .select('id, email, name')
|
|
185
|
-
* .eq('email', 'john@example.com')
|
|
186
|
-
* ```
|
|
187
|
-
*/
|
|
188
|
-
declare function encryptedSupabase(config: EncryptedSupabaseConfig): EncryptedSupabaseInstance;
|
|
189
|
-
/**
|
|
190
|
-
* Create an encrypted Supabase wrapper for **EQL v3** schemas — tables
|
|
191
|
-
* authored with `@cipherstash/stack/eql/v3` whose columns are native
|
|
192
|
-
* `eql_v3.*` domains.
|
|
193
|
-
*
|
|
194
|
-
* The public surface and call shape are identical to {@link encryptedSupabase}
|
|
195
|
-
* (`.eq/.neq/.in/.gt/.gte/.lt/.lte/.like/.ilike/.match/.or/.not/.filter`,
|
|
196
|
-
* `withLockContext`, `audit`); only the schema type and the wire encoding
|
|
197
|
-
* differ. The same Supabase caveats carry over: the `eql_v3` schema must be
|
|
198
|
-
* added to the project's **Exposed schemas** and granted to the Supabase
|
|
199
|
-
* roles for the operators to resolve, and encrypted `ORDER BY` is
|
|
200
|
-
* unsupported (range *filtering* works).
|
|
201
|
-
*
|
|
202
|
-
* @example
|
|
203
|
-
* ```typescript
|
|
204
|
-
* import { Encryption } from '@cipherstash/stack'
|
|
205
|
-
* import { encryptedTable, types } from '@cipherstash/stack/eql/v3'
|
|
206
|
-
* import { encryptedSupabaseV3 } from '@cipherstash/stack/supabase'
|
|
207
|
-
*
|
|
208
|
-
* const users = encryptedTable('users', {
|
|
209
|
-
* email: types.TextSearch('email'), // eql_v3.text_search
|
|
210
|
-
* amount: types.IntegerOrd('amount'), // eql_v3.integer_ord
|
|
211
|
-
* })
|
|
212
|
-
*
|
|
213
|
-
* const client = await Encryption({ schemas: [users] })
|
|
214
|
-
* const es = encryptedSupabaseV3({ encryptionClient: client, supabaseClient: supabase })
|
|
215
|
-
*
|
|
216
|
-
* await es.from('users', users).insert({ email: 'a@b.com', amount: 30 })
|
|
217
|
-
* await es.from('users', users).select('id, email, amount').eq('email', 'a@b.com')
|
|
218
|
-
* await es.from('users', users).select('id, amount').gte('amount', 10).lte('amount', 100)
|
|
219
|
-
* ```
|
|
220
|
-
*/
|
|
221
|
-
declare function encryptedSupabaseV3(config: EncryptedSupabaseV3Config): EncryptedSupabaseV3Instance;
|
|
222
|
-
|
|
223
|
-
export { type EncryptedQueryBuilder, type EncryptedQueryBuilderV3, type EncryptedSupabaseConfig, type EncryptedSupabaseError, type EncryptedSupabaseInstance, type EncryptedSupabaseResponse, type EncryptedSupabaseV3Config, type EncryptedSupabaseV3Instance, type PendingOrCondition, type SupabaseClientLike, type V3FilterableKeys, encryptedSupabase, encryptedSupabaseV3 };
|