rea-agents 1.7.0 → 2.1.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.
Files changed (333) hide show
  1. package/README.md +112 -59
  2. package/bridge/ghidra/ReaGhidraBridge.java +96 -11
  3. package/dist/application/ArtifactExtraction.js +1 -1
  4. package/dist/application/ArtifactInventory/classify.js +42 -0
  5. package/dist/application/ArtifactInventory/hash.js +43 -0
  6. package/dist/application/ArtifactInventory/reader.js +41 -0
  7. package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
  8. package/dist/application/ArtifactInventory/scanReader.js +124 -0
  9. package/dist/application/ArtifactInventory/types.js +10 -0
  10. package/dist/application/ArtifactInventory.js +9 -351
  11. package/dist/application/AuthorizedArtifactInventory.js +2 -2
  12. package/dist/application/BinarySession.js +47 -270
  13. package/dist/application/BinarySessionExecution.js +28 -0
  14. package/dist/application/BinarySessionOpen.js +39 -0
  15. package/dist/application/BinarySessionRecords.js +149 -0
  16. package/dist/application/BinarySessionStatus.js +75 -0
  17. package/dist/application/CapabilityInventory.js +42 -2
  18. package/dist/application/ClientRegistrationStatus.js +1 -1
  19. package/dist/application/CrossVersionInventory.js +8 -2
  20. package/dist/application/CrossVersionInvestigation.js +11 -29
  21. package/dist/application/CrossVersionInvestigationCollections.js +23 -0
  22. package/dist/application/DirectAnalysis.js +47 -44
  23. package/dist/application/Doctor.js +165 -197
  24. package/dist/application/DoctorDiagnostics.js +180 -0
  25. package/dist/application/ElectronBoundaryAnalysis.js +112 -0
  26. package/dist/application/ElectronBoundaryGraph.js +9 -0
  27. package/dist/application/ElectronBoundaryGraphContext.js +62 -0
  28. package/dist/application/ElectronBoundaryGraphIpc.js +242 -0
  29. package/dist/application/ElectronBoundaryGraphNative.js +86 -0
  30. package/dist/application/ElectronBoundaryGraphWindows.js +223 -0
  31. package/dist/application/EnhancedToolPagination.js +22 -0
  32. package/dist/application/EnhancedToolTypes.js +4 -0
  33. package/dist/application/EnhancedTools.js +58 -50
  34. package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
  35. package/dist/application/InvestigationProviders.js +30 -0
  36. package/dist/application/InvestigationWorkspaceStore.js +24 -10
  37. package/dist/application/JavaScriptApplicationEvidence.js +26 -0
  38. package/dist/application/JavaScriptApplicationEvidenceGraph.js +89 -0
  39. package/dist/application/JavaScriptApplicationService.js +74 -0
  40. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +29 -0
  41. package/dist/application/JavaScriptApplicationWorkflowService.js +90 -0
  42. package/dist/application/JavaScriptArtifactAnalysis.js +52 -7
  43. package/dist/application/JavaScriptArtifactFiles.js +6 -2
  44. package/dist/application/JavaScriptArtifactGraphBuilder.js +82 -17
  45. package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
  46. package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
  47. package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
  48. package/dist/application/JavaScriptArtifactGraphEvidence.js +24 -14
  49. package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
  50. package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
  51. package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
  52. package/dist/application/JavaScriptArtifactReconstruction.js +4 -1
  53. package/dist/application/JavaScriptArtifactReconstructionInput.js +2 -83
  54. package/dist/application/JavaScriptJsonModules.js +39 -0
  55. package/dist/application/JavaScriptModuleRelationships.js +262 -0
  56. package/dist/application/JavaScriptReplayPermission.js +16 -0
  57. package/dist/application/JavaScriptReplayPlanning.js +201 -0
  58. package/dist/application/JavaScriptReplayService.js +292 -0
  59. package/dist/application/JavaScriptRuntimeReconciliationEvidence.js +25 -0
  60. package/dist/application/JavaScriptRuntimeReconciliationService.js +27 -0
  61. package/dist/application/LinuxHopper.js +10 -0
  62. package/dist/application/MacHopper.js +22 -11
  63. package/dist/application/ManagedApplicationGraphService.js +55 -0
  64. package/dist/application/ManagedMemberComparisonService.js +122 -0
  65. package/dist/application/ManagedNativeVerificationService.js +39 -0
  66. package/dist/application/ManagedReconstructionService.js +58 -0
  67. package/dist/application/ManagedRuntimeCorrelationService.js +103 -0
  68. package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
  69. package/dist/application/PermissionAuthority.js +106 -63
  70. package/dist/application/ProcessCaptureCapability.js +1 -1
  71. package/dist/application/ProcessCapturePermission.js +13 -0
  72. package/dist/application/ProcessCli.js +2 -12
  73. package/dist/application/ProcessHarness.js +1 -1
  74. package/dist/application/ProcessSampling.js +15 -11
  75. package/dist/application/ProjectPermissionStore.js +49 -9
  76. package/dist/application/RealHopperAssertions.js +76 -0
  77. package/dist/application/ReconstructionCoverageService.js +69 -0
  78. package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
  79. package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
  80. package/dist/application/Setup.js +147 -259
  81. package/dist/application/SetupClientConfiguration.js +220 -0
  82. package/dist/application/SetupClients.js +24 -2
  83. package/dist/application/SetupPlan.js +123 -12
  84. package/dist/application/SetupSkill.js +26 -12
  85. package/dist/application/SupportedClients.js +1 -0
  86. package/dist/application/Uninstall.js +6 -3
  87. package/dist/application/WindowsCapabilities.js +86 -0
  88. package/dist/application/runtime.js +2 -0
  89. package/dist/artifacts/AsarArtifactReader.js +11 -0
  90. package/dist/browser/BrowserProcessStartup.js +88 -0
  91. package/dist/browser/CdpCaptureDocuments.js +12 -8
  92. package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
  93. package/dist/browser/CdpCaptureEventHandlers.js +336 -0
  94. package/dist/browser/CdpCaptureEventHelpers.js +71 -0
  95. package/dist/browser/CdpCaptureEventState.js +1 -0
  96. package/dist/browser/CdpCaptureEventTypes.js +1 -0
  97. package/dist/browser/CdpCaptureEvents.js +46 -464
  98. package/dist/browser/CdpElectronInspection.js +106 -162
  99. package/dist/browser/CdpElectronProvider.js +5 -1
  100. package/dist/browser/CdpElectronScriptEvents.js +69 -0
  101. package/dist/browser/CdpElectronScripts.js +94 -0
  102. package/dist/browser/CdpElectronWorkers.js +56 -0
  103. package/dist/browser/CdpObservationSession.js +51 -8
  104. package/dist/browser/CdpPageCapture.js +12 -129
  105. package/dist/browser/CdpPageCaptureScripts.js +97 -0
  106. package/dist/browser/CdpPageCaptureWorkers.js +46 -0
  107. package/dist/browser/CdpWebMcpDiscovery.js +38 -14
  108. package/dist/browser/PngVisualDiff.js +9 -2
  109. package/dist/catalogIdentity.js +8 -1
  110. package/dist/cli/artifactCommands.js +82 -0
  111. package/dist/cli/coreAnalysisCommands.js +232 -0
  112. package/dist/cli/managedCommands.js +397 -0
  113. package/dist/cli/managedProjectGraphCommand.js +24 -0
  114. package/dist/cli/options.js +9 -0
  115. package/dist/cli/setupCommands.js +108 -0
  116. package/dist/cli/types.js +1 -0
  117. package/dist/cli/utilityCommands.js +122 -0
  118. package/dist/cli.js +13 -383
  119. package/dist/cliApplicationCommands.js +176 -0
  120. package/dist/cliBrowserAdvancedCommands.js +73 -16
  121. package/dist/cliBrowserCommands.js +39 -115
  122. package/dist/cliCommandNames.js +17 -0
  123. package/dist/cliElectronCommands.js +100 -27
  124. package/dist/cliEvidenceCommands.js +13 -2
  125. package/dist/cliInvestigationCommands.js +53 -10
  126. package/dist/cliJsonInput.js +54 -0
  127. package/dist/cliObservationOptions.js +137 -0
  128. package/dist/cliPolicyCommands.js +80 -46
  129. package/dist/cliSetup.js +289 -0
  130. package/dist/config/environment.js +107 -0
  131. package/dist/config/parseConfig.js +228 -0
  132. package/dist/config/parsers.js +68 -0
  133. package/dist/config/permissions.js +30 -0
  134. package/dist/config/types.js +1 -0
  135. package/dist/config.js +1 -292
  136. package/dist/contracts/applicationToolContracts.js +225 -0
  137. package/dist/contracts/artifactToolContracts.js +5 -9
  138. package/dist/contracts/browserToolContracts.js +14 -62
  139. package/dist/contracts/electronToolContracts.js +45 -19
  140. package/dist/contracts/errorSchemas.js +1 -0
  141. package/dist/contracts/investigationExamples.js +0 -6
  142. package/dist/contracts/javascriptApplicationWorkflowExamples.js +46 -0
  143. package/dist/contracts/javascriptRuntimeReconciliationExample.js +208 -0
  144. package/dist/contracts/managedToolContracts.js +153 -0
  145. package/dist/contracts/managedWorkflowExamples.js +346 -0
  146. package/dist/contracts/managedWorkflowToolContracts.js +203 -0
  147. package/dist/contracts/nativeToolContracts.js +2 -6
  148. package/dist/contracts/promptContracts.js +18 -2
  149. package/dist/contracts/providerSelection.js +2 -0
  150. package/dist/contracts/toolContractExamples.js +10 -25
  151. package/dist/contracts/toolContracts.js +49 -47
  152. package/dist/contracts/toolEffects.js +174 -0
  153. package/dist/contracts/toolOutputSchemaGroups.js +232 -0
  154. package/dist/contracts/toolOutputSchemaPrimitives.js +327 -0
  155. package/dist/contracts/toolOutputSchemas.js +2 -535
  156. package/dist/doctorRuntime.js +42 -1
  157. package/dist/domain/analysisErrorPresentation.js +234 -0
  158. package/dist/domain/analysisErrorProjection.js +284 -0
  159. package/dist/domain/artifactComparison.js +37 -19
  160. package/dist/domain/binaryTarget.js +87 -37
  161. package/dist/domain/browserObservation.js +1 -282
  162. package/dist/domain/browserObservationSchemas.js +286 -0
  163. package/dist/domain/bundleComparison.js +4 -4
  164. package/dist/domain/electronObservation.js +13 -0
  165. package/dist/domain/electronStaticAnalysis.js +9 -0
  166. package/dist/domain/electronStaticAnalysisBrowser.js +206 -0
  167. package/dist/domain/electronStaticAnalysisIpc.js +171 -0
  168. package/dist/domain/electronStaticAnalysisNative.js +164 -0
  169. package/dist/domain/electronStaticAnalysisTypes.js +1 -0
  170. package/dist/domain/electronStaticAnalysisValues.js +103 -0
  171. package/dist/domain/errors.js +32 -448
  172. package/dist/domain/functionComparison.js +4 -165
  173. package/dist/domain/functionComparisonDimensions.js +164 -0
  174. package/dist/domain/functionComparisonSchemas.js +3 -8
  175. package/dist/domain/inputIssueProjection.js +52 -0
  176. package/dist/domain/javascriptApplicationAnalysis.js +155 -0
  177. package/dist/domain/javascriptApplicationChangeGraph.js +231 -0
  178. package/dist/domain/javascriptApplicationEvidenceSchemas.js +18 -0
  179. package/dist/domain/javascriptApplicationGraph.js +2 -1
  180. package/dist/domain/javascriptApplicationGraphSchemas.js +7 -0
  181. package/dist/domain/javascriptApplicationVersionComparison.js +116 -0
  182. package/dist/domain/javascriptApplicationVersionComparisonSchemas.js +139 -0
  183. package/dist/domain/javascriptApplicationVersionItems.js +233 -0
  184. package/dist/domain/javascriptApplicationVersionKeys.js +170 -0
  185. package/dist/domain/javascriptExportInstrumentation.js +97 -0
  186. package/dist/domain/javascriptFeatureSeed.js +140 -0
  187. package/dist/domain/javascriptFeatureTrace.js +232 -0
  188. package/dist/domain/javascriptFeatureTraceSchemas.js +136 -0
  189. package/dist/domain/javascriptFeatureTraversal.js +100 -0
  190. package/dist/domain/javascriptNativeHandoff.js +85 -0
  191. package/dist/domain/javascriptReplay.js +361 -0
  192. package/dist/domain/javascriptRuntimeLoadState.js +106 -0
  193. package/dist/domain/javascriptRuntimeReconciliation.js +42 -0
  194. package/dist/domain/javascriptRuntimeReconciliationGraph.js +169 -0
  195. package/dist/domain/javascriptRuntimeReconciliationMatching.js +247 -0
  196. package/dist/domain/javascriptRuntimeReconciliationParsing.js +160 -0
  197. package/dist/domain/javascriptRuntimeReconciliationResult.js +119 -0
  198. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +316 -0
  199. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +245 -0
  200. package/dist/domain/javascriptRuntimeStaticCandidates.js +193 -0
  201. package/dist/domain/javascriptSemanticAnalysis.js +386 -0
  202. package/dist/domain/javascriptSemanticIr.js +30 -0
  203. package/dist/domain/javascriptSemanticProjection.js +366 -0
  204. package/dist/domain/javascriptSemanticState.js +40 -0
  205. package/dist/domain/javascriptSemanticTraversal.js +22 -0
  206. package/dist/domain/javascriptSemanticValues.js +352 -0
  207. package/dist/domain/javascriptStaticAnalysis.js +26 -254
  208. package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
  209. package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
  210. package/dist/domain/javascriptStaticAnalysisFindings.js +39 -0
  211. package/dist/domain/javascriptStaticAnalysisHelpers.js +81 -2
  212. package/dist/domain/javascriptStaticAnalysisState.js +6 -0
  213. package/dist/domain/knownPageCoverage.js +21 -0
  214. package/dist/domain/managedApplicationGraph.js +206 -0
  215. package/dist/domain/managedApplicationGraphCoverage.js +170 -0
  216. package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
  217. package/dist/domain/managedApplicationGraphNodes.js +336 -0
  218. package/dist/domain/managedArtifact.js +452 -0
  219. package/dist/domain/managedMemberComparison.js +211 -0
  220. package/dist/domain/managedMemberComparisonCoverage.js +72 -0
  221. package/dist/domain/managedMemberComparisonMatch.js +356 -0
  222. package/dist/domain/managedNativeVerification.js +46 -0
  223. package/dist/domain/managedNativeVerificationMatch.js +272 -0
  224. package/dist/domain/managedNativeVerificationSchemas.js +141 -0
  225. package/dist/domain/managedReconstruction.js +196 -0
  226. package/dist/domain/managedRuntimeCorrelation.js +184 -0
  227. package/dist/domain/nodeRuntimeCharacterization.js +66 -0
  228. package/dist/domain/permissionPolicy.js +2 -0
  229. package/dist/domain/reconstructionCoverage.js +387 -0
  230. package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
  231. package/dist/domain/reconstructionVerificationSchemas.js +9 -3
  232. package/dist/domain/runtimeCharacterization.js +85 -0
  233. package/dist/domain/webBundleAnalyzer.js +3 -409
  234. package/dist/domain/webBundleAnalyzerAst.js +77 -0
  235. package/dist/domain/webBundleAnalyzerInspection.js +307 -0
  236. package/dist/domain/webBundleAnalyzerResult.js +120 -0
  237. package/dist/dotnet/ManagedArtifactInspector.js +339 -0
  238. package/dist/dotnet/ManagedMemberInspector.js +153 -0
  239. package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
  240. package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
  241. package/dist/dotnet/ManagedMemberRows.js +120 -0
  242. package/dist/dotnet/ManagedMetadataHeaps.js +131 -0
  243. package/dist/dotnet/ManagedMetadataInventory.js +104 -0
  244. package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
  245. package/dist/dotnet/ManagedMetadataLayout.js +259 -0
  246. package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
  247. package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
  248. package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
  249. package/dist/dotnet/ManagedNativeBoundaryInspector.js +143 -0
  250. package/dist/dotnet/ManagedPeReader.js +188 -0
  251. package/dist/dotnet/ManagedReaderFailure.js +10 -0
  252. package/dist/dotnet/ManagedStaticProvider.js +203 -0
  253. package/dist/generatedPackageMetadata.js +2 -2
  254. package/dist/ghidra/GhidraClient.js +76 -91
  255. package/dist/ghidra/GhidraClientStartup.js +29 -0
  256. package/dist/ghidra/GhidraClientWire.js +34 -0
  257. package/dist/ghidra/GhidraDefaults.js +1 -1
  258. package/dist/ghidra/GhidraDiagnostics.js +6 -1
  259. package/dist/ghidra/GhidraInstallation.js +20 -15
  260. package/dist/ghidra/GhidraLauncher.js +93 -29
  261. package/dist/ghidra/GhidraProvider.js +67 -161
  262. package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
  263. package/dist/ghidra/GhidraSessionValues.js +2 -0
  264. package/dist/ghidra/GhidraSocketConnection.js +44 -7
  265. package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
  266. package/dist/ghidra/GhidraTransport.js +71 -0
  267. package/dist/identity.js +3 -2
  268. package/dist/main/messages.js +5 -0
  269. package/dist/main/reload.js +49 -0
  270. package/dist/main/shutdown.js +25 -0
  271. package/dist/main/startup.js +14 -0
  272. package/dist/main/state.js +26 -0
  273. package/dist/main/transport.js +61 -0
  274. package/dist/main/types.js +1 -0
  275. package/dist/main.js +35 -132
  276. package/dist/process/PrivateRuntimeRoot.js +3 -2
  277. package/dist/process/ProcessOwnership.js +35 -0
  278. package/dist/process/ProviderProcess.js +2 -0
  279. package/dist/replay/JavaScriptReplayWorker.js +300 -0
  280. package/dist/replay/LinuxJavaScriptReplayRunner.js +217 -0
  281. package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
  282. package/dist/replay/LinuxRuntimeClosure.js +46 -0
  283. package/dist/replay/LinuxSeccompPolicy.js +40 -0
  284. package/dist/replay/ReplayOutcome.js +95 -0
  285. package/dist/replay/ReplayProcessLifecycle.js +71 -0
  286. package/dist/replay/ReplayWorkerProtocol.js +55 -0
  287. package/dist/replay/SystemJavaScriptReplayHost.js +182 -0
  288. package/dist/server/ProcessCaptureElicitation.js +157 -0
  289. package/dist/server/createServer.js +158 -41
  290. package/dist/server/registerApplicationTools/characterization.js +57 -0
  291. package/dist/server/registerApplicationTools/compareVersions.js +34 -0
  292. package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
  293. package/dist/server/registerApplicationTools/coverage.js +84 -0
  294. package/dist/server/registerApplicationTools/helpers.js +42 -0
  295. package/dist/server/registerApplicationTools/traceFeature.js +26 -0
  296. package/dist/server/registerApplicationTools/types.js +1 -0
  297. package/dist/server/registerApplicationTools.js +13 -0
  298. package/dist/server/registerArtifactComparisonTool.js +16 -9
  299. package/dist/server/registerBrowserTools.js +61 -60
  300. package/dist/server/registerBundleComparisonTool.js +17 -20
  301. package/dist/server/registerElectronTools.js +39 -12
  302. package/dist/server/registerEnhancedTools.js +52 -15
  303. package/dist/server/registerEvidenceResources.js +54 -0
  304. package/dist/server/registerEvidenceTools.js +5 -1
  305. package/dist/server/registerFunctionComparisonTool.js +14 -7
  306. package/dist/server/registerInvestigationTools/helpers.js +74 -0
  307. package/dist/server/registerInvestigationTools/types.js +1 -0
  308. package/dist/server/registerInvestigationTools.js +103 -132
  309. package/dist/server/registerManagedTools.js +6 -0
  310. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
  311. package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
  312. package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
  313. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
  314. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
  315. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
  316. package/dist/server/registerManagedWorkflowTools/types.js +1 -0
  317. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
  318. package/dist/server/registerManagedWorkflowTools.js +13 -0
  319. package/dist/server/registerOfficialTools.js +81 -67
  320. package/dist/server/registerProcessComparisonTool.js +25 -47
  321. package/dist/server/registerSessionRecordTools.js +137 -0
  322. package/dist/server/registerSessionStatusTool.js +9 -8
  323. package/dist/server/registerSessionTools.js +77 -216
  324. package/dist/server/sessionAvailabilityPolicy.js +10 -0
  325. package/dist/server/sessionEvidence.js +14 -19
  326. package/dist/server/toolInputValidation.js +77 -0
  327. package/dist/server/toolRegistrationOptions.js +177 -2
  328. package/dist/server/toolResult.js +30 -17
  329. package/package.json +21 -14
  330. package/scripts/rea.mjs +1 -1
  331. package/skills/{rea-analysis → reverse-engineer-anything}/SKILL.md +75 -6
  332. package/scripts/prepare-node-pty.mjs +0 -35
  333. package/scripts/rebuild-native.mjs +0 -22
