@cloudflare/sandbox 0.8.4 → 0.8.5
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.d.ts +1 -1
- package/dist/index.js +42 -22
- package/dist/index.js.map +1 -1
- package/dist/openai/index.d.ts +1 -1
- package/dist/opencode/index.d.ts +1 -1
- package/dist/{sandbox-BoLbdjOe.d.ts → sandbox-DW5aQ1lD.d.ts} +6 -5
- package/dist/sandbox-DW5aQ1lD.d.ts.map +1 -0
- package/package.json +1 -1
- package/dist/sandbox-BoLbdjOe.d.ts.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $ as CheckChangesOptions, A as DesktopStopResponse, At as SandboxOptions, B as ExecuteResponse, Bt as ExposePortRequest, C as ClickOptions, Ct as ProcessListResult, D as DesktopStartOptions, Dt as ProcessStatus, E as DesktopClient, Et as ProcessStartResult, F as ScreenshotRegion, Ft as WatchOptions, G as HttpClientOptions, Gt as Execution, H as BaseApiResponse, Ht as PtyOptions, I as ScreenshotResponse, It as isExecResult, J as SessionRequest, K as RequestConfig, Kt as ExecutionResult, L as ScrollDirection, Lt as isProcess, M as ScreenSizeResponse, Mt as StreamOptions, N as ScreenshotBytesResponse, Nt as WaitForLogResult, O as DesktopStartResponse, Ot as RemoteMountBucketOptions, P as ScreenshotOptions, Pt as WaitForPortOptions, Q as BucketProvider, R as TypeOptions, Rt as isProcessStatus, S as WriteFileRequest, St as ProcessKillResult, T as Desktop, Tt as ProcessOptions, U as ContainerStub, Ut as CodeContext, V as BackupClient, Vt as StartProcessRequest, W as ErrorResponse, Wt as CreateContextOptions, X as BaseExecOptions, Y as BackupOptions, Z as BucketCredentials, _ as GitClient, _t as PortExposeResult, a as CreateSessionRequest, at as ExecutionSession, b as MkdirRequest, bt as ProcessCleanupResult, c as DeleteSessionResponse, ct as FileStreamEvent, d as ProcessClient, dt as ISandbox, et as CheckChangesResult, f as PortClient, ft as ListFilesOptions, g as GitCheckoutRequest, gt as PortCloseResult, h as InterpreterClient, ht as MountBucketOptions, i as CommandsResponse, it as ExecResult, j as KeyInput, jt as SessionOptions, k as DesktopStatusResponse, kt as RestoreBackupResult, l as PingResponse, lt as FileWatchSSEEvent, m as ExecutionCallbacks, mt as LogEvent, n as getSandbox, nt as ExecEvent, o as CreateSessionResponse, ot as FileChunk, p as UnexposePortRequest, pt as LocalMountBucketOptions, q as ResponseHandler, qt as RunCodeOptions, r as SandboxClient, rt as ExecOptions, s as DeleteSessionRequest, st as FileMetadata, t as Sandbox, tt as DirectoryBackup, u as UtilityClient, ut as GitCheckoutResult, v as FileClient, vt as PortListResult, w as CursorPositionResponse, wt as ProcessLogsResult, x as ReadFileRequest, xt as ProcessInfoResult, y as FileOperationRequest, yt as Process, z as CommandClient, zt as ExecuteRequest } from "./sandbox-
|
|
1
|
+
import { $ as CheckChangesOptions, A as DesktopStopResponse, At as SandboxOptions, B as ExecuteResponse, Bt as ExposePortRequest, C as ClickOptions, Ct as ProcessListResult, D as DesktopStartOptions, Dt as ProcessStatus, E as DesktopClient, Et as ProcessStartResult, F as ScreenshotRegion, Ft as WatchOptions, G as HttpClientOptions, Gt as Execution, H as BaseApiResponse, Ht as PtyOptions, I as ScreenshotResponse, It as isExecResult, J as SessionRequest, K as RequestConfig, Kt as ExecutionResult, L as ScrollDirection, Lt as isProcess, M as ScreenSizeResponse, Mt as StreamOptions, N as ScreenshotBytesResponse, Nt as WaitForLogResult, O as DesktopStartResponse, Ot as RemoteMountBucketOptions, P as ScreenshotOptions, Pt as WaitForPortOptions, Q as BucketProvider, R as TypeOptions, Rt as isProcessStatus, S as WriteFileRequest, St as ProcessKillResult, T as Desktop, Tt as ProcessOptions, U as ContainerStub, Ut as CodeContext, V as BackupClient, Vt as StartProcessRequest, W as ErrorResponse, Wt as CreateContextOptions, X as BaseExecOptions, Y as BackupOptions, Z as BucketCredentials, _ as GitClient, _t as PortExposeResult, a as CreateSessionRequest, at as ExecutionSession, b as MkdirRequest, bt as ProcessCleanupResult, c as DeleteSessionResponse, ct as FileStreamEvent, d as ProcessClient, dt as ISandbox, et as CheckChangesResult, f as PortClient, ft as ListFilesOptions, g as GitCheckoutRequest, gt as PortCloseResult, h as InterpreterClient, ht as MountBucketOptions, i as CommandsResponse, it as ExecResult, j as KeyInput, jt as SessionOptions, k as DesktopStatusResponse, kt as RestoreBackupResult, l as PingResponse, lt as FileWatchSSEEvent, m as ExecutionCallbacks, mt as LogEvent, n as getSandbox, nt as ExecEvent, o as CreateSessionResponse, ot as FileChunk, p as UnexposePortRequest, pt as LocalMountBucketOptions, q as ResponseHandler, qt as RunCodeOptions, r as SandboxClient, rt as ExecOptions, s as DeleteSessionRequest, st as FileMetadata, t as Sandbox, tt as DirectoryBackup, u as UtilityClient, ut as GitCheckoutResult, v as FileClient, vt as PortListResult, w as CursorPositionResponse, wt as ProcessLogsResult, x as ReadFileRequest, xt as ProcessInfoResult, y as FileOperationRequest, yt as Process, z as CommandClient, zt as ExecuteRequest } from "./sandbox-DW5aQ1lD.js";
|
|
2
2
|
import { a as DesktopCoordinateErrorContext, d as ErrorResponse$1, f as OperationType, i as BackupRestoreContext, l as ProcessExitedBeforeReadyContext, n as BackupExpiredContext, o as DesktopErrorContext, p as ErrorCode, r as BackupNotFoundContext, s as InvalidBackupConfigContext, t as BackupCreateContext, u as ProcessReadyTimeoutContext } from "./contexts-CeQR115r.js";
|
|
3
3
|
import { ContainerProxy } from "@cloudflare/containers";
|
|
4
4
|
|
package/dist/index.js
CHANGED
|
@@ -2813,6 +2813,19 @@ var SandboxClient = class {
|
|
|
2813
2813
|
}
|
|
2814
2814
|
};
|
|
2815
2815
|
|
|
2816
|
+
//#endregion
|
|
2817
|
+
//#region ../shared/src/backup.ts
|
|
2818
|
+
/**
|
|
2819
|
+
* Absolute directory prefixes supported by backup and restore operations.
|
|
2820
|
+
*/
|
|
2821
|
+
const BACKUP_ALLOWED_PREFIXES = [
|
|
2822
|
+
"/workspace",
|
|
2823
|
+
"/home",
|
|
2824
|
+
"/tmp",
|
|
2825
|
+
"/var/tmp",
|
|
2826
|
+
"/app"
|
|
2827
|
+
];
|
|
2828
|
+
|
|
2816
2829
|
//#endregion
|
|
2817
2830
|
//#region src/security.ts
|
|
2818
2831
|
/**
|
|
@@ -3632,7 +3645,7 @@ function buildS3fsSource(bucket, prefix) {
|
|
|
3632
3645
|
* This file is auto-updated by .github/changeset-version.ts during releases
|
|
3633
3646
|
* DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump
|
|
3634
3647
|
*/
|
|
3635
|
-
const SDK_VERSION = "0.8.
|
|
3648
|
+
const SDK_VERSION = "0.8.5";
|
|
3636
3649
|
|
|
3637
3650
|
//#endregion
|
|
3638
3651
|
//#region src/sandbox.ts
|
|
@@ -5554,7 +5567,7 @@ var Sandbox = class Sandbox extends Container {
|
|
|
5554
5567
|
static UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
5555
5568
|
/**
|
|
5556
5569
|
* Validate that a directory path is safe for backup operations.
|
|
5557
|
-
* Rejects empty, relative, traversal,
|
|
5570
|
+
* Rejects empty, relative, traversal, null-byte, and unsupported-root paths.
|
|
5558
5571
|
*/
|
|
5559
5572
|
static validateBackupDir(dir, label) {
|
|
5560
5573
|
if (!dir || !dir.startsWith("/")) throw new InvalidBackupConfigError({
|
|
@@ -5578,6 +5591,13 @@ var Sandbox = class Sandbox extends Container {
|
|
|
5578
5591
|
context: { reason: `${label} must not contain ".." path segments` },
|
|
5579
5592
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
5580
5593
|
});
|
|
5594
|
+
if (!BACKUP_ALLOWED_PREFIXES.some((prefix) => dir === prefix || dir.startsWith(`${prefix}/`))) throw new InvalidBackupConfigError({
|
|
5595
|
+
message: `${label} must be inside one of the supported backup roots (${BACKUP_ALLOWED_PREFIXES.join(", ")})`,
|
|
5596
|
+
code: ErrorCode.INVALID_BACKUP_CONFIG,
|
|
5597
|
+
httpStatus: 400,
|
|
5598
|
+
context: { reason: `${label} must be inside one of the supported backup roots` },
|
|
5599
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
5600
|
+
});
|
|
5581
5601
|
}
|
|
5582
5602
|
/**
|
|
5583
5603
|
* Returns the R2 bucket or throws if backup is not configured.
|
|
@@ -5948,19 +5968,19 @@ var Sandbox = class Sandbox extends Container {
|
|
|
5948
5968
|
const restoreStartTime = Date.now();
|
|
5949
5969
|
const bucket = this.requireBackupBucket();
|
|
5950
5970
|
this.requirePresignedUrlSupport();
|
|
5951
|
-
const { id
|
|
5971
|
+
const { id, dir } = backup;
|
|
5952
5972
|
let outcome = "error";
|
|
5953
5973
|
let caughtError;
|
|
5954
5974
|
let backupSession;
|
|
5955
5975
|
try {
|
|
5956
|
-
if (!
|
|
5976
|
+
if (!id || typeof id !== "string") throw new InvalidBackupConfigError({
|
|
5957
5977
|
message: "Invalid backup: missing or invalid id",
|
|
5958
5978
|
code: ErrorCode.INVALID_BACKUP_CONFIG,
|
|
5959
5979
|
httpStatus: 400,
|
|
5960
5980
|
context: { reason: "missing or invalid id" },
|
|
5961
5981
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
5962
5982
|
});
|
|
5963
|
-
if (!Sandbox.UUID_REGEX.test(
|
|
5983
|
+
if (!Sandbox.UUID_REGEX.test(id)) throw new InvalidBackupConfigError({
|
|
5964
5984
|
message: "Invalid backup: id must be a valid UUID (e.g. from createBackup)",
|
|
5965
5985
|
code: ErrorCode.INVALID_BACKUP_CONFIG,
|
|
5966
5986
|
httpStatus: 400,
|
|
@@ -5968,13 +5988,13 @@ var Sandbox = class Sandbox extends Container {
|
|
|
5968
5988
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
5969
5989
|
});
|
|
5970
5990
|
Sandbox.validateBackupDir(dir, "Invalid backup: dir");
|
|
5971
|
-
const metaKey = `backups/${
|
|
5991
|
+
const metaKey = `backups/${id}/meta.json`;
|
|
5972
5992
|
const metaObject = await bucket.get(metaKey);
|
|
5973
5993
|
if (!metaObject) throw new BackupNotFoundError({
|
|
5974
|
-
message: `Backup not found: ${
|
|
5994
|
+
message: `Backup not found: ${id}. Verify the backup ID is correct and the backup has not been deleted.`,
|
|
5975
5995
|
code: ErrorCode.BACKUP_NOT_FOUND,
|
|
5976
5996
|
httpStatus: 404,
|
|
5977
|
-
context: { backupId },
|
|
5997
|
+
context: { backupId: id },
|
|
5978
5998
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
5979
5999
|
});
|
|
5980
6000
|
const metadata = await metaObject.json();
|
|
@@ -5986,44 +6006,44 @@ var Sandbox = class Sandbox extends Container {
|
|
|
5986
6006
|
httpStatus: 500,
|
|
5987
6007
|
context: {
|
|
5988
6008
|
dir,
|
|
5989
|
-
backupId
|
|
6009
|
+
backupId: id
|
|
5990
6010
|
},
|
|
5991
6011
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
5992
6012
|
});
|
|
5993
6013
|
const expiresAt = createdAt + metadata.ttl * 1e3;
|
|
5994
6014
|
if (Date.now() + TTL_BUFFER_MS > expiresAt) throw new BackupExpiredError({
|
|
5995
|
-
message: `Backup ${
|
|
6015
|
+
message: `Backup ${id} has expired (created: ${metadata.createdAt}, TTL: ${metadata.ttl}s). Create a new backup.`,
|
|
5996
6016
|
code: ErrorCode.BACKUP_EXPIRED,
|
|
5997
6017
|
httpStatus: 400,
|
|
5998
6018
|
context: {
|
|
5999
|
-
backupId,
|
|
6019
|
+
backupId: id,
|
|
6000
6020
|
expiredAt: new Date(expiresAt).toISOString()
|
|
6001
6021
|
},
|
|
6002
6022
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6003
6023
|
});
|
|
6004
|
-
const r2Key = `backups/${
|
|
6024
|
+
const r2Key = `backups/${id}/data.sqsh`;
|
|
6005
6025
|
const archiveHead = await bucket.head(r2Key);
|
|
6006
6026
|
if (!archiveHead) throw new BackupNotFoundError({
|
|
6007
|
-
message: `Backup archive not found in R2: ${
|
|
6027
|
+
message: `Backup archive not found in R2: ${id}. The archive may have been deleted by R2 lifecycle rules.`,
|
|
6008
6028
|
code: ErrorCode.BACKUP_NOT_FOUND,
|
|
6009
6029
|
httpStatus: 404,
|
|
6010
|
-
context: { backupId },
|
|
6030
|
+
context: { backupId: id },
|
|
6011
6031
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6012
6032
|
});
|
|
6013
6033
|
backupSession = await this.ensureBackupSession();
|
|
6014
|
-
const archivePath = `/var/backups/${
|
|
6015
|
-
const mountGlob = `/var/backups/mounts/${
|
|
6034
|
+
const archivePath = `/var/backups/${id}.sqsh`;
|
|
6035
|
+
const mountGlob = `/var/backups/mounts/${id}`;
|
|
6016
6036
|
await this.execWithSession(`/usr/bin/fusermount3 -uz ${shellEscape(dir)} 2>/dev/null || true`, backupSession, { origin: "internal" }).catch(() => {});
|
|
6017
6037
|
await this.execWithSession(`for d in ${shellEscape(mountGlob)}_*/lower ${shellEscape(mountGlob)}/lower; do [ -d "$d" ] && /usr/bin/fusermount3 -uz "$d" 2>/dev/null; done; true`, backupSession, { origin: "internal" }).catch(() => {});
|
|
6018
6038
|
const sizeCheck = await this.execWithSession(`stat -c %s ${shellEscape(archivePath)} 2>/dev/null || echo 0`, backupSession, { origin: "internal" }).catch(() => ({ stdout: "0" }));
|
|
6019
|
-
if (Number.parseInt((sizeCheck.stdout ?? "0").trim(), 10) !== archiveHead.size) await this.downloadBackupPresigned(archivePath, r2Key, archiveHead.size,
|
|
6039
|
+
if (Number.parseInt((sizeCheck.stdout ?? "0").trim(), 10) !== archiveHead.size) await this.downloadBackupPresigned(archivePath, r2Key, archiveHead.size, id, dir, backupSession);
|
|
6020
6040
|
if (!(await this.client.backup.restoreArchive(dir, archivePath, backupSession)).success) throw new BackupRestoreError({
|
|
6021
6041
|
message: "Container failed to restore backup archive",
|
|
6022
6042
|
code: ErrorCode.BACKUP_RESTORE_FAILED,
|
|
6023
6043
|
httpStatus: 500,
|
|
6024
6044
|
context: {
|
|
6025
6045
|
dir,
|
|
6026
|
-
backupId
|
|
6046
|
+
backupId: id
|
|
6027
6047
|
},
|
|
6028
6048
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6029
6049
|
});
|
|
@@ -6031,12 +6051,12 @@ var Sandbox = class Sandbox extends Container {
|
|
|
6031
6051
|
return {
|
|
6032
6052
|
success: true,
|
|
6033
6053
|
dir,
|
|
6034
|
-
id
|
|
6054
|
+
id
|
|
6035
6055
|
};
|
|
6036
6056
|
} catch (error) {
|
|
6037
6057
|
caughtError = error instanceof Error ? error : new Error(String(error));
|
|
6038
|
-
if (
|
|
6039
|
-
const archivePath = `/var/backups/${
|
|
6058
|
+
if (id && backupSession) {
|
|
6059
|
+
const archivePath = `/var/backups/${id}.sqsh`;
|
|
6040
6060
|
await this.execWithSession(`rm -f ${shellEscape(archivePath)}`, backupSession, { origin: "internal" }).catch(() => {});
|
|
6041
6061
|
}
|
|
6042
6062
|
throw error;
|
|
@@ -6046,7 +6066,7 @@ var Sandbox = class Sandbox extends Container {
|
|
|
6046
6066
|
event: "backup.restore",
|
|
6047
6067
|
outcome,
|
|
6048
6068
|
durationMs: Date.now() - restoreStartTime,
|
|
6049
|
-
backupId,
|
|
6069
|
+
backupId: id,
|
|
6050
6070
|
dir,
|
|
6051
6071
|
error: caughtError
|
|
6052
6072
|
});
|