@packall/core 0.1.0 → 0.3.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 (96) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -0
  3. package/dist/archive-DmF9XNl7.js +284 -0
  4. package/dist/archive-DmF9XNl7.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 +11 -1
  19. package/dist/errors.d.ts.map +1 -1
  20. package/dist/index.d.ts +12 -10
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +169 -344
  23. package/dist/index.js.map +1 -1
  24. package/dist/input-file.d.ts.map +1 -1
  25. package/dist/integrity.d.ts +37 -5
  26. package/dist/integrity.d.ts.map +1 -1
  27. package/dist/layout.d.ts +41 -7
  28. package/dist/layout.d.ts.map +1 -1
  29. package/dist/locked-resolve.d.ts.map +1 -1
  30. package/dist/lockfile/bun.d.ts.map +1 -1
  31. package/dist/lockfile/detect.d.ts.map +1 -1
  32. package/dist/lockfile/json.d.ts.map +1 -1
  33. package/dist/lockfile/names.d.ts.map +1 -1
  34. package/dist/lockfile/npm.d.ts.map +1 -1
  35. package/dist/lockfile/parse.d.ts.map +1 -1
  36. package/dist/lockfile/pnpm.d.ts.map +1 -1
  37. package/dist/lockfile/tree-builder.d.ts.map +1 -1
  38. package/dist/lockfile/types.d.ts.map +1 -1
  39. package/dist/manifest.d.ts.map +1 -1
  40. package/dist/node/archiver.d.ts +5 -0
  41. package/dist/node/archiver.d.ts.map +1 -0
  42. package/dist/node/index.d.ts +13 -0
  43. package/dist/node/index.d.ts.map +1 -0
  44. package/dist/node/index.js +55 -0
  45. package/dist/node/index.js.map +1 -0
  46. package/dist/options.d.ts +3 -3
  47. package/dist/options.d.ts.map +1 -1
  48. package/dist/platform.d.ts +5 -10
  49. package/dist/platform.d.ts.map +1 -1
  50. package/dist/progress.d.ts.map +1 -1
  51. package/dist/registry.d.ts.map +1 -1
  52. package/dist/resolve.d.ts.map +1 -1
  53. package/dist/schemas/lenient.d.ts.map +1 -1
  54. package/dist/schemas/package-json.d.ts.map +1 -1
  55. package/dist/spec.d.ts.map +1 -1
  56. package/dist/types/value-of.d.ts.map +1 -1
  57. package/dist/utils/is-record.d.ts.map +1 -1
  58. package/package.json +11 -10
  59. package/src/archive.ts +95 -92
  60. package/src/bundle.ts +736 -616
  61. package/src/dependency-range.ts +121 -115
  62. package/src/download.ts +155 -133
  63. package/src/enums/artifact-kind.ts +5 -5
  64. package/src/enums/edge-kind.ts +13 -13
  65. package/src/enums/input-file-kind.ts +9 -9
  66. package/src/enums/layout.ts +20 -20
  67. package/src/enums/lockfile-format.ts +6 -6
  68. package/src/enums/phase.ts +8 -8
  69. package/src/errors.ts +211 -199
  70. package/src/index.ts +126 -113
  71. package/src/input-file.ts +246 -234
  72. package/src/integrity.ts +165 -121
  73. package/src/layout.ts +63 -29
  74. package/src/locked-resolve.ts +471 -461
  75. package/src/lockfile/bun.ts +214 -207
  76. package/src/lockfile/detect.ts +80 -80
  77. package/src/lockfile/json.ts +91 -92
  78. package/src/lockfile/names.ts +9 -9
  79. package/src/lockfile/npm.ts +328 -308
  80. package/src/lockfile/parse.ts +32 -32
  81. package/src/lockfile/pnpm.ts +230 -225
  82. package/src/lockfile/tree-builder.ts +116 -116
  83. package/src/lockfile/types.ts +52 -52
  84. package/src/manifest.ts +129 -133
  85. package/src/node/archiver.ts +85 -0
  86. package/src/node/index.ts +13 -0
  87. package/src/options.ts +84 -84
  88. package/src/platform.ts +97 -101
  89. package/src/progress.ts +105 -106
  90. package/src/registry.ts +116 -115
  91. package/src/resolve.ts +560 -537
  92. package/src/schemas/lenient.ts +67 -60
  93. package/src/schemas/package-json.ts +11 -10
  94. package/src/spec.ts +123 -119
  95. package/src/types/value-of.ts +1 -1
  96. package/src/utils/is-record.ts +1 -1
