the universal sandbox runtime for agents and humans. pocketenv.io
sandbox openclaw agent claude-code vercel-sandbox deno-sandbox cloudflare-sandbox atproto sprites daytona
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add error handling for sandbox backup and restore

Rename SelectBakcup -> SelectBackup in the backups schema and imports.
Wrap sandbox API calls in try/catch and log failures instead of
throwing.

+36 -25
+4 -2
apps/api/src/schema/backups.ts
··· 3 3 import sandboxes from "./sandboxes"; 4 4 5 5 const backups = pgTable("backups", { 6 - id: text("id").primaryKey().default(sql`xata_id()`), 6 + id: text("id") 7 + .primaryKey() 8 + .default(sql`xata_id()`), 7 9 sandboxId: text("sandbox_id") 8 10 .notNull() 9 11 .references(() => sandboxes.id, { onDelete: "cascade" }), ··· 14 16 createdAt: timestamp("created_at").defaultNow().notNull(), 15 17 }); 16 18 17 - export type SelectBakcup = InferSelectModel<typeof backups>; 19 + export type SelectBackup = InferSelectModel<typeof backups>; 18 20 export type InsertBackup = InferInsertModel<typeof backups>; 19 21 20 22 export default backups;
+18 -13
apps/api/src/xrpc/io/pocketenv/sandbox/createBackup.ts
··· 1 1 import { XRPCError, type HandlerAuth } from "@atproto/xrpc-server"; 2 + import { consola } from "consola"; 2 3 import { Providers } from "consts"; 3 4 import type { Context } from "context"; 4 5 import { and, eq, or } from "drizzle-orm"; ··· 9 10 } from "lexicon/types/io/pocketenv/sandbox/createBackup"; 10 11 import generateJwt from "lib/generateJwt"; 11 12 import schema from "schema"; 12 - import type { SelectBakcup } from "schema/backups"; 13 + import type { SelectBackup } from "schema/backups"; 13 14 14 15 export default function (server: Server, ctx: Context) { 15 16 const createBackup = async ( ··· 50 51 ? ctx.cfsandbox(record.sandboxes.base!) 51 52 : ctx.sandbox(); 52 53 53 - await sandbox.post<SelectBakcup>( 54 - `/v1/sandboxes/${record.sandboxes.id}/backup`, 55 - { 56 - directory: input.directory, 57 - description: input.description, 58 - ttl: input.ttl, 59 - }, 60 - { 61 - headers: { 62 - Authorization: `Bearer ${await generateJwt(auth?.credentials?.did || "")}`, 54 + try { 55 + await sandbox.post<SelectBackup>( 56 + `/v1/sandboxes/${record.sandboxes.id}/backup`, 57 + { 58 + directory: input.directory, 59 + description: input.description, 60 + ttl: input.ttl, 63 61 }, 64 - }, 65 - ); 62 + { 63 + headers: { 64 + Authorization: `Bearer ${await generateJwt(auth?.credentials?.did || "")}`, 65 + }, 66 + }, 67 + ); 68 + } catch (error) { 69 + consola.warn("Failed to create backup in sandbox", error); 70 + } 66 71 }; 67 72 server.io.pocketenv.sandbox.createBackup({ 68 73 auth: ctx.authVerifier,
+14 -10
apps/api/src/xrpc/io/pocketenv/sandbox/restoreBackup.ts
··· 49 49 ? ctx.cfsandbox(record.sandboxes.base!) 50 50 : ctx.sandbox(); 51 51 52 - await sandbox.post( 53 - `/v1/sandboxes/${record.sandboxes.id}/restore`, 54 - { 55 - backupId: input.backupId, 56 - }, 57 - { 58 - headers: { 59 - Authorization: `Bearer ${await generateJwt(auth?.credentials?.did || "")}`, 52 + try { 53 + await sandbox.post( 54 + `/v1/sandboxes/${record.sandboxes.id}/restore`, 55 + { 56 + backupId: input.backupId, 60 57 }, 61 - }, 62 - ); 58 + { 59 + headers: { 60 + Authorization: `Bearer ${await generateJwt(auth?.credentials?.did || "")}`, 61 + }, 62 + }, 63 + ); 64 + } catch (error) { 65 + console.warn("Failed to restore backup", error); 66 + } 63 67 64 68 return {}; 65 69 };