|
1 | | -<div align="center"> |
2 | | - <img src="./media/header_template.png" alt="TanStack Template" /> |
3 | | -</div> |
| 1 | +# TanStack Workflow |
4 | 2 |
|
5 | | -<br /> |
| 3 | +Type-safe durable execution for TypeScript. Workflows are ordinary async functions that can pause, persist progress to an append-only log, and resume after approvals, webhooks, timers, or process restarts. |
6 | 4 |
|
7 | | -<div align="center"> |
8 | | - <a href="https://www.npmjs.com/package/@tanstack/template" target="\_parent"> |
9 | | - <img alt="npm downloads" src="https://img.shields.io/npm/dm/@tanstack/template.svg" /> |
10 | | - </a> |
11 | | - <a href="https://github.com/TanStack/template" target="\_parent"> |
12 | | - <img alt="GitHub stars" src="https://img.shields.io/github/stars/TanStack/template.svg?style=social&label=Star" /> |
13 | | - </a> |
14 | | - <a href="https://bundlephobia.com/result?p=@tanstack/react-template@latest" target="\_parent"> |
15 | | - <img alt="Bundle size" src="https://badgen.net/bundlephobia/minzip/@tanstack/react-template@latest" /> |
16 | | - </a> |
17 | | -</div> |
18 | | - |
19 | | -<div align="center"> |
20 | | - <a href="#badge"> |
21 | | - <img alt="semantic-release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg"> |
22 | | - </a> |
23 | | - <a href="#badge"> |
24 | | - <img src="https://img.shields.io/github/v/release/tanstack/template" alt="Release"/> |
25 | | - </a> |
26 | | - <a href="https://twitter.com/tan_stack"> |
27 | | - <img src="https://img.shields.io/twitter/follow/tan_stack.svg?style=social" alt="Follow @TanStack"/> |
28 | | - </a> |
29 | | -</div> |
30 | | - |
31 | | -<div align="center"> |
32 | | - |
33 | | -### [Become a Sponsor!](https://github.com/sponsors/tannerlinsley/) |
34 | | - |
35 | | -</div> |
36 | | - |
37 | | -# TanStack Template |
38 | | - |
39 | | -> [!NOTE] |
40 | | -> TanStack Template is a starting point for new TanStack libraries. Replace this README content with product-specific copy before release. |
41 | | -
|
42 | | -Build a TanStack library with a framework-agnostic core, React and Solid adapters, devtools packages, documentation, examples, CI, release automation, and package quality checks already wired together. |
| 5 | +```bash |
| 6 | +pnpm add @tanstack/workflow-core |
| 7 | +``` |
43 | 8 |
|
44 | | -- Framework-agnostic core package ready for domain logic |
45 | | -- React and Solid adapters with matching examples and docs structure |
46 | | -- Devtools package placeholders for framework-specific integrations |
47 | | -- pnpm, Nx, TypeScript, tsdown, Vitest, ESLint, Prettier, Changesets, and TypeDoc setup |
48 | | -- GitHub workflows for PR checks, release, preview publishing, provenance, and autofix |
| 9 | +Install `zod` or another Standard Schema-compatible library if you want runtime validation for workflow inputs, outputs, state, or signal payloads. |
| 10 | + |
| 11 | +## Example |
| 12 | + |
| 13 | +```ts |
| 14 | +import { |
| 15 | + createWorkflow, |
| 16 | + inMemoryRunStore, |
| 17 | + runWorkflow, |
| 18 | +} from '@tanstack/workflow-core' |
| 19 | +import { z } from 'zod' |
| 20 | + |
| 21 | +const checkout = createWorkflow({ |
| 22 | + id: 'checkout', |
| 23 | + input: z.object({ userId: z.string(), amount: z.number() }), |
| 24 | + output: z.object({ status: z.enum(['approved', 'rejected']) }), |
| 25 | +}).handler(async (ctx) => { |
| 26 | + const charge = await ctx.step('charge-card', (stepCtx) => |
| 27 | + stripe.charges.create( |
| 28 | + { customer: ctx.input.userId, amount: ctx.input.amount }, |
| 29 | + { idempotencyKey: stepCtx.id }, |
| 30 | + ), |
| 31 | + ) |
| 32 | + |
| 33 | + if (ctx.input.amount > 10_000) { |
| 34 | + const decision = await ctx.approve({ title: 'Approve large charge?' }) |
| 35 | + if (!decision.approved) return { status: 'rejected' as const } |
| 36 | + } |
| 37 | + |
| 38 | + await ctx.step('send-receipt', () => sendReceipt(charge.id)) |
| 39 | + return { status: 'approved' as const } |
| 40 | +}) |
| 41 | + |
| 42 | +const store = inMemoryRunStore() |
| 43 | + |
| 44 | +for await (const event of runWorkflow({ |
| 45 | + workflow: checkout, |
| 46 | + input: { userId: 'cus_123', amount: 4200 }, |
| 47 | + runStore: store, |
| 48 | +})) { |
| 49 | + console.log(event.type, event) |
| 50 | +} |
| 51 | +``` |
49 | 52 |
|
50 | | -### <a href="https://tanstack.com/template">Read the docs -></a> |
| 53 | +## Core Ideas |
51 | 54 |
|
52 | | -<br /> |
| 55 | +- Side effects live inside `ctx.step(id, fn)`, which records results and skips re-execution on replay. |
| 56 | +- `ctx.waitForEvent`, `ctx.approve`, `ctx.sleep`, and `ctx.sleepUntil` pause runs until the host delivers a matching signal or approval. |
| 57 | +- `ctx.now()` and `ctx.uuid()` record deterministic values for replay. |
| 58 | +- Middleware can extend `ctx` with typed dependencies such as users, database handles, or tracing. |
| 59 | +- Storage is pluggable through `RunStore`; the package ships an in-memory store for local development and tests. |
53 | 60 |
|
54 | | -> [!NOTE] |
55 | | -> New libraries created from this template currently include these adapter packages: |
56 | | -> |
57 | | -> - [**React Template**](https://tanstack.com/template/latest/docs/framework/react/adapter) |
58 | | -> - [**Solid Template**](https://tanstack.com/template/latest/docs/framework/solid/adapter) |
| 61 | +## Packages |
59 | 62 |
|
60 | | -## Template Usage |
| 63 | +- `@tanstack/workflow-core`: engine, workflow builder, middleware, event types, request parsing helpers, version routing, and in-memory `RunStore`. |
61 | 64 |
|
62 | | -Start with [TEMPLATE_GUIDE.md](./TEMPLATE_GUIDE.md), then replace the placeholder names, package descriptions, docs, examples, source code, issue templates, and README copy with the new library's product-specific content. |
| 65 | +Storage adapters, framework bindings, and devtools are planned as follow-up packages. |
63 | 66 |
|
64 | | -## Development Commands |
| 67 | +## Development |
65 | 68 |
|
66 | 69 | ```bash |
67 | 70 | pnpm install |
68 | | -pnpm build:all |
69 | | -pnpm test:lib |
70 | | -pnpm test:pr |
71 | | -pnpm lint:all |
72 | | -pnpm format |
73 | | -pnpm generate-docs |
74 | | -pnpm watch |
| 71 | +pnpm --filter @tanstack/workflow-core test:lib |
| 72 | +pnpm --filter @tanstack/workflow-core test:types |
| 73 | +pnpm --filter @tanstack/workflow-core build |
| 74 | +pnpm test |
75 | 75 | ``` |
76 | 76 |
|
77 | | -## Get Involved |
78 | | - |
79 | | -- We welcome issues and pull requests. |
80 | | -- Participate in [GitHub discussions](https://github.com/TanStack/template/discussions). |
81 | | -- Chat with the community on [Discord](https://discord.com/invite/WrRKjPJ). |
82 | | -- See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup instructions. |
83 | | - |
84 | | -## Partners |
85 | | - |
86 | | -<div align="center"> |
87 | | - |
88 | | -<table align="center"> |
89 | | - <tr> |
90 | | - <td> |
91 | | - <a href="https://www.coderabbit.ai/?via=tanstack"> |
92 | | - <picture> |
93 | | - <source media="(prefers-color-scheme: dark)" srcset="https://tanstack.com/assets/coderabbit-dark-D643Zkrv.svg" height="40" /> |
94 | | - <source media="(prefers-color-scheme: light)" srcset="https://tanstack.com/assets/coderabbit-light-CIzGLYU_.svg" height="40" /> |
95 | | - <img src="https://tanstack.com/assets/coderabbit-light-DVMJ2jHi.svg" height="40" alt="CodeRabbit" /> |
96 | | - </picture> |
97 | | - </a> |
98 | | - </td> |
99 | | - <td> |
100 | | - <a href="https://www.cloudflare.com?utm_source=tanstack"> |
101 | | - <picture> |
102 | | - <source media="(prefers-color-scheme: dark)" srcset="https://tanstack.com/assets/cloudflare-white-Co-Tyjbl.svg" height="60" /> |
103 | | - <source media="(prefers-color-scheme: light)" srcset="https://tanstack.com/assets/cloudflare-black-6Ojsn8yh.svg" height="60" /> |
104 | | - <img src="https://tanstack.com/assets/cloudflare-black-CPufaW0B.svg" height="60" alt="Cloudflare" /> |
105 | | - </picture> |
106 | | - </a> |
107 | | - </td> |
108 | | - </tr> |
109 | | -</table> |
110 | | - |
111 | | -</div> |
112 | | - |
113 | | -## Explore the TanStack Ecosystem |
114 | | - |
115 | | -- <a href="https://github.com/tanstack/config"><b>TanStack Config</b></a> - Tooling for JS/TS packages |
116 | | -- <a href="https://github.com/tanstack/db"><b>TanStack DB</b></a> - Reactive sync client store |
117 | | -- <a href="https://github.com/tanstack/devtools"><b>TanStack DevTools</b></a> - Unified devtools panel |
118 | | -- <a href="https://github.com/tanstack/form"><b>TanStack Form</b></a> - Type-safe form state |
119 | | -- <a href="https://github.com/tanstack/hotkeys"><b>TanStack Hotkeys</b></a> - Type-safe keyboard shortcuts |
120 | | -- <a href="https://github.com/tanstack/query"><b>TanStack Query</b></a> - Async state and caching |
121 | | -- <a href="https://github.com/tanstack/router"><b>TanStack Router</b></a> - Type-safe routing, caching and URL state |
122 | | -- <a href="https://github.com/tanstack/start"><b>TanStack Start</b></a> - Full-stack SSR and streaming |
123 | | -- <a href="https://github.com/tanstack/store"><b>TanStack Store</b></a> - Reactive data store |
124 | | -- <a href="https://github.com/tanstack/table"><b>TanStack Table</b></a> - Headless datagrids |
125 | | -- <a href="https://github.com/tanstack/virtual"><b>TanStack Virtual</b></a> - Virtualized rendering |
126 | | - |
127 | | -... and more at <a href="https://tanstack.com"><b>TanStack.com »</b></a> |
| 77 | +## Docs |
| 78 | + |
| 79 | +- [Overview](./docs/overview.md) |
| 80 | +- [Installation](./docs/installation.md) |
| 81 | +- [Quick start](./docs/quick-start.md) |
| 82 | +- [Primitives](./docs/concepts/primitives.md) |
| 83 | +- [Replay and resume](./docs/concepts/replay-and-resume.md) |
| 84 | +- [Scheduling](./docs/concepts/scheduling.md) |
128 | 85 |
|
129 | 86 | ## License |
130 | 87 |
|
|
0 commit comments