@@ -1,25 +1,25 @@
1
- import type { ValueOf } from "../types/value-of.js"
1
+ import type { ValueOf } from "../types/value-of.js";
2
2
 
3
3
  /** How the resulting tarball(s) are shaped. */
4
4
  export const Layout = {
5
- /**
6
- * One tarball per requested spec, each carrying its own complete dependency
7
- * closure. Shared dependencies repeat across tarballs, so the total is
8
- * larger — but each one imports, rolls back and hands off independently.
9
- */
10
- PerSpec: "per-spec",
11
- /**
12
- * One tarball for everything, with the union of all closures deduplicated.
13
- * Smallest output and a single import step; all-or-nothing to roll back.
14
- */
15
- Single: "single",
16
- /**
17
- * No archive at all — just the npm-layout directory tree, ready for
18
- * `jf rt upload` or rsync.
19
- */
20
- Dir: "dir"
21
- } as const
5
+ /**
6
+ * One tarball per requested spec, each carrying its own complete dependency
7
+ * closure. Shared dependencies repeat across tarballs, so the total is
8
+ * larger — but each one imports, rolls back and hands off independently.
9
+ */
10
+ PerSpec: "per-spec",
11
+ /**
12
+ * One tarball for everything, with the union of all closures deduplicated.
13
+ * Smallest output and a single import step; all-or-nothing to roll back.
14
+ */
15
+ Single: "single",
16
+ /**
17
+ * No archive at all — just the npm-layout directory tree, ready for
18
+ * `jf rt upload` or rsync.
19
+ */
20
+ Dir: "dir",
21
+ } as const;
22
22
 
23
- export type Layout = ValueOf<typeof Layout>
23
+ export type Layout = ValueOf<typeof Layout>;
24
24
 
25
- export const Layouts: ReadonlyArray<Layout> = Object.values(Layout)
25
+ export const Layouts: ReadonlyArray<Layout> = Object.values(Layout);
@@ -1,10 +1,10 @@
1
- import type { ValueOf } from "../types/value-of.js"
1
+ import type { ValueOf } from "../types/value-of.js";
2
2
 
3
3
  /** Which package manager wrote a lockfile. */
4
4
  export const LockfileFormat = {
5
- Npm: "npm",
6
- Pnpm: "pnpm",
7
- Bun: "bun"
8
- } as const
5
+ Npm: "npm",
6
+ Pnpm: "pnpm",
7
+ Bun: "bun",
8
+ } as const;
9
9
 
10
- export type LockfileFormat = ValueOf<typeof LockfileFormat>
10
+ export type LockfileFormat = ValueOf<typeof LockfileFormat>;
@@ -1,12 +1,12 @@
1
- import type { ValueOf } from "../types/value-of.js"
1
+ import type { ValueOf } from "../types/value-of.js";
2
2
 
3
3
  /** The phases a bundle run moves through, in order. */
4
4
  export const Phase = {
5
- Preflight: "preflight",
6
- Resolve: "resolve",
7
- Download: "download",
8
- Archive: "archive",
9
- Done: "done"
10
- } as const
5
+ Preflight: "preflight",
6
+ Resolve: "resolve",
7
+ Download: "download",
8
+ Archive: "archive",
9
+ Done: "done",
10
+ } as const;
11
11
 
12
- export type Phase = ValueOf<typeof Phase>
12
+ export type Phase = ValueOf<typeof Phase>;
package/src/errors.ts CHANGED
@@ -13,66 +13,66 @@
13
13
 
14
14
  /** Discriminant union of every failure the bundler can produce. */
15
15
  export type BundlerError =
