@package-pal/cli 0.0.6 → 0.0.7

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@package-pal/cli",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "CLI tool exposing core PackagePal functionality.",
5
5
  "keywords": [
6
6
  "package",
@@ -2,7 +2,7 @@ import {
2
2
  dirname, join, resolve,
3
3
  } from 'path';
4
4
  import { fileURLToPath } from 'url';
5
- import packageJson from '../../../../package.json' with { type: 'json' };;
5
+ import packageJson from '../../../../package.json' with { type: 'json' };
6
6
 
7
7
  /**
8
8
  * @param {Bun.Platform} platform
@@ -19,11 +19,10 @@ export const getPlatformInfo = () => {
19
19
  case 'linux':
20
20
  let isMusl = false;
21
21
  try {
22
- // Determine if the OS is using musl libc.
23
22
  // The report will not have a glibcVersionRuntime property if musl is being used.
24
- // @ts-expect-error unknown type
25
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
26
- isMusl = !process.report.getReport().header?.glibcVersionRuntime;
23
+ /** @type {{ header?: { glibcVersionRuntime?: unknown } }} */
24
+ const report = process.report.getReport();
25
+ isMusl = !report.header?.glibcVersionRuntime;
27
26
  } catch {
28
27
  isMusl = true;
29
28
  }
@@ -39,7 +38,7 @@ export const getPlatformInfo = () => {
39
38
  }
40
39
 
41
40
  if (!targetPackage) {
42
- throw new Error(`Unsupported platform: ${usePlatform} ${useArch}.`);
41
+ throw new Error(`Unsupported target: ${usePlatform} ${useArch}.`);
43
42
  }
44
43
 
45
44
  return {
@@ -3,52 +3,72 @@ import { pipeline } from 'stream/promises';
3
3
  import { x } from 'tar';
4
4
  import packageJson from '../../../../package.json' with { type: 'json' };
5
5
 
6
+ const maxRetries = 3;
7
+ const initialBackoffMs = 500;
8
+
6
9
  /**
7
10
  * @param {string} tarballUrl
8
11
  * @param {string} binName
9
12
  * @param {string} outputBinDir
10
13
  */
11
- const downloadAndExtract = async (
14
+ const tryDownloadAndExtract = (
12
15
  tarballUrl, binName, outputBinDir,
13
16
  ) => {
14
- for (let i = 0; i < 3; i++) {
15
- try {
16
- await new Promise((resolve, reject) => {
17
- get(tarballUrl, (res) => {
18
- if (res.statusCode === 301 || res.statusCode === 302) {
19
- if (!res.headers.location) {
20
- reject(new Error(`Failed to download binary: Redirect location missing.`));
21
- return;
22
- }
17
+ return new Promise((resolve, reject) => {
18
+ get(tarballUrl, (res) => {
19
+ const isRedirect = res.statusCode === 301 || res.statusCode === 302;
20
+ const isSuccess = res.statusCode === 200;
23
21
 
24
- downloadAndExtract(
25
- res.headers.location, binName, outputBinDir,
26
- ).then(resolve, reject);
27
- return;
28
- }
29
-
30
- if (res.statusCode !== 200) {
31
- reject(new Error(`Failed to download binary: ${res.statusCode?.toString() ?? 'Unknown'}.`));
32
- return;
33
- }
22
+ if (isRedirect) {
23
+ if (!res.headers.location) {
24
+ reject(new Error(`Failed to download binary: Redirect location missing.`));
25
+ return;
26
+ }
27
+ downloadAndExtract(
28
+ res.headers.location, binName, outputBinDir,
29
+ )
30
+ .then(resolve)
31
+ .catch(reject);
32
+ return;
33
+ }
34
34
 
35
- const extractStream = x({
36
- cwd: outputBinDir,
37
- strip: 1,
38
- filter: path => path === `package/bin/${binName}`,
39
- });
35
+ if (!isSuccess) {
36
+ reject(new Error(`Failed to download binary: ${res.statusCode?.toString() ?? 'Unknown'}`));
37
+ return;
38
+ }
40
39
 
41
- pipeline(res, extractStream).then(resolve)
42
- .catch(reject);
43
- }).on('error', reject);
40
+ const extractStream = x({
41
+ cwd: outputBinDir,
42
+ strip: 1,
43
+ filter: path => path === `package/bin/${binName}`,
44
44
  });
45
45
 
46
+ pipeline(res, extractStream).then(resolve)
47
+ .catch(reject);
48
+ }).on('error', reject);
49
+ });
50
+ };
51
+
52
+ /**
53
+ * @param {string} tarballUrl
54
+ * @param {string} binName
55
+ * @param {string} outputBinDir
56
+ */
57
+ const downloadAndExtract = async (
58
+ tarballUrl, binName, outputBinDir,
59
+ ) => {
60
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
61
+ try {
62
+ await tryDownloadAndExtract(
63
+ tarballUrl, binName, outputBinDir,
64
+ );
46
65
  return;
47
- } catch (e) {
48
- if (i < 2) {
49
- console.warn(`Download failed, retrying...`);
66
+ } catch (error) {
67
+ if (attempt < maxRetries) {
68
+ const delay = initialBackoffMs * 2 ** (attempt - 1);
69
+ console.warn(`Download failed (attempt ${attempt.toString()}), retrying in ${delay.toString()}ms...`);
50
70
  } else {
51
- throw e;
71
+ throw error;
52
72
  }
53
73
  }
54
74
  }
@@ -63,14 +83,15 @@ export const loadMissingBinary = async (
63
83
  binName, targetPackage, outputBinDir,
64
84
  ) => {
65
85
  const fullTargetPackageName = `@package-pal/${targetPackage}`;
66
- // @ts-expect-error unknown key
67
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
68
- const targetPackageVersion = packageJson.optionalDependencies[fullTargetPackageName];
86
+ /** @type {Record<string, string>} */
87
+ const optionalDeps = packageJson.optionalDependencies;
88
+ const targetPackageVersion = optionalDeps[fullTargetPackageName];
89
+
69
90
  if (!targetPackageVersion) {
70
91
  throw new Error(`No version found for target package '${fullTargetPackageName}'.`);
71
92
  }
72
93
 
73
- const tarballUrl = `https://registry.npmjs.org/${fullTargetPackageName}/-/${fullTargetPackageName.replace('@', '').replace('/', '-')}-${String(targetPackageVersion)}.tgz`;
94
+ const tarballUrl = `https://registry.npmjs.org/${fullTargetPackageName}/-/${targetPackage}-${targetPackageVersion}.tgz`;
74
95
  console.log(`Downloading '${fullTargetPackageName}' from ${tarballUrl}...`);
75
96
 
76
97
  await downloadAndExtract(