@buenojs/bueno 0.8.5 → 0.8.7

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 (421) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/README.md +259 -15
  3. package/dist/cache/index.d.ts +187 -0
  4. package/dist/cache/index.d.ts.map +1 -0
  5. package/dist/cli/bin.d.ts +8 -0
  6. package/dist/cli/bin.d.ts.map +1 -0
  7. package/dist/cli/bin.js +484 -156
  8. package/dist/cli/commands/add-frontend.d.ts +7 -0
  9. package/dist/cli/commands/add-frontend.d.ts.map +1 -0
  10. package/dist/cli/commands/build.d.ts +7 -0
  11. package/dist/cli/commands/build.d.ts.map +1 -0
  12. package/dist/cli/commands/dev.d.ts +7 -0
  13. package/dist/cli/commands/dev.d.ts.map +1 -0
  14. package/dist/cli/commands/generate.d.ts +7 -0
  15. package/dist/cli/commands/generate.d.ts.map +1 -0
  16. package/dist/cli/commands/help.d.ts +7 -0
  17. package/dist/cli/commands/help.d.ts.map +1 -0
  18. package/dist/cli/commands/index.d.ts +59 -0
  19. package/dist/cli/commands/index.d.ts.map +1 -0
  20. package/dist/cli/commands/migration.d.ts +7 -0
  21. package/dist/cli/commands/migration.d.ts.map +1 -0
  22. package/dist/cli/commands/new.d.ts +7 -0
  23. package/dist/cli/commands/new.d.ts.map +1 -0
  24. package/dist/cli/commands/start.d.ts +7 -0
  25. package/dist/cli/commands/start.d.ts.map +1 -0
  26. package/dist/cli/core/args.d.ts +61 -0
  27. package/dist/cli/core/args.d.ts.map +1 -0
  28. package/dist/cli/core/console.d.ts +135 -0
  29. package/dist/cli/core/console.d.ts.map +1 -0
  30. package/dist/cli/core/index.d.ts +10 -0
  31. package/dist/cli/core/index.d.ts.map +1 -0
  32. package/dist/cli/core/prompt.d.ts +63 -0
  33. package/dist/cli/core/prompt.d.ts.map +1 -0
  34. package/dist/cli/core/spinner.d.ts +111 -0
  35. package/dist/cli/core/spinner.d.ts.map +1 -0
  36. package/dist/cli/index.d.ts +47 -0
  37. package/dist/cli/index.d.ts.map +1 -0
  38. package/dist/cli/templates/database/index.d.ts +24 -0
  39. package/dist/cli/templates/database/index.d.ts.map +1 -0
  40. package/dist/cli/templates/database/mysql.d.ts +6 -0
  41. package/dist/cli/templates/database/mysql.d.ts.map +1 -0
  42. package/dist/cli/templates/database/none.d.ts +8 -0
  43. package/dist/cli/templates/database/none.d.ts.map +1 -0
  44. package/dist/cli/templates/database/postgresql.d.ts +6 -0
  45. package/dist/cli/templates/database/postgresql.d.ts.map +1 -0
  46. package/dist/cli/templates/database/sqlite.d.ts +6 -0
  47. package/dist/cli/templates/database/sqlite.d.ts.map +1 -0
  48. package/dist/cli/templates/deploy.d.ts +41 -0
  49. package/dist/cli/templates/deploy.d.ts.map +1 -0
  50. package/dist/cli/templates/docker.d.ts +30 -0
  51. package/dist/cli/templates/docker.d.ts.map +1 -0
  52. package/dist/cli/templates/frontend/index.d.ts +25 -0
  53. package/dist/cli/templates/frontend/index.d.ts.map +1 -0
  54. package/dist/cli/templates/frontend/none.d.ts +8 -0
  55. package/dist/cli/templates/frontend/none.d.ts.map +1 -0
  56. package/dist/cli/templates/frontend/react.d.ts +6 -0
  57. package/dist/cli/templates/frontend/react.d.ts.map +1 -0
  58. package/dist/cli/templates/frontend/solid.d.ts +6 -0
  59. package/dist/cli/templates/frontend/solid.d.ts.map +1 -0
  60. package/dist/cli/templates/frontend/svelte.d.ts +6 -0
  61. package/dist/cli/templates/frontend/svelte.d.ts.map +1 -0
  62. package/dist/cli/templates/frontend/vue.d.ts +6 -0
  63. package/dist/cli/templates/frontend/vue.d.ts.map +1 -0
  64. package/dist/cli/templates/generators/index.d.ts +29 -0
  65. package/dist/cli/templates/generators/index.d.ts.map +1 -0
  66. package/dist/cli/templates/generators/types.d.ts +32 -0
  67. package/dist/cli/templates/generators/types.d.ts.map +1 -0
  68. package/dist/cli/templates/index.d.ts +12 -0
  69. package/dist/cli/templates/index.d.ts.map +1 -0
  70. package/dist/cli/templates/project/api.d.ts +6 -0
  71. package/dist/cli/templates/project/api.d.ts.map +1 -0
  72. package/dist/cli/templates/project/default.d.ts +6 -0
  73. package/dist/cli/templates/project/default.d.ts.map +1 -0
  74. package/dist/cli/templates/project/fullstack.d.ts +14 -0
  75. package/dist/cli/templates/project/fullstack.d.ts.map +1 -0
  76. package/dist/cli/templates/project/index.d.ts +26 -0
  77. package/dist/cli/templates/project/index.d.ts.map +1 -0
  78. package/dist/cli/templates/project/minimal.d.ts +6 -0
  79. package/dist/cli/templates/project/minimal.d.ts.map +1 -0
  80. package/dist/cli/templates/project/types.d.ts +80 -0
  81. package/dist/cli/templates/project/types.d.ts.map +1 -0
  82. package/dist/cli/templates/project/website.d.ts +8 -0
  83. package/dist/cli/templates/project/website.d.ts.map +1 -0
  84. package/dist/cli/utils/fs.d.ts +137 -0
  85. package/dist/cli/utils/fs.d.ts.map +1 -0
  86. package/dist/cli/utils/index.d.ts +9 -0
  87. package/dist/cli/utils/index.d.ts.map +1 -0
  88. package/dist/cli/utils/strings.d.ts +86 -0
  89. package/dist/cli/utils/strings.d.ts.map +1 -0
  90. package/dist/cli/utils/version.d.ts +15 -0
  91. package/dist/cli/utils/version.d.ts.map +1 -0
  92. package/dist/config/env-validation.d.ts +49 -0
  93. package/dist/config/env-validation.d.ts.map +1 -0
  94. package/dist/config/env.d.ts +167 -0
  95. package/dist/config/env.d.ts.map +1 -0
  96. package/dist/config/index.d.ts +168 -0
  97. package/dist/config/index.d.ts.map +1 -0
  98. package/dist/config/loader.d.ts +81 -0
  99. package/dist/config/loader.d.ts.map +1 -0
  100. package/dist/config/merge.d.ts +66 -0
  101. package/dist/config/merge.d.ts.map +1 -0
  102. package/dist/config/types.d.ts +322 -0
  103. package/dist/config/types.d.ts.map +1 -0
  104. package/dist/config/validation.d.ts +100 -0
  105. package/dist/config/validation.d.ts.map +1 -0
  106. package/dist/container/forward-ref.d.ts +116 -0
  107. package/dist/container/forward-ref.d.ts.map +1 -0
  108. package/dist/container/index.d.ts +95 -0
  109. package/dist/container/index.d.ts.map +1 -0
  110. package/dist/container/index.js +26 -3
  111. package/dist/context/index.d.ts +143 -0
  112. package/dist/context/index.d.ts.map +1 -0
  113. package/dist/database/index.d.ts +219 -0
  114. package/dist/database/index.d.ts.map +1 -0
  115. package/dist/database/migrations/index.d.ts +146 -0
  116. package/dist/database/migrations/index.d.ts.map +1 -0
  117. package/dist/database/orm/builder.d.ts +122 -0
  118. package/dist/database/orm/builder.d.ts.map +1 -0
  119. package/dist/database/orm/casts/index.d.ts +16 -0
  120. package/dist/database/orm/casts/index.d.ts.map +1 -0
  121. package/dist/database/orm/casts/types.d.ts +16 -0
  122. package/dist/database/orm/casts/types.d.ts.map +1 -0
  123. package/dist/database/orm/compiler.d.ts +90 -0
  124. package/dist/database/orm/compiler.d.ts.map +1 -0
  125. package/dist/database/orm/hooks/index.d.ts +53 -0
  126. package/dist/database/orm/hooks/index.d.ts.map +1 -0
  127. package/dist/database/orm/index.d.ts +21 -0
  128. package/dist/database/orm/index.d.ts.map +1 -0
  129. package/dist/database/orm/model-registry.d.ts +33 -0
  130. package/dist/database/orm/model-registry.d.ts.map +1 -0
  131. package/dist/database/orm/model.d.ts +245 -0
  132. package/dist/database/orm/model.d.ts.map +1 -0
  133. package/dist/database/orm/relationships/base.d.ts +69 -0
  134. package/dist/database/orm/relationships/base.d.ts.map +1 -0
  135. package/dist/database/orm/relationships/belongs-to-many.d.ts +47 -0
  136. package/dist/database/orm/relationships/belongs-to-many.d.ts.map +1 -0
  137. package/dist/database/orm/relationships/belongs-to.d.ts +17 -0
  138. package/dist/database/orm/relationships/belongs-to.d.ts.map +1 -0
  139. package/dist/database/orm/relationships/has-many.d.ts +14 -0
  140. package/dist/database/orm/relationships/has-many.d.ts.map +1 -0
  141. package/dist/database/orm/relationships/has-one.d.ts +14 -0
  142. package/dist/database/orm/relationships/has-one.d.ts.map +1 -0
  143. package/dist/database/orm/relationships/index.d.ts +10 -0
  144. package/dist/database/orm/relationships/index.d.ts.map +1 -0
  145. package/dist/database/orm/scopes/index.d.ts +36 -0
  146. package/dist/database/orm/scopes/index.d.ts.map +1 -0
  147. package/dist/database/schema/index.d.ts +155 -0
  148. package/dist/database/schema/index.d.ts.map +1 -0
  149. package/dist/events/__tests__/event-system.test.d.ts +2 -0
  150. package/dist/events/__tests__/event-system.test.d.ts.map +1 -0
  151. package/dist/events/config.d.ts +16 -0
  152. package/dist/events/config.d.ts.map +1 -0
  153. package/dist/events/example-usage.d.ts +12 -0
  154. package/dist/events/example-usage.d.ts.map +1 -0
  155. package/dist/events/index.d.ts +27 -0
  156. package/dist/events/index.d.ts.map +1 -0
  157. package/dist/events/manager.d.ts +33 -0
  158. package/dist/events/manager.d.ts.map +1 -0
  159. package/dist/events/registry.d.ts +31 -0
  160. package/dist/events/registry.d.ts.map +1 -0
  161. package/dist/events/types.d.ts +105 -0
  162. package/dist/events/types.d.ts.map +1 -0
  163. package/dist/frontend/api-routes.d.ts +189 -0
  164. package/dist/frontend/api-routes.d.ts.map +1 -0
  165. package/dist/frontend/bundler.d.ts +99 -0
  166. package/dist/frontend/bundler.d.ts.map +1 -0
  167. package/dist/frontend/console-client.d.ts +11 -0
  168. package/dist/frontend/console-client.d.ts.map +1 -0
  169. package/dist/frontend/console-stream.d.ts +138 -0
  170. package/dist/frontend/console-stream.d.ts.map +1 -0
  171. package/dist/frontend/dev-server.d.ts +174 -0
  172. package/dist/frontend/dev-server.d.ts.map +1 -0
  173. package/dist/frontend/file-router.d.ts +170 -0
  174. package/dist/frontend/file-router.d.ts.map +1 -0
  175. package/dist/frontend/frameworks/index.d.ts +41 -0
  176. package/dist/frontend/frameworks/index.d.ts.map +1 -0
  177. package/dist/frontend/frameworks/react.d.ts +32 -0
  178. package/dist/frontend/frameworks/react.d.ts.map +1 -0
  179. package/dist/frontend/frameworks/solid.d.ts +42 -0
  180. package/dist/frontend/frameworks/solid.d.ts.map +1 -0
  181. package/dist/frontend/frameworks/svelte.d.ts +57 -0
  182. package/dist/frontend/frameworks/svelte.d.ts.map +1 -0
  183. package/dist/frontend/frameworks/vue.d.ts +36 -0
  184. package/dist/frontend/frameworks/vue.d.ts.map +1 -0
  185. package/dist/frontend/hmr-client.d.ts +22 -0
  186. package/dist/frontend/hmr-client.d.ts.map +1 -0
  187. package/dist/frontend/hmr.d.ts +185 -0
  188. package/dist/frontend/hmr.d.ts.map +1 -0
  189. package/dist/frontend/index.d.ts +34 -0
  190. package/dist/frontend/index.d.ts.map +1 -0
  191. package/dist/frontend/islands.d.ts +135 -0
  192. package/dist/frontend/islands.d.ts.map +1 -0
  193. package/dist/frontend/isr.d.ts +143 -0
  194. package/dist/frontend/isr.d.ts.map +1 -0
  195. package/dist/frontend/layout.d.ts +140 -0
  196. package/dist/frontend/layout.d.ts.map +1 -0
  197. package/dist/frontend/ssr/react.d.ts +118 -0
  198. package/dist/frontend/ssr/react.d.ts.map +1 -0
  199. package/dist/frontend/ssr/solid.d.ts +141 -0
  200. package/dist/frontend/ssr/solid.d.ts.map +1 -0
  201. package/dist/frontend/ssr/svelte.d.ts +158 -0
  202. package/dist/frontend/ssr/svelte.d.ts.map +1 -0
  203. package/dist/frontend/ssr/vue.d.ts +161 -0
  204. package/dist/frontend/ssr/vue.d.ts.map +1 -0
  205. package/dist/frontend/ssr.d.ts +147 -0
  206. package/dist/frontend/ssr.d.ts.map +1 -0
  207. package/dist/frontend/types.d.ts +1902 -0
  208. package/dist/frontend/types.d.ts.map +1 -0
  209. package/dist/graphql/built-in-engine.d.ts +36 -0
  210. package/dist/graphql/built-in-engine.d.ts.map +1 -0
  211. package/dist/graphql/context-builder.d.ts +44 -0
  212. package/dist/graphql/context-builder.d.ts.map +1 -0
  213. package/dist/graphql/decorators.d.ts +162 -0
  214. package/dist/graphql/decorators.d.ts.map +1 -0
  215. package/dist/graphql/execution-pipeline.d.ts +67 -0
  216. package/dist/graphql/execution-pipeline.d.ts.map +1 -0
  217. package/dist/graphql/graphql-module.d.ts +70 -0
  218. package/dist/graphql/graphql-module.d.ts.map +1 -0
  219. package/dist/graphql/index.d.ts +48 -0
  220. package/dist/graphql/index.d.ts.map +1 -0
  221. package/dist/graphql/index.js +2156 -0
  222. package/dist/graphql/metadata.d.ts +37 -0
  223. package/dist/graphql/metadata.d.ts.map +1 -0
  224. package/dist/graphql/schema-builder.d.ts +34 -0
  225. package/dist/graphql/schema-builder.d.ts.map +1 -0
  226. package/dist/graphql/subscription-handler.d.ts +47 -0
  227. package/dist/graphql/subscription-handler.d.ts.map +1 -0
  228. package/dist/graphql/types.d.ts +252 -0
  229. package/dist/graphql/types.d.ts.map +1 -0
  230. package/dist/health/index.d.ts +176 -0
  231. package/dist/health/index.d.ts.map +1 -0
  232. package/dist/i18n/engine.d.ts +105 -0
  233. package/dist/i18n/engine.d.ts.map +1 -0
  234. package/dist/i18n/index.d.ts +13 -0
  235. package/dist/i18n/index.d.ts.map +1 -0
  236. package/dist/i18n/loader.d.ts +79 -0
  237. package/dist/i18n/loader.d.ts.map +1 -0
  238. package/dist/i18n/middleware.d.ts +96 -0
  239. package/dist/i18n/middleware.d.ts.map +1 -0
  240. package/dist/i18n/negotiator.d.ts +84 -0
  241. package/dist/i18n/negotiator.d.ts.map +1 -0
  242. package/dist/i18n/types.d.ts +129 -0
  243. package/dist/i18n/types.d.ts.map +1 -0
  244. package/dist/index.d.ts +48 -0
  245. package/dist/index.d.ts.map +1 -0
  246. package/dist/index.js +520 -434
  247. package/dist/jobs/drivers/memory.d.ts +38 -0
  248. package/dist/jobs/drivers/memory.d.ts.map +1 -0
  249. package/dist/jobs/drivers/redis.d.ts +34 -0
  250. package/dist/jobs/drivers/redis.d.ts.map +1 -0
  251. package/dist/jobs/index.d.ts +12 -0
  252. package/dist/jobs/index.d.ts.map +1 -0
  253. package/dist/jobs/queue.d.ts +93 -0
  254. package/dist/jobs/queue.d.ts.map +1 -0
  255. package/dist/jobs/types.d.ts +193 -0
  256. package/dist/jobs/types.d.ts.map +1 -0
  257. package/dist/jobs/worker.d.ts +91 -0
  258. package/dist/jobs/worker.d.ts.map +1 -0
  259. package/dist/lock/index.d.ts +141 -0
  260. package/dist/lock/index.d.ts.map +1 -0
  261. package/dist/logger/index.d.ts +156 -0
  262. package/dist/logger/index.d.ts.map +1 -0
  263. package/dist/logger/transports/index.d.ts +371 -0
  264. package/dist/logger/transports/index.d.ts.map +1 -0
  265. package/dist/metrics/index.d.ts +163 -0
  266. package/dist/metrics/index.d.ts.map +1 -0
  267. package/dist/middleware/built-in.d.ts +50 -0
  268. package/dist/middleware/built-in.d.ts.map +1 -0
  269. package/dist/middleware/index.d.ts +40 -0
  270. package/dist/middleware/index.d.ts.map +1 -0
  271. package/dist/migrations/index.d.ts +10 -0
  272. package/dist/migrations/index.d.ts.map +1 -0
  273. package/dist/modules/filters.d.ts +150 -0
  274. package/dist/modules/filters.d.ts.map +1 -0
  275. package/dist/modules/guards.d.ts +188 -0
  276. package/dist/modules/guards.d.ts.map +1 -0
  277. package/dist/modules/index.d.ts +266 -0
  278. package/dist/modules/index.d.ts.map +1 -0
  279. package/dist/modules/index.js +514 -449
  280. package/dist/modules/interceptors.d.ts +242 -0
  281. package/dist/modules/interceptors.d.ts.map +1 -0
  282. package/dist/modules/lazy.d.ts +187 -0
  283. package/dist/modules/lazy.d.ts.map +1 -0
  284. package/dist/modules/lifecycle.d.ts +221 -0
  285. package/dist/modules/lifecycle.d.ts.map +1 -0
  286. package/dist/modules/metadata.d.ts +32 -0
  287. package/dist/modules/metadata.d.ts.map +1 -0
  288. package/dist/modules/pipes.d.ts +287 -0
  289. package/dist/modules/pipes.d.ts.map +1 -0
  290. package/dist/notification/channels/base.d.ts +32 -0
  291. package/dist/notification/channels/base.d.ts.map +1 -0
  292. package/dist/notification/channels/email.d.ts +37 -0
  293. package/dist/notification/channels/email.d.ts.map +1 -0
  294. package/dist/notification/channels/push.d.ts +37 -0
  295. package/dist/notification/channels/push.d.ts.map +1 -0
  296. package/dist/notification/channels/sms.d.ts +37 -0
  297. package/dist/notification/channels/sms.d.ts.map +1 -0
  298. package/dist/notification/channels/whatsapp.d.ts +37 -0
  299. package/dist/notification/channels/whatsapp.d.ts.map +1 -0
  300. package/dist/notification/index.d.ts +15 -0
  301. package/dist/notification/index.d.ts.map +1 -0
  302. package/dist/notification/service.d.ts +100 -0
  303. package/dist/notification/service.d.ts.map +1 -0
  304. package/dist/notification/types.d.ts +253 -0
  305. package/dist/notification/types.d.ts.map +1 -0
  306. package/dist/observability/__tests__/observability.test.d.ts +2 -0
  307. package/dist/observability/__tests__/observability.test.d.ts.map +1 -0
  308. package/dist/observability/breadcrumbs.d.ts +48 -0
  309. package/dist/observability/breadcrumbs.d.ts.map +1 -0
  310. package/dist/observability/index.d.ts +95 -0
  311. package/dist/observability/index.d.ts.map +1 -0
  312. package/dist/observability/interceptor.d.ts +19 -0
  313. package/dist/observability/interceptor.d.ts.map +1 -0
  314. package/dist/observability/service.d.ts +101 -0
  315. package/dist/observability/service.d.ts.map +1 -0
  316. package/dist/observability/trace.d.ts +21 -0
  317. package/dist/observability/trace.d.ts.map +1 -0
  318. package/dist/observability/types.d.ts +172 -0
  319. package/dist/observability/types.d.ts.map +1 -0
  320. package/dist/openapi/__tests__/decorators.test.d.ts +2 -0
  321. package/dist/openapi/__tests__/decorators.test.d.ts.map +1 -0
  322. package/dist/openapi/__tests__/document-builder.test.d.ts +2 -0
  323. package/dist/openapi/__tests__/document-builder.test.d.ts.map +1 -0
  324. package/dist/openapi/__tests__/route-scanner.test.d.ts +2 -0
  325. package/dist/openapi/__tests__/route-scanner.test.d.ts.map +1 -0
  326. package/dist/openapi/__tests__/schema-generator.test.d.ts +2 -0
  327. package/dist/openapi/__tests__/schema-generator.test.d.ts.map +1 -0
  328. package/dist/openapi/decorators.d.ts +173 -0
  329. package/dist/openapi/decorators.d.ts.map +1 -0
  330. package/dist/openapi/document-builder.d.ts +82 -0
  331. package/dist/openapi/document-builder.d.ts.map +1 -0
  332. package/dist/openapi/index.d.ts +48 -0
  333. package/dist/openapi/index.d.ts.map +1 -0
  334. package/dist/openapi/index.js +59 -40
  335. package/dist/openapi/metadata.d.ts +36 -0
  336. package/dist/openapi/metadata.d.ts.map +1 -0
  337. package/dist/openapi/route-scanner.d.ts +34 -0
  338. package/dist/openapi/route-scanner.d.ts.map +1 -0
  339. package/dist/openapi/schema-generator.d.ts +53 -0
  340. package/dist/openapi/schema-generator.d.ts.map +1 -0
  341. package/dist/openapi/swagger-module.d.ts +57 -0
  342. package/dist/openapi/swagger-module.d.ts.map +1 -0
  343. package/dist/openapi/types.d.ts +344 -0
  344. package/dist/openapi/types.d.ts.map +1 -0
  345. package/dist/orm/index.d.ts +10 -0
  346. package/dist/orm/index.d.ts.map +1 -0
  347. package/dist/router/index.d.ts +73 -0
  348. package/dist/router/index.d.ts.map +1 -0
  349. package/dist/router/linear.d.ts +54 -0
  350. package/dist/router/linear.d.ts.map +1 -0
  351. package/dist/router/regex.d.ts +49 -0
  352. package/dist/router/regex.d.ts.map +1 -0
  353. package/dist/router/tree.d.ts +112 -0
  354. package/dist/router/tree.d.ts.map +1 -0
  355. package/dist/rpc/index.d.ts +321 -0
  356. package/dist/rpc/index.d.ts.map +1 -0
  357. package/dist/schema/index.d.ts +10 -0
  358. package/dist/schema/index.d.ts.map +1 -0
  359. package/dist/security/index.d.ts +126 -0
  360. package/dist/security/index.d.ts.map +1 -0
  361. package/dist/ssg/index.d.ts +73 -0
  362. package/dist/ssg/index.d.ts.map +1 -0
  363. package/dist/storage/index.d.ts +99 -0
  364. package/dist/storage/index.d.ts.map +1 -0
  365. package/dist/telemetry/index.d.ts +376 -0
  366. package/dist/telemetry/index.d.ts.map +1 -0
  367. package/dist/template/index.d.ts +7 -0
  368. package/dist/template/index.d.ts.map +1 -0
  369. package/dist/templates/engine.d.ts +60 -0
  370. package/dist/templates/engine.d.ts.map +1 -0
  371. package/dist/templates/index.d.ts +9 -0
  372. package/dist/templates/index.d.ts.map +1 -0
  373. package/dist/templates/loader.d.ts +45 -0
  374. package/dist/templates/loader.d.ts.map +1 -0
  375. package/dist/templates/renderers/markdown.d.ts +46 -0
  376. package/dist/templates/renderers/markdown.d.ts.map +1 -0
  377. package/dist/templates/renderers/simple.d.ts +35 -0
  378. package/dist/templates/renderers/simple.d.ts.map +1 -0
  379. package/dist/templates/types.d.ts +138 -0
  380. package/dist/templates/types.d.ts.map +1 -0
  381. package/dist/testing/index.d.ts +539 -0
  382. package/dist/testing/index.d.ts.map +1 -0
  383. package/dist/types/index.d.ts +116 -0
  384. package/dist/types/index.d.ts.map +1 -0
  385. package/dist/validation/index.d.ts +89 -0
  386. package/dist/validation/index.d.ts.map +1 -0
  387. package/dist/validation/schemas.d.ts +243 -0
  388. package/dist/validation/schemas.d.ts.map +1 -0
  389. package/dist/websocket/index.d.ts +252 -0
  390. package/dist/websocket/index.d.ts.map +1 -0
  391. package/llms.txt +231 -0
  392. package/package.json +6 -2
  393. package/src/cli/ARCHITECTURE.md +3 -3
  394. package/src/cli/commands/add-frontend.ts +444 -0
  395. package/src/cli/commands/new.ts +23 -0
  396. package/src/cli/index.ts +1 -0
  397. package/src/cli/templates/frontend/react.ts +2 -1
  398. package/src/cli/templates/frontend/solid.ts +2 -1
  399. package/src/cli/templates/frontend/svelte.ts +2 -1
  400. package/src/cli/templates/frontend/vue.ts +2 -1
  401. package/src/cli/templates/project/api.ts +1 -1
  402. package/src/cli/templates/project/default.ts +1 -1
  403. package/src/cli/templates/project/fullstack.ts +14 -104
  404. package/src/cli/templates/project/website.ts +63 -12
  405. package/src/config/types.ts +21 -0
  406. package/src/graphql/built-in-engine.ts +598 -0
  407. package/src/graphql/context-builder.ts +110 -0
  408. package/src/graphql/decorators.ts +358 -0
  409. package/src/graphql/execution-pipeline.ts +227 -0
  410. package/src/graphql/graphql-module.ts +563 -0
  411. package/src/graphql/index.ts +101 -0
  412. package/src/graphql/metadata.ts +237 -0
  413. package/src/graphql/schema-builder.ts +319 -0
  414. package/src/graphql/subscription-handler.ts +283 -0
  415. package/src/graphql/types.ts +324 -0
  416. package/src/index.ts +3 -0
  417. package/src/modules/index.ts +48 -1
  418. package/tests/integration/cli.test.ts +19 -19
  419. package/tests/unit/cli.test.ts +1 -1
  420. package/tests/unit/graphql.test.ts +991 -0
  421. package/tsconfig.declaration.json +14 -0
