@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.js
CHANGED
|
@@ -72,6 +72,12 @@ var NotEnoughSpaceError = class extends SandboxError {
|
|
|
72
72
|
this.name = "NotEnoughSpaceError";
|
|
73
73
|
}
|
|
74
74
|
};
|
|
75
|
+
var ConflictError = class extends SandboxError {
|
|
76
|
+
constructor(message, opts) {
|
|
77
|
+
super(message, opts);
|
|
78
|
+
this.name = "ConflictError";
|
|
79
|
+
}
|
|
80
|
+
};
|
|
75
81
|
var TemplateError = class extends SandboxError {
|
|
76
82
|
constructor(message, opts) {
|
|
77
83
|
super(message, opts);
|
|
@@ -117,6 +123,8 @@ var CommandExitError = class extends SandboxError {
|
|
|
117
123
|
|
|
118
124
|
// src/api/client.ts
|
|
119
125
|
var _dispatcherPromise;
|
|
126
|
+
var _resolvedDispatcher;
|
|
127
|
+
var _dispatcherResolved = false;
|
|
120
128
|
function getDispatcher() {
|
|
121
129
|
if (_dispatcherPromise) return _dispatcherPromise;
|
|
122
130
|
_dispatcherPromise = (async () => {
|
|
@@ -141,7 +149,14 @@ function getDispatcher() {
|
|
|
141
149
|
maxConcurrentStreams,
|
|
142
150
|
keepAliveTimeout: 3e4,
|
|
143
151
|
keepAliveMaxTimeout: 6e4,
|
|
144
|
-
|
|
152
|
+
// NOTE: do NOT set `pipelining` here. undici applies it to H2 sessions
|
|
153
|
+
// too, where `pipelining: 1` caps each connection to ONE in-flight
|
|
154
|
+
// stream — silently defeating the H2 multiplexing that allowH2 enables.
|
|
155
|
+
// Omitted, H2 sessions default to unlimited concurrent streams (capped
|
|
156
|
+
// by maxConcurrentStreams) and H1.1 fallback defaults to 1 (safe, no
|
|
157
|
+
// head-of-line risk on non-idempotent POSTs). This is the single
|
|
158
|
+
// biggest burst-latency lever: with pipelining:1 a 100-concurrent burst
|
|
159
|
+
// queued ~36 requests behind the `connections` cap.
|
|
145
160
|
allowH2: true,
|
|
146
161
|
connect: { keepAlive: true, keepAliveInitialDelay: 5e3 }
|
|
147
162
|
});
|
|
@@ -149,13 +164,21 @@ function getDispatcher() {
|
|
|
149
164
|
return void 0;
|
|
150
165
|
}
|
|
151
166
|
})();
|
|
167
|
+
void _dispatcherPromise.then((d) => {
|
|
168
|
+
_resolvedDispatcher = d;
|
|
169
|
+
_dispatcherResolved = true;
|
|
170
|
+
});
|
|
152
171
|
return _dispatcherPromise;
|
|
153
172
|
}
|
|
173
|
+
void getDispatcher();
|
|
154
174
|
var STATUS_ERROR_MAP = {
|
|
175
|
+
400: InvalidArgumentError,
|
|
155
176
|
401: AuthenticationError,
|
|
156
177
|
403: AuthenticationError,
|
|
157
178
|
404: NotFoundError,
|
|
158
179
|
408: TimeoutError,
|
|
180
|
+
409: ConflictError,
|
|
181
|
+
413: NotEnoughSpaceError,
|
|
159
182
|
422: InvalidArgumentError,
|
|
160
183
|
507: NotEnoughSpaceError
|
|
161
184
|
};
|
|
@@ -167,7 +190,7 @@ var ApiClient = class {
|
|
|
167
190
|
constructor(config, opts) {
|
|
168
191
|
this.config = config ?? new ConnectionConfig();
|
|
169
192
|
this.maxRetries = opts?.maxRetries ?? 3;
|
|
170
|
-
this.retryDelay = opts?.retryDelay ?? 0.
|
|
193
|
+
this.retryDelay = opts?.retryDelay ?? 0.1;
|
|
171
194
|
this.abortController = new AbortController();
|
|
172
195
|
}
|
|
173
196
|
/** Send a GET request and return parsed JSON. */
|
|
@@ -261,7 +284,7 @@ var ApiClient = class {
|
|
|
261
284
|
signals.push(AbortSignal.timeout(timeoutMs));
|
|
262
285
|
}
|
|
263
286
|
const signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
|
|
264
|
-
const dispatcher = await getDispatcher();
|
|
287
|
+
const dispatcher = _dispatcherResolved ? _resolvedDispatcher : await getDispatcher();
|
|
265
288
|
const fetchOpts = {
|
|
266
289
|
method,
|
|
267
290
|
headers,
|
|
@@ -814,6 +837,49 @@ function invisibleTextConfigToJSON(config) {
|
|
|
814
837
|
return result;
|
|
815
838
|
}
|
|
816
839
|
|
|
840
|
+
// src/security/customPolicy.ts
|
|
841
|
+
function parseCustomPolicyConfig(data) {
|
|
842
|
+
return {
|
|
843
|
+
enabled: data.enabled ?? false,
|
|
844
|
+
inlineRego: data.inline_rego ?? data.inlineRego,
|
|
845
|
+
inlineModules: data.inline_modules ?? data.inlineModules,
|
|
846
|
+
policyRef: data.policy_ref ?? data.policyRef,
|
|
847
|
+
defaultDeny: data.default_deny ?? data.defaultDeny ?? false
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
function customPolicyConfigToJSON(config) {
|
|
851
|
+
return {
|
|
852
|
+
enabled: config.enabled,
|
|
853
|
+
inline_rego: config.inlineRego,
|
|
854
|
+
inline_modules: config.inlineModules,
|
|
855
|
+
policy_ref: config.policyRef,
|
|
856
|
+
default_deny: config.defaultDeny
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// src/security/contentGate.ts
|
|
861
|
+
function createContentGateConfig(opts) {
|
|
862
|
+
return {
|
|
863
|
+
enabled: opts?.enabled ?? false,
|
|
864
|
+
domains: opts?.domains
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
function parseContentGateConfig(data) {
|
|
868
|
+
return {
|
|
869
|
+
enabled: data.enabled ?? false,
|
|
870
|
+
domains: data.domains
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
function contentGateConfigToJSON(config) {
|
|
874
|
+
const result = {
|
|
875
|
+
enabled: config.enabled
|
|
876
|
+
};
|
|
877
|
+
if (config.domains !== void 0) {
|
|
878
|
+
result.domains = config.domains;
|
|
879
|
+
}
|
|
880
|
+
return result;
|
|
881
|
+
}
|
|
882
|
+
|
|
817
883
|
// src/security/policy.ts
|
|
818
884
|
function createSecurityPolicy(opts) {
|
|
819
885
|
return {
|
|
@@ -825,12 +891,16 @@ function createSecurityPolicy(opts) {
|
|
|
825
891
|
envSecurity: opts?.envSecurity ?? createEnvSecurityConfig(),
|
|
826
892
|
toxicity: opts?.toxicity,
|
|
827
893
|
codeSecurity: opts?.codeSecurity,
|
|
828
|
-
invisibleText: opts?.invisibleText
|
|
894
|
+
invisibleText: opts?.invisibleText,
|
|
895
|
+
contentGate: opts?.contentGate,
|
|
896
|
+
customPolicy: opts?.customPolicy
|
|
829
897
|
};
|
|
830
898
|
}
|
|
831
899
|
function parseSecurityPolicy(data) {
|
|
832
900
|
const injDef = data.injection_defense ?? data.injectionDefense;
|
|
833
901
|
const auditData = data.audit;
|
|
902
|
+
const customPolicyData = data.custom_policy ?? data.customPolicy;
|
|
903
|
+
const contentGateData = data.content_gate ?? data.contentGate;
|
|
834
904
|
return {
|
|
835
905
|
pii: data.pii ? parsePIIConfig(data.pii) : createPIIConfig(),
|
|
836
906
|
injectionDefense: typeof injDef === "boolean" ? injDef : injDef ? parseInjectionDefenseConfig(injDef) : false,
|
|
@@ -840,7 +910,9 @@ function parseSecurityPolicy(data) {
|
|
|
840
910
|
envSecurity: data.env_security ?? data.envSecurity ? parseEnvSecurityConfig(data.env_security ?? data.envSecurity) : createEnvSecurityConfig(),
|
|
841
911
|
toxicity: data.toxicity ? parseToxicityConfig(data.toxicity) : void 0,
|
|
842
912
|
codeSecurity: data.code_security ?? data.codeSecurity ? parseCodeSecurityConfig(data.code_security ?? data.codeSecurity) : void 0,
|
|
843
|
-
invisibleText: data.invisible_text ?? data.invisibleText ? parseInvisibleTextConfig(data.invisible_text ?? data.invisibleText) : void 0
|
|
913
|
+
invisibleText: data.invisible_text ?? data.invisibleText ? parseInvisibleTextConfig(data.invisible_text ?? data.invisibleText) : void 0,
|
|
914
|
+
contentGate: contentGateData ? parseContentGateConfig(contentGateData) : void 0,
|
|
915
|
+
customPolicy: customPolicyData ? parseCustomPolicyConfig(customPolicyData) : void 0
|
|
844
916
|
};
|
|
845
917
|
}
|
|
846
918
|
function securityPolicyToJSON(policy) {
|
|
@@ -890,6 +962,12 @@ function securityPolicyToJSON(policy) {
|
|
|
890
962
|
if (policy.invisibleText) {
|
|
891
963
|
result.invisible_text = invisibleTextConfigToJSON(policy.invisibleText);
|
|
892
964
|
}
|
|
965
|
+
if (policy.contentGate) {
|
|
966
|
+
result.content_gate = contentGateConfigToJSON(policy.contentGate);
|
|
967
|
+
}
|
|
968
|
+
if (policy.customPolicy) {
|
|
969
|
+
result.custom_policy = customPolicyConfigToJSON(policy.customPolicy);
|
|
970
|
+
}
|
|
893
971
|
return result;
|
|
894
972
|
}
|
|
895
973
|
function requiresTlsInterception(policy) {
|
|
@@ -1908,11 +1986,53 @@ function parseVolumeInfo(data) {
|
|
|
1908
1986
|
sizeBytes: Number(data.size_bytes ?? 0),
|
|
1909
1987
|
contentType: String(data.content_type ?? ""),
|
|
1910
1988
|
metadata: data.metadata ?? {},
|
|
1911
|
-
createdAt: String(data.created_at ?? "")
|
|
1989
|
+
createdAt: String(data.created_at ?? ""),
|
|
1990
|
+
backend: String(data.backend ?? ""),
|
|
1991
|
+
quotaBytes: Number(data.quota_bytes ?? 0),
|
|
1992
|
+
updatedAt: String(data.updated_at ?? "")
|
|
1993
|
+
};
|
|
1994
|
+
}
|
|
1995
|
+
function parseFileEntry(data) {
|
|
1996
|
+
return {
|
|
1997
|
+
name: String(data.name ?? ""),
|
|
1998
|
+
path: String(data.path ?? ""),
|
|
1999
|
+
isDir: Boolean(data.is_dir ?? false),
|
|
2000
|
+
size: Number(data.size ?? 0),
|
|
2001
|
+
modTime: String(data.mod_time ?? ""),
|
|
2002
|
+
mode: Number(data.mode ?? 0)
|
|
2003
|
+
};
|
|
2004
|
+
}
|
|
2005
|
+
function parseFileInfo(data) {
|
|
2006
|
+
return {
|
|
2007
|
+
...parseFileEntry(data),
|
|
2008
|
+
version: String(data.version ?? "")
|
|
2009
|
+
};
|
|
2010
|
+
}
|
|
2011
|
+
function parseLockLease(data) {
|
|
2012
|
+
return {
|
|
2013
|
+
token: String(data.token ?? ""),
|
|
2014
|
+
ttlSeconds: Number(data.ttl_seconds ?? 0),
|
|
2015
|
+
expiresAt: String(data.expires_at ?? "")
|
|
2016
|
+
};
|
|
2017
|
+
}
|
|
2018
|
+
function parseLockStatus(data) {
|
|
2019
|
+
return {
|
|
2020
|
+
held: Boolean(data.held ?? false),
|
|
2021
|
+
expiresInMs: Number(data.expires_in_ms ?? 0)
|
|
1912
2022
|
};
|
|
1913
2023
|
}
|
|
1914
2024
|
function volumeAttachmentToJSON(att) {
|
|
1915
|
-
|
|
2025
|
+
const out = {
|
|
2026
|
+
volume_id: att.volumeId,
|
|
2027
|
+
mount_path: att.mountPath
|
|
2028
|
+
};
|
|
2029
|
+
if (att.mode) {
|
|
2030
|
+
out.mode = att.mode;
|
|
2031
|
+
}
|
|
2032
|
+
if (att.subpath) {
|
|
2033
|
+
out.subpath = att.subpath;
|
|
2034
|
+
}
|
|
2035
|
+
return out;
|
|
1916
2036
|
}
|
|
1917
2037
|
|
|
1918
2038
|
// src/sandbox/sandbox.ts
|
|
@@ -2738,7 +2858,7 @@ var Template = class {
|
|
|
2738
2858
|
}
|
|
2739
2859
|
};
|
|
2740
2860
|
|
|
2741
|
-
// src/volumes/
|
|
2861
|
+
// src/volumes/files.ts
|
|
2742
2862
|
var VALID_VOLUME_ID_RE = /^[a-zA-Z0-9_-]+$/;
|
|
2743
2863
|
function assertValidVolumeId(id) {
|
|
2744
2864
|
if (!id || !VALID_VOLUME_ID_RE.test(id)) {
|
|
@@ -2747,8 +2867,223 @@ function assertValidVolumeId(id) {
|
|
|
2747
2867
|
);
|
|
2748
2868
|
}
|
|
2749
2869
|
}
|
|
2870
|
+
var VolumeFiles = class {
|
|
2871
|
+
volumeId;
|
|
2872
|
+
opts;
|
|
2873
|
+
constructor(volumeId, opts) {
|
|
2874
|
+
assertValidVolumeId(volumeId);
|
|
2875
|
+
this.volumeId = volumeId;
|
|
2876
|
+
this.opts = opts;
|
|
2877
|
+
}
|
|
2878
|
+
client() {
|
|
2879
|
+
const config = new ConnectionConfig({
|
|
2880
|
+
apiKey: this.opts?.apiKey,
|
|
2881
|
+
domain: this.opts?.domain,
|
|
2882
|
+
apiUrl: this.opts?.apiUrl,
|
|
2883
|
+
requestTimeout: this.opts?.requestTimeout
|
|
2884
|
+
});
|
|
2885
|
+
return getSharedClient(config);
|
|
2886
|
+
}
|
|
2887
|
+
timeout() {
|
|
2888
|
+
return this.opts?.requestTimeout;
|
|
2889
|
+
}
|
|
2890
|
+
/** Write raw bytes to `path`. Optionally conditional on `ifVersion` (CAS). */
|
|
2891
|
+
async write(path, data, opts) {
|
|
2892
|
+
if (!path) {
|
|
2893
|
+
throw new InvalidArgumentError("path is required");
|
|
2894
|
+
}
|
|
2895
|
+
const params = { path };
|
|
2896
|
+
if (opts?.ifVersion) {
|
|
2897
|
+
params.if_version = opts.ifVersion;
|
|
2898
|
+
}
|
|
2899
|
+
const body = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
2900
|
+
const resp = await this.client().put(`/volumes/${this.volumeId}/files/raw`, {
|
|
2901
|
+
params,
|
|
2902
|
+
body,
|
|
2903
|
+
headers: { "Content-Type": "application/octet-stream" },
|
|
2904
|
+
timeout: opts?.requestTimeout ?? this.timeout()
|
|
2905
|
+
});
|
|
2906
|
+
return String(resp.path ?? path);
|
|
2907
|
+
}
|
|
2908
|
+
/** Read raw bytes from `path`. */
|
|
2909
|
+
async read(path) {
|
|
2910
|
+
if (!path) {
|
|
2911
|
+
throw new InvalidArgumentError("path is required");
|
|
2912
|
+
}
|
|
2913
|
+
return this.client().getBytes(`/volumes/${this.volumeId}/files/raw`, {
|
|
2914
|
+
params: { path },
|
|
2915
|
+
timeout: this.timeout()
|
|
2916
|
+
});
|
|
2917
|
+
}
|
|
2918
|
+
/** List directory entries under `path`. */
|
|
2919
|
+
async list(path) {
|
|
2920
|
+
if (!path) {
|
|
2921
|
+
throw new InvalidArgumentError("path is required");
|
|
2922
|
+
}
|
|
2923
|
+
const resp = await this.client().get(`/volumes/${this.volumeId}/files/list`, {
|
|
2924
|
+
params: { path },
|
|
2925
|
+
timeout: this.timeout()
|
|
2926
|
+
});
|
|
2927
|
+
const rows = resp.entries ?? [];
|
|
2928
|
+
return rows.map(parseFileEntry);
|
|
2929
|
+
}
|
|
2930
|
+
/** Stat `path`, returning the entry plus the CAS `version` token. */
|
|
2931
|
+
async info(path) {
|
|
2932
|
+
if (!path) {
|
|
2933
|
+
throw new InvalidArgumentError("path is required");
|
|
2934
|
+
}
|
|
2935
|
+
const resp = await this.client().get(`/volumes/${this.volumeId}/files/info`, {
|
|
2936
|
+
params: { path },
|
|
2937
|
+
timeout: this.timeout()
|
|
2938
|
+
});
|
|
2939
|
+
return parseFileInfo(resp);
|
|
2940
|
+
}
|
|
2941
|
+
/** Return whether `path` exists. */
|
|
2942
|
+
async exists(path) {
|
|
2943
|
+
if (!path) {
|
|
2944
|
+
throw new InvalidArgumentError("path is required");
|
|
2945
|
+
}
|
|
2946
|
+
const resp = await this.client().get(`/volumes/${this.volumeId}/files/exists`, {
|
|
2947
|
+
params: { path },
|
|
2948
|
+
timeout: this.timeout()
|
|
2949
|
+
});
|
|
2950
|
+
return Boolean(resp.exists ?? false);
|
|
2951
|
+
}
|
|
2952
|
+
/** Remove `path`. Pass `{ recursive: true }` to remove a directory tree. */
|
|
2953
|
+
async remove(path, opts) {
|
|
2954
|
+
if (!path) {
|
|
2955
|
+
throw new InvalidArgumentError("path is required");
|
|
2956
|
+
}
|
|
2957
|
+
const params = {
|
|
2958
|
+
path,
|
|
2959
|
+
recursive: opts?.recursive ? "true" : "false"
|
|
2960
|
+
};
|
|
2961
|
+
await this.client().delete(`/volumes/${this.volumeId}/files`, {
|
|
2962
|
+
params,
|
|
2963
|
+
timeout: opts?.requestTimeout ?? this.timeout()
|
|
2964
|
+
});
|
|
2965
|
+
}
|
|
2966
|
+
/** Rename `oldPath` to `newPath`. */
|
|
2967
|
+
async rename(oldPath, newPath) {
|
|
2968
|
+
if (!oldPath || !newPath) {
|
|
2969
|
+
throw new InvalidArgumentError("oldPath and newPath are required");
|
|
2970
|
+
}
|
|
2971
|
+
const resp = await this.client().patch(`/volumes/${this.volumeId}/files`, {
|
|
2972
|
+
json: { old_path: oldPath, new_path: newPath },
|
|
2973
|
+
timeout: this.timeout()
|
|
2974
|
+
});
|
|
2975
|
+
return {
|
|
2976
|
+
oldPath: String(resp.old_path ?? oldPath),
|
|
2977
|
+
newPath: String(resp.new_path ?? newPath)
|
|
2978
|
+
};
|
|
2979
|
+
}
|
|
2980
|
+
/** Create a directory at `path`. */
|
|
2981
|
+
async mkdir(path) {
|
|
2982
|
+
if (!path) {
|
|
2983
|
+
throw new InvalidArgumentError("path is required");
|
|
2984
|
+
}
|
|
2985
|
+
const resp = await this.client().post(`/volumes/${this.volumeId}/files/mkdir`, {
|
|
2986
|
+
json: { path },
|
|
2987
|
+
timeout: this.timeout()
|
|
2988
|
+
});
|
|
2989
|
+
return String(resp.path ?? path);
|
|
2990
|
+
}
|
|
2991
|
+
};
|
|
2992
|
+
|
|
2993
|
+
// src/volumes/locks.ts
|
|
2994
|
+
var VALID_VOLUME_ID_RE2 = /^[a-zA-Z0-9_-]+$/;
|
|
2995
|
+
function assertValidVolumeId2(id) {
|
|
2996
|
+
if (!id || !VALID_VOLUME_ID_RE2.test(id)) {
|
|
2997
|
+
throw new InvalidArgumentError(
|
|
2998
|
+
`Invalid volume ID: "${id}". Must be alphanumeric with hyphens/underscores only.`
|
|
2999
|
+
);
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
var VolumeLocks = class {
|
|
3003
|
+
volumeId;
|
|
3004
|
+
opts;
|
|
3005
|
+
constructor(volumeId, opts) {
|
|
3006
|
+
assertValidVolumeId2(volumeId);
|
|
3007
|
+
this.volumeId = volumeId;
|
|
3008
|
+
this.opts = opts;
|
|
3009
|
+
}
|
|
3010
|
+
client() {
|
|
3011
|
+
const config = new ConnectionConfig({
|
|
3012
|
+
apiKey: this.opts?.apiKey,
|
|
3013
|
+
domain: this.opts?.domain,
|
|
3014
|
+
apiUrl: this.opts?.apiUrl,
|
|
3015
|
+
requestTimeout: this.opts?.requestTimeout
|
|
3016
|
+
});
|
|
3017
|
+
return getSharedClient(config);
|
|
3018
|
+
}
|
|
3019
|
+
timeout() {
|
|
3020
|
+
return this.opts?.requestTimeout;
|
|
3021
|
+
}
|
|
3022
|
+
/** Acquire a lock on `path`. Throws ConflictError (409) if already held. */
|
|
3023
|
+
async acquire(path, ttlSeconds) {
|
|
3024
|
+
if (!path) {
|
|
3025
|
+
throw new InvalidArgumentError("path is required");
|
|
3026
|
+
}
|
|
3027
|
+
const json = { path };
|
|
3028
|
+
if (ttlSeconds !== void 0) {
|
|
3029
|
+
json.ttl_seconds = ttlSeconds;
|
|
3030
|
+
}
|
|
3031
|
+
const resp = await this.client().post(`/volumes/${this.volumeId}/locks`, {
|
|
3032
|
+
json,
|
|
3033
|
+
timeout: this.timeout()
|
|
3034
|
+
});
|
|
3035
|
+
return parseLockLease(resp);
|
|
3036
|
+
}
|
|
3037
|
+
/** Release a lock on `path` held under `token`. Throws ConflictError (409) if not the holder. */
|
|
3038
|
+
async release(path, token) {
|
|
3039
|
+
if (!path || !token) {
|
|
3040
|
+
throw new InvalidArgumentError("path and token are required");
|
|
3041
|
+
}
|
|
3042
|
+
const resp = await this.client().delete(`/volumes/${this.volumeId}/locks`, {
|
|
3043
|
+
json: { path, token },
|
|
3044
|
+
timeout: this.timeout()
|
|
3045
|
+
});
|
|
3046
|
+
return Boolean(resp.released ?? false);
|
|
3047
|
+
}
|
|
3048
|
+
/** Renew a lock on `path` held under `token`. Throws ConflictError (409) if not the holder. */
|
|
3049
|
+
async renew(path, token, ttlSeconds) {
|
|
3050
|
+
if (!path || !token) {
|
|
3051
|
+
throw new InvalidArgumentError("path and token are required");
|
|
3052
|
+
}
|
|
3053
|
+
const json = { path, token };
|
|
3054
|
+
if (ttlSeconds !== void 0) {
|
|
3055
|
+
json.ttl_seconds = ttlSeconds;
|
|
3056
|
+
}
|
|
3057
|
+
const resp = await this.client().post(`/volumes/${this.volumeId}/locks/renew`, {
|
|
3058
|
+
json,
|
|
3059
|
+
timeout: this.timeout()
|
|
3060
|
+
});
|
|
3061
|
+
return { ...parseLockLease(resp), token };
|
|
3062
|
+
}
|
|
3063
|
+
/** Query whether `path` is currently locked. */
|
|
3064
|
+
async status(path) {
|
|
3065
|
+
if (!path) {
|
|
3066
|
+
throw new InvalidArgumentError("path is required");
|
|
3067
|
+
}
|
|
3068
|
+
const resp = await this.client().get(`/volumes/${this.volumeId}/locks`, {
|
|
3069
|
+
params: { path },
|
|
3070
|
+
timeout: this.timeout()
|
|
3071
|
+
});
|
|
3072
|
+
return parseLockStatus(resp);
|
|
3073
|
+
}
|
|
3074
|
+
};
|
|
3075
|
+
|
|
3076
|
+
// src/volumes/volumes.ts
|
|
3077
|
+
var VALID_VOLUME_ID_RE3 = /^[a-zA-Z0-9_-]+$/;
|
|
3078
|
+
function assertValidVolumeId3(id) {
|
|
3079
|
+
if (!id || !VALID_VOLUME_ID_RE3.test(id)) {
|
|
3080
|
+
throw new InvalidArgumentError(
|
|
3081
|
+
`Invalid volume ID: "${id}". Must be alphanumeric with hyphens/underscores only.`
|
|
3082
|
+
);
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
2750
3085
|
var Volumes = class {
|
|
2751
|
-
/** Create a volume by streaming a tarball to the server. */
|
|
3086
|
+
/** Create a volume by streaming a tarball (gzip tar.gz) to the server. */
|
|
2752
3087
|
static async create(name, data, opts) {
|
|
2753
3088
|
if (!name) {
|
|
2754
3089
|
throw new InvalidArgumentError("volume name is required");
|
|
@@ -2769,9 +3104,113 @@ var Volumes = class {
|
|
|
2769
3104
|
});
|
|
2770
3105
|
return parseVolumeInfo(resp);
|
|
2771
3106
|
}
|
|
3107
|
+
/**
|
|
3108
|
+
* Capture the attached volume's mount path in `sandboxId` into a NEW volume.
|
|
3109
|
+
*
|
|
3110
|
+
* The source volume is left unchanged. If `name` is omitted the server names
|
|
3111
|
+
* the new volume "<source-name>-commit". Returns the new VolumeInfo.
|
|
3112
|
+
*/
|
|
3113
|
+
static async commit(sandboxId, volumeId, name, opts) {
|
|
3114
|
+
if (!sandboxId || !VALID_VOLUME_ID_RE3.test(sandboxId)) {
|
|
3115
|
+
throw new InvalidArgumentError(
|
|
3116
|
+
`Invalid sandbox ID: "${sandboxId}". Must be alphanumeric with hyphens/underscores only.`
|
|
3117
|
+
);
|
|
3118
|
+
}
|
|
3119
|
+
assertValidVolumeId3(volumeId);
|
|
3120
|
+
const config = new ConnectionConfig({
|
|
3121
|
+
apiKey: opts?.apiKey,
|
|
3122
|
+
domain: opts?.domain,
|
|
3123
|
+
apiUrl: opts?.apiUrl,
|
|
3124
|
+
requestTimeout: opts?.requestTimeout
|
|
3125
|
+
});
|
|
3126
|
+
const client = getSharedClient(config);
|
|
3127
|
+
const resp = await client.post(`/sandboxes/${sandboxId}/volumes/${volumeId}/commit`, {
|
|
3128
|
+
params: name ? { name } : void 0,
|
|
3129
|
+
timeout: opts?.requestTimeout
|
|
3130
|
+
});
|
|
3131
|
+
return parseVolumeInfo(resp);
|
|
3132
|
+
}
|
|
3133
|
+
/**
|
|
3134
|
+
* Snapshot an arbitrary absolute in-sandbox `path` into a NEW volume.
|
|
3135
|
+
*
|
|
3136
|
+
* Unlike `commit` (which captures an already-attached volume's mount path),
|
|
3137
|
+
* `snapshot` captures any path in the running sandbox. `name` defaults to
|
|
3138
|
+
* "snapshot" on the server. Synthetic paths (/proc, /sys, /dev) are rejected.
|
|
3139
|
+
*/
|
|
3140
|
+
static async snapshot(sandboxId, path, name, opts) {
|
|
3141
|
+
if (!sandboxId || !VALID_VOLUME_ID_RE3.test(sandboxId)) {
|
|
3142
|
+
throw new InvalidArgumentError(
|
|
3143
|
+
`Invalid sandbox ID: "${sandboxId}". Must be alphanumeric with hyphens/underscores only.`
|
|
3144
|
+
);
|
|
3145
|
+
}
|
|
3146
|
+
if (!path) {
|
|
3147
|
+
throw new InvalidArgumentError("path is required");
|
|
3148
|
+
}
|
|
3149
|
+
const config = new ConnectionConfig({
|
|
3150
|
+
apiKey: opts?.apiKey,
|
|
3151
|
+
domain: opts?.domain,
|
|
3152
|
+
apiUrl: opts?.apiUrl,
|
|
3153
|
+
requestTimeout: opts?.requestTimeout
|
|
3154
|
+
});
|
|
3155
|
+
const client = getSharedClient(config);
|
|
3156
|
+
const params = { path };
|
|
3157
|
+
if (name) {
|
|
3158
|
+
params.name = name;
|
|
3159
|
+
}
|
|
3160
|
+
const resp = await client.post(`/sandboxes/${sandboxId}/volumes/snapshot`, {
|
|
3161
|
+
params,
|
|
3162
|
+
timeout: opts?.requestTimeout
|
|
3163
|
+
});
|
|
3164
|
+
return parseVolumeInfo(resp);
|
|
3165
|
+
}
|
|
3166
|
+
/**
|
|
3167
|
+
* Create an empty file-granular volume. Requires a file-granular backend
|
|
3168
|
+
* (503 if not configured). Returns the new VolumeInfo.
|
|
3169
|
+
*/
|
|
3170
|
+
static async empty(name, opts) {
|
|
3171
|
+
if (!name) {
|
|
3172
|
+
throw new InvalidArgumentError("volume name is required");
|
|
3173
|
+
}
|
|
3174
|
+
const config = new ConnectionConfig({
|
|
3175
|
+
apiKey: opts?.apiKey,
|
|
3176
|
+
domain: opts?.domain,
|
|
3177
|
+
apiUrl: opts?.apiUrl,
|
|
3178
|
+
requestTimeout: opts?.requestTimeout
|
|
3179
|
+
});
|
|
3180
|
+
const client = getSharedClient(config);
|
|
3181
|
+
const resp = await client.post("/volumes/empty", {
|
|
3182
|
+
params: { name },
|
|
3183
|
+
timeout: opts?.requestTimeout
|
|
3184
|
+
});
|
|
3185
|
+
return parseVolumeInfo(resp);
|
|
3186
|
+
}
|
|
3187
|
+
/**
|
|
3188
|
+
* Ingest a gzip tar.gz archive into a NEW file-granular volume. Requires a
|
|
3189
|
+
* file-granular backend (503 if not configured). 413 on quota exceeded.
|
|
3190
|
+
*/
|
|
3191
|
+
static async ingest(name, data, opts) {
|
|
3192
|
+
if (!name) {
|
|
3193
|
+
throw new InvalidArgumentError("volume name is required");
|
|
3194
|
+
}
|
|
3195
|
+
const config = new ConnectionConfig({
|
|
3196
|
+
apiKey: opts?.apiKey,
|
|
3197
|
+
domain: opts?.domain,
|
|
3198
|
+
apiUrl: opts?.apiUrl,
|
|
3199
|
+
requestTimeout: opts?.requestTimeout
|
|
3200
|
+
});
|
|
3201
|
+
const client = getSharedClient(config);
|
|
3202
|
+
const body = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
3203
|
+
const resp = await client.post("/volumes/ingest", {
|
|
3204
|
+
params: { name },
|
|
3205
|
+
body,
|
|
3206
|
+
headers: { "Content-Type": opts?.contentType ?? "application/gzip" },
|
|
3207
|
+
timeout: opts?.requestTimeout
|
|
3208
|
+
});
|
|
3209
|
+
return parseVolumeInfo(resp);
|
|
3210
|
+
}
|
|
2772
3211
|
/** Fetch metadata for a single volume. */
|
|
2773
3212
|
static async get(volumeId, opts) {
|
|
2774
|
-
|
|
3213
|
+
assertValidVolumeId3(volumeId);
|
|
2775
3214
|
const config = new ConnectionConfig({
|
|
2776
3215
|
apiKey: opts?.apiKey,
|
|
2777
3216
|
domain: opts?.domain,
|
|
@@ -2799,9 +3238,23 @@ var Volumes = class {
|
|
|
2799
3238
|
const rows = resp.volumes ?? [];
|
|
2800
3239
|
return rows.map(parseVolumeInfo);
|
|
2801
3240
|
}
|
|
3241
|
+
/** Download the volume's contents as raw bytes (the stored archive/blob). */
|
|
3242
|
+
static async download(volumeId, opts) {
|
|
3243
|
+
assertValidVolumeId3(volumeId);
|
|
3244
|
+
const config = new ConnectionConfig({
|
|
3245
|
+
apiKey: opts?.apiKey,
|
|
3246
|
+
domain: opts?.domain,
|
|
3247
|
+
apiUrl: opts?.apiUrl,
|
|
3248
|
+
requestTimeout: opts?.requestTimeout
|
|
3249
|
+
});
|
|
3250
|
+
const client = getSharedClient(config);
|
|
3251
|
+
return client.getBytes(`/volumes/${volumeId}/download`, {
|
|
3252
|
+
timeout: opts?.requestTimeout
|
|
3253
|
+
});
|
|
3254
|
+
}
|
|
2802
3255
|
/** Delete a volume and its blob. Idempotent on the wire. */
|
|
2803
3256
|
static async delete(volumeId, opts) {
|
|
2804
|
-
|
|
3257
|
+
assertValidVolumeId3(volumeId);
|
|
2805
3258
|
const config = new ConnectionConfig({
|
|
2806
3259
|
apiKey: opts?.apiKey,
|
|
2807
3260
|
domain: opts?.domain,
|
|
@@ -2811,6 +3264,100 @@ var Volumes = class {
|
|
|
2811
3264
|
const client = getSharedClient(config);
|
|
2812
3265
|
await client.delete(`/volumes/${volumeId}`, { timeout: opts?.requestTimeout });
|
|
2813
3266
|
}
|
|
3267
|
+
/**
|
|
3268
|
+
* File-granular operations (read/write/list/info/exists/remove/rename/mkdir,
|
|
3269
|
+
* plus CAS via `write(..., { ifVersion })`) on `volumeId`. File-granular
|
|
3270
|
+
* volumes only.
|
|
3271
|
+
*/
|
|
3272
|
+
static files(volumeId, opts) {
|
|
3273
|
+
return new VolumeFiles(volumeId, opts);
|
|
3274
|
+
}
|
|
3275
|
+
/** Advisory locks (acquire/release/renew/status) over a (volume, path). */
|
|
3276
|
+
static locks(volumeId, opts) {
|
|
3277
|
+
return new VolumeLocks(volumeId, opts);
|
|
3278
|
+
}
|
|
3279
|
+
};
|
|
3280
|
+
|
|
3281
|
+
// src/governance/models.ts
|
|
3282
|
+
function parseGovernanceControl(data) {
|
|
3283
|
+
return {
|
|
3284
|
+
control: String(data.control ?? ""),
|
|
3285
|
+
gate: String(data.gate ?? ""),
|
|
3286
|
+
rule: String(data.rule ?? ""),
|
|
3287
|
+
playbook: String(data.playbook ?? "")
|
|
3288
|
+
};
|
|
3289
|
+
}
|
|
3290
|
+
function parseGovernanceAdvisory(data) {
|
|
3291
|
+
return {
|
|
3292
|
+
control: String(data.control ?? ""),
|
|
3293
|
+
reason: String(data.reason ?? "")
|
|
3294
|
+
};
|
|
3295
|
+
}
|
|
3296
|
+
function parseGovernancePack(data) {
|
|
3297
|
+
const rawEnforces = data.enforces ?? [];
|
|
3298
|
+
const rawAdvisory = data.advisory ?? [];
|
|
3299
|
+
return {
|
|
3300
|
+
name: String(data.name ?? ""),
|
|
3301
|
+
version: String(data.version ?? ""),
|
|
3302
|
+
framework: String(data.framework ?? ""),
|
|
3303
|
+
description: String(data.description ?? ""),
|
|
3304
|
+
gates: data.gates ?? [],
|
|
3305
|
+
enforces: rawEnforces.map(parseGovernanceControl),
|
|
3306
|
+
advisory: rawAdvisory.map(parseGovernanceAdvisory),
|
|
3307
|
+
policyRef: String(data.policy_ref ?? data.policyRef ?? ""),
|
|
3308
|
+
seeded: Boolean(data.seeded ?? false)
|
|
3309
|
+
};
|
|
3310
|
+
}
|
|
3311
|
+
|
|
3312
|
+
// src/governance/governance.ts
|
|
3313
|
+
var VALID_PACK_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
3314
|
+
function assertValidPackName(name) {
|
|
3315
|
+
if (!name || !VALID_PACK_NAME_RE.test(name)) {
|
|
3316
|
+
throw new InvalidArgumentError(
|
|
3317
|
+
`Invalid pack name: "${name}". Must be alphanumeric with hyphens/underscores only.`
|
|
3318
|
+
);
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
var Governance = class {
|
|
3322
|
+
/**
|
|
3323
|
+
* List all available governance packs.
|
|
3324
|
+
*
|
|
3325
|
+
* Sends GET /governance/packs and returns the `packs` array.
|
|
3326
|
+
*/
|
|
3327
|
+
static async listPacks(opts) {
|
|
3328
|
+
const config = new ConnectionConfig({
|
|
3329
|
+
apiKey: opts?.apiKey,
|
|
3330
|
+
domain: opts?.domain,
|
|
3331
|
+
apiUrl: opts?.apiUrl,
|
|
3332
|
+
requestTimeout: opts?.requestTimeout
|
|
3333
|
+
});
|
|
3334
|
+
const client = getSharedClient(config);
|
|
3335
|
+
const resp = await client.get("/governance/packs", {
|
|
3336
|
+
timeout: opts?.requestTimeout
|
|
3337
|
+
});
|
|
3338
|
+
const rows = resp.packs ?? [];
|
|
3339
|
+
return rows.map(parseGovernancePack);
|
|
3340
|
+
}
|
|
3341
|
+
/**
|
|
3342
|
+
* Fetch a single governance pack by name.
|
|
3343
|
+
*
|
|
3344
|
+
* Sends GET /governance/packs/:name and returns the pack object.
|
|
3345
|
+
* Throws InvalidArgumentError if the name contains unsafe characters.
|
|
3346
|
+
*/
|
|
3347
|
+
static async getPack(name, opts) {
|
|
3348
|
+
assertValidPackName(name);
|
|
3349
|
+
const config = new ConnectionConfig({
|
|
3350
|
+
apiKey: opts?.apiKey,
|
|
3351
|
+
domain: opts?.domain,
|
|
3352
|
+
apiUrl: opts?.apiUrl,
|
|
3353
|
+
requestTimeout: opts?.requestTimeout
|
|
3354
|
+
});
|
|
3355
|
+
const client = getSharedClient(config);
|
|
3356
|
+
const resp = await client.get(`/governance/packs/${name}`, {
|
|
3357
|
+
timeout: opts?.requestTimeout
|
|
3358
|
+
});
|
|
3359
|
+
return parseGovernancePack(resp);
|
|
3360
|
+
}
|
|
2814
3361
|
};
|
|
2815
3362
|
export {
|
|
2816
3363
|
ALL_TRAFFIC,
|
|
@@ -2820,6 +3367,7 @@ export {
|
|
|
2820
3367
|
CommandExitError,
|
|
2821
3368
|
CommandHandle,
|
|
2822
3369
|
Commands,
|
|
3370
|
+
ConflictError,
|
|
2823
3371
|
ConnectionConfig,
|
|
2824
3372
|
DEFAULT_MASK_PATTERNS,
|
|
2825
3373
|
FileType,
|
|
@@ -2828,6 +3376,7 @@ export {
|
|
|
2828
3376
|
FilesystemEventType,
|
|
2829
3377
|
GitAuthError,
|
|
2830
3378
|
GitUpstreamError,
|
|
3379
|
+
Governance,
|
|
2831
3380
|
InjectionAction,
|
|
2832
3381
|
InjectionSensitivity,
|
|
2833
3382
|
InvalidArgumentError,
|
|
@@ -2849,12 +3398,16 @@ export {
|
|
|
2849
3398
|
TemplateError,
|
|
2850
3399
|
TimeoutError,
|
|
2851
3400
|
TransformDirection,
|
|
3401
|
+
VolumeFiles,
|
|
3402
|
+
VolumeLocks,
|
|
2852
3403
|
Volumes,
|
|
2853
3404
|
WatchHandle,
|
|
2854
3405
|
applyTransformation,
|
|
2855
3406
|
codeSecurityConfigToJSON,
|
|
3407
|
+
contentGateConfigToJSON,
|
|
2856
3408
|
createAuditConfig,
|
|
2857
3409
|
createCodeSecurityConfig,
|
|
3410
|
+
createContentGateConfig,
|
|
2858
3411
|
createEnvSecurityConfig,
|
|
2859
3412
|
createInjectionDefenseConfig,
|
|
2860
3413
|
createInvisibleTextConfig,
|
|
@@ -2873,11 +3426,17 @@ export {
|
|
|
2873
3426
|
parseBuildInfo,
|
|
2874
3427
|
parseCodeSecurityConfig,
|
|
2875
3428
|
parseCommandResult,
|
|
3429
|
+
parseContentGateConfig,
|
|
2876
3430
|
parseEntryInfo,
|
|
2877
3431
|
parseEnvSecurityConfig,
|
|
3432
|
+
parseFileEntry,
|
|
3433
|
+
parseFileInfo,
|
|
2878
3434
|
parseFilesystemEvent,
|
|
3435
|
+
parseGovernancePack,
|
|
2879
3436
|
parseInjectionDefenseConfig,
|
|
2880
3437
|
parseInvisibleTextConfig,
|
|
3438
|
+
parseLockLease,
|
|
3439
|
+
parseLockStatus,
|
|
2881
3440
|
parseNetworkPolicy,
|
|
2882
3441
|
parsePIIConfig,
|
|
2883
3442
|
parseProcessInfo,
|