Skip to main content

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.

ModuleProvides
@stage/inferenceinference.chat(), .embed(), .image(), .usage()
@stage/computecompute.query(), .mutation(), .action()
@stage/utilsfetchWithRetry(), 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}`);