Skip to content

Commit 02dc697

Browse files
committed
[Artifacts] flesh out Sandbox SDK example
1 parent 2350b19 commit 02dc697

File tree

1 file changed

+108
-3
lines changed

1 file changed

+108
-3
lines changed
Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,116 @@
11
---
22
title: Sandbox SDK + Artifacts
3-
description: Example Artifacts integration with Sandbox SDK.
3+
description: Connect a sandbox to an Artifacts repo.
44
pcx_content_type: example
55
sidebar:
66
order: 3
77
---
88

9-
This example will show how Sandbox SDK workloads can read from and write to Artifacts during isolated execution.
9+
import { TypeScriptExample, WranglerConfig } from "~/components";
1010

11-
Use it as a reference for build, analysis, and agent workflows that need shared versioned storage.
11+
Use this pattern when you want a sandbox and an Artifacts repo to share the same stable ID.
12+
13+
- Calls `getSandbox(env.Sandbox, "my-sandbox")` to create or reuse the sandbox from the minimal Sandbox SDK example.
14+
- Looks up an Artifacts repo with the same ID. If the repo does not exist, it creates one. If the repo exists, it reuses the remote and mints a fresh write token.
15+
- Converts the token into an authenticated Git remote in the form `https://x:<token-secret>@...` and stores it in `ARTIFACTS_GIT_REMOTE` inside the sandbox.
16+
17+
Add the Sandbox and Artifacts bindings to `wrangler.jsonc`:
18+
19+
<WranglerConfig>
20+
21+
```jsonc title="wrangler.jsonc"
22+
{
23+
"main": "src/index.ts",
24+
"compatibility_date": "$today",
25+
"compatibility_flags": ["nodejs_compat"],
26+
"containers": [
27+
{
28+
"class_name": "Sandbox",
29+
"image": "./Dockerfile",
30+
"instance_type": "lite",
31+
"max_instances": 1
32+
}
33+
],
34+
"durable_objects": {
35+
"bindings": [
36+
{
37+
"name": "Sandbox",
38+
"class_name": "Sandbox"
39+
}
40+
]
41+
},
42+
"migrations": [
43+
{
44+
"tag": "v1",
45+
"new_sqlite_classes": ["Sandbox"]
46+
}
47+
],
48+
"artifacts": [
49+
{
50+
"binding": "ARTIFACTS",
51+
"namespace": "default"
52+
}
53+
]
54+
}
55+
```
56+
57+
</WranglerConfig>
58+
59+
Then create or reuse the sandbox and repo:
60+
61+
<TypeScriptExample filename="src/index.ts" typescriptFirst={true}>
62+
63+
```ts
64+
import { getSandbox } from "@cloudflare/sandbox";
65+
66+
export { Sandbox } from "@cloudflare/sandbox";
67+
68+
interface Env {
69+
Sandbox: DurableObjectNamespace<Sandbox>;
70+
ARTIFACTS: Artifacts;
71+
}
72+
73+
function toAuthenticatedRemote(remote: string, token: string) {
74+
const tokenSecret = token.split("?expires=")[0];
75+
return `https://x:${tokenSecret}@${remote.slice("https://".length)}`;
76+
}
77+
78+
export default {
79+
async fetch(_request: Request, env: Env): Promise<Response> {
80+
const sandboxId = "my-sandbox";
81+
const sandbox = getSandbox(env.Sandbox, sandboxId);
82+
83+
const existingRepo = await env.ARTIFACTS.get(sandboxId);
84+
85+
let remote: string;
86+
let token: string;
87+
88+
if (existingRepo) {
89+
const info = await existingRepo.info();
90+
if (!info) {
91+
throw new Error("Repo metadata not found");
92+
}
93+
94+
remote = info.remote;
95+
token = (await existingRepo.createToken("write", 3600)).plaintext;
96+
} else {
97+
const created = await env.ARTIFACTS.create(sandboxId);
98+
remote = created.remote;
99+
token = created.token;
100+
}
101+
102+
await sandbox.setEnvVars({
103+
ARTIFACTS_GIT_REMOTE: toAuthenticatedRemote(remote, token),
104+
});
105+
106+
return Response.json({
107+
sandboxId,
108+
repo: sandboxId,
109+
message:
110+
"Sandbox can read ARTIFACTS_GIT_REMOTE for git clone, fetch, pull, or push.",
111+
});
112+
},
113+
} satisfies ExportedHandler<Env>;
114+
```
115+
116+
</TypeScriptExample>

0 commit comments

Comments
 (0)