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