zilmate 1.8.0 → 1.8.5
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/.agents/skills/copywriting/SKILL.md +252 -0
- package/.agents/skills/copywriting/evals/evals.json +111 -0
- package/.agents/skills/copywriting/references/copy-frameworks.md +344 -0
- package/.agents/skills/copywriting/references/natural-transitions.md +272 -0
- package/.agents/skills/firecrawl-deep-research/SKILL.md +108 -0
- package/.agents/skills/shadcn/SKILL.md +267 -0
- package/.agents/skills/shadcn/agents/openai.yml +5 -0
- package/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
- package/.agents/skills/shadcn/assets/shadcn.png +0 -0
- package/.agents/skills/shadcn/cli.md +290 -0
- package/.agents/skills/shadcn/customization.md +209 -0
- package/.agents/skills/shadcn/evals/evals.json +47 -0
- package/.agents/skills/shadcn/mcp.md +105 -0
- package/.agents/skills/shadcn/registry.md +277 -0
- package/.agents/skills/shadcn/rules/base-vs-radix.md +306 -0
- package/.agents/skills/shadcn/rules/composition.md +195 -0
- package/.agents/skills/shadcn/rules/forms.md +192 -0
- package/.agents/skills/shadcn/rules/icons.md +101 -0
- package/.agents/skills/shadcn/rules/styling.md +162 -0
- package/.agents/skills/tavily-research/SKILL.md +100 -0
- package/.agents/skills/upstash/SKILL.md +48 -0
- package/.agents/skills/upstash/upstash-box-js/overview.md +243 -0
- package/.agents/skills/upstash/upstash-box-py/overview.md +275 -0
- package/.agents/skills/upstash/upstash-cli/overview.md +138 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/callbacks.md +147 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/deduplication.md +86 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/dlq.md +164 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/multi-region/summary.md +388 -0
- package/.agents/skills/upstash/upstash-qstash-js/advanced/multi-region/verify-multi-region-setup.ts +388 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/local-development.md +106 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/publishing-messages.md +144 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/queues-and-flow-control.md +148 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/schedules.md +177 -0
- package/.agents/skills/upstash/upstash-qstash-js/fundamentals/url-groups.md +127 -0
- package/.agents/skills/upstash/upstash-qstash-js/overview.md +81 -0
- package/.agents/skills/upstash/upstash-qstash-js/verification/platform-specific/nextjs.md +171 -0
- package/.agents/skills/upstash/upstash-qstash-js/verification/receiver.md +213 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/algorithms.md +84 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/features.md +117 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/methods-getting-started.md +77 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/overview.md +26 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/pricing-cost.md +146 -0
- package/.agents/skills/upstash/upstash-ratelimit-js/traffic-protection.md +77 -0
- package/.agents/skills/upstash/upstash-redis-js/advanced-features/auto-pipeline.md +49 -0
- package/.agents/skills/upstash/upstash-redis-js/advanced-features/pipeline-and-transactions.md +42 -0
- package/.agents/skills/upstash/upstash-redis-js/advanced-features/scripting.md +124 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/hashes.md +71 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/json.md +133 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/lists.md +72 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/sets.md +90 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/sorted-sets.md +126 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/streams.md +196 -0
- package/.agents/skills/upstash/upstash-redis-js/data-structures/strings.md +73 -0
- package/.agents/skills/upstash/upstash-redis-js/migrations/from-ioredis.md +163 -0
- package/.agents/skills/upstash/upstash-redis-js/migrations/from-redis-node.md +205 -0
- package/.agents/skills/upstash/upstash-redis-js/overview.md +183 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/caching.md +58 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/distributed-locks.md +130 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/leaderboard.md +134 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/rate-limiting.md +187 -0
- package/.agents/skills/upstash/upstash-redis-js/patterns/session-management.md +217 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/batching-operations.md +76 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/data-serialization.md +134 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/error-handling.md +118 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/pipeline-optimization.md +105 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/redis-replicas.md +14 -0
- package/.agents/skills/upstash/upstash-redis-js/performance/ttl-expiration.md +32 -0
- package/.agents/skills/upstash/upstash-redis-js/search/adapters.md +99 -0
- package/.agents/skills/upstash/upstash-redis-js/search/commands/aggregating.md +234 -0
- package/.agents/skills/upstash/upstash-redis-js/search/commands/aliases.md +76 -0
- package/.agents/skills/upstash/upstash-redis-js/search/commands/index-management.md +124 -0
- package/.agents/skills/upstash/upstash-redis-js/search/commands/querying.md +315 -0
- package/.agents/skills/upstash/upstash-redis-js/search/overview.md +155 -0
- package/.agents/skills/upstash/upstash-redis-start/overview.md +71 -0
- package/.agents/skills/upstash/upstash-search-js/overview.md +48 -0
- package/.agents/skills/upstash/upstash-search-js/quick-start.md +158 -0
- package/.agents/skills/upstash/upstash-search-js/sdk-overview.md +158 -0
- package/.agents/skills/upstash/upstash-vector-js/features/filtering-and-metadata.md +82 -0
- package/.agents/skills/upstash/upstash-vector-js/features/index-structure.md +193 -0
- package/.agents/skills/upstash/upstash-vector-js/features/namespaces.md +32 -0
- package/.agents/skills/upstash/upstash-vector-js/overview.md +44 -0
- package/.agents/skills/upstash/upstash-vector-js/sdk-methods.md +210 -0
- package/.agents/skills/upstash/upstash-workflow-js/agents.md +248 -0
- package/.agents/skills/upstash/upstash-workflow-js/basics/client.md +180 -0
- package/.agents/skills/upstash/upstash-workflow-js/basics/context.md +230 -0
- package/.agents/skills/upstash/upstash-workflow-js/basics/serve.md +70 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/flow-control.md +145 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/invoke.md +97 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/retries-failures-reliability.md +239 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/wait-for-event.md +97 -0
- package/.agents/skills/upstash/upstash-workflow-js/features/webhooks.md +79 -0
- package/.agents/skills/upstash/upstash-workflow-js/how-to/local-dev.md +177 -0
- package/.agents/skills/upstash/upstash-workflow-js/how-to/middleware.md +166 -0
- package/.agents/skills/upstash/upstash-workflow-js/how-to/migrations.md +201 -0
- package/.agents/skills/upstash/upstash-workflow-js/how-to/realtime.md +186 -0
- package/.agents/skills/upstash/upstash-workflow-js/overview.md +55 -0
- package/.agents/skills/upstash/upstash-workflow-js/rest-api.md +156 -0
- package/.agents/skills/upstash/upstash-workflow-js/troubleshooting.md +201 -0
- package/.agents/skills/upstash-box-js/SKILL.md +248 -0
- package/.agents/skills/upstash-box-py/SKILL.md +280 -0
- package/.agents/skills/upstash-cli/SKILL.md +143 -0
- package/.agents/skills/upstash-qstash-js/SKILL.md +86 -0
- package/.agents/skills/upstash-qstash-js/advanced/callbacks.md +147 -0
- package/.agents/skills/upstash-qstash-js/advanced/deduplication.md +86 -0
- package/.agents/skills/upstash-qstash-js/advanced/dlq.md +164 -0
- package/.agents/skills/upstash-qstash-js/advanced/multi-region/summary.md +388 -0
- package/.agents/skills/upstash-qstash-js/advanced/multi-region/verify-multi-region-setup.ts +388 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/local-development.md +106 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/publishing-messages.md +144 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/queues-and-flow-control.md +148 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/schedules.md +177 -0
- package/.agents/skills/upstash-qstash-js/fundamentals/url-groups.md +127 -0
- package/.agents/skills/upstash-qstash-js/verification/platform-specific/nextjs.md +171 -0
- package/.agents/skills/upstash-qstash-js/verification/receiver.md +213 -0
- package/.agents/skills/upstash-ratelimit-js/SKILL.md +31 -0
- package/.agents/skills/upstash-ratelimit-js/algorithms.md +84 -0
- package/.agents/skills/upstash-ratelimit-js/features.md +117 -0
- package/.agents/skills/upstash-ratelimit-js/methods-getting-started.md +77 -0
- package/.agents/skills/upstash-ratelimit-js/pricing-cost.md +146 -0
- package/.agents/skills/upstash-ratelimit-js/traffic-protection.md +77 -0
- package/.agents/skills/upstash-redis-js/SKILL.md +188 -0
- package/.agents/skills/upstash-redis-js/advanced-features/auto-pipeline.md +49 -0
- package/.agents/skills/upstash-redis-js/advanced-features/pipeline-and-transactions.md +42 -0
- package/.agents/skills/upstash-redis-js/advanced-features/scripting.md +124 -0
- package/.agents/skills/upstash-redis-js/data-structures/hashes.md +71 -0
- package/.agents/skills/upstash-redis-js/data-structures/json.md +133 -0
- package/.agents/skills/upstash-redis-js/data-structures/lists.md +72 -0
- package/.agents/skills/upstash-redis-js/data-structures/sets.md +90 -0
- package/.agents/skills/upstash-redis-js/data-structures/sorted-sets.md +126 -0
- package/.agents/skills/upstash-redis-js/data-structures/streams.md +196 -0
- package/.agents/skills/upstash-redis-js/data-structures/strings.md +73 -0
- package/.agents/skills/upstash-redis-js/migrations/from-ioredis.md +163 -0
- package/.agents/skills/upstash-redis-js/migrations/from-redis-node.md +205 -0
- package/.agents/skills/upstash-redis-js/patterns/caching.md +58 -0
- package/.agents/skills/upstash-redis-js/patterns/distributed-locks.md +130 -0
- package/.agents/skills/upstash-redis-js/patterns/leaderboard.md +134 -0
- package/.agents/skills/upstash-redis-js/patterns/rate-limiting.md +187 -0
- package/.agents/skills/upstash-redis-js/patterns/session-management.md +217 -0
- package/.agents/skills/upstash-redis-js/performance/batching-operations.md +76 -0
- package/.agents/skills/upstash-redis-js/performance/data-serialization.md +134 -0
- package/.agents/skills/upstash-redis-js/performance/error-handling.md +118 -0
- package/.agents/skills/upstash-redis-js/performance/pipeline-optimization.md +105 -0
- package/.agents/skills/upstash-redis-js/performance/redis-replicas.md +14 -0
- package/.agents/skills/upstash-redis-js/performance/ttl-expiration.md +32 -0
- package/.agents/skills/upstash-redis-js/search/adapters.md +99 -0
- package/.agents/skills/upstash-redis-js/search/commands/aggregating.md +234 -0
- package/.agents/skills/upstash-redis-js/search/commands/aliases.md +76 -0
- package/.agents/skills/upstash-redis-js/search/commands/index-management.md +124 -0
- package/.agents/skills/upstash-redis-js/search/commands/querying.md +315 -0
- package/.agents/skills/upstash-redis-js/search/overview.md +155 -0
- package/.agents/skills/upstash-redis-start/SKILL.md +76 -0
- package/.agents/skills/upstash-search-js/SKILL.md +53 -0
- package/.agents/skills/upstash-search-js/quick-start.md +158 -0
- package/.agents/skills/upstash-search-js/sdk-overview.md +158 -0
- package/.agents/skills/upstash-vector-js/SKILL.md +49 -0
- package/.agents/skills/upstash-vector-js/features/filtering-and-metadata.md +82 -0
- package/.agents/skills/upstash-vector-js/features/index-structure.md +193 -0
- package/.agents/skills/upstash-vector-js/features/namespaces.md +32 -0
- package/.agents/skills/upstash-vector-js/sdk-methods.md +210 -0
- package/.agents/skills/upstash-workflow-js/SKILL.md +60 -0
- package/.agents/skills/upstash-workflow-js/agents.md +248 -0
- package/.agents/skills/upstash-workflow-js/basics/client.md +180 -0
- package/.agents/skills/upstash-workflow-js/basics/context.md +230 -0
- package/.agents/skills/upstash-workflow-js/basics/serve.md +70 -0
- package/.agents/skills/upstash-workflow-js/features/flow-control.md +145 -0
- package/.agents/skills/upstash-workflow-js/features/invoke.md +97 -0
- package/.agents/skills/upstash-workflow-js/features/retries-failures-reliability.md +239 -0
- package/.agents/skills/upstash-workflow-js/features/wait-for-event.md +97 -0
- package/.agents/skills/upstash-workflow-js/features/webhooks.md +79 -0
- package/.agents/skills/upstash-workflow-js/how-to/local-dev.md +177 -0
- package/.agents/skills/upstash-workflow-js/how-to/middleware.md +166 -0
- package/.agents/skills/upstash-workflow-js/how-to/migrations.md +201 -0
- package/.agents/skills/upstash-workflow-js/how-to/realtime.md +186 -0
- package/.agents/skills/upstash-workflow-js/rest-api.md +156 -0
- package/.agents/skills/upstash-workflow-js/troubleshooting.md +201 -0
- package/dist/agents/coding.agent.d.ts +185 -42
- package/dist/agents/coding.agent.d.ts.map +1 -1
- package/dist/agents/coding.agent.js +42 -5
- package/dist/agents/coding.agent.js.map +1 -1
- package/dist/agents/manager.d.ts +216 -41
- package/dist/agents/manager.d.ts.map +1 -1
- package/dist/agents/manager.js +103 -140
- package/dist/agents/manager.js.map +1 -1
- package/dist/agents/security.agent.d.ts +3 -3
- package/dist/agents/swarm/development/lead.d.ts +3 -0
- package/dist/agents/swarm/development/lead.d.ts.map +1 -0
- package/dist/agents/swarm/development/lead.js +24 -0
- package/dist/agents/swarm/development/lead.js.map +1 -0
- package/dist/agents/swarm/main.d.ts +69 -0
- package/dist/agents/swarm/main.d.ts.map +1 -1
- package/dist/agents/swarm/main.js +65 -11
- package/dist/agents/swarm/main.js.map +1 -1
- package/dist/agents/swarm/registry.d.ts +2 -1
- package/dist/agents/swarm/registry.d.ts.map +1 -1
- package/dist/agents/swarm/registry.js +225 -95
- package/dist/agents/swarm/registry.js.map +1 -1
- package/dist/cli/composer.d.ts.map +1 -1
- package/dist/cli/composer.js +85 -30
- package/dist/cli/composer.js.map +1 -1
- package/dist/cli/confirm.d.ts +2 -2
- package/dist/cli/confirm.d.ts.map +1 -1
- package/dist/cli/confirm.js +373 -4
- package/dist/cli/confirm.js.map +1 -1
- package/dist/cli/doctor.d.ts +1 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +47 -2
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/format.d.ts +4 -0
- package/dist/cli/format.d.ts.map +1 -1
- package/dist/cli/format.js +352 -65
- package/dist/cli/format.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +80 -2
- package/dist/cli/interactive.js.map +1 -1
- package/dist/cli/menu.d.ts.map +1 -1
- package/dist/cli/menu.js +93 -83
- package/dist/cli/menu.js.map +1 -1
- package/dist/cli/render.d.ts.map +1 -1
- package/dist/cli/render.js +2 -1
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +262 -27
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/swarm.d.ts.map +1 -1
- package/dist/cli/swarm.js +13 -10
- package/dist/cli/swarm.js.map +1 -1
- package/dist/cli/theme.d.ts +7 -1
- package/dist/cli/theme.d.ts.map +1 -1
- package/dist/cli/theme.js +4 -16
- package/dist/cli/theme.js.map +1 -1
- package/dist/cli/update.d.ts.map +1 -1
- package/dist/cli/update.js +27 -4
- package/dist/cli/update.js.map +1 -1
- package/dist/config/env.d.ts +3 -1
- package/dist/config/env.d.ts.map +1 -1
- package/dist/config/env.js +22 -2
- package/dist/config/env.js.map +1 -1
- package/dist/config/models.d.ts +1 -0
- package/dist/config/models.d.ts.map +1 -1
- package/dist/config/models.js +17 -1
- package/dist/config/models.js.map +1 -1
- package/dist/documents/pdf.d.ts.map +1 -1
- package/dist/documents/pdf.js +282 -22
- package/dist/documents/pdf.js.map +1 -1
- package/dist/documents/slides.d.ts.map +1 -1
- package/dist/documents/slides.js +160 -30
- package/dist/documents/slides.js.map +1 -1
- package/dist/index.js +73 -18
- package/dist/index.js.map +1 -1
- package/dist/memory/history.js +1 -1
- package/dist/observability/doctor.d.ts.map +1 -1
- package/dist/observability/doctor.js +3 -0
- package/dist/observability/doctor.js.map +1 -1
- package/dist/runtime/progress.d.ts +5 -1
- package/dist/runtime/progress.d.ts.map +1 -1
- package/dist/runtime/progress.js.map +1 -1
- package/dist/runtime/swarm.d.ts +1 -1
- package/dist/runtime/swarm.d.ts.map +1 -1
- package/dist/runtime/swarm.js +19 -3
- package/dist/runtime/swarm.js.map +1 -1
- package/dist/runtime/tool-utils.d.ts +2 -0
- package/dist/runtime/tool-utils.d.ts.map +1 -1
- package/dist/runtime/tool-utils.js +91 -0
- package/dist/runtime/tool-utils.js.map +1 -1
- package/dist/server.js +1 -1
- package/dist/server.js.map +1 -1
- package/dist/skills/loader.d.ts.map +1 -1
- package/dist/skills/loader.js +16 -0
- package/dist/skills/loader.js.map +1 -1
- package/dist/test-call.d.ts +2 -0
- package/dist/test-call.d.ts.map +1 -0
- package/dist/test-call.js +29 -0
- package/dist/test-call.js.map +1 -0
- package/dist/test-manager-call.d.ts +2 -0
- package/dist/test-manager-call.d.ts.map +1 -0
- package/dist/test-manager-call.js +138 -0
- package/dist/test-manager-call.js.map +1 -0
- package/dist/test-manager-filtered.d.ts +2 -0
- package/dist/test-manager-filtered.d.ts.map +1 -0
- package/dist/test-manager-filtered.js +130 -0
- package/dist/test-manager-filtered.js.map +1 -0
- package/dist/test-mcp-call.d.ts +2 -0
- package/dist/test-mcp-call.d.ts.map +1 -0
- package/dist/test-mcp-call.js +103 -0
- package/dist/test-mcp-call.js.map +1 -0
- package/dist/tools/composio.tool.d.ts +1 -1
- package/dist/tools/composio.tool.d.ts.map +1 -1
- package/dist/tools/composio.tool.js +7 -16
- package/dist/tools/composio.tool.js.map +1 -1
- package/dist/tools/daytona-browser.tool.js +1 -1
- package/dist/tools/daytona-browser.tool.js.map +1 -1
- package/dist/tools/executive.tool.d.ts +40 -0
- package/dist/tools/executive.tool.d.ts.map +1 -0
- package/dist/tools/executive.tool.js +74 -0
- package/dist/tools/executive.tool.js.map +1 -0
- package/dist/tools/filesystem.tool.d.ts +183 -40
- package/dist/tools/filesystem.tool.d.ts.map +1 -1
- package/dist/tools/filesystem.tool.js +564 -111
- package/dist/tools/filesystem.tool.js.map +1 -1
- package/dist/tools/mcp.tool.d.ts +56 -0
- package/dist/tools/mcp.tool.d.ts.map +1 -0
- package/dist/tools/mcp.tool.js +285 -0
- package/dist/tools/mcp.tool.js.map +1 -0
- package/dist/tools/osint.tool.d.ts +4 -4
- package/dist/tools/pentest.tool.d.ts +2 -2
- package/dist/tools/setup-assistant.tool.d.ts +1 -1
- package/dist/tools/setup-assistant.tool.js +1 -1
- package/dist/tools/setup-assistant.tool.js.map +1 -1
- package/dist/workspace/paths.d.ts +1 -0
- package/dist/workspace/paths.d.ts.map +1 -1
- package/dist/workspace/paths.js +3 -4
- package/dist/workspace/paths.js.map +1 -1
- package/package.json +8 -4
- package/scripts/postinstall.mjs +19 -4
- package/scripts/release-github.mjs +11 -11
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# Middlewares
|
|
2
|
+
|
|
3
|
+
This guide explains how to intercept workflow lifecycle and debug events using middleware. It covers how to attach middlewares, define event handlers, initialize resources, and combine functionality into efficient implementations.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Middlewares plug into the workflow engine and listen to:
|
|
8
|
+
|
|
9
|
+
- Lifecycle events such as run start, run completion, and step execution
|
|
10
|
+
- Debug messages such as errors, warnings, and informational logs
|
|
11
|
+
|
|
12
|
+
They are useful for logging, monitoring, instrumentation, and integrating with external systems.
|
|
13
|
+
|
|
14
|
+
## Using Built‑in Middleware
|
|
15
|
+
|
|
16
|
+
Add middleware inside the `middlewares` array when serving a workflow:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { serve } from "@upstash/workflow/nextjs";
|
|
20
|
+
import { loggingMiddleware } from "@upstash/workflow";
|
|
21
|
+
|
|
22
|
+
export const { POST } = serve(
|
|
23
|
+
async (ctx) => {
|
|
24
|
+
await ctx.run("step-1", () => "Hello World");
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
middlewares: [loggingMiddleware], // emits run/step logs
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Creating Custom Middleware
|
|
33
|
+
|
|
34
|
+
You define middleware by instantiating `WorkflowMiddleware` with callbacks for the events you want to handle.
|
|
35
|
+
|
|
36
|
+
### Direct Callback Definitions
|
|
37
|
+
|
|
38
|
+
All lifecycle and debug events can be defined in one object.
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
import { WorkflowMiddleware } from "@upstash/workflow";
|
|
42
|
+
|
|
43
|
+
const customMiddleware = new WorkflowMiddleware({
|
|
44
|
+
name: "custom-logger",
|
|
45
|
+
callbacks: {
|
|
46
|
+
// Lifecycle events
|
|
47
|
+
runStarted: async ({ context }) => {
|
|
48
|
+
console.log(`Run ${context.workflowRunId} started`);
|
|
49
|
+
},
|
|
50
|
+
beforeExecution: async ({ context, stepName }) => {
|
|
51
|
+
console.log(`→ Executing step: ${stepName}`);
|
|
52
|
+
},
|
|
53
|
+
afterExecution: async ({ context, stepName, result }) => {
|
|
54
|
+
console.log(`✓ Step ${stepName} completed`, result);
|
|
55
|
+
},
|
|
56
|
+
runCompleted: async ({ context, result }) => {
|
|
57
|
+
console.log(`Run ${context.workflowRunId} finished`, result);
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
// Debug events
|
|
61
|
+
onError: async ({ workflowRunId, error }) => {
|
|
62
|
+
console.error(`Error in ${workflowRunId}`, error);
|
|
63
|
+
},
|
|
64
|
+
onWarning: async ({ workflowRunId, warning }) => {
|
|
65
|
+
console.warn(`Warning from ${workflowRunId}`, warning);
|
|
66
|
+
},
|
|
67
|
+
onInfo: async ({ workflowRunId, info }) => {
|
|
68
|
+
console.info(`Info from ${workflowRunId}`, info);
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Initialization With `init`
|
|
75
|
+
|
|
76
|
+
Use `init` when you need setup logic (connecting to a DB, creating clients, loading configuration). `init` returns an object containing the callbacks.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
import { WorkflowMiddleware } from "@upstash/workflow";
|
|
80
|
+
|
|
81
|
+
const databaseMiddleware = new WorkflowMiddleware({
|
|
82
|
+
name: "database-logger",
|
|
83
|
+
init: async () => {
|
|
84
|
+
const db = await connectToDatabase();
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
runStarted: async ({ context }) => {
|
|
88
|
+
await db.insert({ workflowRunId: context.workflowRunId, status: "started" });
|
|
89
|
+
},
|
|
90
|
+
runCompleted: async ({ context, result }) => {
|
|
91
|
+
await db.update({ workflowRunId: context.workflowRunId, status: "completed", result });
|
|
92
|
+
},
|
|
93
|
+
onError: async ({ workflowRunId, error }) => {
|
|
94
|
+
await db.insert({ workflowRunId, level: "error", message: error.message });
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Event Reference
|
|
102
|
+
|
|
103
|
+
Below is a concise list of supported event handlers and what they receive.
|
|
104
|
+
|
|
105
|
+
### Lifecycle
|
|
106
|
+
|
|
107
|
+
- **runStarted**: `{ context }`
|
|
108
|
+
- **beforeExecution**: `{ context, stepName }`
|
|
109
|
+
- **afterExecution**: `{ context, stepName, result }`
|
|
110
|
+
- **runCompleted**: `{ context, result }`
|
|
111
|
+
|
|
112
|
+
### Debug
|
|
113
|
+
|
|
114
|
+
- **onError**: `{ workflowRunId?, error }`
|
|
115
|
+
- **onWarning**: `{ workflowRunId?, warning }`
|
|
116
|
+
- **onInfo**: `{ workflowRunId?, info }`
|
|
117
|
+
|
|
118
|
+
## Combined Example
|
|
119
|
+
|
|
120
|
+
Single snippet showing typical usage patterns.
|
|
121
|
+
|
|
122
|
+
```ts
|
|
123
|
+
import { serve } from "@upstash/workflow/nextjs";
|
|
124
|
+
import { WorkflowMiddleware } from "@upstash/workflow";
|
|
125
|
+
|
|
126
|
+
// Error tracking
|
|
127
|
+
const errorTrackingMiddleware = new WorkflowMiddleware({
|
|
128
|
+
name: "errors",
|
|
129
|
+
callbacks: {
|
|
130
|
+
onError: async ({ workflowRunId, error }) => {
|
|
131
|
+
await fetch("https://monitoring/errors", {
|
|
132
|
+
method: "POST",
|
|
133
|
+
body: JSON.stringify({ workflowRunId, error: error.message }),
|
|
134
|
+
});
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// Performance measurement
|
|
140
|
+
const timings = new Map();
|
|
141
|
+
const performanceMiddleware = new WorkflowMiddleware({
|
|
142
|
+
name: "perf",
|
|
143
|
+
callbacks: {
|
|
144
|
+
beforeExecution: ({ stepName }) => timings.set(stepName, Date.now()),
|
|
145
|
+
afterExecution: ({ stepName }) => {
|
|
146
|
+
const t = timings.get(stepName);
|
|
147
|
+
if (t) console.log(`Step ${stepName} took ${Date.now() - t}ms`);
|
|
148
|
+
timings.delete(stepName);
|
|
149
|
+
},
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
export const { POST } = serve(
|
|
154
|
+
async (ctx) => {
|
|
155
|
+
await ctx.run("task", () => "done");
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
middlewares: [errorTrackingMiddleware, performanceMiddleware],
|
|
159
|
+
}
|
|
160
|
+
);
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Pitfalls and Tips
|
|
164
|
+
|
|
165
|
+
- Ensure `init` returns all callbacks; missing keys simply mean the event is ignored.
|
|
166
|
+
- Debug events may be called without a `workflowRunId` if errors occur before run id is identified.
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Migration Guide for Upstash Workflow (TypeScript)
|
|
2
|
+
|
|
3
|
+
This document provides a clear, task-focused overview of migrations between Workflow versions. It highlights breaking changes, how to update your code, and common pitfalls to avoid. Code samples combine multiple parameters in each example to reduce redundancy.
|
|
4
|
+
|
|
5
|
+
## January 2026 – Major Release 1.0.0
|
|
6
|
+
|
|
7
|
+
### Agents API → moved to a separate package
|
|
8
|
+
|
|
9
|
+
The Agents API was removed from the core workflow package and placed into `@upstash/workflow-agents` so the base SDK no longer depends on large AI-related libraries.
|
|
10
|
+
|
|
11
|
+
**Key changes**:
|
|
12
|
+
|
|
13
|
+
- Must install and import `agentWorkflow` from the new package.
|
|
14
|
+
- Agents access now happens through an `agents` helper created per workflow invocation.
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
// Before
|
|
18
|
+
import { serve } from "@upstash/workflow/nextjs";
|
|
19
|
+
export const { POST } = serve(async (context) => {
|
|
20
|
+
const model = context.agents.openai("gpt-3.5-turbo");
|
|
21
|
+
const agent = context.agents.agent({
|
|
22
|
+
/* ... */
|
|
23
|
+
});
|
|
24
|
+
const task = context.agents.task({
|
|
25
|
+
/* ... */
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// After
|
|
30
|
+
import { serve } from "@upstash/workflow/nextjs";
|
|
31
|
+
import { agentWorkflow } from "@upstash/workflow-agents";
|
|
32
|
+
export const { POST } = serve(async (context) => {
|
|
33
|
+
const agents = agentWorkflow(context);
|
|
34
|
+
const model = agents.openai("gpt-3.5-turbo");
|
|
35
|
+
const agent = agents.agent({
|
|
36
|
+
/* ... */
|
|
37
|
+
});
|
|
38
|
+
const task = agents.task({
|
|
39
|
+
/* ... */
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
### `keepTriggerConfig` and `useFailureFunction` removed
|
|
47
|
+
|
|
48
|
+
These fields were redundant—both behaviors are now always enabled.
|
|
49
|
+
|
|
50
|
+
```ts
|
|
51
|
+
// Before
|
|
52
|
+
await client.trigger({
|
|
53
|
+
url: "...",
|
|
54
|
+
retries: 3,
|
|
55
|
+
keepTriggerConfig: true,
|
|
56
|
+
useFailureFunction: true,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// After
|
|
60
|
+
await client.trigger({ url: "...", retries: 3 });
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
### Configuration moved from `serve()` → `client.trigger()`
|
|
66
|
+
|
|
67
|
+
Options such as `retries`, `flowControl`, `retryDelay`, and `failureUrl` no longer belong in `serve()`.
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
// Before
|
|
71
|
+
export const { POST } = serve(
|
|
72
|
+
async (context) => {
|
|
73
|
+
/* ... */
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
retries: 3,
|
|
77
|
+
retryDelay: "1000 * (1 + retried)",
|
|
78
|
+
flowControl: { key: "my-key", rate: 10 },
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
await client.trigger({ url: "..." });
|
|
82
|
+
|
|
83
|
+
// After
|
|
84
|
+
export const { POST } = serve(async (context) => {
|
|
85
|
+
/* ... */
|
|
86
|
+
});
|
|
87
|
+
await client.trigger({
|
|
88
|
+
url: "...",
|
|
89
|
+
retries: 3,
|
|
90
|
+
retryDelay: "1000 * (1 + retried)",
|
|
91
|
+
flowControl: { key: "my-key", rate: 10 },
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
### `stringifyBody` removed from `context.call` and `context.invoke`
|
|
98
|
+
|
|
99
|
+
Bodies must now be strings.
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
// Before
|
|
103
|
+
await context.call("step", {
|
|
104
|
+
url: "https://api.example.com",
|
|
105
|
+
method: "POST",
|
|
106
|
+
body: { key: "value" },
|
|
107
|
+
stringifyBody: true,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// After
|
|
111
|
+
await context.call("step", {
|
|
112
|
+
url: "https://api.example.com",
|
|
113
|
+
method: "POST",
|
|
114
|
+
body: JSON.stringify({ key: "value" }),
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Same change applies to invoke
|
|
118
|
+
await context.invoke("other", {
|
|
119
|
+
workflow: otherWorkflow,
|
|
120
|
+
body: JSON.stringify({ key: "value" }),
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
### Logger removed → middleware system added
|
|
127
|
+
|
|
128
|
+
Removed `WorkflowLogger` class and added `WorkflowMiddleware`. Updated `verbose` param to only allow `true` (in this case, `loggingMiddleware` will be used which prints to console).
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { loggingMiddleware, WorkflowMiddleware } from "@upstash/workflow";
|
|
132
|
+
|
|
133
|
+
const stepFinish = new WorkflowMiddleware({
|
|
134
|
+
name: "step-finish",
|
|
135
|
+
callbacks: {
|
|
136
|
+
afterExecution: async ({ stepName, result }) =>
|
|
137
|
+
console.log(`Step ${stepName} finished`, result),
|
|
138
|
+
},
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
export const { POST } = serve(
|
|
142
|
+
async (context) => {
|
|
143
|
+
/* ... */
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
middlewares: [loggingMiddleware, stepFinish],
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## October 2024 – Migration from `@upstash/qstash`
|
|
154
|
+
|
|
155
|
+
### Install the new package
|
|
156
|
+
|
|
157
|
+
Replace all workflow usage from `@upstash/qstash` with `@upstash/workflow`.
|
|
158
|
+
|
|
159
|
+
### Serve import and return shape changed
|
|
160
|
+
|
|
161
|
+
Most environments now require destructuring `{ POST }`.
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
// Before
|
|
165
|
+
import { serve } from "@upstash/qstash/nextjs";
|
|
166
|
+
export const POST = serve(...);
|
|
167
|
+
|
|
168
|
+
// After
|
|
169
|
+
import { serve } from "@upstash/workflow/nextjs";
|
|
170
|
+
export const { POST } = serve(...);
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### `context.call` updated
|
|
174
|
+
|
|
175
|
+
Now returns `{ status, headers, body }` and **does not fail** the workflow if the HTTP call fails.
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
const { status, headers, body } = await context.call("call-step", {
|
|
179
|
+
url: "https://example.com/api",
|
|
180
|
+
method: "POST",
|
|
181
|
+
});
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
**Pitfall**: Old runs may not contain `status` or `headers` until fully migrated.
|
|
185
|
+
|
|
186
|
+
### Errors renamed
|
|
187
|
+
|
|
188
|
+
- `QStashWorkflowError` → `WorkflowError`
|
|
189
|
+
- `QStashWorkflowAbort` → `WorkflowAbort`
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## Summary of Common Mistakes
|
|
194
|
+
|
|
195
|
+
- Using `context.agents` instead of the new `agentWorkflow()` helper.
|
|
196
|
+
- Leaving old serve-config options (`retries`, `flowControl`, etc.).
|
|
197
|
+
- Forgetting to `JSON.stringify` bodies.
|
|
198
|
+
- Assuming `context.call` failures stop workflow execution.
|
|
199
|
+
- Mix-and-matching `@upstash/qstash` and `@upstash/workflow` imports.
|
|
200
|
+
|
|
201
|
+
This guide ensures smooth migration with minimal friction while highlighting where behavioral changes may break existing workflows.
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
# Realtime Workflow Integration (TypeScript)
|
|
2
|
+
|
|
3
|
+
This Skill provides guidance for building real‑time and human‑in‑the‑loop workflows using Upstash Workflow + Upstash Realtime. It covers event schemas, workflow patterns, emitting/receiving updates, and handling interactive pauses.
|
|
4
|
+
|
|
5
|
+
Key capabilities:
|
|
6
|
+
|
|
7
|
+
- Emit strongly typed workflow events.
|
|
8
|
+
- Subscribe to live updates in the frontend.
|
|
9
|
+
- Implement pause/resume workflows using `waitForEvent` and `notify`.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Core Concepts
|
|
14
|
+
|
|
15
|
+
### Realtime schema design
|
|
16
|
+
|
|
17
|
+
Define all workflow event types in one schema. Keep event definitions minimal and stable.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// lib/realtime.ts
|
|
21
|
+
const schema = {
|
|
22
|
+
workflow: {
|
|
23
|
+
// Completion events
|
|
24
|
+
runFinish: z.object({}),
|
|
25
|
+
stepFinish: z.object({ stepName: z.string(), result: z.unknown().optional() }),
|
|
26
|
+
|
|
27
|
+
// Human‑in‑the‑loop events
|
|
28
|
+
waitingForInput: z.object({ eventId: z.string(), message: z.string() }),
|
|
29
|
+
inputResolved: z.object({ eventId: z.string() }),
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const realtime = new Realtime({ schema, redis });
|
|
34
|
+
export type RealtimeEvents = InferRealtimeEvents<typeof realtime>;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Common mistakes:
|
|
38
|
+
|
|
39
|
+
- Forgetting to wrap events under a namespace (e.g. `workflow.*`).
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Emitting Events Inside Workflows
|
|
44
|
+
|
|
45
|
+
Emit inside `context.run()` whenever possible to avoid duplicate emissions on retries.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
// app/api/workflow/route.ts
|
|
49
|
+
export const { POST } = serve(async (context) => {
|
|
50
|
+
const channel = realtime.channel(context.workflowRunId);
|
|
51
|
+
|
|
52
|
+
// Emit step updates
|
|
53
|
+
await context.run("validate", async () => {
|
|
54
|
+
const result = { ok: true };
|
|
55
|
+
await channel.emit("workflow.stepFinish", { stepName: "validate", result });
|
|
56
|
+
return result;
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Final event
|
|
60
|
+
await context.run("finish", () => channel.emit("workflow.runFinish", {}));
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Pitfall:
|
|
65
|
+
|
|
66
|
+
- Emitting events _outside_ of `context.run()` risks duplicate delivery if retries happen.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Human‑in‑the‑Loop Workflows
|
|
71
|
+
|
|
72
|
+
Use `waitForEvent()` with unique `eventId` values and emit a `waitingForInput` event immediately.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
// Step that pauses for human input
|
|
76
|
+
const eventId = `approval-${context.workflowRunId}`;
|
|
77
|
+
|
|
78
|
+
const [{ eventData, timeout }] = await Promise.all([
|
|
79
|
+
context.waitForEvent("wait-for-approval", eventId, { timeout: "5m" }),
|
|
80
|
+
context.run("notify-wait", () =>
|
|
81
|
+
channel.emit("workflow.waitingForInput", {
|
|
82
|
+
eventId,
|
|
83
|
+
message: "Waiting for approval...",
|
|
84
|
+
})
|
|
85
|
+
),
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
if (timeout) return { success: false, reason: "timeout" };
|
|
89
|
+
|
|
90
|
+
await context.run("resolved", () => channel.emit("workflow.inputResolved", { eventId }));
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Important details:
|
|
94
|
+
|
|
95
|
+
- Always handle timeout: otherwise the workflow may appear stuck.
|
|
96
|
+
- Emit `inputResolved` so the UI can clear any pending state.
|
|
97
|
+
- Use deterministic `eventId` prefixes per action/approval.
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Notify Endpoint (User Response)
|
|
102
|
+
|
|
103
|
+
The frontend sends input back to the workflow using `client.notify()`.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
// app/api/notify/route.ts
|
|
107
|
+
export async function POST(req: NextRequest) {
|
|
108
|
+
const { eventId, eventData } = await req.json();
|
|
109
|
+
|
|
110
|
+
await workflowClient.notify({ eventId, eventData }); // resumes workflow
|
|
111
|
+
return NextResponse.json({ success: true });
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Common mistakes:
|
|
116
|
+
|
|
117
|
+
- Sending the wrong `eventId` → workflow never resumes.
|
|
118
|
+
- Sending `eventData` that doesn’t match the awaited type.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Realtime Subscription in the Frontend
|
|
123
|
+
|
|
124
|
+
Use a single hook to consume all workflow‑related events and manage state.
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
// lib/realtime-client.ts & useWorkflow hooks
|
|
128
|
+
useRealtime({
|
|
129
|
+
enabled: !!workflowRunId,
|
|
130
|
+
channels: [workflowRunId],
|
|
131
|
+
events: [
|
|
132
|
+
"workflow.stepFinish",
|
|
133
|
+
"workflow.runFinish",
|
|
134
|
+
"workflow.waitingForInput",
|
|
135
|
+
"workflow.inputResolved",
|
|
136
|
+
],
|
|
137
|
+
onData({ event, data }) {
|
|
138
|
+
switch (event) {
|
|
139
|
+
case "workflow.stepFinish":
|
|
140
|
+
setSteps((prev) => [...prev, data]);
|
|
141
|
+
break;
|
|
142
|
+
case "workflow.waitingForInput":
|
|
143
|
+
setWaitingState(data);
|
|
144
|
+
break;
|
|
145
|
+
case "workflow.inputResolved":
|
|
146
|
+
setWaitingState((prev) => (prev?.eventId === data.eventId ? null : prev));
|
|
147
|
+
break;
|
|
148
|
+
case "workflow.runFinish":
|
|
149
|
+
setIsRunFinished(true);
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Pitfalls:
|
|
156
|
+
|
|
157
|
+
- Forgetting to clear waiting state on `inputResolved`.
|
|
158
|
+
- Forgetting to reset state on re‑trigger.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Triggering the Workflow
|
|
163
|
+
|
|
164
|
+
One simple endpoint triggers both basic and human‑in‑the‑loop flows.
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
// app/api/trigger/route.ts
|
|
168
|
+
export async function POST(req: NextRequest) {
|
|
169
|
+
const workflowUrl = `${req.nextUrl.origin}/api/workflow`; // or /human-in-loop
|
|
170
|
+
const { workflowRunId } = await workflowClient.trigger({
|
|
171
|
+
url: workflowUrl,
|
|
172
|
+
body: { userId: "123", action: "process" },
|
|
173
|
+
});
|
|
174
|
+
return NextResponse.json({ workflowRunId });
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
---
|
|
179
|
+
|
|
180
|
+
## Recommended Patterns
|
|
181
|
+
|
|
182
|
+
- Use one channel per workflow run (`workflowRunId`).
|
|
183
|
+
- Always place event emissions inside `context.run()`.
|
|
184
|
+
- Use stable `eventId` formats for all interactive steps.
|
|
185
|
+
- Subscribe to only the events your UI needs.
|
|
186
|
+
- Reset UI state before every new trigger.
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# Workflow REST API Skill
|
|
2
|
+
|
|
3
|
+
This Skill provides TypeScript-focused guidance for interacting with the Upstash QStash Workflow Dead Letter Queue (DLQ) REST API. It includes practical usage examples, consolidated patterns, and key considerations for safely restarting, resuming, listing, deleting, and inspecting failed workflow runs.
|
|
4
|
+
|
|
5
|
+
The goal is to help agents construct correct TypeScript API requests, handle optional fields, and avoid common pitfalls when working with workflow recovery operations.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Core Concepts
|
|
10
|
+
|
|
11
|
+
• **DLQ Entries** represent failed workflow runs containing metadata such as payload, headers, timestamps, failure callback state, and workflow configuration.
|
|
12
|
+
• **Restart** recreates the entire workflow run from the beginning (fresh execution, no preserved state).
|
|
13
|
+
• **Resume** creates a new run continuing from the failed step (preserves successful steps).
|
|
14
|
+
• **Bulk operations** process up to 50 DLQ entries per request and may return a cursor for pagination.
|
|
15
|
+
• **Flow-Control and Retry Overrides** are passed via headers and apply only to the newly created workflow run.
|
|
16
|
+
|
|
17
|
+
Be careful: changing workflow code **before** the failed step may cause resume operations to break.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# HTTP Endpoints Overview
|
|
22
|
+
|
|
23
|
+
Below is a complete summary of the API endpoints supported by this skill.
|
|
24
|
+
|
|
25
|
+
• `GET /v2/workflows/dlq` — List DLQ entries with filtering.
|
|
26
|
+
• `GET /v2/workflows/dlq/{dlqId}` — Retrieve a single DLQ entry.
|
|
27
|
+
• `DELETE /v2/workflows/dlq/{dlqId}` — Delete a DLQ entry.
|
|
28
|
+
• `POST /v2/workflows/dlq/restart/{dlqId}` — Restart a workflow from scratch.
|
|
29
|
+
• `POST /v2/workflows/dlq/resume/{dlqId}` — Resume a workflow from point of failure.
|
|
30
|
+
• `POST /v2/workflows/dlq/restart` — Bulk restart (up to 50).
|
|
31
|
+
• `POST /v2/workflows/dlq/resume` — Bulk resume (up to 50).
|
|
32
|
+
• `POST /v2/workflows/dlq/callback/{dlqId}` — Rerun a failed failure-callback.
|
|
33
|
+
• `GET /v2/flowControl` and `/v2/flowControl/{key}` — Flow-control inspection.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
# TypeScript Usage Patterns
|
|
38
|
+
|
|
39
|
+
Below is a single integrated example illustrating several endpoints, optional query parameters, header overrides, and response field handling.
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import fetch from "node-fetch";
|
|
43
|
+
|
|
44
|
+
const token = process.env.QSTASH_TOKEN;
|
|
45
|
+
const base = "https://qstash.upstash.io/v2";
|
|
46
|
+
|
|
47
|
+
async function example() {
|
|
48
|
+
// 1. List DLQ items with filters
|
|
49
|
+
const list = await fetch(
|
|
50
|
+
`${base}/workflows/dlq?workflowUrl=https://my.app/workflow&fromDate=1700000000000`,
|
|
51
|
+
{
|
|
52
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
53
|
+
}
|
|
54
|
+
).then((r) => r.json());
|
|
55
|
+
|
|
56
|
+
const firstDlqId = list.messages?.[0]?.dlqId;
|
|
57
|
+
|
|
58
|
+
// 2. Restart or Resume a specific run (headers may override flow control or retries)
|
|
59
|
+
const restart = await fetch(`${base}/workflows/dlq/restart/${firstDlqId}`, {
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers: {
|
|
62
|
+
Authorization: `Bearer ${token}`,
|
|
63
|
+
"Upstash-Flow-Control-Key": "my-key", // optional
|
|
64
|
+
"Upstash-Flow-Control-Value": "parallelism=1", // optional
|
|
65
|
+
"Upstash-Retries": "3", // optional
|
|
66
|
+
},
|
|
67
|
+
}).then((r) => r.json());
|
|
68
|
+
|
|
69
|
+
// 3. Bulk resume using filters and cursor handling
|
|
70
|
+
const bulkResume = await fetch(`${base}/workflows/dlq/resume`, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
73
|
+
body: JSON.stringify({
|
|
74
|
+
fromDate: 1700000000000,
|
|
75
|
+
workflowUrl: "https://my.app/workflow",
|
|
76
|
+
dlqIds: [firstDlqId], // optional; filters also supported
|
|
77
|
+
}),
|
|
78
|
+
}).then((r) => r.json());
|
|
79
|
+
|
|
80
|
+
// 4. Rerun failure callback
|
|
81
|
+
const callback = await fetch(`${base}/workflows/dlq/callback/${firstDlqId}`, {
|
|
82
|
+
method: "POST",
|
|
83
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
84
|
+
}).then((r) => r.json());
|
|
85
|
+
|
|
86
|
+
// 5. Delete a DLQ entry
|
|
87
|
+
await fetch(`${base}/workflows/dlq/${firstDlqId}`, {
|
|
88
|
+
method: "DELETE",
|
|
89
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// 6. Inspect Flow-Control
|
|
93
|
+
const fc = await fetch(`${base}/flowControl/my-key`, {
|
|
94
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
95
|
+
}).then((r) => r.json());
|
|
96
|
+
|
|
97
|
+
console.log({ list, restart, bulkResume, callback, fc });
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
# Key Fields and Behaviors
|
|
104
|
+
|
|
105
|
+
## Request Query Fields
|
|
106
|
+
|
|
107
|
+
• **dlqIds: string[]** — Exact DLQ IDs for targeting specific failed runs (bulk restart/resume).
|
|
108
|
+
• **fromDate / toDate: number** — Millisecond timestamps; inclusive range filters.
|
|
109
|
+
• **workflowUrl: string** — Filters by workflow endpoint URL.
|
|
110
|
+
• **workflowRunId: string** — Can match full run ID or prefix.
|
|
111
|
+
• **workflowCreatedAt: number** — Timestamp filter for creation time.
|
|
112
|
+
• **responseStatus: number** — Filter by HTTP status of failed run.
|
|
113
|
+
• **callerIP: string** — Filter by origin IP.
|
|
114
|
+
• **failureCallbackState: string** — Filter runs whose failure callback succeeded or failed.
|
|
115
|
+
• **cursor: string** — Pagination cursor; returned by list & bulk ops.
|
|
116
|
+
• **count: number** — Limit for listing DLQ entries (default/max 100).
|
|
117
|
+
|
|
118
|
+
## Header Overrides
|
|
119
|
+
|
|
120
|
+
These apply only when creating a **new workflow run** (restart or resume).
|
|
121
|
+
|
|
122
|
+
• **Upstash-Flow-Control-Key** — Override flow-control key.
|
|
123
|
+
• **Upstash-Flow-Control-Value** — Override flow-control config (e.g., "parallelism=1").
|
|
124
|
+
• **Upstash-Retries** — Override step retry configuration.
|
|
125
|
+
|
|
126
|
+
All are optional; original values are reused if omitted.
|
|
127
|
+
|
|
128
|
+
## Response Fields
|
|
129
|
+
|
|
130
|
+
• **cursor?: string** — If returned, additional entries exist.
|
|
131
|
+
• **workflowRuns: { workflowRunId: string; workflowCreatedAt: number }[]** — Returned by bulk restart/resume.
|
|
132
|
+
• **message objects** (DLQ list/get) include:
|
|
133
|
+
|
|
134
|
+
- **workflowRunId, workflowCreatedAt, workflowUrl**
|
|
135
|
+
- **responseStatus, responseHeader, responseBody**
|
|
136
|
+
- **failureCallbackInfo.state** — Identify failed callbacks.
|
|
137
|
+
- **dlqId** — Unique DLQ entry identifier.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
# Pitfalls & Best Practices
|
|
142
|
+
|
|
143
|
+
• **Resume only works if workflow code before the failed step stays unchanged**. Any change may cause resume to fail.
|
|
144
|
+
• **Bulk operations process max 50 items**. Always check `cursor` to continue processing.
|
|
145
|
+
• **Deleting a DLQ entry is permanent**; once removed, it cannot be resumed or restarted.
|
|
146
|
+
• **Failure callback reruns are independent** and do not affect workflow execution. They only retry the failure-notification step.
|
|
147
|
+
• **Prefix matching on workflowRunId** can unintentionally match more runs than expected—use full ID for precision.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
# Recommended Patterns
|
|
152
|
+
|
|
153
|
+
• Fetch → Check cursor → Continue looping for bulk operations.
|
|
154
|
+
• Always log `failureCallbackInfo.state` to determine whether a callback rerun is required.
|
|
155
|
+
• Apply header overrides sparingly; flow-control misconfiguration may stall large batches.
|
|
156
|
+
• Prefer filtering in bulk operations instead of manually passing large dlqIds arrays.
|