@packall/core 0.0.1 → 0.1.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 (126) hide show
  1. package/dist/{Archive.d.ts → archive.d.ts} +5 -5
  2. package/dist/archive.d.ts.map +1 -0
  3. package/dist/{Bundle.d.ts → bundle.d.ts} +51 -36
  4. package/dist/bundle.d.ts.map +1 -0
  5. package/dist/{DependencyRange.d.ts → dependency-range.d.ts} +2 -2
  6. package/dist/dependency-range.d.ts.map +1 -0
  7. package/dist/{Download.d.ts → download.d.ts} +7 -7
  8. package/dist/download.d.ts.map +1 -0
  9. package/dist/enums/artifact-kind.d.ts +8 -0
  10. package/dist/enums/artifact-kind.d.ts.map +1 -0
  11. package/dist/enums/edge-kind.d.ts +29 -0
  12. package/dist/enums/edge-kind.d.ts.map +1 -0
  13. package/dist/enums/input-file-kind.d.ts +12 -0
  14. package/dist/enums/input-file-kind.d.ts.map +1 -0
  15. package/dist/enums/layout.d.ts +23 -0
  16. package/dist/enums/layout.d.ts.map +1 -0
  17. package/dist/enums/lockfile-format.d.ts +9 -0
  18. package/dist/enums/lockfile-format.d.ts.map +1 -0
  19. package/dist/enums/phase.d.ts +11 -0
  20. package/dist/enums/phase.d.ts.map +1 -0
  21. package/dist/{Errors.d.ts → errors.d.ts} +49 -7
  22. package/dist/errors.d.ts.map +1 -0
  23. package/dist/index.d.ts +44 -28
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +2416 -1180
  26. package/dist/index.js.map +1 -1
  27. package/dist/input-file.d.ts +77 -0
  28. package/dist/input-file.d.ts.map +1 -0
  29. package/dist/{Integrity.d.ts → integrity.d.ts} +3 -3
  30. package/dist/integrity.d.ts.map +1 -0
  31. package/dist/{Layout.d.ts → layout.d.ts} +1 -1
  32. package/dist/{Layout.d.ts.map → layout.d.ts.map} +1 -1
  33. package/dist/locked-resolve.d.ts +47 -0
  34. package/dist/locked-resolve.d.ts.map +1 -0
  35. package/dist/lockfile/bun.d.ts +3 -0
  36. package/dist/lockfile/bun.d.ts.map +1 -0
  37. package/dist/lockfile/detect.d.ts +31 -0
  38. package/dist/lockfile/detect.d.ts.map +1 -0
  39. package/dist/lockfile/json.d.ts +23 -0
  40. package/dist/lockfile/json.d.ts.map +1 -0
  41. package/dist/lockfile/names.d.ts +16 -0
  42. package/dist/lockfile/names.d.ts.map +1 -0
  43. package/dist/lockfile/npm.d.ts +3 -0
  44. package/dist/lockfile/npm.d.ts.map +1 -0
  45. package/dist/lockfile/parse.d.ts +23 -0
  46. package/dist/lockfile/parse.d.ts.map +1 -0
  47. package/dist/lockfile/pnpm.d.ts +20 -0
  48. package/dist/lockfile/pnpm.d.ts.map +1 -0
  49. package/dist/lockfile/tree-builder.d.ts +70 -0
  50. package/dist/lockfile/tree-builder.d.ts.map +1 -0
  51. package/dist/lockfile/types.d.ts +70 -0
  52. package/dist/lockfile/types.d.ts.map +1 -0
  53. package/dist/{Manifest.d.ts → manifest.d.ts} +7 -15
  54. package/dist/manifest.d.ts.map +1 -0
  55. package/dist/{Options.d.ts → options.d.ts} +9 -27
  56. package/dist/options.d.ts.map +1 -0
  57. package/dist/{Platform.d.ts → platform.d.ts} +9 -9
  58. package/dist/platform.d.ts.map +1 -0
  59. package/dist/{Progress.d.ts → progress.d.ts} +10 -9
  60. package/dist/progress.d.ts.map +1 -0
  61. package/dist/{Registry.d.ts → registry.d.ts} +42 -44
  62. package/dist/registry.d.ts.map +1 -0
  63. package/dist/{Resolve.d.ts → resolve.d.ts} +25 -26
  64. package/dist/resolve.d.ts.map +1 -0
  65. package/dist/schemas/lenient.d.ts +38 -0
  66. package/dist/schemas/lenient.d.ts.map +1 -0
  67. package/dist/schemas/package-json.d.ts +44 -0
  68. package/dist/schemas/package-json.d.ts.map +1 -0
  69. package/dist/{Spec.d.ts → spec.d.ts} +4 -4
  70. package/dist/spec.d.ts.map +1 -0
  71. package/dist/types/value-of.d.ts +9 -0
  72. package/dist/types/value-of.d.ts.map +1 -0
  73. package/dist/utils/is-record.d.ts +8 -0
  74. package/dist/utils/is-record.d.ts.map +1 -0
  75. package/package.json +3 -2
  76. package/src/{Archive.ts → archive.ts} +92 -92
  77. package/src/{Bundle.ts → bundle.ts} +616 -570
  78. package/src/{DependencyRange.ts → dependency-range.ts} +115 -115
  79. package/src/{Download.ts → download.ts} +133 -132
  80. package/src/enums/artifact-kind.ts +9 -0
  81. package/src/enums/edge-kind.ts +32 -0
  82. package/src/enums/input-file-kind.ts +13 -0
  83. package/src/enums/layout.ts +25 -0
  84. package/src/enums/lockfile-format.ts +10 -0
  85. package/src/enums/phase.ts +12 -0
  86. package/src/{Errors.ts → errors.ts} +87 -5
  87. package/src/index.ts +133 -35
  88. package/src/{InputFile.ts → input-file.ts} +127 -44
  89. package/src/{Integrity.ts → integrity.ts} +121 -122
  90. package/src/locked-resolve.ts +461 -0
  91. package/src/lockfile/bun.ts +207 -0
  92. package/src/lockfile/detect.ts +80 -0
  93. package/src/lockfile/json.ts +132 -0
  94. package/src/lockfile/names.ts +20 -0
  95. package/src/lockfile/npm.ts +308 -0
  96. package/src/lockfile/parse.ts +56 -0
  97. package/src/lockfile/pnpm.ts +225 -0
  98. package/src/lockfile/tree-builder.ts +166 -0
  99. package/src/lockfile/types.ts +74 -0
  100. package/src/{Manifest.ts → manifest.ts} +133 -133
  101. package/src/{Options.ts → options.ts} +7 -27
  102. package/src/{Platform.ts → platform.ts} +23 -23
  103. package/src/{Progress.ts → progress.ts} +106 -106
  104. package/src/{Registry.ts → registry.ts} +115 -121
  105. package/src/{Resolve.ts → resolve.ts} +537 -528
  106. package/src/schemas/lenient.ts +123 -0
  107. package/src/schemas/package-json.ts +27 -0
  108. package/src/{Spec.ts → spec.ts} +11 -19
  109. package/src/types/value-of.ts +8 -0
  110. package/src/utils/is-record.ts +8 -0
  111. package/dist/Archive.d.ts.map +0 -1
  112. package/dist/Bundle.d.ts.map +0 -1
  113. package/dist/DependencyRange.d.ts.map +0 -1
  114. package/dist/Download.d.ts.map +0 -1
  115. package/dist/Errors.d.ts.map +0 -1
  116. package/dist/InputFile.d.ts +0 -46
  117. package/dist/InputFile.d.ts.map +0 -1
  118. package/dist/Integrity.d.ts.map +0 -1
  119. package/dist/Manifest.d.ts.map +0 -1
  120. package/dist/Options.d.ts.map +0 -1
  121. package/dist/Platform.d.ts.map +0 -1
  122. package/dist/Progress.d.ts.map +0 -1
  123. package/dist/Registry.d.ts.map +0 -1
  124. package/dist/Resolve.d.ts.map +0 -1
  125. package/dist/Spec.d.ts.map +0 -1
  126. /package/src/{Layout.ts → layout.ts} +0 -0
