@shrkcrft/presets 0.1.0-alpha.7 → 0.1.0-alpha.9

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 +1 -1
  2. package/dist/builtin/builtin-presets.d.ts.map +1 -1
  3. package/dist/builtin/builtin-presets.js +9 -30
  4. package/dist/builtin/r26-presets.d.ts.map +1 -1
  5. package/dist/builtin/r26-presets.js +3 -3
  6. package/dist/builtin/r45-presets.d.ts.map +1 -1
  7. package/dist/builtin/r45-presets.js +3 -3
  8. package/dist/builtin/r47-presets.d.ts.map +1 -1
  9. package/dist/builtin/r47-presets.js +3 -3
  10. package/dist/builtin/shared-snippets.d.ts +3 -25
  11. package/dist/builtin/shared-snippets.d.ts.map +1 -1
  12. package/dist/builtin/shared-snippets.js +0 -265
  13. package/dist/emit/synthesize-files.d.ts.map +1 -1
  14. package/dist/emit/synthesize-files.js +17 -76
  15. package/package.json +8 -9
  16. package/dist/builtin/angular21-presets.d.ts +0 -9
  17. package/dist/builtin/angular21-presets.d.ts.map +0 -1
  18. package/dist/builtin/angular21-presets.js +0 -218
  19. package/dist/builtin/angular21-snippets.d.ts +0 -28
  20. package/dist/builtin/angular21-snippets.d.ts.map +0 -1
  21. package/dist/builtin/angular21-snippets.js +0 -243
  22. package/dist/builtin/nest11-presets.d.ts +0 -11
  23. package/dist/builtin/nest11-presets.d.ts.map +0 -1
  24. package/dist/builtin/nest11-presets.js +0 -257
  25. package/dist/builtin/nest11-snippets.d.ts +0 -32
  26. package/dist/builtin/nest11-snippets.d.ts.map +0 -1
  27. package/dist/builtin/nest11-snippets.js +0 -270
  28. package/dist/builtin/react19-presets.d.ts +0 -12
  29. package/dist/builtin/react19-presets.d.ts.map +0 -1
  30. package/dist/builtin/react19-presets.js +0 -299
  31. package/dist/builtin/react19-snippets.d.ts +0 -43
  32. package/dist/builtin/react19-snippets.d.ts.map +0 -1
  33. package/dist/builtin/react19-snippets.js +0 -363
