@craft-ts/mcp 0.7.0-beta.13

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 (33) hide show
  1. package/README.md +71 -0
  2. package/content/agents.md +35 -0
  3. package/content/best-practices.md +79 -0
  4. package/content/docs-index.json +658 -0
  5. package/dist/catalog.d.ts +27 -0
  6. package/dist/catalog.js +67 -0
  7. package/dist/catalog.js.map +1 -0
  8. package/dist/main.d.ts +2 -0
  9. package/dist/main.js +13 -0
  10. package/dist/main.js.map +1 -0
  11. package/dist/mcp-server.d.ts +3 -0
  12. package/dist/mcp-server.js +144 -0
  13. package/dist/mcp-server.js.map +1 -0
  14. package/dist/resources.d.ts +10 -0
  15. package/dist/resources.js +63 -0
  16. package/dist/resources.js.map +1 -0
  17. package/mcp.json +10 -0
  18. package/package.json +62 -0
  19. package/plugin.json +19 -0
  20. package/skills/craft-ts/SKILL.md +43 -0
  21. package/skills/craft-ts-architecture-tests/SKILL.md +110 -0
  22. package/skills/craft-ts-effect-v4/SKILL.md +31 -0
  23. package/skills/craft-ts-routes/SKILL.md +135 -0
  24. package/skills/craft-ts-routes/references/di-checks.md +101 -0
  25. package/skills/craft-ts-routes/references/eslint-workflow.md +52 -0
  26. package/skills/craft-ts-routes/references/pending-and-exceptions.md +93 -0
  27. package/skills/craft-ts-routes/references/scaling-and-pitfalls.md +111 -0
  28. package/skills/craft-ts-service-migration/SKILL.md +86 -0
  29. package/skills/migrate-to-craft-ts/SKILL.md +135 -0
  30. package/skills/translate-spec-to-craft-ts/SKILL.md +86 -0
  31. package/skills/translate-spec-to-craft-ts/references/lexical-map.md +322 -0
  32. package/skills/translate-spec-to-craft-ts/references/pattern-recipes.md +123 -0
  33. package/skills/translate-spec-to-craft-ts/references/project-index.md +52 -0
