@cloudflare/sandbox 0.8.9 → 0.8.10
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 +57 -75
- 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/opencode/index.d.ts.map +1 -1
- package/dist/{sandbox-KLljXK8V.d.ts → sandbox-CbGbomnq.d.ts} +5 -7
- package/dist/{sandbox-KLljXK8V.d.ts.map → sandbox-CbGbomnq.d.ts.map} +1 -1
- package/package.json +1 -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-CbGbomnq.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-DqnVW04M.js";
|
|
3
3
|
import { ContainerProxy } from "@cloudflare/containers";
|
|
4
4
|
|
package/dist/index.js
CHANGED
|
@@ -3702,7 +3702,7 @@ function buildS3fsSource(bucket, prefix) {
|
|
|
3702
3702
|
* This file is auto-updated by .github/changeset-version.ts during releases
|
|
3703
3703
|
* DO NOT EDIT MANUALLY - Changes will be overwritten on the next version bump
|
|
3704
3704
|
*/
|
|
3705
|
-
const SDK_VERSION = "0.8.
|
|
3705
|
+
const SDK_VERSION = "0.8.10";
|
|
3706
3706
|
|
|
3707
3707
|
//#endregion
|
|
3708
3708
|
//#region src/sandbox.ts
|
|
@@ -4327,7 +4327,7 @@ var Sandbox = class Sandbox extends Container {
|
|
|
4327
4327
|
/**
|
|
4328
4328
|
* Execute S3FS mount command
|
|
4329
4329
|
*/
|
|
4330
|
-
async executeS3FSMount(bucket, mountPath, options, provider, passwordFilePath) {
|
|
4330
|
+
async executeS3FSMount(bucket, mountPath, options, provider, passwordFilePath, sessionId) {
|
|
4331
4331
|
const resolvedOptions = resolveS3fsOptions(provider, options.s3fsOptions);
|
|
4332
4332
|
const s3fsArgs = [];
|
|
4333
4333
|
s3fsArgs.push(`passwd_file=${passwordFilePath}`);
|
|
@@ -4336,7 +4336,7 @@ var Sandbox = class Sandbox extends Container {
|
|
|
4336
4336
|
s3fsArgs.push(`url=${options.endpoint}`);
|
|
4337
4337
|
const optionsStr = shellEscape(s3fsArgs.join(","));
|
|
4338
4338
|
const mountCmd = `s3fs ${shellEscape(bucket)} ${shellEscape(mountPath)} -o ${optionsStr}`;
|
|
4339
|
-
const result = await this.execInternal(mountCmd);
|
|
4339
|
+
const result = sessionId ? await this.execWithSession(mountCmd, sessionId, { origin: "internal" }) : await this.execInternal(mountCmd);
|
|
4340
4340
|
if (result.exitCode !== 0) throw new S3FSMountError(`S3FS mount failed: ${result.stderr || result.stdout || "Unknown error"}`);
|
|
4341
4341
|
}
|
|
4342
4342
|
/**
|
|
@@ -5803,74 +5803,54 @@ var Sandbox = class Sandbox extends Container {
|
|
|
5803
5803
|
}
|
|
5804
5804
|
}
|
|
5805
5805
|
/**
|
|
5806
|
-
*
|
|
5807
|
-
* The container curls the archive directly from R2, bypassing the DO.
|
|
5808
|
-
* ~93 MB/s throughput vs ~0.6 MB/s for base64 writeFile.
|
|
5806
|
+
* Mount a backup archive from R2 via s3fs so squashfuse can read it lazily.
|
|
5809
5807
|
*/
|
|
5810
|
-
async
|
|
5811
|
-
const
|
|
5812
|
-
|
|
5813
|
-
const
|
|
5814
|
-
const
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5818
|
-
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5822
|
-
|
|
5823
|
-
const
|
|
5824
|
-
|
|
5825
|
-
|
|
5808
|
+
async mountBackupR2(mountPath, prefix, backupSession) {
|
|
5809
|
+
const { accountId, bucketName } = this.requirePresignedUrlSupport();
|
|
5810
|
+
const endpoint = `https://${accountId}.r2.cloudflarestorage.com`;
|
|
5811
|
+
const normalizedPrefix = prefix.startsWith("/") ? prefix : `/${prefix}`;
|
|
5812
|
+
const options = {
|
|
5813
|
+
endpoint,
|
|
5814
|
+
provider: "r2",
|
|
5815
|
+
readOnly: true,
|
|
5816
|
+
prefix: normalizedPrefix,
|
|
5817
|
+
s3fsOptions: ["use_path_request_style"]
|
|
5818
|
+
};
|
|
5819
|
+
const passwordFilePath = this.generatePasswordFilePath();
|
|
5820
|
+
const s3fsSource = buildS3fsSource(bucketName, normalizedPrefix);
|
|
5821
|
+
const envObj = this.env;
|
|
5822
|
+
const credentials = detectCredentials(options, {
|
|
5823
|
+
AWS_ACCESS_KEY_ID: getEnvString(envObj, "AWS_ACCESS_KEY_ID"),
|
|
5824
|
+
AWS_SECRET_ACCESS_KEY: getEnvString(envObj, "AWS_SECRET_ACCESS_KEY"),
|
|
5825
|
+
R2_ACCESS_KEY_ID: this.r2AccessKeyId || void 0,
|
|
5826
|
+
R2_SECRET_ACCESS_KEY: this.r2SecretAccessKey || void 0,
|
|
5827
|
+
...this.envVars
|
|
5826
5828
|
});
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
await this.
|
|
5844
|
-
|
|
5845
|
-
|
|
5846
|
-
code: ErrorCode.BACKUP_RESTORE_FAILED,
|
|
5847
|
-
httpStatus: 500,
|
|
5848
|
-
context: {
|
|
5849
|
-
dir,
|
|
5850
|
-
backupId
|
|
5851
|
-
},
|
|
5852
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
5853
|
-
});
|
|
5854
|
-
}
|
|
5855
|
-
const mvResult = await this.execWithSession(`mv ${shellEscape(tmpPath)} ${shellEscape(archivePath)}`, backupSession, { origin: "internal" });
|
|
5856
|
-
if (mvResult.exitCode !== 0) {
|
|
5857
|
-
await this.execWithSession(`rm -f ${shellEscape(tmpPath)}`, backupSession, { origin: "internal" }).catch(() => {});
|
|
5858
|
-
throw new BackupRestoreError({
|
|
5859
|
-
message: `Failed to finalize downloaded archive: ${mvResult.stderr}`,
|
|
5860
|
-
code: ErrorCode.BACKUP_RESTORE_FAILED,
|
|
5861
|
-
httpStatus: 500,
|
|
5862
|
-
context: {
|
|
5863
|
-
dir,
|
|
5864
|
-
backupId
|
|
5865
|
-
},
|
|
5866
|
-
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
5867
|
-
});
|
|
5829
|
+
const mountInfo = {
|
|
5830
|
+
mountType: "fuse",
|
|
5831
|
+
bucket: s3fsSource,
|
|
5832
|
+
mountPath,
|
|
5833
|
+
endpoint,
|
|
5834
|
+
provider: "r2",
|
|
5835
|
+
passwordFilePath,
|
|
5836
|
+
mounted: false
|
|
5837
|
+
};
|
|
5838
|
+
this.activeMounts.set(mountPath, mountInfo);
|
|
5839
|
+
try {
|
|
5840
|
+
await this.createPasswordFile(passwordFilePath, bucketName, credentials);
|
|
5841
|
+
await this.execWithSession(`mkdir -p ${shellEscape(mountPath)}`, backupSession, { origin: "internal" });
|
|
5842
|
+
await this.executeS3FSMount(s3fsSource, mountPath, options, "r2", passwordFilePath, backupSession);
|
|
5843
|
+
mountInfo.mounted = true;
|
|
5844
|
+
} catch (error) {
|
|
5845
|
+
await this.deletePasswordFile(passwordFilePath);
|
|
5846
|
+
this.activeMounts.delete(mountPath);
|
|
5847
|
+
throw error;
|
|
5868
5848
|
}
|
|
5869
5849
|
}
|
|
5870
5850
|
/**
|
|
5871
5851
|
* Serialize backup operations on this sandbox instance.
|
|
5872
5852
|
* Concurrent backup/restore calls are queued so the multi-step
|
|
5873
|
-
* create-archive → read → upload (or
|
|
5853
|
+
* create-archive → read → upload (or mount → extract) flow
|
|
5874
5854
|
* is not interleaved with another backup operation on the same directory.
|
|
5875
5855
|
*/
|
|
5876
5856
|
enqueueBackupOp(fn) {
|
|
@@ -6017,7 +5997,7 @@ var Sandbox = class Sandbox extends Container {
|
|
|
6017
5997
|
*
|
|
6018
5998
|
* Flow:
|
|
6019
5999
|
* 1. DO reads metadata from R2 and checks TTL
|
|
6020
|
-
* 2. Container
|
|
6000
|
+
* 2. Container mounts the backup archive from R2 via s3fs
|
|
6021
6001
|
* 3. Container mounts the squashfs archive with FUSE overlayfs
|
|
6022
6002
|
*
|
|
6023
6003
|
* The target directory becomes an overlay mount with the backup as a
|
|
@@ -6101,8 +6081,7 @@ var Sandbox = class Sandbox extends Container {
|
|
|
6101
6081
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6102
6082
|
});
|
|
6103
6083
|
const r2Key = `backups/${id}/data.sqsh`;
|
|
6104
|
-
|
|
6105
|
-
if (!archiveHead) throw new BackupNotFoundError({
|
|
6084
|
+
if (!await bucket.head(r2Key)) throw new BackupNotFoundError({
|
|
6106
6085
|
message: `Backup archive not found in R2: ${id}. The archive may have been deleted by R2 lifecycle rules.`,
|
|
6107
6086
|
code: ErrorCode.BACKUP_NOT_FOUND,
|
|
6108
6087
|
httpStatus: 404,
|
|
@@ -6110,12 +6089,19 @@ var Sandbox = class Sandbox extends Container {
|
|
|
6110
6089
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6111
6090
|
});
|
|
6112
6091
|
backupSession = await this.ensureBackupSession();
|
|
6113
|
-
const
|
|
6114
|
-
const
|
|
6092
|
+
const r2MountPath = `/var/backups/r2mount/${id}`;
|
|
6093
|
+
const archivePath = `${r2MountPath}/data.sqsh`;
|
|
6094
|
+
const mountGlob = `/var/backups/mounts/r2mount/${id}/data`;
|
|
6115
6095
|
await this.execWithSession(`/usr/bin/fusermount3 -uz ${shellEscape(dir)} 2>/dev/null || true`, backupSession, { origin: "internal" }).catch(() => {});
|
|
6116
6096
|
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(() => {});
|
|
6117
|
-
|
|
6118
|
-
|
|
6097
|
+
await this.execWithSession(`/usr/bin/fusermount3 -u ${shellEscape(r2MountPath)} 2>/dev/null; /usr/bin/fusermount3 -uz ${shellEscape(r2MountPath)} 2>/dev/null; true`, backupSession, { origin: "internal" }).catch(() => {});
|
|
6098
|
+
const previousBackupMount = this.activeMounts.get(r2MountPath);
|
|
6099
|
+
if (previousBackupMount?.mountType === "fuse") {
|
|
6100
|
+
previousBackupMount.mounted = false;
|
|
6101
|
+
this.activeMounts.delete(r2MountPath);
|
|
6102
|
+
await this.deletePasswordFile(previousBackupMount.passwordFilePath);
|
|
6103
|
+
}
|
|
6104
|
+
await this.mountBackupR2(r2MountPath, `backups/${id}/`, backupSession);
|
|
6119
6105
|
if (!(await this.client.backup.restoreArchive(dir, archivePath, backupSession)).success) throw new BackupRestoreError({
|
|
6120
6106
|
message: "Container failed to restore backup archive",
|
|
6121
6107
|
code: ErrorCode.BACKUP_RESTORE_FAILED,
|
|
@@ -6134,10 +6120,6 @@ var Sandbox = class Sandbox extends Container {
|
|
|
6134
6120
|
};
|
|
6135
6121
|
} catch (error) {
|
|
6136
6122
|
caughtError = error instanceof Error ? error : new Error(String(error));
|
|
6137
|
-
if (id && backupSession) {
|
|
6138
|
-
const archivePath = `/var/backups/${id}.sqsh`;
|
|
6139
|
-
await this.execWithSession(`rm -f ${shellEscape(archivePath)}`, backupSession, { origin: "internal" }).catch(() => {});
|
|
6140
|
-
}
|
|
6141
6123
|
throw error;
|
|
6142
6124
|
} finally {
|
|
6143
6125
|
if (backupSession) await this.client.utils.deleteSession(backupSession).catch(() => {});
|