@cipherstash/stack 0.16.0 → 0.19.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 (102) hide show
  1. package/CHANGELOG.md +225 -0
  2. package/README.md +2 -2
  3. package/dist/{chunk-CY5B4LIF.js → chunk-36AA7IBJ.js} +303 -204
  4. package/dist/chunk-36AA7IBJ.js.map +1 -0
  5. package/dist/{chunk-MD6742R6.js → chunk-4AVL4VZD.js} +1 -1
  6. package/dist/chunk-4AVL4VZD.js.map +1 -0
  7. package/dist/{chunk-4RNBI3UH.js → chunk-BNO32ZMV.js} +1 -1
  8. package/dist/chunk-BNO32ZMV.js.map +1 -0
  9. package/dist/{chunk-6FD7OBGM.js → chunk-HQANMV7R.js} +3 -3
  10. package/dist/chunk-HQANMV7R.js.map +1 -0
  11. package/dist/chunk-IADZCZEA.js +23 -0
  12. package/dist/chunk-IADZCZEA.js.map +1 -0
  13. package/dist/chunk-IBSK6P33.js +209 -0
  14. package/dist/chunk-IBSK6P33.js.map +1 -0
  15. package/dist/chunk-JSG2AMDI.js +17 -0
  16. package/dist/chunk-JSG2AMDI.js.map +1 -0
  17. package/dist/chunk-MP3SSDNN.js +4439 -0
  18. package/dist/chunk-MP3SSDNN.js.map +1 -0
  19. package/dist/chunk-OFQ555AX.js +191 -0
  20. package/dist/chunk-OFQ555AX.js.map +1 -0
  21. package/dist/chunk-PZ5AY32C.js +10 -0
  22. package/dist/chunk-PZ5AY32C.js.map +1 -0
  23. package/dist/chunk-U66S7VIF.js +435 -0
  24. package/dist/chunk-U66S7VIF.js.map +1 -0
  25. package/dist/{client-C_7TF8EL.d.cts → client-DSGHBN-g.d.cts} +209 -72
  26. package/dist/{client-BLbA6aFD.d.ts → client-DfCrlHXh.d.ts} +209 -72
  27. package/dist/client.cjs +4103 -43
  28. package/dist/client.cjs.map +1 -1
  29. package/dist/client.d.cts +5 -5
  30. package/dist/client.d.ts +5 -5
  31. package/dist/client.js +3 -1
  32. package/dist/drizzle/index.cjs +4139 -77
  33. package/dist/drizzle/index.cjs.map +1 -1
  34. package/dist/drizzle/index.d.cts +33 -33
  35. package/dist/drizzle/index.d.ts +33 -33
  36. package/dist/drizzle/index.js +39 -33
  37. package/dist/drizzle/index.js.map +1 -1
  38. package/dist/dynamodb/index.cjs +31 -14
  39. package/dist/dynamodb/index.cjs.map +1 -1
  40. package/dist/dynamodb/index.d.cts +12 -12
  41. package/dist/dynamodb/index.d.ts +12 -12
  42. package/dist/dynamodb/index.js +16 -12
  43. package/dist/dynamodb/index.js.map +1 -1
  44. package/dist/encryption/index.cjs +4611 -257
  45. package/dist/encryption/index.cjs.map +1 -1
  46. package/dist/encryption/index.d.cts +3 -3
  47. package/dist/encryption/index.d.ts +3 -3
  48. package/dist/encryption/index.js +35 -7
  49. package/dist/encryption/v3.cjs +7791 -0
  50. package/dist/encryption/v3.cjs.map +1 -0
  51. package/dist/encryption/v3.d.cts +100 -0
  52. package/dist/encryption/v3.d.ts +100 -0
  53. package/dist/encryption/v3.js +161 -0
  54. package/dist/encryption/v3.js.map +1 -0
  55. package/dist/eql/v3/index.cjs +612 -0
  56. package/dist/eql/v3/index.cjs.map +1 -0
  57. package/dist/eql/v3/index.d.cts +71 -0
  58. package/dist/eql/v3/index.d.ts +71 -0
  59. package/dist/eql/v3/index.js +89 -0
  60. package/dist/eql/v3/index.js.map +1 -0
  61. package/dist/errors/index.js +1 -0
  62. package/dist/identity/index.cjs +55 -35
  63. package/dist/identity/index.cjs.map +1 -1
  64. package/dist/identity/index.d.cts +54 -30
  65. package/dist/identity/index.d.ts +54 -30
  66. package/dist/identity/index.js +9 -177
  67. package/dist/identity/index.js.map +1 -1
  68. package/dist/index.cjs +4625 -273
  69. package/dist/index.cjs.map +1 -1
  70. package/dist/index.d.cts +18 -7
  71. package/dist/index.d.ts +18 -7
  72. package/dist/index.js +20 -5
  73. package/dist/index.js.map +1 -1
  74. package/dist/schema/index.cjs +4108 -44
  75. package/dist/schema/index.cjs.map +1 -1
  76. package/dist/schema/index.d.cts +1 -1
  77. package/dist/schema/index.d.ts +1 -1
  78. package/dist/schema/index.js +3 -1
  79. package/dist/supabase/index.cjs +4500 -75
  80. package/dist/supabase/index.cjs.map +1 -1
  81. package/dist/supabase/index.d.cts +113 -34
  82. package/dist/supabase/index.d.ts +113 -34
  83. package/dist/supabase/index.js +350 -32
  84. package/dist/supabase/index.js.map +1 -1
  85. package/dist/table-CIH7jZ2h.d.ts +603 -0
  86. package/dist/table-DihEAlxG.d.cts +603 -0
  87. package/dist/{types-public-Dv-r6Ik0.d.ts → types-public-CpS5KjwX.d.cts} +209 -36
  88. package/dist/{types-public-Dv-r6Ik0.d.cts → types-public-CpS5KjwX.d.ts} +209 -36
  89. package/dist/types-public.cjs.map +1 -1
  90. package/dist/types-public.d.cts +2 -2
  91. package/dist/types-public.d.ts +2 -2
  92. package/dist/types-public.js +2 -1
  93. package/dist/wasm-inline.d.ts +1269 -0
  94. package/dist/wasm-inline.js +4594 -0
  95. package/dist/wasm-inline.js.map +1 -0
  96. package/package.json +63 -13
  97. package/dist/chunk-4RNBI3UH.js.map +0 -1
  98. package/dist/chunk-6FD7OBGM.js.map +0 -1
  99. package/dist/chunk-CY5B4LIF.js.map +0 -1
  100. package/dist/chunk-JDZ2QUUF.js +0 -381
  101. package/dist/chunk-JDZ2QUUF.js.map +0 -1
  102. package/dist/chunk-MD6742R6.js.map +0 -1
