nitro 3.0.1-alpha.2 → 3.0.260415-beta

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 (297) hide show
  1. package/LICENSE +6 -0
  2. package/README.md +2 -2
  3. package/dist/THIRD-PARTY-LICENSES.md +1646 -0
  4. package/dist/_build/common.mjs +7261 -3812
  5. package/dist/_build/rolldown.mjs +32 -42
  6. package/dist/_build/rollup.mjs +28 -48
  7. package/dist/_build/vite.build.mjs +10 -10
  8. package/dist/_chunks/nitro.mjs +102 -327
  9. package/dist/_chunks/nitro2.mjs +8 -9
  10. package/dist/_chunks/nitro3.mjs +136 -0
  11. package/dist/_chunks/nitro4.mjs +127 -0
  12. package/dist/_chunks/utils.mjs +40 -29
  13. package/dist/_common.mjs +13 -25
  14. package/dist/_dev.d.mts +0 -3
  15. package/dist/{_chunks/dev.mjs → _dev.mjs} +132 -330
  16. package/dist/_libs/_.mjs +2 -0
  17. package/dist/_libs/_2.mjs +2 -0
  18. package/dist/_libs/_3.mjs +2 -0
  19. package/dist/_libs/_4.mjs +2 -0
  20. package/dist/_libs/_5.mjs +2 -0
  21. package/dist/_libs/_6.mjs +2 -0
  22. package/dist/_libs/_7.mjs +2 -0
  23. package/dist/_libs/c12+rc9.mjs +814 -0
  24. package/dist/_libs/{c12+giget+readdirp+chokidar.d.mts → c12+readdirp+chokidar.d.mts} +49 -40
  25. package/dist/_libs/citty.mjs +142 -41
  26. package/dist/_libs/commondir+is-reference.mjs +60 -56
  27. package/dist/_libs/compatx.d.mts +0 -2
  28. package/dist/_libs/compatx.mjs +1 -4
  29. package/dist/_libs/esbuild.d.mts +0 -1
  30. package/dist/_libs/escape-string-regexp.mjs +1 -4
  31. package/dist/_libs/{pluginutils+plugin-commonjs.d.mts → estree+pluginutils.d.mts} +0 -5
  32. package/dist/_libs/estree-walker.mjs +4 -92
  33. package/dist/_libs/exsolve.d.mts +1 -0
  34. package/dist/_libs/hasown+resolve+deepmerge.mjs +160 -246
  35. package/dist/_libs/httpxy.d.mts +20 -13
  36. package/dist/_libs/httpxy.mjs +519 -95
  37. package/dist/_libs/js-tokens.d.mts +1 -0
  38. package/dist/_libs/klona.mjs +1 -4
  39. package/dist/_libs/magic-string.d.mts +0 -2
  40. package/dist/_libs/mlly.d.mts +0 -2
  41. package/dist/_libs/nypm+tinyexec.mjs +822 -0
  42. package/dist/_libs/perfect-debounce.mjs +68 -0
  43. package/dist/_libs/pkg-types.d.mts +0 -3
  44. package/dist/_libs/plugin-alias.mjs +1 -5
  45. package/dist/_libs/plugin-inject.mjs +1 -7
  46. package/dist/_libs/plugin-json.mjs +1 -5
  47. package/dist/_libs/pluginutils.mjs +3 -35
  48. package/dist/_libs/readdirp+chokidar.mjs +187 -365
  49. package/dist/_libs/remapping.mjs +1 -5
  50. package/dist/_libs/resolve-uri+gen-mapping.mjs +15 -53
  51. package/dist/_libs/rou3.d.mts +1 -4
  52. package/dist/_libs/rou3.mjs +223 -78
  53. package/dist/_libs/std-env.d.mts +8 -2
  54. package/dist/_libs/strip-literal.d.mts +1 -0
  55. package/dist/_libs/tsconfck.mjs +21 -334
  56. package/dist/_libs/ultrahtml.mjs +3 -16
  57. package/dist/_libs/unimport+unplugin.mjs +244 -388
  58. package/dist/_libs/unplugin+unimport.d.mts +5 -15
  59. package/dist/_libs/unwasm.d.mts +0 -3
  60. package/dist/_presets.mjs +576 -488
  61. package/dist/builder.d.mts +5 -25
  62. package/dist/builder.mjs +3 -8
  63. package/dist/cli/_chunks/build.mjs +22 -25
  64. package/dist/cli/_chunks/common.mjs +1 -4
  65. package/dist/cli/_chunks/deploy.mjs +37 -0
  66. package/dist/cli/_chunks/dev.mjs +6 -11
  67. package/dist/cli/_chunks/docs.mjs +28 -0
  68. package/dist/cli/_chunks/list.mjs +4 -8
  69. package/dist/cli/_chunks/prepare.mjs +2 -6
  70. package/dist/cli/_chunks/preview.mjs +48 -0
  71. package/dist/cli/_chunks/run.mjs +7 -11
  72. package/dist/cli/_chunks/task.mjs +1 -5
  73. package/dist/cli/index.mjs +5 -6
  74. package/dist/docs/0.docs/0.index/index.md +56 -0
  75. package/dist/docs/0.docs/1.quick-start.md +110 -0
  76. package/dist/docs/0.docs/10.lifecycle.md +204 -0
  77. package/dist/docs/0.docs/11.openapi.md +291 -0
  78. package/dist/docs/0.docs/12.plugins.md +164 -0
  79. package/dist/docs/0.docs/13.tasks.md +277 -0
  80. package/dist/docs/0.docs/14.websocket.md +386 -0
  81. package/dist/docs/0.docs/15.migration.md +213 -0
  82. package/dist/docs/0.docs/16.nightly.md +31 -0
  83. package/dist/docs/0.docs/2.renderer.md +322 -0
  84. package/dist/docs/0.docs/3.routing.md +711 -0
  85. package/dist/docs/0.docs/4.server-entry.md +239 -0
  86. package/dist/docs/0.docs/5.cache.md +408 -0
  87. package/dist/docs/0.docs/6.storage.md +261 -0
  88. package/dist/docs/0.docs/7.assets.md +166 -0
  89. package/dist/docs/0.docs/8.configuration.md +256 -0
  90. package/dist/docs/0.docs/9.database.md +185 -0
  91. package/dist/docs/1.deploy/0.index/index.md +64 -0
  92. package/dist/docs/1.deploy/1.runtimes/0.node.md +63 -0
  93. package/dist/docs/1.deploy/1.runtimes/1.bun.md +15 -0
  94. package/dist/docs/1.deploy/1.runtimes/2.deno.md +19 -0
  95. package/dist/docs/1.deploy/2.providers/0.alwaysdata.md +50 -0
  96. package/dist/docs/1.deploy/2.providers/1.aws.md +47 -0
  97. package/dist/docs/1.deploy/2.providers/10.flightcontrol.md +67 -0
  98. package/dist/docs/1.deploy/2.providers/11.genezio.md +67 -0
  99. package/dist/docs/1.deploy/2.providers/12.github-pages.md +68 -0
  100. package/dist/docs/1.deploy/2.providers/13.gitlab-pages.md +37 -0
  101. package/dist/docs/1.deploy/2.providers/14.heroku.md +84 -0
  102. package/dist/docs/1.deploy/2.providers/15.iis.md +38 -0
  103. package/dist/docs/1.deploy/2.providers/16.koyeb.md +109 -0
  104. package/dist/docs/1.deploy/2.providers/17.netlify.md +47 -0
  105. package/dist/docs/1.deploy/2.providers/18.platform-sh.md +37 -0
  106. package/dist/docs/1.deploy/2.providers/19.render.md +37 -0
  107. package/dist/docs/1.deploy/2.providers/2.aws-amplify.md +81 -0
  108. package/dist/docs/1.deploy/2.providers/20.stormkit.md +24 -0
  109. package/dist/docs/1.deploy/2.providers/21.vercel.md +270 -0
  110. package/dist/docs/1.deploy/2.providers/22.zeabur.md +19 -0
  111. package/dist/docs/1.deploy/2.providers/23.zephyr.md +99 -0
  112. package/dist/docs/1.deploy/2.providers/24.zerops.md +102 -0
  113. package/dist/docs/1.deploy/2.providers/3.azure.md +72 -0
  114. package/dist/docs/1.deploy/2.providers/4.cleavr.md +33 -0
  115. package/dist/docs/1.deploy/2.providers/5.cloudflare.md +369 -0
  116. package/dist/docs/1.deploy/2.providers/6.deno-deploy.md +66 -0
  117. package/dist/docs/1.deploy/2.providers/7.digitalocean.md +46 -0
  118. package/dist/docs/1.deploy/2.providers/8.edgeone.md +20 -0
  119. package/dist/docs/1.deploy/2.providers/9.firebase.md +32 -0
  120. package/dist/docs/2.config/0.index/index.md +1221 -0
  121. package/dist/docs/3.examples/0.index/index.md +3 -0
  122. package/dist/docs/3.examples/1.api-routes.md +145 -0
  123. package/dist/docs/3.examples/10.hono.md +74 -0
  124. package/dist/docs/3.examples/11.import-alias.md +97 -0
  125. package/dist/docs/3.examples/12.middleware.md +91 -0
  126. package/dist/docs/3.examples/13.mono-jsx.md +68 -0
  127. package/dist/docs/3.examples/14.nano-jsx.md +70 -0
  128. package/dist/docs/3.examples/15.plugins.md +91 -0
  129. package/dist/docs/3.examples/16.renderer.md +113 -0
  130. package/dist/docs/3.examples/17.runtime-config.md +97 -0
  131. package/dist/docs/3.examples/18.server-fetch.md +87 -0
  132. package/dist/docs/3.examples/19.shiki.md +198 -0
  133. package/dist/docs/3.examples/2.auto-imports.md +92 -0
  134. package/dist/docs/3.examples/20.virtual-routes.md +74 -0
  135. package/dist/docs/3.examples/21.vite-nitro-plugin.md +79 -0
  136. package/dist/docs/3.examples/22.vite-rsc.md +1041 -0
  137. package/dist/docs/3.examples/23.vite-ssr-html.md +217 -0
  138. package/dist/docs/3.examples/24.vite-ssr-preact.md +247 -0
  139. package/dist/docs/3.examples/25.vite-ssr-react.md +226 -0
  140. package/dist/docs/3.examples/26.vite-ssr-solid.md +256 -0
  141. package/dist/docs/3.examples/27.vite-ssr-tsr-react.md +442 -0
  142. package/dist/docs/3.examples/28.vite-ssr-tss-react.md +444 -0
  143. package/dist/docs/3.examples/29.vite-ssr-vue-router.md +617 -0
  144. package/dist/docs/3.examples/3.cached-handler.md +81 -0
  145. package/dist/docs/3.examples/30.vite-trpc.md +335 -0
  146. package/dist/docs/3.examples/31.websocket.md +282 -0
  147. package/dist/docs/3.examples/4.custom-error-handler.md +98 -0
  148. package/dist/docs/3.examples/5.database.md +157 -0
  149. package/dist/docs/3.examples/6.elysia.md +70 -0
  150. package/dist/docs/3.examples/7.express.md +78 -0
  151. package/dist/docs/3.examples/8.fastify.md +79 -0
  152. package/dist/docs/3.examples/9.hello-world.md +68 -0
  153. package/dist/docs/README.md +86 -0
  154. package/dist/docs/index.md +121 -0
  155. package/dist/node_modules/@poppinss/dumper/build/formatters/html/main.js +8 -0
  156. package/dist/node_modules/@poppinss/dumper/package.json +1 -1
  157. package/dist/node_modules/@speed-highlight/core/dist/index.js +4 -4
  158. package/dist/node_modules/@speed-highlight/core/dist/terminal.js +2 -2
  159. package/dist/node_modules/@speed-highlight/core/package.json +1 -1
  160. package/dist/node_modules/cookie-es/dist/index.mjs +299 -250
  161. package/dist/node_modules/cookie-es/package.json +26 -23
  162. package/dist/node_modules/croner/dist/croner.js +1 -1
  163. package/dist/node_modules/croner/package.json +11 -1
  164. package/dist/node_modules/defu/dist/defu.mjs +2 -2
  165. package/dist/node_modules/defu/package.json +33 -28
  166. package/dist/node_modules/rendu/dist/_chunks/libs/cookie-es.mjs +151 -0
  167. package/dist/node_modules/rendu/dist/index.mjs +5 -112
  168. package/dist/node_modules/rendu/package.json +25 -24
  169. package/dist/node_modules/youch/build/helpers-B9BQYaS6.js +23 -0
  170. package/dist/node_modules/youch/build/index.js +204 -351
  171. package/dist/node_modules/youch/build/public/error_info/script.js +1 -1
  172. package/dist/node_modules/youch/build/public_dir-C5bujZKB.js +25 -0
  173. package/dist/node_modules/youch/build/src/templates/error_cause/main.js +44 -0
  174. package/dist/node_modules/youch/build/src/templates/error_info/main.js +72 -0
  175. package/dist/node_modules/youch/build/src/templates/error_metadata/main.js +65 -0
  176. package/dist/node_modules/youch/build/src/templates/error_stack/main.js +152 -0
  177. package/dist/node_modules/youch/build/src/templates/error_stack_source/main.js +46 -0
  178. package/dist/node_modules/youch/build/src/templates/header/main.js +24 -0
  179. package/dist/node_modules/youch/build/src/templates/layout/main.js +27 -0
  180. package/dist/node_modules/youch/package.json +35 -32
  181. package/dist/presets/_nitro/runtime/nitro-dev.mjs +12 -57
  182. package/dist/presets/_nitro/runtime/nitro-prerenderer.mjs +1 -0
  183. package/dist/presets/_nitro/runtime/service-worker.mjs +1 -2
  184. package/dist/presets/aws-lambda/runtime/_utils.mjs +6 -6
  185. package/dist/presets/aws-lambda/runtime/aws-lambda-streaming.mjs +3 -1
  186. package/dist/presets/azure/runtime/_utils.mjs +5 -5
  187. package/dist/presets/azure/runtime/azure-swa.mjs +5 -5
  188. package/dist/presets/bun/runtime/bun.mjs +9 -6
  189. package/dist/presets/cloudflare/runtime/_module-handler.mjs +1 -1
  190. package/dist/presets/cloudflare/runtime/cloudflare-durable.mjs +4 -4
  191. package/dist/presets/cloudflare/runtime/cloudflare-module.mjs +3 -3
  192. package/dist/presets/cloudflare/runtime/cloudflare-pages.mjs +2 -2
  193. package/dist/presets/cloudflare/runtime/plugin.dev.mjs +10 -21
  194. package/dist/presets/deno/runtime/deno-deploy.mjs +4 -4
  195. package/dist/presets/deno/runtime/deno-server.mjs +9 -6
  196. package/dist/presets/edgeone/runtime/edgeone.mjs +10 -0
  197. package/dist/presets/netlify/runtime/netlify-edge.mjs +2 -3
  198. package/dist/presets/netlify/runtime/netlify.mjs +1 -1
  199. package/dist/presets/node/runtime/node-cluster.mjs +5 -4
  200. package/dist/presets/node/runtime/node-middleware.mjs +1 -1
  201. package/dist/presets/node/runtime/node-server.mjs +8 -5
  202. package/dist/presets/stormkit/runtime/stormkit.mjs +1 -2
  203. package/dist/presets/vercel/runtime/cron-handler.mjs +25 -0
  204. package/dist/presets/vercel/runtime/queue-handler.mjs +21 -0
  205. package/dist/presets/vercel/runtime/vercel.node.mjs +3 -3
  206. package/dist/presets/vercel/runtime/vercel.web.mjs +3 -5
  207. package/dist/presets/winterjs/runtime/winterjs.mjs +10 -10
  208. package/dist/presets/zephyr/runtime/server.mjs +3 -0
  209. package/dist/runtime/internal/app.mjs +12 -11
  210. package/dist/runtime/internal/cache.d.mts +0 -4
  211. package/dist/runtime/internal/cache.mjs +32 -256
  212. package/dist/runtime/internal/context.d.mts +3 -1
  213. package/dist/runtime/internal/context.mjs +1 -9
  214. package/dist/runtime/internal/error/dev.d.mts +5 -4
  215. package/dist/runtime/internal/error/dev.mjs +47 -49
  216. package/dist/runtime/internal/error/hooks.d.mts +1 -1
  217. package/dist/runtime/internal/error/prod.d.mts +2 -5
  218. package/dist/runtime/internal/error/prod.mjs +19 -33
  219. package/dist/runtime/internal/error/utils.d.mts +4 -4
  220. package/dist/runtime/internal/meta.d.mts +1 -1
  221. package/dist/runtime/internal/plugin.d.mts +2 -2
  222. package/dist/runtime/internal/route-rules.d.mts +11 -4
  223. package/dist/runtime/internal/route-rules.mjs +15 -5
  224. package/dist/runtime/internal/routes/dev-tasks.d.mts +3 -2
  225. package/dist/runtime/internal/routes/dev-tasks.mjs +15 -10
  226. package/dist/runtime/internal/routes/openapi.mjs +2 -2
  227. package/dist/runtime/internal/routes/renderer-template.d.mts +1 -1
  228. package/dist/runtime/internal/routes/renderer-template.dev.d.mts +2 -1
  229. package/dist/runtime/internal/routes/scalar.mjs +3 -3
  230. package/dist/runtime/internal/routes/swagger.mjs +7 -4
  231. package/dist/runtime/internal/runtime-config.d.mts +1 -1
  232. package/dist/runtime/internal/runtime-config.mjs +2 -2
  233. package/dist/runtime/internal/static.mjs +5 -4
  234. package/dist/runtime/internal/task.d.mts +3 -1
  235. package/dist/runtime/internal/task.mjs +7 -7
  236. package/dist/runtime/internal/vite/dev-entry.mjs +6 -3
  237. package/dist/runtime/internal/vite/dev-worker.mjs +264 -0
  238. package/dist/runtime/meta.d.mts +1 -0
  239. package/dist/runtime/meta.mjs +2 -0
  240. package/dist/runtime/nitro.d.mts +2 -0
  241. package/dist/runtime/nitro.mjs +4 -2
  242. package/dist/runtime/virtual/error-handler.mjs +1 -1
  243. package/dist/runtime/virtual/renderer-template.mjs +1 -1
  244. package/dist/runtime/virtual/server-assets.d.mts +2 -1
  245. package/dist/runtime/virtual/tracing.d.mts +5 -0
  246. package/dist/runtime/virtual/tracing.mjs +1 -0
  247. package/dist/runtime/vite.d.mts +1 -1
  248. package/dist/types/index.d.mts +215 -195
  249. package/dist/types/index.mjs +1 -11
  250. package/dist/vite.d.mts +3 -8
  251. package/dist/vite.mjs +285 -253
  252. package/lib/tsconfig.json +3 -5
  253. package/package.json +97 -80
  254. package/dist/_libs/confbox.mjs +0 -2509
  255. package/dist/_libs/nypm+giget+tinyexec.mjs +0 -3603
  256. package/dist/_libs/rc9+c12+dotenv.mjs +0 -972
  257. package/dist/node_modules/hookable/dist/index.mjs +0 -266
  258. package/dist/node_modules/hookable/package.json +0 -52
  259. package/dist/node_modules/youch/build/chunk-4L7RY2JA.js +0 -42
  260. package/dist/node_modules/youch/build/chunk-7QV3D5YX.js +0 -83
  261. package/dist/node_modules/youch/build/chunk-AUGPHE32.js +0 -39
  262. package/dist/node_modules/youch/build/chunk-CM7DWJNZ.js +0 -44
  263. package/dist/node_modules/youch/build/chunk-EJH674NB.js +0 -223
  264. package/dist/node_modules/youch/build/chunk-OIJ3WD7L.js +0 -81
  265. package/dist/node_modules/youch/build/chunk-P36L72PL.js +0 -87
  266. package/dist/node_modules/youch/build/chunk-PE3GG3TN.js +0 -65
  267. package/dist/node_modules/youch/build/chunk-X53OIOJH.js +0 -70
  268. package/dist/presets/_nitro/runtime/nitro-dev.d.mts +0 -2
  269. package/dist/presets/_nitro/runtime/nitro-prerenderer.d.mts +0 -3
  270. package/dist/presets/_nitro/runtime/service-worker.d.mts +0 -2
  271. package/dist/presets/aws-amplify/runtime/aws-amplify.d.mts +0 -2
  272. package/dist/presets/aws-lambda/runtime/_utils.d.mts +0 -8
  273. package/dist/presets/aws-lambda/runtime/aws-lambda-streaming.d.mts +0 -2
  274. package/dist/presets/aws-lambda/runtime/aws-lambda.d.mts +0 -3
  275. package/dist/presets/azure/runtime/_utils.d.mts +0 -2
  276. package/dist/presets/azure/runtime/azure-swa.d.mts +0 -5
  277. package/dist/presets/bun/runtime/bun.d.mts +0 -3
  278. package/dist/presets/cloudflare/runtime/_module-handler.d.mts +0 -16
  279. package/dist/presets/cloudflare/runtime/cloudflare-durable.d.mts +0 -11
  280. package/dist/presets/cloudflare/runtime/cloudflare-module.d.mts +0 -3
  281. package/dist/presets/cloudflare/runtime/cloudflare-pages.d.mts +0 -20
  282. package/dist/presets/cloudflare/runtime/plugin.dev.d.mts +0 -3
  283. package/dist/presets/deno/runtime/deno-deploy.d.mts +0 -5
  284. package/dist/presets/deno/runtime/deno-server.d.mts +0 -3
  285. package/dist/presets/netlify/runtime/netlify-edge.d.mts +0 -3
  286. package/dist/presets/netlify/runtime/netlify.d.mts +0 -4
  287. package/dist/presets/node/runtime/node-cluster.d.mts +0 -3
  288. package/dist/presets/node/runtime/node-middleware.d.mts +0 -3
  289. package/dist/presets/node/runtime/node-server.d.mts +0 -3
  290. package/dist/presets/standard/runtime/server.d.mts +0 -3
  291. package/dist/presets/stormkit/runtime/stormkit.d.mts +0 -21
  292. package/dist/presets/vercel/runtime/isr.d.mts +0 -2
  293. package/dist/presets/vercel/runtime/vercel.node.d.mts +0 -3
  294. package/dist/presets/vercel/runtime/vercel.web.d.mts +0 -8
  295. package/dist/presets/winterjs/runtime/winterjs.d.mts +0 -2
  296. package/dist/presets/zeabur/runtime/zeabur.d.mts +0 -3
  297. package/dist/runtime/internal/vite/node-runner.mjs +0 -359