16
- | InvalidSpecError
17
- | InvalidInputFileError
18
- | LockfileError
19
- | LockfileIncompleteError
20
- | LockfileOutOfDateError
21
- | RegistryUnreachableError
22
- | PackageNotFoundError
23
- | VersionNotFoundError
24
- | NoMatchingVersionsError
25
- | RegistryResponseError
26
- | AuthenticationError
27
- | IntegrityError
28
- | ArchiveError
29
- | OutputError
16
+ | InvalidSpecError
17
+ | InvalidInputFileError
18
+ | LockfileError
19
+ | LockfileIncompleteError
20
+ | LockfileOutOfDateError
21
+ | RegistryUnreachableError
22
+ | PackageNotFoundError
23
+ | VersionNotFoundError
24
+ | NoMatchingVersionsError
25
+ | RegistryResponseError
26
+ | AuthenticationError
27
+ | IntegrityError
28
+ | ArchiveError
29
+ | OutputError;
30
30
 
31
31
  abstract class BundlerErrorBase extends Error {
32
- abstract readonly _tag: string
33
- constructor(message: string, options?: ErrorOptions) {
34
- super(message, options)
35
- this.name = new.target.name
36
- }
32
+ abstract readonly _tag: string;
33
+ constructor(message: string, options?: ErrorOptions) {
34
+ super(message, options);
35
+ this.name = new.target.name;
36
+ }
37
37
  }
38
38
 
39
39
  /** A package spec on the command line or in an input file could not be parsed. */
40
40
  export class InvalidSpecError extends BundlerErrorBase {
41
- readonly _tag = "InvalidSpecError" as const
42
- readonly spec: string
43
- readonly reason: string
44
- constructor(spec: string, reason: string) {
45
- super(`Invalid package spec ${JSON.stringify(spec)}: ${reason}`)
46
- this.spec = spec
47
- this.reason = reason
48
- }
41
+ readonly _tag = "InvalidSpecError" as const;
42
+ readonly spec: string;
43
+ readonly reason: string;
44
+ constructor(spec: string, reason: string) {
45
+ super(`Invalid package spec ${JSON.stringify(spec)}: ${reason}`);
46
+ this.spec = spec;
47
+ this.reason = reason;
48
+ }
49
49
  }
50
50
 
51
51
  /** `--file` pointed at something that is neither a usable package.json nor a spec list. */
52
52
  export class InvalidInputFileError extends BundlerErrorBase {
53
- readonly _tag = "InvalidInputFileError" as const
54
- readonly path: string
55
- readonly reason: string
56
- constructor(path: string, reason: string, options?: { cause?: unknown }) {
57
- super(`Cannot read specs from ${path}: ${reason}`, options)
58
- this.path = path
59
- this.reason = reason
60
- }
53
+ readonly _tag = "InvalidInputFileError" as const;
54
+ readonly path: string;
55
+ readonly reason: string;
56
+ constructor(path: string, reason: string, options?: { cause?: unknown }) {
57
+ super(`Cannot read specs from ${path}: ${reason}`, options);
58
+ this.path = path;
59
+ this.reason = reason;
60
+ }
61
61
  }
62
62
 
63
63
  /** A lockfile could not be read, or is in a format we do not support. */
64
64
  export class LockfileError extends BundlerErrorBase {
65
- readonly _tag = "LockfileError" as const
66
- readonly path: string
67
- readonly reason: string
68
- constructor(path: string, reason: string, options?: { cause?: unknown }) {
69
- // Opens with "Lockfile" so the renderer's tag prefix does not stutter, and
70
- // because not every reason is a read failure — "does not cover this
71
- // package" is about a file that read perfectly well.
72
- super(`Lockfile ${path}: ${reason}`, options)
73
- this.path = path
74
- this.reason = reason
75
- }
65
+ readonly _tag = "LockfileError" as const;
66
+ readonly path: string;
67
+ readonly reason: string;
68
+ constructor(path: string, reason: string, options?: { cause?: unknown }) {
69
+ // Opens with "Lockfile" so the renderer's tag prefix does not stutter, and
70
+ // because not every reason is a read failure — "does not cover this
71
+ // package" is about a file that read perfectly well.
72
+ super(`Lockfile ${path}: ${reason}`, options);
73
+ this.path = path;
74
+ this.reason = reason;
75
+ }
76
76
  }
