@cipherstash/stack 0.4.0 → 0.5.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 +13 -0
- package/README.md +9 -36
- package/dist/bin/stash.js +215 -179
- package/dist/bin/stash.js.map +1 -1
- package/dist/{chunk-OAPLZLR5.js → chunk-GXGEW6T4.js} +2 -76
- package/dist/chunk-GXGEW6T4.js.map +1 -0
- package/dist/{chunk-KOU2MHXJ.js → chunk-HCL75LXQ.js} +1 -1
- package/dist/chunk-HCL75LXQ.js.map +1 -0
- package/dist/chunk-LBMC4D6D.js +19 -0
- package/dist/chunk-LBMC4D6D.js.map +1 -0
- package/dist/chunk-Q5FTQLYG.js +68 -0
- package/dist/chunk-Q5FTQLYG.js.map +1 -0
- package/dist/{chunk-WUZGKTMG.js → chunk-TGUELLJS.js} +16 -19
- package/dist/chunk-TGUELLJS.js.map +1 -0
- package/dist/chunk-YLISU7FD.js +357 -0
- package/dist/chunk-YLISU7FD.js.map +1 -0
- package/dist/{client-CUGXheRq.d.cts → client-BFrHTgC6.d.ts} +36 -3
- package/dist/{client-CrGQnSlk.d.ts → client-BVQvgvdY.d.cts} +36 -3
- package/dist/client.d.cts +4 -4
- package/dist/client.d.ts +4 -4
- package/dist/drizzle/index.cjs.map +1 -1
- package/dist/drizzle/index.d.cts +14 -6
- package/dist/drizzle/index.d.ts +14 -6
- package/dist/drizzle/index.js +3 -3
- package/dist/drizzle/index.js.map +1 -1
- package/dist/dynamodb/index.cjs +68 -0
- package/dist/dynamodb/index.cjs.map +1 -1
- package/dist/dynamodb/index.d.cts +4 -4
- package/dist/dynamodb/index.d.ts +4 -4
- package/dist/dynamodb/index.js +9 -0
- package/dist/dynamodb/index.js.map +1 -1
- package/dist/encryption/index.cjs +2572 -0
- package/dist/encryption/index.cjs.map +1 -0
- package/dist/encryption/index.d.cts +7 -0
- package/dist/encryption/index.d.ts +7 -0
- package/dist/encryption/index.js +17 -0
- package/dist/encryption/index.js.map +1 -0
- package/dist/errors/index.cjs +44 -0
- package/dist/errors/index.cjs.map +1 -0
- package/dist/errors/index.d.cts +94 -0
- package/dist/errors/index.d.ts +94 -0
- package/dist/errors/index.js +9 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/identity/index.cjs +21 -13
- package/dist/identity/index.cjs.map +1 -1
- package/dist/identity/index.d.cts +78 -2
- package/dist/identity/index.d.ts +78 -2
- package/dist/identity/index.js +7 -3
- package/dist/identity/index.js.map +1 -1
- package/dist/index.cjs +379 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -19
- package/dist/index.d.ts +21 -19
- package/dist/index.js +14 -8
- package/dist/schema/index.d.cts +1 -2
- package/dist/schema/index.d.ts +1 -2
- package/dist/secrets/index.cjs +70 -39
- package/dist/secrets/index.cjs.map +1 -1
- package/dist/secrets/index.d.cts +4 -6
- package/dist/secrets/index.d.ts +4 -6
- package/dist/secrets/index.js +9 -318
- package/dist/secrets/index.js.map +1 -1
- package/dist/supabase/index.cjs +84 -1
- package/dist/supabase/index.cjs.map +1 -1
- package/dist/supabase/index.d.cts +4 -4
- package/dist/supabase/index.d.ts +4 -4
- package/dist/supabase/index.js +24 -1
- package/dist/supabase/index.js.map +1 -1
- package/dist/{types-public-Wj6tB_ux.d.ts → types-public-dKxDzTIL.d.cts} +1 -9
- package/dist/{types-public-Wj6tB_ux.d.cts → types-public-dKxDzTIL.d.ts} +1 -9
- package/dist/types-public.cjs.map +1 -1
- package/dist/types-public.d.cts +1 -2
- package/dist/types-public.d.ts +1 -2
- package/dist/types-public.js +1 -1
- package/package.json +29 -1
- package/dist/chunk-KOU2MHXJ.js.map +0 -1
- package/dist/chunk-OAPLZLR5.js.map +0 -1
- package/dist/chunk-WUZGKTMG.js.map +0 -1
- package/dist/index-9-Ya3fDK.d.cts +0 -169
- package/dist/index-9-Ya3fDK.d.ts +0 -169
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# @cipherstash/stack
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- a645115: ### Documentation
|
|
8
|
+
|
|
9
|
+
- **TypeDoc**: Improved JSDoc for `Encryption()`, `EncryptOptions`, schema builders (`encryptedTable`, `encryptedColumn`, `encryptedField`, `EncryptedField`, `EncryptedTableColumn`), and `encrypt` / `bulkEncrypt` with clearer `@param`, `@returns`, `@throws`, `@example`, and `@see` links.
|
|
10
|
+
- **README**: Refreshed main repo README and Stack package readme; basic example README now uses `npm install @cipherstash/stack`, CipherStash account and dashboard credentials, and drops Stash CLI references. Added docs badge linking to cipherstash.com/docs.
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
- **Logging**: Logger is now used consistently across Stack client interfaces for initialization and operations.
|
|
15
|
+
|
|
3
16
|
## 0.4.0
|
|
4
17
|
|
|
5
18
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -502,48 +502,21 @@ const client2 = await Encryption({
|
|
|
502
502
|
|
|
503
503
|
### Logging
|
|
504
504
|
|
|
505
|
-
The SDK uses
|
|
505
|
+
The SDK uses structured logging across all interfaces (Encryption, Secrets, Supabase, DynamoDB). Each operation emits a single wide event with context such as the operation type, table, column, lock context status, and duration.
|
|
506
506
|
|
|
507
|
-
|
|
507
|
+
Configure the log level with the `STASH_STACK_LOG` environment variable:
|
|
508
508
|
|
|
509
509
|
```bash
|
|
510
|
-
|
|
510
|
+
STASH_STACK_LOG=error # debug | info | error (default: error)
|
|
511
511
|
```
|
|
512
512
|
|
|
513
|
-
|
|
513
|
+
| Value | What is logged |
|
|
514
|
+
| ------- | ---------------------- |
|
|
515
|
+
| `error` | Errors only (default) |
|
|
516
|
+
| `info` | Info and errors |
|
|
517
|
+
| `debug` | Debug, info, and errors |
|
|
514
518
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
```typescript
|
|
518
|
-
const client = await Encryption({
|
|
519
|
-
schemas: [users],
|
|
520
|
-
logging: {
|
|
521
|
-
enabled: true, // toggle logging on/off (default: true)
|
|
522
|
-
pretty: true, // pretty-print in development (default: auto-detected)
|
|
523
|
-
},
|
|
524
|
-
})
|
|
525
|
-
```
|
|
526
|
-
|
|
527
|
-
#### Log draining
|
|
528
|
-
|
|
529
|
-
Send structured logs to an external observability platform by providing a `drain` callback:
|
|
530
|
-
|
|
531
|
-
```typescript
|
|
532
|
-
import { Encryption } from "@cipherstash/stack"
|
|
533
|
-
|
|
534
|
-
const client = await Encryption({
|
|
535
|
-
schemas: [users],
|
|
536
|
-
logging: {
|
|
537
|
-
drain: (ctx) => {
|
|
538
|
-
// Forward to Axiom, Datadog, OTLP, etc.
|
|
539
|
-
fetch("https://your-service.com/logs", {
|
|
540
|
-
method: "POST",
|
|
541
|
-
body: JSON.stringify(ctx.event),
|
|
542
|
-
})
|
|
543
|
-
},
|
|
544
|
-
},
|
|
545
|
-
})
|
|
546
|
-
```
|
|
519
|
+
When `STASH_STACK_LOG` is not set, the SDK defaults to `error` (errors only).
|
|
547
520
|
|
|
548
521
|
The SDK never logs plaintext data.
|
|
549
522
|
|
package/dist/bin/stash.js
CHANGED
|
@@ -1125,13 +1125,71 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
|
|
|
1125
1125
|
} };
|
|
1126
1126
|
};
|
|
1127
1127
|
|
|
1128
|
-
// src/bin/commands/init/
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
}
|
|
1128
|
+
// src/bin/commands/init/providers/base.ts
|
|
1129
|
+
function createBaseProvider() {
|
|
1130
|
+
return {
|
|
1131
|
+
name: "base",
|
|
1132
|
+
introMessage: "Setting up CipherStash for your project...",
|
|
1133
|
+
connectionOptions: [
|
|
1134
|
+
{ value: "drizzle", label: "Drizzle ORM", hint: "recommended" },
|
|
1135
|
+
{ value: "prisma", label: "Prisma" },
|
|
1136
|
+
{ value: "raw-sql", label: "Raw SQL / pg" }
|
|
1137
|
+
],
|
|
1138
|
+
getNextSteps(state) {
|
|
1139
|
+
const steps = [
|
|
1140
|
+
"Install @cipherstash/stack: npm install @cipherstash/stack"
|
|
1141
|
+
];
|
|
1142
|
+
if (state.connectionMethod === "drizzle") {
|
|
1143
|
+
steps.push("Import encryptedType from @cipherstash/stack/drizzle");
|
|
1144
|
+
} else if (state.connectionMethod === "prisma") {
|
|
1145
|
+
steps.push("Set up Prisma with @cipherstash/stack");
|
|
1146
|
+
}
|
|
1147
|
+
steps.push(
|
|
1148
|
+
"Define your encrypted schema",
|
|
1149
|
+
"Read the docs: https://docs.cipherstash.com"
|
|
1150
|
+
);
|
|
1151
|
+
return steps;
|
|
1152
|
+
}
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
// src/bin/commands/init/providers/supabase.ts
|
|
1157
|
+
function createSupabaseProvider() {
|
|
1158
|
+
return {
|
|
1159
|
+
name: "supabase",
|
|
1160
|
+
introMessage: "Setting up CipherStash for your Supabase project...",
|
|
1161
|
+
connectionOptions: [
|
|
1162
|
+
{
|
|
1163
|
+
value: "supabase-js",
|
|
1164
|
+
label: "Supabase JS Client",
|
|
1165
|
+
hint: "recommended"
|
|
1166
|
+
},
|
|
1167
|
+
{ value: "drizzle", label: "Drizzle ORM" },
|
|
1168
|
+
{ value: "prisma", label: "Prisma" },
|
|
1169
|
+
{ value: "raw-sql", label: "Raw SQL / pg" }
|
|
1170
|
+
],
|
|
1171
|
+
getNextSteps(state) {
|
|
1172
|
+
const steps = [
|
|
1173
|
+
"Install @cipherstash/stack: npm install @cipherstash/stack"
|
|
1174
|
+
];
|
|
1175
|
+
if (state.connectionMethod === "supabase-js") {
|
|
1176
|
+
steps.push("Import encryptedSupabase from @cipherstash/stack/supabase");
|
|
1177
|
+
} else if (state.connectionMethod === "drizzle") {
|
|
1178
|
+
steps.push("Import encryptedType from @cipherstash/stack/drizzle");
|
|
1179
|
+
} else if (state.connectionMethod === "prisma") {
|
|
1180
|
+
steps.push("Set up Prisma with @cipherstash/stack");
|
|
1181
|
+
}
|
|
1182
|
+
steps.push(
|
|
1183
|
+
"Define your encrypted schema",
|
|
1184
|
+
"Supabase guides: https://cipherstash.com/docs/supabase/encrypt-user-data",
|
|
1185
|
+
"Multi-tenant encryption: https://docs.cipherstash.com/docs/multi-tenant",
|
|
1186
|
+
"Migrating existing data: https://docs.cipherstash.com/docs/migration",
|
|
1187
|
+
"Need help? #supabase in Discord or support@cipherstash.com"
|
|
1188
|
+
);
|
|
1189
|
+
return steps;
|
|
1190
|
+
}
|
|
1191
|
+
};
|
|
1192
|
+
}
|
|
1135
1193
|
|
|
1136
1194
|
// src/bin/commands/init/stubs.ts
|
|
1137
1195
|
function delay(ms) {
|
|
@@ -1174,6 +1232,14 @@ async function installEqlExtension(databaseUrl) {
|
|
|
1174
1232
|
await delay(1500);
|
|
1175
1233
|
}
|
|
1176
1234
|
|
|
1235
|
+
// src/bin/commands/init/types.ts
|
|
1236
|
+
var CancelledError = class extends Error {
|
|
1237
|
+
constructor() {
|
|
1238
|
+
super("cancelled");
|
|
1239
|
+
this.name = "CancelledError";
|
|
1240
|
+
}
|
|
1241
|
+
};
|
|
1242
|
+
|
|
1177
1243
|
// src/bin/commands/init/steps/authenticate.ts
|
|
1178
1244
|
var authenticateStep = {
|
|
1179
1245
|
id: "authenticate",
|
|
@@ -1195,78 +1261,6 @@ Code: ${userCode}`,
|
|
|
1195
1261
|
}
|
|
1196
1262
|
};
|
|
1197
1263
|
|
|
1198
|
-
// src/bin/commands/init/steps/select-workspace.ts
|
|
1199
|
-
var selectWorkspaceStep = {
|
|
1200
|
-
id: "select-workspace",
|
|
1201
|
-
name: "Select workspace",
|
|
1202
|
-
async run(state, _provider) {
|
|
1203
|
-
const s = Y2();
|
|
1204
|
-
s.start("Loading workspaces...");
|
|
1205
|
-
const workspaces = await fetchWorkspaces(state.accessToken);
|
|
1206
|
-
s.stop("Workspaces loaded");
|
|
1207
|
-
const options = [
|
|
1208
|
-
...workspaces.map((ws2) => ({ value: ws2.id, label: ws2.name })),
|
|
1209
|
-
{ value: "__create__", label: "Create new workspace" }
|
|
1210
|
-
];
|
|
1211
|
-
const selected = await ve({
|
|
1212
|
-
message: "Select a workspace",
|
|
1213
|
-
options
|
|
1214
|
-
});
|
|
1215
|
-
if (pD(selected)) throw new CancelledError();
|
|
1216
|
-
if (selected === "__create__") {
|
|
1217
|
-
const name = await he({
|
|
1218
|
-
message: "What should we call your new workspace?",
|
|
1219
|
-
placeholder: "my-project",
|
|
1220
|
-
validate: (val) => {
|
|
1221
|
-
if (!val.trim()) return "Workspace name is required";
|
|
1222
|
-
}
|
|
1223
|
-
});
|
|
1224
|
-
if (pD(name)) throw new CancelledError();
|
|
1225
|
-
const s2 = Y2();
|
|
1226
|
-
s2.start("Creating workspace...");
|
|
1227
|
-
const ws2 = await createWorkspace(state.accessToken, name);
|
|
1228
|
-
s2.stop(`Workspace created: ${ws2.name}`);
|
|
1229
|
-
return { ...state, workspaceId: ws2.id, workspaceName: ws2.name };
|
|
1230
|
-
}
|
|
1231
|
-
const ws = workspaces.find((w2) => w2.id === selected);
|
|
1232
|
-
return { ...state, workspaceId: ws.id, workspaceName: ws.name };
|
|
1233
|
-
}
|
|
1234
|
-
};
|
|
1235
|
-
|
|
1236
|
-
// src/bin/commands/init/steps/select-region.ts
|
|
1237
|
-
var REGIONS = [
|
|
1238
|
-
{ value: "ap-southeast-2", label: "Asia Pacific (Sydney)" },
|
|
1239
|
-
{ value: "us-east-1", label: "US East (N. Virginia)" },
|
|
1240
|
-
{ value: "us-west-2", label: "US West (Oregon)" },
|
|
1241
|
-
{ value: "eu-west-1", label: "Europe (Ireland)" }
|
|
1242
|
-
];
|
|
1243
|
-
var selectRegionStep = {
|
|
1244
|
-
id: "select-region",
|
|
1245
|
-
name: "Select region",
|
|
1246
|
-
async run(state, _provider) {
|
|
1247
|
-
const region = await ve({
|
|
1248
|
-
message: "Where should we create your workspace?",
|
|
1249
|
-
options: REGIONS
|
|
1250
|
-
});
|
|
1251
|
-
if (pD(region)) throw new CancelledError();
|
|
1252
|
-
return { ...state, region };
|
|
1253
|
-
}
|
|
1254
|
-
};
|
|
1255
|
-
|
|
1256
|
-
// src/bin/commands/init/steps/select-connection.ts
|
|
1257
|
-
var selectConnectionStep = {
|
|
1258
|
-
id: "select-connection",
|
|
1259
|
-
name: "Select connection method",
|
|
1260
|
-
async run(state, provider) {
|
|
1261
|
-
const method = await ve({
|
|
1262
|
-
message: "How will you connect to your database?",
|
|
1263
|
-
options: provider.connectionOptions
|
|
1264
|
-
});
|
|
1265
|
-
if (pD(method)) throw new CancelledError();
|
|
1266
|
-
return { ...state, connectionMethod: method };
|
|
1267
|
-
}
|
|
1268
|
-
};
|
|
1269
|
-
|
|
1270
1264
|
// src/bin/commands/init/steps/detect-database-url.ts
|
|
1271
1265
|
function maskUrl(url) {
|
|
1272
1266
|
return url.replace(/:\/\/([^:]+):([^@]+)@/, "://***@");
|
|
@@ -1296,7 +1290,8 @@ var detectDatabaseUrlStep = {
|
|
|
1296
1290
|
placeholder: "postgresql://user:password@host:5432/database",
|
|
1297
1291
|
validate: (val) => {
|
|
1298
1292
|
if (!val.trim()) return "Database URL is required";
|
|
1299
|
-
if (!val.startsWith("postgres"))
|
|
1293
|
+
if (!val.startsWith("postgres"))
|
|
1294
|
+
return "Must be a PostgreSQL connection string";
|
|
1300
1295
|
}
|
|
1301
1296
|
});
|
|
1302
1297
|
if (pD(url)) throw new CancelledError();
|
|
@@ -1358,67 +1353,77 @@ var nextStepsStep = {
|
|
|
1358
1353
|
}
|
|
1359
1354
|
};
|
|
1360
1355
|
|
|
1361
|
-
// src/bin/commands/init/
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
"Install @cipherstash/stack: npm install @cipherstash/stack"
|
|
1375
|
-
];
|
|
1376
|
-
if (state.connectionMethod === "supabase-js") {
|
|
1377
|
-
steps.push("Import encryptedSupabase from @cipherstash/stack/supabase");
|
|
1378
|
-
} else if (state.connectionMethod === "drizzle") {
|
|
1379
|
-
steps.push("Import encryptedType from @cipherstash/stack/drizzle");
|
|
1380
|
-
} else if (state.connectionMethod === "prisma") {
|
|
1381
|
-
steps.push("Set up Prisma with @cipherstash/stack");
|
|
1382
|
-
}
|
|
1383
|
-
steps.push(
|
|
1384
|
-
"Define your encrypted schema",
|
|
1385
|
-
"Supabase guides: https://cipherstash.com/docs/supabase/encrypt-user-data",
|
|
1386
|
-
"Multi-tenant encryption: https://docs.cipherstash.com/docs/multi-tenant",
|
|
1387
|
-
"Migrating existing data: https://docs.cipherstash.com/docs/migration",
|
|
1388
|
-
"Need help? #supabase in Discord or support@cipherstash.com"
|
|
1389
|
-
);
|
|
1390
|
-
return steps;
|
|
1391
|
-
}
|
|
1392
|
-
};
|
|
1393
|
-
}
|
|
1356
|
+
// src/bin/commands/init/steps/select-connection.ts
|
|
1357
|
+
var selectConnectionStep = {
|
|
1358
|
+
id: "select-connection",
|
|
1359
|
+
name: "Select connection method",
|
|
1360
|
+
async run(state, provider) {
|
|
1361
|
+
const method = await ve({
|
|
1362
|
+
message: "How will you connect to your database?",
|
|
1363
|
+
options: provider.connectionOptions
|
|
1364
|
+
});
|
|
1365
|
+
if (pD(method)) throw new CancelledError();
|
|
1366
|
+
return { ...state, connectionMethod: method };
|
|
1367
|
+
}
|
|
1368
|
+
};
|
|
1394
1369
|
|
|
1395
|
-
// src/bin/commands/init/
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1370
|
+
// src/bin/commands/init/steps/select-region.ts
|
|
1371
|
+
var REGIONS = [
|
|
1372
|
+
{ value: "ap-southeast-2", label: "Asia Pacific (Sydney)" },
|
|
1373
|
+
{ value: "us-east-1", label: "US East (N. Virginia)" },
|
|
1374
|
+
{ value: "us-west-2", label: "US West (Oregon)" },
|
|
1375
|
+
{ value: "eu-west-1", label: "Europe (Ireland)" }
|
|
1376
|
+
];
|
|
1377
|
+
var selectRegionStep = {
|
|
1378
|
+
id: "select-region",
|
|
1379
|
+
name: "Select region",
|
|
1380
|
+
async run(state, _provider) {
|
|
1381
|
+
const region = await ve({
|
|
1382
|
+
message: "Where should we create your workspace?",
|
|
1383
|
+
options: REGIONS
|
|
1384
|
+
});
|
|
1385
|
+
if (pD(region)) throw new CancelledError();
|
|
1386
|
+
return { ...state, region };
|
|
1387
|
+
}
|
|
1388
|
+
};
|
|
1389
|
+
|
|
1390
|
+
// src/bin/commands/init/steps/select-workspace.ts
|
|
1391
|
+
var selectWorkspaceStep = {
|
|
1392
|
+
id: "select-workspace",
|
|
1393
|
+
name: "Select workspace",
|
|
1394
|
+
async run(state, _provider) {
|
|
1395
|
+
const s = Y2();
|
|
1396
|
+
s.start("Loading workspaces...");
|
|
1397
|
+
const workspaces = await fetchWorkspaces(state.accessToken);
|
|
1398
|
+
s.stop("Workspaces loaded");
|
|
1399
|
+
const options = [
|
|
1400
|
+
...workspaces.map((ws2) => ({ value: ws2.id, label: ws2.name })),
|
|
1401
|
+
{ value: "__create__", label: "Create new workspace" }
|
|
1402
|
+
];
|
|
1403
|
+
const selected = await ve({
|
|
1404
|
+
message: "Select a workspace",
|
|
1405
|
+
options
|
|
1406
|
+
});
|
|
1407
|
+
if (pD(selected)) throw new CancelledError();
|
|
1408
|
+
if (selected === "__create__") {
|
|
1409
|
+
const name = await he({
|
|
1410
|
+
message: "What should we call your new workspace?",
|
|
1411
|
+
placeholder: "my-project",
|
|
1412
|
+
validate: (val) => {
|
|
1413
|
+
if (!val.trim()) return "Workspace name is required";
|
|
1414
|
+
}
|
|
1415
|
+
});
|
|
1416
|
+
if (pD(name)) throw new CancelledError();
|
|
1417
|
+
const s2 = Y2();
|
|
1418
|
+
s2.start("Creating workspace...");
|
|
1419
|
+
const ws2 = await createWorkspace(state.accessToken, name);
|
|
1420
|
+
s2.stop(`Workspace created: ${ws2.name}`);
|
|
1421
|
+
return { ...state, workspaceId: ws2.id, workspaceName: ws2.name };
|
|
1419
1422
|
}
|
|
1420
|
-
|
|
1421
|
-
}
|
|
1423
|
+
const ws = workspaces.find((w2) => w2.id === selected);
|
|
1424
|
+
return { ...state, workspaceId: ws.id, workspaceName: ws.name };
|
|
1425
|
+
}
|
|
1426
|
+
};
|
|
1422
1427
|
|
|
1423
1428
|
// src/bin/commands/init/index.ts
|
|
1424
1429
|
var PROVIDER_MAP = {
|
|
@@ -1501,15 +1506,6 @@ function isEncryptedPayload(value) {
|
|
|
1501
1506
|
return true;
|
|
1502
1507
|
}
|
|
1503
1508
|
|
|
1504
|
-
// src/errors/index.ts
|
|
1505
|
-
var EncryptionErrorTypes = {
|
|
1506
|
-
ClientInitError: "ClientInitError",
|
|
1507
|
-
EncryptionError: "EncryptionError",
|
|
1508
|
-
DecryptionError: "DecryptionError",
|
|
1509
|
-
LockContextError: "LockContextError",
|
|
1510
|
-
CtsTokenError: "CtsTokenError"
|
|
1511
|
-
};
|
|
1512
|
-
|
|
1513
1509
|
// src/schema/index.ts
|
|
1514
1510
|
import { z as z2 } from "zod";
|
|
1515
1511
|
var castAsEnum = z2.enum(["bigint", "boolean", "date", "number", "string", "json", "text"]).default("text");
|
|
@@ -1834,6 +1830,15 @@ function buildEncryptConfig(...protectTables) {
|
|
|
1834
1830
|
return config3;
|
|
1835
1831
|
}
|
|
1836
1832
|
|
|
1833
|
+
// src/errors/index.ts
|
|
1834
|
+
var EncryptionErrorTypes = {
|
|
1835
|
+
ClientInitError: "ClientInitError",
|
|
1836
|
+
EncryptionError: "EncryptionError",
|
|
1837
|
+
DecryptionError: "DecryptionError",
|
|
1838
|
+
LockContextError: "LockContextError",
|
|
1839
|
+
CtsTokenError: "CtsTokenError"
|
|
1840
|
+
};
|
|
1841
|
+
|
|
1837
1842
|
// src/utils/config/index.ts
|
|
1838
1843
|
import fs from "node:fs";
|
|
1839
1844
|
import path from "node:path";
|
|
@@ -1898,26 +1903,34 @@ function loadWorkSpaceId(suppliedCrn) {
|
|
|
1898
1903
|
}
|
|
1899
1904
|
|
|
1900
1905
|
// src/utils/logger/index.ts
|
|
1901
|
-
import {
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1906
|
+
import { createRequestLogger, initLogger } from "evlog";
|
|
1907
|
+
var validLevels = ["debug", "info", "error"];
|
|
1908
|
+
function levelFromEnv() {
|
|
1909
|
+
const env = process.env.STASH_STACK_LOG;
|
|
1910
|
+
if (env && validLevels.includes(env)) return env;
|
|
1911
|
+
return "error";
|
|
1912
|
+
}
|
|
1913
|
+
function samplingRatesForLevel(level) {
|
|
1914
|
+
switch (level) {
|
|
1915
|
+
case "debug":
|
|
1916
|
+
return { debug: 100, info: 100, warn: 100, error: 100 };
|
|
1917
|
+
case "info":
|
|
1918
|
+
return { debug: 0, info: 100, warn: 100, error: 100 };
|
|
1919
|
+
case "error":
|
|
1920
|
+
default:
|
|
1921
|
+
return { debug: 0, info: 0, warn: 0, error: 100 };
|
|
1922
|
+
}
|
|
1909
1923
|
}
|
|
1910
1924
|
var initialized = false;
|
|
1911
|
-
function initStackLogger(
|
|
1925
|
+
function initStackLogger() {
|
|
1912
1926
|
if (initialized) return;
|
|
1913
1927
|
initialized = true;
|
|
1914
|
-
const
|
|
1928
|
+
const level = levelFromEnv();
|
|
1929
|
+
const rates = samplingRatesForLevel(level);
|
|
1915
1930
|
initLogger({
|
|
1916
1931
|
env: { service: "@cipherstash/stack" },
|
|
1917
|
-
enabled:
|
|
1918
|
-
|
|
1919
|
-
...rates && { sampling: { rates } },
|
|
1920
|
-
...config3?.drain && { drain: config3.drain }
|
|
1932
|
+
enabled: true,
|
|
1933
|
+
sampling: { rates }
|
|
1921
1934
|
});
|
|
1922
1935
|
}
|
|
1923
1936
|
initStackLogger();
|
|
@@ -1955,6 +1968,7 @@ var logger = {
|
|
|
1955
1968
|
// src/encryption/index.ts
|
|
1956
1969
|
import { withResult as withResult11 } from "@byteslice/result";
|
|
1957
1970
|
import { newClient } from "@cipherstash/protect-ffi";
|
|
1971
|
+
import { validate as uuidValidate } from "uuid";
|
|
1958
1972
|
|
|
1959
1973
|
// src/encryption/helpers/type-guards.ts
|
|
1960
1974
|
function isScalarQueryTermArray(value) {
|
|
@@ -4245,23 +4259,14 @@ var EncryptionClient = class {
|
|
|
4245
4259
|
};
|
|
4246
4260
|
}
|
|
4247
4261
|
};
|
|
4248
|
-
|
|
4249
|
-
// src/index.ts
|
|
4250
|
-
function isValidUuid(uuid) {
|
|
4251
|
-
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
4252
|
-
return uuidRegex.test(uuid);
|
|
4253
|
-
}
|
|
4254
4262
|
var Encryption = async (config3) => {
|
|
4255
|
-
if (config3.logging) {
|
|
4256
|
-
initStackLogger(config3.logging);
|
|
4257
|
-
}
|
|
4258
4263
|
const { schemas, config: clientConfig } = config3;
|
|
4259
4264
|
if (!schemas.length) {
|
|
4260
4265
|
throw new Error(
|
|
4261
4266
|
"[encryption]: At least one encryptedTable must be provided to initialize the encryption client"
|
|
4262
4267
|
);
|
|
4263
4268
|
}
|
|
4264
|
-
if (clientConfig?.keyset && "id" in clientConfig.keyset && !
|
|
4269
|
+
if (clientConfig?.keyset && "id" in clientConfig.keyset && !uuidValidate(clientConfig.keyset.id)) {
|
|
4265
4270
|
throw new Error(
|
|
4266
4271
|
"[encryption]: Invalid UUID provided for keyset id. Must be a valid UUID."
|
|
4267
4272
|
);
|
|
@@ -4287,7 +4292,22 @@ var Secrets = class {
|
|
|
4287
4292
|
value: encryptedColumn("value")
|
|
4288
4293
|
});
|
|
4289
4294
|
constructor(config3) {
|
|
4290
|
-
|
|
4295
|
+
const workspaceCRN = config3.workspaceCRN ?? process.env.CS_WORKSPACE_CRN;
|
|
4296
|
+
const clientId = config3.clientId ?? process.env.CS_CLIENT_ID;
|
|
4297
|
+
const clientKey = config3.clientKey ?? process.env.CS_CLIENT_KEY;
|
|
4298
|
+
const accessKey = config3.accessKey ?? process.env.CS_CLIENT_ACCESS_KEY;
|
|
4299
|
+
if (!workspaceCRN || !clientId || !clientKey || !accessKey) {
|
|
4300
|
+
throw new Error(
|
|
4301
|
+
"Missing required configuration or environment variables."
|
|
4302
|
+
);
|
|
4303
|
+
}
|
|
4304
|
+
this.config = {
|
|
4305
|
+
environment: config3.environment,
|
|
4306
|
+
workspaceCRN,
|
|
4307
|
+
clientId,
|
|
4308
|
+
clientKey,
|
|
4309
|
+
accessKey
|
|
4310
|
+
};
|
|
4291
4311
|
}
|
|
4292
4312
|
initPromise = null;
|
|
4293
4313
|
/**
|
|
@@ -4300,24 +4320,24 @@ var Secrets = class {
|
|
|
4300
4320
|
return this.initPromise;
|
|
4301
4321
|
}
|
|
4302
4322
|
async _doInit() {
|
|
4323
|
+
logger.debug("Initializing the Secrets client.");
|
|
4303
4324
|
this.encryptionClient = await Encryption({
|
|
4304
4325
|
schemas: [this.secretsSchema],
|
|
4305
4326
|
config: {
|
|
4306
4327
|
workspaceCrn: this.config.workspaceCRN,
|
|
4307
4328
|
clientId: this.config.clientId,
|
|
4308
4329
|
clientKey: this.config.clientKey,
|
|
4309
|
-
accessKey: this.config.
|
|
4310
|
-
keyset: {
|
|
4311
|
-
name: this.config.environment
|
|
4312
|
-
}
|
|
4330
|
+
accessKey: this.config.accessKey,
|
|
4331
|
+
keyset: { name: this.config.environment }
|
|
4313
4332
|
}
|
|
4314
4333
|
});
|
|
4334
|
+
logger.debug("Successfully initialized the Secrets client.");
|
|
4315
4335
|
}
|
|
4316
4336
|
/**
|
|
4317
4337
|
* Get the authorization header for API requests
|
|
4318
4338
|
*/
|
|
4319
4339
|
getAuthHeader() {
|
|
4320
|
-
return `Bearer ${this.config.
|
|
4340
|
+
return `Bearer ${this.config.accessKey}`;
|
|
4321
4341
|
}
|
|
4322
4342
|
/**
|
|
4323
4343
|
* Make an API request with error handling.
|
|
@@ -4332,6 +4352,7 @@ var Secrets = class {
|
|
|
4332
4352
|
const searchParams = new URLSearchParams(options.params);
|
|
4333
4353
|
url = `${url}?${searchParams.toString()}`;
|
|
4334
4354
|
}
|
|
4355
|
+
logger.debug(`Secrets API request: ${method} ${path2}`);
|
|
4335
4356
|
const headers = {
|
|
4336
4357
|
"Content-Type": "application/json",
|
|
4337
4358
|
Authorization: this.getAuthHeader()
|
|
@@ -4350,6 +4371,7 @@ var Secrets = class {
|
|
|
4350
4371
|
} catch {
|
|
4351
4372
|
errorMessage = errorText || errorMessage;
|
|
4352
4373
|
}
|
|
4374
|
+
logger.error(`Secrets API error on ${method} ${path2}: ${errorMessage}`);
|
|
4353
4375
|
return {
|
|
4354
4376
|
failure: {
|
|
4355
4377
|
type: "ApiError",
|
|
@@ -4357,13 +4379,16 @@ var Secrets = class {
|
|
|
4357
4379
|
}
|
|
4358
4380
|
};
|
|
4359
4381
|
}
|
|
4382
|
+
logger.debug(`Secrets API request successful: ${method} ${path2}`);
|
|
4360
4383
|
const data = await response.json();
|
|
4361
4384
|
return { data };
|
|
4362
4385
|
} catch (error) {
|
|
4386
|
+
const message = error instanceof Error ? error.message : "Unknown network error occurred";
|
|
4387
|
+
logger.error(`Secrets network error on ${method} ${path2}: ${message}`);
|
|
4363
4388
|
return {
|
|
4364
4389
|
failure: {
|
|
4365
4390
|
type: "NetworkError",
|
|
4366
|
-
message
|
|
4391
|
+
message
|
|
4367
4392
|
}
|
|
4368
4393
|
};
|
|
4369
4394
|
}
|
|
@@ -4379,6 +4404,7 @@ var Secrets = class {
|
|
|
4379
4404
|
* @returns A Result containing the API response or an error
|
|
4380
4405
|
*/
|
|
4381
4406
|
async set(name, value) {
|
|
4407
|
+
logger.debug("Setting secret");
|
|
4382
4408
|
await this.ensureInitialized();
|
|
4383
4409
|
if (!this.encryptionClient) {
|
|
4384
4410
|
return {
|
|
@@ -4393,6 +4419,7 @@ var Secrets = class {
|
|
|
4393
4419
|
table: this.secretsSchema
|
|
4394
4420
|
});
|
|
4395
4421
|
if (encryptResult.failure) {
|
|
4422
|
+
logger.error("Failed to encrypt secret");
|
|
4396
4423
|
return {
|
|
4397
4424
|
failure: {
|
|
4398
4425
|
type: "EncryptionError",
|
|
@@ -4420,6 +4447,7 @@ var Secrets = class {
|
|
|
4420
4447
|
* @returns A Result containing the decrypted value or an error
|
|
4421
4448
|
*/
|
|
4422
4449
|
async get(name) {
|
|
4450
|
+
logger.debug("Getting secret");
|
|
4423
4451
|
await this.ensureInitialized();
|
|
4424
4452
|
if (!this.encryptionClient) {
|
|
4425
4453
|
return {
|
|
@@ -4444,6 +4472,7 @@ var Secrets = class {
|
|
|
4444
4472
|
apiResult.data.encryptedValue.data
|
|
4445
4473
|
);
|
|
4446
4474
|
if (decryptResult.failure) {
|
|
4475
|
+
logger.error("Failed to decrypt secret");
|
|
4447
4476
|
return {
|
|
4448
4477
|
failure: {
|
|
4449
4478
|
type: "DecryptionError",
|
|
@@ -4452,6 +4481,7 @@ var Secrets = class {
|
|
|
4452
4481
|
};
|
|
4453
4482
|
}
|
|
4454
4483
|
if (typeof decryptResult.data !== "string") {
|
|
4484
|
+
logger.error("Decrypted secret value is not a string");
|
|
4455
4485
|
return {
|
|
4456
4486
|
failure: {
|
|
4457
4487
|
type: "DecryptionError",
|
|
@@ -4476,6 +4506,7 @@ var Secrets = class {
|
|
|
4476
4506
|
* @returns A Result containing an object mapping secret names to their decrypted values
|
|
4477
4507
|
*/
|
|
4478
4508
|
async getMany(names) {
|
|
4509
|
+
logger.debug(`Getting ${names.length} secrets.`);
|
|
4479
4510
|
await this.ensureInitialized();
|
|
4480
4511
|
if (!this.encryptionClient) {
|
|
4481
4512
|
return {
|
|
@@ -4522,6 +4553,9 @@ var Secrets = class {
|
|
|
4522
4553
|
}));
|
|
4523
4554
|
const decryptResult = await this.encryptionClient.bulkDecryptModels(dataToDecrypt);
|
|
4524
4555
|
if (decryptResult.failure) {
|
|
4556
|
+
logger.error(
|
|
4557
|
+
`Failed to decrypt secrets: ${decryptResult.failure.message}`
|
|
4558
|
+
);
|
|
4525
4559
|
return {
|
|
4526
4560
|
failure: {
|
|
4527
4561
|
type: "DecryptionError",
|
|
@@ -4547,6 +4581,7 @@ var Secrets = class {
|
|
|
4547
4581
|
* @returns A Result containing the list of secrets or an error
|
|
4548
4582
|
*/
|
|
4549
4583
|
async list() {
|
|
4584
|
+
logger.debug("Listing secrets.");
|
|
4550
4585
|
const workspaceId = extractWorkspaceIdFromCrn(this.config.workspaceCRN);
|
|
4551
4586
|
const apiResult = await this.apiRequest(
|
|
4552
4587
|
"GET",
|
|
@@ -4572,6 +4607,7 @@ var Secrets = class {
|
|
|
4572
4607
|
* @returns A Result containing the API response or an error
|
|
4573
4608
|
*/
|
|
4574
4609
|
async delete(name) {
|
|
4610
|
+
logger.debug("Deleting secret");
|
|
4575
4611
|
const workspaceId = extractWorkspaceIdFromCrn(this.config.workspaceCRN);
|
|
4576
4612
|
return await this.apiRequest("POST", "/delete", {
|
|
4577
4613
|
body: {
|