@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/integrity.ts
CHANGED
|
@@ -1,121 +1,165 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Checksum verification for downloaded tarballs.
|
|
3
|
-
*
|
|
4
|
-
* A
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Checksum verification for downloaded tarballs.
|
|
3
|
+
*
|
|
4
|
+
* A failed check discards the download rather than warning and carrying on —
|
|
5
|
+
* see `notes/requirements.md` § FR-9 for why that strictness is a requirement
|
|
6
|
+
* rather than a preference.
|
|
7
|
+
*
|
|
8
|
+
* Built on Effect's `Crypto` service rather than `node:crypto` directly. The
|
|
9
|
+
* four digests `Crypto` offers — SHA-1, SHA-256, SHA-384, SHA-512 — are exactly
|
|
10
|
+
* the four npm publishes, so nothing is given up, and the same verification
|
|
11
|
+
* then runs unchanged against WebCrypto in a browser. Parsing stays here
|
|
12
|
+
* because the subset of Subresource Integrity npm actually emits is small and
|
|
13
|
+
* entirely mechanical; `ssri` would be a dependency for a regex.
|
|
14
|
+
*/
|
|
15
|
+
import * as Crypto from "effect/Crypto";
|
|
16
|
+
import * as Effect from "effect/Effect";
|
|
17
|
+
import * as Encoding from "effect/Encoding";
|
|
18
|
+
import type { PlatformError } from "effect/PlatformError";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The digests npm publishes, mapped to what `Crypto.digest` calls them.
|
|
22
|
+
*
|
|
23
|
+
* Doubles as the supported-algorithm list: an SRI token whose algorithm is not
|
|
24
|
+
* a key here is one we cannot check, and is dropped during parsing.
|
|
25
|
+
*/
|
|
26
|
+
const digestAlgorithmByName = {
|
|
27
|
+
sha512: "SHA-512",
|
|
28
|
+
sha384: "SHA-384",
|
|
29
|
+
sha256: "SHA-256",
|
|
30
|
+
sha1: "SHA-1",
|
|
31
|
+
} as const satisfies Record<string, Crypto.DigestAlgorithm>;
|
|
32
|
+
|
|
33
|
+
/** An algorithm this module can verify against. */
|
|
34
|
+
export type IntegrityAlgorithm = keyof typeof digestAlgorithmByName;
|
|
35
|
+
|
|
36
|
+
const isSupported = (algorithm: string): algorithm is IntegrityAlgorithm =>
|
|
37
|
+
Object.hasOwn(digestAlgorithmByName, algorithm);
|
|
38
|
+
|
|
39
|
+
/** One parsed SRI hash. */
|
|
40
|
+
export type IntegrityHash = {
|
|
41
|
+
readonly algorithm: IntegrityAlgorithm;
|
|
42
|
+
/** Base64 digest, exactly as written in the SRI string. */
|
|
43
|
+
readonly digest: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Parses an SRI string such as `sha512-abc...==`.
|
|
48
|
+
*
|
|
49
|
+
* npm permits several space-separated hashes; we keep every one we can verify
|
|
50
|
+
* and ignore algorithms we cannot.
|
|
51
|
+
*/
|
|
52
|
+
export const parseIntegrity = (integrity: string): ReadonlyArray<IntegrityHash> => {
|
|
53
|
+
const hashes: Array<IntegrityHash> = [];
|
|
54
|
+
for (const token of integrity.trim().split(/\s+/)) {
|
|
55
|
+
if (token.length === 0) continue;
|
|
56
|
+
const dash = token.indexOf("-");
|
|
57
|
+
if (dash <= 0) continue;
|
|
58
|
+
const algorithm = token.slice(0, dash).toLowerCase();
|
|
59
|
+
const digest = token.slice(dash + 1);
|
|
60
|
+
if (!isSupported(algorithm) || digest.length === 0) continue;
|
|
61
|
+
hashes.push({ algorithm, digest });
|
|
62
|
+
}
|
|
63
|
+
return hashes;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
const digestBytes = (
|
|
67
|
+
data: Uint8Array,
|
|
68
|
+
algorithm: IntegrityAlgorithm,
|
|
69
|
+
): Effect.Effect<Uint8Array, PlatformError, Crypto.Crypto> =>
|
|
70
|
+
Effect.gen(function* () {
|
|
71
|
+
const crypto = yield* Crypto.Crypto;
|
|
72
|
+
return yield* crypto.digest(digestAlgorithmByName[algorithm], data);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
/** Computes the base64 digest of some bytes under one algorithm. */
|
|
76
|
+
export const digestOf = (
|
|
77
|
+
data: Uint8Array,
|
|
78
|
+
algorithm: IntegrityAlgorithm,
|
|
79
|
+
): Effect.Effect<string, PlatformError, Crypto.Crypto> =>
|
|
80
|
+
Effect.map(digestBytes(data, algorithm), Encoding.encodeBase64);
|
|
81
|
+
|
|
82
|
+
/** Computes the hex digest of some bytes — the form legacy `shasum` uses. */
|
|
83
|
+
export const hexDigestOf = (
|
|
84
|
+
data: Uint8Array,
|
|
85
|
+
algorithm: IntegrityAlgorithm,
|
|
86
|
+
): Effect.Effect<string, PlatformError, Crypto.Crypto> =>
|
|
87
|
+
Effect.map(digestBytes(data, algorithm), Encoding.encodeHex);
|
|
88
|
+
|
|
89
|
+
/** Result of checking a download. */
|
|
90
|
+
export type VerificationResult =
|
|
91
|
+
/** Verified against at least one checksum. */
|
|
92
|
+
| { readonly _tag: "Verified"; readonly using: string }
|
|
93
|
+
/** The registry advertised no checksum we could use. */
|
|
94
|
+
| { readonly _tag: "Unverifiable"; readonly reason: string }
|
|
95
|
+
/** A checksum was present and did not match. */
|
|
96
|
+
| { readonly _tag: "Mismatch"; readonly expected: string; readonly actual: string };
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Constant-time comparison of two digest strings.
|
|
100
|
+
*
|
|
101
|
+
* Written by hand rather than with `node:crypto`'s `timingSafeEqual`, which
|
|
102
|
+
* needs `Buffer` and would pin this module to Node. Both digests here are
|
|
103
|
+
* public knowledge, so the timing property is close to theatre — but it costs
|
|
104
|
+
* four lines, and the alternative is explaining in a review why it was dropped.
|
|
105
|
+
*/
|
|
106
|
+
const digestsEqual = (a: string, b: string): boolean => {
|
|
107
|
+
if (a.length !== b.length) return false;
|
|
108
|
+
let difference = 0;
|
|
109
|
+
for (let index = 0; index < a.length; index++) {
|
|
110
|
+
difference |= a.charCodeAt(index) ^ b.charCodeAt(index);
|
|
111
|
+
}
|
|
112
|
+
return difference === 0;
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Checks bytes against whichever checksums the registry supplied.
|
|
117
|
+
*
|
|
118
|
+
* SRI is preferred; `shasum` is the fallback for versions published before
|
|
119
|
+
* integrity strings existed. If the registry gave us neither, that is reported
|
|
120
|
+
* as `Unverifiable` rather than silently treated as a pass — the caller decides
|
|
121
|
+
* whether to tolerate it.
|
|
122
|
+
*/
|
|
123
|
+
export const verify = (
|
|
124
|
+
data: Uint8Array,
|
|
125
|
+
dist: { readonly integrity?: string | undefined; readonly shasum?: string | undefined },
|
|
126
|
+
): Effect.Effect<VerificationResult, PlatformError, Crypto.Crypto> =>
|
|
127
|
+
Effect.gen(function* () {
|
|
128
|
+
if (dist.integrity !== undefined && dist.integrity.length > 0) {
|
|
129
|
+
// Strongest first, so a mismatch is reported against the best hash present.
|
|
130
|
+
const [best] = parseIntegrity(dist.integrity).toSorted(
|
|
131
|
+
(a, b) => strengthByAlgorithm[b.algorithm] - strengthByAlgorithm[a.algorithm],
|
|
132
|
+
);
|
|
133
|
+
if (best === undefined) {
|
|
134
|
+
return {
|
|
135
|
+
_tag: "Unverifiable",
|
|
136
|
+
reason: `no supported algorithm in "${dist.integrity}"`,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const actual = yield* digestOf(data, best.algorithm);
|
|
141
|
+
return digestsEqual(actual, best.digest)
|
|
142
|
+
? { _tag: "Verified", using: best.algorithm }
|
|
143
|
+
: {
|
|
144
|
+
_tag: "Mismatch",
|
|
145
|
+
expected: `${best.algorithm}-${best.digest}`,
|
|
146
|
+
actual: `${best.algorithm}-${actual}`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (dist.shasum !== undefined && dist.shasum.length > 0) {
|
|
151
|
+
const actual = yield* hexDigestOf(data, "sha1");
|
|
152
|
+
return digestsEqual(actual.toLowerCase(), dist.shasum.toLowerCase())
|
|
153
|
+
? { _tag: "Verified", using: "sha1" }
|
|
154
|
+
: { _tag: "Mismatch", expected: `sha1-${dist.shasum}`, actual: `sha1-${actual}` };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return { _tag: "Unverifiable", reason: "registry advertised no integrity or shasum" };
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
const strengthByAlgorithm = {
|
|
161
|
+
sha512: 4,
|
|
162
|
+
sha384: 3,
|
|
163
|
+
sha256: 2,
|
|
164
|
+
sha1: 1,
|
|
165
|
+
} as const satisfies Record<IntegrityAlgorithm, number>;
|
package/src/layout.ts
CHANGED
|
@@ -7,27 +7,29 @@
|
|
|
7
7
|
* @babel/core/-/core-7.24.0.tgz
|
|
8
8
|
*
|
|
9
9
|
* That is not an Artifactory convention — it is the path structure in every
|
|
10
|
-
* `dist.tarball` URL npm publishes
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* `dist.tarball` URL npm publishes. See `notes/requirements.md` § FR-12 for
|
|
11
|
+
* what that buys.
|
|
12
|
+
*
|
|
13
|
+
* The one shape worth noticing before editing anything here: a scoped
|
|
14
|
+
* package's file name drops the scope, so `@babel/core` becomes
|
|
15
|
+
* `core-7.24.0.tgz` under an `@babel/core/-/` directory.
|
|
14
16
|
*/
|
|
15
17
|
|
|
16
18
|
/** Splits `@scope/name` into its parts. `scope` is undefined when unscoped. */
|
|
17
19
|
export const splitName = (
|
|
18
|
-
|
|
20
|
+
name: string,
|
|
19
21
|
): { readonly scope: string | undefined; readonly bare: string } => {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
22
|
+
if (!name.startsWith("@")) return { scope: undefined, bare: name };
|
|
23
|
+
const slash = name.indexOf("/");
|
|
24
|
+
if (slash === -1) return { scope: undefined, bare: name };
|
|
25
|
+
return { scope: name.slice(0, slash), bare: name.slice(slash + 1) };
|
|
26
|
+
};
|
|
25
27
|
|
|
26
28
|
/** `@babel/core` + `7.24.0` -> `core-7.24.0.tgz` */
|
|
27
29
|
export const tarballFileName = (name: string, version: string): string => {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
30
|
+
const { bare } = splitName(name);
|
|
31
|
+
return `${bare}-${version}.tgz`;
|
|
32
|
+
};
|
|
31
33
|
|
|
32
34
|
/**
|
|
33
35
|
* The path of one package tarball within a bundle, using `/` separators
|
|
@@ -35,29 +37,61 @@ export const tarballFileName = (name: string, version: string): string => {
|
|
|
35
37
|
* are always POSIX.
|
|
36
38
|
*/
|
|
37
39
|
export const packagePath = (name: string, version: string): string =>
|
|
38
|
-
|
|
40
|
+
`${name}/-/${tarballFileName(name, version)}`;
|
|
39
41
|
|
|
40
42
|
/** File name of the manifest that ships inside every bundle. */
|
|
41
|
-
export const MANIFEST_FILE = "bundle-manifest.json"
|
|
43
|
+
export const MANIFEST_FILE = "bundle-manifest.json";
|
|
42
44
|
|
|
43
45
|
/** File name of the short import guide that ships inside every bundle. */
|
|
44
|
-
export const README_FILE = "IMPORT.md"
|
|
46
|
+
export const README_FILE = "IMPORT.md";
|
|
45
47
|
|
|
46
48
|
/**
|
|
47
49
|
* Name of the archive produced for one root spec in `per-spec` layout.
|
|
48
50
|
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
51
|
+
* It is the spec, with the one character a file name cannot hold taken out:
|
|
52
|
+
* `@types/react@19.2.18` becomes `@types-react@19.2.18.tgz`. So the name of the
|
|
53
|
+
* file answers the question somebody has when they are looking at a directory
|
|
54
|
+
* of them — which package, and which version — in the notation they would have
|
|
55
|
+
* typed to ask for it.
|
|
56
|
+
*
|
|
57
|
+
* The version is joined with `@` rather than `-` for the same reason. A
|
|
58
|
+
* hyphen made `foo-bar-1.0.0` ambiguous by eye: package `foo` at `bar-1.0.0`,
|
|
59
|
+
* or `foo-bar` at `1.0.0`? npm's own syntax has no such problem, because a
|
|
60
|
+
* package name may not contain `@` beyond its scope.
|
|
61
|
+
*
|
|
62
|
+
* **The scope's `@` stays**, and it is the difference between a correct bundle
|
|
63
|
+
* and a quietly incomplete one.
|
|
64
|
+
*
|
|
65
|
+
* Dropping it — which this did, matching what `npm pack` produces — meant
|
|
66
|
+
* `@something/somewhat` and `something-somewhat` were both
|
|
67
|
+
* `something-somewhat-1.0.0.tgz`. Two different packages, one path: the second
|
|
68
|
+
* landed on the first, and the run reported two artifacts for the one file that
|
|
69
|
+
* survived. A bundle short a package, called complete, found at the far end of
|
|
70
|
+
* an air gap.
|
|
71
|
+
*
|
|
72
|
+
* Keeping the `@` makes that impossible by construction rather than by a check,
|
|
73
|
+
* because an unscoped npm name may not begin with one. It is also the more
|
|
74
|
+
* honest name: the scope is part of what the package *is*, and a directory of
|
|
75
|
+
* archives that has forgotten which ones were scoped is a directory somebody
|
|
76
|
+
* has to cross-reference against a manifest.
|
|
77
|
+
*
|
|
78
|
+
* It does not make every collision impossible — `@a/b-c` and `@a-b/c` still
|
|
79
|
+
* meet — so `assertDistinctOutputs` still runs. That pair is pathological; the
|
|
80
|
+
* scoped-against-unscoped one is `@babel/core` beside `babel-core`, which is a
|
|
81
|
+
* real migration somebody could be bundling.
|
|
82
|
+
*
|
|
83
|
+
* The leading `@` is safe here in a way it is not inside the archive: tar's
|
|
84
|
+
* splice convention applies to the *file list* it is given, which is what
|
|
85
|
+
* `archive.ts` guards with `./`. This is the output path, not an entry.
|
|
52
86
|
*/
|
|
53
87
|
export const perSpecArchiveName = (name: string, version: string): string => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
88
|
+
const { scope, bare } = splitName(name);
|
|
89
|
+
const prefix = scope === undefined ? bare : `${scope}-${bare}`;
|
|
90
|
+
return `${prefix}@${version}.tgz`;
|
|
91
|
+
};
|
|
58
92
|
|
|
59
93
|
/** Name of the archive produced in `single` layout. */
|
|
60
|
-
export const singleArchiveName = (base = "bundle"): string => `${base}.tgz
|
|
94
|
+
export const singleArchiveName = (base = "bundle"): string => `${base}.tgz`;
|
|
61
95
|
|
|
62
96
|
/**
|
|
63
97
|
* The import guide written into each bundle.
|
|
@@ -66,11 +100,11 @@ export const singleArchiveName = (base = "bundle"): string => `${base}.tgz`
|
|
|
66
100
|
* restricted network and does not want prose.
|
|
67
101
|
*/
|
|
68
102
|
export const importGuide = (options: {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
103
|
+
readonly packageCount: number;
|
|
104
|
+
readonly createdAt: string;
|
|
105
|
+
readonly toolVersion: string;
|
|
72
106
|
}): string =>
|
|
73
|
-
|
|
107
|
+
`# Importing this bundle
|
|
74
108
|
|
|
75
109
|
${options.packageCount} package tarball(s), laid out exactly as an npm registry serves them:
|
|
76
110
|
|
|
@@ -100,4 +134,4 @@ Publish each tarball individually:
|
|
|
100
134
|
|
|
101
135
|
Every entry in ${MANIFEST_FILE} carries the integrity string the source registry
|
|
102
136
|
advertised, and each tarball was checked against it at download time.
|
|
103
|
-
|
|
137
|
+
`;
|