@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,385 @@
1
+ ---
2
+ name: stacks-sms
3
+ description: Use when implementing SMS in Stacks — sending text messages, the SmsBuilder fluent API, SMS templates, phone verification (OTP/2FA), bulk sending, Twilio/Vonage drivers, E.164 formatting, or the SMS facade. Covers @stacksjs/sms and config/sms.ts.
4
+ license: MIT
5
+ compatibility: Bun >= 1.3.0, TypeScript
6
+ allowed-tools: Read Edit Write Bash Grep Glob
7
+ ---
8
+
9
+ # Stacks SMS
10
+
11
+ Multi-driver SMS system with verification (OTP), templates, bulk sending, and a fluent builder API. Two fully implemented drivers: Twilio and Vonage.
12
+
13
+ ## Key Paths
14
+ - Core package: `storage/framework/core/sms/src/`
15
+ - SMS facade and builder: `storage/framework/core/sms/src/sms.ts`
16
+ - Twilio driver: `storage/framework/core/sms/src/drivers/twilio.ts`
17
+ - Vonage driver: `storage/framework/core/sms/src/drivers/vonage.ts`
18
+ - Drivers index: `storage/framework/core/sms/src/drivers/index.ts`
19
+ - Configuration: `config/sms.ts`
20
+
21
+ ## Package Exports
22
+
23
+ ```typescript
24
+ // Main facade and functions
25
+ import SMS, { sms, send, sendSms, sendBulk, sendTemplate } from '@stacksjs/sms'
26
+ import { startVerification, checkVerification, cancelVerification } from '@stacksjs/sms'
27
+ import { formatE164, isValidPhoneNumber, isEnabled, getConfig, configure, getDriver, init } from '@stacksjs/sms'
28
+ import { SmsBuilder } from '@stacksjs/sms'
29
+
30
+ // Drivers
31
+ import { TwilioDriver, createTwilioDriver } from '@stacksjs/sms'
32
+ import { VonageDriver, createVonageDriver } from '@stacksjs/sms'
33
+ ```
34
+
35
+ ## SMS Facade Object
36
+
37
+ The `SMS` default export aggregates all functions:
38
+
39
+ ```typescript
40
+ SMS.init() // Load config from config/sms.ts
41
+ SMS.configure(config) // Override config at runtime
42
+ SMS.isEnabled() // Check if SMS is enabled (config.enabled)
43
+ SMS.getConfig() // Get current config (returns copy)
44
+
45
+ SMS.send(message) // Send single SMS
46
+ SMS.sendSms(message) // Alias for send
47
+ SMS.sendBulk(messages) // Send multiple SMS
48
+ SMS.sendTemplate(to, name, vars) // Send using template
49
+
50
+ SMS.getStatus(messageId) // Get delivery status
51
+ SMS.getBalance() // Get account balance
52
+ SMS.verifyNumber(phone) // Lookup/verify phone number
53
+
54
+ SMS.startVerification(req) // Start OTP flow
55
+ SMS.checkVerification(req) // Verify OTP code
56
+ SMS.cancelVerification(id) // Cancel pending verification
57
+
58
+ SMS.formatE164(phone, cc?) // Format to E.164
59
+ SMS.isValidPhoneNumber(phone) // Validate E.164 format
60
+
61
+ SMS.sms() // Create SmsBuilder instance
62
+ SMS.getDriver(provider?) // Get driver instance
63
+ SMS.getVerificationDriver(p?) // Get verification driver
64
+ ```
65
+
66
+ ## SmsBuilder (Fluent API)
67
+
68
+ ```typescript
69
+ import { sms } from '@stacksjs/sms'
70
+
71
+ // Basic SMS
72
+ await sms()
73
+ .to('+1234567890')
74
+ .body('Your code is 123456')
75
+ .from('+0987654321')
76
+ .send()
77
+
78
+ // With provider selection
79
+ await sms()
80
+ .to('+1234567890')
81
+ .body('Hello!')
82
+ .via('vonage')
83
+ .send()
84
+
85
+ // MMS with media and callback
86
+ await sms()
87
+ .to(['+1111111111', '+2222222222'])
88
+ .body('Check this out')
89
+ .media(['https://example.com/image.jpg'])
90
+ .callback('https://myapp.com/sms/status')
91
+ .send()
92
+
93
+ // .text() is an alias for .body()
94
+ await sms()
95
+ .to('+1234567890')
96
+ .text('Hello!')
97
+ .send()
98
+ ```
99
+
100
+ The builder validates that `to` and `body` are set before sending. If missing, it returns a failed `SmsSendResult` without throwing. If `.via(provider)` is set, it creates a new driver for that provider; otherwise uses the default driver.
101
+
102
+ ## Direct Send Functions
103
+
104
+ ```typescript
105
+ import { send, sendBulk } from '@stacksjs/sms'
106
+
107
+ // SmsMessage shape
108
+ await send({
109
+ to: '+1234567890', // string or string[]
110
+ body: 'Hello!',
111
+ from: '+0987654321', // optional, falls back to config
112
+ mediaUrls: ['url'], // optional, for MMS
113
+ statusCallback: 'url', // optional, webhook for status updates
114
+ })
115
+
116
+ // Bulk send
117
+ await sendBulk([msg1, msg2, msg3]) // returns SmsSendResult[]
118
+ ```
119
+
120
+ `send()` and all sending functions call `ensureConfig()` first, which lazily loads `config/sms.ts` via dynamic import.
121
+
122
+ ## Message Status & Info
123
+
124
+ ```typescript
125
+ import { getStatus, verifyNumber, getBalance } from '@stacksjs/sms'
126
+
127
+ // Get delivery status for a message
128
+ const status = await getStatus('SM_message_id')
129
+ // Returns SmsStatusUpdate | null (null if driver doesn't support it)
130
+
131
+ // Verify/lookup a phone number
132
+ const info = await verifyNumber('+1234567890')
133
+ // Returns { valid: boolean, carrier?: string, type?: string }
134
+
135
+ // Get account balance
136
+ const balance = await getBalance()
137
+ // Returns { balance: number, currency: string } | null
138
+ ```
139
+
140
+ ## Phone Verification (OTP/2FA)
141
+
142
+ ```typescript
143
+ import { startVerification, checkVerification, cancelVerification } from '@stacksjs/sms'
144
+
145
+ // Start -- sends OTP code via SMS (or 'call', 'email' for Twilio; 'sms', 'whatsapp' for Vonage)
146
+ const result = await startVerification({
147
+ to: '+1234567890',
148
+ channel: 'sms', // default: 'sms'
149
+ codeLength: 6, // optional
150
+ locale: 'en', // optional
151
+ customMessage: 'Your code: {code}', // optional, Twilio only
152
+ })
153
+ // Returns { success: boolean, verificationId?: string, status: 'pending' | 'denied', error?: string }
154
+
155
+ // Check -- verify the code the user entered
156
+ const check = await checkVerification({
157
+ to: '+1234567890', // Twilio requires 'to'
158
+ verificationId: result.verificationId, // Vonage requires this
159
+ code: '123456',
160
+ })
161
+ // Returns { success: boolean, verificationId?: string, status: 'approved' | 'denied', error?: string }
162
+
163
+ // Cancel -- cancel a pending verification
164
+ const cancelled = await cancelVerification(result.verificationId!)
165
+ // Returns boolean
166
+ ```
167
+
168
+ **Twilio** uses the Verify service (`verify.twilio.com/v2`) and requires `verifyServiceSid` passed to the TwilioDriver constructor.
169
+
170
+ **Vonage** uses the Verify V2 API (`api.nexmo.com/v2/verify`). Whatsapp channel maps to `whatsapp_interactive`.
171
+
172
+ ## SMS Templates
173
+
174
+ ```typescript
175
+ import { sendTemplate } from '@stacksjs/sms'
176
+
177
+ await sendTemplate('+1234567890', 'order-confirmation', {
178
+ orderNumber: '#12345',
179
+ total: '$29.99',
180
+ })
181
+ ```
182
+
183
+ Templates are defined in `config/sms.ts` under `templates[]`. Each template has `name`, `body`, and optional `variables`. Variables use single-brace syntax `{variableName}` in the template body. The function finds the template by name, replaces variables, and sends via the default driver.
184
+
185
+ Returns a failed result (without throwing) if the template is not found.
186
+
187
+ ## Phone Number Utilities
188
+
189
+ ```typescript
190
+ import { formatE164, isValidPhoneNumber } from '@stacksjs/sms'
191
+
192
+ // Normalize to E.164 format
193
+ formatE164('+1 (234) 567-890') // '+12345678900'
194
+ formatE164('2345678900', '1') // '+12345678900'
195
+ formatE164('002345678900') // '+2345678900' (00 prefix stripped)
196
+
197
+ // Validate E.164 format (regex: /^\+[1-9]\d{6,14}$/)
198
+ isValidPhoneNumber('+1234567890') // true
199
+ isValidPhoneNumber('1234567890') // true (formatted first, then validated)
200
+ ```
201
+
202
+ `formatE164()` strips spaces, dashes, and parentheses. If the number starts with `+`, returns as-is. If it starts with `00`, replaces with `+`. Otherwise prepends `+` and the default country code (from `config.defaultCountryCode` or `'1'` for US).
203
+
204
+ ## Twilio Driver
205
+
206
+ ```typescript
207
+ import { TwilioDriver, createTwilioDriver } from '@stacksjs/sms'
208
+
209
+ const driver = new TwilioDriver({
210
+ accountSid: 'AC...',
211
+ authToken: '...',
212
+ from: '+1234567890',
213
+ messagingServiceSid: 'MG...', // optional, used instead of 'from'
214
+ statusCallback: 'https://...', // optional, default callback URL
215
+ }, 'VA_verify_service_sid') // optional second arg for verification
216
+
217
+ // Or use factory
218
+ const driver = createTwilioDriver(config, verifyServiceSid?)
219
+ ```
220
+
221
+ Uses REST API at `https://api.twilio.com/2010-04-01`. Auth via HTTP Basic (`accountSid:authToken`).
222
+
223
+ Features:
224
+ - `send(message)` -- sends via Messages API, supports MMS (mediaUrls), statusCallback, messagingServiceSid
225
+ - `sendBulk(messages)` -- sends in parallel via `Promise.all`
226
+ - `getStatus(messageId)` -- retrieves message status
227
+ - `verify(phoneNumber)` -- uses Twilio Lookup API v2 with line_type_intelligence
228
+ - `getBalance()` -- retrieves account balance
229
+ - `startVerification(req)` -- Twilio Verify service
230
+ - `checkVerification(req)` -- check OTP code
231
+ - `cancelVerification(id)` -- cancel pending verification
232
+
233
+ Status mapping: queued, sending, sent, delivered, undelivered -> `SmsStatus`; canceled -> 'failed'.
234
+
235
+ ## Vonage Driver
236
+
237
+ ```typescript
238
+ import { VonageDriver, createVonageDriver } from '@stacksjs/sms'
239
+
240
+ const driver = new VonageDriver({
241
+ apiKey: '...',
242
+ apiSecret: '...',
243
+ from: 'MyApp',
244
+ applicationId: '...', // optional, for JWT auth
245
+ privateKey: '...', // optional, for JWT auth
246
+ }, true) // optional: useMessagesApi (default: false)
247
+
248
+ // Or use factory
249
+ const driver = createVonageDriver(config, useMessagesApi?)
250
+ ```
251
+
252
+ Two send modes:
253
+ - **SMS API** (legacy, default) -- `https://rest.nexmo.com/sms/json`, uses API key/secret in body
254
+ - **Messages API** (newer) -- `https://api.nexmo.com/v1/messages`, uses Basic auth or JWT
255
+
256
+ Features:
257
+ - `send(message)` -- sends via chosen API mode
258
+ - `sendBulk(messages)` -- sends in parallel
259
+ - `getStatus(messageId)` -- Messages API only
260
+ - `verify(phoneNumber)` -- Vonage Number Insight API (basic)
261
+ - `getBalance()` -- account balance in EUR
262
+ - `startVerification(req)` -- Vonage Verify V2 API
263
+ - `checkVerification(req)` -- requires `verificationId`
264
+ - `cancelVerification(id)` -- DELETE request to cancel
265
+
266
+ The `nexmo` export is a legacy alias for `vonage`.
267
+
268
+ ## Other Drivers (Commented Out / Placeholder)
269
+
270
+ The `drivers/` directory contains placeholder files for: `gupshup`, `nexmo` (alias for vonage), `plivo`, `sms77`, `sns`, `telnyx`, `termii`. These are all commented out and not functional. Only Twilio and Vonage are active.
271
+
272
+ ## config/sms.ts
273
+
274
+ ```typescript
275
+ {
276
+ enabled: false, // Must explicitly enable
277
+ provider: 'twilio', // 'twilio' | 'vonage'
278
+ from: env.SMS_FROM_NUMBER || '',
279
+ defaultCountryCode: 'US',
280
+ messageType: 'TRANSACTIONAL', // TRANSACTIONAL or PROMOTIONAL
281
+
282
+ drivers: {
283
+ twilio: {
284
+ accountSid: env.TWILIO_ACCOUNT_SID || '',
285
+ authToken: env.TWILIO_AUTH_TOKEN || '',
286
+ from: env.TWILIO_FROM_NUMBER || '',
287
+ messagingServiceSid: env.TWILIO_MESSAGING_SERVICE_SID || '',
288
+ },
289
+ vonage: {
290
+ apiKey: env.VONAGE_API_KEY || '',
291
+ apiSecret: env.VONAGE_API_SECRET || '',
292
+ from: env.VONAGE_FROM_NUMBER || '',
293
+ },
294
+ pinpoint: {
295
+ region: env.AWS_REGION || 'us-east-1',
296
+ accessKeyId: env.AWS_ACCESS_KEY_ID || '',
297
+ secretAccessKey: env.AWS_SECRET_ACCESS_KEY || '',
298
+ senderId: env.SMS_SENDER_ID || '',
299
+ originationNumber: env.SMS_ORIGINATION_NUMBER || '',
300
+ },
301
+ },
302
+
303
+ maxSpendPerMonth: 100,
304
+ optOut: {
305
+ enabled: true,
306
+ keywords: ['STOP', 'UNSUBSCRIBE', 'CANCEL', 'END', 'QUIT'],
307
+ },
308
+ templates: [], // Array of { name, body, variables }
309
+ twoWay: {
310
+ enabled: false,
311
+ },
312
+ } satisfies SmsConfig
313
+ ```
314
+
315
+ ## Type Interfaces (from @stacksjs/types)
316
+
317
+ ```typescript
318
+ interface SmsMessage {
319
+ to: string | string[]
320
+ body: string
321
+ from?: string
322
+ mediaUrls?: string[]
323
+ statusCallback?: string
324
+ }
325
+
326
+ interface SmsSendResult {
327
+ success: boolean
328
+ messageId?: string
329
+ status?: SmsStatus
330
+ to: string
331
+ provider: string
332
+ error?: string
333
+ segments?: number
334
+ price?: number
335
+ currency?: string
336
+ }
337
+
338
+ type SmsStatus = 'queued' | 'sending' | 'sent' | 'delivered' | 'undelivered' | 'failed' | 'unknown'
339
+
340
+ interface SmsStatusUpdate {
341
+ messageId: string
342
+ to: string
343
+ status: SmsStatus
344
+ timestamp: Date
345
+ errorCode?: string
346
+ errorMessage?: string
347
+ }
348
+
349
+ type SmsProvider = 'twilio' | 'vonage' | 'pinpoint'
350
+
351
+ interface VerificationRequest {
352
+ to: string
353
+ channel?: string // 'sms' | 'call' | 'email' | 'whatsapp'
354
+ codeLength?: number
355
+ locale?: string
356
+ customMessage?: string // Twilio only
357
+ }
358
+
359
+ interface VerificationCheckRequest {
360
+ to: string
361
+ code: string
362
+ verificationId?: string
363
+ }
364
+
365
+ interface VerificationResult {
366
+ success: boolean
367
+ verificationId?: string
368
+ status: 'pending' | 'approved' | 'denied'
369
+ error?: string
370
+ }
371
+ ```
372
+
373
+ ## Gotchas
374
+ - SMS is **disabled by default** (`enabled: false`) -- must set to `true` in `config/sms.ts`
375
+ - Provider API keys go in `.env`, not config files
376
+ - Config is loaded lazily via dynamic import on first `send()`/operation -- `init()` pre-loads it
377
+ - Only Twilio and Vonage drivers are fully implemented; other drivers (gupshup, plivo, sns, telnyx, etc.) are commented-out placeholders
378
+ - `pinpoint` appears in config but has no driver implementation in `getDriver()` -- using it throws `'Unsupported SMS provider: pinpoint'`
379
+ - The `defaultCountryCode` in config is `'US'` but `formatE164()` uses it as a numeric code prefix (the fallback is `'1'`), so the actual behavior uses the number `'1'` for US
380
+ - Template variables use single-brace syntax `{variableName}`, NOT double-brace
381
+ - `sendBulk()` sends all messages in parallel via `Promise.all` -- no rate limiting
382
+ - Twilio verification requires a `verifyServiceSid` passed to the driver constructor, which is not part of the standard config structure
383
+ - Vonage JWT authentication is a simplified placeholder -- real RS256 signing is not fully implemented
384
+ - `getDriver()` creates a new driver instance each time unless accessed through the cached `getDefaultDriver()`
385
+ - `sendTemplate()` returns a failed result (not an exception) if the template name is not found
@@ -0,0 +1,303 @@
1
+ ---
2
+ name: stacks-socials
3
+ description: Use when implementing social authentication in Stacks — OAuth2 flows with GitHub/Google/Facebook/Twitter providers, the AbstractProvider base class, PKCE support, state management, scope configuration, social user profiles, or token handling. Covers @stacksjs/socials.
4
+ license: MIT
5
+ compatibility: Bun >= 1.3.0, TypeScript
6
+ allowed-tools: Read Edit Write Bash Grep Glob
7
+ ---
8
+
9
+ # Stacks Socials
10
+
11
+ OAuth2-based social authentication with 4 built-in providers.
12
+
13
+ ## Key Paths
14
+ - Core package: `storage/framework/core/socials/src/`
15
+
16
+ ## Source Files
17
+ ```
18
+ socials/src/
19
+ ├── index.ts # re-exports from drivers/
20
+ ├── abstract.ts # AbstractProvider base class
21
+ ├── token.ts # Token class
22
+ ├── types.ts # SocialUser, provider-specific interfaces
23
+ ├── exceptions.ts # InvalidStateException, ConfigException
24
+ └── drivers/
25
+ ├── index.ts # re-exports all 4 providers
26
+ ├── github.ts # GitHub OAuth provider
27
+ ├── google.ts # Google OAuth provider
28
+ ├── facebook.ts # Facebook OAuth provider
29
+ └── twitter.ts # Twitter/X OAuth2 + PKCE provider
30
+ ```
31
+
32
+ ## AbstractProvider Base Class
33
+
34
+ All providers extend `AbstractProvider` which implements `ProviderInterface`. The constructor takes a `ProviderConfig`:
35
+
36
+ ```typescript
37
+ interface ProviderConfig {
38
+ clientId: string
39
+ clientSecret: string
40
+ redirectUrl: string
41
+ guzzle?: Record<string, any>
42
+ }
43
+ ```
44
+
45
+ Properties and methods on `AbstractProvider`:
46
+
47
+ ```typescript
48
+ abstract class AbstractProvider implements ProviderInterface {
49
+ // Protected state
50
+ protected clientId: string
51
+ protected clientSecret: string
52
+ protected redirectUrl: string
53
+ protected parameters: Record<string, any> = {}
54
+ protected _scopes: string[] = []
55
+ protected scopeSeparator: string = ','
56
+ protected _stateless: boolean = false
57
+ protected _usesPKCE: boolean = false
58
+ protected user: SocialUser | null = null
59
+
60
+ // Abstract methods (each provider implements)
61
+ abstract getAuthUrl(): Promise<string> // public, returns Promise
62
+ protected abstract getTokenUrl(): string // protected
63
+ abstract getAccessToken(code: string): Promise<string>
64
+ abstract getUserByToken(token: string): Promise<SocialUser>
65
+
66
+ // Scope management
67
+ scopes(scopes: string | string[]): this // merge into existing (deduplicates via Set)
68
+ setScopes(scopes: string | string[]): this // replace all scopes (deduplicates via Set)
69
+ getScopes(): string[]
70
+
71
+ // Configuration
72
+ setRedirectUrl(url: string): this
73
+ stateless(): this // sets _stateless = true
74
+ enablePKCE(): this // sets _usesPKCE = true
75
+ with(parameters: Record<string, any>): this // replaces custom query parameters
76
+
77
+ // User retrieval
78
+ async userFromToken(token: string): Promise<SocialUser> // calls getUserByToken, adds token
79
+
80
+ // URL building (protected)
81
+ protected buildAuthUrlFromBase(url: string, state: string | null): string
82
+ protected getCodeFields(state: string | null = null): Record<string, any>
83
+ protected formatScopes(scopes: string[], scopeSeparator: string): string
84
+
85
+ // State helpers (protected)
86
+ protected usesState(): boolean // returns !_stateless
87
+ protected isStateless(): boolean // returns _stateless
88
+ protected getState(): string // 20 random bytes -> 40 hex chars
89
+
90
+ // PKCE helpers (protected)
91
+ protected usesPKCE(): boolean
92
+ protected getCodeVerifier(): string // 48 random bytes -> 96 hex chars
93
+ protected async getCodeChallenge(): Promise<string> // SHA-256 of verifier, base64url encoded
94
+ protected getCodeChallengeMethod(): string // always 'S256'
95
+ }
96
+ ```
97
+
98
+ The `getCodeFields()` method builds the query parameters for the authorization URL:
99
+ - Always includes: `client_id`, `redirect_uri`, `scope` (joined by `scopeSeparator`), `response_type: 'code'`
100
+ - Conditionally adds `state` when `usesState()` is true
101
+ - Conditionally adds `code_challenge` and `code_challenge_method` when `usesPKCE()` is true
102
+ - Merges in any custom `parameters` set via `with()`
103
+
104
+ ## Provider Implementations
105
+
106
+ ### GitHub Provider
107
+
108
+ ```typescript
109
+ class GitHubProvider extends AbstractProvider {
110
+ protected baseUrl = 'https://github.com'
111
+ protected apiUrl = 'https://api.github.com'
112
+ }
113
+ ```
114
+
115
+ - Config source: `config.services.github` (clientId, clientSecret, redirectUrl, scopes)
116
+ - Default scopes: `['read:user', 'user:email']`
117
+ - Auth URL: `https://github.com/login/oauth/authorize` with scopes joined by space
118
+ - Token URL: `https://github.com/login/oauth/access_token` (POST)
119
+ - User API: Fetches `/user` and `/user/emails` in parallel via `Promise.all`
120
+ - Email resolution: Primary email first, then verified, then first available
121
+ - Uses `@stacksjs/api` `fetcher` for HTTP requests
122
+ - Throws `ConfigException` if clientId, clientSecret, or redirectUrl missing
123
+ - GitHub token response: `GitHubTokenResponse { access_token, error?, error_description? }`
124
+
125
+ ### Google Provider
126
+
127
+ ```typescript
128
+ class GoogleProvider extends AbstractProvider {
129
+ protected baseUrl = 'https://accounts.google.com'
130
+ protected apiUrl = 'https://www.googleapis.com'
131
+ }
132
+ ```
133
+
134
+ - Config source: `config.services.google`
135
+ - Default scopes: `['https://www.googleapis.com/auth/userinfo.profile', 'https://www.googleapis.com/auth/userinfo.email']`
136
+ - Auth URL: `https://accounts.google.com/o/oauth2/v2/auth` (includes `access_type: 'offline'`, `prompt: 'consent'`)
137
+ - Token URL: `https://accounts.google.com/oauth2/v4/token` (POST with `grant_type: 'authorization_code'`)
138
+ - User API: `https://www.googleapis.com/oauth2/v2/userinfo` with Bearer token
139
+ - Maps `given_name` to `nickname`, `picture` to `avatar`
140
+ - Google user type: `{ id, email, verified_email, name, given_name, family_name, picture, locale }`
141
+
142
+ ### Facebook Provider
143
+
144
+ ```typescript
145
+ class FacebookProvider extends AbstractProvider {
146
+ protected baseUrl = 'https://www.facebook.com'
147
+ protected apiUrl = 'https://graph.facebook.com'
148
+ }
149
+ ```
150
+
151
+ - Config source: `config.services.facebook`
152
+ - Default scopes: `['email', 'public_profile']`
153
+ - Auth URL: `https://www.facebook.com/v18.0/dialog/oauth` with scopes joined by comma
154
+ - Token URL: `https://graph.facebook.com/v18.0/oauth/access_token` (GET request, not POST)
155
+ - User API: `https://graph.facebook.com/v18.0/me?fields=id,name,email,picture`
156
+ - Token is passed as query parameter `access_token`, not in Authorization header
157
+ - Always sets `nickname: null` (Facebook does not expose usernames)
158
+ - Avatar extracted from `picture.data.url`
159
+ - Error response shape: `{ error: { message, type, code } }` (nested object, unlike other providers)
160
+
161
+ ### Twitter/X Provider
162
+
163
+ ```typescript
164
+ class TwitterProvider extends AbstractProvider {
165
+ protected baseUrl = 'https://twitter.com'
166
+ protected apiUrl = 'https://api.twitter.com'
167
+ private codeVerifier: string | null = null
168
+ }
169
+ ```
170
+
171
+ - Config source: `config.services.twitter`
172
+ - Default scopes: `['users.read', 'tweet.read']`
173
+ - Uses OAuth 2.0 with PKCE (not OAuth 1.0a)
174
+ - Auth URL: `https://twitter.com/i/oauth2/authorize` with PKCE code challenge
175
+ - Token URL: `https://api.twitter.com/2/oauth2/token` (POST with Basic auth)
176
+ - User API: `https://api.twitter.com/2/users/me?user.fields=profile_image_url` with Bearer token
177
+ - PKCE implementation uses its own `generateCodeVerifier()` and `generateCodeChallenge()` methods (using `node:crypto` `randomBytes` and `createHash`), not the base class PKCE
178
+ - Code verifier: `randomBytes(32)` -> base64 -> alphanumeric only -> max 128 chars
179
+ - Token exchange uses Basic auth: `Buffer.from(clientId:clientSecret).toString('base64')`
180
+ - `getAccessToken()` throws if `codeVerifier` is null -- `getAuthUrl()` must be called first
181
+ - Maps `username` to `nickname`, `profile_image_url` to `avatar`
182
+
183
+ ## SocialUser Interface
184
+
185
+ ```typescript
186
+ interface SocialUser {
187
+ id: string
188
+ nickname: string | null
189
+ name: string
190
+ email: string | null
191
+ avatar: string | null
192
+ token: string
193
+ raw?: any // full provider API response
194
+ }
195
+ ```
196
+
197
+ ## ProviderInterface
198
+
199
+ ```typescript
200
+ interface ProviderInterface {
201
+ getAuthUrl: () => Promise<string>
202
+ getAccessToken: (code: string) => Promise<string>
203
+ getUserByToken: (token: string) => Promise<SocialUser>
204
+ }
205
+ ```
206
+
207
+ ## Token Class
208
+
209
+ ```typescript
210
+ class Token {
211
+ constructor(
212
+ public accessToken: string,
213
+ public refreshToken: string | null = null,
214
+ public expiresIn: number | null = null,
215
+ public approvedScopes: string[] = [],
216
+ ) {}
217
+ }
218
+ ```
219
+
220
+ ## Provider-Specific Types
221
+
222
+ ```typescript
223
+ // GitHub
224
+ interface GitHubUser { id: number, login: string, name: string | null, avatar_url: string | null, [key: string]: any }
225
+ interface GitHubEmail { email: string, primary: boolean, verified: boolean }
226
+ interface GitHubTokenResponse { access_token: string, error?: string, error_description?: string }
227
+
228
+ // Twitter/X
229
+ interface TwitterUser { id: string, username: string, name: string, email?: string, profile_image_url?: string }
230
+ interface TwitterTokenResponse { access_token: string, token_type: string, expires_in: number, scope: string, error?: string, error_description?: string }
231
+
232
+ // Google (local to google.ts)
233
+ interface GoogleUser { id: string, email: string, verified_email: boolean, name: string, given_name: string, family_name: string, picture: string, locale: string }
234
+ interface GoogleTokenResponse { access_token: string, token_type: string, expires_in: number, error?: string, error_description?: string }
235
+
236
+ // Facebook (local to facebook.ts)
237
+ interface FacebookUser { id: string, email?: string, name: string, picture?: { data: { url: string } } }
238
+ interface FacebookTokenResponse { access_token: string, token_type: string, expires_in: number, error?: { message: string, type: string, code: number } }
239
+ ```
240
+
241
+ ## Exceptions
242
+
243
+ ```typescript
244
+ class InvalidStateException extends Error { name = 'InvalidStateException' }
245
+ class ConfigException extends Error { name = 'ConfigException' }
246
+ ```
247
+
248
+ Providers throw `ConfigException` when `clientId`, `clientSecret`, or `redirectUrl` are missing.
249
+
250
+ ## OAuth2 Flow
251
+
252
+ ### 1. Get Auth URL
253
+ ```typescript
254
+ const github = new GitHubProvider({ clientId: '', clientSecret: '', redirectUrl: '' })
255
+ const authUrl = await github.scopes(['user:email', 'read:org']).getAuthUrl()
256
+ // Each provider reads actual config from config.services.<provider>
257
+ // The constructor config is overridden by getConfig() in each provider
258
+ ```
259
+
260
+ ### 2. Handle Callback
261
+ ```typescript
262
+ const token = await github.getAccessToken(code)
263
+ const user = await github.getUserByToken(token)
264
+ // user: { id, nickname, name, email, avatar, token, raw }
265
+ ```
266
+
267
+ ### 3. User from Existing Token
268
+ ```typescript
269
+ const user = await github.userFromToken(existingToken)
270
+ // Calls getUserByToken internally, adds token to result
271
+ ```
272
+
273
+ ## Configuration Source
274
+
275
+ All providers read from the Stacks config object:
276
+ ```typescript
277
+ config.services.github // { clientId, clientSecret, redirectUrl, scopes }
278
+ config.services.google // { clientId, clientSecret, redirectUrl, scopes }
279
+ config.services.facebook // { clientId, clientSecret, redirectUrl, scopes }
280
+ config.services.twitter // { clientId, clientSecret, redirectUrl, scopes }
281
+ ```
282
+
283
+ Each provider's `getConfig()` method reads these and also calls `this.setScopes()` with the configured scopes.
284
+
285
+ ## Dependencies
286
+ - `@stacksjs/api` -- `fetcher` used for all HTTP requests (provides `.withHeaders()`, `.get()`, `.post()`)
287
+ - `@stacksjs/config` -- provides `config.services.*` for provider credentials
288
+ - `node:buffer` and `node:crypto` -- used by Twitter provider for PKCE and Basic auth
289
+
290
+ ## Gotchas
291
+ - The `ProviderConfig` constructor params are largely ignored -- each provider's `getConfig()` reads from `config.services.*` instead
292
+ - `getAuthUrl()` returns `Promise<string>` (not `string`) -- it is async
293
+ - `getTokenUrl()` is `protected` -- not part of the public `ProviderInterface`
294
+ - GitHub joins scopes with space, Facebook with comma, Google with space, Twitter with space
295
+ - Facebook uses GET for token exchange; all others use POST
296
+ - Facebook `nickname` is always `null`
297
+ - Twitter requires `getAuthUrl()` before `getAccessToken()` because the code verifier is stored as instance state
298
+ - Twitter uses its own PKCE implementation via `node:crypto`, not the base class `getCodeVerifier()`/`getCodeChallenge()`
299
+ - Google auth URL includes `access_type: 'offline'` and `prompt: 'consent'` for refresh token support
300
+ - The base class state token is 40 hex chars (20 bytes), not the 20 chars stated in some docs
301
+ - `userFromToken()` spreads the user object and adds/overwrites the `token` field
302
+ - All providers include the full API response in `SocialUser.raw`
303
+ - Errors from GitHub/Google/Twitter are flat objects with `error` + `error_description`; Facebook nests it under `error.message`