@askrjs/cli 0.0.2

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 (460) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +140 -0
  3. package/dist/add-DqhqRzBQ.js +555 -0
  4. package/dist/add-DqhqRzBQ.js.map +1 -0
  5. package/dist/add.js +3 -0
  6. package/dist/cli.js +91 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/create.js +923 -0
  9. package/dist/create.js.map +1 -0
  10. package/dist/is-direct-execution-Cdlr-ZUl.js +20 -0
  11. package/dist/is-direct-execution-Cdlr-ZUl.js.map +1 -0
  12. package/dist/openapi.js +127 -0
  13. package/dist/openapi.js.map +1 -0
  14. package/dist/skills/askr-accessibility/SKILL.md +68 -0
  15. package/dist/skills/askr-accessibility/agents/openai.yaml +4 -0
  16. package/dist/skills/askr-agent-execution/SKILL.md +85 -0
  17. package/dist/skills/askr-agent-execution/agents/openai.yaml +4 -0
  18. package/dist/skills/askr-agent-workflows/SKILL.md +57 -0
  19. package/dist/skills/askr-agent-workflows/agents/openai.yaml +4 -0
  20. package/dist/skills/askr-api-integration/SKILL.md +79 -0
  21. package/dist/skills/askr-api-integration/agents/openai.yaml +4 -0
  22. package/dist/skills/askr-app-builder/SKILL.md +99 -0
  23. package/dist/skills/askr-app-builder/agents/openai.yaml +4 -0
  24. package/dist/skills/askr-auth-access/SKILL.md +74 -0
  25. package/dist/skills/askr-auth-access/agents/openai.yaml +4 -0
  26. package/dist/skills/askr-cli-vite/SKILL.md +76 -0
  27. package/dist/skills/askr-cli-vite/agents/openai.yaml +4 -0
  28. package/dist/skills/askr-dashboard-charts/SKILL.md +82 -0
  29. package/dist/skills/askr-dashboard-charts/agents/openai.yaml +4 -0
  30. package/dist/skills/askr-design-system/SKILL.md +86 -0
  31. package/dist/skills/askr-design-system/agents/openai.yaml +4 -0
  32. package/dist/skills/askr-env-config/SKILL.md +74 -0
  33. package/dist/skills/askr-env-config/agents/openai.yaml +4 -0
  34. package/dist/skills/askr-error-loading-empty/SKILL.md +89 -0
  35. package/dist/skills/askr-error-loading-empty/agents/openai.yaml +4 -0
  36. package/dist/skills/askr-file-upload-artifacts/SKILL.md +77 -0
  37. package/dist/skills/askr-file-upload-artifacts/agents/openai.yaml +4 -0
  38. package/dist/skills/askr-forms-tables-crud/SKILL.md +98 -0
  39. package/dist/skills/askr-forms-tables-crud/agents/openai.yaml +4 -0
  40. package/dist/skills/askr-mental-model/SKILL.md +109 -0
  41. package/dist/skills/askr-mental-model/agents/openai.yaml +4 -0
  42. package/dist/skills/askr-migration-react/SKILL.md +81 -0
  43. package/dist/skills/askr-migration-react/agents/openai.yaml +4 -0
  44. package/dist/skills/askr-observability-debugging/SKILL.md +83 -0
  45. package/dist/skills/askr-observability-debugging/agents/openai.yaml +4 -0
  46. package/dist/skills/askr-project-structure/SKILL.md +79 -0
  47. package/dist/skills/askr-project-structure/agents/openai.yaml +4 -0
  48. package/dist/skills/askr-query-mutation/SKILL.md +115 -0
  49. package/dist/skills/askr-query-mutation/agents/openai.yaml +4 -0
  50. package/dist/skills/askr-realtime-streaming/SKILL.md +76 -0
  51. package/dist/skills/askr-realtime-streaming/agents/openai.yaml +4 -0
  52. package/dist/skills/askr-resources-data/SKILL.md +100 -0
  53. package/dist/skills/askr-resources-data/agents/openai.yaml +4 -0
  54. package/dist/skills/askr-routing-layouts/SKILL.md +107 -0
  55. package/dist/skills/askr-routing-layouts/agents/openai.yaml +4 -0
  56. package/dist/skills/askr-runtime-reactivity/SKILL.md +92 -0
  57. package/dist/skills/askr-runtime-reactivity/agents/openai.yaml +4 -0
  58. package/dist/skills/askr-ssr-ssg/SKILL.md +76 -0
  59. package/dist/skills/askr-ssr-ssg/agents/openai.yaml +4 -0
  60. package/dist/skills/askr-testing-determinism/SKILL.md +75 -0
  61. package/dist/skills/askr-testing-determinism/agents/openai.yaml +4 -0
  62. package/dist/skills/askr-theming/SKILL.md +86 -0
  63. package/dist/skills/askr-theming/agents/openai.yaml +4 -0
  64. package/dist/skills/askr-ui-composition/SKILL.md +92 -0
  65. package/dist/skills/askr-ui-composition/agents/openai.yaml +4 -0
  66. package/dist/skills-Bh0mEhIx.js +682 -0
  67. package/dist/skills-Bh0mEhIx.js.map +1 -0
  68. package/dist/skills.js +3 -0
  69. package/dist/ssg.js +188 -0
  70. package/dist/ssg.js.map +1 -0
  71. package/dist/templates/full-stack/AGENTS.md +12 -0
  72. package/dist/templates/full-stack/README.md +18 -0
  73. package/dist/templates/full-stack/gitignore.template +4 -0
  74. package/dist/templates/full-stack/index.html +14 -0
  75. package/dist/templates/full-stack/package.json +37 -0
  76. package/dist/templates/full-stack/server.ts +13 -0
  77. package/dist/templates/full-stack/src/action-authorizations.ts +10 -0
  78. package/dist/templates/full-stack/src/actions/create-message.ts +10 -0
  79. package/dist/templates/full-stack/src/i18n.ts +8 -0
  80. package/dist/templates/full-stack/src/main.tsx +12 -0
  81. package/dist/templates/full-stack/src/pages/home.tsx +25 -0
  82. package/dist/templates/full-stack/src/pages/layout.tsx +33 -0
  83. package/dist/templates/full-stack/src/pages/not-found.tsx +4 -0
  84. package/dist/templates/full-stack/src/routes.tsx +20 -0
  85. package/dist/templates/full-stack/src/schemas.ts +11 -0
  86. package/dist/templates/full-stack/src/server/action-registry.ts +12 -0
  87. package/dist/templates/full-stack/src/server/actions/create-message.ts +14 -0
  88. package/dist/templates/full-stack/src/server/app.ts +66 -0
  89. package/dist/templates/full-stack/src/server/dependencies.ts +55 -0
  90. package/dist/templates/full-stack/src/server/entry-server.ts +8 -0
  91. package/dist/templates/full-stack/src/telemetry.ts +4 -0
  92. package/dist/templates/full-stack/src/vite-server.d.ts +6 -0
  93. package/dist/templates/full-stack/tests/actions/create-message.test.ts +13 -0
  94. package/dist/templates/full-stack/tsconfig.json +16 -0
  95. package/dist/templates/full-stack/vite.config.ts +11 -0
  96. package/dist/templates/spa/AGENTS.md +60 -0
  97. package/dist/templates/spa/README.md +96 -0
  98. package/dist/templates/spa/gitignore.template +16 -0
  99. package/dist/templates/spa/index.html +13 -0
  100. package/dist/templates/spa/package.json +35 -0
  101. package/dist/templates/spa/src/adapters/operations-client.ts +90 -0
  102. package/dist/templates/spa/src/components/shared/metric-card.tsx +27 -0
  103. package/dist/templates/spa/src/components/shared/status-badge.tsx +24 -0
  104. package/dist/templates/spa/src/features/operations/operations.query.ts +9 -0
  105. package/dist/templates/spa/src/main.tsx +10 -0
  106. package/dist/templates/spa/src/pages/_layout.tsx +9 -0
  107. package/dist/templates/spa/src/pages/_routes.tsx +27 -0
  108. package/dist/templates/spa/src/pages/app/_layout.tsx +94 -0
  109. package/dist/templates/spa/src/pages/app/_routes.tsx +10 -0
  110. package/dist/templates/spa/src/pages/app/admin-home.tsx +152 -0
  111. package/dist/templates/spa/src/pages/app/agent-runs.tsx +93 -0
  112. package/dist/templates/spa/src/pages/app/settings.tsx +91 -0
  113. package/dist/templates/spa/src/pages/auth/_layout.tsx +38 -0
  114. package/dist/templates/spa/src/pages/auth/_routes.tsx +6 -0
  115. package/dist/templates/spa/src/pages/auth/login.tsx +63 -0
  116. package/dist/templates/spa/src/pages/not-found.tsx +22 -0
  117. package/dist/templates/spa/src/pages/public/_layout.tsx +47 -0
  118. package/dist/templates/spa/src/pages/public/_routes.tsx +6 -0
  119. package/dist/templates/spa/src/pages/public/home.tsx +143 -0
  120. package/dist/templates/spa/src/shared/format.ts +12 -0
  121. package/dist/templates/spa/src/shared/navigation.ts +15 -0
  122. package/dist/templates/spa/src/styles/components.css +49 -0
  123. package/dist/templates/spa/src/styles/layout.css +192 -0
  124. package/dist/templates/spa/src/styles/reset.css +44 -0
  125. package/dist/templates/spa/src/styles/theme.css +57 -0
  126. package/dist/templates/spa/src/styles/tokens.css +20 -0
  127. package/dist/templates/spa/src/styles.css +7 -0
  128. package/dist/templates/spa/src/styles.d.ts +1 -0
  129. package/dist/templates/spa/tests/app.test.tsx +37 -0
  130. package/dist/templates/spa/tests/components/shared.test.tsx +12 -0
  131. package/dist/templates/spa/tests/resources.test.ts +22 -0
  132. package/dist/templates/spa/tsconfig.json +20 -0
  133. package/dist/templates/spa/tsconfig.node.json +10 -0
  134. package/dist/templates/spa/vite.config.ts +24 -0
  135. package/dist/templates/spa/vitest.config.ts +17 -0
  136. package/dist/templates/ssg/AGENTS.md +55 -0
  137. package/dist/templates/ssg/README.md +39 -0
  138. package/dist/templates/ssg/gitignore.template +17 -0
  139. package/dist/templates/ssg/index.html +13 -0
  140. package/dist/templates/ssg/package.json +35 -0
  141. package/dist/templates/ssg/src/app.tsx +14 -0
  142. package/dist/templates/ssg/src/components/badge.tsx +3 -0
  143. package/dist/templates/ssg/src/components/counter.tsx +30 -0
  144. package/dist/templates/ssg/src/components/site-shell.tsx +111 -0
  145. package/dist/templates/ssg/src/jsx.d.ts +23 -0
  146. package/dist/templates/ssg/src/main.tsx +8 -0
  147. package/dist/templates/ssg/src/pages/about.tsx +82 -0
  148. package/dist/templates/ssg/src/pages/content.tsx +63 -0
  149. package/dist/templates/ssg/src/pages/example.tsx +97 -0
  150. package/dist/templates/ssg/src/pages/home.tsx +51 -0
  151. package/dist/templates/ssg/src/resources/user.ts +15 -0
  152. package/dist/templates/ssg/src/routes.tsx +15 -0
  153. package/dist/templates/ssg/src/styles.css +89 -0
  154. package/dist/templates/ssg/src/vite-env.d.ts +5 -0
  155. package/dist/templates/ssg/ssg.config.ts +34 -0
  156. package/dist/templates/ssg/tests/app.test.tsx +19 -0
  157. package/dist/templates/ssg/tests/components/counter.test.tsx +18 -0
  158. package/dist/templates/ssg/tests/resources.test.ts +11 -0
  159. package/dist/templates/ssg/tests/ssg-config.test.ts +11 -0
  160. package/dist/templates/ssg/tsconfig.json +20 -0
  161. package/dist/templates/ssg/tsconfig.node.json +10 -0
  162. package/dist/templates/ssg/vite.config.ts +24 -0
  163. package/dist/templates/ssg/vitest.config.ts +17 -0
  164. package/dist/templates/ssr/AGENTS.md +28 -0
  165. package/dist/templates/ssr/README.md +38 -0
  166. package/dist/templates/ssr/gitignore.template +16 -0
  167. package/dist/templates/ssr/index.html +13 -0
  168. package/dist/templates/ssr/package.json +34 -0
  169. package/dist/templates/ssr/server.ts +16 -0
  170. package/dist/templates/ssr/src/app.tsx +21 -0
  171. package/dist/templates/ssr/src/components/counter.tsx +26 -0
  172. package/dist/templates/ssr/src/entry-server.tsx +10 -0
  173. package/dist/templates/ssr/src/main.tsx +11 -0
  174. package/dist/templates/ssr/src/pages/about.tsx +75 -0
  175. package/dist/templates/ssr/src/pages/example.tsx +113 -0
  176. package/dist/templates/ssr/src/pages/home.tsx +56 -0
  177. package/dist/templates/ssr/src/resources/user.ts +15 -0
  178. package/dist/templates/ssr/src/routes.tsx +13 -0
  179. package/dist/templates/ssr/src/styles.css +148 -0
  180. package/dist/templates/ssr/src/vite-server.d.ts +7 -0
  181. package/dist/templates/ssr/tests/app.test.tsx +24 -0
  182. package/dist/templates/ssr/tests/components/counter.test.tsx +13 -0
  183. package/dist/templates/ssr/tests/resources.test.ts +11 -0
  184. package/dist/templates/ssr/tsconfig.json +22 -0
  185. package/dist/templates/ssr/tsconfig.node.json +10 -0
  186. package/dist/templates/ssr/tsconfig.server.json +15 -0
  187. package/dist/templates/ssr/vite.config.ts +25 -0
  188. package/dist/templates/ssr/vitest.config.ts +13 -0
  189. package/dist/templates/startkit/AGENTS.md +77 -0
  190. package/dist/templates/startkit/README.md +192 -0
  191. package/dist/templates/startkit/gitignore.template +16 -0
  192. package/dist/templates/startkit/index.html +13 -0
  193. package/dist/templates/startkit/package.json +35 -0
  194. package/dist/templates/startkit/src/components/app-header.tsx +93 -0
  195. package/dist/templates/startkit/src/components/app-sidebar.tsx +95 -0
  196. package/dist/templates/startkit/src/components/data-table.tsx +80 -0
  197. package/dist/templates/startkit/src/components/empty-state.tsx +13 -0
  198. package/dist/templates/startkit/src/components/page-header.tsx +23 -0
  199. package/dist/templates/startkit/src/components/stat-card.tsx +24 -0
  200. package/dist/templates/startkit/src/features/accounts/account-filters.tsx +61 -0
  201. package/dist/templates/startkit/src/features/accounts/account-table.tsx +79 -0
  202. package/dist/templates/startkit/src/lib/format.ts +31 -0
  203. package/dist/templates/startkit/src/lib/mock-data.ts +441 -0
  204. package/dist/templates/startkit/src/lib/routes.ts +116 -0
  205. package/dist/templates/startkit/src/main.tsx +12 -0
  206. package/dist/templates/startkit/src/pages/_layout.tsx +56 -0
  207. package/dist/templates/startkit/src/pages/auth/_layout.tsx +7 -0
  208. package/dist/templates/startkit/src/pages/auth/login.tsx +129 -0
  209. package/dist/templates/startkit/src/pages/home.tsx +83 -0
  210. package/dist/templates/startkit/src/pages/not-found.tsx +24 -0
  211. package/dist/templates/startkit/src/pages/workspace/_layout.tsx +17 -0
  212. package/dist/templates/startkit/src/pages/workspace/accounts/index.tsx +217 -0
  213. package/dist/templates/startkit/src/pages/workspace/dashboard.tsx +118 -0
  214. package/dist/templates/startkit/src/pages/workspace/settings.tsx +218 -0
  215. package/dist/templates/startkit/src/router.tsx +7 -0
  216. package/dist/templates/startkit/src/routes/auth-config.ts +38 -0
  217. package/dist/templates/startkit/src/routes/auth.ts +8 -0
  218. package/dist/templates/startkit/src/routes/index.ts +28 -0
  219. package/dist/templates/startkit/src/routes/public.ts +8 -0
  220. package/dist/templates/startkit/src/routes/workspace/accounts.ts +8 -0
  221. package/dist/templates/startkit/src/routes/workspace/index.ts +14 -0
  222. package/dist/templates/startkit/src/styles/components.css +396 -0
  223. package/dist/templates/startkit/src/styles/layout.css +192 -0
  224. package/dist/templates/startkit/src/styles/reset.css +38 -0
  225. package/dist/templates/startkit/src/styles/theme.css +76 -0
  226. package/dist/templates/startkit/src/styles/tokens.css +67 -0
  227. package/dist/templates/startkit/src/styles.css +7 -0
  228. package/dist/templates/startkit/src/toast.ts +55 -0
  229. package/dist/templates/startkit/src/utils/join-classes.ts +4 -0
  230. package/dist/templates/startkit/src/vite-env.d.ts +5 -0
  231. package/dist/templates/startkit/tests/app.test.tsx +32 -0
  232. package/dist/templates/startkit/tests/preferences.test.ts +43 -0
  233. package/dist/templates/startkit/tests/resources.test.ts +82 -0
  234. package/dist/templates/startkit/tsconfig.json +20 -0
  235. package/dist/templates/startkit/tsconfig.node.json +10 -0
  236. package/dist/templates/startkit/vite.config.ts +32 -0
  237. package/dist/templates/startkit/vitest.config.ts +13 -0
  238. package/dist/update-DyW1na5V.js +1140 -0
  239. package/dist/update-DyW1na5V.js.map +1 -0
  240. package/dist/update.js +3 -0
  241. package/package.json +84 -0
  242. package/skills/askr-accessibility/SKILL.md +68 -0
  243. package/skills/askr-accessibility/agents/openai.yaml +4 -0
  244. package/skills/askr-agent-execution/SKILL.md +85 -0
  245. package/skills/askr-agent-execution/agents/openai.yaml +4 -0
  246. package/skills/askr-agent-workflows/SKILL.md +57 -0
  247. package/skills/askr-agent-workflows/agents/openai.yaml +4 -0
  248. package/skills/askr-api-integration/SKILL.md +79 -0
  249. package/skills/askr-api-integration/agents/openai.yaml +4 -0
  250. package/skills/askr-app-builder/SKILL.md +99 -0
  251. package/skills/askr-app-builder/agents/openai.yaml +4 -0
  252. package/skills/askr-auth-access/SKILL.md +74 -0
  253. package/skills/askr-auth-access/agents/openai.yaml +4 -0
  254. package/skills/askr-cli-vite/SKILL.md +76 -0
  255. package/skills/askr-cli-vite/agents/openai.yaml +4 -0
  256. package/skills/askr-dashboard-charts/SKILL.md +82 -0
  257. package/skills/askr-dashboard-charts/agents/openai.yaml +4 -0
  258. package/skills/askr-design-system/SKILL.md +86 -0
  259. package/skills/askr-design-system/agents/openai.yaml +4 -0
  260. package/skills/askr-env-config/SKILL.md +74 -0
  261. package/skills/askr-env-config/agents/openai.yaml +4 -0
  262. package/skills/askr-error-loading-empty/SKILL.md +89 -0
  263. package/skills/askr-error-loading-empty/agents/openai.yaml +4 -0
  264. package/skills/askr-file-upload-artifacts/SKILL.md +77 -0
  265. package/skills/askr-file-upload-artifacts/agents/openai.yaml +4 -0
  266. package/skills/askr-forms-tables-crud/SKILL.md +98 -0
  267. package/skills/askr-forms-tables-crud/agents/openai.yaml +4 -0
  268. package/skills/askr-mental-model/SKILL.md +109 -0
  269. package/skills/askr-mental-model/agents/openai.yaml +4 -0
  270. package/skills/askr-migration-react/SKILL.md +81 -0
  271. package/skills/askr-migration-react/agents/openai.yaml +4 -0
  272. package/skills/askr-observability-debugging/SKILL.md +83 -0
  273. package/skills/askr-observability-debugging/agents/openai.yaml +4 -0
  274. package/skills/askr-project-structure/SKILL.md +79 -0
  275. package/skills/askr-project-structure/agents/openai.yaml +4 -0
  276. package/skills/askr-query-mutation/SKILL.md +115 -0
  277. package/skills/askr-query-mutation/agents/openai.yaml +4 -0
  278. package/skills/askr-realtime-streaming/SKILL.md +76 -0
  279. package/skills/askr-realtime-streaming/agents/openai.yaml +4 -0
  280. package/skills/askr-resources-data/SKILL.md +100 -0
  281. package/skills/askr-resources-data/agents/openai.yaml +4 -0
  282. package/skills/askr-routing-layouts/SKILL.md +107 -0
  283. package/skills/askr-routing-layouts/agents/openai.yaml +4 -0
  284. package/skills/askr-runtime-reactivity/SKILL.md +92 -0
  285. package/skills/askr-runtime-reactivity/agents/openai.yaml +4 -0
  286. package/skills/askr-ssr-ssg/SKILL.md +76 -0
  287. package/skills/askr-ssr-ssg/agents/openai.yaml +4 -0
  288. package/skills/askr-testing-determinism/SKILL.md +75 -0
  289. package/skills/askr-testing-determinism/agents/openai.yaml +4 -0
  290. package/skills/askr-theming/SKILL.md +86 -0
  291. package/skills/askr-theming/agents/openai.yaml +4 -0
  292. package/skills/askr-ui-composition/SKILL.md +92 -0
  293. package/skills/askr-ui-composition/agents/openai.yaml +4 -0
  294. package/templates/full-stack/AGENTS.md +12 -0
  295. package/templates/full-stack/README.md +18 -0
  296. package/templates/full-stack/gitignore.template +4 -0
  297. package/templates/full-stack/index.html +14 -0
  298. package/templates/full-stack/package.json +37 -0
  299. package/templates/full-stack/server.ts +13 -0
  300. package/templates/full-stack/src/action-authorizations.ts +10 -0
  301. package/templates/full-stack/src/actions/create-message.ts +10 -0
  302. package/templates/full-stack/src/i18n.ts +8 -0
  303. package/templates/full-stack/src/main.tsx +12 -0
  304. package/templates/full-stack/src/pages/home.tsx +25 -0
  305. package/templates/full-stack/src/pages/layout.tsx +33 -0
  306. package/templates/full-stack/src/pages/not-found.tsx +4 -0
  307. package/templates/full-stack/src/routes.tsx +20 -0
  308. package/templates/full-stack/src/schemas.ts +11 -0
  309. package/templates/full-stack/src/server/action-registry.ts +12 -0
  310. package/templates/full-stack/src/server/actions/create-message.ts +14 -0
  311. package/templates/full-stack/src/server/app.ts +66 -0
  312. package/templates/full-stack/src/server/dependencies.ts +55 -0
  313. package/templates/full-stack/src/server/entry-server.ts +8 -0
  314. package/templates/full-stack/src/telemetry.ts +4 -0
  315. package/templates/full-stack/src/vite-server.d.ts +6 -0
  316. package/templates/full-stack/tests/actions/create-message.test.ts +13 -0
  317. package/templates/full-stack/tsconfig.json +16 -0
  318. package/templates/full-stack/vite.config.ts +11 -0
  319. package/templates/spa/AGENTS.md +60 -0
  320. package/templates/spa/README.md +96 -0
  321. package/templates/spa/gitignore.template +16 -0
  322. package/templates/spa/index.html +13 -0
  323. package/templates/spa/package.json +35 -0
  324. package/templates/spa/src/adapters/operations-client.ts +90 -0
  325. package/templates/spa/src/components/shared/metric-card.tsx +27 -0
  326. package/templates/spa/src/components/shared/status-badge.tsx +24 -0
  327. package/templates/spa/src/features/operations/operations.query.ts +9 -0
  328. package/templates/spa/src/main.tsx +10 -0
  329. package/templates/spa/src/pages/_layout.tsx +9 -0
  330. package/templates/spa/src/pages/_routes.tsx +27 -0
  331. package/templates/spa/src/pages/app/_layout.tsx +94 -0
  332. package/templates/spa/src/pages/app/_routes.tsx +10 -0
  333. package/templates/spa/src/pages/app/admin-home.tsx +152 -0
  334. package/templates/spa/src/pages/app/agent-runs.tsx +93 -0
  335. package/templates/spa/src/pages/app/settings.tsx +91 -0
  336. package/templates/spa/src/pages/auth/_layout.tsx +38 -0
  337. package/templates/spa/src/pages/auth/_routes.tsx +6 -0
  338. package/templates/spa/src/pages/auth/login.tsx +63 -0
  339. package/templates/spa/src/pages/not-found.tsx +22 -0
  340. package/templates/spa/src/pages/public/_layout.tsx +47 -0
  341. package/templates/spa/src/pages/public/_routes.tsx +6 -0
  342. package/templates/spa/src/pages/public/home.tsx +143 -0
  343. package/templates/spa/src/shared/format.ts +12 -0
  344. package/templates/spa/src/shared/navigation.ts +15 -0
  345. package/templates/spa/src/styles/components.css +49 -0
  346. package/templates/spa/src/styles/layout.css +192 -0
  347. package/templates/spa/src/styles/reset.css +44 -0
  348. package/templates/spa/src/styles/theme.css +57 -0
  349. package/templates/spa/src/styles/tokens.css +20 -0
  350. package/templates/spa/src/styles.css +7 -0
  351. package/templates/spa/src/styles.d.ts +1 -0
  352. package/templates/spa/tests/app.test.tsx +37 -0
  353. package/templates/spa/tests/components/shared.test.tsx +12 -0
  354. package/templates/spa/tests/resources.test.ts +22 -0
  355. package/templates/spa/tsconfig.json +20 -0
  356. package/templates/spa/tsconfig.node.json +10 -0
  357. package/templates/spa/vite.config.ts +24 -0
  358. package/templates/spa/vitest.config.ts +17 -0
  359. package/templates/ssg/AGENTS.md +55 -0
  360. package/templates/ssg/README.md +39 -0
  361. package/templates/ssg/gitignore.template +17 -0
  362. package/templates/ssg/index.html +13 -0
  363. package/templates/ssg/package.json +35 -0
  364. package/templates/ssg/src/app.tsx +14 -0
  365. package/templates/ssg/src/components/badge.tsx +3 -0
  366. package/templates/ssg/src/components/counter.tsx +30 -0
  367. package/templates/ssg/src/components/site-shell.tsx +111 -0
  368. package/templates/ssg/src/jsx.d.ts +23 -0
  369. package/templates/ssg/src/main.tsx +8 -0
  370. package/templates/ssg/src/pages/about.tsx +82 -0
  371. package/templates/ssg/src/pages/content.tsx +63 -0
  372. package/templates/ssg/src/pages/example.tsx +97 -0
  373. package/templates/ssg/src/pages/home.tsx +51 -0
  374. package/templates/ssg/src/resources/user.ts +15 -0
  375. package/templates/ssg/src/routes.tsx +15 -0
  376. package/templates/ssg/src/styles.css +89 -0
  377. package/templates/ssg/src/vite-env.d.ts +5 -0
  378. package/templates/ssg/ssg.config.ts +34 -0
  379. package/templates/ssg/tests/app.test.tsx +19 -0
  380. package/templates/ssg/tests/components/counter.test.tsx +18 -0
  381. package/templates/ssg/tests/resources.test.ts +11 -0
  382. package/templates/ssg/tests/ssg-config.test.ts +11 -0
  383. package/templates/ssg/tsconfig.json +20 -0
  384. package/templates/ssg/tsconfig.node.json +10 -0
  385. package/templates/ssg/vite.config.ts +24 -0
  386. package/templates/ssg/vitest.config.ts +17 -0
  387. package/templates/ssr/AGENTS.md +28 -0
  388. package/templates/ssr/README.md +38 -0
  389. package/templates/ssr/gitignore.template +16 -0
  390. package/templates/ssr/index.html +13 -0
  391. package/templates/ssr/package.json +34 -0
  392. package/templates/ssr/server.ts +16 -0
  393. package/templates/ssr/src/app.tsx +21 -0
  394. package/templates/ssr/src/components/counter.tsx +26 -0
  395. package/templates/ssr/src/entry-server.tsx +10 -0
  396. package/templates/ssr/src/main.tsx +11 -0
  397. package/templates/ssr/src/pages/about.tsx +75 -0
  398. package/templates/ssr/src/pages/example.tsx +113 -0
  399. package/templates/ssr/src/pages/home.tsx +56 -0
  400. package/templates/ssr/src/resources/user.ts +15 -0
  401. package/templates/ssr/src/routes.tsx +13 -0
  402. package/templates/ssr/src/styles.css +148 -0
  403. package/templates/ssr/src/vite-server.d.ts +7 -0
  404. package/templates/ssr/tests/app.test.tsx +24 -0
  405. package/templates/ssr/tests/components/counter.test.tsx +13 -0
  406. package/templates/ssr/tests/resources.test.ts +11 -0
  407. package/templates/ssr/tsconfig.json +22 -0
  408. package/templates/ssr/tsconfig.node.json +10 -0
  409. package/templates/ssr/tsconfig.server.json +15 -0
  410. package/templates/ssr/vite.config.ts +25 -0
  411. package/templates/ssr/vitest.config.ts +13 -0
  412. package/templates/startkit/AGENTS.md +77 -0
  413. package/templates/startkit/README.md +192 -0
  414. package/templates/startkit/gitignore.template +16 -0
  415. package/templates/startkit/index.html +13 -0
  416. package/templates/startkit/package.json +35 -0
  417. package/templates/startkit/src/components/app-header.tsx +93 -0
  418. package/templates/startkit/src/components/app-sidebar.tsx +95 -0
  419. package/templates/startkit/src/components/data-table.tsx +80 -0
  420. package/templates/startkit/src/components/empty-state.tsx +13 -0
  421. package/templates/startkit/src/components/page-header.tsx +23 -0
  422. package/templates/startkit/src/components/stat-card.tsx +24 -0
  423. package/templates/startkit/src/features/accounts/account-filters.tsx +61 -0
  424. package/templates/startkit/src/features/accounts/account-table.tsx +79 -0
  425. package/templates/startkit/src/lib/format.ts +31 -0
  426. package/templates/startkit/src/lib/mock-data.ts +441 -0
  427. package/templates/startkit/src/lib/routes.ts +116 -0
  428. package/templates/startkit/src/main.tsx +12 -0
  429. package/templates/startkit/src/pages/_layout.tsx +56 -0
  430. package/templates/startkit/src/pages/auth/_layout.tsx +7 -0
  431. package/templates/startkit/src/pages/auth/login.tsx +129 -0
  432. package/templates/startkit/src/pages/home.tsx +83 -0
  433. package/templates/startkit/src/pages/not-found.tsx +24 -0
  434. package/templates/startkit/src/pages/workspace/_layout.tsx +17 -0
  435. package/templates/startkit/src/pages/workspace/accounts/index.tsx +217 -0
  436. package/templates/startkit/src/pages/workspace/dashboard.tsx +118 -0
  437. package/templates/startkit/src/pages/workspace/settings.tsx +218 -0
  438. package/templates/startkit/src/router.tsx +7 -0
  439. package/templates/startkit/src/routes/auth-config.ts +38 -0
  440. package/templates/startkit/src/routes/auth.ts +8 -0
  441. package/templates/startkit/src/routes/index.ts +28 -0
  442. package/templates/startkit/src/routes/public.ts +8 -0
  443. package/templates/startkit/src/routes/workspace/accounts.ts +8 -0
  444. package/templates/startkit/src/routes/workspace/index.ts +14 -0
  445. package/templates/startkit/src/styles/components.css +396 -0
  446. package/templates/startkit/src/styles/layout.css +192 -0
  447. package/templates/startkit/src/styles/reset.css +38 -0
  448. package/templates/startkit/src/styles/theme.css +76 -0
  449. package/templates/startkit/src/styles/tokens.css +67 -0
  450. package/templates/startkit/src/styles.css +7 -0
  451. package/templates/startkit/src/toast.ts +55 -0
  452. package/templates/startkit/src/utils/join-classes.ts +4 -0
  453. package/templates/startkit/src/vite-env.d.ts +5 -0
  454. package/templates/startkit/tests/app.test.tsx +32 -0
  455. package/templates/startkit/tests/preferences.test.ts +43 -0
  456. package/templates/startkit/tests/resources.test.ts +82 -0
  457. package/templates/startkit/tsconfig.json +20 -0
  458. package/templates/startkit/tsconfig.node.json +10 -0
  459. package/templates/startkit/vite.config.ts +32 -0
  460. package/templates/startkit/vitest.config.ts +13 -0
