@packall/core 0.1.0 → 0.2.0

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.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/archive-6sqTn1C4.js +274 -0
  4. package/dist/archive-6sqTn1C4.js.map +1 -0
  5. package/dist/archive.d.ts +47 -15
  6. package/dist/archive.d.ts.map +1 -1
  7. package/dist/bundle.d.ts +6 -3
  8. package/dist/bundle.d.ts.map +1 -1
  9. package/dist/dependency-range.d.ts.map +1 -1
  10. package/dist/download.d.ts +2 -1
  11. package/dist/download.d.ts.map +1 -1
  12. package/dist/enums/artifact-kind.d.ts.map +1 -1
  13. package/dist/enums/edge-kind.d.ts.map +1 -1
  14. package/dist/enums/input-file-kind.d.ts.map +1 -1
  15. package/dist/enums/layout.d.ts.map +1 -1
  16. package/dist/enums/lockfile-format.d.ts.map +1 -1
  17. package/dist/enums/phase.d.ts.map +1 -1
  18. package/dist/errors.d.ts.map +1 -1
  19. package/dist/index.d.ts +12 -10
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +169 -344
  22. package/dist/index.js.map +1 -1
  23. package/dist/input-file.d.ts.map +1 -1
  24. package/dist/integrity.d.ts +37 -5
  25. package/dist/integrity.d.ts.map +1 -1
  26. package/dist/layout.d.ts +41 -7
  27. package/dist/layout.d.ts.map +1 -1
  28. package/dist/locked-resolve.d.ts.map +1 -1
  29. package/dist/lockfile/bun.d.ts.map +1 -1
  30. package/dist/lockfile/detect.d.ts.map +1 -1
  31. package/dist/lockfile/json.d.ts.map +1 -1
  32. package/dist/lockfile/names.d.ts.map +1 -1
  33. package/dist/lockfile/npm.d.ts.map +1 -1
  34. package/dist/lockfile/parse.d.ts.map +1 -1
  35. package/dist/lockfile/pnpm.d.ts.map +1 -1
  36. package/dist/lockfile/tree-builder.d.ts.map +1 -1
  37. package/dist/lockfile/types.d.ts.map +1 -1
  38. package/dist/manifest.d.ts.map +1 -1
  39. package/dist/node/archiver.d.ts +5 -0
  40. package/dist/node/archiver.d.ts.map +1 -0
  41. package/dist/node/index.d.ts +13 -0
  42. package/dist/node/index.d.ts.map +1 -0
  43. package/dist/node/index.js +55 -0
  44. package/dist/node/index.js.map +1 -0
  45. package/dist/options.d.ts +3 -3
  46. package/dist/options.d.ts.map +1 -1
  47. package/dist/platform.d.ts +5 -10
  48. package/dist/platform.d.ts.map +1 -1
  49. package/dist/progress.d.ts.map +1 -1
  50. package/dist/registry.d.ts.map +1 -1
  51. package/dist/resolve.d.ts.map +1 -1
  52. package/dist/schemas/lenient.d.ts.map +1 -1
  53. package/dist/schemas/package-json.d.ts.map +1 -1
  54. package/dist/spec.d.ts.map +1 -1
  55. package/dist/types/value-of.d.ts.map +1 -1
  56. package/dist/utils/is-record.d.ts.map +1 -1
  57. package/package.json +11 -10
  58. package/src/archive.ts +95 -92
  59. package/src/bundle.ts +736 -616
  60. package/src/dependency-range.ts +121 -115
  61. package/src/download.ts +155 -133
  62. package/src/enums/artifact-kind.ts +5 -5
  63. package/src/enums/edge-kind.ts +13 -13
  64. package/src/enums/input-file-kind.ts +9 -9
  65. package/src/enums/layout.ts +20 -20
  66. package/src/enums/lockfile-format.ts +6 -6
  67. package/src/enums/phase.ts +8 -8
  68. package/src/errors.ts +200 -198
  69. package/src/index.ts +126 -113
  70. package/src/input-file.ts +246 -234
  71. package/src/integrity.ts +165 -121
  72. package/src/layout.ts +63 -29
  73. package/src/locked-resolve.ts +471 -461
  74. package/src/lockfile/bun.ts +214 -207
  75. package/src/lockfile/detect.ts +80 -80
  76. package/src/lockfile/json.ts +91 -92
  77. package/src/lockfile/names.ts +9 -9
  78. package/src/lockfile/npm.ts +328 -308
  79. package/src/lockfile/parse.ts +32 -32
  80. package/src/lockfile/pnpm.ts +230 -225
  81. package/src/lockfile/tree-builder.ts +116 -116
  82. package/src/lockfile/types.ts +52 -52
  83. package/src/manifest.ts +129 -133
  84. package/src/node/archiver.ts +85 -0
  85. package/src/node/index.ts +13 -0
  86. package/src/options.ts +84 -84
  87. package/src/platform.ts +97 -101
  88. package/src/progress.ts +105 -106
  89. package/src/registry.ts +116 -115
  90. package/src/resolve.ts +560 -537
  91. package/src/schemas/lenient.ts +67 -60
  92. package/src/schemas/package-json.ts +11 -10
  93. package/src/spec.ts +123 -119
  94. package/src/types/value-of.ts +1 -1
  95. package/src/utils/is-record.ts +1 -1
