@declaw/sdk 1.2.2 → 1.3.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 +24 -0
- package/dist/index.cjs +344 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +162 -7
- package/dist/index.d.ts +162 -7
- package/dist/index.js +339 -8
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,30 @@ All notable changes to the Declaw TypeScript / JavaScript SDK are documented in
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.3.0]
|
|
9
|
+
|
|
10
|
+
_2026-07 train: credential vault client + injection domain scoping._
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Credential vault client — the `Vault` API for managing secrets **by name**:
|
|
15
|
+
`Vault.createSecret()`, `listSecrets()`, `rotateSecret()`, `deleteSecret()`,
|
|
16
|
+
`updateScopes()`, and `listPresets()`. Secret values are write-only (never
|
|
17
|
+
returned after create). Attach secrets to a sandbox with
|
|
18
|
+
`vaultRefs: { ENV_VAR: "secret-name" }`; the value is injected at the egress
|
|
19
|
+
proxy and never enters the sandbox (#386, #399, #408, #456).
|
|
20
|
+
- Opt-in domain scoping for full injection defense via the `domains` option.
|
|
21
|
+
|
|
22
|
+
## [1.2.3]
|
|
23
|
+
|
|
24
|
+
_Restore the conservative default connection ceiling._
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Reverted the default connection-pool ceiling back to 64 (from the 512
|
|
29
|
+
introduced in 1.2.2). High-concurrency workloads should opt in explicitly
|
|
30
|
+
via `DECLAW_SDK_CONNECTIONS`. No public API change.
|
|
31
|
+
|
|
8
32
|
## [1.2.2]
|
|
9
33
|
|
|
10
34
|
_Higher default connection ceiling._
|
package/dist/index.cjs
CHANGED
|
@@ -68,6 +68,7 @@ __export(index_exports, {
|
|
|
68
68
|
TemplateError: () => TemplateError,
|
|
69
69
|
TimeoutError: () => TimeoutError,
|
|
70
70
|
TransformDirection: () => TransformDirection,
|
|
71
|
+
Vault: () => Vault,
|
|
71
72
|
VolumeFiles: () => VolumeFiles,
|
|
72
73
|
VolumeLocks: () => VolumeLocks,
|
|
73
74
|
Volumes: () => Volumes,
|
|
@@ -119,6 +120,9 @@ __export(index_exports, {
|
|
|
119
120
|
parseSnapshotInfo: () => parseSnapshotInfo,
|
|
120
121
|
parseTemplateBuildStatus: () => parseTemplateBuildStatus,
|
|
121
122
|
parseToxicityConfig: () => parseToxicityConfig,
|
|
123
|
+
parseVaultPreset: () => parseVaultPreset,
|
|
124
|
+
parseVaultScope: () => parseVaultScope,
|
|
125
|
+
parseVaultSecret: () => parseVaultSecret,
|
|
122
126
|
parseVolumeInfo: () => parseVolumeInfo,
|
|
123
127
|
parseWriteInfo: () => parseWriteInfo,
|
|
124
128
|
requiresTlsInterception: () => requiresTlsInterception,
|
|
@@ -126,6 +130,7 @@ __export(index_exports, {
|
|
|
126
130
|
securityPolicyToJSON: () => securityPolicyToJSON,
|
|
127
131
|
toxicityConfigToJSON: () => toxicityConfigToJSON,
|
|
128
132
|
validateNetworkEntry: () => validateNetworkEntry,
|
|
133
|
+
vaultScopeToJSON: () => vaultScopeToJSON,
|
|
129
134
|
volumeAttachmentToJSON: () => volumeAttachmentToJSON
|
|
130
135
|
});
|
|
131
136
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -269,7 +274,7 @@ function getDispatcher() {
|
|
|
269
274
|
}
|
|
270
275
|
const undici = await import("undici");
|
|
271
276
|
const connOverride = parseInt(process.env.DECLAW_SDK_CONNECTIONS || "", 10);
|
|
272
|
-
const connections = Number.isFinite(connOverride) && connOverride > 0 ? connOverride :
|
|
277
|
+
const connections = Number.isFinite(connOverride) && connOverride > 0 ? connOverride : 64;
|
|
273
278
|
const streamsOverride = parseInt(process.env.DECLAW_SDK_MAX_CONCURRENT_STREAMS || "", 10);
|
|
274
279
|
const maxConcurrentStreams = Number.isFinite(streamsOverride) && streamsOverride > 0 ? streamsOverride : 1e3;
|
|
275
280
|
return new undici.Agent({
|
|
@@ -286,7 +291,9 @@ function getDispatcher() {
|
|
|
286
291
|
// stream — silently defeating the H2 multiplexing that allowH2 enables.
|
|
287
292
|
// Omitted, H2 sessions default to unlimited concurrent streams (capped
|
|
288
293
|
// by maxConcurrentStreams) and H1.1 fallback defaults to 1 (safe, no
|
|
289
|
-
// head-of-line risk on non-idempotent POSTs).
|
|
294
|
+
// head-of-line risk on non-idempotent POSTs). This is the single
|
|
295
|
+
// biggest burst-latency lever: with pipelining:1 a 100-concurrent burst
|
|
296
|
+
// queued ~36 requests behind the `connections` cap.
|
|
290
297
|
allowH2: true,
|
|
291
298
|
connect: { keepAlive: true, keepAliveInitialDelay: 5e3 }
|
|
292
299
|
});
|
|
@@ -639,7 +646,7 @@ function createInjectionDefenseConfig(opts) {
|
|
|
639
646
|
enabled: opts?.enabled ?? false,
|
|
640
647
|
sensitivity: opts?.sensitivity ?? "medium" /* Medium */,
|
|
641
648
|
action: opts?.action ?? "log_only" /* LogOnly */,
|
|
642
|
-
threshold: opts?.threshold ?? 0.
|
|
649
|
+
threshold: opts?.threshold ?? 0.95,
|
|
643
650
|
domains: opts?.domains,
|
|
644
651
|
judge: opts?.judge,
|
|
645
652
|
injectionMode: opts?.injectionMode
|
|
@@ -666,7 +673,7 @@ function parseInjectionDefenseConfig(data) {
|
|
|
666
673
|
enabled: data.enabled ?? false,
|
|
667
674
|
sensitivity: data.sensitivity ?? "medium" /* Medium */,
|
|
668
675
|
action: data.action ?? "log_only" /* LogOnly */,
|
|
669
|
-
threshold: data.threshold ?? 0.
|
|
676
|
+
threshold: data.threshold ?? 0.95,
|
|
670
677
|
domains: data.domains,
|
|
671
678
|
judge: data.judge ? { enabled: data.judge.enabled ?? false, always: data.judge.always, policy: data.judge.policy } : void 0,
|
|
672
679
|
injectionMode: data.injection_mode ?? data.injectionMode
|
|
@@ -1044,14 +1051,14 @@ function fullInjectionDefensePolicy(opts) {
|
|
|
1044
1051
|
injectionDefense: createInjectionDefenseConfig({
|
|
1045
1052
|
enabled: true,
|
|
1046
1053
|
action: opts?.action ?? "block",
|
|
1047
|
-
threshold: opts?.threshold ?? 0.
|
|
1054
|
+
threshold: opts?.threshold ?? 0.95,
|
|
1048
1055
|
domains: opts?.domains,
|
|
1049
1056
|
injectionMode: opts?.mode ?? "balanced",
|
|
1050
1057
|
judge: { enabled: true, always: opts?.alwaysJudge ?? false, policy: opts?.agentPolicy ?? "" }
|
|
1051
1058
|
}),
|
|
1052
1059
|
customPolicy: createCustomPolicyConfig({
|
|
1053
1060
|
enabled: true,
|
|
1054
|
-
policyRef: "prompt-injection@
|
|
1061
|
+
policyRef: "prompt-injection@v3",
|
|
1055
1062
|
defaultDeny: false
|
|
1056
1063
|
})
|
|
1057
1064
|
});
|
|
@@ -1092,7 +1099,7 @@ function securityPolicyToJSON(policy) {
|
|
|
1092
1099
|
action: injDefConfig.action,
|
|
1093
1100
|
threshold: injDefConfig.threshold
|
|
1094
1101
|
};
|
|
1095
|
-
if (injDefConfig.domains !== void 0) {
|
|
1102
|
+
if (injDefConfig.domains !== void 0 && injDefConfig.domains.length > 0) {
|
|
1096
1103
|
injDef.domains = injDefConfig.domains;
|
|
1097
1104
|
}
|
|
1098
1105
|
if (injDefConfig.injectionMode !== void 0) {
|
|
@@ -2204,6 +2211,311 @@ function volumeAttachmentToJSON(att) {
|
|
|
2204
2211
|
return out;
|
|
2205
2212
|
}
|
|
2206
2213
|
|
|
2214
|
+
// src/vault/models.ts
|
|
2215
|
+
function parseVaultScope(data) {
|
|
2216
|
+
const scope = {
|
|
2217
|
+
domainRegex: String(data.domain_regex ?? "")
|
|
2218
|
+
};
|
|
2219
|
+
if (data.injection_type !== void 0 && data.injection_type !== null) {
|
|
2220
|
+
scope.injectionType = String(data.injection_type);
|
|
2221
|
+
}
|
|
2222
|
+
if (data.header_name !== void 0 && data.header_name !== null) {
|
|
2223
|
+
scope.headerName = String(data.header_name);
|
|
2224
|
+
}
|
|
2225
|
+
if (data.value_prefix !== void 0 && data.value_prefix !== null) {
|
|
2226
|
+
scope.valuePrefix = String(data.value_prefix);
|
|
2227
|
+
}
|
|
2228
|
+
if (data.basic_username !== void 0 && data.basic_username !== null) {
|
|
2229
|
+
scope.basicUsername = String(data.basic_username);
|
|
2230
|
+
}
|
|
2231
|
+
if (data.extra_headers !== void 0 && data.extra_headers !== null) {
|
|
2232
|
+
scope.extraHeaders = data.extra_headers;
|
|
2233
|
+
}
|
|
2234
|
+
if (data.query_params !== void 0 && data.query_params !== null) {
|
|
2235
|
+
scope.queryParams = data.query_params;
|
|
2236
|
+
}
|
|
2237
|
+
return scope;
|
|
2238
|
+
}
|
|
2239
|
+
function parseVaultSecret(data) {
|
|
2240
|
+
const secret = {
|
|
2241
|
+
secretId: String(data.secret_id ?? ""),
|
|
2242
|
+
name: String(data.name ?? ""),
|
|
2243
|
+
createdAt: String(data.created_at ?? ""),
|
|
2244
|
+
updatedAt: String(data.updated_at ?? "")
|
|
2245
|
+
};
|
|
2246
|
+
const rawScopes = data.scopes;
|
|
2247
|
+
if (rawScopes && rawScopes.length > 0) {
|
|
2248
|
+
secret.scopes = rawScopes.map(parseVaultScope);
|
|
2249
|
+
}
|
|
2250
|
+
if (data.rotated_at !== void 0 && data.rotated_at !== null) {
|
|
2251
|
+
secret.rotatedAt = String(data.rotated_at);
|
|
2252
|
+
}
|
|
2253
|
+
if (data.rotation_interval_days !== void 0 && data.rotation_interval_days !== null) {
|
|
2254
|
+
secret.rotationIntervalDays = Number(data.rotation_interval_days);
|
|
2255
|
+
}
|
|
2256
|
+
if (data.rotation_due !== void 0 && data.rotation_due !== null) {
|
|
2257
|
+
secret.rotationDue = Boolean(data.rotation_due);
|
|
2258
|
+
}
|
|
2259
|
+
return secret;
|
|
2260
|
+
}
|
|
2261
|
+
function parseVaultPreset(data) {
|
|
2262
|
+
const rawScopes = data.scopes ?? [];
|
|
2263
|
+
const preset = {
|
|
2264
|
+
key: String(data.key ?? ""),
|
|
2265
|
+
name: String(data.name ?? ""),
|
|
2266
|
+
category: String(data.category ?? ""),
|
|
2267
|
+
keyHint: String(data.key_hint ?? ""),
|
|
2268
|
+
scopes: rawScopes.map(parseVaultScope)
|
|
2269
|
+
};
|
|
2270
|
+
if (data.docs_url !== void 0 && data.docs_url !== null) {
|
|
2271
|
+
preset.docsUrl = String(data.docs_url);
|
|
2272
|
+
}
|
|
2273
|
+
return preset;
|
|
2274
|
+
}
|
|
2275
|
+
function vaultScopeToJSON(scope) {
|
|
2276
|
+
const out = {
|
|
2277
|
+
domain_regex: scope.domainRegex
|
|
2278
|
+
};
|
|
2279
|
+
if (scope.injectionType !== void 0) {
|
|
2280
|
+
out.injection_type = scope.injectionType;
|
|
2281
|
+
}
|
|
2282
|
+
if (scope.headerName !== void 0) {
|
|
2283
|
+
out.header_name = scope.headerName;
|
|
2284
|
+
}
|
|
2285
|
+
if (scope.valuePrefix !== void 0) {
|
|
2286
|
+
out.value_prefix = scope.valuePrefix;
|
|
2287
|
+
}
|
|
2288
|
+
if (scope.basicUsername !== void 0) {
|
|
2289
|
+
out.basic_username = scope.basicUsername;
|
|
2290
|
+
}
|
|
2291
|
+
if (scope.extraHeaders !== void 0) {
|
|
2292
|
+
out.extra_headers = scope.extraHeaders;
|
|
2293
|
+
}
|
|
2294
|
+
if (scope.queryParams !== void 0) {
|
|
2295
|
+
out.query_params = scope.queryParams;
|
|
2296
|
+
}
|
|
2297
|
+
return out;
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
// src/vault/vault.ts
|
|
2301
|
+
var DEFAULT_TEAM_NAME = "default";
|
|
2302
|
+
var DEFAULT_ENV_NAME = "prod";
|
|
2303
|
+
var defaultTeamCache = /* @__PURE__ */ new Map();
|
|
2304
|
+
function cacheKey(config) {
|
|
2305
|
+
return `${config.apiUrl}\0${config.apiKey}`;
|
|
2306
|
+
}
|
|
2307
|
+
async function resolveDefaultTeamId(config, create, timeout) {
|
|
2308
|
+
const key = cacheKey(config);
|
|
2309
|
+
const cached = defaultTeamCache.get(key);
|
|
2310
|
+
if (cached !== void 0) return cached;
|
|
2311
|
+
const client = getSharedClient(config);
|
|
2312
|
+
const resp = await client.get("/teams", { timeout });
|
|
2313
|
+
const rows = resp.teams ?? [];
|
|
2314
|
+
let best = null;
|
|
2315
|
+
for (const t of rows) {
|
|
2316
|
+
if (t.name === DEFAULT_TEAM_NAME) {
|
|
2317
|
+
if (best === null || t.created_at < best.created_at) {
|
|
2318
|
+
best = t;
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
if (best !== null) {
|
|
2323
|
+
defaultTeamCache.set(key, best.team_id);
|
|
2324
|
+
return best.team_id;
|
|
2325
|
+
}
|
|
2326
|
+
if (!create) return null;
|
|
2327
|
+
const created = await client.post("/teams", {
|
|
2328
|
+
json: { name: DEFAULT_TEAM_NAME },
|
|
2329
|
+
timeout
|
|
2330
|
+
});
|
|
2331
|
+
defaultTeamCache.set(key, created.team_id);
|
|
2332
|
+
return created.team_id;
|
|
2333
|
+
}
|
|
2334
|
+
async function ensureDefaultEnv(config, teamId, timeout) {
|
|
2335
|
+
const client = getSharedClient(config);
|
|
2336
|
+
const resp = await client.get(
|
|
2337
|
+
`/teams/${encodeURIComponent(teamId)}/environments`,
|
|
2338
|
+
{ timeout }
|
|
2339
|
+
);
|
|
2340
|
+
const rows = resp.environments ?? [];
|
|
2341
|
+
if (rows.some((e) => e.name === DEFAULT_ENV_NAME)) return;
|
|
2342
|
+
try {
|
|
2343
|
+
await client.post(`/teams/${encodeURIComponent(teamId)}/environments`, {
|
|
2344
|
+
json: { name: DEFAULT_ENV_NAME },
|
|
2345
|
+
timeout
|
|
2346
|
+
});
|
|
2347
|
+
} catch {
|
|
2348
|
+
const resp2 = await client.get(
|
|
2349
|
+
`/teams/${encodeURIComponent(teamId)}/environments`,
|
|
2350
|
+
{ timeout }
|
|
2351
|
+
);
|
|
2352
|
+
const rows2 = resp2.environments ?? [];
|
|
2353
|
+
if (rows2.some((e) => e.name === DEFAULT_ENV_NAME)) return;
|
|
2354
|
+
throw new Error(`Failed to ensure default environment "${DEFAULT_ENV_NAME}" on team ${teamId}`);
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
async function expandVaultRefs(config, refs, timeout) {
|
|
2358
|
+
if (Object.keys(refs).length === 0) return refs;
|
|
2359
|
+
const needsTeam = Object.values(refs).some((v) => !v.startsWith("vault://"));
|
|
2360
|
+
if (!needsTeam) return refs;
|
|
2361
|
+
const teamId = await resolveDefaultTeamId(config, false, timeout);
|
|
2362
|
+
if (teamId === null) {
|
|
2363
|
+
throw new Error("vault_refs given but no vault secrets exist for this account");
|
|
2364
|
+
}
|
|
2365
|
+
const out = {};
|
|
2366
|
+
for (const [envVar, ref] of Object.entries(refs)) {
|
|
2367
|
+
out[envVar] = ref.startsWith("vault://") ? ref : `vault://${teamId}/${DEFAULT_ENV_NAME}/${ref}`;
|
|
2368
|
+
}
|
|
2369
|
+
return out;
|
|
2370
|
+
}
|
|
2371
|
+
function buildConfig(opts) {
|
|
2372
|
+
return new ConnectionConfig({
|
|
2373
|
+
apiKey: opts?.apiKey,
|
|
2374
|
+
domain: opts?.domain,
|
|
2375
|
+
apiUrl: opts?.apiUrl,
|
|
2376
|
+
requestTimeout: opts?.requestTimeout
|
|
2377
|
+
});
|
|
2378
|
+
}
|
|
2379
|
+
var Vault = class _Vault {
|
|
2380
|
+
// -------------------------------------------------------------------------
|
|
2381
|
+
// Secrets
|
|
2382
|
+
// -------------------------------------------------------------------------
|
|
2383
|
+
/**
|
|
2384
|
+
* Store a secret's value (server-side, in OpenBao) plus its injection
|
|
2385
|
+
* scopes, under the auto-provisioned default team + "prod" environment.
|
|
2386
|
+
* Returns metadata only — the value is never echoed.
|
|
2387
|
+
*
|
|
2388
|
+
* POST /teams/{teamId}/vault/secrets
|
|
2389
|
+
*/
|
|
2390
|
+
static async createSecret(input, opts) {
|
|
2391
|
+
const config = buildConfig(opts);
|
|
2392
|
+
const teamId = await resolveDefaultTeamId(config, true, opts?.requestTimeout);
|
|
2393
|
+
if (teamId === null) throw new Error("Failed to resolve or create default team");
|
|
2394
|
+
await ensureDefaultEnv(config, teamId, opts?.requestTimeout);
|
|
2395
|
+
const body = {
|
|
2396
|
+
environment: DEFAULT_ENV_NAME,
|
|
2397
|
+
value: input.value
|
|
2398
|
+
};
|
|
2399
|
+
if (input.name) body.name = input.name;
|
|
2400
|
+
if (input.provider) body.provider = input.provider;
|
|
2401
|
+
if (input.scopes && input.scopes.length > 0) {
|
|
2402
|
+
body.scopes = input.scopes.map(vaultScopeToJSON);
|
|
2403
|
+
}
|
|
2404
|
+
if (input.rotationIntervalDays && input.rotationIntervalDays > 0) {
|
|
2405
|
+
body.rotation_interval_days = input.rotationIntervalDays;
|
|
2406
|
+
}
|
|
2407
|
+
const client = getSharedClient(config);
|
|
2408
|
+
const resp = await client.post(
|
|
2409
|
+
`/teams/${encodeURIComponent(teamId)}/vault/secrets`,
|
|
2410
|
+
{ json: body, timeout: opts?.requestTimeout }
|
|
2411
|
+
);
|
|
2412
|
+
return parseVaultSecret(resp);
|
|
2413
|
+
}
|
|
2414
|
+
/**
|
|
2415
|
+
* List secret metadata for the default team. Returns an empty array if no
|
|
2416
|
+
* default team has been provisioned yet.
|
|
2417
|
+
*
|
|
2418
|
+
* GET /teams/{teamId}/vault/secrets -> {secrets}
|
|
2419
|
+
*/
|
|
2420
|
+
static async listSecrets(opts) {
|
|
2421
|
+
const config = buildConfig(opts);
|
|
2422
|
+
const teamId = await resolveDefaultTeamId(config, false, opts?.requestTimeout);
|
|
2423
|
+
if (teamId === null) return [];
|
|
2424
|
+
const client = getSharedClient(config);
|
|
2425
|
+
const resp = await client.get(
|
|
2426
|
+
`/teams/${encodeURIComponent(teamId)}/vault/secrets`,
|
|
2427
|
+
{ timeout: opts?.requestTimeout }
|
|
2428
|
+
);
|
|
2429
|
+
const rows = resp.secrets ?? [];
|
|
2430
|
+
return rows.map(parseVaultSecret);
|
|
2431
|
+
}
|
|
2432
|
+
/**
|
|
2433
|
+
* Replace a secret's value by name (server-side); scopes are unchanged.
|
|
2434
|
+
*
|
|
2435
|
+
* POST /teams/{teamId}/vault/secrets/{secretId}/rotate {value}
|
|
2436
|
+
*/
|
|
2437
|
+
static async rotateSecret(name, value, opts) {
|
|
2438
|
+
const config = buildConfig(opts);
|
|
2439
|
+
const teamId = await resolveDefaultTeamId(config, false, opts?.requestTimeout);
|
|
2440
|
+
if (teamId === null) throw new Error(`vault secret "${name}" not found`);
|
|
2441
|
+
const secretId = await _Vault._resolveSecretId(config, teamId, name, opts?.requestTimeout);
|
|
2442
|
+
const client = getSharedClient(config);
|
|
2443
|
+
await client.post(
|
|
2444
|
+
`/teams/${encodeURIComponent(teamId)}/vault/secrets/${encodeURIComponent(secretId)}/rotate`,
|
|
2445
|
+
{ json: { value }, timeout: opts?.requestTimeout }
|
|
2446
|
+
);
|
|
2447
|
+
}
|
|
2448
|
+
/**
|
|
2449
|
+
* Delete a secret by name — metadata and stored value.
|
|
2450
|
+
*
|
|
2451
|
+
* DELETE /teams/{teamId}/vault/secrets/{secretId}
|
|
2452
|
+
*/
|
|
2453
|
+
static async deleteSecret(name, opts) {
|
|
2454
|
+
const config = buildConfig(opts);
|
|
2455
|
+
const teamId = await resolveDefaultTeamId(config, false, opts?.requestTimeout);
|
|
2456
|
+
if (teamId === null) throw new Error(`vault secret "${name}" not found`);
|
|
2457
|
+
const secretId = await _Vault._resolveSecretId(config, teamId, name, opts?.requestTimeout);
|
|
2458
|
+
const client = getSharedClient(config);
|
|
2459
|
+
await client.delete(
|
|
2460
|
+
`/teams/${encodeURIComponent(teamId)}/vault/secrets/${encodeURIComponent(secretId)}`,
|
|
2461
|
+
{ timeout: opts?.requestTimeout }
|
|
2462
|
+
);
|
|
2463
|
+
}
|
|
2464
|
+
/**
|
|
2465
|
+
* Replace a secret's injection scopes by name; the value is unchanged. Use
|
|
2466
|
+
* this to change a secret's destination(s) or injection format in place
|
|
2467
|
+
* instead of delete + recreate. At least one scope is required.
|
|
2468
|
+
*
|
|
2469
|
+
* POST /teams/{teamId}/vault/secrets/{secretId}/scopes
|
|
2470
|
+
*/
|
|
2471
|
+
static async updateScopes(name, scopes, opts) {
|
|
2472
|
+
if (!scopes || scopes.length === 0) {
|
|
2473
|
+
throw new Error("at least one scope is required");
|
|
2474
|
+
}
|
|
2475
|
+
const config = buildConfig(opts);
|
|
2476
|
+
const teamId = await resolveDefaultTeamId(config, false, opts?.requestTimeout);
|
|
2477
|
+
if (teamId === null) throw new Error(`vault secret "${name}" not found`);
|
|
2478
|
+
const secretId = await _Vault._resolveSecretId(config, teamId, name, opts?.requestTimeout);
|
|
2479
|
+
const client = getSharedClient(config);
|
|
2480
|
+
await client.post(
|
|
2481
|
+
`/teams/${encodeURIComponent(teamId)}/vault/secrets/${encodeURIComponent(secretId)}/scopes`,
|
|
2482
|
+
{ json: { scopes: scopes.map(vaultScopeToJSON) }, timeout: opts?.requestTimeout }
|
|
2483
|
+
);
|
|
2484
|
+
}
|
|
2485
|
+
// -------------------------------------------------------------------------
|
|
2486
|
+
// Presets
|
|
2487
|
+
// -------------------------------------------------------------------------
|
|
2488
|
+
/**
|
|
2489
|
+
* List built-in provider preset catalog (templates only, no secret material).
|
|
2490
|
+
*
|
|
2491
|
+
* GET /vault/presets -> {presets}
|
|
2492
|
+
*/
|
|
2493
|
+
static async listPresets(opts) {
|
|
2494
|
+
const client = getSharedClient(buildConfig(opts));
|
|
2495
|
+
const resp = await client.get("/vault/presets", {
|
|
2496
|
+
timeout: opts?.requestTimeout
|
|
2497
|
+
});
|
|
2498
|
+
const rows = resp.presets ?? [];
|
|
2499
|
+
return rows.map(parseVaultPreset);
|
|
2500
|
+
}
|
|
2501
|
+
// -------------------------------------------------------------------------
|
|
2502
|
+
// Internal helpers
|
|
2503
|
+
// -------------------------------------------------------------------------
|
|
2504
|
+
/** Maps a secret name to its id within the given team. */
|
|
2505
|
+
static async _resolveSecretId(config, teamId, name, timeout) {
|
|
2506
|
+
const client = getSharedClient(config);
|
|
2507
|
+
const resp = await client.get(
|
|
2508
|
+
`/teams/${encodeURIComponent(teamId)}/vault/secrets`,
|
|
2509
|
+
{ timeout }
|
|
2510
|
+
);
|
|
2511
|
+
const rows = resp.secrets ?? [];
|
|
2512
|
+
for (const s of rows) {
|
|
2513
|
+
if (s.name === name) return String(s.secret_id ?? "");
|
|
2514
|
+
}
|
|
2515
|
+
throw new Error(`vault secret "${name}" not found`);
|
|
2516
|
+
}
|
|
2517
|
+
};
|
|
2518
|
+
|
|
2207
2519
|
// src/sandbox/sandbox.ts
|
|
2208
2520
|
var DEFAULT_TEMPLATE = "base";
|
|
2209
2521
|
var DEFAULT_TIMEOUT = 300;
|
|
@@ -2349,6 +2661,9 @@ var Sandbox = class _Sandbox {
|
|
|
2349
2661
|
if (opts?.envs) {
|
|
2350
2662
|
body.envs = opts.envs;
|
|
2351
2663
|
}
|
|
2664
|
+
if (opts?.vaultRefs) {
|
|
2665
|
+
body.vault_refs = await expandVaultRefs(config, opts.vaultRefs, opts.requestTimeout);
|
|
2666
|
+
}
|
|
2352
2667
|
if (opts?.network) {
|
|
2353
2668
|
body.network = networkOptsToJSON(opts.network);
|
|
2354
2669
|
} else if (opts?.allowInternetAccess === false) {
|
|
@@ -3252,7 +3567,16 @@ function assertValidVolumeId3(id) {
|
|
|
3252
3567
|
}
|
|
3253
3568
|
}
|
|
3254
3569
|
var Volumes = class {
|
|
3255
|
-
/**
|
|
3570
|
+
/**
|
|
3571
|
+
* Create a volume named `name`, optionally populated with `data`.
|
|
3572
|
+
*
|
|
3573
|
+
* `POST /volumes` is the canonical create endpoint. With `data` (a gzip tar.gz)
|
|
3574
|
+
* the body is ingested into a new file-granular volume (or a legacy tarball
|
|
3575
|
+
* blob if no file-granular backend is configured). Creating an empty volume
|
|
3576
|
+
* (no `data`, or an empty buffer) requires a file-granular backend.
|
|
3577
|
+
* `empty(name)` / `ingest(name, data)` remain available for explicit,
|
|
3578
|
+
* backend-specific control.
|
|
3579
|
+
*/
|
|
3256
3580
|
static async create(name, data, opts) {
|
|
3257
3581
|
if (!name) {
|
|
3258
3582
|
throw new InvalidArgumentError("volume name is required");
|
|
@@ -3264,6 +3588,13 @@ var Volumes = class {
|
|
|
3264
3588
|
requestTimeout: opts?.requestTimeout
|
|
3265
3589
|
});
|
|
3266
3590
|
const client = getSharedClient(config);
|
|
3591
|
+
if (data === void 0 || data.byteLength === 0) {
|
|
3592
|
+
const resp2 = await client.post("/volumes", {
|
|
3593
|
+
params: { name },
|
|
3594
|
+
timeout: opts?.requestTimeout
|
|
3595
|
+
});
|
|
3596
|
+
return parseVolumeInfo(resp2);
|
|
3597
|
+
}
|
|
3267
3598
|
const body = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
3268
3599
|
const resp = await client.post("/volumes", {
|
|
3269
3600
|
params: { name },
|
|
@@ -3568,6 +3899,7 @@ var Governance = class {
|
|
|
3568
3899
|
TemplateError,
|
|
3569
3900
|
TimeoutError,
|
|
3570
3901
|
TransformDirection,
|
|
3902
|
+
Vault,
|
|
3571
3903
|
VolumeFiles,
|
|
3572
3904
|
VolumeLocks,
|
|
3573
3905
|
Volumes,
|
|
@@ -3619,6 +3951,9 @@ var Governance = class {
|
|
|
3619
3951
|
parseSnapshotInfo,
|
|
3620
3952
|
parseTemplateBuildStatus,
|
|
3621
3953
|
parseToxicityConfig,
|
|
3954
|
+
parseVaultPreset,
|
|
3955
|
+
parseVaultScope,
|
|
3956
|
+
parseVaultSecret,
|
|
3622
3957
|
parseVolumeInfo,
|
|
3623
3958
|
parseWriteInfo,
|
|
3624
3959
|
requiresTlsInterception,
|
|
@@ -3626,6 +3961,7 @@ var Governance = class {
|
|
|
3626
3961
|
securityPolicyToJSON,
|
|
3627
3962
|
toxicityConfigToJSON,
|
|
3628
3963
|
validateNetworkEntry,
|
|
3964
|
+
vaultScopeToJSON,
|
|
3629
3965
|
volumeAttachmentToJSON
|
|
3630
3966
|
});
|
|
3631
3967
|
//# sourceMappingURL=index.cjs.map
|