@steadlake/run 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +231 -7
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,15 +1,239 @@
1
- # steppler
1
+ # @steadlake/run
2
2
 
3
- To install dependencies:
3
+ Durable task execution for your backend. Define tasks with steps, retries, scheduling, and event-driven workflows — without managing infrastructure.
4
+
5
+ ## Install
4
6
 
5
7
  ```bash
6
- bun install
8
+ npm install @steadlake/run
7
9
  ```
8
10
 
9
- To run:
11
+ ## Setup
10
12
 
11
- ```bash
12
- bun run index.ts
13
+ **Environment variables:**
14
+
15
+ ```
16
+ STEADLAKE_API_KEY=sk_live_...
17
+ STEADLAKE_PROJECT_ID=proj_...
18
+ ```
19
+
20
+ ## Quick start
21
+
22
+ ### 1. Define tasks
23
+
24
+ ```ts
25
+ // tasks/send-email.ts
26
+ import { task } from "@steadlake/run";
27
+ import { z } from "zod";
28
+
29
+ export const sendEmail = task({
30
+ id: "send-email",
31
+ schema: z.object({ to: z.string().email(), subject: z.string() }),
32
+ run: async ({ payload }) => {
33
+ await emailService.send(payload.to, payload.subject);
34
+ return { sent: true };
35
+ },
36
+ });
37
+ ```
38
+
39
+ ### 2. Mount the handler
40
+
41
+ **Next.js**
42
+ ```ts
43
+ // app/api/steadlake/route.ts
44
+ import { createNextHandler } from "@steadlake/run/adapters/next";
45
+ import { sendEmail } from "@/tasks/send-email";
46
+
47
+ export const { POST } = createNextHandler({
48
+ baseUrl: process.env.APP_URL!,
49
+ tasks: [sendEmail],
50
+ });
51
+ ```
52
+
53
+ **Hono / Generic**
54
+ ```ts
55
+ import { createHandler } from "@steadlake/run/adapters/generic";
56
+ import { sendEmail } from "./tasks/send-email";
57
+
58
+ const handler = createHandler({
59
+ baseUrl: process.env.APP_URL!,
60
+ tasks: [sendEmail],
61
+ });
62
+
63
+ app.post("/api/steadlake", (c) => handler(c.req.raw));
64
+ ```
65
+
66
+ **Cloudflare Workers**
67
+ ```ts
68
+ import { createWorkerHandler } from "@steadlake/run/adapters/worker";
69
+ import { sendEmail } from "./tasks/send-email";
70
+
71
+ const handler = createWorkerHandler({ tasks: [sendEmail] });
72
+
73
+ export default {
74
+ fetch(req: Request, env: Env) {
75
+ if (new URL(req.url).pathname === "/api/steadlake") {
76
+ return handler(req, env, env.WORKER_URL);
77
+ }
78
+ return app.fetch(req, env);
79
+ },
80
+ };
81
+ ```
82
+
83
+ ### 3. Trigger
84
+
85
+ ```ts
86
+ // anywhere in your server code
87
+ import { sendEmail } from "@/tasks/send-email";
88
+
89
+ await sendEmail.trigger({ to: "user@example.com", subject: "Welcome!" });
90
+ ```
91
+
92
+ ---
93
+
94
+ ## Steps
95
+
96
+ Break long tasks into named, durable steps. Completed steps are replayed from state on retry — they never re-execute.
97
+
98
+ ```ts
99
+ export const importUsers = task({
100
+ id: "import-users",
101
+ run: async ({ payload, step }) => {
102
+ const users = await step.run("fetch", () => api.getUsers(payload.source));
103
+ const valid = await step.run("validate", () => users.filter(isValid));
104
+ await step.run("insert", () => db.users.bulkInsert(valid));
105
+ return { imported: valid.length };
106
+ },
107
+ });
108
+ ```
109
+
110
+ ### Sleep
111
+
112
+ ```ts
113
+ await step.sleep("wait", "3d"); // duration: ms, s, m, h, d
114
+ await step.sleepUntil("until", date); // Date | ISO string
115
+ ```
116
+
117
+ ### Wait for external event
118
+
119
+ ```ts
120
+ const shipment = await step.waitForEvent<{ trackingId: string }>("shipped", {
121
+ event: "order.shipped",
122
+ timeout: "7d",
123
+ });
124
+ ```
125
+
126
+ Resume by calling `run.sendEvent("order.shipped", { trackingId: "..." })`.
127
+
128
+ ### Human approval
129
+
130
+ ```ts
131
+ const { approved } = await step.approve("review", {
132
+ title: "Approve $10,000 payout?",
133
+ timeout: "24h",
134
+ });
135
+ ```
136
+
137
+ Resume by calling `client.resolveApproval(runId, stepId, true)`.
138
+
139
+ ### Emit events to other runs
140
+
141
+ ```ts
142
+ step.emit("order.shipped", { trackingId: "TRK123" });
13
143
  ```
14
144
 
15
- This project was created using `bun init` in bun v1.3.10. [Bun](https://bun.com) is a fast all-in-one JavaScript runtime.
145
+ ---
146
+
147
+ ## Retries
148
+
149
+ ```ts
150
+ export const chargeCustomer = task({
151
+ id: "charge-customer",
152
+ retry: {
153
+ maxAttempts: 5,
154
+ backoff: "exponential", // "exponential" | "linear" | "fixed"
155
+ },
156
+ run: async ({ payload }) => {
157
+ await stripe.charges.create({ amount: payload.amount });
158
+ },
159
+ });
160
+ ```
161
+
162
+ Throw `FatalError` to fail permanently without retrying. Throw `RetryableError` to retry explicitly.
163
+
164
+ ---
165
+
166
+ ## Cron
167
+
168
+ ```ts
169
+ export const dailyReport = task({
170
+ id: "daily-report",
171
+ cron: "0 9 * * 1-5",
172
+ run: async () => { ... },
173
+ });
174
+
175
+ // With timezone
176
+ export const digest = task({
177
+ id: "digest",
178
+ cron: { pattern: "0 8 * * *", timezone: "America/New_York" },
179
+ run: async () => { ... },
180
+ });
181
+ ```
182
+
183
+ ---
184
+
185
+ ## Queues
186
+
187
+ ```ts
188
+ export const processVideo = task({
189
+ id: "process-video",
190
+ queue: {
191
+ name: "video",
192
+ concurrencyLimit: 3,
193
+ rateLimit: { max: 100, duration: "1h" },
194
+ },
195
+ run: async ({ payload }) => { ... },
196
+ });
197
+ ```
198
+
199
+ ---
200
+
201
+ ## Trigger options
202
+
203
+ ```ts
204
+ await sendEmail.trigger(payload, {
205
+ idempotencyKey: `email-${userId}`,
206
+ webhook: "https://myapp.com/webhooks/done",
207
+ tags: ["transactional"],
208
+ priority: 10,
209
+ scheduledAt: new Date(Date.now() + 60_000).toISOString(),
210
+ });
211
+ ```
212
+
213
+ Wait for result:
214
+
215
+ ```ts
216
+ const result = await sendEmail.triggerAndWait(payload, { timeoutMs: 30_000 });
217
+ console.log(result.status); // "success" | "failed"
218
+ console.log(result.result);
219
+ ```
220
+
221
+ ---
222
+
223
+ ## Error types
224
+
225
+ | | HTTP | DEW behaviour |
226
+ |---|---|---|
227
+ | `FatalError` | 400 | Permanent failure, no retry |
228
+ | `RetryableError` | 500 | Explicit retry request |
229
+ | Any other error | 500 | Retry if attempts remain |
230
+
231
+ ---
232
+
233
+ ## Environment variables
234
+
235
+ | Variable | Description |
236
+ |---|---|
237
+ | `STEADLAKE_API_KEY` | Your project API key |
238
+ | `STEADLAKE_PROJECT_ID` | Your project ID |
239
+ | `STEADLAKE_API_URL` | Override platform URL (self-hosted) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steadlake/run",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Durable task execution SDK for Steadlake — define tasks with steps, retries, scheduling, and event-driven workflows.",
5
5
  "files": [
6
6
  "dist"
@@ -36,7 +36,7 @@
36
36
  "format:check": "oxfmt --check .",
37
37
  "changeset": "changeset",
38
38
  "version": "changeset version",
39
- "release": "npm run build && npm publish"
39
+ "release": "npm run build && changeset publish"
40
40
  },
41
41
  "dependencies": {
42
42
  "@steadlake/core": "^0.3.2",