@madojs/mado 0.8.0 → 0.10.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 (83) hide show
  1. package/AGENTS.md +81 -4
  2. package/CHANGELOG.md +202 -1
  3. package/README.md +184 -242
  4. package/ROADMAP.md +174 -79
  5. package/TODO.md +8 -5
  6. package/dist/src/component.d.ts +2 -12
  7. package/dist/src/component.js +30 -29
  8. package/dist/src/component.js.map +1 -1
  9. package/dist/src/diagnostics.d.ts +0 -4
  10. package/dist/src/diagnostics.js +1 -0
  11. package/dist/src/diagnostics.js.map +1 -1
  12. package/dist/src/forms.js +17 -0
  13. package/dist/src/forms.js.map +1 -1
  14. package/dist/src/html/bindings.js +35 -3
  15. package/dist/src/html/bindings.js.map +1 -1
  16. package/dist/src/html/parser.js +60 -3
  17. package/dist/src/html/parser.js.map +1 -1
  18. package/dist/src/lifecycle.js +18 -0
  19. package/dist/src/lifecycle.js.map +1 -1
  20. package/dist/src/persisted.js +43 -9
  21. package/dist/src/persisted.js.map +1 -1
  22. package/dist/src/resource.d.ts +13 -6
  23. package/dist/src/resource.js +83 -16
  24. package/dist/src/resource.js.map +1 -1
  25. package/dist/src/router/manifest.d.ts +0 -3
  26. package/dist/src/router/manifest.js +23 -2
  27. package/dist/src/router/manifest.js.map +1 -1
  28. package/dist/src/router/navigation.js +56 -2
  29. package/dist/src/router/navigation.js.map +1 -1
  30. package/dist/src/router.d.ts +1 -1
  31. package/dist/src/router.js +1 -1
  32. package/dist/src/router.js.map +1 -1
  33. package/dist/src/signal.d.ts +0 -4
  34. package/dist/src/signal.js +56 -7
  35. package/dist/src/signal.js.map +1 -1
  36. package/docs/en/00-the-mado-way.md +23 -12
  37. package/docs/en/03-static-bake.md +1 -2
  38. package/docs/en/05-why-mado.md +78 -68
  39. package/docs/en/06-for-backenders.md +80 -55
  40. package/docs/en/07-llm-pitfalls.md +101 -0
  41. package/docs/en/08-llm-zero-history-test.md +5 -0
  42. package/docs/en/18-api-freeze-map.md +63 -0
  43. package/docs/en/19-reactivity-ordering.md +93 -0
  44. package/docs/en/20-v1-stability.md +83 -0
  45. package/docs/en/README.md +3 -0
  46. package/docs/fr/00-the-mado-way.md +25 -13
  47. package/docs/fr/03-static-bake.md +1 -2
  48. package/docs/fr/06-for-backenders.md +6 -0
  49. package/docs/fr/07-llm-pitfalls.md +2 -0
  50. package/docs/fr/08-llm-zero-history-test.md +5 -0
  51. package/docs/fr/18-api-freeze-map.md +63 -0
  52. package/docs/fr/19-reactivity-ordering.md +97 -0
  53. package/docs/fr/20-v1-stability.md +88 -0
  54. package/docs/fr/README.md +3 -0
  55. package/docs/ru/00-the-mado-way.md +24 -11
  56. package/docs/ru/03-static-bake.md +2 -3
  57. package/docs/ru/06-for-backenders.md +6 -0
  58. package/docs/ru/07-llm-pitfalls.md +2 -0
  59. package/docs/ru/08-llm-zero-history-test.md +5 -0
  60. package/docs/ru/18-api-freeze-map.md +62 -0
  61. package/docs/ru/19-reactivity-ordering.md +95 -0
  62. package/docs/ru/20-v1-stability.md +82 -0
  63. package/docs/ru/README.md +3 -0
  64. package/docs/uk/00-the-mado-way.md +3 -1
  65. package/docs/uk/06-for-backenders.md +5 -0
  66. package/docs/uk/07-llm-pitfalls.md +2 -0
  67. package/docs/uk/08-llm-zero-history-test.md +5 -0
  68. package/docs/uk/18-api-freeze-map.md +61 -0
  69. package/docs/uk/19-reactivity-ordering.md +95 -0
  70. package/docs/uk/20-v1-stability.md +83 -0
  71. package/docs/uk/README.md +3 -0
  72. package/llms.txt +63 -7
  73. package/package.json +10 -5
  74. package/scripts/bake.mjs +0 -1
  75. package/scripts/bundle.mjs +6 -6
  76. package/scripts/cli.mjs +17 -0
  77. package/scripts/llm-zero-history-smoke.mjs +93 -0
  78. package/scripts/new.mjs +1 -1
  79. package/scripts/package-smoke.mjs +74 -0
  80. package/scripts/size-budget.mjs +88 -0
  81. package/starters/admin/package.json +2 -2
  82. package/starters/crud/package.json +2 -2
  83. package/starters/minimal/package.json +2 -2
