@madojs/mado 0.11.1 → 0.13.0

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 (298) hide show
  1. package/AGENTS.md +116 -32
  2. package/CHANGELOG.md +216 -1
  3. package/README.md +158 -173
  4. package/dist/src/component.d.ts +6 -3
  5. package/dist/src/component.d.ts.map +1 -0
  6. package/dist/src/component.js +163 -36
  7. package/dist/src/component.js.map +1 -1
  8. package/dist/src/context.d.ts +13 -32
  9. package/dist/src/context.d.ts.map +1 -0
  10. package/dist/src/context.js +73 -48
  11. package/dist/src/context.js.map +1 -1
  12. package/dist/src/css.d.ts +1 -0
  13. package/dist/src/css.d.ts.map +1 -0
  14. package/dist/src/css.js +34 -5
  15. package/dist/src/css.js.map +1 -1
  16. package/dist/src/devtools-hook.d.ts +14 -0
  17. package/dist/src/devtools-hook.d.ts.map +1 -0
  18. package/dist/src/devtools-hook.js +27 -0
  19. package/dist/src/devtools-hook.js.map +1 -0
  20. package/dist/src/devtools.d.ts +24 -22
  21. package/dist/src/devtools.d.ts.map +1 -0
  22. package/dist/src/devtools.js +230 -58
  23. package/dist/src/devtools.js.map +1 -1
  24. package/dist/src/diagnostics.d.ts +12 -0
  25. package/dist/src/diagnostics.d.ts.map +1 -0
  26. package/dist/src/diagnostics.js +68 -8
  27. package/dist/src/diagnostics.js.map +1 -1
  28. package/dist/src/each.d.ts +1 -5
  29. package/dist/src/each.d.ts.map +1 -0
  30. package/dist/src/each.js +0 -8
  31. package/dist/src/each.js.map +1 -1
  32. package/dist/src/forms.d.ts +27 -96
  33. package/dist/src/forms.d.ts.map +1 -0
  34. package/dist/src/forms.js +184 -394
  35. package/dist/src/forms.js.map +1 -1
  36. package/dist/src/head.d.ts +7 -6
  37. package/dist/src/head.d.ts.map +1 -0
  38. package/dist/src/head.js +8 -7
  39. package/dist/src/head.js.map +1 -1
  40. package/dist/src/html/bindings.d.ts +1 -0
  41. package/dist/src/html/bindings.d.ts.map +1 -0
  42. package/dist/src/html/bindings.js.map +1 -1
  43. package/dist/src/html/parser.d.ts +4 -5
  44. package/dist/src/html/parser.d.ts.map +1 -0
  45. package/dist/src/html/parser.js +64 -15
  46. package/dist/src/html/parser.js.map +1 -1
  47. package/dist/src/html/template-types.d.ts +1 -0
  48. package/dist/src/html/template-types.d.ts.map +1 -0
  49. package/dist/src/html/template-types.js.map +1 -1
  50. package/dist/src/html/template.d.ts +5 -1
  51. package/dist/src/html/template.d.ts.map +1 -0
  52. package/dist/src/html/template.js +102 -13
  53. package/dist/src/html/template.js.map +1 -1
  54. package/dist/src/index.d.ts +15 -12
  55. package/dist/src/index.d.ts.map +1 -0
  56. package/dist/src/index.js +18 -10
  57. package/dist/src/index.js.map +1 -1
  58. package/dist/src/json.d.ts +3 -0
  59. package/dist/src/json.d.ts.map +1 -0
  60. package/dist/src/json.js +14 -0
  61. package/dist/src/json.js.map +1 -0
  62. package/dist/src/lifecycle.d.ts +1 -0
  63. package/dist/src/lifecycle.d.ts.map +1 -0
  64. package/dist/src/lifecycle.js +3 -2
  65. package/dist/src/lifecycle.js.map +1 -1
  66. package/dist/src/page.d.ts +63 -28
  67. package/dist/src/page.d.ts.map +1 -0
  68. package/dist/src/page.js +5 -0
  69. package/dist/src/page.js.map +1 -1
  70. package/dist/src/persisted.d.ts +6 -1
  71. package/dist/src/persisted.d.ts.map +1 -0
  72. package/dist/src/persisted.js +17 -11
  73. package/dist/src/persisted.js.map +1 -1
  74. package/dist/src/resource.d.ts +2 -1
  75. package/dist/src/resource.d.ts.map +1 -0
  76. package/dist/src/resource.js +128 -50
  77. package/dist/src/resource.js.map +1 -1
  78. package/dist/src/router/base.d.ts +66 -0
  79. package/dist/src/router/base.d.ts.map +1 -0
  80. package/dist/src/router/base.js +168 -0
  81. package/dist/src/router/base.js.map +1 -0
  82. package/dist/src/router/manifest.d.ts +1 -0
  83. package/dist/src/router/manifest.d.ts.map +1 -0
  84. package/dist/src/router/manifest.js +156 -171
  85. package/dist/src/router/manifest.js.map +1 -1
  86. package/dist/src/router/match.d.ts +17 -2
  87. package/dist/src/router/match.d.ts.map +1 -0
  88. package/dist/src/router/match.js +60 -6
  89. package/dist/src/router/match.js.map +1 -1
  90. package/dist/src/router/navigation.d.ts +1 -0
  91. package/dist/src/router/navigation.d.ts.map +1 -0
  92. package/dist/src/router/navigation.js +58 -9
  93. package/dist/src/router/navigation.js.map +1 -1
  94. package/dist/src/signal.d.ts +1 -0
  95. package/dist/src/signal.d.ts.map +1 -0
  96. package/dist/src/signal.js +46 -17
  97. package/dist/src/signal.js.map +1 -1
  98. package/dist/src/static-runtime.d.ts +82 -0
  99. package/dist/src/static-runtime.d.ts.map +1 -0
  100. package/dist/src/static-runtime.js +209 -0
  101. package/dist/src/static-runtime.js.map +1 -0
  102. package/dist/src/vite/index.d.ts +32 -3
  103. package/dist/src/vite/index.d.ts.map +1 -0
  104. package/dist/src/vite/index.js +49 -17
  105. package/dist/src/vite/index.js.map +1 -1
  106. package/docs/README.md +5 -8
  107. package/docs/architecture/adr/0001-browser-static-snapshots.md +132 -0
  108. package/docs/architecture/v1-roadmap.md +19 -0
  109. package/docs/en/00-the-mado-way.md +1 -1
  110. package/docs/en/01-quickstart.md +183 -0
  111. package/docs/en/10-pages-and-components.md +279 -0
  112. package/docs/en/11-templates-and-signals.md +211 -0
  113. package/docs/en/12-routing.md +229 -0
  114. package/docs/en/13-data.md +227 -0
  115. package/docs/en/14-forms.md +91 -0
  116. package/docs/en/15-static-snapshots.md +181 -0
  117. package/docs/en/{10-app-architecture.md → 16-app-architecture.md} +56 -4
  118. package/docs/en/{13-deployment.md → 20-deployment.md} +79 -17
  119. package/docs/en/{15-error-handling.md → 21-error-handling.md} +9 -6
  120. package/docs/en/{14-testing.md → 22-testing.md} +6 -5
  121. package/docs/en/23-cookbook.md +292 -0
  122. package/docs/en/24-devtools-and-diagnostics.md +45 -0
  123. package/docs/en/{18-api-freeze-map.md → 30-api-freeze-map.md} +17 -9
  124. package/docs/en/{20-v1-stability.md → 32-v1-stability.md} +5 -5
  125. package/docs/en/33-migration-0.12-0.13.md +56 -0
  126. package/docs/en/40-llm-guide.md +774 -0
  127. package/docs/en/{06-for-backenders.md → 41-for-backenders.md} +28 -25
  128. package/docs/en/{05-why-mado.md → 42-why-mado.md} +3 -3
  129. package/docs/en/README.md +99 -27
  130. package/docs/recipes/nginx/Containerfile +26 -0
  131. package/docs/recipes/nginx/nginx.conf +42 -0
  132. package/llms.txt +263 -210
  133. package/package.json +51 -23
  134. package/scripts/clean.mjs +8 -0
  135. package/scripts/cli/generate.mjs +57 -10
  136. package/scripts/cli/help.mjs +13 -5
  137. package/scripts/cli/index.mjs +31 -7
  138. package/scripts/cli/init.mjs +19 -19
  139. package/scripts/cli/release.mjs +38 -83
  140. package/scripts/cli/run.mjs +5 -3
  141. package/scripts/logger.mjs +117 -0
  142. package/scripts/output-guard.mjs +128 -0
  143. package/scripts/preview.mjs +105 -24
  144. package/scripts/static/browser.mjs +695 -0
  145. package/scripts/static/discover.mjs +284 -0
  146. package/scripts/static/output.mjs +141 -0
  147. package/scripts/static/serialize.mjs +212 -0
  148. package/scripts/static/server.mjs +167 -0
  149. package/scripts/static.mjs +205 -0
  150. package/starters/default/README.md +57 -55
  151. package/starters/default/package.json +6 -12
  152. package/starters/default/src/app.routes.ts +20 -33
  153. package/starters/default/src/components/feature-card.component.ts +40 -0
  154. package/starters/default/src/components/live-counter.component.ts +57 -0
  155. package/starters/default/src/content/guides.ts +55 -0
  156. package/starters/default/src/main.ts +9 -13
  157. package/starters/default/src/pages/app.page.ts +41 -0
  158. package/starters/default/src/pages/guide.page.ts +40 -0
  159. package/starters/default/src/pages/home.page.ts +49 -0
  160. package/starters/default/src/pages/not-found.page.ts +18 -0
  161. package/starters/default/src/styles/document.css +39 -0
  162. package/starters/default/src/styles/reset.css +37 -0
  163. package/starters/default/src/styles/tokens.css +30 -0
  164. package/starters/default/src/styles.d.ts +3 -1
  165. package/starters/default/src/vite-env.d.ts +1 -1
  166. package/starters/default/tsconfig.node.json +13 -0
  167. package/starters/default/vite.config.ts +14 -4
  168. package/starters/modular/README.md +142 -0
  169. package/starters/modular/index.html +13 -0
  170. package/starters/modular/package.json +30 -0
  171. package/starters/modular/src/app.routes.ts +39 -0
  172. package/starters/{default → modular}/src/layouts/app-shell.layout.ts +9 -7
  173. package/starters/{default → modular}/src/layouts/auth-shell.layout.ts +3 -3
  174. package/starters/modular/src/main.ts +16 -0
  175. package/starters/{default → modular}/src/modules/auth/login.page.ts +5 -12
  176. package/starters/{default → modular}/src/modules/billing/pages/invoice-detail.page.ts +3 -4
  177. package/starters/{default → modular}/src/modules/billing/pages/invoices-list.page.ts +4 -4
  178. package/starters/{default → modular}/src/modules/home/home.page.ts +5 -7
  179. package/starters/modular/src/modules/home/not-found.page.ts +14 -0
  180. package/starters/{default → modular}/src/shared/styles/reset.css +21 -1
  181. package/starters/modular/src/styles.d.ts +1 -0
  182. package/starters/modular/src/vite-env.d.ts +1 -0
  183. package/starters/modular/tsconfig.json +33 -0
  184. package/starters/modular/tsconfig.node.json +13 -0
  185. package/starters/modular/vite.config.ts +132 -0
  186. package/TODO.md +0 -79
  187. package/dist/src/lazy.d.ts +0 -38
  188. package/dist/src/lazy.js +0 -73
  189. package/dist/src/lazy.js.map +0 -1
  190. package/docs/en/01-routing.md +0 -152
  191. package/docs/en/02-project-layout.md +0 -124
  192. package/docs/en/03-static-bake.md +0 -249
  193. package/docs/en/04-ide-setup.md +0 -162
  194. package/docs/en/07-llm-pitfalls.md +0 -724
  195. package/docs/en/08-llm-zero-history-test.md +0 -56
  196. package/docs/en/09-shadow-vs-light-dom.md +0 -174
  197. package/docs/en/11-layouts.md +0 -113
  198. package/docs/en/12-auth-and-api.md +0 -124
  199. package/docs/en/16-bake-cookbook.md +0 -100
  200. package/docs/en/17-shadow-dom-forms.md +0 -192
  201. package/docs/fr/00-the-mado-way.md +0 -85
  202. package/docs/fr/01-routing.md +0 -120
  203. package/docs/fr/02-project-layout.md +0 -84
  204. package/docs/fr/03-static-bake.md +0 -289
  205. package/docs/fr/04-ide-setup.md +0 -162
  206. package/docs/fr/05-why-mado.md +0 -193
  207. package/docs/fr/06-for-backenders.md +0 -438
  208. package/docs/fr/07-llm-pitfalls.md +0 -625
  209. package/docs/fr/08-llm-zero-history-test.md +0 -38
  210. package/docs/fr/09-shadow-vs-light-dom.md +0 -65
  211. package/docs/fr/10-app-architecture.md +0 -138
  212. package/docs/fr/11-layouts.md +0 -47
  213. package/docs/fr/12-auth-and-api.md +0 -76
  214. package/docs/fr/13-deployment.md +0 -57
  215. package/docs/fr/14-testing.md +0 -41
  216. package/docs/fr/15-error-handling.md +0 -50
  217. package/docs/fr/16-bake-cookbook.md +0 -88
  218. package/docs/fr/17-shadow-dom-forms.md +0 -196
  219. package/docs/fr/18-api-freeze-map.md +0 -63
  220. package/docs/fr/19-reactivity-ordering.md +0 -97
  221. package/docs/fr/20-v1-stability.md +0 -88
  222. package/docs/fr/README.md +0 -27
  223. package/docs/ru/00-the-mado-way.md +0 -84
  224. package/docs/ru/01-routing.md +0 -119
  225. package/docs/ru/02-project-layout.md +0 -84
  226. package/docs/ru/03-static-bake.md +0 -250
  227. package/docs/ru/04-ide-setup.md +0 -144
  228. package/docs/ru/05-why-mado.md +0 -193
  229. package/docs/ru/06-for-backenders.md +0 -428
  230. package/docs/ru/07-llm-pitfalls.md +0 -624
  231. package/docs/ru/08-llm-zero-history-test.md +0 -57
  232. package/docs/ru/09-shadow-vs-light-dom.md +0 -63
  233. package/docs/ru/10-app-architecture.md +0 -152
  234. package/docs/ru/11-layouts.md +0 -47
  235. package/docs/ru/12-auth-and-api.md +0 -75
  236. package/docs/ru/13-deployment.md +0 -66
  237. package/docs/ru/14-testing.md +0 -50
  238. package/docs/ru/15-error-handling.md +0 -56
  239. package/docs/ru/16-bake-cookbook.md +0 -95
  240. package/docs/ru/17-shadow-dom-forms.md +0 -193
  241. package/docs/ru/18-api-freeze-map.md +0 -64
  242. package/docs/ru/19-reactivity-ordering.md +0 -95
  243. package/docs/ru/20-v1-stability.md +0 -82
  244. package/docs/ru/README.md +0 -25
  245. package/docs/uk/00-the-mado-way.md +0 -82
  246. package/docs/uk/01-routing.md +0 -76
  247. package/docs/uk/02-project-layout.md +0 -73
  248. package/docs/uk/03-static-bake.md +0 -48
  249. package/docs/uk/04-ide-setup.md +0 -26
  250. package/docs/uk/05-why-mado.md +0 -34
  251. package/docs/uk/06-for-backenders.md +0 -55
  252. package/docs/uk/07-llm-pitfalls.md +0 -145
  253. package/docs/uk/08-llm-zero-history-test.md +0 -34
  254. package/docs/uk/09-shadow-vs-light-dom.md +0 -58
  255. package/docs/uk/10-app-architecture.md +0 -97
  256. package/docs/uk/11-layouts.md +0 -47
  257. package/docs/uk/12-auth-and-api.md +0 -70
  258. package/docs/uk/13-deployment.md +0 -40
  259. package/docs/uk/14-testing.md +0 -34
  260. package/docs/uk/15-error-handling.md +0 -32
  261. package/docs/uk/16-bake-cookbook.md +0 -36
  262. package/docs/uk/17-shadow-dom-forms.md +0 -193
  263. package/docs/uk/18-api-freeze-map.md +0 -61
  264. package/docs/uk/19-reactivity-ordering.md +0 -95
  265. package/docs/uk/20-v1-stability.md +0 -83
  266. package/docs/uk/README.md +0 -27
  267. package/scripts/bake.mjs +0 -570
  268. package/scripts/package-smoke.mjs +0 -77
  269. package/scripts/release-notes.mjs +0 -66
  270. package/scripts/size-budget.mjs +0 -91
  271. package/starters/default/src/modules/home/not-found.page.ts +0 -11
  272. package/starters/default/src/shared/ui/x-button.component.ts +0 -49
  273. /package/docs/en/{19-reactivity-ordering.md → 31-reactivity-ordering.md} +0 -0
  274. /package/starters/{default → modular}/.editorconfig +0 -0
  275. /package/starters/{default → modular}/eslint.config.mjs +0 -0
  276. /package/starters/{default → modular}/public/favicon.svg +0 -0
  277. /package/starters/{default → modular}/src/modules/auth/_contracts/auth-api.types.ts +0 -0
  278. /package/starters/{default → modular}/src/modules/auth/auth.connector.ts +0 -0
  279. /package/starters/{default → modular}/src/modules/auth/auth.guard.ts +0 -0
  280. /package/starters/{default → modular}/src/modules/auth/auth.public.ts +0 -0
  281. /package/starters/{default → modular}/src/modules/auth/auth.routes.ts +0 -0
  282. /package/starters/{default → modular}/src/modules/auth/auth.service.ts +0 -0
  283. /package/starters/{default → modular}/src/modules/auth/auth.types.ts +0 -0
  284. /package/starters/{default → modular}/src/modules/billing/_contracts/stripe.types.ts +0 -0
  285. /package/starters/{default → modular}/src/modules/billing/api/stripe.connector.ts +0 -0
  286. /package/starters/{default → modular}/src/modules/billing/billing.public.ts +0 -0
  287. /package/starters/{default → modular}/src/modules/billing/billing.routes.ts +0 -0
  288. /package/starters/{default → modular}/src/modules/billing/billing.types.ts +0 -0
  289. /package/starters/{default → modular}/src/modules/billing/components/invoice-status-badge.component.ts +0 -0
  290. /package/starters/{default → modular}/src/modules/billing/data/invoices.resource.ts +0 -0
  291. /package/starters/{default → modular}/src/shared/http/http-client.ts +0 -0
  292. /package/starters/{default → modular}/src/shared/http/http-error.ts +0 -0
  293. /package/starters/{default → modular}/src/shared/http/interceptors.ts +0 -0
  294. /package/starters/{default → modular}/src/shared/lib/format-date.ts +0 -0
  295. /package/starters/{default → modular}/src/shared/styles/content.css +0 -0
  296. /package/starters/{default → modular}/src/shared/styles/shell.css +0 -0
  297. /package/starters/{default → modular}/src/shared/styles/tokens.css +0 -0
  298. /package/starters/{default → modular}/src/shared/ui/x-spinner.component.ts +0 -0
