@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.
- package/LICENSE +21 -0
- package/README.md +58 -0
- package/dist/archive-DmF9XNl7.js +284 -0
- package/dist/archive-DmF9XNl7.js.map +1 -0
- package/dist/archive.d.ts +47 -15
- package/dist/archive.d.ts.map +1 -1
- package/dist/bundle.d.ts +6 -3
- package/dist/bundle.d.ts.map +1 -1
- package/dist/dependency-range.d.ts.map +1 -1
- package/dist/download.d.ts +2 -1
- package/dist/download.d.ts.map +1 -1
- package/dist/enums/artifact-kind.d.ts.map +1 -1
- package/dist/enums/edge-kind.d.ts.map +1 -1
- package/dist/enums/input-file-kind.d.ts.map +1 -1
- package/dist/enums/layout.d.ts.map +1 -1
- package/dist/enums/lockfile-format.d.ts.map +1 -1
- package/dist/enums/phase.d.ts.map +1 -1
- package/dist/errors.d.ts +11 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/index.d.ts +12 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +169 -344
- package/dist/index.js.map +1 -1
- package/dist/input-file.d.ts.map +1 -1
- package/dist/integrity.d.ts +37 -5
- package/dist/integrity.d.ts.map +1 -1
- package/dist/layout.d.ts +41 -7
- package/dist/layout.d.ts.map +1 -1
- package/dist/locked-resolve.d.ts.map +1 -1
- package/dist/lockfile/bun.d.ts.map +1 -1
- package/dist/lockfile/detect.d.ts.map +1 -1
- package/dist/lockfile/json.d.ts.map +1 -1
- package/dist/lockfile/names.d.ts.map +1 -1
- package/dist/lockfile/npm.d.ts.map +1 -1
- package/dist/lockfile/parse.d.ts.map +1 -1
- package/dist/lockfile/pnpm.d.ts.map +1 -1
- package/dist/lockfile/tree-builder.d.ts.map +1 -1
- package/dist/lockfile/types.d.ts.map +1 -1
- package/dist/manifest.d.ts.map +1 -1
- package/dist/node/archiver.d.ts +5 -0
- package/dist/node/archiver.d.ts.map +1 -0
- package/dist/node/index.d.ts +13 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +55 -0
- package/dist/node/index.js.map +1 -0
- package/dist/options.d.ts +3 -3
- package/dist/options.d.ts.map +1 -1
- package/dist/platform.d.ts +5 -10
- package/dist/platform.d.ts.map +1 -1
- package/dist/progress.d.ts.map +1 -1
- package/dist/registry.d.ts.map +1 -1
- package/dist/resolve.d.ts.map +1 -1
- package/dist/schemas/lenient.d.ts.map +1 -1
- package/dist/schemas/package-json.d.ts.map +1 -1
- package/dist/spec.d.ts.map +1 -1
- package/dist/types/value-of.d.ts.map +1 -1
- package/dist/utils/is-record.d.ts.map +1 -1
- package/package.json +11 -10
- package/src/archive.ts +95 -92
- package/src/bundle.ts +736 -616
- package/src/dependency-range.ts +121 -115
- package/src/download.ts +155 -133
- package/src/enums/artifact-kind.ts +5 -5
- package/src/enums/edge-kind.ts +13 -13
- package/src/enums/input-file-kind.ts +9 -9
- package/src/enums/layout.ts +20 -20
- package/src/enums/lockfile-format.ts +6 -6
- package/src/enums/phase.ts +8 -8
- package/src/errors.ts +211 -199
- package/src/index.ts +126 -113
- package/src/input-file.ts +246 -234
- package/src/integrity.ts +165 -121
- package/src/layout.ts +63 -29
- package/src/locked-resolve.ts +471 -461
- package/src/lockfile/bun.ts +214 -207
- package/src/lockfile/detect.ts +80 -80
- package/src/lockfile/json.ts +91 -92
- package/src/lockfile/names.ts +9 -9
- package/src/lockfile/npm.ts +328 -308
- package/src/lockfile/parse.ts +32 -32
- package/src/lockfile/pnpm.ts +230 -225
- package/src/lockfile/tree-builder.ts +116 -116
- package/src/lockfile/types.ts +52 -52
- package/src/manifest.ts +129 -133
- package/src/node/archiver.ts +85 -0
- package/src/node/index.ts +13 -0
- package/src/options.ts +84 -84
- package/src/platform.ts +97 -101
- package/src/progress.ts +105 -106
- package/src/registry.ts +116 -115
- package/src/resolve.ts +560 -537
- package/src/schemas/lenient.ts +67 -60
- package/src/schemas/package-json.ts +11 -10
- package/src/spec.ts +123 -119
- package/src/types/value-of.ts +1 -1
- package/src/utils/is-record.ts +1 -1
package/src/enums/layout.ts
CHANGED
|
@@ -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
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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>;
|
package/src/enums/phase.ts
CHANGED
|
@@ -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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
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
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
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
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
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
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
}
|
|
304
|
+
try {
|
|
305
|
+
const url = new URL(registry);
|
|
306
|
+
return url.host + url.pathname.replace(/\/+$/, "");
|
|
307
|
+
} catch {
|
|
308
|
+
return registry;
|
|
309
|
+
}
|
|
310
|
+
};
|