@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/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
- pipelining: 1,
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.5;
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
- return { volume_id: att.volumeId, mount_path: att.mountPath };
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/volumes.ts
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
- assertValidVolumeId(volumeId);
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
- assertValidVolumeId(volumeId);
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,