@declaw/sdk 1.1.13 → 1.2.1
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 +36 -0
- package/LICENSE +1 -1
- package/dist/index.cjs +582 -11
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +327 -12
- package/dist/index.d.ts +327 -12
- package/dist/index.js +570 -11
- package/dist/index.js.map +1 -1
- package/package.json +7 -1
package/dist/index.cjs
CHANGED
|
@@ -37,6 +37,7 @@ __export(index_exports, {
|
|
|
37
37
|
CommandExitError: () => CommandExitError,
|
|
38
38
|
CommandHandle: () => CommandHandle,
|
|
39
39
|
Commands: () => Commands,
|
|
40
|
+
ConflictError: () => ConflictError,
|
|
40
41
|
ConnectionConfig: () => ConnectionConfig,
|
|
41
42
|
DEFAULT_MASK_PATTERNS: () => DEFAULT_MASK_PATTERNS,
|
|
42
43
|
FileType: () => FileType,
|
|
@@ -45,6 +46,7 @@ __export(index_exports, {
|
|
|
45
46
|
FilesystemEventType: () => FilesystemEventType,
|
|
46
47
|
GitAuthError: () => GitAuthError,
|
|
47
48
|
GitUpstreamError: () => GitUpstreamError,
|
|
49
|
+
Governance: () => Governance,
|
|
48
50
|
InjectionAction: () => InjectionAction,
|
|
49
51
|
InjectionSensitivity: () => InjectionSensitivity,
|
|
50
52
|
InvalidArgumentError: () => InvalidArgumentError,
|
|
@@ -66,12 +68,16 @@ __export(index_exports, {
|
|
|
66
68
|
TemplateError: () => TemplateError,
|
|
67
69
|
TimeoutError: () => TimeoutError,
|
|
68
70
|
TransformDirection: () => TransformDirection,
|
|
71
|
+
VolumeFiles: () => VolumeFiles,
|
|
72
|
+
VolumeLocks: () => VolumeLocks,
|
|
69
73
|
Volumes: () => Volumes,
|
|
70
74
|
WatchHandle: () => WatchHandle,
|
|
71
75
|
applyTransformation: () => applyTransformation,
|
|
72
76
|
codeSecurityConfigToJSON: () => codeSecurityConfigToJSON,
|
|
77
|
+
contentGateConfigToJSON: () => contentGateConfigToJSON,
|
|
73
78
|
createAuditConfig: () => createAuditConfig,
|
|
74
79
|
createCodeSecurityConfig: () => createCodeSecurityConfig,
|
|
80
|
+
createContentGateConfig: () => createContentGateConfig,
|
|
75
81
|
createEnvSecurityConfig: () => createEnvSecurityConfig,
|
|
76
82
|
createInjectionDefenseConfig: () => createInjectionDefenseConfig,
|
|
77
83
|
createInvisibleTextConfig: () => createInvisibleTextConfig,
|
|
@@ -90,11 +96,17 @@ __export(index_exports, {
|
|
|
90
96
|
parseBuildInfo: () => parseBuildInfo,
|
|
91
97
|
parseCodeSecurityConfig: () => parseCodeSecurityConfig,
|
|
92
98
|
parseCommandResult: () => parseCommandResult,
|
|
99
|
+
parseContentGateConfig: () => parseContentGateConfig,
|
|
93
100
|
parseEntryInfo: () => parseEntryInfo,
|
|
94
101
|
parseEnvSecurityConfig: () => parseEnvSecurityConfig,
|
|
102
|
+
parseFileEntry: () => parseFileEntry,
|
|
103
|
+
parseFileInfo: () => parseFileInfo,
|
|
95
104
|
parseFilesystemEvent: () => parseFilesystemEvent,
|
|
105
|
+
parseGovernancePack: () => parseGovernancePack,
|
|
96
106
|
parseInjectionDefenseConfig: () => parseInjectionDefenseConfig,
|
|
97
107
|
parseInvisibleTextConfig: () => parseInvisibleTextConfig,
|
|
108
|
+
parseLockLease: () => parseLockLease,
|
|
109
|
+
parseLockStatus: () => parseLockStatus,
|
|
98
110
|
parseNetworkPolicy: () => parseNetworkPolicy,
|
|
99
111
|
parsePIIConfig: () => parsePIIConfig,
|
|
100
112
|
parseProcessInfo: () => parseProcessInfo,
|
|
@@ -191,6 +203,12 @@ var NotEnoughSpaceError = class extends SandboxError {
|
|
|
191
203
|
this.name = "NotEnoughSpaceError";
|
|
192
204
|
}
|
|
193
205
|
};
|
|
206
|
+
var ConflictError = class extends SandboxError {
|
|
207
|
+
constructor(message, opts) {
|
|
208
|
+
super(message, opts);
|
|
209
|
+
this.name = "ConflictError";
|
|
210
|
+
}
|
|
211
|
+
};
|
|
194
212
|
var TemplateError = class extends SandboxError {
|
|
195
213
|
constructor(message, opts) {
|
|
196
214
|
super(message, opts);
|
|
@@ -236,6 +254,8 @@ var CommandExitError = class extends SandboxError {
|
|
|
236
254
|
|
|
237
255
|
// src/api/client.ts
|
|
238
256
|
var _dispatcherPromise;
|
|
257
|
+
var _resolvedDispatcher;
|
|
258
|
+
var _dispatcherResolved = false;
|
|
239
259
|
function getDispatcher() {
|
|
240
260
|
if (_dispatcherPromise) return _dispatcherPromise;
|
|
241
261
|
_dispatcherPromise = (async () => {
|
|
@@ -260,7 +280,14 @@ function getDispatcher() {
|
|
|
260
280
|
maxConcurrentStreams,
|
|
261
281
|
keepAliveTimeout: 3e4,
|
|
262
282
|
keepAliveMaxTimeout: 6e4,
|
|
263
|
-
|
|
283
|
+
// NOTE: do NOT set `pipelining` here. undici applies it to H2 sessions
|
|
284
|
+
// too, where `pipelining: 1` caps each connection to ONE in-flight
|
|
285
|
+
// stream — silently defeating the H2 multiplexing that allowH2 enables.
|
|
286
|
+
// Omitted, H2 sessions default to unlimited concurrent streams (capped
|
|
287
|
+
// by maxConcurrentStreams) and H1.1 fallback defaults to 1 (safe, no
|
|
288
|
+
// head-of-line risk on non-idempotent POSTs). This is the single
|
|
289
|
+
// biggest burst-latency lever: with pipelining:1 a 100-concurrent burst
|
|
290
|
+
// queued ~36 requests behind the `connections` cap.
|
|
264
291
|
allowH2: true,
|
|
265
292
|
connect: { keepAlive: true, keepAliveInitialDelay: 5e3 }
|
|
266
293
|
});
|
|
@@ -268,13 +295,21 @@ function getDispatcher() {
|
|
|
268
295
|
return void 0;
|
|
269
296
|
}
|
|
270
297
|
})();
|
|
298
|
+
void _dispatcherPromise.then((d) => {
|
|
299
|
+
_resolvedDispatcher = d;
|
|
300
|
+
_dispatcherResolved = true;
|
|
301
|
+
});
|
|
271
302
|
return _dispatcherPromise;
|
|
272
303
|
}
|
|
304
|
+
void getDispatcher();
|
|
273
305
|
var STATUS_ERROR_MAP = {
|
|
306
|
+
400: InvalidArgumentError,
|
|
274
307
|
401: AuthenticationError,
|
|
275
308
|
403: AuthenticationError,
|
|
276
309
|
404: NotFoundError,
|
|
277
310
|
408: TimeoutError,
|
|
311
|
+
409: ConflictError,
|
|
312
|
+
413: NotEnoughSpaceError,
|
|
278
313
|
422: InvalidArgumentError,
|
|
279
314
|
507: NotEnoughSpaceError
|
|
280
315
|
};
|
|
@@ -286,7 +321,7 @@ var ApiClient = class {
|
|
|
286
321
|
constructor(config, opts) {
|
|
287
322
|
this.config = config ?? new ConnectionConfig();
|
|
288
323
|
this.maxRetries = opts?.maxRetries ?? 3;
|
|
289
|
-
this.retryDelay = opts?.retryDelay ?? 0.
|
|
324
|
+
this.retryDelay = opts?.retryDelay ?? 0.1;
|
|
290
325
|
this.abortController = new AbortController();
|
|
291
326
|
}
|
|
292
327
|
/** Send a GET request and return parsed JSON. */
|
|
@@ -380,7 +415,7 @@ var ApiClient = class {
|
|
|
380
415
|
signals.push(AbortSignal.timeout(timeoutMs));
|
|
381
416
|
}
|
|
382
417
|
const signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
|
|
383
|
-
const dispatcher = await getDispatcher();
|
|
418
|
+
const dispatcher = _dispatcherResolved ? _resolvedDispatcher : await getDispatcher();
|
|
384
419
|
const fetchOpts = {
|
|
385
420
|
method,
|
|
386
421
|
headers,
|
|
@@ -933,6 +968,49 @@ function invisibleTextConfigToJSON(config) {
|
|
|
933
968
|
return result;
|
|
934
969
|
}
|
|
935
970
|
|
|
971
|
+
// src/security/customPolicy.ts
|
|
972
|
+
function parseCustomPolicyConfig(data) {
|
|
973
|
+
return {
|
|
974
|
+
enabled: data.enabled ?? false,
|
|
975
|
+
inlineRego: data.inline_rego ?? data.inlineRego,
|
|
976
|
+
inlineModules: data.inline_modules ?? data.inlineModules,
|
|
977
|
+
policyRef: data.policy_ref ?? data.policyRef,
|
|
978
|
+
defaultDeny: data.default_deny ?? data.defaultDeny ?? false
|
|
979
|
+
};
|
|
980
|
+
}
|
|
981
|
+
function customPolicyConfigToJSON(config) {
|
|
982
|
+
return {
|
|
983
|
+
enabled: config.enabled,
|
|
984
|
+
inline_rego: config.inlineRego,
|
|
985
|
+
inline_modules: config.inlineModules,
|
|
986
|
+
policy_ref: config.policyRef,
|
|
987
|
+
default_deny: config.defaultDeny
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
// src/security/contentGate.ts
|
|
992
|
+
function createContentGateConfig(opts) {
|
|
993
|
+
return {
|
|
994
|
+
enabled: opts?.enabled ?? false,
|
|
995
|
+
domains: opts?.domains
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
function parseContentGateConfig(data) {
|
|
999
|
+
return {
|
|
1000
|
+
enabled: data.enabled ?? false,
|
|
1001
|
+
domains: data.domains
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
function contentGateConfigToJSON(config) {
|
|
1005
|
+
const result = {
|
|
1006
|
+
enabled: config.enabled
|
|
1007
|
+
};
|
|
1008
|
+
if (config.domains !== void 0) {
|
|
1009
|
+
result.domains = config.domains;
|
|
1010
|
+
}
|
|
1011
|
+
return result;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
936
1014
|
// src/security/policy.ts
|
|
937
1015
|
function createSecurityPolicy(opts) {
|
|
938
1016
|
return {
|
|
@@ -944,12 +1022,16 @@ function createSecurityPolicy(opts) {
|
|
|
944
1022
|
envSecurity: opts?.envSecurity ?? createEnvSecurityConfig(),
|
|
945
1023
|
toxicity: opts?.toxicity,
|
|
946
1024
|
codeSecurity: opts?.codeSecurity,
|
|
947
|
-
invisibleText: opts?.invisibleText
|
|
1025
|
+
invisibleText: opts?.invisibleText,
|
|
1026
|
+
contentGate: opts?.contentGate,
|
|
1027
|
+
customPolicy: opts?.customPolicy
|
|
948
1028
|
};
|
|
949
1029
|
}
|
|
950
1030
|
function parseSecurityPolicy(data) {
|
|
951
1031
|
const injDef = data.injection_defense ?? data.injectionDefense;
|
|
952
1032
|
const auditData = data.audit;
|
|
1033
|
+
const customPolicyData = data.custom_policy ?? data.customPolicy;
|
|
1034
|
+
const contentGateData = data.content_gate ?? data.contentGate;
|
|
953
1035
|
return {
|
|
954
1036
|
pii: data.pii ? parsePIIConfig(data.pii) : createPIIConfig(),
|
|
955
1037
|
injectionDefense: typeof injDef === "boolean" ? injDef : injDef ? parseInjectionDefenseConfig(injDef) : false,
|
|
@@ -959,7 +1041,9 @@ function parseSecurityPolicy(data) {
|
|
|
959
1041
|
envSecurity: data.env_security ?? data.envSecurity ? parseEnvSecurityConfig(data.env_security ?? data.envSecurity) : createEnvSecurityConfig(),
|
|
960
1042
|
toxicity: data.toxicity ? parseToxicityConfig(data.toxicity) : void 0,
|
|
961
1043
|
codeSecurity: data.code_security ?? data.codeSecurity ? parseCodeSecurityConfig(data.code_security ?? data.codeSecurity) : void 0,
|
|
962
|
-
invisibleText: data.invisible_text ?? data.invisibleText ? parseInvisibleTextConfig(data.invisible_text ?? data.invisibleText) : void 0
|
|
1044
|
+
invisibleText: data.invisible_text ?? data.invisibleText ? parseInvisibleTextConfig(data.invisible_text ?? data.invisibleText) : void 0,
|
|
1045
|
+
contentGate: contentGateData ? parseContentGateConfig(contentGateData) : void 0,
|
|
1046
|
+
customPolicy: customPolicyData ? parseCustomPolicyConfig(customPolicyData) : void 0
|
|
963
1047
|
};
|
|
964
1048
|
}
|
|
965
1049
|
function securityPolicyToJSON(policy) {
|
|
@@ -1009,6 +1093,12 @@ function securityPolicyToJSON(policy) {
|
|
|
1009
1093
|
if (policy.invisibleText) {
|
|
1010
1094
|
result.invisible_text = invisibleTextConfigToJSON(policy.invisibleText);
|
|
1011
1095
|
}
|
|
1096
|
+
if (policy.contentGate) {
|
|
1097
|
+
result.content_gate = contentGateConfigToJSON(policy.contentGate);
|
|
1098
|
+
}
|
|
1099
|
+
if (policy.customPolicy) {
|
|
1100
|
+
result.custom_policy = customPolicyConfigToJSON(policy.customPolicy);
|
|
1101
|
+
}
|
|
1012
1102
|
return result;
|
|
1013
1103
|
}
|
|
1014
1104
|
function requiresTlsInterception(policy) {
|
|
@@ -2027,11 +2117,53 @@ function parseVolumeInfo(data) {
|
|
|
2027
2117
|
sizeBytes: Number(data.size_bytes ?? 0),
|
|
2028
2118
|
contentType: String(data.content_type ?? ""),
|
|
2029
2119
|
metadata: data.metadata ?? {},
|
|
2030
|
-
createdAt: String(data.created_at ?? "")
|
|
2120
|
+
createdAt: String(data.created_at ?? ""),
|
|
2121
|
+
backend: String(data.backend ?? ""),
|
|
2122
|
+
quotaBytes: Number(data.quota_bytes ?? 0),
|
|
2123
|
+
updatedAt: String(data.updated_at ?? "")
|
|
2124
|
+
};
|
|
2125
|
+
}
|
|
2126
|
+
function parseFileEntry(data) {
|
|
2127
|
+
return {
|
|
2128
|
+
name: String(data.name ?? ""),
|
|
2129
|
+
path: String(data.path ?? ""),
|
|
2130
|
+
isDir: Boolean(data.is_dir ?? false),
|
|
2131
|
+
size: Number(data.size ?? 0),
|
|
2132
|
+
modTime: String(data.mod_time ?? ""),
|
|
2133
|
+
mode: Number(data.mode ?? 0)
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
function parseFileInfo(data) {
|
|
2137
|
+
return {
|
|
2138
|
+
...parseFileEntry(data),
|
|
2139
|
+
version: String(data.version ?? "")
|
|
2140
|
+
};
|
|
2141
|
+
}
|
|
2142
|
+
function parseLockLease(data) {
|
|
2143
|
+
return {
|
|
2144
|
+
token: String(data.token ?? ""),
|
|
2145
|
+
ttlSeconds: Number(data.ttl_seconds ?? 0),
|
|
2146
|
+
expiresAt: String(data.expires_at ?? "")
|
|
2147
|
+
};
|
|
2148
|
+
}
|
|
2149
|
+
function parseLockStatus(data) {
|
|
2150
|
+
return {
|
|
2151
|
+
held: Boolean(data.held ?? false),
|
|
2152
|
+
expiresInMs: Number(data.expires_in_ms ?? 0)
|
|
2031
2153
|
};
|
|
2032
2154
|
}
|
|
2033
2155
|
function volumeAttachmentToJSON(att) {
|
|
2034
|
-
|
|
2156
|
+
const out = {
|
|
2157
|
+
volume_id: att.volumeId,
|
|
2158
|
+
mount_path: att.mountPath
|
|
2159
|
+
};
|
|
2160
|
+
if (att.mode) {
|
|
2161
|
+
out.mode = att.mode;
|
|
2162
|
+
}
|
|
2163
|
+
if (att.subpath) {
|
|
2164
|
+
out.subpath = att.subpath;
|
|
2165
|
+
}
|
|
2166
|
+
return out;
|
|
2035
2167
|
}
|
|
2036
2168
|
|
|
2037
2169
|
// src/sandbox/sandbox.ts
|
|
@@ -2857,7 +2989,7 @@ var Template = class {
|
|
|
2857
2989
|
}
|
|
2858
2990
|
};
|
|
2859
2991
|
|
|
2860
|
-
// src/volumes/
|
|
2992
|
+
// src/volumes/files.ts
|
|
2861
2993
|
var VALID_VOLUME_ID_RE = /^[a-zA-Z0-9_-]+$/;
|
|
2862
2994
|
function assertValidVolumeId(id) {
|
|
2863
2995
|
if (!id || !VALID_VOLUME_ID_RE.test(id)) {
|
|
@@ -2866,8 +2998,223 @@ function assertValidVolumeId(id) {
|
|
|
2866
2998
|
);
|
|
2867
2999
|
}
|
|
2868
3000
|
}
|
|
3001
|
+
var VolumeFiles = class {
|
|
3002
|
+
volumeId;
|
|
3003
|
+
opts;
|
|
3004
|
+
constructor(volumeId, opts) {
|
|
3005
|
+
assertValidVolumeId(volumeId);
|
|
3006
|
+
this.volumeId = volumeId;
|
|
3007
|
+
this.opts = opts;
|
|
3008
|
+
}
|
|
3009
|
+
client() {
|
|
3010
|
+
const config = new ConnectionConfig({
|
|
3011
|
+
apiKey: this.opts?.apiKey,
|
|
3012
|
+
domain: this.opts?.domain,
|
|
3013
|
+
apiUrl: this.opts?.apiUrl,
|
|
3014
|
+
requestTimeout: this.opts?.requestTimeout
|
|
3015
|
+
});
|
|
3016
|
+
return getSharedClient(config);
|
|
3017
|
+
}
|
|
3018
|
+
timeout() {
|
|
3019
|
+
return this.opts?.requestTimeout;
|
|
3020
|
+
}
|
|
3021
|
+
/** Write raw bytes to `path`. Optionally conditional on `ifVersion` (CAS). */
|
|
3022
|
+
async write(path, data, opts) {
|
|
3023
|
+
if (!path) {
|
|
3024
|
+
throw new InvalidArgumentError("path is required");
|
|
3025
|
+
}
|
|
3026
|
+
const params = { path };
|
|
3027
|
+
if (opts?.ifVersion) {
|
|
3028
|
+
params.if_version = opts.ifVersion;
|
|
3029
|
+
}
|
|
3030
|
+
const body = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
3031
|
+
const resp = await this.client().put(`/volumes/${this.volumeId}/files/raw`, {
|
|
3032
|
+
params,
|
|
3033
|
+
body,
|
|
3034
|
+
headers: { "Content-Type": "application/octet-stream" },
|
|
3035
|
+
timeout: opts?.requestTimeout ?? this.timeout()
|
|
3036
|
+
});
|
|
3037
|
+
return String(resp.path ?? path);
|
|
3038
|
+
}
|
|
3039
|
+
/** Read raw bytes from `path`. */
|
|
3040
|
+
async read(path) {
|
|
3041
|
+
if (!path) {
|
|
3042
|
+
throw new InvalidArgumentError("path is required");
|
|
3043
|
+
}
|
|
3044
|
+
return this.client().getBytes(`/volumes/${this.volumeId}/files/raw`, {
|
|
3045
|
+
params: { path },
|
|
3046
|
+
timeout: this.timeout()
|
|
3047
|
+
});
|
|
3048
|
+
}
|
|
3049
|
+
/** List directory entries under `path`. */
|
|
3050
|
+
async list(path) {
|
|
3051
|
+
if (!path) {
|
|
3052
|
+
throw new InvalidArgumentError("path is required");
|
|
3053
|
+
}
|
|
3054
|
+
const resp = await this.client().get(`/volumes/${this.volumeId}/files/list`, {
|
|
3055
|
+
params: { path },
|
|
3056
|
+
timeout: this.timeout()
|
|
3057
|
+
});
|
|
3058
|
+
const rows = resp.entries ?? [];
|
|
3059
|
+
return rows.map(parseFileEntry);
|
|
3060
|
+
}
|
|
3061
|
+
/** Stat `path`, returning the entry plus the CAS `version` token. */
|
|
3062
|
+
async info(path) {
|
|
3063
|
+
if (!path) {
|
|
3064
|
+
throw new InvalidArgumentError("path is required");
|
|
3065
|
+
}
|
|
3066
|
+
const resp = await this.client().get(`/volumes/${this.volumeId}/files/info`, {
|
|
3067
|
+
params: { path },
|
|
3068
|
+
timeout: this.timeout()
|
|
3069
|
+
});
|
|
3070
|
+
return parseFileInfo(resp);
|
|
3071
|
+
}
|
|
3072
|
+
/** Return whether `path` exists. */
|
|
3073
|
+
async exists(path) {
|
|
3074
|
+
if (!path) {
|
|
3075
|
+
throw new InvalidArgumentError("path is required");
|
|
3076
|
+
}
|
|
3077
|
+
const resp = await this.client().get(`/volumes/${this.volumeId}/files/exists`, {
|
|
3078
|
+
params: { path },
|
|
3079
|
+
timeout: this.timeout()
|
|
3080
|
+
});
|
|
3081
|
+
return Boolean(resp.exists ?? false);
|
|
3082
|
+
}
|
|
3083
|
+
/** Remove `path`. Pass `{ recursive: true }` to remove a directory tree. */
|
|
3084
|
+
async remove(path, opts) {
|
|
3085
|
+
if (!path) {
|
|
3086
|
+
throw new InvalidArgumentError("path is required");
|
|
3087
|
+
}
|
|
3088
|
+
const params = {
|
|
3089
|
+
path,
|
|
3090
|
+
recursive: opts?.recursive ? "true" : "false"
|
|
3091
|
+
};
|
|
3092
|
+
await this.client().delete(`/volumes/${this.volumeId}/files`, {
|
|
3093
|
+
params,
|
|
3094
|
+
timeout: opts?.requestTimeout ?? this.timeout()
|
|
3095
|
+
});
|
|
3096
|
+
}
|
|
3097
|
+
/** Rename `oldPath` to `newPath`. */
|
|
3098
|
+
async rename(oldPath, newPath) {
|
|
3099
|
+
if (!oldPath || !newPath) {
|
|
3100
|
+
throw new InvalidArgumentError("oldPath and newPath are required");
|
|
3101
|
+
}
|
|
3102
|
+
const resp = await this.client().patch(`/volumes/${this.volumeId}/files`, {
|
|
3103
|
+
json: { old_path: oldPath, new_path: newPath },
|
|
3104
|
+
timeout: this.timeout()
|
|
3105
|
+
});
|
|
3106
|
+
return {
|
|
3107
|
+
oldPath: String(resp.old_path ?? oldPath),
|
|
3108
|
+
newPath: String(resp.new_path ?? newPath)
|
|
3109
|
+
};
|
|
3110
|
+
}
|
|
3111
|
+
/** Create a directory at `path`. */
|
|
3112
|
+
async mkdir(path) {
|
|
3113
|
+
if (!path) {
|
|
3114
|
+
throw new InvalidArgumentError("path is required");
|
|
3115
|
+
}
|
|
3116
|
+
const resp = await this.client().post(`/volumes/${this.volumeId}/files/mkdir`, {
|
|
3117
|
+
json: { path },
|
|
3118
|
+
timeout: this.timeout()
|
|
3119
|
+
});
|
|
3120
|
+
return String(resp.path ?? path);
|
|
3121
|
+
}
|
|
3122
|
+
};
|
|
3123
|
+
|
|
3124
|
+
// src/volumes/locks.ts
|
|
3125
|
+
var VALID_VOLUME_ID_RE2 = /^[a-zA-Z0-9_-]+$/;
|
|
3126
|
+
function assertValidVolumeId2(id) {
|
|
3127
|
+
if (!id || !VALID_VOLUME_ID_RE2.test(id)) {
|
|
3128
|
+
throw new InvalidArgumentError(
|
|
3129
|
+
`Invalid volume ID: "${id}". Must be alphanumeric with hyphens/underscores only.`
|
|
3130
|
+
);
|
|
3131
|
+
}
|
|
3132
|
+
}
|
|
3133
|
+
var VolumeLocks = class {
|
|
3134
|
+
volumeId;
|
|
3135
|
+
opts;
|
|
3136
|
+
constructor(volumeId, opts) {
|
|
3137
|
+
assertValidVolumeId2(volumeId);
|
|
3138
|
+
this.volumeId = volumeId;
|
|
3139
|
+
this.opts = opts;
|
|
3140
|
+
}
|
|
3141
|
+
client() {
|
|
3142
|
+
const config = new ConnectionConfig({
|
|
3143
|
+
apiKey: this.opts?.apiKey,
|
|
3144
|
+
domain: this.opts?.domain,
|
|
3145
|
+
apiUrl: this.opts?.apiUrl,
|
|
3146
|
+
requestTimeout: this.opts?.requestTimeout
|
|
3147
|
+
});
|
|
3148
|
+
return getSharedClient(config);
|
|
3149
|
+
}
|
|
3150
|
+
timeout() {
|
|
3151
|
+
return this.opts?.requestTimeout;
|
|
3152
|
+
}
|
|
3153
|
+
/** Acquire a lock on `path`. Throws ConflictError (409) if already held. */
|
|
3154
|
+
async acquire(path, ttlSeconds) {
|
|
3155
|
+
if (!path) {
|
|
3156
|
+
throw new InvalidArgumentError("path is required");
|
|
3157
|
+
}
|
|
3158
|
+
const json = { path };
|
|
3159
|
+
if (ttlSeconds !== void 0) {
|
|
3160
|
+
json.ttl_seconds = ttlSeconds;
|
|
3161
|
+
}
|
|
3162
|
+
const resp = await this.client().post(`/volumes/${this.volumeId}/locks`, {
|
|
3163
|
+
json,
|
|
3164
|
+
timeout: this.timeout()
|
|
3165
|
+
});
|
|
3166
|
+
return parseLockLease(resp);
|
|
3167
|
+
}
|
|
3168
|
+
/** Release a lock on `path` held under `token`. Throws ConflictError (409) if not the holder. */
|
|
3169
|
+
async release(path, token) {
|
|
3170
|
+
if (!path || !token) {
|
|
3171
|
+
throw new InvalidArgumentError("path and token are required");
|
|
3172
|
+
}
|
|
3173
|
+
const resp = await this.client().delete(`/volumes/${this.volumeId}/locks`, {
|
|
3174
|
+
json: { path, token },
|
|
3175
|
+
timeout: this.timeout()
|
|
3176
|
+
});
|
|
3177
|
+
return Boolean(resp.released ?? false);
|
|
3178
|
+
}
|
|
3179
|
+
/** Renew a lock on `path` held under `token`. Throws ConflictError (409) if not the holder. */
|
|
3180
|
+
async renew(path, token, ttlSeconds) {
|
|
3181
|
+
if (!path || !token) {
|
|
3182
|
+
throw new InvalidArgumentError("path and token are required");
|
|
3183
|
+
}
|
|
3184
|
+
const json = { path, token };
|
|
3185
|
+
if (ttlSeconds !== void 0) {
|
|
3186
|
+
json.ttl_seconds = ttlSeconds;
|
|
3187
|
+
}
|
|
3188
|
+
const resp = await this.client().post(`/volumes/${this.volumeId}/locks/renew`, {
|
|
3189
|
+
json,
|
|
3190
|
+
timeout: this.timeout()
|
|
3191
|
+
});
|
|
3192
|
+
return { ...parseLockLease(resp), token };
|
|
3193
|
+
}
|
|
3194
|
+
/** Query whether `path` is currently locked. */
|
|
3195
|
+
async status(path) {
|
|
3196
|
+
if (!path) {
|
|
3197
|
+
throw new InvalidArgumentError("path is required");
|
|
3198
|
+
}
|
|
3199
|
+
const resp = await this.client().get(`/volumes/${this.volumeId}/locks`, {
|
|
3200
|
+
params: { path },
|
|
3201
|
+
timeout: this.timeout()
|
|
3202
|
+
});
|
|
3203
|
+
return parseLockStatus(resp);
|
|
3204
|
+
}
|
|
3205
|
+
};
|
|
3206
|
+
|
|
3207
|
+
// src/volumes/volumes.ts
|
|
3208
|
+
var VALID_VOLUME_ID_RE3 = /^[a-zA-Z0-9_-]+$/;
|
|
3209
|
+
function assertValidVolumeId3(id) {
|
|
3210
|
+
if (!id || !VALID_VOLUME_ID_RE3.test(id)) {
|
|
3211
|
+
throw new InvalidArgumentError(
|
|
3212
|
+
`Invalid volume ID: "${id}". Must be alphanumeric with hyphens/underscores only.`
|
|
3213
|
+
);
|
|
3214
|
+
}
|
|
3215
|
+
}
|
|
2869
3216
|
var Volumes = class {
|
|
2870
|
-
/** Create a volume by streaming a tarball to the server. */
|
|
3217
|
+
/** Create a volume by streaming a tarball (gzip tar.gz) to the server. */
|
|
2871
3218
|
static async create(name, data, opts) {
|
|
2872
3219
|
if (!name) {
|
|
2873
3220
|
throw new InvalidArgumentError("volume name is required");
|
|
@@ -2888,9 +3235,113 @@ var Volumes = class {
|
|
|
2888
3235
|
});
|
|
2889
3236
|
return parseVolumeInfo(resp);
|
|
2890
3237
|
}
|
|
3238
|
+
/**
|
|
3239
|
+
* Capture the attached volume's mount path in `sandboxId` into a NEW volume.
|
|
3240
|
+
*
|
|
3241
|
+
* The source volume is left unchanged. If `name` is omitted the server names
|
|
3242
|
+
* the new volume "<source-name>-commit". Returns the new VolumeInfo.
|
|
3243
|
+
*/
|
|
3244
|
+
static async commit(sandboxId, volumeId, name, opts) {
|
|
3245
|
+
if (!sandboxId || !VALID_VOLUME_ID_RE3.test(sandboxId)) {
|
|
3246
|
+
throw new InvalidArgumentError(
|
|
3247
|
+
`Invalid sandbox ID: "${sandboxId}". Must be alphanumeric with hyphens/underscores only.`
|
|
3248
|
+
);
|
|
3249
|
+
}
|
|
3250
|
+
assertValidVolumeId3(volumeId);
|
|
3251
|
+
const config = new ConnectionConfig({
|
|
3252
|
+
apiKey: opts?.apiKey,
|
|
3253
|
+
domain: opts?.domain,
|
|
3254
|
+
apiUrl: opts?.apiUrl,
|
|
3255
|
+
requestTimeout: opts?.requestTimeout
|
|
3256
|
+
});
|
|
3257
|
+
const client = getSharedClient(config);
|
|
3258
|
+
const resp = await client.post(`/sandboxes/${sandboxId}/volumes/${volumeId}/commit`, {
|
|
3259
|
+
params: name ? { name } : void 0,
|
|
3260
|
+
timeout: opts?.requestTimeout
|
|
3261
|
+
});
|
|
3262
|
+
return parseVolumeInfo(resp);
|
|
3263
|
+
}
|
|
3264
|
+
/**
|
|
3265
|
+
* Snapshot an arbitrary absolute in-sandbox `path` into a NEW volume.
|
|
3266
|
+
*
|
|
3267
|
+
* Unlike `commit` (which captures an already-attached volume's mount path),
|
|
3268
|
+
* `snapshot` captures any path in the running sandbox. `name` defaults to
|
|
3269
|
+
* "snapshot" on the server. Synthetic paths (/proc, /sys, /dev) are rejected.
|
|
3270
|
+
*/
|
|
3271
|
+
static async snapshot(sandboxId, path, name, opts) {
|
|
3272
|
+
if (!sandboxId || !VALID_VOLUME_ID_RE3.test(sandboxId)) {
|
|
3273
|
+
throw new InvalidArgumentError(
|
|
3274
|
+
`Invalid sandbox ID: "${sandboxId}". Must be alphanumeric with hyphens/underscores only.`
|
|
3275
|
+
);
|
|
3276
|
+
}
|
|
3277
|
+
if (!path) {
|
|
3278
|
+
throw new InvalidArgumentError("path is required");
|
|
3279
|
+
}
|
|
3280
|
+
const config = new ConnectionConfig({
|
|
3281
|
+
apiKey: opts?.apiKey,
|
|
3282
|
+
domain: opts?.domain,
|
|
3283
|
+
apiUrl: opts?.apiUrl,
|
|
3284
|
+
requestTimeout: opts?.requestTimeout
|
|
3285
|
+
});
|
|
3286
|
+
const client = getSharedClient(config);
|
|
3287
|
+
const params = { path };
|
|
3288
|
+
if (name) {
|
|
3289
|
+
params.name = name;
|
|
3290
|
+
}
|
|
3291
|
+
const resp = await client.post(`/sandboxes/${sandboxId}/volumes/snapshot`, {
|
|
3292
|
+
params,
|
|
3293
|
+
timeout: opts?.requestTimeout
|
|
3294
|
+
});
|
|
3295
|
+
return parseVolumeInfo(resp);
|
|
3296
|
+
}
|
|
3297
|
+
/**
|
|
3298
|
+
* Create an empty file-granular volume. Requires a file-granular backend
|
|
3299
|
+
* (503 if not configured). Returns the new VolumeInfo.
|
|
3300
|
+
*/
|
|
3301
|
+
static async empty(name, opts) {
|
|
3302
|
+
if (!name) {
|
|
3303
|
+
throw new InvalidArgumentError("volume name is required");
|
|
3304
|
+
}
|
|
3305
|
+
const config = new ConnectionConfig({
|
|
3306
|
+
apiKey: opts?.apiKey,
|
|
3307
|
+
domain: opts?.domain,
|
|
3308
|
+
apiUrl: opts?.apiUrl,
|
|
3309
|
+
requestTimeout: opts?.requestTimeout
|
|
3310
|
+
});
|
|
3311
|
+
const client = getSharedClient(config);
|
|
3312
|
+
const resp = await client.post("/volumes/empty", {
|
|
3313
|
+
params: { name },
|
|
3314
|
+
timeout: opts?.requestTimeout
|
|
3315
|
+
});
|
|
3316
|
+
return parseVolumeInfo(resp);
|
|
3317
|
+
}
|
|
3318
|
+
/**
|
|
3319
|
+
* Ingest a gzip tar.gz archive into a NEW file-granular volume. Requires a
|
|
3320
|
+
* file-granular backend (503 if not configured). 413 on quota exceeded.
|
|
3321
|
+
*/
|
|
3322
|
+
static async ingest(name, data, opts) {
|
|
3323
|
+
if (!name) {
|
|
3324
|
+
throw new InvalidArgumentError("volume name is required");
|
|
3325
|
+
}
|
|
3326
|
+
const config = new ConnectionConfig({
|
|
3327
|
+
apiKey: opts?.apiKey,
|
|
3328
|
+
domain: opts?.domain,
|
|
3329
|
+
apiUrl: opts?.apiUrl,
|
|
3330
|
+
requestTimeout: opts?.requestTimeout
|
|
3331
|
+
});
|
|
3332
|
+
const client = getSharedClient(config);
|
|
3333
|
+
const body = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
3334
|
+
const resp = await client.post("/volumes/ingest", {
|
|
3335
|
+
params: { name },
|
|
3336
|
+
body,
|
|
3337
|
+
headers: { "Content-Type": opts?.contentType ?? "application/gzip" },
|
|
3338
|
+
timeout: opts?.requestTimeout
|
|
3339
|
+
});
|
|
3340
|
+
return parseVolumeInfo(resp);
|
|
3341
|
+
}
|
|
2891
3342
|
/** Fetch metadata for a single volume. */
|
|
2892
3343
|
static async get(volumeId, opts) {
|
|
2893
|
-
|
|
3344
|
+
assertValidVolumeId3(volumeId);
|
|
2894
3345
|
const config = new ConnectionConfig({
|
|
2895
3346
|
apiKey: opts?.apiKey,
|
|
2896
3347
|
domain: opts?.domain,
|
|
@@ -2918,9 +3369,23 @@ var Volumes = class {
|
|
|
2918
3369
|
const rows = resp.volumes ?? [];
|
|
2919
3370
|
return rows.map(parseVolumeInfo);
|
|
2920
3371
|
}
|
|
3372
|
+
/** Download the volume's contents as raw bytes (the stored archive/blob). */
|
|
3373
|
+
static async download(volumeId, opts) {
|
|
3374
|
+
assertValidVolumeId3(volumeId);
|
|
3375
|
+
const config = new ConnectionConfig({
|
|
3376
|
+
apiKey: opts?.apiKey,
|
|
3377
|
+
domain: opts?.domain,
|
|
3378
|
+
apiUrl: opts?.apiUrl,
|
|
3379
|
+
requestTimeout: opts?.requestTimeout
|
|
3380
|
+
});
|
|
3381
|
+
const client = getSharedClient(config);
|
|
3382
|
+
return client.getBytes(`/volumes/${volumeId}/download`, {
|
|
3383
|
+
timeout: opts?.requestTimeout
|
|
3384
|
+
});
|
|
3385
|
+
}
|
|
2921
3386
|
/** Delete a volume and its blob. Idempotent on the wire. */
|
|
2922
3387
|
static async delete(volumeId, opts) {
|
|
2923
|
-
|
|
3388
|
+
assertValidVolumeId3(volumeId);
|
|
2924
3389
|
const config = new ConnectionConfig({
|
|
2925
3390
|
apiKey: opts?.apiKey,
|
|
2926
3391
|
domain: opts?.domain,
|
|
@@ -2930,6 +3395,100 @@ var Volumes = class {
|
|
|
2930
3395
|
const client = getSharedClient(config);
|
|
2931
3396
|
await client.delete(`/volumes/${volumeId}`, { timeout: opts?.requestTimeout });
|
|
2932
3397
|
}
|
|
3398
|
+
/**
|
|
3399
|
+
* File-granular operations (read/write/list/info/exists/remove/rename/mkdir,
|
|
3400
|
+
* plus CAS via `write(..., { ifVersion })`) on `volumeId`. File-granular
|
|
3401
|
+
* volumes only.
|
|
3402
|
+
*/
|
|
3403
|
+
static files(volumeId, opts) {
|
|
3404
|
+
return new VolumeFiles(volumeId, opts);
|
|
3405
|
+
}
|
|
3406
|
+
/** Advisory locks (acquire/release/renew/status) over a (volume, path). */
|
|
3407
|
+
static locks(volumeId, opts) {
|
|
3408
|
+
return new VolumeLocks(volumeId, opts);
|
|
3409
|
+
}
|
|
3410
|
+
};
|
|
3411
|
+
|
|
3412
|
+
// src/governance/models.ts
|
|
3413
|
+
function parseGovernanceControl(data) {
|
|
3414
|
+
return {
|
|
3415
|
+
control: String(data.control ?? ""),
|
|
3416
|
+
gate: String(data.gate ?? ""),
|
|
3417
|
+
rule: String(data.rule ?? ""),
|
|
3418
|
+
playbook: String(data.playbook ?? "")
|
|
3419
|
+
};
|
|
3420
|
+
}
|
|
3421
|
+
function parseGovernanceAdvisory(data) {
|
|
3422
|
+
return {
|
|
3423
|
+
control: String(data.control ?? ""),
|
|
3424
|
+
reason: String(data.reason ?? "")
|
|
3425
|
+
};
|
|
3426
|
+
}
|
|
3427
|
+
function parseGovernancePack(data) {
|
|
3428
|
+
const rawEnforces = data.enforces ?? [];
|
|
3429
|
+
const rawAdvisory = data.advisory ?? [];
|
|
3430
|
+
return {
|
|
3431
|
+
name: String(data.name ?? ""),
|
|
3432
|
+
version: String(data.version ?? ""),
|
|
3433
|
+
framework: String(data.framework ?? ""),
|
|
3434
|
+
description: String(data.description ?? ""),
|
|
3435
|
+
gates: data.gates ?? [],
|
|
3436
|
+
enforces: rawEnforces.map(parseGovernanceControl),
|
|
3437
|
+
advisory: rawAdvisory.map(parseGovernanceAdvisory),
|
|
3438
|
+
policyRef: String(data.policy_ref ?? data.policyRef ?? ""),
|
|
3439
|
+
seeded: Boolean(data.seeded ?? false)
|
|
3440
|
+
};
|
|
3441
|
+
}
|
|
3442
|
+
|
|
3443
|
+
// src/governance/governance.ts
|
|
3444
|
+
var VALID_PACK_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
3445
|
+
function assertValidPackName(name) {
|
|
3446
|
+
if (!name || !VALID_PACK_NAME_RE.test(name)) {
|
|
3447
|
+
throw new InvalidArgumentError(
|
|
3448
|
+
`Invalid pack name: "${name}". Must be alphanumeric with hyphens/underscores only.`
|
|
3449
|
+
);
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
var Governance = class {
|
|
3453
|
+
/**
|
|
3454
|
+
* List all available governance packs.
|
|
3455
|
+
*
|
|
3456
|
+
* Sends GET /governance/packs and returns the `packs` array.
|
|
3457
|
+
*/
|
|
3458
|
+
static async listPacks(opts) {
|
|
3459
|
+
const config = new ConnectionConfig({
|
|
3460
|
+
apiKey: opts?.apiKey,
|
|
3461
|
+
domain: opts?.domain,
|
|
3462
|
+
apiUrl: opts?.apiUrl,
|
|
3463
|
+
requestTimeout: opts?.requestTimeout
|
|
3464
|
+
});
|
|
3465
|
+
const client = getSharedClient(config);
|
|
3466
|
+
const resp = await client.get("/governance/packs", {
|
|
3467
|
+
timeout: opts?.requestTimeout
|
|
3468
|
+
});
|
|
3469
|
+
const rows = resp.packs ?? [];
|
|
3470
|
+
return rows.map(parseGovernancePack);
|
|
3471
|
+
}
|
|
3472
|
+
/**
|
|
3473
|
+
* Fetch a single governance pack by name.
|
|
3474
|
+
*
|
|
3475
|
+
* Sends GET /governance/packs/:name and returns the pack object.
|
|
3476
|
+
* Throws InvalidArgumentError if the name contains unsafe characters.
|
|
3477
|
+
*/
|
|
3478
|
+
static async getPack(name, opts) {
|
|
3479
|
+
assertValidPackName(name);
|
|
3480
|
+
const config = new ConnectionConfig({
|
|
3481
|
+
apiKey: opts?.apiKey,
|
|
3482
|
+
domain: opts?.domain,
|
|
3483
|
+
apiUrl: opts?.apiUrl,
|
|
3484
|
+
requestTimeout: opts?.requestTimeout
|
|
3485
|
+
});
|
|
3486
|
+
const client = getSharedClient(config);
|
|
3487
|
+
const resp = await client.get(`/governance/packs/${name}`, {
|
|
3488
|
+
timeout: opts?.requestTimeout
|
|
3489
|
+
});
|
|
3490
|
+
return parseGovernancePack(resp);
|
|
3491
|
+
}
|
|
2933
3492
|
};
|
|
2934
3493
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2935
3494
|
0 && (module.exports = {
|
|
@@ -2940,6 +3499,7 @@ var Volumes = class {
|
|
|
2940
3499
|
CommandExitError,
|
|
2941
3500
|
CommandHandle,
|
|
2942
3501
|
Commands,
|
|
3502
|
+
ConflictError,
|
|
2943
3503
|
ConnectionConfig,
|
|
2944
3504
|
DEFAULT_MASK_PATTERNS,
|
|
2945
3505
|
FileType,
|
|
@@ -2948,6 +3508,7 @@ var Volumes = class {
|
|
|
2948
3508
|
FilesystemEventType,
|
|
2949
3509
|
GitAuthError,
|
|
2950
3510
|
GitUpstreamError,
|
|
3511
|
+
Governance,
|
|
2951
3512
|
InjectionAction,
|
|
2952
3513
|
InjectionSensitivity,
|
|
2953
3514
|
InvalidArgumentError,
|
|
@@ -2969,12 +3530,16 @@ var Volumes = class {
|
|
|
2969
3530
|
TemplateError,
|
|
2970
3531
|
TimeoutError,
|
|
2971
3532
|
TransformDirection,
|
|
3533
|
+
VolumeFiles,
|
|
3534
|
+
VolumeLocks,
|
|
2972
3535
|
Volumes,
|
|
2973
3536
|
WatchHandle,
|
|
2974
3537
|
applyTransformation,
|
|
2975
3538
|
codeSecurityConfigToJSON,
|
|
3539
|
+
contentGateConfigToJSON,
|
|
2976
3540
|
createAuditConfig,
|
|
2977
3541
|
createCodeSecurityConfig,
|
|
3542
|
+
createContentGateConfig,
|
|
2978
3543
|
createEnvSecurityConfig,
|
|
2979
3544
|
createInjectionDefenseConfig,
|
|
2980
3545
|
createInvisibleTextConfig,
|
|
@@ -2993,11 +3558,17 @@ var Volumes = class {
|
|
|
2993
3558
|
parseBuildInfo,
|
|
2994
3559
|
parseCodeSecurityConfig,
|
|
2995
3560
|
parseCommandResult,
|
|
3561
|
+
parseContentGateConfig,
|
|
2996
3562
|
parseEntryInfo,
|
|
2997
3563
|
parseEnvSecurityConfig,
|
|
3564
|
+
parseFileEntry,
|
|
3565
|
+
parseFileInfo,
|
|
2998
3566
|
parseFilesystemEvent,
|
|
3567
|
+
parseGovernancePack,
|
|
2999
3568
|
parseInjectionDefenseConfig,
|
|
3000
3569
|
parseInvisibleTextConfig,
|
|
3570
|
+
parseLockLease,
|
|
3571
|
+
parseLockStatus,
|
|
3001
3572
|
parseNetworkPolicy,
|
|
3002
3573
|
parsePIIConfig,
|
|
3003
3574
|
parseProcessInfo,
|