import { chunks, MAX_IN_LIST, placeholders } from "../db";
import { repoDb, stmt, type ScopedStatement } from "../scoped-db";
import { packageKey, publishedAdvisoryCounts } from "./advisory-packages";
import { loadRepoById } from "../repos";
import { withStore } from "../git/store";
import { branchSha, refreshRefs } from "../git/refs";
import { manifestKind } from "./manifests";
import type { Dependency, Ecosystem } from "./manifests";
import { notifyDependencyAlerts } from "../notify/security";
import { loadSecuritySettings } from "./settings";
const MAX_TREE_ENTRIES = 20_000;
const MAX_MANIFESTS = 50;
const MAX_MANIFEST_BYTES = 2 * 1024 * 1024;
const MAX_DEPENDENCIES = 5000;
const DEPENDENCY_COLUMNS = 7;
const STATEMENTS_PER_BATCH = 50;
const DEPENDENCY_PAGE = 100;
const MAX_NAME_LENGTH = 214;
const MAX_REQUIREMENT_LENGTH = 100;
const decoder = new TextDecoder();
type Parsed = { path: string; ecosystem: Ecosystem; dependencies: Dependency[] };
/** Rebuilds the dependency graph for a commit from its manifests and lockfiles, within fixed budgets. */
export async function scanDependencies(repoId: string, sha: string): Promise<number> {
const repo = await loadRepoById(repoId);
if (!repo || !(await loadSecuritySettings(repo.id)).dependencyGraph) return 0;
const parsed = await withStore(repo.artifacts_name, async (store) => {
const commit = await store.commit(sha);
if (!commit) return null;
const { entries } = await store.walk(commit.treeSha, MAX_TREE_ENTRIES);
const manifests = entries
.filter((entry) => entry.type === "blob" && manifestKind(entry.path))
.slice(0, MAX_MANIFESTS);
const out: Parsed[] = [];
let total = 0;
for (const entry of manifests) {
const kind = manifestKind(entry.path);
const blob = kind ? await store.blob(entry.sha) : null;