queuebear 0.1.0 → 0.1.2
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.
- package/README.md +72 -59
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,9 +13,7 @@ npm install queuebear
|
|
|
13
13
|
```typescript
|
|
14
14
|
import { QueueBear, serve } from "queuebear";
|
|
15
15
|
|
|
16
|
-
// Create client
|
|
17
16
|
const qb = new QueueBear({
|
|
18
|
-
baseUrl: "https://your-queuebear-instance.com",
|
|
19
17
|
apiKey: "qb_live_xxx",
|
|
20
18
|
projectId: "proj_xxx",
|
|
21
19
|
});
|
|
@@ -25,12 +23,12 @@ const qb = new QueueBear({
|
|
|
25
23
|
|
|
26
24
|
The SDK provides access to all QueueBear APIs:
|
|
27
25
|
|
|
28
|
-
| API
|
|
29
|
-
|
|
30
|
-
| `qb.messages`
|
|
31
|
-
| `qb.schedules` | Create and manage cron-based recurring jobs
|
|
32
|
-
| `qb.dlq`
|
|
33
|
-
| `qb.workflows` | Trigger and manage durable workflows
|
|
26
|
+
| API | Description |
|
|
27
|
+
| -------------- | ----------------------------------------------- |
|
|
28
|
+
| `qb.messages` | Publish and manage webhook messages |
|
|
29
|
+
| `qb.schedules` | Create and manage cron-based recurring jobs |
|
|
30
|
+
| `qb.dlq` | Manage failed messages in the dead letter queue |
|
|
31
|
+
| `qb.workflows` | Trigger and manage durable workflows |
|
|
34
32
|
|
|
35
33
|
---
|
|
36
34
|
|
|
@@ -45,13 +43,13 @@ const { messageId } = await qb.messages.publish(
|
|
|
45
43
|
"https://api.example.com/webhook",
|
|
46
44
|
{ event: "user.created", userId: "123" },
|
|
47
45
|
{
|
|
48
|
-
delay: "30s",
|
|
49
|
-
retries: 5,
|
|
50
|
-
method: "POST",
|
|
46
|
+
delay: "30s", // Delay before delivery
|
|
47
|
+
retries: 5, // Number of retry attempts
|
|
48
|
+
method: "POST", // HTTP method
|
|
51
49
|
headers: { "X-API-Key": "secret" }, // Headers to forward
|
|
52
|
-
callbackUrl: "https://...",
|
|
50
|
+
callbackUrl: "https://...", // Success callback
|
|
53
51
|
failureCallbackUrl: "https://...", // Failure callback
|
|
54
|
-
deduplicationId: "unique-id",
|
|
52
|
+
deduplicationId: "unique-id", // Prevent duplicate messages
|
|
55
53
|
}
|
|
56
54
|
);
|
|
57
55
|
```
|
|
@@ -60,7 +58,7 @@ const { messageId } = await qb.messages.publish(
|
|
|
60
58
|
|
|
61
59
|
```typescript
|
|
62
60
|
const message = await qb.messages.get(messageId);
|
|
63
|
-
console.log(message.status);
|
|
61
|
+
console.log(message.status); // "pending" | "completed" | "failed"
|
|
64
62
|
console.log(message.deliveryLogs); // Delivery attempt history
|
|
65
63
|
```
|
|
66
64
|
|
|
@@ -102,7 +100,7 @@ Create cron-based recurring jobs.
|
|
|
102
100
|
```typescript
|
|
103
101
|
const schedule = await qb.schedules.create({
|
|
104
102
|
destination: "https://api.example.com/cron-job",
|
|
105
|
-
cron: "0 9 * * *",
|
|
103
|
+
cron: "0 9 * * *", // Daily at 9 AM
|
|
106
104
|
timezone: "America/New_York",
|
|
107
105
|
method: "POST",
|
|
108
106
|
body: JSON.stringify({ type: "daily-report" }),
|
|
@@ -114,14 +112,14 @@ const schedule = await qb.schedules.create({
|
|
|
114
112
|
|
|
115
113
|
### Common Cron Expressions
|
|
116
114
|
|
|
117
|
-
| Expression
|
|
118
|
-
|
|
119
|
-
| `* * * * *`
|
|
120
|
-
| `0 * * * *`
|
|
121
|
-
| `0 9 * * *`
|
|
122
|
-
| `0 9 * * 1-5` | Weekdays at 9:00 AM
|
|
123
|
-
| `0 0 1 * *`
|
|
124
|
-
| `0 */6 * * *` | Every 6 hours
|
|
115
|
+
| Expression | Description |
|
|
116
|
+
| ------------- | ----------------------- |
|
|
117
|
+
| `* * * * *` | Every minute |
|
|
118
|
+
| `0 * * * *` | Every hour |
|
|
119
|
+
| `0 9 * * *` | Daily at 9:00 AM |
|
|
120
|
+
| `0 9 * * 1-5` | Weekdays at 9:00 AM |
|
|
121
|
+
| `0 0 1 * *` | First day of each month |
|
|
122
|
+
| `0 */6 * * *` | Every 6 hours |
|
|
125
123
|
|
|
126
124
|
### List Schedules
|
|
127
125
|
|
|
@@ -161,15 +159,15 @@ for (const entry of entries) {
|
|
|
161
159
|
|
|
162
160
|
```typescript
|
|
163
161
|
const entry = await qb.dlq.get(dlqId);
|
|
164
|
-
console.log(entry.body);
|
|
165
|
-
console.log(entry.totalAttempts);
|
|
162
|
+
console.log(entry.body); // Original message body
|
|
163
|
+
console.log(entry.totalAttempts); // Number of failed attempts
|
|
166
164
|
```
|
|
167
165
|
|
|
168
166
|
### Retry a Failed Message
|
|
169
167
|
|
|
170
168
|
```typescript
|
|
171
169
|
const result = await qb.dlq.retry(dlqId);
|
|
172
|
-
console.log(result.newMessageId);
|
|
170
|
+
console.log(result.newMessageId); // New message created
|
|
173
171
|
```
|
|
174
172
|
|
|
175
173
|
### Delete Entry / Purge All
|
|
@@ -193,6 +191,7 @@ console.log(`Retried ${results.length} entries`);
|
|
|
193
191
|
Build durable, fault-tolerant workflows with automatic step caching.
|
|
194
192
|
|
|
195
193
|
Workflows consist of two parts:
|
|
194
|
+
|
|
196
195
|
1. **Workflow endpoint** - Created with `serve()`, handles workflow execution
|
|
197
196
|
2. **Client** - Uses `qb.workflows` to trigger and manage workflow runs
|
|
198
197
|
|
|
@@ -213,32 +212,36 @@ export const POST = serve<InputType>(async (context) => {
|
|
|
213
212
|
|
|
214
213
|
**Parameters:**
|
|
215
214
|
|
|
216
|
-
| Parameter | Type
|
|
217
|
-
|
|
215
|
+
| Parameter | Type | Description |
|
|
216
|
+
| --------- | --------------------------------------------- | ---------------------- |
|
|
218
217
|
| `handler` | `(context: WorkflowContext<T>) => Promise<R>` | Your workflow function |
|
|
219
|
-
| `options` | `ServeOptions`
|
|
218
|
+
| `options` | `ServeOptions` | Optional configuration |
|
|
220
219
|
|
|
221
220
|
**Options:**
|
|
222
221
|
|
|
223
|
-
| Option
|
|
224
|
-
|
|
225
|
-
| `signingSecret` | `string` | Secret to verify requests come from QueueBear
|
|
226
|
-
| `baseUrl`
|
|
222
|
+
| Option | Type | Description |
|
|
223
|
+
| --------------- | -------- | ------------------------------------------------------ |
|
|
224
|
+
| `signingSecret` | `string` | Secret to verify requests come from QueueBear |
|
|
225
|
+
| `baseUrl` | `string` | Override QueueBear base URL (auto-detected if not set) |
|
|
227
226
|
|
|
228
227
|
### Framework Integration
|
|
229
228
|
|
|
230
229
|
**Next.js (App Router)**
|
|
230
|
+
|
|
231
231
|
```typescript
|
|
232
232
|
// app/api/workflows/my-workflow/route.ts
|
|
233
233
|
import { serve } from "queuebear";
|
|
234
234
|
|
|
235
235
|
export const POST = serve(async (context) => {
|
|
236
|
-
await context.run("step-1", async () => {
|
|
236
|
+
await context.run("step-1", async () => {
|
|
237
|
+
/* ... */
|
|
238
|
+
});
|
|
237
239
|
return { success: true };
|
|
238
240
|
});
|
|
239
241
|
```
|
|
240
242
|
|
|
241
243
|
**Express**
|
|
244
|
+
|
|
242
245
|
```typescript
|
|
243
246
|
import express from "express";
|
|
244
247
|
import { serve } from "queuebear";
|
|
@@ -247,21 +250,26 @@ const app = express();
|
|
|
247
250
|
app.use(express.json());
|
|
248
251
|
|
|
249
252
|
const handler = serve(async (context) => {
|
|
250
|
-
await context.run("step-1", async () => {
|
|
253
|
+
await context.run("step-1", async () => {
|
|
254
|
+
/* ... */
|
|
255
|
+
});
|
|
251
256
|
return { success: true };
|
|
252
257
|
});
|
|
253
258
|
|
|
254
259
|
app.post("/api/workflows/my-workflow", async (req, res) => {
|
|
255
|
-
const response = await handler(
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
+
const response = await handler(
|
|
261
|
+
new Request(req.url, {
|
|
262
|
+
method: "POST",
|
|
263
|
+
headers: req.headers as HeadersInit,
|
|
264
|
+
body: JSON.stringify(req.body),
|
|
265
|
+
})
|
|
266
|
+
);
|
|
260
267
|
res.status(response.status).json(await response.json());
|
|
261
268
|
});
|
|
262
269
|
```
|
|
263
270
|
|
|
264
271
|
**Hono**
|
|
272
|
+
|
|
265
273
|
```typescript
|
|
266
274
|
import { Hono } from "hono";
|
|
267
275
|
import { serve } from "queuebear";
|
|
@@ -269,7 +277,9 @@ import { serve } from "queuebear";
|
|
|
269
277
|
const app = new Hono();
|
|
270
278
|
|
|
271
279
|
const handler = serve(async (context) => {
|
|
272
|
-
await context.run("step-1", async () => {
|
|
280
|
+
await context.run("step-1", async () => {
|
|
281
|
+
/* ... */
|
|
282
|
+
});
|
|
273
283
|
return { success: true };
|
|
274
284
|
});
|
|
275
285
|
|
|
@@ -292,26 +302,29 @@ interface OnboardingInput {
|
|
|
292
302
|
email: string;
|
|
293
303
|
}
|
|
294
304
|
|
|
295
|
-
export const POST = serve<OnboardingInput>(
|
|
296
|
-
|
|
305
|
+
export const POST = serve<OnboardingInput>(
|
|
306
|
+
async (context) => {
|
|
307
|
+
const { userId, email } = context.input;
|
|
297
308
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
309
|
+
// Step 1: Send welcome email (cached if already done)
|
|
310
|
+
await context.run("send-welcome", async () => {
|
|
311
|
+
await sendEmail(email, "welcome");
|
|
312
|
+
});
|
|
302
313
|
|
|
303
|
-
|
|
304
|
-
|
|
314
|
+
// Step 2: Wait 3 days
|
|
315
|
+
await context.sleep("wait-3-days", 60 * 60 * 24 * 3);
|
|
305
316
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
317
|
+
// Step 3: Send tips email
|
|
318
|
+
await context.run("send-tips", async () => {
|
|
319
|
+
await sendEmail(email, "tips");
|
|
320
|
+
});
|
|
310
321
|
|
|
311
|
-
|
|
312
|
-
},
|
|
313
|
-
|
|
314
|
-
|
|
322
|
+
return { completed: true };
|
|
323
|
+
},
|
|
324
|
+
{
|
|
325
|
+
signingSecret: process.env.QUEUEBEAR_SIGNING_SECRET,
|
|
326
|
+
}
|
|
327
|
+
);
|
|
315
328
|
```
|
|
316
329
|
|
|
317
330
|
### Trigger a Workflow
|
|
@@ -333,7 +346,7 @@ const { runId } = await qb.workflows.trigger(
|
|
|
333
346
|
```typescript
|
|
334
347
|
const status = await qb.workflows.getStatus(runId);
|
|
335
348
|
console.log(status.status); // "running" | "sleeping" | "completed"
|
|
336
|
-
console.log(status.steps);
|
|
349
|
+
console.log(status.steps); // Array of step details
|
|
337
350
|
```
|
|
338
351
|
|
|
339
352
|
### Wait for Completion
|
|
@@ -416,7 +429,7 @@ Make an HTTP call as a cached step.
|
|
|
416
429
|
const data = await context.call("fetch-api", {
|
|
417
430
|
url: "https://api.example.com/data",
|
|
418
431
|
method: "POST",
|
|
419
|
-
headers: {
|
|
432
|
+
headers: { Authorization: "Bearer xxx" },
|
|
420
433
|
body: { key: "value" },
|
|
421
434
|
});
|
|
422
435
|
```
|