@@ -0,0 +1,135 @@
1
+ ---
2
+ name: migrate-to-craft-ts
3
+ description: Migrate an Angular application to @craft-ts/core with the craft-migrate codemod, then resolve its manual diagnostics and verify the result. Use when the user asks to migrate an Angular project, services, signals, Signal Forms, dependency injection, HTTP resources, or routes to CraftTS; asks to run craft-migrate; or needs help finishing work left by the migration scripts.
4
+ ---
5
+
6
+ # Migrate To NG Craft
7
+
8
+ Run the deterministic codemods first, then complete semantic migrations that
9
+ cannot be inferred safely. Preserve unrelated user changes.
10
+
11
+ ## Workflow
12
+
13
+ 1. Inspect the repository before modifying it:
14
+ - Read `AGENTS.md`, `CONTEXT.md`, and relevant ADRs when present.
15
+ - Check `git status --short`; do not overwrite existing changes.
16
+ - Locate the application `tsconfig.app.json`, source root, ESLint config,
17
+ tests, and build commands.
18
+ - Read the installed `@craft-ts/core` version and avoid generating APIs that
19
+ version does not expose.
20
+
21
+ 2. Install or build `@craft-ts/dev-tools` only when needed.
22
+
23
+ 3. Preview the complete migration:
24
+
25
+ ```shell
26
+ npx craft-migrate \
27
+ --project path/to/tsconfig.app.json \
28
+ --root path/to/src \
29
+ --dry-run \
30
+ --json craft-migration-report.json
31
+ ```
32
+
33
+ 4. Review diagnostics before writing. Classify them by primitives/forms,
34
+ services/DI, and routes.
35
+
36
+ 5. Apply deterministic changes:
37
+
38
+ ```shell
39
+ npx craft-migrate \
40
+ --project path/to/tsconfig.app.json \
41
+ --root path/to/src \
42
+ --write \
43
+ --json craft-migration-report.json
44
+ ```
45
+
46
+ 6. Complete the manual work described below.
47
+
48
+ 7. Re-run in enforcement mode:
49
+
50
+ ```shell
51
+ npx craft-migrate \
52
+ --project path/to/tsconfig.app.json \
53
+ --root path/to/src \
54
+ --check \
55
+ --fail-on-manual
56
+ ```
57
+
58
+ 8. `craft-migrate --write` scaffolds the baseline architecture suite as its last
59
+ step. If `architecture/` is still missing, load `craft-ts-architecture-tests`
60
+ and offer `craft-migrate-architecture --write`. Do not add an architecture
61
+ rule for each migrated feature.
62
+
63
+ 9. Run targeted tests first, then lint, application type-check, architecture
64
+ tests (`npx nx architecture <app>` or `npx vitest run --config vitest.architecture.config.ts`),
65
+ full tests, and production build. Report command exit codes separately;
66
+ filtered output is not proof that the complete command succeeded.
67
+
68
+ ## Manual Migration Rules
69
+
70
+ ### Signals and forms
71
+
72
+ - Convert Angular `signal` usage to `state`; preserve broad explicit types with
73
+ `value as T satisfies T` when inference would narrow the state incorrectly.
74
+ - Convert Signal Forms to:
75
+
76
+ ```ts
77
+ const { myForm } = state(
78
+ 'myForm',
79
+ initialValue,
80
+ (context) =>
81
+ craftPipe(
82
+ context,
83
+ ({ set, update }) => ({ set, update }),
84
+ insertForm(/* field trees and submit */),
85
+ ),
86
+ )
87
+ ```
88
+
89
+ - Use `insertSelectFormTree` and `insertFormAttributes` for nested fields.
90
+ - Map validators to `cRequired`, `cMaxLength`, and other Craft validators.
91
+ - Capture a parent sub-form state when a child validator depends on a sibling.
92
+ - Convert `validateAsync`/`rxResource` to a tracked `query` plus
93
+ `cAsyncValidate`.
94
+ - Convert `submission.action` to a tracked `mutation` plus `insertFormSubmit`.
95
+ - Represent validation and submit failures with `craftException`.
96
+ - Do not generate `makeFormTreeInsert` solely to migrate a form.
97
+
98
+ ### Services and dependency injection
99
+
100
+ - Author application/domain services with `craftService`.
101
+ - Adapt Angular, framework, and third-party tokens once with `toCraftService`.
102
+ - Use the generated `X()` helper in components and `yield* X(...)` in generators.
103
+ - Use `CraftRouter` directly instead of wrapping Angular Router.
104
+ - Prefer `scope: 'function'` for a dependency used by one function and
105
+ `scope: 'toProvide'` for feature-owned services.
106
+ - Place `provideX(...)` near the route or feature owning the instance.
107
+ - Resolve every generated `CRAFT_IMPLEMENTATION_REQUIRED` companion.
108
+ - Wrap dependent primitives in `yield* track(...)`.
109
+ - Use `query` for reads and `mutation` for writes. Keep mutations with the
110
+ lifecycle owner when moving subscription callbacks would alter semantics.
111
+
112
+ ### Routes
113
+
114
+ - Complete unresolved guards, redirects, lazy collections, inherited
115
+ providers, and dynamic route diagnostics manually.
116
+ - Keep `componentDeps` and file-level `ValidateCascadeRoutesFile` or
117
+ `RouteCheckedDI` checks.
118
+ - Prefer provider names and `ProvidedValues = never` after direct Angular DI is
119
+ removed.
120
+ - Run ESLint fixes to regenerate `GenDeps_*` aliases after dependency changes.
121
+
122
+ ## Verification Checklist
123
+
124
+ - No unreviewed migration diagnostics or migration marker comments remain.
125
+ - No new direct Angular `inject(...)` or application `@Injectable` service was
126
+ introduced.
127
+ - Signal Forms validate conditional and asynchronous fields correctly.
128
+ - Submit success, submit errors, navigation, and store cleanup work.
129
+ - HTTP mutations retain their intended callback and lifecycle behavior.
130
+ - Route pending/error UI and exception exhaustiveness compile.
131
+ - Targeted regression tests cover semantic rewrites.
132
+ - Lint, type-check, architecture tests, tests, and production build all pass.
133
+
134
+ If a diagnostic requires a business decision, stop before guessing and present
135
+ the exact file, diagnostic, available options, and behavioral tradeoff.
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: translate-spec-to-craft-ts
3
+ description: Translate functional specifications, user stories, page requirements, CRUD flows, list/detail screens, filters, pagination, bulk actions, optimistic updates, forms, and Angular feature-store architecture into @craft-ts/core primitives, insertions, store utilities, and source helpers. Use when a request asks which craft-ts utility to choose, or when wording such as "afficher", "liste", "detail", "supprimer", "selection multiple", "pagination", "filtre URL", "formulaire", "recharger en cas d'erreur", or "feature store" must be mapped to `query`, `mutation`, `state`, `queryParams`, `craft*`, form helpers, or entity helpers.
4
+ ---
5
+
6
+ # Translate Spec To Ng Craft
7
+
8
+ ## Objective
9
+
10
+ Translate business wording into concrete `@craft-ts/core` APIs and default compositions.
11
+ Prioritize documented public APIs from the installed `@craft-ts/core` package and
12
+ the published docs (MCP `search_documentation`, or https://ng-angular-stack.github.io/craft/llms.txt).
13
+
14
+ ## Workflow
15
+
16
+ 1. Decompose the spec into:
17
+ - remote reads
18
+ - remote writes
19
+ - local UI state
20
+ - URL state
21
+ - events and triggers
22
+ - forms and validation
23
+ - store boundaries and dependency injection
24
+ 2. Read [references/lexical-map.md](references/lexical-map.md) first.
25
+ 3. Read [references/pattern-recipes.md](references/pattern-recipes.md) when the spec combines several concerns or asks for defaults.
26
+ 4. Read [references/project-index.md](references/project-index.md) when examples or exact local paths are needed.
27
+ 5. Return a concrete mapping, not a generic architecture overview.
28
+
29
+ ## Decision Rules
30
+
31
+ - Match server reads to `query`.
32
+ - Match server writes to `mutation`.
33
+ - Match generic asynchronous client tasks to `asyncProcess`.
34
+ - Match local UI-only state to `state`.
35
+ - Match URL-backed state to `queryParams`.
36
+ - Match reusable, page-level, or global store requirements to `craft` plus `craft*` helpers.
37
+ - Match event buses, resets, refreshes, and hidden triggers to `source$` and `on$`.
38
+ - Match list collection semantics to `insertEntities` and the entity helpers when the spec explicitly talks about add, remove, update, upsert, replace, or clear.
39
+ - Match nested sub-state behavior to `insertSelect`.
40
+ - Match forms to `insertForm`, `insertSelectFormTree`, `insertFormAttributes`, and `insertFormSubmit`.
41
+ - Treat `computedSource`, `toSource`, `signalSource`, `linkedSource`, `resourceById`, `toInject`, and other infra helpers as advanced choices. Do not choose them first unless the spec is about plumbing.
42
+
43
+ ## Default Heuristics
44
+
45
+ - A primitive accepts ONE insertion. When composing 2+ insertions on the same primitive, use the universal `craftPipe` with an explicit context: `primitive(config, (context) => craftPipe(context, insertion1, insertion2))`. Never generate the removed variadic form `primitive(config, insertion1, insertion2)`. The same form applies to the nested insertions of `insertSelect`: `insertSelect('grid', (gridContext) => craftPipe(gridContext, ...))`. Exception: the form-tree helpers stay variadic.
46
+ - When a mutation affects data already visible in a `query`, add `insertReactOnMutation` on the `query`.
47
+ - When the optimistic path is obvious, prefer `optimisticPatch` for shallow field edits and `optimisticUpdate` for array or structural changes.
48
+ - When using optimistic update, enable `reload: { onMutationError: true }` by default unless the spec forbids a refetch.
49
+ - When optimistic deletion can empty the current page, consider a second `insertReactOnMutation(..., { reload: { onMutationResolved: true } })`.
50
+ - When the spec mentions pagination or page transitions, consider `identifier` on the `query` and `insertPaginationPlaceholderData`.
51
+ - When the spec mentions remembered filters, remembered results, refresh survival, or lightweight cache, consider `insertLocalStoragePersister`.
52
+ - When the spec mentions parent-provided values or route or context values that are not URL query params, consider `craftInputs`.
53
+ - When the spec mentions Angular services or a facade over a service, consider `craftInject` or `injectService`.
54
+
55
+ ## Output Contract
56
+
57
+ Always structure the answer as:
58
+
59
+ 1. `Spec fragment -> utility`
60
+ 2. `Recommended composition`
61
+ 3. `Default behaviors`
62
+ 4. `Baseline helper already covering this` — the existing architecture-suite helper (`assertMutationHasReactOn`, `assertHttpEndpointUnique`, `assertCraftUnique`, `assertPersistedPrimitiveHasUnique`, `assertInsertSelectUnique`, `assertInteractiveElementNamed`, `assertRouteDiProofs`, …). This is not a new `it()`. Do not add an architecture rule for the feature.
63
+ 5. `Open questions or assumptions`
64
+
65
+ Propose a **new** custom architecture rule only when the spec states a product invariant the baseline helpers do not cover (this feature must not depend on that one). Then load `craft-ts-architecture-tests`.
66
+
67
+ Name the concrete public APIs exactly as exported by the library.
68
+ When the spec implies a helper method, name it too: `removeOne`, `removeMany`, `updateOne`, `upsertMany`, `cRequired`, `cMinLength`, and similar helpers.
69
+
70
+ ## Example Mappings
71
+
72
+ Spec: `Creer une page qui affiche une liste d'utilisateurs.`
73
+ Mapping: `query` for remote list loading. Add `queryParams` only if pagination, filters, sort, or shareable URL state are part of the spec.
74
+
75
+ Spec: `Creer une page qui affiche une liste d'utilisateurs. On peut supprimer un utilisateur via un bouton, ou en selectionner plusieurs pour en supprimer plusieurs.`
76
+ Mapping: `query` for the list, one `mutation` for single delete, one `mutation` for bulk delete, one selection `state` or `craftState` for selected ids, and `insertReactOnMutation` on the `query` with optimistic removal plus `reload.onMutationError = true`. Use `removeOne` and `removeMany` for the optimistic transforms.
77
+ Baseline helper already covering this: `assertMutationHasReactOn` (and `assertHttpEndpointUnique` if the list HTTP is owned once). Do not add an architecture rule for the feature.
78
+
79
+ Spec: `Creer une page de recherche avec filtres dans l'URL et pagination sans flicker.`
80
+ Mapping: `queryParams` for filter and pagination state, `query` for results, `insertPaginationPlaceholderData` to keep previous page data visible during transitions, `craftSetAllQueriesParamsStandalone` if the page must generate URLs outside injection context.
81
+
82
+ ## References
83
+
84
+ - Read [references/lexical-map.md](references/lexical-map.md) for the lexical mapping.
85
+ - Read [references/pattern-recipes.md](references/pattern-recipes.md) for default compositions.
86
+ - Read [references/project-index.md](references/project-index.md) for the local source material to consult.
@@ -0,0 +1,322 @@
1
+ # Lexical Map
2
+
3
+ ## Read This First
4
+
5
+ Use this file to translate product wording into concrete public APIs.
6
+ Prefer the documented APIs first. Use the advanced exports only when the request is explicitly about plumbing, source wiring, or custom infrastructure.
7
+
8
+ ## Primary Primitives
9
+
10
+ ### `query`
11
+
12
+ Match: `afficher`, `liste`, `tableau`, `detail`, `charger`, `recuperer`, `fetch`, `read`, `dashboard`, `feed`, `resultats`, `historique`, `stats`, `donnees serveur`, `recharger`, `rafraichir`.
13
+ Pair with: `queryParams`, `insertReactOnMutation`, `insertPaginationPlaceholderData`, `insertLocalStoragePersister`, `craftQuery`.
14
+ Default: Use `params` for reactive inputs, `method` for explicit trigger flows, `identifier` for pagination or parallel instances, and `preservePreviousValue` or placeholder strategies when flicker matters.
15
+
16
+ ### `mutation`
17
+
18
+ Match: `creer`, `ajouter`, `enregistrer`, `modifier`, `mettre a jour`, `editer`, `patcher`, `supprimer`, `archiver`, `activer`, `desactiver`, `publier`, `bulk action`, `submit`, `confirmer`.
19
+ Pair with: `insertReactOnMutation`, `insertFormSubmit`, `craftMutations`, `query`.
20
+ Default: Create one mutation per server intent. Add `identifier` when row-level actions need independent loading states or cancellation semantics.
21
+
22
+ ### `asyncProcess`
23
+
24
+ Match: `debounce`, `temporiser`, `retarder`, `valider en asynchrone`, `autosave`, `partager`, `clipboard`, `native API`, `background task`, `processus asynchrone`, `polling`.
25
+ Pair with: `source$`, `afterRecomputation`, `craftAsyncProcesses`.
26
+ Default: Choose this when the flow is asynchronous but is not the canonical server read cache and is not a write that should drive query synchronization.
27
+
28
+ ### `state`
29
+
30
+ Match: `etat local`, `selection`, `toggle`, `ouvert`, `ferme`, `modal`, `onglet actif`, `draft`, `brouillon`, `checkbox`, `expanded`, `wizard step`, `current tab`, `UI state`.
31
+ Pair with: `insertSelect`, `insertEntities`, `insertForm`, `craftState`.
32
+ Default: Keep the state granular. Use it for client-only state and view state that should not live in the URL.
33
+
34
+ ### `queryParams`
35
+
36
+ Match: `URL`, `query string`, `search params`, `filtre URL`, `pagination URL`, `tri dans l'URL`, `onglet partageable`, `deep link`, `etat partageable`, `back-forward`.
37
+ Pair with: `query`, `craftQueryParams`, `craftQueryParams`, `craftSetAllQueriesParamsStandalone`.
38
+ Default: Split URL concerns by group when useful. Put `page`, `pageSize`, `sort`, `search`, `filters`, `tab`, and similar shareable state here.
39
+
40
+ ### `source$`
41
+
42
+ Match: `trigger`, `refresh`, `reset`, `bus evenementiel`, `broadcast`, `declencher`, `signal d'action`, `event stream`, `cross feature trigger`.
43
+ Pair with: `on$`, `afterRecomputation`, `craftSources`.
44
+ Default: Choose this when the spec describes an event, not a persistent state.
45
+
46
+ ### `on$`
47
+
48
+ Match: `quand X arrive alors`, `react to`, `reset on`, `sync on`, `internal reaction`, `hidden binding`, `do not expose this method`.
49
+ Pair with: `source$`, `state`, `mutation`, `asyncProcess`, `injectService`.
50
+ Default: Use this for hidden reactive wiring that should run from a source but should not become part of the public API.
51
+
52
+ ### `injectService`
53
+
54
+ Match: `facade`, `wrapper de service`, `exposer une petite API`, `renommer des methodes`, `derive from service signals`, `hide imperative router/service API`.
55
+ Pair with: `on$`, `computed`, `craftInject`.
56
+ Default: Choose this outside store composition when the user wants a smaller typed service-facing API.
57
+
58
+ ## Store Composition
59
+
60
+ ### `craft`
61
+
62
+ Match: `feature store`, `page store`, `global store`, `store reutilisable`, `compose store`, `DI`, `providedIn`, `scope`, `reusable state module`.
63
+ Pair with: `craftState`, `craftQuery`, `craftMutations`, `craftSources`, `craftInputs`, `craftQueryParams`, `craftQueryParams`, `craftInject`, `craftComputedStates`, `craftAsyncProcesses`.
64
+ Default: Use `providedIn: 'feature'` for page or route scoped logic and `providedIn: 'root'` for global shared logic.
65
+
66
+ ### `craftState`
67
+
68
+ Match: `etat local dans le store`, `selection store`, `modal store`, `draft store`, `store-owned UI state`.
69
+ Pair with: `state`, `on$`.
70
+ Default: Use when the state belongs inside a `craft` store and should be exposed as store entries and prefixed methods.
71
+
72
+ ### `craftQuery`
73
+
74
+ Match: `requete dans le store`, `server state in store`, `cached resource in feature store`, `page query`.
75
+ Pair with: `query`, `craftInputs`, `craftInject`, `craftQueryParams`, `insertReactOnMutation`.
76
+ Default: Use when a `query` belongs inside a composed store boundary.
77
+
78
+ ### `craftMutations`
79
+
80
+ Match: `actions serveur du store`, `store mutations`, `CRUD actions grouped in store`, `row actions in store`.
81
+ Pair with: `mutation`, `craftQuery`, `insertReactOnMutation`.
82
+ Default: Group server write actions here so the store gets prefixed trigger methods and typed state access.
83
+
84
+ ### `craftAsyncProcesses`
85
+
86
+ Match: `async workflow in store`, `debounced action in store`, `delayed delete`, `background task in store`.
87
+ Pair with: `asyncProcess`, `craftSources`.
88
+ Default: Use when async client tasks belong to a `craft` store but are not the primary server-read/write state.
89
+
90
+ ### `craftSources`
91
+
92
+ Match: `reset event`, `refresh event`, `select event`, `open modal event`, `trigger inside store`.
93
+ Pair with: `source$`, `on$`, `afterRecomputation`.
94
+ Default: Use this to define event channels inside a store and to auto-generate `emit*`, `set*`, or `next*` methods.
95
+
96
+ ### `craftInputs`
97
+
98
+ Match: `parent provides id`, `route provides id`, `component input`, `external signal`, `context value`, `page receives userId`.
99
+ Pair with: `craftQuery`, `craftState`, `craftMutations`.
100
+ Default: Use this instead of `queryParams` when the value does not belong in the URL.
101
+
102
+ ### `craftQueryParams`
103
+
104
+ Match: `one query param group in store`, `pagination in store`, `filters in store`, `search params in store`.
105
+ Pair with: `queryParams`, `craftQuery`, `craftSetAllQueriesParamsStandalone`.
106
+ Default: Use when one named query-params group should live inside a `craft` store.
107
+
108
+ ### `craftQueryParams`
109
+
110
+ Match: `several URL state groups`, `pagination + filters + active tab`, `multiple query param groups`.
111
+ Pair with: `queryParams`, `craftSetAllQueriesParamsStandalone`.
112
+ Default: Use when the store needs several named query-params groups.
113
+
114
+ ### `craftComputedStates`
115
+
116
+ Match: `derived store data`, `isAllSelected`, `count`, `filtered count`, `UI flags`, `aggregation`, `composed loading state`.
117
+ Pair with: `computed`, `craftState`, `craftQuery`.
118
+ Default: Use for derived store-level signals instead of duplicating state.
119
+
120
+ ### `craftInject`
121
+
122
+ Match: `inject ApiService`, `inject Router`, `inject HttpClient`, `inject token`, `service dependency in store`.
123
+ Pair with: `craft`, `craftQuery`, `craftMutations`.
124
+ Default: Use inside `craft` when store factories need Angular services or tokens.
125
+
126
+ ### `craftSetAllQueriesParamsStandalone`
127
+
128
+ Match: `generate URL`, `router navigate queryParams`, `shareable link`, `build full query string outside injection context`.
129
+ Pair with: `craftQueryParams`, `craftQueryParams`.
130
+ Default: Use when the spec mentions programmatic navigation or link generation from the current query-params model.
131
+
132
+ ## Insertions
133
+
134
+ Every primitive accepts **one** insertion. To attach several insertions,
135
+ compose them with the universal `craftPipe`, passing the context explicitly:
136
+ `primitive(config, (context) => craftPipe(context, insertion1, insertion2))`.
137
+ Members run left to right, previous outputs are visible on
138
+ `context.insertions`. Generated code MUST use this form — the variadic
139
+ `primitive(config, insertion1, insertion2, ...)` signature no longer exists.
140
+ The same applies to the nested insertions of `insertSelect`
141
+ (`insertSelect('grid', (gridContext) => craftPipe(gridContext, ...))`).
142
+ Exception: the form-tree helpers
143
+ (`insertForm`/`insertSelectFormTree`/`makeFormTreeInsert`) stay variadic.
144
+
145
+ ### `craftPipe`
146
+
147
+ Match: `plusieurs insertions`, `combine insertions`, `persister + optimistic update`, `several reactions on one query`.
148
+ Pair with: every insertion below.
149
+ Default: Wrap 2+ insertions of one primitive in `(context) => craftPipe(context, ...)`; a single insertion is passed directly without a pipe.
150
+
151
+ ### `insertReactOnMutation`
152
+
153
+ Match: `optimistic update`, `keep list in sync`, `instant UI update`, `cache invalidation`, `reload on failure`, `patch visible data after mutation`, `remove row immediately`, `sync query with mutation`.
154
+ Pair with: `query`, `mutation`, `removeOne`, `removeMany`, `updateOne`, `setOne`.
155
+ Default: Put this on the `query`, not on the mutation. Use `optimisticPatch` for shallow fields, `optimisticUpdate` for arrays and structural changes, and `reload.onMutationError: true` by default when optimistic behavior is enabled.
156
+
157
+ ### `insertPaginationPlaceholderData`
158
+
159
+ Match: `pagination without flicker`, `keep previous page visible`, `placeholder data`, `smooth page transition`.
160
+ Pair with: `query`, `queryParams`.
161
+ Default: Prefer this when pagination is user-visible and loading empty states would degrade the UX.
162
+
163
+ ### `insertLocalStoragePersister`
164
+
165
+ Match: `remember filters`, `remember last data`, `persist cache`, `survive refresh`, `restore session`, `client cache`.
166
+ Pair with: `query`, `state`, `mutation`, `asyncProcess`.
167
+ Default: This is the public insertion name even if some docs page titles still say `insertLocalStorage`.
168
+
169
+ ### `insertEntities`
170
+
171
+ Match: `entity collection`, `array of entities`, `manage list items by id`, `adapter-like methods`, `bulk array operations`, `collection helper methods`.
172
+ Pair with: `state`, `query`, `queryParams`, entity helpers such as `removeOne`, `updateMany`, and `upsertOne`.
173
+ Default: Use this when the spec repeatedly talks about item-level collection operations and the collection should expose reusable typed methods.
174
+
175
+ ### `insertSelect`
176
+
177
+ Match: `nested state`, `row-level behavior`, `cell`, `grid`, `sub-tree`, `select nested object`, `per-item nested methods`.
178
+ Pair with: `state`, `craftPipe`.
179
+ Default: Use this for object or array sub-state behavior. It accepts ONE nested insertion; for several, use `insertSelect('name', (selectedContext) => craftPipe(selectedContext, ...))`.
180
+
181
+ ### `insertNoopTypingAnchor`
182
+
183
+ Match: `form tree typing issue`.
184
+ Pair with: `insertSelectFormTree`.
185
+ Default: Use only as a typing anchor for the form-tree helpers. No longer needed with `insertSelect` (craftPipe preserves nested contextual typing).
186
+
187
+ ## Entity Helpers
188
+
189
+ | Helper | Match |
190
+ | --- | --- |
191
+ | `addOne` | `add one`, `append`, `insert item`, `push row`, `create local row` |
192
+ | `addMany` | `add several`, `append many`, `bulk insert local items` |
193
+ | `setOne` | `replace one by id`, `sync one entity`, `override row` |
194
+ | `setMany` | `replace several by id`, `merge incoming entities` |
195
+ | `setAll` | `replace whole list`, `reset collection from server` |
196
+ | `updateOne` | `partial update one`, `patch one row`, `edit one entity` |
197
+ | `updateMany` | `partial update several`, `bulk patch` |
198
+ | `upsertOne` | `create or update one`, `insert if missing` |
199
+ | `upsertMany` | `create or update several`, `merge or append` |
200
+ | `removeOne` | `delete one`, `remove one`, `remove row`, `optimistic single delete` |
201
+ | `removeMany` | `delete several`, `bulk delete`, `remove selected`, `optimistic bulk delete` |
202
+ | `removeAll` | `clear list`, `empty collection`, `reset all` |
203
+ | `map` | `transform all`, `recompute whole list`, `toggle all`, `mark all` |
204
+ | `mapOne` | `transform one by id`, `toggle one`, `edit one with custom mapper` |
205
+ | `computedTotal` | `count`, `total`, `number of items` |
206
+ | `computedIds` | `all ids`, `selected ids`, `row ids` |
207
+
208
+ ## Forms
209
+
210
+ ### `insertForm`
211
+
212
+ Match: `form`, `inline edit`, `edition`, `create form`, `submit form`, `field state`.
213
+ Pair with: `insertSelectFormTree`, `insertFormAttributes`, `insertFormSubmit`.
214
+ Default: Use this when the spec explicitly talks about a form experience. The form API is currently early-stage, so keep implementations close to the documented examples.
215
+
216
+ ### `insertSelectFormTree`
217
+
218
+ Match: `field`, `field subtree`, `name input`, `email input`, `nested form field`.
219
+ Pair with: `insertForm`, `insertNoopTypingAnchor`, `insertFormAttributes`.
220
+ Default: Use this to target form fields or nested form paths.
221
+
222
+ ### `insertFormAttributes`
223
+
224
+ Match: `validation rules`, `disabled field`, `hidden field`, `field attributes`, `visible exceptions`.
225
+ Pair with: `insertSelectFormTree`, validators such as `cRequired` and `cEmail`.
226
+ Default: Put synchronous validators and field presentation rules here.
227
+
228
+ ### `insertFormSubmit`
229
+
230
+ Match: `submit form`, `save form`, `form -> mutation`, `validated submit`, `submitting state`.
231
+ Pair with: `mutation`, `insertForm`.
232
+ Default: Connect form submission to the mutation that owns the server write intent.
233
+
234
+ ### Validators
235
+
236
+ | Validator | Match |
237
+ | --- | --- |
238
+ | `cRequired` | `required`, `mandatory`, `must not be empty` |
239
+ | `cEmail` | `email`, `must be a valid email` |
240
+ | `cMin` | `minimum numeric value`, `at least N`, `lower bound` |
241
+ | `cMax` | `maximum numeric value`, `at most N`, `upper bound` |
242
+ | `cMinLength` | `minimum length`, `at least N characters` |
243
+ | `cMaxLength` | `maximum length`, `no more than N characters` |
244
+ | `cPattern` | `regex`, `format`, `must match pattern` |
245
+ | `cValidate` | `custom validator`, `domain rule`, `business validation` |
246
+ | `cAsyncValidate` | `async validator`, `server-side validation`, `check availability` |
247
+
248
+ ## Event And Source Bridges
249
+
250
+ ### `afterRecomputation`
251
+
252
+ Match: `auto-trigger from source`, `map source payload before query`, `hidden transformed trigger`, `source-based execution`.
253
+ Pair with: `source$`, `signalSource`, `query`, `mutation`, `asyncProcess`.
254
+ Default: Use this when the spec is about event-driven execution and the payload needs a transformation before reaching the resource.
255
+
256
+ ### `fromEventToSource$`
257
+
258
+ Match: `DOM event to source`, `click stream`, `input stream`, `scroll source`, `window resize source`.
259
+ Pair with: `on$`, `state`, `asyncProcess`.
260
+ Default: Prefer this when the event must become a readonly source with signal access to the last emitted value.
261
+
262
+ ### `sourceFromEvent`
263
+
264
+ Match: `DOM event to state reducer`, `event mapper`, `legacy event bridge`.
265
+ Pair with: `state`.
266
+ Default: Choose this only if the reducer-style event mapping fits better than `fromEventToSource$`.
267
+
268
+ ### `toSource`
269
+
270
+ Match: `signal to source`, `route signal to event pipeline`, `form signal to auto query`, `debounced signal bridge`.
271
+ Pair with: `afterRecomputation`, `query`, `mutation`, `asyncProcess`.
272
+ Default: Use only when the starting point is already a signal and the next stage expects a source.
273
+
274
+ ### `computedSource`
275
+
276
+ Match: `source to source transformation`, `extract field from source`, `format source payload`, `compose source pipeline`.
277
+ Pair with: `afterRecomputation`, `signalSource`.
278
+ Default: Use when the spec is explicit about source transformation pipelines.
279
+
280
+ ### `signalSource`
281
+
282
+ Match: `source with signal shape`, `event source with set`, `lazy event signal`, `source semantics with preserveLastValue`.
283
+ Pair with: `craftSources`, `afterRecomputation`, `linkedSource`.
284
+ Default: Choose this only when the implementation specifically wants signal-like source behavior rather than `source$`.
285
+
286
+ ### `linkedSource`
287
+
288
+ Match: `derived signalSource`, `preserve last computed source value`, `source derivation with writable source semantics`.
289
+ Pair with: `signalSource`.
290
+ Default: Keep this for advanced source composition.
291
+
292
+ ### `stackedSource`
293
+
294
+ Match: `collect several source payloads`, `stack events in same cycle`, `aggregate source emissions`.
295
+ Pair with: advanced source composition only.
296
+ Default: Treat this as infrastructure-level. Do not infer it from ordinary product wording.
297
+
298
+ ## Persistence And Infra
299
+
300
+ ### `GlobalPersisterHandlerService`
301
+
302
+ Match: `logout clears cache`, `switch account`, `privacy wipe`, `force full cache reset`, `clear persisted data`.
303
+ Pair with: `insertLocalStoragePersister`.
304
+ Default: Use this when the requirement explicitly asks to clear all craft-ts persisted cache.
305
+
306
+ ### `localStoragePersister`
307
+
308
+ Match: `custom persister factory`, `storage backend`, `manual persistence infrastructure`.
309
+ Pair with: `insertLocalStoragePersister`.
310
+ Default: Prefer the insertion for product specs. Use this lower-level factory only for custom persistence infrastructure.
311
+
312
+ ### `resourceById`
313
+
314
+ Match: `low-level resource registry`, `resources keyed by identifier`, `manual per-id cache infrastructure`, `bind one resource-by-id to another`.
315
+ Pair with: `query.identifier`, `mutation.identifier`.
316
+ Default: Prefer ordinary `query` and `mutation` with `identifier` until the request explicitly asks for custom resource infrastructure.
317
+
318
+ ### `toInject`
319
+
320
+ Match: `bind external signals into service entries`, `service ...Entry wiring`, `service adapter for signals`.
321
+ Pair with: Angular services exposing writable `...Entry` signals.
322
+ Default: Use only when the service API already follows the `...Entry` convention and the request is about service binding infrastructure.
@@ -0,0 +1,123 @@
1
+ # Pattern Recipes
2
+
3
+ > Composition rule: a primitive takes ONE insertion. When a recipe below lists
4
+ > several insertions for the same primitive, compose them with `craftPipe`,
5
+ > passing the context explicitly, e.g.
6
+ > `query(name, cfg, (context) => craftPipe(context, insertLocalStoragePersister(...), insertReactOnMutation(...), insertReactOnMutation(...)))`.
7
+ > The same form works for the nested insertions of `insertSelect`:
8
+ > `insertSelect('grid', (gridContext) => craftPipe(gridContext, ...))`.
9
+ > Exception: the form-tree helpers stay variadic.
10
+
11
+ ## Read-Only List Page
12
+
13
+ Use:
14
+ - `query` for the remote collection.
15
+ - `queryParams` when pagination, sort, search, filters, or tabs live in the URL.
16
+ - `insertPaginationPlaceholderData` when page transitions should keep old data visible.
17
+ - `insertLocalStoragePersister` when results or params should survive a refresh.
18
+
19
+ Default policy:
20
+ - Put `page`, `pageSize`, `search`, `sort`, and filters in `queryParams`.
21
+ - Use `identifier` on the `query` when page or filter combinations should keep independent cached instances.
22
+ - Prefer `currentPageData()` and `currentPageStatus()` when using pagination placeholders.
23
+
24
+ ## Detail Page
25
+
26
+ Use:
27
+ - `query` for the entity detail.
28
+ - `mutation` for update or delete intents.
29
+ - `insertReactOnMutation` on the detail `query` when edits should be reflected immediately.
30
+ - `craftInputs` when the entity id comes from component or route context but does not belong in query params.
31
+
32
+ Default policy:
33
+ - Keep one detail `query` per detail intent.
34
+ - Use `optimisticPatch` when a shallow field like `name`, `status`, or `email` changes.
35
+
36
+ ## List Page With Single Delete And Bulk Delete
37
+
38
+ Use:
39
+ - one `query` for the list.
40
+ - one `mutation` for single delete.
41
+ - one `mutation` for bulk delete.
42
+ - one selection `state` or `craftState` holding selected ids.
43
+ - `insertReactOnMutation` on the list `query` for each mutation.
44
+
45
+ Default policy:
46
+ - For single delete, prefer `optimisticUpdate` with `removeOne`.
47
+ - For bulk delete, prefer `optimisticUpdate` with `removeMany`.
48
+ - Enable `reload: { onMutationError: true }` on both optimistic reactions by default.
49
+ - Add a second `insertReactOnMutation(..., { reload: { onMutationResolved: true } })` when optimistic delete can empty the current page and the next page should be reloaded; compose all the reactions on the list `query` with `(context) => craftPipe(context, ...)`.
50
+ - Add `mutation.identifier` when row-level loading or cancel buttons matter.
51
+
52
+ ## Inline Edit Or Create Form
53
+
54
+ Use:
55
+ - `state` plus `insertForm`.
56
+ - `insertSelectFormTree` to target the edited fields.
57
+ - `insertFormAttributes` for validators, disable rules, visibility, or field metadata.
58
+ - `mutation` for submit.
59
+ - `insertFormSubmit(mutationRef)` to connect the form to the mutation.
60
+ - `insertReactOnMutation` on visible queries when the updated entity is already displayed elsewhere.
61
+
62
+ Default policy:
63
+ - Put synchronous business validation in form validators first.
64
+ - Use `cRequired`, `cEmail`, `cMinLength`, and the other validator helpers before writing custom validators.
65
+ - Keep one mutation per submit intent, not one mutation per field.
66
+
67
+ ## Search Page With URL Filters
68
+
69
+ Use:
70
+ - `queryParams` or `craftQueryParams` for the filters.
71
+ - `query` for the result list.
72
+ - `craftSetAllQueriesParamsStandalone` when links or router navigation must be generated outside injection context.
73
+
74
+ Default policy:
75
+ - Reset `page` to `1` when a search term or filter changes.
76
+ - Keep URL parsing and serialization explicit for each field.
77
+ - Choose `craftQueryParams` when the page has several named query-params groups.
78
+
79
+ ## Feature Or Page Store
80
+
81
+ Use:
82
+ - `craft` as the boundary.
83
+ - `craftInject` for services and tokens.
84
+ - `craftInputs` for non-URL external values.
85
+ - `craftQueryParams` or `craftQueryParams` for URL-backed state.
86
+ - `craftSources` for reset, refresh, and cross-entry triggers.
87
+ - `craftQuery`, `craftMutations`, `craftState`, and `craftComputedStates` for the actual feature logic.
88
+
89
+ Default policy:
90
+ - Choose `providedIn: 'feature'` for page or route scoped stores.
91
+ - Choose `providedIn: 'root'` for global shared stores.
92
+ - Keep remote state in `craftQuery` and `craftMutations`, not in ad-hoc service fields.
93
+
94
+ ## Smaller Facade Over An Angular Service
95
+
96
+ Use:
97
+ - `injectService` when no `craft` store is needed.
98
+ - `craftInject` when the service participates in a store composition.
99
+
100
+ Default policy:
101
+ - Expose only the service surface the feature actually needs.
102
+ - Hide reactive bindings with `on$` when they should not become part of the public API.
103
+
104
+ ## Event-Driven Execution
105
+
106
+ Use:
107
+ - `source$` or `signalSource` for the trigger.
108
+ - `afterRecomputation` when the trigger payload needs adaptation.
109
+ - source-based `query`, `mutation`, or `asyncProcess` when the resource should run automatically on emission.
110
+
111
+ Default policy:
112
+ - Prefer `source$` for ordinary product flows.
113
+ - Escalate to `toSource`, `computedSource`, or `linkedSource` only when the inputs are already signals or the request is explicitly about source pipelines.
114
+
115
+ ## Persistence And Cache Reset
116
+
117
+ Use:
118
+ - `insertLocalStoragePersister` when a specific state or query should survive refreshes.
119
+ - `GlobalPersisterHandlerService` when the requirement says logout, account switch, or privacy reset must clear persisted cache.
120
+
121
+ Default policy:
122
+ - Persist only the state that improves UX.
123
+ - Clear all persisted cache on user boundary changes when the stored data becomes invalid or sensitive.