@cipherstash/stack 0.10.0 → 0.11.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/dist/bin/stash.js +49 -103
- package/dist/bin/stash.js.map +1 -1
- package/dist/{chunk-HCL75LXQ.js → chunk-46PDK2Z6.js} +1 -1
- package/dist/chunk-46PDK2Z6.js.map +1 -0
- package/dist/{chunk-3BOJHROP.js → chunk-EHDOOLWU.js} +3 -3
- package/dist/{chunk-Y3KSTOVR.js → chunk-GNLU3I27.js} +14 -3
- package/dist/chunk-GNLU3I27.js.map +1 -0
- package/dist/{chunk-4C52Q5R6.js → chunk-O4MBO4DJ.js} +8 -22
- package/dist/chunk-O4MBO4DJ.js.map +1 -0
- package/dist/{client-_63nbmO7.d.ts → client-CZLBiToT.d.ts} +1 -7
- package/dist/{client-CV7X5Hrt.d.cts → client-bW-5wG9Y.d.cts} +1 -7
- package/dist/client.cjs +13 -2
- 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 +13 -2
- 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/encryption/index.cjs +22 -96
- package/dist/encryption/index.cjs.map +1 -1
- package/dist/encryption/index.d.cts +2 -2
- package/dist/encryption/index.d.ts +2 -2
- package/dist/encryption/index.js +3 -4
- package/dist/index.cjs +29 -81
- 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 +13 -2
- 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 +29 -81
- 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 +12 -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 +1 -1
- package/dist/{types-public-B5YxQhR6.d.cts → types-public-WADaA-TW.d.cts} +119 -1
- package/dist/{types-public-B5YxQhR6.d.ts → types-public-WADaA-TW.d.ts} +119 -1
- 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-4C52Q5R6.js.map +0 -1
- package/dist/chunk-HCL75LXQ.js.map +0 -1
- package/dist/chunk-Y3KSTOVR.js.map +0 -1
- /package/dist/{chunk-3BOJHROP.js.map → chunk-EHDOOLWU.js.map} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @cipherstash/stack
|
|
2
2
|
|
|
3
|
+
## 0.11.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- b0e56b8: Upgrade protect-ffi to 0.21.0 and enable array_index_mode for searchable JSON
|
|
8
|
+
|
|
9
|
+
- Upgrade `@cipherstash/protect-ffi` to 0.21.0 across all packages
|
|
10
|
+
- Enable `array_index_mode: 'all'` on STE vec indexes so JSON array operations
|
|
11
|
+
(jsonb_array_elements, jsonb_array_length, array containment) work correctly
|
|
12
|
+
- Delegate credential resolution entirely to protect-ffi's `withEnvCredentials`
|
|
13
|
+
- Download latest EQL at build/runtime instead of bundling hardcoded SQL files
|
|
14
|
+
|
|
3
15
|
## 0.10.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/dist/bin/stash.js
CHANGED
|
@@ -104,8 +104,8 @@ var require_package = __commonJS({
|
|
|
104
104
|
var require_main = __commonJS({
|
|
105
105
|
"../../node_modules/.pnpm/dotenv@16.4.7/node_modules/dotenv/lib/main.js"(exports, module) {
|
|
106
106
|
"use strict";
|
|
107
|
-
var
|
|
108
|
-
var
|
|
107
|
+
var fs = __require("fs");
|
|
108
|
+
var path = __require("path");
|
|
109
109
|
var os = __require("os");
|
|
110
110
|
var crypto = __require("crypto");
|
|
111
111
|
var packageJson = require_package();
|
|
@@ -211,7 +211,7 @@ var require_main = __commonJS({
|
|
|
211
211
|
if (options && options.path && options.path.length > 0) {
|
|
212
212
|
if (Array.isArray(options.path)) {
|
|
213
213
|
for (const filepath of options.path) {
|
|
214
|
-
if (
|
|
214
|
+
if (fs.existsSync(filepath)) {
|
|
215
215
|
possibleVaultPath = filepath.endsWith(".vault") ? filepath : `${filepath}.vault`;
|
|
216
216
|
}
|
|
217
217
|
}
|
|
@@ -219,15 +219,15 @@ var require_main = __commonJS({
|
|
|
219
219
|
possibleVaultPath = options.path.endsWith(".vault") ? options.path : `${options.path}.vault`;
|
|
220
220
|
}
|
|
221
221
|
} else {
|
|
222
|
-
possibleVaultPath =
|
|
222
|
+
possibleVaultPath = path.resolve(process.cwd(), ".env.vault");
|
|
223
223
|
}
|
|
224
|
-
if (
|
|
224
|
+
if (fs.existsSync(possibleVaultPath)) {
|
|
225
225
|
return possibleVaultPath;
|
|
226
226
|
}
|
|
227
227
|
return null;
|
|
228
228
|
}
|
|
229
229
|
function _resolveHome(envPath) {
|
|
230
|
-
return envPath[0] === "~" ?
|
|
230
|
+
return envPath[0] === "~" ? path.join(os.homedir(), envPath.slice(1)) : envPath;
|
|
231
231
|
}
|
|
232
232
|
function _configVault(options) {
|
|
233
233
|
_log("Loading env from encrypted .env.vault");
|
|
@@ -240,7 +240,7 @@ var require_main = __commonJS({
|
|
|
240
240
|
return { parsed };
|
|
241
241
|
}
|
|
242
242
|
function configDotenv(options) {
|
|
243
|
-
const dotenvPath =
|
|
243
|
+
const dotenvPath = path.resolve(process.cwd(), ".env");
|
|
244
244
|
let encoding = "utf8";
|
|
245
245
|
const debug = Boolean(options && options.debug);
|
|
246
246
|
if (options && options.encoding) {
|
|
@@ -263,13 +263,13 @@ var require_main = __commonJS({
|
|
|
263
263
|
}
|
|
264
264
|
let lastError;
|
|
265
265
|
const parsedAll = {};
|
|
266
|
-
for (const
|
|
266
|
+
for (const path2 of optionPaths) {
|
|
267
267
|
try {
|
|
268
|
-
const parsed = DotenvModule.parse(
|
|
268
|
+
const parsed = DotenvModule.parse(fs.readFileSync(path2, { encoding }));
|
|
269
269
|
DotenvModule.populate(parsedAll, parsed, options);
|
|
270
270
|
} catch (e2) {
|
|
271
271
|
if (debug) {
|
|
272
|
-
_debug(`Failed to load ${
|
|
272
|
+
_debug(`Failed to load ${path2} ${e2.message}`);
|
|
273
273
|
}
|
|
274
274
|
lastError = e2;
|
|
275
275
|
}
|
|
@@ -1768,8 +1768,18 @@ var matchIndexOptsSchema = z2.object({
|
|
|
1768
1768
|
m: z2.number().default(2048).optional(),
|
|
1769
1769
|
include_original: z2.boolean().default(false).optional()
|
|
1770
1770
|
});
|
|
1771
|
+
var arrayIndexModeSchema = z2.union([
|
|
1772
|
+
z2.literal("all"),
|
|
1773
|
+
z2.literal("none"),
|
|
1774
|
+
z2.object({
|
|
1775
|
+
item: z2.boolean().optional(),
|
|
1776
|
+
wildcard: z2.boolean().optional(),
|
|
1777
|
+
position: z2.boolean().optional()
|
|
1778
|
+
})
|
|
1779
|
+
]);
|
|
1771
1780
|
var steVecIndexOptsSchema = z2.object({
|
|
1772
|
-
prefix: z2.string()
|
|
1781
|
+
prefix: z2.string(),
|
|
1782
|
+
array_index_mode: arrayIndexModeSchema.optional()
|
|
1773
1783
|
});
|
|
1774
1784
|
var indexesSchema = z2.object({
|
|
1775
1785
|
ore: oreIndexOptsSchema.optional(),
|
|
@@ -1966,7 +1976,7 @@ var EncryptedColumn = class {
|
|
|
1966
1976
|
*/
|
|
1967
1977
|
searchableJson() {
|
|
1968
1978
|
this.castAsValue = "json";
|
|
1969
|
-
this.indexesValue.ste_vec = { prefix: "enabled" };
|
|
1979
|
+
this.indexesValue.ste_vec = { prefix: "enabled", array_index_mode: "all" };
|
|
1970
1980
|
return this;
|
|
1971
1981
|
}
|
|
1972
1982
|
build() {
|
|
@@ -2014,6 +2024,7 @@ var EncryptedTable = class {
|
|
|
2014
2024
|
indexes: {
|
|
2015
2025
|
...builtColumn.indexes,
|
|
2016
2026
|
ste_vec: {
|
|
2027
|
+
...builtColumn.indexes.ste_vec,
|
|
2017
2028
|
prefix: `${this.tableName}/${colName}`
|
|
2018
2029
|
}
|
|
2019
2030
|
}
|
|
@@ -2075,69 +2086,6 @@ var EncryptionErrorTypes = {
|
|
|
2075
2086
|
CtsTokenError: "CtsTokenError"
|
|
2076
2087
|
};
|
|
2077
2088
|
|
|
2078
|
-
// src/utils/config/index.ts
|
|
2079
|
-
import fs from "node:fs";
|
|
2080
|
-
import path from "node:path";
|
|
2081
|
-
function getWorkspaceCrn(tomlString) {
|
|
2082
|
-
let currentSection = "";
|
|
2083
|
-
let workspaceCrn;
|
|
2084
|
-
const lines = tomlString.split(/\r?\n/);
|
|
2085
|
-
for (const line of lines) {
|
|
2086
|
-
const trimmedLine = line.trim();
|
|
2087
|
-
if (!trimmedLine || trimmedLine.startsWith("#")) {
|
|
2088
|
-
continue;
|
|
2089
|
-
}
|
|
2090
|
-
const sectionMatch = trimmedLine.match(/^\[([^\]]+)\]$/);
|
|
2091
|
-
if (sectionMatch) {
|
|
2092
|
-
currentSection = sectionMatch[1];
|
|
2093
|
-
continue;
|
|
2094
|
-
}
|
|
2095
|
-
const kvMatch = trimmedLine.match(/^(\w+)\s*=\s*"([^"]+)"$/);
|
|
2096
|
-
if (kvMatch) {
|
|
2097
|
-
const [_3, key, value] = kvMatch;
|
|
2098
|
-
if (currentSection === "auth" && key === "workspace_crn") {
|
|
2099
|
-
workspaceCrn = value;
|
|
2100
|
-
break;
|
|
2101
|
-
}
|
|
2102
|
-
}
|
|
2103
|
-
}
|
|
2104
|
-
return workspaceCrn;
|
|
2105
|
-
}
|
|
2106
|
-
function extractWorkspaceIdFromCrn(crn) {
|
|
2107
|
-
const match = crn.match(/crn:[^:]+:([^:]+)$/);
|
|
2108
|
-
if (!match) {
|
|
2109
|
-
throw new Error("Invalid CRN format");
|
|
2110
|
-
}
|
|
2111
|
-
return match[1];
|
|
2112
|
-
}
|
|
2113
|
-
function loadWorkSpaceId(suppliedCrn) {
|
|
2114
|
-
const configPath = path.join(process.cwd(), "cipherstash.toml");
|
|
2115
|
-
if (suppliedCrn) {
|
|
2116
|
-
return extractWorkspaceIdFromCrn(suppliedCrn);
|
|
2117
|
-
}
|
|
2118
|
-
if (!fs.existsSync(configPath) && !process.env.CS_WORKSPACE_CRN) {
|
|
2119
|
-
throw new Error(
|
|
2120
|
-
"You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable."
|
|
2121
|
-
);
|
|
2122
|
-
}
|
|
2123
|
-
if (process.env.CS_WORKSPACE_CRN) {
|
|
2124
|
-
return extractWorkspaceIdFromCrn(process.env.CS_WORKSPACE_CRN);
|
|
2125
|
-
}
|
|
2126
|
-
if (!fs.existsSync(configPath)) {
|
|
2127
|
-
throw new Error(
|
|
2128
|
-
"You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable."
|
|
2129
|
-
);
|
|
2130
|
-
}
|
|
2131
|
-
const tomlString = fs.readFileSync(configPath, "utf8");
|
|
2132
|
-
const workspaceCrn = getWorkspaceCrn(tomlString);
|
|
2133
|
-
if (!workspaceCrn) {
|
|
2134
|
-
throw new Error(
|
|
2135
|
-
"You have not defined a workspace CRN in your config file, or the CS_WORKSPACE_CRN environment variable."
|
|
2136
|
-
);
|
|
2137
|
-
}
|
|
2138
|
-
return extractWorkspaceIdFromCrn(workspaceCrn);
|
|
2139
|
-
}
|
|
2140
|
-
|
|
2141
2089
|
// src/utils/logger/index.ts
|
|
2142
2090
|
import { createRequestLogger, initLogger } from "evlog";
|
|
2143
2091
|
var validLevels = ["debug", "info", "error"];
|
|
@@ -2631,11 +2579,11 @@ import {
|
|
|
2631
2579
|
decryptBulk,
|
|
2632
2580
|
encryptBulk
|
|
2633
2581
|
} from "@cipherstash/protect-ffi";
|
|
2634
|
-
function setNestedValue(obj,
|
|
2582
|
+
function setNestedValue(obj, path, value) {
|
|
2635
2583
|
const FORBIDDEN_KEYS = ["__proto__", "prototype", "constructor"];
|
|
2636
2584
|
let current = obj;
|
|
2637
|
-
for (let i = 0; i <
|
|
2638
|
-
const part =
|
|
2585
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
2586
|
+
const part = path[i];
|
|
2639
2587
|
if (FORBIDDEN_KEYS.includes(part)) {
|
|
2640
2588
|
throw new Error(`[encryption]: Forbidden key "${part}" in field path`);
|
|
2641
2589
|
}
|
|
@@ -2644,7 +2592,7 @@ function setNestedValue(obj, path2, value) {
|
|
|
2644
2592
|
}
|
|
2645
2593
|
current = current[part];
|
|
2646
2594
|
}
|
|
2647
|
-
const lastKey =
|
|
2595
|
+
const lastKey = path[path.length - 1];
|
|
2648
2596
|
if (FORBIDDEN_KEYS.includes(lastKey)) {
|
|
2649
2597
|
throw new Error(`[encryption]: Forbidden key "${lastKey}" in field path`);
|
|
2650
2598
|
}
|
|
@@ -2721,7 +2669,7 @@ function prepareFieldsForEncryption(model, table) {
|
|
|
2721
2669
|
continue;
|
|
2722
2670
|
}
|
|
2723
2671
|
if (typeof value === "object" && !isEncryptedPayload(value) && !columnPaths2.includes(fullKey)) {
|
|
2724
|
-
if (columnPaths2.some((
|
|
2672
|
+
if (columnPaths2.some((path) => path.startsWith(fullKey))) {
|
|
2725
2673
|
processNestedFields(
|
|
2726
2674
|
value,
|
|
2727
2675
|
fullKey,
|
|
@@ -2899,7 +2847,7 @@ function prepareBulkModelsForOperation(models, table) {
|
|
|
2899
2847
|
continue;
|
|
2900
2848
|
}
|
|
2901
2849
|
if (typeof value === "object" && !isEncryptedPayload(value) && !columnPaths.includes(fullKey)) {
|
|
2902
|
-
if (columnPaths.some((
|
|
2850
|
+
if (columnPaths.some((path) => path.startsWith(fullKey))) {
|
|
2903
2851
|
processNestedFields(
|
|
2904
2852
|
value,
|
|
2905
2853
|
fullKey,
|
|
@@ -4074,11 +4022,6 @@ var noClientError = () => new Error(
|
|
|
4074
4022
|
var EncryptionClient = class {
|
|
4075
4023
|
client;
|
|
4076
4024
|
encryptConfig;
|
|
4077
|
-
workspaceId;
|
|
4078
|
-
constructor(workspaceCrn) {
|
|
4079
|
-
const workspaceId = loadWorkSpaceId(workspaceCrn);
|
|
4080
|
-
this.workspaceId = workspaceId;
|
|
4081
|
-
}
|
|
4082
4025
|
/**
|
|
4083
4026
|
* Initializes the EncryptionClient with the provided configuration.
|
|
4084
4027
|
* @internal
|
|
@@ -4100,10 +4043,10 @@ var EncryptionClient = class {
|
|
|
4100
4043
|
this.client = await newClient({
|
|
4101
4044
|
encryptConfig: validated,
|
|
4102
4045
|
clientOpts: {
|
|
4103
|
-
workspaceCrn: config3.workspaceCrn
|
|
4104
|
-
accessKey: config3.accessKey
|
|
4105
|
-
clientId: config3.clientId
|
|
4106
|
-
clientKey: config3.clientKey
|
|
4046
|
+
workspaceCrn: config3.workspaceCrn,
|
|
4047
|
+
accessKey: config3.accessKey,
|
|
4048
|
+
clientId: config3.clientId,
|
|
4049
|
+
clientKey: config3.clientKey,
|
|
4107
4050
|
keyset: toFfiKeysetIdentifier(config3.keyset)
|
|
4108
4051
|
}
|
|
4109
4052
|
});
|
|
@@ -4488,12 +4431,6 @@ var EncryptionClient = class {
|
|
|
4488
4431
|
bulkDecrypt(encryptedPayloads) {
|
|
4489
4432
|
return new BulkDecryptOperation(this.client, encryptedPayloads);
|
|
4490
4433
|
}
|
|
4491
|
-
/** e.g., debugging or environment info */
|
|
4492
|
-
clientInfo() {
|
|
4493
|
-
return {
|
|
4494
|
-
workspaceId: this.workspaceId
|
|
4495
|
-
};
|
|
4496
|
-
}
|
|
4497
4434
|
/**
|
|
4498
4435
|
* Get the encrypt config object.
|
|
4499
4436
|
*
|
|
@@ -4515,7 +4452,7 @@ var Encryption = async (config3) => {
|
|
|
4515
4452
|
"[encryption]: Invalid UUID provided for keyset id. Must be a valid UUID."
|
|
4516
4453
|
);
|
|
4517
4454
|
}
|
|
4518
|
-
const client = new EncryptionClient(
|
|
4455
|
+
const client = new EncryptionClient();
|
|
4519
4456
|
const encryptConfig = buildEncryptConfig(...schemas);
|
|
4520
4457
|
const result = await client.init({
|
|
4521
4458
|
encryptConfig,
|
|
@@ -4527,6 +4464,15 @@ var Encryption = async (config3) => {
|
|
|
4527
4464
|
return result.data;
|
|
4528
4465
|
};
|
|
4529
4466
|
|
|
4467
|
+
// src/utils/config/index.ts
|
|
4468
|
+
function extractWorkspaceIdFromCrn(crn) {
|
|
4469
|
+
const match = crn.match(/crn:[^:]+:([^:]+)$/);
|
|
4470
|
+
if (!match) {
|
|
4471
|
+
throw new Error("Invalid CRN format");
|
|
4472
|
+
}
|
|
4473
|
+
return match[1];
|
|
4474
|
+
}
|
|
4475
|
+
|
|
4530
4476
|
// src/secrets/index.ts
|
|
4531
4477
|
var Secrets = class {
|
|
4532
4478
|
encryptionClient = null;
|
|
@@ -4589,14 +4535,14 @@ var Secrets = class {
|
|
|
4589
4535
|
* For GET requests, `params` are appended as URL query parameters.
|
|
4590
4536
|
* For POST requests, `body` is sent as JSON in the request body.
|
|
4591
4537
|
*/
|
|
4592
|
-
async apiRequest(method,
|
|
4538
|
+
async apiRequest(method, path, options) {
|
|
4593
4539
|
try {
|
|
4594
|
-
let url = `${this.apiBaseUrl}${
|
|
4540
|
+
let url = `${this.apiBaseUrl}${path}`;
|
|
4595
4541
|
if (options?.params) {
|
|
4596
4542
|
const searchParams = new URLSearchParams(options.params);
|
|
4597
4543
|
url = `${url}?${searchParams.toString()}`;
|
|
4598
4544
|
}
|
|
4599
|
-
logger.debug(`Secrets API request: ${method} ${
|
|
4545
|
+
logger.debug(`Secrets API request: ${method} ${path}`);
|
|
4600
4546
|
const headers = {
|
|
4601
4547
|
"Content-Type": "application/json",
|
|
4602
4548
|
Authorization: this.getAuthHeader()
|
|
@@ -4615,7 +4561,7 @@ var Secrets = class {
|
|
|
4615
4561
|
} catch {
|
|
4616
4562
|
errorMessage = errorText || errorMessage;
|
|
4617
4563
|
}
|
|
4618
|
-
logger.error(`Secrets API error on ${method} ${
|
|
4564
|
+
logger.error(`Secrets API error on ${method} ${path}: ${errorMessage}`);
|
|
4619
4565
|
return {
|
|
4620
4566
|
failure: {
|
|
4621
4567
|
type: "ApiError",
|
|
@@ -4623,12 +4569,12 @@ var Secrets = class {
|
|
|
4623
4569
|
}
|
|
4624
4570
|
};
|
|
4625
4571
|
}
|
|
4626
|
-
logger.debug(`Secrets API request successful: ${method} ${
|
|
4572
|
+
logger.debug(`Secrets API request successful: ${method} ${path}`);
|
|
4627
4573
|
const data = await response.json();
|
|
4628
4574
|
return { data };
|
|
4629
4575
|
} catch (error) {
|
|
4630
4576
|
const message = error instanceof Error ? error.message : "Unknown network error occurred";
|
|
4631
|
-
logger.error(`Secrets network error on ${method} ${
|
|
4577
|
+
logger.error(`Secrets network error on ${method} ${path}: ${message}`);
|
|
4632
4578
|
return {
|
|
4633
4579
|
failure: {
|
|
4634
4580
|
type: "NetworkError",
|