zilmate 1.8.1 → 1.9.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 (317) hide show
  1. package/.agents/skills/copywriting/SKILL.md +252 -0
  2. package/.agents/skills/copywriting/evals/evals.json +111 -0
  3. package/.agents/skills/copywriting/references/copy-frameworks.md +344 -0
  4. package/.agents/skills/copywriting/references/natural-transitions.md +272 -0
  5. package/.agents/skills/firecrawl-deep-research/SKILL.md +108 -0
  6. package/.agents/skills/shadcn/SKILL.md +267 -0
  7. package/.agents/skills/shadcn/agents/openai.yml +5 -0
  8. package/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
  9. package/.agents/skills/shadcn/assets/shadcn.png +0 -0
  10. package/.agents/skills/shadcn/cli.md +290 -0
  11. package/.agents/skills/shadcn/customization.md +209 -0
  12. package/.agents/skills/shadcn/evals/evals.json +47 -0
  13. package/.agents/skills/shadcn/mcp.md +105 -0
  14. package/.agents/skills/shadcn/registry.md +277 -0
  15. package/.agents/skills/shadcn/rules/base-vs-radix.md +306 -0
  16. package/.agents/skills/shadcn/rules/composition.md +195 -0
  17. package/.agents/skills/shadcn/rules/forms.md +192 -0
  18. package/.agents/skills/shadcn/rules/icons.md +101 -0
  19. package/.agents/skills/shadcn/rules/styling.md +162 -0
  20. package/.agents/skills/tavily-research/SKILL.md +100 -0
  21. package/.agents/skills/upstash/SKILL.md +48 -0
  22. package/.agents/skills/upstash/upstash-box-js/overview.md +243 -0
  23. package/.agents/skills/upstash/upstash-box-py/overview.md +275 -0
  24. package/.agents/skills/upstash/upstash-cli/overview.md +138 -0
  25. package/.agents/skills/upstash/upstash-qstash-js/advanced/callbacks.md +147 -0
  26. package/.agents/skills/upstash/upstash-qstash-js/advanced/deduplication.md +86 -0
  27. package/.agents/skills/upstash/upstash-qstash-js/advanced/dlq.md +164 -0
  28. package/.agents/skills/upstash/upstash-qstash-js/advanced/multi-region/summary.md +388 -0
  29. package/.agents/skills/upstash/upstash-qstash-js/advanced/multi-region/verify-multi-region-setup.ts +388 -0
  30. package/.agents/skills/upstash/upstash-qstash-js/fundamentals/local-development.md +106 -0
  31. package/.agents/skills/upstash/upstash-qstash-js/fundamentals/publishing-messages.md +144 -0
  32. package/.agents/skills/upstash/upstash-qstash-js/fundamentals/queues-and-flow-control.md +148 -0
  33. package/.agents/skills/upstash/upstash-qstash-js/fundamentals/schedules.md +177 -0
  34. package/.agents/skills/upstash/upstash-qstash-js/fundamentals/url-groups.md +127 -0
  35. package/.agents/skills/upstash/upstash-qstash-js/overview.md +81 -0
  36. package/.agents/skills/upstash/upstash-qstash-js/verification/platform-specific/nextjs.md +171 -0
  37. package/.agents/skills/upstash/upstash-qstash-js/verification/receiver.md +213 -0
  38. package/.agents/skills/upstash/upstash-ratelimit-js/algorithms.md +84 -0
  39. package/.agents/skills/upstash/upstash-ratelimit-js/features.md +117 -0
  40. package/.agents/skills/upstash/upstash-ratelimit-js/methods-getting-started.md +77 -0
  41. package/.agents/skills/upstash/upstash-ratelimit-js/overview.md +26 -0
  42. package/.agents/skills/upstash/upstash-ratelimit-js/pricing-cost.md +146 -0
  43. package/.agents/skills/upstash/upstash-ratelimit-js/traffic-protection.md +77 -0
  44. package/.agents/skills/upstash/upstash-redis-js/advanced-features/auto-pipeline.md +49 -0
  45. package/.agents/skills/upstash/upstash-redis-js/advanced-features/pipeline-and-transactions.md +42 -0
  46. package/.agents/skills/upstash/upstash-redis-js/advanced-features/scripting.md +124 -0
  47. package/.agents/skills/upstash/upstash-redis-js/data-structures/hashes.md +71 -0
  48. package/.agents/skills/upstash/upstash-redis-js/data-structures/json.md +133 -0
  49. package/.agents/skills/upstash/upstash-redis-js/data-structures/lists.md +72 -0
  50. package/.agents/skills/upstash/upstash-redis-js/data-structures/sets.md +90 -0
  51. package/.agents/skills/upstash/upstash-redis-js/data-structures/sorted-sets.md +126 -0
  52. package/.agents/skills/upstash/upstash-redis-js/data-structures/streams.md +196 -0
  53. package/.agents/skills/upstash/upstash-redis-js/data-structures/strings.md +73 -0
  54. package/.agents/skills/upstash/upstash-redis-js/migrations/from-ioredis.md +163 -0
  55. package/.agents/skills/upstash/upstash-redis-js/migrations/from-redis-node.md +205 -0
  56. package/.agents/skills/upstash/upstash-redis-js/overview.md +183 -0
  57. package/.agents/skills/upstash/upstash-redis-js/patterns/caching.md +58 -0
  58. package/.agents/skills/upstash/upstash-redis-js/patterns/distributed-locks.md +130 -0
  59. package/.agents/skills/upstash/upstash-redis-js/patterns/leaderboard.md +134 -0
  60. package/.agents/skills/upstash/upstash-redis-js/patterns/rate-limiting.md +187 -0
  61. package/.agents/skills/upstash/upstash-redis-js/patterns/session-management.md +217 -0
  62. package/.agents/skills/upstash/upstash-redis-js/performance/batching-operations.md +76 -0
  63. package/.agents/skills/upstash/upstash-redis-js/performance/data-serialization.md +134 -0
  64. package/.agents/skills/upstash/upstash-redis-js/performance/error-handling.md +118 -0
  65. package/.agents/skills/upstash/upstash-redis-js/performance/pipeline-optimization.md +105 -0
  66. package/.agents/skills/upstash/upstash-redis-js/performance/redis-replicas.md +14 -0
  67. package/.agents/skills/upstash/upstash-redis-js/performance/ttl-expiration.md +32 -0
  68. package/.agents/skills/upstash/upstash-redis-js/search/adapters.md +99 -0
  69. package/.agents/skills/upstash/upstash-redis-js/search/commands/aggregating.md +234 -0
  70. package/.agents/skills/upstash/upstash-redis-js/search/commands/aliases.md +76 -0
  71. package/.agents/skills/upstash/upstash-redis-js/search/commands/index-management.md +124 -0
  72. package/.agents/skills/upstash/upstash-redis-js/search/commands/querying.md +315 -0
  73. package/.agents/skills/upstash/upstash-redis-js/search/overview.md +155 -0
  74. package/.agents/skills/upstash/upstash-redis-start/overview.md +71 -0
  75. package/.agents/skills/upstash/upstash-search-js/overview.md +48 -0
  76. package/.agents/skills/upstash/upstash-search-js/quick-start.md +158 -0
  77. package/.agents/skills/upstash/upstash-search-js/sdk-overview.md +158 -0
  78. package/.agents/skills/upstash/upstash-vector-js/features/filtering-and-metadata.md +82 -0
  79. package/.agents/skills/upstash/upstash-vector-js/features/index-structure.md +193 -0
  80. package/.agents/skills/upstash/upstash-vector-js/features/namespaces.md +32 -0
  81. package/.agents/skills/upstash/upstash-vector-js/overview.md +44 -0
  82. package/.agents/skills/upstash/upstash-vector-js/sdk-methods.md +210 -0
  83. package/.agents/skills/upstash/upstash-workflow-js/agents.md +248 -0
  84. package/.agents/skills/upstash/upstash-workflow-js/basics/client.md +180 -0
  85. package/.agents/skills/upstash/upstash-workflow-js/basics/context.md +230 -0
  86. package/.agents/skills/upstash/upstash-workflow-js/basics/serve.md +70 -0
  87. package/.agents/skills/upstash/upstash-workflow-js/features/flow-control.md +145 -0
  88. package/.agents/skills/upstash/upstash-workflow-js/features/invoke.md +97 -0
  89. package/.agents/skills/upstash/upstash-workflow-js/features/retries-failures-reliability.md +239 -0
  90. package/.agents/skills/upstash/upstash-workflow-js/features/wait-for-event.md +97 -0
  91. package/.agents/skills/upstash/upstash-workflow-js/features/webhooks.md +79 -0
  92. package/.agents/skills/upstash/upstash-workflow-js/how-to/local-dev.md +177 -0
  93. package/.agents/skills/upstash/upstash-workflow-js/how-to/middleware.md +166 -0
  94. package/.agents/skills/upstash/upstash-workflow-js/how-to/migrations.md +201 -0
  95. package/.agents/skills/upstash/upstash-workflow-js/how-to/realtime.md +186 -0
  96. package/.agents/skills/upstash/upstash-workflow-js/overview.md +55 -0
  97. package/.agents/skills/upstash/upstash-workflow-js/rest-api.md +156 -0
  98. package/.agents/skills/upstash/upstash-workflow-js/troubleshooting.md +201 -0
  99. package/.agents/skills/upstash-box-js/SKILL.md +248 -0
  100. package/.agents/skills/upstash-box-py/SKILL.md +280 -0
  101. package/.agents/skills/upstash-cli/SKILL.md +143 -0
  102. package/.agents/skills/upstash-qstash-js/SKILL.md +86 -0
  103. package/.agents/skills/upstash-qstash-js/advanced/callbacks.md +147 -0
  104. package/.agents/skills/upstash-qstash-js/advanced/deduplication.md +86 -0
  105. package/.agents/skills/upstash-qstash-js/advanced/dlq.md +164 -0
  106. package/.agents/skills/upstash-qstash-js/advanced/multi-region/summary.md +388 -0
  107. package/.agents/skills/upstash-qstash-js/advanced/multi-region/verify-multi-region-setup.ts +388 -0
  108. package/.agents/skills/upstash-qstash-js/fundamentals/local-development.md +106 -0
  109. package/.agents/skills/upstash-qstash-js/fundamentals/publishing-messages.md +144 -0
  110. package/.agents/skills/upstash-qstash-js/fundamentals/queues-and-flow-control.md +148 -0
  111. package/.agents/skills/upstash-qstash-js/fundamentals/schedules.md +177 -0
  112. package/.agents/skills/upstash-qstash-js/fundamentals/url-groups.md +127 -0
  113. package/.agents/skills/upstash-qstash-js/verification/platform-specific/nextjs.md +171 -0
  114. package/.agents/skills/upstash-qstash-js/verification/receiver.md +213 -0
  115. package/.agents/skills/upstash-ratelimit-js/SKILL.md +31 -0
  116. package/.agents/skills/upstash-ratelimit-js/algorithms.md +84 -0
  117. package/.agents/skills/upstash-ratelimit-js/features.md +117 -0
  118. package/.agents/skills/upstash-ratelimit-js/methods-getting-started.md +77 -0
  119. package/.agents/skills/upstash-ratelimit-js/pricing-cost.md +146 -0
  120. package/.agents/skills/upstash-ratelimit-js/traffic-protection.md +77 -0
  121. package/.agents/skills/upstash-redis-js/SKILL.md +188 -0
  122. package/.agents/skills/upstash-redis-js/advanced-features/auto-pipeline.md +49 -0
  123. package/.agents/skills/upstash-redis-js/advanced-features/pipeline-and-transactions.md +42 -0
  124. package/.agents/skills/upstash-redis-js/advanced-features/scripting.md +124 -0
  125. package/.agents/skills/upstash-redis-js/data-structures/hashes.md +71 -0
  126. package/.agents/skills/upstash-redis-js/data-structures/json.md +133 -0
  127. package/.agents/skills/upstash-redis-js/data-structures/lists.md +72 -0
  128. package/.agents/skills/upstash-redis-js/data-structures/sets.md +90 -0
  129. package/.agents/skills/upstash-redis-js/data-structures/sorted-sets.md +126 -0
  130. package/.agents/skills/upstash-redis-js/data-structures/streams.md +196 -0
  131. package/.agents/skills/upstash-redis-js/data-structures/strings.md +73 -0
  132. package/.agents/skills/upstash-redis-js/migrations/from-ioredis.md +163 -0
  133. package/.agents/skills/upstash-redis-js/migrations/from-redis-node.md +205 -0
  134. package/.agents/skills/upstash-redis-js/patterns/caching.md +58 -0
  135. package/.agents/skills/upstash-redis-js/patterns/distributed-locks.md +130 -0
  136. package/.agents/skills/upstash-redis-js/patterns/leaderboard.md +134 -0
  137. package/.agents/skills/upstash-redis-js/patterns/rate-limiting.md +187 -0
  138. package/.agents/skills/upstash-redis-js/patterns/session-management.md +217 -0
  139. package/.agents/skills/upstash-redis-js/performance/batching-operations.md +76 -0
  140. package/.agents/skills/upstash-redis-js/performance/data-serialization.md +134 -0
  141. package/.agents/skills/upstash-redis-js/performance/error-handling.md +118 -0
  142. package/.agents/skills/upstash-redis-js/performance/pipeline-optimization.md +105 -0
  143. package/.agents/skills/upstash-redis-js/performance/redis-replicas.md +14 -0
  144. package/.agents/skills/upstash-redis-js/performance/ttl-expiration.md +32 -0
  145. package/.agents/skills/upstash-redis-js/search/adapters.md +99 -0
  146. package/.agents/skills/upstash-redis-js/search/commands/aggregating.md +234 -0
  147. package/.agents/skills/upstash-redis-js/search/commands/aliases.md +76 -0
  148. package/.agents/skills/upstash-redis-js/search/commands/index-management.md +124 -0
  149. package/.agents/skills/upstash-redis-js/search/commands/querying.md +315 -0
  150. package/.agents/skills/upstash-redis-js/search/overview.md +155 -0
  151. package/.agents/skills/upstash-redis-start/SKILL.md +76 -0
  152. package/.agents/skills/upstash-search-js/SKILL.md +53 -0
  153. package/.agents/skills/upstash-search-js/quick-start.md +158 -0
  154. package/.agents/skills/upstash-search-js/sdk-overview.md +158 -0
  155. package/.agents/skills/upstash-vector-js/SKILL.md +49 -0
  156. package/.agents/skills/upstash-vector-js/features/filtering-and-metadata.md +82 -0
  157. package/.agents/skills/upstash-vector-js/features/index-structure.md +193 -0
  158. package/.agents/skills/upstash-vector-js/features/namespaces.md +32 -0
  159. package/.agents/skills/upstash-vector-js/sdk-methods.md +210 -0
  160. package/.agents/skills/upstash-workflow-js/SKILL.md +60 -0
  161. package/.agents/skills/upstash-workflow-js/agents.md +248 -0
  162. package/.agents/skills/upstash-workflow-js/basics/client.md +180 -0
  163. package/.agents/skills/upstash-workflow-js/basics/context.md +230 -0
  164. package/.agents/skills/upstash-workflow-js/basics/serve.md +70 -0
  165. package/.agents/skills/upstash-workflow-js/features/flow-control.md +145 -0
  166. package/.agents/skills/upstash-workflow-js/features/invoke.md +97 -0
  167. package/.agents/skills/upstash-workflow-js/features/retries-failures-reliability.md +239 -0
  168. package/.agents/skills/upstash-workflow-js/features/wait-for-event.md +97 -0
  169. package/.agents/skills/upstash-workflow-js/features/webhooks.md +79 -0
  170. package/.agents/skills/upstash-workflow-js/how-to/local-dev.md +177 -0
  171. package/.agents/skills/upstash-workflow-js/how-to/middleware.md +166 -0
  172. package/.agents/skills/upstash-workflow-js/how-to/migrations.md +201 -0
  173. package/.agents/skills/upstash-workflow-js/how-to/realtime.md +186 -0
  174. package/.agents/skills/upstash-workflow-js/rest-api.md +156 -0
  175. package/.agents/skills/upstash-workflow-js/troubleshooting.md +201 -0
  176. package/dist/agents/coding.agent.d.ts +185 -42
  177. package/dist/agents/coding.agent.d.ts.map +1 -1
  178. package/dist/agents/coding.agent.js +42 -5
  179. package/dist/agents/coding.agent.js.map +1 -1
  180. package/dist/agents/manager.d.ts +216 -41
  181. package/dist/agents/manager.d.ts.map +1 -1
  182. package/dist/agents/manager.js +103 -140
  183. package/dist/agents/manager.js.map +1 -1
  184. package/dist/agents/security.agent.d.ts +3 -3
  185. package/dist/agents/swarm/development/lead.d.ts +3 -0
  186. package/dist/agents/swarm/development/lead.d.ts.map +1 -0
  187. package/dist/agents/swarm/development/lead.js +24 -0
  188. package/dist/agents/swarm/development/lead.js.map +1 -0
  189. package/dist/agents/swarm/main.d.ts +69 -0
  190. package/dist/agents/swarm/main.d.ts.map +1 -1
  191. package/dist/agents/swarm/main.js +65 -11
  192. package/dist/agents/swarm/main.js.map +1 -1
  193. package/dist/agents/swarm/registry.d.ts +2 -1
  194. package/dist/agents/swarm/registry.d.ts.map +1 -1
  195. package/dist/agents/swarm/registry.js +225 -95
  196. package/dist/agents/swarm/registry.js.map +1 -1
  197. package/dist/cli/composer.d.ts.map +1 -1
  198. package/dist/cli/composer.js +85 -30
  199. package/dist/cli/composer.js.map +1 -1
  200. package/dist/cli/confirm.d.ts +2 -2
  201. package/dist/cli/confirm.d.ts.map +1 -1
  202. package/dist/cli/confirm.js +373 -4
  203. package/dist/cli/confirm.js.map +1 -1
  204. package/dist/cli/doctor.d.ts +1 -0
  205. package/dist/cli/doctor.d.ts.map +1 -1
  206. package/dist/cli/doctor.js +47 -2
  207. package/dist/cli/doctor.js.map +1 -1
  208. package/dist/cli/format.d.ts +4 -0
  209. package/dist/cli/format.d.ts.map +1 -1
  210. package/dist/cli/format.js +352 -65
  211. package/dist/cli/format.js.map +1 -1
  212. package/dist/cli/interactive.d.ts.map +1 -1
  213. package/dist/cli/interactive.js +80 -2
  214. package/dist/cli/interactive.js.map +1 -1
  215. package/dist/cli/menu.d.ts.map +1 -1
  216. package/dist/cli/menu.js +93 -83
  217. package/dist/cli/menu.js.map +1 -1
  218. package/dist/cli/render.d.ts.map +1 -1
  219. package/dist/cli/render.js +2 -1
  220. package/dist/cli/render.js.map +1 -1
  221. package/dist/cli/setup.d.ts.map +1 -1
  222. package/dist/cli/setup.js +292 -28
  223. package/dist/cli/setup.js.map +1 -1
  224. package/dist/cli/swarm.d.ts.map +1 -1
  225. package/dist/cli/swarm.js +13 -10
  226. package/dist/cli/swarm.js.map +1 -1
  227. package/dist/cli/theme.d.ts +7 -1
  228. package/dist/cli/theme.d.ts.map +1 -1
  229. package/dist/cli/theme.js +4 -16
  230. package/dist/cli/theme.js.map +1 -1
  231. package/dist/cli/tunnel.d.ts +2 -0
  232. package/dist/cli/tunnel.d.ts.map +1 -1
  233. package/dist/cli/tunnel.js +63 -7
  234. package/dist/cli/tunnel.js.map +1 -1
  235. package/dist/cli/update.d.ts.map +1 -1
  236. package/dist/cli/update.js +12 -4
  237. package/dist/cli/update.js.map +1 -1
  238. package/dist/config/env.d.ts +3 -1
  239. package/dist/config/env.d.ts.map +1 -1
  240. package/dist/config/env.js +22 -2
  241. package/dist/config/env.js.map +1 -1
  242. package/dist/config/models.d.ts +1 -0
  243. package/dist/config/models.d.ts.map +1 -1
  244. package/dist/config/models.js +17 -1
  245. package/dist/config/models.js.map +1 -1
  246. package/dist/documents/pdf.d.ts.map +1 -1
  247. package/dist/documents/pdf.js +282 -22
  248. package/dist/documents/pdf.js.map +1 -1
  249. package/dist/documents/slides.d.ts.map +1 -1
  250. package/dist/documents/slides.js +160 -30
  251. package/dist/documents/slides.js.map +1 -1
  252. package/dist/index.js +73 -18
  253. package/dist/index.js.map +1 -1
  254. package/dist/memory/history.js +1 -1
  255. package/dist/observability/doctor.d.ts.map +1 -1
  256. package/dist/observability/doctor.js +3 -0
  257. package/dist/observability/doctor.js.map +1 -1
  258. package/dist/runtime/progress.d.ts +5 -1
  259. package/dist/runtime/progress.d.ts.map +1 -1
  260. package/dist/runtime/progress.js.map +1 -1
  261. package/dist/runtime/swarm.d.ts +1 -1
  262. package/dist/runtime/swarm.d.ts.map +1 -1
  263. package/dist/runtime/swarm.js +19 -3
  264. package/dist/runtime/swarm.js.map +1 -1
  265. package/dist/runtime/tool-utils.d.ts +2 -0
  266. package/dist/runtime/tool-utils.d.ts.map +1 -1
  267. package/dist/runtime/tool-utils.js +91 -0
  268. package/dist/runtime/tool-utils.js.map +1 -1
  269. package/dist/server.js +1 -1
  270. package/dist/server.js.map +1 -1
  271. package/dist/skills/loader.d.ts.map +1 -1
  272. package/dist/skills/loader.js +16 -0
  273. package/dist/skills/loader.js.map +1 -1
  274. package/dist/test-call.d.ts +2 -0
  275. package/dist/test-call.d.ts.map +1 -0
  276. package/dist/test-call.js +29 -0
  277. package/dist/test-call.js.map +1 -0
  278. package/dist/test-manager-call.d.ts +2 -0
  279. package/dist/test-manager-call.d.ts.map +1 -0
  280. package/dist/test-manager-call.js +138 -0
  281. package/dist/test-manager-call.js.map +1 -0
  282. package/dist/test-manager-filtered.d.ts +2 -0
  283. package/dist/test-manager-filtered.d.ts.map +1 -0
  284. package/dist/test-manager-filtered.js +130 -0
  285. package/dist/test-manager-filtered.js.map +1 -0
  286. package/dist/test-mcp-call.d.ts +2 -0
  287. package/dist/test-mcp-call.d.ts.map +1 -0
  288. package/dist/test-mcp-call.js +103 -0
  289. package/dist/test-mcp-call.js.map +1 -0
  290. package/dist/tools/composio.tool.d.ts +1 -1
  291. package/dist/tools/composio.tool.d.ts.map +1 -1
  292. package/dist/tools/composio.tool.js +7 -16
  293. package/dist/tools/composio.tool.js.map +1 -1
  294. package/dist/tools/executive.tool.d.ts +40 -0
  295. package/dist/tools/executive.tool.d.ts.map +1 -0
  296. package/dist/tools/executive.tool.js +74 -0
  297. package/dist/tools/executive.tool.js.map +1 -0
  298. package/dist/tools/filesystem.tool.d.ts +183 -40
  299. package/dist/tools/filesystem.tool.d.ts.map +1 -1
  300. package/dist/tools/filesystem.tool.js +564 -111
  301. package/dist/tools/filesystem.tool.js.map +1 -1
  302. package/dist/tools/mcp.tool.d.ts +56 -0
  303. package/dist/tools/mcp.tool.d.ts.map +1 -0
  304. package/dist/tools/mcp.tool.js +285 -0
  305. package/dist/tools/mcp.tool.js.map +1 -0
  306. package/dist/tools/osint.tool.d.ts +4 -4
  307. package/dist/tools/pentest.tool.d.ts +2 -2
  308. package/dist/tools/setup-assistant.tool.d.ts +1 -1
  309. package/dist/tools/setup-assistant.tool.js +1 -1
  310. package/dist/tools/setup-assistant.tool.js.map +1 -1
  311. package/dist/workspace/paths.d.ts +1 -0
  312. package/dist/workspace/paths.d.ts.map +1 -1
  313. package/dist/workspace/paths.js +3 -4
  314. package/dist/workspace/paths.js.map +1 -1
  315. package/package.json +6 -3
  316. package/scripts/postinstall.mjs +19 -4
  317. package/scripts/release-github.mjs +13 -11