@@ -0,0 +1,92 @@
1
+ ---
2
+ name: askr-ui-composition
3
+ description: Use when composing Askr UI with @askrjs/ui headless primitives, accessibility behavior, asChild polymorphism, root-owned state, private component context, slots, keyboard behavior, overlays, and app-local components.
4
+ ---
5
+
6
+ # Askr UI Composition
7
+
8
+ Use this when the hard part is behavior and composition rather than theming. The goal is to reuse `@askrjs/ui` for focus, keyboard, dismissal, and ARIA behavior instead of rebuilding it locally.
9
+
10
+ ## Inspect First
11
+
12
+ - Existing component imports and slot naming
13
+ - The nearest shared component with similar behavior
14
+ - Existing theme usage to decide whether headless or themed primitives fit better
15
+ - Existing tests for keyboard or focus behavior
16
+
17
+ ## Use This When
18
+
19
+ - You need dialog, popover, menu, select, toggle, checkbox, or other interactive behavior.
20
+ - The app needs headless primitives or already owns its own CSS.
21
+ - You are tempted to rebuild keyboard, focus, or dismissal logic locally.
22
+ - Themed primitives are not enough because behavior composition is the real problem.
23
+
24
+ ## Choose UI Or Theme
25
+
26
+ - Use `@askrjs/ui` directly when the app has its own CSS or needs a headless behavior primitive.
27
+ - Use `@askrjs/themes` when the existing visual system should also style the primitive.
28
+ - Do not create app-local wrappers for solved theme surfaces unless the wrapper adds product semantics.
29
+
30
+ ## Do This In Order
31
+
32
+ 1. Pick the primitive family that already owns the behavior.
33
+ 2. Keep coordination state in the root component that owns the interaction.
34
+ 3. Use `asChild` only when caller markup must be preserved.
35
+ 4. Use `data-slot` on app structure that needs stable styling hooks.
36
+ 5. Validate keyboard, pointer, and ARIA behavior.
37
+
38
+ ## Copy This Shape
39
+
40
+ ```tsx
41
+ import {
42
+ AlertDialog,
43
+ AlertDialogAction,
44
+ AlertDialogCancel,
45
+ AlertDialogContent,
46
+ AlertDialogOverlay,
47
+ AlertDialogPortal,
48
+ AlertDialogTitle,
49
+ AlertDialogTrigger,
50
+ } from "@askrjs/ui/alert-dialog";
51
+
52
+ <AlertDialog>
53
+ <AlertDialogTrigger asChild>
54
+ <button>Archive</button>
55
+ </AlertDialogTrigger>
56
+ <AlertDialogPortal>
57
+ <AlertDialogOverlay />
58
+ <AlertDialogContent>
59
+ <AlertDialogTitle>Archive account?</AlertDialogTitle>
60
+ <AlertDialogCancel>Cancel</AlertDialogCancel>
61
+ <AlertDialogAction>Archive</AlertDialogAction>
62
+ </AlertDialogContent>
63
+ </AlertDialogPortal>
64
+ </AlertDialog>;
65
+ ```
66
+
67
+ ## Never Do These
68
+
69
+ - Reimplementing keyboard, focus, or dismissal behavior already owned by a primitive.
70
+ - Styling or business logic inside behavior primitives.
71
+ - Leaf components that fetch data or own routing.
72
+ - Silent invalid composition when a part requires a root scope.
73
+ - Prop bloat where composition would be clearer.
74
+
75
+ ## Validate
76
+
77
+ - Keyboard and pointer behavior match the primitive contract.
78
+ - ARIA labels, names, and roles are present where required.
79
+ - `asChild` preserves expected markup and events.
80
+ - User-facing interaction has jsdom or browser coverage.
81
+
82
+ ## Done When
83
+
84
+ - The app reused the primitive that already owns the behavior.
85
+ - Product composition stayed in the app, while behavior stayed in the primitive.
86
+ - No local behavior clone was introduced.
87
+
88
+ ## Handoff
89
+
90
+ - Use `askr-theming` when the next step is visual styling and shell coherence.
91
+ - Use `askr-accessibility` when the next step is announcement, focus, or semantic review.
92
+ - Use `askr-testing-determinism` before closing user-facing interaction changes.
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "Askr UI Composition"
3
+ short_description: "Compose accessible headless UI"
4
+ default_prompt: "Use $askr-ui-composition to compose Askr UI primitives correctly."
@@ -0,0 +1,12 @@
1
+ # {{appName}}
2
+
3
+ This project is the progressive full-stack stage of an Askr application.
4
+
5
+ - Prefer functions, closures, and structural interfaces over classes.
6
+ - Keep action descriptors and schemas browser-safe under `src/actions` and `src/schemas.ts`.
7
+ - Keep handlers, repositories, secrets, and composition dependencies under `src/server`.
8
+ - Authorize every page action through the matched `route(..., { actions })` declaration.
9
+ - Keep `index.html` as the only document source. Preserve exactly one `<!--askr-head-->` and one `<!--askr-app-->` marker.
10
+ - Use native forms first; enhanced submission must preserve the same validation and authorization behavior.
11
+ - Never log cookies, authorization values, tokens, form fields, request bodies, or personal data.
12
+
@@ -0,0 +1,18 @@
1
+ # {{appName}}
2
+
3
+ An Askr full-stack application with shared routes, executable schemas, declared actions, API routes, SSR hydration, i18n, telemetry seams, and Node/Vite production entrypoints.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ npm install
9
+ npm run dev
10
+ npm run check
11
+ npm run build
12
+ npm run preview
13
+ ```
14
+
15
+ Use `askr add action <name> --route <path>` to generate a browser-safe descriptor, server handler, composition-root registration, route authorization, and focused test.
16
+
17
+ `index.html` owns the static document. `@askrjs/vite/server` injects only Askr-owned head nodes and composes the streamed app response at `<!--askr-app-->`.
18
+
@@ -0,0 +1,4 @@
1
+ node_modules
2
+ dist
3
+ coverage
4
+ .env
@@ -0,0 +1,14 @@
1
+ <!doctype html>
2
+ <html lang="en" dir="ltr">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <meta name="theme-color" content="#111827" />
7
+ <!--askr-head-->
8
+ </head>
9
+ <body>
10
+ <div id="app"><!--askr-app--></div>
11
+ <script type="module" src="/src/main.tsx"></script>
12
+ </body>
13
+ </html>
14
+
@@ -0,0 +1,37 @@
1
+ {
2
+ "name": "{{appName}}",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "type": "module",
6
+ "scripts": {
7
+ "dev": "vp dev",
8
+ "build": "vp build && vp build --ssr server.ts --outDir dist/server",
9
+ "preview": "node dist/server/server.js",
10
+ "test": "vp test run",
11
+ "typecheck": "tsc --noEmit",
12
+ "lint": "vp lint src server.ts tests vite.config.ts",
13
+ "fmt": "vp fmt .",
14
+ "check": "npm run lint && npm run typecheck && npm test && npm run build"
15
+ },
16
+ "dependencies": {
17
+ "@askrjs/auth": ">=0.0.1 <0.1.0",
18
+ "@askrjs/askr": ">=0.0.53 <0.1.0",
19
+ "@askrjs/i18n": ">=0.0.1 <0.1.0",
20
+ "@askrjs/node": ">=0.0.1 <0.1.0",
21
+ "@askrjs/otel": ">=0.0.1 <0.1.0",
22
+ "@askrjs/schema": ">=0.0.1 <0.1.0",
23
+ "@askrjs/server": ">=0.0.1 <0.1.0",
24
+ "@askrjs/themes": ">=0.0.12 <0.1.0",
25
+ "@askrjs/ui": ">=0.0.13 <0.1.0",
26
+ "@opentelemetry/api": "^1.9.0"
27
+ },
28
+ "devDependencies": {
29
+ "@askrjs/vite": ">=0.0.6 <0.1.0",
30
+ "@types/node": "^26.0.0",
31
+ "jsdom": "^29.1.1",
32
+ "typescript": "^6.0.3",
33
+ "vite-plus": "^0.2.4",
34
+ "vitest": "^4.1.10"
35
+ },
36
+ "engines": { "node": "^20.19.0 || >=22.12.0" }
37
+ }
@@ -0,0 +1,13 @@
1
+ import { listen } from '@askrjs/node';
2
+ import app from 'virtual:askr-server';
3
+
4
+ const port = Number(process.env.PORT ?? 3000);
5
+ const server = await listen(app, {
6
+ host: process.env.HOST ?? '127.0.0.1',
7
+ port,
8
+ });
9
+
10
+ const shutdown = () => server.close();
11
+ process.once('SIGINT', shutdown);
12
+ process.once('SIGTERM', shutdown);
13
+
@@ -0,0 +1,10 @@
1
+ import type { ActionDescriptor } from '@askrjs/askr/actions';
2
+ import { createMessageAction } from './actions/create-message';
3
+
4
+ const actionsByRoute: Readonly<Record<string, readonly ActionDescriptor[]>> = Object.freeze({
5
+ "/": [createMessageAction],
6
+ });
7
+
8
+ export function actionsFor(path: string): readonly ActionDescriptor[] {
9
+ return actionsByRoute[path] ?? [];
10
+ }
@@ -0,0 +1,10 @@
1
+ import { defineAction } from '@askrjs/askr/actions';
2
+ import { MessageInput } from '../schemas';
3
+
4
+ export const createMessageActionRoute = '/';
5
+
6
+ export const createMessageAction = defineAction({
7
+ id: 'create-message',
8
+ input: MessageInput,
9
+ invalidates: ['messages'],
10
+ });
@@ -0,0 +1,8 @@
1
+ import { createI18n } from '@askrjs/i18n';
2
+
3
+ export const messages = createI18n('en', {
4
+ en: {
5
+ title: () => '{{appName}}',
6
+ intro: () => 'A progressive full-stack Askr application.',
7
+ },
8
+ });
@@ -0,0 +1,12 @@
1
+ import { createSPA, hydrateSPA } from '@askrjs/askr/boot';
2
+ import { pageRegistry } from './routes';
3
+
4
+ const root = document.getElementById('app');
5
+ if (!root) throw new Error('Missing #app root element.');
6
+
7
+ if (root.hasChildNodes()) {
8
+ await hydrateSPA({ root, registry: pageRegistry });
9
+ } else {
10
+ await createSPA({ root, registry: pageRegistry });
11
+ }
12
+
@@ -0,0 +1,25 @@
1
+ import { ActionForm } from '@askrjs/askr/actions';
2
+ import { createMessageAction } from '../actions/create-message';
3
+ import { messages } from '../i18n';
4
+
5
+ export function HomePage() {
6
+ return (
7
+ <main>
8
+ <h1>{messages.text('title')}</h1>
9
+ <p>{messages.text('intro')}</p>
10
+ <form method="post" action="/api/session">
11
+ <button type="submit">Start demo session</button>
12
+ </form>
13
+ {ActionForm({
14
+ action: createMessageAction,
15
+ children: (
16
+ <>
17
+ <label htmlFor="message">Message</label>
18
+ <input id="message" name="value" required />
19
+ <button type="submit">Create message</button>
20
+ </>
21
+ ),
22
+ })}
23
+ </main>
24
+ );
25
+ }
@@ -0,0 +1,33 @@
1
+ import { Link } from '@askrjs/askr/router';
2
+ import { Block, Container, Header, Navbar, NavBrand, NavGroup, NavLink } from '@askrjs/themes/components';
3
+ import { ThemeScope, ThemeToggle } from '@askrjs/themes/theme';
4
+ import { messages } from '../i18n';
5
+
6
+ function ScopedLayout({ children }: { children?: unknown }) {
7
+ return (
8
+ <ThemeScope defaultTheme="light" storageKey="{{appName}}-theme">
9
+ <Block minHeight="screen">
10
+ <Header sticky>
11
+ <Container paddingY="sm">
12
+ <Navbar aria-label="Primary navigation" width="full">
13
+ <NavBrand><Link href="/">{messages.text('title')}</Link></NavBrand>
14
+ <NavGroup align="end">
15
+ <NavLink href="/">Home</NavLink>
16
+ <ThemeToggle aria-label="Toggle theme" />
17
+ </NavGroup>
18
+ </Navbar>
19
+ </Container>
20
+ </Header>
21
+ <Container paddingY="2xl">{children}</Container>
22
+ </Block>
23
+ </ThemeScope>
24
+ );
25
+ }
26
+
27
+ export function AppLayout({ children }: { children?: unknown }) {
28
+ return (
29
+ <messages.Scope locale="en" dir="ltr">
30
+ <ScopedLayout>{children}</ScopedLayout>
31
+ </messages.Scope>
32
+ );
33
+ }
@@ -0,0 +1,4 @@
1
+ export function NotFoundPage() {
2
+ return <main><h1>Not found</h1></main>;
3
+ }
4
+
@@ -0,0 +1,20 @@
1
+ import { createRouteRegistry, group, route } from '@askrjs/askr/router';
2
+ import { actionsFor } from './action-authorizations';
3
+ import { AppLayout } from './pages/layout';
4
+ import { HomePage } from './pages/home';
5
+ import { NotFoundPage } from './pages/not-found';
6
+
7
+ export const pageRegistry = createRouteRegistry(() => {
8
+ group({ layout: AppLayout }, () => {
9
+ route('/', HomePage, {
10
+ actions: actionsFor('/'),
11
+ meta: {
12
+ title: '{{appName}}',
13
+ description: 'A progressive full-stack Askr application.',
14
+ html: { lang: 'en', dir: 'ltr' },
15
+ },
16
+ });
17
+ route('/*', NotFoundPage);
18
+ });
19
+ });
20
+
@@ -0,0 +1,11 @@
1
+ import { schema } from '@askrjs/schema';
2
+
3
+ export const MessageInput = schema.object({
4
+ value: schema.string({ minLength: 1, maxLength: 200 }),
5
+ });
6
+
7
+ export const Message = schema.object({
8
+ id: schema.string(),
9
+ value: schema.string(),
10
+ });
11
+
@@ -0,0 +1,12 @@
1
+ import { createActionRegistry } from '@askrjs/server/askr';
2
+ import { createMessageAction } from '../actions/create-message';
3
+ import { createMessage } from './actions/create-message';
4
+ import type { AppDependencies } from './dependencies';
5
+
6
+ export function createActions(deps: AppDependencies) {
7
+ const registry = createActionRegistry(deps, {
8
+ csrf: { secret: process.env.CSRF_SECRET ?? 'development-only-secret' },
9
+ });
10
+ registry.register(createMessageAction, createMessage);
11
+ return registry;
12
+ }
@@ -0,0 +1,14 @@
1
+ import type { InferSchema } from '@askrjs/schema';
2
+ import { createMessageAction } from '../../actions/create-message';
3
+ import type { AppDependencies } from '../dependencies';
4
+
5
+ type Input = InferSchema<typeof createMessageAction.input>;
6
+
7
+ export async function createMessage(
8
+ _context: unknown,
9
+ input: Input,
10
+ deps: Pick<AppDependencies, 'actions'>,
11
+ ) {
12
+ await deps.actions.record({ action: createMessageAction.id, value: input.value });
13
+ return { result: { accepted: true } };
14
+ }
@@ -0,0 +1,66 @@
1
+ import { createAuth } from '@askrjs/auth';
2
+ import { createServerApp } from '@askrjs/server';
3
+ import { createAskrPageHandler } from '@askrjs/server/askr';
4
+ import { csrf, rateLimit, requestId, securityHeaders } from '@askrjs/server/middleware';
5
+ import { createApi } from '@askrjs/server/openapi';
6
+ import { pageRegistry } from '../routes';
7
+ import { Message, MessageInput } from '../schemas';
8
+ import { telemetry } from '../telemetry';
9
+ import { createActions } from './action-registry';
10
+ import type { AppDependencies } from './dependencies';
11
+
12
+ export function createApp(deps: AppDependencies) {
13
+ const api = createApi<AppDependencies>({
14
+ info: { title: '{{appName}} API', version: '1.0.0' },
15
+ });
16
+ api.post('/api/messages', {
17
+ input: {
18
+ body: {
19
+ schema: MessageInput,
20
+ mediaTypes: ['application/json'],
21
+ },
22
+ },
23
+ documentation: { body: { required: true } },
24
+ async handler(ctx, input, dependencies) {
25
+ const message = { id: crypto.randomUUID(), value: input.body.value };
26
+ await dependencies.actions.record({ action: 'api.create-message', value: message.value });
27
+ return ctx.created(message);
28
+ },
29
+ })
30
+ .operationId('createMessage')
31
+ .summary('Create a message')
32
+ .tags('Messages')
33
+ .use(
34
+ csrf({ secret: process.env.CSRF_SECRET ?? 'development-only-secret' }),
35
+ rateLimit({ store: deps.rateLimits, limit: 30, windowMs: 60_000 }),
36
+ )
37
+ .created(Message)
38
+ .badRequest()
39
+ .unprocessableEntity()
40
+ .tooManyRequests();
41
+
42
+ const router = api.createRouter(deps);
43
+ router.post('/api/session', (ctx) => {
44
+ const response = ctx.redirect('/', 303);
45
+ return ctx.setCookie(response, 'askr-session', 'demo-session', {
46
+ httpOnly: true,
47
+ sameSite: 'lax',
48
+ secure: ctx.url.protocol === 'https:',
49
+ path: '/',
50
+ });
51
+ });
52
+ return createServerApp({
53
+ router,
54
+ auth: createAuth({
55
+ sessions: deps.sessions,
56
+ principals: deps.principals,
57
+ sessionCookie: 'askr-session',
58
+ }),
59
+ middleware: [requestId(), securityHeaders()],
60
+ telemetry,
61
+ fallback: createAskrPageHandler({
62
+ registry: pageRegistry,
63
+ actions: createActions(deps),
64
+ }),
65
+ });
66
+ }
@@ -0,0 +1,55 @@
1
+ export interface AppDependencies {
2
+ readonly sessions: {
3
+ get(id: string): Promise<{ id: string; subject: string } | null>;
4
+ };
5
+ readonly principals: {
6
+ get(subject: string): Promise<{
7
+ id: string;
8
+ subject: string;
9
+ permissions: readonly string[];
10
+ } | null>;
11
+ };
12
+ readonly actions: {
13
+ record(entry: { action: string; value: string }): Promise<void>;
14
+ };
15
+ readonly rateLimits: {
16
+ consume(key: string, limit: number, windowMs: number): Promise<{
17
+ allowed: boolean;
18
+ remaining: number;
19
+ reset: number;
20
+ }>;
21
+ };
22
+ }
23
+
24
+ export function createDependencies(): AppDependencies {
25
+ const counters = new Map<string, { count: number; reset: number }>();
26
+ return {
27
+ sessions: {
28
+ get: async (id) => id === 'demo-session'
29
+ ? { id, subject: 'demo-user' }
30
+ : null,
31
+ },
32
+ principals: {
33
+ get: async (subject) => subject === 'demo-user'
34
+ ? { id: subject, subject, permissions: ['messages:create'] }
35
+ : null,
36
+ },
37
+ actions: { record: async () => undefined },
38
+ rateLimits: {
39
+ async consume(key, limit, windowMs) {
40
+ const now = Date.now();
41
+ const current = counters.get(key);
42
+ const window = !current || current.reset <= now
43
+ ? { count: 0, reset: now + windowMs }
44
+ : current;
45
+ window.count += 1;
46
+ counters.set(key, window);
47
+ return {
48
+ allowed: window.count <= limit,
49
+ remaining: Math.max(0, limit - window.count),
50
+ reset: window.reset,
51
+ };
52
+ },
53
+ },
54
+ };
55
+ }
@@ -0,0 +1,8 @@
1
+ import { createApp } from './app';
2
+ import { createDependencies } from './dependencies';
3
+
4
+ const app = createApp(createDependencies());
5
+
6
+ export { app };
7
+ export { telemetry } from '../telemetry';
8
+ export default app;
@@ -0,0 +1,4 @@
1
+ import { createTelemetry } from '@askrjs/otel';
2
+
3
+ export const telemetry = createTelemetry();
4
+
@@ -0,0 +1,6 @@
1
+ declare module 'virtual:askr-server' {
2
+ import type { ServerApp } from '@askrjs/server';
3
+ const app: ServerApp;
4
+ export default app;
5
+ }
6
+
@@ -0,0 +1,13 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createMessageAction } from '../../src/actions/create-message';
3
+
4
+ describe('create message action', () => {
5
+ it('should reject an empty message given declared input validation', () => {
6
+ expect(createMessageAction.input.safeParse({ value: '' }).success).toBe(false);
7
+ });
8
+
9
+ it('should accept a message given valid input', () => {
10
+ expect(createMessageAction.input.safeParse({ value: 'hello' }).success).toBe(true);
11
+ });
12
+ });
13
+
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "strict": true,
8
+ "skipLibCheck": true,
9
+ "noEmit": true,
10
+ "jsx": "preserve",
11
+ "jsxImportSource": "@askrjs/askr",
12
+ "types": ["vite/client", "node"]
13
+ },
14
+ "include": ["src", "tests", "server.ts", "vite.config.ts"]
15
+ }
16
+
@@ -0,0 +1,11 @@
1
+ import { defineConfig } from 'vite-plus';
2
+ import { askr } from '@askrjs/vite';
3
+ import { askrServer } from '@askrjs/vite/server';
4
+
5
+ export default defineConfig({
6
+ plugins: [askr(), askrServer({ entry: './src/server/entry-server.ts' })],
7
+ lint: { ignorePatterns: ['dist/**', 'node_modules/**', 'coverage/**'] },
8
+ server: { port: 5173, open: true },
9
+ build: { manifest: true, sourcemap: true },
10
+ });
11
+
@@ -0,0 +1,60 @@
1
+ # {{appName}}
2
+
3
+ Client-side SPA built with Askr, askr-ui, askr-themes, and askr-charts.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ npm run dev # Vite dev server with HMR (port 5173)
9
+ npm run build # Production build to dist/
10
+ npm run preview # Serve production build locally
11
+ npm test # Vitest (jsdom)
12
+ npm run typecheck # tsc --noEmit
13
+ npm run lint # ESLint
14
+ npm run fmt # Prettier
15
+ ```
16
+
17
+ ## Architecture
18
+
19
+ - **Routing:** `src/main.tsx` imports `src/pages/_routes.tsx`, then boots `createSPA()` with the route manifest. Route branches live under `src/pages/public`, `src/pages/auth`, and `src/pages/app`.
20
+ - **Layouts:** `_layout.tsx` files own shells. The root layout owns `ThemeScope`; public layouts own landing chrome, auth layouts own sign-in chrome, and app layouts own authenticated sidebar chrome.
21
+ - **UI:** Prefer the `@askrjs/themes/components` catalog before writing local components. Use app-local components only for product concepts such as `MetricCard` and `StatusBadge`; keep charts in `@askrjs/charts`.
22
+ - **State:** `const [value, setValue] = state(initial)`. Read with `value()`, update with `setValue(...)`. Use `derive()` for computed values and `resource()` for async data.
23
+ - **Data:** Route/container components own resources; `src/features` owns product workflows; `src/adapters` owns API clients, transports, abort handling, and generated clients.
24
+ - **Consistency:** Event-sourced screens should expose pending writes, projection lag, stale data, retries, and manual refresh instead of hiding everything behind one loading state.
25
+ - **Styling:** Keep `src/styles.css` thin. Customize theme values in `src/styles/tokens.css`, global defaults in `src/styles/theme.css`, shell structure in `src/styles/layout.css`, and component classes in `src/styles/components.css`.
26
+ - **Charts:** Import chart components from `@askrjs/charts/components`; chart CSS is loaded from `@askrjs/charts/default`.
27
+ - **Vite plugin:** `askr()` from `@askrjs/vite` handles JSX transform. Do not add manual esbuild JSX config.
28
+
29
+ ## File Structure
30
+
31
+ ```
32
+ src/
33
+ main.tsx
34
+ pages/
35
+ _routes.tsx
36
+ _layout.tsx
37
+ public/
38
+ auth/
39
+ app/
40
+ components/shared/
41
+ features/
42
+ adapters/
43
+ shared/
44
+ styles/
45
+ reset.css
46
+ tokens.css
47
+ theme.css
48
+ layout.css
49
+ components.css
50
+ tests/
51
+ ```
52
+
53
+ ## Conventions
54
+
55
+ - Keep routes thin and route-first.
56
+ - Keep shell chrome in layouts, not leaf pages.
57
+ - Keep business logic out of `src/pages`.
58
+ - Use `Link` and `navigate` from `@askrjs/askr/router`.
59
+ - Use headless `@askrjs/ui/*` for behavior primitives and `@askrjs/themes/*` for composed visual surfaces.
60
+ - Avoid hardcoded color systems, custom component catalogs, and React habits like effect-driven data loading.