@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
package/AGENTS.md CHANGED
@@ -3,14 +3,20 @@
3
3
  > This file is read by AI agents in IDEs (Cursor, Cline, Copilot, Continue, etc.).
4
4
  > Goal: prevent them from generating React-like code where Mado should be used.
5
5
  >
6
- > / `TODO.md` unless the user explicitly resumes that tracker.
6
+ > Skip `TODO.md` unless the user explicitly resumes that tracker.
7
7
 
8
8
  ## Project at a glance
9
9
 
10
- - **Mado** — a calm browser-native SPA framework for internal tools, admin panels and business apps.
10
+ - **Mado** — a calm native-first web framework for both static sites
11
+ and live SPAs. One Web Component model, one page model, one release
12
+ command.
13
+ - Current development release: **0.13.0**.
11
14
  - Built on Web Components + signals + tagged-template `html`.
12
- - Zero runtime dependencies. Generated apps use dev tooling (`typescript`,
13
- `vite`, `linkedom`) for dev/build/bake/release.
15
+ - **Vite is the canonical transport** for development, build and the
16
+ static snapshot pipeline. Generated apps depend on `typescript`,
17
+ `vite` and `playwright-core` (the last only for `mado release`,
18
+ which captures real Chromium-rendered HTML).
19
+ - Zero runtime dependencies (Vite is dev/build tooling, not bundled).
14
20
  - Small TypeScript core in `src/`; production size budgets are enforced in CI.
15
21
 
16
22
  ## HARD RULES — violation = bug
@@ -295,8 +301,9 @@ const { register, handleSubmit } = useForm({ resolver: yupResolver(schema) });
295
301
  import { useForm } from "@madojs/mado";
296
302
 
297
303
  const f = useForm({
298
- email: { required: true, type: "email" },
299
- age: { required: true, type: "number", min: 18 },
304
+ initial: { email: "", age: "" as number | "" },
305
+ validate: async (values, { signal }) =>
306
+ await api.valid(values, { signal }) ? null : { email: "Unavailable" },
300
307
  });
301
308
 
302
309
  html`
@@ -305,7 +312,8 @@ html`
305
312
  await api.save(v);
306
313
  })}
307
314
  >