77
77
 
78
78
  /**
@@ -84,25 +84,23 @@ export class LockfileError extends BundlerErrorBase {
84
84
  * gap at once so one `npm install` fixes all of them.
85
85
  */
86
86
  export class LockfileIncompleteError extends BundlerErrorBase {
87
- readonly _tag = "LockfileIncompleteError" as const
88
- readonly path: string
89
- readonly missing: ReadonlyArray<string>
90
- constructor(
91
- path: string,
92
- missing: ReadonlyArray<string>,
93
- detail: string,
94
- remedy: string
95
- ) {
96
- const shown = missing.slice(0, 10).map((entry) => ` ${entry}`).join("\n")
97
- const rest = missing.length > 10 ? `\n … and ${missing.length - 10} more` : ""
98
- super(
99
- `${path} is incomplete ${detail}:\n${shown}${rest}\n` +
100
- ` ${remedy}\n` +
101
- ` Or pass --lockfile off to resolve version ranges fresh instead.`
102
- )
103
- this.path = path
104
- this.missing = missing
105
- }
87
+ readonly _tag = "LockfileIncompleteError" as const;
88
+ readonly path: string;
89
+ readonly missing: ReadonlyArray<string>;
90
+ constructor(path: string, missing: ReadonlyArray<string>, detail: string, remedy: string) {
91
+ const shown = missing
92
+ .slice(0, 10)
93
+ .map((entry) => ` ${entry}`)
94
+ .join("\n");
95
+ const rest = missing.length > 10 ? `\n … and ${missing.length - 10} more` : "";
96
+ super(
97
+ `${path} is incomplete ${detail}:\n${shown}${rest}\n` +
98
+ ` ${remedy}\n` +
99
+ ` Or pass --lockfile off to resolve version ranges fresh instead.`,
100
+ );
101
+ this.path = path;
102
+ this.missing = missing;
103
+ }
106
104
  }
107
105
 
108
106
  /**
@@ -113,133 +111,147 @@ export class LockfileIncompleteError extends BundlerErrorBase {
113
111
  * version would produce exactly the mismatch this feature exists to prevent.
114
112
  */
115
113
  export class LockfileOutOfDateError extends BundlerErrorBase {
116
- readonly _tag = "LockfileOutOfDateError" as const
117
- readonly path: string
118
- readonly registry: string
119
- readonly missing: ReadonlyArray<{ readonly name: string; readonly version: string }>
120
- constructor(
121
- path: string,
122
- registry: string,
123
- missing: ReadonlyArray<{ readonly name: string; readonly version: string; readonly detail: string }>
124
- ) {
125
- const shown = missing
126
- .slice(0, 10)
127
- .map((entry) => ` ${entry.name}@${entry.version} — ${entry.detail}`)
128
- .join("\n")
129
- const rest = missing.length > 10 ? `\n … and ${missing.length - 10} more` : ""
130
- super(
131
- `${path} pins ${missing.length} version${missing.length === 1 ? "" : "s"} ` +
132
- `that ${registry} does not serve:\n${shown}${rest}\n` +
133
- ` Refresh the lockfile against this registry, or pass --lockfile off to\n` +
134
- ` resolve version ranges fresh instead.`
135
- )
136
- this.path = path
137
- this.registry = registry
138
- this.missing = missing.map(({ name, version }) => ({ name, version }))
139
- }
114
+ readonly _tag = "LockfileOutOfDateError" as const;
115
+ readonly path: string;
116
+ readonly registry: string;
117
+ readonly missing: ReadonlyArray<{ readonly name: string; readonly version: string }>;
118
+ constructor(
119
+ path: string,
120
+ registry: string,
121
+ missing: ReadonlyArray<{
122
+ readonly name: string;
123
+ readonly version: string;
124
+ readonly detail: string;
125
+ }>,
126
+ ) {
127
+ const shown = missing
128
+ .slice(0, 10)
129
+ .map((entry) => ` ${entry.name}@${entry.version} ${entry.detail}`)
130
+ .join("\n");
131
+ const rest = missing.length > 10 ? `\n … and ${missing.length - 10} more` : "";
132
+ super(
133
+ `${path} pins ${missing.length} version${missing.length === 1 ? "" : "s"} ` +
134
+ `that ${registry} does not serve:\n${shown}${rest}\n` +
135
+ ` Refresh the lockfile against this registry, or pass --lockfile off to\n` +
136
+ ` resolve version ranges fresh instead.`,
137
+ );
138
+ this.path = path;
139
+ this.registry = registry;
140
+ this.missing = missing.map(({ name, version }) => ({ name, version }));
141
+ }
140
142
  }