@@ -0,0 +1,88 @@
1
+ # Stabilité v1
2
+
3
+ > Ce que Mado promet après v1, et ce qui reste libre d'évoluer.
4
+
5
+ Mado v1 signifie que le contrat public côté application est assez stable pour
6
+ de vraies applications métier. Cela ne veut pas dire que chaque fichier interne,
7
+ octet généré, starter copy ou diagnostic string est gelé pour toujours.
8
+
9
+ À lire avec :
10
+
11
+ - [Carte de gel de l'API](./18-api-freeze-map.md)
12
+ - [Ordre de la réactivité](./19-reactivity-ordering.md)
13
+
14
+ ## Stable sous SemVer
15
+
16
+ Après v1, Mado considère comme protégés par SemVer :
17
+
18
+ - Les exports publics de `@madojs/mado`.
19
+ - Les types TypeScript publics exportés depuis `@madojs/mado`.
20
+ - Le subpath side-effect `@madojs/mado/devtools.js`.
21
+ - La syntaxe de template binding : child `${}`, `@event`, `.prop`,
22
+ `?boolean`, attribute bindings, directives et `each()`.
23
+ - Les semantics des signals documentées dans le guide d'ordre de réactivité.
24
+ - Les semantics du lifecycle composant : setup une fois par connection
25
+ lifetime, teardown différé pour les same-tick moves, cleanup via
26
+ `ctx.onDispose`.
27
+ - Les contrats router/page/resource/form documentés dans les docs anglaises.
28
+ - Les noms de commandes CLI et leur intention générale (`build`, `dev`,
29
+ `release`, `bake`, `bundle`, `preview`, `init`, `new`).
30
+
31
+ Casser cela nécessite une version majeure.
32
+
33
+ ## Autorisé en minor releases
34
+
35
+ Les minor releases peuvent ajouter :
36
+
37
+ - De nouveaux root exports.
38
+ - De nouvelles options sur des API existantes.
39
+ - De nouveaux diagnostics et warnings.
40
+ - De nouveaux starters, examples, docs et flags CLI.
41
+ - Des améliorations de performance et des rewrites internes.
42
+
43
+ Une minor release ne devrait pas forcer les apps correctes existantes à changer
44
+ leur code.
45
+
46
+ ## Autorisé en patch releases
47
+
48
+ Les patch releases peuvent corriger des bugs, durcir les diagnostics, améliorer
49
+ les docs et faire des changements d'implémentation compatibles. Un patch peut
50
+ changer le timing seulement si l'ancien timing était un bug non documenté et
51
+ que le changement conserve le contrat d'ordre de réactivité.
52
+
53
+ ## Non stable
54
+
55
+ Ne sont volontairement pas protégés par SemVer :
56
+
57
+ - Les subpaths internes du package autres que `@madojs/mado/devtools.js`.
58
+ - Les fichiers sous `src/`, `dist/src/` et les frontières de modules
59
+ d'implémentation.
60
+ - `_testHooks`, internals de diagnostics et warning codes.
61
+ - Le JavaScript exact généré, les noms de chunks, le contenu sourcemap et le
62
+ byte layout du bundle.
63
+ - Les structures internes du parser, des bindings, du routeur et du cache
64
+ resource.
65
+ - Le texte visuel et les données de démonstration des starters.
66
+
67
+ Les apps ne doivent pas importer de fichiers internes ni vérifier l'output exact
68
+ du bundle.
69
+
70
+ ## Bundle et output de release
71
+
72
+ Mado gardera un size budget et des tests de release déterministe, mais la
73
+ stabilité v1 ne fige pas l'output du bundler octet par octet. Les hashes,
74
+ frontières de chunks et noms d'assets générés peuvent changer tant que le
75
+ contrat de déploiement documenté continue de fonctionner.
76
+
77
+ ## Si une release vous casse
78
+
79
+ Si une mise à jour casse du code qui utilise seulement les exports publics et le
80
+ comportement documenté, traitez-le comme un bug. Ouvrez une issue avec :
81
+
82
+ - la version de Mado avant et après ;
83
+ - l'API publique impliquée ;
84
+ - une reproduction minimale ;
85
+ - si la casse concerne le runtime, les types TypeScript, l'output CLI ou les docs.
86
+
87
+ Si la casse dépend d'un subpath interne ou de l'output généré exact, cela peut
88
+ quand même valoir un rapport, mais ce n'est pas considéré comme une casse SemVer.
package/docs/fr/README.md CHANGED
@@ -22,3 +22,6 @@ Documentation française.
22
22
  | Gestion des erreurs | [15-error-handling.md](./15-error-handling.md) |
23
23
  | Guide de recettes bake | [16-bake-cookbook.md](./16-bake-cookbook.md) |
24
24
  | Shadow DOM + formulaires | [17-shadow-dom-forms.md](./17-shadow-dom-forms.md) |
25
+ | Carte de gel de l'API | [18-api-freeze-map.md](./18-api-freeze-map.md) |
26
+ | Ordre de la réactivité | [19-reactivity-ordering.md](./19-reactivity-ordering.md) |
27
+ | Stabilité v1 | [20-v1-stability.md](./20-v1-stability.md) |
@@ -2,7 +2,11 @@
2
2
 
3
3
  > Один правильный путь. Жёсткие контракты. Никакой магии.
4
4
 
5
- Mado — это не просто фреймворк, это **набор соглашений**. Если ты следуешь им, проект остаётся понятным даже когда в нём 200 экранов и 5 разработчиков. Если нарушаешь — типы и линтер скажут об этом сразу.
5
+ Mado — фреймворк для команд, которые строят админки, внутренние инструменты
6
+ и бизнес-SPA — приложения, которые должны быть просты в разработке и скучны
7
+ в поддержке. Для этого он задаёт **набор соглашений**. Если ты следуешь им,
8
+ проект остаётся понятным даже когда в нём 200 экранов и 5 разработчиков. Если
9
+ нарушаешь — типы и линтер скажут об этом сразу.
6
10
 
7
11
  ## Принципы
8
12
 
@@ -32,13 +36,21 @@ src/
32
36
 
33
37
  ```ts
34
38
  // src/components/user-card.ts
35
- import { component, html, css } from '@madojs/mado';
36
-
37
- component('x-user-card', () => {
38
- return () => html`<div class="card"><slot/></div>`;
39
- }, {
40
- styles: css`.card { padding: 1rem; }`,
41
- });
39
+ import { component, html, css } from "@madojs/mado";
40
+
41
+ component(
42
+ "x-user-card",
43
+ () => {
44
+ return () => html`<div class="card"><slot /></div>`;
45
+ },
46
+ {
47
+ styles: css`
48
+ .card {
49
+ padding: 1rem;
50
+ }
51
+ `,
52
+ },
53
+ );
42
54
  ```
43
55
 
44
56
  Импорт `import './components/user-card.js'` **регистрирует** компонент через `customElements.define`. Это side-effect. Где компонент нужен — там и импортируем.
@@ -52,7 +64,7 @@ component('x-user-card', () => {
52
64
  const user = resource(() => `/api/users/${id()}`, jsonFetcher());
53
65
 
54
66
  // запись → mutation
55
- const save = mutation(api.save, { invalidates: ['/api/users*'] });
67
+ const save = mutation(api.save, { invalidates: ["/api/users*"] });
56
68
  ```
57
69
 
58
70
  Это даёт кеш, отмену, обработку ошибок, авто-инвалидацию.
@@ -61,11 +73,11 @@ const save = mutation(api.save, { invalidates: ['/api/users*'] });
61
73
 
62
74
  ```ts
63
75
  // src/pages/user-profile.ts
64
- import { page, html, resource, jsonFetcher } from '@madojs/mado';
76
+ import { page, html, resource, jsonFetcher } from "@madojs/mado";
65
77
 
66
78
  export default page({
67
79
  title: ({ id }) => `User #${id}`,
68
- view: ({ params }) => html`...`,
80
+ view: ({ params }) => html`...`,
69
81
  });
70
82
  ```
71
83
 
@@ -87,6 +99,7 @@ export default page({
87
99
  ## Когда сомневаешься
88
100
 
89
101
  Если ты задаёшься вопросом "а как тут лучше?" — это сигнал, что:
102
+
90
103
  1. Либо есть встроенный хелпер, который ты не знаешь (загляни в `docs/`).
91
104
  2. Либо это новая ситуация — её надо обсудить и **зафиксировать** в этом документе как ещё одно соглашение.
92
105
 
@@ -129,7 +129,6 @@ out/
129
129
  {"@context":"https://schema.org","@type":"Product","..."}
130
130
  </script>
131
131
  <meta name="bake-revalidate" content="3600" data-mado-head="baked">
132
- <meta name="bake-stamp" content="1234567890" data-mado-head="baked">
133
132
  </head>
134
133
  <body>
135
134
  <div id="app">
@@ -212,7 +211,7 @@ export default page<{ slug: string }>({
212
211
 
213
212
  ## Revalidate / CDN
214
213
 
215
- `bake.revalidate: 3600` пишет в HTML `<meta name="bake-revalidate" content="3600">` и `bake-stamp`. Это **метаданные** — фреймворк сам ничего не перевыпекает. Стратегии:
214
+ `bake.revalidate: 3600` пишет в HTML `<meta name="bake-revalidate" content="3600">`. Это **метаданные** — фреймворк сам ничего не перевыпекает. Стратегии:
216
215
 
217
216
  1. **Простейший вариант**: cron в CI — `npm run bake && rsync out/ origin:/var/www/`.
218
217
  2. **Через CDN** (Cloudflare/Fastly): кладёте HTML с `Cache-Control: max-age=3600`. CDN сам инвалидирует.
@@ -248,4 +247,4 @@ export default page<{ slug: string }>({
248
247
 
249
248
  Если страница **общая для всех пользователей**, имеет **относительно стабильный набор URL'ов** и важен **SEO + первый paint** — добавьте `bake: { paths, data }` и получите статический HTML с meta/JSON-LD/sitemap за миллисекунды. Без node-сервера, без Chrome, без магии.
250
249
 
251
- Если страница персонализирована, или URL'ов миллион, или контент меняется в реальном времени — `bake` не ваш инструмент. Оставляйте SPA или подключайте отдельный SSR-фреймворк.
250
+ Если страница персонализирована, или URL'ов миллион, или контент меняется в реальном времени — `bake` не ваш инструмент. Оставляйте SPA или подключайте отдельный SSR-фреймворк.
@@ -150,6 +150,12 @@ await save.run(newUser);
150
150
  // автоматически: user.data() обновится, если совпал glob
151
151
  ```
152
152
 
153
+ Ключи `resource()` — это identity кеша. Включайте endpoint, query params и
154
+ форму данных в ключ: два живых `resource()` с одинаковым ключом разделяют кеш
155
+ и in-flight request. Если один и тот же ключ используется с другим fetcher,
156
+ Mado предупреждает, потому что обычно это значит, что ключ кеша слишком
157
+ широкий.
158
+
153
159
  Если бы такая абстракция была в Go-мире для серверных кешей — мы бы все плакали от счастья.
154
160
 
155
161
  ---
@@ -618,5 +618,7 @@ component("x-input", ({ host, attr }) => {
618
618
  | `@customElement('x')` | `component('x-name', setup)` |
619
619
  | `host.getAttribute('x')` в render | `ctx.attr('x', default)` (реактивно) |
620
620
  | `jsonFetcher()` с авторизацией | `apiFetcher()` (прикрепляет Bearer токен) |
621
+ | `setInterval` в page view | `onDispose(() => clearInterval(id))` |
622
+ | чтение сигнала в async init view() | `untracked(() => cursor())` |
621
623
 
622
624
  Если что-то не подходит из этого списка — открой `src/` и **прочитай 500 строк**. Это серьёзно. Mado специально маленький, чтобы быть читаемым.
@@ -51,6 +51,11 @@
51
51
  Текущая реализация `examples/tickets` не потребовала новых публичных API или
52
52
  runtime-зависимостей.
53
53
 
54
+ CI запускает `npm run llm:smoke` как детерминированный proxy для этой задачи:
55
+ проверяет, что `llms.txt` всё ещё содержит ключевые правила, сверяет
56
+ зафиксированный артефакт `examples/tickets` с нужной Mado API surface и
57
+ failure patterns, затем собирает проект и запускает `test/tickets-smoke.test.mjs`.
58
+
54
59
  Основная болевая точка в документации остается lifecycle: старые примеры могут
55
60
  создать впечатление, что создание `resource()` прямо в `page.view()` допустимо.
56
61
  Пример tickets использует page-level wrapper-компоненты вместо этого, поэтому
@@ -0,0 +1,62 @@
1
+ # Карта заморозки API
2
+
3
+ > Что публично, что внутреннее, и что SemVer будет защищать в v1.
4
+
5
+ Контракт Mado v1 намеренно небольшой. Код приложения импортирует API из корня
6
+ пакета:
7
+
8
+ ```ts
9
+ import { component, html, resource, routes, signal } from "@madojs/mado";
10
+ ```
11
+
12
+ Единственный публичный subpath — side-effect модуль devtools:
13
+
14
+ ```ts
15
+ import "@madojs/mado/devtools.js";
16
+ ```
17
+
18
+ Все остальное под `dist/src/` — деталь реализации, даже если файл виден в
19
+ репозитории.
20
+
21
+ ## Стабильный публичный API
22
+
23
+ Эти имена публичны и будут защищены SemVer после v1:
24
+
25
+ - Reactivity: `signal`, `computed`, `effect`, `untracked`, `batch`,
26
+ `flushSync`.
27
+ - Templates и directives: `html`, `render`, `each`, `list`, `unsafeHTML`,
28
+ `ref`, `classMap`, `styleMap`.
29
+ - Components и CSS: `component`, `css`, `cssVars`.
30
+ - Routing и pages: `routes`, `router`, `page`, `layout`, `nested`,
31
+ `navigate`, `queryParam`, `prefetchPath`.
32
+ - Data: `resource`, `mutation`, `invalidate`, `jsonFetcher`, `HttpError`.
33
+ - Forms: `useForm`.
34
+ - Head и persistence: `applyHead`, `persisted`.
35
+ - Context: `createContext`, `provide`, `inject`.
36
+ - Advanced lifecycle helpers: `createLifecycle`, `runInLifecycle`,
37
+ `getCurrentLifecycle`.
38
+ - Публичные TypeScript-типы, экспортируемые из `@madojs/mado`.
39
+
40
+ ## Внутреннее или нестабильное
41
+
42
+ Это не публичный API:
43
+
44
+ - Package subpaths кроме `@madojs/mado` и `@madojs/mado/devtools.js`.
45
+ - Internals парсера/биндингов: `html/parser.js`, `html/bindings.js`,
46
+ `ChildState`, `EachEntry`.
47
+ - Internals роутера: `router/match.js`, `router/navigation.js`,
48
+ `router/manifest.js`.
49
+ - Diagnostics internals и все `_testHooks`.
50
+ - Точный текст bundle, имена chunks и внутренняя структура файлов.
51
+
52
+ Тесты репозитория могут импортировать внутренние файлы через относительные
53
+ пути `dist/`. Код приложений так делать не должен.
54
+
55
+ ## Что может меняться
56
+
57
+ Patch и minor релизы могут добавлять root exports, опции, diagnostics, docs или
58
+ starter files. Они также могут менять internals, форму bundle и детали
59
+ реализации, если стабильный API и задокументированное поведение остаются
60
+ совместимыми.
61
+
62
+ Ломающие изменения стабильного API требуют major version.
@@ -0,0 +1,95 @@
1
+ # Порядок reactivity
2
+
3
+ > Небольшой набор ordering-гарантий, которые Mado считает публичным поведением.
4
+
5
+ Reactivity в Mado синхронна для чтения и планирует side effects. Цель —
6
+ предсказуемые UI-обновления без большой scheduling-модели.
7
+
8
+ ## Signals
9
+
10
+ `signal(value)` возвращает getter-функцию. `set(next)` меняет значение сразу,
11
+ если `Object.is(previous, next)` не вернул `true`.
12
+
13
+ ```ts
14
+ const count = signal(0);
15
+ count.set(1);
16
+ count(); // 1, сразу
17
+ ```
18
+
19
+ `computed` помечается до запуска effects, поэтому effect, читающий computed,
20
+ видит актуальные dependencies, а не старый кеш.
21
+
22
+ ## Effects
23
+
24
+ `effect(fn)` запускается один раз сразу. Последующие изменения dependencies
25
+ планируют один запуск effect в microtask. В тестах можно вызвать `flushSync()`,
26
+ чтобы синхронно очистить очередь.
27
+
28
+ Если effect возвращает cleanup-функцию, Mado запускает ее перед следующим
29
+ запуском effect и еще раз при вызове disposer.
30
+
31
+ ```ts
32
+ const stop = effect(() => {
33
+ const id = setInterval(tick, 1000);
34
+ return () => clearInterval(id);
35
+ });
36
+
37
+ stop();
38
+ ```
39
+
40
+ В компонентах и pages для unmount cleanup предпочитайте `ctx.onDispose()` /
41
+ page `onDispose()`. Cleanup effect — это cleanup между запусками.
42
+
43
+ ## Batch
44
+
45
+ `batch(fn)` группирует записи signals в один subscriber pass. Effects не
46
+ запускаются до выхода из внешнего batch, включая вложенные batches.
47
+
48
+ ```ts
49
+ batch(() => {
50
+ first.set("Ada");
51
+ batch(() => last.set("Lovelace"));
52
+ });
53
+ // effects увидят только финальную пару
54
+ ```
55
+
56
+ Наблюдаемые `computed({ equals })` также сохраняют batch atomicity: они
57
+ пересчитываются один раз после внешнего batch на полностью примененном state.
58
+ Они не должны видеть половинчатый batch вроде `(new x, old y)`.
59
+
60
+ ## DOM updates
61
+
62
+ `render(result, container)` переиспользует существующий template instance, когда
63
+ следующий render имеет те же template strings. Для child bindings, возвращающих
64
+ вложенный `html```, действует то же правило: те же strings обновляются на
65
+ месте, другие strings пересобирают ветку.
66
+
67
+ Это значит, что несвязанные изменения signals не пересоздают `<input>` внутри
68
+ стабильного вложенного template, поэтому focus, DOM state и listeners
69
+ сохраняются.
70
+
71
+ Списки должны использовать `each(items, key, renderItem)`. Keys задают DOM
72
+ identity. Duplicate keys предупреждают в development и получают positional
73
+ suffix, чтобы все элементы все равно отрендерились, но duplicate keys — это
74
+ ошибка данных.
75
+
76
+ ## Teardown компонентов
77
+
78
+ Custom elements могут получить `disconnectedCallback()`, а затем
79
+ `connectedCallback()` во время same-tick move. Mado откладывает teardown
80
+ компонента до microtask и отменяет его при reconnect, поэтому keyed reorders
81
+ сохраняют state компонента. Настоящее удаление все равно запускает cleanup на
82
+ следующей microtask.
83
+
84
+ ## Не гарантируется
85
+
86
+ Mado не гарантирует точное число внутренних scheduler microtasks, порядок
87
+ независимых effects без общих dependencies, форму generated bundle или
88
+ внутреннюю структуру modules. Это детали реализации.
89
+
90
+ Invariant tests для этого контракта:
91
+
92
+ - `test/reactivity-ordering.test.mjs`
93
+ - `test/signal-batch-equals.test.mjs`
94
+ - `test/update-nested-reuse.test.mjs`
95
+ - `test/each-component-state.test.mjs`
@@ -0,0 +1,82 @@
1
+ # Стабильность v1
2
+
3
+ > Что Mado обещает после v1, и что остается свободным для развития.
4
+
5
+ Mado v1 означает, что публичный app-facing contract достаточно стабилен для
6
+ реальных business apps. Это не значит, что каждый внутренний файл, generated
7
+ byte, starter copy или diagnostic string заморожены навсегда.
8
+
9
+ Читайте вместе с:
10
+
11
+ - [Карта заморозки API](./18-api-freeze-map.md)
12
+ - [Порядок reactivity](./19-reactivity-ordering.md)
13
+
14
+ ## Стабильно под SemVer
15
+
16
+ После v1 Mado считает SemVer-protected:
17
+
18
+ - Public exports из `@madojs/mado`.
19
+ - Public TypeScript types из `@madojs/mado`.
20
+ - Side-effect subpath `@madojs/mado/devtools.js`.
21
+ - Template binding syntax: child `${}`, `@event`, `.prop`, `?boolean`,
22
+ attribute bindings, directives и `each()`.
23
+ - Signal semantics, описанные в reactivity ordering guide.
24
+ - Component lifecycle semantics: setup один раз за connection lifetime,
25
+ deferred teardown для same-tick moves, cleanup через `ctx.onDispose`.
26
+ - Router/page/resource/form contracts, описанные в English docs.
27
+ - Имена CLI commands и широкий смысл команд (`build`, `dev`, `release`,
28
+ `bake`, `bundle`, `preview`, `init`, `new`).
29
+
30
+ Ломать это можно только в major version.
31
+
32
+ ## Разрешено в minor releases
33
+
34
+ Minor releases могут добавлять:
35
+
36
+ - New root exports.
37
+ - New options на существующих API.
38
+ - New diagnostics и warnings.
39
+ - New starters, examples, docs и CLI flags.
40
+ - Performance improvements и внутренние rewrites.
41
+
42
+ Minor release не должен требовать изменений в уже корректных apps.
43
+
44
+ ## Разрешено в patch releases
45
+
46
+ Patch releases могут исправлять bugs, ужесточать diagnostics, улучшать docs и
47
+ делать совместимые implementation changes. Patch может изменить timing только
48
+ когда старый timing был незадокументированным bug и новое поведение сохраняет
49
+ reactivity ordering contract.
50
+
51
+ ## Нестабильно
52
+
53
+ Это намеренно не защищено SemVer:
54
+
55
+ - Internal package subpaths кроме `@madojs/mado/devtools.js`.
56
+ - Файлы под `src/`, `dist/src/` и implementation module boundaries.
57
+ - `_testHooks`, diagnostics internals и warning codes.
58
+ - Точный JavaScript output, chunk names, sourcemap content и bundle byte layout.
59
+ - Internal parser, binding, router и resource cache data structures.
60
+ - Visual copy и demo data в starters.
61
+
62
+ Apps не должны импортировать internal files или проверять точный bundle output.
63
+
64
+ ## Bundle и release output
65
+
66
+ Mado держит size budget и deterministic release tests, но v1 stability не
67
+ замораживает byte-for-byte bundler output. Hashes, chunk boundaries и asset
68
+ names могут меняться, если задокументированный deployment contract продолжает
69
+ работать.
70
+
71
+ ## Если релиз вас сломал
72
+
73
+ Если update ломает код, который использует только public exports и
74
+ задокументированное поведение, считайте это bug. Откройте issue и укажите:
75
+
76
+ - версию Mado до и после;
77
+ - задействованный public API;
78
+ - минимальную репродукцию;
79
+ - это runtime behaviour, TypeScript types, CLI output или docs.
80
+
81
+ Если поломка зависит от internal subpath или точного generated output, ее все
82
+ равно можно зарепортить, но это не считается SemVer break.
package/docs/ru/README.md CHANGED
@@ -20,3 +20,6 @@
20
20
  | Обработка ошибок | [15-error-handling.md](./15-error-handling.md) |
21
21
  | Рецепты bake | [16-bake-cookbook.md](./16-bake-cookbook.md) |
22
22
  | Shadow DOM + формы | [17-shadow-dom-forms.md](./17-shadow-dom-forms.md) |
23
+ | Карта заморозки API | [18-api-freeze-map.md](./18-api-freeze-map.md) |
24
+ | Порядок reactivity | [19-reactivity-ordering.md](./19-reactivity-ordering.md) |
25
+ | Стабильность v1 | [20-v1-stability.md](./20-v1-stability.md) |
@@ -2,7 +2,9 @@
2
2
 
3
3
  > Один зрозумілий шлях. Жорсткі контракти. Мінімум магії.
4
4
 
5
- Mado — це не лише набір API, а набір домовленостей. Якщо їх дотримуватись,
5
+ Mado — фреймворк для команд, що будують адмін-панелі, внутрішні інструменти
6
+ та бізнес-SPA — застосунки, які мають бути простими у розробці та нудними в
7
+ підтримці. Для цього він задає **набір домовленостей**. Якщо їх дотримуватись,
6
8
  проєкт залишається читабельним навіть тоді, коли в ньому десятки сторінок і
7
9
  кілька розробників.
8
10
 
@@ -26,6 +26,11 @@ const save = mutation(api.saveUser, {
26
26
  });
27
27
  ```
28
28
 
29
+ Ключі `resource()` — це identity кешу. Додавайте endpoint, query params і форму
30
+ даних у ключ: два живі `resource()` з однаковим ключем ділять cache та
31
+ in-flight request. Якщо той самий ключ використано з іншим fetcher, Mado
32
+ попереджає, бо зазвичай це означає, що ключ кешу занадто широкий.
33
+
29
34
  ## Форми
30
35
 
31
36
  ```ts
@@ -141,3 +141,5 @@ Object.defineProperty(host, "value", {
141
141
  | `class extends HTMLElement` | `component('x-name', setup)` |
142
142
  | `host.getAttribute('x')` | `ctx.attr('x', default)` |
143
143
  | `jsonFetcher()` з auth | `apiFetcher()` |
144
+ | `setInterval` в page view | `onDispose(() => clearInterval(id))` |
145
+ | читання сигналу в async init | `untracked(() => cursor())` |
@@ -27,5 +27,10 @@ Mado CRUD, не перетворюючи його на React у tagged templates
27
27
  resources, mutations, invalidation, `queryParam`, `computed`, `signal` і
28
28
  keyed lists.
29
29
 
30
+ CI запускає `npm run llm:smoke` як детермінований proxy для цієї задачі:
31
+ перевіряє, що `llms.txt` містить ключові правила, звіряє закомічений артефакт
32
+ `examples/tickets` з потрібною Mado API surface та failure patterns, потім
33
+ збирає проєкт і запускає `test/tickets-smoke.test.mjs`.
34
+
30
35
  Критерій успіху: код виглядає як Mado, а не як React/Vue, переодягнений у
31
36
  template strings.
@@ -0,0 +1,61 @@
1
+ # Карта замороження API
2
+
3
+ > Що є публічним, що внутрішнім, і що SemVer захищатиме у v1.
4
+
5
+ Контракт Mado v1 навмисно невеликий. Код застосунку імпортує API з кореня
6
+ пакета:
7
+
8
+ ```ts
9
+ import { component, html, resource, routes, signal } from "@madojs/mado";
10
+ ```
11
+
12
+ Єдиний публічний subpath — side-effect модуль devtools:
13
+
14
+ ```ts
15
+ import "@madojs/mado/devtools.js";
16
+ ```
17
+
18
+ Усе інше під `dist/src/` — деталь реалізації, навіть якщо файл видно в
19
+ репозиторії.
20
+
21
+ ## Стабільний публічний API
22
+
23
+ Ці імена публічні й захищаються SemVer після v1:
24
+
25
+ - Reactivity: `signal`, `computed`, `effect`, `untracked`, `batch`,
26
+ `flushSync`.
27
+ - Templates і directives: `html`, `render`, `each`, `list`, `unsafeHTML`,
28
+ `ref`, `classMap`, `styleMap`.
29
+ - Components і CSS: `component`, `css`, `cssVars`.
30
+ - Routing і pages: `routes`, `router`, `page`, `layout`, `nested`,
31
+ `navigate`, `queryParam`, `prefetchPath`.
32
+ - Data: `resource`, `mutation`, `invalidate`, `jsonFetcher`, `HttpError`.
33
+ - Forms: `useForm`.
34
+ - Head і persistence: `applyHead`, `persisted`.
35
+ - Context: `createContext`, `provide`, `inject`.
36
+ - Advanced lifecycle helpers: `createLifecycle`, `runInLifecycle`,
37
+ `getCurrentLifecycle`.
38
+ - Публічні TypeScript-типи, експортовані з `@madojs/mado`.
39
+
40
+ ## Внутрішнє або нестабільне
41
+
42
+ Це не публічний API:
43
+
44
+ - Package subpaths крім `@madojs/mado` і `@madojs/mado/devtools.js`.
45
+ - Internals parser/binding: `html/parser.js`, `html/bindings.js`,
46
+ `ChildState`, `EachEntry`.
47
+ - Internals router: `router/match.js`, `router/navigation.js`,
48
+ `router/manifest.js`.
49
+ - Diagnostics internals і всі `_testHooks`.
50
+ - Точний текст bundle, назви chunks і внутрішня структура файлів.
51
+
52
+ Тести репозиторію можуть імпортувати internal files через відносні шляхи
53
+ `dist/`. Код застосунків не повинен цього робити.
54
+
55
+ ## Що може змінюватися
56
+
57
+ Patch і minor releases можуть додавати root exports, options, diagnostics, docs
58
+ або starter files. Вони також можуть змінювати internals, форму bundle і деталі
59
+ реалізації, якщо stable API та задокументована поведінка лишаються сумісними.
60
+
61
+ Breaking changes стабільного API потребують major version.