@@ -1,63 +0,0 @@
1
- # Shadow DOM vs Light DOM
2
-
3
- Mado components используют Shadow DOM по умолчанию. Это хороший default для
4
- самодостаточных виджетов, но app zones и страницы обычно должны оставаться
5
- простыми light DOM templates.
6
-
7
- ## Правило
8
-
9
- Используйте route layouts для app zones:
10
-
11
- ```ts
12
- export default page({
13
- view: ({ child }) => html`<main class="app-main">${child}</main>`,
14
- });
15
- ```
16
-
17
- Такие файлы живут в `src/layouts/` и подключаются в `src/app.routes.ts` через
18
- `layout()`. Они стилизуются обычным CSS из `src/shared/styles/shell.css`.
19
-
20
- Используйте page files для screens:
21
-
22
- ```ts
23
- export default page({
24
- view: () => html`<section><h1>Users</h1></section>`,
25
- });
26
- ```
27
-
28
- Page-level tables, forms, prose and simple states стилизуются из
29
- `src/shared/styles/content.css`.
30
-
31
- Используйте Shadow DOM components для leaf widgets:
32
-
33
- - buttons, badges, cards, metrics;
34
- - spinners, modals, toasts;
35
- - widgets, которые должны владеть своим CSS.
36
-
37
- ```ts
38
- component("x-status-badge", ({ attr }) => {
39
- const status = attr("status", "draft");
40
- return () => html`<span>${status}</span>`;
41
- }, {
42
- styles: css`
43
- :host { display: inline-block; }
44
- span { color: var(--color-text-muted); }
45
- `,
46
- });
47
- ```
48
-
49
- ## Как ведут себя стили
50
-
51
- - `tokens.css` задает CSS custom properties; `var(...)` проходит через Shadow
52
- DOM.
53
- - `reset.css`, `shell.css`, `content.css` применяются только к document/light
54
- DOM.
55
- - Class selectors вроде `.data`, `.app-main`, `.error` не проходят внутрь
56
- Shadow DOM.
57
- - Component-local styles пишутся в ``css`...` `` внутри `component()` options.
58
- - Если Shadow component принимает children, используйте `<slot>` и стилизуйте
59
- frame внутри component styles.
60
-
61
- Если page выглядит без стилей, почти всегда вы использовали global classes
62
- внутри Shadow DOM component. Вынесите markup в page/layout или перенесите CSS в
63
- component styles.
@@ -1,152 +0,0 @@
1
- # Архитектура приложения
2
-
3
- Официальный starter — каноничная production-форма Mado-приложения. Это не
4
- framework внутри framework: только файлы, imports, Mado primitives и ESLint
5
- boundaries.
6
-
7
- ## Структура
8
-
9
- ```txt
10
- src/
11
- ├── main.ts
12
- ├── app.routes.ts
13
- ├── layouts/
14
- │ ├── app-shell.layout.ts
15
- │ └── auth-shell.layout.ts
16
- ├── shared/
17
- │ ├── http/
18
- │ ├── lib/
19
- │ ├── styles/
20
- │ └── ui/
21
- └── modules/
22
- ├── auth/
23
- │ ├── auth.routes.ts
24
- │ ├── auth.public.ts
25
- │ ├── auth.service.ts
26
- │ ├── auth.connector.ts
27
- │ ├── auth.guard.ts
28
- │ ├── login.page.ts
29
- │ └── _contracts/
30
- └── billing/
31
- ├── billing.routes.ts
32
- ├── billing.public.ts
33
- ├── billing.types.ts
34
- ├── api/
35
- ├── data/
36
- ├── pages/
37
- ├── components/
38
- └── _contracts/
39
- ```
40
-
41
- ## App Map
42
-
43
- `src/app.routes.ts` — карта всего приложения. Modules экспортируют plain route
44
- maps; app routes решают, какой shell и guard оборачивают каждую зону.
45
-
46
- ```ts
47
- import { layout, routes } from "@madojs/mado";
48
- import { requireAuth } from "./modules/auth/auth.public";
49
- import { authRoutes } from "./modules/auth/auth.routes";
50
- import { billingRoutes } from "./modules/billing/billing.routes";
51
-
52
- export const manifest = {
53
- "/": () => import("./modules/home/home.page"),
54
- "/login": layout({
55
- layout: () => import("./layouts/auth-shell.layout"),
56
- routes: authRoutes,
57
- }),
58
- "/billing": layout({
59
- layout: () => import("./layouts/app-shell.layout"),
60
- guard: requireAuth,
61
- routes: billingRoutes,
62
- }),
63
- "*": () => import("./modules/home/not-found.page"),
64
- };
65
-
66
- export default routes(manifest);
67
- ```
68
-
69
- Rules:
70
-
71
- - Export `manifest`, чтобы `mado bake` мог найти bakeable pages.
72
- - Modules не вызывают `layout()`.
73
- - Layouts описывают app zones, не домены.
74
- - Router не прячется в custom element или втором shell в `main.ts`.
75
-
76
- ## File Forms
77
-
78
- | Suffix | Role |
79
- | --- | --- |
80
- | `*.page.ts` | route page, default `page({...})` |
81
- | `*.layout.ts` | app-zone wrapper, default `page(...)` |
82
- | `*.connector.ts` | one external API system |
83
- | `*.resource.ts` | `resource()` and `mutation()` layer |
84
- | `*.service.ts` | module singleton state |
85
- | `*.guard.ts` | route guard |
86
- | `*.routes.ts` | module-local route map |
87
- | `*.public.ts` | only public module surface |
88
- | `*.types.ts` | domain types |
89
- | `*.component.ts` | Web Component registration |
90
-
91
- Page-local signals, resources and forms live inside `view()`. Module-wide state
92
- lives in `*.service.ts`.
93
-
94
- ## Data Flow
95
-
96
- ```txt
97
- shared/http/http-client.ts
98
-
99
- modules/<x>/api/*.connector.ts DTO -> domain mapping
100
-
101
- modules/<x>/data/*.resource.ts cache keys + mutations
102
-
103
- modules/<x>/pages/*.page.ts UI consumes domain types
104
- ```
105
-
106
- ## Module Boundaries
107
-
108
- Модуль opaque, кроме `<module>.public.ts`. Другие modules импортируют через этот
109
- файл или никак. DTO внешних систем лежат в `_contracts/` и остаются private для
110
- connector.
111
-
112
- Default starter enforces this with ESLint:
113
-
114
- - no barrels (`index.ts`);
115
- - no `export *`;
116
- - no CSS imports outside `src/main.ts`;
117
- - no cross-module imports except public surfaces;
118
- - no `_contracts` imports outside connectors.
119
-
120
- ## Styles
121
-
122
- | File | Role |
123
- | --- | --- |
124
- | `src/shared/styles/tokens.css` | design tokens as CSS custom properties |
125
- | `src/shared/styles/reset.css` | document/light DOM reset |
126
- | `src/shared/styles/shell.css` | app-zone layouts from `src/layouts/` |
127
- | `src/shared/styles/content.css` | page-level forms, tables, prose and states |
128
-
129
- Reusable leaf components keep their own styles in ``css`...` `` inside
130
- `component()` options and depend on tokens, not global classes.
131
-
132
- `vite.config.ts` opts into Vite Lightning CSS transformer. Mado does not own
133
- prefixing, CSS lowering or minification.
134
-
135
- ## CLI
136
-
137
- Use `mado new` for boring file scaffolding:
138
-
139
- ```bash
140
- mado new module billing
141
- mado new page billing/pages/invoices-list
142
- mado new connector billing/api/stripe
143
- mado new resource billing/data/invoices
144
- mado new service billing/cart
145
- mado new form billing/invoice
146
- mado new component billing/components/invoice-status-badge
147
- mado new guard billing/billing
148
- mado new layout app-shell
149
- ```
150
-
151
- The generator writes files only. It does not edit `app.routes.ts`, does not scan
152
- the filesystem, and refuses to overwrite existing files.
@@ -1,47 +0,0 @@
1
- # Layouts
2
-
3
- Blessed layout способ в Mado — route group в `src/app.routes.ts`.
4
- Не заворачивайте каждую страницу вручную и не кладите общий shell в `main.ts`,
5
- если есть разные зоны: public, auth, app, embed.
6
-
7
- ```ts
8
- import { layout, routes } from "@madojs/mado";
9
- import { requireAuth } from "./modules/auth/auth.public";
10
- import { authRoutes } from "./modules/auth/auth.routes";
11
- import { billingRoutes } from "./modules/billing/billing.routes";
12
-
13
- export const manifest = {
14
- "/": () => import("./modules/home/home.page.js"),
15
- "/login": layout({
16
- layout: () => import("./layouts/auth-shell.layout.js"),
17
- routes: authRoutes,
18
- }),
19
- "/billing": layout({
20
- layout: () => import("./layouts/app-shell.layout.js"),
21
- guard: requireAuth,
22
- routes: billingRoutes,
23
- }),
24
- "*": () => import("./modules/home/not-found.page.js"),
25
- };
26
-
27
- export default routes(manifest);
28
- ```
29
-
30
- Layout — обычный `page({ view })`, который рендерит `child`:
31
-
32
- ```ts
33
- export default page({
34
- view: ({ child }) => html`
35
- <div class="layout layout--app">
36
- <main class="app-main">${child}</main>
37
- </div>
38
- `,
39
- });
40
- ```
41
-
42
- Rules:
43
-
44
- - one shell per route group, not per page;
45
- - modules export plain route maps and do not call `layout()`;
46
- - guard on a group protects the whole subtree;
47
- - layout view stays stateless; page-local state lives in pages/components/resources.
@@ -1,75 +0,0 @@
1
- # Auth and API
2
-
3
- Default starter — blessed recipe. HTTP mechanics живут в `src/shared/http/`,
4
- auth state — в `src/modules/auth/`.
5
-
6
- ```txt
7
- src/shared/http/
8
- http-client.ts
9
- http-error.ts
10
- interceptors.ts
11
-
12
- src/modules/auth/
13
- auth.connector.ts
14
- auth.service.ts
15
- auth.guard.ts
16
- auth.routes.ts
17
- auth.public.ts
18
- _contracts/
19
- ```
20
-
21
- Flow для business module:
22
-
23
- ```txt
24
- connector -> resource/mutation -> page
25
- ```
26
-
27
- Pages не импортируют DTOs и не вызывают `fetch()` напрямую. Connectors не
28
- импортируют Mado reactivity или UI.
29
-
30
- ## Auth Service
31
-
32
- Auth state — ES module singleton:
33
-
34
- ```ts
35
- const _user = signal<User | null>(null);
36
- const _token = signal<string | null>(null);
37
-
38
- export const user = () => _user();
39
- export const isAuthed = computed(() => _user() !== null);
40
- ```
41
-
42
- Expose only what other modules need through `auth.public.ts`.
43
-
44
- ## Guards
45
-
46
- ```ts
47
- export function requireAuth(): boolean | string {
48
- if (isAuthed()) return true;
49
- return "/login";
50
- }
51
- ```
52
-
53
- Use in `src/app.routes.ts`:
54
-
55
- ```ts
56
- "/billing": layout({
57
- layout: () => import("./layouts/app-shell.layout"),
58
- guard: requireAuth,
59
- routes: billingRoutes,
60
- }),
61
- ```
62
-
63
- ## Dev Proxy
64
-
65
- ```ts
66
- export default defineConfig({
67
- plugins: [mado()],
68
- server: {
69
- proxy: { "/api": "http://localhost:3000" },
70
- },
71
- });
72
- ```
73
-
74
- Rule: `shared/http` knows HTTP, connectors know one external system, resources
75
- know cache keys, pages know UI, `*.public.ts` is the cross-module surface.
@@ -1,66 +0,0 @@
1
- # Deployment
2
-
3
- Одна команда, один deploy artifact:
4
-
5
- ```bash
6
- mado release
7
- ```
8
-
9
- Результат:
10
-
11
- ```txt
12
- out/
13
- ├── index.html ← SPA shell или baked HTML для /
14
- ├── assets/ ← Vite hashed assets
15
- │ ├── *.gz ← precompressed gzip
16
- │ └── *.br ← precompressed brotli
17
- ├── <route>/index.html ← baked HTML для static hosts
18
- ├── sitemap.xml ← sitemap в root сайта
19
- ├── _redirects ← Cloudflare Pages / Netlify SPA fallback
20
- └── _headers ← cache rules
21
- ```
22
-
23
- `out/` можно деплоить на nginx, Cloudflare Pages, Netlify, S3/CloudFront или
24
- GitHub Pages. Деплоится только `out/`.
25
-
26
- ## Preview
27
-
28
- ```bash
29
- mado release
30
- mado preview
31
- ```
32
-
33
- `mado preview` сервит финальный `out/` как обычный static host: сначала реальные
34
- файлы (`/<route>/index.html`, если route был baked), потом SPA fallback в
35
- `index.html`. Preview проверяет ровно то, что будет загружено на хостинг.
36
-
37
- ## VPS + nginx
38
-
39
- ```bash
40
- mado release
41
- rsync -avz --delete out/ user@server:/var/www/myapp/
42
- ```
43
-
44
- Опциональный nginx-рецепт лежит в `docs/recipes/nginx/`: assets кешируются
45
- immutable, HTML идет с `no-cache`, deep links работают через SPA fallback.
46
-
47
- ## Cloudflare / Netlify
48
-
49
- ```bash
50
- mado release
51
- npx wrangler pages deploy out --project-name=myapp
52
- ```
53
-
54
- `_redirects` и `_headers` генерируются автоматически, если ты не положил свои.
55
- Baked routes промотируются в реальные файлы (`out/<route>/index.html`), поэтому
56
- static host отдаст их до SPA fallback.
57
-
58
- ## Cache Rules
59
-
60
- | Path | Cache-Control |
61
- |---|---|
62
- | `/assets/main-*.js` | `public, max-age=31536000, immutable` |
63
- | `/*.html` | `no-cache, must-revalidate` |
64
- | other static files | `public, max-age=86400` |
65
-
66
- Если hard refresh на deep link дает 404, проблема в fallback настройке хоста.
@@ -1,50 +0,0 @@
1
- # Тестирование
2
-
3
- Mado — это обычный TypeScript и browser APIs. В репозитории фреймворка тесты
4
- идут через Node test runner и `linkedom`.
5
-
6
- ## Команды
7
-
8
- ```bash
9
- npm run typecheck
10
- npm run build
11
- npm test
12
- ```
13
-
14
- Перед merge/release прогоняй все три.
15
-
16
- ## DOM-тест
17
-
18
- ```js
19
- import test from "node:test";
20
- import assert from "node:assert/strict";
21
-
22
- const { parseHTML } = await import("linkedom");
23
- const { window } = parseHTML("<!doctype html><html><body></body></html>");
24
- globalThis.window = window;
25
- globalThis.document = window.document;
26
- globalThis.Node = window.Node;
27
- globalThis.HTMLElement = window.HTMLElement;
28
-
29
- const { html, render } = await import("../dist/src/html/template.js");
30
-
31
- test("renders a value", () => {
32
- const root = document.createElement("div");
33
- render(html`<p>${"hello"}</p>`, root);
34
- assert.equal(root.querySelector("p").textContent, "hello");
35
- });
36
- ```
37
-
38
- Сначала `npm run build`, потом импорт из `dist/`.
39
-
40
- ## Что покрывать
41
-
42
- - signals/computed/effect: scheduling и cleanup;
43
- - template bindings: children, attrs, events, directives;
44
- - routes: guards, redirects, scroll/focus, error boundaries;
45
- - forms: sync/async validation, races, field arrays;
46
- - resources/mutations: cache keys, invalidation, lifecycle cleanup;
47
- - CLI: `mado release`, `mado bake`, `mado preview`.
48
-
49
- Для реального браузера оставляй маленькие smoke-тесты: открыть страницу,
50
- кликнуть ссылку или отправить форму, проверить видимый результат.
@@ -1,56 +0,0 @@
1
- # Обработка ошибок
2
-
3
- В Mado есть три практичных слоя ошибок: загрузка роутов, загрузка данных и
4
- действия пользователя.
5
-
6
- ## Route errors
7
-
8
- Глобальная граница:
9
-
10
- ```ts
11
- export default routes(manifest, {
12
- errorPage: (err) => html`
13
- <main>
14
- <h1>Что-то пошло не так</h1>
15
- <pre>${err.message}</pre>
16
- <a data-link href="/">На главную</a>
17
- </main>
18
- `,
19
- });
20
- ```
21
-
22
- Локальная `page({ errorView })` имеет приоритет над `errorPage`.
23
-
24
- ## Resource errors
25
-
26
- `resource()` дает `error()` и `loading()`. Показывай retry рядом с данными.
27
-
28
- ```ts
29
- const users = resource(() => "/api/users", jsonFetcher<User[]>());
30
-
31
- html`
32
- ${() => users.error()
33
- ? html`<p role="alert">${users.error()!.message}</p>
34
- <button @click=${users.refresh}>Повторить</button>`
35
- : null}
36
- `;
37
- ```
38
-
39
- ## Forms and mutations
40
-
41
- Ошибки валидации — в `useForm()`. Ошибки записи — рядом с submit-кнопкой.
42
-
43
- ```ts
44
- const form = useForm(
45
- { email: { required: true, type: "email" } },
46
- { validateAsync: (values) => api.validateUser(values) },
47
- );
48
- const save = mutation((values) => api.post("/users", values), {
49
- invalidates: ["/api/users*"],
50
- });
51
- ```
52
-
53
- ## Cleanup
54
-
55
- Внешние browser subscriptions чисти через `ctx.onDispose()`. `resource()`,
56
- `effect()` и signals внутри component setup уже привязаны к lifecycle.
@@ -1,95 +0,0 @@
1
- # Bake Cookbook
2
-
3
- `mado bake` рендерит выбранные роуты в статический HTML. Это для SEO и быстрого
4
- первого ответа, не SSR с hydration.
5
-
6
- ## Минимальная Страница
7
-
8
- ```ts
9
- export default page({
10
- head: () => ({ title: "Products", description: "Catalog" }),
11
- view: ({ data }) => html`
12
- <main>
13
- <h1>Products</h1>
14
- ${data.products.map((p) => html`<article><h2>${p.name}</h2></article>`)}
15
- </main>
16
- `,
17
- bake: {
18
- paths: () => [{}],
19
- data: async () => ({ products: await api.products() }),
20
- revalidate: 3600,
21
- },
22
- });
23
- ```
24
-
25
- В baked views лучше использовать обычные массивы (`items.map(...)`). Runtime
26
- директивы вроде keyed `each()` нужны браузеру.
27
-
28
- ## Dynamic Routes
29
-
30
- ```ts
31
- export default page<{ slug: string }>({
32
- head: ({ slug }, data) => ({ title: data.title, canonical: `/blog/${slug}` }),
33
- view: ({ data }) => html`<article>${unsafeHTML(data.html)}</article>`,
34
- bake: {
35
- paths: async () => (await api.posts()).map((p) => ({ slug: p.slug })),
36
- data: ({ slug }) => api.post(slug),
37
- },
38
- });
39
- ```
40
-
41
- `unsafeHTML()` используй только для доверенного или заранее очищенного HTML.
42
-
43
- ## Route Manifest
44
-
45
- `mado bake` нужен source manifest:
46
-
47
- ```ts
48
- export const manifest = {
49
- "/": () => import("./pages/home.js"),
50
- "/blog/:slug": () => import("./pages/blog-post.js"),
51
- };
52
-
53
- export default routes(manifest);
54
- ```
55
-
56
- ## Output
57
-
58
- Standalone `mado bake` по умолчанию пишет baked pages прямо в `out/`.
59
- `mado release` сначала запускает Vite build, затем bake заменяет route HTML
60
- на месте и пишет sitemap в `out/sitemap.xml`.
61
-
62
- ```bash
63
- mado release
64
- tree out
65
- ```
66
-
67
- Deployable folder — `out/`, не `dist/`.
68
-
69
- `mado release --keep-bake-dir` оставляет дополнительную копию `out/baked/`
70
- только для debugging/inspection.
71
-
72
- ## Client Boot
73
-
74
- Baked HTML помечает `#app` атрибутом `data-mado-baked`. Это не hydration:
75
- клиентский `render()` заменяет baked DOM живыми bindings при старте приложения.
76
- Так первый ответ содержит SEO/first-paint HTML, а SPA после загрузки работает
77
- как обычно.
78
-
79
- ## Unsupported Values
80
-
81
- Bake намеренно падает громко вместо записи `[object Object]`. Если baked view
82
- ругается на unsupported directive:
83
-
84
- - замени `each()` на `items.map(...)` в baked markup;
85
- - интерактивные виджеты оставь в client-only routes;
86
- - убедись, что все значения сериализуются в статический HTML.
87
-
88
- ## Canonical Links
89
-
90
- Передай `--base-url`, чтобы canonical links и sitemap указывали на production.
91
-
92
- ```bash
93
- mado bake --base-url https://example.com
94
- mado release --base-url https://example.com
95
- ```