@zaimokuza/dsh-plugin-hub 0.1.1 → 0.1.2

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": "@zaimokuza/dsh-plugin-hub",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "private": false,
5
5
  "description": "Extensible DSH plugin marketplace and reusable enterprise marketplace runtime",
6
6
  "type": "module",
@@ -44,7 +44,7 @@
44
44
  "semver": "7.8.5",
45
45
  "tar": "7.5.22",
46
46
  "undici": "7.28.0",
47
- "@zaimokuza/dsh-plugin-hub-catalog-demo": "0.1.0"
47
+ "@zaimokuza/dsh-plugin-hub-catalog-demo": "0.1.2"
48
48
  },
49
49
  "devDependencies": {
50
50
  "esbuild": "0.28.1",
package/src/identity.js CHANGED
@@ -1,5 +1,11 @@
1
1
  export const MARKET_PACKAGE = '@zaimokuza/dsh-plugin-hub';
2
2
  export const CATALOG_PACKAGE = '@zaimokuza/dsh-plugin-hub-catalog-demo';
3
+ export function normalizeRegistry(value) {
4
+ let url;
5
+ try { if (typeof value !== 'string') throw new Error(); url = new URL(value); } catch { throw new Error('npm registry must be an HTTPS URL without credentials / npm registry 必须是无凭据的 HTTPS 地址'); }
6
+ if (url.protocol !== 'https:' || url.username || url.password || url.search || url.hash) throw new Error('npm registry must be an HTTPS URL without credentials / npm registry 必须是无凭据的 HTTPS 地址');
7
+ return url.href.replace(/\/?$/, '/');
8
+ }
3
9
  export function catalogVerification(value = 'if-present') {
4
10
  if (!['if-present', 'required', 'none'].includes(value)) throw new Error('catalogVerification must be if-present, required or none');
5
11
  return value;
package/src/index.js CHANGED
@@ -8,6 +8,7 @@ import { dshEnvironment, createDshInstaller } from './dsh.js';
8
8
  import { PACKAGE_NAME, validateCatalog } from './catalog.js';
9
9
  import { createProviderApi } from './provider-api.js';
10
10
  import { readReleaseAge } from './release-age.js';
11
+ import { readRegistry } from './registry-config.js';
11
12
 
12
13
  export const name = MARKET_PACKAGE;
13
14
  export const inject = ['webServer', 'connection'];
@@ -32,12 +33,10 @@ export async function apply(ctx, options = {}) {
32
33
  const source = { kind: 'npm', packageName: options.catalogPackage ?? CATALOG_PACKAGE };
33
34
  if (options.source) throw new Error('目录来源已改为 Nexus npm 包,请使用 catalogPackage 配置');
34
35
  if (!PACKAGE_NAME.test(source.packageName)) throw new Error('目录 npm 包名无效');
35
- const registry = new URL(options.registry ?? 'https://registry.npmjs.org/');
36
- if (registry.protocol !== 'https:' || registry.username || registry.password) throw new Error('npm registry 必须是无凭据的 HTTPS 地址');
37
- const releaseAge = await readReleaseAge(environment.profileDir);
36
+ const [registry, releaseAge] = await Promise.all([readRegistry(options.registry, environment.profileDir), readReleaseAge(environment.profileDir)]);
38
37
  const sources = options.catalogSources ?? [{ id: 'company', displayName: source.packageName === CATALOG_PACKAGE ? 'Demo catalog' : brand.title, ...source, priority: 100 }];
39
38
  if (!Array.isArray(sources) || sources.length > 20 || sources.some(s => s?.kind !== 'npm')) throw new Error('catalogSources must contain at most 20 npm sources; JSON providers register through the plugin API');
40
- const config = { source, sources, brand, identity, catalogVerification: catalogVerification(options.catalogVerification), packageName: options.packageName ?? MARKET_PACKAGE, registry: registry.href.replace(/\/?$/, '/'), cacheDir: join(environment.profileDir, '.dsh-plugin-hub', identity.id), ...releaseAge };
39
+ const config = { source, sources, brand, identity, catalogVerification: catalogVerification(options.catalogVerification), packageName: options.packageName ?? MARKET_PACKAGE, registry, cacheDir: join(environment.profileDir, '.dsh-plugin-hub', identity.id), ...releaseAge };
41
40
  const installer = createDshInstaller(environment, config);
42
41
  const market = new Marketplace({ config, host: environment.host, fetcher: createRegistryFetch(config.registry), installer });
43
42
  // The public package ships an independent catalog snapshot for first-open discovery.
@@ -0,0 +1,27 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ import { normalizeRegistry } from './identity.js';
4
+
5
+ const runFile = promisify(execFile);
6
+ const DEFAULT_REGISTRY = 'https://registry.npmjs.org/';
7
+
8
+ /** Match the profile directory used by DSH's pnpm installer, without downloading tools. */
9
+ export async function readRegistry(explicit, cwd, { run = runFile, env = process.env, platform = process.platform } = {}) {
10
+ if (explicit !== undefined) return normalizeRegistry(explicit);
11
+ for (const manager of ['pnpm', 'npm']) {
12
+ let output;
13
+ try {
14
+ const { stdout } = await run(platform === 'win32' ? `${manager}.cmd` : manager, ['config', 'get', 'registry'], {
15
+ cwd, timeout: 5000, maxBuffer: 16384, windowsHide: true, shell: platform === 'win32',
16
+ env: { ...env, COREPACK_ENABLE_NETWORK: '0', COREPACK_ENABLE_PROJECT_SPEC: '0',
17
+ npm_config_manage_package_manager_versions: 'false', pnpm_config_manage_package_manager_versions: 'false' },
18
+ });
19
+ output = String(stdout).trim().split(/\r?\n/).at(-1);
20
+ } catch { continue; }
21
+ try { output = JSON.parse(output); } catch { /* npm commonly prints an unquoted URL. */ }
22
+ if (output == null || output === '' || output === 'undefined' || output === 'null') continue;
23
+ // A configured but invalid address is an error, not permission to query a public registry.
24
+ return normalizeRegistry(output);
25
+ }
26
+ return DEFAULT_REGISTRY;
27
+ }