@@ -1,78 +1,126 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import canonicalize from "canonicalize";
3
3
  import { BrowserObservationError } from "../domain/errors.js";
4
- import { createWebTextArtifact } from "../domain/webContentArtifact.js";
5
4
  import { CdpCaptureCompleteness } from "./CdpCaptureCompleteness.js";
6
- import { boundedText, delayWithCancellation, numberValue, recordValue, recordsValue, requiredRecord, stringValue, } from "./CdpCaptureValues.js";
5
+ import { delayWithCancellation, numberValue, recordValue, recordsValue, requiredRecord, stringValue, } from "./CdpCaptureValues.js";
6
+ import { ingestElectronScriptEvent, } from "./CdpElectronScriptEvents.js";
7
+ import { captureElectronScripts } from "./CdpElectronScripts.js";
8
+ import { captureElectronWorkers } from "./CdpElectronWorkers.js";
7
9
  import { authorizedElectronFile, canonicalElectronRoots, } from "./ElectronFileScope.js";
8
10
  /** Passively inspect one root-confined Electron file page. */
9
11
  export const inspectCdpElectronPage = async (context) => {
10
- const roots = await canonicalElectronRoots(context.input.allowed_file_roots);
11
- const completeness = new CdpCaptureCompleteness();
12
- const scripts = [];
13
- let mainFrameId;
14
- let navigationDuringCapture = false;
12
+ const state = {
13
+ roots: await canonicalElectronRoots(context.input.allowed_file_roots),
14
+ completeness: new CdpCaptureCompleteness(),
15
+ scripts: [],
16
+ executionContextFrames: new Map(),
17
+ limitations: [
18
+ "Only canonical file paths contained by an approved root are retained.",
19
+ "REA does not evaluate renderer JavaScript, invoke Electron APIs, navigate, click, or close the page.",
20
+ "Script contents require separate source-capture approval and remain byte bounded.",
21
+ ],
22
+ mainFrameId: undefined,
23
+ navigationDuringCapture: false,
24
+ };
15
25
  const removeListener = context.connection.onEvent((event) => {
16
26
  if (event.sessionId !== context.sessionId)
17
27
  return;
18
- ingestScript(event, scripts, completeness);
19
- if (mainFrameId !== undefined && navigatedFrameId(event) === mainFrameId)
20
- navigationDuringCapture = true;
28
+ ingestElectronScriptEvent({
29
+ event,
30
+ scripts: state.scripts,
31
+ executionContextFrames: state.executionContextFrames,
32
+ completeness: state.completeness,
33
+ });
34
+ if (state.mainFrameId !== undefined &&
35
+ navigatedFrameId(event) === state.mainFrameId)
36
+ state.navigationDuringCapture = true;
21
37
  });
22
- const startedAt = new Date().toISOString();
23
38
  try {
24
- await report(context.progress, 1, "Authorizing Electron file frames");
25
- await context.connection.send("Page.enable", {}, context.sessionId, context.signal);
26
- const before = await context.connection.send("Page.getFrameTree", {}, context.sessionId, context.signal);
27
- const frames = await captureFrames(before, roots, context.input.limits.max_frames, completeness);
28
- const main = frames[0];
29
- if (main === undefined)
30
- throw new BrowserObservationError("inspect_web_page", "target_not_allowed");
31
- mainFrameId = main.frame_id;
32
- await context.connection.send("Debugger.enable", { maxScriptsCacheSize: 4 * 1_024 * 1_024 }, context.sessionId, context.signal);
33
- await delayWithCancellation(context.input.observation_ms, "inspect_electron_page", context.signal);
34
- await report(context.progress, 2, "Capturing Electron structure");
35
- const resources = await captureResources(context, roots, completeness);
36
- const dom = await captureDom(context, roots, completeness);
37
- const normalizedScripts = await captureScripts(context, roots, scripts, completeness);
38
- const after = await context.connection.send("Page.getFrameTree", {}, context.sessionId, context.signal);
39
- const afterMain = await mainFilePath(after, roots);
40
- if (afterMain === undefined)
41
- throw new BrowserObservationError("inspect_web_page", "target_not_allowed");
42
- if (navigationDuringCapture || afterMain !== main.file_path)
43
- throw new BrowserObservationError("inspect_web_page", "target_changed");
44
- await report(context.progress, 3, "Electron inspection complete");
45
- return {
46
- schema_version: 1,
47
- browser: context.discovery.version,
48
- target: {
49
- target_id: context.target.id,
50
- type: context.target.type,
51
- title: context.target.title.slice(0, 16_384),
52
- file_path: main.file_path,
53
- attached: context.target.attached,
54
- },
55
- capture_window: {
56
- started_at: startedAt,
57
- ended_at: new Date().toISOString(),
58
- observation_ms: context.input.observation_ms,
59
- },
60
- completeness: completeness.snapshot(),
61
- frames,
62
- dom,
63
- scripts: normalizedScripts,
64
- resources,
65
- limitations: [
66
- "Only canonical file paths contained by an approved root are retained.",
67
- "REA does not evaluate renderer JavaScript, invoke Electron APIs, navigate, click, or close the page.",
68
- "Script contents require separate source-capture approval and remain byte bounded.",
69
- ],
70
- };
39
+ return await runElectronInspection(context, state, new Date().toISOString());
71
40
  }
72
41
  finally {
73
42
  removeListener();
74
43
  }
75
44
  };
