emit.run
v0.1.7
Published
TypeScript client library for the full emit.run API surface
Readme
emit.run
TypeScript SDK for emit.run workers, producers, and realtime clients.
This package covers:
- Jobs API (create/list/poll/claim/lifecycle/progress/log reads)
- Worker helpers (polling loop + push wake handling)
- Realtime sockets (
connectJobcan be anonymous,connectSpacestays authenticated) - Claimed job helper object with batched
job.log.*writes
The SDK is space-scoped at client initialization.
Installation
npm install emit.runCreate a client
import { EmitClient } from "emit.run";
const client = new EmitClient({
spaceId: process.env.EMIT_SPACE_ID!,
apiKey: process.env.EMIT_API_KEY!,
// optional:
// baseUrl: "https://emit.run/api/v1",
});apiKey is optional when you only use public single-job realtime streams (client.realtime.connectJob(...)).
Producer example
const job = await client.jobs.create({
name: "transcode",
payload: {
inputUrl: "s3://bucket/input.mp4",
outputKey: "output/video-720p.mp4",
},
maxRetries: 5,
timeoutSeconds: 600,
});
console.log(job.id, job.spaceId);jobs.create() returns a minimal reference for each created job:
// { id: string, spaceId: string }Worker example (polling)
onJob receives a claimed job helper with lifecycle methods and logger helpers.
await client.workers.runPolling({
types: ["transcode", "thumbnail"],
count: 5,
autoAck: true,
autoFailOnError: true,
autoComplete: false,
keepaliveIntervalMs: 60_000,
logger: {
source: "worker-gpu-a",
maxBatchSize: 100,
flushIntervalMs: 1_000,
gzip: true,
},
onJob: async (job) => {
job.log.info("job started", { metadata: { jobId: job.id } });
await job.progress({
percent: 15,
message: "Downloading source",
subProgress: {
download: { percent: 15, message: "Connecting" },
},
});
// ...work...
await job.checkpoint({ offsetSeconds: 90 });
await job.event({ phase: "transcode", codec: "h264" });
await job.complete({ outputUrl: "s3://bucket/output.mp4" });
},
});Push wake handler example
Use this for emit.run HTTP push payloads (event: "job.pending").
const handlePush = client.workers.createPushHandler({
autoAck: true,
autoFailOnError: true,
onJob: async (job) => {
job.log.info("woken by push", { metadata: { jobId: job.id } });
await job.complete({ ok: true });
},
});
// HTTP handler
// const payload = await request.json()
// const result = await handlePush(payload)Realtime examples
Job stream
connectJob supports anonymous progress-only streams (no apiKey required).
const connection = client.realtime.connectJob("job_123", {
autoReconnect: true,
onEvent: (event) => {
if (event.type === "progress") {
console.log("progress", event.data);
}
if (event.type === "completed") {
connection.close();
}
},
});Space stream
client.realtime.connectSpace(client.spaceId, {
autoReconnect: true,
onEvent: (event) => {
console.log(event.type, event.jobId, event.status, event.seq);
},
});Surface area
client.jobs
create(job | jobs[])list(query?)poll(request?)claim(jobId)get(jobId)getProgress(jobId)getLogs(jobId, query?)ack(jobId)progress(jobId, payload)checkpoint(jobId, payload)event(jobId, payload)complete(jobId, result?)fail(jobId, error?)kill(jobId, reason?)keepalive(jobId)createClaimedJob(snapshot, loggerOptions?)
Claimed job helper (onJob arg)
job.ack()job.progress(payload)job.checkpoint(payload)job.event(payload)job.complete(result?)job.fail(error?)job.kill(reason?)job.keepalive()job.getDetails()job.getProgress()job.getLogs(query?)job.log.trace/debug/info/warn/error/fatal(message, options?)job.log.flush()job.log.close()
client.workers
runPolling(options)handlePush(payload, options)createPushHandler(options)
client.realtime
connectJob(jobId, options?)connectSpace(spaceId, options?)
Defaults and optional options
EmitClient options
| Option | Required | Default | Notes |
| --- | --- | --- | --- |
| spaceId | Yes | - | Space bound to this client instance |
| apiKey | No | - | Required for authenticated REST calls and connectSpace; optional for anonymous connectJob |
| baseUrl | No | https://emit.run/api/v1 | Set for staging/self-hosted |
| apiKeyHeader | No | x-api-key | x-api-key or authorization |
| headers | No | {} | Merged into every request |
| credentials | No | same-origin | Passed to fetch |
| fetch | No | globalThis.fetch | Custom runtime fetch |
| webSocketFactory | No | globalThis.WebSocket | Needed on runtimes without global WS |
workers.runPolling options
| Option | Required | Default | Notes |
| --- | --- | --- | --- |
| onJob | Yes | - | Claimed job handler |
| count | No | 1 | Poll batch size |
| types | No | none | Name/type filter for poll |
| pollIntervalMs | No | 1000 | Base idle delay |
| maxBackoffMs | No | 15000 | Backoff cap when no jobs/errors |
| autoAck | No | true | Calls job.ack() before handler |
| autoFailOnError | No | true | Calls job.fail(...) on thrown errors |
| autoComplete | No | false | Completes with handler return value |
| keepaliveIntervalMs | No | disabled | Calls job.keepalive() on interval |
| stopOnError | No | false | Rethrows worker loop errors |
| onError | No | none | Error callback after handler failure |
| logger | No | defaults below | Claimed-job logger config |
| signal | No | none | Abort signal for loop shutdown |
Logger options (logger)
| Option | Required | Default | Notes |
| --- | --- | --- | --- |
| flushIntervalMs | No | 1000 | Time-based flush interval |
| maxBatchSize | No | 100 | Flush when queue reaches this size |
| maxBufferedEntries | No | 10000 | Queue cap (oldest entries dropped) |
| gzip | No | true | gzip NDJSON body when runtime supports it |
| source | No | none | Default source for job.log.* calls |
workers.handlePush / createPushHandler options
Uses the same execution options as runPolling (onJob, autoAck, autoFailOnError,
autoComplete, keepaliveIntervalMs, stopOnError, onError, logger).
Realtime options
| Option | Required | Default | Notes |
| --- | --- | --- | --- |
| token | No | client apiKey (when configured) | Explicit realtime token override |
| autoReconnect | No | false | Reconnect on close/error |
| reconnectDelayMs | No | 1000 | Initial reconnect delay |
| maxReconnectDelayMs | No | 15000 | Exponential backoff cap |
| signal | No | none | Abort closes connection |
| onOpen | No | none | Open callback |
| onEvent | No | none | Message callback |
| onError | No | none | Error callback |
| onClose | No | none | Close callback |
For connectSpace, you can also pass:
| Option | Required | Default | Notes |
| --- | --- | --- | --- |
| since | No | none | Resume cursor |
| streamInstanceId | No | none | Restart detection cursor |
Development
npm install
npm run typecheck
npm test
npm run build