@declaw/sdk 1.1.13 → 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.cjs CHANGED
@@ -37,6 +37,7 @@ __export(index_exports, {
37
37
  CommandExitError: () => CommandExitError,
38
38
  CommandHandle: () => CommandHandle,
39
39
  Commands: () => Commands,
40
+ ConflictError: () => ConflictError,
40
41
  ConnectionConfig: () => ConnectionConfig,
41
42
  DEFAULT_MASK_PATTERNS: () => DEFAULT_MASK_PATTERNS,
42
43
  FileType: () => FileType,
@@ -45,6 +46,7 @@ __export(index_exports, {
45
46
  FilesystemEventType: () => FilesystemEventType,
46
47
  GitAuthError: () => GitAuthError,
47
48
  GitUpstreamError: () => GitUpstreamError,
49
+ Governance: () => Governance,
48
50
  InjectionAction: () => InjectionAction,
49
51
  InjectionSensitivity: () => InjectionSensitivity,
50
52
  InvalidArgumentError: () => InvalidArgumentError,
@@ -66,12 +68,16 @@ __export(index_exports, {
66
68
  TemplateError: () => TemplateError,
67
69
  TimeoutError: () => TimeoutError,
68
70
  TransformDirection: () => TransformDirection,
71
+ VolumeFiles: () => VolumeFiles,
72
+ VolumeLocks: () => VolumeLocks,
69
73
  Volumes: () => Volumes,
70
74
  WatchHandle: () => WatchHandle,
71
75
  applyTransformation: () => applyTransformation,
72
76
  codeSecurityConfigToJSON: () => codeSecurityConfigToJSON,
77
+ contentGateConfigToJSON: () => contentGateConfigToJSON,
73
78
  createAuditConfig: () => createAuditConfig,
74
79
  createCodeSecurityConfig: () => createCodeSecurityConfig,
80
+ createContentGateConfig: () => createContentGateConfig,
75
81
  createEnvSecurityConfig: () => createEnvSecurityConfig,
76
82
  createInjectionDefenseConfig: () => createInjectionDefenseConfig,
77
83
  createInvisibleTextConfig: () => createInvisibleTextConfig,
@@ -90,11 +96,17 @@ __export(index_exports, {
90
96
  parseBuildInfo: () => parseBuildInfo,
91
97
  parseCodeSecurityConfig: () => parseCodeSecurityConfig,
92
98
  parseCommandResult: () => parseCommandResult,
99
+ parseContentGateConfig: () => parseContentGateConfig,
93
100
  parseEntryInfo: () => parseEntryInfo,
94
101
  parseEnvSecurityConfig: () => parseEnvSecurityConfig,
102
+ parseFileEntry: () => parseFileEntry,
103
+ parseFileInfo: () => parseFileInfo,
95
104
  parseFilesystemEvent: () => parseFilesystemEvent,
105
+ parseGovernancePack: () => parseGovernancePack,
96
106
  parseInjectionDefenseConfig: () => parseInjectionDefenseConfig,
97
107
  parseInvisibleTextConfig: () => parseInvisibleTextConfig,
108
+ parseLockLease: () => parseLockLease,
109
+ parseLockStatus: () => parseLockStatus,
98
110
  parseNetworkPolicy: () => parseNetworkPolicy,
99
111
  parsePIIConfig: () => parsePIIConfig,
100
112
  parseProcessInfo: () => parseProcessInfo,
@@ -191,6 +203,12 @@ var NotEnoughSpaceError = class extends SandboxError {
191
203
  this.name = "NotEnoughSpaceError";
192
204
  }
193
205
  };
206
+ var ConflictError = class extends SandboxError {
207
+ constructor(message, opts) {
208
+ super(message, opts);
209
+ this.name = "ConflictError";
210
+ }
211
+ };
194
212
  var TemplateError = class extends SandboxError {
195
213
  constructor(message, opts) {
196
214
  super(message, opts);
@@ -271,10 +289,13 @@ function getDispatcher() {
271
289
  return _dispatcherPromise;
272
290
  }
273
291
  var STATUS_ERROR_MAP = {
292
+ 400: InvalidArgumentError,
274
293
  401: AuthenticationError,
275
294
  403: AuthenticationError,
276
295
  404: NotFoundError,
277
296
  408: TimeoutError,
297
+ 409: ConflictError,
298
+ 413: NotEnoughSpaceError,
278
299
  422: InvalidArgumentError,
279
300
  507: NotEnoughSpaceError
280
301
  };
@@ -933,6 +954,49 @@ function invisibleTextConfigToJSON(config) {
933
954
  return result;
934
955
  }
935
956
 
957
+ // src/security/customPolicy.ts
958
+ function parseCustomPolicyConfig(data) {
959
+ return {
960
+ enabled: data.enabled ?? false,
961
+ inlineRego: data.inline_rego ?? data.inlineRego,
962
+ inlineModules: data.inline_modules ?? data.inlineModules,
963
+ policyRef: data.policy_ref ?? data.policyRef,
964
+ defaultDeny: data.default_deny ?? data.defaultDeny ?? false
965
+ };
966
+ }
967
+ function customPolicyConfigToJSON(config) {
968
+ return {
969
+ enabled: config.enabled,
970
+ inline_rego: config.inlineRego,
971
+ inline_modules: config.inlineModules,
972
+ policy_ref: config.policyRef,
973
+ default_deny: config.defaultDeny
974
+ };
975
+ }
976
+
977
+ // src/security/contentGate.ts
978
+ function createContentGateConfig(opts) {
979
+ return {
980
+ enabled: opts?.enabled ?? false,
981
+ domains: opts?.domains
982
+ };
983
+ }
984
+ function parseContentGateConfig(data) {
985
+ return {
986
+ enabled: data.enabled ?? false,
987
+ domains: data.domains
988
+ };
989
+ }
990
+ function contentGateConfigToJSON(config) {
991
+ const result = {
992
+ enabled: config.enabled
993
+ };
994
+ if (config.domains !== void 0) {
995
+ result.domains = config.domains;
996
+ }
997
+ return result;
998
+ }
999
+
936
1000
  // src/security/policy.ts
937
1001
  function createSecurityPolicy(opts) {
938
1002
  return {
@@ -944,12 +1008,16 @@ function createSecurityPolicy(opts) {
944
1008
  envSecurity: opts?.envSecurity ?? createEnvSecurityConfig(),
945
1009
  toxicity: opts?.toxicity,
946
1010
  codeSecurity: opts?.codeSecurity,
947
- invisibleText: opts?.invisibleText
1011
+ invisibleText: opts?.invisibleText,
1012
+ contentGate: opts?.contentGate,
1013
+ customPolicy: opts?.customPolicy
948
1014
  };
949
1015
  }
950
1016
  function parseSecurityPolicy(data) {
951
1017
  const injDef = data.injection_defense ?? data.injectionDefense;
952
1018
  const auditData = data.audit;
1019
+ const customPolicyData = data.custom_policy ?? data.customPolicy;
1020
+ const contentGateData = data.content_gate ?? data.contentGate;
953
1021
  return {
954
1022
  pii: data.pii ? parsePIIConfig(data.pii) : createPIIConfig(),
955
1023
  injectionDefense: typeof injDef === "boolean" ? injDef : injDef ? parseInjectionDefenseConfig(injDef) : false,
@@ -959,7 +1027,9 @@ function parseSecurityPolicy(data) {
959
1027
  envSecurity: data.env_security ?? data.envSecurity ? parseEnvSecurityConfig(data.env_security ?? data.envSecurity) : createEnvSecurityConfig(),
960
1028
  toxicity: data.toxicity ? parseToxicityConfig(data.toxicity) : void 0,
961
1029
  codeSecurity: data.code_security ?? data.codeSecurity ? parseCodeSecurityConfig(data.code_security ?? data.codeSecurity) : void 0,
962
- invisibleText: data.invisible_text ?? data.invisibleText ? parseInvisibleTextConfig(data.invisible_text ?? data.invisibleText) : void 0
1030
+ invisibleText: data.invisible_text ?? data.invisibleText ? parseInvisibleTextConfig(data.invisible_text ?? data.invisibleText) : void 0,
1031
+ contentGate: contentGateData ? parseContentGateConfig(contentGateData) : void 0,
1032
+ customPolicy: customPolicyData ? parseCustomPolicyConfig(customPolicyData) : void 0
963
1033
  };
964
1034
  }
965
1035
  function securityPolicyToJSON(policy) {
@@ -1009,6 +1079,12 @@ function securityPolicyToJSON(policy) {
1009
1079
  if (policy.invisibleText) {
1010
1080
  result.invisible_text = invisibleTextConfigToJSON(policy.invisibleText);
1011
1081
  }
1082
+ if (policy.contentGate) {
1083
+ result.content_gate = contentGateConfigToJSON(policy.contentGate);
1084
+ }
1085
+ if (policy.customPolicy) {
1086
+ result.custom_policy = customPolicyConfigToJSON(policy.customPolicy);
1087
+ }
1012
1088
  return result;
1013
1089
  }
1014
1090
  function requiresTlsInterception(policy) {
@@ -2027,11 +2103,53 @@ function parseVolumeInfo(data) {
2027
2103
  sizeBytes: Number(data.size_bytes ?? 0),
2028
2104
  contentType: String(data.content_type ?? ""),
2029
2105
  metadata: data.metadata ?? {},
2030
- createdAt: String(data.created_at ?? "")
2106
+ createdAt: String(data.created_at ?? ""),
2107
+ backend: String(data.backend ?? ""),
2108
+ quotaBytes: Number(data.quota_bytes ?? 0),
2109
+ updatedAt: String(data.updated_at ?? "")
2110
+ };
2111
+ }
2112
+ function parseFileEntry(data) {
2113
+ return {
2114
+ name: String(data.name ?? ""),
2115
+ path: String(data.path ?? ""),
2116
+ isDir: Boolean(data.is_dir ?? false),
2117
+ size: Number(data.size ?? 0),
2118
+ modTime: String(data.mod_time ?? ""),
2119
+ mode: Number(data.mode ?? 0)
2120
+ };
2121
+ }
2122
+ function parseFileInfo(data) {
2123
+ return {
2124
+ ...parseFileEntry(data),
2125
+ version: String(data.version ?? "")
2126
+ };
2127
+ }
2128
+ function parseLockLease(data) {
2129
+ return {
2130
+ token: String(data.token ?? ""),
2131
+ ttlSeconds: Number(data.ttl_seconds ?? 0),
2132
+ expiresAt: String(data.expires_at ?? "")
2133
+ };
2134
+ }
2135
+ function parseLockStatus(data) {
2136
+ return {
2137
+ held: Boolean(data.held ?? false),
2138
+ expiresInMs: Number(data.expires_in_ms ?? 0)
2031
2139
  };
2032
2140
  }
2033
2141
  function volumeAttachmentToJSON(att) {
2034
- return { volume_id: att.volumeId, mount_path: att.mountPath };
2142
+ const out = {
2143
+ volume_id: att.volumeId,
2144
+ mount_path: att.mountPath
2145
+ };
2146
+ if (att.mode) {
2147
+ out.mode = att.mode;
2148
+ }
2149
+ if (att.subpath) {
2150
+ out.subpath = att.subpath;
2151
+ }
2152
+ return out;
2035
2153
  }
2036
2154
 
2037
2155
  // src/sandbox/sandbox.ts
@@ -2857,7 +2975,7 @@ var Template = class {
2857
2975
  }
2858
2976
  };
2859
2977
 
2860
- // src/volumes/volumes.ts
2978
+ // src/volumes/files.ts
2861
2979
  var VALID_VOLUME_ID_RE = /^[a-zA-Z0-9_-]+$/;
2862
2980
  function assertValidVolumeId(id) {
2863
2981
  if (!id || !VALID_VOLUME_ID_RE.test(id)) {
@@ -2866,8 +2984,223 @@ function assertValidVolumeId(id) {
2866
2984
  );
2867
2985
  }
2868
2986
  }
2987
+ var VolumeFiles = class {
2988
+ volumeId;
2989
+ opts;
2990
+ constructor(volumeId, opts) {
2991
+ assertValidVolumeId(volumeId);
2992
+ this.volumeId = volumeId;
2993
+ this.opts = opts;
2994
+ }
2995
+ client() {
2996
+ const config = new ConnectionConfig({
2997
+ apiKey: this.opts?.apiKey,
2998
+ domain: this.opts?.domain,
2999
+ apiUrl: this.opts?.apiUrl,
3000
+ requestTimeout: this.opts?.requestTimeout
3001
+ });
3002
+ return getSharedClient(config);
3003
+ }
3004
+ timeout() {
3005
+ return this.opts?.requestTimeout;
3006
+ }
3007
+ /** Write raw bytes to `path`. Optionally conditional on `ifVersion` (CAS). */
3008
+ async write(path, data, opts) {
3009
+ if (!path) {
3010
+ throw new InvalidArgumentError("path is required");
3011
+ }
3012
+ const params = { path };
3013
+ if (opts?.ifVersion) {
3014
+ params.if_version = opts.ifVersion;
3015
+ }
3016
+ const body = data instanceof Uint8Array ? data : new Uint8Array(data);
3017
+ const resp = await this.client().put(`/volumes/${this.volumeId}/files/raw`, {
3018
+ params,
3019
+ body,
3020
+ headers: { "Content-Type": "application/octet-stream" },
3021
+ timeout: opts?.requestTimeout ?? this.timeout()
3022
+ });
3023
+ return String(resp.path ?? path);
3024
+ }
3025
+ /** Read raw bytes from `path`. */
3026
+ async read(path) {
3027
+ if (!path) {
3028
+ throw new InvalidArgumentError("path is required");
3029
+ }
3030
+ return this.client().getBytes(`/volumes/${this.volumeId}/files/raw`, {
3031
+ params: { path },
3032
+ timeout: this.timeout()
3033
+ });
3034
+ }
3035
+ /** List directory entries under `path`. */
3036
+ async list(path) {
3037
+ if (!path) {
3038
+ throw new InvalidArgumentError("path is required");
3039
+ }
3040
+ const resp = await this.client().get(`/volumes/${this.volumeId}/files/list`, {
3041
+ params: { path },
3042
+ timeout: this.timeout()
3043
+ });
3044
+ const rows = resp.entries ?? [];
3045
+ return rows.map(parseFileEntry);
3046
+ }
3047
+ /** Stat `path`, returning the entry plus the CAS `version` token. */
3048
+ async info(path) {
3049
+ if (!path) {
3050
+ throw new InvalidArgumentError("path is required");
3051
+ }
3052
+ const resp = await this.client().get(`/volumes/${this.volumeId}/files/info`, {
3053
+ params: { path },
3054
+ timeout: this.timeout()
3055
+ });
3056
+ return parseFileInfo(resp);
3057
+ }
3058
+ /** Return whether `path` exists. */
3059
+ async exists(path) {
3060
+ if (!path) {
3061
+ throw new InvalidArgumentError("path is required");
3062
+ }
3063
+ const resp = await this.client().get(`/volumes/${this.volumeId}/files/exists`, {
3064
+ params: { path },
3065
+ timeout: this.timeout()
3066
+ });
3067
+ return Boolean(resp.exists ?? false);
3068
+ }
3069
+ /** Remove `path`. Pass `{ recursive: true }` to remove a directory tree. */
3070
+ async remove(path, opts) {
3071
+ if (!path) {
3072
+ throw new InvalidArgumentError("path is required");
3073
+ }
3074
+ const params = {
3075
+ path,
3076
+ recursive: opts?.recursive ? "true" : "false"
3077
+ };
3078
+ await this.client().delete(`/volumes/${this.volumeId}/files`, {
3079
+ params,
3080
+ timeout: opts?.requestTimeout ?? this.timeout()
3081
+ });
3082
+ }
3083
+ /** Rename `oldPath` to `newPath`. */
3084
+ async rename(oldPath, newPath) {
3085
+ if (!oldPath || !newPath) {
3086
+ throw new InvalidArgumentError("oldPath and newPath are required");
3087
+ }
3088
+ const resp = await this.client().patch(`/volumes/${this.volumeId}/files`, {
3089
+ json: { old_path: oldPath, new_path: newPath },
3090
+ timeout: this.timeout()
3091
+ });
3092
+ return {
3093
+ oldPath: String(resp.old_path ?? oldPath),
3094
+ newPath: String(resp.new_path ?? newPath)
3095
+ };
3096
+ }
3097
+ /** Create a directory at `path`. */
3098
+ async mkdir(path) {
3099
+ if (!path) {
3100
+ throw new InvalidArgumentError("path is required");
3101
+ }
3102
+ const resp = await this.client().post(`/volumes/${this.volumeId}/files/mkdir`, {
3103
+ json: { path },
3104
+ timeout: this.timeout()
3105
+ });
3106
+ return String(resp.path ?? path);
3107
+ }
3108
+ };
3109
+
3110
+ // src/volumes/locks.ts
3111
+ var VALID_VOLUME_ID_RE2 = /^[a-zA-Z0-9_-]+$/;
3112
+ function assertValidVolumeId2(id) {
3113
+ if (!id || !VALID_VOLUME_ID_RE2.test(id)) {
3114
+ throw new InvalidArgumentError(
3115
+ `Invalid volume ID: "${id}". Must be alphanumeric with hyphens/underscores only.`
3116
+ );
3117
+ }
3118
+ }
3119
+ var VolumeLocks = class {
3120
+ volumeId;
3121
+ opts;
3122
+ constructor(volumeId, opts) {
3123
+ assertValidVolumeId2(volumeId);
3124
+ this.volumeId = volumeId;
3125
+ this.opts = opts;
3126
+ }
3127
+ client() {
3128
+ const config = new ConnectionConfig({
3129
+ apiKey: this.opts?.apiKey,
3130
+ domain: this.opts?.domain,
3131
+ apiUrl: this.opts?.apiUrl,
3132
+ requestTimeout: this.opts?.requestTimeout
3133
+ });
3134
+ return getSharedClient(config);
3135
+ }
3136
+ timeout() {
3137
+ return this.opts?.requestTimeout;
3138
+ }
3139
+ /** Acquire a lock on `path`. Throws ConflictError (409) if already held. */
3140
+ async acquire(path, ttlSeconds) {
3141
+ if (!path) {
3142
+ throw new InvalidArgumentError("path is required");
3143
+ }
3144
+ const json = { path };
3145
+ if (ttlSeconds !== void 0) {
3146
+ json.ttl_seconds = ttlSeconds;
3147
+ }
3148
+ const resp = await this.client().post(`/volumes/${this.volumeId}/locks`, {
3149
+ json,
3150
+ timeout: this.timeout()
3151
+ });
3152
+ return parseLockLease(resp);
3153
+ }
3154
+ /** Release a lock on `path` held under `token`. Throws ConflictError (409) if not the holder. */
3155
+ async release(path, token) {
3156
+ if (!path || !token) {
3157
+ throw new InvalidArgumentError("path and token are required");
3158
+ }
3159
+ const resp = await this.client().delete(`/volumes/${this.volumeId}/locks`, {
3160
+ json: { path, token },
3161
+ timeout: this.timeout()
3162
+ });
3163
+ return Boolean(resp.released ?? false);
3164
+ }
3165
+ /** Renew a lock on `path` held under `token`. Throws ConflictError (409) if not the holder. */
3166
+ async renew(path, token, ttlSeconds) {
3167
+ if (!path || !token) {
3168
+ throw new InvalidArgumentError("path and token are required");
3169
+ }
3170
+ const json = { path, token };
3171
+ if (ttlSeconds !== void 0) {
3172
+ json.ttl_seconds = ttlSeconds;
3173
+ }
3174
+ const resp = await this.client().post(`/volumes/${this.volumeId}/locks/renew`, {
3175
+ json,
3176
+ timeout: this.timeout()
3177
+ });
3178
+ return { ...parseLockLease(resp), token };
3179
+ }
3180
+ /** Query whether `path` is currently locked. */
3181
+ async status(path) {
3182
+ if (!path) {
3183
+ throw new InvalidArgumentError("path is required");
3184
+ }
3185
+ const resp = await this.client().get(`/volumes/${this.volumeId}/locks`, {
3186
+ params: { path },
3187
+ timeout: this.timeout()
3188
+ });
3189
+ return parseLockStatus(resp);
3190
+ }
3191
+ };
3192
+
3193
+ // src/volumes/volumes.ts
3194
+ var VALID_VOLUME_ID_RE3 = /^[a-zA-Z0-9_-]+$/;
3195
+ function assertValidVolumeId3(id) {
3196
+ if (!id || !VALID_VOLUME_ID_RE3.test(id)) {
3197
+ throw new InvalidArgumentError(
3198
+ `Invalid volume ID: "${id}". Must be alphanumeric with hyphens/underscores only.`
3199
+ );
3200
+ }
3201
+ }
2869
3202
  var Volumes = class {
2870
- /** Create a volume by streaming a tarball to the server. */
3203
+ /** Create a volume by streaming a tarball (gzip tar.gz) to the server. */
2871
3204
  static async create(name, data, opts) {
2872
3205
  if (!name) {
2873
3206
  throw new InvalidArgumentError("volume name is required");
@@ -2888,9 +3221,113 @@ var Volumes = class {
2888
3221
  });
2889
3222
  return parseVolumeInfo(resp);
2890
3223
  }
3224
+ /**
3225
+ * Capture the attached volume's mount path in `sandboxId` into a NEW volume.
3226
+ *
3227
+ * The source volume is left unchanged. If `name` is omitted the server names
3228
+ * the new volume "<source-name>-commit". Returns the new VolumeInfo.
3229
+ */
3230
+ static async commit(sandboxId, volumeId, name, opts) {
3231
+ if (!sandboxId || !VALID_VOLUME_ID_RE3.test(sandboxId)) {
3232
+ throw new InvalidArgumentError(
3233
+ `Invalid sandbox ID: "${sandboxId}". Must be alphanumeric with hyphens/underscores only.`
3234
+ );
3235
+ }
3236
+ assertValidVolumeId3(volumeId);
3237
+ const config = new ConnectionConfig({
3238
+ apiKey: opts?.apiKey,
3239
+ domain: opts?.domain,
3240
+ apiUrl: opts?.apiUrl,
3241
+ requestTimeout: opts?.requestTimeout
3242
+ });
3243
+ const client = getSharedClient(config);
3244
+ const resp = await client.post(`/sandboxes/${sandboxId}/volumes/${volumeId}/commit`, {
3245
+ params: name ? { name } : void 0,
3246
+ timeout: opts?.requestTimeout
3247
+ });
3248
+ return parseVolumeInfo(resp);
3249
+ }
3250
+ /**
3251
+ * Snapshot an arbitrary absolute in-sandbox `path` into a NEW volume.
3252
+ *
3253
+ * Unlike `commit` (which captures an already-attached volume's mount path),
3254
+ * `snapshot` captures any path in the running sandbox. `name` defaults to
3255
+ * "snapshot" on the server. Synthetic paths (/proc, /sys, /dev) are rejected.
3256
+ */
3257
+ static async snapshot(sandboxId, path, name, opts) {
3258
+ if (!sandboxId || !VALID_VOLUME_ID_RE3.test(sandboxId)) {
3259
+ throw new InvalidArgumentError(
3260
+ `Invalid sandbox ID: "${sandboxId}". Must be alphanumeric with hyphens/underscores only.`
3261
+ );
3262
+ }
3263
+ if (!path) {
3264
+ throw new InvalidArgumentError("path is required");
3265
+ }
3266
+ const config = new ConnectionConfig({
3267
+ apiKey: opts?.apiKey,
3268
+ domain: opts?.domain,
3269
+ apiUrl: opts?.apiUrl,
3270
+ requestTimeout: opts?.requestTimeout
3271
+ });
3272
+ const client = getSharedClient(config);
3273
+ const params = { path };
3274
+ if (name) {
3275
+ params.name = name;
3276
+ }
3277
+ const resp = await client.post(`/sandboxes/${sandboxId}/volumes/snapshot`, {
3278
+ params,
3279
+ timeout: opts?.requestTimeout
3280
+ });
3281
+ return parseVolumeInfo(resp);
3282
+ }
3283
+ /**
3284
+ * Create an empty file-granular volume. Requires a file-granular backend
3285
+ * (503 if not configured). Returns the new VolumeInfo.
3286
+ */
3287
+ static async empty(name, opts) {
3288
+ if (!name) {
3289
+ throw new InvalidArgumentError("volume name is required");
3290
+ }
3291
+ const config = new ConnectionConfig({
3292
+ apiKey: opts?.apiKey,
3293
+ domain: opts?.domain,
3294
+ apiUrl: opts?.apiUrl,
3295
+ requestTimeout: opts?.requestTimeout
3296
+ });
3297
+ const client = getSharedClient(config);
3298
+ const resp = await client.post("/volumes/empty", {
3299
+ params: { name },
3300
+ timeout: opts?.requestTimeout
3301
+ });
3302
+ return parseVolumeInfo(resp);
3303
+ }
3304
+ /**
3305
+ * Ingest a gzip tar.gz archive into a NEW file-granular volume. Requires a
3306
+ * file-granular backend (503 if not configured). 413 on quota exceeded.
3307
+ */
3308
+ static async ingest(name, data, opts) {
3309
+ if (!name) {
3310
+ throw new InvalidArgumentError("volume name is required");
3311
+ }
3312
+ const config = new ConnectionConfig({
3313
+ apiKey: opts?.apiKey,
3314
+ domain: opts?.domain,
3315
+ apiUrl: opts?.apiUrl,
3316
+ requestTimeout: opts?.requestTimeout
3317
+ });
3318
+ const client = getSharedClient(config);
3319
+ const body = data instanceof Uint8Array ? data : new Uint8Array(data);
3320
+ const resp = await client.post("/volumes/ingest", {
3321
+ params: { name },
3322
+ body,
3323
+ headers: { "Content-Type": opts?.contentType ?? "application/gzip" },
3324
+ timeout: opts?.requestTimeout
3325
+ });
3326
+ return parseVolumeInfo(resp);
3327
+ }
2891
3328
  /** Fetch metadata for a single volume. */
2892
3329
  static async get(volumeId, opts) {
2893
- assertValidVolumeId(volumeId);
3330
+ assertValidVolumeId3(volumeId);
2894
3331
  const config = new ConnectionConfig({
2895
3332
  apiKey: opts?.apiKey,
2896
3333
  domain: opts?.domain,
@@ -2918,9 +3355,23 @@ var Volumes = class {
2918
3355
  const rows = resp.volumes ?? [];
2919
3356
  return rows.map(parseVolumeInfo);
2920
3357
  }
3358
+ /** Download the volume's contents as raw bytes (the stored archive/blob). */
3359
+ static async download(volumeId, opts) {
3360
+ assertValidVolumeId3(volumeId);
3361
+ const config = new ConnectionConfig({
3362
+ apiKey: opts?.apiKey,
3363
+ domain: opts?.domain,
3364
+ apiUrl: opts?.apiUrl,
3365
+ requestTimeout: opts?.requestTimeout
3366
+ });
3367
+ const client = getSharedClient(config);
3368
+ return client.getBytes(`/volumes/${volumeId}/download`, {
3369
+ timeout: opts?.requestTimeout
3370
+ });
3371
+ }
2921
3372
  /** Delete a volume and its blob. Idempotent on the wire. */
2922
3373
  static async delete(volumeId, opts) {
2923
- assertValidVolumeId(volumeId);
3374
+ assertValidVolumeId3(volumeId);
2924
3375
  const config = new ConnectionConfig({
2925
3376
  apiKey: opts?.apiKey,
2926
3377
  domain: opts?.domain,
@@ -2930,6 +3381,100 @@ var Volumes = class {
2930
3381
  const client = getSharedClient(config);
2931
3382
  await client.delete(`/volumes/${volumeId}`, { timeout: opts?.requestTimeout });
2932
3383
  }
3384
+ /**
3385
+ * File-granular operations (read/write/list/info/exists/remove/rename/mkdir,
3386
+ * plus CAS via `write(..., { ifVersion })`) on `volumeId`. File-granular
3387
+ * volumes only.
3388
+ */
3389
+ static files(volumeId, opts) {
3390
+ return new VolumeFiles(volumeId, opts);
3391
+ }
3392
+ /** Advisory locks (acquire/release/renew/status) over a (volume, path). */
3393
+ static locks(volumeId, opts) {
3394
+ return new VolumeLocks(volumeId, opts);
3395
+ }
3396
+ };
3397
+
3398
+ // src/governance/models.ts
3399
+ function parseGovernanceControl(data) {
3400
+ return {
3401
+ control: String(data.control ?? ""),
3402
+ gate: String(data.gate ?? ""),
3403
+ rule: String(data.rule ?? ""),
3404
+ playbook: String(data.playbook ?? "")
3405
+ };
3406
+ }
3407
+ function parseGovernanceAdvisory(data) {
3408
+ return {
3409
+ control: String(data.control ?? ""),
3410
+ reason: String(data.reason ?? "")
3411
+ };
3412
+ }
3413
+ function parseGovernancePack(data) {
3414
+ const rawEnforces = data.enforces ?? [];
3415
+ const rawAdvisory = data.advisory ?? [];
3416
+ return {
3417
+ name: String(data.name ?? ""),
3418
+ version: String(data.version ?? ""),
3419
+ framework: String(data.framework ?? ""),
3420
+ description: String(data.description ?? ""),
3421
+ gates: data.gates ?? [],
3422
+ enforces: rawEnforces.map(parseGovernanceControl),
3423
+ advisory: rawAdvisory.map(parseGovernanceAdvisory),
3424
+ policyRef: String(data.policy_ref ?? data.policyRef ?? ""),
3425
+ seeded: Boolean(data.seeded ?? false)
3426
+ };
3427
+ }
3428
+
3429
+ // src/governance/governance.ts
3430
+ var VALID_PACK_NAME_RE = /^[a-zA-Z0-9_-]+$/;
3431
+ function assertValidPackName(name) {
3432
+ if (!name || !VALID_PACK_NAME_RE.test(name)) {
3433
+ throw new InvalidArgumentError(
3434
+ `Invalid pack name: "${name}". Must be alphanumeric with hyphens/underscores only.`
3435
+ );
3436
+ }
3437
+ }
3438
+ var Governance = class {
3439
+ /**
3440
+ * List all available governance packs.
3441
+ *
3442
+ * Sends GET /governance/packs and returns the `packs` array.
3443
+ */
3444
+ static async listPacks(opts) {
3445
+ const config = new ConnectionConfig({
3446
+ apiKey: opts?.apiKey,
3447
+ domain: opts?.domain,
3448
+ apiUrl: opts?.apiUrl,
3449
+ requestTimeout: opts?.requestTimeout
3450
+ });
3451
+ const client = getSharedClient(config);
3452
+ const resp = await client.get("/governance/packs", {
3453
+ timeout: opts?.requestTimeout
3454
+ });
3455
+ const rows = resp.packs ?? [];
3456
+ return rows.map(parseGovernancePack);
3457
+ }
3458
+ /**
3459
+ * Fetch a single governance pack by name.
3460
+ *
3461
+ * Sends GET /governance/packs/:name and returns the pack object.
3462
+ * Throws InvalidArgumentError if the name contains unsafe characters.
3463
+ */
3464
+ static async getPack(name, opts) {
3465
+ assertValidPackName(name);
3466
+ const config = new ConnectionConfig({
3467
+ apiKey: opts?.apiKey,
3468
+ domain: opts?.domain,
3469
+ apiUrl: opts?.apiUrl,
3470
+ requestTimeout: opts?.requestTimeout
3471
+ });
3472
+ const client = getSharedClient(config);
3473
+ const resp = await client.get(`/governance/packs/${name}`, {
3474
+ timeout: opts?.requestTimeout
3475
+ });
3476
+ return parseGovernancePack(resp);
3477
+ }
2933
3478
  };
2934
3479
  // Annotate the CommonJS export names for ESM import in node:
2935
3480
  0 && (module.exports = {
@@ -2940,6 +3485,7 @@ var Volumes = class {
2940
3485
  CommandExitError,
2941
3486
  CommandHandle,
2942
3487
  Commands,
3488
+ ConflictError,
2943
3489
  ConnectionConfig,
2944
3490
  DEFAULT_MASK_PATTERNS,
2945
3491
  FileType,
@@ -2948,6 +3494,7 @@ var Volumes = class {
2948
3494
  FilesystemEventType,
2949
3495
  GitAuthError,
2950
3496
  GitUpstreamError,
3497
+ Governance,
2951
3498
  InjectionAction,
2952
3499
  InjectionSensitivity,
2953
3500
  InvalidArgumentError,
@@ -2969,12 +3516,16 @@ var Volumes = class {
2969
3516
  TemplateError,
2970
3517
  TimeoutError,
2971
3518
  TransformDirection,
3519
+ VolumeFiles,
3520
+ VolumeLocks,
2972
3521
  Volumes,
2973
3522
  WatchHandle,
2974
3523
  applyTransformation,
2975
3524
  codeSecurityConfigToJSON,
3525
+ contentGateConfigToJSON,
2976
3526
  createAuditConfig,
2977
3527
  createCodeSecurityConfig,
3528
+ createContentGateConfig,
2978
3529
  createEnvSecurityConfig,
2979
3530
  createInjectionDefenseConfig,
2980
3531
  createInvisibleTextConfig,
@@ -2993,11 +3544,17 @@ var Volumes = class {
2993
3544
  parseBuildInfo,
2994
3545
  parseCodeSecurityConfig,
2995
3546
  parseCommandResult,
3547
+ parseContentGateConfig,
2996
3548
  parseEntryInfo,
2997
3549
  parseEnvSecurityConfig,
3550
+ parseFileEntry,
3551
+ parseFileInfo,
2998
3552
  parseFilesystemEvent,
3553
+ parseGovernancePack,
2999
3554
  parseInjectionDefenseConfig,
3000
3555
  parseInvisibleTextConfig,
3556
+ parseLockLease,
3557
+ parseLockStatus,
3001
3558
  parseNetworkPolicy,
3002
3559
  parsePIIConfig,
3003
3560
  parseProcessInfo,