45
+ const runElectronInspection = async (context, state, startedAt) => {
46
+ const frames = await authorizeInitialFrames(context, state);
47
+ const main = frames[0];
48
+ state.mainFrameId = main.frame_id;
49
+ await enableElectronCapture(context);
50
+ await delayWithCancellation(context.input.observation_ms, "inspect_electron_page", context.signal);
51
+ const captured = await captureElectronContent(context, state, frames);
52
+ await assertStableMainFrame(context, state, main.file_path);
53
+ await report(context.progress, 3, "Electron inspection complete");
54
+ return {
55
+ schema_version: 1,
56
+ browser: context.discovery.version,
57
+ target: {
58
+ target_id: context.target.id,
59
+ type: context.target.type,
60
+ title: context.target.title.slice(0, 16_384),
61
+ file_path: main.file_path,
62
+ attached: context.target.attached,
63
+ },
64
+ capture_window: {
65
+ started_at: startedAt,
66
+ ended_at: new Date().toISOString(),
67
+ observation_ms: context.input.observation_ms,
68
+ },
69
+ completeness: state.completeness.snapshot(),
70
+ frames,
71
+ ...captured,
72
+ limitations: state.limitations,
73
+ };
74
+ };
75
+ const authorizeInitialFrames = async (context, state) => {
76
+ await report(context.progress, 1, "Authorizing Electron file frames");
77
+ await context.connection.send("Page.enable", {}, context.sessionId, context.signal);
78
+ const result = await context.connection.send("Page.getFrameTree", {}, context.sessionId, context.signal);
79
+ const frames = await captureFrames(result, state.roots, context.input.limits.max_frames, state.completeness);
80
+ if (frames[0] === undefined)
81
+ throw new BrowserObservationError("inspect_web_page", "target_not_allowed");
82
+ return frames;
83
+ };
84
+ const enableElectronCapture = async (context) => {
85
+ await context.connection.send("Runtime.enable", {}, context.sessionId, context.signal);
86
+ await context.connection.send("Debugger.enable", { maxScriptsCacheSize: 4 * 1_024 * 1_024 }, context.sessionId, context.signal);
87
+ };
88
+ const captureElectronContent = async (context, state, frames) => {
89
+ await report(context.progress, 2, "Capturing Electron structure");
90
+ const frameIds = new Set(frames.map((frame) => frame.frame_id));
91
+ const resources = await captureResources(context, state.roots, state.completeness);
92
+ const dom = await captureDom(context, state.roots, state.completeness);
93
+ const scripts = await captureElectronScripts({
94
+ connection: context.connection,
95
+ sessionId: context.sessionId,
96
+ ...(context.signal === undefined ? {} : { signal: context.signal }),
97
+ request: context.input,
98
+ roots: state.roots,
99
+ scripts: state.scripts,
100
+ executionContextFrames: state.executionContextFrames,
101
+ frameIds,
102
+ completeness: state.completeness,
103
+ });
104
+ const workers = await captureElectronWorkers({
105
+ connection: context.connection,
106
+ ...(context.signal === undefined ? {} : { signal: context.signal }),
107
+ target: context.target,
108
+ request: context.input,
109
+ roots: state.roots,
110
+ frameIds,
111
+ completeness: state.completeness,
112
+ limitations: state.limitations,
113
+ });
114
+ return { dom, scripts, resources, workers };
115
+ };
116
+ const assertStableMainFrame = async (context, state, expectedPath) => {
117
+ const result = await context.connection.send("Page.getFrameTree", {}, context.sessionId, context.signal);
118
+ const afterPath = await mainFilePath(result, state.roots);
119
+ if (afterPath === undefined)
120
+ throw new BrowserObservationError("inspect_web_page", "target_not_allowed");
121
+ if (state.navigationDuringCapture || afterPath !== expectedPath)
122
+ throw new BrowserObservationError("inspect_web_page", "target_changed");
123
+ };
76
124
  const navigatedFrameId = (event) => {
77
125
  const params = recordValue(event.params);
78
126
  if (params === undefined)
@@ -83,33 +131,6 @@ const navigatedFrameId = (event) => {
83
131
  return stringValue(params.frameId);
84
132
  return undefined;
85
133
  };
86
- const ingestScript = (event, scripts, completeness) => {
87
- if (event.method !== "Debugger.scriptParsed")
88
- return;
89
- const value = recordValue(event.params);
90
- const scriptId = stringValue(value?.scriptId);
91
- const rawUrl = stringValue(value?.url);
92
- if (scriptId === undefined || scriptId.length > 256) {
93
- completeness.exclude("scripts", "invalid_protocol_value");
94
- return;
95
- }
96
- if (rawUrl === undefined || rawUrl === "") {
97
- completeness.exclude("scripts", "unattributed_origin");
98
- return;
99
- }
100
- if (scripts.length >= 2_000) {
101
- completeness.drop("scripts");
102
- return;
103
- }
104
- scripts.push({
105
- scriptId,
106
- rawUrl,
107
- hash: (stringValue(value?.hash) ?? "").slice(0, 512),
108
- length: nonnegativeInteger(value?.length),
109
- isModule: value?.isModule === true,
110
- language: boundedText(value?.scriptLanguage, 100),
111
- });
112
- };
113
134
  const captureFrames = async (result, roots, maximum, completeness) => {
114
135
  const frameTree = recordValue(requiredRecord(result).frameTree);
115
136
  if (frameTree === undefined)
@@ -227,82 +248,6 @@ const captureDom = async (context, roots, completeness) => {
227
248
  completeness.truncate("dom");
228
249
  return { total_nodes: total, nodes };
229
250
  };
230
- const captureScripts = async (context, roots, scripts, completeness) => {
231
- let total = 0;
232
- let sourceBytes = 0;
233
- const items = [];
234
- const seen = new Set();
235
- for (const script of scripts) {
236
- const path = await authorizedElectronFile(script.rawUrl, roots);
237
- if (path === undefined) {
238
- completeness.exclude("scripts", "out_of_target_scope");
239
- continue;
240
- }
241
- const identity = {
242
- file_path: path,
243
- cdp_hash: script.hash,
244
- length: script.length,
245
- is_module: script.isModule,
246
- language: script.language,
247
- };
248
- const scriptKey = `electron_script_${digest(identity)}`;
249
- if (seen.has(scriptKey))
250
- continue;
251
- seen.add(scriptKey);
252
- total += 1;
253
- if (items.length >= context.input.limits.max_scripts) {
254
- completeness.drop("scripts");
255
- continue;
256
- }
257
- let source = {
258
- included: false,
259
- reason: "source capture was not approved",
260
- };
261
- if (context.input.include_script_sources) {
262
- if (script.length > context.input.limits.max_script_source_bytes ||
263
- sourceBytes + script.length >
264
- context.input.limits.max_total_script_source_bytes) {
265
- source = {
266
- included: false,
267
- reason: "script source byte limit reached",
268
- };
269
- completeness.truncate("script_sources");
270
- }
271
- else {
272
- const result = requiredRecord(await context.connection.send("Debugger.getScriptSource", { scriptId: script.scriptId }, context.sessionId, context.signal));
273
- const text = stringValue(result.scriptSource) ?? "";
274
- const bytes = Buffer.byteLength(text);
275
- if (bytes > context.input.limits.max_script_source_bytes ||
276
- sourceBytes + bytes >
277
- context.input.limits.max_total_script_source_bytes) {
278
- source = {
279
- included: false,
280
- reason: "script source byte limit reached",
281
- };
282
- completeness.truncate("script_sources");
283
- }
284
- else {
285
- source = {
286
- included: true,
287
- artifact: createWebTextArtifact(text, "text/javascript"),
288
- };
289
- sourceBytes += bytes;
290
- }
291
- }
292
- }
293
- items.push({
294
- script_key: scriptKey,
295
- ...identity,
296
- source,
297
- });
298
- }
299
- if (!context.input.include_script_sources)
300
- completeness.exclude("script_sources", "not_approved", total);
301
- return {
302
- total,
303
- items: items.sort((left, right) => left.script_key.localeCompare(right.script_key)),
304
- };
305
- };
306
251
  const mainFilePath = async (result, roots) => {
307
252
  const frameTree = recordValue(requiredRecord(result).frameTree);
308
253
  const frame = recordValue(frameTree?.frame);
@@ -314,7 +259,6 @@ const integer = (value, fallback) => {
314
259
  const number = numberValue(value);
315
260
  return number === undefined ? fallback : Math.trunc(number);
316
261
  };
317
- const nonnegativeInteger = (value) => Math.max(0, integer(value, 0));
318
262
  const digest = (value) => {
319
263
  const encoded = canonicalize(value);
320
264
  if (encoded === undefined)
@@ -108,7 +108,11 @@ export class CdpElectronProvider {
108
108
  }
109
109
  finally {
110
110
  if (targetSession !== undefined)
111
- await closeCdpTargetSession(targetSession, ["Debugger", "Page"]);
111
+ await closeCdpTargetSession(targetSession, [
112
+ "Debugger",
113
+ "Runtime",
114
+ "Page",
115
+ ]);
112
116
  }
113
117
  }
114
118
  }
@@ -0,0 +1,69 @@
1
+ import { CdpCaptureCompleteness } from "./CdpCaptureCompleteness.js";
2
+ import { boundedText, numberValue, recordValue, stringValue, } from "./CdpCaptureValues.js";
3
+ /** Retain only bounded script/frame metadata from passive Electron events. */
4
+ export const ingestElectronScriptEvent = (input) => {
5
+ if (input.event.method === "Runtime.executionContextsCleared") {
6
+ input.executionContextFrames.clear();
7
+ return;
8
+ }
9
+ if (input.event.method === "Runtime.executionContextDestroyed") {
10
+ const parameters = recordValue(input.event.params);
11
+ const key = executionContextKey(parameters?.executionContextId);
12
+ if (key !== null)
13
+ input.executionContextFrames.delete(key);
14
+ return;
15
+ }
16
+ if (input.event.method === "Runtime.executionContextCreated") {
17
+ retainExecutionContext(input.event, input.executionContextFrames, input.completeness);
18
+ return;
19
+ }
20
+ if (input.event.method !== "Debugger.scriptParsed")
21
+ return;
22
+ const value = recordValue(input.event.params);
23
+ const scriptId = stringValue(value?.scriptId);
24
+ const rawUrl = stringValue(value?.url);
25
+ if (scriptId === undefined || scriptId.length > 256) {
26
+ input.completeness.exclude("scripts", "invalid_protocol_value");
27
+ return;
28
+ }
29
+ if (rawUrl === undefined || rawUrl === "") {
30
+ input.completeness.exclude("scripts", "unattributed_origin");
31
+ return;
32
+ }
33
+ if (input.scripts.length >= 2_000) {
34
+ input.completeness.drop("scripts");
35
+ return;
36
+ }
37
+ input.scripts.push({
38
+ scriptId,
39
+ rawUrl,
40
+ hash: (stringValue(value?.hash) ?? "").slice(0, 512),
41
+ length: nonnegativeInteger(value?.length),
42
+ isModule: value?.isModule === true,
43
+ language: boundedText(value?.scriptLanguage, 100),
44
+ executionContextKey: executionContextKey(value?.executionContextId),
45
+ });
46
+ };
47
+ const retainExecutionContext = (event, frames, completeness) => {
48
+ const parameters = recordValue(event.params);
49
+ const runtimeContext = recordValue(parameters?.context);
50
+ const contextKey = executionContextKey(runtimeContext?.id);
51
+ const frameId = stringValue(recordValue(runtimeContext?.auxData)?.frameId);
52
+ if (contextKey === null || frameId === undefined || frameId.length > 256)
53
+ return;
54
+ if (frames.size >= 2_000 && !frames.has(contextKey)) {
55
+ completeness.truncate("scripts");
56
+ return;
57
+ }
58
+ frames.set(contextKey, frameId);
59
+ };
60
+ const nonnegativeInteger = (value) => {
61
+ const number = numberValue(value);
62
+ return number === undefined ? 0 : Math.max(0, Math.trunc(number));
63
+ };
64
+ const executionContextKey = (value) => {
65
+ const identifier = numberValue(value);
66
+ return identifier !== undefined && Number.isSafeInteger(identifier)
67
+ ? String(identifier)
68
+ : null;
69
+ };
@@ -0,0 +1,94 @@
1
+ import { createHash } from "node:crypto";
2
+ import canonicalize from "canonicalize";
3
+ import { createWebTextArtifact } from "../domain/webContentArtifact.js";
4
+ import { CdpCaptureCompleteness } from "./CdpCaptureCompleteness.js";
5
+ import { requiredRecord, stringValue } from "./CdpCaptureValues.js";
6
+ import { authorizedElectronFile } from "./ElectronFileScope.js";
7
+ /** Normalize root-confined script metadata and optionally approved source. */
8
+ export const captureElectronScripts = async (input) => {
9
+ let total = 0;
10
+ let sourceBytes = 0;
11
+ const items = [];
12
+ const seen = new Set();
13
+ for (const script of input.scripts) {
14
+ const path = await authorizedElectronFile(script.rawUrl, input.roots);
15
+ if (path === undefined) {
16
+ input.completeness.exclude("scripts", "out_of_target_scope");
17
+ continue;
18
+ }
19
+ const mappedFrame = script.executionContextKey === null
20
+ ? undefined
21
+ : input.executionContextFrames.get(script.executionContextKey);
22
+ const identity = {
23
+ frame_id: mappedFrame !== undefined && input.frameIds.has(mappedFrame)
24
+ ? mappedFrame
25
+ : null,
26
+ file_path: path,
27
+ cdp_hash: script.hash,
28
+ length: script.length,
29
+ is_module: script.isModule,
30
+ language: script.language,
31
+ };
32
+ const scriptKey = `electron_script_${digest(identity)}`;
33
+ if (seen.has(scriptKey))
34
+ continue;
35
+ seen.add(scriptKey);
36
+ total += 1;
37
+ if (items.length >= input.request.limits.max_scripts) {
38
+ input.completeness.drop("scripts");
39
+ continue;
40
+ }
41
+ const capturedSource = await captureScriptSource(input, script, sourceBytes);
42
+ sourceBytes += capturedSource.bytes;
43
+ items.push({
44
+ script_key: scriptKey,
45
+ ...identity,
46
+ source: capturedSource.source,
47
+ });
48
+ }
49
+ if (!input.request.include_script_sources)
50
+ input.completeness.exclude("script_sources", "not_approved", total);
51
+ return {
52
+ total,
53
+ items: items.sort((left, right) => left.script_key.localeCompare(right.script_key)),
54
+ };
55
+ };
56
+ const captureScriptSource = async (input, script, sourceBytes) => {
57
+ if (!input.request.include_script_sources)
58
+ return {
59
+ source: {
60
+ included: false,
61
+ reason: "source capture was not approved",
62
+ },
63
+ bytes: 0,
64
+ };
65
+ if (sourceLimitReached(input.request.limits, script.length, sourceBytes))
66
+ return sourceLimitResult(input.completeness);
67
+ const result = requiredRecord(await input.connection.send("Debugger.getScriptSource", { scriptId: script.scriptId }, input.sessionId, input.signal));
68
+ const text = stringValue(result.scriptSource) ?? "";
69
+ const bytes = Buffer.byteLength(text);
70
+ if (sourceLimitReached(input.request.limits, bytes, sourceBytes))
71
+ return sourceLimitResult(input.completeness);
72
+ return {
73
+ source: {
74
+ included: true,
75
+ artifact: createWebTextArtifact(text, "text/javascript"),
76
+ },
77
+ bytes,
78
+ };
79
+ };
80
+ const sourceLimitReached = (limits, bytes, previousBytes) => bytes > limits.max_script_source_bytes ||
81
+ previousBytes + bytes > limits.max_total_script_source_bytes;
82
+ const sourceLimitResult = (completeness) => {
83
+ completeness.truncate("script_sources");
84
+ return {
85
+ source: { included: false, reason: "script source byte limit reached" },
86
+ bytes: 0,
87
+ };
88
+ };
89
+ const digest = (value) => {
90
+ const encoded = canonicalize(value);
91
+ if (encoded === undefined)
92
+ throw new TypeError("Expected canonical JSON");
93
+ return createHash("sha256").update(encoded).digest("hex");
94
+ };
@@ -0,0 +1,56 @@
1
+ import { CdpCaptureCompleteness } from "./CdpCaptureCompleteness.js";
2
+ import { boundedText, recordValue, recordsValue, stringValue, } from "./CdpCaptureValues.js";
3
+ import { optionalCdpCommand } from "./CdpOptionalCommand.js";
4
+ import { authorizedElectronFile } from "./ElectronFileScope.js";
5
+ /** Inventory root-confined worker targets without attaching to them. */
6
+ export const captureElectronWorkers = async (input) => {
7
+ const result = await optionalCdpCommand({
8
+ connection: input.connection,
9
+ sessionId: undefined,
10
+ ...(input.signal === undefined ? {} : { signal: input.signal }),
11
+ }, "Target.getTargets", {}, input.limitations);
12
+ if (result === undefined) {
13
+ input.completeness.unavailable("workers");
14
+ return [];
15
+ }
16
+ const workers = [];
17
+ for (const target of recordsValue(recordValue(result)?.targetInfos)) {
18
+ const type = stringValue(target.type) ?? "";
19
+ if (!type.includes("worker"))
20
+ continue;
21
+ const openerTargetId = boundedTargetField(target.openerId);
22
+ const parentFrameId = boundedTargetField(target.parentFrameId);
23
+ if (openerTargetId !== input.target.id &&
24
+ (parentFrameId === null || !input.frameIds.has(parentFrameId))) {
25
+ input.completeness.exclude("workers", "out_of_target_scope");
26
+ continue;
27
+ }
28
+ const path = await authorizedElectronFile(stringValue(target.url) ?? "", input.roots);
29
+ if (path === undefined) {
30
+ input.completeness.exclude("workers", "out_of_target_scope");
31
+ continue;
32
+ }
33
+ if (workers.length >= input.request.limits.max_workers) {
34
+ input.completeness.truncate("workers");
35
+ continue;
36
+ }
37
+ const targetId = boundedTargetField(target.targetId);
38
+ if (targetId === null) {
39
+ input.completeness.exclude("workers", "invalid_protocol_value");
40
+ continue;
41
+ }
42
+ workers.push({
43
+ target_id: targetId,
44
+ type: type.slice(0, 100),
45
+ file_path: path,
46
+ attached: target.attached === true,
47
+ opener_target_id: openerTargetId,
48
+ parent_frame_id: parentFrameId,
49
+ });
50
+ }
51
+ return workers.sort((left, right) => left.target_id.localeCompare(right.target_id));
52
+ };
53
+ const boundedTargetField = (value) => {
54
+ const field = boundedText(value, 256);
55
+ return field === null || field === "" ? null : field;
56
+ };
@@ -133,7 +133,13 @@ class TimelineCapture {
133
133
  targetTerminated() {
134
134
  if (this.#endReason !== undefined)
135
135
  return;
136
- this.#add("target_terminated", {}, null, null, "target_terminated");
136
+ this.#add({
137
+ type: "target_terminated",
138
+ params: {},
139
+ rawUrl: null,
140
+ requestId: null,
141
+ detail: "target_terminated",
142
+ });
137
143
  this.end("target_terminated");
138
144
  }
139
145
  setFinalUrl(rawUrl) {
@@ -145,7 +151,13 @@ class TimelineCapture {
145
151
  return;
146
152
  const reason = safeDetail(params.reason);
147
153
  this.#pendingReload = reason === "reload";
148
- this.#add("navigation_requested", params, stringValue(params.url), null, reason);
154
+ this.#add({
155
+ type: "navigation_requested",
156
+ params,
157
+ rawUrl: stringValue(params.url) ?? null,
158
+ requestId: null,
159
+ detail: reason,
160
+ });
149
161
  }
150
162
  #navigationCommitted(params) {
151
163
  const frame = recordValue(params.frame);
@@ -153,7 +165,13 @@ class TimelineCapture {
153
165
  return;
154
166
  const rawUrl = stringValue(frame?.url);
155
167
  const destination = scopedUrl(rawUrl, this.allowedOrigins);
156
- this.#add(this.#pendingReload ? "same_origin_reload" : "navigation_committed", { ...params, frameId: frame?.id, loaderId: frame?.loaderId }, rawUrl, null, safeDetail(frame?.transitionType));
168
+ this.#add({
169
+ type: this.#pendingReload ? "same_origin_reload" : "navigation_committed",
170
+ params: { ...params, frameId: frame?.id, loaderId: frame?.loaderId },
171
+ rawUrl: rawUrl ?? null,
172
+ requestId: null,
173
+ detail: safeDetail(frame?.transitionType),
174
+ });
157
175
  this.#pendingReload = false;