@@ -1,243 +0,0 @@
1
- // Modern Angular 18 / 19 / 20 / 21 rule snippets.
2
- //
3
- // Covers the post-decorators wave: signal-based reactivity, signal-based
4
- // queries (`viewChild()` / `contentChild()` etc.), signal-based I/O
5
- // (`input()` / `output()` / `model()`), zoneless change detection, the new
6
- // template control flow (`@if` / `@for` / `@switch` / `@defer` / `@let`),
7
- // `inject()` over constructor DI, `afterRender` / `afterNextRender`,
8
- // `resource()` / `httpResource()`, `linkedSignal`, `NgOptimizedImage`,
9
- // self-closing component tags, and the no-NgModules / hybrid-rendering
10
- // posture.
11
- //
12
- // Each snippet is a string injected verbatim into a generated
13
- // `sharkcraft/*.ts` file; `defineKnowledgeEntry`, `KnowledgeType`, and
14
- // `KnowledgePriority` are provided by the local-mirror preamble the
15
- // synthesizer prepends.
16
- import { ruleSnippet } from "./r26-snippets.js";
17
- // ─── Signal-based reactivity (Angular 16+, fully baked by 19/20) ──────────
18
- export const NG21_SIGNAL_STATE = ruleSnippet({
19
- id: 'angular21.signal-state',
20
- title: 'Local component state lives in signals',
21
- priority: 'critical',
22
- tags: ['angular', 'angular-21', 'signals'],
23
- appliesWhen: ['generate-component', 'generate-code'],
24
- content: 'Use signal() for every piece of component-local mutable state. Derive read-only values with computed(). Reserve effect() for side effects only (DOM imperative code, logging, external I/O) — never write to a signal from inside an effect.',
25
- });
26
- export const NG21_LINKED_SIGNAL = ruleSnippet({
27
- id: 'angular21.linked-signal',
28
- title: 'Use linkedSignal for writable derived state',
29
- priority: 'high',
30
- tags: ['angular', 'angular-21', 'signals'],
31
- appliesWhen: ['generate-component', 'refactor'],
32
- content: 'When you need a writable signal that resets whenever a source signal changes (e.g. a selection that follows a filtered list), use linkedSignal({ source, computation }) instead of an effect that pokes a writable signal — that pattern is officially discouraged.',
33
- });
34
- export const NG21_NO_EFFECT_FOR_DERIVED = ruleSnippet({
35
- id: 'angular21.no-effect-for-derived',
36
- title: 'Never derive state inside an effect()',
37
- priority: 'critical',
38
- tags: ['angular', 'angular-21', 'signals'],
39
- appliesWhen: ['generate-code', 'review'],
40
- content: 'If you find yourself writing effect(() => mySignal.set(compute(otherSignal()))), switch to computed() or linkedSignal(). Writing inside effects breaks single-source-of-truth and reintroduces the very glitches signals were designed to remove.',
41
- });
42
- // ─── Signal-based queries (Angular 17.2+) ─────────────────────────────────
43
- export const NG21_SIGNAL_VIEW_CHILD = ruleSnippet({
44
- id: 'angular21.signal-view-child',
45
- title: 'Use viewChild() / viewChildren() functions, not @ViewChild',
46
- priority: 'critical',
47
- tags: ['angular', 'angular-21', 'queries', 'signals'],
48
- appliesWhen: ['generate-component', 'refactor'],
49
- content: 'Replace @ViewChild and @ViewChildren with the viewChild() / viewChildren() functions. The signal form is reactive (you can pipe it through computed()/effect()), avoids the "expression has changed after it was checked" class of bug, and integrates with OnPush + zoneless out of the box. Use viewChild.required<ElementRef>("name") when the element is guaranteed.',
50
- });
51
- export const NG21_SIGNAL_CONTENT_CHILD = ruleSnippet({
52
- id: 'angular21.signal-content-child',
53
- title: 'Use contentChild() / contentChildren() functions, not @ContentChild',
54
- priority: 'critical',
55
- tags: ['angular', 'angular-21', 'queries', 'signals'],
56
- appliesWhen: ['generate-component', 'refactor'],
57
- content: 'Replace @ContentChild and @ContentChildren with the contentChild() / contentChildren() functions. Same reactivity story as viewChild — and contentChild() resolves at the same lifecycle moment regardless of static/dynamic, so you no longer need the {static: true} workaround.',
58
- });
59
- // ─── Signal-based inputs / outputs (Angular 17.1+ / 17.3+) ───────────────
60
- export const NG21_SIGNAL_INPUTS = ruleSnippet({
61
- id: 'angular21.signal-inputs',
62
- title: 'Use input() and input.required(), not @Input()',
63
- priority: 'critical',
64
- tags: ['angular', 'angular-21', 'inputs', 'signals'],
65
- appliesWhen: ['generate-component', 'refactor'],
66
- content: 'Declare inputs as `readonly user = input<User>()` or `readonly id = input.required<string>()` instead of @Input(). Signal inputs are read-only signals — call them as a function in the template (`{{ user() }}`) or pipe them through computed() in the class. Use the transform option for coerced inputs: `input(false, { transform: booleanAttribute })`.',
67
- });
68
- export const NG21_SIGNAL_OUTPUTS = ruleSnippet({
69
- id: 'angular21.signal-outputs',
70
- title: 'Use output(), not @Output() EventEmitter',
71
- priority: 'critical',
72
- tags: ['angular', 'angular-21', 'outputs', 'signals'],
73
- appliesWhen: ['generate-component', 'refactor'],
74
- content: 'Declare outputs as `readonly select = output<UserId>()` instead of `@Output() select = new EventEmitter<UserId>()`. The output() helper drops the RxJS dependency, is fully typed, and emits via `this.select.emit(id)`. It still composes with `outputToObservable()` when a stream is needed.',
75
- });
76
- export const NG21_MODEL_TWO_WAY = ruleSnippet({
77
- id: 'angular21.model-two-way',
78
- title: 'Use model() for two-way bindings',
79
- priority: 'high',
80
- tags: ['angular', 'angular-21', 'inputs', 'outputs', 'signals'],
81
- appliesWhen: ['generate-component'],
82
- content: 'For components that own a piece of state the parent wants to bind two-way, use `readonly value = model<string>("")`. Banana-in-a-box syntax (`[(value)]="x"`) wires up automatically — no manual @Input + @Output pair, no `valueChange` EventEmitter.',
83
- });
84
- // ─── Zoneless change detection (stable in Angular 21) ─────────────────────
85
- export const NG21_ZONELESS = ruleSnippet({
86
- id: 'angular21.zoneless',
87
- title: 'Configure zoneless change detection',
88
- priority: 'critical',
89
- tags: ['angular', 'angular-21', 'zoneless', 'performance'],
90
- appliesWhen: ['bootstrap', 'configure'],
91
- content: 'Bootstrap with provideZonelessChangeDetection() and remove `zone.js` from polyfills + angular.json. Once zoneless, change detection runs only when a signal changes, an input updates, an event handler fires, or a marked component opts in via markForCheck(). Verify by reading the platform: ApplicationRef.componentTypes should not include any zone-aware regressions.',
92
- });
93
- export const NG21_NO_ZONE_APIS = ruleSnippet({
94
- id: 'angular21.no-zone-apis',
95
- title: 'Do not call NgZone APIs in zoneless code',
96
- priority: 'high',
97
- tags: ['angular', 'angular-21', 'zoneless'],
98
- appliesWhen: ['generate-code', 'review'],
99
- content: 'In zoneless apps NgZone.run / runOutsideAngular are no-ops. Replace them with explicit ChangeDetectorRef.markForCheck() (rare), afterNextRender() for DOM-aware logic, or simply let the signal graph propagate.',
100
- });
101
- // ─── New template control flow (Angular 17+) ──────────────────────────────
102
- export const NG21_CONTROL_FLOW = ruleSnippet({
103
- id: 'angular21.control-flow',
104
- title: 'Use @if / @for / @switch, not *ngIf / *ngFor / [ngSwitch]',
105
- priority: 'critical',
106
- tags: ['angular', 'angular-21', 'templates'],
107
- appliesWhen: ['generate-template', 'refactor'],
108
- content: 'Built-in control flow is the canonical form. `@if`, `@else if`, `@else`; `@for (item of items; track item.id)` — track is REQUIRED, not optional; `@switch (x) { @case (\'a\') { … } @default { … } }`. Migrate legacy structural directives with `ng generate @angular/core:control-flow`.',
109
- });
110
- export const NG21_DEFER = ruleSnippet({
111
- id: 'angular21.defer',
112
- title: 'Use @defer for non-critical UI',
113
- priority: 'high',
114
- tags: ['angular', 'angular-21', 'templates', 'performance'],
115
- appliesWhen: ['generate-template', 'optimize-bundle'],
116
- content: 'Wrap heavy, below-the-fold, or interaction-gated UI in `@defer (on viewport)` / `(on hover)` / `(on idle)` / `(when condition())`. Pair with `@placeholder`, `@loading`, and `@error` blocks. Each @defer block is its own lazy-loaded chunk — no manual `loadComponent` plumbing needed.',
117
- });
118
- export const NG21_LET_TEMPLATE = ruleSnippet({
119
- id: 'angular21.let-template',
120
- title: 'Use @let for template-local values',
121
- priority: 'medium',
122
- tags: ['angular', 'angular-21', 'templates'],
123
- appliesWhen: ['generate-template'],
124
- content: 'Introduce template-scoped names with `@let total = items().reduce(...)`. This replaces the `*ngIf="x as y"` aliasing trick — works anywhere in the template, no implicit-element baggage.',
125
- });
126
- export const NG21_SELF_CLOSING_TAGS = ruleSnippet({
127
- id: 'angular21.self-closing-tags',
128
- title: 'Self-close components with no content children',
129
- priority: 'low',
130
- tags: ['angular', 'angular-21', 'templates'],
131
- appliesWhen: ['generate-template'],
132
- content: 'Components / directives that take no projected content should be written `<app-foo [x]="y" />`, not `<app-foo …></app-foo>`. Saves a token and matches modern Angular / JSX conventions.',
133
- });
134
- export const NG21_NG_OPTIMIZED_IMAGE = ruleSnippet({
135
- id: 'angular21.ng-optimized-image',
136
- title: 'Use NgOptimizedImage for raster images',
137
- priority: 'high',
138
- tags: ['angular', 'angular-21', 'performance', 'a11y'],
139
- appliesWhen: ['generate-template'],
140
- content: 'Replace `<img src="...">` with `<img ngSrc="..." width="…" height="…" priority? />`. NgOptimizedImage adds automatic responsive `srcset`, lazy-loads non-priority images, sets fetchpriority on LCP images, and enforces explicit dimensions to prevent layout shift.',
141
- });
142
- // ─── inject(), afterRender, modern lifecycle (Angular 14+ / 16+) ──────────
143
- export const NG21_INJECT_FN = ruleSnippet({
144
- id: 'angular21.inject-fn',
145
- title: 'Use inject(), not constructor parameters',
146
- priority: 'high',
147
- tags: ['angular', 'angular-21', 'di'],
148
- appliesWhen: ['generate-component', 'generate-service', 'refactor'],
149
- content: 'Default to `private readonly users = inject(UsersService)` over constructor-parameter injection. Required for functional guards / interceptors, makes inheritance straightforward, and removes the need for `@Self()` / `@SkipSelf()` / `@Optional()` decorator stacks (use the options bag instead).',
150
- });
151
- export const NG21_AFTER_RENDER = ruleSnippet({
152
- id: 'angular21.after-render',
153
- title: 'Use afterNextRender / afterRender for DOM-aware logic',
154
- priority: 'high',
155
- tags: ['angular', 'angular-21', 'lifecycle'],
156
- appliesWhen: ['generate-component'],
157
- content: 'For code that needs the DOM (measuring, focusing, third-party libs): use afterNextRender(() => …) for one-shot setup or afterRender(() => …) for every CD pass. Both run only in the browser, so they\'re SSR-safe by construction — replacing the ngAfterViewInit + isPlatformBrowser dance.',
158
- });
159
- export const NG21_PROVIDED_IN_ROOT = ruleSnippet({
160
- id: 'angular21.provided-in-root',
161
- title: 'Services use providedIn: \'root\' (tree-shakeable)',
162
- priority: 'high',
163
- tags: ['angular', 'angular-21', 'di', 'services'],
164
- appliesWhen: ['generate-service'],
165
- content: 'Inject services via `@Injectable({ providedIn: "root" })` so unused services tree-shake out. Only override with component / route providers when you need a fresh instance per consumer.',
166
- });
167
- // ─── No NgModules / standalone-only ───────────────────────────────────────
168
- export const NG21_NO_NGMODULES = ruleSnippet({
169
- id: 'angular21.no-ngmodules',
170
- title: 'Do not create new NgModules',
171
- priority: 'critical',
172
- tags: ['angular', 'angular-21', 'architecture'],
173
- appliesWhen: ['generate-code', 'create-feature'],
174
- content: 'Angular 21 starter apps are NgModule-free. Components, directives, and pipes are standalone by default (the `standalone: true` flag is the default since v19). Configure providers via `provideX()` functions in bootstrapApplication() or route data, never with @NgModule. If you find yourself writing @NgModule, you are working against the grain.',
175
- });
176
- export const NG21_BOOTSTRAP_APPLICATION = ruleSnippet({
177
- id: 'angular21.bootstrap-application',
178
- title: 'bootstrap via bootstrapApplication + provideX functions',
179
- priority: 'high',
180
- tags: ['angular', 'angular-21', 'bootstrap'],
181
- appliesWhen: ['bootstrap'],
182
- content: 'main.ts uses bootstrapApplication(AppComponent, { providers: [provideRouter(routes), provideHttpClient(withFetch()), provideZonelessChangeDetection(), provideAnimationsAsync()] }). Each capability has a provideX() — no AppModule needed.',
183
- });
184
- // ─── Async data: resource() / httpResource() (Angular 19/20+) ────────────
185
- export const NG21_RESOURCE_API = ruleSnippet({
186
- id: 'angular21.resource-api',
187
- title: 'Model async state with resource()',
188
- priority: 'high',
189
- tags: ['angular', 'angular-21', 'async', 'signals'],
190
- appliesWhen: ['generate-component', 'generate-service'],
191
- content: 'For "fetch X based on signal Y" patterns, use resource({ request: () => y(), loader: ({ request, abortSignal }) => fetch(...) }). The resource exposes `.value()`, `.status()`, `.error()`, and `.reload()` — a fully-typed state machine driven by signals. Don\'t hand-roll subscription + loading-state + error-state triplets anymore.',
192
- });
193
- export const NG21_HTTP_RESOURCE = ruleSnippet({
194
- id: 'angular21.http-resource',
195
- title: 'Use httpResource() for declarative HTTP',
196
- priority: 'high',
197
- tags: ['angular', 'angular-21', 'http', 'signals'],
198
- appliesWhen: ['generate-service'],
199
- content: 'For straight reads, `const user = httpResource<User>(() => \\`/api/users/${id()}\\`)` replaces an HttpClient.get + BehaviorSubject + loading flag triple. The signal in the URL closure is tracked; updating it refetches.',
200
- });
201
- // ─── Modern SSR / hybrid rendering (Angular 19+) ─────────────────────────
202
- export const NG21_HYBRID_RENDERING = ruleSnippet({
203
- id: 'angular21.hybrid-rendering',
204
- title: 'Configure routes with server-rendering modes',
205
- priority: 'medium',
206
- tags: ['angular', 'angular-21', 'ssr'],
207
- appliesWhen: ['configure-routes'],
208
- content: 'In app.routes.server.ts, tag each route with a RenderMode: `Prerender` for static, `Server` for per-request SSR, `Client` for CSR-only. The default `provideServerRouting(serverRoutes)` enforces the boundary — no more "did this code accidentally run on the server?" guesswork.',
209
- });
210
- export const NG21_PROVIDE_HTTP_FETCH = ruleSnippet({
211
- id: 'angular21.provide-http-fetch',
212
- title: 'provideHttpClient(withFetch()) — never the XHR backend',
213
- priority: 'high',
214
- tags: ['angular', 'angular-21', 'http', 'ssr'],
215
- appliesWhen: ['configure'],
216
- content: 'Provide HttpClient with the fetch backend (`provideHttpClient(withFetch())`). XHR breaks under SSR and pays a startup cost; fetch is universal, supports streaming, and is required for resource transfer between server and client.',
217
- });
218
- // ─── Forms — modern signal-compatible patterns ───────────────────────────
219
- export const NG21_SIGNAL_FORMS_INTEROP = ruleSnippet({
220
- id: 'angular21.signal-forms-interop',
221
- title: 'Bridge reactive forms into signals with toSignal()',
222
- priority: 'medium',
223
- tags: ['angular', 'angular-21', 'forms', 'signals'],
224
- appliesWhen: ['generate-component'],
225
- content: 'When you need a form value as a signal, do `const value = toSignal(form.valueChanges, { initialValue: form.getRawValue() })`. Don\'t mix .subscribe() into a component that otherwise relies on signal-driven CD — that subscription will leak.',
226
- });
227
- // ─── Testing — modern flow ───────────────────────────────────────────────
228
- export const NG21_TEST_SIGNAL_INPUT = ruleSnippet({
229
- id: 'angular21.test-signal-input',
230
- title: 'Set signal inputs in tests via setInput()',
231
- priority: 'medium',
232
- tags: ['angular', 'angular-21', 'testing'],
233
- appliesWhen: ['generate-test'],
234
- content: 'In TestBed, set signal-input values with `fixture.componentRef.setInput("user", u)` — not by assigning `component.user`. Detection runs only when the input signal is updated, and setInput is the supported path that triggers it.',
235
- });
236
- export const NG21_TEST_NO_DETECT_CHANGES_OUTSIDE = ruleSnippet({
237
- id: 'angular21.test-no-detect-changes-outside',
238
- title: 'Let the framework drive CD in tests',
239
- priority: 'low',
240
- tags: ['angular', 'angular-21', 'testing'],
241
- appliesWhen: ['generate-test'],
242
- content: 'In zoneless tests, call `fixture.detectChanges()` only at deliberate "settle" points; signal updates inside the test run schedule the next CD automatically. Sprinkling detectChanges() after every assignment masks real reactivity bugs.',
243
- });
@@ -1,11 +0,0 @@
1
- import type { IPreset } from '../model/preset.js';
2
- export declare const NEST_11_ARCHITECTURE: IPreset;
3
- export declare const NEST_11_VALIDATION: IPreset;
4
- export declare const NEST_11_ASYNC_LIFECYCLE: IPreset;
5
- export declare const NEST_11_PERFORMANCE: IPreset;
6
- export declare const NEST_11_SECURITY: IPreset;
7
- export declare const NEST_11_OBSERVABILITY: IPreset;
8
- export declare const NEST_11_TESTING: IPreset;
9
- export declare const NEST_11_MODERN: IPreset;
10
- export declare const NEST_11_PRESETS: readonly IPreset[];
11
- //# sourceMappingURL=nest11-presets.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"nest11-presets.d.ts","sourceRoot":"","sources":["../../src/builtin/nest11-presets.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAsDlD,eAAO,MAAM,oBAAoB,EAAE,OA+BjC,CAAC;AAIH,eAAO,MAAM,kBAAkB,EAAE,OA6B/B,CAAC;AAIH,eAAO,MAAM,uBAAuB,EAAE,OA2BpC,CAAC;AAIH,eAAO,MAAM,mBAAmB,EAAE,OA4BhC,CAAC;AAIH,eAAO,MAAM,gBAAgB,EAAE,OA8B7B,CAAC;AAIH,eAAO,MAAM,qBAAqB,EAAE,OA4BlC,CAAC;AAIH,eAAO,MAAM,eAAe,EAAE,OA2B5B,CAAC;AAIH,eAAO,MAAM,cAAc,EAAE,OA4C3B,CAAC;AAEH,eAAO,MAAM,eAAe,EAAE,SAAS,OAAO,EAS5C,CAAC"}
@@ -1,257 +0,0 @@
1
- // NestJS 11+ preset family.
2
- //
3
- // Seven focused presets covering modern Nest practice — architecture,
4
- // validation, async lifecycle, performance, security, observability,
5
- // testing — plus one comprehensive `nest-11-modern` that composes them.
6
- // Targets HasNestJS workspaces with weight set above the legacy R26
7
- // `nestjs-service` (weight 7) and R47 `nest-service` canonical alias
8
- // (weight 9), so the recommender prefers these when the workspace
9
- // declares HasNestJS.
10
- import { WorkspaceProfile } from '@shrkcrft/workspace';
11
- import { definePreset } from "../define/define-preset.js";
12
- import { COMMON_AGENT_BRIEFING, COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV, COMMON_PIPELINE_UNIT_TEST, COMMON_SAFETY_RULE, NEST_PATH_E2E, NEST_PATH_SRC, OVERVIEW_DOC, } from "./shared-snippets.js";
13
- import { NEST11_API_VERSIONING, NEST11_ASYNC_PROVIDERS, NEST11_CACHE_MANAGER, NEST11_CLASS_VALIDATOR_DTO, NEST11_DTO_AT_BOUNDARY, NEST11_E2E_SUPERTEST, NEST11_ENABLE_SHUTDOWN_HOOKS, NEST11_EXPLICIT_CORS, NEST11_FASTIFY_ADAPTER, NEST11_GLOBAL_VALIDATION_PIPE, NEST11_HELMET, NEST11_JWT_GUARDS, NEST11_LIFECYCLE_HOOKS, NEST11_LOGGER_WITH_CONTEXT, NEST11_MODULE_PER_FEATURE, NEST11_MODULE_PUBLIC_API, NEST11_NO_CIRCULAR_MODULES, NEST11_NO_LOG_SECRETS, NEST11_NO_QUERY_IN_CONTROLLER, NEST11_NO_SECRETS_IN_CODE, NEST11_PAGINATION_BY_DEFAULT, NEST11_REQUEST_RESPONSE_DTOS, NEST11_SERVICE_OWNS_DOMAIN, NEST11_STRUCTURED_LOGS, NEST11_SWAGGER_DECORATORS, NEST11_TERMINUS_HEALTH, NEST11_TEST_FILE_LAYOUT, NEST11_TESTING_MODULE, NEST11_THIN_CONTROLLERS, NEST11_THROTTLER, NEST11_TRUST_PROXY_AWARE, } from "./nest11-snippets.js";
14
- const NEST11_TAGS = ['nestjs', 'nest-11', 'backend'];
15
- const NEST11_NEXT_COMMANDS = [
16
- 'shrk doctor',
17
- 'shrk task "<task>"',
18
- 'shrk ci scaffold github-actions --quickstart',
19
- ];
20
- // ─── 1) Architecture — modules, controllers, services, repos ─────────────
21
- export const NEST_11_ARCHITECTURE = definePreset({
22
- id: 'nest-11-architecture',
23
- title: 'NestJS 11 — module + controller + service architecture',
24
- description: 'Module-per-feature, thin controllers (validate + delegate, nothing more), services own domain logic, repositories abstract data access, DTOs at every HTTP boundary, no circular module dependencies. The structural backbone of a maintainable Nest service.',
25
- tags: [...NEST11_TAGS, 'architecture'],
26
- appliesTo: [WorkspaceProfile.HasNestJS, WorkspaceProfile.IsBackend],
27
- weight: 11,
28
- includes: {
29
- knowledge: [COMMON_AGENT_BRIEFING],
30
- rules: [
31
- COMMON_SAFETY_RULE,
32
- NEST11_THIN_CONTROLLERS,
33
- NEST11_SERVICE_OWNS_DOMAIN,
34
- NEST11_MODULE_PER_FEATURE,
35
- NEST11_MODULE_PUBLIC_API,
36
- NEST11_NO_CIRCULAR_MODULES,
37
- NEST11_DTO_AT_BOUNDARY,
38
- NEST11_NO_QUERY_IN_CONTROLLER,
39
- ],
40
- paths: [NEST_PATH_SRC, NEST_PATH_E2E],
41
- templates: [],
42
- pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
43
- docs: {
44
- 'overview.md': OVERVIEW_DOC('NestJS 11 architecture', 'Module per feature under src/<feature>/. Controllers parse + delegate. Services own domain logic; data access goes through repositories. Modules export only their public providers. DTOs at every boundary; entities never leave the service layer.'),
45
- },
46
- },
47
- recommendedNextCommands: NEST11_NEXT_COMMANDS,
48
- });
49
- // ─── 2) Validation — ValidationPipe + class-validator + DTOs ─────────────
50
- export const NEST_11_VALIDATION = definePreset({
51
- id: 'nest-11-validation',
52
- title: 'NestJS 11 — strict validation at the boundary',
53
- description: 'Global ValidationPipe with whitelist + forbidNonWhitelisted + transform, class-validator decorators on every DTO field, separated request and response DTOs, @ApiProperty annotations for the OpenAPI contract.',
54
- tags: [...NEST11_TAGS, 'validation'],
55
- appliesTo: [WorkspaceProfile.HasNestJS, WorkspaceProfile.IsBackend],
56
- weight: 11,
57
- includes: {
58
- knowledge: [COMMON_AGENT_BRIEFING],
59
- rules: [
60
- COMMON_SAFETY_RULE,
61
- NEST11_GLOBAL_VALIDATION_PIPE,
62
- NEST11_CLASS_VALIDATOR_DTO,
63
- NEST11_REQUEST_RESPONSE_DTOS,
64
- NEST11_DTO_AT_BOUNDARY,
65
- NEST11_SWAGGER_DECORATORS,
66
- ],
67
- paths: [NEST_PATH_SRC],
68
- templates: [],
69
- pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
70
- docs: {
71
- 'overview.md': OVERVIEW_DOC('NestJS 11 validation', 'ValidationPipe is registered globally with strict options. Every DTO is a class with class-validator decorators; @Type() wires nested objects through class-transformer. Request and response DTOs are separate classes — input is whitelisted, output is projected.'),
72
- },
73
- },
74
- recommendedNextCommands: NEST11_NEXT_COMMANDS,
75
- });
76
- // ─── 3) Async lifecycle + graceful shutdown ──────────────────────────────
77
- export const NEST_11_ASYNC_LIFECYCLE = definePreset({
78
- id: 'nest-11-async-lifecycle',
79
- title: 'NestJS 11 — async providers + graceful shutdown',
80
- description: 'Async configuration providers via useFactory, OnModuleInit / OnApplicationBootstrap / OnModuleDestroy / OnApplicationShutdown lifecycle hooks, enableShutdownHooks() at bootstrap so SIGTERM cleanly tears down DB pools and message clients.',
81
- tags: [...NEST11_TAGS, 'lifecycle'],
82
- appliesTo: [WorkspaceProfile.HasNestJS, WorkspaceProfile.IsBackend],
83
- weight: 11,
84
- includes: {
85
- knowledge: [COMMON_AGENT_BRIEFING],
86
- rules: [
87
- COMMON_SAFETY_RULE,
88
- NEST11_LIFECYCLE_HOOKS,
89
- NEST11_ENABLE_SHUTDOWN_HOOKS,
90
- NEST11_ASYNC_PROVIDERS,
91
- ],
92
- paths: [NEST_PATH_SRC],
93
- templates: [],
94
- pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
95
- docs: {
96
- 'overview.md': OVERVIEW_DOC('NestJS 11 lifecycle', 'enableShutdownHooks() in main.ts so the OnModuleDestroy / OnApplicationShutdown hooks fire on SIGTERM. Configuration that must resolve at boot uses { useFactory } async providers — not lazy init from inside a service.'),
97
- },
98
- },
99
- recommendedNextCommands: NEST11_NEXT_COMMANDS,
100
- });
101
- // ─── 4) Performance — Fastify, cache, throttler, pagination ──────────────
102
- export const NEST_11_PERFORMANCE = definePreset({
103
- id: 'nest-11-performance',
104
- title: 'NestJS 11 — Fastify, caching, throttling, pagination',
105
- description: 'NestFastifyApplication adapter for ~2× throughput vs. Express, @nestjs/cache-manager for hot reads, @nestjs/throttler for per-IP rate limiting, mandatory pagination on every list endpoint.',
106
- tags: [...NEST11_TAGS, 'performance'],
107
- appliesTo: [WorkspaceProfile.HasNestJS, WorkspaceProfile.IsBackend],
108
- weight: 11,
109
- includes: {
110
- knowledge: [COMMON_AGENT_BRIEFING],
111
- rules: [
112
- COMMON_SAFETY_RULE,
113
- NEST11_FASTIFY_ADAPTER,
114
- NEST11_CACHE_MANAGER,
115
- NEST11_THROTTLER,
116
- NEST11_PAGINATION_BY_DEFAULT,
117
- ],
118
- paths: [NEST_PATH_SRC],
119
- templates: [],
120
- pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
121
- docs: {
122
- 'overview.md': OVERVIEW_DOC('NestJS 11 performance', 'Fastify adapter for high-throughput HTTP. Idempotent GETs cached via CacheInterceptor with explicit per-route TTLs. Global ThrottlerModule with sane defaults (60 req/min/IP); per-route overrides via @Throttle. List endpoints paginate by default; pageSize is capped server-side.'),
123
- },
124
- },
125
- recommendedNextCommands: NEST11_NEXT_COMMANDS,
126
- });
127
- // ─── 5) Security — helmet, CORS, auth, secrets, trust-proxy ──────────────
128
- export const NEST_11_SECURITY = definePreset({
129
- id: 'nest-11-security',
130
- title: 'NestJS 11 — security baseline',
131
- description: 'helmet middleware for HTTP security headers, explicit CORS allowlist (never `origin: true`), JWT auth via @nestjs/passport guards, no-secrets-in-source enforcement, trust-proxy configured for load-balanced deployments, throttler for abuse protection.',
132
- tags: [...NEST11_TAGS, 'security'],
133
- appliesTo: [WorkspaceProfile.HasNestJS, WorkspaceProfile.IsBackend],
134
- weight: 11,
135
- includes: {
136
- knowledge: [COMMON_AGENT_BRIEFING],
137
- rules: [
138
- COMMON_SAFETY_RULE,
139
- NEST11_HELMET,
140
- NEST11_EXPLICIT_CORS,
141
- NEST11_JWT_GUARDS,
142
- NEST11_NO_SECRETS_IN_CODE,
143
- NEST11_TRUST_PROXY_AWARE,
144
- NEST11_THROTTLER,
145
- ],
146
- paths: [NEST_PATH_SRC],
147
- templates: [],
148
- pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
149
- docs: {
150
- 'overview.md': OVERVIEW_DOC('NestJS 11 security', 'helmet registered before any route. CORS allowlist explicit. Authentication runs through Guards (JwtAuthGuard + @UseGuards), not middleware. Secrets come from ConfigService.get only. trust-proxy configured. Throttler in place.'),
151
- },
152
- },
153
- recommendedNextCommands: NEST11_NEXT_COMMANDS,
154
- });
155
- // ─── 6) Observability — Logger, structured logs, terminus ────────────────
156
- export const NEST_11_OBSERVABILITY = definePreset({
157
- id: 'nest-11-observability',
158
- title: 'NestJS 11 — structured logging + health checks',
159
- description: 'Per-provider Logger instances with context names, structured JSON logs in production (pino / nest-winston), redact-list for secrets and PII, @nestjs/terminus health checks with separated liveness and readiness endpoints.',
160
- tags: [...NEST11_TAGS, 'observability'],
161
- appliesTo: [WorkspaceProfile.HasNestJS, WorkspaceProfile.IsBackend],
162
- weight: 11,
163
- includes: {
164
- knowledge: [COMMON_AGENT_BRIEFING],
165
- rules: [
166
- COMMON_SAFETY_RULE,
167
- NEST11_LOGGER_WITH_CONTEXT,
168
- NEST11_STRUCTURED_LOGS,
169
- NEST11_NO_LOG_SECRETS,
170
- NEST11_TERMINUS_HEALTH,
171
- ],
172
- paths: [NEST_PATH_SRC],
173
- templates: [],
174
- pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_FEATURE_DEV],
175
- docs: {
176
- 'overview.md': OVERVIEW_DOC('NestJS 11 observability', 'Each provider holds its own Logger(MyService.name). Production logger is structured JSON via pino or nest-winston with a redact list for tokens / passwords / PII. /health/liveness and /health/readiness are separate endpoints; readiness fails 503 when a critical dep is down.'),
177
- },
178
- },
179
- recommendedNextCommands: NEST11_NEXT_COMMANDS,
180
- });
181
- // ─── 7) Testing — TestingModule + e2e ───────────────────────────────────
182
- export const NEST_11_TESTING = definePreset({
183
- id: 'nest-11-testing',
184
- title: 'NestJS 11 — TestingModule + supertest e2e',
185
- description: 'Unit tests via Test.createTestingModule + overrideProvider for slow deps, co-located *.spec.ts files; e2e under test/*.e2e-spec.ts driving the real AppModule through supertest with the validation pipeline live.',
186
- tags: [...NEST11_TAGS, 'testing'],
187
- appliesTo: [WorkspaceProfile.HasNestJS, WorkspaceProfile.IsBackend],
188
- weight: 11,
189
- includes: {
190
- knowledge: [COMMON_AGENT_BRIEFING],
191
- rules: [
192
- COMMON_SAFETY_RULE,
193
- NEST11_TESTING_MODULE,
194
- NEST11_E2E_SUPERTEST,
195
- NEST11_TEST_FILE_LAYOUT,
196
- ],
197
- paths: [NEST_PATH_SRC, NEST_PATH_E2E],
198
- templates: [],
199
- pipelines: [COMMON_PIPELINE_CONTEXT_ONLY, COMMON_PIPELINE_UNIT_TEST],
200
- docs: {
201
- 'overview.md': OVERVIEW_DOC('NestJS 11 testing', 'Unit specs are co-located beside their unit; they use Test.createTestingModule + overrideProvider to fake the expensive deps. E2E specs live under test/, drive AppModule through supertest, and keep the real validation pipeline + guards + interceptors active — that is the contract being tested.'),
202
- },
203
- },
204
- recommendedNextCommands: NEST11_NEXT_COMMANDS,
205
- });
206
- // ─── 8) The whole stack — composes 1-7 ──────────────────────────────────
207
- export const NEST_11_MODERN = definePreset({
208
- id: 'nest-11-modern',
209
- title: 'NestJS 11 — modern stack (architecture + validation + lifecycle + perf + security + obs + testing)',
210
- description: 'The canonical preset for a new NestJS 11+ service. Composes the seven focused presets, then layers on API versioning. Use this unless you specifically want a narrower slice.',
211
- tags: [...NEST11_TAGS, 'comprehensive'],
212
- appliesTo: [WorkspaceProfile.HasNestJS, WorkspaceProfile.IsBackend, WorkspaceProfile.IsService],
213
- weight: 12,
214
- composes: [
215
- 'nest-11-architecture',
216
- 'nest-11-validation',
217
- 'nest-11-async-lifecycle',
218
- 'nest-11-performance',
219
- 'nest-11-security',
220
- 'nest-11-observability',
221
- 'nest-11-testing',
222
- ],
223
- includes: {
224
- knowledge: [COMMON_AGENT_BRIEFING],
225
- rules: [
226
- COMMON_SAFETY_RULE,
227
- // Extras that don't fit any single focused preset:
228
- NEST11_API_VERSIONING,
229
- ],
230
- paths: [NEST_PATH_SRC, NEST_PATH_E2E],
231
- templates: [],
232
- pipelines: [
233
- COMMON_PIPELINE_CONTEXT_ONLY,
234
- COMMON_PIPELINE_FEATURE_DEV,
235
- COMMON_PIPELINE_UNIT_TEST,
236
- ],
237
- docs: {
238
- 'overview.md': OVERVIEW_DOC('NestJS 11 modern stack', 'Module-per-feature architecture. Thin controllers, services own domain, repositories abstract data. Global ValidationPipe + class-validator. Fastify adapter, cache-manager, throttler, mandatory pagination. helmet + CORS allowlist + JWT guards + no-secrets. Per-provider Logger + structured JSON logs + terminus health. TestingModule unit specs + supertest e2e. URI versioning when the API has external consumers.'),
239
- },
240
- },
241
- recommendedNextCommands: [
242
- 'shrk doctor',
243
- 'shrk task "<task>"',
244
- 'shrk ci scaffold github-actions --quickstart',
245
- 'nest g resource <feature>',
246
- ],
247
- });
248
- export const NEST_11_PRESETS = Object.freeze([
249
- NEST_11_ARCHITECTURE,
250
- NEST_11_VALIDATION,
251
- NEST_11_ASYNC_LIFECYCLE,
252
- NEST_11_PERFORMANCE,
253
- NEST_11_SECURITY,
254
- NEST_11_OBSERVABILITY,
255
- NEST_11_TESTING,
256
- NEST_11_MODERN,
257
- ]);
@@ -1,32 +0,0 @@
1
- export declare const NEST11_THIN_CONTROLLERS: string;
2
- export declare const NEST11_SERVICE_OWNS_DOMAIN: string;
3
- export declare const NEST11_MODULE_PER_FEATURE: string;
4
- export declare const NEST11_MODULE_PUBLIC_API: string;
5
- export declare const NEST11_NO_CIRCULAR_MODULES: string;
6
- export declare const NEST11_DTO_AT_BOUNDARY: string;
7
- export declare const NEST11_GLOBAL_VALIDATION_PIPE: string;
8
- export declare const NEST11_CLASS_VALIDATOR_DTO: string;
9
- export declare const NEST11_REQUEST_RESPONSE_DTOS: string;
10
- export declare const NEST11_SWAGGER_DECORATORS: string;
11
- export declare const NEST11_LIFECYCLE_HOOKS: string;
12
- export declare const NEST11_ENABLE_SHUTDOWN_HOOKS: string;
13
- export declare const NEST11_ASYNC_PROVIDERS: string;
14
- export declare const NEST11_FASTIFY_ADAPTER: string;
15
- export declare const NEST11_CACHE_MANAGER: string;
16
- export declare const NEST11_THROTTLER: string;
17
- export declare const NEST11_PAGINATION_BY_DEFAULT: string;
18
- export declare const NEST11_HELMET: string;
19
- export declare const NEST11_EXPLICIT_CORS: string;
20
- export declare const NEST11_JWT_GUARDS: string;
21
- export declare const NEST11_NO_SECRETS_IN_CODE: string;
22
- export declare const NEST11_TRUST_PROXY_AWARE: string;
23
- export declare const NEST11_LOGGER_WITH_CONTEXT: string;
24
- export declare const NEST11_STRUCTURED_LOGS: string;
25
- export declare const NEST11_NO_LOG_SECRETS: string;
26
- export declare const NEST11_TERMINUS_HEALTH: string;
27
- export declare const NEST11_TESTING_MODULE: string;
28
- export declare const NEST11_E2E_SUPERTEST: string;
29
- export declare const NEST11_TEST_FILE_LAYOUT: string;
30
- export declare const NEST11_API_VERSIONING: string;
31
- export declare const NEST11_NO_QUERY_IN_CONTROLLER: string;
32
- //# sourceMappingURL=nest11-snippets.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"nest11-snippets.d.ts","sourceRoot":"","sources":["../../src/builtin/nest11-snippets.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,uBAAuB,QAQlC,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAQrC,CAAC;AAEH,eAAO,MAAM,yBAAyB,QAQpC,CAAC;AAEH,eAAO,MAAM,wBAAwB,QAQnC,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAQrC,CAAC;AAEH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAIH,eAAO,MAAM,6BAA6B,QAQxC,CAAC;AAEH,eAAO,MAAM,0BAA0B,QAQrC,CAAC;AAEH,eAAO,MAAM,4BAA4B,QAQvC,CAAC;AAEH,eAAO,MAAM,yBAAyB,QAQpC,CAAC;AAIH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAEH,eAAO,MAAM,4BAA4B,QAQvC,CAAC;AAEH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAIH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAEH,eAAO,MAAM,oBAAoB,QAQ/B,CAAC;AAEH,eAAO,MAAM,gBAAgB,QAQ3B,CAAC;AAEH,eAAO,MAAM,4BAA4B,QAQvC,CAAC;AAIH,eAAO,MAAM,aAAa,QAQxB,CAAC;AAEH,eAAO,MAAM,oBAAoB,QAQ/B,CAAC;AAEH,eAAO,MAAM,iBAAiB,QAQ5B,CAAC;AAEH,eAAO,MAAM,yBAAyB,QAQpC,CAAC;AAEH,eAAO,MAAM,wBAAwB,QAQnC,CAAC;AAIH,eAAO,MAAM,0BAA0B,QAQrC,CAAC;AAEH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAEH,eAAO,MAAM,qBAAqB,QAQhC,CAAC;AAEH,eAAO,MAAM,sBAAsB,QAQjC,CAAC;AAIH,eAAO,MAAM,qBAAqB,QAQhC,CAAC;AAEH,eAAO,MAAM,oBAAoB,QAQ/B,CAAC;AAEH,eAAO,MAAM,uBAAuB,QAQlC,CAAC;AAIH,eAAO,MAAM,qBAAqB,QAQhC,CAAC;AAEH,eAAO,MAAM,6BAA6B,QAQxC,CAAC"}