rea-agents 2.0.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.
- package/README.md +78 -32
- package/bridge/ghidra/ReaGhidraBridge.java +96 -11
- package/dist/application/ArtifactExtraction.js +1 -1
- package/dist/application/ArtifactInventory/classify.js +42 -0
- package/dist/application/ArtifactInventory/hash.js +43 -0
- package/dist/application/ArtifactInventory/reader.js +41 -0
- package/dist/application/ArtifactInventory/scanCanonical.js +155 -0
- package/dist/application/ArtifactInventory/scanReader.js +124 -0
- package/dist/application/ArtifactInventory/types.js +10 -0
- package/dist/application/ArtifactInventory.js +9 -351
- package/dist/application/AuthorizedArtifactInventory.js +2 -2
- package/dist/application/BinarySession.js +47 -270
- package/dist/application/BinarySessionExecution.js +28 -0
- package/dist/application/BinarySessionOpen.js +39 -0
- package/dist/application/BinarySessionRecords.js +149 -0
- package/dist/application/BinarySessionStatus.js +75 -0
- package/dist/application/CapabilityInventory.js +24 -2
- package/dist/application/ClientRegistrationStatus.js +1 -1
- package/dist/application/CrossVersionInventory.js +8 -2
- package/dist/application/CrossVersionInvestigation.js +1 -23
- package/dist/application/CrossVersionInvestigationCollections.js +23 -0
- package/dist/application/DirectAnalysis.js +47 -44
- package/dist/application/Doctor.js +156 -238
- package/dist/application/DoctorDiagnostics.js +180 -0
- package/dist/application/ElectronBoundaryAnalysis.js +23 -7
- package/dist/application/ElectronBoundaryGraphWindows.js +32 -8
- package/dist/application/EnhancedToolPagination.js +22 -0
- package/dist/application/EnhancedToolTypes.js +4 -0
- package/dist/application/EnhancedTools.js +20 -37
- package/dist/application/InstrumentedJavaScriptReplayHost.js +36 -0
- package/dist/application/InvestigationWorkspaceStore.js +24 -10
- package/dist/application/JavaScriptArtifactAnalysis.js +45 -6
- package/dist/application/JavaScriptArtifactFiles.js +6 -2
- package/dist/application/JavaScriptArtifactGraphBuilder.js +23 -1
- package/dist/application/JavaScriptArtifactGraphBundlers.js +225 -0
- package/dist/application/JavaScriptArtifactGraphContext.js +37 -36
- package/dist/application/JavaScriptArtifactGraphDocuments.js +27 -4
- package/dist/application/JavaScriptArtifactGraphFindings.js +54 -8
- package/dist/application/JavaScriptArtifactGraphStructure.js +29 -101
- package/dist/application/JavaScriptArtifactPathResolution.js +269 -0
- package/dist/application/JavaScriptArtifactReconstruction.js +1 -1
- package/dist/application/JavaScriptJsonModules.js +39 -0
- package/dist/application/JavaScriptModuleRelationships.js +262 -0
- package/dist/application/JavaScriptReplayPermission.js +16 -0
- package/dist/application/JavaScriptReplayService.js +182 -156
- package/dist/application/LinuxHopper.js +10 -0
- package/dist/application/MacHopper.js +22 -11
- package/dist/application/NodeRuntimeCharacterizationService.js +196 -0
- package/dist/application/PermissionAuthority.js +106 -63
- package/dist/application/ProcessCaptureCapability.js +1 -1
- package/dist/application/ProcessCapturePermission.js +13 -0
- package/dist/application/ProcessCli.js +2 -12
- package/dist/application/ProcessHarness.js +1 -1
- package/dist/application/ProjectPermissionStore.js +48 -9
- package/dist/application/RealHopperAssertions.js +76 -0
- package/dist/application/ReconstructionCoverageService.js +69 -0
- package/dist/application/ReconstructionCoverageWorkspaceStore.js +31 -0
- package/dist/application/RuntimeExecutableDiagnostics.js +172 -0
- package/dist/application/Setup.js +147 -259
- package/dist/application/SetupClientConfiguration.js +220 -0
- package/dist/application/SetupClients.js +24 -2
- package/dist/application/SetupPlan.js +123 -12
- package/dist/application/SetupSkill.js +26 -12
- package/dist/application/SupportedClients.js +1 -0
- package/dist/application/Uninstall.js +6 -3
- package/dist/application/WindowsCapabilities.js +86 -0
- package/dist/artifacts/AsarArtifactReader.js +11 -0
- package/dist/browser/BrowserProcessStartup.js +88 -0
- package/dist/browser/CdpCaptureDocuments.js +12 -8
- package/dist/browser/CdpCaptureEventBodyShapes.js +75 -0
- package/dist/browser/CdpCaptureEventHandlers.js +336 -0
- package/dist/browser/CdpCaptureEventHelpers.js +71 -0
- package/dist/browser/CdpCaptureEventState.js +1 -0
- package/dist/browser/CdpCaptureEventTypes.js +1 -0
- package/dist/browser/CdpCaptureEvents.js +29 -496
- package/dist/browser/CdpObservationSession.js +51 -8
- package/dist/browser/CdpPageCapture.js +12 -133
- package/dist/browser/CdpPageCaptureScripts.js +97 -0
- package/dist/browser/CdpPageCaptureWorkers.js +46 -0
- package/dist/browser/CdpWebMcpDiscovery.js +38 -14
- package/dist/browser/PngVisualDiff.js +9 -2
- package/dist/catalogIdentity.js +4 -0
- package/dist/cli/artifactCommands.js +82 -0
- package/dist/cli/coreAnalysisCommands.js +232 -0
- package/dist/cli/managedCommands.js +397 -0
- package/dist/cli/managedProjectGraphCommand.js +24 -0
- package/dist/cli/options.js +9 -0
- package/dist/cli/setupCommands.js +108 -0
- package/dist/cli/types.js +1 -0
- package/dist/cli/utilityCommands.js +122 -0
- package/dist/cli.js +10 -768
- package/dist/cliApplicationCommands.js +118 -4
- package/dist/cliBrowserAdvancedCommands.js +73 -16
- package/dist/cliBrowserCommands.js +39 -115
- package/dist/cliCommandNames.js +4 -0
- package/dist/cliElectronCommands.js +33 -62
- package/dist/cliEvidenceCommands.js +13 -2
- package/dist/cliInvestigationCommands.js +53 -10
- package/dist/cliObservationOptions.js +137 -0
- package/dist/cliPolicyCommands.js +80 -46
- package/dist/cliSetup.js +289 -0
- package/dist/config/environment.js +107 -0
- package/dist/config/parseConfig.js +228 -0
- package/dist/config/parsers.js +68 -0
- package/dist/config/permissions.js +30 -0
- package/dist/config/types.js +1 -0
- package/dist/config.js +1 -375
- package/dist/contracts/applicationToolContracts.js +134 -0
- package/dist/contracts/managedToolContracts.js +1 -1
- package/dist/contracts/managedWorkflowToolContracts.js +3 -3
- package/dist/contracts/providerSelection.js +2 -0
- package/dist/contracts/toolContracts.js +2 -2
- package/dist/contracts/toolEffects.js +14 -0
- package/dist/contracts/toolOutputSchemaGroups.js +232 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +327 -0
- package/dist/contracts/toolOutputSchemas.js +2 -550
- package/dist/domain/analysisErrorPresentation.js +234 -0
- package/dist/domain/analysisErrorProjection.js +284 -0
- package/dist/domain/artifactComparison.js +34 -15
- package/dist/domain/binaryTarget.js +87 -37
- package/dist/domain/browserObservation.js +1 -285
- package/dist/domain/browserObservationSchemas.js +286 -0
- package/dist/domain/electronStaticAnalysisBrowser.js +14 -2
- package/dist/domain/errors.js +4 -486
- package/dist/domain/functionComparison.js +4 -165
- package/dist/domain/functionComparisonDimensions.js +164 -0
- package/dist/domain/javascriptApplicationVersionItems.js +18 -6
- package/dist/domain/javascriptApplicationVersionKeys.js +8 -8
- package/dist/domain/javascriptExportInstrumentation.js +97 -0
- package/dist/domain/javascriptFeatureTraversal.js +19 -7
- package/dist/domain/javascriptRuntimeStaticCandidates.js +3 -1
- package/dist/domain/javascriptSemanticAnalysis.js +386 -0
- package/dist/domain/javascriptSemanticIr.js +30 -0
- package/dist/domain/javascriptSemanticProjection.js +366 -0
- package/dist/domain/javascriptSemanticState.js +40 -0
- package/dist/domain/javascriptSemanticTraversal.js +22 -0
- package/dist/domain/javascriptSemanticValues.js +352 -0
- package/dist/domain/javascriptStaticAnalysis.js +5 -221
- package/dist/domain/javascriptStaticAnalysisBundler.js +209 -0
- package/dist/domain/javascriptStaticAnalysisCalls.js +180 -0
- package/dist/domain/javascriptStaticAnalysisHelpers.js +71 -2
- package/dist/domain/knownPageCoverage.js +21 -0
- package/dist/domain/managedApplicationGraph.js +14 -364
- package/dist/domain/managedApplicationGraphCoverage.js +170 -0
- package/dist/domain/managedApplicationGraphNodeCoverage.js +6 -0
- package/dist/domain/managedApplicationGraphNodes.js +336 -0
- package/dist/domain/managedArtifact.js +16 -8
- package/dist/domain/managedMemberComparison.js +37 -391
- package/dist/domain/managedMemberComparisonCoverage.js +72 -0
- package/dist/domain/managedMemberComparisonMatch.js +356 -0
- package/dist/domain/managedNativeVerification.js +27 -389
- package/dist/domain/managedNativeVerificationMatch.js +272 -0
- package/dist/domain/managedNativeVerificationSchemas.js +141 -0
- package/dist/domain/managedReconstruction.js +82 -69
- package/dist/domain/managedRuntimeCorrelation.js +12 -3
- package/dist/domain/nodeRuntimeCharacterization.js +66 -0
- package/dist/domain/permissionPolicy.js +2 -0
- package/dist/domain/reconstructionCoverage.js +387 -0
- package/dist/domain/reconstructionCoverageEvaluation.js +212 -0
- package/dist/domain/reconstructionVerificationSchemas.js +8 -0
- package/dist/domain/runtimeCharacterization.js +85 -0
- package/dist/domain/webBundleAnalyzer.js +3 -409
- package/dist/domain/webBundleAnalyzerAst.js +77 -0
- package/dist/domain/webBundleAnalyzerInspection.js +307 -0
- package/dist/domain/webBundleAnalyzerResult.js +120 -0
- package/dist/dotnet/ManagedArtifactInspector.js +50 -29
- package/dist/dotnet/ManagedMemberInspector.js +51 -785
- package/dist/dotnet/ManagedMemberInspectorCore.js +297 -0
- package/dist/dotnet/ManagedMemberInstructionDecoder.js +427 -0
- package/dist/dotnet/ManagedMemberRows.js +120 -0
- package/dist/dotnet/ManagedMetadataInventory.js +42 -306
- package/dist/dotnet/ManagedMetadataInventoryRows.js +292 -0
- package/dist/dotnet/ManagedMetadataLayout.js +48 -111
- package/dist/dotnet/ManagedMetadataRowSizes.js +54 -0
- package/dist/dotnet/ManagedMethodBodyReader.js +143 -0
- package/dist/dotnet/ManagedNativeBoundaryHelpers.js +311 -0
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +102 -350
- package/dist/dotnet/ManagedPeReader.js +59 -28
- package/dist/generatedPackageMetadata.js +2 -2
- package/dist/ghidra/GhidraClient.js +76 -91
- package/dist/ghidra/GhidraClientStartup.js +29 -0
- package/dist/ghidra/GhidraClientWire.js +34 -0
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraDiagnostics.js +6 -1
- package/dist/ghidra/GhidraInstallation.js +20 -15
- package/dist/ghidra/GhidraLauncher.js +93 -29
- package/dist/ghidra/GhidraProvider.js +61 -161
- package/dist/ghidra/GhidraProviderCapabilities.js +173 -0
- package/dist/ghidra/GhidraSessionValues.js +2 -0
- package/dist/ghidra/GhidraSocketConnection.js +44 -7
- package/dist/ghidra/GhidraTargetSnapshot.js +30 -0
- package/dist/ghidra/GhidraTransport.js +71 -0
- package/dist/identity.js +3 -2
- package/dist/main/messages.js +5 -0
- package/dist/main/reload.js +49 -0
- package/dist/main/shutdown.js +25 -0
- package/dist/main/startup.js +14 -0
- package/dist/main/state.js +26 -0
- package/dist/main/transport.js +61 -0
- package/dist/main/types.js +1 -0
- package/dist/main.js +35 -146
- package/dist/process/PrivateRuntimeRoot.js +3 -2
- package/dist/process/ProcessOwnership.js +35 -0
- package/dist/process/ProviderProcess.js +2 -0
- package/dist/replay/JavaScriptReplayWorker.js +64 -50
- package/dist/replay/LinuxJavaScriptReplayRunner.js +173 -390
- package/dist/replay/LinuxJavaScriptReplaySandbox.js +140 -0
- package/dist/replay/ReplayOutcome.js +95 -0
- package/dist/replay/ReplayProcessLifecycle.js +71 -0
- package/dist/server/ProcessCaptureElicitation.js +157 -0
- package/dist/server/createServer.js +119 -54
- package/dist/server/registerApplicationTools/characterization.js +57 -0
- package/dist/server/registerApplicationTools/compareVersions.js +34 -0
- package/dist/server/registerApplicationTools/controlledReplay.js +38 -0
- package/dist/server/registerApplicationTools/coverage.js +84 -0
- package/dist/server/registerApplicationTools/helpers.js +42 -0
- package/dist/server/registerApplicationTools/traceFeature.js +26 -0
- package/dist/server/registerApplicationTools/types.js +1 -0
- package/dist/server/registerApplicationTools.js +10 -112
- package/dist/server/registerBrowserTools.js +59 -83
- package/dist/server/registerElectronTools.js +31 -46
- package/dist/server/registerEnhancedTools.js +34 -42
- package/dist/server/registerEvidenceResources.js +54 -0
- package/dist/server/registerInvestigationTools/helpers.js +74 -0
- package/dist/server/registerInvestigationTools/types.js +1 -0
- package/dist/server/registerInvestigationTools.js +83 -116
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +65 -0
- package/dist/server/registerManagedWorkflowTools/contract.js +8 -0
- package/dist/server/registerManagedWorkflowTools/evidence.js +43 -0
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +39 -0
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +39 -0
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +52 -0
- package/dist/server/registerManagedWorkflowTools/types.js +1 -0
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +75 -0
- package/dist/server/registerManagedWorkflowTools.js +10 -274
- package/dist/server/registerOfficialTools.js +73 -59
- package/dist/server/registerSessionRecordTools.js +137 -0
- package/dist/server/registerSessionStatusTool.js +2 -1
- package/dist/server/registerSessionTools.js +60 -164
- package/dist/server/sessionAvailabilityPolicy.js +10 -0
- package/dist/server/toolRegistrationOptions.js +101 -3
- package/dist/server/toolResult.js +5 -0
- package/package.json +10 -11
- package/skills/{rea-analysis → reverse-engineer-anything}/SKILL.md +20 -7
- package/scripts/prepare-node-pty.mjs +0 -35
- package/scripts/rebuild-native.mjs +0 -22
|
@@ -70,6 +70,14 @@ export const reconstructionSpecificationSchema = z
|
|
|
70
70
|
/** Bounded reconstruction-verification input. */
|
|
71
71
|
export const reconstructionVerificationInputSchema = z.strictObject({
|
|
72
72
|
specification: reconstructionSpecificationSchema,
|
|
73
|
+
coverage: z
|
|
74
|
+
.strictObject({
|
|
75
|
+
workspace_id: z.string().regex(/^rcw_[a-f0-9]{64}$/u),
|
|
76
|
+
revision: z.number().int().min(1),
|
|
77
|
+
revision_sha256: digestSchema,
|
|
78
|
+
boundary_id: z.string().min(1).max(200),
|
|
79
|
+
})
|
|
80
|
+
.optional(),
|
|
73
81
|
offset: z.number().int().min(0).default(0),
|
|
74
82
|
limit: z.number().int().min(1).max(100).default(100),
|
|
75
83
|
unknown_registry_approved: z.literal(true).optional(),
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import canonicalize from "canonicalize";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
|
|
5
|
+
const stableIdSchema = z.string().regex(/^[A-Za-z][A-Za-z0-9._:/-]{0,199}$/u);
|
|
6
|
+
const runtimeIdentitySchema = z.strictObject({
|
|
7
|
+
family: z.string().trim().min(1).max(100),
|
|
8
|
+
provider_id: stableIdSchema,
|
|
9
|
+
executable_path: z.string().min(1).max(4_096),
|
|
10
|
+
executable_sha256: digestSchema,
|
|
11
|
+
version: z.string().trim().min(1).max(500),
|
|
12
|
+
profile_sha256: digestSchema,
|
|
13
|
+
});
|
|
14
|
+
const artifactIdentitySchema = z.strictObject({
|
|
15
|
+
path: z.string().min(1).max(4_096),
|
|
16
|
+
sha256: digestSchema,
|
|
17
|
+
byte_length: z.number().int().min(0).max(Number.MAX_SAFE_INTEGER),
|
|
18
|
+
});
|
|
19
|
+
const callableIdentitySchema = z.strictObject({
|
|
20
|
+
callable_id: stableIdSchema,
|
|
21
|
+
module_id: stableIdSchema,
|
|
22
|
+
export_name: z.string().min(1).max(1_000),
|
|
23
|
+
semantic_evidence_id: z
|
|
24
|
+
.string()
|
|
25
|
+
.regex(/^ev_[a-f0-9]{64}$/u)
|
|
26
|
+
.nullable(),
|
|
27
|
+
selector_sha256: digestSchema,
|
|
28
|
+
});
|
|
29
|
+
export const runtimeCharacterizationPlanSchema = z.strictObject({
|
|
30
|
+
schema_version: z.literal(1),
|
|
31
|
+
plan_sha256: digestSchema,
|
|
32
|
+
preparation_sha256: digestSchema,
|
|
33
|
+
artifact: artifactIdentitySchema,
|
|
34
|
+
runtime: runtimeIdentitySchema,
|
|
35
|
+
callable: callableIdentitySchema,
|
|
36
|
+
working_directory: z.string().min(1).max(4_096),
|
|
37
|
+
isolated_home: z.string().min(1).max(4_096),
|
|
38
|
+
expected_effect: z.enum(["pure", "bounded-effects", "observation-only"]),
|
|
39
|
+
allowed_boundaries: z.array(stableIdSchema).max(1_000),
|
|
40
|
+
limits: z.strictObject({
|
|
41
|
+
max_calls: z.number().int().min(1).max(10_000),
|
|
42
|
+
max_processes: z.number().int().min(0).max(1_000),
|
|
43
|
+
max_files: z.number().int().min(0).max(100_000),
|
|
44
|
+
max_bytes: z.number().int().min(1).max(Number.MAX_SAFE_INTEGER),
|
|
45
|
+
max_handles: z.number().int().min(0).max(100_000),
|
|
46
|
+
timeout_ms: z.number().int().min(1).max(300_000),
|
|
47
|
+
idle_timeout_ms: z.number().int().min(1).max(300_000),
|
|
48
|
+
}),
|
|
49
|
+
determinism: z.strictObject({
|
|
50
|
+
clock: z.enum(["fixed", "real"]),
|
|
51
|
+
randomness: z.enum(["seeded", "system"]),
|
|
52
|
+
identifiers: z.enum(["deterministic", "runtime"]),
|
|
53
|
+
seed: z.number().int().min(0).max(0xffff_ffff),
|
|
54
|
+
}),
|
|
55
|
+
authority: z.strictObject({
|
|
56
|
+
preparation_approved: z.literal(true),
|
|
57
|
+
execution_approved: z.literal(false),
|
|
58
|
+
network: z.enum(["none", "loopback"]),
|
|
59
|
+
provider_owned_process_only: z.literal(true),
|
|
60
|
+
}),
|
|
61
|
+
});
|
|
62
|
+
/** Commit a provider-neutral preparation plan; execution requires a later approval. */
|
|
63
|
+
export const createRuntimeCharacterizationPlan = (input) => {
|
|
64
|
+
const parsed = runtimeCharacterizationPlanSchema
|
|
65
|
+
.omit({ plan_sha256: true })
|
|
66
|
+
.parse(input);
|
|
67
|
+
return runtimeCharacterizationPlanSchema.parse({
|
|
68
|
+
...parsed,
|
|
69
|
+
plan_sha256: digest(parsed),
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
/** Parse a characterization plan and reject altered commitments. */
|
|
73
|
+
export const parseRuntimeCharacterizationPlan = (input) => {
|
|
74
|
+
const parsed = runtimeCharacterizationPlanSchema.parse(input);
|
|
75
|
+
const { plan_sha256: planSha256, ...semantic } = parsed;
|
|
76
|
+
if (planSha256 !== digest(semantic))
|
|
77
|
+
throw new TypeError("Runtime characterization plan digest is invalid");
|
|
78
|
+
return parsed;
|
|
79
|
+
};
|
|
80
|
+
const digest = (value) => {
|
|
81
|
+
const encoded = canonicalize(value);
|
|
82
|
+
if (encoded === undefined)
|
|
83
|
+
throw new TypeError("Runtime characterization plan is not canonical JSON");
|
|
84
|
+
return createHash("sha256").update(encoded).digest("hex");
|
|
85
|
+
};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import { sanitizeBrowserUrl } from "./browserObservation.js";
|
|
4
|
-
import { webBundleAnalysisSchema, } from "./webBundleAnalysis.js";
|
|
1
|
+
import { analyzeScript, emptyAccumulator, isIncludedScript, } from "./webBundleAnalyzerInspection.js";
|
|
2
|
+
import { buildWebBundleAnalysis } from "./webBundleAnalyzerResult.js";
|
|
5
3
|
/** Analyze captured, explicitly approved JavaScript source without execution. */
|
|
6
4
|
export const analyzeCapturedWebBundle = (inspection, input, sourceMaps = {
|
|
7
5
|
status: "not_requested",
|
|
@@ -15,409 +13,5 @@ export const analyzeCapturedWebBundle = (inspection, input, sourceMaps = {
|
|
|
15
13
|
const sourceScripts = inspection.scripts.items.filter(isIncludedScript);
|
|
16
14
|
for (const script of sourceScripts)
|
|
17
15
|
analyzeScript(script, input, accumulator);
|
|
18
|
-
|
|
19
|
-
.filter((script) => !script.source.included)
|
|
20
|
-
.map(({ script_key }) => script_key);
|
|
21
|
-
const sourceMapIncomplete = sourceMaps.status === "partial" || sourceMaps.status === "unavailable";
|
|
22
|
-
const partial = accumulator.parseFailures > 0 ||
|
|
23
|
-
unavailable.length > 0 ||
|
|
24
|
-
sourceMapIncomplete;
|
|
25
|
-
const truncated = accumulator.astLimitReached ||
|
|
26
|
-
accumulator.droppedFindings > 0 ||
|
|
27
|
-
sourceMaps.status === "truncated";
|
|
28
|
-
return webBundleAnalysisSchema.parse({
|
|
29
|
-
schema_version: 1,
|
|
30
|
-
capture: {
|
|
31
|
-
target_url: inspection.target.url,
|
|
32
|
-
scripts_observed: inspection.scripts.total,
|
|
33
|
-
scripts_analyzed: sourceScripts.length,
|
|
34
|
-
source_artifacts: sourceScripts.map((script) => {
|
|
35
|
-
if (!script.source.included)
|
|
36
|
-
throw new TypeError("Filtered source changed");
|
|
37
|
-
const { text: _text, ...artifact } = script.source.artifact;
|
|
38
|
-
return { ...artifact, text_available: true };
|
|
39
|
-
}),
|
|
40
|
-
},
|
|
41
|
-
observations: {
|
|
42
|
-
chunks: {
|
|
43
|
-
nodes: sourceScripts.map((script) => {
|
|
44
|
-
if (!script.source.included)
|
|
45
|
-
throw new TypeError("Filtered source changed");
|
|
46
|
-
return {
|
|
47
|
-
script_key: script.script_key,
|
|
48
|
-
url: script.url,
|
|
49
|
-
artifact_sha256: script.source.artifact.sha256,
|
|
50
|
-
bytes: script.source.artifact.bytes,
|
|
51
|
-
};
|
|
52
|
-
}),
|
|
53
|
-
edges: accumulator.edges,
|
|
54
|
-
},
|
|
55
|
-
routes: accumulator.routes,
|
|
56
|
-
endpoints: accumulator.endpoints,
|
|
57
|
-
webmcp_declarations: accumulator.webMcp,
|
|
58
|
-
source_maps: sourceMaps,
|
|
59
|
-
},
|
|
60
|
-
inferences: accumulator.inferences,
|
|
61
|
-
unknowns: [
|
|
62
|
-
...(unavailable.length === 0
|
|
63
|
-
? []
|
|
64
|
-
: [
|
|
65
|
-
{
|
|
66
|
-
dimension: "script_source",
|
|
67
|
-
reason: "Source artifact was not captured within approved limits",
|
|
68
|
-
affected_script_keys: unavailable,
|
|
69
|
-
},
|
|
70
|
-
]),
|
|
71
|
-
...(accumulator.parseFailures === 0
|
|
72
|
-
? []
|
|
73
|
-
: [
|
|
74
|
-
{
|
|
75
|
-
dimension: "javascript_ast",
|
|
76
|
-
reason: "One or more source artifacts could not be parsed",
|
|
77
|
-
affected_script_keys: sourceScripts.map(({ script_key }) => script_key),
|
|
78
|
-
},
|
|
79
|
-
]),
|
|
80
|
-
...(sourceMaps.status === "not_requested" ||
|
|
81
|
-
sourceMaps.status === "included"
|
|
82
|
-
? []
|
|
83
|
-
: [
|
|
84
|
-
{
|
|
85
|
-
dimension: "source_maps",
|
|
86
|
-
reason: sourceMaps.status === "truncated"
|
|
87
|
-
? "Source-map evidence was truncated by approved limits"
|
|
88
|
-
: "One or more requested source maps were unavailable or incomplete",
|
|
89
|
-
affected_script_keys: [
|
|
90
|
-
...new Set([
|
|
91
|
-
...sourceMaps.items
|
|
92
|
-
.filter(({ status }) => status !== "included")
|
|
93
|
-
.map(({ script_key }) => script_key),
|
|
94
|
-
...sourceMaps.dropped_script_keys,
|
|
95
|
-
]),
|
|
96
|
-
].sort(),
|
|
97
|
-
},
|
|
98
|
-
]),
|
|
99
|
-
],
|
|
100
|
-
completeness: {
|
|
101
|
-
status: truncated
|
|
102
|
-
? "truncated"
|
|
103
|
-
: partial
|
|
104
|
-
? "partial"
|
|
105
|
-
: "complete_within_limits",
|
|
106
|
-
parsed_scripts: accumulator.parsedScripts,
|
|
107
|
-
parse_failures: accumulator.parseFailures,
|
|
108
|
-
visited_ast_nodes: accumulator.visitedNodes,
|
|
109
|
-
dropped_findings: accumulator.droppedFindings,
|
|
110
|
-
},
|
|
111
|
-
limitations: [
|
|
112
|
-
"Static bundle findings are observations or bounded inferences; REA does not execute captured JavaScript.",
|
|
113
|
-
"String-built routes and endpoints, encrypted configuration, and server-side behavior may remain unknown.",
|
|
114
|
-
"Page-declared WebMCP metadata is untrusted and is never registered or invoked as an REA tool.",
|
|
115
|
-
],
|
|
116
|
-
});
|
|
16
|
+
return buildWebBundleAnalysis(inspection, sourceScripts, sourceMaps, accumulator);
|
|
117
17
|
};
|
|
118
|
-
const analyzeScript = (script, input, accumulator) => {
|
|
119
|
-
let file;
|
|
120
|
-
try {
|
|
121
|
-
file = parse(script.source.artifact.text, {
|
|
122
|
-
sourceType: "unambiguous",
|
|
123
|
-
errorRecovery: true,
|
|
124
|
-
plugins: ["jsx", "typescript"],
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
catch {
|
|
128
|
-
accumulator.parseFailures += 1;
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
accumulator.parsedScripts += 1;
|
|
132
|
-
detectVendorFingerprints(script, accumulator, input.analysis_limits.max_findings);
|
|
133
|
-
t.traverseFast(file, (node) => {
|
|
134
|
-
accumulator.visitedNodes += 1;
|
|
135
|
-
if (accumulator.visitedNodes > input.analysis_limits.max_ast_nodes) {
|
|
136
|
-
accumulator.astLimitReached = true;
|
|
137
|
-
return t.traverseFast.stop;
|
|
138
|
-
}
|
|
139
|
-
inspectNode(script, node, accumulator, input.analysis_limits.max_findings);
|
|
140
|
-
return undefined;
|
|
141
|
-
});
|
|
142
|
-
};
|
|
143
|
-
const inspectNode = (script, node, accumulator, maximumFindings) => {
|
|
144
|
-
if ((t.isImportDeclaration(node) || t.isExportAllDeclaration(node)) &&
|
|
145
|
-
node.source !== undefined)
|
|
146
|
-
addEdge(script, node.source.value, "static_import", node, accumulator, maximumFindings);
|
|
147
|
-
else if (t.isExportNamedDeclaration(node) && node.source != null)
|
|
148
|
-
addEdge(script, node.source.value, "static_import", node, accumulator, maximumFindings);
|
|
149
|
-
else if (t.isImportExpression(node) && t.isStringLiteral(node.source))
|
|
150
|
-
addEdge(script, node.source.value, "dynamic_import", node, accumulator, maximumFindings);
|
|
151
|
-
if (t.isObjectProperty(node))
|
|
152
|
-
inspectRouteProperty(script, node, accumulator, maximumFindings);
|
|
153
|
-
if (t.isCallExpression(node) || t.isNewExpression(node))
|
|
154
|
-
inspectCall(script, node, accumulator, maximumFindings);
|
|
155
|
-
};
|
|
156
|
-
const inspectCall = (script, node, accumulator, maximumFindings) => {
|
|
157
|
-
const name = calleeName(node.callee);
|
|
158
|
-
const first = stringArgument(node.arguments[0]);
|
|
159
|
-
if ((name === "require" || name.endsWith(".require")) && first !== undefined)
|
|
160
|
-
addEdge(script, first, "require", node, accumulator, maximumFindings);
|
|
161
|
-
if ((name === "importScripts" || name.endsWith(".importScripts")) &&
|
|
162
|
-
first !== undefined)
|
|
163
|
-
addEdge(script, first, "worker_import", node, accumulator, maximumFindings);
|
|
164
|
-
if (routeCallNames.some((candidate) => name === candidate || name.endsWith(`.${candidate}`))) {
|
|
165
|
-
if (first !== undefined)
|
|
166
|
-
addFinding(accumulator.routes, script, first, `call:${name}`, node, accumulator, maximumFindings);
|
|
167
|
-
addRouteFrameworkInference(script, name, node, accumulator, maximumFindings);
|
|
168
|
-
}
|
|
169
|
-
const endpoint = endpointArgument(name, node.arguments);
|
|
170
|
-
if (endpoint !== undefined)
|
|
171
|
-
addFinding(accumulator.endpoints, script, endpoint, `call:${name}`, node, accumulator, maximumFindings);
|
|
172
|
-
if (name.endsWith("modelContext.registerTool") ||
|
|
173
|
-
name === "modelContext.registerTool")
|
|
174
|
-
addWebMcpDeclaration(script, node, accumulator, maximumFindings);
|
|
175
|
-
};
|
|
176
|
-
const inspectRouteProperty = (script, node, accumulator, maximumFindings) => {
|
|
177
|
-
const key = propertyName(node.key);
|
|
178
|
-
if ((key === "path" || key === "route") && t.isStringLiteral(node.value))
|
|
179
|
-
addFinding(accumulator.routes, script, node.value.value, `property:${key}`, node, accumulator, maximumFindings);
|
|
180
|
-
};
|
|
181
|
-
const addEdge = (script, specifier, kind, node, accumulator, maximumFindings) => {
|
|
182
|
-
const bounded = specifier.slice(0, 4_096);
|
|
183
|
-
const key = `edge\0${script.script_key}\0${kind}\0${bounded}`;
|
|
184
|
-
addBounded(accumulator, key, maximumFindings, () => accumulator.edges.push({
|
|
185
|
-
from_script_key: script.script_key,
|
|
186
|
-
kind,
|
|
187
|
-
specifier: bounded,
|
|
188
|
-
resolved_url: resolveSpecifier(bounded, script.url),
|
|
189
|
-
location: location(script.script_key, node),
|
|
190
|
-
}));
|
|
191
|
-
};
|
|
192
|
-
const addFinding = (collection, script, rawValue, mechanism, node, accumulator, maximumFindings) => {
|
|
193
|
-
const value = sanitizeCandidate(rawValue);
|
|
194
|
-
const key = `finding\0${mechanism}\0${script.script_key}\0${value}`;
|
|
195
|
-
addBounded(accumulator, key, maximumFindings, () => collection.push({
|
|
196
|
-
value,
|
|
197
|
-
mechanism,
|
|
198
|
-
location: location(script.script_key, node),
|
|
199
|
-
}));
|
|
200
|
-
};
|
|
201
|
-
const addWebMcpDeclaration = (script, node, accumulator, maximumFindings) => {
|
|
202
|
-
const declaration = node.arguments[0];
|
|
203
|
-
if (!t.isObjectExpression(declaration))
|
|
204
|
-
return;
|
|
205
|
-
const name = objectString(declaration, "name");
|
|
206
|
-
const description = objectString(declaration, "description");
|
|
207
|
-
const schema = objectValue(declaration, "inputSchema") ??
|
|
208
|
-
objectValue(declaration, "input_schema");
|
|
209
|
-
const declaredProperties = t.isObjectExpression(schema)
|
|
210
|
-
? objectValue(schema, "properties")
|
|
211
|
-
: undefined;
|
|
212
|
-
const propertyObject = t.isObjectExpression(declaredProperties)
|
|
213
|
-
? declaredProperties
|
|
214
|
-
: schema;
|
|
215
|
-
const schemaPropertyNames = t.isObjectExpression(propertyObject)
|
|
216
|
-
? propertyObject.properties.flatMap((property) => t.isObjectProperty(property)
|
|
217
|
-
? [propertyName(property.key)].filter(Boolean)
|
|
218
|
-
: [])
|
|
219
|
-
: [];
|
|
220
|
-
const key = `webmcp\0${script.script_key}\0${name ?? ""}\0${schemaPropertyNames.join("\0")}`;
|
|
221
|
-
addBounded(accumulator, key, maximumFindings, () => accumulator.webMcp.push({
|
|
222
|
-
name: name?.slice(0, 256) ?? null,
|
|
223
|
-
description: description?.slice(0, 2_048) ?? null,
|
|
224
|
-
schema_property_names: [...new Set(schemaPropertyNames)]
|
|
225
|
-
.sort()
|
|
226
|
-
.slice(0, 256),
|
|
227
|
-
trust: "page-declared-untrusted",
|
|
228
|
-
location: location(script.script_key, node),
|
|
229
|
-
}));
|
|
230
|
-
};
|
|
231
|
-
const detectVendorFingerprints = (script, accumulator, maximumFindings) => {
|
|
232
|
-
const text = script.source.artifact.text;
|
|
233
|
-
for (const detector of vendorDetectors) {
|
|
234
|
-
if (!detector.patterns.some((pattern) => text.includes(pattern)))
|
|
235
|
-
continue;
|
|
236
|
-
const key = `vendor\0${script.script_key}\0${detector.value}`;
|
|
237
|
-
addBounded(accumulator, key, maximumFindings, () => accumulator.inferences.push({
|
|
238
|
-
kind: detector.kind,
|
|
239
|
-
value: detector.value,
|
|
240
|
-
confidence: detector.confidence,
|
|
241
|
-
basis: [basis(script, detector.detector)],
|
|
242
|
-
}));
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
const addRouteFrameworkInference = (script, name, node, accumulator, maximumFindings) => {
|
|
246
|
-
const value = name.endsWith("useRoutes") || name.endsWith("createBrowserRouter")
|
|
247
|
-
? "React Router-compatible route API"
|
|
248
|
-
: "Generic route registration API";
|
|
249
|
-
const key = `route-framework\0${script.script_key}\0${value}`;
|
|
250
|
-
addBounded(accumulator, key, maximumFindings, () => accumulator.inferences.push({
|
|
251
|
-
kind: "route_framework",
|
|
252
|
-
value,
|
|
253
|
-
confidence: "medium",
|
|
254
|
-
basis: [{ ...basis(script, `call:${name}`), ...locationFields(node) }],
|
|
255
|
-
}));
|
|
256
|
-
};
|
|
257
|
-
const addBounded = (accumulator, key, maximum, add) => {
|
|
258
|
-
if (accumulator.seen.has(key))
|
|
259
|
-
return;
|
|
260
|
-
const findings = accumulator.edges.length +
|
|
261
|
-
accumulator.routes.length +
|
|
262
|
-
accumulator.endpoints.length +
|
|
263
|
-
accumulator.webMcp.length +
|
|
264
|
-
accumulator.inferences.length;
|
|
265
|
-
if (findings >= maximum) {
|
|
266
|
-
accumulator.droppedFindings += 1;
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
accumulator.seen.add(key);
|
|
270
|
-
add();
|
|
271
|
-
};
|
|
272
|
-
const endpointArgument = (name, args) => {
|
|
273
|
-
if (name === "fetch" || name.endsWith(".fetch") || name === "WebSocket")
|
|
274
|
-
return stringArgument(args[0]);
|
|
275
|
-
if (name.endsWith(".open") && stringArgument(args[1]) !== undefined)
|
|
276
|
-
return stringArgument(args[1]);
|
|
277
|
-
if (["get", "post", "put", "patch", "delete", "request"].some((method) => name === method || name.endsWith(`.${method}`)))
|
|
278
|
-
return stringArgument(args[0]);
|
|
279
|
-
return undefined;
|
|
280
|
-
};
|
|
281
|
-
const calleeName = (callee) => {
|
|
282
|
-
if (t.isIdentifier(callee))
|
|
283
|
-
return callee.name;
|
|
284
|
-
if (t.isImport(callee))
|
|
285
|
-
return "import";
|
|
286
|
-
if (t.isMemberExpression(callee) || t.isOptionalMemberExpression(callee)) {
|
|
287
|
-
const object = t.isExpression(callee.object)
|
|
288
|
-
? calleeName(callee.object)
|
|
289
|
-
: "";
|
|
290
|
-
const property = propertyName(callee.property);
|
|
291
|
-
return object === "" ? property : `${object}.${property}`;
|
|
292
|
-
}
|
|
293
|
-
return "";
|
|
294
|
-
};
|
|
295
|
-
const stringArgument = (value) => (t.isStringLiteral(value) ? value.value : undefined);
|
|
296
|
-
const propertyName = (value) => {
|
|
297
|
-
if (t.isIdentifier(value))
|
|
298
|
-
return value.name;
|
|
299
|
-
if (t.isStringLiteral(value))
|
|
300
|
-
return value.value;
|
|
301
|
-
return "";
|
|
302
|
-
};
|
|
303
|
-
const objectValue = (object, name) => {
|
|
304
|
-
for (const property of object.properties)
|
|
305
|
-
if (t.isObjectProperty(property) && propertyName(property.key) === name)
|
|
306
|
-
return property.value;
|
|
307
|
-
return undefined;
|
|
308
|
-
};
|
|
309
|
-
const objectString = (object, name) => {
|
|
310
|
-
const value = objectValue(object, name);
|
|
311
|
-
return t.isStringLiteral(value) ? value.value : undefined;
|
|
312
|
-
};
|
|
313
|
-
const resolveSpecifier = (specifier, base) => {
|
|
314
|
-
try {
|
|
315
|
-
const resolved = new URL(specifier, base);
|
|
316
|
-
if (resolved.protocol !== "http:" && resolved.protocol !== "https:")
|
|
317
|
-
return null;
|
|
318
|
-
return sanitizeBrowserUrl(resolved.href).url;
|
|
319
|
-
}
|
|
320
|
-
catch {
|
|
321
|
-
return null;
|
|
322
|
-
}
|
|
323
|
-
};
|
|
324
|
-
const sanitizeCandidate = (value) => {
|
|
325
|
-
const bounded = value.slice(0, 4_096);
|
|
326
|
-
try {
|
|
327
|
-
const parsed = new URL(bounded, "https://rea.invalid");
|
|
328
|
-
const sanitized = sanitizeBrowserUrl(parsed.href).url;
|
|
329
|
-
return parsed.origin === "https://rea.invalid"
|
|
330
|
-
? sanitized.replace("https://rea.invalid", "")
|
|
331
|
-
: sanitized;
|
|
332
|
-
}
|
|
333
|
-
catch {
|
|
334
|
-
return bounded.split("#", 1)[0]?.split("?", 1)[0] ?? "";
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
const location = (scriptKey, node) => ({
|
|
338
|
-
script_key: scriptKey,
|
|
339
|
-
...locationFields(node),
|
|
340
|
-
});
|
|
341
|
-
const locationFields = (node) => ({
|
|
342
|
-
line: node.loc?.start.line ?? null,
|
|
343
|
-
column: node.loc?.start.column ?? null,
|
|
344
|
-
});
|
|
345
|
-
const basis = (script, detector) => ({
|
|
346
|
-
script_key: script.script_key,
|
|
347
|
-
artifact_sha256: script.source.artifact.sha256,
|
|
348
|
-
line: null,
|
|
349
|
-
column: null,
|
|
350
|
-
detector,
|
|
351
|
-
});
|
|
352
|
-
const emptyAccumulator = () => ({
|
|
353
|
-
edges: [],
|
|
354
|
-
routes: [],
|
|
355
|
-
endpoints: [],
|
|
356
|
-
webMcp: [],
|
|
357
|
-
inferences: [],
|
|
358
|
-
seen: new Set(),
|
|
359
|
-
visitedNodes: 0,
|
|
360
|
-
parsedScripts: 0,
|
|
361
|
-
parseFailures: 0,
|
|
362
|
-
droppedFindings: 0,
|
|
363
|
-
astLimitReached: false,
|
|
364
|
-
});
|
|
365
|
-
const isIncludedScript = (script) => script.source.included;
|
|
366
|
-
const routeCallNames = [
|
|
367
|
-
"route",
|
|
368
|
-
"addRoute",
|
|
369
|
-
"useRoutes",
|
|
370
|
-
"createBrowserRouter",
|
|
371
|
-
"createHashRouter",
|
|
372
|
-
];
|
|
373
|
-
const vendorDetectors = [
|
|
374
|
-
{
|
|
375
|
-
value: "webpack",
|
|
376
|
-
detector: "webpack-runtime",
|
|
377
|
-
patterns: ["__webpack_require__"],
|
|
378
|
-
confidence: "high",
|
|
379
|
-
kind: "bundle_runtime",
|
|
380
|
-
},
|
|
381
|
-
{
|
|
382
|
-
value: "Vite",
|
|
383
|
-
detector: "vite-runtime",
|
|
384
|
-
patterns: ["__vite__", "import.meta.hot"],
|
|
385
|
-
confidence: "medium",
|
|
386
|
-
kind: "bundle_runtime",
|
|
387
|
-
},
|
|
388
|
-
{
|
|
389
|
-
value: "React",
|
|
390
|
-
detector: "react-runtime",
|
|
391
|
-
patterns: ["__REACT_DEVTOOLS_GLOBAL_HOOK__", "React.createElement"],
|
|
392
|
-
confidence: "medium",
|
|
393
|
-
kind: "vendor_fingerprint",
|
|
394
|
-
},
|
|
395
|
-
{
|
|
396
|
-
value: "Vue",
|
|
397
|
-
detector: "vue-runtime",
|
|
398
|
-
patterns: ["__VUE__", "createApp("],
|
|
399
|
-
confidence: "medium",
|
|
400
|
-
kind: "vendor_fingerprint",
|
|
401
|
-
},
|
|
402
|
-
{
|
|
403
|
-
value: "Next.js",
|
|
404
|
-
detector: "next-runtime",
|
|
405
|
-
patterns: ["__NEXT_DATA__", "/_next/"],
|
|
406
|
-
confidence: "high",
|
|
407
|
-
kind: "vendor_fingerprint",
|
|
408
|
-
},
|
|
409
|
-
{
|
|
410
|
-
value: "Angular",
|
|
411
|
-
detector: "angular-runtime",
|
|
412
|
-
patterns: ["ɵɵdefineComponent"],
|
|
413
|
-
confidence: "high",
|
|
414
|
-
kind: "vendor_fingerprint",
|
|
415
|
-
},
|
|
416
|
-
{
|
|
417
|
-
value: "Svelte",
|
|
418
|
-
detector: "svelte-runtime",
|
|
419
|
-
patterns: ["svelte/internal"],
|
|
420
|
-
confidence: "medium",
|
|
421
|
-
kind: "vendor_fingerprint",
|
|
422
|
-
},
|
|
423
|
-
];
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import * as t from "@babel/types";
|
|
2
|
+
import { sanitizeBrowserUrl } from "./browserObservation.js";
|
|
3
|
+
/** Name of a call/new callee from its AST node. */
|
|
4
|
+
export const calleeName = (callee) => {
|
|
5
|
+
if (t.isIdentifier(callee))
|
|
6
|
+
return callee.name;
|
|
7
|
+
if (t.isImport(callee))
|
|
8
|
+
return "import";
|
|
9
|
+
if (t.isMemberExpression(callee) || t.isOptionalMemberExpression(callee)) {
|
|
10
|
+
const object = t.isExpression(callee.object)
|
|
11
|
+
? calleeName(callee.object)
|
|
12
|
+
: "";
|
|
13
|
+
const property = propertyName(callee.property);
|
|
14
|
+
return object === "" ? property : `${object}.${property}`;
|
|
15
|
+
}
|
|
16
|
+
return "";
|
|
17
|
+
};
|
|
18
|
+
export const stringArgument = (value) => (t.isStringLiteral(value) ? value.value : undefined);
|
|
19
|
+
export const propertyName = (value) => {
|
|
20
|
+
if (t.isIdentifier(value))
|
|
21
|
+
return value.name;
|
|
22
|
+
if (t.isStringLiteral(value))
|
|
23
|
+
return value.value;
|
|
24
|
+
return "";
|
|
25
|
+
};
|
|
26
|
+
export const objectValue = (object, name) => {
|
|
27
|
+
for (const property of object.properties)
|
|
28
|
+
if (t.isObjectProperty(property) && propertyName(property.key) === name)
|
|
29
|
+
return property.value;
|
|
30
|
+
return undefined;
|
|
31
|
+
};
|
|
32
|
+
export const objectString = (object, name) => {
|
|
33
|
+
const value = objectValue(object, name);
|
|
34
|
+
return t.isStringLiteral(value) ? value.value : undefined;
|
|
35
|
+
};
|
|
36
|
+
export const resolveSpecifier = (specifier, base) => {
|
|
37
|
+
try {
|
|
38
|
+
const resolved = new URL(specifier, base);
|
|
39
|
+
if (resolved.protocol !== "http:" && resolved.protocol !== "https:")
|
|
40
|
+
return null;
|
|
41
|
+
return sanitizeBrowserUrl(resolved.href).url;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
export const sanitizeCandidate = (value) => {
|
|
48
|
+
const bounded = value.slice(0, 4_096);
|
|
49
|
+
try {
|
|
50
|
+
const parsed = new URL(bounded, "https://rea.invalid");
|
|
51
|
+
const sanitized = sanitizeBrowserUrl(parsed.href).url;
|
|
52
|
+
return parsed.origin === "https://rea.invalid"
|
|
53
|
+
? sanitized.replace("https://rea.invalid", "")
|
|
54
|
+
: sanitized;
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return bounded.split("#", 1)[0]?.split("?", 1)[0] ?? "";
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
export const location = (scriptKey, node) => ({
|
|
61
|
+
script_key: scriptKey,
|
|
62
|
+
...locationFields(node),
|
|
63
|
+
});
|
|
64
|
+
export const locationFields = (node) => ({
|
|
65
|
+
line: node.loc?.start.line ?? null,
|
|
66
|
+
column: node.loc?.start.column ?? null,
|
|
67
|
+
});
|
|
68
|
+
/** Pick the endpoint argument for common network-call patterns. */
|
|
69
|
+
export const endpointArgument = (name, args) => {
|
|
70
|
+
if (name === "fetch" || name.endsWith(".fetch") || name === "WebSocket")
|
|
71
|
+
return stringArgument(args[0]);
|
|
72
|
+
if (name.endsWith(".open") && stringArgument(args[1]) !== undefined)
|
|
73
|
+
return stringArgument(args[1]);
|
|
74
|
+
if (["get", "post", "put", "patch", "delete", "request"].some((method) => name === method || name.endsWith(`.${method}`)))
|
|
75
|
+
return stringArgument(args[0]);
|
|
76
|
+
return undefined;
|
|
77
|
+
};
|