@stacksjs/defaults 0.70.206 → 0.70.208

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 (408) hide show
  1. package/TODO.md +21 -0
  2. package/ai/AGENTS.md +79 -0
  3. package/ai/README.md +45 -0
  4. package/ai/claude/launch.json +12 -0
  5. package/ai/skills/stacks-actions/SKILL.md +128 -0
  6. package/ai/skills/stacks-ai/SKILL.md +276 -0
  7. package/ai/skills/stacks-alias/SKILL.md +94 -0
  8. package/ai/skills/stacks-analytics/SKILL.md +91 -0
  9. package/ai/skills/stacks-api/SKILL.md +738 -0
  10. package/ai/skills/stacks-arrays/SKILL.md +277 -0
  11. package/ai/skills/stacks-auth/SKILL.md +422 -0
  12. package/ai/skills/stacks-auto-imports/SKILL.md +138 -0
  13. package/ai/skills/stacks-brandkit/SKILL.md +811 -0
  14. package/ai/skills/stacks-browse/SKILL.md +127 -0
  15. package/ai/skills/stacks-browse/scripts/browse.ts +492 -0
  16. package/ai/skills/stacks-browser/SKILL.md +145 -0
  17. package/ai/skills/stacks-buddy/SKILL.md +676 -0
  18. package/ai/skills/stacks-build/SKILL.md +163 -0
  19. package/ai/skills/stacks-cache/SKILL.md +125 -0
  20. package/ai/skills/stacks-calendar/SKILL.md +113 -0
  21. package/ai/skills/stacks-chat/SKILL.md +371 -0
  22. package/ai/skills/stacks-cli/SKILL.md +112 -0
  23. package/ai/skills/stacks-cloud/SKILL.md +192 -0
  24. package/ai/skills/stacks-cms/SKILL.md +217 -0
  25. package/ai/skills/stacks-collections/SKILL.md +82 -0
  26. package/ai/skills/stacks-commerce/SKILL.md +114 -0
  27. package/ai/skills/stacks-composables/SKILL.md +161 -0
  28. package/ai/skills/stacks-config/SKILL.md +144 -0
  29. package/ai/skills/stacks-configuration/SKILL.md +154 -0
  30. package/ai/skills/stacks-cron/SKILL.md +123 -0
  31. package/ai/skills/stacks-crosswind/SKILL.md +190 -0
  32. package/ai/skills/stacks-dashboard/SKILL.md +173 -0
  33. package/ai/skills/stacks-database/SKILL.md +286 -0
  34. package/ai/skills/stacks-datetime/SKILL.md +269 -0
  35. package/ai/skills/stacks-dependencies/SKILL.md +111 -0
  36. package/ai/skills/stacks-deploy/SKILL.md +102 -0
  37. package/ai/skills/stacks-design-brutalist/SKILL.md +110 -0
  38. package/ai/skills/stacks-design-minimalist/SKILL.md +115 -0
  39. package/ai/skills/stacks-design-output/SKILL.md +55 -0
  40. package/ai/skills/stacks-design-soft/SKILL.md +156 -0
  41. package/ai/skills/stacks-design-taste/SKILL.md +1012 -0
  42. package/ai/skills/stacks-design-taste-codex/SKILL.md +294 -0
  43. package/ai/skills/stacks-desktop/SKILL.md +78 -0
  44. package/ai/skills/stacks-development/SKILL.md +298 -0
  45. package/ai/skills/stacks-dns/SKILL.md +149 -0
  46. package/ai/skills/stacks-docs/SKILL.md +109 -0
  47. package/ai/skills/stacks-email/SKILL.md +236 -0
  48. package/ai/skills/stacks-enums/SKILL.md +100 -0
  49. package/ai/skills/stacks-env/SKILL.md +181 -0
  50. package/ai/skills/stacks-error-handling/SKILL.md +137 -0
  51. package/ai/skills/stacks-events/SKILL.md +228 -0
  52. package/ai/skills/stacks-faker/SKILL.md +158 -0
  53. package/ai/skills/stacks-git/SKILL.md +158 -0
  54. package/ai/skills/stacks-guard/SKILL.md +98 -0
  55. package/ai/skills/stacks-health/SKILL.md +75 -0
  56. package/ai/skills/stacks-http/SKILL.md +316 -0
  57. package/ai/skills/stacks-i18n/SKILL.md +198 -0
  58. package/ai/skills/stacks-image-to-code/SKILL.md +629 -0
  59. package/ai/skills/stacks-imagegen-mobile/SKILL.md +1474 -0
  60. package/ai/skills/stacks-imagegen-web/SKILL.md +998 -0
  61. package/ai/skills/stacks-investigate/SKILL.md +119 -0
  62. package/ai/skills/stacks-jobs/SKILL.md +136 -0
  63. package/ai/skills/stacks-lint/SKILL.md +184 -0
  64. package/ai/skills/stacks-listeners/SKILL.md +99 -0
  65. package/ai/skills/stacks-logging/SKILL.md +78 -0
  66. package/ai/skills/stacks-mail/SKILL.md +120 -0
  67. package/ai/skills/stacks-middleware/SKILL.md +249 -0
  68. package/ai/skills/stacks-migrations/SKILL.md +105 -0
  69. package/ai/skills/stacks-models/SKILL.md +267 -0
  70. package/ai/skills/stacks-new-feature/SKILL.md +206 -0
  71. package/ai/skills/stacks-notifications/SKILL.md +210 -0
  72. package/ai/skills/stacks-objects/SKILL.md +205 -0
  73. package/ai/skills/stacks-office-hours/SKILL.md +134 -0
  74. package/ai/skills/stacks-orm/SKILL.md +342 -0
  75. package/ai/skills/stacks-path/SKILL.md +118 -0
  76. package/ai/skills/stacks-payments/SKILL.md +373 -0
  77. package/ai/skills/stacks-plan-review/SKILL.md +152 -0
  78. package/ai/skills/stacks-plugins/SKILL.md +149 -0
  79. package/ai/skills/stacks-push/SKILL.md +376 -0
  80. package/ai/skills/stacks-query-builder/SKILL.md +128 -0
  81. package/ai/skills/stacks-queue/SKILL.md +559 -0
  82. package/ai/skills/stacks-realtime/SKILL.md +442 -0
  83. package/ai/skills/stacks-redesign/SKILL.md +182 -0
  84. package/ai/skills/stacks-registry/SKILL.md +58 -0
  85. package/ai/skills/stacks-repl/SKILL.md +80 -0
  86. package/ai/skills/stacks-retro/SKILL.md +122 -0
  87. package/ai/skills/stacks-review/SKILL.md +135 -0
  88. package/ai/skills/stacks-router/SKILL.md +231 -0
  89. package/ai/skills/stacks-routes/SKILL.md +105 -0
  90. package/ai/skills/stacks-scaffolding/SKILL.md +162 -0
  91. package/ai/skills/stacks-scheduler/SKILL.md +363 -0
  92. package/ai/skills/stacks-search-engine/SKILL.md +112 -0
  93. package/ai/skills/stacks-security/SKILL.md +129 -0
  94. package/ai/skills/stacks-security-audit/SKILL.md +128 -0
  95. package/ai/skills/stacks-server/SKILL.md +458 -0
  96. package/ai/skills/stacks-shell/SKILL.md +62 -0
  97. package/ai/skills/stacks-slug/SKILL.md +87 -0
  98. package/ai/skills/stacks-sms/SKILL.md +385 -0
  99. package/ai/skills/stacks-socials/SKILL.md +303 -0
  100. package/ai/skills/stacks-storage/SKILL.md +576 -0
  101. package/ai/skills/stacks-strings/SKILL.md +416 -0
  102. package/ai/skills/stacks-stx/SKILL.md +176 -0
  103. package/ai/skills/stacks-technical-diagrams/LICENSE +22 -0
  104. package/ai/skills/stacks-technical-diagrams/SKILL.md +290 -0
  105. package/ai/skills/stacks-technical-diagrams/agents/openai.yaml +4 -0
  106. package/ai/skills/stacks-technical-diagrams/assets/template.html +1252 -0
  107. package/ai/skills/stacks-technical-diagrams/bin/technical-diagrams.mjs +289 -0
  108. package/ai/skills/stacks-technical-diagrams/bunfig.toml +1 -0
  109. package/ai/skills/stacks-technical-diagrams/examples/agent-run.lifecycle.json +64 -0
  110. package/ai/skills/stacks-technical-diagrams/examples/agent-tool-call.workflow.json +88 -0
  111. package/ai/skills/stacks-technical-diagrams/examples/cache-miss-request.sequence.json +75 -0
  112. package/ai/skills/stacks-technical-diagrams/examples/product-analytics.dataflow.json +70 -0
  113. package/ai/skills/stacks-technical-diagrams/examples/web-app.architecture.json +41 -0
  114. package/ai/skills/stacks-technical-diagrams/renderers/architecture/grid.mjs +62 -0
  115. package/ai/skills/stacks-technical-diagrams/renderers/architecture/render-architecture.mjs +371 -0
  116. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/README.md +82 -0
  117. package/ai/skills/stacks-technical-diagrams/renderers/dataflow/render-dataflow.mjs +295 -0
  118. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/README.md +91 -0
  119. package/ai/skills/stacks-technical-diagrams/renderers/lifecycle/render-lifecycle.mjs +384 -0
  120. package/ai/skills/stacks-technical-diagrams/renderers/sequence/README.md +84 -0
  121. package/ai/skills/stacks-technical-diagrams/renderers/sequence/render-sequence.mjs +257 -0
  122. package/ai/skills/stacks-technical-diagrams/renderers/shared/cli.mjs +42 -0
  123. package/ai/skills/stacks-technical-diagrams/renderers/shared/generated-validators.mjs +13 -0
  124. package/ai/skills/stacks-technical-diagrams/renderers/shared/geometry.mjs +230 -0
  125. package/ai/skills/stacks-technical-diagrams/renderers/shared/layout-report.mjs +40 -0
  126. package/ai/skills/stacks-technical-diagrams/renderers/shared/utils.mjs +88 -0
  127. package/ai/skills/stacks-technical-diagrams/renderers/shared/validator.mjs +40 -0
  128. package/ai/skills/stacks-technical-diagrams/renderers/workflow/README.md +103 -0
  129. package/ai/skills/stacks-technical-diagrams/renderers/workflow/render-workflow.mjs +481 -0
  130. package/ai/skills/stacks-technical-diagrams/schemas/README.md +68 -0
  131. package/ai/skills/stacks-technical-diagrams/schemas/architecture.schema.json +121 -0
  132. package/ai/skills/stacks-technical-diagrams/schemas/common.schema.json +43 -0
  133. package/ai/skills/stacks-technical-diagrams/schemas/dataflow.schema.json +221 -0
  134. package/ai/skills/stacks-technical-diagrams/schemas/lifecycle.schema.json +241 -0
  135. package/ai/skills/stacks-technical-diagrams/schemas/sequence.schema.json +186 -0
  136. package/ai/skills/stacks-technical-diagrams/schemas/workflow.schema.json +332 -0
  137. package/ai/skills/stacks-technical-diagrams/scripts/check-render-output.mjs +297 -0
  138. package/ai/skills/stacks-technical-diagrams/scripts/render-examples.mjs +28 -0
  139. package/ai/skills/stacks-testing/SKILL.md +129 -0
  140. package/ai/skills/stacks-tunnel/SKILL.md +125 -0
  141. package/ai/skills/stacks-types/SKILL.md +178 -0
  142. package/ai/skills/stacks-ui/SKILL.md +246 -0
  143. package/ai/skills/stacks-utils/SKILL.md +444 -0
  144. package/ai/skills/stacks-validation/SKILL.md +371 -0
  145. package/ai/skills/stacks-whois/SKILL.md +315 -0
  146. package/assets/world-map-data.ts +121 -0
  147. package/bootstrap.ts +114 -0
  148. package/docs/api-examples.md +46 -0
  149. package/docs/index.md +24 -0
  150. package/docs/markdown-examples.md +87 -0
  151. package/functions/analytics.ts +97 -0
  152. package/functions/api.ts +143 -0
  153. package/functions/auth.ts +208 -0
  154. package/functions/billing/payments.ts +149 -0
  155. package/functions/blog.ts +120 -0
  156. package/functions/cms/categorizables.ts +107 -0
  157. package/functions/cms/pages.ts +108 -0
  158. package/functions/cms/posts.ts +100 -0
  159. package/functions/cms/taggables.ts +102 -0
  160. package/functions/commerce/coupons.ts +128 -0
  161. package/functions/commerce/customers.ts +128 -0
  162. package/functions/commerce/gift-cards.ts +119 -0
  163. package/functions/commerce/orders.ts +112 -0
  164. package/functions/commerce/payments.ts +119 -0
  165. package/functions/commerce/products/categories.ts +123 -0
  166. package/functions/commerce/products/manufacturers.ts +123 -0
  167. package/functions/commerce/products/products.ts +123 -0
  168. package/functions/commerce/products/reviews.ts +123 -0
  169. package/functions/commerce/products/units.ts +123 -0
  170. package/functions/commerce/products/variants.ts +123 -0
  171. package/functions/commerce/shippings/delivery-routes.ts +123 -0
  172. package/functions/commerce/shippings/digital-deliveries.ts +119 -0
  173. package/functions/commerce/shippings/drivers.ts +123 -0
  174. package/functions/commerce/shippings/license-keys.ts +123 -0
  175. package/functions/commerce/shippings/shipping-methods.ts +123 -0
  176. package/functions/commerce/shippings/shipping-rates.ts +119 -0
  177. package/functions/commerce/shippings/shipping-zones.ts +119 -0
  178. package/functions/commerce/taxes.ts +119 -0
  179. package/functions/commerce/waitlist/products.ts +123 -0
  180. package/functions/commerce/waitlist/restaurants.ts +123 -0
  181. package/functions/craft.ts +107 -0
  182. package/functions/dashboard.ts +153 -0
  183. package/functions/inbox.ts +95 -0
  184. package/functions/jobs.ts +86 -0
  185. package/functions/monitoring/errors.ts +295 -0
  186. package/functions/queue.ts +111 -0
  187. package/functions/realtime/websockets.ts +96 -0
  188. package/functions/realtime.ts +52 -0
  189. package/functions/releases.ts +49 -0
  190. package/functions/search.ts +126 -0
  191. package/functions/toasts.ts +95 -0
  192. package/functions/uploads.ts +216 -0
  193. package/ide/.gitignore +4 -0
  194. package/ide/cursor/rules/auto-imports.mdc +574 -0
  195. package/ide/cursor/rules/code-style.mdc +12 -0
  196. package/ide/cursor/rules/documentation.mdc +9 -0
  197. package/ide/cursor/rules/error-handling-validation.mdc +11 -0
  198. package/ide/cursor/rules/key-conventions.mdc +11 -0
  199. package/ide/cursor/rules/project-structure.mdc +169 -0
  200. package/ide/cursor/rules/readme.mdc +318 -0
  201. package/ide/cursor/rules/syntax-formatting.mdc +9 -0
  202. package/ide/cursor/rules/testing.mdc +10 -0
  203. package/ide/cursor/rules/typescript.mdc +9 -0
  204. package/ide/cursor/rules/ui-styling.mdc +0 -0
  205. package/ide/dictionary.txt +397 -0
  206. package/ide/jetbrains/.fleet/settings.json +4 -0
  207. package/ide/jetbrains/.idea/.gitignore +5 -0
  208. package/ide/jetbrains/.idea/.name +1 -0
  209. package/ide/jetbrains/.idea/inspectionProfiles/Project_Default.xml +6 -0
  210. package/ide/jetbrains/.idea/jsLinters/eslint.xml +7 -0
  211. package/ide/jetbrains/.idea/modules.xml +8 -0
  212. package/ide/jetbrains/.idea/stacks.iml +22 -0
  213. package/ide/jetbrains/.idea/vcs.xml +6 -0
  214. package/ide/jetbrains/.idea/webResources.xml +14 -0
  215. package/ide/jetbrains/IntelliJ IDEA Global Settings +0 -0
  216. package/ide/jetbrains/installed.txt +4 -0
  217. package/ide/jetbrains/options/github-copilot.xml +5 -0
  218. package/ide/jetbrains/options/nodejs.xml +7 -0
  219. package/ide/jetbrains/options/templates.xml +124 -0
  220. package/ide/jetbrains/templates/JavaScript.xml +6 -0
  221. package/ide/jetbrains/templates/Stacks.xml +8 -0
  222. package/ide/vscode/.vscode/README.md +23 -0
  223. package/ide/vscode/.vscode/extensions.json +5 -0
  224. package/ide/vscode/.vscode/settings.json +176 -0
  225. package/ide/vscode/.vscode/stacks.code-snippets +181 -0
  226. package/ide/vscode/LICENSE.md +21 -0
  227. package/ide/vscode/README.md +36 -0
  228. package/ide/vscode/logo.png +0 -0
  229. package/ide/vscode/package.json +79 -0
  230. package/ide/zed/.zed/settings.json +139 -0
  231. package/lang/README.md +28 -0
  232. package/lang/de.yml +14 -0
  233. package/lang/en.yml +15 -0
  234. package/package.json +19 -3
  235. package/project/bootstrap +161 -0
  236. package/project/buddy +175 -0
  237. package/project/storage/framework/tsconfig.app.json +50 -0
  238. package/project/storage/framework/tsconfig.base.json +58 -0
  239. package/routes/core.ts +78 -0
  240. package/routes/dashboard-api.ts +233 -0
  241. package/routes/dashboard.ts +739 -0
  242. package/routes/email.ts +129 -0
  243. package/stores/[name].stx +16 -0
  244. package/stores/git.ts +71 -0
  245. package/stores/payment.ts +474 -0
  246. package/stores/queue.ts +43 -0
  247. package/stores/user.ts +29 -0
  248. package/stx-components-plugin.ts +25 -0
  249. package/styles/design-tokens.css +597 -0
  250. package/types/dashboard.ts +70 -0
  251. package/types/defaults.ts +438 -0
  252. package/vcs/github/CODE_OF_CONDUCT.md +83 -0
  253. package/vcs/github/CONTRIBUTING.md +187 -0
  254. package/vcs/github/EXPLANATIONS.md +41 -0
  255. package/vcs/github/FUNDING.yml +1 -0
  256. package/vcs/github/ISSUE_TEMPLATE/bug_report.yml +49 -0
  257. package/vcs/github/ISSUE_TEMPLATE/config.yml +10 -0
  258. package/vcs/github/ISSUE_TEMPLATE/feature_request.yml +44 -0
  259. package/vcs/github/SECURITY.md +70 -0
  260. package/vcs/github/renovate.json +5 -0
  261. package/vcs/github/stale.yml +14 -0
  262. package/vcs/github/workflows/README.md +16 -0
  263. package/vcs/github/workflows/ci.yml +114 -0
  264. package/vcs/github/workflows/export-size.yml +25 -0
  265. package/vcs/github/workflows/labeler.yml +13 -0
  266. package/vcs/github/workflows/release.yml +219 -0
  267. package/views/[...all].stx +8 -0
  268. package/views/about.md +3 -0
  269. package/views/auth/login.stx +1 -0
  270. package/views/auth/signup.stx +85 -0
  271. package/views/dashboard/.discovered-models.json +542 -0
  272. package/views/dashboard/AUDIT.md +904 -0
  273. package/views/dashboard/[...all].stx +89 -0
  274. package/views/dashboard/access-tokens/index.stx +177 -0
  275. package/views/dashboard/actions/index.stx +129 -0
  276. package/views/dashboard/analytics/blog/index.stx +356 -0
  277. package/views/dashboard/analytics/browsers/index.stx +263 -0
  278. package/views/dashboard/analytics/commerce/sales/index.stx +329 -0
  279. package/views/dashboard/analytics/commerce/web/index.stx +379 -0
  280. package/views/dashboard/analytics/countries/index.stx +289 -0
  281. package/views/dashboard/analytics/devices/index.stx +305 -0
  282. package/views/dashboard/analytics/events/index.stx +536 -0
  283. package/views/dashboard/analytics/index.stx +88 -0
  284. package/views/dashboard/analytics/marketing/index.stx +315 -0
  285. package/views/dashboard/analytics/pages/index.stx +271 -0
  286. package/views/dashboard/analytics/referrers/index.stx +319 -0
  287. package/views/dashboard/analytics/web/index.stx +356 -0
  288. package/views/dashboard/buddy/index.stx +198 -0
  289. package/views/dashboard/ci/index.stx +462 -0
  290. package/views/dashboard/cloud/index.stx +452 -0
  291. package/views/dashboard/commands/index.stx +295 -0
  292. package/views/dashboard/commerce/categories/index.stx +406 -0
  293. package/views/dashboard/commerce/coupons/index.stx +485 -0
  294. package/views/dashboard/commerce/customers/index.stx +410 -0
  295. package/views/dashboard/commerce/dashboard/index.stx +287 -0
  296. package/views/dashboard/commerce/delivery/delivery-routes.stx +305 -0
  297. package/views/dashboard/commerce/delivery/digital-delivery.stx +332 -0
  298. package/views/dashboard/commerce/delivery/drivers.stx +397 -0
  299. package/views/dashboard/commerce/delivery/index.stx +18 -0
  300. package/views/dashboard/commerce/delivery/license-keys.stx +380 -0
  301. package/views/dashboard/commerce/delivery/shipping-methods.stx +346 -0
  302. package/views/dashboard/commerce/delivery/shipping-rates.stx +338 -0
  303. package/views/dashboard/commerce/delivery/shipping-zones.stx +302 -0
  304. package/views/dashboard/commerce/delivery/tabs.ts +25 -0
  305. package/views/dashboard/commerce/gift-cards/index.stx +561 -0
  306. package/views/dashboard/commerce/manufacturers/index.stx +308 -0
  307. package/views/dashboard/commerce/orders/index.stx +247 -0
  308. package/views/dashboard/commerce/payments/index.stx +535 -0
  309. package/views/dashboard/commerce/pos/index.stx +653 -0
  310. package/views/dashboard/commerce/printers/devices/index.stx +273 -0
  311. package/views/dashboard/commerce/printers/receipts/index.stx +308 -0
  312. package/views/dashboard/commerce/products/detail.stx +563 -0
  313. package/views/dashboard/commerce/products/index.stx +370 -0
  314. package/views/dashboard/commerce/reviews/index.stx +656 -0
  315. package/views/dashboard/commerce/reviews/index.ts +0 -0
  316. package/views/dashboard/commerce/taxes/index.stx +377 -0
  317. package/views/dashboard/commerce/units/index.stx +317 -0
  318. package/views/dashboard/commerce/variants/index.stx +319 -0
  319. package/views/dashboard/commerce/waitlist/products.stx +942 -0
  320. package/views/dashboard/commerce/waitlist/restaurant.stx +1024 -0
  321. package/views/dashboard/components/index.stx +330 -0
  322. package/views/dashboard/composables/index.ts +19 -0
  323. package/views/dashboard/composables/useChart.ts +77 -0
  324. package/views/dashboard/composables/useNavigation.ts +99 -0
  325. package/views/dashboard/composables/useRole.ts +58 -0
  326. package/views/dashboard/composables/useTheme.ts +74 -0
  327. package/views/dashboard/content/authors/index.stx +171 -0
  328. package/views/dashboard/content/blog/index.stx +493 -0
  329. package/views/dashboard/content/categories/index.stx +169 -0
  330. package/views/dashboard/content/comments/index.stx +189 -0
  331. package/views/dashboard/content/dashboard.stx +383 -0
  332. package/views/dashboard/content/files/index.stx +706 -0
  333. package/views/dashboard/content/pages/index.stx +174 -0
  334. package/views/dashboard/content/posts/index.stx +269 -0
  335. package/views/dashboard/content/seo/index.stx +240 -0
  336. package/views/dashboard/content/tags/index.stx +167 -0
  337. package/views/dashboard/data/activity/index.stx +261 -0
  338. package/views/dashboard/data/dashboard/index.stx +116 -0
  339. package/views/dashboard/data/subscribers.stx +270 -0
  340. package/views/dashboard/data/teams.stx +275 -0
  341. package/views/dashboard/data/users.stx +279 -0
  342. package/views/dashboard/dependencies/index.stx +178 -0
  343. package/views/dashboard/deployments/[id].stx +234 -0
  344. package/views/dashboard/deployments/index.stx +9 -0
  345. package/views/dashboard/dns/index.stx +163 -0
  346. package/views/dashboard/environment/index.stx +283 -0
  347. package/views/dashboard/errors/index.stx +274 -0
  348. package/views/dashboard/forgot-password.stx +57 -0
  349. package/views/dashboard/functions/index.stx +159 -0
  350. package/views/dashboard/health/index.stx +248 -0
  351. package/views/dashboard/inbox/activity.stx +350 -0
  352. package/views/dashboard/inbox/index.stx +452 -0
  353. package/views/dashboard/inbox/settings.stx +290 -0
  354. package/views/dashboard/index.stx +252 -0
  355. package/views/dashboard/insights/index.stx +529 -0
  356. package/views/dashboard/jobs/[id].stx +430 -0
  357. package/views/dashboard/jobs/history.stx +222 -0
  358. package/views/dashboard/jobs/index.stx +214 -0
  359. package/views/dashboard/kanban/[id].stx +899 -0
  360. package/views/dashboard/kanban/index.stx +260 -0
  361. package/views/dashboard/layouts/default.stx +565 -0
  362. package/views/dashboard/layouts/guest.stx +10 -0
  363. package/views/dashboard/login.stx +48 -0
  364. package/views/dashboard/logs/index.stx +540 -0
  365. package/views/dashboard/mailboxes/index.stx +149 -0
  366. package/views/dashboard/management/permissions/index.stx +490 -0
  367. package/views/dashboard/marketing/campaigns/index.stx +604 -0
  368. package/views/dashboard/marketing/lists/index.stx +514 -0
  369. package/views/dashboard/marketing/reviews/index.stx +475 -0
  370. package/views/dashboard/marketing/social-posts/index.stx +560 -0
  371. package/views/dashboard/models/[model].stx +195 -0
  372. package/views/dashboard/models/index.stx +159 -0
  373. package/views/dashboard/monitoring/errors/index.stx +415 -0
  374. package/views/dashboard/notifications/dashboard.stx +383 -0
  375. package/views/dashboard/notifications/email.stx +336 -0
  376. package/views/dashboard/notifications/history.stx +373 -0
  377. package/views/dashboard/notifications/sms.stx +332 -0
  378. package/views/dashboard/packages/index.stx +195 -0
  379. package/views/dashboard/queries/[id].stx +381 -0
  380. package/views/dashboard/queries/history.stx +227 -0
  381. package/views/dashboard/queries/index.stx +335 -0
  382. package/views/dashboard/queries/slow.stx +318 -0
  383. package/views/dashboard/queue/index.stx +427 -0
  384. package/views/dashboard/realtime/index.stx +429 -0
  385. package/views/dashboard/register.stx +46 -0
  386. package/views/dashboard/releases/index.stx +389 -0
  387. package/views/dashboard/requests/index.stx +462 -0
  388. package/views/dashboard/serverless/index.stx +475 -0
  389. package/views/dashboard/servers/[id].stx +299 -0
  390. package/views/dashboard/servers/index.stx +483 -0
  391. package/views/dashboard/settings/billing.stx +50 -0
  392. package/views/dashboard/settings/index.stx +256 -0
  393. package/views/dashboard/settings/mail.stx +252 -0
  394. package/views/dashboard/stores/auth.ts +123 -0
  395. package/views/dashboard/stores/ci.ts +342 -0
  396. package/views/dashboard/stores/index.ts +129 -0
  397. package/views/dashboard/stores/kanban.ts +723 -0
  398. package/views/dashboard/stores/rbac.ts +350 -0
  399. package/views/dashboard/stx.config.ts +34 -0
  400. package/views/dashboard/teams/[id].stx +170 -0
  401. package/views/forum/category.stx +92 -0
  402. package/views/forum/index.stx +209 -0
  403. package/views/forum/new-topic.stx +113 -0
  404. package/views/forum/profile.stx +1 -0
  405. package/views/forum/topic.stx +143 -0
  406. package/views/hello-world/[name].stx +47 -0
  407. package/views/index.stx +21 -0
  408. package/views/system-tray/index.stx +147 -0
