@memlab/mcp-server 2.18.1 → 2.86.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.
- package/README.md +30 -16
- package/bin/.eslintrc.js +26 -0
- package/bin/memlab-cli.js +313 -0
- package/dist/anonymized-snapshot.d.ts +75 -0
- package/dist/anonymized-snapshot.d.ts.map +1 -0
- package/dist/anonymized-snapshot.js +101 -0
- package/dist/anonymized-snapshot.js.map +1 -0
- package/dist/artifact-classes.d.ts +86 -0
- package/dist/artifact-classes.d.ts.map +1 -0
- package/dist/artifact-classes.js +261 -0
- package/dist/artifact-classes.js.map +1 -0
- package/dist/capture-mode.d.ts +60 -0
- package/dist/capture-mode.d.ts.map +1 -0
- package/dist/capture-mode.js +39 -0
- package/dist/capture-mode.js.map +1 -0
- package/dist/eval-hints.d.ts +41 -0
- package/dist/eval-hints.d.ts.map +1 -0
- package/dist/eval-hints.js +115 -0
- package/dist/eval-hints.js.map +1 -0
- package/dist/guardrail.d.ts.map +1 -1
- package/dist/guardrail.js +13 -0
- package/dist/guardrail.js.map +1 -1
- package/dist/heap-budget.d.ts +32 -0
- package/dist/heap-budget.d.ts.map +1 -0
- package/dist/heap-budget.js +90 -0
- package/dist/heap-budget.js.map +1 -0
- package/dist/heap-shapes.d.ts +148 -0
- package/dist/heap-shapes.d.ts.map +1 -0
- package/dist/heap-shapes.js +193 -0
- package/dist/heap-shapes.js.map +1 -0
- package/dist/heap-state.d.ts +109 -2
- package/dist/heap-state.d.ts.map +1 -1
- package/dist/heap-state.js +194 -3
- package/dist/heap-state.js.map +1 -1
- package/dist/index.js +102 -1
- package/dist/index.js.map +1 -1
- package/dist/progress.d.ts +25 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +46 -0
- package/dist/progress.js.map +1 -0
- package/dist/react-shapes.d.ts +42 -0
- package/dist/react-shapes.d.ts.map +1 -0
- package/dist/react-shapes.js +149 -0
- package/dist/react-shapes.js.map +1 -0
- package/dist/result-handles.d.ts +11 -0
- package/dist/result-handles.d.ts.map +1 -0
- package/dist/result-handles.js +77 -0
- package/dist/result-handles.js.map +1 -0
- package/dist/server-version.d.ts +19 -0
- package/dist/server-version.d.ts.map +1 -0
- package/dist/server-version.js +19 -0
- package/dist/server-version.js.map +1 -0
- package/dist/snapshot-borrow.d.ts +67 -0
- package/dist/snapshot-borrow.d.ts.map +1 -0
- package/dist/snapshot-borrow.js +113 -0
- package/dist/snapshot-borrow.js.map +1 -0
- package/dist/string-index.d.ts +55 -0
- package/dist/string-index.d.ts.map +1 -0
- package/dist/string-index.js +99 -0
- package/dist/string-index.js.map +1 -0
- package/dist/tool-registry.d.ts +42 -0
- package/dist/tool-registry.d.ts.map +1 -0
- package/dist/tool-registry.js +20 -0
- package/dist/tool-registry.js.map +1 -0
- package/dist/tools/analyze-run.d.ts +12 -0
- package/dist/tools/analyze-run.d.ts.map +1 -0
- package/dist/tools/analyze-run.js +404 -0
- package/dist/tools/analyze-run.js.map +1 -0
- package/dist/tools/anonymize-snapshot.d.ts +12 -0
- package/dist/tools/anonymize-snapshot.d.ts.map +1 -0
- package/dist/tools/anonymize-snapshot.js +159 -0
- package/dist/tools/anonymize-snapshot.js.map +1 -0
- package/dist/tools/app-config.d.ts +12 -0
- package/dist/tools/app-config.d.ts.map +1 -0
- package/dist/tools/app-config.js +217 -0
- package/dist/tools/app-config.js.map +1 -0
- package/dist/tools/app-heap.d.ts +30 -0
- package/dist/tools/app-heap.d.ts.map +1 -0
- package/dist/tools/app-heap.js +106 -0
- package/dist/tools/app-heap.js.map +1 -0
- package/dist/tools/artifact-budget.d.ts +12 -0
- package/dist/tools/artifact-budget.d.ts.map +1 -0
- package/dist/tools/artifact-budget.js +219 -0
- package/dist/tools/artifact-budget.js.map +1 -0
- package/dist/tools/async-census.d.ts +12 -0
- package/dist/tools/async-census.d.ts.map +1 -0
- package/dist/tools/async-census.js +243 -0
- package/dist/tools/async-census.js.map +1 -0
- package/dist/tools/auto-investigate.d.ts.map +1 -1
- package/dist/tools/auto-investigate.js +54 -5
- package/dist/tools/auto-investigate.js.map +1 -1
- package/dist/tools/batch.d.ts +12 -0
- package/dist/tools/batch.d.ts.map +1 -0
- package/dist/tools/batch.js +196 -0
- package/dist/tools/batch.js.map +1 -0
- package/dist/tools/cache-analysis.d.ts +15 -0
- package/dist/tools/cache-analysis.d.ts.map +1 -1
- package/dist/tools/cache-analysis.js +240 -14
- package/dist/tools/cache-analysis.js.map +1 -1
- package/dist/tools/census-diff.d.ts +55 -0
- package/dist/tools/census-diff.d.ts.map +1 -0
- package/dist/tools/census-diff.js +228 -0
- package/dist/tools/census-diff.js.map +1 -0
- package/dist/tools/chain-walk.d.ts +12 -0
- package/dist/tools/chain-walk.d.ts.map +1 -0
- package/dist/tools/chain-walk.js +184 -0
- package/dist/tools/chain-walk.js.map +1 -0
- package/dist/tools/class-histogram.d.ts.map +1 -1
- package/dist/tools/class-histogram.js +14 -3
- package/dist/tools/class-histogram.js.map +1 -1
- package/dist/tools/collection-diff.d.ts +44 -0
- package/dist/tools/collection-diff.d.ts.map +1 -0
- package/dist/tools/collection-diff.js +343 -0
- package/dist/tools/collection-diff.js.map +1 -0
- package/dist/tools/collection-trend.d.ts +55 -0
- package/dist/tools/collection-trend.d.ts.map +1 -0
- package/dist/tools/collection-trend.js +315 -0
- package/dist/tools/collection-trend.js.map +1 -0
- package/dist/tools/detached-dom.d.ts +5 -0
- package/dist/tools/detached-dom.d.ts.map +1 -1
- package/dist/tools/detached-dom.js +368 -22
- package/dist/tools/detached-dom.js.map +1 -1
- package/dist/tools/dev-artifacts.d.ts +62 -6
- package/dist/tools/dev-artifacts.d.ts.map +1 -1
- package/dist/tools/dev-artifacts.js +685 -24
- package/dist/tools/dev-artifacts.js.map +1 -1
- package/dist/tools/diff-snapshots.d.ts.map +1 -1
- package/dist/tools/diff-snapshots.js +18 -2
- package/dist/tools/diff-snapshots.js.map +1 -1
- package/dist/tools/dom-audit.d.ts +37 -0
- package/dist/tools/dom-audit.d.ts.map +1 -0
- package/dist/tools/dom-audit.js +247 -0
- package/dist/tools/dom-audit.js.map +1 -0
- package/dist/tools/dominator-attribution.d.ts +12 -0
- package/dist/tools/dominator-attribution.d.ts.map +1 -0
- package/dist/tools/dominator-attribution.js +189 -0
- package/dist/tools/dominator-attribution.js.map +1 -0
- package/dist/tools/dominator-chain.d.ts +12 -0
- package/dist/tools/dominator-chain.d.ts.map +1 -0
- package/dist/tools/dominator-chain.js +92 -0
- package/dist/tools/dominator-chain.js.map +1 -0
- package/dist/tools/duplicate-objects.d.ts +12 -0
- package/dist/tools/duplicate-objects.d.ts.map +1 -0
- package/dist/tools/duplicate-objects.js +172 -0
- package/dist/tools/duplicate-objects.js.map +1 -0
- package/dist/tools/duplicated-strings.d.ts.map +1 -1
- package/dist/tools/duplicated-strings.js +49 -40
- package/dist/tools/duplicated-strings.js.map +1 -1
- package/dist/tools/eval-across.d.ts +12 -0
- package/dist/tools/eval-across.d.ts.map +1 -0
- package/dist/tools/eval-across.js +135 -0
- package/dist/tools/eval-across.js.map +1 -0
- package/dist/tools/eval.d.ts +79 -0
- package/dist/tools/eval.d.ts.map +1 -1
- package/dist/tools/eval.js +2523 -197
- package/dist/tools/eval.js.map +1 -1
- package/dist/tools/event-listener-leaks.d.ts.map +1 -1
- package/dist/tools/event-listener-leaks.js +42 -17
- package/dist/tools/event-listener-leaks.js.map +1 -1
- package/dist/tools/event-registry.d.ts.map +1 -1
- package/dist/tools/event-registry.js +42 -8
- package/dist/tools/event-registry.js.map +1 -1
- package/dist/tools/explain-delta.d.ts +12 -0
- package/dist/tools/explain-delta.d.ts.map +1 -0
- package/dist/tools/explain-delta.js +221 -0
- package/dist/tools/explain-delta.js.map +1 -0
- package/dist/tools/find-nodes-by-class.d.ts.map +1 -1
- package/dist/tools/find-nodes-by-class.js +112 -13
- package/dist/tools/find-nodes-by-class.js.map +1 -1
- package/dist/tools/finding-index.d.ts +203 -0
- package/dist/tools/finding-index.d.ts.map +1 -0
- package/dist/tools/finding-index.js +566 -0
- package/dist/tools/finding-index.js.map +1 -0
- package/dist/tools/for-each.d.ts.map +1 -1
- package/dist/tools/for-each.js +15 -3
- package/dist/tools/for-each.js.map +1 -1
- package/dist/tools/get-referrers.d.ts.map +1 -1
- package/dist/tools/get-referrers.js +17 -0
- package/dist/tools/get-referrers.js.map +1 -1
- package/dist/tools/get-value.d.ts +16 -0
- package/dist/tools/get-value.d.ts.map +1 -1
- package/dist/tools/get-value.js +96 -2
- package/dist/tools/get-value.js.map +1 -1
- package/dist/tools/hunt-report.d.ts +12 -0
- package/dist/tools/hunt-report.d.ts.map +1 -0
- package/dist/tools/hunt-report.js +186 -0
- package/dist/tools/hunt-report.js.map +1 -0
- package/dist/tools/hypothesis.d.ts +12 -0
- package/dist/tools/hypothesis.d.ts.map +1 -0
- package/dist/tools/hypothesis.js +280 -0
- package/dist/tools/hypothesis.js.map +1 -0
- package/dist/tools/id-space-audit.d.ts +12 -0
- package/dist/tools/id-space-audit.d.ts.map +1 -0
- package/dist/tools/id-space-audit.js +262 -0
- package/dist/tools/id-space-audit.js.map +1 -0
- package/dist/tools/identify.d.ts +12 -0
- package/dist/tools/identify.d.ts.map +1 -0
- package/dist/tools/identify.js +205 -0
- package/dist/tools/identify.js.map +1 -0
- package/dist/tools/identity-diff.d.ts +12 -0
- package/dist/tools/identity-diff.d.ts.map +1 -0
- package/dist/tools/identity-diff.js +188 -0
- package/dist/tools/identity-diff.js.map +1 -0
- package/dist/tools/intern-opportunities.d.ts.map +1 -1
- package/dist/tools/intern-opportunities.js +116 -50
- package/dist/tools/intern-opportunities.js.map +1 -1
- package/dist/tools/ladder-probe.d.ts +65 -0
- package/dist/tools/ladder-probe.d.ts.map +1 -0
- package/dist/tools/ladder-probe.js +445 -0
- package/dist/tools/ladder-probe.js.map +1 -0
- package/dist/tools/ladder.d.ts +33 -0
- package/dist/tools/ladder.d.ts.map +1 -0
- package/dist/tools/ladder.js +266 -0
- package/dist/tools/ladder.js.map +1 -0
- package/dist/tools/largest-objects.d.ts.map +1 -1
- package/dist/tools/largest-objects.js +6 -2
- package/dist/tools/largest-objects.js.map +1 -1
- package/dist/tools/leak-report.d.ts +35 -0
- package/dist/tools/leak-report.d.ts.map +1 -0
- package/dist/tools/leak-report.js +398 -0
- package/dist/tools/leak-report.js.map +1 -0
- package/dist/tools/load-snapshot.d.ts +29 -0
- package/dist/tools/load-snapshot.d.ts.map +1 -1
- package/dist/tools/load-snapshot.js +294 -23
- package/dist/tools/load-snapshot.js.map +1 -1
- package/dist/tools/map-entries.d.ts +12 -0
- package/dist/tools/map-entries.d.ts.map +1 -0
- package/dist/tools/map-entries.js +139 -0
- package/dist/tools/map-entries.js.map +1 -0
- package/dist/tools/match-object.d.ts +12 -0
- package/dist/tools/match-object.d.ts.map +1 -0
- package/dist/tools/match-object.js +165 -0
- package/dist/tools/match-object.js.map +1 -0
- package/dist/tools/metric.d.ts +13 -0
- package/dist/tools/metric.d.ts.map +1 -0
- package/dist/tools/metric.js +185 -0
- package/dist/tools/metric.js.map +1 -0
- package/dist/tools/module-attribution.d.ts +36 -0
- package/dist/tools/module-attribution.d.ts.map +1 -0
- package/dist/tools/module-attribution.js +235 -0
- package/dist/tools/module-attribution.js.map +1 -0
- package/dist/tools/next-measurement.d.ts +26 -0
- package/dist/tools/next-measurement.d.ts.map +1 -0
- package/dist/tools/next-measurement.js +149 -0
- package/dist/tools/next-measurement.js.map +1 -0
- package/dist/tools/object-cost-breakdown.d.ts.map +1 -1
- package/dist/tools/object-cost-breakdown.js +64 -0
- package/dist/tools/object-cost-breakdown.js.map +1 -1
- package/dist/tools/object-shape.d.ts.map +1 -1
- package/dist/tools/object-shape.js +53 -5
- package/dist/tools/object-shape.js.map +1 -1
- package/dist/tools/population-diff.d.ts +57 -0
- package/dist/tools/population-diff.d.ts.map +1 -0
- package/dist/tools/population-diff.js +338 -0
- package/dist/tools/population-diff.js.map +1 -0
- package/dist/tools/population-vs-owners.d.ts +12 -0
- package/dist/tools/population-vs-owners.d.ts.map +1 -0
- package/dist/tools/population-vs-owners.js +183 -0
- package/dist/tools/population-vs-owners.js.map +1 -0
- package/dist/tools/property-names.d.ts +29 -0
- package/dist/tools/property-names.d.ts.map +1 -0
- package/dist/tools/property-names.js +131 -0
- package/dist/tools/property-names.js.map +1 -0
- package/dist/tools/quick-diagnosis.d.ts.map +1 -1
- package/dist/tools/quick-diagnosis.js +7 -1
- package/dist/tools/quick-diagnosis.js.map +1 -1
- package/dist/tools/react-owners.d.ts +12 -0
- package/dist/tools/react-owners.d.ts.map +1 -0
- package/dist/tools/react-owners.js +167 -0
- package/dist/tools/react-owners.js.map +1 -0
- package/dist/tools/react-update-queues.d.ts +12 -0
- package/dist/tools/react-update-queues.d.ts.map +1 -0
- package/dist/tools/react-update-queues.js +173 -0
- package/dist/tools/react-update-queues.js.map +1 -0
- package/dist/tools/replicate.d.ts +49 -0
- package/dist/tools/replicate.d.ts.map +1 -0
- package/dist/tools/replicate.js +241 -0
- package/dist/tools/replicate.js.map +1 -0
- package/dist/tools/retainer-diff.d.ts +12 -0
- package/dist/tools/retainer-diff.d.ts.map +1 -0
- package/dist/tools/retainer-diff.js +168 -0
- package/dist/tools/retainer-diff.js.map +1 -0
- package/dist/tools/retainer-layers.d.ts +23 -0
- package/dist/tools/retainer-layers.d.ts.map +1 -0
- package/dist/tools/retainer-layers.js +179 -0
- package/dist/tools/retainer-layers.js.map +1 -0
- package/dist/tools/retainer-summary.d.ts +18 -0
- package/dist/tools/retainer-summary.d.ts.map +1 -1
- package/dist/tools/retainer-summary.js +210 -51
- package/dist/tools/retainer-summary.js.map +1 -1
- package/dist/tools/retainer-trace.d.ts.map +1 -1
- package/dist/tools/retainer-trace.js +14 -2
- package/dist/tools/retainer-trace.js.map +1 -1
- package/dist/tools/round-audit.d.ts +66 -0
- package/dist/tools/round-audit.d.ts.map +1 -0
- package/dist/tools/round-audit.js +258 -0
- package/dist/tools/round-audit.js.map +1 -0
- package/dist/tools/round-digest.d.ts +12 -0
- package/dist/tools/round-digest.d.ts.map +1 -0
- package/dist/tools/round-digest.js +190 -0
- package/dist/tools/round-digest.js.map +1 -0
- package/dist/tools/script-census.d.ts +12 -0
- package/dist/tools/script-census.d.ts.map +1 -0
- package/dist/tools/script-census.js +182 -0
- package/dist/tools/script-census.js.map +1 -0
- package/dist/tools/search-nodes.d.ts.map +1 -1
- package/dist/tools/search-nodes.js +5 -1
- package/dist/tools/search-nodes.js.map +1 -1
- package/dist/tools/search-strings.d.ts.map +1 -1
- package/dist/tools/search-strings.js +53 -7
- package/dist/tools/search-strings.js.map +1 -1
- package/dist/tools/sequence-analysis.d.ts +53 -0
- package/dist/tools/sequence-analysis.d.ts.map +1 -1
- package/dist/tools/sequence-analysis.js +313 -89
- package/dist/tools/sequence-analysis.js.map +1 -1
- package/dist/tools/server-status.d.ts.map +1 -1
- package/dist/tools/server-status.js +4 -1
- package/dist/tools/server-status.js.map +1 -1
- package/dist/tools/settle-check.d.ts +12 -0
- package/dist/tools/settle-check.d.ts.map +1 -0
- package/dist/tools/settle-check.js +188 -0
- package/dist/tools/settle-check.js.map +1 -0
- package/dist/tools/shape-histogram.d.ts.map +1 -1
- package/dist/tools/shape-histogram.js +9 -2
- package/dist/tools/shape-histogram.js.map +1 -1
- package/dist/tools/sliced-strings.d.ts.map +1 -1
- package/dist/tools/sliced-strings.js +2 -1
- package/dist/tools/sliced-strings.js.map +1 -1
- package/dist/tools/snapshots.d.ts.map +1 -1
- package/dist/tools/snapshots.js +24 -6
- package/dist/tools/snapshots.js.map +1 -1
- package/dist/tools/sparse-elements.d.ts +12 -0
- package/dist/tools/sparse-elements.d.ts.map +1 -0
- package/dist/tools/sparse-elements.js +215 -0
- package/dist/tools/sparse-elements.js.map +1 -0
- package/dist/tools/stale-collections.d.ts +17 -0
- package/dist/tools/stale-collections.d.ts.map +1 -1
- package/dist/tools/stale-collections.js +28 -0
- package/dist/tools/stale-collections.js.map +1 -1
- package/dist/tools/string-patterns.d.ts.map +1 -1
- package/dist/tools/string-patterns.js +7 -5
- package/dist/tools/string-patterns.js.map +1 -1
- package/dist/tools/tools-index.d.ts +12 -0
- package/dist/tools/tools-index.d.ts.map +1 -0
- package/dist/tools/tools-index.js +492 -0
- package/dist/tools/tools-index.js.map +1 -0
- package/dist/tools/trace-all.d.ts +42 -0
- package/dist/tools/trace-all.d.ts.map +1 -0
- package/dist/tools/trace-all.js +263 -0
- package/dist/tools/trace-all.js.map +1 -0
- package/dist/tools/unit-cost.d.ts +12 -0
- package/dist/tools/unit-cost.d.ts.map +1 -0
- package/dist/tools/unit-cost.js +219 -0
- package/dist/tools/unit-cost.js.map +1 -0
- package/dist/tools/verify-fix.d.ts +23 -0
- package/dist/tools/verify-fix.d.ts.map +1 -0
- package/dist/tools/verify-fix.js +219 -0
- package/dist/tools/verify-fix.js.map +1 -0
- package/dist/tools/weakmap-entries.d.ts.map +1 -1
- package/dist/tools/weakmap-entries.js +6 -1
- package/dist/tools/weakmap-entries.js.map +1 -1
- package/dist/tools/weakref-census.d.ts +15 -0
- package/dist/tools/weakref-census.d.ts.map +1 -0
- package/dist/tools/weakref-census.js +147 -0
- package/dist/tools/weakref-census.js.map +1 -0
- package/dist/tools/what-if.d.ts +12 -0
- package/dist/tools/what-if.d.ts.map +1 -0
- package/dist/tools/what-if.js +285 -0
- package/dist/tools/what-if.js.map +1 -0
- package/dist/utils.d.ts +238 -3
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +507 -15
- package/dist/utils.js.map +1 -1
- package/package.json +7 -6
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall memory_lab
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Registry of heap classes whose growth is a MEASUREMENT artifact rather than an
|
|
12
|
+
* application leak.
|
|
13
|
+
*
|
|
14
|
+
* Motivation: across a six-round leak hunt, every single class reported at the
|
|
15
|
+
* top of `sequence_analysis` as "↑ every step (LEAK signal)" belonged to one of
|
|
16
|
+
* the families below — CDP inspector bookkeeping, V8 JIT warmup, or captured
|
|
17
|
+
* error stacks. None was ever a leak. An agent that does not already know this
|
|
18
|
+
* list reads the label and reports a false leak, which is exactly what happened
|
|
19
|
+
* repeatedly before the families were catalogued.
|
|
20
|
+
*
|
|
21
|
+
* These are deliberately matched on CLASS NAME only. Name matching cannot prove
|
|
22
|
+
* that a given instance is an artifact, so the classification is used to
|
|
23
|
+
* annotate and down-rank rows — never to hide them outright (callers can always
|
|
24
|
+
* pass `include_artifacts: true`). Anything that is genuinely ambiguous is left
|
|
25
|
+
* unclassified on purpose: a false "this is an artifact" is far more damaging
|
|
26
|
+
* than a false "this might be a leak".
|
|
27
|
+
*/
|
|
28
|
+
export type ArtifactKind = 'warmup' | 'ax' | 'cdp-network' | 'cdp-perf' | 'cdp-console' | 'stack-capture';
|
|
29
|
+
export declare function artifactLabel(kind: ArtifactKind): string;
|
|
30
|
+
export declare function artifactNote(kind: ArtifactKind): string;
|
|
31
|
+
/**
|
|
32
|
+
* Where a non-production string came from. Both kinds are equally unshippable,
|
|
33
|
+
* but they call for different follow-up: `harness` means re-run without the
|
|
34
|
+
* bridge attached to measure the app cleanly, `dev-build` means measure a
|
|
35
|
+
* production build.
|
|
36
|
+
*/
|
|
37
|
+
export type NonProductionStringKind = 'harness' | 'dev-build';
|
|
38
|
+
/**
|
|
39
|
+
* Classify a string VALUE as non-production (harness-injected or DEV-build
|
|
40
|
+
* only), or null when it is app content that really does ship.
|
|
41
|
+
*/
|
|
42
|
+
export declare function classifyNonProductionString(value: string): {
|
|
43
|
+
kind: NonProductionStringKind;
|
|
44
|
+
what: string;
|
|
45
|
+
} | null;
|
|
46
|
+
/**
|
|
47
|
+
* Back-compatible wrapper returning just the description. Prefer
|
|
48
|
+
* {@link classifyNonProductionString} when the caller can act on the kind.
|
|
49
|
+
*/
|
|
50
|
+
export declare function classifyHarnessString(value: string): string | null;
|
|
51
|
+
/**
|
|
52
|
+
* React Fast Refresh module-scope registries, by the edge name that binds each
|
|
53
|
+
* one. These live in the refresh runtime's closure and are reachable only
|
|
54
|
+
* through compiled-code constant pools, so a retainer-root scan does not find
|
|
55
|
+
* them and they classify as `production` unless matched by name here. See
|
|
56
|
+
* `tools/dev-artifacts` for the measured cost of missing them.
|
|
57
|
+
*/
|
|
58
|
+
export declare const REACT_REFRESH_REGISTRY_EDGE_NAMES: ReadonlySet<string>;
|
|
59
|
+
/**
|
|
60
|
+
* The rarest property of the react-refresh signature record. Callers gate on
|
|
61
|
+
* this before confirming the full shape, so a scan stays one name compare per
|
|
62
|
+
* edge on everything else.
|
|
63
|
+
*/
|
|
64
|
+
export declare const REACT_REFRESH_SIGNATURE_GATE_PROP = "getCustomHooks";
|
|
65
|
+
/**
|
|
66
|
+
* Recognize the per-type signature record react-refresh stores via
|
|
67
|
+
* `setSignature(type, key, forceReset, getCustomHooks)` — the value side of
|
|
68
|
+
* `allSignaturesByType`, shaped `{forceReset, ownKey, fullKey, getCustomHooks}`.
|
|
69
|
+
*/
|
|
70
|
+
export declare function isReactRefreshSignatureShape(propNames: Iterable<string>): boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Recognize the parent object SHAPE of an MCP/devtools tool manifest entry.
|
|
73
|
+
*
|
|
74
|
+
* The bridge's tool definitions carry long `.description` strings — one per tool
|
|
75
|
+
* — and a per-load intern pool would happily "save" them. The shape is
|
|
76
|
+
* distinctive enough to match directly, and matching the shape (rather than the
|
|
77
|
+
* description text) keeps app strings that merely have a `description` property
|
|
78
|
+
* out of it.
|
|
79
|
+
*/
|
|
80
|
+
export declare function isHarnessToolManifestShape(propNames: ReadonlyArray<string>): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Classify a class NAME as a known measurement artifact, or null when it is a
|
|
83
|
+
* genuine leak candidate.
|
|
84
|
+
*/
|
|
85
|
+
export declare function classifyArtifact(name: string): ArtifactKind | null;
|
|
86
|
+
//# sourceMappingURL=artifact-classes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-classes.d.ts","sourceRoot":"","sources":["../src/artifact-classes.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,MAAM,YAAY,GACpB,QAAQ,GACR,IAAI,GACJ,aAAa,GACb,UAAU,GACV,aAAa,GACb,eAAe,CAAC;AAwGpB,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAExD;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,GAAG,MAAM,CAEvD;AAED;;;;;GAKG;AACH,MAAM,MAAM,uBAAuB,GAAG,SAAS,GAAG,WAAW,CAAC;AAkE9D;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,KAAK,EAAE,MAAM,GACZ;IAAC,IAAI,EAAE,uBAAuB,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,GAAG,IAAI,CAKtD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAElE;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iCAAiC,EAAE,WAAW,CAAC,MAAM,CAWhE,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,mBAAmB,CAAC;AASlE;;;;GAIG;AACH,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,GAC1B,OAAO,CAOT;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,aAAa,CAAC,MAAM,CAAC,GAC/B,OAAO,CAQT;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CASlE"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall memory_lab
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* V8 internal structures emitted while JIT-compiling and warming up code paths.
|
|
12
|
+
* Exercising NEW interactions during a hunt compiles new functions, so this
|
|
13
|
+
* whole family climbs "every step" without being an app leak.
|
|
14
|
+
*
|
|
15
|
+
* Note what is deliberately NOT here: `PropertyArray`, `DescriptorArray`,
|
|
16
|
+
* `(object elements)`, `(object properties)`, `Context`. Those grow with real
|
|
17
|
+
* application objects and suppressing them would hide genuine leaks.
|
|
18
|
+
*/
|
|
19
|
+
const WARMUP_CLASS_NAMES = new Set([
|
|
20
|
+
'InstructionStream',
|
|
21
|
+
'Code',
|
|
22
|
+
'CodeDataContainer',
|
|
23
|
+
'CodeWrapper',
|
|
24
|
+
'BytecodeArray',
|
|
25
|
+
'BytecodeWrapper',
|
|
26
|
+
'FeedbackVector',
|
|
27
|
+
'FeedbackMetadata',
|
|
28
|
+
'FeedbackCell',
|
|
29
|
+
'ClosureFeedbackCellArray',
|
|
30
|
+
'ScopeInfo',
|
|
31
|
+
'SharedFunctionInfo',
|
|
32
|
+
'SharedFunctionInfoWrapper',
|
|
33
|
+
'UncompiledDataWithoutPreparseData',
|
|
34
|
+
'UncompiledDataWithPreparseData',
|
|
35
|
+
'InterpreterData',
|
|
36
|
+
'TrustedByteArray',
|
|
37
|
+
'ProtectedFixedArray',
|
|
38
|
+
'TrustedWeakFixedArray',
|
|
39
|
+
'WeakArrayList',
|
|
40
|
+
'LoadHandler',
|
|
41
|
+
'StoreHandler',
|
|
42
|
+
'AllocationSite',
|
|
43
|
+
'ConstantPool',
|
|
44
|
+
'(constant pool)',
|
|
45
|
+
'ObjectBoilerplateDescription',
|
|
46
|
+
]);
|
|
47
|
+
/**
|
|
48
|
+
* Blink accessibility caches, materialized by CDP-driven automation.
|
|
49
|
+
*/
|
|
50
|
+
const AX_NAME_RE = /AXObjectCache|AXNodeObject|AXDirtyObject|AXComputedObject|blink::AX/;
|
|
51
|
+
/**
|
|
52
|
+
* The attached inspector's network log. Every request the page makes while CDP
|
|
53
|
+
* is attached is retained by `blink::InspectorNetworkAgent` for the lifetime of
|
|
54
|
+
* the session, so on a dev build that polls (hot reload, long-poll transports)
|
|
55
|
+
* this climbs forever. Retained by the DevToolsSession, not by the app.
|
|
56
|
+
*/
|
|
57
|
+
const CDP_NETWORK_NAME_RE = /NetworkResourcesData|XHRReplayData|InspectorNetworkAgent|PerformanceResourceTiming|^URI$/;
|
|
58
|
+
/**
|
|
59
|
+
* The inspector's performance timeline. Long-task/layout-shift/script-timing
|
|
60
|
+
* entries accumulate only because something is observing them.
|
|
61
|
+
*/
|
|
62
|
+
const CDP_PERF_NAME_RE = /PerformanceLongTaskTiming|PerformanceLongAnimationFrameTiming|PerformanceScriptTiming|TaskAttributionTiming|ScriptTimingInfo|^LayoutShift$|LayoutShiftAttribution/;
|
|
63
|
+
/**
|
|
64
|
+
* Console message storage held by the inspector. Distinct from
|
|
65
|
+
* `dev_artifacts`' console detection, which works on retainer edges: this
|
|
66
|
+
* catches the native message objects by class name.
|
|
67
|
+
*/
|
|
68
|
+
const CDP_CONSOLE_NAME_RE = /ConsoleMessage/;
|
|
69
|
+
/**
|
|
70
|
+
* Captured error stacks. `StackFrameInfo` / `ErrorStackData` balloon when
|
|
71
|
+
* something constructs `Error`s at high frequency — most often React's DEV-only
|
|
72
|
+
* `_debugStack` owner stacks (see the `reactDebugStack` detector in
|
|
73
|
+
* `dev-artifacts`), or dev-build logging that captures a stack per record.
|
|
74
|
+
*
|
|
75
|
+
* Flagged as `stack-capture` rather than asserted dev-only: a production build
|
|
76
|
+
* can legitimately grow these, so the annotation points at the likely cause
|
|
77
|
+
* instead of dismissing the row.
|
|
78
|
+
*/
|
|
79
|
+
const STACK_CAPTURE_NAME_RE = /StackFrameInfo|ErrorStackData/;
|
|
80
|
+
const KIND_LABEL = {
|
|
81
|
+
warmup: '⚙ JIT/compile warmup (not a leak)',
|
|
82
|
+
ax: '♿ a11y/CDP cache (automation artifact)',
|
|
83
|
+
'cdp-network': '🔌 CDP network-inspector retention (artifact)',
|
|
84
|
+
'cdp-perf': '🔌 CDP performance-timeline retention (artifact)',
|
|
85
|
+
'cdp-console': '🔌 CDP console retention (artifact)',
|
|
86
|
+
'stack-capture': '🧵 captured Error stacks (often React DEV _debugStack)',
|
|
87
|
+
};
|
|
88
|
+
const KIND_NOTE = {
|
|
89
|
+
warmup: '⚙️ V8 **compilation-warmup** structures (`Code`, `BytecodeArray`, `FeedbackVector`, `ScopeInfo`, `InstructionStream`, …) are growing. Exercising new code paths during a hunt JIT-compiles them, so they climb every step without being an app leak.',
|
|
90
|
+
ax: '♿ Blink **accessibility caches** (`AXObjectCacheImpl` / `AXNodeObject` / `AXDirtyObject`) are growing. These are inflated by CDP-driven automation building the a11y tree, and they co-retain detached DOM, so retainer traces can route through them and mislead.',
|
|
91
|
+
'cdp-network': '🔌 The attached inspector is retaining the **network log** (`blink::NetworkResourcesData` / `XHRReplayData` / `PerformanceResourceTiming`). Every request made while CDP is attached is held by `blink::DevToolsSession → InspectorNetworkAgent` for the session, so a dev build that polls (hot reload, long-poll transports) grows this forever. Not app memory.',
|
|
92
|
+
'cdp-perf': '🔌 The attached inspector is retaining the **performance timeline** (long-task / layout-shift / script-timing entries). These accumulate because something is observing them, not because the app leaks.',
|
|
93
|
+
'cdp-console': '🔌 The attached inspector is retaining **console messages**. Cross-check with `memlab_dev_artifacts`, which also detects console retention by retainer edge.',
|
|
94
|
+
'stack-capture': '🧵 **Captured Error stacks** (`StackFrameInfo` / `ErrorStackData`) are growing. The usual cause is React DEV `_debugStack` owner stacks or dev-build logging that captures a stack per record — both dev-build-only. `memlab_dev_artifacts` reports the `React DEV owner stack` category when that is the source.',
|
|
95
|
+
};
|
|
96
|
+
export function artifactLabel(kind) {
|
|
97
|
+
return KIND_LABEL[kind];
|
|
98
|
+
}
|
|
99
|
+
export function artifactNote(kind) {
|
|
100
|
+
return KIND_NOTE[kind];
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Content signatures of strings that do NOT ship: the CDP-driven bridge the
|
|
104
|
+
* agent injects to observe the page (browser MCP plugin, browser-tools
|
|
105
|
+
* extension, Puppeteer helpers), and DEV-build-only framework machinery.
|
|
106
|
+
*
|
|
107
|
+
* Why this needs its own classifier, separate from `classifyArtifact`: these are
|
|
108
|
+
* matched on string CONTENT, not on a class name, and they are not reachable
|
|
109
|
+
* from a dev *global*, so neither the class-name registry above nor
|
|
110
|
+
* `dev_artifacts`' root scan sees them.
|
|
111
|
+
*
|
|
112
|
+
* Why it matters: on a measured WA Web round the injected bridge bundle appeared
|
|
113
|
+
* as 64 copies of one 235.6 KB string — 14.7 MB total, the single largest entry
|
|
114
|
+
* in `duplicated_strings` and the single largest "opportunity" in
|
|
115
|
+
* `intern_opportunities`. Interning it would save the application nothing,
|
|
116
|
+
* because none of it ships. Reporting it as a win is worse than not reporting it
|
|
117
|
+
* at all: it sends a fix author after the test rig. The React DEV entries below
|
|
118
|
+
* were the same story a round later: 4,529 `_debugStack` Error stacks, 3.0 MB,
|
|
119
|
+
* none of which exist in a production build.
|
|
120
|
+
*
|
|
121
|
+
* Every pattern here has to be specific enough that application source cannot
|
|
122
|
+
* match it — a false "this doesn't ship" hides a real win, which is the more
|
|
123
|
+
* expensive direction to be wrong in for THIS classifier (the opposite of
|
|
124
|
+
* `classifyArtifact`, where a false artifact hides a real leak).
|
|
125
|
+
*/
|
|
126
|
+
const NON_PRODUCTION_STRING_SIGNATURES = [
|
|
127
|
+
{
|
|
128
|
+
// The UMD/CommonJS prologue every bundled bridge is wrapped in. Anchored at
|
|
129
|
+
// the start and required to reach `commonjsGlobal` within the prologue, so
|
|
130
|
+
// ordinary application source strings do not match.
|
|
131
|
+
re: /^\(function\s*\(exports\)\s*\{[\s\S]{0,400}commonjsGlobal/,
|
|
132
|
+
kind: 'harness',
|
|
133
|
+
what: 'injected CommonJS bundle (automation/devtools bridge)',
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
re: /^\s*at (?:Object\.)?__PUPPETEER|puppeteer_evaluation_script/,
|
|
137
|
+
kind: 'harness',
|
|
138
|
+
what: 'Puppeteer evaluation frame',
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
// react-dom DEV names the frames it inserts into owner stacks
|
|
142
|
+
// `react-stack-top-frame` / `react-stack-bottom-frame`, in hyphenated and
|
|
143
|
+
// underscored spellings depending on the build. BOTH ends must be matched:
|
|
144
|
+
// measured on one 2.5M-node capture, `react-stack-top-frame` appears 56
|
|
145
|
+
// times and `react_stack_bottom_frame` twice, so a bottom-only pattern
|
|
146
|
+
// misses the dominant form and classifies most DEV owner stacks as
|
|
147
|
+
// production. The hyphenated spelling cannot be a JS identifier, so it only
|
|
148
|
+
// ever appears inside a captured stack string.
|
|
149
|
+
re: /react[-_]stack[-_](?:top|bottom)[-_]frame/,
|
|
150
|
+
kind: 'dev-build',
|
|
151
|
+
what: 'React DEV owner stack (_debugStack) — not captured in production',
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
// A compiled DEV module's Fast Refresh epilogue. Requires the call form, so
|
|
155
|
+
// a string that merely mentions the identifier does not match.
|
|
156
|
+
re: /\$RefreshReg\$\(|\$RefreshSig\$\(/,
|
|
157
|
+
kind: 'dev-build',
|
|
158
|
+
what: 'React Fast Refresh instrumentation in compiled source (DEV bundle only)',
|
|
159
|
+
},
|
|
160
|
+
];
|
|
161
|
+
/**
|
|
162
|
+
* Classify a string VALUE as non-production (harness-injected or DEV-build
|
|
163
|
+
* only), or null when it is app content that really does ship.
|
|
164
|
+
*/
|
|
165
|
+
export function classifyNonProductionString(value) {
|
|
166
|
+
for (const { re, kind, what } of NON_PRODUCTION_STRING_SIGNATURES) {
|
|
167
|
+
if (re.test(value))
|
|
168
|
+
return { kind, what };
|
|
169
|
+
}
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Back-compatible wrapper returning just the description. Prefer
|
|
174
|
+
* {@link classifyNonProductionString} when the caller can act on the kind.
|
|
175
|
+
*/
|
|
176
|
+
export function classifyHarnessString(value) {
|
|
177
|
+
return classifyNonProductionString(value)?.what ?? null;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* React Fast Refresh module-scope registries, by the edge name that binds each
|
|
181
|
+
* one. These live in the refresh runtime's closure and are reachable only
|
|
182
|
+
* through compiled-code constant pools, so a retainer-root scan does not find
|
|
183
|
+
* them and they classify as `production` unless matched by name here. See
|
|
184
|
+
* `tools/dev-artifacts` for the measured cost of missing them.
|
|
185
|
+
*/
|
|
186
|
+
export const REACT_REFRESH_REGISTRY_EDGE_NAMES = new Set([
|
|
187
|
+
'allFamiliesByID',
|
|
188
|
+
'allFamiliesByType',
|
|
189
|
+
'allSignaturesByType',
|
|
190
|
+
'updatedFamiliesByType',
|
|
191
|
+
'pendingUpdates',
|
|
192
|
+
'helpersByRendererID',
|
|
193
|
+
'helpersByRoot',
|
|
194
|
+
'mountedRoots',
|
|
195
|
+
'failedRoots',
|
|
196
|
+
'rootElements',
|
|
197
|
+
]);
|
|
198
|
+
/**
|
|
199
|
+
* The rarest property of the react-refresh signature record. Callers gate on
|
|
200
|
+
* this before confirming the full shape, so a scan stays one name compare per
|
|
201
|
+
* edge on everything else.
|
|
202
|
+
*/
|
|
203
|
+
export const REACT_REFRESH_SIGNATURE_GATE_PROP = 'getCustomHooks';
|
|
204
|
+
const REACT_REFRESH_SIGNATURE_PROPS = [
|
|
205
|
+
'forceReset',
|
|
206
|
+
'ownKey',
|
|
207
|
+
'fullKey',
|
|
208
|
+
'getCustomHooks',
|
|
209
|
+
];
|
|
210
|
+
/**
|
|
211
|
+
* Recognize the per-type signature record react-refresh stores via
|
|
212
|
+
* `setSignature(type, key, forceReset, getCustomHooks)` — the value side of
|
|
213
|
+
* `allSignaturesByType`, shaped `{forceReset, ownKey, fullKey, getCustomHooks}`.
|
|
214
|
+
*/
|
|
215
|
+
export function isReactRefreshSignatureShape(propNames) {
|
|
216
|
+
const seen = new Set();
|
|
217
|
+
for (const name of propNames) {
|
|
218
|
+
if (REACT_REFRESH_SIGNATURE_PROPS.includes(name))
|
|
219
|
+
seen.add(name);
|
|
220
|
+
if (seen.size === REACT_REFRESH_SIGNATURE_PROPS.length)
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Recognize the parent object SHAPE of an MCP/devtools tool manifest entry.
|
|
227
|
+
*
|
|
228
|
+
* The bridge's tool definitions carry long `.description` strings — one per tool
|
|
229
|
+
* — and a per-load intern pool would happily "save" them. The shape is
|
|
230
|
+
* distinctive enough to match directly, and matching the shape (rather than the
|
|
231
|
+
* description text) keeps app strings that merely have a `description` property
|
|
232
|
+
* out of it.
|
|
233
|
+
*/
|
|
234
|
+
export function isHarnessToolManifestShape(propNames) {
|
|
235
|
+
const props = new Set(propNames);
|
|
236
|
+
return (props.has('description') &&
|
|
237
|
+
props.has('inputSchema') &&
|
|
238
|
+
(props.has('call') || props.has('handler')) &&
|
|
239
|
+
props.has('name'));
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Classify a class NAME as a known measurement artifact, or null when it is a
|
|
243
|
+
* genuine leak candidate.
|
|
244
|
+
*/
|
|
245
|
+
export function classifyArtifact(name) {
|
|
246
|
+
const bare = name.replace(/^system \/ /, '');
|
|
247
|
+
if (WARMUP_CLASS_NAMES.has(bare))
|
|
248
|
+
return 'warmup';
|
|
249
|
+
if (AX_NAME_RE.test(name))
|
|
250
|
+
return 'ax';
|
|
251
|
+
if (CDP_NETWORK_NAME_RE.test(bare))
|
|
252
|
+
return 'cdp-network';
|
|
253
|
+
if (CDP_PERF_NAME_RE.test(bare))
|
|
254
|
+
return 'cdp-perf';
|
|
255
|
+
if (CDP_CONSOLE_NAME_RE.test(bare))
|
|
256
|
+
return 'cdp-console';
|
|
257
|
+
if (STACK_CAPTURE_NAME_RE.test(bare))
|
|
258
|
+
return 'stack-capture';
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=artifact-classes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-classes.js","sourceRoot":"","sources":["../src/artifact-classes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall memory_lab
|
|
9
|
+
*/
|
|
10
|
+
import type { SnapshotEnv } from './heap-state.js';
|
|
11
|
+
/**
|
|
12
|
+
* Was this snapshot captured with numeric-value capture on?
|
|
13
|
+
*
|
|
14
|
+
* Background: `heap number` is a perennial top grower, and the standing advice
|
|
15
|
+
* was "that is probably a capture artifact — check whether you captured with
|
|
16
|
+
* numeric values on". That advice pushed a decision onto the caller that the
|
|
17
|
+
* caller usually cannot answer (the snapshot may be days old, or captured by
|
|
18
|
+
* someone else), and it rested on a mechanism that was never measured.
|
|
19
|
+
*
|
|
20
|
+
* It was measured for this change, with matched pairs — the same program/page,
|
|
21
|
+
* two snapshots differing ONLY in the `captureNumericValue` CDP flag:
|
|
22
|
+
*
|
|
23
|
+
* - **Node.js** (`inspector` → `HeapProfiler.takeHeapSnapshot`): the flag adds
|
|
24
|
+
* `smi number` nodes and nothing else. Off: 10,100 number nodes, zero of them
|
|
25
|
+
* `smi number`. On: 10,390, of which 290 `smi number`. `heap number` was
|
|
26
|
+
* IDENTICAL at 10,100 in both. Smis are immediate values, not heap objects,
|
|
27
|
+
* so they only become graph nodes when the flag asks V8 to materialize them —
|
|
28
|
+
* which makes their presence a sound detector here.
|
|
29
|
+
* - **Chrome**: no detectable difference at all. On a page holding 20,000
|
|
30
|
+
* objects each with a double and a Smi field, on and off produced the same
|
|
31
|
+
* populations to the node: 40,026 `heap number`, 20,000 `smi number`, 1,063
|
|
32
|
+
* `int`. Chrome emits `smi number` either way, so the Node detector does not
|
|
33
|
+
* transfer, and no other field varies.
|
|
34
|
+
*
|
|
35
|
+
* Neither environment ever encodes the numeric VALUE in the node name (0
|
|
36
|
+
* value-named number nodes across all four snapshots), so name-based detection
|
|
37
|
+
* — the approach a previous round tried and rejected — cannot work in principle.
|
|
38
|
+
*
|
|
39
|
+
* Two consequences, both of which change what the tools should say:
|
|
40
|
+
* 1. For a BROWSER snapshot the question is not merely unanswerable, it is
|
|
41
|
+
* moot: the flag changes nothing, so `heap number` growth in a browser
|
|
42
|
+
* capture is never a numeric-capture artifact and must be investigated as
|
|
43
|
+
* real.
|
|
44
|
+
* 2. The old claim that the mode "emits one node per distinct number and ~3x
|
|
45
|
+
* inflates the graph" is not what was measured in either environment.
|
|
46
|
+
*/
|
|
47
|
+
export type NumericCaptureMode = 'on' | 'off' | 'not-applicable' | 'unknown';
|
|
48
|
+
export interface NumericCaptureVerdict {
|
|
49
|
+
mode: NumericCaptureMode;
|
|
50
|
+
/** One sentence stating the answer, for direct inclusion in a tool result. */
|
|
51
|
+
note: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* @param env which runtime produced the snapshot
|
|
55
|
+
* @param hasSmiNumberNodes whether any `smi number` node is present
|
|
56
|
+
*/
|
|
57
|
+
export declare function classifyNumericCapture(env: SnapshotEnv, hasSmiNumberNodes: boolean): NumericCaptureVerdict;
|
|
58
|
+
/** Class-histogram key for the marker node type, as `type::name`. */
|
|
59
|
+
export declare const SMI_NUMBER_CLASS_KEY = "number::smi number";
|
|
60
|
+
//# sourceMappingURL=capture-mode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-mode.d.ts","sourceRoot":"","sources":["../src/capture-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,iBAAiB,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,KAAK,GAAG,gBAAgB,GAAG,SAAS,CAAC;AAE7E,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,kBAAkB,CAAC;IACzB,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,WAAW,EAChB,iBAAiB,EAAE,OAAO,GACzB,qBAAqB,CAsBvB;AAED,qEAAqE;AACrE,eAAO,MAAM,oBAAoB,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall memory_lab
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* @param env which runtime produced the snapshot
|
|
12
|
+
* @param hasSmiNumberNodes whether any `smi number` node is present
|
|
13
|
+
*/
|
|
14
|
+
export function classifyNumericCapture(env, hasSmiNumberNodes) {
|
|
15
|
+
if (env === 'browser') {
|
|
16
|
+
return {
|
|
17
|
+
mode: 'not-applicable',
|
|
18
|
+
note: 'This is a **browser** capture, where `capture_numeric_value` makes no difference to the snapshot: a matched pair taken with the flag on and off produced identical number-node populations (40,026 `heap number` / 20,000 `smi number` in both). So `heap number` growth here is **not** a numeric-capture artifact — treat it as real and trace it with `memlab_retainer_summary` on `heap number`.',
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
if (env === 'node') {
|
|
22
|
+
return hasSmiNumberNodes
|
|
23
|
+
? {
|
|
24
|
+
mode: 'on',
|
|
25
|
+
note: 'This **Node.js** capture was taken with **numeric-value capture ON** — `smi number` nodes are present, and V8 only materializes Smis as graph nodes in that mode. `smi number` growth is therefore a capture artifact. `heap number` is emitted either way (a matched pair had an identical `heap number` count with the flag on and off), so `heap number` growth is still worth investigating.',
|
|
26
|
+
}
|
|
27
|
+
: {
|
|
28
|
+
mode: 'off',
|
|
29
|
+
note: 'This **Node.js** capture was taken with **numeric-value capture OFF** (no `smi number` nodes present). `heap number` nodes are therefore ordinary boxed doubles that V8 allocates anyway — this growth may be real, so investigate it rather than dismissing it.',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
mode: 'unknown',
|
|
34
|
+
note: 'The runtime that produced this snapshot could not be identified, so the numeric-capture mode cannot be stated. In browser captures the flag makes no difference; in Node.js captures it adds `smi number` nodes.',
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Class-histogram key for the marker node type, as `type::name`. */
|
|
38
|
+
export const SMI_NUMBER_CLASS_KEY = 'number::smi number';
|
|
39
|
+
//# sourceMappingURL=capture-mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capture-mode.js","sourceRoot":"","sources":["../src/capture-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgDH;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,GAAgB,EAChB,iBAA0B;IAE1B,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO;YACL,IAAI,EAAE,gBAAgB;YACtB,IAAI,EAAE,sYAAsY;SAC7Y,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,OAAO,iBAAiB;YACtB,CAAC,CAAC;gBACE,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,kYAAkY;aACzY;YACH,CAAC,CAAC;gBACE,IAAI,EAAE,KAAK;gBACX,IAAI,EAAE,kQAAkQ;aACzQ,CAAC;IACR,CAAC;IACD,OAAO;QACL,IAAI,EAAE,SAAS;QACf,IAAI,EAAE,kNAAkN;KACzN,CAAC;AACJ,CAAC;AAED,qEAAqE;AACrE,MAAM,CAAC,MAAM,oBAAoB,GAAG,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall memory_lab
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Recognise an eval that is re-implementing a tool that already exists, and say
|
|
12
|
+
* so alongside the result.
|
|
13
|
+
*
|
|
14
|
+
* The discoverability problem this addresses is measured, not hypothetical: in
|
|
15
|
+
* one long session `memlab_eval_across`, `memlab_population_diff`,
|
|
16
|
+
* `memlab_event_registry`, `memlab_collection_trend` and `memlab_verify_fix`
|
|
17
|
+
* all existed, all would have saved work, and none was called — while the same
|
|
18
|
+
* questions were answered with hand-written evals, several times each. The
|
|
19
|
+
* operator had even read the warning about exactly this and still did not open
|
|
20
|
+
* the catalogue, because under time pressure writing the eval is the shorter
|
|
21
|
+
* path and nothing in that path mentions the alternative.
|
|
22
|
+
*
|
|
23
|
+
* So the hint is attached to the RESULT of the call that made the mistake,
|
|
24
|
+
* which is the one moment the caller is guaranteed to read. Two rules keep it
|
|
25
|
+
* from becoming noise:
|
|
26
|
+
*
|
|
27
|
+
* - **Never suppress or alter the result.** The eval ran; the hint is a
|
|
28
|
+
* footnote. A hint that blocked or replaced output would be worse than the
|
|
29
|
+
* duplication it is trying to prevent.
|
|
30
|
+
* - **Match on structure, not vocabulary.** A pattern fires only when the code
|
|
31
|
+
* shows the SHAPE of the built-in's job (a `{callback, context}` census, a
|
|
32
|
+
* per-class count keyed by snapshot, a detached-node distribution), not
|
|
33
|
+
* merely because it mentions a word.
|
|
34
|
+
*/
|
|
35
|
+
export interface EvalHint {
|
|
36
|
+
tool: string;
|
|
37
|
+
why: string;
|
|
38
|
+
}
|
|
39
|
+
export declare function hintsForEval(code: string): EvalHint[];
|
|
40
|
+
export declare function formatEvalHints(hints: EvalHint[]): string | null;
|
|
41
|
+
//# sourceMappingURL=eval-hints.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-hints.d.ts","sourceRoot":"","sources":["../src/eval-hints.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAkGD,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,EAAE,CASrD;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,GAAG,IAAI,CAKhE"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @format
|
|
8
|
+
* @oncall memory_lab
|
|
9
|
+
*/
|
|
10
|
+
const RULES = [
|
|
11
|
+
{
|
|
12
|
+
tool: 'memlab_event_registry',
|
|
13
|
+
why: 'counts `{callback, context}` listener records by event and host directly',
|
|
14
|
+
// `callback` and `context` are two of the most common identifiers in
|
|
15
|
+
// JavaScript, so matching them alone fires on evals that have nothing to do
|
|
16
|
+
// with listeners. Require the SHAPE as well: both read as properties off
|
|
17
|
+
// the same record, and the eval is accumulating or iterating over them.
|
|
18
|
+
all: [
|
|
19
|
+
/[.[]['"]?callback\b|\bcallback\s*:/,
|
|
20
|
+
/[.[]['"]?context\b|\bcontext\s*:/,
|
|
21
|
+
/&&|\+\+|\+= ?1|\|\| ?0\) ?\+ ?1|\?\? ?0\) ?\+ ?1|\.push\(|\bfor\b/,
|
|
22
|
+
],
|
|
23
|
+
// Already going through the census tool, or bucketing something else.
|
|
24
|
+
none: [/memlab_event_registry/],
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
tool: 'memlab_detached_dom',
|
|
28
|
+
why: 'reports the detached-node population and its per-class distribution, using the same pinned/GC-eligible split the other tools use',
|
|
29
|
+
all: [/is_detached|isRealDetached|Detached </],
|
|
30
|
+
none: [/memlab_detached_dom/],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
tool: 'memlab_census_diff',
|
|
34
|
+
why: 'takes the detached and listener census on BOTH rungs and diffs them per class in one call — no manual map-building or unload/reload cycle',
|
|
35
|
+
all: [
|
|
36
|
+
/is_detached|isRealDetached|Detached </,
|
|
37
|
+
/\bbaseline\b|\bbefore\b|\bprev\b/,
|
|
38
|
+
],
|
|
39
|
+
none: [/memlab_census_diff/],
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
tool: 'memlab_class_histogram',
|
|
43
|
+
why: 'produces the per-class count/size table without a hand-written walk',
|
|
44
|
+
// Deliberately not keyed to the identifier `node`: the callback parameter
|
|
45
|
+
// is as often `n`, and requiring the long spelling made the rule silently
|
|
46
|
+
// never fire on the shape it exists to catch.
|
|
47
|
+
all: [
|
|
48
|
+
/snapshot\.nodes\.forEach|for\s*\(\s*const\s+\w+\s+of\s+snapshot\.nodes/,
|
|
49
|
+
/\.name\b/,
|
|
50
|
+
/\+\+|\+= ?1|\|\| ?0\) ?\+ ?1|\?\? ?0\) ?\+ ?1/,
|
|
51
|
+
],
|
|
52
|
+
none: [/memlab_class_histogram|helpers\.classCounts/],
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
tool: 'memlab_ladder_probe',
|
|
56
|
+
why: 'runs ONE numeric probe across an ordered ladder and returns the series, the per-cycle rate and r² — loading one rung at a time, so it works on captures too large to hold simultaneously',
|
|
57
|
+
all: [/helpers\.(save|load)\(|__rung|perRung|per_rung/],
|
|
58
|
+
none: [/memlab_ladder_probe/],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
tool: 'memlab_duplicate_objects',
|
|
62
|
+
why: 'is a ready-made dedup report over object content signatures',
|
|
63
|
+
all: [/shapeSignature|objectContentSignature/, /\bMap\b|\bSet\b/],
|
|
64
|
+
none: [/memlab_duplicate_objects/],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
// One canonical tool name per hint. The pair used to be crammed into this
|
|
68
|
+
// single field, which rendered as one backticked identifier containing a
|
|
69
|
+
// slash and spaces — not a name any caller or renderer can resolve. The
|
|
70
|
+
// sibling tool goes in `why`, as prose, where it belongs.
|
|
71
|
+
tool: 'memlab_map_entries',
|
|
72
|
+
why: 'enumerates collection entries without the backing-store walk (see `memlab_weakmap_entries` for WeakMaps)',
|
|
73
|
+
all: [/table|backing/i, /\bMap\b|\bWeakMap\b/],
|
|
74
|
+
none: [
|
|
75
|
+
/helpers\.mapEntries|helpers\.weakmapEntries/,
|
|
76
|
+
/memlab_map_entries|memlab_weakmap_entries/,
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
tool: 'memlab_retainer_trace',
|
|
81
|
+
why: 'walks retainer paths with framework filtering and path collapsing already applied',
|
|
82
|
+
all: [
|
|
83
|
+
/\.referrers\b/,
|
|
84
|
+
/while\s*\(|for\s*\(/,
|
|
85
|
+
/pathEdge|dominatorNode|\.referrers\[0\]/,
|
|
86
|
+
],
|
|
87
|
+
none: [/memlab_retainer_trace|helpers\.pathBetween/],
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
/**
|
|
91
|
+
* At most this many hints per call. Beyond two the footnote stops being a
|
|
92
|
+
* pointer and starts being a second result the caller has to read.
|
|
93
|
+
*/
|
|
94
|
+
const MAX_HINTS = 2;
|
|
95
|
+
export function hintsForEval(code) {
|
|
96
|
+
const hints = [];
|
|
97
|
+
for (const rule of RULES) {
|
|
98
|
+
if (hints.length >= MAX_HINTS)
|
|
99
|
+
break;
|
|
100
|
+
if (rule.none?.some(re => re.test(code)))
|
|
101
|
+
continue;
|
|
102
|
+
if (!rule.all.every(re => re.test(code)))
|
|
103
|
+
continue;
|
|
104
|
+
hints.push({ tool: rule.tool, why: rule.why });
|
|
105
|
+
}
|
|
106
|
+
return hints;
|
|
107
|
+
}
|
|
108
|
+
export function formatEvalHints(hints) {
|
|
109
|
+
if (hints.length === 0)
|
|
110
|
+
return null;
|
|
111
|
+
return hints
|
|
112
|
+
.map(h => `note: \`${h.tool}\` does this directly — it ${h.why}.`)
|
|
113
|
+
.join('\n');
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=eval-hints.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eval-hints.js","sourceRoot":"","sources":["../src/eval-hints.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA0CH,MAAM,KAAK,GAAe;IACxB;QACE,IAAI,EAAE,uBAAuB;QAC7B,GAAG,EAAE,0EAA0E;QAC/E,qEAAqE;QACrE,4EAA4E;QAC5E,yEAAyE;QACzE,wEAAwE;QACxE,GAAG,EAAE;YACH,oCAAoC;YACpC,kCAAkC;YAClC,mEAAmE;SACpE;QACD,sEAAsE;QACtE,IAAI,EAAE,CAAC,uBAAuB,CAAC;KAChC;IACD;QACE,IAAI,EAAE,qBAAqB;QAC3B,GAAG,EAAE,kIAAkI;QACvI,GAAG,EAAE,CAAC,uCAAuC,CAAC;QAC9C,IAAI,EAAE,CAAC,qBAAqB,CAAC;KAC9B;IACD;QACE,IAAI,EAAE,oBAAoB;QAC1B,GAAG,EAAE,2IAA2I;QAChJ,GAAG,EAAE;YACH,uCAAuC;YACvC,kCAAkC;SACnC;QACD,IAAI,EAAE,CAAC,oBAAoB,CAAC;KAC7B;IACD;QACE,IAAI,EAAE,wBAAwB;QAC9B,GAAG,EAAE,qEAAqE;QAC1E,0EAA0E;QAC1E,0EAA0E;QAC1E,8CAA8C;QAC9C,GAAG,EAAE;YACH,wEAAwE;YACxE,UAAU;YACV,+CAA+C;SAChD;QACD,IAAI,EAAE,CAAC,6CAA6C,CAAC;KACtD;IACD;QACE,IAAI,EAAE,qBAAqB;QAC3B,GAAG,EAAE,0LAA0L;QAC/L,GAAG,EAAE,CAAC,gDAAgD,CAAC;QACvD,IAAI,EAAE,CAAC,qBAAqB,CAAC;KAC9B;IACD;QACE,IAAI,EAAE,0BAA0B;QAChC,GAAG,EAAE,6DAA6D;QAClE,GAAG,EAAE,CAAC,uCAAuC,EAAE,iBAAiB,CAAC;QACjE,IAAI,EAAE,CAAC,0BAA0B,CAAC;KACnC;IACD;QACE,0EAA0E;QAC1E,yEAAyE;QACzE,wEAAwE;QACxE,0DAA0D;QAC1D,IAAI,EAAE,oBAAoB;QAC1B,GAAG,EAAE,0GAA0G;QAC/G,GAAG,EAAE,CAAC,gBAAgB,EAAE,qBAAqB,CAAC;QAC9C,IAAI,EAAE;YACJ,6CAA6C;YAC7C,2CAA2C;SAC5C;KACF;IACD;QACE,IAAI,EAAE,uBAAuB;QAC7B,GAAG,EAAE,mFAAmF;QACxF,GAAG,EAAE;YACH,eAAe;YACf,qBAAqB;YACrB,yCAAyC;SAC1C;QACD,IAAI,EAAE,CAAC,4CAA4C,CAAC;KACrD;CACF,CAAC;AAEF;;;GAGG;AACH,MAAM,SAAS,GAAG,CAAC,CAAC;AAEpB,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,KAAK,CAAC,MAAM,IAAI,SAAS;YAAE,MAAM;QACrC,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAE,SAAS;QACnD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAAE,SAAS;QACnD,KAAK,CAAC,IAAI,CAAC,EAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAAC,CAAC,CAAC;IAC/C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAiB;IAC/C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,IAAI,8BAA8B,CAAC,CAAC,GAAG,GAAG,CAAC;SACjE,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC"}
|
package/dist/guardrail.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guardrail.d.ts","sourceRoot":"","sources":["../src/guardrail.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"guardrail.d.ts","sourceRoot":"","sources":["../src/guardrail.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,yCAAyC,CAAC;AAavE;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwDhE"}
|