SDK: Stage
The Stage client provides methods for creating sandbox sessions, pushing files, setting Google scopes, triggering renders, and working with published apps.
Access it via client.stage.
Sessions
Create a session
const session = await client.stage.sessions.create({ name: "my-app" });
// session.id
Returns a minimal session payload:
interface CreateSessionResult {
id: string;
}
Declare Google scopes
await client.stage.sessions.setGoogleScopes(session.id, [
"https://www.googleapis.com/auth/drive.readonly",
]);
Push files to a session
await client.stage.sessions.pushFiles(session.id, [
{
path: "/app/App.tsx",
content: `export default function App() {
return <h1>Hello from ShiftCal</h1>;
}`,
},
]);
Trigger a render
After pushing files, trigger the sandbox to render:
const result = await client.stage.sessions.render(session.id);
Get session status
Check the current state of a session, including its file list and render status:
const status = await client.stage.sessions.status(session.id);
console.log(status.render?.version);
console.log(status.files.map((f) => f.path));
Read a file from a session
Read back a specific file from the session:
const file = await client.stage.sessions.readFile(session.id, "/app/App.tsx");
console.log(file.content);
Published Apps
const app = await client.stage.apps.publish({
sessionId: session.id,
name: "shiftcal-preview",
description: "Calendar smoke app",
});
const apps = await client.stage.apps.list({ author: "user@the-shift.dev" });
const current = await client.stage.apps.get(app.sid);
await client.stage.apps.update(app.sid, {
status: "archived",
});
Version Channels
// Get channel summary for an app
const channels = await client.stage.apps.channels(app.sid);
console.log(channels.preview?.appVersionSid);
console.log(channels.production?.appVersionSid);
Published API Backend Modules
Published Stage apps can expose server-side API routes that use virtual modules for in-process platform access. These modules are available only inside Published API backends — they cannot be imported in browser-side code.
| Module | Provides |
|---|---|
@stage/inference | inference.chat(), .embed(), .image(), .usage() |
@stage/compute | compute.query(), .mutation(), .action() |
@stage/utils | fetchWithRetry(), batchedMap() |
// Inside a Published API backend
import { inference } from "@stage/inference";
import { compute } from "@stage/compute";
import { fetchWithRetry } from "@stage/utils";
const data = await compute.query("tasks", "list", { status: "active" });
const summary = await inference.chat({
model: "gpt-4o-mini",
messages: [{ role: "user", content: `Summarize: ${JSON.stringify(data)}` }],
});
See the Published API Backends reference for full details.
Full Example
import { createClient } from "@the-shift/sdk";
const client = createClient({
gatewayUrl: "https://app.the-shift.dev",
apiKey: process.env.SHIFT_API_KEY,
});
// Create a new sandbox session
const session = await client.stage.sessions.create({ name: "shiftcal-preview" });
console.log(`Session created: ${session.id}`);
// Push application files
await client.stage.sessions.pushFiles(session.id, [
{
path: "/app/App.tsx",
content: `
export default function App() {
return <h1>ShiftCal</h1>;
}`,
},
]);
await client.stage.sessions.setGoogleScopes(session.id, [
"https://www.googleapis.com/auth/drive.readonly",
]);
// Trigger render
await client.stage.sessions.render(session.id);
// Check status
const status = await client.stage.sessions.status(session.id);
console.log(`Render version: ${status.render?.version}`);
console.log(`Files: ${status.files.map((file) => file.path).join(", ")}`);
// Read back a file
const appFile = await client.stage.sessions.readFile(session.id, "/app/App.tsx");
console.log(`App.tsx content length: ${appFile.content.length}`);