@@ -0,0 +1,283 @@
1
+ /**
2
+ * GraphQL Subscription Handler
3
+ *
4
+ * Implements the graphql-transport-ws protocol over Bun's native WebSocket.
5
+ * Registered via app.setWebSocketHandler() so subscriptions run on the same
6
+ * port as the HTTP server — no separate port needed.
7
+ *
8
+ * Protocol spec: https://github.com/enisdenjo/graphql-ws/blob/master/PROTOCOL.md
9
+ *
10
+ * ## Usage
11
+ * Automatically configured by GraphQLModule.setup() when subscriptions: true.
12
+ * Requires an engine with supportsSubscriptions = true (e.g. GraphQLJsAdapter).
13
+ */
14
+
15
+ import type { GraphQLEngine, GraphQLContext, ResolvedSchema } from "./types";
16
+ import type { Container } from "../container";
17
+ import type { Guard, Interceptor } from "./execution-pipeline";
18
+ import { buildGraphQLContext } from "./context-builder";
19
+
20
+ // ============= Protocol Message Types =============
21
+
22
+ interface ConnectionInitMessage {
23
+ type: "connection_init";
24
+ payload?: Record<string, unknown>;
25
+ }
26
+ interface ConnectionAckMessage {
27
+ type: "connection_ack";
28
+ }
29
+ interface SubscribeMessage {
30
+ type: "subscribe";
31
+ id: string;
32
+ payload: {
33
+ query: string;
34
+ variables?: Record<string, unknown>;
35
+ operationName?: string;
36
+ };
37
+ }
38
+ interface NextMessage {
39
+ type: "next";
40
+ id: string;
41
+ payload: { data?: unknown; errors?: unknown[] };
42
+ }
43
+ interface ErrorMessage {
44
+ type: "error";
45
+ id: string;
46
+ payload: Array<{ message: string }>;
47
+ }
48
+ interface CompleteMessage {
49
+ type: "complete";
50
+ id?: string;
51
+ }
52
+
53
+ type ServerMessage = ConnectionAckMessage | NextMessage | ErrorMessage | CompleteMessage;
54
+ type ClientMessage = ConnectionInitMessage | SubscribeMessage | CompleteMessage;
55
+
56
+ // ============= Connection State =============
57
+
58
+ interface SubscriptionState {
59
+ generator: AsyncGenerator<unknown>;
60
+ }
61
+
62
+ interface ConnectionState {
63
+ subscriptions: Map<string, SubscriptionState>;
64
+ initialized: boolean;
65
+ }
66
+
67
+ // ============= WebSocket Data =============
68
+
69
+ interface WsData {
70
+ connectionId: string;
71
+ }
72
+
73
+ // ============= Subscription Handler =============
74
+
75
+ export class SubscriptionHandler {
76
+ private connections = new Map<string, ConnectionState>();
77
+
78
+ constructor(
79
+ private engine: GraphQLEngine,
80
+ private engineSchema: unknown,
81
+ private graphqlPath: string,
82
+ private container: Container,
83
+ private globalGuards: Guard[],
84
+ private globalInterceptors: Interceptor[],
85
+ ) {}
86
+
87
+ /**
88
+ * Returns a Bun WebSocketHandler to register on the server via app.setWebSocketHandler().
89
+ * Attaches an __upgradeHandler so Application.listen() can delegate WebSocket upgrades.
90
+ */
91
+ getWebSocketConfig(): Bun.WebSocketHandler<WsData> & { __upgradeHandler: (req: Request, srv: Bun.Server) => Response | undefined } {
92
+ const upgradeHandler = this.handleUpgrade.bind(this);
93
+ return {
94
+ __upgradeHandler: upgradeHandler,
95
+ open: (ws) => {
96
+ this.connections.set(ws.data.connectionId, {
97
+ subscriptions: new Map(),
98
+ initialized: false,
99
+ });
100
+ },
101
+
102
+ message: async (ws, raw) => {
103
+ try {
104
+ const text =
105
+ typeof raw === "string" ? raw : new TextDecoder().decode(raw as ArrayBuffer);
106
+ const msg = JSON.parse(text) as ClientMessage;
107
+ await this.handleMessage(ws, msg);
108
+ } catch (err) {
109
+ this.send(ws, {
110
+ type: "error",
111
+ id: "",
112
+ payload: [{ message: `Protocol error: ${(err as Error).message}` }],
113
+ });
114
+ }
115
+ },
116
+
117
+ close: (ws) => {
118
+ const state = this.connections.get(ws.data.connectionId);
119
+ if (state) {
120
+ // Cancel all active subscriptions
121
+ for (const sub of state.subscriptions.values()) {
122
+ sub.generator.return?.(undefined);
123
+ }
124
+ this.connections.delete(ws.data.connectionId);
125
+ }
126
+ },
127
+
128
+ error: (ws, error) => {
129
+ console.error("[GraphQL WS] WebSocket error:", error);
130
+ },
131
+ };
132
+ }
133
+
134
+ /**
135
+ * Middleware-like upgrade handler.
136
+ * Call this from the app's fetch function for WebSocket upgrade requests.
137
+ * Returns a Response if not a GraphQL WS path, undefined if upgraded.
138
+ */
139
+ handleUpgrade(req: Request, server: Bun.Server): Response | undefined {
140
+ const url = new URL(req.url);
141
+ if (url.pathname !== this.graphqlPath) {
142
+ return undefined; // Not our path — let normal routing handle it
143
+ }
144
+
145
+ const protocol = req.headers.get("sec-websocket-protocol") ?? "";
146
+ if (!protocol.includes("graphql-transport-ws")) {
147
+ return new Response("Unsupported WebSocket protocol", { status: 426 });
148
+ }
149
+
150
+ const connectionId = crypto.randomUUID();
151
+ const upgraded = server.upgrade<WsData>(req, {
152
+ headers: {
153
+ "Sec-WebSocket-Protocol": "graphql-transport-ws",
154
+ },
155
+ data: { connectionId },
156
+ });
157
+
158
+ return upgraded ? undefined : new Response("WebSocket upgrade failed", { status: 400 });
159
+ }
160
+
161
+ // ============= Message Handlers =============
162
+
163
+ private async handleMessage(
164
+ ws: Bun.ServerWebSocket<WsData>,
165
+ msg: ClientMessage,
166
+ ): Promise<void> {
167
+ const state = this.connections.get(ws.data.connectionId);
168
+ if (!state) return;
169
+
170
+ switch (msg.type) {
171
+ case "connection_init":
172
+ if (state.initialized) {
173
+ // Already initialized — send error and close
174
+ ws.close(4429, "Too many initialisation requests");
175
+ return;
176
+ }
177
+ state.initialized = true;
178
+ this.send(ws, { type: "connection_ack" });
179
+ break;
180
+
181
+ case "subscribe":
182
+ if (!state.initialized) {
183
+ ws.close(4401, "Unauthorized: connection not initialized");
184
+ return;
185
+ }
186
+ if (state.subscriptions.has(msg.id)) {
187
+ ws.close(4409, `Subscriber for ${msg.id} already exists`);
188
+ return;
189
+ }
190
+ await this.handleSubscribe(ws, state, msg);
191
+ break;
192
+
193
+ case "complete":
194
+ if (msg.id) {
195
+ const sub = state.subscriptions.get(msg.id);
196
+ if (sub) {
197
+ sub.generator.return?.(undefined);
198
+ state.subscriptions.delete(msg.id);
199
+ }
200
+ }
201
+ break;
202
+ }
203
+ }
204
+
205
+ private async handleSubscribe(
206
+ ws: Bun.ServerWebSocket<WsData>,
207
+ state: ConnectionState,
208
+ msg: SubscribeMessage,
209
+ ): Promise<void> {
210
+ if (!this.engine.subscribe) {
211
+ this.send(ws, {
212
+ type: "error",
213
+ id: msg.id,
214
+ payload: [
215
+ {
216
+ message:
217
+ "Subscriptions are not supported by the configured GraphQL engine. " +
218
+ "Use GraphQLJsAdapter for subscription support.",
219
+ },
220
+ ],
221
+ });
222
+ return;
223
+ }
224
+
225
+ const context: GraphQLContext = {
226
+ request: new Request(`ws://localhost${this.graphqlPath}`),
227
+ user: undefined,
228
+ httpContext: null,
229
+ };
230
+
231
+ let generator: AsyncGenerator<unknown>;
232
+ try {
233
+ generator = await this.engine.subscribe(
234
+ this.engineSchema,
235
+ msg.payload.query,
236
+ msg.payload.variables ?? {},
237
+ context,
238
+ msg.payload.operationName,
239
+ );
240
+ } catch (err) {
241
+ this.send(ws, {
242
+ type: "error",
243
+ id: msg.id,
244
+ payload: [{ message: (err as Error).message }],
245
+ });
246
+ return;
247
+ }
248
+
249
+ state.subscriptions.set(msg.id, { generator });
250
+
251
+ // Stream results
252
+ (async () => {
253
+ try {
254
+ for await (const result of generator) {
255
+ if (!state.subscriptions.has(msg.id)) break; // Cancelled
256
+ this.send(ws, {
257
+ type: "next",
258
+ id: msg.id,
259
+ payload: result as { data?: unknown; errors?: unknown[] },
260
+ });
261
+ }
262
+ // Subscription completed
263
+ this.send(ws, { type: "complete", id: msg.id });
264
+ state.subscriptions.delete(msg.id);
265
+ } catch (err) {
266
+ this.send(ws, {
267
+ type: "error",
268
+ id: msg.id,
269
+ payload: [{ message: (err as Error).message }],
270
+ });
271
+ state.subscriptions.delete(msg.id);
272
+ }
273
+ })();
274
+ }
275
+
276
+ private send(ws: Bun.ServerWebSocket<WsData>, msg: ServerMessage): void {
277
+ try {
278
+ ws.send(JSON.stringify(msg));
279
+ } catch {
280
+ // Connection may have closed — ignore
281
+ }
282
+ }
283
+ }
@@ -0,0 +1,324 @@
1
+ /**
2
+ * GraphQL Module Types
3
+ *
4
+ * Core type definitions for the Bueno GraphQL integration layer.
5
+ */
6
+
7
+ // ============= Constructor Type =============
8
+
9
+ export type Constructor<T = unknown> = new (...args: unknown[]) => T;
10
+
11
+ // ============= Scalar Types =============
12
+
13
+ /**
14
+ * Represents a GraphQL scalar type via its JS constructor.
15
+ * Usage: () => String, () => Number, () => Boolean, () => GraphQLID
16
+ */
17
+ export type GraphQLScalar =
18
+ | StringConstructor
19
+ | NumberConstructor
20
+ | BooleanConstructor
21
+ | typeof GraphQLID
22
+ | typeof GraphQLInt
23
+ | typeof GraphQLFloat;
24
+
25
+ /**
26
+ * A thunk that returns a type constructor or array of constructors.
27
+ * Used to avoid circular reference issues in type definitions.
28
+ *
29
+ * @example
30
+ * () => String // GraphQL String scalar
31
+ * () => Number // GraphQL Float scalar
32
+ * () => [User] // [User!]! list
33
+ * () => User // User object type
34
+ */
35
+ export type TypeFn = () => Constructor | Constructor[] | GraphQLScalar;
36
+
37
+ // ============= Scalar Sentinels =============
38
+
39
+ /**
40
+ * Sentinel class representing GraphQL ID scalar.
41
+ * Usage: @Field(() => GraphQLID)
42
+ */
43
+ export class GraphQLID {
44
+ static readonly __type = "ID";
45
+ }
46
+
47
+ /**
48
+ * Sentinel class representing GraphQL Int scalar.
49
+ * Usage: @Field(() => GraphQLInt)
50
+ */
51
+ export class GraphQLInt {
52
+ static readonly __type = "Int";
53
+ }
54
+
55
+ /**
56
+ * Sentinel class representing GraphQL Float scalar.
57
+ * Usage: @Field(() => GraphQLFloat)
58
+ */
59
+ export class GraphQLFloat {
60
+ static readonly __type = "Float";
61
+ }
62
+
63
+ // ============= Metadata Shapes =============
64
+
65
+ /** Options for @Field decorator */
66
+ export interface FieldDecoratorOptions {
67
+ /** Whether the field can be null (default: false → non-null) */
68
+ nullable?: boolean;
69
+ /** Human-readable description */
70
+ description?: string;
71
+ /** Deprecation reason */
72
+ deprecationReason?: string;
73
+ /** Default value for input types */
74
+ defaultValue?: unknown;
75
+ }
76
+
77
+ /** Options for @Query/@Mutation/@Subscription decorators */
78
+ export interface FieldOptions extends FieldDecoratorOptions {
79
+ /** GraphQL field name override (default: method name) */
80
+ name?: string;
81
+ }
82
+
83
+ /** Metadata stored per @Field-decorated property */
84
+ export interface FieldMetadata {
85
+ propertyKey: string;
86
+ typeFn: TypeFn;
87
+ nullable: boolean;
88
+ description?: string;
89
+ deprecationReason?: string;
90
+ defaultValue?: unknown;
91
+ }
92
+
93
+ /** Metadata for a single resolver method parameter */
94
+ export interface ParamMetadata {
95
+ index: number;
96
+ kind: "args" | "argsObject" | "context";
97
+ /** For @Args('name') — the specific argument name */
98
+ argName?: string;
99
+ /** For @Args('name', InputType) — the input object type */
100
+ inputTypeFn?: TypeFn;
101
+ }
102
+
103
+ /** Metadata stored per @Query/@Mutation/@Subscription method */
104
+ export interface ResolverFieldMetadata {
105
+ /** Actual method name on the class */
106
+ methodName: string;
107
+ /** GraphQL field name (defaults to methodName) */
108
+ fieldName: string;
109
+ typeFn: TypeFn;
110
+ kind: "query" | "mutation" | "subscription";
111
+ nullable: boolean;
112
+ description?: string;
113
+ deprecationReason?: string;
114
+ paramMetadata: ParamMetadata[];
115
+ }
116
+
117
+ /** Metadata stored per @Resolver-decorated class */
118
+ export interface ResolverClassMetadata {
119
+ /** GraphQL type name (default: class name) */
120
+ name: string;
121
+ }
122
+
123
+ /** Metadata stored per @ObjectType / @InputType class */
124
+ export interface TypeClassMetadata {
125
+ name: string;
126
+ kind: "object" | "input";
127
+ description?: string;
128
+ }
129
+
130
+ // ============= Schema Representation =============
131
+
132
+ /** A single resolvable field in the built schema */
133
+ export interface ResolvedField {
134
+ resolverInstance: unknown;
135
+ methodName: string;
136
+ paramMetadata: ParamMetadata[];
137
+ typeFn: TypeFn;
138
+ nullable: boolean;
139
+ }
140
+
141
+ /** Internal schema representation consumed by the built-in engine */
142
+ export interface ResolvedSchema {
143
+ queryFields: Map<string, ResolvedField>;
144
+ mutationFields: Map<string, ResolvedField>;
145
+ subscriptionFields: Map<string, ResolvedField>;
146
+ }
147
+
148
+ // ============= GraphQL Context =============
149
+
150
+ /** Context available inside resolver methods */
151
+ export interface GraphQLContext {
152
+ /** The original HTTP Request */
153
+ request: Request;
154
+ /** Authenticated user (set by auth guards via context.set('user', ...)) */
155
+ user?: unknown;
156
+ /** Reference to the HTTP Context for advanced use */
157
+ httpContext: unknown;
158
+ /** Allow arbitrary values */
159
+ [key: string]: unknown;
160
+ }
161
+
162
+ // ============= Execution Results =============
163
+
164
+ /** A GraphQL error entry in the response */
165
+ export interface GraphQLError {
166
+ message: string;
167
+ locations?: Array<{ line: number; column: number }>;
168
+ path?: Array<string | number>;
169
+ extensions?: Record<string, unknown>;
170
+ }
171
+
172
+ /** The GraphQL response envelope */
173
+ export interface GraphQLResult {
174
+ data?: Record<string, unknown> | null;
175
+ errors?: GraphQLError[];
176
+ }
177
+
178
+ // ============= Engine Interface =============
179
+
180
+ /**
181
+ * Pluggable GraphQL execution engine.
182
+ * Implement this interface to use graphql-js, GraphQL Yoga, Mercurius, etc.
183
+ *
184
+ * @example
185
+ * ```typescript
186
+ * import * as graphqlJs from 'graphql';
187
+ * import { GraphQLJsAdapter } from '@buenojs/bueno/graphql';
188
+ *
189
+ * GraphQLModule.setup(app, {
190
+ * engine: new GraphQLJsAdapter(graphqlJs),
191
+ * resolvers: [UserResolver],
192
+ * });
193
+ * ```
194
+ */
195
+ export interface GraphQLEngine {
196
+ /**
197
+ * Build the internal schema representation from resolver and type metadata.
198
+ * Returns an opaque schema object that is passed back to execute().
199
+ */
200
+ buildSchema(
201
+ resolvers: ResolverFieldsByType,
202
+ types: Map<string, FieldMetadata[]>,
203
+ sdl: string,
204
+ ): unknown;
205
+
206
+ /**
207
+ * Execute a GraphQL query or mutation.
208
+ */
209
+ execute(
210
+ schema: unknown,
211
+ query: string,
212
+ variables: Record<string, unknown>,
213
+ context: GraphQLContext,
214
+ operationName?: string,
215
+ ): Promise<GraphQLResult>;
216
+
217
+ /**
218
+ * Execute a GraphQL subscription (optional).
219
+ * Returns an async generator that yields results.
220
+ */
221
+ subscribe?(
222
+ schema: unknown,
223
+ query: string,
224
+ variables: Record<string, unknown>,
225
+ context: GraphQLContext,
226
+ operationName?: string,
227
+ ): Promise<AsyncGenerator<GraphQLResult>>;
228
+
229
+ /**
230
+ * Whether this engine supports introspection queries.
231
+ * Used to determine if the GraphQL Playground should be enabled.
232
+ */
233
+ readonly supportsIntrospection: boolean;
234
+
235
+ /**
236
+ * Whether this engine supports subscriptions.
237
+ */
238
+ readonly supportsSubscriptions: boolean;
239
+ }
240
+
241
+ /** Resolver fields organized by root type */
242
+ export interface ResolverFieldsByType {
243
+ queries: Map<string, ResolvedField>;
244
+ mutations: Map<string, ResolvedField>;
245
+ subscriptions: Map<string, ResolvedField>;
246
+ }
247
+
248
+ // ============= Module Options =============
249
+
250
+ /**
251
+ * Options passed to GraphQLModule.setup()
252
+ */
253
+ export interface GraphQLModuleOptions {
254
+ /**
255
+ * Resolver classes to register.
256
+ * Dependencies are resolved from the DI container.
257
+ */
258
+ resolvers: Constructor[];
259
+
260
+ /**
261
+ * GraphQL engine adapter (default: built-in lightweight engine).
262
+ * Use GraphQLJsAdapter for full spec compliance.
263
+ */
264
+ engine?: GraphQLEngine;
265
+
266
+ /**
267
+ * HTTP path for the GraphQL endpoint (default: '/graphql').
268
+ */
269
+ path?: string;
270
+
271
+ /**
272
+ * Enable GraphiQL playground UI at GET <path>.
273
+ * Default: true when using an engine with supportsIntrospection,
274
+ * false when using the built-in engine.
275
+ * Set to true to force-enable even with the built-in engine (with warning).
276
+ */
277
+ playground?: boolean;
278
+
279
+ /**
280
+ * Serve the SDL at GET <path>/schema (default: true).
281
+ */
282
+ introspection?: boolean;
283
+
284
+ /**
285
+ * Enable WebSocket subscriptions (default: false).
286
+ * Requires an engine with supportsSubscriptions.
287
+ */
288
+ subscriptions?: boolean;
289
+
290
+ /**
291
+ * Sync @Field metadata to the OpenAPI property store (default: false).
292
+ * Enables unified types: one class works for both GraphQL and REST/OpenAPI.
293
+ * Requires @buenojs/bueno/openapi to be in scope.
294
+ */
295
+ syncOpenAPI?: boolean;
296
+
297
+ /** Maximum query complexity score (default: 1000) */
298
+ complexityLimit?: number;
299
+
300
+ /** Maximum query depth (default: 10) */
301
+ maxDepth?: number;
302
+ }
303
+
304
+ // ============= Config Interface =============
305
+
306
+ /**
307
+ * GraphQL configuration added to BuenoConfig.
308
+ */
309
+ export interface GraphQLConfig {
310
+ /** Enable GraphQL support (default: false) */
311
+ enabled?: boolean;
312
+ /** HTTP path (default: '/graphql') */
313
+ path?: string;
314
+ /** Enable playground (default: auto) */
315
+ playground?: boolean;
316
+ /** Enable introspection SDL endpoint (default: true) */
317
+ introspection?: boolean;
318
+ /** Maximum query complexity (default: 1000) */
319
+ complexityLimit?: number;
320
+ /** Maximum query depth (default: 10) */
321
+ maxDepth?: number;
322
+ /** Enable subscriptions (default: false) */
323
+ subscriptions?: boolean;
324
+ }
package/src/index.ts CHANGED
@@ -418,6 +418,9 @@ export {
418
418
  type ObservabilityConfig,
419
419
  } from "./observability";
