@js-recon/js-recon 1.3.1-beta.2
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/.gitattributes +2 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +29 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/.github/ISSUE_TEMPLATE/new_tech_support_request.md +26 -0
- package/.github/workflows/build-and-prettify.yaml +121 -0
- package/.github/workflows/pr_checker.yml +22 -0
- package/.github/workflows/publish-js-recon.yml +169 -0
- package/.prettierignore +2 -0
- package/.prettierrc +6 -0
- package/CHANGELOG.md +692 -0
- package/CLAUDE.md +290 -0
- package/Dockerfile +34 -0
- package/LICENSE +21 -0
- package/README.md +101 -0
- package/SECURITY.md +37 -0
- package/build/analyze/engine/astEngine.js +224 -0
- package/build/analyze/engine/astEngine.js.map +1 -0
- package/build/analyze/engine/index.js +59 -0
- package/build/analyze/engine/index.js.map +1 -0
- package/build/analyze/engine/requestEngine.js +100 -0
- package/build/analyze/engine/requestEngine.js.map +1 -0
- package/build/analyze/helpers/engineHelpers/findDirectAssignment.js +37 -0
- package/build/analyze/helpers/engineHelpers/findDirectAssignment.js.map +1 -0
- package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js +29 -0
- package/build/analyze/helpers/engineHelpers/findMemberExpressionAssignment.js.map +1 -0
- package/build/analyze/helpers/engineHelpers/resolveFunctionIdentifier.js +38 -0
- package/build/analyze/helpers/engineHelpers/resolveFunctionIdentifier.js.map +1 -0
- package/build/analyze/helpers/engineHelpers/taintFlow.js +250 -0
- package/build/analyze/helpers/engineHelpers/taintFlow.js.map +1 -0
- package/build/analyze/helpers/initRules.js +111 -0
- package/build/analyze/helpers/initRules.js.map +1 -0
- package/build/analyze/helpers/outputHelper.js +14 -0
- package/build/analyze/helpers/outputHelper.js.map +1 -0
- package/build/analyze/helpers/schemas.js +57 -0
- package/build/analyze/helpers/schemas.js.map +1 -0
- package/build/analyze/helpers/validate.js +89 -0
- package/build/analyze/helpers/validate.js.map +1 -0
- package/build/analyze/index.js +150 -0
- package/build/analyze/index.js.map +1 -0
- package/build/analyze/types/index.js +2 -0
- package/build/analyze/types/index.js.map +1 -0
- package/build/api_gateway/checkFeasibility.js +41 -0
- package/build/api_gateway/checkFeasibility.js.map +1 -0
- package/build/api_gateway/checkFireWallBlocking.js +33 -0
- package/build/api_gateway/checkFireWallBlocking.js.map +1 -0
- package/build/api_gateway/genReq.js +205 -0
- package/build/api_gateway/genReq.js.map +1 -0
- package/build/api_gateway/index.js +291 -0
- package/build/api_gateway/index.js.map +1 -0
- package/build/endpoints/gen_report/gen_json.js +30 -0
- package/build/endpoints/gen_report/gen_json.js.map +1 -0
- package/build/endpoints/gen_report/utility/iterate_n_store.js +64 -0
- package/build/endpoints/gen_report/utility/iterate_n_store.js.map +1 -0
- package/build/endpoints/index.js +101 -0
- package/build/endpoints/index.js.map +1 -0
- package/build/endpoints/next_js/client_jsFilesHref.js +100 -0
- package/build/endpoints/next_js/client_jsFilesHref.js.map +1 -0
- package/build/endpoints/next_js/client_jsonParse.js +89 -0
- package/build/endpoints/next_js/client_jsonParse.js.map +1 -0
- package/build/endpoints/next_js/client_mappedJsonFile.js +103 -0
- package/build/endpoints/next_js/client_mappedJsonFile.js.map +1 -0
- package/build/endpoints/next_js/client_subsequentRequests.js +211 -0
- package/build/endpoints/next_js/client_subsequentRequests.js.map +1 -0
- package/build/fingerprint/index.js +123 -0
- package/build/fingerprint/index.js.map +1 -0
- package/build/globalConfig.js +16 -0
- package/build/globalConfig.js.map +1 -0
- package/build/index.js +332 -0
- package/build/index.js.map +1 -0
- package/build/lazyLoad/angular/angular_getFromMainJs.js +55 -0
- package/build/lazyLoad/angular/angular_getFromMainJs.js.map +1 -0
- package/build/lazyLoad/angular/angular_getFromPageSource.js +43 -0
- package/build/lazyLoad/angular/angular_getFromPageSource.js.map +1 -0
- package/build/lazyLoad/downloadFilesUtil.js +127 -0
- package/build/lazyLoad/downloadFilesUtil.js.map +1 -0
- package/build/lazyLoad/downloadLoadedJsUtil.js +44 -0
- package/build/lazyLoad/downloadLoadedJsUtil.js.map +1 -0
- package/build/lazyLoad/downloadQueue.js +191 -0
- package/build/lazyLoad/downloadQueue.js.map +1 -0
- package/build/lazyLoad/globals.js +107 -0
- package/build/lazyLoad/globals.js.map +1 -0
- package/build/lazyLoad/index.js +377 -0
- package/build/lazyLoad/index.js.map +1 -0
- package/build/lazyLoad/next_js/NextJsCrawler.js +332 -0
- package/build/lazyLoad/next_js/NextJsCrawler.js.map +1 -0
- package/build/lazyLoad/next_js/next_GetJSScript.js +126 -0
- package/build/lazyLoad/next_js/next_GetJSScript.js.map +1 -0
- package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js +83 -0
- package/build/lazyLoad/next_js/next_GetLazyResourcesBuildManifestJs.js.map +1 -0
- package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js +222 -0
- package/build/lazyLoad/next_js/next_GetLazyResourcesWebpackJs.js.map +1 -0
- package/build/lazyLoad/next_js/next_SubsequentRequests.js +208 -0
- package/build/lazyLoad/next_js/next_SubsequentRequests.js.map +1 -0
- package/build/lazyLoad/next_js/next_bruteForceJsFiles.js +37 -0
- package/build/lazyLoad/next_js/next_bruteForceJsFiles.js.map +1 -0
- package/build/lazyLoad/next_js/next_buildId.js +55 -0
- package/build/lazyLoad/next_js/next_buildId.js.map +1 -0
- package/build/lazyLoad/next_js/next_getClientSidePaths.js +83 -0
- package/build/lazyLoad/next_js/next_getClientSidePaths.js.map +1 -0
- package/build/lazyLoad/next_js/next_globals.js +8 -0
- package/build/lazyLoad/next_js/next_globals.js.map +1 -0
- package/build/lazyLoad/next_js/next_parseLayoutJs.js +116 -0
- package/build/lazyLoad/next_js/next_parseLayoutJs.js.map +1 -0
- package/build/lazyLoad/next_js/next_promiseResolve.js +85 -0
- package/build/lazyLoad/next_js/next_promiseResolve.js.map +1 -0
- package/build/lazyLoad/next_js/next_scriptTagsSubsequentRequests.js +51 -0
- package/build/lazyLoad/next_js/next_scriptTagsSubsequentRequests.js.map +1 -0
- package/build/lazyLoad/nuxt_js/nuxt_astParse.js +202 -0
- package/build/lazyLoad/nuxt_js/nuxt_astParse.js.map +1 -0
- package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js +82 -0
- package/build/lazyLoad/nuxt_js/nuxt_getFromPageSource.js.map +1 -0
- package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js +108 -0
- package/build/lazyLoad/nuxt_js/nuxt_stringAnalysisJSFiles.js.map +1 -0
- package/build/lazyLoad/react/react_followImports.js +105 -0
- package/build/lazyLoad/react/react_followImports.js.map +1 -0
- package/build/lazyLoad/react/react_getScriptTags.js +52 -0
- package/build/lazyLoad/react/react_getScriptTags.js.map +1 -0
- package/build/lazyLoad/react/react_sourcemapUrls.js +44 -0
- package/build/lazyLoad/react/react_sourcemapUrls.js.map +1 -0
- package/build/lazyLoad/react/react_webpackChunkPaths.js +188 -0
- package/build/lazyLoad/react/react_webpackChunkPaths.js.map +1 -0
- package/build/lazyLoad/sourcemap.js +188 -0
- package/build/lazyLoad/sourcemap.js.map +1 -0
- package/build/lazyLoad/svelte/svelte_discoverPagesFromJs.js +162 -0
- package/build/lazyLoad/svelte/svelte_discoverPagesFromJs.js.map +1 -0
- package/build/lazyLoad/svelte/svelte_getFromPageSource.js +91 -0
- package/build/lazyLoad/svelte/svelte_getFromPageSource.js.map +1 -0
- package/build/lazyLoad/svelte/svelte_recursivePageCrawl.js +180 -0
- package/build/lazyLoad/svelte/svelte_recursivePageCrawl.js.map +1 -0
- package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js +123 -0
- package/build/lazyLoad/svelte/svelte_stringAnalysisJSFiles.js.map +1 -0
- package/build/lazyLoad/techDetect/checkAngularJS.js +70 -0
- package/build/lazyLoad/techDetect/checkAngularJS.js.map +1 -0
- package/build/lazyLoad/techDetect/checkNextJS.js +45 -0
- package/build/lazyLoad/techDetect/checkNextJS.js.map +1 -0
- package/build/lazyLoad/techDetect/checkNuxtJS.js +39 -0
- package/build/lazyLoad/techDetect/checkNuxtJS.js.map +1 -0
- package/build/lazyLoad/techDetect/checkReact.js +86 -0
- package/build/lazyLoad/techDetect/checkReact.js.map +1 -0
- package/build/lazyLoad/techDetect/checkSvelte.js +69 -0
- package/build/lazyLoad/techDetect/checkSvelte.js.map +1 -0
- package/build/lazyLoad/techDetect/checkVueJS.js +118 -0
- package/build/lazyLoad/techDetect/checkVueJS.js.map +1 -0
- package/build/lazyLoad/techDetect/index.js +161 -0
- package/build/lazyLoad/techDetect/index.js.map +1 -0
- package/build/lazyLoad/vue/vue_RuntimeJs.js +169 -0
- package/build/lazyLoad/vue/vue_RuntimeJs.js.map +1 -0
- package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js +102 -0
- package/build/lazyLoad/vue/vue_SingleJsFileOnHome.js.map +1 -0
- package/build/lazyLoad/vue/vue_discoverJsFiles.js +82 -0
- package/build/lazyLoad/vue/vue_discoverJsFiles.js.map +1 -0
- package/build/lazyLoad/vue/vue_getClientSidePaths.js +155 -0
- package/build/lazyLoad/vue/vue_getClientSidePaths.js.map +1 -0
- package/build/lazyLoad/vue/vue_jsImports.js +76 -0
- package/build/lazyLoad/vue/vue_jsImports.js.map +1 -0
- package/build/lazyLoad/vue/vue_pageSrc.js +60 -0
- package/build/lazyLoad/vue/vue_pageSrc.js.map +1 -0
- package/build/lazyLoad/vue/vue_reconstructSourceMaps.js +64 -0
- package/build/lazyLoad/vue/vue_reconstructSourceMaps.js.map +1 -0
- package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js +142 -0
- package/build/lazyLoad/vue/vue_recursiveClientSidePathDownload.js.map +1 -0
- package/build/lazyLoad/vue/vue_severalJsFilesHome.js +57 -0
- package/build/lazyLoad/vue/vue_severalJsFilesHome.js.map +1 -0
- package/build/lazyLoad/vue/vue_sourcemapExtract.js +166 -0
- package/build/lazyLoad/vue/vue_sourcemapExtract.js.map +1 -0
- package/build/lazyLoad/vue/vue_stringJsFiles.js +148 -0
- package/build/lazyLoad/vue/vue_stringJsFiles.js.map +1 -0
- package/build/lazyLoad/vue/vue_viteMapDeps.js +89 -0
- package/build/lazyLoad/vue/vue_viteMapDeps.js.map +1 -0
- package/build/load/index.js +316 -0
- package/build/load/index.js.map +1 -0
- package/build/map/graphql/resolveGraphql.js +296 -0
- package/build/map/graphql/resolveGraphql.js.map +1 -0
- package/build/map/index.js +261 -0
- package/build/map/index.js.map +1 -0
- package/build/map/next_js/getAxiosInstances.js +64 -0
- package/build/map/next_js/getAxiosInstances.js.map +1 -0
- package/build/map/next_js/getExports.js +101 -0
- package/build/map/next_js/getExports.js.map +1 -0
- package/build/map/next_js/getFetchInstances.js +139 -0
- package/build/map/next_js/getFetchInstances.js.map +1 -0
- package/build/map/next_js/getTurbopackConnections.js +255 -0
- package/build/map/next_js/getTurbopackConnections.js.map +1 -0
- package/build/map/next_js/getWebpackConnections.js +235 -0
- package/build/map/next_js/getWebpackConnections.js.map +1 -0
- package/build/map/next_js/interactive.js +69 -0
- package/build/map/next_js/interactive.js.map +1 -0
- package/build/map/next_js/interactive_helpers/commandHandler.js +310 -0
- package/build/map/next_js/interactive_helpers/commandHandler.js.map +1 -0
- package/build/map/next_js/interactive_helpers/commandHelpers.js +245 -0
- package/build/map/next_js/interactive_helpers/commandHelpers.js.map +1 -0
- package/build/map/next_js/interactive_helpers/esqueryGen.js +370 -0
- package/build/map/next_js/interactive_helpers/esqueryGen.js.map +1 -0
- package/build/map/next_js/interactive_helpers/helpMenu.js +12 -0
- package/build/map/next_js/interactive_helpers/helpMenu.js.map +1 -0
- package/build/map/next_js/interactive_helpers/inputPatch.js +207 -0
- package/build/map/next_js/interactive_helpers/inputPatch.js.map +1 -0
- package/build/map/next_js/interactive_helpers/keybindings.js +90 -0
- package/build/map/next_js/interactive_helpers/keybindings.js.map +1 -0
- package/build/map/next_js/interactive_helpers/printer.js +23 -0
- package/build/map/next_js/interactive_helpers/printer.js.map +1 -0
- package/build/map/next_js/interactive_helpers/ui.js +88 -0
- package/build/map/next_js/interactive_helpers/ui.js.map +1 -0
- package/build/map/next_js/resolveAxios.js +152 -0
- package/build/map/next_js/resolveAxios.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/astNodeToJsonString.js +64 -0
- package/build/map/next_js/resolveAxiosHelpers/astNodeToJsonString.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/directCallsWithoutAssignment.js +48 -0
- package/build/map/next_js/resolveAxiosHelpers/directCallsWithoutAssignment.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/findAxiosClients.js +34 -0
- package/build/map/next_js/resolveAxiosHelpers/findAxiosClients.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js +39 -0
- package/build/map/next_js/resolveAxiosHelpers/findAxiosInstance.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js +312 -0
- package/build/map/next_js/resolveAxiosHelpers/findCrossChunkParams.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js +173 -0
- package/build/map/next_js/resolveAxiosHelpers/handleAxiosCreate.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js +261 -0
- package/build/map/next_js/resolveAxiosHelpers/handleZDotCreate.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/interceptorHeaders.js +206 -0
- package/build/map/next_js/resolveAxiosHelpers/interceptorHeaders.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js +168 -0
- package/build/map/next_js/resolveAxiosHelpers/processAxiosCall.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js +121 -0
- package/build/map/next_js/resolveAxiosHelpers/processDirectAxiosCall.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js +274 -0
- package/build/map/next_js/resolveAxiosHelpers/processExportedEndpoints.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js +518 -0
- package/build/map/next_js/resolveAxiosHelpers/traceAxiosInstanceExports.js.map +1 -0
- package/build/map/next_js/resolveAxiosHelpers/traceBody.js +913 -0
- package/build/map/next_js/resolveAxiosHelpers/traceBody.js.map +1 -0
- package/build/map/next_js/resolveFetch.js +533 -0
- package/build/map/next_js/resolveFetch.js.map +1 -0
- package/build/map/next_js/resolveNewRequest.js +749 -0
- package/build/map/next_js/resolveNewRequest.js.map +1 -0
- package/build/map/next_js/resolveServerActions.js +449 -0
- package/build/map/next_js/resolveServerActions.js.map +1 -0
- package/build/map/next_js/utils.js +1600 -0
- package/build/map/next_js/utils.js.map +1 -0
- package/build/map/react_js/getReactConnections.js +303 -0
- package/build/map/react_js/getReactConnections.js.map +1 -0
- package/build/map/react_js/interactive.js +4 -0
- package/build/map/react_js/interactive.js.map +1 -0
- package/build/map/react_js/react_resolveFetch.js +6 -0
- package/build/map/react_js/react_resolveFetch.js.map +1 -0
- package/build/map/svelte_js/interactive.js +58 -0
- package/build/map/svelte_js/interactive.js.map +1 -0
- package/build/map/svelte_js/interactive_helpers/commandHandler.js +4 -0
- package/build/map/svelte_js/interactive_helpers/commandHandler.js.map +1 -0
- package/build/map/vue_js/bodyResolver.js +477 -0
- package/build/map/vue_js/bodyResolver.js.map +1 -0
- package/build/map/vue_js/crossFileResolver.js +438 -0
- package/build/map/vue_js/crossFileResolver.js.map +1 -0
- package/build/map/vue_js/getViteConnections.js +343 -0
- package/build/map/vue_js/getViteConnections.js.map +1 -0
- package/build/map/vue_js/interactive.js +67 -0
- package/build/map/vue_js/interactive.js.map +1 -0
- package/build/map/vue_js/interactive_helpers/commandHandler.js +307 -0
- package/build/map/vue_js/interactive_helpers/commandHandler.js.map +1 -0
- package/build/map/vue_js/interactive_helpers/commandHelpers.js +39 -0
- package/build/map/vue_js/interactive_helpers/commandHelpers.js.map +1 -0
- package/build/map/vue_js/interactive_helpers/helpMenu.js +12 -0
- package/build/map/vue_js/interactive_helpers/helpMenu.js.map +1 -0
- package/build/map/vue_js/taint_utils.js +621 -0
- package/build/map/vue_js/taint_utils.js.map +1 -0
- package/build/map/vue_js/vue_resolveFetch.js +416 -0
- package/build/map/vue_js/vue_resolveFetch.js.map +1 -0
- package/build/map/vue_js/vue_resolveHttpClient.js +738 -0
- package/build/map/vue_js/vue_resolveHttpClient.js.map +1 -0
- package/build/map/vue_js/vue_resolveXhr.js +282 -0
- package/build/map/vue_js/vue_resolveXhr.js.map +1 -0
- package/build/mcp/chatOneShot.js +101 -0
- package/build/mcp/chatOneShot.js.map +1 -0
- package/build/mcp/claudeCodeCreds.js +150 -0
- package/build/mcp/claudeCodeCreds.js.map +1 -0
- package/build/mcp/cli.js +372 -0
- package/build/mcp/cli.js.map +1 -0
- package/build/mcp/commands.js +227 -0
- package/build/mcp/commands.js.map +1 -0
- package/build/mcp/config.js +68 -0
- package/build/mcp/config.js.map +1 -0
- package/build/mcp/index.js +50 -0
- package/build/mcp/index.js.map +1 -0
- package/build/mcp/intent.js +204 -0
- package/build/mcp/intent.js.map +1 -0
- package/build/mcp/jobs.js +199 -0
- package/build/mcp/jobs.js.map +1 -0
- package/build/mcp/mcpServer.js +241 -0
- package/build/mcp/mcpServer.js.map +1 -0
- package/build/mcp/providers.js +170 -0
- package/build/mcp/providers.js.map +1 -0
- package/build/mcp/skills.js +115 -0
- package/build/mcp/skills.js.map +1 -0
- package/build/mcp/tools.js +185 -0
- package/build/mcp/tools.js.map +1 -0
- package/build/refactor/index.js +85 -0
- package/build/refactor/index.js.map +1 -0
- package/build/refactor/next/index.js +109 -0
- package/build/refactor/next/index.js.map +1 -0
- package/build/refactor/react/index.js +636 -0
- package/build/refactor/react/index.js.map +1 -0
- package/build/report/index.js +68 -0
- package/build/report/index.js.map +1 -0
- package/build/report/utility/dataTables/genDataTablesPage.js +158 -0
- package/build/report/utility/dataTables/genDataTablesPage.js.map +1 -0
- package/build/report/utility/genHtml.js +516 -0
- package/build/report/utility/genHtml.js.map +1 -0
- package/build/report/utility/initReportDb.js +96 -0
- package/build/report/utility/initReportDb.js.map +1 -0
- package/build/report/utility/markdownGen/addAnalyze.js +53 -0
- package/build/report/utility/markdownGen/addAnalyze.js.map +1 -0
- package/build/report/utility/markdownGen/addMappedJson.js +33 -0
- package/build/report/utility/markdownGen/addMappedJson.js.map +1 -0
- package/build/report/utility/populateDb/populateAnalysisFindings.js +31 -0
- package/build/report/utility/populateDb/populateAnalysisFindings.js.map +1 -0
- package/build/report/utility/populateDb/populateEndpoints.js +50 -0
- package/build/report/utility/populateDb/populateEndpoints.js.map +1 -0
- package/build/report/utility/populateDb/populateMappedJson.js +31 -0
- package/build/report/utility/populateDb/populateMappedJson.js.map +1 -0
- package/build/report/utility/populateDb/populateMappedOpenapi.js +49 -0
- package/build/report/utility/populateDb/populateMappedOpenapi.js.map +1 -0
- package/build/run/index.js +446 -0
- package/build/run/index.js.map +1 -0
- package/build/run/interruptHandler.js +93 -0
- package/build/run/interruptHandler.js.map +1 -0
- package/build/strings/index.js +239 -0
- package/build/strings/index.js.map +1 -0
- package/build/strings/openapi.js +63 -0
- package/build/strings/openapi.js.map +1 -0
- package/build/strings/permutate.js +62 -0
- package/build/strings/permutate.js.map +1 -0
- package/build/strings/secrets.js +102 -0
- package/build/strings/secrets.js.map +1 -0
- package/build/utility/ai.js +97 -0
- package/build/utility/ai.js.map +1 -0
- package/build/utility/configureSandbox.js +14 -0
- package/build/utility/configureSandbox.js.map +1 -0
- package/build/utility/globals.js +322 -0
- package/build/utility/globals.js.map +1 -0
- package/build/utility/interfaces.js +2 -0
- package/build/utility/interfaces.js.map +1 -0
- package/build/utility/makeReq.js +448 -0
- package/build/utility/makeReq.js.map +1 -0
- package/build/utility/openapiGenerator.js +254 -0
- package/build/utility/openapiGenerator.js.map +1 -0
- package/build/utility/postmanGenerator.js +216 -0
- package/build/utility/postmanGenerator.js.map +1 -0
- package/build/utility/progressLog.js +50 -0
- package/build/utility/progressLog.js.map +1 -0
- package/build/utility/puppeteerInstance.js +5 -0
- package/build/utility/puppeteerInstance.js.map +1 -0
- package/build/utility/replaceUrlPlaceholders.js +48 -0
- package/build/utility/replaceUrlPlaceholders.js.map +1 -0
- package/build/utility/resolvePath.js +44 -0
- package/build/utility/resolvePath.js.map +1 -0
- package/build/utility/runSandboxed.js +42 -0
- package/build/utility/runSandboxed.js.map +1 -0
- package/build/utility/urlUtils.js +21 -0
- package/build/utility/urlUtils.js.map +1 -0
- package/contributing/nextjs.md +410 -0
- package/package.json +75 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves a relative path with a given base URL.
|
|
3
|
+
*
|
|
4
|
+
* The behavior of the URL constructor is used to handle various cases of path resolution.
|
|
5
|
+
* If the base URL does not end with a '/', its last path segment is typically treated as a "file",
|
|
6
|
+
* and relative paths are resolved from the "directory" containing that "file".
|
|
7
|
+
* Examples:
|
|
8
|
+
* - url='https://site.com/something', path='./main.js' => 'https://site.com/main.js'
|
|
9
|
+
* (Base for resolution becomes 'https://site.com/')
|
|
10
|
+
* - url='https://site.com/something/', path='./main.js' => 'https://site.com/something/main.js'
|
|
11
|
+
* (Base for resolution is 'https://site.com/something/')
|
|
12
|
+
* - url='https://site.com/something/other', path='../main.js' => 'https://site.com/main.js'
|
|
13
|
+
* (Base for resolution becomes 'https://site.com/something/', then '../' navigates up)
|
|
14
|
+
*
|
|
15
|
+
* @param {string} url - The base URL for resolving the relative path
|
|
16
|
+
* @param {string} path - The relative path to be resolved
|
|
17
|
+
* @returns {string} The resolved absolute URL
|
|
18
|
+
* @throws {Error} If an error occurs while resolving the path
|
|
19
|
+
*/
|
|
20
|
+
const resolvePath = (url, path) => {
|
|
21
|
+
try {
|
|
22
|
+
// The URL constructor handles various cases of path resolution.
|
|
23
|
+
// If 'url' (the base URL) does not end with a '/', its last path segment
|
|
24
|
+
// is typically treated as a "file", and relative paths are resolved
|
|
25
|
+
// from the "directory" containing that "file".
|
|
26
|
+
// This behavior aligns with the provided examples:
|
|
27
|
+
// - url='https://site.com/something', path='./main.js' => 'https://site.com/main.js'
|
|
28
|
+
// (Base for resolution becomes 'https://site.com/')
|
|
29
|
+
// - url='https://site.com/something/', path='./main.js' => 'https://site.com/something/main.js'
|
|
30
|
+
// (Base for resolution is 'https://site.com/something/')
|
|
31
|
+
// - url='https://site.com/something/other', path='../main.js' => 'https://site.com/main.js'
|
|
32
|
+
// (Base for resolution becomes 'https://site.com/something/', then '../' navigates up)
|
|
33
|
+
const resolvedUrl = new URL(path, url);
|
|
34
|
+
return resolvedUrl.href;
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
console.error(`Error resolving path "${path}" with base URL "${url}": ${e.message}`);
|
|
38
|
+
// Rethrowing the error to signal failure to the caller.
|
|
39
|
+
// Alternative error handling (e.g., returning null) can be implemented if required.
|
|
40
|
+
throw e;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
export default resolvePath;
|
|
44
|
+
//# sourceMappingURL=resolvePath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvePath.js","sourceRoot":"","sources":["../../src/utility/resolvePath.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,WAAW,GAAG,CAAC,GAAW,EAAE,IAAY,EAAE,EAAE;IAC9C,IAAI,CAAC;QACD,gEAAgE;QAChE,yEAAyE;QACzE,oEAAoE;QACpE,+CAA+C;QAC/C,mDAAmD;QACnD,qFAAqF;QACrF,sDAAsD;QACtD,gGAAgG;QAChG,2DAA2D;QAC3D,4FAA4F;QAC5F,yFAAyF;QACzF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACvC,OAAO,WAAW,CAAC,IAAI,CAAC;IAC5B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACT,OAAO,CAAC,KAAK,CAAC,yBAAyB,IAAI,oBAAoB,GAAG,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;QACrF,wDAAwD;QACxD,oFAAoF;QACpF,MAAM,CAAC,CAAC;IACZ,CAAC;AACL,CAAC,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import "ses";
|
|
2
|
+
// Lock down the global environment for security
|
|
3
|
+
lockdown();
|
|
4
|
+
/**
|
|
5
|
+
* Executes a given function in a sandboxed environment.
|
|
6
|
+
* @param {string} code - The code to execute.
|
|
7
|
+
* @param {any} param - The parameter to pass to the function.
|
|
8
|
+
* @returns {any} The result of the function execution.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Executes a given function in a sandboxed environment.
|
|
12
|
+
*
|
|
13
|
+
* This function takes a string of code that represents a function, and
|
|
14
|
+
* executes it in a sandboxed environment. It also takes a parameter
|
|
15
|
+
* that is passed to the function when it is executed.
|
|
16
|
+
*
|
|
17
|
+
* The sandboxed environment is created using the vm module's
|
|
18
|
+
* Compartment class. This class is used to create a new global
|
|
19
|
+
* environment that is isolated from the current global environment.
|
|
20
|
+
*
|
|
21
|
+
* The function that is passed as a string is wrapped in a self-invoking
|
|
22
|
+
* anonymous function, and then evaluated in the sandboxed environment.
|
|
23
|
+
* The parameter that is passed to the function is then passed to the evaluated
|
|
24
|
+
* function, and the result of the function execution is returned.
|
|
25
|
+
*
|
|
26
|
+
* @param {string} code - The code to execute. This should represent a function.
|
|
27
|
+
* @param {any} param - The parameter to pass to the function.
|
|
28
|
+
* @returns {any} The result of the function execution.
|
|
29
|
+
*/
|
|
30
|
+
const execFunc = (code, param) => {
|
|
31
|
+
const c = new Compartment({
|
|
32
|
+
console,
|
|
33
|
+
});
|
|
34
|
+
const wrappedCode = `
|
|
35
|
+
(${code})
|
|
36
|
+
`;
|
|
37
|
+
const func = c.evaluate(wrappedCode);
|
|
38
|
+
const output = func(param);
|
|
39
|
+
return output;
|
|
40
|
+
};
|
|
41
|
+
export default execFunc;
|
|
42
|
+
//# sourceMappingURL=runSandboxed.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runSandboxed.js","sourceRoot":"","sources":["../../src/utility/runSandboxed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC;AAEb,gDAAgD;AAChD,QAAQ,EAAE,CAAC;AAEX;;;;;GAKG;AACH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;IAC7B,MAAM,CAAC,GAAG,IAAI,WAAW,CAAC;QACtB,OAAO;KACV,CAAC,CAAC;IACH,MAAM,WAAW,GAAG;OACjB,IAAI;GACR,CAAC;IACA,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;IAE3B,OAAO,MAAM,CAAC;AAClB,CAAC,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Given a URL, returns an object with the host and directory
|
|
3
|
+
* of the URL. The directory is the path of the URL after the
|
|
4
|
+
* host, and the filename is removed if it ends with a file extension.
|
|
5
|
+
* For example, given "https://vercel.com/static/js/main.js", it will return
|
|
6
|
+
* an object with host "vercel.com" and directory "/static/js".
|
|
7
|
+
* @param {string} url - The URL to parse.
|
|
8
|
+
* @returns {Object} An object with the host and directory of the URL.
|
|
9
|
+
*/
|
|
10
|
+
const getURLDirectory = (url) => {
|
|
11
|
+
const u = new URL(url);
|
|
12
|
+
const pathname = u.pathname;
|
|
13
|
+
// Remove filename (last part after final /) if it ends with .js or any file extension
|
|
14
|
+
const dir = pathname.replace(/\/[^\/?#]+\.[^\/?#]+$/, "");
|
|
15
|
+
return {
|
|
16
|
+
host: u.host.replace(":", "_"), // e.g., "vercel.com" or "localhost_3000"
|
|
17
|
+
directory: dir, // e.g., "/static/js"
|
|
18
|
+
};
|
|
19
|
+
};
|
|
20
|
+
export { getURLDirectory };
|
|
21
|
+
//# sourceMappingURL=urlUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"urlUtils.js","sourceRoot":"","sources":["../../src/utility/urlUtils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,eAAe,GAAG,CAAC,GAAW,EAAE,EAAE;IACpC,MAAM,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACvB,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC;IAE5B,sFAAsF;IACtF,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC;IAE1D,OAAO;QACH,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,yCAAyC;QACzE,SAAS,EAAE,GAAG,EAAE,qBAAqB;KACxC,CAAC;AACN,CAAC,CAAC;AAEF,OAAO,EAAE,eAAe,EAAE,CAAC"}
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
# Contributing New Next.js Discovery Methods
|
|
2
|
+
|
|
3
|
+
This guide explains how to add new JavaScript file discovery techniques for Next.js applications to `js-recon`.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Architecture Overview](#architecture-overview)
|
|
8
|
+
- [Discovery Method Types](#discovery-method-types)
|
|
9
|
+
- [Adding a New Discovery Method](#adding-a-new-discovery-method)
|
|
10
|
+
- [Integration into NextJsCrawler](#integration-into-nextjscrawler)
|
|
11
|
+
- [Best Practices](#best-practices)
|
|
12
|
+
- [Testing Your Method](#testing-your-method)
|
|
13
|
+
- [Research Mode](#research-mode)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Architecture Overview
|
|
18
|
+
|
|
19
|
+
The Next.js discovery system is built around the **`NextJsCrawler`** class (`src/lazyLoad/next_js/NextJsCrawler.ts`), which implements a **three-phase crawling strategy**:
|
|
20
|
+
|
|
21
|
+
### Phase 1: Initial Discovery
|
|
22
|
+
|
|
23
|
+
Heavyweight methods that run **once** to bootstrap the crawl:
|
|
24
|
+
|
|
25
|
+
- Script tag parsing (`next_getJSScript`)
|
|
26
|
+
- Webpack runtime analysis (`next_GetLazyResourcesWebpackJs`) – uses Puppeteer
|
|
27
|
+
- `_buildManifest.js` parsing (`next_getLazyResourcesBuildManifestJs`)
|
|
28
|
+
- Subsequent requests with RSC headers (`subsequentRequests`)
|
|
29
|
+
|
|
30
|
+
### Phase 2: Recursive Discovery
|
|
31
|
+
|
|
32
|
+
Lightweight methods that run **multiple times** on newly discovered URLs until convergence:
|
|
33
|
+
|
|
34
|
+
- Promise.all pattern detection (`next_promiseResolve`)
|
|
35
|
+
- Layout.js href extraction (`next_parseLayoutJs`)
|
|
36
|
+
- Script tag re-parsing on new pages (`next_getJSScript`)
|
|
37
|
+
|
|
38
|
+
### Phase 3: Finalization
|
|
39
|
+
|
|
40
|
+
Post-processing on the final URL set:
|
|
41
|
+
|
|
42
|
+
- Source map brute-forcing (`next_bruteForceJsFiles`)
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Discovery Method Types
|
|
47
|
+
|
|
48
|
+
### Initial Discovery Methods
|
|
49
|
+
|
|
50
|
+
**When to use:**
|
|
51
|
+
|
|
52
|
+
- The method is **expensive** (e.g., launches a browser, makes many requests)
|
|
53
|
+
- The method doesn't benefit from being run multiple times
|
|
54
|
+
- The method provides a bootstrap set of URLs
|
|
55
|
+
|
|
56
|
+
**Characteristics:**
|
|
57
|
+
|
|
58
|
+
- Runs exactly **once** per crawl
|
|
59
|
+
- Added to `initialDiscovery()` in `NextJsCrawler.ts`
|
|
60
|
+
- Examples: Puppeteer-based webpack analysis, manifest parsing
|
|
61
|
+
|
|
62
|
+
### Recursive Discovery Methods
|
|
63
|
+
|
|
64
|
+
**When to use:**
|
|
65
|
+
|
|
66
|
+
- The method analyzes **JavaScript file contents** to find more JS files
|
|
67
|
+
- The method discovers **client-side paths** that need to be visited
|
|
68
|
+
- The method can find new URLs by examining URLs found in previous passes
|
|
69
|
+
|
|
70
|
+
**Characteristics:**
|
|
71
|
+
|
|
72
|
+
- Runs in a **loop** until no new URLs are discovered (max 10 iterations by default)
|
|
73
|
+
- Takes an array of URLs as input and returns newly discovered URLs
|
|
74
|
+
- Added to `recursivePass()` in `NextJsCrawler.ts`
|
|
75
|
+
- Examples: Promise.all pattern detection, layout href parsing
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Adding a New Discovery Method
|
|
80
|
+
|
|
81
|
+
### Step 1: Create the Method Module
|
|
82
|
+
|
|
83
|
+
Create a new file in `src/lazyLoad/next_js/` following the naming convention `next_<methodName>.ts`.
|
|
84
|
+
|
|
85
|
+
#### Example: Detecting dynamic imports
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
// src/lazyLoad/next_js/next_dynamicImports.ts
|
|
89
|
+
import chalk from "chalk";
|
|
90
|
+
import makeRequest from "../../utility/makeReq.js";
|
|
91
|
+
import parser from "@babel/parser";
|
|
92
|
+
import _traverse from "@babel/traverse";
|
|
93
|
+
const traverse = _traverse.default;
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Finds JS files referenced in dynamic import() statements.
|
|
97
|
+
*
|
|
98
|
+
* @param baseUrl - The base URL of the application
|
|
99
|
+
* @param urls - Array of JS file URLs to analyze
|
|
100
|
+
* @returns Array of newly discovered JS file URLs
|
|
101
|
+
*/
|
|
102
|
+
const next_dynamicImports = async (baseUrl: string, urls: string[]): Promise<string[]> => {
|
|
103
|
+
console.log(chalk.cyan("[i] Analyzing dynamic import() statements"));
|
|
104
|
+
|
|
105
|
+
const discoveredUrls: string[] = [];
|
|
106
|
+
|
|
107
|
+
for (const url of urls) {
|
|
108
|
+
try {
|
|
109
|
+
const response = await makeRequest(url);
|
|
110
|
+
if (!response?.ok) continue;
|
|
111
|
+
|
|
112
|
+
const jsContent = await response.text();
|
|
113
|
+
const ast = parser.parse(jsContent, {
|
|
114
|
+
sourceType: "unambiguous",
|
|
115
|
+
plugins: ["jsx", "typescript"],
|
|
116
|
+
errorRecovery: true,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
traverse(ast, {
|
|
120
|
+
Import(path) {
|
|
121
|
+
// Detect: import('path/to/file.js')
|
|
122
|
+
const parent = path.parent;
|
|
123
|
+
if (
|
|
124
|
+
parent.type === "CallExpression" &&
|
|
125
|
+
parent.arguments.length > 0 &&
|
|
126
|
+
parent.arguments[0].type === "StringLiteral"
|
|
127
|
+
) {
|
|
128
|
+
const importPath = parent.arguments[0].value;
|
|
129
|
+
if (importPath.endsWith(".js")) {
|
|
130
|
+
// Resolve relative to base URL
|
|
131
|
+
const resolvedUrl = new URL(importPath, baseUrl).href;
|
|
132
|
+
discoveredUrls.push(resolvedUrl);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
} catch (error) {
|
|
138
|
+
// Skip files that can't be parsed
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
const uniqueUrls = [...new Set(discoveredUrls)];
|
|
144
|
+
|
|
145
|
+
if (uniqueUrls.length > 0) {
|
|
146
|
+
console.log(chalk.green(`[✓] Found ${uniqueUrls.length} JS files from dynamic imports`));
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return uniqueUrls;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
export default next_dynamicImports;
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Step 2: Method Signature Guidelines
|
|
156
|
+
|
|
157
|
+
**For initial discovery methods:**
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
async function next_methodName(url: string): Promise<string[]>;
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
- Takes the base URL as input
|
|
164
|
+
- Returns array of discovered URLs
|
|
165
|
+
|
|
166
|
+
**For recursive discovery methods:**
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
async function next_methodName(baseUrl: string, urls: string[]): Promise<string[]>;
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
- Takes base URL and array of URLs to analyze
|
|
173
|
+
- Returns array of **newly** discovered URLs
|
|
174
|
+
- Should handle empty input gracefully
|
|
175
|
+
|
|
176
|
+
### Step 3: Common Patterns
|
|
177
|
+
|
|
178
|
+
#### Pattern 1: AST-based Analysis
|
|
179
|
+
|
|
180
|
+
Use Babel parser to analyze JavaScript syntax:
|
|
181
|
+
|
|
182
|
+
```typescript
|
|
183
|
+
import parser from "@babel/parser";
|
|
184
|
+
import _traverse from "@babel/traverse";
|
|
185
|
+
const traverse = _traverse.default;
|
|
186
|
+
|
|
187
|
+
const ast = parser.parse(jsContent, {
|
|
188
|
+
sourceType: "unambiguous",
|
|
189
|
+
plugins: ["jsx", "typescript"],
|
|
190
|
+
errorRecovery: true,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
traverse(ast, {
|
|
194
|
+
// Visitor pattern
|
|
195
|
+
CallExpression(path) {
|
|
196
|
+
// Analyze specific AST nodes
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
#### Pattern 2: String/Regex Matching
|
|
202
|
+
|
|
203
|
+
Quick pattern detection without parsing:
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
const matches = jsContent.matchAll(/static\/chunks\/[a-zA-Z0-9_\-]+\.js/g);
|
|
207
|
+
for (const match of matches) {
|
|
208
|
+
discoveredUrls.push(resolveUrl(match[0]));
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
#### Pattern 3: Request-Based Discovery
|
|
213
|
+
|
|
214
|
+
Make HTTP requests to known patterns:
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
const candidateUrl = `${baseUrl}/_next/static/${hash}/chunk.js`;
|
|
218
|
+
const response = await makeRequest(candidateUrl);
|
|
219
|
+
if (response.status === 200) {
|
|
220
|
+
discoveredUrls.push(candidateUrl);
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Integration into NextJsCrawler
|
|
227
|
+
|
|
228
|
+
### For Initial Discovery Methods
|
|
229
|
+
|
|
230
|
+
Add to `initialDiscovery()` in `NextJsCrawler.ts`. Use this phase for methods that only need to run once, like those starting from the application's root URL:
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
private async initialDiscovery(): Promise<void> {
|
|
234
|
+
// ... existing methods ...
|
|
235
|
+
|
|
236
|
+
// 5. Your new initial discovery method
|
|
237
|
+
const jsFromPrefetch = await next_prefetchHints(this.url);
|
|
238
|
+
this.techniqueEfficiencyMapping["next_prefetchHints"] = jsFromPrefetch;
|
|
239
|
+
this.registerUrls(jsFromPrefetch);
|
|
240
|
+
|
|
241
|
+
// ... rest of the method ...
|
|
242
|
+
}
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
**Don't forget to add the import at the top:**
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
import next_prefetchHints from "./next_prefetchHints.js";
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### For Recursive Discovery Methods
|
|
252
|
+
|
|
253
|
+
Add to `recursivePass()` in `NextJsCrawler.ts`. Use this phase for methods that analyze JS file contents to find more JS files:
|
|
254
|
+
|
|
255
|
+
```typescript
|
|
256
|
+
private async recursivePass(jsUrls: string[]): Promise<string[]> {
|
|
257
|
+
let newInThisPass: string[] = [];
|
|
258
|
+
|
|
259
|
+
// ... existing methods ...
|
|
260
|
+
|
|
261
|
+
// Your new recursive method
|
|
262
|
+
const jsFromDynamicImports = await next_dynamicImports(this.url, jsUrls);
|
|
263
|
+
this.techniqueEfficiencyMapping["next_dynamicImports"] = [
|
|
264
|
+
...(this.techniqueEfficiencyMapping["next_dynamicImports"] || []),
|
|
265
|
+
...jsFromDynamicImports,
|
|
266
|
+
];
|
|
267
|
+
newInThisPass.push(...this.registerUrls(jsFromDynamicImports));
|
|
268
|
+
|
|
269
|
+
return newInThisPass;
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
**Key points:**
|
|
274
|
+
|
|
275
|
+
- Append to `techniqueEfficiencyMapping` (not replace) for recursive methods
|
|
276
|
+
- Use `registerUrls()` to deduplicate and track new URLs
|
|
277
|
+
- Only add truly new URLs to `newInThisPass`
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
281
|
+
## Best Practices
|
|
282
|
+
|
|
283
|
+
### 1. Error Handling
|
|
284
|
+
|
|
285
|
+
Always handle errors gracefully – don't crash the entire crawl:
|
|
286
|
+
|
|
287
|
+
```typescript
|
|
288
|
+
try {
|
|
289
|
+
const response = await makeRequest(url);
|
|
290
|
+
if (!response?.ok) return [];
|
|
291
|
+
// ... process response ...
|
|
292
|
+
} catch (error) {
|
|
293
|
+
// Log if needed, but continue
|
|
294
|
+
return [];
|
|
295
|
+
}
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
### 2. URL Resolution
|
|
299
|
+
|
|
300
|
+
Use `URL` constructor for proper relative URL resolution:
|
|
301
|
+
|
|
302
|
+
```typescript
|
|
303
|
+
const absoluteUrl = new URL(relativePath, baseUrl).href;
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
### 3. Deduplication
|
|
307
|
+
|
|
308
|
+
Always deduplicate before returning:
|
|
309
|
+
|
|
310
|
+
```typescript
|
|
311
|
+
return [...new Set(discoveredUrls)];
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### 4. Performance
|
|
315
|
+
|
|
316
|
+
- Cache expensive operations (e.g., don't re-fetch the same URL)
|
|
317
|
+
- Use `lazyLoadGlobals.presentInCrawledUrls()` to check if already visited
|
|
318
|
+
- Mark URLs as crawled with `lazyLoadGlobals.addCrawledUrl()`
|
|
319
|
+
|
|
320
|
+
```typescript
|
|
321
|
+
import { presentInCrawledUrls, addCrawledUrl } from "../globals.js";
|
|
322
|
+
|
|
323
|
+
for (const url of urls) {
|
|
324
|
+
if (presentInCrawledUrls(url)) continue;
|
|
325
|
+
|
|
326
|
+
// ... analyze URL ...
|
|
327
|
+
|
|
328
|
+
addCrawledUrl(url);
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### 5. Logging
|
|
333
|
+
|
|
334
|
+
Use `chalk` for consistent logging:
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
import chalk from "chalk";
|
|
338
|
+
|
|
339
|
+
console.log(chalk.cyan("[i] Starting analysis...")); // Info
|
|
340
|
+
console.log(chalk.green("[✓] Found 10 files")); // Success
|
|
341
|
+
console.log(chalk.yellow("[!] Warning message")); // Warning
|
|
342
|
+
console.log(chalk.red("[!] Error occurred")); // Error
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
---
|
|
346
|
+
|
|
347
|
+
## Testing Your Method
|
|
348
|
+
|
|
349
|
+
### 1. Integration Test with Real Sites
|
|
350
|
+
|
|
351
|
+
Test against known Next.js sites:
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
npm run cleanup && npm run start -- run -u https://nextjs.org -y --research
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
Check `research.json` to see how many URLs your method discovered:
|
|
358
|
+
|
|
359
|
+
```json
|
|
360
|
+
{
|
|
361
|
+
"next_dynamicImports": [
|
|
362
|
+
"https://nextjs.org/_next/static/chunks/123.js",
|
|
363
|
+
"https://nextjs.org/_next/static/chunks/456.js"
|
|
364
|
+
]
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
### 2. Verify Convergence
|
|
369
|
+
|
|
370
|
+
Ensure your recursive method doesn't cause infinite loops:
|
|
371
|
+
|
|
372
|
+
- Check that "Recursive crawl converged" message appears
|
|
373
|
+
- If it hits max iterations (defaults to 10), investigate why
|
|
374
|
+
|
|
375
|
+
### 3. Performance Validation
|
|
376
|
+
|
|
377
|
+
Monitor execution time:
|
|
378
|
+
|
|
379
|
+
```bash
|
|
380
|
+
time npm run start -- run -u https://example.com -y
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
---
|
|
384
|
+
|
|
385
|
+
## Research Mode
|
|
386
|
+
|
|
387
|
+
Use research mode to validate and compare discovery methods:
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
npm run start -- run -u https://example.com -y --research
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
This generates `research.json` with per-method efficiency:
|
|
394
|
+
|
|
395
|
+
```json
|
|
396
|
+
{
|
|
397
|
+
"next_getJSScript": [
|
|
398
|
+
"https://example.com/_next/static/chunks/main.js",
|
|
399
|
+
"https://example.com/_next/static/chunks/webpack.js"
|
|
400
|
+
],
|
|
401
|
+
"next_dynamicImports": ["https://example.com/_next/static/chunks/lazy-component.js"],
|
|
402
|
+
"next_promiseResolve": ["https://example.com/_next/static/chunks/pages/about.js"]
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
**Analysis tips:**
|
|
407
|
+
|
|
408
|
+
- **Unique discoveries**: Methods that find URLs no other method finds
|
|
409
|
+
- **Overlap**: Methods that discover the same URLs (candidates for removal)
|
|
410
|
+
- **Efficiency**: URLs found per method execution
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@js-recon/js-recon",
|
|
3
|
+
"version": "1.3.1-beta.2",
|
|
4
|
+
"description": "JS Recon Tool",
|
|
5
|
+
"main": "build/index.js",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"js-recon": "build/index.js"
|
|
9
|
+
},
|
|
10
|
+
"types": "build/index.d.ts",
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "rm -rf build/ && tsc",
|
|
13
|
+
"start": "node --max-old-space-size=8192 build/index.js",
|
|
14
|
+
"test": "node build/index.js -h",
|
|
15
|
+
"cleanup": "rm -rf build output .resp_cache.json endpoints.json extracted_urls{.txt,.json,-openapi.json} strings.json mapped{-openapi.json,.json,-openapi.postman_collection.json} analyze.json test{.yaml,.js} shriyanss-js-recon-*.tgz js-recon.db report.{html,md} js_recon_run_output *_test.js extracted/ research.json results* out.* && tsc"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [],
|
|
18
|
+
"author": "Shriyans Sudhi",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@anthropic-ai/sdk": "^0.102.0",
|
|
22
|
+
"@aws-sdk/client-api-gateway": "^3.958.0",
|
|
23
|
+
"@babel/parser": "^7.28.5",
|
|
24
|
+
"@babel/traverse": "^7.28.5",
|
|
25
|
+
"@babel/types": "^7.27.6",
|
|
26
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
27
|
+
"@types/chalk": "^0.4.31",
|
|
28
|
+
"@types/cli-progress": "^3.11.6",
|
|
29
|
+
"better-sqlite3": "^12.5.0",
|
|
30
|
+
"blessed": "^0.1.81",
|
|
31
|
+
"chalk": "^5.6.2",
|
|
32
|
+
"cheerio": "^1.0.0",
|
|
33
|
+
"cli-highlight": "^2.1.11",
|
|
34
|
+
"cli-progress": "^3.12.0",
|
|
35
|
+
"commander": "^14.0.0",
|
|
36
|
+
"datatables.net": "^2.3.6",
|
|
37
|
+
"datatables.net-dt": "^2.3.6",
|
|
38
|
+
"esquery": "^1.6.0",
|
|
39
|
+
"fs": "^0.0.2",
|
|
40
|
+
"graphql": "^16.14.1",
|
|
41
|
+
"highlight.js": "^11.11.1",
|
|
42
|
+
"inquirer": "^12.6.3",
|
|
43
|
+
"marked": "^16.1.2",
|
|
44
|
+
"md5": "^2.3.0",
|
|
45
|
+
"ollama": "^0.6.3",
|
|
46
|
+
"openai": "^5.8.2",
|
|
47
|
+
"path": "^0.12.7",
|
|
48
|
+
"prettier": "^3.7.4",
|
|
49
|
+
"puppeteer": "^24.43.1",
|
|
50
|
+
"puppeteer-extra": "^3.3.6",
|
|
51
|
+
"puppeteer-extra-plugin-stealth": "^2.11.2",
|
|
52
|
+
"readline": "^1.3.0",
|
|
53
|
+
"ses": "^1.13.0",
|
|
54
|
+
"yaml": "^2.8.0",
|
|
55
|
+
"zod": "^3.23.8"
|
|
56
|
+
},
|
|
57
|
+
"repository": {
|
|
58
|
+
"type": "git",
|
|
59
|
+
"url": "git+https://github.com/shriyanss/js-recon.git"
|
|
60
|
+
},
|
|
61
|
+
"bugs": {
|
|
62
|
+
"url": "https://github.com/shriyanss/js-recon/issues"
|
|
63
|
+
},
|
|
64
|
+
"homepage": "https://github.com/shriyanss/js-recon#readme",
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@types/babel__traverse": "^7.28.0",
|
|
67
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
68
|
+
"@types/blessed": "^0.1.25",
|
|
69
|
+
"@types/graphql": "^14.2.3",
|
|
70
|
+
"@types/node": "^24.12.4",
|
|
71
|
+
"ts-node": "^10.9.2",
|
|
72
|
+
"tsconfig-paths": "^4.2.0",
|
|
73
|
+
"typescript": "^5.9.2"
|
|
74
|
+
}
|
|
75
|
+
}
|