@pstdio/tiny-tasks 
Composable, interrupt-friendly workflows for TypeScript/JavaScript. Turn async functions into checkpoint-able generators that can pause, persist, and resume.
Install 
bash
npm i @pstdio/tiny-tasksQuick Start 
ts
import { createRuntime } from "@pstdio/tiny-tasks";
const { task, MemorySaver } = createRuntime();
const saver = new MemorySaver();
const opts = { runId: "demo", checkpointer: saver };
const workflow = task("workflow", async function* (name: string, ctx) {
  yield `processing ${name}`;
  const resume = ctx.interrupt({ message: "wait" });
  yield `done: ${resume.message}`;
});
// first run – yields once and interrupts
for await (const [msg, , intr] of workflow("job", opts)) {
  if (msg) console.log(msg);
  if (intr) console.log("interrupt →", intr);
}
// resume after external work is finished
for await (const [msg] of workflow.resume({ message: "ok" }, opts)) {
  if (msg) console.log(msg);
}Examples 
Nested streaming 
ts
const step = task("step", async function* (q: string) {
  yield `processing ${q}`;
  yield `done: ${q}`;
});
const aggregate = task("aggregate", async function* (q: string) {
  const state: string[] = [];
  for await (const [msg] of step(q)) {
    if (msg) state.push(msg as string);
    yield state.slice();
  }
  return [...state, "aggregate done"];
});
for await (const [partial] of aggregate("task")) {
  console.log(partial);
}Nested interrupts 
ts
const inner = task("inner", async function* (_: void, ctx) {
  ctx.interrupt("stop");
  yield "resumed";
});
const outer = task("outer", async function* (_: void, ctx) {
  for await (const [msg, , intr] of inner()) {
    if (msg) yield msg;
    if (intr) ctx.interrupt(intr);
  }
  return "done";
});
for await (const [msg, , intr] of outer()) {
  console.log(msg, intr);
}API Overview 
- task: Wrap an async generator. Use ctx.interrupt(value)inside to pause and persist.
- createRuntime: Browser-friendly initializer returning { task, MemorySaver, ... }.
- MemorySaver: In-memory checkpoint store for demos/tests.
Each task yields tuples [partial, snapshot, interrupt] during execution and supports:
- .invoke(input, opts)– run to completion and resolve final result
- .resume(value, opts)– resume after an interrupt
Notes & Caveats 
- Use a consistent runIdwhen resuming to locate prior checkpoints.
- Avoid mutating shared state between yields; earlier steps may re-run on resume.
- The default MemorySaveris ephemeral; implement your own saver for persistence.