@sparkelf/dsh-plus 0.1.0-rc.39 → 0.1.0-rc.40

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/lib/bin.js CHANGED
@@ -363,11 +363,40 @@ function installProfilePackages(paths, consumerDirectory) {
363
363
  linkNestedBundles(paths, profileModules);
364
364
  return;
365
365
  }
366
- runPnpm(paths.profileDirectory, ["install", "--no-frozen-lockfile"], "pnpm install in the plus profile");
366
+ installWithRegistryFallback(paths);
367
367
  alignReplacedPackageNames(profileModules);
368
368
  linkNestedBundles(paths, profileModules);
369
369
  }
370
370
  /**
371
+ * Install the profile from the first registry that answers.
372
+ *
373
+ * The install fetches a full dependency closure, and a mainland consumer reaches the
374
+ * mirror far faster than the origin. Trying the preferred registry and falling back once
375
+ * keeps a first start quick without failing when the preferred one is unreachable.
376
+ *
377
+ * @param paths - resolved standalone paths.
378
+ */
379
+ function installWithRegistryFallback(paths) {
380
+ const registries = registryOrder();
381
+ for (const [index, registry] of registries.entries()) {
382
+ const result = spawnSync("pnpm", [
383
+ "install",
384
+ "--no-frozen-lockfile",
385
+ "--registry",
386
+ registry
387
+ ], {
388
+ cwd: paths.profileDirectory,
389
+ stdio: "inherit",
390
+ shell: process.platform === "win32"
391
+ });
392
+ if (result.error !== void 0) throw result.error;
393
+ if (result.status === 0) return;
394
+ const next = registries[index + 1];
395
+ if (next === void 0) throw new Error("pnpm install in the plus profile failed with exit code " + String(result.status));
396
+ console.log("Install from " + registry + " failed; trying " + next + ".");
397
+ }
398
+ }
399
+ /**
371
400
  * Make each replaced package declare the name of the location it occupies.
372
401
  *
373
402
  * \`overrides\` installs our build at the official path, but the manifest inside still
@@ -401,25 +430,25 @@ function alignReplacedPackageNames(profileModules) {
401
430
  renameSync(temporary, manifestPath);
402
431
  }
403
432
  }
433
+ /** The npm registry the distribution installs from by default. */
434
+ const OFFICIAL_REGISTRY = "https://registry.npmjs.org";
435
+ /** The mainland mirror, which serves the same packages and answers faster there. */
436
+ const MAINLAND_REGISTRY = "https://registry.npmmirror.com";
404
437
  /**
405
- * Run pnpm in one directory, inheriting its output.
438
+ * The registries to try, in order, for this machine.
406
439
  *
407
- * Windows resolves a command through its shell: \`spawnSync\` on a \`.cmd\` shim fails
408
- * with EINVAL, so the call goes through \`cmd.exe\` there. This matches the runner in
409
- * \`apply.ts\`, which the apply path has used on Windows since it shipped.
440
+ * A mainland locale reaches the mirror faster than the origin, which is why the Desktop
441
+ * installer already prefers it there. The same choice belongs to the profile install: it
442
+ * fetches a full dependency closure, so the delay is the first thing a consumer notices.
443
+ * `DSH_PLUS_INSTALL_REGISTRY` overrides the choice, and a failure falls back once.
410
444
  *
411
- * @param cwd - the directory pnpm runs in.
412
- * @param args - pnpm arguments, without the executable.
413
- * @param label - the failing step's name, for the error.
445
+ * @returns registries to try in order.
414
446
  */
