/** * Package-shape check. * * Validates that the @angriff36/manifest package's public surface — the * subpath exports, the bin entry, and the shipped files list — actually * resolves at runtime in the current install. Catches packaging mistakes * (missing subpath in `exports`, missing file in `files`, broken bin * shebang) before they reach a downstream consumer. * * Two layers: * * 1. Subpath imports — programmatically import each documented subpath * and confirm a non-null module came back. Failures here mean the * consumer's `import '@angriff36/manifest/'` will throw. * * 2. Tarball contents — pack the package to a temporary directory and * list the resulting `.tgz` to confirm the SQL schemas, CLI bin, * and dist/manifest tree are included. Failures here mean the * published tarball is missing files the runtime needs. * * The subpath layer runs in every invocation. The tarball layer requires * `pnpm` (or `npm`) on PATH plus a writable temp directory, so callers * can opt out via the `skipTarball` option (e.g. when running inside a * sandboxed CI step that does not have a packing toolchain available). * * Tarball tool selection: prefers `pnpm pack` over `npm pack --dry-run`. * * - `pnpm pack` is deterministic on this repo's layout (pnpm-managed * node_modules) and produces an actual .tgz which we then list via * `tar -tzf` to read the file inventory. * - `npm pack --dry-run` has a known upstream bug * (`@npmcli/arborist#findMissingEdges` crashes with * "Cannot read properties of null (reading 'package')") that triggers * intermittently when it walks a pnpm-style `node_modules/.pnpm` store * on Windows. Reproduced at ~40% failure rate locally with * npm 10.9.3 + Node 22.18 on Windows 11. CI publishes have worked so * far because CI installs are fresh and the bug is timing-sensitive, * but relying on it for a verification check is not safe. * * If pnpm is not available we fall back to npm — and the caller is * responsible for treating a non-zero exit as a real failure (the * `tarball.error` field carries the diagnostic). */ export interface SubpathImportResult { subpath: string; ok: boolean; error?: string; /** Names of exports actually present on the imported module. */ exports: string[]; } export interface TarballContentResult { ran: boolean; ok?: boolean; /** Which packer produced the file list (`'pnpm'` or `'npm'`). */ packer?: 'pnpm' | 'npm'; /** Files included in the published tarball, repo-relative. */ files: string[]; /** Expected entries that were missing from the tarball. */ missingExpectedEntries: string[]; /** Raw error if the packer failed. */ error?: string; } export interface PackageShapeResult { ok: boolean; /** * True only if the tarball sub-check was intentionally skipped via * `skipTarball: true`. Distinguishes a deliberate skip from * "we tried to run `npm pack` and it failed to spawn". */ tarballSkipped: boolean; subpathImports: SubpathImportResult[]; tarball: TarballContentResult; } export interface PublicSubpathExpectation { subpath: string; expectedExports: string[]; } /** * Derive the public subpaths directly from package.json so this check stays in * sync with the published library surface. The only intentional omission here * is `./package.json` because JSON import semantics differ by host. */ export declare function getPackageShapeSubpaths(packageRoot: string): Promise; export interface PackageShapeOptions { /** Root of the @angriff36/manifest package (where package.json lives). */ packageRoot: string; /** Skip the `npm pack --dry-run` step (useful in restricted CI sandboxes). */ skipTarball?: boolean; } export declare function checkPackageShape(opts: PackageShapeOptions): Promise; //# sourceMappingURL=package-shape.d.ts.map