@declaw/sdk 1.1.12 → 1.2.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 +35 -0
- package/LICENSE +1 -1
- package/dist/index.cjs +566 -9
- 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 +554 -9
- 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);
|
|
@@ -129,7 +135,7 @@ function getDispatcher() {
|
|
|
129
135
|
}
|
|
130
136
|
const undici = await import("undici");
|
|
131
137
|
const connOverride = parseInt(process.env.DECLAW_SDK_CONNECTIONS || "", 10);
|
|
132
|
-
const connections = Number.isFinite(connOverride) && connOverride > 0 ? connOverride :
|
|
138
|
+
const connections = Number.isFinite(connOverride) && connOverride > 0 ? connOverride : 64;
|
|
133
139
|
const streamsOverride = parseInt(process.env.DECLAW_SDK_MAX_CONCURRENT_STREAMS || "", 10);
|
|
134
140
|
const maxConcurrentStreams = Number.isFinite(streamsOverride) && streamsOverride > 0 ? streamsOverride : 1e3;
|
|
135
141
|
return new undici.Agent({
|
|
@@ -152,10 +158,13 @@ function getDispatcher() {
|
|
|
152
158
|
return _dispatcherPromise;
|
|
153
159
|
}
|
|
154
160
|
var STATUS_ERROR_MAP = {
|
|
161
|
+
400: InvalidArgumentError,
|
|
155
162
|
401: AuthenticationError,
|
|
156
163
|
403: AuthenticationError,
|
|
157
164
|
404: NotFoundError,
|
|
158
165
|
408: TimeoutError,
|
|
166
|
+
409: ConflictError,
|
|
167
|
+
413: NotEnoughSpaceError,
|
|
159
168
|
422: InvalidArgumentError,
|
|
160
169
|
507: NotEnoughSpaceError
|
|
161
170
|
};
|
|
@@ -814,6 +823,49 @@ function invisibleTextConfigToJSON(config) {
|
|
|
814
823
|
return result;
|
|
815
824
|
}
|
|
816
825
|
|
|
826
|
+
// src/security/customPolicy.ts
|
|
827
|
+
function parseCustomPolicyConfig(data) {
|
|
828
|
+
return {
|
|
829
|
+
enabled: data.enabled ?? false,
|
|
830
|
+
inlineRego: data.inline_rego ?? data.inlineRego,
|
|
831
|
+
inlineModules: data.inline_modules ?? data.inlineModules,
|
|
832
|
+
policyRef: data.policy_ref ?? data.policyRef,
|
|
833
|
+
defaultDeny: data.default_deny ?? data.defaultDeny ?? false
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
function customPolicyConfigToJSON(config) {
|
|
837
|
+
return {
|
|
838
|
+
enabled: config.enabled,
|
|
839
|
+
inline_rego: config.inlineRego,
|
|
840
|
+
inline_modules: config.inlineModules,
|
|
841
|
+
policy_ref: config.policyRef,
|
|
842
|
+
default_deny: config.defaultDeny
|
|
843
|
+
};
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
// src/security/contentGate.ts
|
|
847
|
+
function createContentGateConfig(opts) {
|
|
848
|
+
return {
|
|
849
|
+
enabled: opts?.enabled ?? false,
|
|
850
|
+
domains: opts?.domains
|
|
851
|
+
};
|
|
852
|
+
}
|
|
853
|
+
function parseContentGateConfig(data) {
|
|
854
|
+
return {
|
|
855
|
+
enabled: data.enabled ?? false,
|
|
856
|
+
domains: data.domains
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
function contentGateConfigToJSON(config) {
|
|
860
|
+
const result = {
|
|
861
|
+
enabled: config.enabled
|
|
862
|
+
};
|
|
863
|
+
if (config.domains !== void 0) {
|
|
864
|
+
result.domains = config.domains;
|
|
865
|
+
}
|
|
866
|
+
return result;
|
|
867
|
+
}
|
|
868
|
+
|
|
817
869
|
// src/security/policy.ts
|
|
818
870
|
function createSecurityPolicy(opts) {
|
|
819
871
|
return {
|
|
@@ -825,12 +877,16 @@ function createSecurityPolicy(opts) {
|
|
|
825
877
|
envSecurity: opts?.envSecurity ?? createEnvSecurityConfig(),
|
|
826
878
|
toxicity: opts?.toxicity,
|
|
827
879
|
codeSecurity: opts?.codeSecurity,
|
|
828
|
-
invisibleText: opts?.invisibleText
|
|
880
|
+
invisibleText: opts?.invisibleText,
|
|
881
|
+
contentGate: opts?.contentGate,
|
|
882
|
+
customPolicy: opts?.customPolicy
|
|
829
883
|
};
|
|
830
884
|
}
|
|
831
885
|
function parseSecurityPolicy(data) {
|
|
832
886
|
const injDef = data.injection_defense ?? data.injectionDefense;
|
|
833
887
|
const auditData = data.audit;
|
|
888
|
+
const customPolicyData = data.custom_policy ?? data.customPolicy;
|
|
889
|
+
const contentGateData = data.content_gate ?? data.contentGate;
|
|
834
890
|
return {
|
|
835
891
|
pii: data.pii ? parsePIIConfig(data.pii) : createPIIConfig(),
|
|
836
892
|
injectionDefense: typeof injDef === "boolean" ? injDef : injDef ? parseInjectionDefenseConfig(injDef) : false,
|
|
@@ -840,7 +896,9 @@ function parseSecurityPolicy(data) {
|
|
|
840
896
|
envSecurity: data.env_security ?? data.envSecurity ? parseEnvSecurityConfig(data.env_security ?? data.envSecurity) : createEnvSecurityConfig(),
|
|
841
897
|
toxicity: data.toxicity ? parseToxicityConfig(data.toxicity) : void 0,
|
|
842
898
|
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
|
|
899
|
+
invisibleText: data.invisible_text ?? data.invisibleText ? parseInvisibleTextConfig(data.invisible_text ?? data.invisibleText) : void 0,
|
|
900
|
+
contentGate: contentGateData ? parseContentGateConfig(contentGateData) : void 0,
|
|
901
|
+
customPolicy: customPolicyData ? parseCustomPolicyConfig(customPolicyData) : void 0
|
|
844
902
|
};
|
|
845
903
|
}
|
|
846
904
|
function securityPolicyToJSON(policy) {
|
|
@@ -890,6 +948,12 @@ function securityPolicyToJSON(policy) {
|
|
|
890
948
|
if (policy.invisibleText) {
|
|
891
949
|
result.invisible_text = invisibleTextConfigToJSON(policy.invisibleText);
|
|
892
950
|
}
|
|
951
|
+
if (policy.contentGate) {
|
|
952
|
+
result.content_gate = contentGateConfigToJSON(policy.contentGate);
|
|
953
|
+
}
|
|
954
|
+
if (policy.customPolicy) {
|
|
955
|
+
result.custom_policy = customPolicyConfigToJSON(policy.customPolicy);
|
|
956
|
+
}
|
|
893
957
|
return result;
|
|
894
958
|
}
|
|
895
959
|
function requiresTlsInterception(policy) {
|
|
@@ -1908,11 +1972,53 @@ function parseVolumeInfo(data) {
|
|
|
1908
1972
|
sizeBytes: Number(data.size_bytes ?? 0),
|
|
1909
1973
|
contentType: String(data.content_type ?? ""),
|
|
1910
1974
|
metadata: data.metadata ?? {},
|
|
1911
|
-
createdAt: String(data.created_at ?? "")
|
|
1975
|
+
createdAt: String(data.created_at ?? ""),
|
|
1976
|
+
backend: String(data.backend ?? ""),
|
|
1977
|
+
quotaBytes: Number(data.quota_bytes ?? 0),
|
|
1978
|
+
updatedAt: String(data.updated_at ?? "")
|
|
1979
|
+
};
|
|
1980
|
+
}
|
|
1981
|
+
function parseFileEntry(data) {
|
|
1982
|
+
return {
|
|
1983
|
+
name: String(data.name ?? ""),
|
|
1984
|
+
path: String(data.path ?? ""),
|
|
1985
|
+
isDir: Boolean(data.is_dir ?? false),
|
|
1986
|
+
size: Number(data.size ?? 0),
|
|
1987
|
+
modTime: String(data.mod_time ?? ""),
|
|
1988
|
+
mode: Number(data.mode ?? 0)
|
|
1989
|
+
};
|
|
1990
|
+
}
|
|
1991
|
+
function parseFileInfo(data) {
|
|
1992
|
+
return {
|
|
1993
|
+
...parseFileEntry(data),
|
|
1994
|
+
version: String(data.version ?? "")
|
|
1995
|
+
};
|
|
1996
|
+
}
|
|
1997
|
+
function parseLockLease(data) {
|
|
1998
|
+
return {
|
|
1999
|
+
token: String(data.token ?? ""),
|
|
2000
|
+
ttlSeconds: Number(data.ttl_seconds ?? 0),
|
|
2001
|
+
expiresAt: String(data.expires_at ?? "")
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
function parseLockStatus(data) {
|
|
2005
|
+
return {
|
|
2006
|
+
held: Boolean(data.held ?? false),
|
|
2007
|
+
expiresInMs: Number(data.expires_in_ms ?? 0)
|
|
1912
2008
|
};
|
|
1913
2009
|
}
|
|
1914
2010
|
function volumeAttachmentToJSON(att) {
|
|
1915
|
-
|
|
2011
|
+
const out = {
|
|
2012
|
+
volume_id: att.volumeId,
|
|
2013
|
+
mount_path: att.mountPath
|
|
2014
|
+
};
|
|
2015
|
+
if (att.mode) {
|
|
2016
|
+
out.mode = att.mode;
|
|
2017
|
+
}
|
|
2018
|
+
if (att.subpath) {
|
|
2019
|
+
out.subpath = att.subpath;
|
|
2020
|
+
}
|
|
2021
|
+
return out;
|
|
1916
2022
|
}
|
|
1917
2023
|
|
|
1918
2024
|
// src/sandbox/sandbox.ts
|
|
@@ -2738,7 +2844,7 @@ var Template = class {
|
|
|
2738
2844
|
}
|
|
2739
2845
|
};
|
|
2740
2846
|
|
|
2741
|
-
// src/volumes/
|
|
2847
|
+
// src/volumes/files.ts
|
|
2742
2848
|
var VALID_VOLUME_ID_RE = /^[a-zA-Z0-9_-]+$/;
|
|
2743
2849
|
function assertValidVolumeId(id) {
|
|
2744
2850
|
if (!id || !VALID_VOLUME_ID_RE.test(id)) {
|
|
@@ -2747,8 +2853,223 @@ function assertValidVolumeId(id) {
|
|
|
2747
2853
|
);
|
|
2748
2854
|
}
|
|
2749
2855
|
}
|
|
2856
|
+
var VolumeFiles = class {
|
|
2857
|
+
volumeId;
|
|
2858
|
+
opts;
|
|
2859
|
+
constructor(volumeId, opts) {
|
|
2860
|
+
assertValidVolumeId(volumeId);
|
|
2861
|
+
this.volumeId = volumeId;
|
|
2862
|
+
this.opts = opts;
|
|
2863
|
+
}
|
|
2864
|
+
client() {
|
|
2865
|
+
const config = new ConnectionConfig({
|
|
2866
|
+
apiKey: this.opts?.apiKey,
|
|
2867
|
+
domain: this.opts?.domain,
|
|
2868
|
+
apiUrl: this.opts?.apiUrl,
|
|
2869
|
+
requestTimeout: this.opts?.requestTimeout
|
|
2870
|
+
});
|
|
2871
|
+
return getSharedClient(config);
|
|
2872
|
+
}
|
|
2873
|
+
timeout() {
|
|
2874
|
+
return this.opts?.requestTimeout;
|
|
2875
|
+
}
|
|
2876
|
+
/** Write raw bytes to `path`. Optionally conditional on `ifVersion` (CAS). */
|
|
2877
|
+
async write(path, data, opts) {
|
|
2878
|
+
if (!path) {
|
|
2879
|
+
throw new InvalidArgumentError("path is required");
|
|
2880
|
+
}
|
|
2881
|
+
const params = { path };
|
|
2882
|
+
if (opts?.ifVersion) {
|
|
2883
|
+
params.if_version = opts.ifVersion;
|
|
2884
|
+
}
|
|
2885
|
+
const body = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
2886
|
+
const resp = await this.client().put(`/volumes/${this.volumeId}/files/raw`, {
|
|
2887
|
+
params,
|
|
2888
|
+
body,
|
|
2889
|
+
headers: { "Content-Type": "application/octet-stream" },
|
|
2890
|
+
timeout: opts?.requestTimeout ?? this.timeout()
|
|
2891
|
+
});
|
|
2892
|
+
return String(resp.path ?? path);
|
|
2893
|
+
}
|
|
2894
|
+
/** Read raw bytes from `path`. */
|
|
2895
|
+
async read(path) {
|
|
2896
|
+
if (!path) {
|
|
2897
|
+
throw new InvalidArgumentError("path is required");
|
|
2898
|
+
}
|
|
2899
|
+
return this.client().getBytes(`/volumes/${this.volumeId}/files/raw`, {
|
|
2900
|
+
params: { path },
|
|
2901
|
+
timeout: this.timeout()
|
|
2902
|
+
});
|
|
2903
|
+
}
|
|
2904
|
+
/** List directory entries under `path`. */
|
|
2905
|
+
async list(path) {
|
|
2906
|
+
if (!path) {
|
|
2907
|
+
throw new InvalidArgumentError("path is required");
|
|
2908
|
+
}
|
|
2909
|
+
const resp = await this.client().get(`/volumes/${this.volumeId}/files/list`, {
|
|
2910
|
+
params: { path },
|
|
2911
|
+
timeout: this.timeout()
|
|
2912
|
+
});
|
|
2913
|
+
const rows = resp.entries ?? [];
|
|
2914
|
+
return rows.map(parseFileEntry);
|
|
2915
|
+
}
|
|
2916
|
+
/** Stat `path`, returning the entry plus the CAS `version` token. */
|
|
2917
|
+
async info(path) {
|
|
2918
|
+
if (!path) {
|
|
2919
|
+
throw new InvalidArgumentError("path is required");
|
|
2920
|
+
}
|
|
2921
|
+
const resp = await this.client().get(`/volumes/${this.volumeId}/files/info`, {
|
|
2922
|
+
params: { path },
|
|
2923
|
+
timeout: this.timeout()
|
|
2924
|
+
});
|
|
2925
|
+
return parseFileInfo(resp);
|
|
2926
|
+
}
|
|
2927
|
+
/** Return whether `path` exists. */
|
|
2928
|
+
async exists(path) {
|
|
2929
|
+
if (!path) {
|
|
2930
|
+
throw new InvalidArgumentError("path is required");
|
|
2931
|
+
}
|
|
2932
|
+
const resp = await this.client().get(`/volumes/${this.volumeId}/files/exists`, {
|
|
2933
|
+
params: { path },
|
|
2934
|
+
timeout: this.timeout()
|
|
2935
|
+
});
|
|
2936
|
+
return Boolean(resp.exists ?? false);
|
|
2937
|
+
}
|
|
2938
|
+
/** Remove `path`. Pass `{ recursive: true }` to remove a directory tree. */
|
|
2939
|
+
async remove(path, opts) {
|
|
2940
|
+
if (!path) {
|
|
2941
|
+
throw new InvalidArgumentError("path is required");
|
|
2942
|
+
}
|
|
2943
|
+
const params = {
|
|
2944
|
+
path,
|
|
2945
|
+
recursive: opts?.recursive ? "true" : "false"
|
|
2946
|
+
};
|
|
2947
|
+
await this.client().delete(`/volumes/${this.volumeId}/files`, {
|
|
2948
|
+
params,
|
|
2949
|
+
timeout: opts?.requestTimeout ?? this.timeout()
|
|
2950
|
+
});
|
|
2951
|
+
}
|
|
2952
|
+
/** Rename `oldPath` to `newPath`. */
|
|
2953
|
+
async rename(oldPath, newPath) {
|
|
2954
|
+
if (!oldPath || !newPath) {
|
|
2955
|
+
throw new InvalidArgumentError("oldPath and newPath are required");
|
|
2956
|
+
}
|
|
2957
|
+
const resp = await this.client().patch(`/volumes/${this.volumeId}/files`, {
|
|
2958
|
+
json: { old_path: oldPath, new_path: newPath },
|
|
2959
|
+
timeout: this.timeout()
|
|
2960
|
+
});
|
|
2961
|
+
return {
|
|
2962
|
+
oldPath: String(resp.old_path ?? oldPath),
|
|
2963
|
+
newPath: String(resp.new_path ?? newPath)
|
|
2964
|
+
};
|
|
2965
|
+
}
|
|
2966
|
+
/** Create a directory at `path`. */
|
|
2967
|
+
async mkdir(path) {
|
|
2968
|
+
if (!path) {
|
|
2969
|
+
throw new InvalidArgumentError("path is required");
|
|
2970
|
+
}
|
|
2971
|
+
const resp = await this.client().post(`/volumes/${this.volumeId}/files/mkdir`, {
|
|
2972
|
+
json: { path },
|
|
2973
|
+
timeout: this.timeout()
|
|
2974
|
+
});
|
|
2975
|
+
return String(resp.path ?? path);
|
|
2976
|
+
}
|
|
2977
|
+
};
|
|
2978
|
+
|
|
2979
|
+
// src/volumes/locks.ts
|
|
2980
|
+
var VALID_VOLUME_ID_RE2 = /^[a-zA-Z0-9_-]+$/;
|
|
2981
|
+
function assertValidVolumeId2(id) {
|
|
2982
|
+
if (!id || !VALID_VOLUME_ID_RE2.test(id)) {
|
|
2983
|
+
throw new InvalidArgumentError(
|
|
2984
|
+
`Invalid volume ID: "${id}". Must be alphanumeric with hyphens/underscores only.`
|
|
2985
|
+
);
|
|
2986
|
+
}
|
|
2987
|
+
}
|
|
2988
|
+
var VolumeLocks = class {
|
|
2989
|
+
volumeId;
|
|
2990
|
+
opts;
|
|
2991
|
+
constructor(volumeId, opts) {
|
|
2992
|
+
assertValidVolumeId2(volumeId);
|
|
2993
|
+
this.volumeId = volumeId;
|
|
2994
|
+
this.opts = opts;
|
|
2995
|
+
}
|
|
2996
|
+
client() {
|
|
2997
|
+
const config = new ConnectionConfig({
|
|
2998
|
+
apiKey: this.opts?.apiKey,
|
|
2999
|
+
domain: this.opts?.domain,
|
|
3000
|
+
apiUrl: this.opts?.apiUrl,
|
|
3001
|
+
requestTimeout: this.opts?.requestTimeout
|
|
3002
|
+
});
|
|
3003
|
+
return getSharedClient(config);
|
|
3004
|
+
}
|
|
3005
|
+
timeout() {
|
|
3006
|
+
return this.opts?.requestTimeout;
|
|
3007
|
+
}
|
|
3008
|
+
/** Acquire a lock on `path`. Throws ConflictError (409) if already held. */
|
|
3009
|
+
async acquire(path, ttlSeconds) {
|
|
3010
|
+
if (!path) {
|
|
3011
|
+
throw new InvalidArgumentError("path is required");
|
|
3012
|
+
}
|
|
3013
|
+
const json = { path };
|
|
3014
|
+
if (ttlSeconds !== void 0) {
|
|
3015
|
+
json.ttl_seconds = ttlSeconds;
|
|
3016
|
+
}
|
|
3017
|
+
const resp = await this.client().post(`/volumes/${this.volumeId}/locks`, {
|
|
3018
|
+
json,
|
|
3019
|
+
timeout: this.timeout()
|
|
3020
|
+
});
|
|
3021
|
+
return parseLockLease(resp);
|
|
3022
|
+
}
|
|
3023
|
+
/** Release a lock on `path` held under `token`. Throws ConflictError (409) if not the holder. */
|
|
3024
|
+
async release(path, token) {
|
|
3025
|
+
if (!path || !token) {
|
|
3026
|
+
throw new InvalidArgumentError("path and token are required");
|
|
3027
|
+
}
|
|
3028
|
+
const resp = await this.client().delete(`/volumes/${this.volumeId}/locks`, {
|
|
3029
|
+
json: { path, token },
|
|
3030
|
+
timeout: this.timeout()
|
|
3031
|
+
});
|
|
3032
|
+
return Boolean(resp.released ?? false);
|
|
3033
|
+
}
|
|
3034
|
+
/** Renew a lock on `path` held under `token`. Throws ConflictError (409) if not the holder. */
|
|
3035
|
+
async renew(path, token, ttlSeconds) {
|
|
3036
|
+
if (!path || !token) {
|
|
3037
|
+
throw new InvalidArgumentError("path and token are required");
|
|
3038
|
+
}
|
|
3039
|
+
const json = { path, token };
|
|
3040
|
+
if (ttlSeconds !== void 0) {
|
|
3041
|
+
json.ttl_seconds = ttlSeconds;
|
|
3042
|
+
}
|
|
3043
|
+
const resp = await this.client().post(`/volumes/${this.volumeId}/locks/renew`, {
|
|
3044
|
+
json,
|
|
3045
|
+
timeout: this.timeout()
|
|
3046
|
+
});
|
|
3047
|
+
return { ...parseLockLease(resp), token };
|
|
3048
|
+
}
|
|
3049
|
+
/** Query whether `path` is currently locked. */
|
|
3050
|
+
async status(path) {
|
|
3051
|
+
if (!path) {
|
|
3052
|
+
throw new InvalidArgumentError("path is required");
|
|
3053
|
+
}
|
|
3054
|
+
const resp = await this.client().get(`/volumes/${this.volumeId}/locks`, {
|
|
3055
|
+
params: { path },
|
|
3056
|
+
timeout: this.timeout()
|
|
3057
|
+
});
|
|
3058
|
+
return parseLockStatus(resp);
|
|
3059
|
+
}
|
|
3060
|
+
};
|
|
3061
|
+
|
|
3062
|
+
// src/volumes/volumes.ts
|
|
3063
|
+
var VALID_VOLUME_ID_RE3 = /^[a-zA-Z0-9_-]+$/;
|
|
3064
|
+
function assertValidVolumeId3(id) {
|
|
3065
|
+
if (!id || !VALID_VOLUME_ID_RE3.test(id)) {
|
|
3066
|
+
throw new InvalidArgumentError(
|
|
3067
|
+
`Invalid volume ID: "${id}". Must be alphanumeric with hyphens/underscores only.`
|
|
3068
|
+
);
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
2750
3071
|
var Volumes = class {
|
|
2751
|
-
/** Create a volume by streaming a tarball to the server. */
|
|
3072
|
+
/** Create a volume by streaming a tarball (gzip tar.gz) to the server. */
|
|
2752
3073
|
static async create(name, data, opts) {
|
|
2753
3074
|
if (!name) {
|
|
2754
3075
|
throw new InvalidArgumentError("volume name is required");
|
|
@@ -2769,9 +3090,113 @@ var Volumes = class {
|
|
|
2769
3090
|
});
|
|
2770
3091
|
return parseVolumeInfo(resp);
|
|
2771
3092
|
}
|
|
3093
|
+
/**
|
|
3094
|
+
* Capture the attached volume's mount path in `sandboxId` into a NEW volume.
|
|
3095
|
+
*
|
|
3096
|
+
* The source volume is left unchanged. If `name` is omitted the server names
|
|
3097
|
+
* the new volume "<source-name>-commit". Returns the new VolumeInfo.
|
|
3098
|
+
*/
|
|
3099
|
+
static async commit(sandboxId, volumeId, name, opts) {
|
|
3100
|
+
if (!sandboxId || !VALID_VOLUME_ID_RE3.test(sandboxId)) {
|
|
3101
|
+
throw new InvalidArgumentError(
|
|
3102
|
+
`Invalid sandbox ID: "${sandboxId}". Must be alphanumeric with hyphens/underscores only.`
|
|
3103
|
+
);
|
|
3104
|
+
}
|
|
3105
|
+
assertValidVolumeId3(volumeId);
|
|
3106
|
+
const config = new ConnectionConfig({
|
|
3107
|
+
apiKey: opts?.apiKey,
|
|
3108
|
+
domain: opts?.domain,
|
|
3109
|
+
apiUrl: opts?.apiUrl,
|
|
3110
|
+
requestTimeout: opts?.requestTimeout
|
|
3111
|
+
});
|
|
3112
|
+
const client = getSharedClient(config);
|
|
3113
|
+
const resp = await client.post(`/sandboxes/${sandboxId}/volumes/${volumeId}/commit`, {
|
|
3114
|
+
params: name ? { name } : void 0,
|
|
3115
|
+
timeout: opts?.requestTimeout
|
|
3116
|
+
});
|
|
3117
|
+
return parseVolumeInfo(resp);
|
|
3118
|
+
}
|
|
3119
|
+
/**
|
|
3120
|
+
* Snapshot an arbitrary absolute in-sandbox `path` into a NEW volume.
|
|
3121
|
+
*
|
|
3122
|
+
* Unlike `commit` (which captures an already-attached volume's mount path),
|
|
3123
|
+
* `snapshot` captures any path in the running sandbox. `name` defaults to
|
|
3124
|
+
* "snapshot" on the server. Synthetic paths (/proc, /sys, /dev) are rejected.
|
|
3125
|
+
*/
|
|
3126
|
+
static async snapshot(sandboxId, path, name, opts) {
|
|
3127
|
+
if (!sandboxId || !VALID_VOLUME_ID_RE3.test(sandboxId)) {
|
|
3128
|
+
throw new InvalidArgumentError(
|
|
3129
|
+
`Invalid sandbox ID: "${sandboxId}". Must be alphanumeric with hyphens/underscores only.`
|
|
3130
|
+
);
|
|
3131
|
+
}
|
|
3132
|
+
if (!path) {
|
|
3133
|
+
throw new InvalidArgumentError("path is required");
|
|
3134
|
+
}
|
|
3135
|
+
const config = new ConnectionConfig({
|
|
3136
|
+
apiKey: opts?.apiKey,
|
|
3137
|
+
domain: opts?.domain,
|
|
3138
|
+
apiUrl: opts?.apiUrl,
|
|
3139
|
+
requestTimeout: opts?.requestTimeout
|
|
3140
|
+
});
|
|
3141
|
+
const client = getSharedClient(config);
|
|
3142
|
+
const params = { path };
|
|
3143
|
+
if (name) {
|
|
3144
|
+
params.name = name;
|
|
3145
|
+
}
|
|
3146
|
+
const resp = await client.post(`/sandboxes/${sandboxId}/volumes/snapshot`, {
|
|
3147
|
+
params,
|
|
3148
|
+
timeout: opts?.requestTimeout
|
|
3149
|
+
});
|
|
3150
|
+
return parseVolumeInfo(resp);
|
|
3151
|
+
}
|
|
3152
|
+
/**
|
|
3153
|
+
* Create an empty file-granular volume. Requires a file-granular backend
|
|
3154
|
+
* (503 if not configured). Returns the new VolumeInfo.
|
|
3155
|
+
*/
|
|
3156
|
+
static async empty(name, opts) {
|
|
3157
|
+
if (!name) {
|
|
3158
|
+
throw new InvalidArgumentError("volume name is required");
|
|
3159
|
+
}
|
|
3160
|
+
const config = new ConnectionConfig({
|
|
3161
|
+
apiKey: opts?.apiKey,
|
|
3162
|
+
domain: opts?.domain,
|
|
3163
|
+
apiUrl: opts?.apiUrl,
|
|
3164
|
+
requestTimeout: opts?.requestTimeout
|
|
3165
|
+
});
|
|
3166
|
+
const client = getSharedClient(config);
|
|
3167
|
+
const resp = await client.post("/volumes/empty", {
|
|
3168
|
+
params: { name },
|
|
3169
|
+
timeout: opts?.requestTimeout
|
|
3170
|
+
});
|
|
3171
|
+
return parseVolumeInfo(resp);
|
|
3172
|
+
}
|
|
3173
|
+
/**
|
|
3174
|
+
* Ingest a gzip tar.gz archive into a NEW file-granular volume. Requires a
|
|
3175
|
+
* file-granular backend (503 if not configured). 413 on quota exceeded.
|
|
3176
|
+
*/
|
|
3177
|
+
static async ingest(name, data, opts) {
|
|
3178
|
+
if (!name) {
|
|
3179
|
+
throw new InvalidArgumentError("volume name is required");
|
|
3180
|
+
}
|
|
3181
|
+
const config = new ConnectionConfig({
|
|
3182
|
+
apiKey: opts?.apiKey,
|
|
3183
|
+
domain: opts?.domain,
|
|
3184
|
+
apiUrl: opts?.apiUrl,
|
|
3185
|
+
requestTimeout: opts?.requestTimeout
|
|
3186
|
+
});
|
|
3187
|
+
const client = getSharedClient(config);
|
|
3188
|
+
const body = data instanceof Uint8Array ? data : new Uint8Array(data);
|
|
3189
|
+
const resp = await client.post("/volumes/ingest", {
|
|
3190
|
+
params: { name },
|
|
3191
|
+
body,
|
|
3192
|
+
headers: { "Content-Type": opts?.contentType ?? "application/gzip" },
|
|
3193
|
+
timeout: opts?.requestTimeout
|
|
3194
|
+
});
|
|
3195
|
+
return parseVolumeInfo(resp);
|
|
3196
|
+
}
|
|
2772
3197
|
/** Fetch metadata for a single volume. */
|
|
2773
3198
|
static async get(volumeId, opts) {
|
|
2774
|
-
|
|
3199
|
+
assertValidVolumeId3(volumeId);
|
|
2775
3200
|
const config = new ConnectionConfig({
|
|
2776
3201
|
apiKey: opts?.apiKey,
|
|
2777
3202
|
domain: opts?.domain,
|
|
@@ -2799,9 +3224,23 @@ var Volumes = class {
|
|
|
2799
3224
|
const rows = resp.volumes ?? [];
|
|
2800
3225
|
return rows.map(parseVolumeInfo);
|
|
2801
3226
|
}
|
|
3227
|
+
/** Download the volume's contents as raw bytes (the stored archive/blob). */
|
|
3228
|
+
static async download(volumeId, opts) {
|
|
3229
|
+
assertValidVolumeId3(volumeId);
|
|
3230
|
+
const config = new ConnectionConfig({
|
|
3231
|
+
apiKey: opts?.apiKey,
|
|
3232
|
+
domain: opts?.domain,
|
|
3233
|
+
apiUrl: opts?.apiUrl,
|
|
3234
|
+
requestTimeout: opts?.requestTimeout
|
|
3235
|
+
});
|
|
3236
|
+
const client = getSharedClient(config);
|
|
3237
|
+
return client.getBytes(`/volumes/${volumeId}/download`, {
|
|
3238
|
+
timeout: opts?.requestTimeout
|
|
3239
|
+
});
|
|
3240
|
+
}
|
|
2802
3241
|
/** Delete a volume and its blob. Idempotent on the wire. */
|
|
2803
3242
|
static async delete(volumeId, opts) {
|
|
2804
|
-
|
|
3243
|
+
assertValidVolumeId3(volumeId);
|
|
2805
3244
|
const config = new ConnectionConfig({
|
|
2806
3245
|
apiKey: opts?.apiKey,
|
|
2807
3246
|
domain: opts?.domain,
|
|
@@ -2811,6 +3250,100 @@ var Volumes = class {
|
|
|
2811
3250
|
const client = getSharedClient(config);
|
|
2812
3251
|
await client.delete(`/volumes/${volumeId}`, { timeout: opts?.requestTimeout });
|
|
2813
3252
|
}
|
|
3253
|
+
/**
|
|
3254
|
+
* File-granular operations (read/write/list/info/exists/remove/rename/mkdir,
|
|
3255
|
+
* plus CAS via `write(..., { ifVersion })`) on `volumeId`. File-granular
|
|
3256
|
+
* volumes only.
|
|
3257
|
+
*/
|
|
3258
|
+
static files(volumeId, opts) {
|
|
3259
|
+
return new VolumeFiles(volumeId, opts);
|
|
3260
|
+
}
|
|
3261
|
+
/** Advisory locks (acquire/release/renew/status) over a (volume, path). */
|
|
3262
|
+
static locks(volumeId, opts) {
|
|
3263
|
+
return new VolumeLocks(volumeId, opts);
|
|
3264
|
+
}
|
|
3265
|
+
};
|
|
3266
|
+
|
|
3267
|
+
// src/governance/models.ts
|
|
3268
|
+
function parseGovernanceControl(data) {
|
|
3269
|
+
return {
|
|
3270
|
+
control: String(data.control ?? ""),
|
|
3271
|
+
gate: String(data.gate ?? ""),
|
|
3272
|
+
rule: String(data.rule ?? ""),
|
|
3273
|
+
playbook: String(data.playbook ?? "")
|
|
3274
|
+
};
|
|
3275
|
+
}
|
|
3276
|
+
function parseGovernanceAdvisory(data) {
|
|
3277
|
+
return {
|
|
3278
|
+
control: String(data.control ?? ""),
|
|
3279
|
+
reason: String(data.reason ?? "")
|
|
3280
|
+
};
|
|
3281
|
+
}
|
|
3282
|
+
function parseGovernancePack(data) {
|
|
3283
|
+
const rawEnforces = data.enforces ?? [];
|
|
3284
|
+
const rawAdvisory = data.advisory ?? [];
|
|
3285
|
+
return {
|
|
3286
|
+
name: String(data.name ?? ""),
|
|
3287
|
+
version: String(data.version ?? ""),
|
|
3288
|
+
framework: String(data.framework ?? ""),
|
|
3289
|
+
description: String(data.description ?? ""),
|
|
3290
|
+
gates: data.gates ?? [],
|
|
3291
|
+
enforces: rawEnforces.map(parseGovernanceControl),
|
|
3292
|
+
advisory: rawAdvisory.map(parseGovernanceAdvisory),
|
|
3293
|
+
policyRef: String(data.policy_ref ?? data.policyRef ?? ""),
|
|
3294
|
+
seeded: Boolean(data.seeded ?? false)
|
|
3295
|
+
};
|
|
3296
|
+
}
|
|
3297
|
+
|
|
3298
|
+
// src/governance/governance.ts
|
|
3299
|
+
var VALID_PACK_NAME_RE = /^[a-zA-Z0-9_-]+$/;
|
|
3300
|
+
function assertValidPackName(name) {
|
|
3301
|
+
if (!name || !VALID_PACK_NAME_RE.test(name)) {
|
|
3302
|
+
throw new InvalidArgumentError(
|
|
3303
|
+
`Invalid pack name: "${name}". Must be alphanumeric with hyphens/underscores only.`
|
|
3304
|
+
);
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
var Governance = class {
|
|
3308
|
+
/**
|
|
3309
|
+
* List all available governance packs.
|
|
3310
|
+
*
|
|
3311
|
+
* Sends GET /governance/packs and returns the `packs` array.
|
|
3312
|
+
*/
|
|
3313
|
+
static async listPacks(opts) {
|
|
3314
|
+
const config = new ConnectionConfig({
|
|
3315
|
+
apiKey: opts?.apiKey,
|
|
3316
|
+
domain: opts?.domain,
|
|
3317
|
+
apiUrl: opts?.apiUrl,
|
|
3318
|
+
requestTimeout: opts?.requestTimeout
|
|
3319
|
+
});
|
|
3320
|
+
const client = getSharedClient(config);
|
|
3321
|
+
const resp = await client.get("/governance/packs", {
|
|
3322
|
+
timeout: opts?.requestTimeout
|
|
3323
|
+
});
|
|
3324
|
+
const rows = resp.packs ?? [];
|
|
3325
|
+
return rows.map(parseGovernancePack);
|
|
3326
|
+
}
|
|
3327
|
+
/**
|
|
3328
|
+
* Fetch a single governance pack by name.
|
|
3329
|
+
*
|
|
3330
|
+
* Sends GET /governance/packs/:name and returns the pack object.
|
|
3331
|
+
* Throws InvalidArgumentError if the name contains unsafe characters.
|
|
3332
|
+
*/
|
|
3333
|
+
static async getPack(name, opts) {
|
|
3334
|
+
assertValidPackName(name);
|
|
3335
|
+
const config = new ConnectionConfig({
|
|
3336
|
+
apiKey: opts?.apiKey,
|
|
3337
|
+
domain: opts?.domain,
|
|
3338
|
+
apiUrl: opts?.apiUrl,
|
|
3339
|
+
requestTimeout: opts?.requestTimeout
|
|
3340
|
+
});
|
|
3341
|
+
const client = getSharedClient(config);
|
|
3342
|
+
const resp = await client.get(`/governance/packs/${name}`, {
|
|
3343
|
+
timeout: opts?.requestTimeout
|
|
3344
|
+
});
|
|
3345
|
+
return parseGovernancePack(resp);
|
|
3346
|
+
}
|
|
2814
3347
|
};
|
|
2815
3348
|
export {
|
|
2816
3349
|
ALL_TRAFFIC,
|
|
@@ -2820,6 +3353,7 @@ export {
|
|
|
2820
3353
|
CommandExitError,
|
|
2821
3354
|
CommandHandle,
|
|
2822
3355
|
Commands,
|
|
3356
|
+
ConflictError,
|
|
2823
3357
|
ConnectionConfig,
|
|
2824
3358
|
DEFAULT_MASK_PATTERNS,
|
|
2825
3359
|
FileType,
|
|
@@ -2828,6 +3362,7 @@ export {
|
|
|
2828
3362
|
FilesystemEventType,
|
|
2829
3363
|
GitAuthError,
|
|
2830
3364
|
GitUpstreamError,
|
|
3365
|
+
Governance,
|
|
2831
3366
|
InjectionAction,
|
|
2832
3367
|
InjectionSensitivity,
|
|
2833
3368
|
InvalidArgumentError,
|
|
@@ -2849,12 +3384,16 @@ export {
|
|
|
2849
3384
|
TemplateError,
|
|
2850
3385
|
TimeoutError,
|
|
2851
3386
|
TransformDirection,
|
|
3387
|
+
VolumeFiles,
|
|
3388
|
+
VolumeLocks,
|
|
2852
3389
|
Volumes,
|
|
2853
3390
|
WatchHandle,
|
|
2854
3391
|
applyTransformation,
|
|
2855
3392
|
codeSecurityConfigToJSON,
|
|
3393
|
+
contentGateConfigToJSON,
|
|
2856
3394
|
createAuditConfig,
|
|
2857
3395
|
createCodeSecurityConfig,
|
|
3396
|
+
createContentGateConfig,
|
|
2858
3397
|
createEnvSecurityConfig,
|
|
2859
3398
|
createInjectionDefenseConfig,
|
|
2860
3399
|
createInvisibleTextConfig,
|
|
@@ -2873,11 +3412,17 @@ export {
|
|
|
2873
3412
|
parseBuildInfo,
|
|
2874
3413
|
parseCodeSecurityConfig,
|
|
2875
3414
|
parseCommandResult,
|
|
3415
|
+
parseContentGateConfig,
|
|
2876
3416
|
parseEntryInfo,
|
|
2877
3417
|
parseEnvSecurityConfig,
|
|
3418
|
+
parseFileEntry,
|
|
3419
|
+
parseFileInfo,
|
|
2878
3420
|
parseFilesystemEvent,
|
|
3421
|
+
parseGovernancePack,
|
|
2879
3422
|
parseInjectionDefenseConfig,
|
|
2880
3423
|
parseInvisibleTextConfig,
|
|
3424
|
+
parseLockLease,
|
|
3425
|
+
parseLockStatus,
|
|
2881
3426
|
parseNetworkPolicy,
|
|
2882
3427
|
parsePIIConfig,
|
|
2883
3428
|
parseProcessInfo,
|