opencloudportDocs

TypeScript SDK

A typed client for the whole API, with no dependencies. Runs anywhere fetch does.

@opencloudport/sdk covers everything in the API, with types. It has no dependencies and runs in Node 18+, Bun, Deno, Cloudflare Workers and browsers.

Not on npm yet

The SDK isn't published yet. Until it is, everything it does is also a plain HTTP call in this API reference.

Set up

import { OpenCloudPort } from '@opencloudport/sdk'

const ocp = new OpenCloudPort({
  apiKey: process.env.OCP_API_KEY!, // a workspace key (ocp_…) or an app key (ocps_…)
  baseUrl: 'https://opencloudport.com',
})

Every call throws an OcpError when it fails, with the API's status, code and message:

import { OcpError } from '@opencloudport/sdk'

try {
  await ocp.apps.create({ name: 'Bakery site' })
} catch (err) {
  if (err instanceof OcpError && err.code === 'insufficient_balance') {
    // ask the person to add funds
  }
}

An app, start to finish

const { id } = await ocp.apps.create({ name: 'Bakery site', external_id: 'customer_42' })
const app = ocp.app(id)

await app.services.add({ type: 'compute' })
await app.services.add({ type: 'database' })                // env.DB
await app.services.add({ type: 'storage', name: 'IMAGES' }) // env.IMAGES
await app.services.add({ type: 'email' })                   // env.EMAIL
await app.services.waitUntilReady()

await app.deploy({ main: 'index.js', files: { 'index.js': code } })
await app.env.set('STRIPE_KEY', 'sk_live_…')

Reference

ocp

MethodWhat it does
apps.create({ name, external_id?, metadata? })Make an app (or get the one with that external_id).
apps.list({ limit?, starting_after?, status?, external_id? })A page of apps.
apps.get(id), apps.update(id, { name?, metadata? }), apps.delete(id)One app.
app(id)Everything about one app, below.
balance()The workspace's balance.
prices()Today's price for every meter.

app.services

MethodWhat it does
add({ type, name? })Plug in a service.
list(), get(serviceId), remove(serviceId)
waitUntilReady({ timeoutMs?, intervalMs? })Wait until every service is set up. Throws service_failed or timeout.

Code and variables

MethodWhat it does
app.deploy({ main, files, compatibilityDate?, compatibilityFlags? })Upload and deploy. files maps each path to a string, bytes or a Blob. Resolves once it's live.
app.deployments.list(), .get(id), .redeploy(id)redeploy is a rollback. A deployment's source says where it came from.
app.usage({ start?, end?, group_by? })This app's usage and cost (ocp.usage(…) for the whole workspace).
app.env.list(), .set(name, value, { type? }), .remove(name)Variables. type is 'secret' (default) or 'plain'.

Databases: app.database(nameOrId)

MethodWhat it does
query(sql, params?, { readOnly? })Run SQL. One result per statement. With readOnly, SQL that would change data is refused before it runs.
rows(sql, params?)The last statement's rows, as objects keyed by column.

Files: app.storage(nameOrId)

MethodWhat it does
put(key, body, { contentType? })Upload, straight to the bucket.
get(key)A Response (read it with .text(), .arrayBuffer()…), or null if there's no such file.
list({ prefix?, cursor?, limit? })A page of files.
delete(key)
signedUrl(key, { method?, expiresIn? })A link to hand a browser.
credentials()Temporary S3 credentials for this bucket, or null where they can't be issued.

Email: app.email(nameOrId)

send({ to, subject, text?, html?, from_name?, reply_to?, end_user? }). Inside an app's own code, use connectEmail(env.EMAIL).send(…) instead: it needs no API key.

Sandboxes

MethodWhat it does
app.sandboxes.create({ size?, idle_timeout_seconds?, internet?, env?, label?, end_user? })Start one.
app.sandboxes.list(), .get(id)
app.sandbox(id).exec(command, { cwd?, env?, timeout_ms? })Run and wait.
.writeFiles(files){ path: text }, or a list with base64 content for binary files.
.readFile(path)Text, or null.
.list(path?), .remove(path)
.startProcess(name, command, { cwd?, env? }), .process(name), .stopProcess(name)Long-running servers.
.previewUrl(port)The preview link, or null until previews have a domain.
.deploy({ folder?, codeFolder?, main?, assetsConfig? })Make what it built live: folder is static files (dist), codeFolder + main bundled code. Nothing is read back through you.
.copyFromBucket(bucket, { prefix?, path? }), .saveToBucket(path, bucket, { prefix? })Move files between the sandbox and a bucket (by name or id), binary included.
.start(), .stop(), .delete()Start again after stopping (empty workspace), stop to stop paying, or delete.

App keys: app.keys

list(), create({ name, service_id?, access?, spend_limit? }) (the secret key is returned this once), setSpendLimit(keyId, dollarsOrNull) and revoke(keyId). An app key can make keys for its sub-agents too, never broader than itself.

Using an app key

A key for one app works the same way, within its app. A key for just one service can't list the app's services, so name the service by id instead:

const db = ocp.app(appId).database('svc_…') // not 'DB'

On this page