@@ -1,122 +1,121 @@
1
- /**
2
- * Checksum verification for downloaded tarballs.
3
- *
4
- * A bundle is a supply-chain artifact that gets imported wholesale into a
5
- * corporate registry, so "the bytes I got are the bytes the registry promised"
6
- * is the one property worth being strict about. A failed check discards the
7
- * download rather than warning and carrying on.
8
- *
9
- * Implemented directly against `node:crypto` rather than pulling in `ssri`,
10
- * because the subset of Subresource Integrity that npm actually publishes is
11
- * small and entirely mechanical.
12
- */
13
- import { createHash, timingSafeEqual } from "node:crypto"
14
-
15
- /** One parsed SRI hash. */
16
- export interface IntegrityHash {
17
- readonly algorithm: string
18
- /** Base64 digest, exactly as written in the SRI string. */
19
- readonly digest: string
20
- }
21
-
22
- const SUPPORTED = new Set(["sha512", "sha384", "sha256", "sha1"])
23
-
24
- /**
25
- * Parses an SRI string such as `sha512-abc...==`.
26
- *
27
- * npm permits several space-separated hashes; we keep every one we can verify
28
- * and ignore algorithms Node does not implement.
29
- */
30
- export const parseIntegrity = (integrity: string): ReadonlyArray<IntegrityHash> => {
31
- const hashes: Array<IntegrityHash> = []
32
- for (const token of integrity.trim().split(/\s+/)) {
33
- if (token.length === 0) continue
34
- const dash = token.indexOf("-")
35
- if (dash <= 0) continue
36
- const algorithm = token.slice(0, dash).toLowerCase()
37
- const digest = token.slice(dash + 1)
38
- if (!SUPPORTED.has(algorithm) || digest.length === 0) continue
39
- hashes.push({ algorithm, digest })
40
- }
41
- return hashes
42
- }
43
-
44
- /** Computes the base64 digest of some bytes under one algorithm. */
45
- export const digestOf = (data: Uint8Array, algorithm: string): string =>
46
- createHash(algorithm).update(data).digest("base64")
47
-
48
- /** Computes the hex digest of some bytes — the form legacy `shasum` uses. */
49
- export const hexDigestOf = (data: Uint8Array, algorithm: string): string =>
50
- createHash(algorithm).update(data).digest("hex")
51
-
52
- /** Result of checking a download. */
53
- export type VerificationResult =
54
- /** Verified against at least one checksum. */
55
- | { readonly _tag: "Verified"; readonly using: string }
56
- /** The registry advertised no checksum we could use. */
57
- | { readonly _tag: "Unverifiable"; readonly reason: string }
58
- /** A checksum was present and did not match. */
59
- | { readonly _tag: "Mismatch"; readonly expected: string; readonly actual: string }
60
-
61
- /** Constant-time comparison of two digest strings of equal length. */
62
- const digestsEqual = (a: string, b: string): boolean => {
63
- const left = Buffer.from(a)
64
- const right = Buffer.from(b)
65
- // `timingSafeEqual` throws on unequal lengths, which is itself a mismatch.
66
- return left.length === right.length && timingSafeEqual(left, right)
67
- }
68
-
69
- /**
70
- * Checks bytes against whichever checksums the registry supplied.
71
- *
72
- * SRI is preferred; `shasum` is the fallback for versions published before
73
- * integrity strings existed. If the registry gave us neither, that is reported
74
- * as `Unverifiable` rather than silently treated as a pass — the caller decides
75
- * whether to tolerate it.
76
- */
77
- export const verify = (
78
- data: Uint8Array,
79
- dist: { readonly integrity?: string | undefined; readonly shasum?: string | undefined }
80
- ): VerificationResult => {
81
- if (dist.integrity !== undefined && dist.integrity.length > 0) {
82
- const hashes = parseIntegrity(dist.integrity)
83
- if (hashes.length === 0) {
84
- return { _tag: "Unverifiable", reason: `no supported algorithm in "${dist.integrity}"` }
85
- }
86
- // Strongest first, so a mismatch is reported against the best hash present.
87
- const ordered = [...hashes].sort(
88
- (a, b) => strength(b.algorithm) - strength(a.algorithm)
89
- )
90
- const best = ordered[0]!
91
- const actual = digestOf(data, best.algorithm)
92
- return digestsEqual(actual, best.digest)
93
- ? { _tag: "Verified", using: best.algorithm }
94
- : {
95
- _tag: "Mismatch",
96
- expected: `${best.algorithm}-${best.digest}`,
97
- actual: `${best.algorithm}-${actual}`
98
- }
99
- }
100
-
101
- if (dist.shasum !== undefined && dist.shasum.length > 0) {
102
- const actual = hexDigestOf(data, "sha1")
103
- return digestsEqual(actual.toLowerCase(), dist.shasum.toLowerCase())
104
- ? { _tag: "Verified", using: "sha1" }
105
- : { _tag: "Mismatch", expected: `sha1-${dist.shasum}`, actual: `sha1-${actual}` }
106
- }
107
-
108
- return { _tag: "Unverifiable", reason: "registry advertised no integrity or shasum" }
109
- }
110
-
111
- const strength = (algorithm: string): number => {
112
- switch (algorithm) {
113
- case "sha512":
114
- return 4
115
- case "sha384":
116
- return 3
117
- case "sha256":
118
- return 2
119
- default:
120
- return 1
121
- }
122
- }
1
+ /**
2
+ * Checksum verification for downloaded tarballs.
3
+ *
4
+ * A bundle is a supply-chain artifact that gets imported wholesale into a
5
+ * corporate registry, so "the bytes I got are the bytes the registry promised"
6
+ * is the one property worth being strict about. A failed check discards the
7
+ * download rather than warning and carrying on.
8
+ *
9
+ * Implemented directly against `node:crypto` rather than pulling in `ssri`,
10
+ * because the subset of Subresource Integrity that npm actually publishes is
11
+ * small and entirely mechanical.
12
+ */
13
+ import { createHash, timingSafeEqual } from "node:crypto"
14
+
15
+ /** One parsed SRI hash. */
16
+ export type IntegrityHash = {
17
+ readonly algorithm: string
18
+ /** Base64 digest, exactly as written in the SRI string. */
19
+ readonly digest: string
20
+ }
21
+
22
+ const SUPPORTED = new Set(["sha512", "sha384", "sha256", "sha1"])
23
+
24
+ /**
25
+ * Parses an SRI string such as `sha512-abc...==`.
26
+ *
27
+ * npm permits several space-separated hashes; we keep every one we can verify
28
+ * and ignore algorithms Node does not implement.
29
+ */
30
+ export const parseIntegrity = (integrity: string): ReadonlyArray<IntegrityHash> => {
31
+ const hashes: Array<IntegrityHash> = []
32
+ for (const token of integrity.trim().split(/\s+/)) {
33
+ if (token.length === 0) continue
34
+ const dash = token.indexOf("-")
35
+ if (dash <= 0) continue
36
+ const algorithm = token.slice(0, dash).toLowerCase()
37
+ const digest = token.slice(dash + 1)
38
+ if (!SUPPORTED.has(algorithm) || digest.length === 0) continue
39
+ hashes.push({ algorithm, digest })
40
+ }
41
+ return hashes
42
+ }
43
+
44
+ /** Computes the base64 digest of some bytes under one algorithm. */
45
+ export const digestOf = (data: Uint8Array, algorithm: string): string =>
46
+ createHash(algorithm).update(data).digest("base64")
47
+
48
+ /** Computes the hex digest of some bytes — the form legacy `shasum` uses. */
49
+ export const hexDigestOf = (data: Uint8Array, algorithm: string): string =>
50
+ createHash(algorithm).update(data).digest("hex")
51
+
52
+ /** Result of checking a download. */
53
+ export type VerificationResult =
54
+ /** Verified against at least one checksum. */
55
+ | { readonly _tag: "Verified"; readonly using: string }
56
+ /** The registry advertised no checksum we could use. */
57
+ | { readonly _tag: "Unverifiable"; readonly reason: string }
58
+ /** A checksum was present and did not match. */
59
+ | { readonly _tag: "Mismatch"; readonly expected: string; readonly actual: string }
60
+
61
+ /** Constant-time comparison of two digest strings of equal length. */
62
+ const digestsEqual = (a: string, b: string): boolean => {
63
+ const left = Buffer.from(a)
64
+ const right = Buffer.from(b)
65
+ // `timingSafeEqual` throws on unequal lengths, which is itself a mismatch.
66
+ return left.length === right.length && timingSafeEqual(left, right)
67
+ }
68
+
69
+ /**
70
+ * Checks bytes against whichever checksums the registry supplied.
71
+ *
72
+ * SRI is preferred; `shasum` is the fallback for versions published before
73
+ * integrity strings existed. If the registry gave us neither, that is reported
74
+ * as `Unverifiable` rather than silently treated as a pass — the caller decides
75
+ * whether to tolerate it.
76
+ */
77
+ export const verify = (
78
+ data: Uint8Array,
79
+ dist: { readonly integrity?: string | undefined; readonly shasum?: string | undefined }
80
+ ): VerificationResult => {
81
+ if (dist.integrity !== undefined && dist.integrity.length > 0) {
82
+ // Strongest first, so a mismatch is reported against the best hash present.
83
+ const [best] = parseIntegrity(dist.integrity).toSorted(
84
+ (a, b) => strength(b.algorithm) - strength(a.algorithm)
85
+ )
86
+ if (best === undefined) {
87
+ return { _tag: "Unverifiable", reason: `no supported algorithm in "${dist.integrity}"` }
88
+ }
89
+
90
+ const actual = digestOf(data, best.algorithm)
91
+ return digestsEqual(actual, best.digest)
92
+ ? { _tag: "Verified", using: best.algorithm }
93
+ : {
94
+ _tag: "Mismatch",
95
+ expected: `${best.algorithm}-${best.digest}`,
96
+ actual: `${best.algorithm}-${actual}`
97
+ }
98
+ }
99
+
100
+ if (dist.shasum !== undefined && dist.shasum.length > 0) {
101
+ const actual = hexDigestOf(data, "sha1")
102
+ return digestsEqual(actual.toLowerCase(), dist.shasum.toLowerCase())
103
+ ? { _tag: "Verified", using: "sha1" }
104
+ : { _tag: "Mismatch", expected: `sha1-${dist.shasum}`, actual: `sha1-${actual}` }
105
+ }
106
+
107
+ return { _tag: "Unverifiable", reason: "registry advertised no integrity or shasum" }
108
+ }
109
+
110
+ const strength = (algorithm: string): number => {
111
+ switch (algorithm) {
112
+ case "sha512":
113
+ return 4
114
+ case "sha384":
115
+ return 3
116
+ case "sha256":
117
+ return 2
118
+ default:
119
+ return 1
120
+ }
121
+ }