@@ -1,7 +1,8 @@
1
- import { A as AuditConfig, a as EncryptionClient } from '../client-C_7TF8EL.cjs';
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';
2
3
  import { EncryptionError } from '../errors/index.cjs';
3
4
  import { LockContext } from '../identity/index.cjs';
4
- import { c as EncryptedTable, d as EncryptedTableColumn } from '../types-public-Dv-r6Ik0.cjs';
5
+ import { g as EncryptedTable, h as EncryptedTableColumn } from '../types-public-CpS5KjwX.cjs';
5
6
  import '@byteslice/result';
6
7
  import '@cipherstash/protect-ffi';
7
8
  import 'zod';
@@ -13,6 +14,51 @@ type EncryptedSupabaseConfig = {
13
14
  interface EncryptedSupabaseInstance {
14
15
  from<T extends Record<string, unknown> = Record<string, unknown>>(tableName: string, schema: EncryptedTable<EncryptedTableColumn>): EncryptedQueryBuilder<T>;
15
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
+ }
16
62
  type EncryptedSupabaseResponse<T> = {
17
63
  data: T | null;
18
64
  error: EncryptedSupabaseError | null;
@@ -39,71 +85,71 @@ interface SupabaseClientLike {
39
85
 
40
86
  /** Helper to extract string keys from T */
41
87
  type StringKeyOf<T> = Extract<keyof T, string>;
42
- interface EncryptedQueryBuilder<T extends Record<string, unknown> = Record<string, unknown>> extends PromiseLike<EncryptedSupabaseResponse<T[]>> {
88
+ interface EncryptedQueryBuilder<T extends Record<string, unknown> = Record<string, unknown>, FK extends StringKeyOf<T> = StringKeyOf<T>> extends PromiseLike<EncryptedSupabaseResponse<T[]>> {
43
89
  select(columns: string, options?: {
44
90
  head?: boolean;
45
91
  count?: 'exact' | 'planned' | 'estimated';
46
- }): EncryptedQueryBuilder<T>;
92
+ }): EncryptedQueryBuilder<T, FK>;
47
93
  insert(data: Partial<T> | Partial<T>[], options?: {
48
94
  count?: 'exact' | 'planned' | 'estimated';
49
95
  defaultToNull?: boolean;
50
96
  onConflict?: string;
51
- }): EncryptedQueryBuilder<T>;
97
+ }): EncryptedQueryBuilder<T, FK>;
52
98
  update(data: Partial<T>, options?: {
53
99
  count?: 'exact' | 'planned' | 'estimated';
54
- }): EncryptedQueryBuilder<T>;
100
+ }): EncryptedQueryBuilder<T, FK>;
55
101
  upsert(data: Partial<T> | Partial<T>[], options?: {
56
102
  count?: 'exact' | 'planned' | 'estimated';
57
103
  onConflict?: string;
58
104
  ignoreDuplicates?: boolean;
59
105
  defaultToNull?: boolean;
60
- }): EncryptedQueryBuilder<T>;
106
+ }): EncryptedQueryBuilder<T, FK>;
61
107
  delete(options?: {
62
108
  count?: 'exact' | 'planned' | 'estimated';
63
- }): EncryptedQueryBuilder<T>;
64
- eq<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
65
- neq<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
66
- gt<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
67
- gte<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
68
- lt<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
69
- lte<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
70
- like<K extends StringKeyOf<T>>(column: K, pattern: string): EncryptedQueryBuilder<T>;
71
- ilike<K extends StringKeyOf<T>>(column: K, pattern: string): EncryptedQueryBuilder<T>;
72
- is<K extends StringKeyOf<T>>(column: K, value: null | boolean): EncryptedQueryBuilder<T>;
73
- in<K extends StringKeyOf<T>>(column: K, values: T[K][]): EncryptedQueryBuilder<T>;
74
- filter<K extends StringKeyOf<T>>(column: K, operator: string, value: T[K]): EncryptedQueryBuilder<T>;
75
- not<K extends StringKeyOf<T>>(column: K, operator: string, value: T[K]): EncryptedQueryBuilder<T>;
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>;
76
122
  or(filters: string, options?: {
77
123
  referencedTable?: string;
78
124
  foreignTable?: string;
79
- }): EncryptedQueryBuilder<T>;
125
+ }): EncryptedQueryBuilder<T, FK>;
80
126
  or(conditions: PendingOrCondition[], options?: {
81
127
  referencedTable?: string;
82
128
  foreignTable?: string;
83
- }): EncryptedQueryBuilder<T>;
84
- match(query: Partial<T>): EncryptedQueryBuilder<T>;
129
+ }): EncryptedQueryBuilder<T, FK>;
130
+ match(query: Partial<Pick<T, FK>>): EncryptedQueryBuilder<T, FK>;
85
131
  order<K extends StringKeyOf<T>>(column: K, options?: {
86
132
  ascending?: boolean;
87
133
  nullsFirst?: boolean;
88
134
  referencedTable?: string;
89
135
  foreignTable?: string;
90
- }): EncryptedQueryBuilder<T>;
136
+ }): EncryptedQueryBuilder<T, FK>;
91
137
  limit(count: number, options?: {
92
138
  referencedTable?: string;
93
139
  foreignTable?: string;
94
- }): EncryptedQueryBuilder<T>;
140
+ }): EncryptedQueryBuilder<T, FK>;
95
141
  range(from: number, to: number, options?: {
96
142
  referencedTable?: string;
97
143
  foreignTable?: string;
98
- }): EncryptedQueryBuilder<T>;
99
- single(): EncryptedQueryBuilder<T>;
100
- maybeSingle(): EncryptedQueryBuilder<T>;
101
- csv(): EncryptedQueryBuilder<T>;
102
- abortSignal(signal: AbortSignal): EncryptedQueryBuilder<T>;
103
- throwOnError(): EncryptedQueryBuilder<T>;
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>;
104
150
  returns<U extends Record<string, unknown>>(): EncryptedQueryBuilder<U>;