141
143
 
142
144
  /**
143
145
  * The registry could not be reached at all — DNS failure, refused connection,
144
- * proxy blackhole, or a preflight that timed out.
146
+ * a certificate the machine does not trust, proxy blackhole, or a preflight
147
+ * that timed out.
145
148
  *
146
149
  * This is the error that fixes "hangs forever with no network": we surface it
147
150
  * quickly and say which host we could not reach.
148
151
  */
149
152
  export class RegistryUnreachableError extends BundlerErrorBase {
150
- readonly _tag = "RegistryUnreachableError" as const
151
- readonly registry: string
152
- readonly timeoutMs: number | undefined
153
- constructor(
154
- registry: string,
155
- detail: string,
156
- options?: { cause?: unknown; timeoutMs?: number }
157
- ) {
158
- super(
159
- `Cannot reach registry ${registry}: ${detail}.\n` +
160
- ` Check your network connection, VPN, and the proxy settings in your .npmrc.`,
161
- options
162
- )
163
- this.registry = registry
164
- this.timeoutMs = options?.timeoutMs
165
- }
153
+ readonly _tag = "RegistryUnreachableError" as const;
154
+ readonly registry: string;
155
+ readonly timeoutMs: number | undefined;
156
+ /**
157
+ * `hint` replaces the closing line of advice.
158
+ *
159
+ * The default suits the common case and is wrong for at least one: a
160
+ * rejected certificate is not a network problem, and telling somebody to
161
+ * check their VPN sends them to look at the one thing that is working. The
162
+ * backend knows which failure it saw, so it is the backend that gets to say.
163
+ */
164
+ constructor(
165
+ registry: string,
166
+ detail: string,
167
+ options?: { cause?: unknown; timeoutMs?: number; hint?: string | undefined },
168
+ ) {
169
+ super(
170
+ `Cannot reach registry ${registry}: ${detail}.\n ${options?.hint ?? NETWORK_HINT}`,
171
+ options,
172
+ );
173
+ this.registry = registry;
174
+ this.timeoutMs = options?.timeoutMs;
175
+ }
166
176
  }
167
177
 
178
+ const NETWORK_HINT = "Check your network connection, VPN, and the proxy settings in your .npmrc.";
179
+
168
180
  /** The registry answered, but has never heard of this package. */
169
181
  export class PackageNotFoundError extends BundlerErrorBase {
170
- readonly _tag = "PackageNotFoundError" as const
171
- readonly packageName: string
172
- readonly registry: string
173
- constructor(packageName: string, registry: string) {
174
- super(`Package "${packageName}" was not found on ${registry}`)
175
- this.packageName = packageName
176
- this.registry = registry
177
- }
182
+ readonly _tag = "PackageNotFoundError" as const;
183
+ readonly packageName: string;
184
+ readonly registry: string;
185
+ constructor(packageName: string, registry: string) {
186
+ super(`Package "${packageName}" was not found on ${registry}`);
187
+ this.packageName = packageName;
188
+ this.registry = registry;
189
+ }
178
190
  }
179
191
 
180
192
  /** The package exists but the exact version requested does not. */
