@packall/core 0.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/dist/Archive.d.ts +32 -0
- package/dist/Archive.d.ts.map +1 -0
- package/dist/Bundle.d.ts +123 -0
- package/dist/Bundle.d.ts.map +1 -0
- package/dist/DependencyRange.d.ts +26 -0
- package/dist/DependencyRange.d.ts.map +1 -0
- package/dist/Download.d.ts +35 -0
- package/dist/Download.d.ts.map +1 -0
- package/dist/Errors.d.ts +124 -0
- package/dist/Errors.d.ts.map +1 -0
- package/dist/InputFile.d.ts +46 -0
- package/dist/InputFile.d.ts.map +1 -0
- package/dist/Integrity.d.ts +48 -0
- package/dist/Integrity.d.ts.map +1 -0
- package/dist/Layout.d.ts +53 -0
- package/dist/Layout.d.ts.map +1 -0
- package/dist/Manifest.d.ts +82 -0
- package/dist/Manifest.d.ts.map +1 -0
- package/dist/Options.d.ts +100 -0
- package/dist/Options.d.ts.map +1 -0
- package/dist/Platform.d.ts +69 -0
- package/dist/Platform.d.ts.map +1 -0
- package/dist/Progress.d.ts +107 -0
- package/dist/Progress.d.ts.map +1 -0
- package/dist/Registry.d.ts +106 -0
- package/dist/Registry.d.ts.map +1 -0
- package/dist/Resolve.d.ts +105 -0
- package/dist/Resolve.d.ts.map +1 -0
- package/dist/Spec.d.ts +62 -0
- package/dist/Spec.d.ts.map +1 -0
- package/dist/index.d.ts +36 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1766 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
- package/src/Archive.ts +92 -0
- package/src/Bundle.ts +570 -0
- package/src/DependencyRange.ts +115 -0
- package/src/Download.ts +132 -0
- package/src/Errors.ts +216 -0
- package/src/InputFile.ts +229 -0
- package/src/Integrity.ts +122 -0
- package/src/Layout.ts +103 -0
- package/src/Manifest.ts +133 -0
- package/src/Options.ts +123 -0
- package/src/Platform.ts +182 -0
- package/src/Progress.ts +106 -0
- package/src/Registry.ts +121 -0
- package/src/Resolve.ts +528 -0
- package/src/Spec.ts +186 -0
- package/src/index.ts +44 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["layerSilent: Layer.Layer<Progress>","Progress.emit","describe","hashes: Array<IntegrityHash>","Progress.emit","unverified: Array<string>","Integrity.verify","allPlatforms: PlatformFilter","OS_ALIASES: Readonly<Record<string, string>>","KNOWN_OS: ReadonlySet<string>","specs: Array<PackageSpec>","errors: Array<InvalidSpecError>","out: Array<PackageSpec>","packages: ReadonlyArray<ManifestEntry>","UNSUPPORTED_PROTOCOLS: ReadonlyArray<readonly [string, string]>","tasks: Array<Task>","warnings: Array<ResolutionWarning>","frontier: ReadonlyArray<Task>","wave: Array<Task>","next: Array<Task>","Progress.emit","out: Array<{ manifest: PackageManifest; reason: Reason }>","roots: Array<RootResolution>","Progress.emit","artifacts: Array<BundleArtifact>","clashes: Array<string>","defaultInputFileOptions: InputFileOptions","parsed: PackageJsonShape","specs: Array<PackageSpec>","warnings: Array<string>","lines: Array<string>","layouts: ReadonlyArray<Layout>","defaultScope: DependencyScope","defaultResolveOptions: ResolveOptions","defaultBundleOptions: Omit<BundleOptions, \"outDir\">"],"sources":["../src/Errors.ts","../src/Progress.ts","../src/Archive.ts","../src/Integrity.ts","../src/Layout.ts","../src/Registry.ts","../src/Download.ts","../src/Platform.ts","../src/Spec.ts","../src/Manifest.ts","../src/DependencyRange.ts","../src/Resolve.ts","../src/Bundle.ts","../src/InputFile.ts","../src/Options.ts"],"sourcesContent":["/**\n * Failure types for the bundler.\n *\n * These are deliberately plain classes carrying a literal `_tag` rather than\n * `Data.TaggedError`. They work with `Effect.catchTag` / `Effect.catchTags`\n * exactly the same way, and they keep the public error surface independent of\n * any single Effect release — useful while Effect v4 is still in beta.\n *\n * Every error carries enough context to be actionable without a stack trace,\n * because the primary consumer is somebody staring at a terminal on a\n * locked-down network trying to work out why a download did not happen.\n */\n\n/** Discriminant union of every failure the bundler can produce. */\nexport type BundlerError =\n | InvalidSpecError\n | InvalidInputFileError\n | RegistryUnreachableError\n | PackageNotFoundError\n | VersionNotFoundError\n | NoMatchingVersionsError\n | RegistryResponseError\n | AuthenticationError\n | IntegrityError\n | ArchiveError\n | OutputError\n\nabstract class BundlerErrorBase extends Error {\n abstract readonly _tag: string\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options as ErrorOptions)\n this.name = new.target.name\n }\n}\n\n/** A package spec on the command line or in an input file could not be parsed. */\nexport class InvalidSpecError extends BundlerErrorBase {\n readonly _tag = \"InvalidSpecError\" as const\n readonly spec: string\n readonly reason: string\n constructor(spec: string, reason: string) {\n super(`Invalid package spec ${JSON.stringify(spec)}: ${reason}`)\n this.spec = spec\n this.reason = reason\n }\n}\n\n/** `--file` pointed at something that is neither a usable package.json nor a spec list. */\nexport class InvalidInputFileError extends BundlerErrorBase {\n readonly _tag = \"InvalidInputFileError\" as const\n readonly path: string\n readonly reason: string\n constructor(path: string, reason: string, options?: { cause?: unknown }) {\n super(`Cannot read specs from ${path}: ${reason}`, options)\n this.path = path\n this.reason = reason\n }\n}\n\n/**\n * The registry could not be reached at all — DNS failure, refused connection,\n * proxy blackhole, or a preflight that timed out.\n *\n * This is the error that fixes \"hangs forever with no network\": we surface it\n * quickly and say which host we could not reach.\n */\nexport class RegistryUnreachableError extends BundlerErrorBase {\n readonly _tag = \"RegistryUnreachableError\" as const\n readonly registry: string\n readonly timeoutMillis: number | undefined\n constructor(\n registry: string,\n detail: string,\n options?: { cause?: unknown; timeoutMillis?: number }\n ) {\n super(\n `Cannot reach registry ${registry}: ${detail}.\\n` +\n ` Check your network connection, VPN, and the proxy settings in your .npmrc.`,\n options\n )\n this.registry = registry\n this.timeoutMillis = options?.timeoutMillis\n }\n}\n\n/** The registry answered, but has never heard of this package. */\nexport class PackageNotFoundError extends BundlerErrorBase {\n readonly _tag = \"PackageNotFoundError\" as const\n readonly packageName: string\n readonly registry: string\n constructor(packageName: string, registry: string) {\n super(`Package \"${packageName}\" was not found on ${registry}`)\n this.packageName = packageName\n this.registry = registry\n }\n}\n\n/** The package exists but the exact version requested does not. */\nexport class VersionNotFoundError extends BundlerErrorBase {\n readonly _tag = \"VersionNotFoundError\" as const\n readonly packageName: string\n readonly version: string\n readonly available: ReadonlyArray<string>\n constructor(packageName: string, version: string, available: ReadonlyArray<string>) {\n const tail = available.slice(-5).join(\", \")\n super(\n `${packageName}@${version} does not exist.` +\n (tail.length > 0 ? ` Most recent published versions: ${tail}` : \"\")\n )\n this.packageName = packageName\n this.version = version\n this.available = available\n }\n}\n\n/** A range (or dist-tag) matched nothing that is actually published. */\nexport class NoMatchingVersionsError extends BundlerErrorBase {\n readonly _tag = \"NoMatchingVersionsError\" as const\n readonly packageName: string\n readonly selector: string\n readonly available: ReadonlyArray<string>\n constructor(packageName: string, selector: string, available: ReadonlyArray<string>) {\n const tail = available.slice(-5).join(\", \")\n super(\n `No published version of ${packageName} satisfies \"${selector}\".` +\n (tail.length > 0 ? ` Most recent published versions: ${tail}` : \"\")\n )\n this.packageName = packageName\n this.selector = selector\n this.available = available\n }\n}\n\n/** The registry responded, but with something we cannot use. */\nexport class RegistryResponseError extends BundlerErrorBase {\n readonly _tag = \"RegistryResponseError\" as const\n readonly url: string\n readonly status: number | undefined\n constructor(url: string, detail: string, options?: { cause?: unknown; status?: number }) {\n super(`Unexpected response from ${url}: ${detail}`, options)\n this.url = url\n this.status = options?.status\n }\n}\n\n/** 401/403 — almost always a missing or stale token in `.npmrc`. */\nexport class AuthenticationError extends BundlerErrorBase {\n readonly _tag = \"AuthenticationError\" as const\n readonly registry: string\n readonly status: number\n constructor(registry: string, status: number, packageName?: string) {\n super(\n `Registry ${registry} rejected the request with HTTP ${status}` +\n (packageName ? ` while fetching \"${packageName}\"` : \"\") +\n `.\\n Add credentials to your .npmrc, e.g.\\n` +\n ` //${safeHost(registry)}/:_authToken=\\${NPM_TOKEN}`\n )\n this.registry = registry\n this.status = status\n }\n}\n\n/**\n * A downloaded tarball did not match the checksum the registry advertised.\n *\n * Never soft-fail this: a bundle is a supply-chain artifact and a corrupt or\n * substituted tarball is exactly what integrity checking exists to catch.\n */\nexport class IntegrityError extends BundlerErrorBase {\n readonly _tag = \"IntegrityError\" as const\n readonly packageName: string\n readonly version: string\n readonly expected: string\n readonly actual: string\n constructor(packageName: string, version: string, expected: string, actual: string) {\n super(\n `Integrity check failed for ${packageName}@${version}.\\n` +\n ` expected: ${expected}\\n` +\n ` actual: ${actual}\\n` +\n ` The download was discarded. This is either corruption in transit or a tampered artifact.`\n )\n this.packageName = packageName\n this.version = version\n this.expected = expected\n this.actual = actual\n }\n}\n\n/** Something went wrong writing the `.tgz`. */\nexport class ArchiveError extends BundlerErrorBase {\n readonly _tag = \"ArchiveError\" as const\n readonly path: string\n constructor(path: string, detail: string, options?: { cause?: unknown }) {\n super(`Failed to create archive ${path}: ${detail}`, options)\n this.path = path\n }\n}\n\n/** Something went wrong preparing or writing to the output directory. */\nexport class OutputError extends BundlerErrorBase {\n readonly _tag = \"OutputError\" as const\n readonly path: string\n constructor(path: string, detail: string, options?: { cause?: unknown }) {\n super(`Output error at ${path}: ${detail}`, options)\n this.path = path\n }\n}\n\nconst safeHost = (registry: string): string => {\n try {\n const url = new URL(registry)\n return url.host + url.pathname.replace(/\\/+$/, \"\")\n } catch {\n return registry\n }\n}\n","/**\n * Progress reporting.\n *\n * The engine emits structured events; it never writes to a terminal. That\n * separation is what lets the CLI draw a live TTY view, CI print plain lines,\n * and the test suite assert on an array of events without any of them\n * interfering with each other.\n */\nimport * as Context from \"effect/Context\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as Ref from \"effect/Ref\"\n\n/** The phases a bundle run moves through, in order. */\nexport type Phase = \"preflight\" | \"resolve\" | \"download\" | \"archive\" | \"done\"\n\n/** A structured progress event. */\nexport type ProgressEvent =\n /** A phase began. `total` is set only when it is known up front. */\n | { readonly _tag: \"PhaseStarted\"; readonly phase: Phase; readonly total?: number | undefined }\n /** A phase finished. */\n | { readonly _tag: \"PhaseCompleted\"; readonly phase: Phase }\n /** The resolver discovered a package that has to be included. */\n | {\n readonly _tag: \"PackageResolved\"\n readonly name: string\n readonly version: string\n /** Running count of resolved packages, for a live counter. */\n readonly resolvedCount: number\n /** Packages still queued for resolution. */\n readonly pendingCount: number\n }\n /** A tarball download started. */\n | { readonly _tag: \"DownloadStarted\"; readonly name: string; readonly version: string }\n /** A tarball download finished. */\n | {\n readonly _tag: \"DownloadCompleted\"\n readonly name: string\n readonly version: string\n readonly bytes: number\n readonly completedCount: number\n readonly totalCount: number\n }\n /** A download failed and will be retried. */\n | {\n readonly _tag: \"DownloadRetrying\"\n readonly name: string\n readonly version: string\n readonly attempt: number\n readonly reason: string\n }\n /** An archive is being written. */\n | { readonly _tag: \"ArchiveStarted\"; readonly path: string; readonly entryCount: number }\n /** An archive finished. */\n | { readonly _tag: \"ArchiveCompleted\"; readonly path: string; readonly bytes: number }\n /** Something noteworthy but non-fatal, e.g. a deprecated package. */\n | { readonly _tag: \"Warning\"; readonly message: string }\n\n/** The reporting sink. */\nexport interface ProgressService {\n readonly emit: (event: ProgressEvent) => Effect.Effect<void>\n}\n\n/** Service tag for progress reporting. */\nexport class Progress extends Context.Service<Progress, ProgressService>()(\n \"@packall/core/Progress\"\n) {}\n\n/** Emits an event to whichever reporter is installed. */\nexport const emit = (event: ProgressEvent): Effect.Effect<void, never, Progress> =>\n Effect.gen(function*() {\n const progress = yield* Progress\n yield* progress.emit(event)\n })\n\n/**\n * Discards every event.\n *\n * The default for library consumers and for tests that do not care about\n * progress — silence should never require ceremony.\n */\nexport const layerSilent: Layer.Layer<Progress> = Layer.succeed(Progress)({\n emit: () => Effect.void\n})\n\n/** Sends every event to a callback. Used by the CLI renderer. */\nexport const layerCallback = (\n onEvent: (event: ProgressEvent) => void\n): Layer.Layer<Progress> =>\n Layer.succeed(Progress)({\n emit: (event) => Effect.sync(() => onEvent(event))\n })\n\n/**\n * Accumulates every event into a `Ref`, for assertions.\n *\n * Returned as `[layer, ref]` so a test can provide the layer and then read the\n * transcript afterwards.\n */\nexport const makeCollector = Effect.gen(function*() {\n const ref = yield* Ref.make<ReadonlyArray<ProgressEvent>>([])\n const layer = Layer.succeed(Progress)({\n emit: (event: ProgressEvent) => Ref.update(ref, (events) => [...events, event])\n })\n return { layer, events: Ref.get(ref) } as const\n})\n","/**\n * Turning a staged directory tree into a gzipped tarball.\n *\n * Uses `node-tar`, the same library npm itself packs with. Writing a USTAR\n * encoder by hand would be a fun afternoon and a bad idea: scoped package\n * paths routinely exceed the 100-byte name field, so correctness depends on\n * prefix-splitting and PAX headers that `tar` already gets right.\n */\nimport * as Effect from \"effect/Effect\"\nimport * as FileSystem from \"effect/FileSystem\"\nimport type { PlatformError } from \"effect/PlatformError\"\nimport { create } from \"tar\"\nimport { ArchiveError } from \"./Errors.js\"\nimport * as Progress from \"./Progress.js\"\n\n/** A finished archive. */\nexport interface ArchiveResult {\n readonly path: string\n readonly bytes: number\n}\n\n/**\n * Packs `entries` (paths relative to `cwd`) into a gzipped tar at `outPath`.\n *\n * `portable` normalises uid/gid/mtime so the same inputs produce byte-identical\n * output — which matters when a security team wants to diff two bundles or\n * re-derive one from a manifest.\n */\nexport const createArchive = (options: {\n readonly cwd: string\n readonly entries: ReadonlyArray<string>\n readonly outPath: string\n readonly gzipLevel?: number | undefined\n}): Effect.Effect<ArchiveResult, ArchiveError | PlatformError, FileSystem.FileSystem | Progress.Progress> =>\n Effect.gen(function*() {\n const fs = yield* FileSystem.FileSystem\n\n yield* Progress.emit({\n _tag: \"ArchiveStarted\",\n path: options.outPath,\n entryCount: options.entries.length\n })\n\n yield* Effect.tryPromise({\n try: () =>\n create(\n {\n gzip: options.gzipLevel === undefined ? true : { level: options.gzipLevel },\n file: options.outPath,\n cwd: options.cwd,\n portable: true,\n // Undo the `./` added below, so recorded entry names stay exactly\n // the registry paths the manifest lists.\n onWriteEntry: (entry) => {\n entry.path = entry.path.replace(/^\\.\\//, \"\")\n }\n },\n // Sorted so archive order is stable across runs and platforms.\n [...options.entries].sort().map(dotSlash)\n ),\n catch: (cause) => new ArchiveError(options.outPath, describe(cause), { cause })\n })\n\n const info = yield* fs.stat(options.outPath)\n const bytes = Number(info.size)\n\n yield* Progress.emit({ _tag: \"ArchiveCompleted\", path: options.outPath, bytes })\n\n return { path: options.outPath, bytes }\n })\n\n/**\n * Guards every entry against tar's `@` convention.\n *\n * In a tar file list, a leading `@` means \"splice in the entries of this other\n * archive\" — a GNU convention `node-tar` implements by stripping the `@` and\n * looking for what is left. Every scoped package is a top-level entry starting\n * with `@`, so this hit the bundler in both possible ways:\n *\n * - `@oxc-project` became `oxc-project`, which does not exist, and the run died\n * with an ENOENT naming a path that appears nowhere in the staging tree.\n * - `@esbuild` became `esbuild`, which *does* exist — the unscoped package of\n * the same name sitting right next to it. No error, and every scoped tarball\n * silently missing from a bundle that reported success. That is the dangerous\n * one: you would not find out until the install failed behind the firewall.\n *\n * `./@scope` is not subject to the convention and resolves identically.\n */\nconst dotSlash = (entry: string): string => (entry.startsWith(\"./\") ? entry : `./${entry}`)\n\nconst describe = (cause: unknown): string =>\n cause instanceof Error ? cause.message : String(cause)\n","/**\n * Checksum verification for downloaded tarballs.\n *\n * A bundle is a supply-chain artifact that gets imported wholesale into a\n * corporate registry, so \"the bytes I got are the bytes the registry promised\"\n * is the one property worth being strict about. A failed check discards the\n * download rather than warning and carrying on.\n *\n * Implemented directly against `node:crypto` rather than pulling in `ssri`,\n * because the subset of Subresource Integrity that npm actually publishes is\n * small and entirely mechanical.\n */\nimport { createHash, timingSafeEqual } from \"node:crypto\"\n\n/** One parsed SRI hash. */\nexport interface IntegrityHash {\n readonly algorithm: string\n /** Base64 digest, exactly as written in the SRI string. */\n readonly digest: string\n}\n\nconst SUPPORTED = new Set([\"sha512\", \"sha384\", \"sha256\", \"sha1\"])\n\n/**\n * Parses an SRI string such as `sha512-abc...==`.\n *\n * npm permits several space-separated hashes; we keep every one we can verify\n * and ignore algorithms Node does not implement.\n */\nexport const parseIntegrity = (integrity: string): ReadonlyArray<IntegrityHash> => {\n const hashes: Array<IntegrityHash> = []\n for (const token of integrity.trim().split(/\\s+/)) {\n if (token.length === 0) continue\n const dash = token.indexOf(\"-\")\n if (dash <= 0) continue\n const algorithm = token.slice(0, dash).toLowerCase()\n const digest = token.slice(dash + 1)\n if (!SUPPORTED.has(algorithm) || digest.length === 0) continue\n hashes.push({ algorithm, digest })\n }\n return hashes\n}\n\n/** Computes the base64 digest of some bytes under one algorithm. */\nexport const digestOf = (data: Uint8Array, algorithm: string): string =>\n createHash(algorithm).update(data).digest(\"base64\")\n\n/** Computes the hex digest of some bytes — the form legacy `shasum` uses. */\nexport const hexDigestOf = (data: Uint8Array, algorithm: string): string =>\n createHash(algorithm).update(data).digest(\"hex\")\n\n/** Result of checking a download. */\nexport type VerificationResult =\n /** Verified against at least one checksum. */\n | { readonly _tag: \"Verified\"; readonly using: string }\n /** The registry advertised no checksum we could use. */\n | { readonly _tag: \"Unverifiable\"; readonly reason: string }\n /** A checksum was present and did not match. */\n | { readonly _tag: \"Mismatch\"; readonly expected: string; readonly actual: string }\n\n/** Constant-time comparison of two digest strings of equal length. */\nconst digestsEqual = (a: string, b: string): boolean => {\n const left = Buffer.from(a)\n const right = Buffer.from(b)\n // `timingSafeEqual` throws on unequal lengths, which is itself a mismatch.\n return left.length === right.length && timingSafeEqual(left, right)\n}\n\n/**\n * Checks bytes against whichever checksums the registry supplied.\n *\n * SRI is preferred; `shasum` is the fallback for versions published before\n * integrity strings existed. If the registry gave us neither, that is reported\n * as `Unverifiable` rather than silently treated as a pass — the caller decides\n * whether to tolerate it.\n */\nexport const verify = (\n data: Uint8Array,\n dist: { readonly integrity?: string | undefined; readonly shasum?: string | undefined }\n): VerificationResult => {\n if (dist.integrity !== undefined && dist.integrity.length > 0) {\n const hashes = parseIntegrity(dist.integrity)\n if (hashes.length === 0) {\n return { _tag: \"Unverifiable\", reason: `no supported algorithm in \"${dist.integrity}\"` }\n }\n // Strongest first, so a mismatch is reported against the best hash present.\n const ordered = [...hashes].sort(\n (a, b) => strength(b.algorithm) - strength(a.algorithm)\n )\n const best = ordered[0]!\n const actual = digestOf(data, best.algorithm)\n return digestsEqual(actual, best.digest)\n ? { _tag: \"Verified\", using: best.algorithm }\n : {\n _tag: \"Mismatch\",\n expected: `${best.algorithm}-${best.digest}`,\n actual: `${best.algorithm}-${actual}`\n }\n }\n\n if (dist.shasum !== undefined && dist.shasum.length > 0) {\n const actual = hexDigestOf(data, \"sha1\")\n return digestsEqual(actual.toLowerCase(), dist.shasum.toLowerCase())\n ? { _tag: \"Verified\", using: \"sha1\" }\n : { _tag: \"Mismatch\", expected: `sha1-${dist.shasum}`, actual: `sha1-${actual}` }\n }\n\n return { _tag: \"Unverifiable\", reason: \"registry advertised no integrity or shasum\" }\n}\n\nconst strength = (algorithm: string): number => {\n switch (algorithm) {\n case \"sha512\":\n return 4\n case \"sha384\":\n return 3\n case \"sha256\":\n return 2\n default:\n return 1\n }\n}\n","/**\n * The on-disk shape of a bundle.\n *\n * Everything is laid out exactly the way a registry serves it:\n *\n * lodash/-/lodash-4.17.21.tgz\n * @babel/core/-/core-7.24.0.tgz\n *\n * That is not an Artifactory convention — it is the path structure in every\n * `dist.tarball` URL npm publishes, which is why the same tree imports into\n * Artifactory, Nexus and Verdaccio without translation. Note that a scoped\n * package's file name drops the scope: `@babel/core` becomes `core-7.24.0.tgz`\n * under an `@babel/core/-/` directory.\n */\n\n/** Splits `@scope/name` into its parts. `scope` is undefined when unscoped. */\nexport const splitName = (\n name: string\n): { readonly scope: string | undefined; readonly bare: string } => {\n if (!name.startsWith(\"@\")) return { scope: undefined, bare: name }\n const slash = name.indexOf(\"/\")\n if (slash === -1) return { scope: undefined, bare: name }\n return { scope: name.slice(0, slash), bare: name.slice(slash + 1) }\n}\n\n/** `@babel/core` + `7.24.0` -> `core-7.24.0.tgz` */\nexport const tarballFileName = (name: string, version: string): string => {\n const { bare } = splitName(name)\n return `${bare}-${version}.tgz`\n}\n\n/**\n * The path of one package tarball within a bundle, using `/` separators\n * regardless of host platform — these become tar entry names, and tar entries\n * are always POSIX.\n */\nexport const packagePath = (name: string, version: string): string =>\n `${name}/-/${tarballFileName(name, version)}`\n\n/** File name of the manifest that ships inside every bundle. */\nexport const MANIFEST_FILE = \"bundle-manifest.json\"\n\n/** File name of the short import guide that ships inside every bundle. */\nexport const README_FILE = \"IMPORT.md\"\n\n/**\n * Name of the archive produced for one root spec in `per-spec` layout.\n *\n * Scoped names are flattened (`@babel/core` -> `babel-core`) because a `/` in a\n * file name is not a thing, and `@` confuses enough shells and web UIs to be\n * worth avoiding.\n */\nexport const perSpecArchiveName = (name: string, version: string): string => {\n const { scope, bare } = splitName(name)\n const prefix = scope === undefined ? bare : `${scope.slice(1)}-${bare}`\n return `${prefix}-${version}.tgz`\n}\n\n/** Name of the archive produced in `single` layout. */\nexport const singleArchiveName = (base = \"bundle\"): string => `${base}.tgz`\n\n/**\n * The import guide written into each bundle.\n *\n * Kept short and copy-pasteable on purpose: whoever opens this is mid-task on a\n * restricted network and does not want prose.\n */\nexport const importGuide = (options: {\n readonly packageCount: number\n readonly createdAt: string\n readonly toolVersion: string\n}): string =>\n `# Importing this bundle\n\n${options.packageCount} package tarball(s), laid out exactly as an npm registry serves them:\n\n <package-name>/-/<file>.tgz\n @<scope>/<name>/-/<file>.tgz\n\nCreated ${options.createdAt} by packall ${options.toolVersion}.\nSee ${MANIFEST_FILE} for the full list with checksums.\n\n## JFrog Artifactory\n\nUnpack, then upload the tree into a **local npm** repository. The layout already\nmatches what Artifactory expects, so no path rewriting is needed:\n\n tar -xzf <this-bundle>.tgz -C ./bundle\n jf rt upload \"bundle/(**)\" \"<npm-local-repo>/{1}\" --flat=false\n\n## Verdaccio / Nexus / any npm registry\n\nPublish each tarball individually:\n\n find ./bundle -name '*.tgz' -exec npm publish --registry <url> {} \\\\;\n\n## Verifying before import\n\n node -e \"const m=require('./bundle/${MANIFEST_FILE}');console.log(m.packages.length+' packages')\"\n\nEvery entry in ${MANIFEST_FILE} carries the integrity string the source registry\nadvertised, and each tarball was checked against it at download time.\n`\n","/**\n * The registry seam.\n *\n * This is the **only** place in the engine that knows a registry exists.\n * Everything downstream — range resolution, the dependency walk, layout,\n * archiving — is expressed against these three operations, so swapping npm for\n * something else means implementing this interface and nothing more.\n *\n * `@packall/registry-npm` provides the implementation that speaks the plain\n * npm registry protocol, which is what Artifactory, Nexus, Verdaccio, GitHub\n * Packages and registry.npmjs.org all serve.\n */\nimport * as Context from \"effect/Context\"\nimport type * as Effect from \"effect/Effect\"\nimport type { BundlerError } from \"./Errors.js\"\n\n/**\n * A single published version, as the registry describes it.\n *\n * This is a narrowed view of a package.json — only the fields that affect what\n * has to be downloaded. Unknown fields are ignored rather than rejected,\n * because registries add metadata over time and a bundler that breaks on new\n * metadata is worse than useless.\n */\nexport interface PackageManifest {\n readonly name: string\n readonly version: string\n\n readonly dependencies?: Readonly<Record<string, string>> | undefined\n readonly optionalDependencies?: Readonly<Record<string, string>> | undefined\n readonly peerDependencies?: Readonly<Record<string, string>> | undefined\n readonly peerDependenciesMeta?:\n | Readonly<Record<string, { readonly optional?: boolean | undefined }>>\n | undefined\n readonly devDependencies?: Readonly<Record<string, string>> | undefined\n readonly bundleDependencies?: ReadonlyArray<string> | undefined\n\n /** Platform constraints, used when `--platform` narrows optional deps. */\n readonly os?: ReadonlyArray<string> | undefined\n readonly cpu?: ReadonlyArray<string> | undefined\n readonly libc?: ReadonlyArray<string> | undefined\n\n readonly deprecated?: string | undefined\n\n readonly dist: PackageDist\n}\n\n/** Where the tarball lives and how to prove it arrived intact. */\nexport interface PackageDist {\n readonly tarball: string\n /** SRI string, e.g. `sha512-...`. Preferred over `shasum`. */\n readonly integrity?: string | undefined\n /** Legacy hex sha1. Still the only checksum on very old versions. */\n readonly shasum?: string | undefined\n readonly unpackedSize?: number | undefined\n readonly fileCount?: number | undefined\n}\n\n/** Everything the registry knows about one package. */\nexport interface Packument {\n readonly name: string\n /** `{ latest: \"1.2.3\", next: \"2.0.0-beta.1\" }` */\n readonly distTags: Readonly<Record<string, string>>\n /** Every published version, keyed by version string. */\n readonly versions: Readonly<Record<string, PackageManifest>>\n}\n\n/** The set of operations a registry backend has to provide. */\nexport interface RegistryService {\n /** Short identifier for the manifest and for error messages, e.g. `\"npm\"`. */\n readonly kind: string\n\n /**\n * The registry URL that will actually be used for a given package, after\n * per-scope configuration is applied. Used for reporting only.\n */\n readonly registryFor: (packageName: string) => string\n\n /**\n * Cheap liveness check, run once before any real work.\n *\n * This is what turns \"hangs forever behind a dead VPN\" into a five-second\n * error naming the host we could not reach.\n */\n readonly preflight: Effect.Effect<void, BundlerError>\n\n /**\n * Full metadata for a package. Implementations are expected to memoise:\n * the dependency walk asks for the same popular packages repeatedly.\n */\n readonly packument: (packageName: string) => Effect.Effect<Packument, BundlerError>\n\n /** Fetches the tarball bytes for one published version. */\n readonly download: (manifest: PackageManifest) => Effect.Effect<Uint8Array, BundlerError>\n}\n\n/**\n * Service tag for the registry backend.\n *\n * @example\n * ```ts\n * import { Effect } from \"effect\"\n * import { Registry } from \"@packall/core\"\n *\n * const program = Effect.gen(function*() {\n * const registry = yield* Registry\n * return yield* registry.packument(\"lodash\")\n * })\n * ```\n */\nexport class Registry extends Context.Service<Registry, RegistryService>()(\n \"@packall/core/Registry\"\n) {}\n\n/** Extracts the dist-tag mapping, defaulting sensibly when a registry omits it. */\nexport const resolveDistTag = (packument: Packument, tag: string): string | undefined =>\n packument.distTags[tag]\n\n/** All published version strings, in registry order. */\nexport const publishedVersions = (packument: Packument): ReadonlyArray<string> =>\n Object.keys(packument.versions)\n","/**\n * Fetching tarballs into the staging tree.\n *\n * Downloads run concurrently, every one is checksum-verified before it is\n * written, and the destination is always the scoped temp directory — nothing\n * lands next to the user's own files.\n */\nimport * as Effect from \"effect/Effect\"\nimport * as FileSystem from \"effect/FileSystem\"\nimport * as Path from \"effect/Path\"\nimport type { PlatformError } from \"effect/PlatformError\"\nimport type { BundlerError } from \"./Errors.js\"\nimport { IntegrityError, OutputError } from \"./Errors.js\"\nimport * as Integrity from \"./Integrity.js\"\nimport { packagePath } from \"./Layout.js\"\nimport * as Progress from \"./Progress.js\"\nimport { Registry } from \"./Registry.js\"\nimport type { ResolvedPackage } from \"./Resolve.js\"\n\n/** What a completed download run produced. */\nexport interface DownloadReport {\n /** `name@version` -> bytes written. */\n readonly sizes: ReadonlyMap<string, number>\n /** Packages the registry advertised no usable checksum for. */\n readonly unverified: ReadonlyArray<string>\n readonly totalBytes: number\n}\n\n/**\n * Downloads every package into `destDir`, laid out the way a registry serves\n * them.\n *\n * `verifyIntegrity` defaulting to on is deliberate: a corrupt tarball that\n * makes it into a corporate registry is far more expensive than a failed run.\n */\nexport const downloadAll = (\n packages: ReadonlyArray<ResolvedPackage>,\n destDir: string,\n options: { readonly concurrency: number; readonly verifyIntegrity: boolean }\n): Effect.Effect<\n DownloadReport,\n BundlerError | PlatformError,\n Registry | Progress.Progress | FileSystem.FileSystem | Path.Path\n> =>\n Effect.gen(function*() {\n const fs = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n const registry = yield* Registry\n\n yield* Progress.emit({ _tag: \"PhaseStarted\", phase: \"download\", total: packages.length })\n\n let completed = 0\n const sizes = new Map<string, number>()\n const unverified: Array<string> = []\n\n const results = yield* Effect.forEach(\n packages,\n (pkg) =>\n Effect.gen(function*() {\n const key = `${pkg.name}@${pkg.version}`\n\n yield* Progress.emit({\n _tag: \"DownloadStarted\",\n name: pkg.name,\n version: pkg.version\n })\n\n const bytes = yield* registry.download(pkg.manifest)\n\n if (options.verifyIntegrity) {\n const result = Integrity.verify(bytes, pkg.manifest.dist)\n if (result._tag === \"Mismatch\") {\n return yield* Effect.fail(\n new IntegrityError(pkg.name, pkg.version, result.expected, result.actual)\n )\n }\n if (result._tag === \"Unverifiable\") {\n yield* Progress.emit({\n _tag: \"Warning\",\n message: `${key} could not be verified (${result.reason})`\n })\n }\n }\n\n const verifiable =\n (pkg.manifest.dist.integrity?.length ?? 0) > 0 ||\n (pkg.manifest.dist.shasum?.length ?? 0) > 0\n\n const relative = packagePath(pkg.name, pkg.version)\n const target = path.join(destDir, ...relative.split(\"/\"))\n\n yield* fs.makeDirectory(path.dirname(target), { recursive: true }).pipe(\n Effect.mapError(\n (cause) =>\n new OutputError(path.dirname(target), \"could not create directory\", { cause })\n )\n )\n yield* fs.writeFile(target, bytes).pipe(\n Effect.mapError((cause) => new OutputError(target, \"could not write tarball\", { cause }))\n )\n\n // Counting here rather than inside the concurrent body would be\n // wrong; each fiber increments as it finishes, which is what makes\n // the progress counter monotonic.\n completed += 1\n yield* Progress.emit({\n _tag: \"DownloadCompleted\",\n name: pkg.name,\n version: pkg.version,\n bytes: bytes.byteLength,\n completedCount: completed,\n totalCount: packages.length\n })\n\n return { key, bytes: bytes.byteLength, verifiable } as const\n }),\n { concurrency: options.concurrency }\n )\n\n for (const result of results) {\n sizes.set(result.key, result.bytes)\n if (!result.verifiable) unverified.push(result.key)\n }\n\n yield* Progress.emit({ _tag: \"PhaseCompleted\", phase: \"download\" })\n\n return {\n sizes,\n unverified,\n totalBytes: results.reduce((sum, r) => sum + r.bytes, 0)\n }\n })\n","/**\n * Platform matching for optional dependencies.\n *\n * This module exists because of one specific, very annoying failure mode.\n *\n * Packages with native code — esbuild, rollup, sharp, swc, lightningcss,\n * `@parcel/watcher` — publish their binary as a *set* of sibling packages, one\n * per platform, and list all of them in `optionalDependencies`. npm installs\n * only the one matching the current machine and silently skips the rest.\n *\n * So if you bundle on a Mac and skip the non-matching optional deps, the\n * resulting bundle installs fine on your Mac and fails on the Linux CI box\n * inside the firewall — which is the only place it actually matters. Hence the\n * default is \"take every platform\" and narrowing is opt-in.\n */\n\n/** A target to keep, e.g. `linux-x64`, `linux-x64-musl`, or just `linux`. */\nexport interface PlatformTarget {\n readonly os: string\n /** Undefined means \"every architecture for this OS\". */\n readonly cpu?: string | undefined\n /** `glibc` / `musl`. Undefined means \"don't care\". */\n readonly libc?: string | undefined\n}\n\n/**\n * Which platforms optional dependencies should be resolved for.\n *\n * - `All` — keep everything, regardless of `os`/`cpu`/`libc` (the default).\n * - `Targets` — keep only packages that could install on one of these.\n */\nexport type PlatformFilter =\n | { readonly _tag: \"All\" }\n | { readonly _tag: \"Targets\"; readonly targets: ReadonlyArray<PlatformTarget> }\n\nexport const allPlatforms: PlatformFilter = { _tag: \"All\" }\n\nexport const platformTargets = (targets: ReadonlyArray<PlatformTarget>): PlatformFilter => ({\n _tag: \"Targets\",\n targets\n})\n\n/** The machine we are currently running on. */\nexport const currentPlatform = (): PlatformTarget => ({\n os: process.platform,\n cpu: process.arch\n})\n\n/**\n * npm's documented `os` values, plus the names people actually type.\n *\n * An OS on its own is a valid target, so a typo has to be caught here — the\n * whole failure mode this tool exists to prevent is a bundle that looks fine\n * and installs nothing. `--platform windows` silently matching no binding at\n * all would be precisely that, so it is corrected rather than accepted.\n */\nconst OS_ALIASES: Readonly<Record<string, string>> = {\n win: \"win32\",\n windows: \"win32\",\n mac: \"darwin\",\n macos: \"darwin\",\n osx: \"darwin\"\n}\n\nconst KNOWN_OS: ReadonlySet<string> = new Set([\n \"aix\",\n \"android\",\n \"cygwin\",\n \"darwin\",\n \"freebsd\",\n \"haiku\",\n \"linux\",\n \"netbsd\",\n \"openbsd\",\n \"sunos\",\n \"win32\"\n])\n\nconst LIBC = new Set([\"musl\", \"glibc\"])\n\n/**\n * Parses `linux`, `linux-x64`, `darwin-arm64`, `win32-x64`, `linux-x64-musl`,\n * `linux-musl`.\n *\n * An OS on its own means every architecture for that OS, which is almost always\n * what you want: \"the Windows and Linux bindings\" is a far more natural way to\n * describe a target set than enumerating four `os-arch` pairs, and it keeps\n * working when a package adds an arm64 build.\n *\n * Returns `null` rather than throwing so the CLI can report every bad value at\n * once alongside the list of accepted forms.\n */\nexport const parsePlatformTarget = (input: string): PlatformTarget | null => {\n const parts = input.trim().toLowerCase().split(\"-\").filter((p) => p.length > 0)\n if (parts.length === 0 || parts.length > 3) return null\n\n const rawOs = parts[0]!\n const os = OS_ALIASES[rawOs] ?? rawOs\n if (!KNOWN_OS.has(os)) return null\n\n if (parts.length === 1) return { os }\n\n // `linux-musl` is an OS plus a libc, not an OS plus an architecture.\n if (parts.length === 2 && LIBC.has(parts[1]!)) return { os, libc: parts[1]! }\n\n const cpu = parts[1]!\n if (parts.length === 2) return { os, cpu }\n\n const libc = parts[2]!\n if (!LIBC.has(libc)) return null\n return { os, cpu, libc }\n}\n\n/**\n * npm's `os`/`cpu`/`libc` fields use a list of allowed values, where a leading\n * `!` negates. An empty or absent list means \"no constraint\".\n *\n * The semantics npm implements: if any negated entry matches, reject. Otherwise\n * if there are any positive entries, at least one must match.\n */\nconst listAllows = (list: ReadonlyArray<string> | undefined, value: string): boolean => {\n if (list === undefined || list.length === 0) return true\n\n let hasPositive = false\n let positiveMatched = false\n\n for (const entry of list) {\n const normalized = entry.trim().toLowerCase()\n if (normalized.length === 0) continue\n if (normalized === \"any\" || normalized === \"*\") return true\n\n if (normalized.startsWith(\"!\")) {\n if (normalized.slice(1) === value) return false\n } else {\n hasPositive = true\n if (normalized === value) positiveMatched = true\n }\n }\n\n return hasPositive ? positiveMatched : true\n}\n\n/** Constraints declared by a package, as they appear in its manifest. */\nexport interface PlatformConstraints {\n readonly os?: ReadonlyArray<string> | undefined\n readonly cpu?: ReadonlyArray<string> | undefined\n readonly libc?: ReadonlyArray<string> | undefined\n}\n\n/** Would this package install on this specific target? */\nexport const matchesTarget = (\n constraints: PlatformConstraints,\n target: PlatformTarget\n): boolean => {\n if (!listAllows(constraints.os, target.os)) return false\n // An undefined cpu means the target is the whole OS, so any architecture the\n // package declares qualifies.\n if (target.cpu !== undefined && !listAllows(constraints.cpu, target.cpu)) return false\n if (target.libc !== undefined && !listAllows(constraints.libc, target.libc)) return false\n return true\n}\n\n/**\n * Should this package be included, given the active filter?\n *\n * Under `All` this is unconditionally `true` — that is the whole point.\n */\nexport const isIncluded = (\n constraints: PlatformConstraints,\n filter: PlatformFilter\n): boolean => {\n if (filter._tag === \"All\") return true\n return filter.targets.some((target) => matchesTarget(constraints, target))\n}\n\n/** Renders a filter for the manifest and for `--dry-run` output. */\nexport const formatPlatformFilter = (filter: PlatformFilter): string => {\n if (filter._tag === \"All\") return \"all\"\n return filter.targets\n .map((t) => [t.os, t.cpu, t.libc].filter((part) => part !== undefined).join(\"-\"))\n .join(\",\")\n}\n","/**\n * Parsing and validation of package specs — the `lodash`, `react@18.2.0`,\n * `@babel/core@^7`, `typescript@next` strings a user types.\n *\n * Deliberately dependency-light and synchronous: parsing must never touch the\n * network, so `--dry-run` and argument validation stay instant.\n */\nimport semver from \"semver\"\nimport { InvalidSpecError } from \"./Errors.js\"\n\n/** How a spec narrows down which version(s) of a package we want. */\nexport type Selector =\n /** An exact, fully-qualified version: `react@18.2.0`. */\n | { readonly _tag: \"Exact\"; readonly version: string }\n /** A semver range: `react@^18`, `react@>=17 <19`, `react@*`. */\n | { readonly _tag: \"Range\"; readonly range: string }\n /** A dist-tag: `react@latest`, `typescript@next`. */\n | { readonly _tag: \"Tag\"; readonly tag: string }\n\n/** A parsed, validated package spec. */\nexport interface PackageSpec {\n /** The npm package name, including scope. */\n readonly name: string\n /** What the user asked for after the `@`. */\n readonly selector: Selector\n /** The original string, kept verbatim for error messages and the manifest. */\n readonly raw: string\n}\n\n/** Renders a spec back into the canonical `name@selector` form. */\nexport const formatSpec = (spec: PackageSpec): string => {\n switch (spec.selector._tag) {\n case \"Exact\":\n return `${spec.name}@${spec.selector.version}`\n case \"Range\":\n return `${spec.name}@${spec.selector.range}`\n case \"Tag\":\n return `${spec.name}@${spec.selector.tag}`\n }\n}\n\n/** Human-readable form of just the selector part. */\nexport const formatSelector = (selector: Selector): string => {\n switch (selector._tag) {\n case \"Exact\":\n return selector.version\n case \"Range\":\n return selector.range\n case \"Tag\":\n return selector.tag\n }\n}\n\nconst MAX_NAME_LENGTH = 214\n\n/**\n * Validates an npm package name against the rules the registry actually\n * enforces. Returns `null` when valid, or the reason it is not.\n */\nexport const validatePackageName = (name: string): string | null => {\n if (name.length === 0) return \"name is empty\"\n if (name.length > MAX_NAME_LENGTH) {\n return `name is longer than ${MAX_NAME_LENGTH} characters`\n }\n if (name.trim() !== name) return \"name has leading or trailing whitespace\"\n if (name.startsWith(\".\")) return \"name cannot start with a period\"\n if (name.startsWith(\"_\")) return \"name cannot start with an underscore\"\n if (name !== name.toLowerCase()) return \"name cannot contain capital letters\"\n\n if (name.startsWith(\"@\")) {\n const slash = name.indexOf(\"/\")\n if (slash === -1) return \"scoped name is missing the '/name' part\"\n const scope = name.slice(1, slash)\n const rest = name.slice(slash + 1)\n if (scope.length === 0) return \"scope is empty\"\n if (rest.length === 0) return \"name after the scope is empty\"\n if (rest.includes(\"/\")) return \"name contains more than one '/'\"\n if (!SEGMENT_RE.test(scope)) return `scope \"${scope}\" contains illegal characters`\n if (!SEGMENT_RE.test(rest)) return `name \"${rest}\" contains illegal characters`\n return null\n }\n\n if (name.includes(\"/\")) return \"unscoped name cannot contain '/'\"\n if (!SEGMENT_RE.test(name)) return \"name contains illegal characters\"\n return null\n}\n\n// The registry accepts URL-safe characters plus `-`, `.` and `_`.\nconst SEGMENT_RE = /^[a-z0-9\\-._~]+$/\n\n/**\n * Parses a single spec string.\n *\n * Splitting on `@` is the fiddly part: a scoped name *starts* with `@`, so we\n * look for the last `@` that is not at index 0.\n */\nexport const parseSpec = (raw: string): PackageSpec => {\n const input = raw.trim()\n if (input.length === 0) {\n throw new InvalidSpecError(raw, \"spec is empty\")\n }\n\n const at = input.lastIndexOf(\"@\")\n const hasSelector = at > 0\n const name = hasSelector ? input.slice(0, at) : input\n const selectorText = hasSelector ? input.slice(at + 1) : \"\"\n\n const nameProblem = validatePackageName(name)\n if (nameProblem !== null) {\n throw new InvalidSpecError(raw, nameProblem)\n }\n\n if (!hasSelector || selectorText.length === 0) {\n return { name, selector: { _tag: \"Tag\", tag: \"latest\" }, raw: input }\n }\n\n return { name, selector: parseSelector(raw, selectorText), raw: input }\n}\n\n/** Classifies the part after the `@` as an exact version, a range, or a dist-tag. */\nexport const parseSelector = (raw: string, text: string): Selector => {\n // `semver.valid` only accepts a complete `x.y.z`, which is exactly the\n // \"pin me to this one version\" case.\n const exact = semver.valid(text, { loose: false })\n if (exact !== null) {\n return { _tag: \"Exact\", version: exact }\n }\n\n if (semver.validRange(text, { loose: false }) !== null) {\n return { _tag: \"Range\", range: text }\n }\n\n // Anything left has to be a dist-tag. Tags may not look like versions and\n // may not contain characters that would break a registry URL.\n if (!DIST_TAG_RE.test(text)) {\n throw new InvalidSpecError(\n raw,\n `\"${text}\" is not a valid version, semver range, or dist-tag`\n )\n }\n return { _tag: \"Tag\", tag: text }\n}\n\nconst DIST_TAG_RE = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/\n\n/**\n * Parses many specs, collecting *every* failure rather than stopping at the\n * first. Somebody bundling forty packages should be told about all four typos\n * in one go, not made to re-run four times.\n */\nexport const parseSpecs = (\n inputs: ReadonlyArray<string>\n): { readonly specs: ReadonlyArray<PackageSpec>; readonly errors: ReadonlyArray<InvalidSpecError> } => {\n const specs: Array<PackageSpec> = []\n const errors: Array<InvalidSpecError> = []\n for (const input of inputs) {\n try {\n specs.push(parseSpec(input))\n } catch (error) {\n if (error instanceof InvalidSpecError) {\n errors.push(error)\n } else {\n throw error\n }\n }\n }\n return { specs, errors }\n}\n\n/**\n * Collapses duplicate specs, keeping the first occurrence.\n *\n * `npmb react react@latest` is a plausible thing to type and should not\n * download React twice.\n */\nexport const dedupeSpecs = (specs: ReadonlyArray<PackageSpec>): ReadonlyArray<PackageSpec> => {\n const seen = new Set<string>()\n const out: Array<PackageSpec> = []\n for (const spec of specs) {\n const key = formatSpec(spec)\n if (seen.has(key)) continue\n seen.add(key)\n out.push(spec)\n }\n return out\n}\n","/**\n * The manifest written into every bundle.\n *\n * This is the audit trail. Before anything is imported into a corporate\n * registry somebody is usually required to answer \"what exactly is in here and\n * where did it come from\" — this file answers that without unpacking a single\n * tarball.\n */\nimport type { Resolution, ResolvedPackage } from \"./Resolve.js\"\nimport { packagePath } from \"./Layout.js\"\nimport type { BundleOptions } from \"./Options.js\"\nimport { formatPlatformFilter } from \"./Platform.js\"\nimport { formatSpec } from \"./Spec.js\"\n\n/** Schema version, bumped when the shape changes incompatibly. */\nexport const MANIFEST_VERSION = 1\n\nexport interface ManifestEntry {\n readonly name: string\n readonly version: string\n /** Path of this tarball inside the bundle. */\n readonly path: string\n /** The URL it was downloaded from. */\n readonly tarball: string\n /** SRI integrity string as advertised by the source registry, when present. */\n readonly integrity?: string | undefined\n /** Legacy sha1, present on older published versions. */\n readonly shasum?: string | undefined\n /** Actual size on disk, in bytes. */\n readonly bytes?: number | undefined\n /** Human-readable justifications: `root:react@18.2.0`, `prod:scheduler@0.23.0`. */\n readonly reasons: ReadonlyArray<string>\n}\n\nexport interface BundleManifest {\n readonly manifestVersion: number\n readonly tool: { readonly name: string; readonly version: string }\n readonly createdAt: string\n readonly registry: { readonly kind: string; readonly url: string }\n /** What the user asked for, verbatim. */\n readonly requested: ReadonlyArray<string>\n /** What each request expanded to. */\n readonly roots: ReadonlyArray<{\n readonly spec: string\n readonly versions: ReadonlyArray<string>\n readonly packageCount: number\n }>\n readonly options: {\n readonly layout: string\n readonly optionalDependencies: boolean\n readonly peerDependencies: boolean\n readonly platforms: string\n readonly allVersions: boolean\n readonly includePrerelease: boolean\n readonly integrityVerified: boolean\n }\n readonly packages: ReadonlyArray<ManifestEntry>\n readonly warnings: ReadonlyArray<string>\n readonly totals: {\n readonly packages: number\n readonly bytes: number\n }\n}\n\n/** Renders a package's reasons into short, greppable strings. */\nexport const formatReasons = (pkg: ResolvedPackage): ReadonlyArray<string> =>\n pkg.reasons.map((reason) =>\n reason._tag === \"Root\" ? `root:${reason.spec}` : `${reason.kind}:${reason.from}`\n )\n\n/** Builds the manifest for a completed (or dry) run. */\nexport const buildManifest = (input: {\n readonly resolution: Resolution\n /** Only the packages actually included in *this* archive. */\n readonly included: ReadonlyArray<ResolvedPackage>\n readonly options: BundleOptions\n readonly registry: { readonly kind: string; readonly url: string }\n readonly toolVersion: string\n readonly sizes: ReadonlyMap<string, number>\n readonly createdAt?: Date | undefined\n}): BundleManifest => {\n const includedNames = new Set(input.included.map((p) => `${p.name}@${p.version}`))\n\n const packages: ReadonlyArray<ManifestEntry> = input.included.map((pkg) => {\n const key = `${pkg.name}@${pkg.version}`\n return {\n name: pkg.name,\n version: pkg.version,\n path: packagePath(pkg.name, pkg.version),\n tarball: pkg.manifest.dist.tarball,\n integrity: pkg.manifest.dist.integrity,\n shasum: pkg.manifest.dist.shasum,\n bytes: input.sizes.get(key),\n reasons: formatReasons(pkg)\n }\n })\n\n const totalBytes = packages.reduce((sum, entry) => sum + (entry.bytes ?? 0), 0)\n\n return {\n manifestVersion: MANIFEST_VERSION,\n tool: { name: \"packall\", version: input.toolVersion },\n createdAt: (input.createdAt ?? new Date()).toISOString(),\n registry: input.registry,\n requested: input.resolution.roots.map((root) => formatSpec(root.spec)),\n roots: input.resolution.roots.map((root) => ({\n spec: formatSpec(root.spec),\n versions: root.versions,\n packageCount: root.closure.filter((key) => includedNames.has(key)).length\n })),\n options: {\n layout: input.options.layout,\n optionalDependencies: input.options.scope.optional,\n peerDependencies: input.options.scope.peer,\n platforms: formatPlatformFilter(input.options.scope.platforms),\n allVersions: input.options.allVersions,\n includePrerelease: input.options.includePrerelease,\n integrityVerified: input.options.verifyIntegrity\n },\n packages,\n warnings: input.resolution.warnings.map((warning) =>\n warning.from === undefined ? warning.message : `${warning.from}: ${warning.message}`\n ),\n totals: {\n packages: packages.length,\n bytes: totalBytes\n }\n }\n}\n\n/** Serialises a manifest with stable key order and a trailing newline. */\nexport const serializeManifest = (manifest: BundleManifest): string =>\n `${JSON.stringify(manifest, null, 2)}\\n`\n","/**\n * Classification of the right-hand side of a dependency entry.\n *\n * `\"dependencies\": { \"x\": \"^1.0.0\" }` is the easy case. Real package.json files\n * also contain aliases, git URLs, tarball URLs, `file:` links and\n * `workspace:` protocols — none of which can be fetched from a registry.\n *\n * Rather than crashing or silently producing a bundle that will not install,\n * we classify each edge and let the caller report precisely what was skipped\n * and why.\n */\nimport semver from \"semver\"\nimport type { Selector } from \"./Spec.js\"\n\n/** What a dependency edge points at. */\nexport type DependencyTarget =\n /** A normal registry dependency. `name` may differ from the key under an alias. */\n | {\n readonly _tag: \"Registry\"\n readonly name: string\n readonly selector: Selector\n /** Set when the edge is an `npm:` alias, e.g. `\"lodash4\": \"npm:lodash@^4\"`. */\n readonly aliasOf?: string | undefined\n }\n /** Something we cannot fetch from a registry. */\n | { readonly _tag: \"Unsupported\"; readonly name: string; readonly raw: string; readonly reason: string }\n\nconst UNSUPPORTED_PROTOCOLS: ReadonlyArray<readonly [string, string]> = [\n [\"file:\", \"local file path\"],\n [\"link:\", \"local link\"],\n [\"workspace:\", \"workspace protocol\"],\n [\"portal:\", \"portal protocol\"],\n [\"patch:\", \"patch protocol\"],\n [\"git:\", \"git dependency\"],\n [\"git+\", \"git dependency\"],\n [\"github:\", \"GitHub shorthand\"],\n [\"gitlab:\", \"GitLab shorthand\"],\n [\"bitbucket:\", \"Bitbucket shorthand\"],\n [\"http:\", \"remote tarball URL\"],\n [\"https:\", \"remote tarball URL\"]\n]\n\n/**\n * Classifies one `name -> range` entry.\n *\n * An empty range, `*`, and `latest` all mean \"any published version\"; npm\n * treats them interchangeably and so do we.\n */\nexport const parseDependencyTarget = (name: string, raw: string): DependencyTarget => {\n const text = raw.trim()\n\n if (text.length === 0 || text === \"*\" || text === \"x\" || text === \"latest\") {\n return { _tag: \"Registry\", name, selector: { _tag: \"Range\", range: \"*\" } }\n }\n\n if (text.startsWith(\"npm:\")) {\n return parseAlias(name, text)\n }\n\n for (const [prefix, reason] of UNSUPPORTED_PROTOCOLS) {\n if (text.startsWith(prefix)) {\n return { _tag: \"Unsupported\", name, raw: text, reason }\n }\n }\n\n // Bare `owner/repo` is GitHub shorthand, but only when it is not a valid\n // range — `>=1.0.0/2` is not a thing, so this ordering is safe.\n if (semver.validRange(text, { loose: true }) === null && /^[\\w.-]+\\/[\\w.-]+/.test(text)) {\n return { _tag: \"Unsupported\", name, raw: text, reason: \"git shorthand\" }\n }\n\n const exact = semver.valid(text, { loose: true })\n if (exact !== null) {\n return { _tag: \"Registry\", name, selector: { _tag: \"Exact\", version: exact } }\n }\n\n if (semver.validRange(text, { loose: true }) !== null) {\n return { _tag: \"Registry\", name, selector: { _tag: \"Range\", range: text } }\n }\n\n // Whatever is left is most plausibly a dist-tag published by a private\n // registry, e.g. `\"@acme/sdk\": \"stable\"`.\n if (/^[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(text)) {\n return { _tag: \"Registry\", name, selector: { _tag: \"Tag\", tag: text } }\n }\n\n return { _tag: \"Unsupported\", name, raw: text, reason: \"unrecognised version specifier\" }\n}\n\n/**\n * Parses `npm:<name>[@<range>]`.\n *\n * The nested name may itself be scoped, so the `@` split has the same\n * \"not at index 0\" caveat as top-level spec parsing.\n */\nconst parseAlias = (key: string, text: string): DependencyTarget => {\n const body = text.slice(\"npm:\".length)\n if (body.length === 0) {\n return { _tag: \"Unsupported\", name: key, raw: text, reason: \"empty npm: alias\" }\n }\n\n const at = body.lastIndexOf(\"@\")\n const target = at > 0 ? body.slice(0, at) : body\n const rangeText = at > 0 ? body.slice(at + 1) : \"\"\n\n if (target.length === 0) {\n return { _tag: \"Unsupported\", name: key, raw: text, reason: \"empty npm: alias target\" }\n }\n\n const inner = parseDependencyTarget(target, rangeText)\n if (inner._tag === \"Unsupported\") {\n return { ...inner, name: key, raw: text }\n }\n return { _tag: \"Registry\", name: target, selector: inner.selector, aliasOf: key }\n}\n","/**\n * Version selection and the dependency closure walk.\n *\n * This is the part that decides *what* ends up in a bundle. Its only side\n * effect is asking the `Registry` service for metadata, which makes the whole\n * of it testable against a fake registry with no network at all.\n *\n * The walk is breadth-first in waves: resolve the current frontier\n * concurrently, collect the newly discovered edges, repeat. Wave-based BFS\n * gives real parallelism without a dynamic worker pool, and because each wave\n * merges its results serially there is no shared mutable state being written\n * from more than one fiber.\n *\n * One subtlety worth calling out: metadata is cached across walks, but each\n * walk still traverses the full graph. That is what lets `per-spec` layout ask\n * \"what does *this* root version depend on\" many times over while the network\n * is touched exactly once per package.\n */\nimport * as Effect from \"effect/Effect\"\nimport semver from \"semver\"\nimport { parseDependencyTarget } from \"./DependencyRange.js\"\nimport type { BundlerError } from \"./Errors.js\"\nimport { NoMatchingVersionsError, VersionNotFoundError } from \"./Errors.js\"\nimport type { ResolveOptions } from \"./Options.js\"\nimport { isIncluded } from \"./Platform.js\"\nimport type { Packument, PackageManifest } from \"./Registry.js\"\nimport { Registry } from \"./Registry.js\"\nimport * as Progress from \"./Progress.js\"\nimport type { PackageSpec, Selector } from \"./Spec.js\"\nimport { formatSelector, formatSpec } from \"./Spec.js\"\n\n/** Why a package is in the bundle. */\nexport type EdgeKind = \"prod\" | \"optional\" | \"peer\"\n\n/** A single justification for including a package. */\nexport type Reason =\n | { readonly _tag: \"Root\"; readonly spec: string }\n | { readonly _tag: \"Edge\"; readonly from: string; readonly kind: EdgeKind }\n\n/** `name@version` — the identity of a resolved package throughout the engine. */\nexport type PackageKey = string\n\nexport const packageKey = (name: string, version: string): PackageKey => `${name}@${version}`\n\n/** One package, pinned to one version, with every reason it was pulled in. */\nexport interface ResolvedPackage {\n readonly name: string\n readonly version: string\n readonly manifest: PackageManifest\n readonly reasons: ReadonlyArray<Reason>\n}\n\n/** Something we could not include, reported rather than thrown. */\nexport interface ResolutionWarning {\n readonly message: string\n /** `name@version` of the package whose manifest contained the problem. */\n readonly from?: string | undefined\n}\n\n/** What one requested spec expanded to. */\nexport interface RootResolution {\n readonly spec: PackageSpec\n /** The concrete versions the spec selected — more than one under `--all-versions`. */\n readonly versions: ReadonlyArray<string>\n /** Closure per selected version, keyed by version. Drives `per-spec` layout. */\n readonly closures: ReadonlyMap<string, ReadonlyArray<PackageKey>>\n /** Union of every per-version closure. */\n readonly closure: ReadonlyArray<PackageKey>\n}\n\n/** The complete result of resolving every requested spec. */\nexport interface Resolution {\n readonly roots: ReadonlyArray<RootResolution>\n /** The deduplicated union of every closure, sorted by name then version. */\n readonly packages: ReadonlyArray<ResolvedPackage>\n readonly warnings: ReadonlyArray<ResolutionWarning>\n}\n\n/** Index of a resolution by `name@version`, for lookups during bundling. */\nexport const indexPackages = (\n resolution: Resolution\n): ReadonlyMap<PackageKey, ResolvedPackage> =>\n new Map(resolution.packages.map((p) => [packageKey(p.name, p.version), p]))\n\n/* -------------------------------------------------------------------------- */\n/* Version selection */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Turns a selector into the concrete version(s) it names.\n *\n * `all` controls whether a range collapses to its best match — npm's behaviour,\n * and what you always want for a transitive dependency — or expands to every\n * satisfying published version, which is what `--all-versions` is for.\n */\nexport const selectVersions = (\n packument: Packument,\n selector: Selector,\n options: {\n readonly all: boolean\n readonly maxVersions?: number | undefined\n readonly includePrerelease: boolean\n }\n): ReadonlyArray<string> => {\n const available = Object.keys(packument.versions)\n\n switch (selector._tag) {\n case \"Exact\": {\n if (!Object.hasOwn(packument.versions, selector.version)) {\n throw new VersionNotFoundError(packument.name, selector.version, sortVersions(available))\n }\n return [selector.version]\n }\n\n case \"Tag\": {\n const version = packument.distTags[selector.tag]\n if (version === undefined || !Object.hasOwn(packument.versions, version)) {\n throw new NoMatchingVersionsError(packument.name, selector.tag, sortVersions(available))\n }\n return [version]\n }\n\n case \"Range\": {\n const satisfying = available\n .filter((v) =>\n semver.satisfies(v, selector.range, {\n loose: true,\n includePrerelease: options.includePrerelease\n })\n )\n .sort(semver.rcompare)\n\n if (satisfying.length === 0) {\n throw new NoMatchingVersionsError(packument.name, selector.range, sortVersions(available))\n }\n\n if (!options.all) return [satisfying[0]!]\n\n return options.maxVersions !== undefined && options.maxVersions > 0\n ? satisfying.slice(0, options.maxVersions)\n : satisfying\n }\n }\n}\n\nconst sortVersions = (versions: ReadonlyArray<string>): ReadonlyArray<string> =>\n [...versions].sort((a, b) =>\n semver.valid(a) && semver.valid(b) ? semver.compare(a, b) : a.localeCompare(b)\n )\n\n/* -------------------------------------------------------------------------- */\n/* Walk state */\n/* -------------------------------------------------------------------------- */\n\n/** One pending item on the BFS frontier. */\nexport interface Task {\n readonly name: string\n readonly selector: Selector\n readonly reason: Reason\n /** Optional edges tolerate resolution failure; required ones do not. */\n readonly tolerateFailure: boolean\n}\n\n/**\n * State shared across every walk in a run.\n *\n * Caching packuments and expanded edges here is what makes repeated walks\n * cheap: the second walk over `react@18.2.0` costs no network at all.\n */\ninterface WalkState {\n readonly resolved: Map<PackageKey, ResolvedPackage>\n readonly edges: Map<PackageKey, ReadonlyArray<Task>>\n readonly packuments: Map<string, Packument>\n readonly warnings: Array<ResolutionWarning>\n /** Warnings are deduplicated — the same skipped edge appears in many walks. */\n readonly warningKeys: Set<string>\n}\n\nconst makeWalkState = (): WalkState => ({\n resolved: new Map(),\n edges: new Map(),\n packuments: new Map(),\n warnings: [],\n warningKeys: new Set()\n})\n\nconst addWarning = (state: WalkState, warning: ResolutionWarning): void => {\n const key = `${warning.from ?? \"\"}|${warning.message}`\n if (state.warningKeys.has(key)) return\n state.warningKeys.add(key)\n state.warnings.push(warning)\n}\n\n/**\n * Fetches a packument, reusing anything already seen in this run.\n *\n * Two fibers in the same wave can race here and both fetch. That is one\n * duplicated GET at worst, and de-racing it would cost more complexity than it\n * saves.\n */\nconst getPackument = (\n state: WalkState,\n name: string\n): Effect.Effect<Packument, BundlerError, Registry> =>\n Effect.gen(function*() {\n const cached = state.packuments.get(name)\n if (cached !== undefined) return cached\n const registry = yield* Registry\n const packument = yield* registry.packument(name)\n state.packuments.set(name, packument)\n return packument\n })\n\n/* -------------------------------------------------------------------------- */\n/* Edge expansion */\n/* -------------------------------------------------------------------------- */\n\n/** Expands one resolved manifest into the edges that follow from it. */\nexport const edgesOf = (\n manifest: PackageManifest,\n options: ResolveOptions\n): {\n readonly tasks: ReadonlyArray<Task>\n readonly warnings: ReadonlyArray<ResolutionWarning>\n} => {\n const from = packageKey(manifest.name, manifest.version)\n const tasks: Array<Task> = []\n const warnings: Array<ResolutionWarning> = []\n\n const add = (\n entries: Readonly<Record<string, string>> | undefined,\n kind: EdgeKind,\n tolerateFailure: boolean,\n skip?: (name: string) => boolean\n ): void => {\n if (entries === undefined) return\n for (const [name, raw] of Object.entries(entries)) {\n if (skip?.(name)) continue\n const target = parseDependencyTarget(name, raw)\n if (target._tag === \"Unsupported\") {\n warnings.push({\n from,\n message:\n `Skipped ${name}@${target.raw} (${target.reason}) — it cannot be fetched from a ` +\n `registry. Vendor it separately if the offline install needs it.`\n })\n continue\n }\n tasks.push({\n name: target.name,\n selector: target.selector,\n reason: { _tag: \"Edge\", from, kind },\n tolerateFailure\n })\n }\n }\n\n // Runtime dependencies are non-negotiable.\n add(manifest.dependencies, \"prod\", false)\n\n // Optional dependencies are allowed to be missing — npm tolerates a 404 here\n // and so must we, or one unpublished platform package fails the whole run.\n if (options.scope.optional) {\n add(manifest.optionalDependencies, \"optional\", true)\n }\n\n if (options.scope.peer) {\n const meta = manifest.peerDependenciesMeta ?? {}\n add(manifest.peerDependencies, \"peer\", false, (name) => meta[name]?.optional === true)\n }\n\n return { tasks, warnings }\n}\n\n/** Edges for a package, computed once and cached. */\nconst edgesFor = (\n state: WalkState,\n manifest: PackageManifest,\n options: ResolveOptions\n): ReadonlyArray<Task> => {\n const key = packageKey(manifest.name, manifest.version)\n const cached = state.edges.get(key)\n if (cached !== undefined) return cached\n\n const { tasks, warnings } = edgesOf(manifest, options)\n for (const warning of warnings) addWarning(state, warning)\n state.edges.set(key, tasks)\n return tasks\n}\n\n/* -------------------------------------------------------------------------- */\n/* The walk */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Resolves everything reachable from `seeds`, returning the closure.\n *\n * `state` is mutated with newly resolved packages and warnings; the returned\n * array is scoped to *this* walk, which is what makes per-root-version\n * closures possible.\n */\nconst walk = (\n state: WalkState,\n seeds: ReadonlyArray<Task>,\n options: ResolveOptions\n): Effect.Effect<ReadonlyArray<PackageKey>, BundlerError, Registry | Progress.Progress> =>\n Effect.gen(function*() {\n const discovered = new Set<PackageKey>()\n // Guards against re-resolving the same (name, selector) pair. Large trees\n // ask for `tslib@^2` hundreds of times, and this is also what terminates\n // dependency cycles.\n const attempted = new Set<string>()\n let frontier: ReadonlyArray<Task> = seeds\n\n while (frontier.length > 0) {\n const wave: Array<Task> = []\n for (const task of frontier) {\n const id = `${task.name} ${formatSelector(task.selector)}`\n if (attempted.has(id)) continue\n attempted.add(id)\n wave.push(task)\n }\n if (wave.length === 0) break\n\n const results = yield* Effect.forEach(\n wave,\n (task) => resolveTask(state, task, options),\n { concurrency: options.concurrency }\n )\n\n const next: Array<Task> = []\n\n // Merged serially: every mutation of `state` happens on one fiber.\n for (const result of results) {\n if (result === null) continue\n\n for (const { manifest, reason } of result) {\n const key = packageKey(manifest.name, manifest.version)\n const isNew = !state.resolved.has(key)\n\n if (isNew) {\n state.resolved.set(key, {\n name: manifest.name,\n version: manifest.version,\n manifest,\n reasons: [reason]\n })\n\n yield* Progress.emit({\n _tag: \"PackageResolved\",\n name: manifest.name,\n version: manifest.version,\n resolvedCount: state.resolved.size,\n pendingCount: next.length\n })\n\n if (manifest.deprecated !== undefined && manifest.deprecated !== \"\") {\n addWarning(state, { from: key, message: `${key} is deprecated: ${manifest.deprecated}` })\n }\n } else {\n const existing = state.resolved.get(key)!\n if (!hasReason(existing.reasons, reason)) {\n state.resolved.set(key, { ...existing, reasons: [...existing.reasons, reason] })\n }\n }\n\n // Expand regardless of whether the package is new. A package resolved\n // during an earlier walk still has to contribute its subtree to\n // *this* walk's closure; `attempted` stops that from looping.\n if (!discovered.has(key)) {\n discovered.add(key)\n next.push(...edgesFor(state, manifest, options))\n }\n }\n }\n\n frontier = next\n }\n\n return [...discovered]\n })\n\nconst hasReason = (reasons: ReadonlyArray<Reason>, candidate: Reason): boolean =>\n reasons.some((reason) => {\n if (reason._tag === \"Root\" && candidate._tag === \"Root\") return reason.spec === candidate.spec\n if (reason._tag === \"Edge\" && candidate._tag === \"Edge\") {\n return reason.from === candidate.from && reason.kind === candidate.kind\n }\n return false\n })\n\n/**\n * Resolves one task to its manifest(s).\n *\n * Returns `null` when an optional edge could not be resolved — the caller\n * treats that as \"skip quietly\", which is what npm does for\n * `optionalDependencies`.\n */\nconst resolveTask = (\n state: WalkState,\n task: Task,\n options: ResolveOptions\n): Effect.Effect<\n ReadonlyArray<{ manifest: PackageManifest; reason: Reason }> | null,\n BundlerError,\n Registry\n> =>\n Effect.gen(function*() {\n const packument = yield* getPackument(state, task.name)\n\n // Transitive edges always collapse to a single best match; only root specs\n // ever fan out, and those arrive here already pinned to an exact version.\n const versions = yield* Effect.try({\n try: () =>\n selectVersions(packument, task.selector, {\n all: false,\n includePrerelease: options.includePrerelease\n }),\n catch: (error) => error as BundlerError\n })\n\n const out: Array<{ manifest: PackageManifest; reason: Reason }> = []\n for (const version of versions) {\n const manifest = packument.versions[version]\n if (manifest === undefined) continue\n\n // Platform narrowing only ever applies to optional edges. Filtering a\n // required dependency by platform would produce a bundle that cannot\n // install anywhere.\n if (\n task.reason._tag === \"Edge\" &&\n task.reason.kind === \"optional\" &&\n !isIncluded(manifest, options.scope.platforms)\n ) {\n continue\n }\n\n out.push({ manifest, reason: task.reason })\n }\n return out\n }).pipe(\n Effect.catch((error) => {\n // A required edge that cannot be resolved is fatal. An optional one is\n // recorded and skipped, matching how npm treats `optionalDependencies`.\n if (!task.tolerateFailure) return Effect.fail(error)\n return Effect.sync(() => {\n addWarning(state, {\n message:\n `Optional dependency ${task.name}@${formatSelector(task.selector)} could not be ` +\n `resolved and was skipped: ${error.message}`\n })\n return null\n })\n })\n )\n\n/* -------------------------------------------------------------------------- */\n/* Entry point */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Resolves every requested spec.\n *\n * Each selected root *version* is walked separately so `per-spec` layout has an\n * exact closure per tarball, while all walks share one cache, so a package\n * reached from twenty roots is fetched once.\n */\nexport const resolve = (\n specs: ReadonlyArray<PackageSpec>,\n options: ResolveOptions\n): Effect.Effect<Resolution, BundlerError, Registry | Progress.Progress> =>\n Effect.gen(function*() {\n yield* Progress.emit({ _tag: \"PhaseStarted\", phase: \"resolve\", total: specs.length })\n\n const state = makeWalkState()\n const roots: Array<RootResolution> = []\n\n for (const spec of specs) {\n const packument = yield* getPackument(state, spec.name)\n\n const versions = yield* Effect.try({\n try: () =>\n selectVersions(packument, spec.selector, {\n all: options.allVersions,\n maxVersions: options.maxVersions,\n includePrerelease: options.includePrerelease\n }),\n catch: (error) => error as BundlerError\n })\n\n const closures = new Map<string, ReadonlyArray<PackageKey>>()\n const union = new Set<PackageKey>()\n\n for (const version of versions) {\n const closure = yield* walk(\n state,\n [\n {\n name: spec.name,\n selector: { _tag: \"Exact\", version },\n reason: { _tag: \"Root\", spec: formatSpec(spec) },\n tolerateFailure: false\n }\n ],\n options\n )\n closures.set(version, closure)\n for (const key of closure) union.add(key)\n }\n\n roots.push({ spec, versions, closures, closure: [...union] })\n }\n\n yield* Progress.emit({ _tag: \"PhaseCompleted\", phase: \"resolve\" })\n\n return {\n roots,\n packages: [...state.resolved.values()].sort(compareResolved),\n warnings: state.warnings\n }\n })\n\nconst compareResolved = (a: ResolvedPackage, b: ResolvedPackage): number => {\n if (a.name !== b.name) return a.name < b.name ? -1 : 1\n return semver.valid(a.version) && semver.valid(b.version)\n ? semver.compare(a.version, b.version)\n : a.version.localeCompare(b.version)\n}\n","/**\n * End-to-end orchestration: specs in, tarballs out.\n *\n * Two properties this module is responsible for, both of them fixes for how\n * the original tool behaved:\n *\n * 1. **Nothing is written outside the output directory.** Every intermediate\n * file lives in a scoped temp directory obtained from\n * `makeTempDirectoryScoped`, so the scope closing — on success, on failure,\n * or on Ctrl-C — takes the whole staging tree with it. The working\n * directory is never touched.\n *\n * 2. **Each package is downloaded exactly once**, no matter how many bundles\n * it ends up in. Per-spec archives are assembled by hard-linking out of one\n * shared download tree, so `per-spec` costs extra disk in the *output*, not\n * extra network.\n */\nimport * as Effect from \"effect/Effect\"\nimport * as FileSystem from \"effect/FileSystem\"\nimport * as Path from \"effect/Path\"\nimport type { PlatformError } from \"effect/PlatformError\"\nimport type { Scope } from \"effect/Scope\"\nimport { createArchive } from \"./Archive.js\"\nimport { downloadAll } from \"./Download.js\"\nimport type { BundlerError } from \"./Errors.js\"\nimport { OutputError } from \"./Errors.js\"\nimport {\n importGuide,\n MANIFEST_FILE,\n packagePath,\n perSpecArchiveName,\n README_FILE,\n singleArchiveName\n} from \"./Layout.js\"\nimport { buildManifest, serializeManifest } from \"./Manifest.js\"\nimport type { BundleOptions, Layout } from \"./Options.js\"\nimport * as Progress from \"./Progress.js\"\nimport { Registry } from \"./Registry.js\"\nimport type { PackageKey, Resolution, ResolvedPackage } from \"./Resolve.js\"\nimport { indexPackages, resolve } from \"./Resolve.js\"\nimport type { PackageSpec } from \"./Spec.js\"\nimport { formatSpec } from \"./Spec.js\"\n\n/** One thing written to the output directory. */\nexport interface BundleArtifact {\n readonly kind: \"archive\" | \"directory\"\n readonly path: string\n readonly bytes: number\n readonly packageCount: number\n /** Which spec this artifact covers. Absent for `single` and `dir`. */\n readonly spec?: string | undefined\n readonly version?: string | undefined\n}\n\n/** The outcome of a bundle run. */\nexport interface BundleResult {\n readonly resolution: Resolution\n readonly artifacts: ReadonlyArray<BundleArtifact>\n /** Total bytes downloaded from the registry. */\n readonly downloadedBytes: number\n /** Packages the registry advertised no usable checksum for. */\n readonly unverified: ReadonlyArray<string>\n readonly dryRun: boolean\n}\n\n/** Everything `bundle` needs beyond the user-facing options. */\nexport interface BundleContext extends BundleOptions {\n /** Recorded in the manifest so a bundle can be traced to the tool that built it. */\n readonly toolVersion: string\n}\n\n/**\n * A summary of what a resolution would produce, for deciding whether the\n * chosen layout is still the right one.\n */\nexport interface PlanSummary {\n /** Distinct packages in the deduplicated union. */\n readonly uniquePackages: number\n /** How many archives `per-spec` layout would emit. */\n readonly perSpecArchives: number\n /**\n * Total package entries across all per-spec archives, counting shared\n * dependencies once per archive they appear in. The gap between this and\n * `uniquePackages` is exactly what `single` layout would save.\n */\n readonly perSpecEntries: number\n}\n\n/** Computes the plan summary for a resolution. */\nexport const summarize = (resolution: Resolution): PlanSummary => {\n let perSpecArchives = 0\n let perSpecEntries = 0\n for (const root of resolution.roots) {\n for (const version of root.versions) {\n perSpecArchives += 1\n perSpecEntries += (root.closures.get(version) ?? []).length\n }\n }\n return {\n uniquePackages: resolution.packages.length,\n perSpecArchives,\n perSpecEntries\n }\n}\n\n/** Replaces the layout on a set of options. */\nexport const withLayout = <T extends BundleOptions>(options: T, layout: Layout): T => ({\n ...options,\n layout\n})\n\ntype BundleEnv = Registry | Progress.Progress | FileSystem.FileSystem | Path.Path\n\n/**\n * Checks the registry is reachable, then resolves every spec.\n *\n * Split out from `bundle` so a caller can inspect the plan — how many packages,\n * how many archives — and act on it before any bytes move. The CLI uses this to\n * offer a different layout when a run turns out to be much larger than\n * expected.\n */\nexport const plan = (\n specs: ReadonlyArray<PackageSpec>,\n options: BundleOptions\n): Effect.Effect<Resolution, BundlerError, Registry | Progress.Progress> =>\n Effect.gen(function*() {\n const registry = yield* Registry\n\n yield* Progress.emit({ _tag: \"PhaseStarted\", phase: \"preflight\" })\n yield* registry.preflight\n yield* Progress.emit({ _tag: \"PhaseCompleted\", phase: \"preflight\" })\n\n return yield* resolve(specs, options)\n })\n\n/**\n * Resolves, downloads and packages a set of specs.\n *\n * Under `dryRun` this stops after resolution and reports the plan — useful for\n * checking what a command *would* pull before committing to a multi-gigabyte\n * download over a slow VPN.\n */\nexport const bundle = (\n specs: ReadonlyArray<PackageSpec>,\n options: BundleContext\n): Effect.Effect<BundleResult, BundlerError | PlatformError, BundleEnv> =>\n Effect.gen(function*() {\n const resolution = yield* plan(specs, options)\n return yield* bundleResolved(resolution, options)\n })\n\n/**\n * Downloads and packages an already-computed resolution.\n *\n * Everything from here on touches the disk, and all of it happens inside\n * `Effect.scoped` — so the staging tree's lifetime is exactly this call,\n * including when it fails partway through or the user hits Ctrl-C.\n */\nexport const bundleResolved = (\n resolution: Resolution,\n options: BundleContext\n): Effect.Effect<BundleResult, BundlerError | PlatformError, BundleEnv> =>\n Effect.gen(function*() {\n if (options.dryRun) {\n return {\n resolution,\n artifacts: [],\n downloadedBytes: 0,\n unverified: [],\n dryRun: true\n }\n }\n return yield* Effect.scoped(runBundle(resolution, options))\n })\n\nconst runBundle = (\n resolution: Resolution,\n options: BundleContext\n): Effect.Effect<\n BundleResult,\n BundlerError | PlatformError,\n BundleEnv | Scope\n> =>\n Effect.gen(function*() {\n const fs = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n const registry = yield* Registry\n\n yield* prepareOutputDir(resolution, options)\n\n const staging = yield* fs.makeTempDirectoryScoped({ prefix: \"packall-\" })\n const packagesDir = path.join(staging, \"packages\")\n yield* fs.makeDirectory(packagesDir, { recursive: true })\n\n const report = yield* downloadAll(resolution.packages, packagesDir, {\n concurrency: options.concurrency,\n verifyIntegrity: options.verifyIntegrity\n })\n\n yield* Progress.emit({ _tag: \"PhaseStarted\", phase: \"archive\" })\n\n const registryInfo = {\n kind: registry.kind,\n url: registry.registryFor(resolution.roots[0]?.spec.name ?? \"\")\n }\n\n const index = indexPackages(resolution)\n\n const artifacts =\n options.layout === \"single\"\n ? yield* emitSingle({ resolution, options, staging, packagesDir, report, registryInfo })\n : options.layout === \"dir\"\n ? yield* emitDirectory({ resolution, options, packagesDir, report, registryInfo })\n : yield* emitPerSpec({\n resolution,\n options,\n staging,\n packagesDir,\n report,\n registryInfo,\n index\n })\n\n yield* Progress.emit({ _tag: \"PhaseCompleted\", phase: \"archive\" })\n yield* Progress.emit({ _tag: \"PhaseStarted\", phase: \"done\" })\n\n return {\n resolution,\n artifacts,\n downloadedBytes: report.totalBytes,\n unverified: report.unverified,\n dryRun: false\n }\n })\n\n/* -------------------------------------------------------------------------- */\n/* Emitters */\n/* -------------------------------------------------------------------------- */\n\ninterface EmitInput {\n readonly resolution: Resolution\n readonly options: BundleContext\n readonly packagesDir: string\n readonly report: { readonly sizes: ReadonlyMap<string, number> }\n readonly registryInfo: { readonly kind: string; readonly url: string }\n}\n\n/** One tarball containing the deduplicated union of every closure. */\nconst emitSingle = (\n input: EmitInput & { readonly staging: string }\n): Effect.Effect<\n ReadonlyArray<BundleArtifact>,\n BundlerError | PlatformError,\n FileSystem.FileSystem | Path.Path | Progress.Progress\n> =>\n Effect.gen(function*() {\n const path = yield* Path.Path\n\n const archiveName = singleArchiveName(input.options.archiveName ?? \"bundle\")\n // Declined at the prompt, and it is the run's only output.\n if (input.options.skipExisting?.has(archiveName) === true) return []\n\n yield* writeBundleMetadata({\n dir: input.packagesDir,\n resolution: input.resolution,\n included: input.resolution.packages,\n options: input.options,\n registryInfo: input.registryInfo,\n sizes: input.report.sizes\n })\n\n const outPath = path.join(input.options.outDir, archiveName)\n\n const result = yield* createArchive({\n cwd: input.packagesDir,\n entries: yield* topLevelEntries(input.packagesDir),\n outPath\n })\n\n return [\n {\n kind: \"archive\" as const,\n path: result.path,\n bytes: result.bytes,\n packageCount: input.resolution.packages.length\n }\n ]\n })\n\n/** The raw npm-layout tree, no archive. */\nconst emitDirectory = (\n input: EmitInput\n): Effect.Effect<\n ReadonlyArray<BundleArtifact>,\n BundlerError | PlatformError,\n FileSystem.FileSystem | Path.Path\n> =>\n Effect.gen(function*() {\n const fs = yield* FileSystem.FileSystem\n\n yield* writeBundleMetadata({\n dir: input.packagesDir,\n resolution: input.resolution,\n included: input.resolution.packages,\n options: input.options,\n registryInfo: input.registryInfo,\n sizes: input.report.sizes\n })\n\n // The staging tree is about to be deleted with its scope, so this is a\n // real copy rather than a move — `copy` also works across devices, which\n // matters because the temp dir often lives on a different filesystem.\n yield* fs.copy(input.packagesDir, input.options.outDir, { overwrite: true }).pipe(\n Effect.mapError(\n (cause) => new OutputError(input.options.outDir, \"could not write output tree\", { cause })\n )\n )\n\n const bytes = [...input.report.sizes.values()].reduce((a, b) => a + b, 0)\n\n return [\n {\n kind: \"directory\" as const,\n path: input.options.outDir,\n bytes,\n packageCount: input.resolution.packages.length\n }\n ]\n })\n\n/**\n * One tarball per resolved root *version*.\n *\n * Under `--all-versions react@^18` this produces `react-18.0.0.tgz`,\n * `react-18.1.0.tgz` and so on, each independently importable — which is the\n * whole reason to prefer this layout.\n */\nconst emitPerSpec = (\n input: EmitInput & {\n readonly staging: string\n readonly index: ReadonlyMap<PackageKey, ResolvedPackage>\n }\n): Effect.Effect<\n ReadonlyArray<BundleArtifact>,\n BundlerError | PlatformError,\n FileSystem.FileSystem | Path.Path | Progress.Progress\n> =>\n Effect.gen(function*() {\n const fs = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n const artifacts: Array<BundleArtifact> = []\n\n let counter = 0\n for (const root of input.resolution.roots) {\n for (const version of root.versions) {\n // Declined at the prompt: the existing file stays, and this archive is\n // simply never built. Skipping the staging work too, not just the write.\n if (input.options.skipExisting?.has(perSpecArchiveName(root.spec.name, version)) === true) {\n continue\n }\n\n const closure = root.closures.get(version) ?? []\n const included = closure\n .map((key) => input.index.get(key))\n .filter((pkg): pkg is ResolvedPackage => pkg !== undefined)\n\n const rootDir = path.join(input.staging, \"roots\", String(counter++))\n yield* fs.makeDirectory(rootDir, { recursive: true })\n\n for (const pkg of included) {\n const relative = packagePath(pkg.name, pkg.version)\n const parts = relative.split(\"/\")\n const source = path.join(input.packagesDir, ...parts)\n const target = path.join(rootDir, ...parts)\n yield* fs.makeDirectory(path.dirname(target), { recursive: true })\n yield* linkOrCopy(source, target)\n }\n\n yield* writeBundleMetadata({\n dir: rootDir,\n resolution: {\n ...input.resolution,\n roots: [{ ...root, versions: [version] }]\n },\n included,\n options: input.options,\n registryInfo: input.registryInfo,\n sizes: input.report.sizes\n })\n\n const outPath = path.join(\n input.options.outDir,\n perSpecArchiveName(root.spec.name, version)\n )\n\n const result = yield* createArchive({\n cwd: rootDir,\n entries: yield* topLevelEntries(rootDir),\n outPath\n })\n\n artifacts.push({\n kind: \"archive\",\n path: result.path,\n bytes: result.bytes,\n packageCount: included.length,\n spec: formatSpec(root.spec),\n version\n })\n }\n }\n\n return artifacts\n })\n\n/* -------------------------------------------------------------------------- */\n/* Helpers */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Hard-links a file, falling back to a copy.\n *\n * Hard links make `per-spec` layout nearly free in the staging tree. They fail\n * across devices and on some Windows configurations, so the copy fallback is\n * not optional.\n */\nconst linkOrCopy = (\n source: string,\n target: string\n): Effect.Effect<void, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function*() {\n const fs = yield* FileSystem.FileSystem\n yield* fs.link(source, target).pipe(\n Effect.catch(() => fs.copyFile(source, target))\n )\n })\n\n/** Writes the manifest and import guide into a staging directory. */\nconst writeBundleMetadata = (input: {\n readonly dir: string\n readonly resolution: Resolution\n readonly included: ReadonlyArray<ResolvedPackage>\n readonly options: BundleContext\n readonly registryInfo: { readonly kind: string; readonly url: string }\n readonly sizes: ReadonlyMap<string, number>\n}): Effect.Effect<void, PlatformError, FileSystem.FileSystem | Path.Path> =>\n Effect.gen(function*() {\n const fs = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n\n const createdAt = new Date()\n const manifest = buildManifest({\n resolution: input.resolution,\n included: input.included,\n options: input.options,\n registry: input.registryInfo,\n toolVersion: input.options.toolVersion,\n sizes: input.sizes,\n createdAt\n })\n\n yield* fs.writeFileString(path.join(input.dir, MANIFEST_FILE), serializeManifest(manifest))\n yield* fs.writeFileString(\n path.join(input.dir, README_FILE),\n importGuide({\n packageCount: input.included.length,\n createdAt: createdAt.toISOString(),\n toolVersion: input.options.toolVersion\n })\n )\n })\n\n/** Sorted top-level entries of a directory, used as the tar entry list. */\nconst topLevelEntries = (\n dir: string\n): Effect.Effect<ReadonlyArray<string>, PlatformError, FileSystem.FileSystem> =>\n Effect.gen(function*() {\n const fs = yield* FileSystem.FileSystem\n const entries = yield* fs.readDirectory(dir)\n return [...entries].sort()\n })\n\n/**\n * Creates the output directory, refusing to clobber an existing non-empty one\n * unless `--force` was passed.\n *\n * Silently overwriting somebody's previous bundle is the kind of thing a tool\n * only gets forgiven for once.\n */\n/**\n * The files a run will write, known before anything is downloaded.\n *\n * `dir` layout is the odd one: it merges a package tree into `outDir`, and\n * package paths are `name/-/name-version.tgz` — the same package at the same\n * version is the same bytes, so an overlap there is idempotent rather than\n * destructive. Only the two summary files are genuinely replaced, and those are\n * the ones worth guarding.\n */\nexport interface PlannedOutput {\n readonly file: string\n /** The root this file belongs to, when one file corresponds to one spec. */\n readonly name?: string | undefined\n readonly version?: string | undefined\n}\n\nexport const plannedOutputs = (\n resolution: Resolution,\n options: BundleContext\n): ReadonlyArray<PlannedOutput> => {\n if (options.layout === \"dir\") return [{ file: MANIFEST_FILE }, { file: README_FILE }]\n if (options.layout === \"single\") {\n return [{ file: singleArchiveName(options.archiveName ?? \"bundle\") }]\n }\n return resolution.roots.flatMap((root) =>\n root.versions.map((version) => ({\n file: perSpecArchiveName(root.spec.name, version),\n name: root.spec.name,\n version\n }))\n )\n}\n\n/**\n * Fails if the run would overwrite something, unless `--force`.\n *\n * The guard is on the *files this run writes*, not on whether the directory has\n * anything in it. An output directory accumulating bundles is the normal way to\n * use this — bundling `esbuild` into an `out/` that already holds `tsdown` is\n * not a conflict, and refusing it made `--out` a single-use directory and the\n * default `.` unusable.\n *\n * Checked before anything is downloaded. Discovering the collision *after* a\n * twenty-minute download would be a uniquely irritating way to fail.\n */\nconst prepareOutputDir = (\n resolution: Resolution,\n options: BundleContext\n): Effect.Effect<void, OutputError | PlatformError, FileSystem.FileSystem | Path.Path> =>\n Effect.gen(function*() {\n const fs = yield* FileSystem.FileSystem\n const path = yield* Path.Path\n const outDir = options.outDir\n\n if (!options.force) {\n const clashes: Array<string> = []\n for (const planned of plannedOutputs(resolution, options)) {\n if (options.skipExisting?.has(planned.file) === true) continue\n if (options.overwrite?.has(planned.file) === true) continue\n const exists = yield* fs\n .exists(path.join(outDir, planned.file))\n .pipe(Effect.orElseSucceed(() => false))\n if (exists) clashes.push(planned.file)\n }\n\n if (clashes.length > 0) {\n return yield* Effect.fail(\n new OutputError(\n outDir,\n `would overwrite ${clashes.length} existing file${clashes.length === 1 ? \"\" : \"s\"} ` +\n `(${clashes.slice(0, 3).join(\", \")}${clashes.length > 3 ? \", …\" : \"\"}). ` +\n `Pass --force true to replace ${clashes.length === 1 ? \"it\" : \"them\"}, or choose a different --out.`\n )\n )\n }\n }\n\n yield* fs.makeDirectory(outDir, { recursive: true }).pipe(\n Effect.mapError((cause) => new OutputError(outDir, \"could not create output directory\", { cause }))\n )\n })\n","/**\n * `--file` handling.\n *\n * One flag, two accepted shapes, detected from the content rather than the\n * extension so that `--file deps.json` and `--file my-packages` both do the\n * obvious thing:\n *\n * - a **package.json** — bundle everything it depends on\n * - a **newline-delimited list** — one spec per line, `#` and `//` comments\n * allowed, blank lines ignored\n */\nimport * as Effect from \"effect/Effect\"\nimport * as FileSystem from \"effect/FileSystem\"\nimport { parseDependencyTarget } from \"./DependencyRange.js\"\nimport { InvalidInputFileError } from \"./Errors.js\"\nimport type { InvalidSpecError } from \"./Errors.js\"\nimport type { PackageSpec } from \"./Spec.js\"\nimport { parseSpecs } from \"./Spec.js\"\n\n/** Which of the two shapes a file turned out to be. */\nexport type InputFileKind = \"package.json\" | \"list\"\n\nexport interface InputFileResult {\n readonly kind: InputFileKind\n readonly specs: ReadonlyArray<PackageSpec>\n /** Entries that were recognised but cannot be bundled from a registry. */\n readonly warnings: ReadonlyArray<string>\n}\n\n/** Which dependency blocks of a package.json become root specs. */\nexport interface InputFileOptions {\n /**\n * Include `devDependencies`.\n *\n * On by default: if you are pointing this tool at a package.json, you are\n * almost certainly trying to make that project installable behind the\n * firewall, and a project without its dev tooling does not build. `--prod`\n * turns it off.\n */\n readonly includeDev: boolean\n}\n\nexport const defaultInputFileOptions: InputFileOptions = { includeDev: true }\n\n/** Reads and parses an input file. */\nexport const readInputFile = (\n filePath: string,\n options: InputFileOptions = defaultInputFileOptions\n): Effect.Effect<InputFileResult, InvalidInputFileError, FileSystem.FileSystem> =>\n Effect.gen(function*() {\n const fs = yield* FileSystem.FileSystem\n\n const exists = yield* fs.exists(filePath).pipe(\n Effect.mapError((cause) => new InvalidInputFileError(filePath, \"could not be read\", { cause }))\n )\n if (!exists) {\n return yield* Effect.fail(new InvalidInputFileError(filePath, \"file does not exist\"))\n }\n\n const content = yield* fs.readFileString(filePath).pipe(\n Effect.mapError((cause) => new InvalidInputFileError(filePath, \"could not be read\", { cause }))\n )\n\n return yield* Effect.try({\n try: () => parseInputFile(filePath, content, options),\n catch: (error) =>\n error instanceof InvalidInputFileError\n ? error\n : new InvalidInputFileError(filePath, describe(error), { cause: error })\n })\n })\n\n/**\n * Parses file content that has already been read.\n *\n * Split out from the IO so the whole of this logic is testable with plain\n * strings and no file system at all.\n */\nexport const parseInputFile = (\n filePath: string,\n content: string,\n options: InputFileOptions = defaultInputFileOptions\n): InputFileResult => {\n const trimmed = content.trim()\n if (trimmed.length === 0) {\n throw new InvalidInputFileError(filePath, \"file is empty\")\n }\n\n return looksLikeJson(trimmed)\n ? fromPackageJson(filePath, trimmed, options)\n : fromList(filePath, content)\n}\n\nconst looksLikeJson = (trimmed: string): boolean => trimmed.startsWith(\"{\")\n\n/* -------------------------------------------------------------------------- */\n/* package.json */\n/* -------------------------------------------------------------------------- */\n\ninterface PackageJsonShape {\n readonly dependencies?: Record<string, string>\n readonly devDependencies?: Record<string, string>\n readonly optionalDependencies?: Record<string, string>\n readonly peerDependencies?: Record<string, string>\n readonly peerDependenciesMeta?: Record<string, { optional?: boolean }>\n}\n\nconst fromPackageJson = (\n filePath: string,\n content: string,\n options: InputFileOptions\n): InputFileResult => {\n let parsed: PackageJsonShape\n try {\n parsed = JSON.parse(content) as PackageJsonShape\n } catch (error) {\n throw new InvalidInputFileError(filePath, `not valid JSON — ${describe(error)}`, {\n cause: error\n })\n }\n\n const specs: Array<PackageSpec> = []\n const warnings: Array<string> = []\n const seen = new Set<string>()\n\n const collect = (\n entries: Record<string, string> | undefined,\n label: string,\n skip?: (name: string) => boolean\n ): void => {\n if (entries === undefined) return\n for (const [name, raw] of Object.entries(entries)) {\n if (skip?.(name)) continue\n const target = parseDependencyTarget(name, raw)\n if (target._tag === \"Unsupported\") {\n warnings.push(\n `${label}: skipped ${name}@${target.raw} (${target.reason}) — not fetchable from a registry`\n )\n continue\n }\n const key = `${target.name}|${JSON.stringify(target.selector)}`\n if (seen.has(key)) continue\n seen.add(key)\n specs.push({\n name: target.name,\n selector: target.selector,\n raw: `${target.name}@${raw}`\n })\n }\n }\n\n collect(parsed.dependencies, \"dependencies\")\n collect(parsed.optionalDependencies, \"optionalDependencies\")\n if (options.includeDev) {\n collect(parsed.devDependencies, \"devDependencies\")\n }\n const meta = parsed.peerDependenciesMeta ?? {}\n collect(parsed.peerDependencies, \"peerDependencies\", (name) => meta[name]?.optional === true)\n\n if (specs.length === 0) {\n throw new InvalidInputFileError(\n filePath,\n options.includeDev\n ? \"package.json declares no dependencies to bundle\"\n : \"package.json declares no non-dev dependencies to bundle (drop --prod to include devDependencies)\"\n )\n }\n\n return { kind: \"package.json\", specs, warnings }\n}\n\n/* -------------------------------------------------------------------------- */\n/* Spec list */\n/* -------------------------------------------------------------------------- */\n\nconst fromList = (filePath: string, content: string): InputFileResult => {\n const lines: Array<string> = []\n const rawLines = content.split(/\\r?\\n/)\n\n for (const line of rawLines) {\n const withoutComment = stripComment(line).trim()\n if (withoutComment.length === 0) continue\n lines.push(withoutComment)\n }\n\n if (lines.length === 0) {\n throw new InvalidInputFileError(filePath, \"no package specs found (only blank lines and comments)\")\n }\n\n const { specs, errors } = parseSpecs(lines)\n if (errors.length > 0) {\n throw new InvalidInputFileError(filePath, formatSpecErrors(errors, rawLines))\n }\n\n return { kind: \"list\", specs, warnings: [] }\n}\n\n/**\n * Strips `#` and `//` comments.\n *\n * `//` only counts when it is not part of a URL, so a future line containing\n * `https://…` does not get silently truncated.\n */\nconst stripComment = (line: string): string => {\n const hash = line.indexOf(\"#\")\n let result = hash === -1 ? line : line.slice(0, hash)\n const slashes = result.indexOf(\"//\")\n if (slashes > 0 && result[slashes - 1] !== \":\") {\n result = result.slice(0, slashes)\n } else if (slashes === 0) {\n result = \"\"\n }\n return result\n}\n\nconst formatSpecErrors = (\n errors: ReadonlyArray<InvalidSpecError>,\n rawLines: ReadonlyArray<string>\n): string => {\n const details = errors.map((error) => {\n const index = rawLines.findIndex((line) => stripComment(line).trim() === error.spec)\n const where = index === -1 ? \"\" : ` (line ${index + 1})`\n return ` ${error.spec}${where}: ${error.reason}`\n })\n return `${errors.length} invalid spec(s):\\n${details.join(\"\\n\")}`\n}\n\nconst describe = (error: unknown): string =>\n error instanceof Error ? error.message : String(error)\n","/**\n * Option types shared by the resolver and the bundler, plus their defaults.\n *\n * Defaults are chosen so that the *unflagged* command produces a bundle that\n * actually installs offline on a machine that is not the one you built it on.\n * Every switch that makes the bundle smaller is opt-in.\n */\nimport type { PlatformFilter } from \"./Platform.js\"\nimport { allPlatforms } from \"./Platform.js\"\n\n/** How the resulting tarball(s) are shaped. */\nexport type Layout =\n /**\n * One tarball per requested spec, each carrying its own complete dependency\n * closure. Shared dependencies repeat across tarballs, so the total is\n * larger — but each one imports, rolls back and hands off independently.\n */\n | \"per-spec\"\n /**\n * One tarball for everything, with the union of all closures deduplicated.\n * Smallest output and a single import step; all-or-nothing to roll back.\n */\n | \"single\"\n /**\n * No archive at all — just the npm-layout directory tree, ready for\n * `jf rt upload` or rsync.\n */\n | \"dir\"\n\nexport const layouts: ReadonlyArray<Layout> = [\"per-spec\", \"single\", \"dir\"]\n\n/** Which dependency edges the resolver follows. */\nexport interface DependencyScope {\n /**\n * Follow `optionalDependencies`. On by default — this is where per-platform\n * native binaries live, and omitting them is the most common reason an\n * offline install fails on a machine other than the one that built it.\n */\n readonly optional: boolean\n /**\n * Follow non-optional `peerDependencies`. On by default, because npm 7+\n * auto-installs peers and will reach for the network if they are absent.\n */\n readonly peer: boolean\n /** Which platforms optional dependencies are kept for. */\n readonly platforms: PlatformFilter\n}\n\nexport const defaultScope: DependencyScope = {\n optional: true,\n peer: true,\n platforms: allPlatforms\n}\n\n/** Options governing version selection and the dependency walk. */\nexport interface ResolveOptions {\n readonly scope: DependencyScope\n /**\n * When a root spec is a range, take *every* published version that satisfies\n * it rather than only the best match.\n *\n * `npmb react@^18` bundles one version; `npmb --all-versions react@^18`\n * bundles all of them.\n */\n readonly allVersions: boolean\n /** With `allVersions`, keep at most this many (newest first). */\n readonly maxVersions?: number | undefined\n /** Let prereleases satisfy ranges that would not normally admit them. */\n readonly includePrerelease: boolean\n /** How many registry requests to have in flight at once. */\n readonly concurrency: number\n}\n\nexport const defaultResolveOptions: ResolveOptions = {\n scope: defaultScope,\n allVersions: false,\n includePrerelease: false,\n concurrency: 10\n}\n\n/** Options for a full bundle run. */\nexport interface BundleOptions extends ResolveOptions {\n readonly layout: Layout\n /** Directory the finished artifacts are written to. */\n readonly outDir: string\n /** Base name for the archive in `single` layout. Defaults to `bundle`. */\n readonly archiveName?: string | undefined\n /** Resolve and report, but download nothing and write nothing. */\n readonly dryRun: boolean\n /**\n * Verify every tarball against the checksum the registry advertised.\n *\n * On by default and there is essentially no good reason to turn it off; the\n * escape hatch exists only for registries that serve broken metadata.\n */\n readonly verifyIntegrity: boolean\n /** Overwrite existing files in `outDir` instead of refusing. */\n readonly force: boolean\n /**\n * Planned output files to leave untouched, by file name.\n *\n * The engine never asks anything; deciding is the caller's job. The CLI's\n * `--force prompt` resolves its per-file answers into this set, so \"keep the\n * existing one\" means that artifact is simply not produced, and the rest of\n * the run continues.\n */\n readonly skipExisting?: ReadonlySet<string> | undefined\n /**\n * Planned output files that may be replaced, by file name.\n *\n * A narrower `force`: `--force tsdown` says \"replace tsdown's bundle, and\n * still ask about anything else\".\n */\n readonly overwrite?: ReadonlySet<string> | undefined\n}\n\nexport const defaultBundleOptions: Omit<BundleOptions, \"outDir\"> = {\n ...defaultResolveOptions,\n layout: \"per-spec\",\n dryRun: false,\n verifyIntegrity: true,\n force: false\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@packall/core",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Registry-agnostic engine for bundling npm packages and their full dependency closure for offline import.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"src"
|
|
15
|
+
],
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"semver": "^7.7.2",
|
|
21
|
+
"tar": "^7.5.1"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"effect": "4.0.0-beta.103"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@effect/platform-node": "4.0.0-beta.103",
|
|
28
|
+
"@types/semver": "^7.7.1",
|
|
29
|
+
"effect": "4.0.0-beta.103"
|
|
30
|
+
},
|
|
31
|
+
"main": "./dist/index.js",
|
|
32
|
+
"module": "./dist/index.js",
|
|
33
|
+
"scripts": {
|
|
34
|
+
"build": "tsdown && tsc -p tsconfig.build.json",
|
|
35
|
+
"check": "tsc -p tsconfig.json",
|
|
36
|
+
"test": "vitest run"
|
|
37
|
+
}
|
|
38
|
+
}
|
package/src/Archive.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning a staged directory tree into a gzipped tarball.
|
|
3
|
+
*
|
|
4
|
+
* Uses `node-tar`, the same library npm itself packs with. Writing a USTAR
|
|
5
|
+
* encoder by hand would be a fun afternoon and a bad idea: scoped package
|
|
6
|
+
* paths routinely exceed the 100-byte name field, so correctness depends on
|
|
7
|
+
* prefix-splitting and PAX headers that `tar` already gets right.
|
|
8
|
+
*/
|
|
9
|
+
import * as Effect from "effect/Effect"
|
|
10
|
+
import * as FileSystem from "effect/FileSystem"
|
|
11
|
+
import type { PlatformError } from "effect/PlatformError"
|
|
12
|
+
import { create } from "tar"
|
|
13
|
+
import { ArchiveError } from "./Errors.js"
|
|
14
|
+
import * as Progress from "./Progress.js"
|
|
15
|
+
|
|
16
|
+
/** A finished archive. */
|
|
17
|
+
export interface ArchiveResult {
|
|
18
|
+
readonly path: string
|
|
19
|
+
readonly bytes: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Packs `entries` (paths relative to `cwd`) into a gzipped tar at `outPath`.
|
|
24
|
+
*
|
|
25
|
+
* `portable` normalises uid/gid/mtime so the same inputs produce byte-identical
|
|
26
|
+
* output — which matters when a security team wants to diff two bundles or
|
|
27
|
+
* re-derive one from a manifest.
|
|
28
|
+
*/
|
|
29
|
+
export const createArchive = (options: {
|
|
30
|
+
readonly cwd: string
|
|
31
|
+
readonly entries: ReadonlyArray<string>
|
|
32
|
+
readonly outPath: string
|
|
33
|
+
readonly gzipLevel?: number | undefined
|
|
34
|
+
}): Effect.Effect<ArchiveResult, ArchiveError | PlatformError, FileSystem.FileSystem | Progress.Progress> =>
|
|
35
|
+
Effect.gen(function*() {
|
|
36
|
+
const fs = yield* FileSystem.FileSystem
|
|
37
|
+
|
|
38
|
+
yield* Progress.emit({
|
|
39
|
+
_tag: "ArchiveStarted",
|
|
40
|
+
path: options.outPath,
|
|
41
|
+
entryCount: options.entries.length
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
yield* Effect.tryPromise({
|
|
45
|
+
try: () =>
|
|
46
|
+
create(
|
|
47
|
+
{
|
|
48
|
+
gzip: options.gzipLevel === undefined ? true : { level: options.gzipLevel },
|
|
49
|
+
file: options.outPath,
|
|
50
|
+
cwd: options.cwd,
|
|
51
|
+
portable: true,
|
|
52
|
+
// Undo the `./` added below, so recorded entry names stay exactly
|
|
53
|
+
// the registry paths the manifest lists.
|
|
54
|
+
onWriteEntry: (entry) => {
|
|
55
|
+
entry.path = entry.path.replace(/^\.\//, "")
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
// Sorted so archive order is stable across runs and platforms.
|
|
59
|
+
[...options.entries].sort().map(dotSlash)
|
|
60
|
+
),
|
|
61
|
+
catch: (cause) => new ArchiveError(options.outPath, describe(cause), { cause })
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
const info = yield* fs.stat(options.outPath)
|
|
65
|
+
const bytes = Number(info.size)
|
|
66
|
+
|
|
67
|
+
yield* Progress.emit({ _tag: "ArchiveCompleted", path: options.outPath, bytes })
|
|
68
|
+
|
|
69
|
+
return { path: options.outPath, bytes }
|
|
70
|
+
})
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Guards every entry against tar's `@` convention.
|
|
74
|
+
*
|
|
75
|
+
* In a tar file list, a leading `@` means "splice in the entries of this other
|
|
76
|
+
* archive" — a GNU convention `node-tar` implements by stripping the `@` and
|
|
77
|
+
* looking for what is left. Every scoped package is a top-level entry starting
|
|
78
|
+
* with `@`, so this hit the bundler in both possible ways:
|
|
79
|
+
*
|
|
80
|
+
* - `@oxc-project` became `oxc-project`, which does not exist, and the run died
|
|
81
|
+
* with an ENOENT naming a path that appears nowhere in the staging tree.
|
|
82
|
+
* - `@esbuild` became `esbuild`, which *does* exist — the unscoped package of
|
|
83
|
+
* the same name sitting right next to it. No error, and every scoped tarball
|
|
84
|
+
* silently missing from a bundle that reported success. That is the dangerous
|
|
85
|
+
* one: you would not find out until the install failed behind the firewall.
|
|
86
|
+
*
|
|
87
|
+
* `./@scope` is not subject to the convention and resolves identically.
|
|
88
|
+
*/
|
|
89
|
+
const dotSlash = (entry: string): string => (entry.startsWith("./") ? entry : `./${entry}`)
|
|
90
|
+
|
|
91
|
+
const describe = (cause: unknown): string =>
|
|
92
|
+
cause instanceof Error ? cause.message : String(cause)
|