package/src/manifest.ts CHANGED
@@ -1,133 +1,129 @@
1
- /**
2
- * The manifest written into every bundle.
3
- *
4
- * This is the audit trail. Before anything is imported into a corporate
5
- * registry somebody is usually required to answer "what exactly is in here and
6
- * where did it come from" — this file answers that without unpacking a single
7
- * tarball.
8
- */
9
- import { packagePath } from "./layout.js"
10
- import type { BundleOptions } from "./options.js"
11
- import { formatPlatformFilter } from "./platform.js"
12
- import type { Resolution, ResolvedPackage } from "./resolve.js"
13
- import { formatSpec } from "./spec.js"
14
-
15
- /** Schema version, bumped when the shape changes incompatibly. */
16
- export const MANIFEST_VERSION = 1
17
-
18
- export type ManifestEntry = {
19
- readonly name: string
20
- readonly version: string
21
- /** Path of this tarball inside the bundle. */
22
- readonly path: string
23
- /** The URL it was downloaded from. */
24
- readonly tarball: string
25
- /** SRI integrity string as advertised by the source registry, when present. */
26
- readonly integrity?: string | undefined
27
- /** Legacy sha1, present on older published versions. */
28
- readonly shasum?: string | undefined
29
- /** Actual size on disk, in bytes. */
30
- readonly bytes?: number | undefined
31
- /** Human-readable justifications: `root:react@18.2.0`, `prod:scheduler@0.23.0`. */
32
- readonly reasons: ReadonlyArray<string>
33
- }
34
-
35
- export type BundleManifest = {
36
- readonly manifestVersion: number
37
- readonly tool: { readonly name: string; readonly version: string }
38
- readonly createdAt: string
39
- readonly registry: { readonly kind: string; readonly url: string }
40
- /** What the user asked for, verbatim. */
41
- readonly requested: ReadonlyArray<string>
42
- /** What each request expanded to. */
43
- readonly roots: ReadonlyArray<{
44
- readonly spec: string
45
- readonly versions: ReadonlyArray<string>
46
- readonly packageCount: number
47
- }>
48
- readonly options: {
49
- readonly layout: string
50
- readonly optionalDependencies: boolean
51
- readonly peerDependencies: boolean
52
- readonly platforms: string
53
- readonly allVersions: boolean
54
- readonly includePrerelease: boolean
55
- readonly integrityVerified: boolean
56
- }
57
- readonly packages: ReadonlyArray<ManifestEntry>
58
- readonly warnings: ReadonlyArray<string>
59
- readonly totals: {
60
- readonly packages: number
61
- readonly bytes: number
62
- }
63
- }
64
-
65
- /** Renders a package's reasons into short, greppable strings. */
66
- export const formatReasons = (pkg: ResolvedPackage): ReadonlyArray<string> =>
67
- pkg.reasons.map((reason) =>
68
- reason._tag === "Root" ? `root:${reason.spec}` : `${reason.kind}:${reason.from}`
69
- )
70
-
71
- /** Builds the manifest for a completed (or dry) run. */
72
- export const buildManifest = (input: {
73
- readonly resolution: Resolution
74
- /** Only the packages actually included in *this* archive. */
75
- readonly included: ReadonlyArray<ResolvedPackage>
76
- readonly options: BundleOptions
77
- readonly registry: { readonly kind: string; readonly url: string }
78
- readonly toolVersion: string
79
- readonly sizes: ReadonlyMap<string, number>
80
- readonly createdAt?: Date | undefined
81
- }): BundleManifest => {
82
- const includedNames = new Set(input.included.map((pkg) => `${pkg.name}@${pkg.version}`))
83
-
84
- const packages: ReadonlyArray<ManifestEntry> = input.included.map((pkg) => {
85
- const key = `${pkg.name}@${pkg.version}`
86
- return {
87
- name: pkg.name,
88
- version: pkg.version,
89
- path: packagePath(pkg.name, pkg.version),
90
- tarball: pkg.manifest.dist.tarball,
91
- integrity: pkg.manifest.dist.integrity,
92
- shasum: pkg.manifest.dist.shasum,
93
- bytes: input.sizes.get(key),
94
- reasons: formatReasons(pkg)
95
- }
96
- })
97
-
98
- const totalBytes = packages.reduce((sum, entry) => sum + (entry.bytes ?? 0), 0)
99
-
100
- return {
101
- manifestVersion: MANIFEST_VERSION,
102
- tool: { name: "packall", version: input.toolVersion },
103
- createdAt: (input.createdAt ?? new Date()).toISOString(),
104
- registry: input.registry,
105
- requested: input.resolution.roots.map((root) => formatSpec(root.spec)),
106
- roots: input.resolution.roots.map((root) => ({
107
- spec: formatSpec(root.spec),
108
- versions: root.versions,
109
- packageCount: root.closure.filter((key) => includedNames.has(key)).length
110
- })),
111
- options: {
112
- layout: input.options.layout,
113
- optionalDependencies: input.options.scope.optional,
114
- peerDependencies: input.options.scope.peer,
115
- platforms: formatPlatformFilter(input.options.scope.platforms),
116
- allVersions: input.options.allVersions,
117
- includePrerelease: input.options.includePrerelease,
118
- integrityVerified: input.options.verifyIntegrity
119
- },
120
- packages,
121
- warnings: input.resolution.warnings.map((warning) =>
122
- warning.from === undefined ? warning.message : `${warning.from}: ${warning.message}`
123
- ),
124
- totals: {
125
- packages: packages.length,
126
- bytes: totalBytes
127
- }
128
- }
129
- }
130
-
131
- /** Serialises a manifest with stable key order and a trailing newline. */
132
- export const serializeManifest = (manifest: BundleManifest): string =>
133
- `${JSON.stringify(manifest, null, 2)}\n`
1
+ /**
2
+ * The manifest written into every bundle — the audit trail, answerable without
3
+ * unpacking a single tarball. See `notes/requirements.md` § FR-10.
4
+ */
5
+ import { packagePath } from "./layout.js";
6
+ import type { BundleOptions } from "./options.js";
7
+ import { formatPlatformFilter } from "./platform.js";
8
+ import type { Resolution, ResolvedPackage } from "./resolve.js";
9
+ import { formatSpec } from "./spec.js";
10
+
11
+ /** Schema version, bumped when the shape changes incompatibly. */
12
+ export const MANIFEST_VERSION = 1;
13
+
14
+ export type ManifestEntry = {
15
+ readonly name: string;
16
+ readonly version: string;
17
+ /** Path of this tarball inside the bundle. */
18
+ readonly path: string;
19
+ /** The URL it was downloaded from. */
20
+ readonly tarball: string;
21
+ /** SRI integrity string as advertised by the source registry, when present. */
22
+ readonly integrity?: string | undefined;
23
+ /** Legacy sha1, present on older published versions. */
24
+ readonly shasum?: string | undefined;
25
+ /** Actual size on disk, in bytes. */
26
+ readonly bytes?: number | undefined;
27
+ /** Human-readable justifications: `root:react@18.2.0`, `prod:scheduler@0.23.0`. */
28
+ readonly reasons: ReadonlyArray<string>;
29
+ };
30
+
31
+ export type BundleManifest = {
32
+ readonly manifestVersion: number;
33
+ readonly tool: { readonly name: string; readonly version: string };
34
+ readonly createdAt: string;
35
+ readonly registry: { readonly kind: string; readonly url: string };
36
+ /** What the user asked for, verbatim. */
37
+ readonly requested: ReadonlyArray<string>;
38
+ /** What each request expanded to. */
39
+ readonly roots: ReadonlyArray<{
40
+ readonly spec: string;
41
+ readonly versions: ReadonlyArray<string>;
42
+ readonly packageCount: number;
43
+ }>;
44
+ readonly options: {
45
+ readonly layout: string;
46
+ readonly optionalDependencies: boolean;
47
+ readonly peerDependencies: boolean;
48
+ readonly platforms: string;
49
+ readonly allVersions: boolean;
50
+ readonly includePrerelease: boolean;
51
+ readonly integrityVerified: boolean;
52
+ };
53
+ readonly packages: ReadonlyArray<ManifestEntry>;
54
+ readonly warnings: ReadonlyArray<string>;
55
+ readonly totals: {
56
+ readonly packages: number;
57
+ readonly bytes: number;
58
+ };
59
+ };
60
+
61
+ /** Renders a package's reasons into short, greppable strings. */
62
+ export const formatReasons = (pkg: ResolvedPackage): ReadonlyArray<string> =>
63
+ pkg.reasons.map((reason) =>
64
+ reason._tag === "Root" ? `root:${reason.spec}` : `${reason.kind}:${reason.from}`,
65
+ );
66
+
67
+ /** Builds the manifest for a completed (or dry) run. */
68
+ export const buildManifest = (input: {
69
+ readonly resolution: Resolution;
70
+ /** Only the packages actually included in *this* archive. */
71
+ readonly included: ReadonlyArray<ResolvedPackage>;
72
+ readonly options: BundleOptions;
73
+ readonly registry: { readonly kind: string; readonly url: string };
74
+ readonly toolVersion: string;
75
+ readonly sizes: ReadonlyMap<string, number>;
76
+ readonly createdAt?: Date | undefined;
77
+ }): BundleManifest => {
78
+ const includedNames = new Set(input.included.map((pkg) => `${pkg.name}@${pkg.version}`));
79
+
80
+ const packages: ReadonlyArray<ManifestEntry> = input.included.map((pkg) => {
81
+ const key = `${pkg.name}@${pkg.version}`;
82
+ return {
83
+ name: pkg.name,
84
+ version: pkg.version,
85
+ path: packagePath(pkg.name, pkg.version),
86
+ tarball: pkg.manifest.dist.tarball,
87
+ integrity: pkg.manifest.dist.integrity,
88
+ shasum: pkg.manifest.dist.shasum,
89
+ bytes: input.sizes.get(key),
90
+ reasons: formatReasons(pkg),
91
+ };
92
+ });
93
+
94
+ const totalBytes = packages.reduce((sum, entry) => sum + (entry.bytes ?? 0), 0);
95
+
96
+ return {
97
+ manifestVersion: MANIFEST_VERSION,
98
+ tool: { name: "packall", version: input.toolVersion },
99
+ createdAt: (input.createdAt ?? new Date()).toISOString(),
100
+ registry: input.registry,
101
+ requested: input.resolution.roots.map((root) => formatSpec(root.spec)),
102
+ roots: input.resolution.roots.map((root) => ({
103
+ spec: formatSpec(root.spec),
104
+ versions: root.versions,
105
+ packageCount: root.closure.filter((key) => includedNames.has(key)).length,
106
+ })),
107
+ options: {
108
+ layout: input.options.layout,
109
+ optionalDependencies: input.options.scope.optional,
110
+ peerDependencies: input.options.scope.peer,
111
+ platforms: formatPlatformFilter(input.options.scope.platforms),
112
+ allVersions: input.options.allVersions,
113
+ includePrerelease: input.options.includePrerelease,
114
+ integrityVerified: input.options.verifyIntegrity,
115
+ },
116
+ packages,
117
+ warnings: input.resolution.warnings.map((warning) =>
118
+ warning.from === undefined ? warning.message : `${warning.from}: ${warning.message}`,
119
+ ),
120
+ totals: {
121
+ packages: packages.length,
122
+ bytes: totalBytes,
123
+ },
124
+ };
125
+ };
126
+
127
+ /** Serialises a manifest with stable key order and a trailing newline. */
128
+ export const serializeManifest = (manifest: BundleManifest): string =>
129
+ `${JSON.stringify(manifest, null, 2)}\n`;
@@ -0,0 +1,85 @@
1
+ /**
2
+ * The Node `Archiver`, backed by `node-tar`.
3
+ *
4
+ * Behind `@packall/core/node` rather than the main barrel: importing
5
+ * `@packall/core` must not drag `node-tar` — and through it `node:fs` — into a
6
+ * browser bundle. Anything running on Node reaches for this explicitly.
7
+ *
8
+ * Uses `node-tar`, the same library npm itself packs with. Writing a USTAR
9
+ * encoder by hand would be a fun afternoon and a bad idea: scoped package
10
+ * paths routinely exceed the 100-byte name field, so correctness depends on
11
+ * prefix-splitting and PAX headers that `tar` already gets right.
12
+ */
13
+ import * as Effect from "effect/Effect";
14
+ import * as FileSystem from "effect/FileSystem";
15
+ import * as Layer from "effect/Layer";
16
+ import type { PlatformError } from "effect/PlatformError";
17
+ import { create } from "tar";
18
+
19
+ import type { ArchiveResult, CreateArchiveOptions } from "../archive.js";
20
+ import { Archiver } from "../archive.js";
21
+ import { ArchiveError } from "../errors.js";
22
+
23
+ const createArchive = (
24
+ options: CreateArchiveOptions,
25
+ ): Effect.Effect<ArchiveResult, ArchiveError | PlatformError, FileSystem.FileSystem> =>
26
+ Effect.gen(function* () {
27
+ const fs = yield* FileSystem.FileSystem;
28
+
29
+ yield* Effect.tryPromise({
30
+ try: () =>
31
+ create(
32
+ {
33
+ gzip: options.gzipLevel === undefined ? true : { level: options.gzipLevel },
34
+ file: options.outPath,
35
+ cwd: options.cwd,
36
+ // Normalises uid/gid/mtime so the same inputs produce byte-identical
37
+ // output — which matters when a security team wants to diff two
38
+ // bundles or re-derive one from a manifest.
39
+ portable: true,
40
+ // Undo the `./` added below, so recorded entry names stay exactly
41
+ // the registry paths the manifest lists.
42
+ onWriteEntry: (entry) => {
43
+ entry.path = entry.path.replace(/^\.\//, "");
44
+ },
45
+ },
46
+ // Sorted so archive order is stable across runs and platforms.
47
+ options.entries.toSorted().map(dotSlash),
48
+ ),
49
+ catch: (cause) => new ArchiveError(options.outPath, describe(cause), { cause }),
50
+ });
51
+
52
+ const info = yield* fs.stat(options.outPath);
53
+
54
+ return { path: options.outPath, bytes: Number(info.size) };
55
+ });
56
+
57
+ /** The Node packing backend. */
58
+ export const layerArchiver: Layer.Layer<Archiver> = Layer.succeed(Archiver)({
59
+ create: createArchive,
60
+ });
61
+
62
+ /**
63
+ * Guards every entry against tar's `@` convention.
64
+ *
65
+ * In a tar file list, a leading `@` means "splice in the entries of this other
66
+ * archive" — a GNU convention `node-tar` implements by stripping the `@` and
67
+ * looking for what is left. Every scoped package is a top-level entry starting
68
+ * with `@`, so this hit the bundler in both possible ways:
69
+ *
70
+ * - `@oxc-project` became `oxc-project`, which does not exist, and the run died
71
+ * with an ENOENT naming a path that appears nowhere in the staging tree.
72
+ * - `@esbuild` became `esbuild`, which *does* exist — the unscoped package of
73
+ * the same name sitting right next to it. No error, and every scoped tarball
74
+ * silently missing from a bundle that reported success. That is the dangerous
75
+ * one: you would not find out until the install failed behind the firewall.
76
+ *
77
+ * `./@scope` is not subject to the convention and resolves identically.
78
+ *
79
+ * Any other backend has to answer this question too — the browser writer must
80
+ * be held to the same test.
81
+ */
82
+ const dotSlash = (entry: string): string => (entry.startsWith("./") ? entry : `./${entry}`);
83
+
84
+ const describe = (cause: unknown): string =>
85
+ cause instanceof Error ? cause.message : String(cause);
@@ -0,0 +1,13 @@
1
+ /**
2
+ * `@packall/core/node` — the engine's Node-specific layers.
3
+ *
4
+ * Everything here is separated from the main barrel for one reason: importing
5
+ * `@packall/core` must stay safe in a browser. The engine itself reaches the
6
+ * outside world only through services — `Registry`, `Progress`, `Archiver`,
7
+ * `FileSystem`, `Path`, `Crypto` — so the platform lives at the edges, and this
8
+ * is the Node edge. A browser supplies its own.
9
+ *
10
+ * This is the entry point's whole public API.
11
+ */
12
+
13
+ export { layerArchiver } from "./archiver.js";
package/src/options.ts CHANGED
@@ -1,103 +1,103 @@
1
1
  /**
2
2
  * Option types shared by the resolver and the bundler, plus their defaults.
3
3
  *
4
- * Defaults are chosen so that the *unflagged* command produces a bundle that
5
- * actually installs offline on a machine that is not the one you built it on.
6
- * Every switch that makes the bundle smaller is opt-in.
4
+ * The rule the defaults below are derived from is stated once, beside the flags
5
+ * that expose them see `descriptors.ts` in `@packall/cli`, and
6
+ * `notes/requirements.md` § FR-13.
7
7
  */
8
- import { Layout } from "./enums/layout.js"
9
- import type { PlatformFilter } from "./platform.js"
10
- import { allPlatforms } from "./platform.js"
8
+ import { Layout } from "./enums/layout.js";
9
+ import type { PlatformFilter } from "./platform.js";
10
+ import { allPlatforms } from "./platform.js";
11
11
 
12
12
  /** Which dependency edges the resolver follows. */
13
13
  export type DependencyScope = {
14
- /**
15
- * Follow `optionalDependencies`. On by default — this is where per-platform
16
- * native binaries live, and omitting them is the most common reason an
17
- * offline install fails on a machine other than the one that built it.
18
- */
19
- readonly optional: boolean
20
- /**
21
- * Follow non-optional `peerDependencies`. On by default, because npm 7+
22
- * auto-installs peers and will reach for the network if they are absent.
23
- */
24
- readonly peer: boolean
25
- /** Which platforms optional dependencies are kept for. */
26
- readonly platforms: PlatformFilter
27
- }
14
+ /**
15
+ * Follow `optionalDependencies`. On by default — this is where per-platform
16
+ * native binaries live, and omitting them is the most common reason an
17
+ * offline install fails on a machine other than the one that built it.
18
+ */
19
+ readonly optional: boolean;
20
+ /**
21
+ * Follow non-optional `peerDependencies`. On by default, because npm 7+
22
+ * auto-installs peers and will reach for the network if they are absent.
23
+ */
24
+ readonly peer: boolean;
25
+ /** Which platforms optional dependencies are kept for. */
26
+ readonly platforms: PlatformFilter;
27
+ };
28
28
 