@@ -0,0 +1,277 @@
1
+ # Tasks
2
+
3
+ > Nitro tasks allow on-off operations in runtime.
4
+
5
+ ## Opt-in to the experimental feature
6
+
7
+ > [!IMPORTANT]
8
+ > Tasks support is currently experimental.
9
+ > See [nitrojs/nitro#1974](https://github.com/nitrojs/nitro/issues/1974) for the relevant discussion.
10
+
11
+ In order to use the tasks API you need to enable experimental feature flag.
12
+
13
+ ```ts [nitro.config.ts]
14
+ import { defineConfig } from "nitro";
15
+
16
+ export default defineConfig({
17
+ experimental: {
18
+ tasks: true
19
+ }
20
+ })
21
+ ```
22
+
23
+ ## Define tasks
24
+
25
+ Tasks can be defined in `tasks/[name].ts` files.
26
+
27
+ Nested directories are supported. The task name will be joined with `:`. (Example: `tasks/db/migrate.ts` task name will be `db:migrate`)
28
+
29
+ **Example:**
30
+
31
+ ```ts [tasks/db/migrate.ts]
32
+ export default defineTask({
33
+ meta: {
34
+ name: "db:migrate",
35
+ description: "Run database migrations",
36
+ },
37
+ run({ payload, context }) {
38
+ console.log("Running DB migration task...");
39
+ return { result: "Success" };
40
+ },
41
+ });
42
+ ```
43
+
44
+ ### Task interface
45
+
46
+ The `defineTask` helper accepts an object with the following properties:
47
+
48
+ - **`meta`** (optional): An object with optional `name` and `description` string fields used for display in the dev server and CLI.
49
+ - **`run`** (required): A function that receives a [`TaskEvent`](#taskevent) and returns (or resolves to) an object with an optional `result` property.
50
+
51
+ ```ts
52
+ interface Task<RT = unknown> {
53
+ meta?: { name?: string; description?: string };
54
+ run(event: TaskEvent): { result?: RT } | Promise<{ result?: RT }>;
55
+ }
56
+ ```
57
+
58
+ ### `TaskEvent`
59
+ The `run` function receives a `TaskEvent` object with the following properties:
60
+
61
+ - **`name`**: The name of the task being executed.
62
+ - **`payload`**: An object (`Record<string, unknown>`) containing any data passed to the task.
63
+ - **`context`**: A `TaskContext` object (may include `waitUntil` depending on the runtime).
64
+
65
+ ```ts
66
+ interface TaskEvent {
67
+ name: string;
68
+ payload: TaskPayload;
69
+ context: TaskContext;
70
+ }
71
+ ```
72
+
73
+ ### Registering tasks via config
74
+ In addition to file-based scanning, tasks can be registered directly in the Nitro config. This is useful for tasks provided by modules or pointing to custom handler paths.
75
+
76
+ ```ts [nitro.config.ts]
77
+ import { defineConfig } from "nitro";
78
+
79
+ export default defineConfig({
80
+ experimental: {
81
+ tasks: true
82
+ },
83
+ tasks: {
84
+ "db:migrate": {
85
+ handler: "./tasks/custom-migrate.ts",
86
+ description: "Run database migrations"
87
+ }
88
+ }
89
+ })
90
+ ```
91
+
92
+ If a task is both scanned from the `tasks/` directory and defined in the config, the config-defined `handler` takes precedence.
93
+
94
+ ## Scheduled tasks
95
+
96
+ You can define scheduled tasks using Nitro configuration to automatically run after each period of time.
97
+
98
+ ```ts [nitro.config.ts]
99
+ import { defineConfig } from "nitro";
100
+
101
+ export default defineConfig({
102
+ scheduledTasks: {
103
+ // Run `cms:update` task every minute
104
+ '* * * * *': ['cms:update'],
105
+ // Run a single task (string shorthand)
106
+ '0 * * * *': 'db:cleanup'
107
+ }
108
+ })
109
+ ```
110
+
111
+ The `scheduledTasks` config maps cron expressions to either a single task name (string) or an array of task names. When multiple tasks are assigned to the same cron expression, they run in parallel.
112
+
113
+ > [!TIP]
114
+ > You can use [crontab.guru](https://crontab.guru/) to easily generate and understand cron tab patterns.
115
+
116
+ When a scheduled task runs, it automatically receives a `payload` with `scheduledTime` set to the current timestamp (`Date.now()`).
117
+
118
+ ### Platform support
119
+
120
+ - **`dev`**, **`node_server`**, **`node_cluster`**, **`node_middleware`**, **`bun`** and **`deno_server`** presets are supported with the [croner](https://croner.56k.guru/) engine.
121
+ - **`cloudflare_module`** and **`cloudflare_pages`** presets have native integration with [Cron Triggers](https://developers.cloudflare.com/workers/configuration/cron-triggers/). Nitro automatically generates the cron triggers in the wrangler config at build time - no manual wrangler setup required.
122
+ - **`vercel`** preset has native integration with [Vercel Cron Jobs](https://vercel.com/docs/cron-jobs). Nitro automatically generates the cron job configuration at build time - no manual `vercel.json` setup required. You can secure cron endpoints by setting the `CRON_SECRET` environment variable.
123
+ - More presets (with native primitives support) are planned to be supported!
124
+
125
+ ## `waitUntil`
126
+ When running background tasks, you might want to make sure the server or worker waits until the task is done.
127
+
128
+ An optional `context.waitUntil` function <u>might</u> be available depending on the runtime.
129
+
130
+ ```ts
131
+ export default defineTask({
132
+ run({ context }) {
133
+ const promise = fetch(...)
134
+ context.waitUntil?.(promise);
135
+ await promise;
136
+ return { result: "Success" };
137
+ },
138
+ });
139
+ ```
140
+
141
+ ## Programmatically run tasks
142
+
143
+ To manually run tasks, you can use `runTask(name, { payload?, context? })` utility from `nitro/task`.
144
+
145
+ **Example:**
146
+
147
+ ```ts [api/migrate.ts]
148
+ import { defineHandler } from "nitro";
149
+
150
+ export default defineHandler(async (event) => {
151
+ // IMPORTANT: Authenticate user and validate payload!
152
+ const payload = Object.fromEntries(event.url.searchParams);
153
+ const { result } = await runTask("db:migrate", { payload });
154
+
155
+ return { result };
156
+ });
157
+ ```
158
+
159
+ ### Error handling
160
+
161
+ `runTask` throws an HTTP error if:
162
+
163
+ - The task does not exist (status `404`).
164
+ - The task has no handler implementation (status `501`).
165
+ Any errors thrown inside the task's `run` function will propagate to the caller.
166
+
167
+ ## Run tasks with dev server
168
+
169
+ Nitro's built-in dev server exposes tasks to be easily executed without programmatic usage.
170
+
171
+ ### Using API routes
172
+
173
+ #### `/_nitro/tasks`
174
+
175
+ This endpoint returns a list of available task names and their meta.
176
+
177
+ ```json
178
+ // [GET] /_nitro/tasks
179
+ {
180
+ "tasks": {
181
+ "db:migrate": {
182
+ "description": "Run database migrations"
183
+ },
184
+ "cms:update": {
185
+ "description": "Update CMS content"
186
+ }
187
+ },
188
+ "scheduledTasks": [
189
+ {
190
+ "cron": "* * * * *",
191
+ "tasks": [
192
+ "cms:update"
193
+ ]
194
+ }
195
+ ]
196
+ }
197
+ ```
198
+
199
+ #### `/_nitro/tasks/:name`
200
+
201
+ This endpoint executes a task. You can provide a payload using both query parameters and body JSON payload. The payload sent in the JSON body payload must be under the `"payload"` property.
202
+
203
+ <code-group>
204
+
205
+ ```ts [tasks/echo/payload.ts]
206
+ export default defineTask({
207
+ meta: {
208
+ name: "echo:payload",
209
+ description: "Returns the provided payload",
210
+ },
211
+ run({ payload, context }) {
212
+ console.log("Running echo task...");
213
+ return { result: payload };
214
+ },
215
+ });
216
+ ```
217
+
218
+ ```json [GET]
219
+ // [GET] /_nitro/tasks/echo:payload?field=value&array=1&array=2
220
+ {
221
+ "field": "value",
222
+ "array": ["1", "2"]
223
+ }
224
+ ```
225
+
226
+ ```json [POST]
227
+ /**
228
+ * [POST] /_nitro/tasks/echo:payload?field=value
229
+ * body: {
230
+ * "payload": {
231
+ * "answer": 42,
232
+ * "nested": {
233
+ * "value": true
234
+ * }
235
+ * }
236
+ * }
237
+ */
238
+ {
239
+ "field": "value",
240
+ "answer": 42,
241
+ "nested": {
242
+ "value": true
243
+ }
244
+ }
245
+ ```
246
+ </code-group>
247
+
248
+ > [!NOTE]
249
+ > The JSON payload included in the body will overwrite the keys present in the query params.
250
+
251
+ ### Using CLI
252
+
253
+ > [!IMPORTANT]
254
+ > It is only possible to run these commands while the **dev server is running**. You should run them in a second terminal.
255
+
256
+ #### List tasks
257
+
258
+ ```sh
259
+ nitro task list
260
+ ```
261
+
262
+ #### Run a task
263
+
264
+ ```sh
265
+ nitro task run db:migrate --payload "{}"
266
+ ```
267
+
268
+ The `--payload` flag accepts a JSON string that will be parsed and passed to the task. If the value is not a valid JSON object, the task runs without a payload.
269
+
270
+ ## Notes
271
+
272
+ ### Concurrency
273
+
274
+ Each task can have **one running instance**. Calling a task of same name multiple times in parallel, results in calling it once and all callers will get the same return value.
275
+
276
+ > [!NOTE]
277
+ > Nitro tasks can be running multiple times and in parallel.
@@ -0,0 +1,386 @@
1
+ # WebSocket
2
+
3
+ > Nitro provides cross-platform WebSocket support powered by [CrossWS](https://crossws.h3.dev/) and [H3](https://h3.dev/).
4
+
5
+ WebSocket enables real-time, bidirectional communication between client and server. Nitro's WebSocket integration works across all supported deployment targets including Node.js, Bun, Deno, and Cloudflare Workers.
6
+
7
+ <read-more></read-more>
8
+
9
+ ## Enable WebSocket
10
+
11
+ Enable WebSocket support in your Nitro configuration:
12
+
13
+ <code-group>
14
+
15
+ ```ts [nitro.config.ts]
16
+ import { defineConfig } from "nitro";
17
+
18
+ export default defineConfig({
19
+ features: {
20
+ websocket: true,
21
+ },
22
+ });
23
+ ```
24
+ </code-group>
25
+
26
+ ## Usage
27
+
28
+ Create a WebSocket handler using `defineWebSocketHandler` and export it from a route file. WebSocket handlers follow the same [file-based routing](/docs/routing) as regular request handlers.
29
+
30
+ ```ts [routes/_ws.ts]
31
+ import { defineWebSocketHandler } from "nitro";
32
+
33
+ export default defineWebSocketHandler({
34
+ open(peer) {
35
+ console.log("Connected:", peer.id);
36
+ },
37
+ message(peer, message) {
38
+ console.log("Message:", message.text());
39
+ peer.send("Hello from server!");
40
+ },
41
+ close(peer, details) {
42
+ console.log("Disconnected:", peer.id, details.code, details.reason);
43
+ },
44
+ error(peer, error) {
45
+ console.error("Error:", error);
46
+ },
47
+ });
48
+ ```
49
+
50
+ <tip>
51
+
52
+ You can use any route path for WebSocket handlers. For example, `routes/chat.ts` handles WebSocket connections on `/chat`.
53
+ </tip>
54
+
55
+ ### Connecting from the client
56
+
57
+ Use the browser's [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) to connect:
58
+
59
+ ```js
60
+ const ws = new WebSocket("ws://localhost:3000/_ws");
61
+
62
+ ws.addEventListener("open", () => {
63
+ console.log("Connected!");
64
+ ws.send("Hello from client!");
65
+ });
66
+
67
+ ws.addEventListener("message", (event) => {
68
+ console.log("Received:", event.data);
69
+ });
70
+ ```
71
+
72
+ ## Hooks
73
+
74
+ WebSocket handlers accept the following lifecycle hooks:
75
+
76
+ ### `upgrade`
77
+
78
+ Called before the WebSocket connection is established. Use it to authenticate requests, set the namespace, or attach context data to the peer.
79
+
80
+ ```ts [routes/chat.ts]
81
+ import { defineWebSocketHandler } from "nitro";
82
+
83
+ export default defineWebSocketHandler({
84
+ upgrade(request) {
85
+ const url = new URL(request.url);
86
+ const token = url.searchParams.get("token");
87
+ if (!isValidToken(token)) {
88
+ throw new Response("Unauthorized", { status: 401 });
89
+ }
90
+ return {
91
+ context: { userId: getUserId(token) },
92
+ };
93
+ },
94
+ open(peer) {
95
+ console.log("User connected:", peer.context.userId);
96
+ },
97
+ // ...
98
+ });
99
+ ```
100
+
101
+ The `upgrade` hook can return an object with:
102
+
103
+ | Property | Type | Description |
104
+ | --- | --- | --- |
105
+ | `headers` | `HeadersInit` | Response headers to include in the upgrade response |
106
+ | `namespace` | `string` | Override the pub/sub namespace for this connection |
107
+ | `context` | `object` | Data attached to `peer.context` |
108
+
109
+ Throw a `Response` to reject the upgrade.
110
+
111
+ ### `open`
112
+
113
+ Called when a WebSocket connection is established and the peer is ready to send and receive messages.
114
+
115
+ ```ts
116
+ open(peer) {
117
+ peer.send("Welcome!");
118
+ }
119
+ ```
120
+
121
+ ### `message`
122
+
123
+ Called when a message is received from a peer.
124
+
125
+ ```ts
126
+ message(peer, message) {
127
+ const text = message.text();
128
+ const data = message.json();
129
+ }
130
+ ```
131
+
132
+ ### `close`
133
+
134
+ Called when a WebSocket connection is closed. Receives a `details` object with optional `code` and `reason`.
135
+
136
+ ```ts
137
+ close(peer, details) {
138
+ console.log(`Closed: ${details.code} - ${details.reason}`);
139
+ }
140
+ ```
141
+
142
+ ### `error`
143
+
144
+ Called when an error occurs on the WebSocket connection.
145
+
146
+ ```ts
147
+ error(peer, error) {
148
+ console.error("WebSocket error:", error);
149
+ }
150
+ ```
151
+
152
+ ## Peer
153
+
154
+ The `peer` object represents a connected WebSocket client. It is available in all hooks except `upgrade`.
155
+
156
+ ### Properties
157
+
158
+ | Property | Type | Description |
159
+ | --- | --- | --- |
160
+ | `id` | `string` | Unique identifier for this peer |
161
+ | `namespace` | `string` | Pub/sub namespace this peer belongs to |
162
+ | `context` | `object` | Arbitrary context data set during `upgrade` |
163
+ | `request` | `Request` | The original upgrade request |
164
+ | `peers` | `Set<Peer>` | All connected peers in the same namespace |
165
+ | `topics` | `Set<string>` | Topics this peer is subscribed to |
166
+ | `remoteAddress` | `string?` | Client IP address (adapter-dependent) |
167
+ | `websocket` | `WebSocket` | The underlying WebSocket instance |
168
+
169
+ ### Methods
170
+
171
+ #### `peer.send(data, options?)`
172
+
173
+ Send a message directly to this peer. Accepts strings, objects (serialized as JSON), or binary data.
174
+
175
+ ```ts
176
+ peer.send("Hello!");
177
+ peer.send({ type: "greeting", text: "Hello!" });
178
+ ```
179
+
180
+ #### `peer.subscribe(topic)`
181
+
182
+ Subscribe this peer to a pub/sub topic.
183
+
184
+ ```ts
185
+ peer.subscribe("notifications");
186
+ ```
187
+
188
+ #### `peer.unsubscribe(topic)`
189
+
190
+ Unsubscribe this peer from a topic.
191
+
192
+ ```ts
193
+ peer.unsubscribe("notifications");
194
+ ```
195
+
196
+ #### `peer.publish(topic, data, options?)`
197
+
198
+ Broadcast a message to all peers subscribed to a topic within the same namespace. The publishing peer does **not** receive the message.
199
+
200
+ ```ts
201
+ peer.publish("chat", { user: "Alice", text: "Hello everyone!" });
202
+ ```
203
+
204
+ #### `peer.close(code?, reason?)`
205
+
206
+ Gracefully close the WebSocket connection.
207
+
208
+ ```ts
209
+ peer.close(1000, "Normal closure");
210
+ ```
211
+
212
+ #### `peer.terminate()`
213
+
214
+ Immediately terminate the connection without sending a close frame.
215
+
216
+ ## Message
217
+
218
+ The `message` object in the `message` hook provides methods to read the incoming data in different formats.
219
+
220
+ | Method | Return Type | Description |
221
+ | --- | --- | --- |
222
+ | `text()` | `string` | Message as a UTF-8 string |
223
+ | `json()` | `T` | Message parsed as JSON |
224
+ | `uint8Array()` | `Uint8Array` | Message as a byte array |
225
+ | `arrayBuffer()` | `ArrayBuffer` | Message as an ArrayBuffer |
226
+ | `blob()` | `Blob` | Message as a Blob |
227
+
228
+ ```ts
229
+ message(peer, message) {
230
+ // Parse as text
231
+ const text = message.text();
232
+
233
+ // Parse as typed JSON
234
+ const data = message.json<{ type: string; payload: unknown }>();
235
+ }
236
+ ```
237
+
238
+ ## Pub/Sub
239
+
240
+ Pub/sub (publish/subscribe) enables broadcasting messages to groups of connected peers through topics. Peers subscribe to topics and receive messages published to those topics.
241
+
242
+ ```ts [routes/chat.ts]
243
+ import { defineWebSocketHandler } from "nitro";
244
+
245
+ export default defineWebSocketHandler({
246
+ open(peer) {
247
+ peer.subscribe("chat");
248
+ peer.publish("chat", { system: `${peer} joined the chat` });
249
+ peer.send({ system: "Welcome to the chat!" });
250
+ },
251
+ message(peer, message) {
252
+ // Broadcast to all other subscribers
253
+ peer.publish("chat", {
254
+ user: peer.toString(),
255
+ text: message.text(),
256
+ });
257
+ // Echo back to sender
258
+ peer.send({ user: "You", text: message.text() });
259
+ },
260
+ close(peer) {
261
+ peer.publish("chat", { system: `${peer} left the chat` });
262
+ },
263
+ });
264
+ ```
265
+
266
+ <note>
267
+
268
+ `peer.publish()` sends the message to all subscribers of the topic **except** the publishing peer. Use `peer.send()` to also send to the publisher.
269
+ </note>
270
+
271
+ ### Namespaces
272
+
273
+ Namespaces provide isolated pub/sub groups for WebSocket connections. Each peer belongs to one namespace, and `peer.publish()` only broadcasts to peers within the same namespace.
274
+
275
+ By default, the namespace is derived from the request URL pathname. This works naturally with [dynamic routes](/docs/routing#dynamic-routes) — each path gets its own isolated namespace:
276
+
277
+ ```ts [routes/rooms/[room].ts]
278
+ import { defineWebSocketHandler } from "nitro";
279
+
280
+ export default defineWebSocketHandler({
281
+ open(peer) {
282
+ peer.subscribe("messages");
283
+ peer.publish("messages", `${peer} joined ${peer.namespace}`);
284
+ },
285
+ message(peer, message) {
286
+ // Only reaches peers in the same room
287
+ peer.publish("messages", `${peer}: ${message.text()}`);
288
+ },
289
+ close(peer) {
290
+ peer.publish("messages", `${peer} left`);
291
+ },
292
+ });
293
+ ```
294
+
295
+ In this example, clients connecting to `/rooms/game` are isolated from clients connecting to `/rooms/lobby` — each path is its own namespace.
296
+
297
+ To override the default namespace, return a custom `namespace` from the `upgrade` hook:
298
+
299
+ ```ts [routes/chat.ts]
300
+ import { defineWebSocketHandler } from "nitro";
301
+
302
+ export default defineWebSocketHandler({
303
+ upgrade(request) {
304
+ // Group connections by a query parameter instead of the pathname
305
+ const url = new URL(request.url);
306
+ const channel = url.searchParams.get("channel") || "general";
307
+ return {
308
+ namespace: `chat:${channel}`,
309
+ };
310
+ },
311
+ open(peer) {
312
+ peer.subscribe("messages");
313
+ peer.publish("messages", `${peer} joined`);
314
+ },
315
+ message(peer, message) {
316
+ peer.publish("messages", `${peer}: ${message.text()}`);
317
+ },
318
+ close(peer) {
319
+ peer.publish("messages", `${peer} left`);
320
+ },
321
+ });
322
+ ```
323
+
324
+ ## Server-Sent Events (SSE)
325
+
326
+ [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events) provide a simpler alternative when you only need server-to-client streaming. Unlike WebSockets, SSE uses standard HTTP and supports automatic reconnection.
327
+
328
+ ```ts [routes/sse.ts]
329
+ import { defineHandler } from "nitro";
330
+ import { createEventStream } from "nitro/h3";
331
+
332
+ export default defineHandler((event) => {
333
+ const stream = createEventStream(event);
334
+
335
+ const interval = setInterval(async () => {
336
+ await stream.push(`Message @ ${new Date().toLocaleTimeString()}`);
337
+ }, 1000);
338
+
339
+ stream.onClosed(() => {
340
+ clearInterval(interval);
341
+ });
342
+
343
+ return stream.send();
344
+ });
345
+ ```
346
+
347
+ Connect from the client using the [EventSource API](https://developer.mozilla.org/en-US/docs/Web/API/EventSource):
348
+
349
+ ```js
350
+ const source = new EventSource("/sse");
351
+
352
+ source.onmessage = (event) => {
353
+ console.log(event.data);
354
+ };
355
+ ```
356
+
357
+ ### Structured messages
358
+
359
+ SSE messages support optional `id`, `event`, and `retry` fields:
360
+
361
+ ```ts [routes/events.ts]
362
+ import { defineHandler } from "nitro";
363
+ import { createEventStream } from "nitro/h3";
364
+
365
+ export default defineHandler((event) => {
366
+ const stream = createEventStream(event);
367
+ let id = 0;
368
+
369
+ const interval = setInterval(async () => {
370
+ await stream.push({
371
+ id: String(id++),
372
+ event: "update",
373
+ data: JSON.stringify({ value: Math.random() }),
374
+ retry: 3000,
375
+ });
376
+ }, 1000);
377
+
378
+ stream.onClosed(() => {
379
+ clearInterval(interval);
380
+ });
381
+
382
+ return stream.send();
383
+ });
384
+ ```
385
+
386
+ <read-more></read-more>