105
- withLockContext(lockContext: LockContext): EncryptedQueryBuilder<T>;
106
- audit(config: AuditConfig): EncryptedQueryBuilder<T>;
151
+ withLockContext(lockContext: LockContext): EncryptedQueryBuilder<T, FK>;
152
+ audit(config: AuditConfig): EncryptedQueryBuilder<T, FK>;
107
153
  }
108
154
 
109
155
  /**
@@ -140,5 +186,38 @@ interface EncryptedQueryBuilder<T extends Record<string, unknown> = Record<strin
140
186
  * ```
141
187
  */
142
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;
143
222
 
144
- export { type EncryptedQueryBuilder, type EncryptedSupabaseConfig, type EncryptedSupabaseError, type EncryptedSupabaseInstance, type EncryptedSupabaseResponse, type PendingOrCondition, type SupabaseClientLike, encryptedSupabase };
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 };
@@ -1,7 +1,8 @@
1
- import { A as AuditConfig, a as EncryptionClient } from '../client-BLbA6aFD.js';
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';
2
3
  import { EncryptionError } from '../errors/index.js';
3
4
  import { LockContext } from '../identity/index.js';
4
- import { c as EncryptedTable, d as EncryptedTableColumn } from '../types-public-Dv-r6Ik0.js';
5
+ import { g as EncryptedTable, h as EncryptedTableColumn } from '../types-public-CpS5KjwX.js';
5
6
  import '@byteslice/result';