29
29
  export const defaultScope: DependencyScope = {
30
- optional: true,
31
- peer: true,
32
- platforms: allPlatforms
33
- }
30
+ optional: true,
31
+ peer: true,
32
+ platforms: allPlatforms,
33
+ };
34
34
 
35
35
  /** Options governing version selection and the dependency walk. */
36
36
  export type ResolveOptions = {
37
- readonly scope: DependencyScope
38
- /**
39
- * When a root spec is a range, take *every* published version that satisfies
40
- * it rather than only the best match.
41
- *
42
- * `npmb react@^18` bundles one version; `npmb --all-versions react@^18`
43
- * bundles all of them.
44
- */
45
- readonly allVersions: boolean
46
- /** With `allVersions`, keep at most this many (newest first). */
47
- readonly maxVersions?: number | undefined
48
- /** Let prereleases satisfy ranges that would not normally admit them. */
49
- readonly includePrerelease: boolean
50
- /** How many registry requests to have in flight at once. */
51
- readonly concurrency: number
52
- }
37
+ readonly scope: DependencyScope;
38
+ /**
39
+ * When a root spec is a range, take *every* published version that satisfies
40
+ * it rather than only the best match.
41
+ *
42
+ * `npmb react@^18` bundles one version; `npmb --all-versions react@^18`
43
+ * bundles all of them.
44
+ */
45
+ readonly allVersions: boolean;
46
+ /** With `allVersions`, keep at most this many (newest first). */
47
+ readonly maxVersions?: number | undefined;
48
+ /** Let prereleases satisfy ranges that would not normally admit them. */
49
+ readonly includePrerelease: boolean;
50
+ /** How many registry requests to have in flight at once. */
51
+ readonly concurrency: number;
52
+ };
53
53
 
