resonate-basic-ephemeral-world-usage-typescript — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited resonate-basic-ephemeral-world-usage-typescript (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
SDK version: This skill reflects @resonatehq/sdk v0.10.0 (current on npm).The Ephemeral World is where your application code lives that is NOT inside generator functions. This is where you:
Key distinction: Ephemeral World code uses resonate (the Client). Durable World code uses ctx (the Context).
┌─────────────────────────────────────────┐
│ EPHEMERAL WORLD (Stateless) │
│ │
│ • Resonate Client initialization │
│ • Function registration │
│ • Top-level run/rpc calls │
│ • Promise management (create/resolve) │
│ • Dependency injection │
│ │
│ Uses: resonate.run(), resonate.rpc() │
└─────────────────────────────────────────┘
↓ invokes ↓
┌─────────────────────────────────────────┐
│ DURABLE WORLD (Stateful) │
│ │
│ • Generator functions with yield* │
│ • Context APIs for sub-invocations │
│ • Durable coordination and recovery │
│ │
│ Uses: ctx.run(), ctx.rpc() │
└─────────────────────────────────────────┘You CANNOT use Context APIs in the ephemeral world, and you CANNOT use Client APIs in durable functions.
import { Resonate } from "@resonatehq/sdk";
// No URL = local in-memory mode
const resonate = new Resonate();Key behaviors:
new Resonate() without a URL, function arguments are wrapped in an arrayimport { Resonate } from "@resonatehq/sdk";
const resonate = new Resonate({
url: "http://localhost:8001",
group: "workers",
auth: {
username: "user",
password: "pass"
}
});When to use:
export RESONATE_URL="http://localhost:8001"
export RESONATE_USERNAME="user"
export RESONATE_PASSWORD="pass"const resonate = new Resonate(); // Picks up env vars automaticallyResolution order:
function* myWorkflow(ctx: Context, arg: string) {
return `Hello ${arg}`;
}
// ✅ CORRECT
const stub = resonate.register(myWorkflow);// ❌ WRONG - Don't use custom string names
resonate.register("my_workflow", myWorkflow);
// ❌ WRONG - Don't use snake_case
resonate.register("db_get_user", dbGetUser);Why this matters:
const workflowStub = resonate.register(myWorkflow);
// Later, invoke directly via stub
const result = await workflowStub.run("execution-1", "World");// Blocks until result is ready
const result = await resonate.run(
"execution-id",
myWorkflow,
"arg1",
"arg2"
);Use when:
// Returns immediately with handle
const handle = await resonate.beginRun(
"execution-id",
myWorkflow,
"arg1"
);
// Do other work...
// Get result later
const result = await handle.result();Use when:
// Blocks until remote execution completes
const result = await resonate.rpc(
"execution-id",
"myWorkflow", // String name!
"arg1",
resonate.options({
target: "poll://any@workers"
})
);Critical differences from run:
const handle = await resonate.beginRpc(
"execution-id",
"myWorkflow",
"arg1",
resonate.options({
target: "poll://any@workers"
})
);
const result = await handle.result();await resonate.run(
"execution-id",
myWorkflow,
"arg1",
resonate.options({
timeout: 60_000, // 60 seconds in ms
tags: { userId: "123" },
version: 1
})
);Available options:
timeout: Max execution time in millisecondstags: Metadata for filtering/searchingversion: Function version for schema evolutiontarget: RPC routing (poll://any@group-name)await resonate.promises.create(
"approval-123",
Date.now() + 30000 // timeout 30s from now
);const promise = await resonate.promises.get("approval-123");// Elsewhere (webhook, UI, CLI):
await resonate.promises.settle("approval-123", "resolved", {
data: JSON.stringify({
approved: true,
approver: "[email protected]",
}),
});await resonate.promises.settle("approval-123", "rejected", {
data: JSON.stringify({
reason: "Insufficient funds",
}),
});import { createClient } from "@supabase/supabase-js";
const db = createClient(url, key);
// Set in ephemeral world
resonate.setDependency("db", db);
resonate.setDependency("config", { apiKey: "..." });Rules:
function* myWorkflow(ctx: Context, userId: string) {
// Get in durable world
const db = ctx.getDependency("db");
const user = yield* ctx.run(async (_ctx, id) => {
return await db.from("users").select().eq("id", id).single();
}, userId);
return user;
}const schedule = await resonate.schedule(
"daily-report",
"0 8 * * *", // Every day at 8am
generateReport,
"arg1"
);
// Later, delete the schedule
await schedule.delete();// Subscribe to existing execution
const handle = await resonate.get("execution-id");
// Wait for result
const result = await handle.result();
// Check if done
const isDone = await handle.done();Use when:
// ❌ WRONG - Using ctx in ephemeral world
async function main() {
const result = await ctx.run(myFunc); // ctx doesn't exist here!
}
// ✅ CORRECT
async function main() {
const result = await resonate.run("id", myFunc);
}// ❌ WRONG
function* myWorkflow(ctx: Context) {
const result = await resonate.run("id", otherFunc); // Wrong API!
}
// ✅ CORRECT
function* myWorkflow(ctx: Context) {
const result = yield* ctx.run(otherFunc);
}// ❌ WRONG - RPC needs target
await resonate.rpc("id", "funcName", "arg");
// ✅ CORRECT
await resonate.rpc(
"id",
"funcName",
"arg",
resonate.options({ target: "poll://any@workers" })
);// In-memory mode (no URL)
const resonate = new Resonate();
function* workflow(ctx: Context, state: MyState) {
// ❌ WRONG - state will be [MyState], not MyState!
console.log(state.someField); // undefined!
}
// ✅ CORRECT - Handle array wrapping in local mode
function* workflow(ctx: Context, state: any) {
const actualState = Array.isArray(state) ? state[0] : state;
console.log(actualState.someField); // Works!
}// ❌ WRONG - Durable functions must be generators
async function* workflow(ctx: Context) { }
// ✅ CORRECT
function* workflow(ctx: Context) { }import "dotenv/config";
import { Resonate, type Context } from "@resonatehq/sdk";
// Initialize client (ephemeral world)
const resonate = new Resonate({
url: process.env.RESONATE_URL,
group: "workers"
});
// Set dependencies (ephemeral world)
resonate.setDependency("apiKey", process.env.API_KEY);
// Register functions (ephemeral world)
const workflowStub = resonate.register(myWorkflow);
// Start execution (ephemeral world)
async function main() {
const handle = await resonate.beginRun(
"workflow-1",
myWorkflow,
{ userId: "123" }
);
console.log("Started:", handle.id);
const result = await handle.result();
console.log("Result:", result);
}
// Durable function (durable world - uses Context APIs)
function* myWorkflow(ctx: Context, input: any) {
const apiKey = ctx.getDependency("apiKey");
const data = yield* ctx.run(fetchData, input.userId);
const processed = yield* ctx.run(processData, data);
return processed;
}
async function fetchData(_ctx: Context, userId: string) {
// Fetch logic
return { userId, data: "..." };
}
async function processData(_ctx: Context, data: any) {
// Process logic
return { processed: true };
}
main().catch(console.error);Where am I?
main() or app entry point → Ephemeral World (use Client APIs)function* with ctx parameter → Durable World (use Context APIs)What do I need to do?
new Resonate()resonate.register(func)resonate.run() or resonate.beginRun()resonate.rpc() or resonate.beginRpc()resonate.promises.*()resonate.setDependency()resonate.schedule()resonate.get()The Ephemeral World is your control plane:
Keep it simple, keep it separate from durable functions.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.