@@ -0,0 +1,388 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-disable @typescript-eslint/no-magic-numbers */
3
+ /* eslint-disable no-console */
4
+
5
+ /**
6
+ * Script to verify QStash environment variable setup
7
+ *
8
+ * This script checks:
9
+ * - Whether the setup is single-region or multi-region
10
+ * - Which region will be used for outgoing messages
11
+ * - Whether all required environment variables are present
12
+ *
13
+ * Usage:
14
+ * npx tsx skills/advanced/scripts/verify-multi-region-setup.ts
15
+ * # or with node
16
+ * node skills/advanced/scripts/verify-multi-region-setup.js
17
+ *
18
+ * To load from .env file, install dotenv first:
19
+ * npm install dotenv
20
+ * npx tsx -r dotenv/config skills/advanced/scripts/verify-multi-region-setup.ts
21
+ */
22
+
23
+ // // Try to load dotenv if available
24
+ try {
25
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-require-imports, unicorn/prefer-module
26
+ require("dotenv").config();
27
+ } catch {
28
+ // dotenv not available, will use process.env directly
29
+ }
30
+
31
+ type QStashRegion = "EU_CENTRAL_1" | "US_EAST_1";
32
+
33
+ const VALID_REGIONS = ["EU_CENTRAL_1", "US_EAST_1"] as const;
34
+ const DEFAULT_QSTASH_URL = "https://qstash.upstash.io";
35
+
36
+ type CheckResult = {
37
+ status: "success" | "warning" | "error";
38
+ message: string;
39
+ };
40
+
41
+ type VerificationResult = {
42
+ mode: "single-region" | "multi-region";
43
+ primaryRegion?: QStashRegion;
44
+ checks: CheckResult[];
45
+ outgoingConfig: {
46
+ url?: string;
47
+ token?: string;
48
+ source: string;
49
+ };
50
+ incomingConfig: {
51
+ currentKey?: string;
52
+ nextKey?: string;
53
+ source: string;
54
+ };
55
+ };
56
+
57
+ // Colors for terminal output
58
+ const colors = {
59
+ reset: "\u001B[0m",
60
+ bright: "\u001B[1m",
61
+ red: "\u001B[31m",
62
+ green: "\u001B[32m",
63
+ yellow: "\u001B[33m",
64
+ blue: "\u001B[34m",
65
+ cyan: "\u001B[36m",
66
+ };
67
+
68
+ function colorize(color: keyof typeof colors, text: string): string {
69
+ return `${colors[color]}${text}${colors.reset}`;
70
+ }
71
+
72
+ function printHeader(text: string): void {
73
+ console.log("\n" + colorize("bright", colorize("cyan", text)));
74
+ console.log(colorize("cyan", "=".repeat(text.length)));
75
+ }
76
+
77
+ function printCheck(result: CheckResult): void {
78
+ const icon = result.status === "success" ? "✓" : result.status === "warning" ? "⚠" : "✗";
79
+ const color =
80
+ result.status === "success" ? "green" : result.status === "warning" ? "yellow" : "red";
81
+ console.log(`${colorize(color, icon)} ${result.message}`);
82
+ }
83
+
84
+ function normalizeRegion(region: string | undefined): QStashRegion | undefined {
85
+ if (!region) return undefined;
86
+
87
+ const normalized = region.replaceAll("-", "_").toUpperCase();
88
+ if (VALID_REGIONS.includes(normalized as QStashRegion)) {
89
+ return normalized as QStashRegion;
90
+ }
91
+
92
+ return undefined;
93
+ }
94
+
95
+ function checkEnvironmentVariable(name: string, required = false): CheckResult {
96
+ const value = process.env[name];
97
+
98
+ if (!value) {
99
+ return {
100
+ status: required ? "error" : "warning",
101
+ message: `${name} is ${required ? "required but " : ""}not set`,
102
+ };
103
+ }
104
+
105
+ const maskedValue = value.length > 10 ? `${value.slice(0, 4)}...${value.slice(-4)}` : "***";
106
+ return {
107
+ status: "success",
108
+ message: `${name} = ${maskedValue}`,
109
+ };
110
+ }
111
+
112
+ function verifySetup(): VerificationResult {
113
+ const checks: CheckResult[] = [];
114
+ const qstashRegion = process.env.QSTASH_REGION;
115
+ const normalizedRegion = normalizeRegion(qstashRegion);
116
+
117
+ // Determine mode
118
+ const mode = normalizedRegion ? "multi-region" : "single-region";
119
+ const primaryRegion = normalizedRegion;
120
+
121
+ printHeader("QStash Environment Verification");
122
+
123
+ // Check mode
124
+ if (mode === "multi-region" && primaryRegion) {
125
+ console.log(colorize("bright", `\nMode: `) + colorize("green", "Multi-Region"));
126
+ console.log(colorize("bright", `Primary Region: `) + colorize("green", primaryRegion));
127
+ } else {
128
+ console.log(colorize("bright", `\nMode: `) + colorize("blue", "Single-Region (Default)"));
129
+ if (qstashRegion && !normalizedRegion) {
130
+ checks.push({
131
+ status: "error",
132
+ message: `Invalid QSTASH_REGION="${qstashRegion}". Valid values: ${VALID_REGIONS.join(", ")}`,
133
+ });
134
+ }
135
+ }
136
+
137
+ let outgoingUrl: string | undefined;
138
+ let outgoingToken: string | undefined;
139
+ let outgoingSource: string;
140
+
141
+ if (mode === "multi-region" && primaryRegion) {
142
+ // Multi-region mode
143
+ const regionUrl = process.env[`${primaryRegion}_QSTASH_URL`];
144
+ const regionToken = process.env[`${primaryRegion}_QSTASH_TOKEN`];
145
+
146
+ if (regionUrl && regionToken) {
147
+ outgoingUrl = regionUrl;
148
+ outgoingToken = regionToken;
149
+ outgoingSource = `${primaryRegion}_QSTASH_*`;
150
+
151
+ checks.push(
152
+ {
153
+ status: "success",
154
+ message: `Using ${primaryRegion} credentials`,
155
+ },
156
+ checkEnvironmentVariable(`${primaryRegion}_QSTASH_URL`, true),
157
+ checkEnvironmentVariable(`${primaryRegion}_QSTASH_TOKEN`, true)
158
+ );
159
+ } else {
160
+ // In multi-region mode, missing region-specific credentials is an error
161
+ checks.push({
162
+ status: "error",
163
+ message: `${primaryRegion} credentials required in multi-region mode`,
164
+ });
165
+
166
+ if (!regionUrl) {
167
+ checks.push(checkEnvironmentVariable(`${primaryRegion}_QSTASH_URL`, true));
168
+ }
169
+ if (!regionToken) {
170
+ checks.push(checkEnvironmentVariable(`${primaryRegion}_QSTASH_TOKEN`, true));
171
+ }
172
+
173
+ // Still set fallback values for summary display
174
+ outgoingUrl = process.env.QSTASH_URL ?? DEFAULT_QSTASH_URL;
175
+ outgoingToken = process.env.QSTASH_TOKEN;
176
+ outgoingSource = "QSTASH_* (fallback - ERROR)";
177
+ }
178
+ } else {
179
+ // Single-region mode
180
+ outgoingUrl = process.env.QSTASH_URL ?? DEFAULT_QSTASH_URL;
181
+ outgoingToken = process.env.QSTASH_TOKEN;
182
+ outgoingSource = "QSTASH_*";
183
+
184
+ checks.push(
185
+ checkEnvironmentVariable("QSTASH_URL", false),
186
+ checkEnvironmentVariable("QSTASH_TOKEN", true)
187
+ );
188
+ }
189
+
190
+ let currentKey: string | undefined;
191
+ let nextKey: string | undefined;
192
+ let incomingSource: string;
193
+
194
+ if (mode === "multi-region" && primaryRegion) {
195
+ // In multi-region mode, check for region-specific keys
196
+ const usCurrentKey = process.env.US_EAST_1_QSTASH_CURRENT_SIGNING_KEY;
197
+ const usNextKey = process.env.US_EAST_1_QSTASH_NEXT_SIGNING_KEY;
198
+ const euCurrentKey = process.env.EU_CENTRAL_1_QSTASH_CURRENT_SIGNING_KEY;
199
+ const euNextKey = process.env.EU_CENTRAL_1_QSTASH_NEXT_SIGNING_KEY;
200
+
201
+ const hasUsKeys = usCurrentKey && usNextKey;
202
+ const hasEuKeys = euCurrentKey && euNextKey;
203
+
204
+ if (hasUsKeys && hasEuKeys) {
205
+ checks.push(
206
+ {
207
+ status: "success",
208
+ message: "Region-specific signing keys configured for both US and EU",
209
+ },
210
+ checkEnvironmentVariable("US_EAST_1_QSTASH_CURRENT_SIGNING_KEY", false),
211
+ checkEnvironmentVariable("US_EAST_1_QSTASH_NEXT_SIGNING_KEY", false),
212
+ checkEnvironmentVariable("EU_CENTRAL_1_QSTASH_CURRENT_SIGNING_KEY", false),
213
+ checkEnvironmentVariable("EU_CENTRAL_1_QSTASH_NEXT_SIGNING_KEY", false)
214
+ );
215
+
216
+ currentKey = primaryRegion === "US_EAST_1" ? usCurrentKey : euCurrentKey;
217
+ nextKey = primaryRegion === "US_EAST_1" ? usNextKey : euNextKey;
218
+ incomingSource = "Region-specific keys";
219
+ } else if (hasUsKeys) {
220
+ checks.push(
221
+ {
222
+ status: "warning",
223
+ message: "Only US region signing keys configured",
224
+ },
225
+ checkEnvironmentVariable("US_EAST_1_QSTASH_CURRENT_SIGNING_KEY", false),
226
+ checkEnvironmentVariable("US_EAST_1_QSTASH_NEXT_SIGNING_KEY", false),
227
+ {
228
+ status: "warning",
229
+ message: "EU signing keys not configured - EU messages will attempt to use keys",
230
+ }
231
+ );
232
+
233
+ currentKey = usCurrentKey;
234
+ nextKey = usNextKey;
235
+ incomingSource = "US-specific keys";
236
+ } else if (hasEuKeys) {
237
+ checks.push(
238
+ {
239
+ status: "warning",
240
+ message: "Only EU region signing keys configured",
241
+ },
242
+ checkEnvironmentVariable("EU_CENTRAL_1_QSTASH_CURRENT_SIGNING_KEY", false),
243
+ checkEnvironmentVariable("EU_CENTRAL_1_QSTASH_NEXT_SIGNING_KEY", false),
244
+ {
245
+ status: "warning",
246
+ message: "US signing keys not configured - US messages will attempt to use default keys",
247
+ }
248
+ );
249
+
250
+ currentKey = euCurrentKey;
251
+ nextKey = euNextKey;
252
+ incomingSource = "EU-specific keys";
253
+ } else {
254
+ checks.push({
255
+ status: "warning",
256
+ message: "No region-specific signing keys found, using default keys",
257
+ });
258
+
259
+ currentKey = process.env.QSTASH_CURRENT_SIGNING_KEY;
260
+ nextKey = process.env.QSTASH_NEXT_SIGNING_KEY;
261
+ incomingSource = "QSTASH_* (default)";
262
+
263
+ checks.push(
264
+ checkEnvironmentVariable("QSTASH_CURRENT_SIGNING_KEY", false),
265
+ checkEnvironmentVariable("QSTASH_NEXT_SIGNING_KEY", false)
266
+ );
267
+ }
268
+ } else {
269
+ // Single-region mode
270
+ currentKey = process.env.QSTASH_CURRENT_SIGNING_KEY;
271
+ nextKey = process.env.QSTASH_NEXT_SIGNING_KEY;
272
+ incomingSource = "QSTASH_*";
273
+
274
+ checks.push(
275
+ checkEnvironmentVariable("QSTASH_CURRENT_SIGNING_KEY", false),
276
+ checkEnvironmentVariable("QSTASH_NEXT_SIGNING_KEY", false)
277
+ );
278
+
279
+ if (!currentKey && !nextKey) {
280
+ checks.push({
281
+ status: "warning",
282
+ message:
283
+ "Signing keys not set - incoming message verification will fail if verifier is used",
284
+ });
285
+ }
286
+ }
287
+
288
+ return {
289
+ mode,
290
+ primaryRegion,
291
+ checks,
292
+ outgoingConfig: {
293
+ url: outgoingUrl,
294
+ token: outgoingToken,
295
+ source: outgoingSource,
296
+ },
297
+ incomingConfig: {
298
+ currentKey,
299
+ nextKey,
300
+ source: incomingSource,
301
+ },
302
+ };
303
+ }
304
+
305
+ function printSummary(result: VerificationResult): void {
306
+ console.log(colorize("bright", "\nOutgoing Messages:"));
307
+ console.log(` URL: ${result.outgoingConfig.url ?? "not set"}`);
308
+ console.log(` Token: ${result.outgoingConfig.token ? "✓ configured" : "✗ not set"}`);
309
+ console.log(` Source: ${result.outgoingConfig.source}`);
310
+
311
+ console.log(colorize("bright", "\nIncoming Messages:"));
312
+ console.log(` Current Key: ${result.incomingConfig.currentKey ? "✓ configured" : "✗ not set"}`);
313
+ console.log(` Next Key: ${result.incomingConfig.nextKey ? "✓ configured" : "✗ not set"}`);
314
+ console.log(` Source: ${result.incomingConfig.source}`);
315
+
316
+ printHeader("Verification Results");
317
+
318
+ const errors = result.checks.filter((c) => c.status === "error");
319
+ const warnings = result.checks.filter((c) => c.status === "warning");
320
+ const successes = result.checks.filter((c) => c.status === "success");
321
+
322
+ for (const element of result.checks) {
323
+ printCheck(element);
324
+ }
325
+
326
+ console.log(
327
+ `\n${colorize("bright", "Summary:")} ${colorize("green", `${successes.length} passed`)}, ${colorize("yellow", `${warnings.length} warnings`)}, ${colorize("red", `${errors.length} errors`)}`
328
+ );
329
+
330
+ if (errors.length > 0) {
331
+ console.log(
332
+ colorize("red", "\n✗ Configuration has errors. Please fix them before using QStash.")
333
+ );
334
+ process.exit(1);
335
+ } else if (warnings.length > 0) {
336
+ console.log(
337
+ colorize("yellow", "\n⚠ Configuration has warnings. Review them to ensure proper setup.")
338
+ );
339
+ } else {
340
+ console.log(colorize("green", "\n✓ Configuration looks good!"));
341
+ }
342
+
343
+ // Provide recommendations
344
+ if (result.mode === "multi-region") {
345
+ printHeader("Multi-Region Recommendations");
346
+
347
+ console.log("For optimal multi-region operation:");
348
+ console.log("1. Configure region-specific signing keys for both US and EU");
349
+ console.log("2. Always pass the 'upstashRegion' parameter in receiver.verify()");
350
+ console.log("3. Monitor SDK warnings in your application logs");
351
+ console.log("4. Test message delivery from both regions");
352
+
353
+ console.log(colorize("cyan", "\nExample verification code:"));
354
+ console.log(`
355
+ await receiver.verify({
356
+ signature: request.headers.get("upstash-signature")!,
357
+ body: await request.text(),
358
+ upstashRegion: request.headers.get("upstash-region") ?? undefined,
359
+ });
360
+ `);
361
+ } else {
362
+ printHeader("Recommendations");
363
+
364
+ if (!result.incomingConfig.currentKey || !result.incomingConfig.nextKey) {
365
+ console.log("Consider adding signing keys for incoming message verification:");
366
+ console.log(" QSTASH_CURRENT_SIGNING_KEY=your_current_key");
367
+ console.log(" QSTASH_NEXT_SIGNING_KEY=your_next_key");
368
+ console.log("\nGet keys from: https://console.upstash.com/qstash");
369
+ }
370
+
371
+ if (!process.env.QSTASH_URL) {
372
+ console.log("\nUsing default EU region. To specify a custom URL:");
373
+ console.log(" QSTASH_URL=https://qstash.upstash.io");
374
+ }
375
+ }
376
+ console.log(" Multi-Region: skills/advanced/multi-region.md");
377
+ console.log(" Verification: skills/verification/receiver.md");
378
+ console.log("");
379
+ }
380
+
381
+ // Main execution
382
+ try {
383
+ const result = verifySetup();
384
+ printSummary(result);
385
+ } catch (error) {
386
+ console.error(colorize("red", "\nError running verification:"), error);
387
+ process.exit(1);
388
+ }
@@ -0,0 +1,106 @@
1
+ # Local Development
2
+
3
+ Use the QStash dev server to test publishing and signature verification end-to-end on your machine — no public tunnel, no real QStash account, no real signing keys.
4
+
5
+ ## Automatic dev server (recommended)
6
+
7
+ Pass `devMode: true` to the `Client` (and the matching verifier). The SDK will download the QStash CLI binary, start it, and wire credentials for you.
8
+
9
+ ```typescript
10
+ import { Client } from "@upstash/qstash";
11
+
12
+ const client = new Client({ devMode: true });
13
+
14
+ await client.publishJSON({
15
+ url: "https://example.com/webhook",
16
+ body: { hello: "world" },
17
+ });
18
+ ```
19
+
20
+ When `devMode` is on:
21
+
22
+ - The SDK downloads the latest `qstash` binary on first use, caches it under the OS cache directory, and reuses it across projects.
23
+ - Spawns the dev server on port `8080` (override via `QSTASH_DEV_PORT`).
24
+ - Reuses an already-running server on the configured port instead of spawning a duplicate.
25
+ - Injects deterministic dev `baseUrl`, `token`, and signing keys. **Any explicit `token` / `baseUrl` / signing keys you pass are ignored** (a warning is printed). To use real credentials, set `devMode: false`.
26
+ - Forwards dev server logs to stdout/stderr with a dim `[QStash CLI]` prefix.
27
+ - No-ops in production (`NODE_ENV=production`), during `next build`, and in browser/edge runtimes.
28
+
29
+ ### Environment variable
30
+
31
+ Instead of hard-coding `devMode: true`, leave the option unset and toggle via env:
32
+
33
+ ```bash
34
+ QSTASH_DEV=true # or "1"
35
+ QSTASH_DEV_PORT=8080 # optional, default 8080
36
+ ```
37
+
38
+ The resolution order is: explicit `devMode` boolean > `QSTASH_DEV` env var > off. Use this so production code never accidentally turns the dev server on.
39
+
40
+ ### Verifying signatures in dev
41
+
42
+ The receiving side also needs `devMode: true` so it verifies against the dev server's deterministic signing keys instead of your real ones.
43
+
44
+ ```typescript
45
+ import { Receiver } from "@upstash/qstash";
46
+
47
+ const receiver = new Receiver({ devMode: true });
48
+
49
+ await receiver.verify({
50
+ signature: request.headers.get("upstash-signature")!,
51
+ body: await request.text(),
52
+ });
53
+ ```
54
+
55
+ For Next.js, the wrappers accept the same flag:
56
+
57
+ ```typescript
58
+ // app/api/webhook/route.ts
59
+ import { verifySignatureAppRouter } from "@upstash/qstash/nextjs";
60
+
61
+ export const POST = verifySignatureAppRouter(
62
+ async (request) => new Response("ok"),
63
+ { devMode: true }
64
+ );
65
+ ```
66
+
67
+ ### Next.js: starting the server before edge routes
68
+
69
+ Edge runtimes cannot spawn child processes. If a route in the Edge Runtime is the first thing to use QStash, the SDK can only check whether the server is reachable — it cannot start it. Call `registerQStashDev()` from `instrumentation.ts` to spawn the server during Next.js startup, before any request hits:
70
+
71
+ ```typescript
72
+ // instrumentation.ts
73
+ import { registerQStashDev } from "@upstash/qstash/nextjs";
74
+
75
+ export function register() {
76
+ registerQStashDev();
77
+ }
78
+ ```
79
+
80
+ `registerQStashDev` is itself a no-op in production and during `next build`.
81
+
82
+ ### Common pitfalls
83
+
84
+ - **Passing `token` alongside `devMode: true`** — the explicit token is ignored and you get a console warning. Drop the `token` field, or set `devMode: false` to use it.
85
+ - **Hitting build-time errors in `next build`** — if a route module is evaluated at build time and instantiates the `Client`, mark the route `export const dynamic = "force-dynamic"` so it isn't pre-rendered.
86
+ - **Port 8080 already in use** — the SDK errors with a clear message; either stop the other process or set `QSTASH_DEV_PORT` to a free port (matched on both client and receiver sides).
87
+ - **Calling QStash from an edge route without `instrumentation.ts`** — the edge runtime can't spawn the binary. Either move the call to a Node-runtime route or wire `registerQStashDev()` as shown above.
88
+
89
+ ## Manual dev server
90
+
91
+ If you cannot use the automatic flow (non-Node runtime, CI without internet, custom binary), run the CLI yourself:
92
+
93
+ ```bash
94
+ npx @upstash/qstash-cli dev
95
+ ```
96
+
97
+ Then construct the client with the printed dev credentials explicitly and **leave `devMode` unset/false**:
98
+
99
+ ```typescript
100
+ const client = new Client({
101
+ baseUrl: "http://127.0.0.1:8080",
102
+ token: "eyJVc2VySUQiOiJkZWZhdWx0VXNlciIsIlBhc3N3b3JkIjoiZGVmYXVsdFBhc3N3b3JkIn0=",
103
+ });
104
+ ```
105
+
106
+ See the [Local Development docs](https://upstash.com/docs/qstash/howto/local-development) for the full list of test users and CLI options.
@@ -0,0 +1,144 @@
1
+ # Publishing Messages
2
+
3
+ Publish HTTP messages to destinations using the QStash SDK. Messages are delivered asynchronously with built-in retries and monitoring.
4
+
5
+ ## Basic Publishing
6
+
7
+ ### publishJSON()
8
+
9
+ ```typescript
10
+ import { Client } from "@upstash/qstash";
11
+
12
+ const client = new Client({ token: process.env.QSTASH_TOKEN! });
13
+
14
+ const result = await client.publishJSON({
15
+ url: "https://api.example.com/webhook",
16
+ body: { userId: "123", event: "order.completed" },
17
+ });
18
+
19
+ console.log(result.messageId); // "msg_123..."
20
+ ```
21
+
22
+ ## Destination Options
23
+
24
+ Specify where to send the message using one of these mutually exclusive options:
25
+
26
+ ```typescript
27
+ await client.publishJSON({
28
+ // Send to a single HTTP endpoint:
29
+ url: "https://api.example.com/webhook",
30
+ // Send to all endpoints in a URL group. Creates one message per endpoint:
31
+ // Learn more in [URL Groups](url-groups.md).
32
+ urlGroup: "my-api-group",
33
+ // ...
34
+ });
35
+ ```
36
+
37
+ ## Message Options
38
+
39
+ ```typescript
40
+ // JSON object
41
+ await client.publishJSON({
42
+ url: "https://api.example.com/webhook",
43
+ // The message payload
44
+ body: { order_id: "123", items: [1, 2, 3] },
45
+ // Send to a FIFO queue for ordered processing:
46
+ // Learn more in [Queues and Flow Control](queues-and-flow-control.md).
47
+ queueName: "my-fifo-queue",
48
+ // Send with a flow control key to limit rate/parallelism:
49
+ flowControl: {
50
+ key: "user-123",
51
+ parallelism: 2,
52
+ rate: 10,
53
+ period: 60,
54
+ },
55
+ // request headers
56
+ headers: {
57
+ "Content-Type": "application/json",
58
+ "X-Custom-Header": "value",
59
+ Authorization: "Bearer token", // auth token for the destination
60
+ },
61
+ // request method
62
+ method: "PUT",
63
+ // Delay message delivery by a duration in seconds:
64
+ delay: 60,
65
+ // alternative of delay, deliver at a specific Unix timestamp in seconds:
66
+ notBefore: 1700000000,
67
+ // retries
68
+ retries: 10,
69
+ // Customize the delay between retries using a mathematical expression.
70
+ // Default is exponential backoff.
71
+ // Supported functions: `pow`, `sqrt`, `abs`, `exp`, `floor`, `ceil`, `round`, `min`, `max`.
72
+ retryDelay: "5000",
73
+ // Maximum duration for the HTTP request in seconds:
74
+ timeout: 15,
75
+ // URL called if the message is successfully delivered:
76
+ callback: "https://api.example.com/qstash-callback",
77
+ // URL called only when all retries are exhausted:
78
+ failureCallback: "https://api.example.com/failure-handler",
79
+ // id for deduplicating messages
80
+ deduplicationId: "custom-id-123",
81
+ // enable content-based deduplication
82
+ contentBasedDeduplication: true,
83
+ // label for filtering logs, dlq, cancellation
84
+ label: "order-webhook",
85
+ });
86
+ ```
87
+
88
+ ## Batch Publishing
89
+
90
+ Publish multiple messages in a single request:
91
+
92
+ ```typescript
93
+ const results = await client.batchJSON([
94
+ {
95
+ url: "https://api.example.com/webhook-1",
96
+ body: { event: "first" },
97
+ },
98
+ {
99
+ url: "https://api.example.com/webhook-2",
100
+ body: { event: "second" },
101
+ delay: 60,
102
+ },
103
+ {
104
+ urlGroup: "my-group",
105
+ body: { event: "third" },
106
+ },
107
+ ]);
108
+ ```
109
+
110
+ Each message in the batch can have different options.
111
+
112
+ ## Response Types
113
+
114
+ ### Single URL
115
+
116
+ When publishing to a `url`, response contains:
117
+
118
+ ```typescript
119
+ {
120
+ messageId: string; // Unique message identifier
121
+ url: string; // Destination URL
122
+ deduplicated?: boolean; // true if message was deduplicated
123
+ }
124
+ ```
125
+
126
+ ### URL Group
127
+
128
+ When publishing to a `urlGroup`, response contains an array:
129
+
130
+ ```typescript
131
+ [
132
+ {
133
+ messageId: string;
134
+ url: string; // First endpoint URL
135
+ deduplicated?: boolean;
136
+ },
137
+ {
138
+ messageId: string;
139
+ url: string; // Second endpoint URL
140
+ deduplicated?: boolean;
141
+ },
142
+ // ... one per endpoint
143
+ ]
144
+ ```