6
7
  import '@cipherstash/protect-ffi';
7
8
  import 'zod';
@@ -13,6 +14,51 @@ type EncryptedSupabaseConfig = {
13
14
  interface EncryptedSupabaseInstance {
14
15
  from<T extends Record<string, unknown> = Record<string, unknown>>(tableName: string, schema: EncryptedTable<EncryptedTableColumn>): EncryptedQueryBuilder<T>;
15
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
+ }
16
62
  type EncryptedSupabaseResponse<T> = {
17
63
  data: T | null;
18
64
  error: EncryptedSupabaseError | null;
@@ -39,71 +85,71 @@ interface SupabaseClientLike {
39
85
 
40
86
  /** Helper to extract string keys from T */
41
87
  type StringKeyOf<T> = Extract<keyof T, string>;
42
- interface EncryptedQueryBuilder<T extends Record<string, unknown> = Record<string, unknown>> extends PromiseLike<EncryptedSupabaseResponse<T[]>> {
88
+ interface EncryptedQueryBuilder<T extends Record<string, unknown> = Record<string, unknown>, FK extends StringKeyOf<T> = StringKeyOf<T>> extends PromiseLike<EncryptedSupabaseResponse<T[]>> {
43
89
  select(columns: string, options?: {
44
90
  head?: boolean;
45
91
  count?: 'exact' | 'planned' | 'estimated';
46
- }): EncryptedQueryBuilder<T>;
92
+ }): EncryptedQueryBuilder<T, FK>;
47
93
  insert(data: Partial<T> | Partial<T>[], options?: {
48
94
  count?: 'exact' | 'planned' | 'estimated';
49
95
  defaultToNull?: boolean;
50
96
  onConflict?: string;
51
- }): EncryptedQueryBuilder<T>;
97
+ }): EncryptedQueryBuilder<T, FK>;
52
98
  update(data: Partial<T>, options?: {
53
99
  count?: 'exact' | 'planned' | 'estimated';
54
- }): EncryptedQueryBuilder<T>;
100
+ }): EncryptedQueryBuilder<T, FK>;
55
101
  upsert(data: Partial<T> | Partial<T>[], options?: {
56
102
  count?: 'exact' | 'planned' | 'estimated';
57
103
  onConflict?: string;
58
104
  ignoreDuplicates?: boolean;
59
105
  defaultToNull?: boolean;
60
- }): EncryptedQueryBuilder<T>;
106
+ }): EncryptedQueryBuilder<T, FK>;
61
107
  delete(options?: {
62
108
  count?: 'exact' | 'planned' | 'estimated';
63
- }): EncryptedQueryBuilder<T>;
64
- eq<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
65
- neq<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
66
- gt<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
67
- gte<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
68
- lt<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
69
- lte<K extends StringKeyOf<T>>(column: K, value: T[K]): EncryptedQueryBuilder<T>;
70
- like<K extends StringKeyOf<T>>(column: K, pattern: string): EncryptedQueryBuilder<T>;
71
- ilike<K extends StringKeyOf<T>>(column: K, pattern: string): EncryptedQueryBuilder<T>;
72
- is<K extends StringKeyOf<T>>(column: K, value: null | boolean): EncryptedQueryBuilder<T>;
73
- in<K extends StringKeyOf<T>>(column: K, values: T[K][]): EncryptedQueryBuilder<T>;
74
- filter<K extends StringKeyOf<T>>(column: K, operator: string, value: T[K]): EncryptedQueryBuilder<T>;
75
- not<K extends StringKeyOf<T>>(column: K, operator: string, value: T[K]): EncryptedQueryBuilder<T>;
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>;
76
122
  or(filters: string, options?: {
77
123
  referencedTable?: string;
78
124
  foreignTable?: string;
79
- }): EncryptedQueryBuilder<T>;
125
+ }): EncryptedQueryBuilder<T, FK>;
80
126
  or(conditions: PendingOrCondition[], options?: {
81
127
  referencedTable?: string;
82
128
  foreignTable?: string;
83
- }): EncryptedQueryBuilder<T>;
84
- match(query: Partial<T>): EncryptedQueryBuilder<T>;
129
+ }): EncryptedQueryBuilder<T, FK>;
130
+ match(query: Partial<Pick<T, FK>>): EncryptedQueryBuilder<T, FK>;
85
131
  order<K extends StringKeyOf<T>>(column: K, options?: {
86
132
  ascending?: boolean;
87
133
  nullsFirst?: boolean;
88
134
  referencedTable?: string;
89
135
  foreignTable?: string;
90
- }): EncryptedQueryBuilder<T>;
136
+ }): EncryptedQueryBuilder<T, FK>;
91
137
  limit(count: number, options?: {
92
138
  referencedTable?: string;
93
139
  foreignTable?: string;
94
- }): EncryptedQueryBuilder<T>;
140
+ }): EncryptedQueryBuilder<T, FK>;
95
141
  range(from: number, to: number, options?: {
96
142
  referencedTable?: string;
97
143
  foreignTable?: string;
98
- }): EncryptedQueryBuilder<T>;
99
- single(): EncryptedQueryBuilder<T>;
100
- maybeSingle(): EncryptedQueryBuilder<T>;
101
- csv(): EncryptedQueryBuilder<T>;
102
- abortSignal(signal: AbortSignal): EncryptedQueryBuilder<T>;
103
- throwOnError(): EncryptedQueryBuilder<T>;
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>;
104
150
  returns<U extends Record<string, unknown>>(): EncryptedQueryBuilder<U>;
105
- withLockContext(lockContext: LockContext): EncryptedQueryBuilder<T>;
106
- audit(config: AuditConfig): EncryptedQueryBuilder<T>;
151
+ withLockContext(lockContext: LockContext): EncryptedQueryBuilder<T, FK>;
152
+ audit(config: AuditConfig): EncryptedQueryBuilder<T, FK>;
107
153
  }
108
154
 
109
155
  /**
@@ -140,5 +186,38 @@ interface EncryptedQueryBuilder<T extends Record<string, unknown> = Record<strin
140
186
  * ```
141
187
  */
142
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;
143
222
 
144
- export { type EncryptedQueryBuilder, type EncryptedSupabaseConfig, type EncryptedSupabaseError, type EncryptedSupabaseInstance, type EncryptedSupabaseResponse, type PendingOrCondition, type SupabaseClientLike, encryptedSupabase };
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 };