415
- function runPnpm(cwd, args, label) {
416
- const result = spawnSync("pnpm", [...args], {
417
- cwd,
418
- stdio: "inherit",
419
- shell: process.platform === "win32"
420
- });
421
- if (result.error !== void 0) throw result.error;
422
- if (result.status !== 0) throw new Error(label + " failed with exit code " + String(result.status));
447
+ function registryOrder() {
448
+ const configured = process.env.DSH_PLUS_INSTALL_REGISTRY;
449
+ if (configured !== void 0 && configured !== "") return [configured, MAINLAND_REGISTRY];
450
+ const locale = (process.env.LANG ?? process.env.LC_ALL ?? "").toLowerCase();
451
+ return locale.includes("zh") || locale.includes("cn") ? [MAINLAND_REGISTRY, OFFICIAL_REGISTRY] : [OFFICIAL_REGISTRY, MAINLAND_REGISTRY];
423
452
  }
424
453
  /**
425
454
  * Report whether pnpm can run.
@@ -447,7 +476,9 @@ function pnpmAvailable() {
447
476
  * @returns commands to try in order, stopping at the first that works.
448
477
  */
449
478
  function pnpmInstallCommands() {
450
- return ["corepack enable pnpm", "npm install -g pnpm"];
479
+ const registry = registryOrder()[0];
480
+ if (registry === void 0) return ["corepack enable pnpm", "npm install -g pnpm"];
481
+ return ["corepack enable pnpm", "npm install -g pnpm --registry " + registry];
451
482
  }
452
483
  /**
453
484
  * The command to show a consumer who declines the automatic install.
@@ -743,9 +774,14 @@ async function start(argv) {
743
774
  return 1;
744
775
  }
745
776
  let installed = false;
777
+ const preferred = registryOrder()[0];
746
778
  for (const candidate of pnpmInstallCommands()) if (spawnSync(candidate, {
747
779
  stdio: "inherit",
748
- shell: true
780
+ shell: true,
781
+ env: preferred === void 0 ? process.env : {
782
+ ...process.env,
783
+ COREPACK_NPM_REGISTRY: preferred
784
+ }
749
785
  }).status === 0 && pnpmAvailable()) {
750
786
  installed = true;
751
787
  break;
@@ -14,7 +14,7 @@ import { dirname, join } from 'node:path';
14
14
  import { fileURLToPath } from 'node:url';
15
15
  import { newerVersion } from "./registry-versions.js";
16
16
  import { DEFAULT_PORT, STOP_GRACE_MILLISECONDS, choosePort, clearState, isRunning, portAvailable, readState, spawnServer, stateDirectory, waitForAuthenticatedUrl, waitForServer, writeState, } from "./standalone-server.js";
17
- import { STANDALONE_PROFILE, applyProfileNpmPatches, ensureProfile, pnpmAvailable, pnpmInstallCommand, pnpmInstallCommands, readDistributionProfile, resolvePaths, } from "./standalone-profile.js";
17
+ import { STANDALONE_PROFILE, applyProfileNpmPatches, ensureProfile, pnpmAvailable, pnpmInstallCommand, pnpmInstallCommands, registryOrder, readDistributionProfile, resolvePaths, } from "./standalone-profile.js";
18
18
  /** Milliseconds a start waits for the server to answer before reporting failure. */
19
19
  const READY_TIMEOUT_MILLISECONDS = 90_000;
20
20
  function parseStartOptions(argv) {
@@ -114,8 +114,17 @@ async function start(argv) {
114
114
  // Try each installer in turn: Corepack is absent on an installation that disabled it,
115
115
  // and npm succeeds there. A failure reports the commands rather than a stack trace.
116
116
  let installed = false;
117
+ const preferred = registryOrder()[0];
117
118
  for (const candidate of pnpmInstallCommands()) {
118
- const attempt = spawnSync(candidate, { stdio: 'inherit', shell: true });
119
+ // Corepack reads its registry from the environment; npm takes a flag, which the
120
+ // command already carries. Setting it for both keeps the download on the mirror.
121
+ const attempt = spawnSync(candidate, {
122
+ stdio: 'inherit',
123
+ shell: true,
124
+ env: preferred === undefined
125
+ ? process.env
126
+ : { ...process.env, COREPACK_NPM_REGISTRY: preferred },
127
+ });
119
128
  if (attempt.status === 0 && pnpmAvailable()) {
120
129
  installed = true;
121
130
  break;
@@ -94,6 +94,17 @@ export declare function installProfilePackages(paths: StandalonePaths, consumerD
94
94
  * @param profileModules - the profile's \`node_modules\` directory.
95
95
  */
96
96
  export declare function alignReplacedPackageNames(profileModules: string): void;
97
+ /**
98
+ * The registries to try, in order, for this machine.
99
+ *
100
+ * A mainland locale reaches the mirror faster than the origin, which is why the Desktop
101
+ * installer already prefers it there. The same choice belongs to the profile install: it
102
+ * fetches a full dependency closure, so the delay is the first thing a consumer notices.
103
+ * `DSH_PLUS_INSTALL_REGISTRY` overrides the choice, and a failure falls back once.
104
+ *
105
+ * @returns registries to try in order.
106
+ */
107
+ export declare function registryOrder(): readonly string[];
97
108
  /**
98
109
  * Report whether pnpm can run.
99
110
  *
@@ -159,10 +159,38 @@ export function installProfilePackages(paths, consumerDirectory) {
159
159
  linkNestedBundles(paths, profileModules);
160
160
  return;
161
161
  }
162
- runPnpm(paths.profileDirectory, ['install', '--no-frozen-lockfile'], 'pnpm install in the plus profile');
162
+ installWithRegistryFallback(paths);
163
163
  alignReplacedPackageNames(profileModules);
164
164
  linkNestedBundles(paths, profileModules);
165
165
  }
166
+ /**
167
+ * Install the profile from the first registry that answers.
168
+ *
169
+ * The install fetches a full dependency closure, and a mainland consumer reaches the
170
+ * mirror far faster than the origin. Trying the preferred registry and falling back once
171
+ * keeps a first start quick without failing when the preferred one is unreachable.
172
+ *
173
+ * @param paths - resolved standalone paths.
174
+ */
175
+ function installWithRegistryFallback(paths) {
176
+ const registries = registryOrder();
177
+ for (const [index, registry] of registries.entries()) {
178
+ const result = spawnSync('pnpm', ['install', '--no-frozen-lockfile', '--registry', registry], {
179
+ cwd: paths.profileDirectory,
180
+ stdio: 'inherit',
181
+ shell: process.platform === 'win32',
182
+ });
183
+ if (result.error !== undefined)
184
+ throw result.error;
185
+ if (result.status === 0)
186
+ return;
187
+ const next = registries[index + 1];
188
+ if (next === undefined) {
189
+ throw new Error('pnpm install in the plus profile failed with exit code ' + String(result.status));
190
+ }
191
+ console.log('Install from ' + registry + ' failed; trying ' + next + '.');
192
+ }
193
+ }
166
194
  /**
167
195
  * Make each replaced package declare the name of the location it occupies.
168
196
  *
@@ -197,27 +225,27 @@ export function alignReplacedPackageNames(profileModules) {
197
225
  renameSync(temporary, manifestPath);
198
226
  }
199
227
  }
228
+ /** The npm registry the distribution installs from by default. */
229
+ const OFFICIAL_REGISTRY = 'https://registry.npmjs.org';
230
+ /** The mainland mirror, which serves the same packages and answers faster there. */
231
+ const MAINLAND_REGISTRY = 'https://registry.npmmirror.com';
200
232
  /**
201
- * Run pnpm in one directory, inheriting its output.
233
+ * The registries to try, in order, for this machine.
202
234
  *
203
- * Windows resolves a command through its shell: \`spawnSync\` on a \`.cmd\` shim fails
204
- * with EINVAL, so the call goes through \`cmd.exe\` there. This matches the runner in
205
- * \`apply.ts\`, which the apply path has used on Windows since it shipped.
235
+ * A mainland locale reaches the mirror faster than the origin, which is why the Desktop
236
+ * installer already prefers it there. The same choice belongs to the profile install: it
237
+ * fetches a full dependency closure, so the delay is the first thing a consumer notices.
238
+ * `DSH_PLUS_INSTALL_REGISTRY` overrides the choice, and a failure falls back once.
206
239
  *
207
- * @param cwd - the directory pnpm runs in.
208
- * @param args - pnpm arguments, without the executable.
209
- * @param label - the failing step's name, for the error.
240
+ * @returns registries to try in order.
210
241
  */
211
- function runPnpm(cwd, args, label) {
212
- const result = spawnSync('pnpm', [...args], {
213
- cwd,
214
- stdio: 'inherit',
215
- shell: process.platform === 'win32',
216
- });
217
- if (result.error !== undefined)
218
- throw result.error;
219
- if (result.status !== 0)
220
- throw new Error(label + ' failed with exit code ' + String(result.status));
242
+ export function registryOrder() {
243
+ const configured = process.env.DSH_PLUS_INSTALL_REGISTRY;
244
+ if (configured !== undefined && configured !== '')
245
+ return [configured, MAINLAND_REGISTRY];
246
+ const locale = (process.env.LANG ?? process.env.LC_ALL ?? '').toLowerCase();
247
+ const mainlandFirst = locale.includes('zh') || locale.includes('cn');
248
+ return mainlandFirst ? [MAINLAND_REGISTRY, OFFICIAL_REGISTRY] : [OFFICIAL_REGISTRY, MAINLAND_REGISTRY];
221
249
  }
222
250
  /**
223
251
  * Report whether pnpm can run.
@@ -246,7 +274,13 @@ export function pnpmAvailable() {
246
274
  * @returns commands to try in order, stopping at the first that works.
247
275
  */
248
276
  export function pnpmInstallCommands() {
249
- return ['corepack enable pnpm', 'npm install -g pnpm'];
277
+ const registry = registryOrder()[0];
278
+ if (registry === undefined)
279
+ return ['corepack enable pnpm', 'npm install -g pnpm'];
280
+ // Both installers take the registry explicitly. npm does so with a flag; corepack reads
281
+ // COREPACK_NPM_REGISTRY, which the caller sets. A mainland consumer therefore downloads
282
+ // the package from the mirror, for the same reason the profile install prefers it.
283
+ return ['corepack enable pnpm', 'npm install -g pnpm --registry ' + registry];
250
284
  }
251
285
  /**
252
286
  * The command to show a consumer who declines the automatic install.
package/package.json CHANGED
@@ -166,5 +166,5 @@
166
166
  },
167
167
  "type": "module",
168
168
  "types": "lib/types/index.d.ts",
169
- "version": "0.1.0-rc.39"
169
+ "version": "0.1.0-rc.40"
170
170
  }