@cipherstash/stack 0.18.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 +704 -0
- package/README.md +97 -79
- 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-VPOTNP4K.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-XWPGAHBZ.js → chunk-BNO32ZMV.js} +1 -1
- package/dist/chunk-BNO32ZMV.js.map +1 -0
- package/dist/chunk-CLM7E4I6.js +4439 -0
- package/dist/chunk-CLM7E4I6.js.map +1 -0
- package/dist/{chunk-LLCCNKDL.js → chunk-HQANMV7R.js} +3 -3
- package/dist/{chunk-LLCCNKDL.js.map → chunk-HQANMV7R.js.map} +1 -1
- package/dist/chunk-JSG2AMDI.js +17 -0
- package/dist/chunk-JSG2AMDI.js.map +1 -0
- package/dist/chunk-OFQ555AX.js +191 -0
- package/dist/chunk-OFQ555AX.js.map +1 -0
- package/dist/chunk-PZ5AY32C.js +10 -0
- package/dist/chunk-PZ5AY32C.js.map +1 -0
- package/dist/chunk-V2Q3NYIH.js +494 -0
- 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-ZYOZHZMJ.js → chunk-ZTP5QJ27.js} +193 -169
- package/dist/chunk-ZTP5QJ27.js.map +1 -0
- package/dist/client.cjs +4124 -49
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +6 -5
- package/dist/client.d.ts +6 -5
- package/dist/client.js +3 -1
- package/dist/columns-D2_YzrCX.d.cts +622 -0
- package/dist/columns-rZc7fQHI.d.ts +622 -0
- package/dist/dynamodb/index.cjs +19 -12
- package/dist/dynamodb/index.cjs.map +1 -1
- package/dist/dynamodb/index.d.cts +3 -2
- package/dist/dynamodb/index.d.ts +3 -2
- package/dist/dynamodb/index.js +8 -10
- package/dist/dynamodb/index.js.map +1 -1
- package/dist/encryption/index.cjs +4496 -222
- 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 +15 -7
- package/dist/encryption/v3.cjs +7896 -0
- package/dist/encryption/v3.cjs.map +1 -0
- package/dist/encryption/v3.d.cts +103 -0
- package/dist/encryption/v3.d.ts +103 -0
- package/dist/encryption/v3.js +189 -0
- package/dist/encryption/v3.js.map +1 -0
- package/dist/eql/v3/index.cjs +663 -0
- package/dist/eql/v3/index.cjs.map +1 -0
- package/dist/eql/v3/index.d.cts +173 -0
- package/dist/eql/v3/index.d.ts +173 -0
- package/dist/eql/v3/index.js +99 -0
- package/dist/eql/v3/index.js.map +1 -0
- package/dist/errors/index.js +1 -0
- package/dist/identity/index.cjs +55 -35
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.d.cts +54 -30
- package/dist/identity/index.d.ts +54 -30
- package/dist/identity/index.js +9 -177
- package/dist/identity/index.js.map +1 -1
- package/dist/index-BquA71_Y.d.ts +24 -0
- package/dist/index-fhWTOV0K.d.cts +24 -0
- package/dist/index.cjs +4547 -243
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -19
- package/dist/index.d.ts +18 -19
- package/dist/index.js +20 -5
- package/dist/index.js.map +1 -1
- package/dist/schema/index.cjs +4128 -49
- 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 +3 -1
- package/dist/{types-public-BTxqjmtv.d.cts → types-public-QMjYNfQO.d.cts} +448 -251
- package/dist/{types-public-BTxqjmtv.d.ts → types-public-QMjYNfQO.d.ts} +448 -251
- package/dist/types-public.cjs.map +1 -1
- package/dist/types-public.d.cts +2 -2
- package/dist/types-public.d.ts +2 -2
- package/dist/types-public.js +2 -1
- package/dist/wasm-inline.d.ts +1643 -0
- package/dist/wasm-inline.js +4901 -0
- package/dist/wasm-inline.js.map +1 -0
- package/package.json +74 -52
- package/dist/chunk-VPOTNP4K.js.map +0 -1
- package/dist/chunk-XWPGAHBZ.js.map +0 -1
- package/dist/chunk-YWQXTZ5M.js +0 -383
- package/dist/chunk-YWQXTZ5M.js.map +0 -1
- package/dist/chunk-ZYOZHZMJ.js.map +0 -1
- package/dist/client-CIsfZ2zg.d.ts +0 -692
- package/dist/client-Dt98Rugc.d.cts +0 -692
- package/dist/drizzle/index.cjs +0 -1558
- 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 -1215
- package/dist/drizzle/index.js.map +0 -1
- package/dist/supabase/index.cjs +0 -1526
- package/dist/supabase/index.cjs.map +0 -1
- package/dist/supabase/index.d.cts +0 -144
- package/dist/supabase/index.d.ts +0 -144
- package/dist/supabase/index.js +0 -899
- package/dist/supabase/index.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cipherstash/stack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-rc.0",
|
|
4
4
|
"description": "CipherStash Stack for TypeScript and JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"encrypted",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"directory": "packages/stack"
|
|
20
20
|
},
|
|
21
21
|
"license": "MIT",
|
|
22
|
-
"author": "CipherStash <
|
|
22
|
+
"author": "CipherStash <humans@cipherstash.com>",
|
|
23
23
|
"files": [
|
|
24
24
|
"dist",
|
|
25
25
|
"README.md",
|
|
@@ -39,6 +39,9 @@
|
|
|
39
39
|
"errors": [
|
|
40
40
|
"./dist/errors/index.d.ts"
|
|
41
41
|
],
|
|
42
|
+
"adapter-kit": [
|
|
43
|
+
"./dist/adapter-kit.d.ts"
|
|
44
|
+
],
|
|
42
45
|
"client": [
|
|
43
46
|
"./dist/client.d.ts"
|
|
44
47
|
],
|
|
@@ -51,17 +54,20 @@
|
|
|
51
54
|
"schema": [
|
|
52
55
|
"./dist/schema/index.d.ts"
|
|
53
56
|
],
|
|
57
|
+
"eql/v3": [
|
|
58
|
+
"./dist/eql/v3/index.d.ts"
|
|
59
|
+
],
|
|
60
|
+
"v3": [
|
|
61
|
+
"./dist/encryption/v3.d.ts"
|
|
62
|
+
],
|
|
54
63
|
"types": [
|
|
55
64
|
"./dist/types-public.d.ts"
|
|
56
65
|
],
|
|
57
|
-
"drizzle": [
|
|
58
|
-
"./dist/drizzle/index.d.ts"
|
|
59
|
-
],
|
|
60
66
|
"dynamodb": [
|
|
61
67
|
"./dist/dynamodb/index.d.ts"
|
|
62
68
|
],
|
|
63
|
-
"
|
|
64
|
-
"./dist/
|
|
69
|
+
"wasm-inline": [
|
|
70
|
+
"./dist/wasm-inline.d.ts"
|
|
65
71
|
]
|
|
66
72
|
}
|
|
67
73
|
},
|
|
@@ -96,16 +102,6 @@
|
|
|
96
102
|
"default": "./dist/identity/index.cjs"
|
|
97
103
|
}
|
|
98
104
|
},
|
|
99
|
-
"./secrets": {
|
|
100
|
-
"import": {
|
|
101
|
-
"types": "./dist/secrets/index.d.ts",
|
|
102
|
-
"default": "./dist/secrets/index.js"
|
|
103
|
-
},
|
|
104
|
-
"require": {
|
|
105
|
-
"types": "./dist/secrets/index.d.cts",
|
|
106
|
-
"default": "./dist/secrets/index.cjs"
|
|
107
|
-
}
|
|
108
|
-
},
|
|
109
105
|
"./schema": {
|
|
110
106
|
"import": {
|
|
111
107
|
"types": "./dist/schema/index.d.ts",
|
|
@@ -116,44 +112,44 @@
|
|
|
116
112
|
"default": "./dist/schema/index.cjs"
|
|
117
113
|
}
|
|
118
114
|
},
|
|
119
|
-
"./
|
|
115
|
+
"./eql/v3": {
|
|
120
116
|
"import": {
|
|
121
|
-
"types": "./dist/
|
|
122
|
-
"default": "./dist/
|
|
117
|
+
"types": "./dist/eql/v3/index.d.ts",
|
|
118
|
+
"default": "./dist/eql/v3/index.js"
|
|
123
119
|
},
|
|
124
120
|
"require": {
|
|
125
|
-
"types": "./dist/
|
|
126
|
-
"default": "./dist/
|
|
121
|
+
"types": "./dist/eql/v3/index.d.cts",
|
|
122
|
+
"default": "./dist/eql/v3/index.cjs"
|
|
127
123
|
}
|
|
128
124
|
},
|
|
129
|
-
"./
|
|
125
|
+
"./v3": {
|
|
130
126
|
"import": {
|
|
131
|
-
"types": "./dist/
|
|
132
|
-
"default": "./dist/
|
|
127
|
+
"types": "./dist/encryption/v3.d.ts",
|
|
128
|
+
"default": "./dist/encryption/v3.js"
|
|
133
129
|
},
|
|
134
130
|
"require": {
|
|
135
|
-
"types": "./dist/
|
|
136
|
-
"default": "./dist/
|
|
131
|
+
"types": "./dist/encryption/v3.d.cts",
|
|
132
|
+
"default": "./dist/encryption/v3.cjs"
|
|
137
133
|
}
|
|
138
134
|
},
|
|
139
|
-
"./
|
|
135
|
+
"./types": {
|
|
140
136
|
"import": {
|
|
141
|
-
"types": "./dist/
|
|
142
|
-
"default": "./dist/
|
|
137
|
+
"types": "./dist/types-public.d.ts",
|
|
138
|
+
"default": "./dist/types-public.js"
|
|
143
139
|
},
|
|
144
140
|
"require": {
|
|
145
|
-
"types": "./dist/
|
|
146
|
-
"default": "./dist/
|
|
141
|
+
"types": "./dist/types-public.d.cts",
|
|
142
|
+
"default": "./dist/types-public.cjs"
|
|
147
143
|
}
|
|
148
144
|
},
|
|
149
|
-
"./
|
|
145
|
+
"./dynamodb": {
|
|
150
146
|
"import": {
|
|
151
|
-
"types": "./dist/
|
|
152
|
-
"default": "./dist/
|
|
147
|
+
"types": "./dist/dynamodb/index.d.ts",
|
|
148
|
+
"default": "./dist/dynamodb/index.js"
|
|
153
149
|
},
|
|
154
150
|
"require": {
|
|
155
|
-
"types": "./dist/
|
|
156
|
-
"default": "./dist/
|
|
151
|
+
"types": "./dist/dynamodb/index.d.cts",
|
|
152
|
+
"default": "./dist/dynamodb/index.cjs"
|
|
157
153
|
}
|
|
158
154
|
},
|
|
159
155
|
"./encryption": {
|
|
@@ -176,51 +172,77 @@
|
|
|
176
172
|
"default": "./dist/errors/index.cjs"
|
|
177
173
|
}
|
|
178
174
|
},
|
|
175
|
+
"./adapter-kit": {
|
|
176
|
+
"import": {
|
|
177
|
+
"types": "./dist/adapter-kit.d.ts",
|
|
178
|
+
"default": "./dist/adapter-kit.js"
|
|
179
|
+
},
|
|
180
|
+
"require": {
|
|
181
|
+
"types": "./dist/adapter-kit.d.cts",
|
|
182
|
+
"default": "./dist/adapter-kit.cjs"
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
"./wasm-inline": {
|
|
186
|
+
"import": {
|
|
187
|
+
"types": "./dist/wasm-inline.d.ts",
|
|
188
|
+
"default": "./dist/wasm-inline.js"
|
|
189
|
+
}
|
|
190
|
+
},
|
|
179
191
|
"./package.json": "./package.json"
|
|
180
192
|
},
|
|
181
193
|
"devDependencies": {
|
|
194
|
+
"@cipherstash/eql": "3.0.0",
|
|
182
195
|
"@clack/prompts": "^1.4.0",
|
|
183
|
-
"@
|
|
196
|
+
"@clerk/backend": "3.4.9",
|
|
197
|
+
"@supabase/postgrest-js": "2.105.4",
|
|
198
|
+
"@supabase/supabase-js": "^2.110.0",
|
|
199
|
+
"@types/pg": "^8.20.0",
|
|
184
200
|
"@types/uuid": "^11.0.0",
|
|
185
201
|
"dotenv": "17.4.2",
|
|
186
202
|
"drizzle-orm": "^0.45.2",
|
|
187
203
|
"execa": "^9.5.2",
|
|
204
|
+
"fast-check": "^4.8.0",
|
|
205
|
+
"fta-cli": "3.0.0",
|
|
188
206
|
"json-schema-to-typescript": "^15.0.2",
|
|
207
|
+
"pg": "8.20.0",
|
|
189
208
|
"postgres": "^3.4.8",
|
|
190
209
|
"tsup": "8.5.1",
|
|
191
210
|
"tsx": "4.22.1",
|
|
192
211
|
"typescript": "5.9.3",
|
|
193
|
-
"vitest": "3.2.
|
|
212
|
+
"vitest": "3.2.6"
|
|
194
213
|
},
|
|
195
214
|
"publishConfig": {
|
|
196
215
|
"access": "public"
|
|
197
216
|
},
|
|
198
217
|
"dependencies": {
|
|
199
218
|
"@byteslice/result": "0.2.0",
|
|
200
|
-
"@cipherstash/
|
|
219
|
+
"@cipherstash/auth": "0.41.0",
|
|
220
|
+
"@cipherstash/protect-ffi": "0.29.0",
|
|
201
221
|
"evlog": "1.11.0",
|
|
202
222
|
"uuid": "14.0.0",
|
|
203
223
|
"zod": "3.25.76"
|
|
204
224
|
},
|
|
205
|
-
"
|
|
206
|
-
|
|
207
|
-
"
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
"
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
"@supabase/supabase-js": {
|
|
214
|
-
"optional": true
|
|
215
|
-
}
|
|
225
|
+
"//optionalDependencies": "@cipherstash/auth ships per-platform native bindings as optional peerDependencies. pnpm does not auto-install platform-matched optional peer deps, so we declare them here as optionalDependencies — pnpm then picks the binary matching the host's os/cpu (from each sub-package's own package.json) and ignores the rest. Required because @cipherstash/stack re-exports the Node auth strategies (OidcFederationStrategy, AccessKeyStrategy, …). All seven names share a single catalog entry to keep them in lockstep.",
|
|
226
|
+
"optionalDependencies": {
|
|
227
|
+
"@cipherstash/auth-darwin-arm64": "0.41.0",
|
|
228
|
+
"@cipherstash/auth-darwin-x64": "0.41.0",
|
|
229
|
+
"@cipherstash/auth-linux-arm64-gnu": "0.41.0",
|
|
230
|
+
"@cipherstash/auth-linux-x64-gnu": "0.41.0",
|
|
231
|
+
"@cipherstash/auth-linux-x64-musl": "0.41.0",
|
|
232
|
+
"@cipherstash/auth-win32-x64-msvc": "0.41.0"
|
|
216
233
|
},
|
|
217
234
|
"engines": {
|
|
218
235
|
"node": ">=22"
|
|
219
236
|
},
|
|
220
237
|
"scripts": {
|
|
238
|
+
"prebuild": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
221
239
|
"build": "tsup",
|
|
222
240
|
"dev": "tsup --watch",
|
|
241
|
+
"analyze:complexity": "fta src/eql/v3 --score-cap 69",
|
|
242
|
+
"db:eql-v3:install": "tsx scripts/install-eql-v3.ts",
|
|
223
243
|
"test": "vitest run",
|
|
224
|
-
"
|
|
244
|
+
"test:types": "vitest --run --typecheck.only",
|
|
245
|
+
"release": "tsup",
|
|
246
|
+
"test:integration": "vitest run --config integration/vitest.config.ts"
|
|
225
247
|
}
|
|
226
248
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["import type {\n EncryptedColumn,\n EncryptedField,\n EncryptedTable,\n EncryptedTableColumn,\n // Imported type-only for the TSDoc {@link} references in the comments below.\n encryptedColumn,\n encryptedField,\n} from '@/schema'\nimport type {\n Encrypted as CipherStashEncrypted,\n EncryptedQuery as CipherStashEncryptedQuery,\n JsPlaintext,\n QueryOpName,\n newClient,\n} from '@cipherstash/protect-ffi'\n\n// ---------------------------------------------------------------------------\n// Branded type utilities\n// ---------------------------------------------------------------------------\n\n/** Brand symbol for nominal typing */\ndeclare const __brand: unique symbol\n\n/** Creates a branded type that is structurally incompatible with the base type */\ntype Brand<T, B extends string> = T & { readonly [__brand]: B }\n\n// ---------------------------------------------------------------------------\n// Core types\n// ---------------------------------------------------------------------------\n\nexport type Client = Awaited<ReturnType<typeof newClient>> | undefined\n\n/** A branded type representing encrypted data. Cannot be accidentally used as plaintext. */\nexport type EncryptedValue = Brand<CipherStashEncrypted, 'encrypted'>\n\n/** Structural type representing encrypted data stored in the database. Always\n * carries a ciphertext. See also `EncryptedValue` for branded nominal typing,\n * and {@link EncryptedQuery} for the search-term shape returned by\n * `encryptQuery`. */\nexport type Encrypted = CipherStashEncrypted\n\n/** Structural type representing an encrypted query term (search needle)\n * returned by `encryptQuery` / `encryptQueryBulk` for scalar\n * (`unique` / `match` / `ore`) lookups and `ste_vec_selector` JSON path\n * queries. Carries no ciphertext — matched against stored values, never\n * decrypted. JSON containment queries (`ste_vec_term`) return a\n * storage-shaped {@link Encrypted} payload instead. */\nexport type EncryptedQuery = CipherStashEncryptedQuery\n\n// ---------------------------------------------------------------------------\n// Client configuration\n// ---------------------------------------------------------------------------\n\nexport type KeysetIdentifier = { name: string } | { id: string }\n\nexport type ClientConfig = {\n /**\n * The CipherStash workspace CRN (Cloud Resource Name).\n * Format: `crn:<region>.aws:<workspace-id>`.\n * Can also be set via the `CS_WORKSPACE_CRN` environment variable.\n */\n workspaceCrn?: string\n\n /**\n * The API access key used for authenticating with the CipherStash API.\n * Can also be set via the `CS_CLIENT_ACCESS_KEY` environment variable.\n * Obtain this from the CipherStash dashboard after creating a workspace.\n */\n accessKey?: string\n\n /**\n * The client identifier used to authenticate with CipherStash services.\n * Can also be set via the `CS_CLIENT_ID` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientId?: string\n\n /**\n * The client key material used in combination with ZeroKMS for encryption operations.\n * Can also be set via the `CS_CLIENT_KEY` environment variable.\n * Generated during workspace onboarding in the CipherStash dashboard.\n */\n clientKey?: string\n\n /**\n * An optional keyset identifier for multi-tenant encryption.\n * Each keyset provides cryptographic isolation, giving each tenant its own keyspace.\n * Specify by name (`{ name: \"tenant-a\" }`) or UUID (`{ id: \"...\" }`).\n * Keysets are created and managed in the CipherStash dashboard.\n */\n keyset?: KeysetIdentifier\n}\n\ntype AtLeastOneCsTable<T> = [T, ...T[]]\n\nexport type EncryptionClientConfig = {\n schemas: AtLeastOneCsTable<EncryptedTable<EncryptedTableColumn>>\n config?: ClientConfig\n}\n\n// ---------------------------------------------------------------------------\n// Encrypt / decrypt operation options and results\n// ---------------------------------------------------------------------------\n\n/**\n * Options for single-value encrypt operations.\n * Use a column from your table schema (from {@link encryptedColumn}) or a nested\n * field (from {@link encryptedField}) as the target for encryption.\n */\nexport type EncryptOptions = {\n /** The column or nested field to encrypt into. From {@link EncryptedColumn} or {@link EncryptedField}. */\n column: EncryptedColumn | EncryptedField\n table: EncryptedTable<EncryptedTableColumn>\n}\n\n/** Format for encrypted query/search term return values */\nexport type EncryptedReturnType =\n | 'eql'\n | 'composite-literal'\n | 'escaped-composite-literal'\n\nexport type SearchTerm = {\n value: JsPlaintext\n column: EncryptedColumn\n table: EncryptedTable<EncryptedTableColumn>\n returnType?: EncryptedReturnType\n}\n\n/** Encrypted search term result. `eql` return type yields either a storage\n * payload (`Encrypted`, for `ste_vec_term`) or a query-only term\n * (`EncryptedQuery`, for scalar lookups and `ste_vec_selector`); the\n * `composite-literal` return types yield a string. */\nexport type EncryptedSearchTerm = Encrypted | EncryptedQuery | string\n\n/** Result of encryptQuery (single or batch). `eql` return type yields either a\n * storage payload (`Encrypted`) or a query-only term (`EncryptedQuery`); the\n * `composite-literal` return types yield a string. */\n// null elements appear in the batch path when a term has a null/undefined\n// value — the operation preserves position so callers can correlate results\n// with their input array.\nexport type EncryptedQueryResult =\n | Encrypted\n | EncryptedQuery\n | string\n | null\n\n// ---------------------------------------------------------------------------\n// Model field types (encrypted vs decrypted views)\n// ---------------------------------------------------------------------------\n\nexport type EncryptedFields<T> = {\n [K in keyof T as NonNullable<T[K]> extends Encrypted ? K : never]: T[K]\n}\n\nexport type OtherFields<T> = {\n [K in keyof T as NonNullable<T[K]> extends Encrypted ? never : K]: T[K]\n}\n\nexport type DecryptedFields<T> = {\n [K in keyof T as NonNullable<T[K]> extends Encrypted\n ? K\n : never]: null extends T[K] ? string | null : string\n}\n\n/** Model with encrypted fields replaced by plaintext (decrypted) values */\nexport type Decrypted<T> = OtherFields<T> & DecryptedFields<T>\n\n/**\n * Maps a plaintext model type to its encrypted form using the table schema.\n *\n * Fields whose keys match columns defined in `S` become `Encrypted`;\n * all other fields retain their original types from `T`.\n *\n * When `S` is the widened `EncryptedTableColumn` (e.g. when a user passes an\n * explicit `<User>` type argument without specifying `S`), the type degrades\n * gracefully to `T` — preserving backward compatibility.\n *\n * @typeParam T - The plaintext model type (e.g. `{ id: string; email: string }`)\n * @typeParam S - The table schema column definition, inferred from the `table` argument\n *\n * @example\n * ```typescript\n * type User = { id: string; email: string }\n * // With a schema that defines `email`:\n * type Encrypted = EncryptedFromSchema<User, { email: EncryptedColumn }>\n * // => { id: string; email: Encrypted }\n * ```\n */\nexport type EncryptedFromSchema<T, S extends EncryptedTableColumn> = {\n [K in keyof T]: [K] extends [keyof S]\n ? [S[K & keyof S]] extends [EncryptedColumn | EncryptedField]\n ? null extends T[K]\n ? Encrypted | null\n : Encrypted\n : T[K]\n : T[K]\n}\n\n// ---------------------------------------------------------------------------\n// Bulk operations\n// ---------------------------------------------------------------------------\n\n// Bulk payloads admit null elements — bulk operations pass them through\n// untouched (encrypt(null) -> null, decrypt(null) -> null) so callers can\n// process mixed nullable arrays without filtering ahead of time. The\n// runtime guards in the operation classes preserve the null in the\n// position-stable output.\nexport type BulkEncryptPayload = Array<{\n id?: string\n plaintext: JsPlaintext | null\n}>\n\nexport type BulkEncryptedData = Array<{ id?: string; data: Encrypted | null }>\nexport type BulkDecryptPayload = Array<{ id?: string; data: Encrypted | null }>\nexport type BulkDecryptedData = Array<DecryptionResult<JsPlaintext | null>>\n\ntype DecryptionSuccess<T> = { error?: never; data: T; id?: string }\ntype DecryptionError<T> = { error: T; id?: string; data?: never }\n\n/**\n * Result type for individual items in bulk decrypt operations.\n * Uses `error`/`data` fields (not `failure`/`data`) since bulk operations\n * can have per-item failures.\n */\nexport type DecryptionResult<T> = DecryptionSuccess<T> | DecryptionError<T>\n\n// ---------------------------------------------------------------------------\n// Query types (for searchable encryption / encryptQuery)\n// ---------------------------------------------------------------------------\n\n/**\n * User-facing query type names for encrypting query values.\n *\n * - `'equality'`: Exact match. [Exact Queries](https://cipherstash.com/docs/stack/cipherstash/encryption/searchable-encryption)\n * - `'freeTextSearch'`: Text search. [Match Queries](https://cipherstash.com/docs/stack/cipherstash/encryption/searchable-encryption)\n * - `'orderAndRange'`: Comparison and range. [Range Queries](https://cipherstash.com/docs/stack/cipherstash/encryption/searchable-encryption)\n * - `'steVecSelector'`: JSONPath selector (e.g. `'$.user.email'`)\n * - `'steVecTerm'`: Containment (e.g. `{ role: 'admin' }`)\n * - `'searchableJson'`: Auto-infers selector or term from plaintext type (recommended)\n */\nexport type QueryTypeName =\n | 'orderAndRange'\n | 'freeTextSearch'\n | 'equality'\n | 'steVecSelector'\n | 'steVecTerm'\n | 'searchableJson'\n\n/** @internal */\nexport type FfiIndexTypeName = 'ore' | 'match' | 'unique' | 'ste_vec'\n\nexport const queryTypes = {\n orderAndRange: 'orderAndRange',\n freeTextSearch: 'freeTextSearch',\n equality: 'equality',\n steVecSelector: 'steVecSelector',\n steVecTerm: 'steVecTerm',\n searchableJson: 'searchableJson',\n} as const satisfies Record<string, QueryTypeName>\n\n/** @internal */\nexport const queryTypeToFfi: Record<QueryTypeName, FfiIndexTypeName> = {\n orderAndRange: 'ore',\n freeTextSearch: 'match',\n equality: 'unique',\n steVecSelector: 'ste_vec',\n steVecTerm: 'ste_vec',\n searchableJson: 'ste_vec',\n}\n\n/** @internal */\nexport const queryTypeToQueryOp: Partial<Record<QueryTypeName, QueryOpName>> = {\n steVecSelector: 'ste_vec_selector',\n steVecTerm: 'ste_vec_term',\n}\n\n/** @internal */\nexport type QueryTermBase = {\n column: EncryptedColumn\n table: EncryptedTable<EncryptedTableColumn>\n queryType?: QueryTypeName\n returnType?: EncryptedReturnType\n}\n\nexport type EncryptQueryOptions = QueryTermBase\n\nexport type ScalarQueryTerm = QueryTermBase & {\n value: JsPlaintext\n}\n"],"mappings":";AA4PO,IAAM,aAAa;AAAA,EACxB,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,gBAAgB;AAClB;AAGO,IAAM,iBAA0D;AAAA,EACrE,eAAe;AAAA,EACf,gBAAgB;AAAA,EAChB,UAAU;AAAA,EACV,gBAAgB;AAAA,EAChB,YAAY;AAAA,EACZ,gBAAgB;AAClB;AAGO,IAAM,qBAAkE;AAAA,EAC7E,gBAAgB;AAAA,EAChB,YAAY;AACd;","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/encryption/helpers/index.ts"],"sourcesContent":["import type { Encrypted, EncryptedQueryResult, KeysetIdentifier } from '@/types'\nimport type {\n Encrypted as CipherStashEncrypted,\n EncryptedQuery as CipherStashEncryptedQuery,\n KeysetIdentifier as KeysetIdentifierFfi,\n} from '@cipherstash/protect-ffi'\n\n/**\n * The shape `encryptQuery` / `encryptQueryBulk` can return: a full storage\n * payload (returned for `ste_vec_term` containment queries) or a query-only\n * payload with no ciphertext (scalar `unique`/`match`/`ore` lookups and\n * `ste_vec_selector` path queries).\n *\n * TODO: duplicated in `@cipherstash/protect` — see\n * `packages/protect/src/helpers/index.ts`. Both copies should be removed once\n * `@cipherstash/protect-ffi` exports a named alias for the `encryptQuery`\n * return type (https://github.com/cipherstash/stack/pull/473).\n */\ntype EncryptedQueryTerm = CipherStashEncrypted | CipherStashEncryptedQuery\n\nexport type EncryptedPgComposite = {\n data: Encrypted\n}\n\n/**\n * Helper function to transform an encrypted payload into a PostgreSQL composite type.\n * Use this when inserting data via Supabase or similar clients.\n */\nexport function encryptedToPgComposite(obj: Encrypted): EncryptedPgComposite {\n return {\n data: obj,\n }\n}\n\n/**\n * Helper function to transform an encrypted payload into a PostgreSQL composite literal string.\n * Use this when querying with `.eq()` or similar equality operations in Supabase.\n *\n * @example\n * ```typescript\n * const literal = encryptedToCompositeLiteral(encrypted)\n * await supabase.from('table').select().eq('column', literal)\n * ```\n */\nexport function encryptedToCompositeLiteral(obj: EncryptedQueryTerm): string {\n return `(${JSON.stringify(JSON.stringify(obj))})`\n}\n\n/**\n * Helper function to transform an encrypted payload into an escaped PostgreSQL composite literal string.\n * Use this when you need the composite literal format to be escaped as a string value.\n *\n * @example\n * ```typescript\n * const escapedLiteral = encryptedToEscapedCompositeLiteral(encrypted)\n * ```\n */\nexport function encryptedToEscapedCompositeLiteral(\n obj: EncryptedQueryTerm,\n): string {\n return JSON.stringify(encryptedToCompositeLiteral(obj))\n}\n\n/**\n * Format an encrypted result based on the requested return type.\n *\n * - `'composite-literal'` → PostgreSQL composite literal string `(\"json\")`\n * - `'escaped-composite-literal'` → escaped variant `\"(\\\"json\\\")\"`\n * - default (`'eql'` or omitted) → raw encrypted object\n */\nexport function formatEncryptedResult(\n encrypted: EncryptedQueryTerm,\n returnType?: string,\n): EncryptedQueryResult {\n if (returnType === 'composite-literal') {\n return encryptedToCompositeLiteral(encrypted)\n }\n if (returnType === 'escaped-composite-literal') {\n return encryptedToEscapedCompositeLiteral(encrypted)\n }\n return encrypted\n}\n\n/**\n * Helper function to transform a model's encrypted fields into PostgreSQL composite types\n */\nexport function modelToEncryptedPgComposites<T extends Record<string, unknown>>(\n model: T,\n): T {\n const result: Record<string, unknown> = {}\n\n for (const [key, value] of Object.entries(model)) {\n if (isEncryptedPayload(value)) {\n result[key] = encryptedToPgComposite(value)\n } else {\n result[key] = value\n }\n }\n\n return result as T\n}\n\n/**\n * Helper function to transform multiple models' encrypted fields into PostgreSQL composite types\n */\nexport function bulkModelsToEncryptedPgComposites<\n T extends Record<string, unknown>,\n>(models: T[]): T[] {\n return models.map((model) => modelToEncryptedPgComposites(model))\n}\n\nexport function toFfiKeysetIdentifier(\n keyset: KeysetIdentifier | undefined,\n): KeysetIdentifierFfi | undefined {\n if (!keyset) return undefined\n\n if ('name' in keyset) {\n return { Name: keyset.name }\n }\n\n return { Uuid: keyset.id }\n}\n\n/**\n * Helper function to check if a value is an encrypted payload\n */\nexport function isEncryptedPayload(value: unknown): value is Encrypted {\n if (value === null) return false\n if (typeof value !== 'object') return false\n\n const obj = value as Record<string, unknown>\n\n // Must have version field (number)\n if (!('v' in obj) || typeof obj.v !== 'number') return false\n\n // Must have index field (object)\n if (!('i' in obj) || typeof obj.i !== 'object') return false\n\n // Must have either ciphertext (c) or searchable vector (sv)\n if (!('c' in obj) && !('sv' in obj)) return false\n\n return true\n}\n\nexport {\n toJsonPath,\n buildNestedObject,\n parseJsonbPath,\n} from './jsonb'\n"],"mappings":";AA4BO,SAAS,uBAAuB,KAAsC;AAC3E,SAAO;AAAA,IACL,MAAM;AAAA,EACR;AACF;AAYO,SAAS,4BAA4B,KAAiC;AAC3E,SAAO,IAAI,KAAK,UAAU,KAAK,UAAU,GAAG,CAAC,CAAC;AAChD;AAWO,SAAS,mCACd,KACQ;AACR,SAAO,KAAK,UAAU,4BAA4B,GAAG,CAAC;AACxD;AASO,SAAS,sBACd,WACA,YACsB;AACtB,MAAI,eAAe,qBAAqB;AACtC,WAAO,4BAA4B,SAAS;AAAA,EAC9C;AACA,MAAI,eAAe,6BAA6B;AAC9C,WAAO,mCAAmC,SAAS;AAAA,EACrD;AACA,SAAO;AACT;AAKO,SAAS,6BACd,OACG;AACH,QAAM,SAAkC,CAAC;AAEzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,GAAG;AAChD,QAAI,mBAAmB,KAAK,GAAG;AAC7B,aAAO,GAAG,IAAI,uBAAuB,KAAK;AAAA,IAC5C,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,kCAEd,QAAkB;AAClB,SAAO,OAAO,IAAI,CAAC,UAAU,6BAA6B,KAAK,CAAC;AAClE;AAEO,SAAS,sBACd,QACiC;AACjC,MAAI,CAAC,OAAQ,QAAO;AAEpB,MAAI,UAAU,QAAQ;AACpB,WAAO,EAAE,MAAM,OAAO,KAAK;AAAA,EAC7B;AAEA,SAAO,EAAE,MAAM,OAAO,GAAG;AAC3B;AAKO,SAAS,mBAAmB,OAAoC;AACrE,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI,OAAO,UAAU,SAAU,QAAO;AAEtC,QAAM,MAAM;AAGZ,MAAI,EAAE,OAAO,QAAQ,OAAO,IAAI,MAAM,SAAU,QAAO;AAGvD,MAAI,EAAE,OAAO,QAAQ,OAAO,IAAI,MAAM,SAAU,QAAO;AAGvD,MAAI,EAAE,OAAO,QAAQ,EAAE,QAAQ,KAAM,QAAO;AAE5C,SAAO;AACT;","names":[]}
|
package/dist/chunk-YWQXTZ5M.js
DELETED
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
// src/schema/index.ts
|
|
2
|
-
import { z } from "zod";
|
|
3
|
-
var eqlCastAsEnum = z.enum([
|
|
4
|
-
"text",
|
|
5
|
-
"int",
|
|
6
|
-
"small_int",
|
|
7
|
-
"big_int",
|
|
8
|
-
"real",
|
|
9
|
-
"double",
|
|
10
|
-
"boolean",
|
|
11
|
-
"date",
|
|
12
|
-
"jsonb"
|
|
13
|
-
]).default("text");
|
|
14
|
-
var castAsEnum = z.enum(["bigint", "boolean", "date", "number", "string", "json", "text"]).default("text");
|
|
15
|
-
function toEqlCastAs(value) {
|
|
16
|
-
switch (value) {
|
|
17
|
-
case "string":
|
|
18
|
-
return "text";
|
|
19
|
-
case "text":
|
|
20
|
-
return "text";
|
|
21
|
-
case "number":
|
|
22
|
-
return "double";
|
|
23
|
-
case "bigint":
|
|
24
|
-
return "big_int";
|
|
25
|
-
case "boolean":
|
|
26
|
-
return "boolean";
|
|
27
|
-
case "date":
|
|
28
|
-
return "date";
|
|
29
|
-
case "json":
|
|
30
|
-
return "jsonb";
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
var tokenFilterSchema = z.object({
|
|
34
|
-
kind: z.literal("downcase")
|
|
35
|
-
});
|
|
36
|
-
var tokenizerSchema = z.union([
|
|
37
|
-
z.object({
|
|
38
|
-
kind: z.literal("standard")
|
|
39
|
-
}),
|
|
40
|
-
z.object({
|
|
41
|
-
kind: z.literal("ngram"),
|
|
42
|
-
token_length: z.number()
|
|
43
|
-
})
|
|
44
|
-
]).default({ kind: "ngram", token_length: 3 }).optional();
|
|
45
|
-
var oreIndexOptsSchema = z.object({});
|
|
46
|
-
var uniqueIndexOptsSchema = z.object({
|
|
47
|
-
token_filters: z.array(tokenFilterSchema).default([]).optional()
|
|
48
|
-
});
|
|
49
|
-
var matchIndexOptsSchema = z.object({
|
|
50
|
-
tokenizer: tokenizerSchema,
|
|
51
|
-
token_filters: z.array(tokenFilterSchema).default([]).optional(),
|
|
52
|
-
k: z.number().default(6).optional(),
|
|
53
|
-
m: z.number().default(2048).optional(),
|
|
54
|
-
include_original: z.boolean().default(false).optional()
|
|
55
|
-
});
|
|
56
|
-
var arrayIndexModeSchema = z.union([
|
|
57
|
-
z.literal("all"),
|
|
58
|
-
z.literal("none"),
|
|
59
|
-
z.object({
|
|
60
|
-
item: z.boolean().optional(),
|
|
61
|
-
wildcard: z.boolean().optional(),
|
|
62
|
-
position: z.boolean().optional()
|
|
63
|
-
})
|
|
64
|
-
]);
|
|
65
|
-
var steVecIndexOptsSchema = z.object({
|
|
66
|
-
prefix: z.string(),
|
|
67
|
-
array_index_mode: arrayIndexModeSchema.optional()
|
|
68
|
-
});
|
|
69
|
-
var indexesSchema = z.object({
|
|
70
|
-
ore: oreIndexOptsSchema.optional(),
|
|
71
|
-
unique: uniqueIndexOptsSchema.optional(),
|
|
72
|
-
match: matchIndexOptsSchema.optional(),
|
|
73
|
-
ste_vec: steVecIndexOptsSchema.optional()
|
|
74
|
-
}).default({});
|
|
75
|
-
var columnSchema = z.object({
|
|
76
|
-
cast_as: castAsEnum,
|
|
77
|
-
indexes: indexesSchema
|
|
78
|
-
}).default({});
|
|
79
|
-
var tableSchema = z.record(columnSchema).default({});
|
|
80
|
-
var tablesSchema = z.record(tableSchema).default({});
|
|
81
|
-
var encryptConfigSchema = z.object({
|
|
82
|
-
v: z.number(),
|
|
83
|
-
tables: tablesSchema
|
|
84
|
-
});
|
|
85
|
-
var EncryptedField = class {
|
|
86
|
-
valueName;
|
|
87
|
-
castAsValue;
|
|
88
|
-
constructor(valueName) {
|
|
89
|
-
this.valueName = valueName;
|
|
90
|
-
this.castAsValue = "string";
|
|
91
|
-
}
|
|
92
|
-
/**
|
|
93
|
-
* Set or override the plaintext data type for this field.
|
|
94
|
-
*
|
|
95
|
-
* By default all values are treated as `'string'`. Use this method to specify
|
|
96
|
-
* a different type so the encryption layer knows how to encode the plaintext
|
|
97
|
-
* before encrypting.
|
|
98
|
-
*
|
|
99
|
-
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'text'`, `'bigint'`, or `'json'`.
|
|
100
|
-
* @returns This `EncryptedField` instance for method chaining.
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* ```typescript
|
|
104
|
-
* import { encryptedField } from "@cipherstash/stack/schema"
|
|
105
|
-
*
|
|
106
|
-
* const age = encryptedField("age").dataType("number")
|
|
107
|
-
* ```
|
|
108
|
-
*/
|
|
109
|
-
dataType(castAs) {
|
|
110
|
-
this.castAsValue = castAs;
|
|
111
|
-
return this;
|
|
112
|
-
}
|
|
113
|
-
build() {
|
|
114
|
-
return {
|
|
115
|
-
cast_as: this.castAsValue,
|
|
116
|
-
indexes: {}
|
|
117
|
-
};
|
|
118
|
-
}
|
|
119
|
-
getName() {
|
|
120
|
-
return this.valueName;
|
|
121
|
-
}
|
|
122
|
-
};
|
|
123
|
-
var EncryptedColumn = class {
|
|
124
|
-
columnName;
|
|
125
|
-
castAsValue;
|
|
126
|
-
indexesValue = {};
|
|
127
|
-
constructor(columnName) {
|
|
128
|
-
this.columnName = columnName;
|
|
129
|
-
this.castAsValue = "string";
|
|
130
|
-
}
|
|
131
|
-
/**
|
|
132
|
-
* Set or override the plaintext data type for this column.
|
|
133
|
-
*
|
|
134
|
-
* By default all columns are treated as `'string'`. Use this method to specify
|
|
135
|
-
* a different type so the encryption layer knows how to encode the plaintext
|
|
136
|
-
* before encrypting.
|
|
137
|
-
*
|
|
138
|
-
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
|
|
139
|
-
* @returns This `EncryptedColumn` instance for method chaining.
|
|
140
|
-
*
|
|
141
|
-
* @example
|
|
142
|
-
* ```typescript
|
|
143
|
-
* import { encryptedColumn } from "@cipherstash/stack/schema"
|
|
144
|
-
*
|
|
145
|
-
* const dateOfBirth = encryptedColumn("date_of_birth").dataType("date")
|
|
146
|
-
* ```
|
|
147
|
-
*/
|
|
148
|
-
dataType(castAs) {
|
|
149
|
-
this.castAsValue = castAs;
|
|
150
|
-
return this;
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Enable Order-Revealing Encryption (ORE) indexing on this column.
|
|
154
|
-
*
|
|
155
|
-
* ORE allows sorting, comparison, and range queries on encrypted data.
|
|
156
|
-
* Use with `encryptQuery` and `queryType: 'orderAndRange'`.
|
|
157
|
-
*
|
|
158
|
-
* @returns This `EncryptedColumn` instance for method chaining.
|
|
159
|
-
*
|
|
160
|
-
* @example
|
|
161
|
-
* ```typescript
|
|
162
|
-
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
163
|
-
*
|
|
164
|
-
* const users = encryptedTable("users", {
|
|
165
|
-
* email: encryptedColumn("email").orderAndRange(),
|
|
166
|
-
* })
|
|
167
|
-
* ```
|
|
168
|
-
*/
|
|
169
|
-
orderAndRange() {
|
|
170
|
-
this.indexesValue.ore = {};
|
|
171
|
-
return this;
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* Enable an exact-match (unique) index on this column.
|
|
175
|
-
*
|
|
176
|
-
* Allows equality queries on encrypted data. Use with `encryptQuery`
|
|
177
|
-
* and `queryType: 'equality'`.
|
|
178
|
-
*
|
|
179
|
-
* @param tokenFilters - Optional array of token filters (e.g. `[{ kind: 'downcase' }]`).
|
|
180
|
-
* When omitted, no token filters are applied.
|
|
181
|
-
* @returns This `EncryptedColumn` instance for method chaining.
|
|
182
|
-
*
|
|
183
|
-
* @example
|
|
184
|
-
* ```typescript
|
|
185
|
-
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
186
|
-
*
|
|
187
|
-
* const users = encryptedTable("users", {
|
|
188
|
-
* email: encryptedColumn("email").equality(),
|
|
189
|
-
* })
|
|
190
|
-
* ```
|
|
191
|
-
*/
|
|
192
|
-
equality(tokenFilters) {
|
|
193
|
-
this.indexesValue.unique = {
|
|
194
|
-
token_filters: tokenFilters ?? []
|
|
195
|
-
};
|
|
196
|
-
return this;
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* Enable a full-text / fuzzy search (match) index on this column.
|
|
200
|
-
*
|
|
201
|
-
* Uses n-gram tokenization by default for substring and fuzzy matching.
|
|
202
|
-
* Use with `encryptQuery` and `queryType: 'freeTextSearch'`.
|
|
203
|
-
*
|
|
204
|
-
* @param opts - Optional match index configuration. Defaults to 3-character ngram
|
|
205
|
-
* tokenization with a downcase filter, `k=6`, `m=2048`, and `include_original=true`.
|
|
206
|
-
* @returns This `EncryptedColumn` instance for method chaining.
|
|
207
|
-
*
|
|
208
|
-
* @example
|
|
209
|
-
* ```typescript
|
|
210
|
-
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
211
|
-
*
|
|
212
|
-
* const users = encryptedTable("users", {
|
|
213
|
-
* email: encryptedColumn("email").freeTextSearch(),
|
|
214
|
-
* })
|
|
215
|
-
*
|
|
216
|
-
* // With custom options
|
|
217
|
-
* const posts = encryptedTable("posts", {
|
|
218
|
-
* body: encryptedColumn("body").freeTextSearch({
|
|
219
|
-
* tokenizer: { kind: "ngram", token_length: 4 },
|
|
220
|
-
* k: 8,
|
|
221
|
-
* m: 4096,
|
|
222
|
-
* }),
|
|
223
|
-
* })
|
|
224
|
-
* ```
|
|
225
|
-
*/
|
|
226
|
-
freeTextSearch(opts) {
|
|
227
|
-
this.indexesValue.match = {
|
|
228
|
-
tokenizer: opts?.tokenizer ?? { kind: "ngram", token_length: 3 },
|
|
229
|
-
token_filters: opts?.token_filters ?? [
|
|
230
|
-
{
|
|
231
|
-
kind: "downcase"
|
|
232
|
-
}
|
|
233
|
-
],
|
|
234
|
-
k: opts?.k ?? 6,
|
|
235
|
-
m: opts?.m ?? 2048,
|
|
236
|
-
include_original: opts?.include_original ?? true
|
|
237
|
-
};
|
|
238
|
-
return this;
|
|
239
|
-
}
|
|
240
|
-
/**
|
|
241
|
-
* Configure this column for searchable encrypted JSON (STE-Vec).
|
|
242
|
-
*
|
|
243
|
-
* Enables encrypted JSONPath selector queries (e.g. `'$.user.email'`) and
|
|
244
|
-
* containment queries (e.g. `{ role: 'admin' }`). Automatically sets the
|
|
245
|
-
* data type to `'json'`.
|
|
246
|
-
*
|
|
247
|
-
* When used with `encryptQuery`, the query operation is auto-inferred from
|
|
248
|
-
* the plaintext type: strings become selector queries, objects/arrays become
|
|
249
|
-
* containment queries.
|
|
250
|
-
*
|
|
251
|
-
* @returns This `EncryptedColumn` instance for method chaining.
|
|
252
|
-
*
|
|
253
|
-
* @example
|
|
254
|
-
* ```typescript
|
|
255
|
-
* import { encryptedTable, encryptedColumn } from "@cipherstash/stack/schema"
|
|
256
|
-
*
|
|
257
|
-
* const documents = encryptedTable("documents", {
|
|
258
|
-
* metadata: encryptedColumn("metadata").searchableJson(),
|
|
259
|
-
* })
|
|
260
|
-
* ```
|
|
261
|
-
*/
|
|
262
|
-
searchableJson() {
|
|
263
|
-
this.castAsValue = "json";
|
|
264
|
-
this.indexesValue.ste_vec = { prefix: "enabled", array_index_mode: "all" };
|
|
265
|
-
return this;
|
|
266
|
-
}
|
|
267
|
-
build() {
|
|
268
|
-
return {
|
|
269
|
-
cast_as: this.castAsValue,
|
|
270
|
-
indexes: this.indexesValue
|
|
271
|
-
};
|
|
272
|
-
}
|
|
273
|
-
getName() {
|
|
274
|
-
return this.columnName;
|
|
275
|
-
}
|
|
276
|
-
};
|
|
277
|
-
var EncryptedTable = class {
|
|
278
|
-
constructor(tableName, columnBuilders) {
|
|
279
|
-
this.tableName = tableName;
|
|
280
|
-
this.columnBuilders = columnBuilders;
|
|
281
|
-
}
|
|
282
|
-
tableName;
|
|
283
|
-
columnBuilders;
|
|
284
|
-
/**
|
|
285
|
-
* Compile this table schema into a `TableDefinition` used internally by the encryption client.
|
|
286
|
-
*
|
|
287
|
-
* Iterates over all column builders, calls `.build()` on each, and assembles
|
|
288
|
-
* the final `{ tableName, columns }` structure. For `searchableJson()` columns,
|
|
289
|
-
* the STE-Vec prefix is automatically set to `"<tableName>/<columnName>"`.
|
|
290
|
-
*
|
|
291
|
-
* @returns A `TableDefinition` containing the table name and built column configs.
|
|
292
|
-
*
|
|
293
|
-
* @example
|
|
294
|
-
* ```typescript
|
|
295
|
-
* const users = encryptedTable("users", {
|
|
296
|
-
* email: encryptedColumn("email").equality(),
|
|
297
|
-
* })
|
|
298
|
-
*
|
|
299
|
-
* const definition = users.build()
|
|
300
|
-
* // { tableName: "users", columns: { email: { cast_as: "string", indexes: { unique: ... } } } }
|
|
301
|
-
* ```
|
|
302
|
-
*/
|
|
303
|
-
build() {
|
|
304
|
-
const builtColumns = {};
|
|
305
|
-
const processColumn = (builder, colName) => {
|
|
306
|
-
if (builder instanceof EncryptedColumn) {
|
|
307
|
-
const builtColumn = builder.build();
|
|
308
|
-
if (builtColumn.cast_as === "json" && builtColumn.indexes.ste_vec?.prefix === "enabled") {
|
|
309
|
-
builtColumns[colName] = {
|
|
310
|
-
...builtColumn,
|
|
311
|
-
indexes: {
|
|
312
|
-
...builtColumn.indexes,
|
|
313
|
-
ste_vec: {
|
|
314
|
-
...builtColumn.indexes.ste_vec,
|
|
315
|
-
prefix: `${this.tableName}/${colName}`
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
};
|
|
319
|
-
} else {
|
|
320
|
-
builtColumns[colName] = builtColumn;
|
|
321
|
-
}
|
|
322
|
-
} else {
|
|
323
|
-
for (const [key, value] of Object.entries(builder)) {
|
|
324
|
-
if (value instanceof EncryptedField) {
|
|
325
|
-
builtColumns[value.getName()] = value.build();
|
|
326
|
-
} else {
|
|
327
|
-
processColumn(value, key);
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
};
|
|
332
|
-
for (const [colName, builder] of Object.entries(this.columnBuilders)) {
|
|
333
|
-
processColumn(builder, colName);
|
|
334
|
-
}
|
|
335
|
-
return {
|
|
336
|
-
tableName: this.tableName,
|
|
337
|
-
columns: builtColumns
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
};
|
|
341
|
-
function encryptedTable(tableName, columns) {
|
|
342
|
-
const tableBuilder = new EncryptedTable(
|
|
343
|
-
tableName,
|
|
344
|
-
columns
|
|
345
|
-
);
|
|
346
|
-
for (const [colName, colBuilder] of Object.entries(columns)) {
|
|
347
|
-
;
|
|
348
|
-
tableBuilder[colName] = colBuilder;
|
|
349
|
-
}
|
|
350
|
-
return tableBuilder;
|
|
351
|
-
}
|
|
352
|
-
function encryptedColumn(columnName) {
|
|
353
|
-
return new EncryptedColumn(columnName);
|
|
354
|
-
}
|
|
355
|
-
function encryptedField(valueName) {
|
|
356
|
-
return new EncryptedField(valueName);
|
|
357
|
-
}
|
|
358
|
-
function buildEncryptConfig(...protectTables) {
|
|
359
|
-
const config = {
|
|
360
|
-
v: 1,
|
|
361
|
-
tables: {}
|
|
362
|
-
};
|
|
363
|
-
for (const tb of protectTables) {
|
|
364
|
-
const tableDef = tb.build();
|
|
365
|
-
config.tables[tableDef.tableName] = tableDef.columns;
|
|
366
|
-
}
|
|
367
|
-
return config;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
export {
|
|
371
|
-
eqlCastAsEnum,
|
|
372
|
-
castAsEnum,
|
|
373
|
-
toEqlCastAs,
|
|
374
|
-
encryptConfigSchema,
|
|
375
|
-
EncryptedField,
|
|
376
|
-
EncryptedColumn,
|
|
377
|
-
EncryptedTable,
|
|
378
|
-
encryptedTable,
|
|
379
|
-
encryptedColumn,
|
|
380
|
-
encryptedField,
|
|
381
|
-
buildEncryptConfig
|
|
382
|
-
};
|
|
383
|
-
//# sourceMappingURL=chunk-YWQXTZ5M.js.map
|