@cipherstash/stack 0.3.0 → 0.4.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 +6 -0
- package/README.md +1 -1
- package/dist/bin/stash.js +46 -141
- package/dist/bin/stash.js.map +1 -1
- package/dist/{chunk-SUYMGQBY.js → chunk-4RNBI3UH.js} +1 -7
- package/dist/chunk-4RNBI3UH.js.map +1 -0
- package/dist/{chunk-JLI27P46.js → chunk-KOU2MHXJ.js} +1 -1
- package/dist/chunk-KOU2MHXJ.js.map +1 -0
- package/dist/{chunk-MW6D52V2.js → chunk-WUZGKTMG.js} +45 -134
- package/dist/chunk-WUZGKTMG.js.map +1 -0
- package/dist/{chunk-TBAIVO6T.js → chunk-Y35W4WFN.js} +6 -6
- package/dist/chunk-Y35W4WFN.js.map +1 -0
- package/dist/{client-Bf0Xw2xo.d.cts → client-CUGXheRq.d.cts} +15 -16
- package/dist/{client-Kfp8OsPB.d.ts → client-CrGQnSlk.d.ts} +15 -16
- package/dist/client.cjs +5 -5
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +2 -2
- package/dist/client.d.ts +2 -2
- package/dist/client.js +1 -1
- package/dist/drizzle/index.cjs +5 -5
- package/dist/drizzle/index.cjs.map +1 -1
- package/dist/drizzle/index.d.cts +2 -2
- package/dist/drizzle/index.d.ts +2 -2
- package/dist/drizzle/index.js +2 -2
- package/dist/dynamodb/index.d.cts +2 -2
- package/dist/dynamodb/index.d.ts +2 -2
- package/dist/index.cjs +46 -141
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +4 -4
- package/dist/schema/index.cjs +5 -5
- 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 +1 -1
- package/dist/secrets/index.cjs +46 -141
- package/dist/secrets/index.cjs.map +1 -1
- package/dist/secrets/index.d.cts +1 -1
- package/dist/secrets/index.d.ts +1 -1
- package/dist/secrets/index.js +4 -4
- package/dist/supabase/index.cjs +2 -2
- package/dist/supabase/index.cjs.map +1 -1
- package/dist/supabase/index.d.cts +2 -2
- package/dist/supabase/index.d.ts +2 -2
- package/dist/supabase/index.js +2 -2
- package/dist/{types-public-0CzBV45X.d.cts → types-public-Wj6tB_ux.d.cts} +47 -26
- package/dist/{types-public-0CzBV45X.d.ts → types-public-Wj6tB_ux.d.ts} +47 -26
- 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/package.json +2 -2
- package/dist/chunk-JLI27P46.js.map +0 -1
- package/dist/chunk-MW6D52V2.js.map +0 -1
- package/dist/chunk-SUYMGQBY.js.map +0 -1
- package/dist/chunk-TBAIVO6T.js.map +0 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { E as EncryptionClient } from './client-
|
|
2
|
-
import { E as EncryptionClientConfig } from './types-public-
|
|
3
|
-
export { d as EncryptedColumn, h as EncryptedField, i as EncryptedFromSchema, f as EncryptedTable, g as EncryptedTableColumn, c as InferEncrypted, I as InferPlaintext, a as encryptedColumn, b as encryptedField, e as encryptedTable } from './types-public-
|
|
1
|
+
import { E as EncryptionClient } from './client-CUGXheRq.cjs';
|
|
2
|
+
import { E as EncryptionClientConfig } from './types-public-Wj6tB_ux.cjs';
|
|
3
|
+
export { d as EncryptedColumn, h as EncryptedField, i as EncryptedFromSchema, f as EncryptedTable, g as EncryptedTableColumn, c as InferEncrypted, I as InferPlaintext, a as encryptedColumn, b as encryptedField, e as encryptedTable } from './types-public-Wj6tB_ux.cjs';
|
|
4
4
|
export { C as ClientInitError, c as CtsTokenError, D as DecryptionOperationError, a as EncryptionError, E as EncryptionErrorTypes, b as EncryptionOperationError, L as LockContextError, S as StackError, g as getErrorMessage } from './index-9-Ya3fDK.cjs';
|
|
5
5
|
import '@byteslice/result';
|
|
6
6
|
import '@cipherstash/protect-ffi';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { E as EncryptionClient } from './client-
|
|
2
|
-
import { E as EncryptionClientConfig } from './types-public-
|
|
3
|
-
export { d as EncryptedColumn, h as EncryptedField, i as EncryptedFromSchema, f as EncryptedTable, g as EncryptedTableColumn, c as InferEncrypted, I as InferPlaintext, a as encryptedColumn, b as encryptedField, e as encryptedTable } from './types-public-
|
|
1
|
+
import { E as EncryptionClient } from './client-CrGQnSlk.js';
|
|
2
|
+
import { E as EncryptionClientConfig } from './types-public-Wj6tB_ux.js';
|
|
3
|
+
export { d as EncryptedColumn, h as EncryptedField, i as EncryptedFromSchema, f as EncryptedTable, g as EncryptedTableColumn, c as InferEncrypted, I as InferPlaintext, a as encryptedColumn, b as encryptedField, e as encryptedTable } from './types-public-Wj6tB_ux.js';
|
|
4
4
|
export { C as ClientInitError, c as CtsTokenError, D as DecryptionOperationError, a as EncryptionError, E as EncryptionErrorTypes, b as EncryptionOperationError, L as LockContextError, S as StackError, g as getErrorMessage } from './index-9-Ya3fDK.js';
|
|
5
5
|
import '@byteslice/result';
|
|
6
6
|
import '@cipherstash/protect-ffi';
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Encryption
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-WUZGKTMG.js";
|
|
4
|
+
import "./chunk-4RNBI3UH.js";
|
|
5
|
+
import "./chunk-KOU2MHXJ.js";
|
|
6
6
|
import {
|
|
7
7
|
EncryptionErrorTypes,
|
|
8
8
|
getErrorMessage
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
encryptedColumn,
|
|
12
12
|
encryptedField,
|
|
13
13
|
encryptedTable
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-Y35W4WFN.js";
|
|
15
15
|
export {
|
|
16
16
|
Encryption,
|
|
17
17
|
EncryptionErrorTypes,
|
package/dist/schema/index.cjs
CHANGED
|
@@ -32,7 +32,7 @@ __export(schema_exports, {
|
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(schema_exports);
|
|
34
34
|
var import_zod = require("zod");
|
|
35
|
-
var castAsEnum = import_zod.z.enum(["bigint", "boolean", "date", "number", "string", "json"]).default("
|
|
35
|
+
var castAsEnum = import_zod.z.enum(["bigint", "boolean", "date", "number", "string", "json", "text"]).default("text");
|
|
36
36
|
var tokenFilterSchema = import_zod.z.object({
|
|
37
37
|
kind: import_zod.z.literal("downcase")
|
|
38
38
|
});
|
|
@@ -80,7 +80,7 @@ var EncryptedField = class {
|
|
|
80
80
|
castAsValue;
|
|
81
81
|
constructor(valueName) {
|
|
82
82
|
this.valueName = valueName;
|
|
83
|
-
this.castAsValue = "
|
|
83
|
+
this.castAsValue = "text";
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
86
|
* Set or override the plaintext data type for this field.
|
|
@@ -89,7 +89,7 @@ var EncryptedField = class {
|
|
|
89
89
|
* a different type so the encryption layer knows how to encode the plaintext
|
|
90
90
|
* before encrypting.
|
|
91
91
|
*
|
|
92
|
-
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
|
|
92
|
+
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'text'`, `'bigint'`, or `'json'`.
|
|
93
93
|
* @returns This `EncryptedField` instance for method chaining.
|
|
94
94
|
*
|
|
95
95
|
* @example
|
|
@@ -105,7 +105,7 @@ var EncryptedField = class {
|
|
|
105
105
|
}
|
|
106
106
|
build() {
|
|
107
107
|
return {
|
|
108
|
-
cast_as: this.castAsValue,
|
|
108
|
+
cast_as: this.castAsValue === "string" ? "text" : this.castAsValue,
|
|
109
109
|
indexes: {}
|
|
110
110
|
};
|
|
111
111
|
}
|
|
@@ -259,7 +259,7 @@ var EncryptedColumn = class {
|
|
|
259
259
|
}
|
|
260
260
|
build() {
|
|
261
261
|
return {
|
|
262
|
-
cast_as: this.castAsValue,
|
|
262
|
+
cast_as: this.castAsValue === "string" ? "text" : this.castAsValue,
|
|
263
263
|
indexes: this.indexesValue
|
|
264
264
|
};
|
|
265
265
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/schema/index.ts"],"sourcesContent":["import type { Encrypted } from '@/types'\nimport { z } from 'zod'\n\n// ------------------------\n// Zod schemas\n// ------------------------\n\n/**\n * Allowed cast types for CipherStash schema fields.\n *\n * **Possible values:**\n * - `\"bigint\"`\n * - `\"boolean\"`\n * - `\"date\"`\n * - `\"number\"`\n * - `\"string\"`\n * - `\"json\"`\n *\n * @remarks\n * This is a Zod enum used at runtime to validate schema definitions.\n * Use {@link CastAs} when typing your own code.\n *\n * @internal\n */\nexport const castAsEnum = z\n .enum(['bigint', 'boolean', 'date', 'number', 'string', 'json'])\n .default('string')\n\nconst tokenFilterSchema = z.object({\n kind: z.literal('downcase'),\n})\n\nconst tokenizerSchema = z\n .union([\n z.object({\n kind: z.literal('standard'),\n }),\n z.object({\n kind: z.literal('ngram'),\n token_length: z.number(),\n }),\n ])\n .default({ kind: 'ngram', token_length: 3 })\n .optional()\n\nconst oreIndexOptsSchema = z.object({})\n\nconst uniqueIndexOptsSchema = z.object({\n token_filters: z.array(tokenFilterSchema).default([]).optional(),\n})\n\nconst matchIndexOptsSchema = z.object({\n tokenizer: tokenizerSchema,\n token_filters: z.array(tokenFilterSchema).default([]).optional(),\n k: z.number().default(6).optional(),\n m: z.number().default(2048).optional(),\n include_original: z.boolean().default(false).optional(),\n})\n\nconst steVecIndexOptsSchema = z.object({\n prefix: z.string(),\n})\n\nconst indexesSchema = z\n .object({\n ore: oreIndexOptsSchema.optional(),\n unique: uniqueIndexOptsSchema.optional(),\n match: matchIndexOptsSchema.optional(),\n ste_vec: steVecIndexOptsSchema.optional(),\n })\n .default({})\n\nconst columnSchema = z\n .object({\n cast_as: castAsEnum,\n indexes: indexesSchema,\n })\n .default({})\n\nconst tableSchema = z.record(columnSchema).default({})\n\nconst tablesSchema = z.record(tableSchema).default({})\n\n/** @internal */\nexport const encryptConfigSchema = z.object({\n v: z.number(),\n tables: tablesSchema,\n})\n\n// ------------------------\n// Type definitions\n// ------------------------\n\n/**\n * Type-safe alias for {@link castAsEnum} used to specify the *unencrypted* data type of a column or value.\n * This is important because once encrypted, all data is stored as binary blobs.\n *\n * @see {@link castAsEnum} for possible values.\n */\nexport type CastAs = z.infer<typeof castAsEnum>\nexport type TokenFilter = z.infer<typeof tokenFilterSchema>\nexport type MatchIndexOpts = z.infer<typeof matchIndexOptsSchema>\nexport type SteVecIndexOpts = z.infer<typeof steVecIndexOptsSchema>\nexport type UniqueIndexOpts = z.infer<typeof uniqueIndexOptsSchema>\nexport type OreIndexOpts = z.infer<typeof oreIndexOptsSchema>\nexport type ColumnSchema = z.infer<typeof columnSchema>\n\n/**\n * Shape of table columns: either top-level {@link EncryptedColumn} or nested\n * objects whose leaves are {@link EncryptedField}. Used with {@link encryptedTable}.\n */\nexport type EncryptedTableColumn = {\n [key: string]:\n | EncryptedColumn\n | {\n [key: string]:\n | EncryptedField\n | {\n [key: string]:\n | EncryptedField\n | {\n [key: string]: EncryptedField\n }\n }\n }\n}\nexport type EncryptConfig = z.infer<typeof encryptConfigSchema>\n\n// ------------------------\n// Interface definitions\n// ------------------------\n\n/**\n * Builder for a nested encrypted field (encrypted but not searchable).\n * Create with {@link encryptedField}. Use inside nested objects in {@link encryptedTable};\n * supports `.dataType()` for plaintext type. No index methods (equality, orderAndRange, etc.).\n */\nexport class EncryptedField {\n private valueName: string\n private castAsValue: CastAs\n\n constructor(valueName: string) {\n this.valueName = valueName\n this.castAsValue = 'string'\n }\n\n /**\n * Set or override the plaintext data type for this field.\n *\n * By default all values are treated as `'string'`. Use this method to specify\n * a different type so the encryption layer knows how to encode the plaintext\n * before encrypting.\n *\n * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.\n * @returns This `EncryptedField` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedField } from \"@cipherstash/stack/schema\"\n *\n * const age = encryptedField(\"age\").dataType(\"number\")\n * ```\n */\n dataType(castAs: CastAs) {\n this.castAsValue = castAs\n return this\n }\n\n build() {\n return {\n cast_as: this.castAsValue,\n indexes: {},\n }\n }\n\n getName() {\n return this.valueName\n }\n}\n\nexport class EncryptedColumn {\n private columnName: string\n private castAsValue: CastAs\n private indexesValue: {\n ore?: OreIndexOpts\n unique?: UniqueIndexOpts\n match?: Required<MatchIndexOpts>\n ste_vec?: SteVecIndexOpts\n } = {}\n\n constructor(columnName: string) {\n this.columnName = columnName\n this.castAsValue = 'string'\n }\n\n /**\n * Set or override the plaintext data type for this column.\n *\n * By default all columns are treated as `'string'`. Use this method to specify\n * a different type so the encryption layer knows how to encode the plaintext\n * before encrypting.\n *\n * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const dateOfBirth = encryptedColumn(\"date_of_birth\").dataType(\"date\")\n * ```\n */\n dataType(castAs: CastAs) {\n this.castAsValue = castAs\n return this\n }\n\n /**\n * Enable Order-Revealing Encryption (ORE) indexing on this column.\n *\n * ORE allows sorting, comparison, and range queries on encrypted data.\n * Use with `encryptQuery` and `queryType: 'orderAndRange'`.\n *\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").orderAndRange(),\n * })\n * ```\n */\n orderAndRange() {\n this.indexesValue.ore = {}\n return this\n }\n\n /**\n * Enable an exact-match (unique) index on this column.\n *\n * Allows equality queries on encrypted data. Use with `encryptQuery`\n * and `queryType: 'equality'`.\n *\n * @param tokenFilters - Optional array of token filters (e.g. `[{ kind: 'downcase' }]`).\n * When omitted, no token filters are applied.\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n * ```\n */\n equality(tokenFilters?: TokenFilter[]) {\n this.indexesValue.unique = {\n token_filters: tokenFilters ?? [],\n }\n return this\n }\n\n /**\n * Enable a full-text / fuzzy search (match) index on this column.\n *\n * Uses n-gram tokenization by default for substring and fuzzy matching.\n * Use with `encryptQuery` and `queryType: 'freeTextSearch'`.\n *\n * @param opts - Optional match index configuration. Defaults to 3-character ngram\n * tokenization with a downcase filter, `k=6`, `m=2048`, and `include_original=true`.\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").freeTextSearch(),\n * })\n *\n * // With custom options\n * const posts = encryptedTable(\"posts\", {\n * body: encryptedColumn(\"body\").freeTextSearch({\n * tokenizer: { kind: \"ngram\", token_length: 4 },\n * k: 8,\n * m: 4096,\n * }),\n * })\n * ```\n */\n freeTextSearch(opts?: MatchIndexOpts) {\n // Provide defaults\n this.indexesValue.match = {\n tokenizer: opts?.tokenizer ?? { kind: 'ngram', token_length: 3 },\n token_filters: opts?.token_filters ?? [\n {\n kind: 'downcase',\n },\n ],\n k: opts?.k ?? 6,\n m: opts?.m ?? 2048,\n include_original: opts?.include_original ?? true,\n }\n return this\n }\n\n /**\n * Configure this column for searchable encrypted JSON (STE-Vec).\n *\n * Enables encrypted JSONPath selector queries (e.g. `'$.user.email'`) and\n * containment queries (e.g. `{ role: 'admin' }`). Automatically sets the\n * data type to `'json'`.\n *\n * When used with `encryptQuery`, the query operation is auto-inferred from\n * the plaintext type: strings become selector queries, objects/arrays become\n * containment queries.\n *\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const documents = encryptedTable(\"documents\", {\n * metadata: encryptedColumn(\"metadata\").searchableJson(),\n * })\n * ```\n */\n searchableJson() {\n this.castAsValue = 'json'\n this.indexesValue.ste_vec = { prefix: 'enabled' }\n return this\n }\n\n build() {\n return {\n cast_as: this.castAsValue,\n indexes: this.indexesValue,\n }\n }\n\n getName() {\n return this.columnName\n }\n}\n\ninterface TableDefinition {\n tableName: string\n columns: Record<string, ColumnSchema>\n}\n\nexport class EncryptedTable<T extends EncryptedTableColumn> {\n /** @internal Type-level brand so TypeScript can infer `T` from `EncryptedTable<T>`. */\n declare readonly _columnType: T\n\n constructor(\n public readonly tableName: string,\n private readonly columnBuilders: T,\n ) {}\n\n /**\n * Compile this table schema into a `TableDefinition` used internally by the encryption client.\n *\n * Iterates over all column builders, calls `.build()` on each, and assembles\n * the final `{ tableName, columns }` structure. For `searchableJson()` columns,\n * the STE-Vec prefix is automatically set to `\"<tableName>/<columnName>\"`.\n *\n * @returns A `TableDefinition` containing the table name and built column configs.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * const definition = users.build()\n * // { tableName: \"users\", columns: { email: { cast_as: \"string\", indexes: { unique: ... } } } }\n * ```\n */\n build(): TableDefinition {\n const builtColumns: Record<string, ColumnSchema> = {}\n\n const processColumn = (\n builder:\n | EncryptedColumn\n | Record<\n string,\n | EncryptedField\n | Record<\n string,\n | EncryptedField\n | Record<\n string,\n EncryptedField | Record<string, EncryptedField>\n >\n >\n >,\n colName: string,\n ) => {\n if (builder instanceof EncryptedColumn) {\n const builtColumn = builder.build()\n\n // Hanlde building the ste_vec index for JSON columns so users don't have to pass the prefix.\n if (\n builtColumn.cast_as === 'json' &&\n builtColumn.indexes.ste_vec?.prefix === 'enabled'\n ) {\n builtColumns[colName] = {\n ...builtColumn,\n indexes: {\n ...builtColumn.indexes,\n ste_vec: {\n prefix: `${this.tableName}/${colName}`,\n },\n },\n }\n } else {\n builtColumns[colName] = builtColumn\n }\n } else {\n for (const [key, value] of Object.entries(builder)) {\n if (value instanceof EncryptedField) {\n builtColumns[value.getName()] = value.build()\n } else {\n processColumn(value, key)\n }\n }\n }\n }\n\n for (const [colName, builder] of Object.entries(this.columnBuilders)) {\n processColumn(builder, colName)\n }\n\n return {\n tableName: this.tableName,\n columns: builtColumns,\n }\n }\n}\n\n// ------------------------\n// Schema type inference helpers\n// ------------------------\n\n/**\n * Infer the plaintext (decrypted) type from a EncryptedTable schema.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * name: encryptedColumn(\"name\"),\n * })\n *\n * type UserPlaintext = InferPlaintext<typeof users>\n * // => { email: string; name: string }\n * ```\n */\nexport type InferPlaintext<T extends EncryptedTable<any>> =\n T extends EncryptedTable<infer C>\n ? {\n [K in keyof C as C[K] extends EncryptedColumn | EncryptedField\n ? K\n : never]: string\n }\n : never\n\n/**\n * Infer the encrypted type from a EncryptedTable schema.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * type UserEncrypted = InferEncrypted<typeof users>\n * // => { email: Encrypted }\n * ```\n */\nexport type InferEncrypted<T extends EncryptedTable<any>> =\n T extends EncryptedTable<infer C>\n ? {\n [K in keyof C as C[K] extends EncryptedColumn | EncryptedField\n ? K\n : never]: Encrypted\n }\n : never\n\n// ------------------------\n// User facing functions\n// ------------------------\n\n/**\n * Define an encrypted table schema.\n *\n * Creates a `EncryptedTable` that maps a database table name to a set of encrypted\n * column definitions. Pass the resulting object to `Encryption({ schemas: [...] })`\n * when initializing the client.\n *\n * The returned object is also a proxy that exposes each column builder directly,\n * so you can reference columns as `users.email` when calling `encrypt`, `decrypt`,\n * and `encryptQuery`.\n *\n * @param tableName - The name of the database table this schema represents.\n * @param columns - An object whose keys are logical column names and values are\n * {@link EncryptedColumn} from {@link encryptedColumn}, or nested objects whose\n * leaves are {@link EncryptedField} from {@link encryptedField}.\n * @returns A `EncryptedTable<T> & T` that can be used as both a schema definition\n * and a column accessor.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality().freeTextSearch(),\n * address: encryptedColumn(\"address\"),\n * })\n *\n * // Use as schema\n * const client = await Encryption({ schemas: [users] })\n *\n * // Use as column accessor\n * await client.encrypt(\"hello@example.com\", { column: users.email, table: users })\n * ```\n */\nexport function encryptedTable<T extends EncryptedTableColumn>(\n tableName: string,\n columns: T,\n): EncryptedTable<T> & T {\n const tableBuilder = new EncryptedTable(\n tableName,\n columns,\n ) as EncryptedTable<T> & T\n\n for (const [colName, colBuilder] of Object.entries(columns)) {\n ;(tableBuilder as EncryptedTableColumn)[colName] = colBuilder\n }\n\n return tableBuilder\n}\n\n/**\n * Define an encrypted column within a table schema.\n *\n * Creates a `EncryptedColumn` builder for the given column name. Chain index\n * methods (`.equality()`, `.freeTextSearch()`, `.orderAndRange()`,\n * `.searchableJson()`) and/or `.dataType()` to configure searchable encryption\n * and the plaintext data type.\n *\n * @param columnName - The name of the database column to encrypt.\n * @returns A new `EncryptedColumn` builder.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality().freeTextSearch().orderAndRange(),\n * })\n * ```\n */\nexport function encryptedColumn(columnName: string) {\n return new EncryptedColumn(columnName)\n}\n\n/**\n * Define an encrypted field for use in nested or structured schemas.\n *\n * `encryptedField` is similar to {@link encryptedColumn} but creates an {@link EncryptedField}\n * for nested fields that are encrypted but not searchable (no indexes). Use `.dataType()`\n * to specify the plaintext type.\n *\n * @param valueName - The name of the value field.\n * @returns A new `EncryptedField` builder.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedField } from \"@cipherstash/stack/schema\"\n *\n * const orders = encryptedTable(\"orders\", {\n * details: {\n * amount: encryptedField(\"amount\").dataType(\"number\"),\n * currency: encryptedField(\"currency\"),\n * },\n * })\n * ```\n */\nexport function encryptedField(valueName: string) {\n return new EncryptedField(valueName)\n}\n\n// ------------------------\n// Internal functions\n// ------------------------\n\n/** @internal */\nexport function buildEncryptConfig(\n ...protectTables: Array<EncryptedTable<EncryptedTableColumn>>\n): EncryptConfig {\n const config: EncryptConfig = {\n v: 2,\n tables: {},\n }\n\n for (const tb of protectTables) {\n const tableDef = tb.build()\n config.tables[tableDef.tableName] = tableDef.columns\n }\n\n return config\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/schema/index.ts"],"sourcesContent":["import type { Encrypted } from '@/types'\nimport { z } from 'zod'\n\n// ------------------------\n// Zod schemas\n// ------------------------\n\n/**\n * Allowed cast types for CipherStash schema fields.\n *\n * **Possible values:**\n * - `\"bigint\"`\n * - `\"boolean\"`\n * - `\"date\"`\n * - `\"number\"`\n * - `\"string\"`\n * - `\"json\"`\n * - `\"text\"`\n *\n * @remarks\n * This is a Zod enum used at runtime to validate schema definitions.\n * Use {@link CastAs} when typing your own code.\n *\n * @internal\n */\nexport const castAsEnum = z\n .enum(['bigint', 'boolean', 'date', 'number', 'string', 'json', 'text'])\n .default('text')\n\nconst tokenFilterSchema = z.object({\n kind: z.literal('downcase'),\n})\n\nconst tokenizerSchema = z\n .union([\n z.object({\n kind: z.literal('standard'),\n }),\n z.object({\n kind: z.literal('ngram'),\n token_length: z.number(),\n }),\n ])\n .default({ kind: 'ngram', token_length: 3 })\n .optional()\n\nconst oreIndexOptsSchema = z.object({})\n\nconst uniqueIndexOptsSchema = z.object({\n token_filters: z.array(tokenFilterSchema).default([]).optional(),\n})\n\nconst matchIndexOptsSchema = z.object({\n tokenizer: tokenizerSchema,\n token_filters: z.array(tokenFilterSchema).default([]).optional(),\n k: z.number().default(6).optional(),\n m: z.number().default(2048).optional(),\n include_original: z.boolean().default(false).optional(),\n})\n\nconst steVecIndexOptsSchema = z.object({\n prefix: z.string(),\n})\n\nconst indexesSchema = z\n .object({\n ore: oreIndexOptsSchema.optional(),\n unique: uniqueIndexOptsSchema.optional(),\n match: matchIndexOptsSchema.optional(),\n ste_vec: steVecIndexOptsSchema.optional(),\n })\n .default({})\n\nconst columnSchema = z\n .object({\n cast_as: castAsEnum,\n indexes: indexesSchema,\n })\n .default({})\n\nconst tableSchema = z.record(columnSchema).default({})\n\nconst tablesSchema = z.record(tableSchema).default({})\n\n/** @internal */\nexport const encryptConfigSchema = z.object({\n v: z.number(),\n tables: tablesSchema,\n})\n\n// ------------------------\n// Type definitions\n// ------------------------\n\n/**\n * Type-safe alias for {@link castAsEnum} used to specify the *unencrypted* data type of a column or value.\n * This is important because once encrypted, all data is stored as binary blobs.\n *\n * @see {@link castAsEnum} for possible values.\n */\nexport type CastAs = z.infer<typeof castAsEnum>\nexport type TokenFilter = z.infer<typeof tokenFilterSchema>\nexport type MatchIndexOpts = z.infer<typeof matchIndexOptsSchema>\nexport type SteVecIndexOpts = z.infer<typeof steVecIndexOptsSchema>\nexport type UniqueIndexOpts = z.infer<typeof uniqueIndexOptsSchema>\nexport type OreIndexOpts = z.infer<typeof oreIndexOptsSchema>\nexport type ColumnSchema = z.infer<typeof columnSchema>\n\n/**\n * Shape of table columns: either top-level {@link EncryptedColumn} or nested\n * objects whose leaves are {@link EncryptedField}. Used with {@link encryptedTable}.\n */\nexport type EncryptedTableColumn = {\n [key: string]:\n | EncryptedColumn\n | {\n [key: string]:\n | EncryptedField\n | {\n [key: string]:\n | EncryptedField\n | {\n [key: string]: EncryptedField\n }\n }\n }\n}\nexport type EncryptConfig = z.infer<typeof encryptConfigSchema>\n\n// ------------------------\n// Interface definitions\n// ------------------------\n\n/**\n * Builder for a nested encrypted field (encrypted but not searchable).\n * Create with {@link encryptedField}. Use inside nested objects in {@link encryptedTable};\n * supports `.dataType()` for plaintext type. No index methods (equality, orderAndRange, etc.).\n */\nexport class EncryptedField {\n private valueName: string\n private castAsValue: CastAs\n\n constructor(valueName: string) {\n this.valueName = valueName\n this.castAsValue = 'text'\n }\n\n /**\n * Set or override the plaintext data type for this field.\n *\n * By default all values are treated as `'string'`. Use this method to specify\n * a different type so the encryption layer knows how to encode the plaintext\n * before encrypting.\n *\n * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'text'`, `'bigint'`, or `'json'`.\n * @returns This `EncryptedField` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedField } from \"@cipherstash/stack/schema\"\n *\n * const age = encryptedField(\"age\").dataType(\"number\")\n * ```\n */\n dataType(castAs: CastAs) {\n this.castAsValue = castAs\n return this\n }\n\n build() {\n return {\n cast_as: this.castAsValue === 'string' ? 'text' : this.castAsValue,\n indexes: {},\n }\n }\n\n getName() {\n return this.valueName\n }\n}\n\nexport class EncryptedColumn {\n private columnName: string\n private castAsValue: CastAs\n private indexesValue: {\n ore?: OreIndexOpts\n unique?: UniqueIndexOpts\n match?: Required<MatchIndexOpts>\n ste_vec?: SteVecIndexOpts\n } = {}\n\n constructor(columnName: string) {\n this.columnName = columnName\n this.castAsValue = 'string'\n }\n\n /**\n * Set or override the plaintext data type for this column.\n *\n * By default all columns are treated as `'string'`. Use this method to specify\n * a different type so the encryption layer knows how to encode the plaintext\n * before encrypting.\n *\n * @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const dateOfBirth = encryptedColumn(\"date_of_birth\").dataType(\"date\")\n * ```\n */\n dataType(castAs: CastAs) {\n this.castAsValue = castAs\n return this\n }\n\n /**\n * Enable Order-Revealing Encryption (ORE) indexing on this column.\n *\n * ORE allows sorting, comparison, and range queries on encrypted data.\n * Use with `encryptQuery` and `queryType: 'orderAndRange'`.\n *\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").orderAndRange(),\n * })\n * ```\n */\n orderAndRange() {\n this.indexesValue.ore = {}\n return this\n }\n\n /**\n * Enable an exact-match (unique) index on this column.\n *\n * Allows equality queries on encrypted data. Use with `encryptQuery`\n * and `queryType: 'equality'`.\n *\n * @param tokenFilters - Optional array of token filters (e.g. `[{ kind: 'downcase' }]`).\n * When omitted, no token filters are applied.\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n * ```\n */\n equality(tokenFilters?: TokenFilter[]) {\n this.indexesValue.unique = {\n token_filters: tokenFilters ?? [],\n }\n return this\n }\n\n /**\n * Enable a full-text / fuzzy search (match) index on this column.\n *\n * Uses n-gram tokenization by default for substring and fuzzy matching.\n * Use with `encryptQuery` and `queryType: 'freeTextSearch'`.\n *\n * @param opts - Optional match index configuration. Defaults to 3-character ngram\n * tokenization with a downcase filter, `k=6`, `m=2048`, and `include_original=true`.\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").freeTextSearch(),\n * })\n *\n * // With custom options\n * const posts = encryptedTable(\"posts\", {\n * body: encryptedColumn(\"body\").freeTextSearch({\n * tokenizer: { kind: \"ngram\", token_length: 4 },\n * k: 8,\n * m: 4096,\n * }),\n * })\n * ```\n */\n freeTextSearch(opts?: MatchIndexOpts) {\n // Provide defaults\n this.indexesValue.match = {\n tokenizer: opts?.tokenizer ?? { kind: 'ngram', token_length: 3 },\n token_filters: opts?.token_filters ?? [\n {\n kind: 'downcase',\n },\n ],\n k: opts?.k ?? 6,\n m: opts?.m ?? 2048,\n include_original: opts?.include_original ?? true,\n }\n return this\n }\n\n /**\n * Configure this column for searchable encrypted JSON (STE-Vec).\n *\n * Enables encrypted JSONPath selector queries (e.g. `'$.user.email'`) and\n * containment queries (e.g. `{ role: 'admin' }`). Automatically sets the\n * data type to `'json'`.\n *\n * When used with `encryptQuery`, the query operation is auto-inferred from\n * the plaintext type: strings become selector queries, objects/arrays become\n * containment queries.\n *\n * @returns This `EncryptedColumn` instance for method chaining.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const documents = encryptedTable(\"documents\", {\n * metadata: encryptedColumn(\"metadata\").searchableJson(),\n * })\n * ```\n */\n searchableJson() {\n this.castAsValue = 'json'\n this.indexesValue.ste_vec = { prefix: 'enabled' }\n return this\n }\n\n build() {\n return {\n cast_as: this.castAsValue === 'string' ? 'text' : this.castAsValue,\n indexes: this.indexesValue,\n }\n }\n\n getName() {\n return this.columnName\n }\n}\n\ninterface TableDefinition {\n tableName: string\n columns: Record<string, ColumnSchema>\n}\n\nexport class EncryptedTable<T extends EncryptedTableColumn> {\n /** @internal Type-level brand so TypeScript can infer `T` from `EncryptedTable<T>`. */\n declare readonly _columnType: T\n\n constructor(\n public readonly tableName: string,\n private readonly columnBuilders: T,\n ) {}\n\n /**\n * Compile this table schema into a `TableDefinition` used internally by the encryption client.\n *\n * Iterates over all column builders, calls `.build()` on each, and assembles\n * the final `{ tableName, columns }` structure. For `searchableJson()` columns,\n * the STE-Vec prefix is automatically set to `\"<tableName>/<columnName>\"`.\n *\n * @returns A `TableDefinition` containing the table name and built column configs.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * const definition = users.build()\n * // { tableName: \"users\", columns: { email: { cast_as: \"string\", indexes: { unique: ... } } } }\n * ```\n */\n build(): TableDefinition {\n const builtColumns: Record<string, ColumnSchema> = {}\n\n const processColumn = (\n builder:\n | EncryptedColumn\n | Record<\n string,\n | EncryptedField\n | Record<\n string,\n | EncryptedField\n | Record<\n string,\n EncryptedField | Record<string, EncryptedField>\n >\n >\n >,\n colName: string,\n ) => {\n if (builder instanceof EncryptedColumn) {\n const builtColumn = builder.build()\n\n // Hanlde building the ste_vec index for JSON columns so users don't have to pass the prefix.\n if (\n builtColumn.cast_as === 'json' &&\n builtColumn.indexes.ste_vec?.prefix === 'enabled'\n ) {\n builtColumns[colName] = {\n ...builtColumn,\n indexes: {\n ...builtColumn.indexes,\n ste_vec: {\n prefix: `${this.tableName}/${colName}`,\n },\n },\n }\n } else {\n builtColumns[colName] = builtColumn\n }\n } else {\n for (const [key, value] of Object.entries(builder)) {\n if (value instanceof EncryptedField) {\n builtColumns[value.getName()] = value.build()\n } else {\n processColumn(value, key)\n }\n }\n }\n }\n\n for (const [colName, builder] of Object.entries(this.columnBuilders)) {\n processColumn(builder, colName)\n }\n\n return {\n tableName: this.tableName,\n columns: builtColumns,\n }\n }\n}\n\n// ------------------------\n// Schema type inference helpers\n// ------------------------\n\n/**\n * Infer the plaintext (decrypted) type from a EncryptedTable schema.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * name: encryptedColumn(\"name\"),\n * })\n *\n * type UserPlaintext = InferPlaintext<typeof users>\n * // => { email: string; name: string }\n * ```\n */\nexport type InferPlaintext<T extends EncryptedTable<any>> =\n T extends EncryptedTable<infer C>\n ? {\n [K in keyof C as C[K] extends EncryptedColumn | EncryptedField\n ? K\n : never]: string\n }\n : never\n\n/**\n * Infer the encrypted type from a EncryptedTable schema.\n *\n * @example\n * ```typescript\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * type UserEncrypted = InferEncrypted<typeof users>\n * // => { email: Encrypted }\n * ```\n */\nexport type InferEncrypted<T extends EncryptedTable<any>> =\n T extends EncryptedTable<infer C>\n ? {\n [K in keyof C as C[K] extends EncryptedColumn | EncryptedField\n ? K\n : never]: Encrypted\n }\n : never\n\n// ------------------------\n// User facing functions\n// ------------------------\n\n/**\n * Define an encrypted table schema.\n *\n * Creates a `EncryptedTable` that maps a database table name to a set of encrypted\n * column definitions. Pass the resulting object to `Encryption({ schemas: [...] })`\n * when initializing the client.\n *\n * The returned object is also a proxy that exposes each column builder directly,\n * so you can reference columns as `users.email` when calling `encrypt`, `decrypt`,\n * and `encryptQuery`.\n *\n * @param tableName - The name of the database table this schema represents.\n * @param columns - An object whose keys are logical column names and values are\n * {@link EncryptedColumn} from {@link encryptedColumn}, or nested objects whose\n * leaves are {@link EncryptedField} from {@link encryptedField}.\n * @returns A `EncryptedTable<T> & T` that can be used as both a schema definition\n * and a column accessor.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality().freeTextSearch(),\n * address: encryptedColumn(\"address\"),\n * })\n *\n * // Use as schema\n * const client = await Encryption({ schemas: [users] })\n *\n * // Use as column accessor\n * await client.encrypt(\"hello@example.com\", { column: users.email, table: users })\n * ```\n */\nexport function encryptedTable<T extends EncryptedTableColumn>(\n tableName: string,\n columns: T,\n): EncryptedTable<T> & T {\n const tableBuilder = new EncryptedTable(\n tableName,\n columns,\n ) as EncryptedTable<T> & T\n\n for (const [colName, colBuilder] of Object.entries(columns)) {\n ;(tableBuilder as EncryptedTableColumn)[colName] = colBuilder\n }\n\n return tableBuilder\n}\n\n/**\n * Define an encrypted column within a table schema.\n *\n * Creates a `EncryptedColumn` builder for the given column name. Chain index\n * methods (`.equality()`, `.freeTextSearch()`, `.orderAndRange()`,\n * `.searchableJson()`) and/or `.dataType()` to configure searchable encryption\n * and the plaintext data type.\n *\n * @param columnName - The name of the database column to encrypt.\n * @returns A new `EncryptedColumn` builder.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedColumn } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality().freeTextSearch().orderAndRange(),\n * })\n * ```\n */\nexport function encryptedColumn(columnName: string) {\n return new EncryptedColumn(columnName)\n}\n\n/**\n * Define an encrypted field for use in nested or structured schemas.\n *\n * `encryptedField` is similar to {@link encryptedColumn} but creates an {@link EncryptedField}\n * for nested fields that are encrypted but not searchable (no indexes). Use `.dataType()`\n * to specify the plaintext type.\n *\n * @param valueName - The name of the value field.\n * @returns A new `EncryptedField` builder.\n *\n * @example\n * ```typescript\n * import { encryptedTable, encryptedField } from \"@cipherstash/stack/schema\"\n *\n * const orders = encryptedTable(\"orders\", {\n * details: {\n * amount: encryptedField(\"amount\").dataType(\"number\"),\n * currency: encryptedField(\"currency\"),\n * },\n * })\n * ```\n */\nexport function encryptedField(valueName: string) {\n return new EncryptedField(valueName)\n}\n\n/**\n * Build an encrypt config from a list of encrypted tables.\n *\n * @param ...tables - The list of encrypted tables to build the config from.\n * @returns An encrypt config object.\n *\n * @example\n * ```typescript\n * import { buildEncryptConfig } from \"@cipherstash/stack/schema\"\n *\n * const users = encryptedTable(\"users\", {\n * email: encryptedColumn(\"email\").equality(),\n * })\n *\n * const orders = encryptedTable(\"orders\", {\n * amount: encryptedColumn(\"amount\").dataType(\"number\"),\n * })\n *\n * const config = buildEncryptConfig(users, orders)\n * console.log(config)\n * ```\n */\nexport function buildEncryptConfig(\n ...protectTables: Array<EncryptedTable<EncryptedTableColumn>>\n): EncryptConfig {\n const config: EncryptConfig = {\n v: 2,\n tables: {},\n }\n\n for (const tb of protectTables) {\n const tableDef = tb.build()\n config.tables[tableDef.tableName] = tableDef.columns\n }\n\n return config\n}\n"],"mappings":"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","names":[]}
|
package/dist/schema/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as CastAs, x as ColumnSchema, t as EncryptConfig, d as EncryptedColumn, h as EncryptedField, f as EncryptedTable, g as EncryptedTableColumn, c as InferEncrypted, I as InferPlaintext, M as MatchIndexOpts, O as OreIndexOpts, w as SteVecIndexOpts, T as TokenFilter, U as UniqueIndexOpts, y as buildEncryptConfig, u as castAsEnum, v as encryptConfigSchema, a as encryptedColumn, b as encryptedField, e as encryptedTable } from '../types-public-
|
|
1
|
+
export { C as CastAs, x as ColumnSchema, t as EncryptConfig, d as EncryptedColumn, h as EncryptedField, f as EncryptedTable, g as EncryptedTableColumn, c as InferEncrypted, I as InferPlaintext, M as MatchIndexOpts, O as OreIndexOpts, w as SteVecIndexOpts, T as TokenFilter, U as UniqueIndexOpts, y as buildEncryptConfig, u as castAsEnum, v as encryptConfigSchema, a as encryptedColumn, b as encryptedField, e as encryptedTable } from '../types-public-Wj6tB_ux.cjs';
|
|
2
2
|
import 'zod';
|
|
3
3
|
import 'evlog';
|
|
4
4
|
import '@cipherstash/protect-ffi';
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { C as CastAs, x as ColumnSchema, t as EncryptConfig, d as EncryptedColumn, h as EncryptedField, f as EncryptedTable, g as EncryptedTableColumn, c as InferEncrypted, I as InferPlaintext, M as MatchIndexOpts, O as OreIndexOpts, w as SteVecIndexOpts, T as TokenFilter, U as UniqueIndexOpts, y as buildEncryptConfig, u as castAsEnum, v as encryptConfigSchema, a as encryptedColumn, b as encryptedField, e as encryptedTable } from '../types-public-
|
|
1
|
+
export { C as CastAs, x as ColumnSchema, t as EncryptConfig, d as EncryptedColumn, h as EncryptedField, f as EncryptedTable, g as EncryptedTableColumn, c as InferEncrypted, I as InferPlaintext, M as MatchIndexOpts, O as OreIndexOpts, w as SteVecIndexOpts, T as TokenFilter, U as UniqueIndexOpts, y as buildEncryptConfig, u as castAsEnum, v as encryptConfigSchema, a as encryptedColumn, b as encryptedField, e as encryptedTable } from '../types-public-Wj6tB_ux.js';
|
|
2
2
|
import 'zod';
|
|
3
3
|
import 'evlog';
|
|
4
4
|
import '@cipherstash/protect-ffi';
|
package/dist/schema/index.js
CHANGED
package/dist/secrets/index.cjs
CHANGED
|
@@ -41,15 +41,9 @@ function encryptedToPgComposite(obj) {
|
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
43
|
function encryptedToCompositeLiteral(obj) {
|
|
44
|
-
if (obj === null) {
|
|
45
|
-
throw new Error("encryptedToCompositeLiteral: obj cannot be null");
|
|
46
|
-
}
|
|
47
44
|
return `(${JSON.stringify(JSON.stringify(obj))})`;
|
|
48
45
|
}
|
|
49
46
|
function encryptedToEscapedCompositeLiteral(obj) {
|
|
50
|
-
if (obj === null) {
|
|
51
|
-
throw new Error("encryptedToEscapedCompositeLiteral: obj cannot be null");
|
|
52
|
-
}
|
|
53
47
|
return JSON.stringify(encryptedToCompositeLiteral(obj));
|
|
54
48
|
}
|
|
55
49
|
function formatEncryptedResult(encrypted, returnType) {
|
|
@@ -89,7 +83,7 @@ var EncryptionErrorTypes = {
|
|
|
89
83
|
|
|
90
84
|
// src/schema/index.ts
|
|
91
85
|
var import_zod = require("zod");
|
|
92
|
-
var castAsEnum = import_zod.z.enum(["bigint", "boolean", "date", "number", "string", "json"]).default("
|
|
86
|
+
var castAsEnum = import_zod.z.enum(["bigint", "boolean", "date", "number", "string", "json", "text"]).default("text");
|
|
93
87
|
var tokenFilterSchema = import_zod.z.object({
|
|
94
88
|
kind: import_zod.z.literal("downcase")
|
|
95
89
|
});
|
|
@@ -137,7 +131,7 @@ var EncryptedField = class {
|
|
|
137
131
|
castAsValue;
|
|
138
132
|
constructor(valueName) {
|
|
139
133
|
this.valueName = valueName;
|
|
140
|
-
this.castAsValue = "
|
|
134
|
+
this.castAsValue = "text";
|
|
141
135
|
}
|
|
142
136
|
/**
|
|
143
137
|
* Set or override the plaintext data type for this field.
|
|
@@ -146,7 +140,7 @@ var EncryptedField = class {
|
|
|
146
140
|
* a different type so the encryption layer knows how to encode the plaintext
|
|
147
141
|
* before encrypting.
|
|
148
142
|
*
|
|
149
|
-
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
|
|
143
|
+
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'text'`, `'bigint'`, or `'json'`.
|
|
150
144
|
* @returns This `EncryptedField` instance for method chaining.
|
|
151
145
|
*
|
|
152
146
|
* @example
|
|
@@ -162,7 +156,7 @@ var EncryptedField = class {
|
|
|
162
156
|
}
|
|
163
157
|
build() {
|
|
164
158
|
return {
|
|
165
|
-
cast_as: this.castAsValue,
|
|
159
|
+
cast_as: this.castAsValue === "string" ? "text" : this.castAsValue,
|
|
166
160
|
indexes: {}
|
|
167
161
|
};
|
|
168
162
|
}
|
|
@@ -316,7 +310,7 @@ var EncryptedColumn = class {
|
|
|
316
310
|
}
|
|
317
311
|
build() {
|
|
318
312
|
return {
|
|
319
|
-
cast_as: this.castAsValue,
|
|
313
|
+
cast_as: this.castAsValue === "string" ? "text" : this.castAsValue,
|
|
320
314
|
indexes: this.indexesValue
|
|
321
315
|
};
|
|
322
316
|
}
|
|
@@ -687,18 +681,6 @@ var EncryptionOperation = class {
|
|
|
687
681
|
};
|
|
688
682
|
|
|
689
683
|
// src/encryption/operations/batch-encrypt-query.ts
|
|
690
|
-
function filterNullTerms(terms) {
|
|
691
|
-
const nullIndices = /* @__PURE__ */ new Set();
|
|
692
|
-
const nonNullTerms = [];
|
|
693
|
-
terms.forEach((term, index) => {
|
|
694
|
-
if (term.value === null || term.value === void 0) {
|
|
695
|
-
nullIndices.add(index);
|
|
696
|
-
} else {
|
|
697
|
-
nonNullTerms.push({ term, originalIndex: index });
|
|
698
|
-
}
|
|
699
|
-
});
|
|
700
|
-
return { nullIndices, nonNullTerms };
|
|
701
|
-
}
|
|
702
684
|
function buildQueryPayload(term, lockContext) {
|
|
703
685
|
assertValidNumericValue(term.value);
|
|
704
686
|
const { indexType, queryOp } = resolveIndexType(
|
|
@@ -719,13 +701,10 @@ function buildQueryPayload(term, lockContext) {
|
|
|
719
701
|
}
|
|
720
702
|
return payload;
|
|
721
703
|
}
|
|
722
|
-
function assembleResults(
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
results[originalIndex] = formatEncryptedResult(encrypted, term.returnType);
|
|
727
|
-
});
|
|
728
|
-
return results;
|
|
704
|
+
function assembleResults(terms, encryptedValues) {
|
|
705
|
+
return terms.map(
|
|
706
|
+
(term, i) => formatEncryptedResult(encryptedValues[i], term.returnType)
|
|
707
|
+
);
|
|
729
708
|
}
|
|
730
709
|
var BatchEncryptQueryOperation = class extends EncryptionOperation {
|
|
731
710
|
constructor(client, terms) {
|
|
@@ -752,23 +731,18 @@ var BatchEncryptQueryOperation = class extends EncryptionOperation {
|
|
|
752
731
|
log.emit();
|
|
753
732
|
return { data: [] };
|
|
754
733
|
}
|
|
755
|
-
const { nullIndices, nonNullTerms } = filterNullTerms(this.terms);
|
|
756
|
-
if (nonNullTerms.length === 0) {
|
|
757
|
-
log.emit();
|
|
758
|
-
return { data: this.terms.map(() => null) };
|
|
759
|
-
}
|
|
760
734
|
const result = await (0, import_result.withResult)(
|
|
761
735
|
async () => {
|
|
762
736
|
if (!this.client) throw noClientError();
|
|
763
737
|
const { metadata } = this.getAuditData();
|
|
764
|
-
const queries =
|
|
765
|
-
(
|
|
738
|
+
const queries = this.terms.map(
|
|
739
|
+
(term) => buildQueryPayload(term)
|
|
766
740
|
);
|
|
767
741
|
const encrypted = await (0, import_protect_ffi2.encryptQueryBulk)(this.client, {
|
|
768
742
|
queries,
|
|
769
743
|
unverifiedContext: metadata
|
|
770
744
|
});
|
|
771
|
-
return assembleResults(this.terms
|
|
745
|
+
return assembleResults(this.terms, encrypted);
|
|
772
746
|
},
|
|
773
747
|
(error) => {
|
|
774
748
|
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
@@ -802,11 +776,6 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
|
|
|
802
776
|
log.emit();
|
|
803
777
|
return { data: [] };
|
|
804
778
|
}
|
|
805
|
-
const { nullIndices, nonNullTerms } = filterNullTerms(this.terms);
|
|
806
|
-
if (nonNullTerms.length === 0) {
|
|
807
|
-
log.emit();
|
|
808
|
-
return { data: this.terms.map(() => null) };
|
|
809
|
-
}
|
|
810
779
|
const lockContextResult = await this.lockContext.getLockContext();
|
|
811
780
|
if (lockContextResult.failure) {
|
|
812
781
|
log.emit();
|
|
@@ -817,15 +786,15 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
|
|
|
817
786
|
async () => {
|
|
818
787
|
if (!this.client) throw noClientError();
|
|
819
788
|
const { metadata } = this.getAuditData();
|
|
820
|
-
const queries =
|
|
821
|
-
(
|
|
789
|
+
const queries = this.terms.map(
|
|
790
|
+
(term) => buildQueryPayload(term, context)
|
|
822
791
|
);
|
|
823
792
|
const encrypted = await (0, import_protect_ffi2.encryptQueryBulk)(this.client, {
|
|
824
793
|
queries,
|
|
825
794
|
serviceToken: ctsToken,
|
|
826
795
|
unverifiedContext: metadata
|
|
827
796
|
});
|
|
828
|
-
return assembleResults(this.terms
|
|
797
|
+
return assembleResults(this.terms, encrypted);
|
|
829
798
|
},
|
|
830
799
|
(error) => {
|
|
831
800
|
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
@@ -845,42 +814,25 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
|
|
|
845
814
|
var import_result2 = require("@byteslice/result");
|
|
846
815
|
var import_protect_ffi3 = require("@cipherstash/protect-ffi");
|
|
847
816
|
var createDecryptPayloads = (encryptedPayloads, lockContext) => {
|
|
848
|
-
return encryptedPayloads.map((
|
|
817
|
+
return encryptedPayloads.map(({ id, data }) => ({
|
|
849
818
|
id,
|
|
850
819
|
ciphertext: data,
|
|
851
|
-
originalIndex,
|
|
852
820
|
...lockContext && { lockContext }
|
|
853
821
|
}));
|
|
854
822
|
};
|
|
855
|
-
var createNullResult = (encryptedPayloads) => {
|
|
856
|
-
return encryptedPayloads.map(({ id }) => ({
|
|
857
|
-
id,
|
|
858
|
-
data: null
|
|
859
|
-
}));
|
|
860
|
-
};
|
|
861
823
|
var mapDecryptedDataToResult = (encryptedPayloads, decryptedData) => {
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
const decryptResult = decryptedData[decryptedIndex];
|
|
869
|
-
if ("error" in decryptResult) {
|
|
870
|
-
result[i] = {
|
|
871
|
-
id: encryptedPayloads[i].id,
|
|
872
|
-
error: decryptResult.error
|
|
873
|
-
};
|
|
874
|
-
} else {
|
|
875
|
-
result[i] = {
|
|
876
|
-
id: encryptedPayloads[i].id,
|
|
877
|
-
data: decryptResult.data
|
|
878
|
-
};
|
|
879
|
-
}
|
|
880
|
-
decryptedIndex++;
|
|
824
|
+
return decryptedData.map((decryptResult, i) => {
|
|
825
|
+
if ("error" in decryptResult) {
|
|
826
|
+
return {
|
|
827
|
+
id: encryptedPayloads[i].id,
|
|
828
|
+
error: decryptResult.error
|
|
829
|
+
};
|
|
881
830
|
}
|
|
882
|
-
|
|
883
|
-
|
|
831
|
+
return {
|
|
832
|
+
id: encryptedPayloads[i].id,
|
|
833
|
+
data: decryptResult.data
|
|
834
|
+
};
|
|
835
|
+
});
|
|
884
836
|
};
|
|
885
837
|
var BulkDecryptOperation = class extends EncryptionOperation {
|
|
886
838
|
client;
|
|
@@ -905,13 +857,10 @@ var BulkDecryptOperation = class extends EncryptionOperation {
|
|
|
905
857
|
if (!this.client) throw noClientError();
|
|
906
858
|
if (!this.encryptedPayloads || this.encryptedPayloads.length === 0)
|
|
907
859
|
return [];
|
|
908
|
-
const
|
|
909
|
-
if (nonNullPayloads.length === 0) {
|
|
910
|
-
return createNullResult(this.encryptedPayloads);
|
|
911
|
-
}
|
|
860
|
+
const payloads = createDecryptPayloads(this.encryptedPayloads);
|
|
912
861
|
const { metadata } = this.getAuditData();
|
|
913
862
|
const decryptedData = await (0, import_protect_ffi3.decryptBulkFallible)(this.client, {
|
|
914
|
-
ciphertexts:
|
|
863
|
+
ciphertexts: payloads,
|
|
915
864
|
unverifiedContext: metadata
|
|
916
865
|
});
|
|
917
866
|
return mapDecryptedDataToResult(this.encryptedPayloads, decryptedData);
|
|
@@ -963,16 +912,13 @@ var BulkDecryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
963
912
|
if (context.failure) {
|
|
964
913
|
throw new Error(`[encryption]: ${context.failure.message}`);
|
|
965
914
|
}
|
|
966
|
-
const
|
|
915
|
+
const payloads = createDecryptPayloads(
|
|
967
916
|
encryptedPayloads,
|
|
968
917
|
context.data.context
|
|
969
918
|
);
|
|
970
|
-
if (nonNullPayloads.length === 0) {
|
|
971
|
-
return createNullResult(encryptedPayloads);
|
|
972
|
-
}
|
|
973
919
|
const { metadata } = this.getAuditData();
|
|
974
920
|
const decryptedData = await (0, import_protect_ffi3.decryptBulkFallible)(client, {
|
|
975
|
-
ciphertexts:
|
|
921
|
+
ciphertexts: payloads,
|
|
976
922
|
serviceToken: context.data.ctsToken,
|
|
977
923
|
unverifiedContext: metadata
|
|
978
924
|
});
|
|
@@ -1611,34 +1557,14 @@ var BulkDecryptModelsOperationWithLockContext = class extends EncryptionOperatio
|
|
|
1611
1557
|
var import_result4 = require("@byteslice/result");
|
|
1612
1558
|
var import_protect_ffi5 = require("@cipherstash/protect-ffi");
|
|
1613
1559
|
var createEncryptPayloads = (plaintexts, column, table, lockContext) => {
|
|
1614
|
-
return plaintexts.map((
|
|
1560
|
+
return plaintexts.map(({ id, plaintext }) => ({
|
|
1615
1561
|
id,
|
|
1616
1562
|
plaintext,
|
|
1617
1563
|
column: column.getName(),
|
|
1618
1564
|
table: table.tableName,
|
|
1619
|
-
originalIndex,
|
|
1620
1565
|
...lockContext && { lockContext }
|
|
1621
1566
|
}));
|
|
1622
1567
|
};
|
|
1623
|
-
var createNullResult2 = (plaintexts) => {
|
|
1624
|
-
return plaintexts.map(({ id }) => ({ id, data: null }));
|
|
1625
|
-
};
|
|
1626
|
-
var mapEncryptedDataToResult = (plaintexts, encryptedData) => {
|
|
1627
|
-
const result = new Array(plaintexts.length);
|
|
1628
|
-
let encryptedIndex = 0;
|
|
1629
|
-
for (let i = 0; i < plaintexts.length; i++) {
|
|
1630
|
-
if (plaintexts[i].plaintext === null) {
|
|
1631
|
-
result[i] = { id: plaintexts[i].id, data: null };
|
|
1632
|
-
} else {
|
|
1633
|
-
result[i] = {
|
|
1634
|
-
id: plaintexts[i].id,
|
|
1635
|
-
data: encryptedData[encryptedIndex]
|
|
1636
|
-
};
|
|
1637
|
-
encryptedIndex++;
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1640
|
-
return result;
|
|
1641
|
-
};
|
|
1642
1568
|
var BulkEncryptOperation = class extends EncryptionOperation {
|
|
1643
1569
|
client;
|
|
1644
1570
|
plaintexts;
|
|
@@ -1671,20 +1597,20 @@ var BulkEncryptOperation = class extends EncryptionOperation {
|
|
|
1671
1597
|
if (!this.plaintexts || this.plaintexts.length === 0) {
|
|
1672
1598
|
return [];
|
|
1673
1599
|
}
|
|
1674
|
-
const
|
|
1600
|
+
const payloads = createEncryptPayloads(
|
|
1675
1601
|
this.plaintexts,
|
|
1676
1602
|
this.column,
|
|
1677
1603
|
this.table
|
|
1678
1604
|
);
|
|
1679
|
-
if (nonNullPayloads.length === 0) {
|
|
1680
|
-
return createNullResult2(this.plaintexts);
|
|
1681
|
-
}
|
|
1682
1605
|
const { metadata } = this.getAuditData();
|
|
1683
1606
|
const encryptedData = await (0, import_protect_ffi5.encryptBulk)(this.client, {
|
|
1684
|
-
plaintexts:
|
|
1607
|
+
plaintexts: payloads,
|
|
1685
1608
|
unverifiedContext: metadata
|
|
1686
1609
|
});
|
|
1687
|
-
return
|
|
1610
|
+
return encryptedData.map((data, i) => ({
|
|
1611
|
+
id: this.plaintexts[i].id,
|
|
1612
|
+
data
|
|
1613
|
+
}));
|
|
1688
1614
|
},
|
|
1689
1615
|
(error) => {
|
|
1690
1616
|
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
@@ -1741,22 +1667,22 @@ var BulkEncryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
1741
1667
|
if (context.failure) {
|
|
1742
1668
|
throw new Error(`[encryption]: ${context.failure.message}`);
|
|
1743
1669
|
}
|
|
1744
|
-
const
|
|
1670
|
+
const payloads = createEncryptPayloads(
|
|
1745
1671
|
plaintexts,
|
|
1746
1672
|
column,
|
|
1747
1673
|
table,
|
|
1748
1674
|
context.data.context
|
|
1749
1675
|
);
|
|
1750
|
-
if (nonNullPayloads.length === 0) {
|
|
1751
|
-
return createNullResult2(plaintexts);
|
|
1752
|
-
}
|
|
1753
1676
|
const { metadata } = this.getAuditData();
|
|
1754
1677
|
const encryptedData = await (0, import_protect_ffi5.encryptBulk)(client, {
|
|
1755
|
-
plaintexts:
|
|
1678
|
+
plaintexts: payloads,
|
|
1756
1679
|
serviceToken: context.data.ctsToken,
|
|
1757
1680
|
unverifiedContext: metadata
|
|
1758
1681
|
});
|
|
1759
|
-
return
|
|
1682
|
+
return encryptedData.map((data, i) => ({
|
|
1683
|
+
id: plaintexts[i].id,
|
|
1684
|
+
data
|
|
1685
|
+
}));
|
|
1760
1686
|
},
|
|
1761
1687
|
(error) => {
|
|
1762
1688
|
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
@@ -1906,9 +1832,6 @@ var DecryptOperation = class extends EncryptionOperation {
|
|
|
1906
1832
|
if (!this.client) {
|
|
1907
1833
|
throw noClientError();
|
|
1908
1834
|
}
|
|
1909
|
-
if (this.encryptedData === null) {
|
|
1910
|
-
return null;
|
|
1911
|
-
}
|
|
1912
1835
|
const { metadata } = this.getAuditData();
|
|
1913
1836
|
return await (0, import_protect_ffi6.decrypt)(this.client, {
|
|
1914
1837
|
ciphertext: this.encryptedData,
|
|
@@ -1959,9 +1882,6 @@ var DecryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
1959
1882
|
if (!client) {
|
|
1960
1883
|
throw noClientError();
|
|
1961
1884
|
}
|
|
1962
|
-
if (encryptedData === null) {
|
|
1963
|
-
return null;
|
|
1964
|
-
}
|
|
1965
1885
|
const { metadata } = this.getAuditData();
|
|
1966
1886
|
const context = await this.lockContext.getLockContext();
|
|
1967
1887
|
if (context.failure) {
|
|
@@ -2115,9 +2035,6 @@ var EncryptOperation = class extends EncryptionOperation {
|
|
|
2115
2035
|
if (!this.client) {
|
|
2116
2036
|
throw noClientError();
|
|
2117
2037
|
}
|
|
2118
|
-
if (this.plaintext === null) {
|
|
2119
|
-
return null;
|
|
2120
|
-
}
|
|
2121
2038
|
if (typeof this.plaintext === "number" && Number.isNaN(this.plaintext)) {
|
|
2122
2039
|
throw new Error("[encryption]: Cannot encrypt NaN value");
|
|
2123
2040
|
}
|
|
@@ -2179,9 +2096,6 @@ var EncryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
2179
2096
|
if (!client) {
|
|
2180
2097
|
throw noClientError();
|
|
2181
2098
|
}
|
|
2182
|
-
if (plaintext === null) {
|
|
2183
|
-
return null;
|
|
2184
|
-
}
|
|
2185
2099
|
const { metadata } = this.getAuditData();
|
|
2186
2100
|
const context = await this.lockContext.getLockContext();
|
|
2187
2101
|
if (context.failure) {
|
|
@@ -2345,10 +2259,6 @@ var EncryptQueryOperation = class extends EncryptionOperation {
|
|
|
2345
2259
|
queryType: this.opts.queryType,
|
|
2346
2260
|
lockContext: false
|
|
2347
2261
|
});
|
|
2348
|
-
if (this.plaintext === null || this.plaintext === void 0) {
|
|
2349
|
-
log.emit();
|
|
2350
|
-
return { data: null };
|
|
2351
|
-
}
|
|
2352
2262
|
const validationError = validateNumericValue(this.plaintext);
|
|
2353
2263
|
if (validationError?.failure) {
|
|
2354
2264
|
log.emit();
|
|
@@ -2412,10 +2322,6 @@ var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
|
|
|
2412
2322
|
queryType: this.opts.queryType,
|
|
2413
2323
|
lockContext: true
|
|
2414
2324
|
});
|
|
2415
|
-
if (this.plaintext === null || this.plaintext === void 0) {
|
|
2416
|
-
log.emit();
|
|
2417
|
-
return { data: null };
|
|
2418
|
-
}
|
|
2419
2325
|
const validationError = validateNumericValue(this.plaintext);
|
|
2420
2326
|
if (validationError?.failure) {
|
|
2421
2327
|
log.emit();
|
|
@@ -2520,7 +2426,7 @@ var EncryptionClient = class {
|
|
|
2520
2426
|
/**
|
|
2521
2427
|
* Encrypt a value - returns a promise which resolves to an encrypted value.
|
|
2522
2428
|
*
|
|
2523
|
-
* @param plaintext - The plaintext value to be encrypted.
|
|
2429
|
+
* @param plaintext - The plaintext value to be encrypted.
|
|
2524
2430
|
* @param opts - Options specifying the column (or nested field) and table for encryption. See {@link EncryptOptions}.
|
|
2525
2431
|
* @returns An EncryptOperation that can be awaited or chained with additional methods.
|
|
2526
2432
|
*
|
|
@@ -2821,7 +2727,7 @@ var EncryptionClient = class {
|
|
|
2821
2727
|
*
|
|
2822
2728
|
* Each value is encrypted with its own unique key via a single call to ZeroKMS.
|
|
2823
2729
|
* Values can include optional `id` fields for correlating results back to
|
|
2824
|
-
* your application data.
|
|
2730
|
+
* your application data.
|
|
2825
2731
|
*
|
|
2826
2732
|
* @param plaintexts - An array of objects with `plaintext` (and optional `id`) fields.
|
|
2827
2733
|
* @param opts - Options specifying the target column (or nested {@link encryptedField}) and table. See {@link EncryptOptions}.
|
|
@@ -2842,7 +2748,6 @@ var EncryptionClient = class {
|
|
|
2842
2748
|
* [
|
|
2843
2749
|
* { id: "u1", plaintext: "alice@example.com" },
|
|
2844
2750
|
* { id: "u2", plaintext: "bob@example.com" },
|
|
2845
|
-
* { id: "u3", plaintext: null },
|
|
2846
2751
|
* ],
|
|
2847
2752
|
* { column: users.email, table: users },
|
|
2848
2753
|
* )
|