@askrjs/cli 0.0.2 → 0.0.4

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 (310) hide show
  1. package/README.md +46 -7
  2. package/dist/add.d.ts +16 -0
  3. package/dist/add.js +558 -1
  4. package/dist/cli.d.ts +5 -0
  5. package/dist/cli.js +43 -16
  6. package/dist/create.d.ts +5 -0
  7. package/dist/create.js +104 -26
  8. package/dist/directory-swap-DWoHtx7C.js +35 -0
  9. package/dist/discovery-Difb7Y4G.js +323 -0
  10. package/dist/generate.d.ts +5 -0
  11. package/dist/generate.js +461 -0
  12. package/dist/is-direct-execution-Cdlr-ZUl.js +0 -2
  13. package/dist/openapi.d.ts +25 -0
  14. package/dist/openapi.js +49 -16
  15. package/dist/planner-VAj7qlxr.js +285 -0
  16. package/dist/range-YUs9eimn.js +125 -0
  17. package/dist/registry-CyrRHRG5.js +209 -0
  18. package/dist/skills/askr-dashboard-charts/SKILL.md +61 -44
  19. package/dist/skills/askr-dashboard-charts/agents/openai.yaml +2 -2
  20. package/dist/skills/askr-ssr-ssg/SKILL.md +3 -1
  21. package/dist/{skills-Bh0mEhIx.js → skills-B7CbWur9.js} +89 -26
  22. package/dist/skills.d.ts +18 -0
  23. package/dist/skills.js +1 -1
  24. package/dist/specification-DXnDOC-0.js +49 -0
  25. package/dist/ssg-config.d.ts +41 -0
  26. package/dist/ssg-config.js +1 -0
  27. package/dist/ssg.d.ts +61 -0
  28. package/dist/ssg.js +360 -24
  29. package/dist/templates/full-stack/AGENTS.md +0 -1
  30. package/dist/templates/full-stack/README.md +0 -1
  31. package/dist/templates/full-stack/index.html +0 -1
  32. package/dist/templates/full-stack/package.json +5 -3
  33. package/dist/templates/full-stack/server.ts +5 -9
  34. package/dist/templates/full-stack/src/action-authorizations.ts +2 -2
  35. package/dist/templates/full-stack/src/actions/create-message.ts +5 -5
  36. package/dist/templates/full-stack/src/i18n.ts +4 -4
  37. package/dist/templates/full-stack/src/main.tsx +4 -5
  38. package/dist/templates/full-stack/src/pages/home.tsx +5 -5
  39. package/dist/templates/full-stack/src/pages/layout.tsx +15 -5
  40. package/dist/templates/full-stack/src/pages/not-found.tsx +5 -2
  41. package/dist/templates/full-stack/src/routes.tsx +11 -12
  42. package/dist/templates/full-stack/src/schemas.ts +1 -2
  43. package/dist/templates/full-stack/src/server/action-registry.ts +5 -10
  44. package/dist/templates/full-stack/src/server/actions/create-message.ts +4 -4
  45. package/dist/templates/full-stack/src/server/app.ts +67 -57
  46. package/dist/templates/full-stack/src/server/dependencies.ts +10 -10
  47. package/dist/templates/full-stack/src/server/entry-server.ts +3 -3
  48. package/dist/templates/full-stack/src/telemetry.ts +1 -2
  49. package/dist/templates/full-stack/tests/actions/create-message.test.ts +7 -8
  50. package/dist/templates/full-stack/tsconfig.json +1 -2
  51. package/dist/templates/full-stack/vite.config.ts +5 -6
  52. package/dist/templates/spa/AGENTS.md +1 -1
  53. package/dist/templates/spa/package.json +3 -4
  54. package/dist/templates/spa/src/adapters/operations-client.ts +7 -2
  55. package/dist/templates/spa/src/pages/app/_routes.tsx +2 -0
  56. package/dist/templates/spa/src/pages/app/admin-home.tsx +21 -3
  57. package/dist/templates/spa/src/pages/public/_routes.tsx +2 -0
  58. package/dist/templates/spa/src/styles.css +1 -1
  59. package/dist/templates/spa/tsconfig.json +2 -1
  60. package/dist/templates/spa/vitest.config.ts +0 -4
  61. package/dist/templates/ssg/README.md +1 -1
  62. package/dist/templates/ssg/package.json +1 -1
  63. package/dist/templates/ssg/ssg.config.ts +7 -0
  64. package/dist/templates/ssg/tests/ssg-config.test.ts +5 -3
  65. package/dist/templates/ssg/tsconfig.json +2 -1
  66. package/dist/templates/ssg/vitest.config.ts +0 -4
  67. package/dist/templates/ssr/package.json +2 -2
  68. package/dist/templates/ssr/server.ts +4 -10
  69. package/dist/templates/ssr/src/entry-server.tsx +6 -4
  70. package/dist/templates/startkit/package.json +2 -2
  71. package/dist/templates/startkit/src/lib/mock-data.ts +17 -39
  72. package/dist/templates/startkit/tsconfig.json +2 -1
  73. package/dist/update.d.ts +41 -0
  74. package/dist/update.js +282 -2
  75. package/dist/writer-D8qe_7ud.js +226 -0
  76. package/package.json +23 -22
  77. package/dist/add-DqhqRzBQ.js +0 -555
  78. package/dist/add-DqhqRzBQ.js.map +0 -1
  79. package/dist/cli.js.map +0 -1
  80. package/dist/create.js.map +0 -1
  81. package/dist/is-direct-execution-Cdlr-ZUl.js.map +0 -1
  82. package/dist/openapi.js.map +0 -1
  83. package/dist/skills-Bh0mEhIx.js.map +0 -1
  84. package/dist/ssg.js.map +0 -1
  85. package/dist/templates/full-stack/src/vite-server.d.ts +0 -6
  86. package/dist/templates/spa/src/styles.d.ts +0 -1
  87. package/dist/templates/ssg/src/vite-env.d.ts +0 -5
  88. package/dist/templates/ssr/src/vite-server.d.ts +0 -7
  89. package/dist/templates/startkit/src/vite-env.d.ts +0 -5
  90. package/dist/update-DyW1na5V.js +0 -1140
  91. package/dist/update-DyW1na5V.js.map +0 -1
  92. package/skills/askr-accessibility/SKILL.md +0 -68
  93. package/skills/askr-accessibility/agents/openai.yaml +0 -4
  94. package/skills/askr-agent-execution/SKILL.md +0 -85
  95. package/skills/askr-agent-execution/agents/openai.yaml +0 -4
  96. package/skills/askr-agent-workflows/SKILL.md +0 -57
  97. package/skills/askr-agent-workflows/agents/openai.yaml +0 -4
  98. package/skills/askr-api-integration/SKILL.md +0 -79
  99. package/skills/askr-api-integration/agents/openai.yaml +0 -4
  100. package/skills/askr-app-builder/SKILL.md +0 -99
  101. package/skills/askr-app-builder/agents/openai.yaml +0 -4
  102. package/skills/askr-auth-access/SKILL.md +0 -74
  103. package/skills/askr-auth-access/agents/openai.yaml +0 -4
  104. package/skills/askr-cli-vite/SKILL.md +0 -76
  105. package/skills/askr-cli-vite/agents/openai.yaml +0 -4
  106. package/skills/askr-dashboard-charts/SKILL.md +0 -82
  107. package/skills/askr-dashboard-charts/agents/openai.yaml +0 -4
  108. package/skills/askr-design-system/SKILL.md +0 -86
  109. package/skills/askr-design-system/agents/openai.yaml +0 -4
  110. package/skills/askr-env-config/SKILL.md +0 -74
  111. package/skills/askr-env-config/agents/openai.yaml +0 -4
  112. package/skills/askr-error-loading-empty/SKILL.md +0 -89
  113. package/skills/askr-error-loading-empty/agents/openai.yaml +0 -4
  114. package/skills/askr-file-upload-artifacts/SKILL.md +0 -77
  115. package/skills/askr-file-upload-artifacts/agents/openai.yaml +0 -4
  116. package/skills/askr-forms-tables-crud/SKILL.md +0 -98
  117. package/skills/askr-forms-tables-crud/agents/openai.yaml +0 -4
  118. package/skills/askr-mental-model/SKILL.md +0 -109
  119. package/skills/askr-mental-model/agents/openai.yaml +0 -4
  120. package/skills/askr-migration-react/SKILL.md +0 -81
  121. package/skills/askr-migration-react/agents/openai.yaml +0 -4
  122. package/skills/askr-observability-debugging/SKILL.md +0 -83
  123. package/skills/askr-observability-debugging/agents/openai.yaml +0 -4
  124. package/skills/askr-project-structure/SKILL.md +0 -79
  125. package/skills/askr-project-structure/agents/openai.yaml +0 -4
  126. package/skills/askr-query-mutation/SKILL.md +0 -115
  127. package/skills/askr-query-mutation/agents/openai.yaml +0 -4
  128. package/skills/askr-realtime-streaming/SKILL.md +0 -76
  129. package/skills/askr-realtime-streaming/agents/openai.yaml +0 -4
  130. package/skills/askr-resources-data/SKILL.md +0 -100
  131. package/skills/askr-resources-data/agents/openai.yaml +0 -4
  132. package/skills/askr-routing-layouts/SKILL.md +0 -107
  133. package/skills/askr-routing-layouts/agents/openai.yaml +0 -4
  134. package/skills/askr-runtime-reactivity/SKILL.md +0 -92
  135. package/skills/askr-runtime-reactivity/agents/openai.yaml +0 -4
  136. package/skills/askr-ssr-ssg/SKILL.md +0 -76
  137. package/skills/askr-ssr-ssg/agents/openai.yaml +0 -4
  138. package/skills/askr-testing-determinism/SKILL.md +0 -75
  139. package/skills/askr-testing-determinism/agents/openai.yaml +0 -4
  140. package/skills/askr-theming/SKILL.md +0 -86
  141. package/skills/askr-theming/agents/openai.yaml +0 -4
  142. package/skills/askr-ui-composition/SKILL.md +0 -92
  143. package/skills/askr-ui-composition/agents/openai.yaml +0 -4
  144. package/templates/full-stack/AGENTS.md +0 -12
  145. package/templates/full-stack/README.md +0 -18
  146. package/templates/full-stack/gitignore.template +0 -4
  147. package/templates/full-stack/index.html +0 -14
  148. package/templates/full-stack/package.json +0 -37
  149. package/templates/full-stack/server.ts +0 -13
  150. package/templates/full-stack/src/action-authorizations.ts +0 -10
  151. package/templates/full-stack/src/actions/create-message.ts +0 -10
  152. package/templates/full-stack/src/i18n.ts +0 -8
  153. package/templates/full-stack/src/main.tsx +0 -12
  154. package/templates/full-stack/src/pages/home.tsx +0 -25
  155. package/templates/full-stack/src/pages/layout.tsx +0 -33
  156. package/templates/full-stack/src/pages/not-found.tsx +0 -4
  157. package/templates/full-stack/src/routes.tsx +0 -20
  158. package/templates/full-stack/src/schemas.ts +0 -11
  159. package/templates/full-stack/src/server/action-registry.ts +0 -12
  160. package/templates/full-stack/src/server/actions/create-message.ts +0 -14
  161. package/templates/full-stack/src/server/app.ts +0 -66
  162. package/templates/full-stack/src/server/dependencies.ts +0 -55
  163. package/templates/full-stack/src/server/entry-server.ts +0 -8
  164. package/templates/full-stack/src/telemetry.ts +0 -4
  165. package/templates/full-stack/src/vite-server.d.ts +0 -6
  166. package/templates/full-stack/tests/actions/create-message.test.ts +0 -13
  167. package/templates/full-stack/tsconfig.json +0 -16
  168. package/templates/full-stack/vite.config.ts +0 -11
  169. package/templates/spa/AGENTS.md +0 -60
  170. package/templates/spa/README.md +0 -96
  171. package/templates/spa/gitignore.template +0 -16
  172. package/templates/spa/index.html +0 -13
  173. package/templates/spa/package.json +0 -35
  174. package/templates/spa/src/adapters/operations-client.ts +0 -90
  175. package/templates/spa/src/components/shared/metric-card.tsx +0 -27
  176. package/templates/spa/src/components/shared/status-badge.tsx +0 -24
  177. package/templates/spa/src/features/operations/operations.query.ts +0 -9
  178. package/templates/spa/src/main.tsx +0 -10
  179. package/templates/spa/src/pages/_layout.tsx +0 -9
  180. package/templates/spa/src/pages/_routes.tsx +0 -27
  181. package/templates/spa/src/pages/app/_layout.tsx +0 -94
  182. package/templates/spa/src/pages/app/_routes.tsx +0 -10
  183. package/templates/spa/src/pages/app/admin-home.tsx +0 -152
  184. package/templates/spa/src/pages/app/agent-runs.tsx +0 -93
  185. package/templates/spa/src/pages/app/settings.tsx +0 -91
  186. package/templates/spa/src/pages/auth/_layout.tsx +0 -38
  187. package/templates/spa/src/pages/auth/_routes.tsx +0 -6
  188. package/templates/spa/src/pages/auth/login.tsx +0 -63
  189. package/templates/spa/src/pages/not-found.tsx +0 -22
  190. package/templates/spa/src/pages/public/_layout.tsx +0 -47
  191. package/templates/spa/src/pages/public/_routes.tsx +0 -6
  192. package/templates/spa/src/pages/public/home.tsx +0 -143
  193. package/templates/spa/src/shared/format.ts +0 -12
  194. package/templates/spa/src/shared/navigation.ts +0 -15
  195. package/templates/spa/src/styles/components.css +0 -49
  196. package/templates/spa/src/styles/layout.css +0 -192
  197. package/templates/spa/src/styles/reset.css +0 -44
  198. package/templates/spa/src/styles/theme.css +0 -57
  199. package/templates/spa/src/styles/tokens.css +0 -20
  200. package/templates/spa/src/styles.css +0 -7
  201. package/templates/spa/src/styles.d.ts +0 -1
  202. package/templates/spa/tests/app.test.tsx +0 -37
  203. package/templates/spa/tests/components/shared.test.tsx +0 -12
  204. package/templates/spa/tests/resources.test.ts +0 -22
  205. package/templates/spa/tsconfig.json +0 -20
  206. package/templates/spa/tsconfig.node.json +0 -10
  207. package/templates/spa/vite.config.ts +0 -24
  208. package/templates/spa/vitest.config.ts +0 -17
  209. package/templates/ssg/AGENTS.md +0 -55
  210. package/templates/ssg/README.md +0 -39
  211. package/templates/ssg/gitignore.template +0 -17
  212. package/templates/ssg/index.html +0 -13
  213. package/templates/ssg/package.json +0 -35
  214. package/templates/ssg/src/app.tsx +0 -14
  215. package/templates/ssg/src/components/badge.tsx +0 -3
  216. package/templates/ssg/src/components/counter.tsx +0 -30
  217. package/templates/ssg/src/components/site-shell.tsx +0 -111
  218. package/templates/ssg/src/jsx.d.ts +0 -23
  219. package/templates/ssg/src/main.tsx +0 -8
  220. package/templates/ssg/src/pages/about.tsx +0 -82
  221. package/templates/ssg/src/pages/content.tsx +0 -63
  222. package/templates/ssg/src/pages/example.tsx +0 -97
  223. package/templates/ssg/src/pages/home.tsx +0 -51
  224. package/templates/ssg/src/resources/user.ts +0 -15
  225. package/templates/ssg/src/routes.tsx +0 -15
  226. package/templates/ssg/src/styles.css +0 -89
  227. package/templates/ssg/src/vite-env.d.ts +0 -5
  228. package/templates/ssg/ssg.config.ts +0 -34
  229. package/templates/ssg/tests/app.test.tsx +0 -19
  230. package/templates/ssg/tests/components/counter.test.tsx +0 -18
  231. package/templates/ssg/tests/resources.test.ts +0 -11
  232. package/templates/ssg/tests/ssg-config.test.ts +0 -11
  233. package/templates/ssg/tsconfig.json +0 -20
  234. package/templates/ssg/tsconfig.node.json +0 -10
  235. package/templates/ssg/vite.config.ts +0 -24
  236. package/templates/ssg/vitest.config.ts +0 -17
  237. package/templates/ssr/AGENTS.md +0 -28
  238. package/templates/ssr/README.md +0 -38
  239. package/templates/ssr/gitignore.template +0 -16
  240. package/templates/ssr/index.html +0 -13
  241. package/templates/ssr/package.json +0 -34
  242. package/templates/ssr/server.ts +0 -16
  243. package/templates/ssr/src/app.tsx +0 -21
  244. package/templates/ssr/src/components/counter.tsx +0 -26
  245. package/templates/ssr/src/entry-server.tsx +0 -10
  246. package/templates/ssr/src/main.tsx +0 -11
  247. package/templates/ssr/src/pages/about.tsx +0 -75
  248. package/templates/ssr/src/pages/example.tsx +0 -113
  249. package/templates/ssr/src/pages/home.tsx +0 -56
  250. package/templates/ssr/src/resources/user.ts +0 -15
  251. package/templates/ssr/src/routes.tsx +0 -13
  252. package/templates/ssr/src/styles.css +0 -148
  253. package/templates/ssr/src/vite-server.d.ts +0 -7
  254. package/templates/ssr/tests/app.test.tsx +0 -24
  255. package/templates/ssr/tests/components/counter.test.tsx +0 -13
  256. package/templates/ssr/tests/resources.test.ts +0 -11
  257. package/templates/ssr/tsconfig.json +0 -22
  258. package/templates/ssr/tsconfig.node.json +0 -10
  259. package/templates/ssr/tsconfig.server.json +0 -15
  260. package/templates/ssr/vite.config.ts +0 -25
  261. package/templates/ssr/vitest.config.ts +0 -13
  262. package/templates/startkit/AGENTS.md +0 -77
  263. package/templates/startkit/README.md +0 -192
  264. package/templates/startkit/gitignore.template +0 -16
  265. package/templates/startkit/index.html +0 -13
  266. package/templates/startkit/package.json +0 -35
  267. package/templates/startkit/src/components/app-header.tsx +0 -93
  268. package/templates/startkit/src/components/app-sidebar.tsx +0 -95
  269. package/templates/startkit/src/components/data-table.tsx +0 -80
  270. package/templates/startkit/src/components/empty-state.tsx +0 -13
  271. package/templates/startkit/src/components/page-header.tsx +0 -23
  272. package/templates/startkit/src/components/stat-card.tsx +0 -24
  273. package/templates/startkit/src/features/accounts/account-filters.tsx +0 -61
  274. package/templates/startkit/src/features/accounts/account-table.tsx +0 -79
  275. package/templates/startkit/src/lib/format.ts +0 -31
  276. package/templates/startkit/src/lib/mock-data.ts +0 -441
  277. package/templates/startkit/src/lib/routes.ts +0 -116
  278. package/templates/startkit/src/main.tsx +0 -12
  279. package/templates/startkit/src/pages/_layout.tsx +0 -56
  280. package/templates/startkit/src/pages/auth/_layout.tsx +0 -7
  281. package/templates/startkit/src/pages/auth/login.tsx +0 -129
  282. package/templates/startkit/src/pages/home.tsx +0 -83
  283. package/templates/startkit/src/pages/not-found.tsx +0 -24
  284. package/templates/startkit/src/pages/workspace/_layout.tsx +0 -17
  285. package/templates/startkit/src/pages/workspace/accounts/index.tsx +0 -217
  286. package/templates/startkit/src/pages/workspace/dashboard.tsx +0 -118
  287. package/templates/startkit/src/pages/workspace/settings.tsx +0 -218
  288. package/templates/startkit/src/router.tsx +0 -7
  289. package/templates/startkit/src/routes/auth-config.ts +0 -38
  290. package/templates/startkit/src/routes/auth.ts +0 -8
  291. package/templates/startkit/src/routes/index.ts +0 -28
  292. package/templates/startkit/src/routes/public.ts +0 -8
  293. package/templates/startkit/src/routes/workspace/accounts.ts +0 -8
  294. package/templates/startkit/src/routes/workspace/index.ts +0 -14
  295. package/templates/startkit/src/styles/components.css +0 -396
  296. package/templates/startkit/src/styles/layout.css +0 -192
  297. package/templates/startkit/src/styles/reset.css +0 -38
  298. package/templates/startkit/src/styles/theme.css +0 -76
  299. package/templates/startkit/src/styles/tokens.css +0 -67
  300. package/templates/startkit/src/styles.css +0 -7
  301. package/templates/startkit/src/toast.ts +0 -55
  302. package/templates/startkit/src/utils/join-classes.ts +0 -4
  303. package/templates/startkit/src/vite-env.d.ts +0 -5
  304. package/templates/startkit/tests/app.test.tsx +0 -32
  305. package/templates/startkit/tests/preferences.test.ts +0 -43
  306. package/templates/startkit/tests/resources.test.ts +0 -82
  307. package/templates/startkit/tsconfig.json +0 -20
  308. package/templates/startkit/tsconfig.node.json +0 -10
  309. package/templates/startkit/vite.config.ts +0 -32
  310. package/templates/startkit/vitest.config.ts +0 -13