181
193
  export class VersionNotFoundError extends BundlerErrorBase {
182
- readonly _tag = "VersionNotFoundError" as const
183
- readonly packageName: string
184
- readonly version: string
185
- readonly available: ReadonlyArray<string>
186
- constructor(packageName: string, version: string, available: ReadonlyArray<string>) {
187
- const tail = available.slice(-5).join(", ")
188
- super(
189
- `${packageName}@${version} does not exist.` +
190
- (tail.length > 0 ? ` Most recent published versions: ${tail}` : "")
191
- )
192
- this.packageName = packageName
193
- this.version = version
194
- this.available = available
195
- }
194
+ readonly _tag = "VersionNotFoundError" as const;
195
+ readonly packageName: string;
196
+ readonly version: string;
197
+ readonly available: ReadonlyArray<string>;
198
+ constructor(packageName: string, version: string, available: ReadonlyArray<string>) {
199
+ const tail = available.slice(-5).join(", ");
200
+ super(
201
+ `${packageName}@${version} does not exist.` +
202
+ (tail.length > 0 ? ` Most recent published versions: ${tail}` : ""),
203
+ );
204
+ this.packageName = packageName;
205
+ this.version = version;
206
+ this.available = available;
207
+ }
196
208
  }
197
209
 
198
210
  /** A range (or dist-tag) matched nothing that is actually published. */
199
211
  export class NoMatchingVersionsError extends BundlerErrorBase {
200
- readonly _tag = "NoMatchingVersionsError" as const
201
- readonly packageName: string
202
- readonly selector: string
203
- readonly available: ReadonlyArray<string>
204
- constructor(packageName: string, selector: string, available: ReadonlyArray<string>) {
205
- const tail = available.slice(-5).join(", ")
206
- super(
207
- `No published version of ${packageName} satisfies "${selector}".` +
208
- (tail.length > 0 ? ` Most recent published versions: ${tail}` : "")
209
- )
210
- this.packageName = packageName
211
- this.selector = selector
212
- this.available = available
213
- }
212
+ readonly _tag = "NoMatchingVersionsError" as const;
213
+ readonly packageName: string;
214
+ readonly selector: string;
215
+ readonly available: ReadonlyArray<string>;
216
+ constructor(packageName: string, selector: string, available: ReadonlyArray<string>) {
217
+ const tail = available.slice(-5).join(", ");
218
+ super(
219
+ `No published version of ${packageName} satisfies "${selector}".` +
220
+ (tail.length > 0 ? ` Most recent published versions: ${tail}` : ""),
221
+ );
222
+ this.packageName = packageName;
223
+ this.selector = selector;
224
+ this.available = available;
225
+ }
214
226
  }
215
227
 
216
228
  /** The registry responded, but with something we cannot use. */
217
229
  export class RegistryResponseError extends BundlerErrorBase {
218
- readonly _tag = "RegistryResponseError" as const
219
- readonly url: string
220
- readonly status: number | undefined
221
- constructor(url: string, detail: string, options?: { cause?: unknown; status?: number }) {
222
- super(`Unexpected response from ${url}: ${detail}`, options)
223
- this.url = url
224
- this.status = options?.status
225
- }
230
+ readonly _tag = "RegistryResponseError" as const;
231
+ readonly url: string;
232
+ readonly status: number | undefined;
233
+ constructor(url: string, detail: string, options?: { cause?: unknown; status?: number }) {
234
+ super(`Unexpected response from ${url}: ${detail}`, options);
235
+ this.url = url;
236
+ this.status = options?.status;
237
+ }
226
238
  }
227
239
 
228
240
  /** 401/403 — almost always a missing or stale token in `.npmrc`. */
229
241
  export class AuthenticationError extends BundlerErrorBase {
230
- readonly _tag = "AuthenticationError" as const
231
- readonly registry: string
232
- readonly status: number
233
- constructor(registry: string, status: number, packageName?: string) {
234
- super(
235
- `Registry ${registry} rejected the request with HTTP ${status}` +
236
- (packageName ? ` while fetching "${packageName}"` : "") +
237
- `.\n Add credentials to your .npmrc, e.g.\n` +
238
- ` //${safeHost(registry)}/:_authToken=\${NPM_TOKEN}`
239
- )
240
- this.registry = registry
241
- this.status = status
242
- }
242
+ readonly _tag = "AuthenticationError" as const;
243
+ readonly registry: string;
244
+ readonly status: number;
245
+ constructor(registry: string, status: number, packageName?: string) {
246
+ super(
247
+ `Registry ${registry} rejected the request with HTTP ${status}` +
248
+ (packageName ? ` while fetching "${packageName}"` : "") +
249
+ `.\n Add credentials to your .npmrc, e.g.\n` +
250
+ ` //${safeHost(registry)}/:_authToken=\${NPM_TOKEN}`,
251
+ );
252
+ this.registry = registry;
253
+ this.status = status;
254
+ }
243
255
  }