54
54
  export const defaultResolveOptions: ResolveOptions = {
55
- scope: defaultScope,
56
- allVersions: false,
57
- includePrerelease: false,
58
- concurrency: 10
59
- }
55
+ scope: defaultScope,
56
+ allVersions: false,
57
+ includePrerelease: false,
58
+ concurrency: 10,
59
+ };
60
60
 
61
61
  /** Options for a full bundle run. */
62
62
  export type BundleOptions = ResolveOptions & {
63
- readonly layout: Layout
64
- /** Directory the finished artifacts are written to. */
65
- readonly outDir: string
66
- /** Base name for the archive in `single` layout. Defaults to `bundle`. */
67
- readonly archiveName?: string | undefined
68
- /** Resolve and report, but download nothing and write nothing. */
69
- readonly dryRun: boolean
70
- /**
71
- * Verify every tarball against the checksum the registry advertised.
72
- *
73
- * On by default and there is essentially no good reason to turn it off; the
74
- * escape hatch exists only for registries that serve broken metadata.
75
- */
76
- readonly verifyIntegrity: boolean
77
- /** Overwrite existing files in `outDir` instead of refusing. */
78
- readonly force: boolean
79
- /**
80
- * Planned output files to leave untouched, by file name.
81
- *
82
- * The engine never asks anything; deciding is the caller's job. The CLI's
83
- * `--force prompt` resolves its per-file answers into this set, so "keep the
84
- * existing one" means that artifact is simply not produced, and the rest of
85
- * the run continues.
86
- */
87
- readonly skipExisting?: ReadonlySet<string> | undefined
88
- /**
89
- * Planned output files that may be replaced, by file name.
90
- *
91
- * A narrower `force`: `--force tsdown` says "replace tsdown's bundle, and
92
- * still ask about anything else".
93
- */
94
- readonly overwrite?: ReadonlySet<string> | undefined
95
- }
63
+ readonly layout: Layout;
64
+ /** Directory the finished artifacts are written to. */
65
+ readonly outDir: string;
66
+ /** Base name for the archive in `single` layout. Defaults to `bundle`. */
67
+ readonly archiveName?: string | undefined;
68
+ /** Resolve and report, but download nothing and write nothing. */
69
+ readonly dryRun: boolean;
70
+ /**
71
+ * Verify every tarball against the checksum the registry advertised.
72
+ *
73
+ * On by default and there is essentially no good reason to turn it off; the
74
+ * escape hatch exists only for registries that serve broken metadata.
75
+ */
76
+ readonly verifyIntegrity: boolean;
77
+ /** Overwrite existing files in `outDir` instead of refusing. */
78
+ readonly force: boolean;
79
+ /**
80
+ * Planned output files to leave untouched, by file name.
81
+ *
82
+ * The engine never asks anything; deciding is the caller's job. The CLI's
83
+ * `--force prompt` resolves its per-file answers into this set, so "keep the
84
+ * existing one" means that artifact is simply not produced, and the rest of
85
+ * the run continues.
86
+ */
87
+ readonly skipExisting?: ReadonlySet<string> | undefined;
88
+ /**
89
+ * Planned output files that may be replaced, by file name.
90
+ *
91
+ * A narrower `force`: `--force tsdown` says "replace tsdown's bundle, and
92
+ * still ask about anything else".
93
+ */
94
+ readonly overwrite?: ReadonlySet<string> | undefined;
95
+ };
96
96
 
97
97
  export const defaultBundleOptions: Omit<BundleOptions, "outDir"> = {
98
- ...defaultResolveOptions,
99
- layout: Layout.PerSpec,
100
- dryRun: false,
101
- verifyIntegrity: true,
102
- force: false
103
- }
98
+ ...defaultResolveOptions,
99
+ layout: Layout.PerSpec,
100
+ dryRun: false,
101
+ verifyIntegrity: true,
102
+ force: false,
103
+ };