308
- <input name="email" @input=${f.onInput} @blur=${f.onBlur} />
315
+ <input name="email" type="email" required @input=${f.onInput} @blur=${f.onBlur} />
316
+ <input name="age" type="number" min="18" @input=${f.onInput} />
309
317
  ${() =>
310
318
  f.touched().email && f.errors().email
311
319
  ? html`<small>${f.errors().email}</small>`
@@ -315,7 +323,8 @@ html`
315
323
  `;
316
324
  ```
317
325
 
318
- Custom validation `validate: (values) => ({ field: 'error message' } | null)`.
326
+ HTML owns native constraints. Custom validation receives an `AbortSignal`.
327
+ Use `setField`, not a schema/field-array abstraction.
319
328
 
320
329
  ### 11. Styles — `css\`\`` + Shadow DOM by default
321
330
 
@@ -362,6 +371,10 @@ component("x-child", ({ host }) => {
362
371
  });
363
372
  ```
364
373
 
374
+ This interoperates through the Web Components `context-request` protocol.
375
+ Providers may expose function values; only real Mado Signals are treated as
376
+ reactive sources. Subscriptions are removed with the active lifecycle.
377
+
365
378
  ### 13. Component registration imports
366
379
 
367
380
  Custom elements are global after registration, but the browser never imports a
@@ -384,16 +397,54 @@ Rules:
384
397
  - Tiny leaf components used everywhere → importing in `main.ts` is acceptable.
385
398
  - Do **not** bulk-import every component "just in case".
386
399
 
387
- ### 14. Bakemeta shell, not SSR/SSG runtime
400
+ ### 14. Static snapshots browser-rendered, not SSR/SSG
401
+
402
+ `mado static` (normally invoked through `mado release`) captures real
403
+ HTML by navigating each page in a headless Chromium and serialising
404
+ the resulting DOM, including the Shadow DOM through Declarative Shadow
405
+ DOM (DSD). On first paint the live SPA **atomically replaces** the
406
+ static tree — there is no hydration protocol, no node reconciliation
407
+ and no per-attribute diffing.
408
+
409
+ A page opts in by declaring `static` on `page({ ... })`:
410
+
411
+ ```ts
412
+ // Static landing page
413
+ export default page({
414
+ static: true,
415
+ title: "Home",
416
+ head: () => ({ description: "Public landing" }),
417
+ view: () => html`<main><h1>Hello</h1></main>`,
418
+ });
419
+
420
+ // Dynamic static route
421
+ export default page({
422
+ static: {
423
+ paths: async () => [{ slug: "alpha" }, { slug: "beta" }],
424
+ initialData: async ({ slug }) => loadGuide(slug),
425
+ },
426
+ title: ({ slug }) => `Guide: ${slug}`,
427
+ view: (ctx) => html`<article>${ctx.data}</article>`,
428
+ });
429
+ ```
388
430
 
389
- `mado bake` is a static meta-shell/prerender pass for SEO and first paint. It is
390
- not SSR with hydration and not a Next-style SSG runtime.
431
+ Important constraints:
391
432
 
392
- - Baked HTML must be deterministic from `params`, `bake.data`, and plain values.
393
- - Do not rely on browser-only effects, timers, relative `fetch`, or keyed
394
- runtime directives such as `each()` during bake.
395
- - Use `page({ head, bake })` for meta/JSON-LD/sitemap data; render dynamic,
396
- personalized, real-time, or auth-dependent content in the client SPA.
433
+ - Static pages cannot use guards (route- or layout-level) they are
434
+ public by definition.
435
+ - `paths()` and `initialData()` run at discovery AND ship in the
436
+ client bundle. Keep them browser-safe; never read secrets.
437
+ - Wildcard routes (`*`) cannot be static.
438
+ - The `static` discovery uses Vite SSR as a control plane only;
439
+ nothing is rendered in Node. The actual capture happens in
440
+ headless Chromium.
441
+
442
+ <!-- docs-lint:allow-legacy-mention -->
443
+ There is no `bake`, no `bake.paths`, no `bake.data`, no
444
+ `bake.revalidate`, no `npm run bake`, no `linkedom` renderer, no
445
+ "meta-shell". Those names refer to a removed system; do not generate
446
+ them. If you see them in older docs, treat them as obsolete.
447
+ <!-- /docs-lint:allow-legacy-mention -->
397
448
 
398
449
  ## SOFT GUIDELINES — recommended, but not critical
399
450
 
@@ -409,19 +460,52 @@ not SSR with hydration and not a Next-style SSG runtime.
409
460
 
410
461
  ## Project structure
411
462
 
463
+ Two official starters target the same Mado runtime:
464
+
412
465
  ```
466
+ # universal starter (default — `mado init my-app`)
467
+ src/
468
+ ├── main.ts
469
+ ├── app.routes.ts
470
+ ├── pages/ ← one *.page.ts per route, light DOM
471
+ ├── components/ ← reusable Web Components (Shadow DOM)
472
+ ├── content/ ← static content (guides, etc.)
473
+ └── styles/
474
+
475
+ # modular starter (`mado init my-app --starter modular`)
413
476
  src/
414
- ├── main.ts ← entry: mount to #app
415
- ├── app.routes.ts ← app map, exports `manifest` + default routes(...)
416
- ├── layouts/ ← app-zone layout modules (`page({ child })`)
417
- ├── shared/ ← ui, http, lib, styles
418
- └── modules/ ← bounded contexts with pages/data/api/services
477
+ ├── main.ts
478
+ ├── app.routes.ts
479
+ ├── layouts/ stateless app-zone shells (`page({ child })`)
480
+ ├── shared/ ← ui, http, lib, styles
481
+ └── modules/ ← bounded contexts with pages/data/api/services
419
482
  ```
420
483
 
484
+ The modular starter ships a dev-only mock API in `vite.config.ts`
485
+ (`/api/auth/*`, `/api/billing/*`). Disable with `MADO_MOCK_API=0`
486
+ or remove the `devApiMock()` plugin before pointing at a real backend.
487
+
488
+ ## Internal links — always `routeUrl()`
489
+
490
+ Vite's `base` flows automatically into `appBase` and `routeUrl()`. App
491
+ code MUST use `routeUrl()` for every internal anchor so the URL stays
492
+ correct under `/`, `/mado/` or any sub-path deployment, and MUST opt
493
+ in with `data-link` for SPA navigation:
494
+
495
+ ```ts
496
+ import { routeUrl } from "@madojs/mado";
497
+
498
+ html`<a data-link href=${routeUrl("/users/42")}>User</a>`;
499
+ html`<a data-link href=${routeUrl("/")}>Home</a>`; // → "/mado/" under base
500
+ ```
501
+
502
+ `navigate("/users/42")` for programmatic navigation. Both accept route
503
+ paths (no base) and apply the active base internally.
504
+
421
505
  ## App architecture for LLM
422
506
 
423
507
  When generating an app, prefer the blessed production shape from
424
- `docs/en/10-app-architecture.md` and the `starters/default/` example:
508
+ `docs/en/16-app-architecture.md` and the `starters/default/` example:
425
509
 
426
510
  - `src/main.ts` mounts `routesApi.view` and imports only global styles,
427
511
  providers, and tiny shared components.
@@ -440,18 +524,18 @@ When generating an app, prefer the blessed production shape from
440
524
 
441
525
  | Question | File |
442
526
  | -------------------------------- | -------------------------------- |
443
- | How does reactivity work? | `src/signal.ts` (283 lines) |
527
+ | How does reactivity work? | `src/signal.ts` |
444
528
  | How are templates parsed? | `src/html/` |
445
529
  | How does the router work? | `src/router/` |
446
- | How does resource + cache work? | `src/resource.ts` (297 lines) |
447
- | How do forms work? | `src/forms.ts` (212 lines) |
448
- | How should an app be structured? | `docs/en/10-app-architecture.md` |
449
- | How should errors be handled? | `docs/en/15-error-handling.md` |
450
- | How should bake be used? | `docs/en/16-bake-cookbook.md` |
451
- | What API is stable? | `docs/en/18-api-freeze-map.md` |
452
- | What ordering is guaranteed? | `docs/en/19-reactivity-ordering.md` |
453
- | What does v1 stability mean? | `docs/en/20-v1-stability.md` |
454
- | When something goes wrong | `docs/en/07-llm-pitfalls.md` |
530
+ | How does resource + cache work? | `src/resource.ts` |
531
+ | How do forms work? | `src/forms.ts` |
532
+ | How should an app be structured? | `docs/en/16-app-architecture.md` |
533
+ | How should errors be handled? | `docs/en/21-error-handling.md` |
534
+ | How should static snapshots be used? | `docs/en/15-static-snapshots.md` / `docs/en/23-cookbook.md` |
535
+ | What API is stable? | `docs/en/30-api-freeze-map.md` |
536
+ | What ordering is guaranteed? | `docs/en/31-reactivity-ordering.md` |
537
+ | What does v1 stability mean? | `docs/en/32-v1-stability.md` |
538
+ | When something goes wrong | `docs/en/40-llm-guide.md` |
455
539
 
456
540
  ## Before committing
457
541
 
package/CHANGELOG.md CHANGED
@@ -1,6 +1,221 @@
1
1
  # Changelog
2
2
 
3
- ## Unreleased
3
+ ## 0.13.0 - 2026-07-11
4
+
5
+ The final planned pre-v1 breaking release hardens ownership and freezes the
6
+ small platform-first API.
7
+
8
+ ### Breaking
9
+
10
+ - Forms now use `useForm({ initial, validate? })`; native controls and
11
+ `ValidityState` own constraints. The schema and field-array APIs are removed.
12
+ - The root surface drops `lazy`, `list` and accidental low-level exports. The
13
+ only public subpaths are the package root, `/vite` and `/devtools.js`.
14
+ - `page.load` is synchronous and returns a value or `Resource`; Promises are
15
+ rejected with a targeted diagnostic.
16
+
17
+ ### Added
18
+
19
+ - `render()` returns a disposer and public `unmount(container)` releases owned
20
+ bindings, events, effects and nested templates.
21
+ - Structured browser and CLI diagnostics, including JSON CLI output, log-level
22
+ controls and `NO_COLOR` support.
23
+ - A development-only Shadow DOM devtools overlay with reactivity, component,
24
+ router/data and timeline/error views, plus an exported controller.
25
+ - The Web Components `context-request` protocol with subscriptions and
26
+ lifecycle cleanup.
27
+
28
+ ### Fixed
29
+
30
+ - Destructive output paths are realpath-checked and cleaned only when owned by
31
+ a `.mado-output` sentinel.
32
+ - JSON-LD/static seed serialization escapes script-breaking input.
33
+ - Effect, component, render and navigation teardown is transactional and
34
+ idempotent, including initial failures and same-tick DOM moves.
35
+ - Route literals are escaped, template markers are opaque and deterministic,
36
+ unsupported self-closing/template-child shapes fail early.
37
+ - Resource cache identity includes the fetcher; `staleTime: 0`, expiry,
38
+ invalidation, refresh and concurrent mutation generations have defined
39
+ semantics. Persisted signal disposal no longer deletes storage implicitly.
40
+ - Static capture blocks undeclared external requests, preserves form/focus
41
+ takeover state, runs bounded route capture and emits portable build metadata.
42
+ - `mado build` and published route discovery now feed the standalone static
43
+ pipeline correctly.
44
+
45
+ ### Tooling and release
46
+
47
+ - Framework/default starter use TypeScript 7; the ESLint modular starter stays
48
+ on TypeScript 6. Node 22.12+ and Vite 8 are the supported baseline.
49
+ - Lightning CSS was removed from starters in favour of Vite's standard CSS
50
+ pipeline.
51
+ - Reproducible tarballs, inline source maps, API golden files, compiled docs
52
+ snippets and a single `verify:release` gate were added.
53
+ - CI covers Node 22/24, Chromium/Firefox/WebKit modular flows and Windows
54
+ package smoke. Runtime and devtools bundles have separate size budgets.
55
+ - Windows package smoke invokes `npm-cli.js` through the active `node.exe`
56
+ instead of relying on `npm`/`npx` command shims, and launches preview
57
+ directly so CI does not leak a nested process tree.
58
+
59
+ See [the migration guide](./docs/en/33-migration-0.12-0.13.md).
60
+
61
+ ## 0.12.0 - 2026-06-24
62
+
63
+ ### Stable polish
64
+
65
+ Two rounds of post-rc polish for the 0.12.0 cut:
66
+
67
+ #### Pre-merge fixes (carried over from the rc.1 review)
68
+
69
+ - **Router base/prefetch.** `routeUrl()` on `"/"` and hover-prefetch
70
+ on Vite `base` deployments now resolve correctly under any sub-path
71
+ (`/`, `/mado/`, `/admin/`).
72
+ - **`mado static` cleanup.** No more race between `process.exit` and
73
+ capture; canonical `<link>` is stripped on SPA navigation into pages
74
+ that don't declare their own head metadata.
75
+ - **Discovery.** `mado static` no longer bypasses `fatal()` when
76
+ Vite SSR import fails; failures abort the snapshot.
77
+ - **Modular starter.** All internal anchors flow through
78
+ `routeUrl()` + `data-link`; generators are context-aware and
79
+ refuse to overwrite existing files.
80
+ - **`package:smoke`.** Now exercises both the default and modular
81
+ starters end to end.
82
+ - **Release publishing.** `next` versions stay on the `next`
83
+ dist-tag; `latest` is reserved for stable cuts. The release and
84
+ weekly workflows install a pinned Playwright Chromium so static
85
+ snapshots never silently skip on CI.
86
+ - **`mado preview`.** Prints the active base URL so users browsing
87
+ under a sub-path see the right entrypoint.
88
+ - **`TODO.md` / `CONTRIBUTING.md` / `package.json#files`** trimmed
89
+ to match the post-rc reality.
90
+
91
+ #### Documentation reorganisation
92
+
93
+ `docs/en/` was rewritten so users (and LLMs) get one happy path:
94
+ **"don't think `shadow: true` vs `shadow: false`; pick `page()` for
95
+ URLs and `component()` for reusable widgets."**
96
+
97
+ - **New flagship doc** `docs/en/10-pages-and-components.md` —
98
+ "the one rule": `page()` for routes, `component()` for reusable
99
+ `<x-tag>`s. Anti-patterns + decision table + `{ shadow: false }`
100
+ escape hatch.
101
+ - **New numbering** groups docs into Start here / Concepts /
102
+ Production / Reference / Meta. Migration map for stale links is in
103
+ `docs/en/README.md`.
104
+ - **Consolidated pages** —
105
+ `11-templates-and-signals.md` (NEW), `12-routing.md` (merges old
106
+ routing + layouts), `13-data.md` (merges old data + auth/api),
107
+ `14-forms.md` (merges old forms + Shadow-DOM forms),
108
+ `15-static-snapshots.md`, `16-app-architecture.md` (merges old
109
+ project-layout), `01-quickstart.md` (merges old IDE-setup),
110
+ `40-llm-guide.md` (merges old pitfalls + zero-history test).
111
+ - **Deleted** `docs/fr`, `docs/uk`, `docs/ru` — English-only since
112
+ v0.12. Several legacy `docs/en/*` files were removed; their
113
+ content lives in the consolidated pages.
114
+ - **Truth pass on retained prose.** Killed obsolete claims:
115
+ no more "tsc-only", "no bundler", "SSE reload", "tsc → browser",
116
+ "edge prerender", "import maps". Vite is consistently named as
117
+ the canonical transport.
118
+ - **`scripts/docs-lint.mjs`** now also blocks the obsolete vocabulary
119
+ above and any links to renamed `docs/en/*` filenames in active
120
+ docs; the migration table in `docs/en/README.md` is wrapped in a
121
+ `docs-lint:allow-legacy-mention` block.
122
+
123
+ ## 0.12.0-rc.1 - 2026-06-22
124
+
125
+ The unified pre-merge release. Mado is no longer "a calm browser-native
126
+ SPA framework for internal tools"; it becomes **"a calm native-first
127
+ web framework for sites and apps"** with one component model end to end.
128
+ The full plan is preserved as
129
+ [ADR 0001 — Browser-rendered static snapshots](./docs/architecture/adr/0001-browser-static-snapshots.md).
130
+
131
+ ### Positioning
132
+
133
+ - New tagline: **One component model. One page model. One release command.**
134
+ - README, `package.json` (description + keywords), CLI help and starter
135
+ READMEs all updated to the sites-and-apps positioning.
136
+ - `MADO_UNIFIED_PRE_MERGE_PLAN.MD` moved to
137
+ `docs/architecture/adr/0001-browser-static-snapshots.md`.
138
+
139
+ ### Added
140
+
141
+ - **`src/router/base.ts`** — single source of truth for the Vite base.
142
+ Exports `appBase`, `normalizeBase`, `stripBase`, `withBase` and the
143
+ new public `routeUrl()` helper. The runtime reads
144
+ `import.meta.env.BASE_URL` once and exposes it through these helpers
145
+ so every internal link is base-aware without any application
146
+ configuration.
147
+ - **Production-served snapshot → live takeover E2E gate.**
148
+ `test/static/dsd-takeover.test.mjs` now scaffolds a real app, runs
149
+ `mado release`, hosts it through `mado preview` and asserts the
150
+ takeover contract through headless Chromium with strict
151
+ no-`.catch()` assertions.
152
+ - **Base-path fixture.** `test/static/base-path.test.mjs` proves the
153
+ whole `/mado/` deployment shape end to end: build, sitemap, capture,
154
+ preview redirects, SPA fallback, runtime stripBase/withBase.
155
+ - **Canonical / `og:url` auto-fallback.** When a page does not declare
156
+ either, the snapshot pipeline derives an absolute
157
+ `site + base + pathname` URL, deduplicates duplicates and rejects
158
+ localhost / capture-origin values.
159
+ - **Strict `JsonValue` validator** with path-aware errors. Date / Map /
160
+ Set / class instances / undefined / NaN / Infinity / cycles all fail
161
+ the build with the exact JSON path that broke
162
+ (`[mado:static] /products/keyboard: seed.product.createdAt is Date`).
163
+ - **Universal default starter** (`mado init my-app`). ~15 source
164
+ files, no backend required, demonstrates one Shadow Component shared
165
+ between a static landing page and a live SPA route.
166
+ - **Modular starter preserved** (`mado init my-app --starter modular`)
167
+ as the long-lived business-application reference architecture.
168
+ - **HTTP policy documented** in `scripts/static/browser.mjs`: fatal
169
+ vs ignored vs quality-hint classes are explicit, with bounded
170
+ timeouts for fonts and paint frames.
171
+ - **`scripts/docs-lint.mjs`** refuses the old vocabulary in current
172
+ docs (page.bake, mado bake, out/baked, "No Vite required",
173
+ "internal tools only") while still allowing it in migration guides
174
+ and ADRs.
175
+ - **Required CI gate** `.github/workflows/ci.yml → static-snapshot`
176
+ installs Playwright-managed Chromium with
177
+ `npx playwright install --with-deps chromium` and runs the static
178
+ tests under `MADO_REQUIRE_BROWSER=1` so they cannot silently skip.
179
+
180
+ ### Changed (breaking)
181
+
182
+ - **`mado build`** in app contexts now performs a Vite production
183
+ build of the deployable SPA (`vite build`). Inside the framework
184
+ repository it still calls `tsc`. The internal tsc compile is
185
+ exposed via `npm run build` in the repo. Use `mado typecheck` if
186
+ you only wanted `tsc --noEmit`.
187
+ - **`out/_mado/build.json`** is dropped from the final release
188
+ artifact. It is internal CLI plumbing emitted by the
189
+ `@madojs/mado/vite` plugin so `mado static` and `mado preview` can
190
+ read the resolved Vite base/site without parsing `vite.config.ts`.
191
+ `mado preview` now derives the base from the build bridge OR from
192
+ the asset prefix in `out/index.html`, so the preview works on the
193
+ shipped artifact.
194
+ - **Static output staging.** `out/_mado/spa.html` is no longer touched
195
+ until every static route captures cleanly; a failure mid-pipeline
196
+ leaves the previous deployment intact. `cleanupTemp()` always runs
197
+ in `finally`.
198
+ - **`whenStable()` phase-bounded.** The runtime now waits for
199
+ routeReady (cap: 15s) and tracked resources (cap: 15s) separately
200
+ so timeout diagnostics name the failing phase. Fonts and paint
201
+ frames are best-effort with bounded timeouts (5s / 1s); on timeout
202
+ the snapshot proceeds with a diagnostic instead of failing.
203
+ - **Browser launch order.** `chromium.launch()` (Playwright-managed)
204
+ is tried *before* `channel: "chrome"` so CI determinism does not
205
+ depend on whatever branded Chrome happens to be installed.
206
+
207
+ ### Migration
208
+
209
+ | Before | After |
210
+ |---|---|
211
+ | `page.bake` | `page.static` |
212
+ | `mado bake` | `mado static` |
213
+ | `out/baked/...` | `out/<route>/index.html` |
214
+ | `#bake` data | `data-mado-static-data` script |
215
+ | `shadow: false` for SEO | open Shadow DOM (snapshotted as DSD) |
216
+ | `site` was optional | required for any `static` route |
217
+ | Vite plugin optional | canonical transport |
218
+ | `mado build` ≈ `tsc` | `mado build` ≈ `vite build` |
4
219
 
5
220
  ## 0.11.1 - 2026-06-21
6
221