@renderinc/sdk
v0.5.1
Published
Render SDK for TypeScript
Downloads
20,074
Readme
Render SDK for TypeScript
The official TypeScript SDK for Render. Define Workflow tasks, manage task runs, and access experimental platform features like object storage.
Features
- REST API Client: Run, monitor, and manage task runs
- Task Definition SDK: Define and register tasks with decorators
- Server-Sent Events: Real-time streaming of task run events
- Async/Await Support: Modern Promise-based API
- TypeScript First: Full type safety and IntelliSense support
- Retry Logic: Configurable retry behavior for tasks
- Subtask Execution: Execute tasks from within other tasks
- Object Storage: Experimental object storage API with upload, download, and list
Installation
npm install @renderinc/sdkOr with yarn:
yarn add @renderinc/sdkOr with pnpm:
pnpm add @renderinc/sdkOr with Bun:
bun add @renderinc/sdkQuick Start
REST API Client
Use the Render SDK to run tasks and monitor their execution:
import { Render } from '@renderinc/sdk';
// Create a Render SDK instance (uses RENDER_API_KEY from environment)
const render = new Render();
// Run a task and wait for completion
const result = await render.workflows.runTask('my-workflow/my-task', [42, 'hello']);
console.log('Status:', result.status);
console.log('Results:', result.results);
// Or start a task and decide when to await the result
const run = await render.workflows.startTask('my-workflow/my-task', [42, 'hello']);
console.log('Task run ID:', run.taskRunId);
const details = await run.get();
// List recent task runs
const taskRuns = await render.workflows.listTaskRuns({ limit: 10 });Alternatively, you can create a workflows client directly:
import { createWorkflowsClient } from '@renderinc/sdk/workflows';
const client = createWorkflowsClient();
const result = await client.runTask('my-workflow/my-task', [42, 'hello']);Task Definition
Define tasks that can be executed by the workflow system:
import { task, startTaskServer } from '@renderinc/sdk/workflows';
// Simple task
const square = task(
{ name: 'square' },
function square(a: number): number {
return a * a;
}
);
// Async task with subtask execution
task(
{ name: 'addSquares' },
async function addSquares(a: number, b: number): Promise<number> {
const result1 = await square(a);
const result2 = await square(b);
return result1 + result2;
}
);
// Task with custom options
task(
{
name: 'retryableTask',
retry: {
maxRetries: 3,
waitDurationMs: 1000,
backoffScaling: 1.5,
},
timeoutSeconds: 86400, // 24h
plan: 'starter',
},
async function retryableTask(input: string): Promise<string> {
// Task implementation
return input.toUpperCase();
}
);
// The task server starts automatically when running in a workflow environment
// (when RENDER_SDK_SOCKET_PATH is set). No need to call startTaskServer() explicitly.
//
// To disable auto-start, set RENDER_SDK_AUTO_START=false in your environment.Run the Local Task Server
For local development, use the Render CLI:
render workflows dev -- <start command>For example:
render workflows dev -- npm startTo interact with tasks registered to the local task server, run CLI commands with the --local flag in another terminal. For example:
render workflows tasks start <task name> --localAPI Reference
Render SDK
new Render(options?)
Creates a new Render SDK instance with access to all Render products.
Options:
token?: string- API token (defaults toRENDER_API_KEYenv var)baseUrl?: string- Base URL (defaults tohttps://api.render.com)useLocalDev?: boolean- Use local development modelocalDevUrl?: string- Local development URLownerId?: string- Default owner ID for object storage (falls back toRENDER_WORKSPACE_IDenv var)region?: string- Default region for object storage (falls back toRENDER_REGIONenv var)
Properties:
workflows- WorkflowsClient instance for managing workflow tasksexperimental- ExperimentalClient instance for object storage and other experimental APIs
Example:
import { Render } from '@renderinc/sdk';
const render = new Render({
token: 'your-api-token',
baseUrl: 'https://api.render.com',
});
// Access workflows client
const result = await render.workflows.runTask('my-workflow/task', [42]);Workflows Client API
The workflows client is accessible via render.workflows or can be created directly using createWorkflowsClient:
import { createWorkflowsClient } from '@renderinc/sdk/workflows';
const client = createWorkflowsClient({
token: 'your-api-token',
baseUrl: 'https://api.render.com',
});Workflows Client Methods
render.workflows.runTask(taskSlug, inputData, signal?)
Runs a task and waits for completion.
Parameters:
taskSlug: string- Task slug in format "workflow-slug/task-name"inputData: any[]- Input data as array of parameterssignal?: AbortSignal- Optional abort signal for cancellation
Returns: Promise<TaskRunDetails>
Example:
const render = new Render();
const result = await render.workflows.runTask('my-workflow/square', [5]);
console.log('Results:', result.results);render.workflows.startTask(taskSlug, inputData, signal?)
Starts a task run and returns a TaskRunResult. Results are not streamed until you call .get() on the returned result. Use this when you need the task run ID, want to defer awaiting, or want fire-and-forget.
Parameters:
taskSlug: string- Task slug in format "workflow-slug/task-name"inputData: any[]- Input data as array of parameterssignal?: AbortSignal- Optional abort signal for cancellation
Returns: Promise<TaskRunResult>
Example:
const render = new Render();
// Start a task and grab its ID
const run = await render.workflows.startTask('my-workflow/square', [5]);
console.log('Task run ID:', run.taskRunId);
// Await the result when you're ready
const result = await run.get();
console.log('Results:', result.results);render.workflows.taskRunEvents(taskRunIds, signal?)
Streams task run events as an async iterable. Yields a TaskRunDetails for each terminal event (completed, failed, or canceled) received on the stream.
Parameters:
taskRunIds: string[]- One or more task run IDs to subscribe tosignal?: AbortSignal- Optional abort signal for cancellation
Returns: AsyncGenerator<TaskRunDetails>
Example:
const render = new Render();
const run1 = await render.workflows.startTask('my-workflow/square', [3]);
const run2 = await render.workflows.startTask('my-workflow/square', [6]);
// The stream stays open until you break or abort.
const pending = new Set([run1.taskRunId, run2.taskRunId]);
for await (const event of render.workflows.taskRunEvents([...pending])) {
console.log('Event:', event.status, event.id, event.results);
pending.delete(event.id);
if (pending.size === 0) break;
}render.workflows.getTaskRun(taskRunId)
Gets task run details by ID.
Parameters:
taskRunId: string- Task run ID
Returns: Promise<TaskRunDetails>
Example:
const render = new Render();
const details = await render.workflows.getTaskRun('task-run-id');render.workflows.cancelTaskRun(taskRunId)
Cancels a running task.
Parameters:
taskRunId: string- Task run ID to cancel
Returns: Promise<void>
Example:
const render = new Render();
const run = await render.workflows.startTask('my-workflow/square', [5]);
await render.workflows.cancelTaskRun(run.taskRunId);render.workflows.listTaskRuns(params)
Lists task runs with optional filters.
Parameters:
params.limit?: number- Maximum number of resultsparams.cursor?: string- Pagination cursorparams.ownerId?: string[]- Filter by owner IDs
Returns: Promise<TaskRun[]>
Example:
const render = new Render();
const taskRuns = await render.workflows.listTaskRuns({ limit: 10 });Task API
task(options, func)
Registers a function as a task.
Parameters:
options: RegisterTaskOptions- Task configurationname: string- Task name (required)retry?: RetryOptions- Optional retry configurationmaxRetries: number- Maximum number of retrieswaitDurationMs: number- Wait duration between retries in millisecondsbackoffScaling?: number- Backoff multiplier (default: 1.5)
timeoutSeconds?: number- Maximum execution time in secondsplan?: string- Resource plan for task execution (e.g.,"starter","standard","pro")
func: TaskFunction- The task function to register
Returns: The registered function with the same signature
Usage:
// Basic usage
const myTask = task(
{ name: 'myTask' },
function myTask(arg: string): string {
return arg.toUpperCase();
}
);
// With retry, timeout, and plan options
task(
{
name: 'retryableTask',
retry: {
maxRetries: 3,
waitDurationMs: 1000,
backoffScaling: 1.5,
},
timeoutSeconds: 300,
plan: 'starter',
},
function retryableTask(arg: string): string {
return arg.toUpperCase();
}
);
// Async task with subtasks
const square = task(
{ name: 'square' },
function square(a: number): number {
return a * a;
}
);
task(
{ name: 'addSquares' },
async function addSquares(a: number, b: number): Promise<number> {
const result1 = await square(a);
const result2 = await square(b);
return result1 + result2;
}
);startTaskServer()
Starts the task server and listens for task execution requests.
Returns: Promise<void>
Example:
await startTaskServer();Types
TaskRunStatus
enum TaskRunStatus {
PENDING = 'pending',
RUNNING = 'running',
COMPLETED = 'completed',
FAILED = 'failed',
CANCELED = 'canceled',
}TaskRun
interface TaskRun {
id: string;
taskId: string;
status: TaskRunStatus;
startedAt?: string;
completedAt?: string;
parentTaskRunId: string;
rootTaskRunId: string;
retries: number;
}TaskRunDetails
interface TaskRunDetails {
id: string;
taskId: string;
status: TaskRunStatus;
results?: any;
error?: string;
startedAt?: string;
completedAt?: string;
}TaskRunResult
class TaskRunResult {
readonly taskRunId: string;
get(): Promise<TaskRunDetails>;
}RegisterTaskOptions
interface RegisterTaskOptions {
name: string;
retry?: {
maxRetries: number;
waitDurationMs: number;
backoffScaling?: number; // default 1.5
};
timeoutSeconds?: number;
plan?: string; // e.g., "starter", "standard", "pro"
}Error Handling
The SDK provides several error classes:
import { Render } from '@renderinc/sdk';
import {
RenderError,
TaskRunError,
ClientError,
ServerError,
AbortError,
} from '@renderinc/sdk';
const render = new Render();
try {
const result = await render.workflows.runTask('my-workflow/task', [42]);
} catch (error) {
if (error instanceof TaskRunError) {
console.error('Task failed:', error.taskRunId, error.message);
} else if (error instanceof ClientError) {
console.error('Client error:', error.statusCode, error.cause);
} else if (error instanceof ServerError) {
console.error('Server error:', error.statusCode, error.cause);
} else if (error instanceof AbortError) {
console.error('Request was aborted');
} else if (error instanceof RenderError) {
console.error('General SDK error:', error.message);
}
}Environment Variables
RENDER_API_KEY- Your Render API key (required)RENDER_WORKSPACE_ID- Default owner ID for object storage (workspace team ID, e.g.tea-xxxxx)RENDER_REGION- Default region for object storage (e.g.oregon,frankfurt)RENDER_USE_LOCAL_DEV- Enable local development mode (true/false)RENDER_LOCAL_DEV_URL- Local development URL (default:http://localhost:8120)RENDER_SDK_MODE- Task execution mode (runorregister)RENDER_SDK_SOCKET_PATH- Unix socket path for task communication
Object Storage
When running on Render, RENDER_WORKSPACE_ID and RENDER_REGION are set automatically. You can also pass them as constructor options:
import { Render } from '@renderinc/sdk';
const render = new Render(); // Uses env vars for auth + object storage defaults
// Upload (no need to pass ownerId/region when env vars are set)
await render.experimental.storage.objects.put({
key: 'path/to/file.png',
data: Buffer.from('binary content'),
contentType: 'image/png',
});
// Download
const obj = await render.experimental.storage.objects.get({ key: 'path/to/file.png' });
// List
const response = await render.experimental.storage.objects.list();Examples
Example 1: Running a Task
import { Render } from '@renderinc/sdk';
const render = new Render();
const result = await render.workflows.runTask('my-workflow/square', [5]);
console.log('Square of 5 is:', result.results[0]); // 25Example 2: Defining Tasks with Subtasks
import { task } from '@renderinc/sdk/workflows';
const square = task(
{ name: 'square' },
function square(a: number): number {
return a * a;
}
);
task(
{ name: 'pythagorean' },
async function pythagorean(a: number, b: number): Promise<number> {
const aSquared = await square(a);
const bSquared = await square(b);
return Math.sqrt(aSquared + bSquared);
}
);Example 3: Error Handling in Tasks
import { task } from '@renderinc/sdk/workflows';
const divide = task(
{ name: 'divide' },
async function divide(a: number, b: number): Promise<number> {
if (b === 0) {
throw new Error('Cannot divide by zero');
}
return a / b;
}
);
task(
{
name: 'safeDivide',
retry: {
maxRetries: 3,
waitDurationMs: 1000,
},
},
async function safeDivide(a: number, b: number): Promise<number> {
try {
return await divide(a, b);
} catch (error) {
console.error('Division failed:', error);
return 0; // Return default value
}
}
);Example 4: Using AbortSignal for Cancellation
import { Render, AbortError } from '@renderinc/sdk';
const render = new Render();
async function runTaskWithCancellation() {
const abortController = new AbortController();
// Cancel the task after 5 seconds
setTimeout(() => abortController.abort(), 5000);
try {
const result = await render.workflows.runTask(
'my-workflow/long-running-task',
[42],
abortController.signal
);
console.log('Task completed:', result.results);
} catch (error) {
if (error instanceof AbortError) {
console.log('Task was cancelled');
} else {
console.error('Task failed:', error);
}
}
}
runTaskWithCancellation();Example 5: Using the Unified Render SDK
import { Render } from '@renderinc/sdk';
// Single entry point for all Render products
const render = new Render({
token: process.env.RENDER_API_KEY,
});
async function workflowExample() {
try {
// Run a workflow task
const result = await render.workflows.runTask('my-workflow/process-data', [
{ userId: 123, data: 'example' },
]);
console.log('Workflow completed:', result.status);
console.log('Results:', result.results);
// List and monitor recent task runs
const recentRuns = await render.workflows.listTaskRuns({ limit: 5 });
console.log(`\nRecent task runs: ${recentRuns.length}`);
for (const run of recentRuns) {
console.log(`- ${run.id}: ${run.status} (${run.taskId})`);
}
} catch (error) {
console.error('Error:', error);
}
}
workflowExample();Development
Building
npm run buildTesting
npm testLinting
npm run lintFormatting
npm run formatProject Structure
typescript/
├── src/
│ ├── render.ts # Main Render SDK class
│ ├── errors.ts # Error classes
│ ├── index.ts # Main exports
│ ├── version.ts # SDK version and user-agent
│ ├── workflows/ # Workflows functionality
│ │ ├── task.ts # task() function
│ │ ├── runner.ts # startTaskServer() and run()
│ │ ├── executor.ts # TaskExecutor
│ │ ├── registry.ts # TaskRegistry
│ │ ├── uds.ts # Unix socket client
│ │ ├── types.ts # Type definitions
│ │ ├── client/ # REST API client
│ │ │ ├── client.ts # WorkflowsClient class
│ │ │ ├── create-client.ts # createWorkflowsClient() factory
│ │ │ ├── task-run-result.ts # TaskRunResult class
│ │ │ ├── sse.ts # SSE event types
│ │ │ ├── types.ts # Client type definitions
│ │ │ └── index.ts # Exports
│ │ └── index.ts # Workflows exports
│ ├── experimental/ # Experimental features
│ │ └── object/ # Object storage API
│ └── utils/ # Shared utilities
├── examples/
│ ├── client/ # Client example
│ │ ├── main.ts
│ │ └── package.json
│ └── task/ # Task example
│ ├── main.ts
│ └── package.json
├── package.json
├── tsconfig.json
└── README.mdLicense
MIT
Support
For issues and questions, please visit:
- GitHub Issues: https://github.com/renderinc/workflow-sdk/issues
- Documentation: https://render.com/docs/workflows
Contributing
Contributions are welcome! Please read our contributing guidelines before submitting pull requests.
