@sparkelf/dsh-plus 0.1.0-rc.39 → 0.1.0-rc.41
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 +58 -18
- package/lib/types/standalone-cli.js +11 -2
- package/lib/types/standalone-profile.d.ts +11 -0
- package/lib/types/standalone-profile.js +60 -19
- package/package.json +10 -11
package/lib/bin.js
CHANGED
|
@@ -363,11 +363,40 @@ function installProfilePackages(paths, consumerDirectory) {
|
|
|
363
363
|
linkNestedBundles(paths, profileModules);
|
|
364
364
|
return;
|
|
365
365
|
}
|
|
366
|
-
|
|
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,29 @@ 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
|
-
*
|
|
438
|
+
* The registries to try, in order, for this machine.
|
|
406
439
|
*
|
|
407
|
-
*
|
|
408
|
-
*
|
|
409
|
-
*
|
|
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
|
-
* @
|
|
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
|
|
416
|
-
const
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
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 = [
|
|
451
|
+
process.env.LANG,
|
|
452
|
+
process.env.LC_ALL,
|
|
453
|
+
Intl.DateTimeFormat().resolvedOptions().locale
|
|
454
|
+
].filter((value) => value !== void 0).join(" ").toLowerCase();
|
|
455
|
+
return locale.includes("zh") || locale.includes("cn") ? [MAINLAND_REGISTRY, OFFICIAL_REGISTRY] : [OFFICIAL_REGISTRY, MAINLAND_REGISTRY];
|
|
423
456
|
}
|
|
424
457
|
/**
|
|
425
458
|
* Report whether pnpm can run.
|
|
@@ -447,7 +480,9 @@ function pnpmAvailable() {
|
|
|
447
480
|
* @returns commands to try in order, stopping at the first that works.
|
|
448
481
|
*/
|
|
449
482
|
function pnpmInstallCommands() {
|
|
450
|
-
|
|
483
|
+
const registry = registryOrder()[0];
|
|
484
|
+
if (registry === void 0) return ["corepack enable pnpm", "npm install -g pnpm"];
|
|
485
|
+
return ["corepack enable pnpm", "npm install -g pnpm --registry " + registry];
|
|
451
486
|
}
|
|
452
487
|
/**
|
|
453
488
|
* The command to show a consumer who declines the automatic install.
|
|
@@ -743,9 +778,14 @@ async function start(argv) {
|
|
|
743
778
|
return 1;
|
|
744
779
|
}
|
|
745
780
|
let installed = false;
|
|
781
|
+
const preferred = registryOrder()[0];
|
|
746
782
|
for (const candidate of pnpmInstallCommands()) if (spawnSync(candidate, {
|
|
747
783
|
stdio: "inherit",
|
|
748
|
-
shell: true
|
|
784
|
+
shell: true,
|
|
785
|
+
env: preferred === void 0 ? process.env : {
|
|
786
|
+
...process.env,
|
|
787
|
+
COREPACK_NPM_REGISTRY: preferred
|
|
788
|
+
}
|
|
749
789
|
}).status === 0 && pnpmAvailable()) {
|
|
750
790
|
installed = true;
|
|
751
791
|
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
|
-
|
|
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
|
-
|
|
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,34 @@ 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
|
-
*
|
|
233
|
+
* The registries to try, in order, for this machine.
|
|
202
234
|
*
|
|
203
|
-
*
|
|
204
|
-
*
|
|
205
|
-
*
|
|
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
|
-
* @
|
|
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
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
242
|
+
export function registryOrder() {
|
|
243
|
+
const configured = process.env.DSH_PLUS_INSTALL_REGISTRY;
|
|
244
|
+
if (configured !== undefined && configured !== '')
|
|
245
|
+
return [configured, MAINLAND_REGISTRY];
|
|
246
|
+
// Intl reports the system locale on every platform. The POSIX variables are empty on
|
|
247
|
+
// Windows, so reading them alone classified every Windows console as non-mainland and
|
|
248
|
+
// reached the origin first — measured in a consumer's log, which showed npmjs failing
|
|
249
|
+
// before the mirror answered.
|
|
250
|
+
const locale = [process.env.LANG, process.env.LC_ALL, Intl.DateTimeFormat().resolvedOptions().locale]
|
|
251
|
+
.filter(value => value !== undefined)
|
|
252
|
+
.join(' ')
|
|
253
|
+
.toLowerCase();
|
|
254
|
+
const mainlandFirst = locale.includes('zh') || locale.includes('cn');
|
|
255
|
+
return mainlandFirst ? [MAINLAND_REGISTRY, OFFICIAL_REGISTRY] : [OFFICIAL_REGISTRY, MAINLAND_REGISTRY];
|
|
221
256
|
}
|
|
222
257
|
/**
|
|
223
258
|
* Report whether pnpm can run.
|
|
@@ -246,7 +281,13 @@ export function pnpmAvailable() {
|
|
|
246
281
|
* @returns commands to try in order, stopping at the first that works.
|
|
247
282
|
*/
|
|
248
283
|
export function pnpmInstallCommands() {
|
|
249
|
-
|
|
284
|
+
const registry = registryOrder()[0];
|
|
285
|
+
if (registry === undefined)
|
|
286
|
+
return ['corepack enable pnpm', 'npm install -g pnpm'];
|
|
287
|
+
// Both installers take the registry explicitly. npm does so with a flag; corepack reads
|
|
288
|
+
// COREPACK_NPM_REGISTRY, which the caller sets. A mainland consumer therefore downloads
|
|
289
|
+
// the package from the mirror, for the same reason the profile install prefers it.
|
|
290
|
+
return ['corepack enable pnpm', 'npm install -g pnpm --registry ' + registry];
|
|
250
291
|
}
|
|
251
292
|
/**
|
|
252
293
|
* The command to show a consumer who declines the automatic install.
|
package/package.json
CHANGED
|
@@ -58,16 +58,15 @@
|
|
|
58
58
|
],
|
|
59
59
|
"profile": {
|
|
60
60
|
"allowBuilds": {
|
|
61
|
-
"@deepseek-ai/dsh-subprocess-local
|
|
62
|
-
"@google/genai
|
|
63
|
-
"@officecli/officecli
|
|
64
|
-
"cpu-features
|
|
65
|
-
"koffi
|
|
66
|
-
"node-pty
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"ssh2@1.17.0": true
|
|
61
|
+
"@deepseek-ai/dsh-subprocess-local": true,
|
|
62
|
+
"@google/genai": false,
|
|
63
|
+
"@officecli/officecli": true,
|
|
64
|
+
"cpu-features": false,
|
|
65
|
+
"koffi": true,
|
|
66
|
+
"node-pty": true,
|
|
67
|
+
"oracledb": true,
|
|
68
|
+
"protobufjs": false,
|
|
69
|
+
"ssh2": true
|
|
71
70
|
},
|
|
72
71
|
"bundles": [
|
|
73
72
|
"@deepseek-ai/dsh-base",
|
|
@@ -166,5 +165,5 @@
|
|
|
166
165
|
},
|
|
167
166
|
"type": "module",
|
|
168
167
|
"types": "lib/types/index.d.ts",
|
|
169
|
-
"version": "0.1.0-rc.
|
|
168
|
+
"version": "0.1.0-rc.41"
|
|
170
169
|
}
|