158
176
  if (destination.scope === "approved")
159
177
  this.finalUrl = destination.url;
@@ -168,7 +186,13 @@ class TimelineCapture {
168
186
  return;
169
187
  const rawUrl = stringValue(params.url);
170
188
  const destination = scopedUrl(rawUrl, this.allowedOrigins);
171
- this.#add("same_document_navigation", params, rawUrl, null, null);
189
+ this.#add({
190
+ type: "same_document_navigation",
191
+ params,
192
+ rawUrl: rawUrl ?? null,
193
+ requestId: null,
194
+ detail: null,
195
+ });
172
196
  if (destination.scope === "approved")
173
197
  this.finalUrl = destination.url;
174
198
  else {
@@ -184,7 +208,13 @@ class TimelineCapture {
184
208
  const request = recordValue(params.request);
185
209
  const rawUrl = stringValue(request?.url);
186
210
  const destination = scopedUrl(rawUrl, this.allowedOrigins);
187
- this.#add("redirect", params, rawUrl, stringValue(params.requestId) ?? null, null);
211
+ this.#add({
212
+ type: "redirect",
213
+ params,
214
+ rawUrl: rawUrl ?? null,
215
+ requestId: stringValue(params.requestId) ?? null,
216
+ detail: null,
217
+ });
188
218
  if (destination.scope !== "approved") {
189
219
  this.completeness.exclude("timeline", "out_of_target_scope");
190
220
  this.end("target_left_scope");
@@ -194,14 +224,27 @@ class TimelineCapture {
194
224
  const frame = stringValue(params.frameId);
195
225
  if (frame !== undefined && frame !== this.mainFrameId)
196
226
  return;
197
- this.#add("load_failed", params, null, stringValue(params.requestId) ?? null, safeNetworkError(params.errorText));
227
+ this.#add({
228
+ type: "load_failed",
229
+ params,
230
+ rawUrl: null,
231
+ requestId: stringValue(params.requestId) ?? null,
232
+ detail: safeNetworkError(params.errorText),
233
+ });
198
234
  }
199
235
  #lifecycle(params) {
200
236
  if (stringValue(params.frameId) !== this.mainFrameId)
201
237
  return;
202
- this.#add("lifecycle", params, null, null, safeDetail(params.name));
238
+ this.#add({
239
+ type: "lifecycle",
240
+ params,
241
+ rawUrl: null,
242
+ requestId: null,
243
+ detail: safeDetail(params.name),
244
+ });
203
245
  }
204
- #add(type, params, rawUrl, requestId, detail) {
246
+ #add(options) {
247
+ const { type, params, rawUrl = null, requestId = null, detail = null, } = options;
205
248
  const destination = rawUrl == null ? null : scopedUrl(rawUrl, this.allowedOrigins);
206
249
  if (this.timeline.length >= this.maximum) {
207
250
  this.completeness.drop("timeline_events");