TypeScript SDK and CLI for the .do Platform - unified API for AI, databases, actions, and workflows on Cloudflare
npm install platform.do


The official TypeScript SDK and CLI for the .do Platform to build Business-as-Code.
``bash`
npm install platform.door
pnpm add platform.door
yarn add platform.do
Platform.do includes a powerful CLI for executing SDK commands directly from the command line:
`bashGenerate content with AI
npx platform.do ai.generate('LandingPage', { domain: 'startups.studio' })
See CLI.md for full CLI documentation.
Quick Start
`typescript
import { $ } from 'platform.do'// Initialize with your API key
$.init({ apiKey: 'your-api-key' })
// Send an email
await $.Email.send({
to: 'user@example.com',
subject: 'Welcome!',
body: 'Thanks for signing up'
})
// Generate AI content
const article = await $.AI.generate({
model: 'claude-3-5-sonnet',
prompt: 'Write about Cloudflare Workers'
})
// Create a GitHub issue
await $.GitHub.createIssue({
owner: 'acme',
repo: 'app',
title: 'Bug report',
body: 'Something is broken'
})
`How It Works
The
$ object is a JavaScript Proxy that provides a clean, intuitive API for executing actions across all platform services.$3
Every action follows this simple pattern:
`typescript
await $.Object.action(params, options)
`- Object - The type of resource (Email, AI, GitHub, Article, User, etc.)
- action - What you want to do (send, create, update, delete, generate, etc.)
- params - The data for the action
- options - Execution options (mode, durability, retry, etc.)
$3
The
$ proxy automatically infers who is performing the action from your authentication context:`typescript
// When you initialize with an API key
$.init({ apiKey: 'user_abc123' })// All subsequent actions automatically include the actor
await $.Article.create({ title: 'Hello' })
// Behind the scenes: actor = 'https://app.do/users/abc123'
// Service account context
$.init({ apiKey: 'service_system' })
await $.Email.send({ to: 'user@example.com' })
// Behind the scenes: actor = 'https://platform.do/system'
`You don't need to pass the actor explicitly - the SDK handles it for you.
Execution Modes
The
$ proxy supports three execution modes via the mode option:$3
Tries to execute immediately. If configured, falls back to queue or workflow on failure.
`typescript
// Default - try immediately
await $.Email.send({
to: 'user@example.com',
subject: 'Hello'
})// With queue fallback
await $.Email.send(
{ to: 'user@example.com' },
{ mode: 'do', queue: true }
)
// With workflow fallback for complex tasks
await $.Article.generate(
{ topic: 'AI' },
{ mode: 'do', durable: true }
)
`When to use:
- Default for most actions
- When you want immediate response if possible
- Cost-conscious (only pay for durability when needed)
Cost: $$ (immediate success) to $$$ (with queue fallback)
$3
Attempts once and returns success/failure without throwing.
`typescript
const result = await $.Analytics.track(
{ event: 'page_view' },
{ mode: 'try' }
)if (result.success) {
console.log('Tracked:', result.data)
} else {
console.log('Failed:', result.error)
}
`When to use:
- Non-critical actions
- Analytics and metrics
- When you want graceful failure
Cost: $ (no logging) to $$ (with logging)
$3
Always queues the action for later processing. Returns immediately with queue ID.
`typescript
// Queue for batch processing
await $.Email.send(
{ to: 'user@example.com' },
{ mode: 'batch' }
)// Delayed execution
await $.Report.generate(
{ type: 'daily' },
{ mode: 'batch', delay: '5m' }
)
// Scheduled execution
await $.Report.generate(
{ type: 'weekly' },
{ mode: 'batch', schedule: '0 9 1' }
)
`When to use:
- Bulk operations
- Rate-limited APIs
- Scheduled/delayed processing
- Cost optimization (batch multiple calls)
Cost: $$$ (queue) to $$$$ (workflow)
Options Reference
All actions accept an optional second argument with these options:
`typescript
interface ExecutionOptions {
// Execution mode
mode?: 'do' | 'try' | 'batch' // Durability
durable?: boolean // Use workflow for multi-step/long-running tasks
queue?: boolean // Queue if immediate execution fails
// Retry configuration
retry?: {
maxAttempts: number
backoff: 'linear' | 'exponential'
backoffMs?: number
}
// Scheduling
delay?: string // Delay execution (e.g., '5m', '1h', '1d')
schedule?: string // Cron expression (e.g., '0 9 *')
// Actor override (admin only)
actor?: string
// Metadata
meta?: Record
// Logging
log?: boolean // Log to analytics (default: true)
}
`Examples
$3
`typescript
// Simple generation
const poem = await $.ai.generate({
model: 'claude-sonnet-4.5',
prompt: 'Write a haiku about code'
})// With durable workflow for long content
const article = await $.ai.generate(
{
model: 'claude-sonnet-4.5',
prompt: 'Write a 5000-word article about Business-as-Code'
},
{ mode: 'do', durable: true }
)
// Embeddings
const vectors = await $.ai.embed({
model: 'gemini-embedding-001',
input: ['Hello world', 'Goodbye world']
})
`$3
`typescript
// Get a resource
const user = await $.db.get('https://app.do/users/123')// Create a resource
const article = await $.db.create({
type: 'Article',
title: 'Hello World',
body: 'Content...'
})
// Update a resource
await $.db.update('https://app.do/articles/456', {
title: 'Updated Title'
})
// Search
const results = await $.db.search({
type: 'Article',
query: 'cloudflare workers',
limit: 10
})
// Find with filters
const users = await $.db.find({
type: 'User',
filters: {
email: { $in: ['alice@example.com', 'bob@example.com'] },
status: 'active'
}
})
`$3
`typescript
await $.Email.send(
{
to: 'user@example.com',
subject: 'Important Update',
body: 'Please read this'
},
{
mode: 'do',
queue: true,
retry: {
maxAttempts: 3,
backoff: 'exponential'
}
}
)
`$3
`typescript
// Daily report at 9am
await $.Report.generate(
{ type: 'daily', format: 'pdf' },
{
mode: 'batch',
schedule: '0 9 *'
}
)// Weekly report on Mondays
await $.Report.generate(
{ type: 'weekly', format: 'csv' },
{
mode: 'batch',
schedule: '0 9 1'
}
)
`$3
`typescript
// Create issue
const issue = await $.GitHub.createIssue({
owner: 'acme',
repo: 'app',
title: 'Feature request',
body: 'We need dark mode',
labels: ['enhancement']
})// Create pull request
const pr = await $.GitHub.createPullRequest({
owner: 'acme',
repo: 'app',
title: 'Add dark mode',
head: 'feature/dark-mode',
base: 'main',
body: 'Implements dark mode support'
})
`$3
`typescript
// Create charge
const charge = await $.Stripe.createCharge(
{
amount: 1000, // $10.00
currency: 'usd',
source: 'tok_visa',
description: 'Premium plan'
},
{
mode: 'do',
queue: true, // Queue if fails
retry: { maxAttempts: 3 }
}
)// Create subscription
const subscription = await $.Stripe.createSubscription({
customer: 'cus_123',
items: [{ price: 'price_premium' }]
})
`$3
`typescript
// Track events (best-effort)
await $.Event.track(
{
event: 'page_view',
properties: {
path: '/dashboard',
referrer: 'https://google.com'
}
},
{ mode: 'try' }
)// Track with guaranteed delivery
await $.Event.track(
{
event: 'purchase_completed',
properties: {
amount: 99.99,
product: 'premium-plan'
}
},
{ mode: 'do', queue: true }
)
`Error Handling
$3
`typescript
try {
await $.Email.send({
to: 'user@example.com',
subject: 'Hello'
})
console.log('Email sent successfully')
} catch (error) {
console.error('Failed to send email:', error)
}
`$3
`typescript
const result = await $.Analytics.track(
{ event: 'click' },
{ mode: 'try' }
)if (result.success) {
console.log('Tracked:', result.data)
} else {
console.log('Failed:', result.error)
}
`$3
`typescript
const result = await $.Email.send(
{ to: 'user@example.com' },
{ mode: 'batch' }
)console.log('Queued with ID:', result.queueId)
`TypeScript Support
The SDK is fully typed with TypeScript:
`typescript
import { $, type ExecutionOptions } from 'platform.do'// All actions are strongly typed
const result: string = await $.AI.generate({
model: 'claude-3-5-sonnet',
prompt: 'Hello'
})
// Options are typed
const options: ExecutionOptions = {
mode: 'do',
queue: true,
retry: {
maxAttempts: 3,
backoff: 'exponential'
}
}
await $.Email.send({ to: 'user@example.com' }, options)
`Framework Integration
$3
`typescript
// app/actions/email.ts
'use server'import { $ } from 'platform.do'
export async function sendWelcomeEmail(email: string) {
return await $.Email.send({
to: email,
subject: 'Welcome!',
body: 'Thanks for signing up'
})
}
`$3
`typescript
// app/api/send-email/route.ts
import { $ } from 'platform.do'
import { NextResponse } from 'next/server'export async function POST(request: Request) {
const { to, subject, body } = await request.json()
const result = await $.Email.send(
{ to, subject, body },
{ mode: 'try' }
)
if (result.success) {
return NextResponse.json({ success: true })
} else {
return NextResponse.json(
{ error: result.error },
{ status: 500 }
)
}
}
`$3
`typescript
import express from 'express'
import { $ } from 'platform.do'const app = express()
app.post('/api/track', async (req, res) => {
const result = await $.Event.track(
{ event: req.body.event, properties: req.body.properties },
{ mode: 'try' }
)
if (result.success) {
res.json({ success: true })
} else {
res.status(500).json({ error: result.error })
}
})
`$3
`typescript
'use client'import { $ } from 'platform.do'
import { useState } from 'react'
export function TrackButton() {
const [tracking, setTracking] = useState(false)
const handleClick = async () => {
setTracking(true)
await $.Event.track(
{ event: 'button_click', properties: { button: 'cta' } },
{ mode: 'try' }
)
setTracking(false)
}
return (
)
}
`Behind the Scenes
When you call
$.Email.send(params), here's what happens:1. Proxy Intercepts - The
$ proxy captures Email and send
2. Actor Resolution - Gets actor from your API key/auth context
3. RPC Call - Sends to actions worker via RPC:
`typescript
rpc.execute({
actor: 'https://app.do/users/123',
action: 'Email.send',
object: params,
mode: 'do'
})
`
4. Execution - Actions worker:
- Tries immediate RPC call to email worker
- On success: logs to analytics and returns result
- On failure (if queue: true): queues for retry
5. Response - Returns result to your codeThe two-layer architecture:
- User API - Clean
$.Object.action() with inferred actor
- RPC Worker - Explicit rpc.execute({ actor, action, object }) for extensibilityCost Optimization
Choose the cheapest mode that meets your requirements:
| Mode | Cost | Use Case |
|------|------|----------|
|
try (no log) | $ | Non-critical tracking |
| try (with log) | $$ | Analytics with tracking |
| do (immediate) | $$ | Most actions |
| do (+ queue) | $$$ | Reliable async |
| batch (queue) | $$$ | Batching, rate limiting |
| do (+ workflow) | $$$$ | Complex multi-step |
| batch (workflow) | $$$$ | Always durable |Tips:
- Use
try mode for non-critical analytics (cheapest)
- Use do mode for most actions (default, good balance)
- Add queue: true only when you need guaranteed delivery (moderate cost)
- Use durable: true only for long-running or complex tasks (highest cost)
- Use batch mode for bulk operations or scheduled tasksAvailable Services
The
$ object provides access to all platform services:-
$.ai - AI models (generate, embed, image, speech, video)
- $.db - Database operations (get, set, create, update, delete, find, search)
- $.Email - Send emails
- $.Event - Track events and analytics
- $.GitHub - GitHub API (issues, PRs, repos)
- $.Stripe - Payments and subscriptions
- $.WorkOS - SSO, directory sync, audit logs
- $.Article - Content generation and management
- $.User - User management
- $.Report - Generate reportsAnd many more! All workers are automatically aggregated into the
$ object.Admin Features
For admin/system use, you can explicitly specify the actor:
`typescript
// Override actor for admin operations
await $.Article.create(
{ title: 'System Announcement' },
{ actor: 'https://platform.do/system' }
)// Or use .as() helper
await $.as('https://app.do/users/123').Article.create({
title: 'User Article'
})
`Contributing
We welcome contributions! Please see our contribution guidelines.
To contribute to the SDK:
1. Fork the repository
2. Create a feature branch:
git checkout -b feature/my-feature
3. Make your changes
4. Run tests: pnpm test
5. Build: pnpm build
6. Submit a pull requestDevelopment
`bash
Install dependencies
pnpm installRun tests in watch mode
pnpm test:watchBuild the package
pnpm buildRun the CLI locally
node dist/cli.js --help
`Publishing
The package uses automated publishing via CI/CD. To publish manually:
`bash
Ensure all tests pass
pnpm testBuild the package
pnpm buildPublish to npm (requires npm auth)
npm publish
``MIT - see LICENSE file for details.
- Documentation
- GitHub Repository
- NPM Package
- CLI Documentation
- Issue Tracker
- Discord Community