@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.
Files changed (60) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/bin/stash.js +49 -103
  3. package/dist/bin/stash.js.map +1 -1
  4. package/dist/{chunk-HCL75LXQ.js → chunk-46PDK2Z6.js} +1 -1
  5. package/dist/chunk-46PDK2Z6.js.map +1 -0
  6. package/dist/{chunk-3BOJHROP.js → chunk-EHDOOLWU.js} +3 -3
  7. package/dist/{chunk-Y3KSTOVR.js → chunk-GNLU3I27.js} +14 -3
  8. package/dist/chunk-GNLU3I27.js.map +1 -0
  9. package/dist/{chunk-4C52Q5R6.js → chunk-O4MBO4DJ.js} +8 -22
  10. package/dist/chunk-O4MBO4DJ.js.map +1 -0
  11. package/dist/{client-_63nbmO7.d.ts → client-CZLBiToT.d.ts} +1 -7
  12. package/dist/{client-CV7X5Hrt.d.cts → client-bW-5wG9Y.d.cts} +1 -7
  13. package/dist/client.cjs +13 -2
  14. package/dist/client.cjs.map +1 -1
  15. package/dist/client.d.cts +2 -2
  16. package/dist/client.d.ts +2 -2
  17. package/dist/client.js +1 -1
  18. package/dist/drizzle/index.cjs +13 -2
  19. package/dist/drizzle/index.cjs.map +1 -1
  20. package/dist/drizzle/index.d.cts +2 -2
  21. package/dist/drizzle/index.d.ts +2 -2
  22. package/dist/drizzle/index.js +2 -2
  23. package/dist/dynamodb/index.d.cts +2 -2
  24. package/dist/dynamodb/index.d.ts +2 -2
  25. package/dist/encryption/index.cjs +22 -96
  26. package/dist/encryption/index.cjs.map +1 -1
  27. package/dist/encryption/index.d.cts +2 -2
  28. package/dist/encryption/index.d.ts +2 -2
  29. package/dist/encryption/index.js +3 -4
  30. package/dist/index.cjs +29 -81
  31. package/dist/index.cjs.map +1 -1
  32. package/dist/index.d.cts +3 -3
  33. package/dist/index.d.ts +3 -3
  34. package/dist/index.js +4 -4
  35. package/dist/schema/index.cjs +13 -2
  36. package/dist/schema/index.cjs.map +1 -1
  37. package/dist/schema/index.d.cts +1 -1
  38. package/dist/schema/index.d.ts +1 -1
  39. package/dist/schema/index.js +1 -1
  40. package/dist/secrets/index.cjs +29 -81
  41. package/dist/secrets/index.cjs.map +1 -1
  42. package/dist/secrets/index.d.cts +1 -1
  43. package/dist/secrets/index.d.ts +1 -1
  44. package/dist/secrets/index.js +4 -4
  45. package/dist/supabase/index.cjs +12 -2
  46. package/dist/supabase/index.cjs.map +1 -1
  47. package/dist/supabase/index.d.cts +2 -2
  48. package/dist/supabase/index.d.ts +2 -2
  49. package/dist/supabase/index.js +1 -1
  50. package/dist/{types-public-B5YxQhR6.d.cts → types-public-WADaA-TW.d.cts} +119 -1
  51. package/dist/{types-public-B5YxQhR6.d.ts → types-public-WADaA-TW.d.ts} +119 -1
  52. package/dist/types-public.cjs.map +1 -1
  53. package/dist/types-public.d.cts +1 -1
  54. package/dist/types-public.d.ts +1 -1
  55. package/dist/types-public.js +1 -1
  56. package/package.json +2 -2
  57. package/dist/chunk-4C52Q5R6.js.map +0 -1
  58. package/dist/chunk-HCL75LXQ.js.map +0 -1
  59. package/dist/chunk-Y3KSTOVR.js.map +0 -1
  60. /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 fs2 = __require("fs");
108
- var path2 = __require("path");
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 (fs2.existsSync(filepath)) {
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 = path2.resolve(process.cwd(), ".env.vault");
222
+ possibleVaultPath = path.resolve(process.cwd(), ".env.vault");
223
223
  }
224
- if (fs2.existsSync(possibleVaultPath)) {
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] === "~" ? path2.join(os.homedir(), envPath.slice(1)) : envPath;
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 = path2.resolve(process.cwd(), ".env");
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 path3 of optionPaths) {
266
+ for (const path2 of optionPaths) {
267
267
  try {
268
- const parsed = DotenvModule.parse(fs2.readFileSync(path3, { encoding }));
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 ${path3} ${e2.message}`);
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, path2, value) {
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 < path2.length - 1; i++) {
2638
- const part = path2[i];
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 = path2[path2.length - 1];
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((path2) => path2.startsWith(fullKey))) {
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((path2) => path2.startsWith(fullKey))) {
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 ?? process.env.CS_WORKSPACE_CRN,
4104
- accessKey: config3.accessKey ?? process.env.CS_CLIENT_ACCESS_KEY,
4105
- clientId: config3.clientId ?? process.env.CS_CLIENT_ID,
4106
- clientKey: config3.clientKey ?? process.env.CS_CLIENT_KEY,
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(clientConfig?.workspaceCrn);
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, path2, options) {
4538
+ async apiRequest(method, path, options) {
4593
4539
  try {
4594
- let url = `${this.apiBaseUrl}${path2}`;
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} ${path2}`);
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} ${path2}: ${errorMessage}`);
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} ${path2}`);
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} ${path2}: ${message}`);
4577
+ logger.error(`Secrets network error on ${method} ${path}: ${message}`);
4632
4578
  return {
4633
4579
  failure: {
4634
4580
  type: "NetworkError",