244
256
 
245
257
  /**
@@ -249,50 +261,50 @@ export class AuthenticationError extends BundlerErrorBase {
249
261
  * substituted tarball is exactly what integrity checking exists to catch.
250
262
  */
251
263
  export class IntegrityError extends BundlerErrorBase {
252
- readonly _tag = "IntegrityError" as const
253
- readonly packageName: string
254
- readonly version: string
255
- readonly expected: string
256
- readonly actual: string
257
- constructor(packageName: string, version: string, expected: string, actual: string) {
258
- super(
259
- `Integrity check failed for ${packageName}@${version}.\n` +
260
- ` expected: ${expected}\n` +
261
- ` actual: ${actual}\n` +
262
- ` The download was discarded. This is either corruption in transit or a tampered artifact.`
263
- )
264
- this.packageName = packageName
265
- this.version = version
266
- this.expected = expected
267
- this.actual = actual
268
- }
264
+ readonly _tag = "IntegrityError" as const;
265
+ readonly packageName: string;
266
+ readonly version: string;
267
+ readonly expected: string;
268
+ readonly actual: string;
269
+ constructor(packageName: string, version: string, expected: string, actual: string) {
270
+ super(
271
+ `Integrity check failed for ${packageName}@${version}.\n` +
272
+ ` expected: ${expected}\n` +
273
+ ` actual: ${actual}\n` +
274
+ ` The download was discarded. This is either corruption in transit or a tampered artifact.`,
275
+ );
276
+ this.packageName = packageName;
277
+ this.version = version;
278
+ this.expected = expected;
279
+ this.actual = actual;
280
+ }
269
281
  }
270
282
 
271
283
  /** Something went wrong writing the `.tgz`. */
272
284
  export class ArchiveError extends BundlerErrorBase {
273
- readonly _tag = "ArchiveError" as const
274
- readonly path: string
275
- constructor(path: string, detail: string, options?: { cause?: unknown }) {
276
- super(`Failed to create archive ${path}: ${detail}`, options)
277
- this.path = path
278
- }
285
+ readonly _tag = "ArchiveError" as const;
286
+ readonly path: string;
287
+ constructor(path: string, detail: string, options?: { cause?: unknown }) {
288
+ super(`Failed to create archive ${path}: ${detail}`, options);
289
+ this.path = path;
290
+ }
279
291
  }
280
292
 
281
293
  /** Something went wrong preparing or writing to the output directory. */
282
294
  export class OutputError extends BundlerErrorBase {
283
- readonly _tag = "OutputError" as const
284
- readonly path: string
285
- constructor(path: string, detail: string, options?: { cause?: unknown }) {
286
- super(`Output error at ${path}: ${detail}`, options)
287
- this.path = path
288
- }
295
+ readonly _tag = "OutputError" as const;
296
+ readonly path: string;
297
+ constructor(path: string, detail: string, options?: { cause?: unknown }) {
298
+ super(`Output error at ${path}: ${detail}`, options);
299
+ this.path = path;
300
+ }
289
301
  }
290
302
 
291
303
  const safeHost = (registry: string): string => {
292
- try {
293
- const url = new URL(registry)
294
- return url.host + url.pathname.replace(/\/+$/, "")
295
- } catch {
296
- return registry
297
- }
298
- }
304
+ try {
305
+ const url = new URL(registry);
306
+ return url.host + url.pathname.replace(/\/+$/, "");
307
+ } catch {
308
+ return registry;
309
+ }
310
+ };