@@ -1,12 +0,0 @@
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
-
@@ -1,18 +0,0 @@
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
-
@@ -1,4 +0,0 @@
1
- node_modules
2
- dist
3
- coverage
4
- .env
@@ -1,14 +0,0 @@
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
-
@@ -1,37 +0,0 @@
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
- }
@@ -1,13 +0,0 @@
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
-
@@ -1,10 +0,0 @@
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
- }
@@ -1,10 +0,0 @@
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
- });
@@ -1,8 +0,0 @@
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
- });
@@ -1,12 +0,0 @@
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
-
@@ -1,25 +0,0 @@
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
- }
@@ -1,33 +0,0 @@
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
- }
@@ -1,4 +0,0 @@
1
- export function NotFoundPage() {
2
- return <main><h1>Not found</h1></main>;
3
- }
4
-
@@ -1,20 +0,0 @@
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
-
@@ -1,11 +0,0 @@
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
-
@@ -1,12 +0,0 @@
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
- }
@@ -1,14 +0,0 @@
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
- }
@@ -1,66 +0,0 @@
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
- }
@@ -1,55 +0,0 @@
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
- }
@@ -1,8 +0,0 @@
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;
@@ -1,4 +0,0 @@
1
- import { createTelemetry } from '@askrjs/otel';
2
-
3
- export const telemetry = createTelemetry();
4
-
@@ -1,6 +0,0 @@
1
- declare module 'virtual:askr-server' {
2
- import type { ServerApp } from '@askrjs/server';
3
- const app: ServerApp;
4
- export default app;
5
- }
6
-
@@ -1,13 +0,0 @@
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
-
@@ -1,16 +0,0 @@
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
-
@@ -1,11 +0,0 @@
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
-
@@ -1,60 +0,0 @@
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.
@@ -1,96 +0,0 @@
1
- # {{appName}} - SPA Template
2
-
3
- A route-first Askr SPA built with `@askrjs/askr`, `@askrjs/ui`, `@askrjs/themes`, and `@askrjs/charts`.
4
-
5
- ## Quick Start
6
-
7
- ```bash
8
- npm install
9
- npm run dev # Start dev server at http://localhost:5173
10
- npm run build # Build for production
11
- npm run preview # Preview production build
12
- npm test # Run tests with Vitest
13
- ```
14
-
15
- ## Project Structure
16
-
17
- ```
18
- src/
19
- |-- main.tsx # SPA boot and route manifest
20
- |-- pages/
21
- | |-- _routes.tsx # Top-level route branches
22
- | |-- _layout.tsx # Theme provider and app root
23
- | |-- public/ # Guest-facing landing pages and shell
24
- | |-- auth/ # Sign-in routes and shell
25
- | `-- app/ # Authenticated branch routes and shell
26
- |-- components/shared/ # App-local wrappers around theme primitives
27
- |-- features/operations/ # Product workflow queries and mutations
28
- |-- adapters/ # API clients and transport adapters
29
- |-- shared/ # Cross-cutting helpers and navigation data
30
- `-- styles/ # reset.css, tokens.css, theme.css, layout.css, components.css
31
- ```
32
-
33
- ## Core Patterns
34
-
35
- Routes live in `src/pages`, shells live in `_layout.tsx`, reusable UI lives in
36
- `src/components/shared`, business workflows live in `src/features`, and adapter
37
- code lives in `src/adapters`.
38
-
39
- ```tsx
40
- // src/pages/_routes.tsx
41
- import { fallback, group, registerRoutes } from '@askrjs/askr/router';
42
- import RootLayout from './_layout';
43
- import NotFoundPage from './not-found';
44
- import AuthLayout from './auth/_layout';
45
- import { registerAuthRoutes } from './auth/_routes';
46
- import AppLayout from './app/_layout';
47
- import { registerAppRoutes } from './app/_routes';
48
- import PublicLayout from './public/_layout';
49
- import { registerPublicRoutes } from './public/_routes';
50
-
51
- registerRoutes(() => {
52
- group({ layout: RootLayout }, () => {
53
- group({ layout: PublicLayout }, () => {
54
- registerPublicRoutes();
55
- });
56
- group({ layout: AuthLayout }, () => {
57
- registerAuthRoutes();
58
- });
59
- group({ layout: AppLayout }, () => {
60
- registerAppRoutes();
61
- });
62
- fallback(NotFoundPage);
63
- });
64
- });
65
- ```
66
-
67
- The template uses the `@askrjs/themes/components` catalog for styled UI
68
- composition and keeps charts in `@askrjs/charts`. Add app-local components only
69
- when they compose those primitives into a product concept. Start with
70
- `src/styles/tokens.css` for theme knobs, then tune `theme.css`, `layout.css`,
71
- and `components.css`.
72
-
73
- Async reads are owned by route or container components with `resource()` and
74
- delegated through feature/adapters:
75
-
76
- ```tsx
77
- const operations = resource(({ signal }) => loadOperations({ signal }), []);
78
- ```
79
-
80
- Cancellation belongs in adapters, loading/error/value states stay visible in the
81
- route, and event-sourced consistency states should be modeled explicitly.
82
-
83
- ## What This Template Includes
84
-
85
- - Public, auth, and authenticated app branches with separate layout shells
86
- - Theme provider, header/nav/sidebar, cards, badges, buttons, empty states, and layout primitives
87
- - A dashboard with async loading, charts, projection lag, and explicit refresh
88
- - Feature and adapter boundaries for data ownership
89
- - Tests that protect the route-first structure and cancellation behavior
90
-
91
- ## Next Steps
92
-
93
- 1. Replace the mock operations adapter with your generated API client.
94
- 2. Tune `src/styles/tokens.css` and `src/styles/theme.css` to match your brand.
95
- 3. Add route metadata for real auth and loader policies.
96
- 4. Keep new screens route-first and compose solved UI through `@askrjs/themes`.
@@ -1,16 +0,0 @@
1
- node_modules/
2
- dist/
3
- build/
4
- .env.local
5
- .env.*.local
6
- npm-debug.log*
7
- yarn-debug.log*
8
- yarn-error.log*
9
- pnpm-debug.log*
10
- .DS_Store
11
- Thumbs.db
12
- .vscode/
13
- .idea/
14
- *.swp
15
- *.swo
16
- *~
@@ -1,13 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <link rel="icon" type="image/svg+xml" href="/vite.svg" />
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
- <title>{{appName}}</title>
8
- </head>
9
- <body>
10
- <div id="app"></div>
11
- <script type="module" src="/src/main.tsx"></script>
12
- </body>
13
- </html>