@cdxgen/cdxgen 0.0.1 → 13.0.1
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 +921 -87
- package/bin/audit.js +239 -0
- package/bin/cdxgen.js +2335 -0
- package/bin/convert.js +220 -0
- package/bin/evinse.js +353 -0
- package/bin/hbom.js +504 -0
- package/bin/repl.js +2224 -0
- package/bin/sign.js +195 -0
- package/bin/tracebom.js +303 -0
- package/bin/validate.js +268 -0
- package/bin/verify.js +189 -0
- package/data/README.md +307 -0
- package/data/bom-1.4.schema.json +1605 -0
- package/data/bom-1.5.schema.json +3660 -0
- package/data/bom-1.6.schema.json +5511 -0
- package/data/bom-1.7.schema.json +6700 -0
- package/data/cbomosdb-queries.json +68 -0
- package/data/component-tags.json +339 -0
- package/data/container-knowledge-index.json +125 -0
- package/data/cosdb-queries.json +17 -0
- package/data/crypto-oid.json +1998 -0
- package/data/cryptography-defs.json +3793 -0
- package/data/cryptography-defs.schema.json +576 -0
- package/data/cyclonedx-2.0-bundled.schema.json +7182 -0
- package/data/frameworks-list.json +219 -0
- package/data/glibc-stdlib.json +117 -0
- package/data/gtfobins-index.json +6296 -0
- package/data/helpers/init.gradle +71 -0
- package/data/jsf-0.82.schema.json +211 -0
- package/data/known-licenses.json +82 -0
- package/data/lic-mapping.json +338 -0
- package/data/license-aliases.json +6624 -0
- package/data/license-db.json +39059 -0
- package/data/license-deprecations.json +302 -0
- package/data/lolbas-index.json +150 -0
- package/data/predictive-audit-allowlist.json +11 -0
- package/data/pypi-pkg-aliases.json +1199 -0
- package/data/python-stdlib.json +308 -0
- package/data/queries-darwin.json +193 -0
- package/data/queries-win.json +257 -0
- package/data/queries.json +268 -0
- package/data/ruby-known-modules.json +281 -0
- package/data/rules/ai-agent-governance.yaml +323 -0
- package/data/rules/ai-bom.yaml +268 -0
- package/data/rules/ai-oversight.yaml +186 -0
- package/data/rules/ai-provenance.yaml +92 -0
- package/data/rules/asar-archives.yaml +150 -0
- package/data/rules/cbom-security.yaml +165 -0
- package/data/rules/chrome-extensions.yaml +248 -0
- package/data/rules/ci-permissions.yaml +802 -0
- package/data/rules/container-risk.yaml +353 -0
- package/data/rules/dependency-sources.yaml +236 -0
- package/data/rules/golem-go.yaml +229 -0
- package/data/rules/hbom-compliance.yaml +325 -0
- package/data/rules/hbom-performance.yaml +307 -0
- package/data/rules/hbom-security.yaml +248 -0
- package/data/rules/host-topology.yaml +165 -0
- package/data/rules/mcp-servers.yaml +388 -0
- package/data/rules/obom-runtime.yaml +1776 -0
- package/data/rules/package-integrity.yaml +364 -0
- package/data/rules/rootfs-hardening.yaml +179 -0
- package/data/rules/vscode-extensions.yaml +237 -0
- package/data/spdx-export.schema.json +6794 -0
- package/data/spdx-license-list.json +7449 -0
- package/data/spdx-licenses.json +759 -0
- package/data/spdx.schema.json +819 -0
- package/data/templates/README.md +3 -0
- package/data/templates/asvs-4.0.3.cdx.json +2943 -0
- package/data/templates/asvs-5.0.cdx.json +3046 -0
- package/data/templates/bsimm-v13.cdx.json +1008 -0
- package/data/templates/masvs-2.0.0.cdx.json +225 -0
- package/data/templates/nist-ssdf-1.1.cdx.json +828 -0
- package/data/templates/pcissc-secure-slc-1.1.cdx.json +1027 -0
- package/data/templates/scvs-1.0.0.cdx.json +813 -0
- package/data/templates/ssaf-DRAFT-2023-11.cdx.json +127 -0
- package/data/vendor-alias.json +41967 -0
- package/data/wrapdb-releases.json +4227 -0
- package/index.cjs +15 -0
- package/lib/audit/index.js +2800 -0
- package/lib/audit/progress.js +114 -0
- package/lib/audit/reporters.js +937 -0
- package/lib/audit/scoring.js +560 -0
- package/lib/audit/targets.js +798 -0
- package/lib/cli/bomAssembly.js +1882 -0
- package/lib/cli/cliOptions.js +543 -0
- package/lib/cli/index.js +2759 -0
- package/lib/cli/jsBom.js +2087 -0
- package/lib/cli/jvmBom.js +1858 -0
- package/lib/cli/managedBom.js +2083 -0
- package/lib/cli/nativeBom.js +2125 -0
- package/lib/core/activity.js +1087 -0
- package/lib/core/env.js +719 -0
- package/lib/core/fs.js +1058 -0
- package/lib/core/httpClient.js +730 -0
- package/lib/core/logger.js +280 -0
- package/lib/core/parallel.js +323 -0
- package/lib/core/paths.js +70 -0
- package/lib/core/projectConfig.js +122 -0
- package/lib/core/propertySanitizer.js +174 -0
- package/lib/core/spdx.js +5 -0
- package/lib/core/state.js +59 -0
- package/lib/core/text.js +207 -0
- package/lib/core/ui.js +920 -0
- package/lib/core/urls.js +84 -0
- package/lib/ecosystems/asarutils.js +1636 -0
- package/lib/ecosystems/bunutils.js +402 -0
- package/lib/ecosystems/caxa.js +77 -0
- package/lib/ecosystems/chromextutils.js +1174 -0
- package/lib/ecosystems/cmakeResolver.js +587 -0
- package/lib/ecosystems/cppEvidence.js +305 -0
- package/lib/ecosystems/denoutils.js +1094 -0
- package/lib/ecosystems/dotnetutils.js +132 -0
- package/lib/ecosystems/ecosystems.js +2772 -0
- package/lib/ecosystems/golem.js +1807 -0
- package/lib/ecosystems/gradleutils.js +1048 -0
- package/lib/ecosystems/jsEvidence.js +317 -0
- package/lib/ecosystems/npmutils.js +586 -0
- package/lib/ecosystems/parsers-bazel.js +875 -0
- package/lib/ecosystems/parsers-dotnet.js +1430 -0
- package/lib/ecosystems/parsers-gleam.js +302 -0
- package/lib/ecosystems/parsers-go.js +818 -0
- package/lib/ecosystems/parsers-js.js +4222 -0
- package/lib/ecosystems/parsers-jvm.js +948 -0
- package/lib/ecosystems/parsers-misc.js +3191 -0
- package/lib/ecosystems/parsers-python.js +2070 -0
- package/lib/ecosystems/parsers-rust.js +1294 -0
- package/lib/ecosystems/parsers-zig.js +861 -0
- package/lib/ecosystems/pep770.js +341 -0
- package/lib/ecosystems/pylockutils.js +427 -0
- package/lib/ecosystems/pythonutils.js +1281 -0
- package/lib/ecosystems/registryProvenance.js +1003 -0
- package/lib/ecosystems/remote/huggingface.js +1343 -0
- package/lib/ecosystems/rubyutils.js +1629 -0
- package/lib/ecosystems/rusi.js +820 -0
- package/lib/ecosystems/sbtutils.js +972 -0
- package/lib/ecosystems/tea.js +607 -0
- package/lib/ecosystems/utils.js +583 -0
- package/lib/ecosystems/zigResolver.js +410 -0
- package/lib/evinser/db.js +145 -0
- package/lib/evinser/evinser.js +2362 -0
- package/lib/evinser/scalasem.js +65 -0
- package/lib/evinser/swiftsem.js +767 -0
- package/lib/helpers/annotationFormatter.js +84 -0
- package/lib/helpers/bomSigner.js +312 -0
- package/lib/helpers/exportUtils.js +160 -0
- package/lib/helpers/remote/dependency-track.js +117 -0
- package/lib/helpers/versutils.js +202 -0
- package/lib/helpers/vsixutils.js +1069 -0
- package/lib/inventory/agentFormulationParser.js +322 -0
- package/lib/inventory/aiCollector.js +2140 -0
- package/lib/inventory/aiInventory.js +414 -0
- package/lib/inventory/aiModelVariants.js +121 -0
- package/lib/inventory/aiOversightCollector.js +661 -0
- package/lib/inventory/aiProvenanceCollector.js +822 -0
- package/lib/inventory/analyzer.js +6089 -0
- package/lib/inventory/analyzerScope.js +807 -0
- package/lib/inventory/astWorker.js +20 -0
- package/lib/inventory/atomUtils.js +1092 -0
- package/lib/inventory/auditCategories.js +192 -0
- package/lib/inventory/bomUtils.js +369 -0
- package/lib/inventory/cacheCommands.js +182 -0
- package/lib/inventory/cacheDir.js +104 -0
- package/lib/inventory/cbomutils.js +590 -0
- package/lib/inventory/cdxrs.js +434 -0
- package/lib/inventory/ciParsers/azurePipelines.js +295 -0
- package/lib/inventory/ciParsers/circleCi.js +286 -0
- package/lib/inventory/ciParsers/common.js +24 -0
- package/lib/inventory/ciParsers/githubActions.js +2434 -0
- package/lib/inventory/ciParsers/gitlabCi.js +213 -0
- package/lib/inventory/ciParsers/jenkins.js +180 -0
- package/lib/inventory/citations.js +234 -0
- package/lib/inventory/communityAiConfigParser.js +756 -0
- package/lib/inventory/containerRisk.js +204 -0
- package/lib/inventory/cryptoAlgorithmFamily.js +258 -0
- package/lib/inventory/deps.js +807 -0
- package/lib/inventory/depsUtils.js +588 -0
- package/lib/inventory/display.js +2128 -0
- package/lib/inventory/dosai.js +601 -0
- package/lib/inventory/dosaiParsers.js +154 -0
- package/lib/inventory/dynamic.js +145 -0
- package/lib/inventory/envcontext.js +1793 -0
- package/lib/inventory/evidenceUtils.js +774 -0
- package/lib/inventory/fetchBatch.js +779 -0
- package/lib/inventory/fetchRate.js +255 -0
- package/lib/inventory/forgeEnricher.js +300 -0
- package/lib/inventory/formulationParsers.js +422 -0
- package/lib/inventory/gtfobins.js +339 -0
- package/lib/inventory/hbom.js +719 -0
- package/lib/inventory/hbomAnalysis.js +310 -0
- package/lib/inventory/hbomLoader.js +35 -0
- package/lib/inventory/hostTopology.js +835 -0
- package/lib/inventory/inventoryStats.js +100 -0
- package/lib/inventory/jsonLike.js +121 -0
- package/lib/inventory/licenseEnhancer.js +918 -0
- package/lib/inventory/lolbas.js +285 -0
- package/lib/inventory/mcp.js +253 -0
- package/lib/inventory/mcpConfigParser.js +683 -0
- package/lib/inventory/mcpDiscovery.js +112 -0
- package/lib/inventory/mcpPinning.js +209 -0
- package/lib/inventory/osPackageResolver.js +493 -0
- package/lib/inventory/osinfo.js +383 -0
- package/lib/inventory/osqueryTransform.js +274 -0
- package/lib/inventory/plugins.js +466 -0
- package/lib/inventory/protobom.js +231 -0
- package/lib/inventory/protobomLoader.js +43 -0
- package/lib/inventory/provenanceUtils.js +224 -0
- package/lib/inventory/purl.js +749 -0
- package/lib/inventory/rustFormulationParser.js +339 -0
- package/lib/inventory/sbomDocument.js +340 -0
- package/lib/inventory/source.js +1488 -0
- package/lib/inventory/spdx.js +361 -0
- package/lib/inventory/spdxExpression.js +512 -0
- package/lib/inventory/spdxUtils.js +107 -0
- package/lib/inventory/table.js +267 -0
- package/lib/inventory/traceRunner.js +439 -0
- package/lib/inventory/unicodeScan.js +147 -0
- package/lib/managers/binary.js +3459 -0
- package/lib/managers/containerutils.js +125 -0
- package/lib/managers/docker.js +2145 -0
- package/lib/managers/dockerConnection.js +162 -0
- package/lib/managers/oci.js +704 -0
- package/lib/managers/piptree.js +267 -0
- package/lib/parsers/cmakeCache.js +199 -0
- package/lib/parsers/gguf.js +492 -0
- package/lib/parsers/gitAiNotes.js +233 -0
- package/lib/parsers/gitmodules.js +239 -0
- package/lib/parsers/htmlExtract.js +610 -0
- package/lib/parsers/huggingfaceManifest.js +551 -0
- package/lib/parsers/huggingfaceUtils.js +506 -0
- package/lib/parsers/iri.js +618 -0
- package/lib/parsers/npmrc.js +99 -0
- package/lib/parsers/ollama.js +101 -0
- package/lib/parsers/xml.js +841 -0
- package/lib/server/openapi.yaml +433 -0
- package/lib/server/server.js +616 -0
- package/lib/stages/postgen/annotator.js +977 -0
- package/lib/stages/postgen/auditBom.js +468 -0
- package/lib/stages/postgen/postgen.js +1239 -0
- package/lib/stages/postgen/ruleEngine.js +731 -0
- package/lib/stages/postgen/sortBom.js +195 -0
- package/lib/stages/postgen/spdxConverter.js +796 -0
- package/lib/stages/postgen/specVersionCompat.js +703 -0
- package/lib/stages/pregen/envAudit.js +388 -0
- package/lib/stages/pregen/pregen.js +637 -0
- package/lib/third-party/README.md +9 -0
- package/lib/third-party/arborist/CHANGELOG.md +1109 -0
- package/lib/third-party/arborist/LICENSE.md +20 -0
- package/lib/third-party/arborist/README.md +315 -0
- package/lib/third-party/arborist/lib/arborist/index.js +258 -0
- package/lib/third-party/arborist/lib/arborist/load-actual.js +605 -0
- package/lib/third-party/arborist/lib/arborist/load-virtual.js +300 -0
- package/lib/third-party/arborist/lib/bin-links.js +120 -0
- package/lib/third-party/arborist/lib/calc-dep-flags.js +130 -0
- package/lib/third-party/arborist/lib/case-insensitive-map.js +51 -0
- package/lib/third-party/arborist/lib/consistent-resolve.js +42 -0
- package/lib/third-party/arborist/lib/debug.js +50 -0
- package/lib/third-party/arborist/lib/dep-valid.js +190 -0
- package/lib/third-party/arborist/lib/edge.js +417 -0
- package/lib/third-party/arborist/lib/from-path.js +36 -0
- package/lib/third-party/arborist/lib/gather-dep-set.js +43 -0
- package/lib/third-party/arborist/lib/index.js +22 -0
- package/lib/third-party/arborist/lib/inventory.js +138 -0
- package/lib/third-party/arborist/lib/link.js +169 -0
- package/lib/third-party/arborist/lib/node.js +1673 -0
- package/lib/third-party/arborist/lib/npm-extension.js +45 -0
- package/lib/third-party/arborist/lib/override-resolves.js +11 -0
- package/lib/third-party/arborist/lib/override-set.js +319 -0
- package/lib/third-party/arborist/lib/package-extensions.js +289 -0
- package/lib/third-party/arborist/lib/printable.js +210 -0
- package/lib/third-party/arborist/lib/proc-log.js +30 -0
- package/lib/third-party/arborist/lib/realpath.js +100 -0
- package/lib/third-party/arborist/lib/relpath.js +4 -0
- package/lib/third-party/arborist/lib/shrinkwrap.js +1291 -0
- package/lib/third-party/arborist/lib/spec-from-lock.js +34 -0
- package/lib/third-party/arborist/lib/tree-check.js +165 -0
- package/lib/third-party/arborist/lib/validate-npm-package-name.js +107 -0
- package/lib/third-party/arborist/lib/version-from-tgz.js +51 -0
- package/lib/third-party/arborist/lib/yarn-lock.js +397 -0
- package/lib/validator/bomValidator.js +985 -0
- package/lib/validator/complianceEngine.js +241 -0
- package/lib/validator/complianceRules.js +1680 -0
- package/lib/validator/generated/runtime.mjs +17 -0
- package/lib/validator/generated/validate-1.6.mjs +21258 -0
- package/lib/validator/generated/validate-1.7.mjs +24803 -0
- package/lib/validator/generated/validate-2.0.mjs +22931 -0
- package/lib/validator/index.js +246 -0
- package/lib/validator/reporters/annotations.js +142 -0
- package/lib/validator/reporters/console.js +160 -0
- package/lib/validator/reporters/index.js +41 -0
- package/lib/validator/reporters/json.js +37 -0
- package/lib/validator/reporters/sarif.js +184 -0
- package/package.json +209 -26
- package/types/bin/audit.d.ts +3 -0
- package/types/bin/audit.d.ts.map +1 -0
- package/types/bin/cdxgen.d.ts +3 -0
- package/types/bin/cdxgen.d.ts.map +1 -0
- package/types/bin/convert.d.ts +3 -0
- package/types/bin/convert.d.ts.map +1 -0
- package/types/bin/evinse.d.ts +3 -0
- package/types/bin/evinse.d.ts.map +1 -0
- package/types/bin/hbom.d.ts +3 -0
- package/types/bin/hbom.d.ts.map +1 -0
- package/types/bin/repl.d.ts +3 -0
- package/types/bin/repl.d.ts.map +1 -0
- package/types/bin/sign.d.ts +3 -0
- package/types/bin/sign.d.ts.map +1 -0
- package/types/bin/tracebom.d.ts +3 -0
- package/types/bin/tracebom.d.ts.map +1 -0
- package/types/bin/validate.d.ts +14 -0
- package/types/bin/validate.d.ts.map +1 -0
- package/types/bin/verify.d.ts +3 -0
- package/types/bin/verify.d.ts.map +1 -0
- package/types/lib/audit/index.d.ts +153 -0
- package/types/lib/audit/index.d.ts.map +1 -0
- package/types/lib/audit/progress.d.ts +31 -0
- package/types/lib/audit/progress.d.ts.map +1 -0
- package/types/lib/audit/reporters.d.ts +62 -0
- package/types/lib/audit/reporters.d.ts.map +1 -0
- package/types/lib/audit/scoring.d.ts +36 -0
- package/types/lib/audit/scoring.d.ts.map +1 -0
- package/types/lib/audit/targets.d.ts +77 -0
- package/types/lib/audit/targets.d.ts.map +1 -0
- package/types/lib/cli/bomAssembly.d.ts +329 -0
- package/types/lib/cli/bomAssembly.d.ts.map +1 -0
- package/types/lib/cli/cliOptions.d.ts +156 -0
- package/types/lib/cli/cliOptions.d.ts.map +1 -0
- package/types/lib/cli/index.d.ts +107 -0
- package/types/lib/cli/index.d.ts.map +1 -0
- package/types/lib/cli/jsBom.d.ts +94 -0
- package/types/lib/cli/jsBom.d.ts.map +1 -0
- package/types/lib/cli/jvmBom.d.ts +54 -0
- package/types/lib/cli/jvmBom.d.ts.map +1 -0
- package/types/lib/cli/managedBom.d.ts +105 -0
- package/types/lib/cli/managedBom.d.ts.map +1 -0
- package/types/lib/cli/nativeBom.d.ts +143 -0
- package/types/lib/cli/nativeBom.d.ts.map +1 -0
- package/types/lib/core/activity.d.ts +178 -0
- package/types/lib/core/activity.d.ts.map +1 -0
- package/types/lib/core/env.d.ts +192 -0
- package/types/lib/core/env.d.ts.map +1 -0
- package/types/lib/core/fs.d.ts +158 -0
- package/types/lib/core/fs.d.ts.map +1 -0
- package/types/lib/core/httpClient.d.ts +149 -0
- package/types/lib/core/httpClient.d.ts.map +1 -0
- package/types/lib/core/logger.d.ts +50 -0
- package/types/lib/core/logger.d.ts.map +1 -0
- package/types/lib/core/parallel.d.ts +95 -0
- package/types/lib/core/parallel.d.ts.map +1 -0
- package/types/lib/core/paths.d.ts +36 -0
- package/types/lib/core/paths.d.ts.map +1 -0
- package/types/lib/core/projectConfig.d.ts +23 -0
- package/types/lib/core/projectConfig.d.ts.map +1 -0
- package/types/lib/core/propertySanitizer.d.ts +23 -0
- package/types/lib/core/propertySanitizer.d.ts.map +1 -0
- package/types/lib/core/spdx.d.ts +5 -0
- package/types/lib/core/spdx.d.ts.map +1 -0
- package/types/lib/core/state.d.ts +20 -0
- package/types/lib/core/state.d.ts.map +1 -0
- package/types/lib/core/text.d.ts +78 -0
- package/types/lib/core/text.d.ts.map +1 -0
- package/types/lib/core/ui.d.ts +87 -0
- package/types/lib/core/ui.d.ts.map +1 -0
- package/types/lib/core/urls.d.ts +43 -0
- package/types/lib/core/urls.d.ts.map +1 -0
- package/types/lib/ecosystems/asarutils.d.ts +71 -0
- package/types/lib/ecosystems/asarutils.d.ts.map +1 -0
- package/types/lib/ecosystems/bunutils.d.ts +38 -0
- package/types/lib/ecosystems/bunutils.d.ts.map +1 -0
- package/types/lib/ecosystems/caxa.d.ts +8 -0
- package/types/lib/ecosystems/caxa.d.ts.map +1 -0
- package/types/lib/ecosystems/chromextutils.d.ts +97 -0
- package/types/lib/ecosystems/chromextutils.d.ts.map +1 -0
- package/types/lib/ecosystems/cmakeResolver.d.ts +176 -0
- package/types/lib/ecosystems/cmakeResolver.d.ts.map +1 -0
- package/types/lib/ecosystems/cppEvidence.d.ts +35 -0
- package/types/lib/ecosystems/cppEvidence.d.ts.map +1 -0
- package/types/lib/ecosystems/denoutils.d.ts +76 -0
- package/types/lib/ecosystems/denoutils.d.ts.map +1 -0
- package/types/lib/ecosystems/dotnetutils.d.ts +45 -0
- package/types/lib/ecosystems/dotnetutils.d.ts.map +1 -0
- package/types/lib/ecosystems/ecosystems.d.ts +279 -0
- package/types/lib/ecosystems/ecosystems.d.ts.map +1 -0
- package/types/lib/ecosystems/golem.d.ts +60 -0
- package/types/lib/ecosystems/golem.d.ts.map +1 -0
- package/types/lib/ecosystems/gradleutils.d.ts +139 -0
- package/types/lib/ecosystems/gradleutils.d.ts.map +1 -0
- package/types/lib/ecosystems/jsEvidence.d.ts +17 -0
- package/types/lib/ecosystems/jsEvidence.d.ts.map +1 -0
- package/types/lib/ecosystems/npmutils.d.ts +183 -0
- package/types/lib/ecosystems/npmutils.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-bazel.d.ts +36 -0
- package/types/lib/ecosystems/parsers-bazel.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts +116 -0
- package/types/lib/ecosystems/parsers-dotnet.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-gleam.d.ts +33 -0
- package/types/lib/ecosystems/parsers-gleam.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-go.d.ts +92 -0
- package/types/lib/ecosystems/parsers-go.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-js.d.ts +242 -0
- package/types/lib/ecosystems/parsers-js.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-jvm.d.ts +100 -0
- package/types/lib/ecosystems/parsers-jvm.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-misc.d.ts +450 -0
- package/types/lib/ecosystems/parsers-misc.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-python.d.ts +145 -0
- package/types/lib/ecosystems/parsers-python.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-rust.d.ts +56 -0
- package/types/lib/ecosystems/parsers-rust.d.ts.map +1 -0
- package/types/lib/ecosystems/parsers-zig.d.ts +83 -0
- package/types/lib/ecosystems/parsers-zig.d.ts.map +1 -0
- package/types/lib/ecosystems/pep770.d.ts +38 -0
- package/types/lib/ecosystems/pep770.d.ts.map +1 -0
- package/types/lib/ecosystems/pylockutils.d.ts +68 -0
- package/types/lib/ecosystems/pylockutils.d.ts.map +1 -0
- package/types/lib/ecosystems/pythonutils.d.ts +70 -0
- package/types/lib/ecosystems/pythonutils.d.ts.map +1 -0
- package/types/lib/ecosystems/registryProvenance.d.ts +26 -0
- package/types/lib/ecosystems/registryProvenance.d.ts.map +1 -0
- package/types/lib/ecosystems/remote/huggingface.d.ts +31 -0
- package/types/lib/ecosystems/remote/huggingface.d.ts.map +1 -0
- package/types/lib/ecosystems/rubyutils.d.ts +182 -0
- package/types/lib/ecosystems/rubyutils.d.ts.map +1 -0
- package/types/lib/ecosystems/rusi.d.ts +40 -0
- package/types/lib/ecosystems/rusi.d.ts.map +1 -0
- package/types/lib/ecosystems/sbtutils.d.ts +179 -0
- package/types/lib/ecosystems/sbtutils.d.ts.map +1 -0
- package/types/lib/ecosystems/tea.d.ts +180 -0
- package/types/lib/ecosystems/tea.d.ts.map +1 -0
- package/types/lib/ecosystems/utils.d.ts +41 -0
- package/types/lib/ecosystems/utils.d.ts.map +1 -0
- package/types/lib/ecosystems/zigResolver.d.ts +70 -0
- package/types/lib/ecosystems/zigResolver.d.ts.map +1 -0
- package/types/lib/evinser/db.d.ts +17 -0
- package/types/lib/evinser/db.d.ts.map +1 -0
- package/types/lib/evinser/evinser.d.ts +354 -0
- package/types/lib/evinser/evinser.d.ts.map +1 -0
- package/types/lib/evinser/scalasem.d.ts +15 -0
- package/types/lib/evinser/scalasem.d.ts.map +1 -0
- package/types/lib/evinser/swiftsem.d.ts +103 -0
- package/types/lib/evinser/swiftsem.d.ts.map +1 -0
- package/types/lib/helpers/annotationFormatter.d.ts +23 -0
- package/types/lib/helpers/annotationFormatter.d.ts.map +1 -0
- package/types/lib/helpers/bomSigner.d.ts +28 -0
- package/types/lib/helpers/bomSigner.d.ts.map +1 -0
- package/types/lib/helpers/exportUtils.d.ts +52 -0
- package/types/lib/helpers/exportUtils.d.ts.map +1 -0
- package/types/lib/helpers/remote/dependency-track.d.ts +23 -0
- package/types/lib/helpers/remote/dependency-track.d.ts.map +1 -0
- package/types/lib/helpers/versutils.d.ts +8 -0
- package/types/lib/helpers/versutils.d.ts.map +1 -0
- package/types/lib/helpers/vsixutils.d.ts +130 -0
- package/types/lib/helpers/vsixutils.d.ts.map +1 -0
- package/types/lib/inventory/agentFormulationParser.d.ts +21 -0
- package/types/lib/inventory/agentFormulationParser.d.ts.map +1 -0
- package/types/lib/inventory/aiCollector.d.ts +61 -0
- package/types/lib/inventory/aiCollector.d.ts.map +1 -0
- package/types/lib/inventory/aiInventory.d.ts +103 -0
- package/types/lib/inventory/aiInventory.d.ts.map +1 -0
- package/types/lib/inventory/aiModelVariants.d.ts +31 -0
- package/types/lib/inventory/aiModelVariants.d.ts.map +1 -0
- package/types/lib/inventory/aiOversightCollector.d.ts +28 -0
- package/types/lib/inventory/aiOversightCollector.d.ts.map +1 -0
- package/types/lib/inventory/aiProvenanceCollector.d.ts +13 -0
- package/types/lib/inventory/aiProvenanceCollector.d.ts.map +1 -0
- package/types/lib/inventory/analyzer.d.ts +157 -0
- package/types/lib/inventory/analyzer.d.ts.map +1 -0
- package/types/lib/inventory/analyzerScope.d.ts +106 -0
- package/types/lib/inventory/analyzerScope.d.ts.map +1 -0
- package/types/lib/inventory/astWorker.d.ts +9 -0
- package/types/lib/inventory/astWorker.d.ts.map +1 -0
- package/types/lib/inventory/atomUtils.d.ts +159 -0
- package/types/lib/inventory/atomUtils.d.ts.map +1 -0
- package/types/lib/inventory/auditCategories.d.ts +80 -0
- package/types/lib/inventory/auditCategories.d.ts.map +1 -0
- package/types/lib/inventory/bomUtils.d.ts +145 -0
- package/types/lib/inventory/bomUtils.d.ts.map +1 -0
- package/types/lib/inventory/cacheCommands.d.ts +28 -0
- package/types/lib/inventory/cacheCommands.d.ts.map +1 -0
- package/types/lib/inventory/cacheDir.d.ts +55 -0
- package/types/lib/inventory/cacheDir.d.ts.map +1 -0
- package/types/lib/inventory/cbomutils.d.ts +37 -0
- package/types/lib/inventory/cbomutils.d.ts.map +1 -0
- package/types/lib/inventory/cdxrs.d.ts +90 -0
- package/types/lib/inventory/cdxrs.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/azurePipelines.d.ts +27 -0
- package/types/lib/inventory/ciParsers/azurePipelines.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/circleCi.d.ts +27 -0
- package/types/lib/inventory/ciParsers/circleCi.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/common.d.ts +11 -0
- package/types/lib/inventory/ciParsers/common.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/githubActions.d.ts +38 -0
- package/types/lib/inventory/ciParsers/githubActions.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/gitlabCi.d.ts +26 -0
- package/types/lib/inventory/ciParsers/gitlabCi.d.ts.map +1 -0
- package/types/lib/inventory/ciParsers/jenkins.d.ts +26 -0
- package/types/lib/inventory/ciParsers/jenkins.d.ts.map +1 -0
- package/types/lib/inventory/citations.d.ts +90 -0
- package/types/lib/inventory/citations.d.ts.map +1 -0
- package/types/lib/inventory/communityAiConfigParser.d.ts +14 -0
- package/types/lib/inventory/communityAiConfigParser.d.ts.map +1 -0
- package/types/lib/inventory/containerRisk.d.ts +20 -0
- package/types/lib/inventory/containerRisk.d.ts.map +1 -0
- package/types/lib/inventory/cryptoAlgorithmFamily.d.ts +37 -0
- package/types/lib/inventory/cryptoAlgorithmFamily.d.ts.map +1 -0
- package/types/lib/inventory/deps.d.ts +140 -0
- package/types/lib/inventory/deps.d.ts.map +1 -0
- package/types/lib/inventory/depsUtils.d.ts +74 -0
- package/types/lib/inventory/depsUtils.d.ts.map +1 -0
- package/types/lib/inventory/display.d.ts +227 -0
- package/types/lib/inventory/display.d.ts.map +1 -0
- package/types/lib/inventory/dosai.d.ts +130 -0
- package/types/lib/inventory/dosai.d.ts.map +1 -0
- package/types/lib/inventory/dosaiParsers.d.ts +59 -0
- package/types/lib/inventory/dosaiParsers.d.ts.map +1 -0
- package/types/lib/inventory/dynamic.d.ts +25 -0
- package/types/lib/inventory/dynamic.d.ts.map +1 -0
- package/types/lib/inventory/envcontext.d.ts +377 -0
- package/types/lib/inventory/envcontext.d.ts.map +1 -0
- package/types/lib/inventory/evidenceUtils.d.ts +74 -0
- package/types/lib/inventory/evidenceUtils.d.ts.map +1 -0
- package/types/lib/inventory/fetchBatch.d.ts +127 -0
- package/types/lib/inventory/fetchBatch.d.ts.map +1 -0
- package/types/lib/inventory/fetchRate.d.ts +118 -0
- package/types/lib/inventory/fetchRate.d.ts.map +1 -0
- package/types/lib/inventory/forgeEnricher.d.ts +31 -0
- package/types/lib/inventory/forgeEnricher.d.ts.map +1 -0
- package/types/lib/inventory/formulationParsers.d.ts +50 -0
- package/types/lib/inventory/formulationParsers.d.ts.map +1 -0
- package/types/lib/inventory/gtfobins.d.ts +27 -0
- package/types/lib/inventory/gtfobins.d.ts.map +1 -0
- package/types/lib/inventory/hbom.d.ts +58 -0
- package/types/lib/inventory/hbom.d.ts.map +1 -0
- package/types/lib/inventory/hbomAnalysis.d.ts +56 -0
- package/types/lib/inventory/hbomAnalysis.d.ts.map +1 -0
- package/types/lib/inventory/hbomLoader.d.ts +7 -0
- package/types/lib/inventory/hbomLoader.d.ts.map +1 -0
- package/types/lib/inventory/hostTopology.d.ts +47 -0
- package/types/lib/inventory/hostTopology.d.ts.map +1 -0
- package/types/lib/inventory/inventoryStats.d.ts +42 -0
- package/types/lib/inventory/inventoryStats.d.ts.map +1 -0
- package/types/lib/inventory/jsonLike.d.ts +23 -0
- package/types/lib/inventory/jsonLike.d.ts.map +1 -0
- package/types/lib/inventory/licenseEnhancer.d.ts +70 -0
- package/types/lib/inventory/licenseEnhancer.d.ts.map +1 -0
- package/types/lib/inventory/lolbas.d.ts +16 -0
- package/types/lib/inventory/lolbas.d.ts.map +1 -0
- package/types/lib/inventory/mcp.d.ts +29 -0
- package/types/lib/inventory/mcp.d.ts.map +1 -0
- package/types/lib/inventory/mcpConfigParser.d.ts +20 -0
- package/types/lib/inventory/mcpConfigParser.d.ts.map +1 -0
- package/types/lib/inventory/mcpDiscovery.d.ts +33 -0
- package/types/lib/inventory/mcpDiscovery.d.ts.map +1 -0
- package/types/lib/inventory/mcpPinning.d.ts +11 -0
- package/types/lib/inventory/mcpPinning.d.ts.map +1 -0
- package/types/lib/inventory/osPackageResolver.d.ts +49 -0
- package/types/lib/inventory/osPackageResolver.d.ts.map +1 -0
- package/types/lib/inventory/osinfo.d.ts +201 -0
- package/types/lib/inventory/osinfo.d.ts.map +1 -0
- package/types/lib/inventory/osqueryTransform.d.ts +84 -0
- package/types/lib/inventory/osqueryTransform.d.ts.map +1 -0
- package/types/lib/inventory/plugins.d.ts +58 -0
- package/types/lib/inventory/plugins.d.ts.map +1 -0
- package/types/lib/inventory/protobom.d.ts +71 -0
- package/types/lib/inventory/protobom.d.ts.map +1 -0
- package/types/lib/inventory/protobomLoader.d.ts +17 -0
- package/types/lib/inventory/protobomLoader.d.ts.map +1 -0
- package/types/lib/inventory/provenanceUtils.d.ts +98 -0
- package/types/lib/inventory/provenanceUtils.d.ts.map +1 -0
- package/types/lib/inventory/purl.d.ts +313 -0
- package/types/lib/inventory/purl.d.ts.map +1 -0
- package/types/lib/inventory/rustFormulationParser.d.ts +17 -0
- package/types/lib/inventory/rustFormulationParser.d.ts.map +1 -0
- package/types/lib/inventory/sbomDocument.d.ts +59 -0
- package/types/lib/inventory/sbomDocument.d.ts.map +1 -0
- package/types/lib/inventory/source.d.ts +163 -0
- package/types/lib/inventory/source.d.ts.map +1 -0
- package/types/lib/inventory/spdx.d.ts +66 -0
- package/types/lib/inventory/spdx.d.ts.map +1 -0
- package/types/lib/inventory/spdxExpression.d.ts +58 -0
- package/types/lib/inventory/spdxExpression.d.ts.map +1 -0
- package/types/lib/inventory/spdxUtils.d.ts +12 -0
- package/types/lib/inventory/spdxUtils.d.ts.map +1 -0
- package/types/lib/inventory/table.d.ts +22 -0
- package/types/lib/inventory/table.d.ts.map +1 -0
- package/types/lib/inventory/traceRunner.d.ts +80 -0
- package/types/lib/inventory/traceRunner.d.ts.map +1 -0
- package/types/lib/inventory/unicodeScan.d.ts +46 -0
- package/types/lib/inventory/unicodeScan.d.ts.map +1 -0
- package/types/lib/managers/binary.d.ts +147 -0
- package/types/lib/managers/binary.d.ts.map +1 -0
- package/types/lib/managers/containerutils.d.ts +30 -0
- package/types/lib/managers/containerutils.d.ts.map +1 -0
- package/types/lib/managers/docker.d.ts +157 -0
- package/types/lib/managers/docker.d.ts.map +1 -0
- package/types/lib/managers/dockerConnection.d.ts +42 -0
- package/types/lib/managers/dockerConnection.d.ts.map +1 -0
- package/types/lib/managers/oci.d.ts +21 -0
- package/types/lib/managers/oci.d.ts.map +1 -0
- package/types/lib/managers/piptree.d.ts +13 -0
- package/types/lib/managers/piptree.d.ts.map +1 -0
- package/types/lib/parsers/cmakeCache.d.ts +70 -0
- package/types/lib/parsers/cmakeCache.d.ts.map +1 -0
- package/types/lib/parsers/gguf.d.ts +39 -0
- package/types/lib/parsers/gguf.d.ts.map +1 -0
- package/types/lib/parsers/gitAiNotes.d.ts +15 -0
- package/types/lib/parsers/gitAiNotes.d.ts.map +1 -0
- package/types/lib/parsers/gitmodules.d.ts +88 -0
- package/types/lib/parsers/gitmodules.d.ts.map +1 -0
- package/types/lib/parsers/htmlExtract.d.ts +34 -0
- package/types/lib/parsers/htmlExtract.d.ts.map +1 -0
- package/types/lib/parsers/huggingfaceManifest.d.ts +153 -0
- package/types/lib/parsers/huggingfaceManifest.d.ts.map +1 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts +155 -0
- package/types/lib/parsers/huggingfaceUtils.d.ts.map +1 -0
- package/types/lib/parsers/iri.d.ts +68 -0
- package/types/lib/parsers/iri.d.ts.map +1 -0
- package/types/lib/parsers/npmrc.d.ts +33 -0
- package/types/lib/parsers/npmrc.d.ts.map +1 -0
- package/types/lib/parsers/ollama.d.ts +22 -0
- package/types/lib/parsers/ollama.d.ts.map +1 -0
- package/types/lib/parsers/xml.d.ts +47 -0
- package/types/lib/parsers/xml.d.ts.map +1 -0
- package/types/lib/server/server.d.ts +51 -0
- package/types/lib/server/server.d.ts.map +1 -0
- package/types/lib/stages/postgen/annotator.d.ts +36 -0
- package/types/lib/stages/postgen/annotator.d.ts.map +1 -0
- package/types/lib/stages/postgen/auditBom.d.ts +92 -0
- package/types/lib/stages/postgen/auditBom.d.ts.map +1 -0
- package/types/lib/stages/postgen/postgen.d.ts +59 -0
- package/types/lib/stages/postgen/postgen.d.ts.map +1 -0
- package/types/lib/stages/postgen/ruleEngine.d.ts +18 -0
- package/types/lib/stages/postgen/ruleEngine.d.ts.map +1 -0
- package/types/lib/stages/postgen/sortBom.d.ts +34 -0
- package/types/lib/stages/postgen/sortBom.d.ts.map +1 -0
- package/types/lib/stages/postgen/spdxConverter.d.ts +11 -0
- package/types/lib/stages/postgen/spdxConverter.d.ts.map +1 -0
- package/types/lib/stages/postgen/specVersionCompat.d.ts +71 -0
- package/types/lib/stages/postgen/specVersionCompat.d.ts.map +1 -0
- package/types/lib/stages/pregen/envAudit.d.ts +14 -0
- package/types/lib/stages/pregen/envAudit.d.ts.map +1 -0
- package/types/lib/stages/pregen/pregen.d.ts +59 -0
- package/types/lib/stages/pregen/pregen.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/arborist/index.d.ts +47 -0
- package/types/lib/third-party/arborist/lib/arborist/index.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts +4 -0
- package/types/lib/third-party/arborist/lib/arborist/load-actual.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts +4 -0
- package/types/lib/third-party/arborist/lib/arborist/load-virtual.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/bin-links.d.ts +18 -0
- package/types/lib/third-party/arborist/lib/bin-links.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/calc-dep-flags.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/calc-dep-flags.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts +9 -0
- package/types/lib/third-party/arborist/lib/case-insensitive-map.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/consistent-resolve.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/consistent-resolve.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/debug.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/debug.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/dep-valid.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/dep-valid.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/edge.d.ts +46 -0
- package/types/lib/third-party/arborist/lib/edge.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/from-path.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/from-path.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/gather-dep-set.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/index.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/index.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/inventory.d.ts +14 -0
- package/types/lib/third-party/arborist/lib/inventory.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/link.d.ts +18 -0
- package/types/lib/third-party/arborist/lib/link.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/node.d.ts +112 -0
- package/types/lib/third-party/arborist/lib/node.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/npm-extension.d.ts +18 -0
- package/types/lib/third-party/arborist/lib/npm-extension.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/override-resolves.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/override-resolves.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/override-set.d.ts +27 -0
- package/types/lib/third-party/arborist/lib/override-set.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/package-extensions.d.ts +36 -0
- package/types/lib/third-party/arborist/lib/package-extensions.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/printable.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/printable.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/proc-log.d.ts +20 -0
- package/types/lib/third-party/arborist/lib/proc-log.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/realpath.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/realpath.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/relpath.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/relpath.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts +54 -0
- package/types/lib/third-party/arborist/lib/shrinkwrap.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/spec-from-lock.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/spec-from-lock.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/tree-check.d.ts +3 -0
- package/types/lib/third-party/arborist/lib/tree-check.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/validate-npm-package-name.d.ts +13 -0
- package/types/lib/third-party/arborist/lib/validate-npm-package-name.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts +6 -0
- package/types/lib/third-party/arborist/lib/version-from-tgz.d.ts.map +1 -0
- package/types/lib/third-party/arborist/lib/yarn-lock.d.ts +35 -0
- package/types/lib/third-party/arborist/lib/yarn-lock.d.ts.map +1 -0
- package/types/lib/validator/bomValidator.d.ts +40 -0
- package/types/lib/validator/bomValidator.d.ts.map +1 -0
- package/types/lib/validator/complianceEngine.d.ts +72 -0
- package/types/lib/validator/complianceEngine.d.ts.map +1 -0
- package/types/lib/validator/complianceRules.d.ts +61 -0
- package/types/lib/validator/complianceRules.d.ts.map +1 -0
- package/types/lib/validator/index.d.ts +101 -0
- package/types/lib/validator/index.d.ts.map +1 -0
- package/types/lib/validator/reporters/annotations.d.ts +37 -0
- package/types/lib/validator/reporters/annotations.d.ts.map +1 -0
- package/types/lib/validator/reporters/console.d.ts +34 -0
- package/types/lib/validator/reporters/console.d.ts.map +1 -0
- package/types/lib/validator/reporters/index.d.ts +30 -0
- package/types/lib/validator/reporters/index.d.ts.map +1 -0
- package/types/lib/validator/reporters/json.d.ts +11 -0
- package/types/lib/validator/reporters/json.d.ts.map +1 -0
- package/types/lib/validator/reporters/sarif.d.ts +22 -0
- package/types/lib/validator/reporters/sarif.d.ts.map +1 -0
- package/mod.d.ts +0 -7
- package/mod.js +0 -22
|
@@ -0,0 +1,779 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Batched registry HTTP, via `cdxrs fetch` when it is available and a JS pool
|
|
3
|
+
* otherwise.
|
|
4
|
+
*
|
|
5
|
+
* The registry metadata functions in `lib/ecosystems/ecosystems.js` know every
|
|
6
|
+
* URL they are going to need before they need any of them, but fetch them one
|
|
7
|
+
* at a time with an `await` in a `for` body. That is the cost this module
|
|
8
|
+
* removes: the URLs are handed off in a single batch, fetched concurrently with
|
|
9
|
+
* a shared per-host rate policy, and returned as a map that the existing loops
|
|
10
|
+
* read instead of the network.
|
|
11
|
+
*
|
|
12
|
+
* There is one policy layer (`fetchRate.js`, mirrored by the Rust `rate.rs`)
|
|
13
|
+
* and two transports. When the `cdxrs` binary is available it is preferred,
|
|
14
|
+
* because it brings an on-disk conditional cache (D26) the JS pool does not
|
|
15
|
+
* have. When it is absent, disabled, or unusable, the JS pool runs every
|
|
16
|
+
* request through `cdxgenAgent` so the secure-mode host allowlist, the
|
|
17
|
+
* activity recorder and the test cassette interceptor all still apply.
|
|
18
|
+
*
|
|
19
|
+
* Two properties are deliberate and load-bearing:
|
|
20
|
+
*
|
|
21
|
+
* 1. **No field derivation happens here or in Rust.** Both transports return
|
|
22
|
+
* registry documents verbatim; every `p.description`, `p.license`,
|
|
23
|
+
* provenance property and SPDX lookup is still computed by the same
|
|
24
|
+
* JavaScript that computes it on the serial path. Neither transport can
|
|
25
|
+
* therefore produce a different SBOM — both can only produce the same one
|
|
26
|
+
* sooner. An earlier design derived fields in Rust and diverged from the
|
|
27
|
+
* JS on all three registries it covered.
|
|
28
|
+
*
|
|
29
|
+
* 2. **Fallback is per URL, not per run.** A URL that the batch could not
|
|
30
|
+
* resolve for a transport reason is simply absent from the map, and the
|
|
31
|
+
* caller's own `cdxgenAgent.get` runs for it exactly as before. A URL that
|
|
32
|
+
* resolved to a definite HTTP error is recorded as such, so the caller does
|
|
33
|
+
* not re-request it only to get the same 404.
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
import {
|
|
37
|
+
cdxgenAgent,
|
|
38
|
+
DEBUG_MODE,
|
|
39
|
+
readEnvironmentVariable,
|
|
40
|
+
} from "../core/activity.js";
|
|
41
|
+
import { resolveCacheDir } from "./cacheDir.js";
|
|
42
|
+
import { cdxrsAvailable, runCdxrs } from "./cdxrs.js";
|
|
43
|
+
import {
|
|
44
|
+
credentialsFor,
|
|
45
|
+
DEFAULT_GLOBAL_CONCURRENCY,
|
|
46
|
+
makeSemaphore,
|
|
47
|
+
policyFor,
|
|
48
|
+
RateLimiter,
|
|
49
|
+
} from "./fetchRate.js";
|
|
50
|
+
|
|
51
|
+
/** Envelope version understood by this bridge; must match Rust's. */
|
|
52
|
+
const BATCH_SCHEMA_VERSION = 1;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Timeout for one batch. Registry I/O for a large project legitimately takes
|
|
56
|
+
* minutes on a cold cache, so this is far longer than the bridge default; both
|
|
57
|
+
* the Rust subprocess and each JS request bound themselves on their own.
|
|
58
|
+
*/
|
|
59
|
+
const DEFAULT_BATCH_TIMEOUT_MS = 600_000;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Maximum retry attempts for a transient failure (5xx, 429, transport errors).
|
|
63
|
+
* Matches the Rust client's `MAX_RETRIES` so the two transports have the same
|
|
64
|
+
* retry budget.
|
|
65
|
+
*/
|
|
66
|
+
const MAX_RETRIES = 3;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Cap for exponential backoff, including jitter. Matches `rate.rs`/`client.rs`.
|
|
70
|
+
*/
|
|
71
|
+
const BACKOFF_CAP_MS = 30_000;
|
|
72
|
+
|
|
73
|
+
let _availabilityChecked = false;
|
|
74
|
+
let _available = false;
|
|
75
|
+
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// JS batcher state.
|
|
78
|
+
//
|
|
79
|
+
// The in-flight map deduplicates concurrent requests for the same URL *across*
|
|
80
|
+
// batches: two `prefetchJson` calls that overlap in time and share a URL share
|
|
81
|
+
// a single HTTP request. The per-batch deduplication (identical URLs in the
|
|
82
|
+
// same request list) is handled by the `seen` Set before dispatch. Together
|
|
83
|
+
// these guarantee one request per unique URL under concurrency, which the
|
|
84
|
+
// serial path got for free from `await`-in-a-loop and which the in-memory
|
|
85
|
+
// `responseCache` cannot provide because it is populated only after a response
|
|
86
|
+
// arrives (and is disabled entirely under `CDXGEN_NO_CACHE`).
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
|
|
89
|
+
/** @type {Map<string, Promise<BatchEntry>>} Keyed by `${url}|${accept}|${authRealm}`. */
|
|
90
|
+
const _inFlight = new Map();
|
|
91
|
+
|
|
92
|
+
/** @type {Map<string, {sem: ReturnType<typeof makeSemaphore>, limiter: RateLimiter}>} */
|
|
93
|
+
const _hostSemaphores = new Map();
|
|
94
|
+
|
|
95
|
+
/** @type {Map<string, RateLimiter>} Kept for the external-delay count; cleared on reset. */
|
|
96
|
+
const _hostLimiters = new Map();
|
|
97
|
+
|
|
98
|
+
const _globalSemaphore = makeSemaphore(DEFAULT_GLOBAL_CONCURRENCY);
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Statistics from the most recent batch, or null when no batch has run.
|
|
102
|
+
*
|
|
103
|
+
* Exposed so a test can assert that the Rust path was *used*, not merely
|
|
104
|
+
* available: a silent fallback to the JS agent would otherwise make a parity
|
|
105
|
+
* comparison compare the JS path with itself and pass.
|
|
106
|
+
*/
|
|
107
|
+
let _lastStats = null;
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @returns {Object|null} Stats from the last batch (requests, unique, ok,
|
|
111
|
+
* failures, cacheHits, elapsedMs, peakConcurrency), or null.
|
|
112
|
+
*/
|
|
113
|
+
export function lastBatchStats() {
|
|
114
|
+
return _lastStats;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Whether batched fetching through cdxrs is available.
|
|
119
|
+
*
|
|
120
|
+
* Memoized because the probe spawns the binary, and this is consulted once per
|
|
121
|
+
* metadata function rather than once per run.
|
|
122
|
+
*
|
|
123
|
+
* @returns {boolean} True when `cdxrs fetch` can be used.
|
|
124
|
+
*/
|
|
125
|
+
export function batchFetchAvailable() {
|
|
126
|
+
if (_availabilityChecked) {
|
|
127
|
+
return _available;
|
|
128
|
+
}
|
|
129
|
+
_availabilityChecked = true;
|
|
130
|
+
_available = cdxrsAvailable("fetch").available === true;
|
|
131
|
+
return _available;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Reset the memoized availability probe and the JS batcher's in-flight map.
|
|
136
|
+
* Tests only.
|
|
137
|
+
*/
|
|
138
|
+
export function resetBatchFetchAvailability() {
|
|
139
|
+
_availabilityChecked = false;
|
|
140
|
+
_available = false;
|
|
141
|
+
_lastStats = null;
|
|
142
|
+
_inFlight.clear();
|
|
143
|
+
_hostSemaphores.clear();
|
|
144
|
+
_hostLimiters.clear();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* The outcome recorded for a single URL in a batch.
|
|
149
|
+
*
|
|
150
|
+
* @typedef {Object} BatchEntry
|
|
151
|
+
* @property {boolean} ok Whether a body was obtained.
|
|
152
|
+
* @property {*} [body] Parsed response body when `ok`.
|
|
153
|
+
* @property {number} [status] HTTP status, when the server produced one.
|
|
154
|
+
* @property {boolean} [definite] True when the status is a final answer (a 4xx
|
|
155
|
+
* other than 429) and re-requesting it in JS would be pointless.
|
|
156
|
+
*/
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Build the cdxrs fetch arguments for cache control.
|
|
160
|
+
*
|
|
161
|
+
* JS is the authority for the cache directory, so `--cache-dir` is always
|
|
162
|
+
* passed when a directory resolves. `--no-cache` and `--cache-ttl` are passed
|
|
163
|
+
* only when the user opts in.
|
|
164
|
+
*
|
|
165
|
+
* @returns {string[]} Extra args for `cdxrs fetch`.
|
|
166
|
+
*/
|
|
167
|
+
function buildCacheArgs() {
|
|
168
|
+
const args = [];
|
|
169
|
+
if (
|
|
170
|
+
readEnvironmentVariable("CDXGEN_NO_CACHE") === "true" ||
|
|
171
|
+
readEnvironmentVariable("CDXGEN_NO_CACHE") === "1"
|
|
172
|
+
) {
|
|
173
|
+
args.push("--no-cache");
|
|
174
|
+
return args;
|
|
175
|
+
}
|
|
176
|
+
const dir = resolveCacheDir();
|
|
177
|
+
if (dir) {
|
|
178
|
+
args.push("--cache-dir", dir);
|
|
179
|
+
}
|
|
180
|
+
if (readEnvironmentVariable("CDXGEN_CACHE_TTL") != null) {
|
|
181
|
+
const ttl = Number.parseInt(
|
|
182
|
+
readEnvironmentVariable("CDXGEN_CACHE_TTL"),
|
|
183
|
+
10,
|
|
184
|
+
);
|
|
185
|
+
if (Number.isFinite(ttl) && ttl >= 0) {
|
|
186
|
+
args.push("--cache-ttl", String(ttl));
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return args;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Fetch a batch of registry URLs concurrently.
|
|
194
|
+
*
|
|
195
|
+
* Dispatches to the Rust subprocess when it is available (it brings the D26
|
|
196
|
+
* on-disk cache), and to the JS pool otherwise. Both transports return a map
|
|
197
|
+
* keyed by URL with the same entry shape, so callers do not know — and do not
|
|
198
|
+
* need to know — which one ran.
|
|
199
|
+
*
|
|
200
|
+
* @param {Array<{url: string, accept?: string, authRealm?: string, responseType?: ("json"|"text"|"buffer"), headers?: Object}>} requests
|
|
201
|
+
* URLs to fetch. Duplicates are fine; they are coalesced.
|
|
202
|
+
* @param {Object} [options]
|
|
203
|
+
* @param {number} [options.timeoutMs] Override the Rust batch timeout.
|
|
204
|
+
* @returns {Promise<Map<string, BatchEntry>>} Map keyed by URL. Empty when
|
|
205
|
+
* prefetching is disabled (cassette replay) or the request list is empty;
|
|
206
|
+
* never empty for "no binary", which is the whole point of the JS pool.
|
|
207
|
+
*/
|
|
208
|
+
export async function prefetchJson(requests, options = {}) {
|
|
209
|
+
const empty = new Map();
|
|
210
|
+
if (!Array.isArray(requests) || !requests.length) {
|
|
211
|
+
return empty;
|
|
212
|
+
}
|
|
213
|
+
if (!prefetchEnabled()) {
|
|
214
|
+
return empty;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// The URL is the correlation id: callers look results up by the URL they
|
|
218
|
+
// were going to request anyway, so there is no separate id to keep in sync.
|
|
219
|
+
const seen = new Set();
|
|
220
|
+
const unique = [];
|
|
221
|
+
for (const request of requests) {
|
|
222
|
+
if (!request?.url || seen.has(request.url)) {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
seen.add(request.url);
|
|
226
|
+
unique.push(request);
|
|
227
|
+
}
|
|
228
|
+
if (!unique.length) {
|
|
229
|
+
return empty;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (batchFetchAvailable() && unique.every(cdxrsCanServe)) {
|
|
233
|
+
return await rustBatchFetch(unique, options);
|
|
234
|
+
}
|
|
235
|
+
return await jsBatchFetch(unique);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Whether cdxrs can serve a request without losing part of it.
|
|
240
|
+
*
|
|
241
|
+
* The protocol carries a URL, an `accept` value and an opaque `authRealm`, and
|
|
242
|
+
* types a result body as JSON. Two kinds of request therefore have no faithful
|
|
243
|
+
* representation in it and run on the JS pool instead:
|
|
244
|
+
*
|
|
245
|
+
* - a non-JSON `responseType`, since the envelope has nowhere to put HTML;
|
|
246
|
+
* - request-specific `headers`, since cdxrs derives its own Authorization from
|
|
247
|
+
* `GITHUB_TOKEN` and would silently drop any other credential, turning an
|
|
248
|
+
* authenticated lookup into an anonymous one.
|
|
249
|
+
*
|
|
250
|
+
* The pool applies the same global and per-host concurrency and rate policy, so
|
|
251
|
+
* the batching win is unaffected; only the on-disk cache is skipped.
|
|
252
|
+
*
|
|
253
|
+
* @param {{responseType?: string, headers?: Object}} request
|
|
254
|
+
* @returns {boolean}
|
|
255
|
+
*/
|
|
256
|
+
function cdxrsCanServe(request) {
|
|
257
|
+
if (request.responseType && request.responseType !== "json") {
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
return !request.headers || !Object.keys(request.headers).length;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Run the batch through the `cdxrs fetch` subprocess and translate its
|
|
265
|
+
* envelope into the shared result shape.
|
|
266
|
+
*
|
|
267
|
+
* @param {Array<{url: string, accept?: string, authRealm?: string}>} unique
|
|
268
|
+
* Already deduplicated by URL.
|
|
269
|
+
* @param {Object} options Options with `timeoutMs`.
|
|
270
|
+
* @returns {Promise<Map<string, BatchEntry>>}
|
|
271
|
+
*/
|
|
272
|
+
async function rustBatchFetch(unique, options) {
|
|
273
|
+
const payload = { requests: [] };
|
|
274
|
+
for (const request of unique) {
|
|
275
|
+
payload.requests.push({
|
|
276
|
+
id: request.url,
|
|
277
|
+
url: request.url,
|
|
278
|
+
...(request.accept ? { accept: request.accept } : {}),
|
|
279
|
+
...(request.authRealm ? { authRealm: request.authRealm } : {}),
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const { ok, stdout, reason } = await runCdxrs("fetch", {
|
|
284
|
+
content: JSON.stringify(payload),
|
|
285
|
+
timeoutMs: options.timeoutMs || DEFAULT_BATCH_TIMEOUT_MS,
|
|
286
|
+
args: buildCacheArgs(),
|
|
287
|
+
});
|
|
288
|
+
if (!ok) {
|
|
289
|
+
if (DEBUG_MODE && reason !== "disabled" && reason !== "binary-not-found") {
|
|
290
|
+
console.log(
|
|
291
|
+
`cdxrs fetch unavailable (${reason}); falling back to the JS batch pool.`,
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
// The Rust path failed in a way that is not "binary absent". Fall through
|
|
295
|
+
// to the JS pool rather than returning an empty map, so a transient cdxrs
|
|
296
|
+
// crash does not take the whole batch's concurrency with it.
|
|
297
|
+
return await jsBatchFetch(unique);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
let envelope;
|
|
301
|
+
try {
|
|
302
|
+
envelope = JSON.parse(stdout);
|
|
303
|
+
} catch (_err) {
|
|
304
|
+
return await jsBatchFetch(unique);
|
|
305
|
+
}
|
|
306
|
+
if (envelope?.schemaVersion !== BATCH_SCHEMA_VERSION) {
|
|
307
|
+
// A binary from a different generation of this protocol is not something
|
|
308
|
+
// to guess at. Fall back rather than misread its output.
|
|
309
|
+
if (DEBUG_MODE) {
|
|
310
|
+
console.log(
|
|
311
|
+
`cdxrs fetch envelope version ${envelope?.schemaVersion} != ${BATCH_SCHEMA_VERSION}; falling back to the JS batch pool.`,
|
|
312
|
+
);
|
|
313
|
+
}
|
|
314
|
+
return await jsBatchFetch(unique);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
_lastStats = envelope.stats || null;
|
|
318
|
+
const results = new Map();
|
|
319
|
+
for (const result of envelope.results || []) {
|
|
320
|
+
if (!result?.id) {
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
if (result.ok) {
|
|
324
|
+
results.set(result.id, { ok: true, body: result.body });
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
// 4xx other than 429 is the registry's final answer. Anything else — a
|
|
328
|
+
// timeout, a connection reset, an offline cache miss — is worth one more
|
|
329
|
+
// try through the JS agent, which has its own proxy and auth handling.
|
|
330
|
+
const status =
|
|
331
|
+
typeof result.status === "number" ? result.status : undefined;
|
|
332
|
+
const definite = status >= 400 && status < 500 && status !== 429;
|
|
333
|
+
results.set(result.id, { ok: false, status, definite });
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
if (DEBUG_MODE && envelope.stats) {
|
|
337
|
+
const s = envelope.stats;
|
|
338
|
+
console.log(
|
|
339
|
+
`cdxrs fetch: ${s.requests} url(s), ${s.unique} unique, ${s.ok} ok, ${s.failures} failed, ${s.cacheHits} cached, peak concurrency ${s.peakConcurrency}, ${s.elapsedMs} ms`,
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
return results;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Resolve or create the per-host semaphore and rate limiter.
|
|
347
|
+
*
|
|
348
|
+
* @param {string} host Lowercased hostname.
|
|
349
|
+
* @returns {{sem: ReturnType<typeof makeSemaphore>, limiter: RateLimiter}}
|
|
350
|
+
*/
|
|
351
|
+
function getHostControls(host) {
|
|
352
|
+
let entry = _hostSemaphores.get(host);
|
|
353
|
+
if (!entry) {
|
|
354
|
+
const policy = policyFor(host, credentialsFor(host));
|
|
355
|
+
entry = {
|
|
356
|
+
sem: makeSemaphore(policy.maxConcurrency),
|
|
357
|
+
limiter: new RateLimiter(policy.minInterval),
|
|
358
|
+
};
|
|
359
|
+
_hostSemaphores.set(host, entry);
|
|
360
|
+
_hostLimiters.set(host, entry.limiter);
|
|
361
|
+
}
|
|
362
|
+
return entry;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* Extract the hostname from a URL, returning null when the URL cannot be
|
|
367
|
+
* parsed. Matching `client.rs::extract_host`.
|
|
368
|
+
*
|
|
369
|
+
* @param {string} url
|
|
370
|
+
* @returns {string|null}
|
|
371
|
+
*/
|
|
372
|
+
function extractHost(url) {
|
|
373
|
+
try {
|
|
374
|
+
return new URL(url).hostname;
|
|
375
|
+
} catch (_err) {
|
|
376
|
+
return null;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Resolve an Authorization header to attach for this URL's host, if any.
|
|
382
|
+
*
|
|
383
|
+
* Mirrors the Rust client: only GitHub hosts get the token, and only when
|
|
384
|
+
* `GITHUB_TOKEN` is set. The value is never logged.
|
|
385
|
+
*
|
|
386
|
+
* @param {string} host
|
|
387
|
+
* @returns {{Authorization: string}|undefined}
|
|
388
|
+
*/
|
|
389
|
+
function resolveAuthHeader(host) {
|
|
390
|
+
if (!host) {
|
|
391
|
+
return undefined;
|
|
392
|
+
}
|
|
393
|
+
const lower = host.toLowerCase();
|
|
394
|
+
const isGitHub =
|
|
395
|
+
lower === "api.github.com" ||
|
|
396
|
+
lower === "github.com" ||
|
|
397
|
+
lower.endsWith(".github.com");
|
|
398
|
+
if (isGitHub && readEnvironmentVariable("GITHUB_TOKEN")) {
|
|
399
|
+
return {
|
|
400
|
+
Authorization: `Bearer ${readEnvironmentVariable("GITHUB_TOKEN")}`,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
return undefined;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* Build the `cdxgenAgent.get` options for one request.
|
|
408
|
+
*
|
|
409
|
+
* @param {Object} request The batch request.
|
|
410
|
+
* @param {string} host The request host, for auth resolution.
|
|
411
|
+
* @returns {Object} Options for `cdxgenAgent.get`.
|
|
412
|
+
*/
|
|
413
|
+
function buildAgentOptions(request, host) {
|
|
414
|
+
const options = {
|
|
415
|
+
responseType: request.responseType || "json",
|
|
416
|
+
};
|
|
417
|
+
const headers = { ...(request.headers || {}) };
|
|
418
|
+
if (request.accept) {
|
|
419
|
+
headers.Accept = request.accept;
|
|
420
|
+
}
|
|
421
|
+
// A credential the caller attached to this request is the specific one; the
|
|
422
|
+
// ambient GITHUB_TOKEN is the fallback. Letting the fallback win would send a
|
|
423
|
+
// token the caller did not choose, silently ignoring an explicitly supplied
|
|
424
|
+
// one such as `--forge-token`.
|
|
425
|
+
const auth = headers.Authorization ? undefined : resolveAuthHeader(host);
|
|
426
|
+
if (auth) {
|
|
427
|
+
headers.Authorization = auth.Authorization;
|
|
428
|
+
}
|
|
429
|
+
if (Object.keys(headers).length) {
|
|
430
|
+
options.headers = headers;
|
|
431
|
+
}
|
|
432
|
+
return options;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Parse a server-supplied back-off, in milliseconds.
|
|
437
|
+
*
|
|
438
|
+
* `Retry-After` may be seconds or an HTTP-date; `X-RateLimit-Reset` /
|
|
439
|
+
* `RateLimit-Reset` is a Unix timestamp. Returns null when no recognised
|
|
440
|
+
* header is present, so the caller can fall back to exponential backoff.
|
|
441
|
+
* Ported from `client.rs::parse_retry_after`.
|
|
442
|
+
*
|
|
443
|
+
* @param {Object} response The `cdxgenAgent` response or HTTPError response.
|
|
444
|
+
* @returns {number|null} Delay in milliseconds, or null.
|
|
445
|
+
*/
|
|
446
|
+
function parseRetryAfter(response) {
|
|
447
|
+
const headers = response?.headers || {};
|
|
448
|
+
const retryAfter = headers["retry-after"] || headers["Retry-After"];
|
|
449
|
+
if (retryAfter) {
|
|
450
|
+
const trimmed = String(retryAfter).trim();
|
|
451
|
+
const seconds = Number.parseInt(trimmed, 10);
|
|
452
|
+
if (Number.isFinite(seconds) && trimmed === String(seconds)) {
|
|
453
|
+
return seconds * 1000;
|
|
454
|
+
}
|
|
455
|
+
// HTTP-date form.
|
|
456
|
+
const target = Date.parse(trimmed);
|
|
457
|
+
if (Number.isFinite(target)) {
|
|
458
|
+
const delay = target - Date.now();
|
|
459
|
+
return delay > 0 ? delay : 0;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
// GitHub sends the reset timestamp rather than Retry-After.
|
|
463
|
+
for (const name of ["x-ratelimit-reset", "ratelimit-reset"]) {
|
|
464
|
+
const value = headers[name];
|
|
465
|
+
if (value === undefined) {
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
const ts = Number.parseInt(String(value).trim(), 10);
|
|
469
|
+
if (!Number.isFinite(ts)) {
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
const now = Math.floor(Date.now() / 1000);
|
|
473
|
+
if (ts > now) {
|
|
474
|
+
return (ts - now) * 1000;
|
|
475
|
+
}
|
|
476
|
+
// A small value (< 1h) is a delta, a large one is an absolute timestamp.
|
|
477
|
+
if (ts < 3600) {
|
|
478
|
+
return ts * 1000;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* Exponential backoff with full jitter, capped at {@link BACKOFF_CAP_MS}.
|
|
486
|
+
* Matches `client.rs::exponential_backoff`.
|
|
487
|
+
*
|
|
488
|
+
* @param {number} attempt 1-based attempt number.
|
|
489
|
+
* @returns {number} Delay in milliseconds.
|
|
490
|
+
*/
|
|
491
|
+
function exponentialBackoffMs(attempt) {
|
|
492
|
+
const shift = Math.min(attempt, 8);
|
|
493
|
+
const baseMs = 100 * (1 << shift);
|
|
494
|
+
const jitter = Math.floor(Math.random() * (baseMs + 1));
|
|
495
|
+
return Math.min(baseMs + jitter, BACKOFF_CAP_MS);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* Issue one request through `cdxgenAgent`, with bounded retries for transient
|
|
500
|
+
* failures and server-supplied back-offs.
|
|
501
|
+
*
|
|
502
|
+
* The caller already holds the global and per-host permits; this function
|
|
503
|
+
* consults the per-host rate limiter on every attempt (including retries) and
|
|
504
|
+
* pushes the gate out when the server asks us to slow down, matching the
|
|
505
|
+
* Rust client's retry loop.
|
|
506
|
+
*
|
|
507
|
+
* @param {Object} request The batch request.
|
|
508
|
+
* @param {RateLimiter} limiter The per-host rate limiter.
|
|
509
|
+
* @returns {Promise<BatchEntry>}
|
|
510
|
+
*/
|
|
511
|
+
async function issueWithRetries(request, limiter) {
|
|
512
|
+
const host = extractHost(request.url);
|
|
513
|
+
const options = buildAgentOptions(request, host);
|
|
514
|
+
let attempt = 0;
|
|
515
|
+
while (true) {
|
|
516
|
+
attempt++;
|
|
517
|
+
await limiter.wait();
|
|
518
|
+
let result;
|
|
519
|
+
try {
|
|
520
|
+
const res = await cdxgenAgent.get(request.url, options);
|
|
521
|
+
result = {
|
|
522
|
+
retryable: false,
|
|
523
|
+
delay: null,
|
|
524
|
+
entry: { ok: true, body: res.body, status: res.statusCode },
|
|
525
|
+
};
|
|
526
|
+
} catch (err) {
|
|
527
|
+
result = classifyAgentError(err);
|
|
528
|
+
}
|
|
529
|
+
if (result.retryable && attempt <= MAX_RETRIES) {
|
|
530
|
+
const delay =
|
|
531
|
+
result.delay !== null && result.delay !== undefined
|
|
532
|
+
? result.delay
|
|
533
|
+
: exponentialBackoffMs(attempt);
|
|
534
|
+
// A server-supplied delay wins over our own backoff and is recorded
|
|
535
|
+
// against the host bucket so the next attempt respects it too.
|
|
536
|
+
if (result.delay !== null && result.delay !== undefined) {
|
|
537
|
+
limiter.externalDelay(delay);
|
|
538
|
+
}
|
|
539
|
+
if (delay > 0) {
|
|
540
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
541
|
+
}
|
|
542
|
+
continue;
|
|
543
|
+
}
|
|
544
|
+
return result.entry;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/**
|
|
549
|
+
* Classify an error thrown by `cdxgenAgent.get` into a retry decision and the
|
|
550
|
+
* batch entry to record when retries are exhausted.
|
|
551
|
+
*
|
|
552
|
+
* @param {Error} err
|
|
553
|
+
* @returns {{retryable: boolean, delay: number|null, entry: BatchEntry}}
|
|
554
|
+
*/
|
|
555
|
+
function classifyAgentError(err) {
|
|
556
|
+
// Secure-mode and dry-run blocks must not be retried, and the caller's own
|
|
557
|
+
// fallback `cdxgenAgent.get` will surface the same error. Recording this as
|
|
558
|
+
// non-definite lets the caller's catch run exactly as it would on the serial
|
|
559
|
+
// path.
|
|
560
|
+
if (err?.options?.context?.activityBlocked) {
|
|
561
|
+
return {
|
|
562
|
+
retryable: false,
|
|
563
|
+
delay: null,
|
|
564
|
+
entry: { ok: false, status: undefined, definite: false },
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
const status = err?.response?.statusCode;
|
|
568
|
+
const headers = err?.response?.headers;
|
|
569
|
+
if (status === 429) {
|
|
570
|
+
return {
|
|
571
|
+
retryable: true,
|
|
572
|
+
delay: parseRetryAfter({ headers }),
|
|
573
|
+
entry: { ok: false, status, definite: false },
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
if (status >= 500 && status < 600) {
|
|
577
|
+
return {
|
|
578
|
+
retryable: true,
|
|
579
|
+
delay: null,
|
|
580
|
+
entry: { ok: false, status, definite: false },
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
if (status >= 400 && status < 500) {
|
|
584
|
+
return {
|
|
585
|
+
retryable: false,
|
|
586
|
+
delay: null,
|
|
587
|
+
entry: { ok: false, status, definite: true },
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
// Transport error (timeout, connection reset). The name check mirrors how
|
|
591
|
+
// httpClient.js distinguishes its two error classes.
|
|
592
|
+
if (err?.name === "RequestError") {
|
|
593
|
+
return {
|
|
594
|
+
retryable: true,
|
|
595
|
+
delay: null,
|
|
596
|
+
entry: { ok: false, status: undefined, definite: false },
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
// Unknown error shape: do not retry, let the caller's fallback decide.
|
|
600
|
+
return {
|
|
601
|
+
retryable: false,
|
|
602
|
+
delay: null,
|
|
603
|
+
entry: { ok: false, status, definite: false },
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
/**
|
|
608
|
+
* Fetch one URL with global + per-host concurrency control.
|
|
609
|
+
*
|
|
610
|
+
* Permits are held for the whole retry sequence, including back-off sleeps, so
|
|
611
|
+
* a host that is asking us to slow down does not get four more slots opened
|
|
612
|
+
* against it in the meantime. The in-flight counter is incremented after both
|
|
613
|
+
* permits are acquired, so the peak it records is real HTTP concurrency rather
|
|
614
|
+
* than tasks queued behind the semaphores; it matches the Rust client's
|
|
615
|
+
* `InFlightGuard`.
|
|
616
|
+
*
|
|
617
|
+
* @param {Object} request
|
|
618
|
+
* @param {{inFlight: number, peak: number}} gauge Batch-scoped concurrency
|
|
619
|
+
* gauge. Scoped to one batch rather than to the module so that the peak a
|
|
620
|
+
* batch reports describes that batch: a process-wide high-water mark would
|
|
621
|
+
* report the widest batch so far for every batch after it, including a
|
|
622
|
+
* single-URL one, and so could not evidence that any given batch fanned out.
|
|
623
|
+
* @returns {Promise<BatchEntry>}
|
|
624
|
+
*/
|
|
625
|
+
async function fetchOne(request, gauge) {
|
|
626
|
+
const host = extractHost(request.url);
|
|
627
|
+
if (!host) {
|
|
628
|
+
return { ok: false, status: undefined, definite: false };
|
|
629
|
+
}
|
|
630
|
+
const controls = getHostControls(host);
|
|
631
|
+
const releaseGlobal = await _globalSemaphore.acquire();
|
|
632
|
+
const releaseHost = await controls.sem.acquire();
|
|
633
|
+
gauge.inFlight += 1;
|
|
634
|
+
if (gauge.inFlight > gauge.peak) {
|
|
635
|
+
gauge.peak = gauge.inFlight;
|
|
636
|
+
}
|
|
637
|
+
try {
|
|
638
|
+
return await issueWithRetries(request, controls.limiter);
|
|
639
|
+
} finally {
|
|
640
|
+
gauge.inFlight -= 1;
|
|
641
|
+
releaseHost();
|
|
642
|
+
releaseGlobal();
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Dedupe key for an in-flight request: the URL, plus everything that changes
|
|
648
|
+
* which response the caller gets back. That is the headers which change what
|
|
649
|
+
* the server returns, and the decode mode, which changes how the same bytes are
|
|
650
|
+
* handed over — two callers wanting one URL as JSON and as text cannot share a
|
|
651
|
+
* promise. Raw credential values are never part of the key; `authRealm` is an
|
|
652
|
+
* opaque label the caller chooses.
|
|
653
|
+
*
|
|
654
|
+
* @param {Object} request
|
|
655
|
+
* @returns {string}
|
|
656
|
+
*/
|
|
657
|
+
function inFlightKey(request) {
|
|
658
|
+
return [
|
|
659
|
+
request.url,
|
|
660
|
+
request.accept || "",
|
|
661
|
+
request.authRealm || "",
|
|
662
|
+
request.responseType || "json",
|
|
663
|
+
].join("|");
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/**
|
|
667
|
+
* Run the batch through the JS pool: every request goes through
|
|
668
|
+
* `cdxgenAgent`, so the secure-mode host allowlist, the activity recorder and
|
|
669
|
+
* the test cassette interceptor all still apply.
|
|
670
|
+
*
|
|
671
|
+
* @param {Array<{url: string, accept?: string, authRealm?: string, responseType?: ("json"|"text"|"buffer"), headers?: Object}>} unique
|
|
672
|
+
* Already deduplicated by URL.
|
|
673
|
+
* @returns {Promise<Map<string, BatchEntry>>}
|
|
674
|
+
*/
|
|
675
|
+
async function jsBatchFetch(unique) {
|
|
676
|
+
const started = Date.now();
|
|
677
|
+
let ok = 0;
|
|
678
|
+
let failures = 0;
|
|
679
|
+
const results = new Map();
|
|
680
|
+
// Concurrency is counted per batch. A request served from another batch's
|
|
681
|
+
// in-flight promise is counted against that batch, not this one.
|
|
682
|
+
const gauge = { inFlight: 0, peak: 0 };
|
|
683
|
+
const tasks = unique.map(async (request) => {
|
|
684
|
+
const key = inFlightKey(request);
|
|
685
|
+
// Cross-batch in-flight dedupe. If another batch already has this URL in
|
|
686
|
+
// flight, await its promise rather than issuing a second request. The
|
|
687
|
+
// entry is removed when the promise settles, so a later request for the
|
|
688
|
+
// same URL (after completion) goes through `responseCache` or, under
|
|
689
|
+
// `CDXGEN_NO_CACHE`, issues a fresh request — which is correct.
|
|
690
|
+
let promise = _inFlight.get(key);
|
|
691
|
+
if (!promise) {
|
|
692
|
+
promise = fetchOne(request, gauge);
|
|
693
|
+
_inFlight.set(key, promise);
|
|
694
|
+
// Remove on settle so the map does not grow unbounded and a later,
|
|
695
|
+
// non-overlapping request for the same URL is not served a stale
|
|
696
|
+
// in-flight promise.
|
|
697
|
+
const clear = () => {
|
|
698
|
+
const current = _inFlight.get(key);
|
|
699
|
+
if (current === promise) {
|
|
700
|
+
_inFlight.delete(key);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
promise.then(clear, clear);
|
|
704
|
+
}
|
|
705
|
+
const entry = await promise;
|
|
706
|
+
if (entry.ok) {
|
|
707
|
+
ok += 1;
|
|
708
|
+
} else {
|
|
709
|
+
failures += 1;
|
|
710
|
+
}
|
|
711
|
+
results.set(request.url, entry);
|
|
712
|
+
});
|
|
713
|
+
await Promise.all(tasks);
|
|
714
|
+
|
|
715
|
+
_lastStats = {
|
|
716
|
+
requests: unique.length,
|
|
717
|
+
unique: unique.length,
|
|
718
|
+
ok,
|
|
719
|
+
failures,
|
|
720
|
+
cacheHits: 0,
|
|
721
|
+
elapsedMs: Date.now() - started,
|
|
722
|
+
peakConcurrency: gauge.peak,
|
|
723
|
+
};
|
|
724
|
+
if (DEBUG_MODE) {
|
|
725
|
+
const s = _lastStats;
|
|
726
|
+
console.log(
|
|
727
|
+
`js batch: ${s.requests} url(s), ${s.ok} ok, ${s.failures} failed, peak concurrency ${s.peakConcurrency}, ${s.elapsedMs} ms`,
|
|
728
|
+
);
|
|
729
|
+
}
|
|
730
|
+
return results;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Read a prefetched response, or signal that the caller should fetch it itself.
|
|
735
|
+
*
|
|
736
|
+
* @param {Map<string, BatchEntry>} prefetched Result of {@link prefetchJson}.
|
|
737
|
+
* @param {string} url The URL the caller is about to request.
|
|
738
|
+
* @returns {{body: *}|undefined} A response-shaped object when the body is
|
|
739
|
+
* available, or `undefined` when the caller should issue its own request.
|
|
740
|
+
* @throws {Error} When the batch established a definite HTTP error for this
|
|
741
|
+
* URL, so that the caller's existing `catch` treats it exactly as it treats a
|
|
742
|
+
* failed `cdxgenAgent.get`.
|
|
743
|
+
*/
|
|
744
|
+
export function prefetchedResponse(prefetched, url) {
|
|
745
|
+
const entry = prefetched?.get(url);
|
|
746
|
+
if (!entry) {
|
|
747
|
+
return undefined;
|
|
748
|
+
}
|
|
749
|
+
if (entry.ok) {
|
|
750
|
+
return { body: entry.body };
|
|
751
|
+
}
|
|
752
|
+
if (entry.definite) {
|
|
753
|
+
const err = new Error(`Request failed with status code ${entry.status}`);
|
|
754
|
+
err.statusCode = entry.status;
|
|
755
|
+
throw err;
|
|
756
|
+
}
|
|
757
|
+
return undefined;
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/**
|
|
761
|
+
* Whether batched prefetching should be attempted at all.
|
|
762
|
+
*
|
|
763
|
+
* The JS pool is always available (it is plain JavaScript through
|
|
764
|
+
* `cdxgenAgent`), so this is true for every real run. The single exception is
|
|
765
|
+
* cassette replay: the cassette interceptor lives inside undici inside this
|
|
766
|
+
* process, and the golden harness asserts exact request ordering and counts.
|
|
767
|
+
* The batch pool reorders requests by design, so it is disabled under replay
|
|
768
|
+
* to keep the golden cassettes stable. `CDXGEN_RS_DISABLE=fetch` and
|
|
769
|
+
* `--no-rust` disable only the Rust subprocess; the JS pool still runs, which
|
|
770
|
+
* is the point of this round.
|
|
771
|
+
*
|
|
772
|
+
* @returns {boolean} True when prefetching is allowed.
|
|
773
|
+
*/
|
|
774
|
+
export function prefetchEnabled() {
|
|
775
|
+
if (readEnvironmentVariable("CDXGEN_CASSETTE_REPLAY") === "true") {
|
|
776
|
+
return false;
|
|
777
|
+
}
|
|
778
|
+
return true;
|
|
779
|
+
}
|