@wenathlan/devthink 2.0.14 → 2.0.19
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/CHANGELOG.md +60 -0
- package/{dist/bridge.d.ts → bridge.d.ts} +1 -1
- package/bridge.d.ts.map +1 -0
- package/bridge.js +1877 -0
- package/bun.d.ts.map +1 -0
- package/bun.js +52329 -0
- package/caps/background.json +712 -0
- package/caps/cli.json +360 -0
- package/caps/library.json +3611 -0
- package/caps/mcp.json +126 -0
- package/caps/pagebridge.json +377 -0
- package/caps/popup.json +51 -0
- package/caps/sidepanel.json +522 -0
- package/checksums.txt +142 -0
- package/cli.d.ts.map +1 -0
- package/{dist/cli.js → cli.js} +2 -2
- package/companion.d.ts.map +1 -0
- package/companion.js +389 -0
- package/crossbrowser.d.ts.map +1 -0
- package/crossbrowser.js +1191 -0
- package/dashdone.d.ts.map +1 -0
- package/dashdone.js +368 -0
- package/deno.d.ts.map +1 -0
- package/deno.js +52325 -0
- package/devthink.umd.js +52346 -0
- package/fixtures/bun.ts +7 -0
- package/fixtures/cjs.js +6 -0
- package/fixtures/deno.ts +6 -0
- package/fixtures/example-org-pagestate.json +22 -0
- package/fixtures/importers/automa-workflow.json +18 -0
- package/fixtures/importers/selenium-side.json +20 -0
- package/fixtures/importers/tabular-plan.csv +7 -0
- package/fixtures/importers/uivision-macro.json +10 -0
- package/fixtures/importers/v1-plan.json +13 -0
- package/fixtures/mcp-client.mjs +14 -0
- package/fixtures/pages/checkout.html +192 -0
- package/fixtures/pages/dashboard.html +110 -0
- package/fixtures/pages/feed.html +113 -0
- package/fixtures/pages/product-grid.html +150 -0
- package/fixtures/plans/form-inventory-plan.json +11 -0
- package/fixtures/plans/release-notes-plan.json +11 -0
- package/fixtures/recipes/agentscompete.json +11 -0
- package/fixtures/recipes/agentsforms.json +11 -0
- package/fixtures/recipes/agentsmonitor.json +11 -0
- package/fixtures/recipes/agentsreview.json +29 -0
- package/fixtures/recipes/agentswarm.json +11 -0
- package/fixtures/recipes/fillcalendar.json +12 -0
- package/fixtures/recipes/fillcheckout.json +13 -0
- package/fixtures/recipes/filldependentdropdowns.json +12 -0
- package/fixtures/recipes/fillfromcsv.json +13 -0
- package/fixtures/recipes/fillloginform.json +12 -0
- package/fixtures/recipes/fillmultistepwizard.json +13 -0
- package/fixtures/recipes/fillregistration.json +12 -0
- package/fixtures/recipes/fillsearchfilters.json +12 -0
- package/fixtures/recipes/filltypeahead.json +11 -0
- package/fixtures/recipes/monitoralerts.json +12 -0
- package/fixtures/recipes/monitoravailability.json +11 -0
- package/fixtures/recipes/monitornetworkquiet.json +12 -0
- package/fixtures/recipes/monitorpagechanges.json +11 -0
- package/fixtures/recipes/monitorpricechange.json +11 -0
- package/fixtures/recipes/monitorschedule.json +12 -0
- package/fixtures/recipes/scrapedynamicprices.json +13 -0
- package/fixtures/recipes/scrapeimagegallery.json +12 -0
- package/fixtures/recipes/scrapeinfinitefeed.json +13 -0
- package/fixtures/recipes/scrapenestedlists.json +12 -0
- package/fixtures/recipes/scrapeproductgrid.json +12 -0
- package/fixtures/recipes/scrapereviews.json +12 -0
- package/fixtures/recipes/scrapesearchresults.json +12 -0
- package/fixtures/recipes/scrapetablepagination.json +12 -0
- package/fixtures/recipes/testaccessibility.json +34 -0
- package/fixtures/recipes/testconsoleerrors.json +12 -0
- package/fixtures/recipes/testdeeplinks.json +12 -0
- package/fixtures/recipes/testformvalidation.json +13 -0
- package/fixtures/recipes/testlayoutshift.json +12 -0
- package/fixtures/recipes/testlinkcheck.json +12 -0
- package/fixtures/recipes/testloadtiming.json +12 -0
- package/fixtures/recipes/testvisualdiff.json +12 -0
- package/fixtures/workflows/changelog-digest-workflow.json +13 -0
- package/fixtures/workflows/form-survey-workflow.json +13 -0
- package/gallery.json +706 -0
- package/hardening.d.ts.map +1 -0
- package/hardening.js +188 -0
- package/headless.d.ts.map +1 -0
- package/headless.js +11522 -0
- package/http.d.ts.map +1 -0
- package/http.js +2165 -0
- package/index.cjs +54682 -0
- package/index.d.ts.map +1 -0
- package/index.js +52310 -0
- package/index.neutral.js +46343 -0
- package/{web/manifest.json → manifest.json} +1 -1
- package/mcp.d.ts.map +1 -0
- package/mcp.js +20515 -0
- package/memory.d.ts.map +1 -0
- package/{memory.ts → memory.js} +2310 -3834
- package/nativehost.template.json +10 -0
- package/node.cjs +54686 -0
- package/node.d.ts.map +1 -0
- package/pack.d.ts.map +1 -0
- package/pack.js +805 -0
- package/package.json +83 -176
- package/policy.d.ts.map +1 -0
- package/{policy.ts → policy.js} +4679 -5073
- package/progress.d.ts.map +1 -0
- package/progress.js +645 -0
- package/protocol.d.ts.map +1 -0
- package/protocol.js +8334 -0
- package/schemas/audit.schema.json +226 -0
- package/schemas/capability.schema.json +113 -0
- package/schemas/envelope.schema.json +162 -0
- package/schemas/memory.schema.json +51 -0
- package/schemas/observation.schema.json +113 -0
- package/schemas/plan.schema.json +208 -0
- package/schemas/progress.schema.json +126 -0
- package/schemas/proposal.schema.json +68 -0
- package/schemas/session.schema.json +82 -0
- package/schemas/tool.schema.json +94 -0
- package/server.d.ts.map +1 -0
- package/server.js +28877 -0
- package/umd-example.html +18 -0
- package/umd.d.ts.map +1 -0
- package/accounts.ts +0 -2087
- package/agent.ts +0 -2331
- package/antigravity.ts +0 -2139
- package/apifreeze.ts +0 -4146
- package/auth.ts +0 -642
- package/background.ts +0 -16837
- package/bridge.ts +0 -2080
- package/build.ts +0 -54
- package/bun.ts +0 -26
- package/capture.ts +0 -1614
- package/checksecrets.ts +0 -72
- package/cjs.ts +0 -9
- package/cli.ts +0 -3500
- package/commands.ts +0 -1101
- package/companion.ts +0 -450
- package/compatibility.ts +0 -37
- package/config.ts +0 -3137
- package/constants.ts +0 -943
- package/core.ts +0 -1473
- package/crossbrowser.ts +0 -1359
- package/dashdone.ts +0 -605
- package/data.ts +0 -943
- package/database.ts +0 -133
- package/debug.ts +0 -850
- package/deno.ts +0 -27
- package/devthink.ts +0 -707
- package/dist/accounts.d.ts +0 -409
- package/dist/agent.d.ts +0 -837
- package/dist/antigravity.d.ts +0 -380
- package/dist/apifreeze.d.ts +0 -113
- package/dist/auth.d.ts +0 -224
- package/dist/capture.d.ts +0 -595
- package/dist/cjs.d.ts +0 -6
- package/dist/commands.d.ts +0 -310
- package/dist/compatibility.d.ts +0 -17
- package/dist/config.d.ts +0 -1853
- package/dist/constants.d.ts +0 -637
- package/dist/core.d.ts +0 -361
- package/dist/data.d.ts +0 -330
- package/dist/database.d.ts +0 -24
- package/dist/debug.d.ts +0 -270
- package/dist/engine.d.ts +0 -74
- package/dist/environments.d.ts +0 -244
- package/dist/evidence.d.ts +0 -277
- package/dist/export.d.ts +0 -311
- package/dist/fingerprint.d.ts +0 -594
- package/dist/flow.d.ts +0 -300
- package/dist/gates.d.ts +0 -103
- package/dist/identity.d.ts +0 -51
- package/dist/ids.d.ts +0 -7
- package/dist/llm.d.ts +0 -652
- package/dist/models.d.ts +0 -1807
- package/dist/net.d.ts +0 -325
- package/dist/neutral.d.ts +0 -41
- package/dist/oauth.d.ts +0 -703
- package/dist/page.d.ts +0 -1166
- package/dist/perf.d.ts +0 -481
- package/dist/plan.d.ts +0 -134
- package/dist/project.d.ts +0 -395
- package/dist/providers.d.ts +0 -37
- package/dist/quota.d.ts +0 -453
- package/dist/recovery.d.ts +0 -621
- package/dist/request.d.ts +0 -1492
- package/dist/run.d.ts +0 -779
- package/dist/runtime.d.ts +0 -212
- package/dist/search.d.ts +0 -375
- package/dist/security.d.ts +0 -534
- package/dist/serve.d.ts +0 -136
- package/dist/session.d.ts +0 -296
- package/dist/storage.d.ts +0 -53
- package/dist/streaming.d.ts +0 -1119
- package/dist/swarm.d.ts +0 -328
- package/dist/tools.d.ts +0 -170
- package/dist/types.d.ts +0 -8357
- package/dist/utils.d.ts +0 -82
- package/dist/version.d.ts +0 -7
- package/dist/versionregistry.d.ts +0 -406
- package/dist/views.d.ts +0 -579
- package/dist/workbenchsession.d.ts +0 -69
- package/dist/workflow.d.ts +0 -649
- package/docs/readme.md +0 -92
- package/docs/schemas/antigravity.json +0 -192
- package/engine.ts +0 -1524
- package/environments.ts +0 -1005
- package/evidence.ts +0 -643
- package/export.ts +0 -889
- package/fingerprint.ts +0 -1458
- package/flow.ts +0 -1190
- package/gates.ts +0 -307
- package/gateway.ts +0 -34
- package/hardening.ts +0 -191
- package/headless.ts +0 -369
- package/http.ts +0 -2110
- package/identity.ts +0 -246
- package/ids.ts +0 -26
- package/index.ts +0 -369
- package/llm.ts +0 -2682
- package/mcp.ts +0 -1835
- package/models.ts +0 -3805
- package/modes.ts +0 -43
- package/net.ts +0 -1214
- package/neutral.ts +0 -362
- package/node.ts +0 -26
- package/oauth.ts +0 -2216
- package/offscreen.ts +0 -170
- package/pack.ts +0 -956
- package/page.ts +0 -7824
- package/pagebridge.ts +0 -1116
- package/perf.ts +0 -957
- package/plan.ts +0 -672
- package/plugin.ts +0 -76
- package/prisma.config.ts +0 -27
- package/progress.ts +0 -1308
- package/project.ts +0 -1291
- package/protocol.ts +0 -4187
- package/providers.ts +0 -246
- package/quota.ts +0 -1887
- package/recovery.ts +0 -2433
- package/request.ts +0 -4482
- package/run.ts +0 -2135
- package/runtime.ts +0 -526
- package/search.ts +0 -1760
- package/security.ts +0 -1673
- package/serve.ts +0 -419
- package/server.ts +0 -5538
- package/session.ts +0 -1162
- package/storage.ts +0 -182
- package/streaming.ts +0 -4101
- package/swarm.ts +0 -884
- package/sync.ts +0 -56
- package/tests/agentcert.test.ts +0 -128
- package/tests/agentfleet.test.ts +0 -214
- package/tests/agentreview.test.ts +0 -241
- package/tests/agentstream.test.ts +0 -335
- package/tests/agentwork.test.ts +0 -356
- package/tests/apifreeze.test.ts +0 -290
- package/tests/apimap.test.ts +0 -112
- package/tests/approvalgate.test.ts +0 -175
- package/tests/artifactmanifest.test.ts +0 -204
- package/tests/attentionfeed.test.ts +0 -163
- package/tests/backgroundruns.test.ts +0 -100
- package/tests/batchscheduling.test.ts +0 -131
- package/tests/blackboard.test.ts +0 -238
- package/tests/bridge.test.ts +0 -1088
- package/tests/browsercoverage.test.ts +0 -134
- package/tests/browserpolyfills.test.ts +0 -124
- package/tests/build.mjs +0 -1260
- package/tests/clientauth.test.ts +0 -223
- package/tests/clitools.test.ts +0 -578
- package/tests/confirmgates.test.ts +0 -190
- package/tests/containerpack.test.ts +0 -143
- package/tests/controlflow.test.ts +0 -2120
- package/tests/coordination.test.ts +0 -345
- package/tests/copyscreen.test.ts +0 -139
- package/tests/core.test.ts +0 -417
- package/tests/costcert.test.ts +0 -95
- package/tests/crossbrowser.test.ts +0 -115
- package/tests/cspaudit.test.ts +0 -79
- package/tests/dashdone.test.ts +0 -615
- package/tests/datagrid.test.ts +0 -137
- package/tests/doccheck.test.ts +0 -107
- package/tests/dombatch.test.ts +0 -109
- package/tests/emulation.test.ts +0 -282
- package/tests/environments.test.ts +0 -259
- package/tests/evidenceviews.test.ts +0 -88
- package/tests/exporttools.test.ts +0 -185
- package/tests/firefoxprep.test.ts +0 -134
- package/tests/flowlibrary.test.ts +0 -242
- package/tests/flowrun.test.ts +0 -303
- package/tests/forensics.test.ts +0 -439
- package/tests/gateway.test.ts +0 -939
- package/tests/headlesslib.test.ts +0 -171
- package/tests/httpstream.test.ts +0 -277
- package/tests/immutablelog.test.ts +0 -157
- package/tests/inboundguard.test.ts +0 -177
- package/tests/lazyload.test.ts +0 -72
- package/tests/librarymodes.test.ts +0 -623
- package/tests/llm.test.ts +0 -696
- package/tests/manifest.test.ts +0 -226
- package/tests/maskinputs.test.ts +0 -150
- package/tests/matrixverify.test.ts +0 -111
- package/tests/mavenpack.test.ts +0 -75
- package/tests/mcpserver.test.ts +0 -704
- package/tests/memory.test.ts +0 -4155
- package/tests/memorycare.test.ts +0 -230
- package/tests/migrateplan.test.ts +0 -349
- package/tests/minimization.test.ts +0 -414
- package/tests/modelroute.test.ts +0 -112
- package/tests/multiagent.test.ts +0 -440
- package/tests/nativebridge.test.ts +0 -807
- package/tests/navigation.test.ts +0 -284
- package/tests/nugetpack.test.ts +0 -83
- package/tests/orchestration.test.ts +0 -449
- package/tests/originpolicy.test.ts +0 -405
- package/tests/outputcompare.test.ts +0 -97
- package/tests/package.test.ts +0 -91
- package/tests/pagebridge.test.ts +0 -5909
- package/tests/pentest.test.ts +0 -75
- package/tests/perfrecords.test.ts +0 -257
- package/tests/permdiff.test.ts +0 -85
- package/tests/phishguard.test.ts +0 -128
- package/tests/pickerviews.test.ts +0 -155
- package/tests/pipelines.test.ts +0 -381
- package/tests/planlint.test.ts +0 -240
- package/tests/planreview.test.ts +0 -383
- package/tests/platformtargets.test.ts +0 -56
- package/tests/policy.test.ts +0 -8284
- package/tests/portability.test.ts +0 -96
- package/tests/progress.test.ts +0 -1036
- package/tests/promptlibrary.test.ts +0 -116
- package/tests/protocol.test.ts +0 -4793
- package/tests/publishingpipeline.test.ts +0 -314
- package/tests/quickactions.test.ts +0 -164
- package/tests/readiness.test.ts +0 -78
- package/tests/recipes.test.ts +0 -163
- package/tests/redactshots.test.ts +0 -216
- package/tests/registernvidiakeys.ts +0 -51
- package/tests/relayserve.test.ts +0 -304
- package/tests/releasenotes.test.ts +0 -276
- package/tests/resilience.test.ts +0 -467
- package/tests/resourceaware.test.ts +0 -187
- package/tests/runbudget.test.ts +0 -125
- package/tests/runhistory.test.ts +0 -299
- package/tests/runreplay.test.ts +0 -113
- package/tests/runresume.test.ts +0 -184
- package/tests/runstate.test.ts +0 -288
- package/tests/runtimeadapters.test.ts +0 -251
- package/tests/safariskeleton.test.ts +0 -115
- package/tests/sandboxframe.test.ts +0 -196
- package/tests/sbom.test.ts +0 -105
- package/tests/secretvault.test.ts +0 -188
- package/tests/selcache.test.ts +0 -111
- package/tests/sessioninterface.test.ts +0 -791
- package/tests/sessions.test.ts +0 -591
- package/tests/siteprefs.test.ts +0 -228
- package/tests/snapshotdelta.test.ts +0 -165
- package/tests/statusviews.test.ts +0 -237
- package/tests/stepmeter.test.ts +0 -200
- package/tests/streamparse.test.ts +0 -163
- package/tests/stylepruning.test.ts +0 -90
- package/tests/surfaces.test.ts +0 -282
- package/tests/sweep.test.ts +0 -78
- package/tests/syncbridge.test.ts +0 -164
- package/tests/taskqueue.test.ts +0 -206
- package/tests/toolcalls.test.ts +0 -336
- package/tests/toolcatalog.test.ts +0 -201
- package/tests/torture-agent.test.ts +0 -706
- package/tests/torture-auth.test.ts +0 -461
- package/tests/torture-commands.test.ts +0 -895
- package/tests/torture-data.test.ts +0 -923
- package/tests/torture-environments.test.ts +0 -285
- package/tests/torture-export.test.ts +0 -263
- package/tests/torture-http.test.ts +0 -1379
- package/tests/torture-llm.test.ts +0 -808
- package/tests/torture-memory.test.ts +0 -1084
- package/tests/torture-plan.test.ts +0 -829
- package/tests/torture-run.test.ts +0 -626
- package/tests/torture-session.test.ts +0 -928
- package/tests/torture-swarm.test.ts +0 -1245
- package/tests/torture-tools.test.ts +0 -964
- package/tests/torture-workflow.test.ts +0 -2354
- package/tests/tourviews.test.ts +0 -52
- package/tests/transparency.test.ts +0 -147
- package/tests/trigger.test.ts +0 -941
- package/tests/v1sunset.test.ts +0 -428
- package/tests/virtlist.test.ts +0 -94
- package/tests/vision.test.ts +0 -540
- package/tests/vsixpack.test.ts +0 -145
- package/tests/webapi.test.ts +0 -523
- package/tests/workflow.test.ts +0 -1785
- package/tests/workfloweditor.test.ts +0 -759
- package/tests/xpipack.test.ts +0 -128
- package/tools.ts +0 -734
- package/types.ts +0 -9908
- package/umd.ts +0 -9
- package/utils.ts +0 -249
- package/version.ts +0 -8
- package/versionregistry.ts +0 -1310
- package/views.ts +0 -2153
- package/vitest.config.ts +0 -12
- package/web/App.tsx +0 -78
- package/web/README.md +0 -47
- package/web/capacitor.config.ts +0 -46
- package/web/const.ts +0 -19
- package/web/control.shell.tsx +0 -66
- package/web/dashboardpage.ts +0 -554
- package/web/db.ts +0 -493
- package/web/design.html +0 -541
- package/web/gatewayview/Gateway.tsx +0 -345
- package/web/gatewayview/config.ts +0 -1042
- package/web/gatewayview/definition.ts +0 -174
- package/web/icons.ts +0 -15
- package/web/optionspage.ts +0 -691
- package/web/popup.ts +0 -1651
- package/web/schema.prisma +0 -176
- package/web/sidepanel.ts +0 -7941
- package/web/sitemanifest.json +0 -13
- package/web/terminal-ui.tsx +0 -622
- package/web/transparencypage.ts +0 -541
- package/web/vite.config.ts +0 -39
- package/web/workspace.ts +0 -23
- package/workbenchmemory.ts +0 -104
- package/workbenchsession.ts +0 -304
- package/workflow.ts +0 -4495
- /package/{dist/bun.d.ts → bun.d.ts} +0 -0
- /package/{dist/cli.d.ts → cli.d.ts} +0 -0
- /package/{dist/companion.d.ts → companion.d.ts} +0 -0
- /package/{dist/crossbrowser.d.ts → crossbrowser.d.ts} +0 -0
- /package/{dist/dashdone.d.ts → dashdone.d.ts} +0 -0
- /package/{dist/deno.d.ts → deno.d.ts} +0 -0
- /package/{dist/hardening.d.ts → hardening.d.ts} +0 -0
- /package/{dist/headless.d.ts → headless.d.ts} +0 -0
- /package/{dist/http.d.ts → http.d.ts} +0 -0
- /package/{dist/index.d.ts → index.d.ts} +0 -0
- /package/{dist/mcp.d.ts → mcp.d.ts} +0 -0
- /package/{dist/memory.d.ts → memory.d.ts} +0 -0
- /package/{dist/node.d.ts → node.d.ts} +0 -0
- /package/{dist/pack.d.ts → pack.d.ts} +0 -0
- /package/{dist/policy.d.ts → policy.d.ts} +0 -0
- /package/{dist/progress.d.ts → progress.d.ts} +0 -0
- /package/{dist/protocol.d.ts → protocol.d.ts} +0 -0
- /package/{dist/server.d.ts → server.d.ts} +0 -0
- /package/{dist/umd.d.ts → umd.d.ts} +0 -0
package/debug.ts
DELETED
|
@@ -1,850 +0,0 @@
|
|
|
1
|
-
/** The debug module of the 1.1.90 consolidation: every correlated variation of the cdp instrumentation and the profilers interned in this one file, so the module family carries one surface without duplicate variations. */
|
|
2
|
-
|
|
3
|
-
/* ── Merged from cdpbus.ts: the 1.1.90 consolidation interns the correlated cdpbus logic here, so no variation of the same file lives beside another. ── */
|
|
4
|
-
import type {
|
|
5
|
-
attachtarget,
|
|
6
|
-
breakpointspec,
|
|
7
|
-
cdpallowlist,
|
|
8
|
-
cdpcommand,
|
|
9
|
-
cdpeventrule,
|
|
10
|
-
cdpsession,
|
|
11
|
-
cpuprofile,
|
|
12
|
-
flowmetric,
|
|
13
|
-
flowspec,
|
|
14
|
-
growsample,
|
|
15
|
-
heaprecord,
|
|
16
|
-
memorytrend,
|
|
17
|
-
pausestate,
|
|
18
|
-
scriptoverride,
|
|
19
|
-
shiftentry,
|
|
20
|
-
sourcemapref,
|
|
21
|
-
stackframe,
|
|
22
|
-
stepmode,
|
|
23
|
-
teardownplan,
|
|
24
|
-
traceannotation,
|
|
25
|
-
tracerecord,
|
|
26
|
-
watchexpression,
|
|
27
|
-
} from "./types.js";
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Devtools protocol bus for the 1.1.46 debugging family.
|
|
31
|
-
* Every correlated rule for the reviewed instrumented devtools session lives in this file: the domain grammar, the attach and detach lifecycle with the honest derivation note, the raw command records with duration and error class, the per session command serialization in send order, the domain event rules with match filters and per domain event counts, the breakpoint input grammar, the pause state capture with call frames, the step mode grammar, the watch expression values per pause, the script override url patterns and the teardown plan that reverts every breakpoint and override and decides the resume policy when the user detaches the debugger.
|
|
32
|
-
* The chrome devtools protocol is unavailable without the debugger permission, which the manifest gate forbids, so every command routes through the page-instrumented harness injected through the scripting api; the derivation is recorded on every session instead of hidden.
|
|
33
|
-
*/
|
|
34
|
-
|
|
35
|
-
/** The debugging kinds of the devtools family, listed among the available capabilities of every proposal request. */
|
|
36
|
-
export const cdpkinds: string[] = [
|
|
37
|
-
"attachcdp",
|
|
38
|
-
"detachcdp",
|
|
39
|
-
"cdpcmd",
|
|
40
|
-
"watchcdp",
|
|
41
|
-
"setbreakpoint",
|
|
42
|
-
"stepcode",
|
|
43
|
-
"watchexpr",
|
|
44
|
-
"overridescript",
|
|
45
|
-
];
|
|
46
|
-
|
|
47
|
-
/** The reviewed devtools domain grammar: runtime evaluation, log capture, debugger state, dom snapshots, network facts and page lifecycle; the enabled subset stays a user choice bounded by this grammar only. */
|
|
48
|
-
export const cdpdomains: string[] = ["Runtime", "Log", "Debugger", "DOM", "Network", "Page"];
|
|
49
|
-
|
|
50
|
-
/** Resolves the domain of one devtools method name of the form Domain.method; malformed methods resolve to undefined. */
|
|
51
|
-
export function methoddomain(method: string): string | undefined {
|
|
52
|
-
const match = /^([A-Z][A-Za-z]*)\.([a-zA-Z][A-Za-z0-9]*)$/.exec(method.trim());
|
|
53
|
-
return match?.[1];
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Normalizes one reviewed devtools domain allowlist: the enabled domains bounded by the reviewed domain grammar and the optional method gates inside the enabled domains; a gate list that names no method of the enabled domains is refused. */
|
|
57
|
-
export function cdpallowlistof(value: unknown): cdpallowlist | undefined {
|
|
58
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
59
|
-
const entry = value as Record<string, unknown>;
|
|
60
|
-
const domains = Array.isArray(entry.domains)
|
|
61
|
-
? entry.domains.filter((domain): domain is string => typeof domain === "string" && cdpdomains.includes(domain))
|
|
62
|
-
: [];
|
|
63
|
-
if (domains.length === 0) return undefined;
|
|
64
|
-
if (entry.methods === undefined) return { domains };
|
|
65
|
-
const methods = Array.isArray(entry.methods)
|
|
66
|
-
? entry.methods.filter(
|
|
67
|
-
(method): method is string =>
|
|
68
|
-
typeof method === "string" &&
|
|
69
|
-
methoddomain(method) !== undefined &&
|
|
70
|
-
domains.includes(methoddomain(method) as string),
|
|
71
|
-
)
|
|
72
|
-
: [];
|
|
73
|
-
if (methods.length === 0) return undefined;
|
|
74
|
-
return { domains, methods };
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/** True when the allowlist covers one method: the method domain must be enabled and a present method gate list must name the method. */
|
|
78
|
-
export function allowlistcovers(allowlist: cdpallowlist, method: string): boolean {
|
|
79
|
-
const domain = methoddomain(method);
|
|
80
|
-
if (domain === undefined) return false;
|
|
81
|
-
if (!allowlist.domains.includes(domain)) return false;
|
|
82
|
-
if (allowlist.methods !== undefined && !allowlist.methods.includes(method)) return false;
|
|
83
|
-
return true;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** Attaches one instrumented devtools session to the run tab with the reviewed enabled domains and the honest debugger derivation note. */
|
|
87
|
-
export function attachcdpsession(input: {
|
|
88
|
-
id: string;
|
|
89
|
-
runid: string;
|
|
90
|
-
stepid: string;
|
|
91
|
-
tabid: number;
|
|
92
|
-
origin: string;
|
|
93
|
-
domains: string[];
|
|
94
|
-
now: number;
|
|
95
|
-
debuggerversion: string;
|
|
96
|
-
}): cdpsession {
|
|
97
|
-
return {
|
|
98
|
-
id: input.id,
|
|
99
|
-
runid: input.runid,
|
|
100
|
-
stepid: input.stepid,
|
|
101
|
-
tabid: input.tabid,
|
|
102
|
-
origin: input.origin,
|
|
103
|
-
attachedat: input.now,
|
|
104
|
-
domains: [...new Set(input.domains)],
|
|
105
|
-
debuggerversion: input.debuggerversion,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/** Detaches one session cleanly: the detach time stamps the record and the domains stay auditable after the detach. */
|
|
110
|
-
export function detachcdpsession(session: cdpsession, at: number, userdetached = false): cdpsession {
|
|
111
|
-
return { ...session, detachedat: at, ...(userdetached ? { userdetached: true } : {}) };
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** Builds one raw protocol command record with its method, params, domain, dotted result path, duration and error class. */
|
|
115
|
-
export function sendcdpcommand(input: {
|
|
116
|
-
id: string;
|
|
117
|
-
sessionid: string;
|
|
118
|
-
runid: string;
|
|
119
|
-
stepid: string;
|
|
120
|
-
method: string;
|
|
121
|
-
params?: Record<string, unknown>;
|
|
122
|
-
resultpath?: string;
|
|
123
|
-
duration: number;
|
|
124
|
-
errorclass?: string;
|
|
125
|
-
at: number;
|
|
126
|
-
}): cdpcommand {
|
|
127
|
-
const domain = methoddomain(input.method);
|
|
128
|
-
if (domain === undefined)
|
|
129
|
-
return {
|
|
130
|
-
...input,
|
|
131
|
-
method: input.method.trim(),
|
|
132
|
-
domain: "",
|
|
133
|
-
duration: input.duration,
|
|
134
|
-
...(input.errorclass !== undefined ? { errorclass: input.errorclass } : { errorclass: "malformedmethod" }),
|
|
135
|
-
at: input.at,
|
|
136
|
-
};
|
|
137
|
-
return {
|
|
138
|
-
...input,
|
|
139
|
-
method: input.method.trim(),
|
|
140
|
-
domain,
|
|
141
|
-
duration: input.duration,
|
|
142
|
-
...(input.errorclass !== undefined ? { errorclass: input.errorclass } : {}),
|
|
143
|
-
at: input.at,
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/** Appends one command to the per session send queue so concurrent commands serialize in send order. */
|
|
148
|
-
export function serializecdpcommand(queue: cdpcommand[], command: cdpcommand): cdpcommand[] {
|
|
149
|
-
return [...queue, command];
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/** Normalizes one reviewed domain event rule: the domain of the reviewed grammar, the event name and the optional payload match filter. */
|
|
153
|
-
export function cdpeventruleof(value: unknown): Pick<cdpeventrule, "domain" | "event" | "match"> | undefined {
|
|
154
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
155
|
-
const entry = value as Record<string, unknown>;
|
|
156
|
-
const domain = typeof entry.domain === "string" && cdpdomains.includes(entry.domain) ? entry.domain : undefined;
|
|
157
|
-
const event = typeof entry.event === "string" && entry.event.trim() ? entry.event.trim() : undefined;
|
|
158
|
-
if (domain === undefined || event === undefined) return undefined;
|
|
159
|
-
const match = typeof entry.match === "string" && entry.match.trim() ? entry.match.trim() : undefined;
|
|
160
|
-
return { domain, event, ...(match !== undefined ? { match } : {}) };
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/** Matches observed domain events against the reviewed rules and counts the matched events per domain; the match filter must appear in the payload before an event forwards. */
|
|
164
|
-
export function watchcdpevents(
|
|
165
|
-
rules: cdpeventrule[],
|
|
166
|
-
events: Array<{ domain: string; event: string; payload?: string }>,
|
|
167
|
-
): {
|
|
168
|
-
matched: Array<{ ruleid: string; domain: string; event: string; payload?: string }>;
|
|
169
|
-
counts: Record<string, number>;
|
|
170
|
-
} {
|
|
171
|
-
const matched: Array<{ ruleid: string; domain: string; event: string; payload?: string }> = [];
|
|
172
|
-
const counts: Record<string, number> = {};
|
|
173
|
-
for (const domain of cdpdomains) counts[domain] = 0;
|
|
174
|
-
for (const event of events) {
|
|
175
|
-
for (const rule of rules) {
|
|
176
|
-
if (rule.domain !== event.domain || rule.event !== event.event) continue;
|
|
177
|
-
if (rule.match !== undefined && !(event.payload ?? "").includes(rule.match)) continue;
|
|
178
|
-
matched.push({
|
|
179
|
-
ruleid: rule.id,
|
|
180
|
-
domain: event.domain,
|
|
181
|
-
event: event.event,
|
|
182
|
-
...(event.payload !== undefined ? { payload: event.payload } : {}),
|
|
183
|
-
});
|
|
184
|
-
counts[event.domain] = (counts[event.domain] ?? 0) + 1;
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
return { matched, counts };
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/** Normalizes one reviewed breakpoint input: the script url, the zero based line, the optional column and the condition of the reviewed expression grammar. */
|
|
191
|
-
export function breakpointinputof(
|
|
192
|
-
value: unknown,
|
|
193
|
-
): Pick<breakpointspec, "url" | "line" | "column" | "condition"> | undefined {
|
|
194
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
195
|
-
const entry = value as Record<string, unknown>;
|
|
196
|
-
const url = typeof entry.url === "string" && entry.url.trim() ? entry.url.trim() : undefined;
|
|
197
|
-
const line =
|
|
198
|
-
typeof entry.line === "number" && Number.isInteger(entry.line) && entry.line >= 0 ? entry.line : undefined;
|
|
199
|
-
if (url === undefined || line === undefined) return undefined;
|
|
200
|
-
const column =
|
|
201
|
-
typeof entry.column === "number" && Number.isInteger(entry.column) && entry.column >= 0 ? entry.column : undefined;
|
|
202
|
-
const condition = typeof entry.condition === "string" && entry.condition.trim() ? entry.condition.trim() : undefined;
|
|
203
|
-
return { url, line, ...(column !== undefined ? { column } : {}), ...(condition !== undefined ? { condition } : {}) };
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/** Captures one pause state from the instrumented pause: the reason, the call frames, the hit breakpoint and the dom snapshot reference of the page bridge capture. */
|
|
207
|
-
export function capturepause(input: {
|
|
208
|
-
id: string;
|
|
209
|
-
runid: string;
|
|
210
|
-
stepid: string;
|
|
211
|
-
reason: string;
|
|
212
|
-
callframes: stackframe[];
|
|
213
|
-
hitbreakpoint?: string;
|
|
214
|
-
domsnapshotid?: string;
|
|
215
|
-
at: number;
|
|
216
|
-
}): pausestate {
|
|
217
|
-
return {
|
|
218
|
-
id: input.id,
|
|
219
|
-
runid: input.runid,
|
|
220
|
-
stepid: input.stepid,
|
|
221
|
-
reason: input.reason,
|
|
222
|
-
callframes: [...input.callframes],
|
|
223
|
-
...(input.hitbreakpoint !== undefined ? { hitbreakpoint: input.hitbreakpoint } : {}),
|
|
224
|
-
...(input.domsnapshotid !== undefined ? { domsnapshotid: input.domsnapshotid } : {}),
|
|
225
|
-
at: input.at,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/** Normalizes one reviewed step mode of the instrumented debugger: stepover, stepinto, stepout or resume. */
|
|
230
|
-
export function stepmodeof(value: unknown): stepmode | undefined {
|
|
231
|
-
const modes: stepmode[] = ["stepover", "stepinto", "stepout", "resume"];
|
|
232
|
-
return typeof value === "string" && modes.includes(value as stepmode) ? (value as stepmode) : undefined;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/** Normalizes one reviewed watch expression input: the expression text and the pause scope it evaluates in. */
|
|
236
|
-
export function watchexpressionof(value: unknown): Pick<watchexpression, "expression" | "scope"> | undefined {
|
|
237
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
238
|
-
const entry = value as Record<string, unknown>;
|
|
239
|
-
const expression =
|
|
240
|
-
typeof entry.expression === "string" && entry.expression.trim() ? entry.expression.trim() : undefined;
|
|
241
|
-
if (expression === undefined) return undefined;
|
|
242
|
-
const scope = typeof entry.scope === "string" && entry.scope.trim() ? entry.scope.trim() : "topframe";
|
|
243
|
-
return { expression, scope };
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/** Records one watch value captured at a pause with the pause scope correlation. */
|
|
247
|
-
export function recordwatchvalue(
|
|
248
|
-
expression: watchexpression,
|
|
249
|
-
pauseid: string,
|
|
250
|
-
value: string,
|
|
251
|
-
at: number,
|
|
252
|
-
): watchexpression {
|
|
253
|
-
return { ...expression, values: [...expression.values, { pauseid, value, at }] };
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/** Normalizes one reviewed script override input: the url pattern that names its origin explicitly and the full fixture source. */
|
|
257
|
-
export function overrideinputof(value: unknown): Pick<scriptoverride, "urlpattern" | "source"> | undefined {
|
|
258
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
259
|
-
const entry = value as Record<string, unknown>;
|
|
260
|
-
const urlpattern =
|
|
261
|
-
typeof entry.urlpattern === "string" && entry.urlpattern.trim() ? entry.urlpattern.trim() : undefined;
|
|
262
|
-
const source = typeof entry.source === "string" ? entry.source : undefined;
|
|
263
|
-
if (urlpattern === undefined || source === undefined || source.trim().length === 0) return undefined;
|
|
264
|
-
return { urlpattern, source };
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/** Matches one script url against a reviewed override pattern of an explicit https origin with single star segments and double star subtrees. */
|
|
268
|
-
export function overridematches(urlpattern: string, url: string): boolean {
|
|
269
|
-
const patternmatch = /^(https:\/\/[^/]+)(\/.*)?$/.exec(urlpattern);
|
|
270
|
-
const urlmatch = /^(https:\/\/[^/]+)(\/.*)?$/.exec(url);
|
|
271
|
-
if (!patternmatch || !urlmatch) return false;
|
|
272
|
-
if (patternmatch[1] !== urlmatch[1]) return false;
|
|
273
|
-
const patternpath = (patternmatch[2] ?? "/").split("/").filter((segment) => segment.length > 0);
|
|
274
|
-
const urlpath = (urlmatch[2] ?? "/").split("/").filter((segment) => segment.length > 0);
|
|
275
|
-
const walk = (patternindex: number, urlindex: number): boolean => {
|
|
276
|
-
if (patternindex >= patternpath.length) return urlindex >= urlpath.length;
|
|
277
|
-
const segment = patternpath[patternindex];
|
|
278
|
-
if (segment === "**")
|
|
279
|
-
return walk(patternindex + 1, urlindex) || (urlindex < urlpath.length && walk(patternindex, urlindex + 1));
|
|
280
|
-
if (urlindex >= urlpath.length) return false;
|
|
281
|
-
if (segment !== "*" && segment !== urlpath[urlindex]) return false;
|
|
282
|
-
return walk(patternindex + 1, urlindex + 1);
|
|
283
|
-
};
|
|
284
|
-
return walk(0, 0);
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/** Normalizes one reviewed teardown plan: the revert steps and the resume policy of resume, pause or ask. */
|
|
288
|
-
export function teardownplanof(value: unknown): teardownplan | undefined {
|
|
289
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
290
|
-
const entry = value as Record<string, unknown>;
|
|
291
|
-
const revertsteps = Array.isArray(entry.revertsteps)
|
|
292
|
-
? entry.revertsteps.filter((step): step is string => typeof step === "string" && step.trim().length > 0)
|
|
293
|
-
: [];
|
|
294
|
-
const policy = entry.resumepolicy;
|
|
295
|
-
if (revertsteps.length === 0) return undefined;
|
|
296
|
-
if (policy !== undefined && policy !== "resume" && policy !== "pause" && policy !== "ask") return undefined;
|
|
297
|
-
return { revertsteps, resumepolicy: policy ?? "ask" };
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/** The teardown outcome of one session: every breakpoint and override reverts, the resume policy decides the continuation and a user detach keeps the session record alive for review while the run pauses. */
|
|
301
|
-
export interface teardowndecision {
|
|
302
|
-
session: cdpsession;
|
|
303
|
-
revertedbreakpoints: string[];
|
|
304
|
-
revertedoverrides: string[];
|
|
305
|
-
resumepolicy: teardownplan["resumepolicy"];
|
|
306
|
-
paused: boolean;
|
|
307
|
-
keepsalive: boolean;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/** Tears one session down safely: the revert steps of the reviewed teardown plan revert every active breakpoint and override in order, the session detaches, and a user detach keeps the session record alive while the run pauses for review before continuing. */
|
|
311
|
-
export function teardowncdpsession(input: {
|
|
312
|
-
session: cdpsession;
|
|
313
|
-
breakpoints: breakpointspec[];
|
|
314
|
-
overrides: scriptoverride[];
|
|
315
|
-
plan: teardownplan | undefined;
|
|
316
|
-
userdetached: boolean;
|
|
317
|
-
at: number;
|
|
318
|
-
}): teardowndecision {
|
|
319
|
-
const revertedbreakpoints = input.breakpoints.filter((spec) => spec.revertedat === undefined).map((spec) => spec.id);
|
|
320
|
-
const revertedoverrides = input.overrides.filter((spec) => spec.revertedat === undefined).map((spec) => spec.id);
|
|
321
|
-
const resumepolicy = input.userdetached ? "pause" : (input.plan?.resumepolicy ?? "ask");
|
|
322
|
-
return {
|
|
323
|
-
session: detachcdpsession(input.session, input.at, input.userdetached),
|
|
324
|
-
revertedbreakpoints,
|
|
325
|
-
revertedoverrides,
|
|
326
|
-
resumepolicy,
|
|
327
|
-
paused: input.userdetached || resumepolicy === "pause",
|
|
328
|
-
keepsalive: input.userdetached,
|
|
329
|
-
};
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/* ── Merged from profilers.ts: the 1.1.90 consolidation interns the correlated profilers logic here, so no variation of the same file lives beside another. ── */
|
|
333
|
-
/**
|
|
334
|
-
* Profilers for the 1.1.47 debugging part three family.
|
|
335
|
-
* Every correlated rule for the reviewed flow, heap, cpu, trace and source map instruments lives in this file: the flow metric grammar with per step mark windows and blocking sums, the on demand heap snapshot records with the user chosen interval, the growth trend slopes with the flagged steps, the cpu profile records with hot functions, the layout shift entries with impacted selectors, the trace records with the reviewed category list and step annotations, the offline replay of a captured trace file, and the source map references with stack rewriting.
|
|
336
|
-
* The chrome devtools protocol needs the debugger permission, which the manifest gate forbids, so every measurement derives from the performance timeline buffers, the injected instrumentation probes of the page harness and the existing page seams; the derivation stays recorded on every record instead of hidden.
|
|
337
|
-
*/
|
|
338
|
-
|
|
339
|
-
/** The profiling kinds of the debugging part three family, listed among the available capabilities of every proposal request. */
|
|
340
|
-
export const profilerkinds: string[] = [
|
|
341
|
-
"measureflow",
|
|
342
|
-
"heapshot",
|
|
343
|
-
"trackmemory",
|
|
344
|
-
"profilecpu",
|
|
345
|
-
"watchshifts",
|
|
346
|
-
"traceload",
|
|
347
|
-
"annotatetrace",
|
|
348
|
-
"replaytrace",
|
|
349
|
-
"capturesourcemaps",
|
|
350
|
-
];
|
|
351
|
-
|
|
352
|
-
/** The reviewed flow metric set: navigation, paint and largest contentful paint timings, first input delay and interaction timings, and the blocking time sums per step window. */
|
|
353
|
-
export const flowmetricnames: string[] = ["navigation", "paint", "lcp", "fid", "interaction", "blocking"];
|
|
354
|
-
|
|
355
|
-
/** The reviewed trace category list applied to every recorded trace; the enabled subset stays a user choice bounded by this grammar only. */
|
|
356
|
-
export const tracecategories: string[] = ["navigation", "scripting", "rendering", "painting", "loading", "network"];
|
|
357
|
-
|
|
358
|
-
/** Normalizes one reviewed profiling attach target: the target kind of page, iframe, worker or service worker with an explicit https url. */
|
|
359
|
-
export function attachtargetof(value: unknown): attachtarget | undefined {
|
|
360
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
361
|
-
const entry = value as Record<string, unknown>;
|
|
362
|
-
const kinds: attachtarget["kind"][] = ["page", "iframe", "worker", "serviceworker"];
|
|
363
|
-
const kind =
|
|
364
|
-
typeof entry.kind === "string" && kinds.includes(entry.kind as attachtarget["kind"])
|
|
365
|
-
? (entry.kind as attachtarget["kind"])
|
|
366
|
-
: undefined;
|
|
367
|
-
const url = typeof entry.url === "string" && entry.url.trim() ? entry.url.trim() : undefined;
|
|
368
|
-
if (kind === undefined || url === undefined) return undefined;
|
|
369
|
-
if (kind !== "page" && !/^https:\/\//.test(url)) return undefined;
|
|
370
|
-
return { kind, url };
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
/** Normalizes one reviewed flow spec: a non-empty mark prefix, a non-empty step window and a metric list of the reviewed metric set. */
|
|
374
|
-
export function flowspecof(value: unknown): flowspec | undefined {
|
|
375
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
376
|
-
const entry = value as Record<string, unknown>;
|
|
377
|
-
const prefix = typeof entry.prefix === "string" && entry.prefix.trim() ? entry.prefix.trim() : undefined;
|
|
378
|
-
const steps = Array.isArray(entry.steps)
|
|
379
|
-
? entry.steps.filter((step): step is string => typeof step === "string" && step.trim().length > 0)
|
|
380
|
-
: [];
|
|
381
|
-
const metrics = Array.isArray(entry.metrics)
|
|
382
|
-
? entry.metrics.filter((metric): metric is string => typeof metric === "string" && flowmetricnames.includes(metric))
|
|
383
|
-
: [];
|
|
384
|
-
if (prefix === undefined || steps.length === 0 || metrics.length === 0) return undefined;
|
|
385
|
-
return { prefix, steps, metrics };
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/** One flattened performance entry of the page buffers: the name, the entry type, the start time and the duration. */
|
|
389
|
-
export interface perfentry {
|
|
390
|
-
name: string;
|
|
391
|
-
type: string;
|
|
392
|
-
start: number;
|
|
393
|
-
duration: number;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
/** Resolves the reviewed step windows of a flow spec from the performance marks of the prefix: every step id of the window gains its start and end from the marks of the measured page. */
|
|
397
|
-
export function stepwindows(spec: flowspec, marks: perfentry[]): Array<{ stepid: string; start: number; end: number }> {
|
|
398
|
-
const windows: Array<{ stepid: string; start: number; end: number }> = [];
|
|
399
|
-
for (const stepid of spec.steps) {
|
|
400
|
-
const start = marks.find((mark) => mark.type === "mark" && mark.name === `${spec.prefix}:${stepid}:start`);
|
|
401
|
-
const end = marks.find((mark) => mark.type === "mark" && mark.name === `${spec.prefix}:${stepid}:end`);
|
|
402
|
-
if (start === undefined || end === undefined) continue;
|
|
403
|
-
windows.push({ stepid, start: start.start, end: Math.max(end.start, start.start) });
|
|
404
|
-
}
|
|
405
|
-
return windows;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/** Measures one reviewed flow from the performance buffers of the page: every metric of the reviewed set carries its window start and end, its duration and the step ids it spans, navigation, paint and largest contentful paint timings come from the navigation and paint buffers, first input delay and interaction timings from the event buffers and the blocking time is summed per step window from the long task entries over the fifty millisecond threshold. */
|
|
409
|
-
export function measure(input: {
|
|
410
|
-
runid: string;
|
|
411
|
-
stepid: string;
|
|
412
|
-
spec: flowspec;
|
|
413
|
-
entries: perfentry[];
|
|
414
|
-
now: number;
|
|
415
|
-
}): flowmetric[] {
|
|
416
|
-
const metrics: flowmetric[] = [];
|
|
417
|
-
const windows = stepwindows(
|
|
418
|
-
input.spec,
|
|
419
|
-
input.entries.filter((entry) => entry.type === "mark"),
|
|
420
|
-
);
|
|
421
|
-
const stepsof = (start: number, end: number): string[] =>
|
|
422
|
-
windows.filter((window) => window.end >= start && window.start <= end).map((window) => window.stepid);
|
|
423
|
-
const push = (name: string, start: number, end: number, steps: string[]): void => {
|
|
424
|
-
if (!input.spec.metrics.includes(name)) return;
|
|
425
|
-
metrics.push({
|
|
426
|
-
id: `${input.runid}-${input.stepid}-${name}-${metrics.length}`,
|
|
427
|
-
runid: input.runid,
|
|
428
|
-
stepid: input.stepid,
|
|
429
|
-
name,
|
|
430
|
-
start,
|
|
431
|
-
end,
|
|
432
|
-
duration: Math.max(0, end - start),
|
|
433
|
-
steps,
|
|
434
|
-
at: input.now,
|
|
435
|
-
});
|
|
436
|
-
};
|
|
437
|
-
const navigation = input.entries.find((entry) => entry.type === "navigation");
|
|
438
|
-
if (navigation !== undefined)
|
|
439
|
-
push(
|
|
440
|
-
"navigation",
|
|
441
|
-
navigation.start,
|
|
442
|
-
navigation.start + navigation.duration,
|
|
443
|
-
stepsof(navigation.start, navigation.start + navigation.duration),
|
|
444
|
-
);
|
|
445
|
-
for (const paint of input.entries.filter((entry) => entry.type === "paint")) {
|
|
446
|
-
if (!input.spec.metrics.includes("paint")) break;
|
|
447
|
-
push("paint", paint.start, paint.start + paint.duration, stepsof(paint.start, paint.start + paint.duration));
|
|
448
|
-
}
|
|
449
|
-
const lcps = input.entries.filter((entry) => entry.type === "largest-contentful-paint");
|
|
450
|
-
const lcp =
|
|
451
|
-
lcps.length > 0 ? lcps.reduce((largest, entry) => (entry.start > largest.start ? entry : largest)) : undefined;
|
|
452
|
-
if (lcp !== undefined) push("lcp", lcp.start, lcp.start + lcp.duration, stepsof(lcp.start, lcp.start + lcp.duration));
|
|
453
|
-
const firstinput = input.entries.find((entry) => entry.type === "first-input");
|
|
454
|
-
if (firstinput !== undefined)
|
|
455
|
-
push(
|
|
456
|
-
"fid",
|
|
457
|
-
firstinput.start,
|
|
458
|
-
firstinput.start + firstinput.duration,
|
|
459
|
-
stepsof(firstinput.start, firstinput.start + firstinput.duration),
|
|
460
|
-
);
|
|
461
|
-
const interactions = input.entries.filter((entry) => entry.type === "event");
|
|
462
|
-
if (interactions.length > 0) {
|
|
463
|
-
const start = interactions.reduce((earliest, entry) => (entry.start < earliest.start ? entry : earliest)).start;
|
|
464
|
-
const end = interactions.reduce(
|
|
465
|
-
(latest, entry) => (entry.start + entry.duration > latest ? entry.start + entry.duration : latest),
|
|
466
|
-
start,
|
|
467
|
-
);
|
|
468
|
-
push("interaction", start, end, stepsof(start, end));
|
|
469
|
-
}
|
|
470
|
-
for (const window of windows) {
|
|
471
|
-
if (!input.spec.metrics.includes("blocking")) break;
|
|
472
|
-
const blocking = input.entries
|
|
473
|
-
.filter((entry) => entry.type === "longtask" && entry.start >= window.start && entry.start <= window.end)
|
|
474
|
-
.reduce((total, entry) => total + Math.max(0, entry.duration - 50), 0);
|
|
475
|
-
metrics.push({
|
|
476
|
-
id: `${input.runid}-${input.stepid}-blocking-${window.stepid}`,
|
|
477
|
-
runid: input.runid,
|
|
478
|
-
stepid: input.stepid,
|
|
479
|
-
name: "blocking",
|
|
480
|
-
start: window.start,
|
|
481
|
-
end: window.end,
|
|
482
|
-
duration: blocking,
|
|
483
|
-
steps: [window.stepid],
|
|
484
|
-
at: input.now,
|
|
485
|
-
});
|
|
486
|
-
}
|
|
487
|
-
return metrics;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/** True when the user chosen heap interval allows a new on demand snapshot: the frequency bound stays a user choice only and an absent interval always allows the capture. */
|
|
491
|
-
export function heapintervalallowed(
|
|
492
|
-
lastcapturedat: number | undefined,
|
|
493
|
-
interval: number | undefined,
|
|
494
|
-
now: number,
|
|
495
|
-
): boolean {
|
|
496
|
-
if (interval === undefined || lastcapturedat === undefined) return true;
|
|
497
|
-
return now - lastcapturedat >= interval;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
/** Captures one on demand heap snapshot record with its byte size, node count and capture time; the counts derive from the page performance memory buffer and the dom node count because no heap profiler exists without the debugger permission. */
|
|
501
|
-
export function heapsnap(input: {
|
|
502
|
-
id: string;
|
|
503
|
-
runid: string;
|
|
504
|
-
stepid: string;
|
|
505
|
-
origin: string;
|
|
506
|
-
usedbytes: number;
|
|
507
|
-
limitbytes: number;
|
|
508
|
-
nodecount: number;
|
|
509
|
-
now: number;
|
|
510
|
-
}): heaprecord {
|
|
511
|
-
return {
|
|
512
|
-
id: input.id,
|
|
513
|
-
runid: input.runid,
|
|
514
|
-
stepid: input.stepid,
|
|
515
|
-
origin: input.origin,
|
|
516
|
-
bytesize: input.usedbytes,
|
|
517
|
-
nodecount: input.nodecount,
|
|
518
|
-
capturedat: input.now,
|
|
519
|
-
};
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
/** Records one heap growth sample taken beside a step with the used and limit bytes of the page memory buffer. */
|
|
523
|
-
export function growsampleof(input: {
|
|
524
|
-
id: string;
|
|
525
|
-
runid: string;
|
|
526
|
-
stepid: string;
|
|
527
|
-
usedbytes: number;
|
|
528
|
-
limitbytes: number;
|
|
529
|
-
now: number;
|
|
530
|
-
}): growsample {
|
|
531
|
-
return {
|
|
532
|
-
id: input.id,
|
|
533
|
-
runid: input.runid,
|
|
534
|
-
stepid: input.stepid,
|
|
535
|
-
usedbytes: input.usedbytes,
|
|
536
|
-
limitbytes: input.limitbytes,
|
|
537
|
-
at: input.now,
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
/** Computes the growth trend of the heap samples: the slope in bytes per millisecond from the first to the last sample, the sample count and the flagged steps whose per step growth exceeds the reviewed slope. */
|
|
542
|
-
export function growthtrend(input: { runid: string; samples: growsample[]; slope: number; now: number }): memorytrend {
|
|
543
|
-
const ordered = [...input.samples].sort((left, right) => left.at - right.at);
|
|
544
|
-
const first = ordered[0];
|
|
545
|
-
const last = ordered[ordered.length - 1];
|
|
546
|
-
const computed =
|
|
547
|
-
first !== undefined && last !== undefined && last.at > first.at
|
|
548
|
-
? (last.usedbytes - first.usedbytes) / (last.at - first.at)
|
|
549
|
-
: 0;
|
|
550
|
-
const flaggedsteps: string[] = [];
|
|
551
|
-
for (let index = 1; index < ordered.length; index += 1) {
|
|
552
|
-
const previous = ordered[index - 1];
|
|
553
|
-
const current = ordered[index];
|
|
554
|
-
if (previous === undefined || current === undefined) continue;
|
|
555
|
-
const growth = current.at > previous.at ? (current.usedbytes - previous.usedbytes) / (current.at - previous.at) : 0;
|
|
556
|
-
if (growth > input.slope && !flaggedsteps.includes(current.stepid)) flaggedsteps.push(current.stepid);
|
|
557
|
-
}
|
|
558
|
-
return { runid: input.runid, slope: computed, samples: ordered.length, flaggedsteps, at: input.now };
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
/** One cpu sample of the profiled window: the observed function name and the sampled time in milliseconds. */
|
|
562
|
-
export interface cpusample {
|
|
563
|
-
name: string;
|
|
564
|
-
time: number;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
/** Captures one cpu profile record around the step window: the profiled duration, the sample count and the hot functions ranked by their accumulated sampled time; the samples derive from the long task attribution and event timing buffers because no sampling profiler exists without the debugger permission. */
|
|
568
|
-
export function cpusnap(input: {
|
|
569
|
-
id: string;
|
|
570
|
-
runid: string;
|
|
571
|
-
stepid: string;
|
|
572
|
-
origin: string;
|
|
573
|
-
duration: number;
|
|
574
|
-
samples: cpusample[];
|
|
575
|
-
now: number;
|
|
576
|
-
}): cpuprofile {
|
|
577
|
-
const ranked = new Map<string, number>();
|
|
578
|
-
for (const sample of input.samples) ranked.set(sample.name, (ranked.get(sample.name) ?? 0) + sample.time);
|
|
579
|
-
const hotfunctions = [...ranked.entries()]
|
|
580
|
-
.sort((left, right) => right[1] - left[1] || left[0].localeCompare(right[0]))
|
|
581
|
-
.map((entry) => entry[0]);
|
|
582
|
-
return {
|
|
583
|
-
id: input.id,
|
|
584
|
-
runid: input.runid,
|
|
585
|
-
stepid: input.stepid,
|
|
586
|
-
origin: input.origin,
|
|
587
|
-
duration: input.duration,
|
|
588
|
-
samplecount: input.samples.length,
|
|
589
|
-
hotfunctions,
|
|
590
|
-
at: input.now,
|
|
591
|
-
};
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
/** Normalizes one observed layout shift entry: the shift score, the start time and the impacted element selectors derived from the shift sources of the page observer. */
|
|
595
|
-
export function shiftentryof(value: unknown): shiftentry | undefined {
|
|
596
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
597
|
-
const entry = value as Record<string, unknown>;
|
|
598
|
-
const score =
|
|
599
|
-
typeof entry.score === "number" && Number.isFinite(entry.score) && entry.score >= 0 ? entry.score : undefined;
|
|
600
|
-
const starttime =
|
|
601
|
-
typeof entry.starttime === "number" && Number.isFinite(entry.starttime) ? entry.starttime : undefined;
|
|
602
|
-
if (score === undefined || starttime === undefined) return undefined;
|
|
603
|
-
const selectors = Array.isArray(entry.selectors)
|
|
604
|
-
? entry.selectors.filter(
|
|
605
|
-
(selector): selector is string => typeof selector === "string" && selector.trim().length > 0,
|
|
606
|
-
)
|
|
607
|
-
: [];
|
|
608
|
-
return {
|
|
609
|
-
id: typeof entry.id === "string" ? entry.id : "",
|
|
610
|
-
runid: typeof entry.runid === "string" ? entry.runid : "",
|
|
611
|
-
stepid: typeof entry.stepid === "string" ? entry.stepid : "",
|
|
612
|
-
score,
|
|
613
|
-
starttime,
|
|
614
|
-
selectors,
|
|
615
|
-
at: typeof entry.at === "number" ? entry.at : starttime,
|
|
616
|
-
};
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
/** Starts one trace record of the flow with the reviewed category list; the record stops at the reviewed window end and the exported file derives from the performance timeline buffers. */
|
|
620
|
-
export function tracestart(input: {
|
|
621
|
-
id: string;
|
|
622
|
-
runid: string;
|
|
623
|
-
stepid: string;
|
|
624
|
-
origin: string;
|
|
625
|
-
categories: string[];
|
|
626
|
-
now: number;
|
|
627
|
-
}): tracerecord {
|
|
628
|
-
return {
|
|
629
|
-
id: input.id,
|
|
630
|
-
runid: input.runid,
|
|
631
|
-
stepid: input.stepid,
|
|
632
|
-
origin: input.origin,
|
|
633
|
-
categories: [...new Set(input.categories)],
|
|
634
|
-
bytesize: 0,
|
|
635
|
-
events: 0,
|
|
636
|
-
annotations: [],
|
|
637
|
-
startedat: input.now,
|
|
638
|
-
endedat: input.now,
|
|
639
|
-
};
|
|
640
|
-
}
|
|
641
|
-
|
|
642
|
-
/** One derived trace event of the recorded window: the name, the reviewed category and the time offset from the trace start. */
|
|
643
|
-
export interface traceevent {
|
|
644
|
-
name: string;
|
|
645
|
-
category: string;
|
|
646
|
-
offset: number;
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
/** Serializes the recorded trace into its exportable file content: the honest derived format of the performance timeline events with the reviewed categories and the step annotations, never the devtools trace binary format. */
|
|
650
|
-
export function tracetofile(
|
|
651
|
-
trace: tracerecord,
|
|
652
|
-
events: traceevent[],
|
|
653
|
-
): { content: string; bytesize: number; events: number } {
|
|
654
|
-
const payload = {
|
|
655
|
-
devthinktrace: "1.1.47",
|
|
656
|
-
runid: trace.runid,
|
|
657
|
-
origin: trace.origin,
|
|
658
|
-
categories: trace.categories,
|
|
659
|
-
startedat: trace.startedat,
|
|
660
|
-
endedat: trace.endedat,
|
|
661
|
-
annotations: trace.annotations,
|
|
662
|
-
traceevents: events.map((event) => ({ name: event.name, cat: event.category, offset: event.offset })),
|
|
663
|
-
};
|
|
664
|
-
const content = JSON.stringify(payload);
|
|
665
|
-
return { content, bytesize: content.length, events: events.length };
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
/** Normalizes one reviewed trace annotation input: the step id, the label and the time offset from the trace start. */
|
|
669
|
-
export function annotationof(value: unknown): traceannotation | undefined {
|
|
670
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return undefined;
|
|
671
|
-
const entry = value as Record<string, unknown>;
|
|
672
|
-
const stepid = typeof entry.stepid === "string" && entry.stepid.trim() ? entry.stepid.trim() : undefined;
|
|
673
|
-
const label = typeof entry.label === "string" && entry.label.trim() ? entry.label.trim() : undefined;
|
|
674
|
-
if (stepid === undefined || label === undefined) return undefined;
|
|
675
|
-
const offset =
|
|
676
|
-
typeof entry.offset === "number" && Number.isFinite(entry.offset) && entry.offset >= 0 ? entry.offset : 0;
|
|
677
|
-
return { stepid, label, offset };
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
/** Writes the reviewed step ids and labels into the trace metadata: every annotation aligns with the run timeline entry of its step so the replay view shows the trace beside the reviewed steps; exported traces without step annotations are refused upstream. */
|
|
681
|
-
export function annotatetrace(input: {
|
|
682
|
-
trace: tracerecord;
|
|
683
|
-
annotations: traceannotation[];
|
|
684
|
-
timeline: Array<{ stepid: string; time: number }>;
|
|
685
|
-
now: number;
|
|
686
|
-
}): tracerecord {
|
|
687
|
-
const aligned = input.annotations.map((annotation) => {
|
|
688
|
-
const entry = input.timeline.find((item) => item.stepid === annotation.stepid);
|
|
689
|
-
if (entry === undefined) return annotation;
|
|
690
|
-
return { ...annotation, offset: Math.max(0, entry.time - input.trace.startedat) };
|
|
691
|
-
});
|
|
692
|
-
return { ...input.trace, annotations: aligned, endedat: Math.max(input.trace.endedat, input.now) };
|
|
693
|
-
}
|
|
694
|
-
|
|
695
|
-
/** The offline replay of one captured trace file: the events, the category counts and the step annotations of the file render without a live browser. */
|
|
696
|
-
export function replaytrace(content: string): {
|
|
697
|
-
traceid: string;
|
|
698
|
-
runid: string;
|
|
699
|
-
categories: Record<string, number>;
|
|
700
|
-
events: Array<{ name: string; category: string; offset: number; stepid?: string }>;
|
|
701
|
-
annotations: traceannotation[];
|
|
702
|
-
} {
|
|
703
|
-
let parsed: unknown;
|
|
704
|
-
try {
|
|
705
|
-
parsed = JSON.parse(content);
|
|
706
|
-
} catch {
|
|
707
|
-
throw new Error("The trace file is not valid json.");
|
|
708
|
-
}
|
|
709
|
-
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
710
|
-
throw new Error("The trace file is not a json object.");
|
|
711
|
-
const record = parsed as Record<string, unknown>;
|
|
712
|
-
const runid = typeof record.runid === "string" ? record.runid : "";
|
|
713
|
-
const annotations = Array.isArray(record.annotations)
|
|
714
|
-
? record.annotations.flatMap((item) => {
|
|
715
|
-
const annotation = annotationof(item);
|
|
716
|
-
return annotation !== undefined ? [annotation] : [];
|
|
717
|
-
})
|
|
718
|
-
: [];
|
|
719
|
-
const rawevents = Array.isArray(record.traceevents) ? record.traceevents : [];
|
|
720
|
-
const categories: Record<string, number> = {};
|
|
721
|
-
const events = rawevents.flatMap((item) => {
|
|
722
|
-
if (!item || typeof item !== "object") return [];
|
|
723
|
-
const entry = item as Record<string, unknown>;
|
|
724
|
-
if (typeof entry.name !== "string" || typeof entry.cat !== "string" || typeof entry.offset !== "number") return [];
|
|
725
|
-
const offset = entry.offset as number;
|
|
726
|
-
categories[entry.cat] = (categories[entry.cat] ?? 0) + 1;
|
|
727
|
-
const annotation = annotations.find((candidate) => Math.abs(candidate.offset - offset) < 1);
|
|
728
|
-
return [
|
|
729
|
-
{
|
|
730
|
-
name: entry.name,
|
|
731
|
-
category: entry.cat,
|
|
732
|
-
offset,
|
|
733
|
-
...(annotation !== undefined ? { stepid: annotation.stepid } : {}),
|
|
734
|
-
},
|
|
735
|
-
];
|
|
736
|
-
});
|
|
737
|
-
return { traceid: typeof record.id === "string" ? record.id : "", runid, categories, events, annotations };
|
|
738
|
-
}
|
|
739
|
-
|
|
740
|
-
/** Resolves the sourceMappingURL declaration of one script source: the map url resolves against the script url and scripts without a declaration have no map to capture. */
|
|
741
|
-
export function mapurlof(scripturl: string, source: string): string | undefined {
|
|
742
|
-
const match = /[#@]\s*sourceMappingURL=(\S+)/.exec(source);
|
|
743
|
-
if (match === null || match[1] === undefined) return undefined;
|
|
744
|
-
try {
|
|
745
|
-
return new URL(match[1], scripturl).toString();
|
|
746
|
-
} catch {
|
|
747
|
-
return undefined;
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
/** Builds the source map reference drafts of the loaded scripts: every script with a sourceMappingURL declaration gains its map url while the parsed state is decided by the capture. */
|
|
752
|
-
export function capturesourcemaps(input: {
|
|
753
|
-
runid: string;
|
|
754
|
-
stepid: string;
|
|
755
|
-
origin: string;
|
|
756
|
-
scripts: Array<{ url: string; source: string }>;
|
|
757
|
-
now: number;
|
|
758
|
-
}): sourcemapref[] {
|
|
759
|
-
return input.scripts.flatMap((script) => {
|
|
760
|
-
const mapurl = mapurlof(script.url, script.source);
|
|
761
|
-
if (mapurl === undefined) return [];
|
|
762
|
-
return [
|
|
763
|
-
{
|
|
764
|
-
id: `${input.runid}-${script.url}`,
|
|
765
|
-
runid: input.runid,
|
|
766
|
-
stepid: input.stepid,
|
|
767
|
-
origin: input.origin,
|
|
768
|
-
scripturl: script.url,
|
|
769
|
-
mapurl,
|
|
770
|
-
parsed: false,
|
|
771
|
-
at: input.now,
|
|
772
|
-
},
|
|
773
|
-
];
|
|
774
|
-
});
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
/** Decodes one base64 vlq segment of a source map mappings field into its integer values. */
|
|
778
|
-
function decodevlq(segment: string): number[] | undefined {
|
|
779
|
-
const values: number[] = [];
|
|
780
|
-
let shift = 0;
|
|
781
|
-
let value = 0;
|
|
782
|
-
for (const character of segment) {
|
|
783
|
-
const digit = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(character);
|
|
784
|
-
if (digit < 0) return undefined;
|
|
785
|
-
value += (digit & 31) << shift;
|
|
786
|
-
shift += 5;
|
|
787
|
-
if ((digit & 32) === 0) {
|
|
788
|
-
const negative = (value & 1) === 1;
|
|
789
|
-
values.push(negative ? -(value >>> 1) : value >>> 1);
|
|
790
|
-
value = 0;
|
|
791
|
-
shift = 0;
|
|
792
|
-
}
|
|
793
|
-
}
|
|
794
|
-
return values.length > 0 ? values : undefined;
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
/** Rewrites one stack location through a parsed source map: the minimal mapping lookup decodes the mappings field, walks the generated lines and resolves the original source file and line of the generated position; unparsed maps leave the location untouched. */
|
|
798
|
-
export function rewritesourcelocation(
|
|
799
|
-
input: { url: string; line: number; column?: number },
|
|
800
|
-
map: { sources?: string[]; mappings?: string },
|
|
801
|
-
): { url: string; line: number } | undefined {
|
|
802
|
-
const sources = Array.isArray(map.sources)
|
|
803
|
-
? map.sources.filter((source): source is string => typeof source === "string")
|
|
804
|
-
: [];
|
|
805
|
-
if (sources.length === 0 || typeof map.mappings !== "string" || map.mappings.length === 0) return undefined;
|
|
806
|
-
const lines = map.mappings.split(";");
|
|
807
|
-
if (input.line >= lines.length) return undefined;
|
|
808
|
-
let sourceindex = 0;
|
|
809
|
-
let sourceline = 0;
|
|
810
|
-
for (let line = 0; line <= input.line; line += 1) {
|
|
811
|
-
const linemappings = lines[line];
|
|
812
|
-
if (linemappings === undefined) continue;
|
|
813
|
-
const first = linemappings.split(",")[0] ?? "";
|
|
814
|
-
if (first.length === 0) continue;
|
|
815
|
-
const values = decodevlq(first);
|
|
816
|
-
if (values === undefined || values.length < 4) continue;
|
|
817
|
-
sourceindex = Math.max(0, sourceindex + (values[1] ?? 0));
|
|
818
|
-
sourceline = Math.max(0, sourceline + (values[2] ?? 0));
|
|
819
|
-
}
|
|
820
|
-
const targetmappings = lines[input.line];
|
|
821
|
-
const target = targetmappings !== undefined ? (targetmappings.split(",")[0] ?? "") : "";
|
|
822
|
-
if (target.length === 0) return undefined;
|
|
823
|
-
const source = sources[Math.min(sources.length - 1, sourceindex)];
|
|
824
|
-
if (source === undefined) return undefined;
|
|
825
|
-
return { url: source, line: sourceline };
|
|
826
|
-
}
|
|
827
|
-
|
|
828
|
-
/** Expires the heavy profile bytes after the user configured retention window: the snapshot bytes, sample payloads and trace file bytes drop while the byte and node counts, the sample counts, hot functions, category lists and step annotations survive. */
|
|
829
|
-
export function expireprofilerecords(input: {
|
|
830
|
-
heaps: heaprecord[];
|
|
831
|
-
profiles: cpuprofile[];
|
|
832
|
-
traces: tracerecord[];
|
|
833
|
-
retention: number | undefined;
|
|
834
|
-
now: number;
|
|
835
|
-
}): { heaps: heaprecord[]; profiles: cpuprofile[]; traces: tracerecord[] } {
|
|
836
|
-
const retention = input.retention;
|
|
837
|
-
if (retention === undefined) return { heaps: input.heaps, profiles: input.profiles, traces: input.traces };
|
|
838
|
-
const expired = (at: number): boolean => input.now - at > retention;
|
|
839
|
-
return {
|
|
840
|
-
heaps: input.heaps.map((heap) =>
|
|
841
|
-
expired(heap.capturedat) && heap.bytesexpired !== true ? { ...heap, bytesexpired: true } : heap,
|
|
842
|
-
),
|
|
843
|
-
profiles: input.profiles.map((profile) =>
|
|
844
|
-
expired(profile.at) && profile.samplesexpired !== true ? { ...profile, samplesexpired: true } : profile,
|
|
845
|
-
),
|
|
846
|
-
traces: input.traces.map((trace) =>
|
|
847
|
-
expired(trace.endedat) && trace.bytesexpired !== true ? { ...trace, bytesexpired: true } : trace,
|
|
848
|
-
),
|
|
849
|
-
};
|
|
850
|
-
}
|