up-cc 0.2.2 → 0.3.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.
@@ -0,0 +1,478 @@
1
+ <overview>
2
+
3
+ Catalogo de anti-padroes de performance para analise estatica de codigo. O agente auditor le este reference e compara contra o codebase para produzir sugestoes com Dimensao = `Performance` no formato `@up/templates/suggestion.md`.
4
+
5
+ **Como usar:** 1) Rode `<stack_detection>` para identificar a stack. 2) Filtre padroes pelo campo **Frameworks**. 3) Execute **Sinal de deteccao** via Grep. 4) Para cada match, produza sugestao.
6
+
7
+ **Impacto:** P = marginal, M = notavel em metricas, G = resolve gargalo real.
8
+
9
+ </overview>
10
+
11
+ <stack_detection>
12
+
13
+ ## Deteccao de Stack
14
+
15
+ | Sinal (em package.json) | Detecta | Categorias |
16
+ |--------------------------|---------|-----------|
17
+ | `"react"` em dependencies | React | re-renders, bundle, assets, css, network, configs, deps |
18
+ | `"vue"` em dependencies | Vue | re-renders, bundle, assets, css, network, configs, deps |
19
+ | `"svelte"` em dependencies | Svelte | bundle, assets, css, network, configs, deps |
20
+ | `"next"` em dependencies | Next.js | + SSR, Image, dynamic imports |
21
+ | `"nuxt"` em dependencies | Nuxt | + SSR, NuxtImage |
22
+ | `tailwind.config.*` existe | Tailwind | Pular seletores CSS pesados |
23
+ | `"bootstrap"` em dependencies | Bootstrap | Verificar import completo vs cherry-pick |
24
+ | `"@prisma/client"` em deps | Prisma | include/select, findMany sem take |
25
+ | `"drizzle-orm"` em deps | Drizzle | query builder patterns |
26
+ | `"sequelize"` em deps | Sequelize | eager loading, N+1 |
27
+ | `"typeorm"` em deps | TypeORM | relations, query builder |
28
+
29
+ ```bash
30
+ grep -E '"(react|vue|svelte|next|nuxt|@prisma/client|drizzle-orm|sequelize|typeorm|tailwindcss|bootstrap)"' package.json 2>/dev/null
31
+ ls tailwind.config.* 2>/dev/null
32
+ ```
33
+
34
+ </stack_detection>
35
+
36
+ <category name="re-renders">
37
+
38
+ ## Re-renders Desnecessarios
39
+
40
+ ### INLINE-OBJECT-PROPS
41
+ **Frameworks:** React, Vue | **Impacto:** M
42
+ **Sinal de deteccao:**
43
+ ```bash
44
+ grep -rn 'style={{\|={\[' src/ --include="*.tsx" --include="*.jsx"
45
+ ```
46
+ **Exemplo ruim:**
47
+ ```tsx
48
+ <Card style={{ padding: 16 }}><Badge options={['new']} /></Card> // novo objeto a cada render
49
+ ```
50
+ **Solucao:**
51
+ ```tsx
52
+ const cardStyle = { padding: 16 }; const opts = ['new'];
53
+ <Card style={cardStyle}><Badge options={opts} /></Card>
54
+ ```
55
+
56
+ ### ANONYMOUS-FN-PROPS
57
+ **Frameworks:** React, Vue | **Impacto:** M
58
+ **Sinal de deteccao:**
59
+ ```bash
60
+ grep -rn 'onClick={() =>\|onChange={() =>' src/ --include="*.tsx" --include="*.jsx"
61
+ ```
62
+ **Exemplo ruim:**
63
+ ```tsx
64
+ {products.map(p => <ProductCard onClick={() => onSelect(p.id)} />)} // nova funcao a cada render
65
+ ```
66
+ **Solucao:**
67
+ ```tsx
68
+ const handleSelect = useCallback((id) => onSelect(id), [onSelect]);
69
+ {products.map(p => <ProductCard id={p.id} onClick={handleSelect} />)}
70
+ ```
71
+
72
+ ### MISSING-MEMO-LIST
73
+ **Frameworks:** React | **Impacto:** G
74
+ **Sinal de deteccao:**
75
+ ```bash
76
+ grep -rn '\.map(' src/ --include="*.tsx" --include="*.jsx" | grep -v 'memo'
77
+ ```
78
+ **Exemplo ruim:**
79
+ ```tsx
80
+ // Cada OrderRow re-renderiza quando qualquer estado do pai muda
81
+ {orders.map(o => <OrderRow key={o.id} order={o} />)}
82
+ ```
83
+ **Solucao:**
84
+ ```tsx
85
+ const OrderRow = React.memo(({ order }) => <tr><td>{order.id}</td></tr>);
86
+ ```
87
+
88
+ ### PARENT-STATE-CASCADE
89
+ **Frameworks:** React, Vue | **Impacto:** G
90
+ **Sinal de deteccao:**
91
+ ```bash
92
+ grep -rn 'setInterval\|addEventListener' src/ --include="*.tsx" --include="*.jsx"
93
+ ```
94
+ **Exemplo ruim:**
95
+ ```tsx
96
+ function Dashboard() {
97
+ const [time, setTime] = useState(Date.now()); // atualiza todo segundo
98
+ useEffect(() => { const id = setInterval(() => setTime(Date.now()), 1000); return () => clearInterval(id); }, []);
99
+ return <><Clock time={time} />{products.map(p => <Card key={p.id} product={p} />)}</>;
100
+ // todos os Cards re-renderizam a cada segundo
101
+ }
102
+ ```
103
+ **Solucao:** Isolar estado volatil em componente separado (`<LiveClock />`) para nao cascatear re-renders.
104
+
105
+ ### MISSING-USEMEMO-EXPENSIVE
106
+ **Frameworks:** React | **Impacto:** M
107
+ **Sinal de deteccao:**
108
+ ```bash
109
+ grep -rn '\.filter(\|\.sort(\|\.reduce(' src/ --include="*.tsx" --include="*.jsx" | grep -v 'useMemo'
110
+ ```
111
+ **Exemplo ruim:**
112
+ ```tsx
113
+ const results = items.filter(i => i.name.includes(query)).sort((a, b) => b.score - a.score); // recalcula a cada render
114
+ ```
115
+ **Solucao:**
116
+ ```tsx
117
+ const results = useMemo(() => items.filter(i => i.name.includes(query)).sort((a, b) => b.score - a.score), [items, query]);
118
+ ```
119
+
120
+ ### MISSING-KEY-STABLE
121
+ **Frameworks:** React, Vue | **Impacto:** M
122
+ **Sinal de deteccao:**
123
+ ```bash
124
+ grep -rn 'key={i}\|key={index}\|key={idx}' src/ --include="*.tsx" --include="*.jsx"
125
+ ```
126
+ **Exemplo ruim:**
127
+ ```tsx
128
+ {items.map((item, index) => <ListItem key={index} item={item} />)} // reordenacao causa reconciliacao completa
129
+ ```
130
+ **Solucao:** Usar ID estavel: `key={item.id}`.
131
+
132
+ </category>
133
+
134
+ <category name="bundle">
135
+
136
+ ## Bundle Size
137
+
138
+ ### FULL-LIBRARY-IMPORT
139
+ **Frameworks:** All | **Impacto:** G
140
+ **Sinal de deteccao:**
141
+ ```bash
142
+ grep -rn "from 'lodash'" src/ --include="*.ts" --include="*.tsx" | grep -v 'lodash/'
143
+ ```
144
+ **Exemplo ruim:**
145
+ ```typescript
146
+ import _ from 'lodash'; // 70KB para usar 1 funcao
147
+ ```
148
+ **Solucao:**
149
+ ```typescript
150
+ import debounce from 'lodash/debounce'; // ~2KB
151
+ ```
152
+
153
+ ### HEAVY-DEP-WITH-ALTERNATIVE
154
+ **Frameworks:** All | **Impacto:** G
155
+ **Sinal de deteccao:**
156
+ ```bash
157
+ grep -E '"(moment|lodash|jquery|axios|classnames|uuid)"' package.json
158
+ ```
159
+ **Tabela:** moment(67KB)->dayjs(2KB), lodash(70KB)->lodash-es, jquery(87KB)->DOM nativo, axios(13KB)->fetch, classnames(1KB)->clsx(0.5KB), uuid(3KB)->crypto.randomUUID().
160
+
161
+ ### MISSING-CODE-SPLITTING
162
+ **Frameworks:** React, Vue, Svelte | **Impacto:** G
163
+ **Sinal de deteccao:**
164
+ ```bash
165
+ grep -rn "import .* from '.*/pages/" src/ --include="*.tsx" --include="*.ts" | grep -v 'lazy\|dynamic\|import('
166
+ ```
167
+ **Exemplo ruim:**
168
+ ```typescript
169
+ import Dashboard from './pages/Dashboard'; // todas as paginas no bundle inicial
170
+ ```
171
+ **Solucao:**
172
+ ```typescript
173
+ const Dashboard = lazy(() => import('./pages/Dashboard')); // chunk separado por rota
174
+ ```
175
+
176
+ ### DEV-DEP-IN-DEPENDENCIES
177
+ **Frameworks:** All | **Impacto:** M
178
+ **Sinal de deteccao:**
179
+ ```bash
180
+ node -e "const p=require('./package.json'),d=Object.keys(p.dependencies||{}),t=['eslint','prettier','jest','vitest','typescript','@types/','storybook','husky','nodemon'];d.filter(x=>t.some(k=>x.includes(k))).forEach(x=>console.log('DEV em deps:',x))"
181
+ ```
182
+ Ferramentas de desenvolvimento devem estar em `devDependencies`, nao `dependencies`.
183
+
184
+ ### UNNECESSARY-POLYFILLS
185
+ **Frameworks:** All | **Impacto:** M
186
+ **Sinal de deteccao:**
187
+ ```bash
188
+ grep -rn "core-js\|@babel/polyfill\|regenerator-runtime" src/ --include="*.ts" --include="*.js"
189
+ ```
190
+ Remover polyfills se browserslist target >= ES2020. Usar `useBuiltIns: 'usage'` para incluir apenas o necessario.
191
+
192
+ ### BARREL-FILE-BLOAT
193
+ **Frameworks:** All | **Impacto:** M
194
+ **Sinal de deteccao:**
195
+ ```bash
196
+ grep -rn "export \* from" src/ --include="index.ts" --include="index.tsx"
197
+ ```
198
+ **Exemplo ruim:**
199
+ ```typescript
200
+ export * from './Button'; export * from './DataGrid'; // barrel re-exporta tudo
201
+ import { Button } from '../components'; // bundler pode incluir DataGrid tambem
202
+ ```
203
+ **Solucao:** Import direto: `import { Button } from '../components/Button'`.
204
+
205
+ </category>
206
+
207
+ <category name="queries">
208
+
209
+ ## Queries e Acesso a Dados
210
+
211
+ ### N-PLUS-ONE
212
+ **Frameworks:** All | **Impacto:** G
213
+ **Sinal de deteccao:**
214
+ ```bash
215
+ grep -rn 'for.*await.*find\|forEach.*await.*find\|\.map(.*await.*find' src/ --include="*.ts" --include="*.js"
216
+ ```
217
+ **Exemplo ruim:**
218
+ ```typescript
219
+ const orders = await prisma.order.findMany();
220
+ for (const o of orders) { o.user = await prisma.user.findUnique({ where: { id: o.userId } }); } // N queries extras
221
+ ```
222
+ **Solucao:**
223
+ ```typescript
224
+ const orders = await prisma.order.findMany({ include: { user: { select: { name: true } } } }); // 1 query
225
+ ```
226
+
227
+ ### MISSING-PAGINATION
228
+ **Frameworks:** All | **Impacto:** G
229
+ **Sinal de deteccao:**
230
+ ```bash
231
+ grep -rn 'findMany(\s*)' src/ --include="*.ts" | grep -v 'take\|skip\|cursor'
232
+ grep -rn 'SELECT.*FROM' src/ --include="*.ts" | grep -vi 'LIMIT'
233
+ ```
234
+ Endpoints que retornam listas sem `take`/`limit` podem causar OOM com dados grandes. Adicionar paginacao com cursor ou offset.
235
+
236
+ ### SELECT-ALL-FIELDS
237
+ **Frameworks:** All | **Impacto:** M
238
+ **Sinal de deteccao:**
239
+ ```bash
240
+ grep -rn 'findMany()' src/ --include="*.ts"
241
+ grep -rn 'SELECT \*' src/ --include="*.ts" --include="*.sql"
242
+ ```
243
+ Retornar apenas campos necessarios via `select`. Evitar `SELECT *` e `findMany()` sem select.
244
+
245
+ ### MISSING-INDEX-HINT
246
+ **Frameworks:** All | **Impacto:** G
247
+ **Sinal de deteccao:**
248
+ ```bash
249
+ grep -rn 'where:' src/ --include="*.ts" -A 5 | grep -v 'id:'
250
+ grep -rn '@@index\|@unique' prisma/schema.prisma 2>/dev/null
251
+ ```
252
+ Campos usados em WHERE/ORDER BY devem ter indice. Verificar schema Prisma por `@@index` nos campos filtrados.
253
+
254
+ ### MISSING-EAGER-LOADING
255
+ **Frameworks:** Sequelize, TypeORM | **Impacto:** G
256
+ **Sinal de deteccao:**
257
+ ```bash
258
+ grep -rn '\.getUser\|\.getOrders\|\.getPosts' src/ --include="*.ts" --include="*.js"
259
+ ```
260
+ Getters de associacao em loop causam N+1. Usar `include` para eager loading.
261
+
262
+ </category>
263
+
264
+ <category name="assets">
265
+
266
+ ## Assets e Midia
267
+
268
+ ### IMG-MISSING-DIMENSIONS
269
+ **Frameworks:** All | **Impacto:** G
270
+ **Sinal de deteccao:**
271
+ ```bash
272
+ grep -rn '<img' src/ --include="*.tsx" --include="*.jsx" --include="*.html" | grep -v 'width\|height\|fill'
273
+ ```
274
+ Imagens sem width/height causam CLS (Cumulative Layout Shift). Adicionar dimensoes explicitas ou `fill` (Next.js Image).
275
+
276
+ ### IMG-MISSING-LAZY
277
+ **Frameworks:** All | **Impacto:** M
278
+ **Sinal de deteccao:**
279
+ ```bash
280
+ grep -rn '<img' src/ --include="*.tsx" --include="*.jsx" | grep -v 'loading=\|priority'
281
+ ```
282
+ Imagens abaixo do fold devem ter `loading="lazy"`. Imagens acima do fold (hero) devem ser `eager`/`priority`.
283
+
284
+ ### FONT-MISSING-DISPLAY
285
+ **Frameworks:** All | **Impacto:** M
286
+ **Sinal de deteccao:**
287
+ ```bash
288
+ grep -rn '@font-face' src/ --include="*.css" --include="*.scss" -A 5 | grep -v 'font-display'
289
+ grep -rn 'fonts.googleapis.com' src/ --include="*.html" --include="*.tsx" | grep -v 'display='
290
+ ```
291
+ `@font-face` sem `font-display: swap` causa FOIT (texto invisivel). Google Fonts deve incluir `&display=swap`.
292
+
293
+ ### LARGE-INLINE-SVG
294
+ **Frameworks:** React, Vue, Svelte | **Impacto:** P
295
+ **Sinal de deteccao:**
296
+ ```bash
297
+ grep -rn '<svg' src/ --include="*.tsx" --include="*.jsx"
298
+ ```
299
+ SVGs inline grandes (>50 linhas) devem ser importados como componentes ou usar sprite sheet.
300
+
301
+ ### UNOPTIMIZED-IMG-FORMAT
302
+ **Frameworks:** All | **Impacto:** M
303
+ **Sinal de deteccao:**
304
+ ```bash
305
+ grep -rn '\.png"\|\.jpg"\|\.jpeg"' src/ --include="*.tsx" --include="*.jsx" --include="*.html" | grep -v 'favicon'
306
+ ```
307
+ Usar `<picture>` com WebP/AVIF e fallback, ou Next.js `<Image>` que otimiza automaticamente.
308
+
309
+ </category>
310
+
311
+ <category name="css">
312
+
313
+ ## CSS e Layout
314
+
315
+ ### EXPENSIVE-SELECTORS
316
+ **Frameworks:** All (menos relevante com Tailwind) | **Impacto:** P
317
+ **Sinal de deteccao:**
318
+ ```bash
319
+ grep -rn '\* {' src/ --include="*.css" --include="*.scss" | grep -v ':root\|html'
320
+ ```
321
+ Seletores universais (`*`) e descendentes profundos (`.a .b .c .d .e`) sao custosos. Preferir classes diretas.
322
+
323
+ ### LAYOUT-THRASHING
324
+ **Frameworks:** All | **Impacto:** G
325
+ **Sinal de deteccao:**
326
+ ```bash
327
+ grep -rn 'offsetHeight\|offsetWidth\|clientHeight\|getBoundingClientRect' src/ --include="*.ts" --include="*.tsx"
328
+ ```
329
+ **Exemplo ruim:**
330
+ ```typescript
331
+ cards.forEach(c => { const h = c.offsetHeight; c.style.height = h + 10 + 'px'; }); // leitura+escrita alternada
332
+ ```
333
+ **Solucao:** Batch: todas as leituras primeiro, depois todas as escritas.
334
+
335
+ ### NON-COMPOSITED-ANIMATIONS
336
+ **Frameworks:** All | **Impacto:** M
337
+ **Sinal de deteccao:**
338
+ ```bash
339
+ grep -rn 'transition\|animation' src/ --include="*.css" --include="*.scss" | grep -i 'width\|height\|top\|left\|margin'
340
+ ```
341
+ Animar `width/height/top/left` causa layout a cada frame. Usar `transform` e `opacity` (GPU-composited, 60fps).
342
+
343
+ ### UNUSED-CSS-LARGE
344
+ **Frameworks:** All (menos relevante com Tailwind purge) | **Impacto:** M
345
+ **Sinal de deteccao:**
346
+ ```bash
347
+ grep -rn "import 'bootstrap'" src/ --include="*.ts" --include="*.tsx" --include="*.js"
348
+ ```
349
+ Import de CSS inteiro de frameworks (Bootstrap 250KB) quando so 10% e usado. Importar modulos especificos ou usar PurgeCSS.
350
+
351
+ </category>
352
+
353
+ <category name="network">
354
+
355
+ ## Rede e Comunicacao
356
+
357
+ ### FETCH-WATERFALL
358
+ **Frameworks:** All | **Impacto:** G
359
+ **Sinal de deteccao:**
360
+ ```bash
361
+ grep -rn 'await.*fetch\|await.*axios' src/ --include="*.ts" --include="*.tsx" -A 1 | grep -B 1 'await.*fetch\|await.*axios'
362
+ ```
363
+ **Exemplo ruim:**
364
+ ```typescript
365
+ const user = await fetch('/api/user').then(r => r.json());
366
+ const orders = await fetch('/api/orders').then(r => r.json()); // espera user terminar
367
+ ```
368
+ **Solucao:**
369
+ ```typescript
370
+ const [user, orders] = await Promise.all([fetch('/api/user').then(r=>r.json()), fetch('/api/orders').then(r=>r.json())]);
371
+ ```
372
+
373
+ ### MISSING-CACHE-HEADERS
374
+ **Frameworks:** All (backend) | **Impacto:** M
375
+ **Sinal de deteccao:**
376
+ ```bash
377
+ grep -rn 'Cache-Control\|max-age\|stale-while-revalidate' src/ --include="*.ts" --include="*.js"
378
+ ```
379
+ Respostas de dados que mudam raramente devem ter `Cache-Control: public, max-age=3600, stale-while-revalidate=86400`.
380
+
381
+ ### LARGE-JSON-PAYLOAD
382
+ **Frameworks:** All | **Impacto:** M
383
+ **Sinal de deteccao:**
384
+ ```bash
385
+ grep -rn 'include:' src/ --include="*.ts" -A 10 | grep -c 'include:'
386
+ ```
387
+ Includes aninhados profundos geram payloads de MB. Usar `select` para limitar campos e paginar resultados.
388
+
389
+ ### MISSING-COMPRESSION
390
+ **Frameworks:** All (backend) | **Impacto:** M
391
+ **Sinal de deteccao:**
392
+ ```bash
393
+ grep -E '"compression"' package.json
394
+ grep -rn "from 'compression'" src/ --include="*.ts" --include="*.js"
395
+ ```
396
+ Express sem middleware `compression` envia JSON sem gzip. Compressao reduz payloads em 70-90%.
397
+
398
+ </category>
399
+
400
+ <category name="configs">
401
+
402
+ ## Configuracao e Build
403
+
404
+ ### SOURCEMAPS-IN-PROD
405
+ **Frameworks:** All | **Impacto:** M
406
+ **Sinal de deteccao:**
407
+ ```bash
408
+ grep -rn 'sourcemap\|sourceMap\|devtool.*source-map' webpack.config.* vite.config.* next.config.* tsconfig.json 2>/dev/null
409
+ ```
410
+ Source maps em producao expoe codigo-fonte. Usar condicional: `devtool: process.env.NODE_ENV === 'production' ? false : 'source-map'`.
411
+
412
+ ### CONSOLE-LOGS-IN-PROD
413
+ **Frameworks:** All | **Impacto:** P
414
+ **Sinal de deteccao:**
415
+ ```bash
416
+ grep -rn 'console\.log\|console\.debug' src/ --include="*.ts" --include="*.tsx" | grep -v '\.test\.\|\.spec\.'
417
+ ```
418
+ Console.log em producao polui o console e pode vazar dados sensiveis. Usar logger estruturado que respeita nivel por ambiente.
419
+
420
+ ### HARDCODED-DEV-VALUES
421
+ **Frameworks:** All | **Impacto:** G
422
+ **Sinal de deteccao:**
423
+ ```bash
424
+ grep -rn 'localhost\|127\.0\.0\.1' src/ --include="*.ts" --include="*.tsx" | grep -v '\.test\.\|\.spec\.'
425
+ ```
426
+ URLs de localhost hardcoded quebram em producao. Usar `process.env.API_URL` com fallback para dev.
427
+
428
+ </category>
429
+
430
+ <category name="deps">
431
+
432
+ ## Dependencias
433
+
434
+ ### HEAVY-DEPS-TABLE
435
+ **Frameworks:** All | **Impacto:** G
436
+ **Sinal de deteccao:**
437
+ ```bash
438
+ grep -E '"(moment|lodash|jquery|axios|classnames|uuid|underscore|request|bluebird|node-fetch)"' package.json
439
+ ```
440
+
441
+ | Dependencia | Tamanho (gz) | Alternativa | Tamanho |
442
+ |-------------|-------------|-------------|---------|
443
+ | moment | 67KB | dayjs | 2KB |
444
+ | lodash | 70KB | lodash-es + cherry-pick | 2-5KB |
445
+ | jquery | 87KB | DOM nativo | 0KB |
446
+ | axios | 13KB | fetch nativo | 0KB |
447
+ | classnames | 1KB | clsx | 0.5KB |
448
+ | uuid | 3KB | crypto.randomUUID() | 0KB |
449
+ | underscore | 18KB | ES2020+ nativos | 0KB |
450
+ | request | 48KB | fetch/undici | 0KB |
451
+ | bluebird | 18KB | Promise nativo | 0KB |
452
+ | node-fetch | 8KB | fetch nativo (Node 18+) | 0KB |
453
+
454
+ ### ABANDONED-DEPS
455
+ **Frameworks:** All | **Impacto:** M
456
+ **Sinal de deteccao:**
457
+ ```bash
458
+ npm view $(node -e "Object.keys(require('./package.json').dependencies||{}).forEach(d=>process.stdout.write(d+' '))") time.modified 2>/dev/null
459
+ ```
460
+ Dependencias com ultimo publish > 2 anos sao candidatas a substituicao. Verificar se README menciona "deprecated".
461
+
462
+ ### DUPLICATE-PURPOSE-DEPS
463
+ **Frameworks:** All | **Impacto:** M
464
+ **Sinal de deteccao:**
465
+ ```bash
466
+ node -e "const d=Object.keys({...require('./package.json').dependencies,...require('./package.json').devDependencies}),g={datas:['moment','dayjs','date-fns','luxon'],http:['axios','got','node-fetch','request','undici'],utils:['lodash','underscore','ramda'],css:['styled-components','@emotion/react','styled-jsx'],state:['redux','mobx','zustand','jotai','recoil']};Object.entries(g).forEach(([c,l])=>{const f=l.filter(x=>d.includes(x));if(f.length>1)console.log(c+': '+f.join(', '))})"
467
+ ```
468
+ Multiplas libs para o mesmo proposito (ex: moment + date-fns) inflam bundle. Consolidar em uma.
469
+
470
+ ### KNOWN-VULNERABILITIES
471
+ **Frameworks:** All | **Impacto:** G
472
+ **Sinal de deteccao:**
473
+ ```bash
474
+ npm audit --json 2>/dev/null | node -e "try{const a=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')),v=a.metadata?.vulnerabilities||{};if(v.high||v.critical)console.log('CRITICO:',v.critical||0,'criticas,',v.high||0,'altas')}catch(e){}"
475
+ ```
476
+ Dependencias com vulnerabilidades high/critical devem ser atualizadas via `npm audit fix`.
477
+
478
+ </category>