420
420
 
421
+ // GraphQL
422
+ export type { GraphQLConfig } from "./graphql/types";
423
+
421
424
  // Types
422
425
  export type {
423
426
  HTTPMethod,
@@ -356,6 +356,8 @@ export class Application {
356
356
  new Map();
357
357
  private moduleLoader: ModuleLoader;
358
358
  private loadedLazyModules = new Set<Constructor>();
359
+ // biome-ignore lint/suspicious/noExplicitAny: WebSocket data type is user-defined
360
+ private websocketHandler: Bun.WebSocketHandler<any> | null = null;
359
361
 
360
362
  constructor(moduleClass: Constructor) {
361
363
  this.container = new Container();
@@ -385,6 +387,37 @@ export class Application {
385
387
  return this;
386
388
  }
387
389
 
390
+ /**
391
+ * Get the list of global guards (live reference).
392
+ * Used by the GraphQL module to run guards on resolver methods.
393
+ */
394
+ getGlobalGuards(): Guard[] {
395
+ return this.globalGuards;
396
+ }
397
+
398
+ /**
399
+ * Get the list of global interceptors (live reference).
400
+ * Used by the GraphQL module to run interceptors on resolver methods.
401
+ */
402
+ getGlobalInterceptors(): Interceptor[] {
403
+ return this.globalInterceptors;
404
+ }
405
+
406
+ /**
407
+ * Register a WebSocket handler to be used when the server starts.
408
+ * Called by the GraphQL module to enable subscriptions on the same port.
409
+ *
410
+ * @example
411
+ * ```typescript
412
+ * app.setWebSocketHandler(subscriptionHandler.getWebSocketConfig());
413
+ * await app.listen(3000);
414
+ * ```
415
+ */
416
+ // biome-ignore lint/suspicious/noExplicitAny: WebSocket data type is user-defined
417
+ setWebSocketHandler(handler: Bun.WebSocketHandler<any>): void {
418
+ this.websocketHandler = handler;
419
+ }
420
+
388
421
  /**
389
422
  * Add global pipes that apply to all parameters
390
423
  * Global pipes run before parameter decorator pipes
@@ -793,7 +826,21 @@ export class Application {
793
826
  this.server = Bun.serve({
794
827
  port,
795
828
  hostname,
796
- fetch: async (request: Request) => {
829
+ ...(this.websocketHandler ? { websocket: this.websocketHandler } : {}),
830
+ fetch: async (request: Request, server: Bun.Server) => {
831
+ // Handle WebSocket upgrade requests for subscriptions
832
+ if (
833
+ this.websocketHandler &&
834
+ request.headers.get("upgrade")?.toLowerCase() === "websocket"
835
+ ) {
836
+ // The GraphQL subscription handler may have registered an upgrade callback
837
+ const wsUpgradeHandler = (this.websocketHandler as unknown as { __upgradeHandler?: (req: Request, srv: Bun.Server) => Response | undefined }).__upgradeHandler;
838
+ if (wsUpgradeHandler) {
839
+ const response = wsUpgradeHandler(request, server);
840
+ if (response) return response;
841
+ }
842
+ }
843
+
797
844
  // Reject new requests during shutdown
798
845
  if (this.isShuttingDown) {
799
846
  return new Response("Service Unavailable", { status: 503 });