@@ -0,0 +1,738 @@
1
+ ---
2
+ name: stacks-api
3
+ description: Use when building, modifying, or debugging API endpoints in a Stacks application — defining routes, handling requests, API middleware, working with the API server, HTTP client (fetcher), API resources, or OpenAPI generation. Covers both @stacksjs/api utilities and the stacks-api server implementation.
4
+ license: MIT
5
+ compatibility: Bun >= 1.3.0, TypeScript
6
+ allowed-tools: Read Edit Write Bash Grep Glob
7
+ ---
8
+
9
+ # Stacks API
10
+
11
+ The Stacks API system comprises two packages: the `@stacksjs/api` utilities package (HTTP client, API resources, OpenAPI generation) and the `stacks-api` server (Bun HTTP server with hot-reload). Routing is delegated to `@stacksjs/router` which wraps `@stacksjs/bun-router`.
12
+
13
+ ## Key Paths
14
+ - Core utilities (package): `storage/framework/core/api/src/`
15
+ - API server: `storage/framework/api/`
16
+ - Router package: `storage/framework/core/router/src/`
17
+ - Route definitions: `routes/`
18
+ - Route registry: `app/Routes.ts` (re-exports `storage/framework/defaults/app/Routes.ts`)
19
+ - Port configuration: `config/ports.ts`
20
+ - Generated OpenAPI spec: `storage/framework/api/openapi.json`
21
+ - Generated API types: `storage/framework/api/api-types.ts`
22
+ - Actions directory: `app/Actions/`
23
+ - Controllers directory: `app/Controllers/`
24
+ - Middleware directory: `app/Middleware/`
25
+ - Middleware alias map: `app/Middleware.ts`
26
+ - Package: `@stacksjs/api`
27
+
28
+ ## Source Files
29
+
30
+ ```
31
+ core/api/src/
32
+ ├── index.ts # Re-exports fetcher, generate-openapi, resource
33
+ ├── fetcher.ts # Fetcher HTTP client class (fluent API)
34
+ ├── generate-openapi.ts # OpenAPI 3.0 spec generator from route definitions
35
+ ├── resource.ts # JsonResource, ResourceCollection, PaginatedResourceCollection
36
+ └── types.ts # FetcherResponse, QueryParams, BodyData, FileAttachment
37
+
38
+ framework/api/
39
+ ├── dev.ts # API server entry point (Bun --hot, file watchers)
40
+ ├── build.ts # Bun.build config for production
41
+ ├── api-types.ts # Auto-generated TypeScript types from OpenAPI spec
42
+ ├── openapi.json # Generated OpenAPI 3.0 specification
43
+ ├── package.json # Dependencies: @stacksjs/router, queue, storage, logging
44
+ └── tsconfig.json
45
+
46
+ core/router/src/
47
+ ├── index.ts # Re-exports bun-router + stacks-specific additions
48
+ ├── stacks-router.ts # Route object, serve(), url(), action/controller resolution
49
+ ├── response.ts # Response factory (json, text, html, redirect, etc.)
50
+ ├── middleware.ts # Middleware class definition
51
+ ├── request-context.ts # AsyncLocalStorage-based request context (request proxy)
52
+ ├── route-loader.ts # Loads route files from registry with auto-prefixing
53
+ ├── error-handler.ts # Ignition-style error pages, query tracking
54
+ └── action-paths.ts # StacksActionPath type definitions
55
+
56
+ routes/
57
+ ├── api.ts # Main API routes (auto-prefixed with /api; see #1835)
58
+ ├── v1.ts # Versioned routes (loaded at /v1/*)
59
+ ├── buddy.ts # Buddy CLI routes (loaded at /buddy/*)
60
+ └── users.ts # Example user routes (commented out)
61
+ ```
62
+
63
+ ## API Server (dev.ts)
64
+
65
+ The API server runs on Bun's HTTP server with hot-reload (`bun --hot run dev.ts`).
66
+
67
+ ```typescript
68
+ import { serve } from '@stacksjs/router'
69
+
70
+ serve({
71
+ port: ports.api || 3008, // Configurable via config/ports.ts or PORT_API env
72
+ timezone: app.timezone || 'UTC',
73
+ })
74
+ ```
75
+
76
+ ### Hot Reload Watchers
77
+ The dev server watches these directories for changes and auto-reloads:
78
+ - `storage/framework/core/*/src/` -- rebuilds core packages on change
79
+ - `routes/` -- detects route file changes
80
+ - `app/Actions/` -- invalidates module cache, hot-reloads actions
81
+ - `app/Controllers/` -- invalidates module cache, hot-reloads controllers
82
+ - `app/Middleware/` -- invalidates module cache, hot-reloads middleware
83
+ - `app/Models/` (user models) -- triggers `buddy generate:model-files`
84
+
85
+ Production build: `bun build.ts` bundles `dev.ts` to `dist/dev.js`.
86
+
87
+ ## Route Definitions
88
+
89
+ ### Route Registry (app/Routes.ts)
90
+
91
+ Routes are organized in `routes/*.ts` files and registered in `app/Routes.ts`:
92
+
93
+ ```typescript
94
+ export interface RouteDefinition {
95
+ path: string // Route file path relative to routes/
96
+ prefix?: string // URL prefix (overrides key-based prefix)
97
+ middleware?: string | string[] // Middleware for all routes in file
98
+ }
99
+
100
+ export type RouteRegistry = Record<string, string | RouteDefinition>
101
+
102
+ export default {
103
+ 'api': 'api', // Auto-prefixed with /api (see #1835)
104
+ 'v1': { path: 'v1', prefix: 'v1' }, // routes at /v1/*
105
+ // 'admin': { path: 'admin', middleware: ['auth'] },
106
+ } satisfies RouteRegistry
107
+ ```
108
+
109
+ `'web'` is the only key that loads at root `/` with no prefix; all other keys (including `'api'`) auto-prefix with `/<key>`. The `'api'` auto-prefix lines up with the rpx proxy forward path so a user route registered as `route.get('/cart/add', ...)` in `routes/api.ts` resolves at `https://<domain>/api/cart/add` through the dev proxy.
110
+
111
+ ### Route Methods
112
+
113
+ ```typescript
114
+ import { route, response } from '@stacksjs/router'
115
+
116
+ // Inline handler
117
+ route.get('/hello', () => response.json({ message: 'Hello' }))
118
+ route.post('/users', () => response.created({ id: 1 }))
119
+
120
+ // String-based handler (Action)
121
+ route.get('/subscribers', 'Actions/SubscriberIndexOrmAction')
122
+ route.post('/login', 'Actions/Auth/LoginAction')
123
+
124
+ // String-based handler (Controller@method)
125
+ route.get('/coming-soon', 'Controllers/ComingSoonController@index')
126
+ route.get('/stats', 'Controllers/QueryController@getStats')
127
+
128
+ // Route with path parameters
129
+ route.get('/foo/bar/{id}', () => response.text('hello'))
130
+ route.get('/users/{id}/posts/{postId}', handler)
131
+
132
+ // Route chaining: middleware + naming
133
+ route.get('/tokens', 'Actions/Auth/ListTokensAction').middleware('auth')
134
+ route.post('/email/subscribe', 'Actions/SubscriberEmailAction').name('email.subscribe')
135
+ route.delete('/tokens/{id}', 'Actions/Auth/RevokeTokenAction').middleware('auth').name('token.revoke')
136
+
137
+ // Route groups (prefix + middleware)
138
+ route.group({ prefix: '/auth' }, () => {
139
+ route.post('/refresh', 'Actions/Auth/RefreshTokenAction')
140
+ route.get('/tokens', 'Actions/Auth/ListTokensAction').middleware('auth')
141
+ })
142
+
143
+ route.group({ middleware: 'auth' }, () => {
144
+ route.get('/me', 'Actions/Auth/AuthUserAction')
145
+ route.post('/logout', 'Actions/Auth/LogoutAction')
146
+ })
147
+
148
+ // Health check (adds GET /health)
149
+ route.health()
150
+ ```
151
+
152
+ ### Named Routes & URL Generation
153
+
154
+ ```typescript
155
+ import { url } from '@stacksjs/router'
156
+
157
+ // Define named routes
158
+ route.get('/api/email/unsubscribe', 'Actions/UnsubscribeAction').name('email.unsubscribe')
159
+ route.get('/users/{id}/posts/{postId}', handler).name('user.post')
160
+
161
+ // Generate URLs
162
+ url('email.unsubscribe', { token: 'abc-123' })
163
+ // => https://stacksjs.com/api/email/unsubscribe?token=abc-123
164
+
165
+ url('user.post', { id: 42, postId: 7 })
166
+ // => https://stacksjs.com/users/42/posts/7
167
+ ```
168
+
169
+ Path parameters (`{id}`) are substituted; remaining params become query string. Uses `APP_URL` env var as base (defaults to `https://localhost`).
170
+
171
+ ## Action Resolution
172
+
173
+ String-based route handlers are resolved at runtime:
174
+
175
+ 1. **Actions** (`'Actions/MyAction'`): checks `app/Actions/MyAction.ts` first, falls back to `storage/framework/defaults/app/Actions/MyAction.ts`
176
+ 2. **ORM Actions** (`'Actions/UserIndexOrmAction'`): loaded from `storage/framework/actions/src/`
177
+ 3. **Controllers** (`'Controllers/MyController@method'`): checks `app/Controllers/` first, falls back to defaults
178
+
179
+ Action modules must export a default object with a `handle(req: EnhancedRequest)` method:
180
+
181
+ ```typescript
182
+ // app/Actions/MyAction.ts
183
+ export default {
184
+ handle(request: EnhancedRequest): Response {
185
+ const name = request.get('name', 'world')
186
+ return Response.json({ message: `Hello ${name}` })
187
+ }
188
+ }
189
+ ```
190
+
191
+ Actions can also define `validations` for automatic input validation:
192
+
193
+ ```typescript
194
+ export default {
195
+ validations: {
196
+ email: {
197
+ rule: { validate: (value) => ({ valid: typeof value === 'string' && value.includes('@') }) },
198
+ message: 'A valid email is required',
199
+ },
200
+ },
201
+ handle(request: EnhancedRequest): Response {
202
+ // Request is validated before reaching handle()
203
+ return Response.json({ success: true })
204
+ },
205
+ }
206
+ ```
207
+
208
+ Validation failures return a `422` response:
209
+ ```json
210
+ { "error": "Validation failed", "errors": { "email": ["A valid email is required"] } }
211
+ ```
212
+
213
+ ## Response Factory
214
+
215
+ ```typescript
216
+ import { response } from '@stacksjs/router'
217
+
218
+ // JSON (200)
219
+ response.json({ message: 'OK' })
220
+ response.json(data, { status: 200, headers: { 'X-Custom': 'value' }, pretty: true })
221
+
222
+ // Status shortcuts
223
+ response.created({ id: 1 }) // 201
224
+ response.noContent() // 204
225
+ response.badRequest({ error: 'Bad' }) // 400
226
+ response.unauthorized() // 401 (default: { error: 'Unauthorized' })
227
+ response.forbidden() // 403 (default: { error: 'Forbidden' })
228
+ response.notFound() // 404 (default: { error: 'Not Found' })
229
+ response.error() // 500 (default: { error: 'Internal Server Error' })
230
+
231
+ // Other content types
232
+ response.text('Hello', { status: 200 })
233
+ response.html('<h1>Hello</h1>')
234
+ response.redirect('/new-url', 302) // 301 | 302 | 303 | 307 | 308
235
+ ```
236
+
237
+ All methods return a standard `Response` object.
238
+
239
+ ## Enhanced Request (EnhancedRequest)
240
+
241
+ Route handlers receive an `EnhancedRequest` (extends `Request`) with Laravel-style helper methods:
242
+
243
+ ```typescript
244
+ // Input access (merges query params + JSON body + form body + route params)
245
+ request.get<T>(key: string, defaultValue?: T): T
246
+ request.input<T>(key: string, defaultValue?: T): T
247
+ request.all(): Record<string, unknown>
248
+ request.only<T>(keys: string[]): T
249
+ request.except<T>(keys: string[]): T
250
+
251
+ // Presence checks
252
+ request.has(key: string | string[]): boolean
253
+ request.hasAny(keys: string[]): boolean
254
+ request.filled(key: string | string[]): boolean
255
+ request.missing(key: string | string[]): boolean
256
+
257
+ // Typed getters
258
+ request.string(key: string, defaultValue?: string): string
259
+ request.integer(key: string, defaultValue?: number): number
260
+ request.float(key: string, defaultValue?: number): number
261
+ request.boolean(key: string, defaultValue?: boolean): boolean
262
+ request.array<T>(key: string): T[]
263
+
264
+ // File handling (returns UploadedFile with store/storeAs methods)
265
+ request.file(key: string): UploadedFile | null
266
+ request.getFiles(key: string): UploadedFile[]
267
+ request.hasFile(key: string): boolean
268
+ request.allFiles(): Record<string, UploadedFile | UploadedFile[]>
269
+
270
+ // Authentication (set by auth middleware)
271
+ await request.user(): Promise<any>
272
+ await request.userToken(): Promise<any>
273
+ await request.tokenCan(ability: string): Promise<boolean>
274
+ await request.tokenCant(ability: string): Promise<boolean>
275
+ request.bearerToken(): string | null
276
+ ```
277
+
278
+ ## Request Context (AsyncLocalStorage)
279
+
280
+ Access the current request from anywhere using the `request` proxy:
281
+
282
+ ```typescript
283
+ import { request, getCurrentRequest, runWithRequest, setCurrentRequest } from '@stacksjs/router'
284
+
285
+ // The `request` export is a Proxy that reads from AsyncLocalStorage
286
+ const token = request.bearerToken()
287
+ const user = await request.user()
288
+
289
+ // Manually run code in a request context
290
+ runWithRequest(enhancedReq, () => {
291
+ // request proxy works here
292
+ })
293
+ ```
294
+
295
+ ## Middleware
296
+
297
+ ### Defining Middleware
298
+
299
+ ```typescript
300
+ // app/Middleware/Auth.ts
301
+ import { Middleware } from '@stacksjs/router'
302
+
303
+ export default new Middleware({
304
+ name: 'Auth',
305
+ priority: 1, // Lower numbers run first (default: 10)
306
+ async handle(request) {
307
+ const token = request.bearerToken()
308
+ if (!token) {
309
+ const error = new Error('Unauthorized') as Error & { statusCode: number }
310
+ error.statusCode = 401
311
+ throw error
312
+ }
313
+ // Set authenticated user on request
314
+ ;(request as any)._authenticatedUser = user
315
+ },
316
+ })
317
+ ```
318
+
319
+ ### Middleware Alias Map
320
+
321
+ Define shorthand names in `app/Middleware.ts`:
322
+
323
+ ```typescript
324
+ export default {
325
+ auth: 'Auth', // maps to app/Middleware/Auth.ts
326
+ verified: 'EnsureEmailIsVerified',
327
+ abilities: 'CheckAbilities', // supports params: 'abilities:read,write'
328
+ }
329
+ ```
330
+
331
+ ### Middleware Resolution Order
332
+ 1. Parse alias via `app/Middleware.ts` (e.g., `'auth'` -> `'Auth'`)
333
+ 2. Load from `app/Middleware/Auth.ts` (user override)
334
+ 3. Fall back to `storage/framework/defaults/app/Middleware/Auth.ts`
335
+
336
+ ### Middleware with Parameters
337
+
338
+ ```typescript
339
+ route.get('/admin', handler).middleware('abilities:admin,write')
340
+ // Params accessible in middleware via: (request as any)._middlewareParams.abilities === 'admin,write'
341
+ ```
342
+
343
+ ## Fetcher (HTTP Client)
344
+
345
+ A fluent HTTP client for making API requests:
346
+
347
+ ```typescript
348
+ import { fetcher } from '@stacksjs/api'
349
+
350
+ // GET request
351
+ const res = await fetcher.get<UserResponse>('/api/users')
352
+ res.data // UserResponse
353
+ res.status // 200
354
+ res.isOk // true
355
+ res.ok() // true (status === 200)
356
+ res.notFound() // false
357
+
358
+ // POST with JSON body
359
+ const res = await fetcher
360
+ .withBody({ name: 'John', email: 'john@example.com' })
361
+ .post<User>('/api/users')
362
+
363
+ // PUT/PATCH/DELETE
364
+ await fetcher.withBody(data).put<User>('/api/users/1')
365
+ await fetcher.withBody(data).patch<User>('/api/users/1')
366
+ await fetcher.delete('/api/users/1')
367
+
368
+ // Query parameters
369
+ await fetcher.withQueryParams({ page: 1, limit: 25 }).get('/api/users')
370
+
371
+ // Custom headers
372
+ await fetcher.withHeaders({ 'X-Custom': 'value' }).get('/api/users')
373
+
374
+ // Authentication
375
+ await fetcher.withToken('bearer-token-here').get('/api/me')
376
+ await fetcher.withBasicAuth('user', 'pass').get('/api/protected')
377
+ await fetcher.withDigestAuth('user', 'pass').get('/api/digest-protected')
378
+
379
+ // Form data
380
+ await fetcher.asForm().withBody({ email: 'test@test.com' }).post('/subscribe')
381
+
382
+ // File uploads (multipart/form-data)
383
+ await fetcher
384
+ .attach('avatar', file, 'photo.jpg')
385
+ .withBody({ name: 'John' })
386
+ .post('/api/upload')
387
+
388
+ // Accept header
389
+ await fetcher.acceptJson().get('/api/data')
390
+ await fetcher.accept('text/xml').get('/api/feed')
391
+ ```
392
+
393
+ ### FetcherResponse<T>
394
+
395
+ ```typescript
396
+ interface FetcherResponse<T = any> {
397
+ data: T
398
+ status: number
399
+ headers: Headers
400
+ isOk: boolean
401
+
402
+ // Status checkers
403
+ ok(): boolean // 200
404
+ created(): boolean // 201
405
+ accepted(): boolean // 202
406
+ noContent(): boolean // 204
407
+ movedPermanently(): boolean // 301
408
+ found(): boolean // 302
409
+ badRequest(): boolean // 400
410
+ unauthorized(): boolean // 401
411
+ paymentRequired(): boolean // 402
412
+ forbidden(): boolean // 403
413
+ notFound(): boolean // 404
414
+ requestTimeout(): boolean // 408
415
+ conflict(): boolean // 409
416
+ unprocessableEntity(): boolean // 422
417
+ tooManyRequests(): boolean // 429
418
+ serverError(): boolean // 500
419
+ }
420
+ ```
421
+
422
+ ### Fetcher Types
423
+
424
+ ```typescript
425
+ type QueryParams = Record<string, string | number | boolean | null | undefined>
426
+ type BodyData = Record<string, any>
427
+
428
+ interface FileAttachment {
429
+ name: string
430
+ content: Blob
431
+ filename?: string
432
+ headers?: Record<string, string>
433
+ }
434
+ ```
435
+
436
+ ## API Resources (Laravel-style)
437
+
438
+ ### JsonResource
439
+
440
+ Transform models into JSON responses with conditional field inclusion:
441
+
442
+ ```typescript
443
+ import { JsonResource } from '@stacksjs/api'
444
+
445
+ class UserResource extends JsonResource<User> {
446
+ toArray() {
447
+ return {
448
+ id: this.resource.id,
449
+ name: this.resource.name,
450
+ email: this.resource.email,
451
+ // Conditional inclusion
452
+ secret: this.when(isAdmin, this.resource.secret),
453
+ avatar: this.whenNotNull(this.resource.avatar),
454
+ // Relationship loading
455
+ posts: this.whenLoaded('posts', () => PostResource.collection(this.resource.posts)),
456
+ posts_count: this.whenCounted('posts'),
457
+ // Conditional merge
458
+ ...this.mergeWhen(isAdmin, { admin_notes: this.resource.adminNotes }),
459
+ }
460
+ }
461
+ }
462
+
463
+ // Single resource
464
+ const response = new UserResource(user).toResponse()
465
+ // => { data: { id: 1, name: 'John', email: 'john@...' } }
466
+
467
+ // With additional data
468
+ new UserResource(user).withAdditional({ meta: { version: 1 } }).toResponse()
469
+
470
+ // JSON string
471
+ new UserResource(user).toJson()
472
+ ```
473
+
474
+ ### JsonResource Methods
475
+
476
+ ```typescript
477
+ abstract class JsonResource<T> {
478
+ resource: T
479
+ additional: Record<string, any>
480
+ static wrap: string | null = 'data' // Wrap key, null to disable
481
+
482
+ abstract toArray(request?: Request): Record<string, any>
483
+
484
+ // Instance methods
485
+ withRequest(request: Request): this
486
+ withAdditional(data: Record<string, any>): this
487
+ resolve(request?: Request): Record<string, any>
488
+ toResponse(request?: Request): Record<string, any>
489
+ toJson(request?: Request): string
490
+
491
+ // Static methods
492
+ static collection<T, R>(resources: T[]): ResourceCollection<T, R>
493
+ static withoutWrapping(): void // Set wrap = null for this class
494
+ static wrapWith(key: string): void // Set custom wrap key
495
+
496
+ // Conditional helpers (protected, use inside toArray)
497
+ protected when<V>(condition: boolean | (() => boolean), value: V | (() => V), defaultValue?: any): V | MissingValue
498
+ protected whenNotNull<V>(value: V | null | undefined, transform?: (v: V) => any): any | MissingValue
499
+ protected whenLoaded<V>(relationship: string, value?: V | (() => V), defaultValue?: any): V | any[] | MissingValue
500
+ protected whenCounted(relationship: string, defaultValue?: number): number | MissingValue
501
+ protected merge(data: Record<string, any>): MergeValue
502
+ protected mergeWhen(condition: boolean | (() => boolean), data: Record<string, any> | (() => Record<string, any>)): MergeValue | MissingValue
503
+ }
504
+ ```
505
+
506
+ ### ResourceCollection
507
+
508
+ ```typescript
509
+ class ResourceCollection<T, R extends JsonResource<T>> {
510
+ resources: T[]
511
+ static wrap: string | null = 'data'
512
+
513
+ withRequest(request: Request): this
514
+ withAdditional(data: Record<string, any>): this
515
+ resolve(request?: Request): Record<string, any>[]
516
+ toResponse(request?: Request): Record<string, any>
517
+ toJson(request?: Request): string
518
+ count(): number
519
+ isEmpty(): boolean
520
+ isNotEmpty(): boolean
521
+ }
522
+
523
+ // Usage
524
+ const collection = UserResource.collection(users)
525
+ collection.toResponse()
526
+ // => { data: [{ id: 1, ... }, { id: 2, ... }] }
527
+ ```
528
+
529
+ ### PaginatedResourceCollection
530
+
531
+ ```typescript
532
+ class PaginatedResourceCollection<T, R extends JsonResource<T>> extends ResourceCollection<T, R> {
533
+ meta: PaginationMeta
534
+ links: PaginationLinks
535
+
536
+ // Create from raw pagination data
537
+ static fromPagination<T, R>(
538
+ data: T[],
539
+ ResourceClass: new (resource: T) => R,
540
+ options: { currentPage: number, perPage: number, total: number, baseUrl?: string },
541
+ ): PaginatedResourceCollection<T, R>
542
+
543
+ toResponse(): Record<string, any>
544
+ // => { data: [...], meta: { current_page, from, last_page, per_page, to, total }, links: { first, last, prev, next } }
545
+ }
546
+
547
+ interface PaginationMeta {
548
+ current_page: number
549
+ from: number | null
550
+ last_page: number
551
+ per_page: number
552
+ to: number | null
553
+ total: number
554
+ }
555
+
556
+ interface PaginationLinks {
557
+ first: string | null
558
+ last: string | null
559
+ prev: string | null
560
+ next: string | null
561
+ }
562
+ ```
563
+
564
+ ### Anonymous Resources
565
+
566
+ Quick inline transformations without defining a class:
567
+
568
+ ```typescript
569
+ import { resource, collection } from '@stacksjs/api'
570
+
571
+ // Single resource
572
+ resource(user, (u) => ({ id: u.id, name: u.name })).toResponse()
573
+ // => { data: { id: 1, name: 'John' } }
574
+
575
+ // Collection
576
+ collection(users, (u) => ({ id: u.id, name: u.name })).toResponse()
577
+ // => { data: [{ id: 1, name: 'John' }, ...] }
578
+ ```
579
+
580
+ ### Conditional Value Types
581
+
582
+ ```typescript
583
+ class MissingValue {
584
+ static instance: MissingValue
585
+ isMissing(): boolean
586
+ }
587
+
588
+ class MergeValue {
589
+ constructor(data: Record<string, any>)
590
+ }
591
+
592
+ class ConditionalValue {
593
+ constructor(condition: boolean | (() => boolean), value: any, defaultValue?: any)
594
+ resolve(): any
595
+ }
596
+ ```
597
+
598
+ `MissingValue` entries are stripped from the final output by `filterAndResolve()` (max depth: 20).
599
+
600
+ ## OpenAPI Generation
601
+
602
+ ```typescript
603
+ import { generateOpenApi } from '@stacksjs/api'
604
+
605
+ await generateOpenApi()
606
+ // Reads all registered routes via `route.routes()`
607
+ // Writes OpenAPI 3.0 spec to storage/framework/api/openapi.json
608
+ ```
609
+
610
+ The generated spec includes:
611
+ - Path definitions from route URLs
612
+ - HTTP methods from route registrations
613
+ - Path parameters extracted from `{param}` placeholders
614
+ - Response/request schemas if defined on routes (`route.responseSchema`, `route.requestSchema`)
615
+ - Operation IDs from route callbacks (action paths)
616
+
617
+ TypeScript types can be generated from the spec:
618
+ ```bash
619
+ # Defined in package.json scripts
620
+ bun run generate-types
621
+ # Runs: open-api ./../../api/openapi.json --output ./../../api/api-types.ts
622
+ ```
623
+
624
+ ## Error Handling
625
+
626
+ ### Error Response Structure
627
+
628
+ ```typescript
629
+ interface ErrorResponseBody {
630
+ error: string
631
+ message: string
632
+ status: number
633
+ timestamp: string
634
+ details?: Record<string, unknown>
635
+ }
636
+ ```
637
+
638
+ ### Development vs Production
639
+ - **Development**: Ignition-style HTML error pages with full stack traces, database queries, and request context
640
+ - **Production**: Simple JSON or HTML error responses (no stack traces)
641
+ - Detection: `APP_ENV !== 'production' && NODE_ENV !== 'production'`
642
+ - API requests (Accept: `application/json`): always get JSON error responses
643
+
644
+ ### Error Functions
645
+
646
+ ```typescript
647
+ import {
648
+ createErrorResponse,
649
+ createMiddlewareErrorResponse,
650
+ createValidationErrorResponse,
651
+ createNotFoundResponse,
652
+ trackQuery,
653
+ clearTrackedQueries,
654
+ } from '@stacksjs/router'
655
+
656
+ // Track queries for error context (circular buffer, max 50)
657
+ trackQuery('SELECT * FROM users', 12.5, 'sqlite')
658
+
659
+ // Create error responses
660
+ await createErrorResponse(error, request, { status: 500, handlerPath: 'Actions/MyAction' })
661
+ await createMiddlewareErrorResponse(error, request) // Uses error.statusCode
662
+ createValidationErrorResponse({ email: ['Required'] }, request) // 422
663
+ await createNotFoundResponse('/missing-path', request) // 404
664
+ ```
665
+
666
+ ### Sensitive Data Sanitization
667
+ Error pages automatically redact fields matching these patterns: `password`, `secret`, `token`, `api_key`, `authorization`, `credential`, `cookie`, `session_id`, and others.
668
+
669
+ ## Port Configuration (config/ports.ts)
670
+
671
+ ```typescript
672
+ {
673
+ frontend: env.PORT ?? 3000,
674
+ backend: env.PORT_BACKEND ?? 3001,
675
+ admin: env.PORT_ADMIN ?? 3002,
676
+ api: env.PORT_API ?? 3008,
677
+ // ... other services
678
+ }
679
+ ```
680
+
681
+ ## Route Groups in routes/api.ts
682
+
683
+ The main `routes/api.ts` file defines route groups for major feature areas:
684
+
685
+ | Prefix | Feature | Actions Prefix |
686
+ |--------|---------|---------------|
687
+ | `/auth` | Authentication & tokens | `Actions/Auth/` |
688
+ | `/password` | Password reset flow | `Actions/Password/` |
689
+ | `/payments` | Stripe payment integration | `Actions/Payment/` |
690
+ | `/commerce` | E-commerce (products, orders, customers, coupons, gift cards, tax rates, reviews, receipts, POS, waitlists) | `Actions/Commerce/` |
691
+ | `/shipping` | Shipping methods, rates, zones, delivery routes, drivers, digital delivery, license keys | `Actions/Commerce/Shipping/` |
692
+ | `/cms` | Blog posts, authors, categories, tags, comments, pages | `Actions/Cms/` |
693
+ | `/blog` | Public blog endpoints (read-only) | `Actions/Cms/` |
694
+ | `/monitoring` | Error tracking & resolution | `Actions/Monitoring/` |
695
+ | `/dashboard` | Dashboard stats & health | `Actions/Dashboard/` |
696
+ | `/queries` | Query log dashboard | `Controllers/QueryController@` |
697
+ | `/queues` | Queue management | `Actions/Queue/` |
698
+ | `/realtime` | WebSocket management | `Actions/Realtime/` |
699
+ | `/voide` | Voice AI code assistant | `Actions/Buddy/` |
700
+
701
+ ## ORM-Generated CRUD Routes
702
+
703
+ Models with `traits.useApi` automatically get CRUD routes via ORM actions:
704
+
705
+ | Method | Path | Action | Status |
706
+ |--------|------|--------|--------|
707
+ | GET | `/api/{model}` | `{Model}IndexOrmAction` | 200 |
708
+ | POST | `/api/{model}` | `{Model}StoreOrmAction` | 201 |
709
+ | GET | `/api/{model}/{id}` | `{Model}ShowOrmAction` | 200 |
710
+ | PATCH | `/api/{model}/{id}` | `{Model}UpdateOrmAction` | 202 |
711
+ | DELETE | `/api/{model}/{id}` | `{Model}DestroyOrmAction` | 204 |
712
+
713
+ ## CLI Commands
714
+
715
+ - `buddy dev` -- starts the API server with hot-reload
716
+ - `buddy generate:api-types` -- regenerates API TypeScript types from OpenAPI spec
717
+
718
+ ## Gotchas
719
+
720
+ - The `fetcher` is a **singleton instance** -- state (headers, body, query params) is reset after each request via `resetState()`, but calling chain methods without executing a request will accumulate state
721
+ - `fetcher.withDigestAuth()` uses SHA-256 internally despite the method name `generateMD5` -- this is a misnomer in the source code
722
+ - `fetcher` always parses responses as JSON (`response.json()`) -- it will throw if the response is not valid JSON
723
+ - Only the `'web'` route file key loads at root `/` with no prefix; all other keys (including `'api'`) auto-prefix with `/<key>`. The `'api'` auto-prefix was added in stacksjs/stacks#1835 so user routes line up with the rpx proxy forward path
724
+ - The `route` object is a global singleton from `stacks-router.ts` -- all route definitions across files share the same router instance
725
+ - String-based handlers (`'Actions/MyAction'`) are resolved lazily at request time, not at registration time -- import errors surface only when the route is hit
726
+ - Actions must export `default` with a `handle()` method; Controllers must export `default` as a class with the specified method (defaults to `index`)
727
+ - The `request` proxy from `@stacksjs/router` returns safe defaults (null, undefined, empty) when accessed outside of a request context -- it warns in non-production
728
+ - `JsonResource.filterAndResolve()` has a max recursion depth of 20 to prevent stack overflow on circular references
729
+ - `ResourceCollection.toResponse()` and `JsonResource.toResponse()` both wrap data in `{ data: ... }` by default -- call `MyResource.withoutWrapping()` to disable
730
+ - The error handler tracks up to 50 recent queries in a circular buffer -- these are cleared after each successful response
731
+ - Middleware runs in registration order (not by priority) within a single route -- the `priority` field on `Middleware` is for documentation/ordering within files
732
+ - Middleware parameters (e.g., `'abilities:read,write'`) are stored on `request._middlewareParams` -- middleware must parse the param string itself
733
+ - The dev server's file watchers use Node's `fs.watch` (not `chokidar`) -- on macOS this uses FSEvents, on Linux it uses inotify
734
+ - `openapi.json` starts empty (`{}`) and is only populated when `generateOpenApi()` is explicitly called
735
+ - The `api-types.ts` file uses operations keyed by action path (e.g., `'Actions/UserIndexOrmAction'`), not by route name
736
+ - CORS headers (`Access-Control-Allow-Origin: http://localhost:5173`) are only added in development mode for error responses
737
+ - Body parsing happens once per request (tracked via `_bodyParsed` flag) -- JSON, URL-encoded, and multipart/form-data are all supported
738
+ - `response.json()` catches circular reference errors and returns `{ error: 'Response data could not be serialized' }` instead of throwing