@cipherstash/stack 0.2.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 +12 -0
- package/README.md +2 -3
- package/dist/bin/stash.js +109 -186
- 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-5G4F4JJG.js → chunk-KOU2MHXJ.js} +1 -1
- package/dist/chunk-KOU2MHXJ.js.map +1 -0
- package/dist/{chunk-5DCT6YU2.js → chunk-OAPLZLR5.js} +7 -3
- package/dist/{chunk-5DCT6YU2.js.map → chunk-OAPLZLR5.js.map} +1 -1
- package/dist/{chunk-LHZ6KZIG.js → chunk-WUZGKTMG.js} +84 -162
- package/dist/chunk-WUZGKTMG.js.map +1 -0
- package/dist/{chunk-7XRPN2KX.js → chunk-Y35W4WFN.js} +31 -28
- package/dist/chunk-Y35W4WFN.js.map +1 -0
- package/dist/{client-D-ZH8SB2.d.cts → client-CUGXheRq.d.cts} +33 -31
- package/dist/{client-BV9pXC-d.d.ts → client-CrGQnSlk.d.ts} +33 -31
- package/dist/client.cjs +30 -27
- 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 +5 -5
- package/dist/drizzle/index.cjs +24 -21
- package/dist/drizzle/index.cjs.map +1 -1
- package/dist/drizzle/index.d.cts +5 -5
- package/dist/drizzle/index.d.ts +5 -5
- package/dist/drizzle/index.js +2 -2
- package/dist/drizzle/index.js.map +1 -1
- package/dist/dynamodb/index.cjs.map +1 -1
- package/dist/dynamodb/index.d.cts +10 -10
- package/dist/dynamodb/index.d.ts +10 -10
- package/dist/dynamodb/index.js.map +1 -1
- package/dist/identity/index.cjs +6 -2
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.js +1 -1
- package/dist/index.cjs +113 -190
- 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 +8 -8
- package/dist/schema/index.cjs +36 -33
- 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 +11 -11
- package/dist/secrets/index.cjs +109 -186
- 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 +5 -5
- package/dist/secrets/index.js.map +1 -1
- package/dist/supabase/index.cjs +9 -9
- package/dist/supabase/index.cjs.map +1 -1
- package/dist/supabase/index.d.cts +3 -3
- package/dist/supabase/index.d.ts +3 -3
- package/dist/supabase/index.js +4 -4
- package/dist/supabase/index.js.map +1 -1
- package/dist/{types-public-Dfg-hkuQ.d.cts → types-public-Wj6tB_ux.d.cts} +115 -76
- package/dist/{types-public-Dfg-hkuQ.d.ts → types-public-Wj6tB_ux.d.ts} +115 -76
- 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-5G4F4JJG.js.map +0 -1
- package/dist/chunk-7XRPN2KX.js.map +0 -1
- package/dist/chunk-LHZ6KZIG.js.map +0 -1
- package/dist/chunk-SUYMGQBY.js.map +0 -1
package/dist/bin/stash.js
CHANGED
|
@@ -1470,15 +1470,9 @@ function encryptedToPgComposite(obj) {
|
|
|
1470
1470
|
};
|
|
1471
1471
|
}
|
|
1472
1472
|
function encryptedToCompositeLiteral(obj) {
|
|
1473
|
-
if (obj === null) {
|
|
1474
|
-
throw new Error("encryptedToCompositeLiteral: obj cannot be null");
|
|
1475
|
-
}
|
|
1476
1473
|
return `(${JSON.stringify(JSON.stringify(obj))})`;
|
|
1477
1474
|
}
|
|
1478
1475
|
function encryptedToEscapedCompositeLiteral(obj) {
|
|
1479
|
-
if (obj === null) {
|
|
1480
|
-
throw new Error("encryptedToEscapedCompositeLiteral: obj cannot be null");
|
|
1481
|
-
}
|
|
1482
1476
|
return JSON.stringify(encryptedToCompositeLiteral(obj));
|
|
1483
1477
|
}
|
|
1484
1478
|
function formatEncryptedResult(encrypted, returnType) {
|
|
@@ -1518,7 +1512,7 @@ var EncryptionErrorTypes = {
|
|
|
1518
1512
|
|
|
1519
1513
|
// src/schema/index.ts
|
|
1520
1514
|
import { z as z2 } from "zod";
|
|
1521
|
-
var castAsEnum = z2.enum(["bigint", "boolean", "date", "number", "string", "json"]).default("
|
|
1515
|
+
var castAsEnum = z2.enum(["bigint", "boolean", "date", "number", "string", "json", "text"]).default("text");
|
|
1522
1516
|
var tokenFilterSchema = z2.object({
|
|
1523
1517
|
kind: z2.literal("downcase")
|
|
1524
1518
|
});
|
|
@@ -1561,28 +1555,28 @@ var encryptConfigSchema = z2.object({
|
|
|
1561
1555
|
v: z2.number(),
|
|
1562
1556
|
tables: tablesSchema
|
|
1563
1557
|
});
|
|
1564
|
-
var
|
|
1558
|
+
var EncryptedField = class {
|
|
1565
1559
|
valueName;
|
|
1566
1560
|
castAsValue;
|
|
1567
1561
|
constructor(valueName) {
|
|
1568
1562
|
this.valueName = valueName;
|
|
1569
|
-
this.castAsValue = "
|
|
1563
|
+
this.castAsValue = "text";
|
|
1570
1564
|
}
|
|
1571
1565
|
/**
|
|
1572
|
-
* Set or override the plaintext data type for this
|
|
1566
|
+
* Set or override the plaintext data type for this field.
|
|
1573
1567
|
*
|
|
1574
1568
|
* By default all values are treated as `'string'`. Use this method to specify
|
|
1575
1569
|
* a different type so the encryption layer knows how to encode the plaintext
|
|
1576
1570
|
* before encrypting.
|
|
1577
1571
|
*
|
|
1578
|
-
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
|
|
1579
|
-
* @returns This `
|
|
1572
|
+
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'text'`, `'bigint'`, or `'json'`.
|
|
1573
|
+
* @returns This `EncryptedField` instance for method chaining.
|
|
1580
1574
|
*
|
|
1581
1575
|
* @example
|
|
1582
1576
|
* ```typescript
|
|
1583
|
-
* import {
|
|
1577
|
+
* import { encryptedField } from "@cipherstash/stack/schema"
|
|
1584
1578
|
*
|
|
1585
|
-
* const age =
|
|
1579
|
+
* const age = encryptedField("age").dataType("number")
|
|
1586
1580
|
* ```
|
|
1587
1581
|
*/
|
|
1588
1582
|
dataType(castAs) {
|
|
@@ -1591,7 +1585,7 @@ var ProtectValue = class {
|
|
|
1591
1585
|
}
|
|
1592
1586
|
build() {
|
|
1593
1587
|
return {
|
|
1594
|
-
cast_as: this.castAsValue,
|
|
1588
|
+
cast_as: this.castAsValue === "string" ? "text" : this.castAsValue,
|
|
1595
1589
|
indexes: {}
|
|
1596
1590
|
};
|
|
1597
1591
|
}
|
|
@@ -1599,7 +1593,7 @@ var ProtectValue = class {
|
|
|
1599
1593
|
return this.valueName;
|
|
1600
1594
|
}
|
|
1601
1595
|
};
|
|
1602
|
-
var
|
|
1596
|
+
var EncryptedColumn = class {
|
|
1603
1597
|
columnName;
|
|
1604
1598
|
castAsValue;
|
|
1605
1599
|
indexesValue = {};
|
|
@@ -1615,7 +1609,7 @@ var ProtectColumn = class {
|
|
|
1615
1609
|
* before encrypting.
|
|
1616
1610
|
*
|
|
1617
1611
|
* @param castAs - The plaintext data type: `'string'`, `'number'`, `'boolean'`, `'date'`, `'bigint'`, or `'json'`.
|
|
1618
|
-
* @returns This `
|
|
1612
|
+
* @returns This `EncryptedColumn` instance for method chaining.
|
|
1619
1613
|
*
|
|
1620
1614
|
* @example
|
|
1621
1615
|
* ```typescript
|
|
@@ -1634,7 +1628,7 @@ var ProtectColumn = class {
|
|
|
1634
1628
|
* ORE allows sorting, comparison, and range queries on encrypted data.
|
|
1635
1629
|
* Use with `encryptQuery` and `queryType: 'orderAndRange'`.
|
|
1636
1630
|
*
|
|
1637
|
-
* @returns This `
|
|
1631
|
+
* @returns This `EncryptedColumn` instance for method chaining.
|
|
1638
1632
|
*
|
|
1639
1633
|
* @example
|
|
1640
1634
|
* ```typescript
|
|
@@ -1657,7 +1651,7 @@ var ProtectColumn = class {
|
|
|
1657
1651
|
*
|
|
1658
1652
|
* @param tokenFilters - Optional array of token filters (e.g. `[{ kind: 'downcase' }]`).
|
|
1659
1653
|
* When omitted, no token filters are applied.
|
|
1660
|
-
* @returns This `
|
|
1654
|
+
* @returns This `EncryptedColumn` instance for method chaining.
|
|
1661
1655
|
*
|
|
1662
1656
|
* @example
|
|
1663
1657
|
* ```typescript
|
|
@@ -1682,7 +1676,7 @@ var ProtectColumn = class {
|
|
|
1682
1676
|
*
|
|
1683
1677
|
* @param opts - Optional match index configuration. Defaults to 3-character ngram
|
|
1684
1678
|
* tokenization with a downcase filter, `k=6`, `m=2048`, and `include_original=true`.
|
|
1685
|
-
* @returns This `
|
|
1679
|
+
* @returns This `EncryptedColumn` instance for method chaining.
|
|
1686
1680
|
*
|
|
1687
1681
|
* @example
|
|
1688
1682
|
* ```typescript
|
|
@@ -1727,7 +1721,7 @@ var ProtectColumn = class {
|
|
|
1727
1721
|
* the plaintext type: strings become selector queries, objects/arrays become
|
|
1728
1722
|
* containment queries.
|
|
1729
1723
|
*
|
|
1730
|
-
* @returns This `
|
|
1724
|
+
* @returns This `EncryptedColumn` instance for method chaining.
|
|
1731
1725
|
*
|
|
1732
1726
|
* @example
|
|
1733
1727
|
* ```typescript
|
|
@@ -1745,7 +1739,7 @@ var ProtectColumn = class {
|
|
|
1745
1739
|
}
|
|
1746
1740
|
build() {
|
|
1747
1741
|
return {
|
|
1748
|
-
cast_as: this.castAsValue,
|
|
1742
|
+
cast_as: this.castAsValue === "string" ? "text" : this.castAsValue,
|
|
1749
1743
|
indexes: this.indexesValue
|
|
1750
1744
|
};
|
|
1751
1745
|
}
|
|
@@ -1753,7 +1747,7 @@ var ProtectColumn = class {
|
|
|
1753
1747
|
return this.columnName;
|
|
1754
1748
|
}
|
|
1755
1749
|
};
|
|
1756
|
-
var
|
|
1750
|
+
var EncryptedTable = class {
|
|
1757
1751
|
constructor(tableName, columnBuilders) {
|
|
1758
1752
|
this.tableName = tableName;
|
|
1759
1753
|
this.columnBuilders = columnBuilders;
|
|
@@ -1780,7 +1774,7 @@ var ProtectTable = class {
|
|
|
1780
1774
|
build() {
|
|
1781
1775
|
const builtColumns = {};
|
|
1782
1776
|
const processColumn = (builder, colName) => {
|
|
1783
|
-
if (builder instanceof
|
|
1777
|
+
if (builder instanceof EncryptedColumn) {
|
|
1784
1778
|
const builtColumn = builder.build();
|
|
1785
1779
|
if (builtColumn.cast_as === "json" && builtColumn.indexes.ste_vec?.prefix === "enabled") {
|
|
1786
1780
|
builtColumns[colName] = {
|
|
@@ -1797,7 +1791,7 @@ var ProtectTable = class {
|
|
|
1797
1791
|
}
|
|
1798
1792
|
} else {
|
|
1799
1793
|
for (const [key, value] of Object.entries(builder)) {
|
|
1800
|
-
if (value instanceof
|
|
1794
|
+
if (value instanceof EncryptedField) {
|
|
1801
1795
|
builtColumns[value.getName()] = value.build();
|
|
1802
1796
|
} else {
|
|
1803
1797
|
processColumn(value, key);
|
|
@@ -1815,7 +1809,10 @@ var ProtectTable = class {
|
|
|
1815
1809
|
}
|
|
1816
1810
|
};
|
|
1817
1811
|
function encryptedTable(tableName, columns) {
|
|
1818
|
-
const tableBuilder = new
|
|
1812
|
+
const tableBuilder = new EncryptedTable(
|
|
1813
|
+
tableName,
|
|
1814
|
+
columns
|
|
1815
|
+
);
|
|
1819
1816
|
for (const [colName, colBuilder] of Object.entries(columns)) {
|
|
1820
1817
|
;
|
|
1821
1818
|
tableBuilder[colName] = colBuilder;
|
|
@@ -1823,7 +1820,7 @@ function encryptedTable(tableName, columns) {
|
|
|
1823
1820
|
return tableBuilder;
|
|
1824
1821
|
}
|
|
1825
1822
|
function encryptedColumn(columnName) {
|
|
1826
|
-
return new
|
|
1823
|
+
return new EncryptedColumn(columnName);
|
|
1827
1824
|
}
|
|
1828
1825
|
function buildEncryptConfig(...protectTables) {
|
|
1829
1826
|
const config3 = {
|
|
@@ -1917,7 +1914,7 @@ function initStackLogger(config3) {
|
|
|
1917
1914
|
const rates = samplingFromEnv();
|
|
1918
1915
|
initLogger({
|
|
1919
1916
|
env: { service: "@cipherstash/stack" },
|
|
1920
|
-
enabled: config3?.enabled ??
|
|
1917
|
+
enabled: config3?.enabled ?? !!rates,
|
|
1921
1918
|
pretty: config3?.pretty,
|
|
1922
1919
|
...rates && { sampling: { rates } },
|
|
1923
1920
|
...config3?.drain && { drain: config3.drain }
|
|
@@ -1930,7 +1927,11 @@ function safeMessage(args) {
|
|
|
1930
1927
|
var logger = {
|
|
1931
1928
|
debug(...args) {
|
|
1932
1929
|
const log = createRequestLogger();
|
|
1933
|
-
log.set({
|
|
1930
|
+
log.set({
|
|
1931
|
+
level: "debug",
|
|
1932
|
+
source: "@cipherstash/stack",
|
|
1933
|
+
message: safeMessage(args)
|
|
1934
|
+
});
|
|
1934
1935
|
log.emit();
|
|
1935
1936
|
},
|
|
1936
1937
|
info(...args) {
|
|
@@ -1951,16 +1952,16 @@ var logger = {
|
|
|
1951
1952
|
}
|
|
1952
1953
|
};
|
|
1953
1954
|
|
|
1954
|
-
// src/encryption/
|
|
1955
|
+
// src/encryption/index.ts
|
|
1955
1956
|
import { withResult as withResult11 } from "@byteslice/result";
|
|
1956
1957
|
import { newClient } from "@cipherstash/protect-ffi";
|
|
1957
1958
|
|
|
1958
|
-
// src/encryption/
|
|
1959
|
+
// src/encryption/helpers/type-guards.ts
|
|
1959
1960
|
function isScalarQueryTermArray(value) {
|
|
1960
1961
|
return Array.isArray(value) && value.length > 0 && typeof value[0] === "object" && value[0] !== null && "column" in value[0] && "table" in value[0];
|
|
1961
1962
|
}
|
|
1962
1963
|
|
|
1963
|
-
// src/encryption/
|
|
1964
|
+
// src/encryption/helpers/error-code.ts
|
|
1964
1965
|
import {
|
|
1965
1966
|
ProtectError as FfiProtectError
|
|
1966
1967
|
} from "@cipherstash/protect-ffi";
|
|
@@ -1968,7 +1969,7 @@ function getErrorCode(error) {
|
|
|
1968
1969
|
return error instanceof FfiProtectError ? error.code : void 0;
|
|
1969
1970
|
}
|
|
1970
1971
|
|
|
1971
|
-
// src/encryption/
|
|
1972
|
+
// src/encryption/operations/batch-encrypt-query.ts
|
|
1972
1973
|
import { withResult } from "@byteslice/result";
|
|
1973
1974
|
import {
|
|
1974
1975
|
encryptQueryBulk as ffiEncryptQueryBulk
|
|
@@ -1988,7 +1989,7 @@ var queryTypeToQueryOp = {
|
|
|
1988
1989
|
steVecTerm: "ste_vec_term"
|
|
1989
1990
|
};
|
|
1990
1991
|
|
|
1991
|
-
// src/encryption/
|
|
1992
|
+
// src/encryption/helpers/infer-index-type.ts
|
|
1992
1993
|
function inferIndexType(column) {
|
|
1993
1994
|
const config3 = column.build();
|
|
1994
1995
|
const indexes = config3.indexes;
|
|
@@ -2048,7 +2049,7 @@ function resolveIndexType(column, queryType, plaintext) {
|
|
|
2048
2049
|
return { indexType };
|
|
2049
2050
|
}
|
|
2050
2051
|
|
|
2051
|
-
// src/encryption/
|
|
2052
|
+
// src/encryption/helpers/validation.ts
|
|
2052
2053
|
function validateNumericValue(value) {
|
|
2053
2054
|
if (typeof value === "number" && Number.isNaN(value)) {
|
|
2054
2055
|
return {
|
|
@@ -2084,7 +2085,7 @@ function assertValueIndexCompatibility(value, indexType, columnName) {
|
|
|
2084
2085
|
}
|
|
2085
2086
|
}
|
|
2086
2087
|
|
|
2087
|
-
// src/encryption/
|
|
2088
|
+
// src/encryption/operations/base-operation.ts
|
|
2088
2089
|
var EncryptionOperation = class {
|
|
2089
2090
|
auditMetadata;
|
|
2090
2091
|
/**
|
|
@@ -2112,19 +2113,7 @@ var EncryptionOperation = class {
|
|
|
2112
2113
|
}
|
|
2113
2114
|
};
|
|
2114
2115
|
|
|
2115
|
-
// src/encryption/
|
|
2116
|
-
function filterNullTerms(terms) {
|
|
2117
|
-
const nullIndices = /* @__PURE__ */ new Set();
|
|
2118
|
-
const nonNullTerms = [];
|
|
2119
|
-
terms.forEach((term, index) => {
|
|
2120
|
-
if (term.value === null || term.value === void 0) {
|
|
2121
|
-
nullIndices.add(index);
|
|
2122
|
-
} else {
|
|
2123
|
-
nonNullTerms.push({ term, originalIndex: index });
|
|
2124
|
-
}
|
|
2125
|
-
});
|
|
2126
|
-
return { nullIndices, nonNullTerms };
|
|
2127
|
-
}
|
|
2116
|
+
// src/encryption/operations/batch-encrypt-query.ts
|
|
2128
2117
|
function buildQueryPayload(term, lockContext) {
|
|
2129
2118
|
assertValidNumericValue(term.value);
|
|
2130
2119
|
const { indexType, queryOp } = resolveIndexType(
|
|
@@ -2145,13 +2134,10 @@ function buildQueryPayload(term, lockContext) {
|
|
|
2145
2134
|
}
|
|
2146
2135
|
return payload;
|
|
2147
2136
|
}
|
|
2148
|
-
function assembleResults(
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
results[originalIndex] = formatEncryptedResult(encrypted, term.returnType);
|
|
2153
|
-
});
|
|
2154
|
-
return results;
|
|
2137
|
+
function assembleResults(terms, encryptedValues) {
|
|
2138
|
+
return terms.map(
|
|
2139
|
+
(term, i) => formatEncryptedResult(encryptedValues[i], term.returnType)
|
|
2140
|
+
);
|
|
2155
2141
|
}
|
|
2156
2142
|
var BatchEncryptQueryOperation = class extends EncryptionOperation {
|
|
2157
2143
|
constructor(client, terms) {
|
|
@@ -2178,23 +2164,18 @@ var BatchEncryptQueryOperation = class extends EncryptionOperation {
|
|
|
2178
2164
|
log.emit();
|
|
2179
2165
|
return { data: [] };
|
|
2180
2166
|
}
|
|
2181
|
-
const { nullIndices, nonNullTerms } = filterNullTerms(this.terms);
|
|
2182
|
-
if (nonNullTerms.length === 0) {
|
|
2183
|
-
log.emit();
|
|
2184
|
-
return { data: this.terms.map(() => null) };
|
|
2185
|
-
}
|
|
2186
2167
|
const result = await withResult(
|
|
2187
2168
|
async () => {
|
|
2188
2169
|
if (!this.client) throw noClientError();
|
|
2189
2170
|
const { metadata } = this.getAuditData();
|
|
2190
|
-
const queries =
|
|
2191
|
-
(
|
|
2171
|
+
const queries = this.terms.map(
|
|
2172
|
+
(term) => buildQueryPayload(term)
|
|
2192
2173
|
);
|
|
2193
2174
|
const encrypted = await ffiEncryptQueryBulk(this.client, {
|
|
2194
2175
|
queries,
|
|
2195
2176
|
unverifiedContext: metadata
|
|
2196
2177
|
});
|
|
2197
|
-
return assembleResults(this.terms
|
|
2178
|
+
return assembleResults(this.terms, encrypted);
|
|
2198
2179
|
},
|
|
2199
2180
|
(error) => {
|
|
2200
2181
|
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
@@ -2228,11 +2209,6 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
|
|
|
2228
2209
|
log.emit();
|
|
2229
2210
|
return { data: [] };
|
|
2230
2211
|
}
|
|
2231
|
-
const { nullIndices, nonNullTerms } = filterNullTerms(this.terms);
|
|
2232
|
-
if (nonNullTerms.length === 0) {
|
|
2233
|
-
log.emit();
|
|
2234
|
-
return { data: this.terms.map(() => null) };
|
|
2235
|
-
}
|
|
2236
2212
|
const lockContextResult = await this.lockContext.getLockContext();
|
|
2237
2213
|
if (lockContextResult.failure) {
|
|
2238
2214
|
log.emit();
|
|
@@ -2243,15 +2219,15 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
|
|
|
2243
2219
|
async () => {
|
|
2244
2220
|
if (!this.client) throw noClientError();
|
|
2245
2221
|
const { metadata } = this.getAuditData();
|
|
2246
|
-
const queries =
|
|
2247
|
-
(
|
|
2222
|
+
const queries = this.terms.map(
|
|
2223
|
+
(term) => buildQueryPayload(term, context)
|
|
2248
2224
|
);
|
|
2249
2225
|
const encrypted = await ffiEncryptQueryBulk(this.client, {
|
|
2250
2226
|
queries,
|
|
2251
2227
|
serviceToken: ctsToken,
|
|
2252
2228
|
unverifiedContext: metadata
|
|
2253
2229
|
});
|
|
2254
|
-
return assembleResults(this.terms
|
|
2230
|
+
return assembleResults(this.terms, encrypted);
|
|
2255
2231
|
},
|
|
2256
2232
|
(error) => {
|
|
2257
2233
|
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
@@ -2267,48 +2243,31 @@ var BatchEncryptQueryOperationWithLockContext = class extends EncryptionOperatio
|
|
|
2267
2243
|
}
|
|
2268
2244
|
};
|
|
2269
2245
|
|
|
2270
|
-
// src/encryption/
|
|
2246
|
+
// src/encryption/operations/bulk-decrypt.ts
|
|
2271
2247
|
import { withResult as withResult2 } from "@byteslice/result";
|
|
2272
2248
|
import {
|
|
2273
2249
|
decryptBulkFallible
|
|
2274
2250
|
} from "@cipherstash/protect-ffi";
|
|
2275
2251
|
var createDecryptPayloads = (encryptedPayloads, lockContext) => {
|
|
2276
|
-
return encryptedPayloads.map((
|
|
2252
|
+
return encryptedPayloads.map(({ id, data }) => ({
|
|
2277
2253
|
id,
|
|
2278
2254
|
ciphertext: data,
|
|
2279
|
-
originalIndex,
|
|
2280
2255
|
...lockContext && { lockContext }
|
|
2281
2256
|
}));
|
|
2282
2257
|
};
|
|
2283
|
-
var createNullResult = (encryptedPayloads) => {
|
|
2284
|
-
return encryptedPayloads.map(({ id }) => ({
|
|
2285
|
-
id,
|
|
2286
|
-
data: null
|
|
2287
|
-
}));
|
|
2288
|
-
};
|
|
2289
2258
|
var mapDecryptedDataToResult = (encryptedPayloads, decryptedData) => {
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
const decryptResult = decryptedData[decryptedIndex];
|
|
2297
|
-
if ("error" in decryptResult) {
|
|
2298
|
-
result[i] = {
|
|
2299
|
-
id: encryptedPayloads[i].id,
|
|
2300
|
-
error: decryptResult.error
|
|
2301
|
-
};
|
|
2302
|
-
} else {
|
|
2303
|
-
result[i] = {
|
|
2304
|
-
id: encryptedPayloads[i].id,
|
|
2305
|
-
data: decryptResult.data
|
|
2306
|
-
};
|
|
2307
|
-
}
|
|
2308
|
-
decryptedIndex++;
|
|
2259
|
+
return decryptedData.map((decryptResult, i) => {
|
|
2260
|
+
if ("error" in decryptResult) {
|
|
2261
|
+
return {
|
|
2262
|
+
id: encryptedPayloads[i].id,
|
|
2263
|
+
error: decryptResult.error
|
|
2264
|
+
};
|
|
2309
2265
|
}
|
|
2310
|
-
|
|
2311
|
-
|
|
2266
|
+
return {
|
|
2267
|
+
id: encryptedPayloads[i].id,
|
|
2268
|
+
data: decryptResult.data
|
|
2269
|
+
};
|
|
2270
|
+
});
|
|
2312
2271
|
};
|
|
2313
2272
|
var BulkDecryptOperation = class extends EncryptionOperation {
|
|
2314
2273
|
client;
|
|
@@ -2333,13 +2292,10 @@ var BulkDecryptOperation = class extends EncryptionOperation {
|
|
|
2333
2292
|
if (!this.client) throw noClientError();
|
|
2334
2293
|
if (!this.encryptedPayloads || this.encryptedPayloads.length === 0)
|
|
2335
2294
|
return [];
|
|
2336
|
-
const
|
|
2337
|
-
if (nonNullPayloads.length === 0) {
|
|
2338
|
-
return createNullResult(this.encryptedPayloads);
|
|
2339
|
-
}
|
|
2295
|
+
const payloads = createDecryptPayloads(this.encryptedPayloads);
|
|
2340
2296
|
const { metadata } = this.getAuditData();
|
|
2341
2297
|
const decryptedData = await decryptBulkFallible(this.client, {
|
|
2342
|
-
ciphertexts:
|
|
2298
|
+
ciphertexts: payloads,
|
|
2343
2299
|
unverifiedContext: metadata
|
|
2344
2300
|
});
|
|
2345
2301
|
return mapDecryptedDataToResult(this.encryptedPayloads, decryptedData);
|
|
@@ -2391,16 +2347,13 @@ var BulkDecryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
2391
2347
|
if (context.failure) {
|
|
2392
2348
|
throw new Error(`[encryption]: ${context.failure.message}`);
|
|
2393
2349
|
}
|
|
2394
|
-
const
|
|
2350
|
+
const payloads = createDecryptPayloads(
|
|
2395
2351
|
encryptedPayloads,
|
|
2396
2352
|
context.data.context
|
|
2397
2353
|
);
|
|
2398
|
-
if (nonNullPayloads.length === 0) {
|
|
2399
|
-
return createNullResult(encryptedPayloads);
|
|
2400
|
-
}
|
|
2401
2354
|
const { metadata } = this.getAuditData();
|
|
2402
2355
|
const decryptedData = await decryptBulkFallible(client, {
|
|
2403
|
-
ciphertexts:
|
|
2356
|
+
ciphertexts: payloads,
|
|
2404
2357
|
serviceToken: context.data.ctsToken,
|
|
2405
2358
|
unverifiedContext: metadata
|
|
2406
2359
|
});
|
|
@@ -2420,10 +2373,10 @@ var BulkDecryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
2420
2373
|
}
|
|
2421
2374
|
};
|
|
2422
2375
|
|
|
2423
|
-
// src/encryption/
|
|
2376
|
+
// src/encryption/operations/bulk-decrypt-models.ts
|
|
2424
2377
|
import { withResult as withResult3 } from "@byteslice/result";
|
|
2425
2378
|
|
|
2426
|
-
// src/encryption/
|
|
2379
|
+
// src/encryption/helpers/model-helpers.ts
|
|
2427
2380
|
import {
|
|
2428
2381
|
decryptBulk,
|
|
2429
2382
|
encryptBulk
|
|
@@ -2941,7 +2894,7 @@ async function bulkEncryptModelsWithLockContext(models, table, client, lockConte
|
|
|
2941
2894
|
});
|
|
2942
2895
|
}
|
|
2943
2896
|
|
|
2944
|
-
// src/encryption/
|
|
2897
|
+
// src/encryption/operations/bulk-decrypt-models.ts
|
|
2945
2898
|
var BulkDecryptModelsOperation = class extends EncryptionOperation {
|
|
2946
2899
|
client;
|
|
2947
2900
|
models;
|
|
@@ -3038,38 +2991,18 @@ var BulkDecryptModelsOperationWithLockContext = class extends EncryptionOperatio
|
|
|
3038
2991
|
}
|
|
3039
2992
|
};
|
|
3040
2993
|
|
|
3041
|
-
// src/encryption/
|
|
2994
|
+
// src/encryption/operations/bulk-encrypt.ts
|
|
3042
2995
|
import { withResult as withResult4 } from "@byteslice/result";
|
|
3043
2996
|
import { encryptBulk as encryptBulk2 } from "@cipherstash/protect-ffi";
|
|
3044
2997
|
var createEncryptPayloads = (plaintexts, column, table, lockContext) => {
|
|
3045
|
-
return plaintexts.map((
|
|
2998
|
+
return plaintexts.map(({ id, plaintext }) => ({
|
|
3046
2999
|
id,
|
|
3047
3000
|
plaintext,
|
|
3048
3001
|
column: column.getName(),
|
|
3049
3002
|
table: table.tableName,
|
|
3050
|
-
originalIndex,
|
|
3051
3003
|
...lockContext && { lockContext }
|
|
3052
3004
|
}));
|
|
3053
3005
|
};
|
|
3054
|
-
var createNullResult2 = (plaintexts) => {
|
|
3055
|
-
return plaintexts.map(({ id }) => ({ id, data: null }));
|
|
3056
|
-
};
|
|
3057
|
-
var mapEncryptedDataToResult = (plaintexts, encryptedData) => {
|
|
3058
|
-
const result = new Array(plaintexts.length);
|
|
3059
|
-
let encryptedIndex = 0;
|
|
3060
|
-
for (let i = 0; i < plaintexts.length; i++) {
|
|
3061
|
-
if (plaintexts[i].plaintext === null) {
|
|
3062
|
-
result[i] = { id: plaintexts[i].id, data: null };
|
|
3063
|
-
} else {
|
|
3064
|
-
result[i] = {
|
|
3065
|
-
id: plaintexts[i].id,
|
|
3066
|
-
data: encryptedData[encryptedIndex]
|
|
3067
|
-
};
|
|
3068
|
-
encryptedIndex++;
|
|
3069
|
-
}
|
|
3070
|
-
}
|
|
3071
|
-
return result;
|
|
3072
|
-
};
|
|
3073
3006
|
var BulkEncryptOperation = class extends EncryptionOperation {
|
|
3074
3007
|
client;
|
|
3075
3008
|
plaintexts;
|
|
@@ -3102,20 +3035,20 @@ var BulkEncryptOperation = class extends EncryptionOperation {
|
|
|
3102
3035
|
if (!this.plaintexts || this.plaintexts.length === 0) {
|
|
3103
3036
|
return [];
|
|
3104
3037
|
}
|
|
3105
|
-
const
|
|
3038
|
+
const payloads = createEncryptPayloads(
|
|
3106
3039
|
this.plaintexts,
|
|
3107
3040
|
this.column,
|
|
3108
3041
|
this.table
|
|
3109
3042
|
);
|
|
3110
|
-
if (nonNullPayloads.length === 0) {
|
|
3111
|
-
return createNullResult2(this.plaintexts);
|
|
3112
|
-
}
|
|
3113
3043
|
const { metadata } = this.getAuditData();
|
|
3114
3044
|
const encryptedData = await encryptBulk2(this.client, {
|
|
3115
|
-
plaintexts:
|
|
3045
|
+
plaintexts: payloads,
|
|
3116
3046
|
unverifiedContext: metadata
|
|
3117
3047
|
});
|
|
3118
|
-
return
|
|
3048
|
+
return encryptedData.map((data, i) => ({
|
|
3049
|
+
id: this.plaintexts[i].id,
|
|
3050
|
+
data
|
|
3051
|
+
}));
|
|
3119
3052
|
},
|
|
3120
3053
|
(error) => {
|
|
3121
3054
|
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
@@ -3172,22 +3105,22 @@ var BulkEncryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
3172
3105
|
if (context.failure) {
|
|
3173
3106
|
throw new Error(`[encryption]: ${context.failure.message}`);
|
|
3174
3107
|
}
|
|
3175
|
-
const
|
|
3108
|
+
const payloads = createEncryptPayloads(
|
|
3176
3109
|
plaintexts,
|
|
3177
3110
|
column,
|
|
3178
3111
|
table,
|
|
3179
3112
|
context.data.context
|
|
3180
3113
|
);
|
|
3181
|
-
if (nonNullPayloads.length === 0) {
|
|
3182
|
-
return createNullResult2(plaintexts);
|
|
3183
|
-
}
|
|
3184
3114
|
const { metadata } = this.getAuditData();
|
|
3185
3115
|
const encryptedData = await encryptBulk2(client, {
|
|
3186
|
-
plaintexts:
|
|
3116
|
+
plaintexts: payloads,
|
|
3187
3117
|
serviceToken: context.data.ctsToken,
|
|
3188
3118
|
unverifiedContext: metadata
|
|
3189
3119
|
});
|
|
3190
|
-
return
|
|
3120
|
+
return encryptedData.map((data, i) => ({
|
|
3121
|
+
id: plaintexts[i].id,
|
|
3122
|
+
data
|
|
3123
|
+
}));
|
|
3191
3124
|
},
|
|
3192
3125
|
(error) => {
|
|
3193
3126
|
log.set({ errorCode: getErrorCode(error) ?? "unknown" });
|
|
@@ -3203,7 +3136,7 @@ var BulkEncryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
3203
3136
|
}
|
|
3204
3137
|
};
|
|
3205
3138
|
|
|
3206
|
-
// src/encryption/
|
|
3139
|
+
// src/encryption/operations/bulk-encrypt-models.ts
|
|
3207
3140
|
import { withResult as withResult5 } from "@byteslice/result";
|
|
3208
3141
|
var BulkEncryptModelsOperation = class extends EncryptionOperation {
|
|
3209
3142
|
client;
|
|
@@ -3312,7 +3245,7 @@ var BulkEncryptModelsOperationWithLockContext = class extends EncryptionOperatio
|
|
|
3312
3245
|
}
|
|
3313
3246
|
};
|
|
3314
3247
|
|
|
3315
|
-
// src/encryption/
|
|
3248
|
+
// src/encryption/operations/decrypt.ts
|
|
3316
3249
|
import { withResult as withResult6 } from "@byteslice/result";
|
|
3317
3250
|
import {
|
|
3318
3251
|
decrypt as ffiDecrypt
|
|
@@ -3339,9 +3272,6 @@ var DecryptOperation = class extends EncryptionOperation {
|
|
|
3339
3272
|
if (!this.client) {
|
|
3340
3273
|
throw noClientError();
|
|
3341
3274
|
}
|
|
3342
|
-
if (this.encryptedData === null) {
|
|
3343
|
-
return null;
|
|
3344
|
-
}
|
|
3345
3275
|
const { metadata } = this.getAuditData();
|
|
3346
3276
|
return await ffiDecrypt(this.client, {
|
|
3347
3277
|
ciphertext: this.encryptedData,
|
|
@@ -3392,9 +3322,6 @@ var DecryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
3392
3322
|
if (!client) {
|
|
3393
3323
|
throw noClientError();
|
|
3394
3324
|
}
|
|
3395
|
-
if (encryptedData === null) {
|
|
3396
|
-
return null;
|
|
3397
|
-
}
|
|
3398
3325
|
const { metadata } = this.getAuditData();
|
|
3399
3326
|
const context = await this.lockContext.getLockContext();
|
|
3400
3327
|
if (context.failure) {
|
|
@@ -3421,7 +3348,7 @@ var DecryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
3421
3348
|
}
|
|
3422
3349
|
};
|
|
3423
3350
|
|
|
3424
|
-
// src/encryption/
|
|
3351
|
+
// src/encryption/operations/decrypt-model.ts
|
|
3425
3352
|
import { withResult as withResult7 } from "@byteslice/result";
|
|
3426
3353
|
var DecryptModelOperation = class extends EncryptionOperation {
|
|
3427
3354
|
client;
|
|
@@ -3517,7 +3444,7 @@ var DecryptModelOperationWithLockContext = class extends EncryptionOperation {
|
|
|
3517
3444
|
}
|
|
3518
3445
|
};
|
|
3519
3446
|
|
|
3520
|
-
// src/encryption/
|
|
3447
|
+
// src/encryption/operations/encrypt.ts
|
|
3521
3448
|
import { withResult as withResult8 } from "@byteslice/result";
|
|
3522
3449
|
import {
|
|
3523
3450
|
encrypt as ffiEncrypt
|
|
@@ -3550,9 +3477,6 @@ var EncryptOperation = class extends EncryptionOperation {
|
|
|
3550
3477
|
if (!this.client) {
|
|
3551
3478
|
throw noClientError();
|
|
3552
3479
|
}
|
|
3553
|
-
if (this.plaintext === null) {
|
|
3554
|
-
return null;
|
|
3555
|
-
}
|
|
3556
3480
|
if (typeof this.plaintext === "number" && Number.isNaN(this.plaintext)) {
|
|
3557
3481
|
throw new Error("[encryption]: Cannot encrypt NaN value");
|
|
3558
3482
|
}
|
|
@@ -3614,9 +3538,6 @@ var EncryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
3614
3538
|
if (!client) {
|
|
3615
3539
|
throw noClientError();
|
|
3616
3540
|
}
|
|
3617
|
-
if (plaintext === null) {
|
|
3618
|
-
return null;
|
|
3619
|
-
}
|
|
3620
3541
|
const { metadata } = this.getAuditData();
|
|
3621
3542
|
const context = await this.lockContext.getLockContext();
|
|
3622
3543
|
if (context.failure) {
|
|
@@ -3645,7 +3566,7 @@ var EncryptOperationWithLockContext = class extends EncryptionOperation {
|
|
|
3645
3566
|
}
|
|
3646
3567
|
};
|
|
3647
3568
|
|
|
3648
|
-
// src/encryption/
|
|
3569
|
+
// src/encryption/operations/encrypt-model.ts
|
|
3649
3570
|
import { withResult as withResult9 } from "@byteslice/result";
|
|
3650
3571
|
var EncryptModelOperation = class extends EncryptionOperation {
|
|
3651
3572
|
client;
|
|
@@ -3752,7 +3673,7 @@ var EncryptModelOperationWithLockContext = class extends EncryptionOperation {
|
|
|
3752
3673
|
}
|
|
3753
3674
|
};
|
|
3754
3675
|
|
|
3755
|
-
// src/encryption/
|
|
3676
|
+
// src/encryption/operations/encrypt-query.ts
|
|
3756
3677
|
import { withResult as withResult10 } from "@byteslice/result";
|
|
3757
3678
|
import {
|
|
3758
3679
|
encryptQuery as ffiEncryptQuery
|
|
@@ -3782,10 +3703,6 @@ var EncryptQueryOperation = class extends EncryptionOperation {
|
|
|
3782
3703
|
queryType: this.opts.queryType,
|
|
3783
3704
|
lockContext: false
|
|
3784
3705
|
});
|
|
3785
|
-
if (this.plaintext === null || this.plaintext === void 0) {
|
|
3786
|
-
log.emit();
|
|
3787
|
-
return { data: null };
|
|
3788
|
-
}
|
|
3789
3706
|
const validationError = validateNumericValue(this.plaintext);
|
|
3790
3707
|
if (validationError?.failure) {
|
|
3791
3708
|
log.emit();
|
|
@@ -3849,10 +3766,6 @@ var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
|
|
|
3849
3766
|
queryType: this.opts.queryType,
|
|
3850
3767
|
lockContext: true
|
|
3851
3768
|
});
|
|
3852
|
-
if (this.plaintext === null || this.plaintext === void 0) {
|
|
3853
|
-
log.emit();
|
|
3854
|
-
return { data: null };
|
|
3855
|
-
}
|
|
3856
3769
|
const validationError = validateNumericValue(this.plaintext);
|
|
3857
3770
|
if (validationError?.failure) {
|
|
3858
3771
|
log.emit();
|
|
@@ -3904,9 +3817,9 @@ var EncryptQueryOperationWithLockContext = class extends EncryptionOperation {
|
|
|
3904
3817
|
}
|
|
3905
3818
|
};
|
|
3906
3819
|
|
|
3907
|
-
// src/encryption/
|
|
3820
|
+
// src/encryption/index.ts
|
|
3908
3821
|
var noClientError = () => new Error(
|
|
3909
|
-
"The
|
|
3822
|
+
"The Encryption client has not been initialized. Please call init() before using the client."
|
|
3910
3823
|
);
|
|
3911
3824
|
var EncryptionClient = class {
|
|
3912
3825
|
client;
|
|
@@ -3929,7 +3842,7 @@ var EncryptionClient = class {
|
|
|
3929
3842
|
config3.encryptConfig
|
|
3930
3843
|
);
|
|
3931
3844
|
logger.debug(
|
|
3932
|
-
"Initializing the
|
|
3845
|
+
"Initializing the Encryption client with the following config:",
|
|
3933
3846
|
{
|
|
3934
3847
|
encryptConfig: validated
|
|
3935
3848
|
}
|
|
@@ -3945,7 +3858,7 @@ var EncryptionClient = class {
|
|
|
3945
3858
|
}
|
|
3946
3859
|
});
|
|
3947
3860
|
this.encryptConfig = validated;
|
|
3948
|
-
logger.debug("Successfully initialized the
|
|
3861
|
+
logger.debug("Successfully initialized the Encryption client.");
|
|
3949
3862
|
return this;
|
|
3950
3863
|
},
|
|
3951
3864
|
(error) => ({
|
|
@@ -3957,8 +3870,8 @@ var EncryptionClient = class {
|
|
|
3957
3870
|
/**
|
|
3958
3871
|
* Encrypt a value - returns a promise which resolves to an encrypted value.
|
|
3959
3872
|
*
|
|
3960
|
-
* @param plaintext - The plaintext value to be encrypted.
|
|
3961
|
-
* @param opts - Options specifying the column and table for encryption.
|
|
3873
|
+
* @param plaintext - The plaintext value to be encrypted.
|
|
3874
|
+
* @param opts - Options specifying the column (or nested field) and table for encryption. See {@link EncryptOptions}.
|
|
3962
3875
|
* @returns An EncryptOperation that can be awaited or chained with additional methods.
|
|
3963
3876
|
*
|
|
3964
3877
|
* @example
|
|
@@ -4021,8 +3934,11 @@ var EncryptionClient = class {
|
|
|
4021
3934
|
* .withLockContext(lockContext)
|
|
4022
3935
|
* ```
|
|
4023
3936
|
*
|
|
3937
|
+
* @see {@link EncryptOptions}
|
|
4024
3938
|
* @see {@link Result}
|
|
4025
3939
|
* @see {@link encryptedTable}
|
|
3940
|
+
* @see {@link encryptedColumn}
|
|
3941
|
+
* @see {@link encryptedField}
|
|
4026
3942
|
* @see {@link LockContext}
|
|
4027
3943
|
* @see {@link EncryptOperation}
|
|
4028
3944
|
*/
|
|
@@ -4130,7 +4046,11 @@ var EncryptionClient = class {
|
|
|
4130
4046
|
* ```
|
|
4131
4047
|
*/
|
|
4132
4048
|
encryptModel(input, table) {
|
|
4133
|
-
return new EncryptModelOperation(
|
|
4049
|
+
return new EncryptModelOperation(
|
|
4050
|
+
this.client,
|
|
4051
|
+
input,
|
|
4052
|
+
table
|
|
4053
|
+
);
|
|
4134
4054
|
}
|
|
4135
4055
|
/**
|
|
4136
4056
|
* Decrypt a model (object) whose fields contain encrypted values.
|
|
@@ -4209,7 +4129,11 @@ var EncryptionClient = class {
|
|
|
4209
4129
|
* ```
|
|
4210
4130
|
*/
|
|
4211
4131
|
bulkEncryptModels(input, table) {
|
|
4212
|
-
return new BulkEncryptModelsOperation(
|
|
4132
|
+
return new BulkEncryptModelsOperation(
|
|
4133
|
+
this.client,
|
|
4134
|
+
input,
|
|
4135
|
+
table
|
|
4136
|
+
);
|
|
4213
4137
|
}
|
|
4214
4138
|
/**
|
|
4215
4139
|
* Decrypt multiple models (objects) in a single bulk operation.
|
|
@@ -4247,10 +4171,10 @@ var EncryptionClient = class {
|
|
|
4247
4171
|
*
|
|
4248
4172
|
* Each value is encrypted with its own unique key via a single call to ZeroKMS.
|
|
4249
4173
|
* Values can include optional `id` fields for correlating results back to
|
|
4250
|
-
* your application data.
|
|
4174
|
+
* your application data.
|
|
4251
4175
|
*
|
|
4252
4176
|
* @param plaintexts - An array of objects with `plaintext` (and optional `id`) fields.
|
|
4253
|
-
* @param opts - Options specifying the target column and table
|
|
4177
|
+
* @param opts - Options specifying the target column (or nested {@link encryptedField}) and table. See {@link EncryptOptions}.
|
|
4254
4178
|
* @returns A `BulkEncryptOperation` that can be awaited to get a `Result`
|
|
4255
4179
|
* containing an array of `{ id?, data: Encrypted }` objects, or an `EncryptionError`.
|
|
4256
4180
|
*
|
|
@@ -4268,7 +4192,6 @@ var EncryptionClient = class {
|
|
|
4268
4192
|
* [
|
|
4269
4193
|
* { id: "u1", plaintext: "alice@example.com" },
|
|
4270
4194
|
* { id: "u2", plaintext: "bob@example.com" },
|
|
4271
|
-
* { id: "u3", plaintext: null },
|
|
4272
4195
|
* ],
|
|
4273
4196
|
* { column: users.email, table: users },
|
|
4274
4197
|
* )
|