45 lines
2.8 KiB
JavaScript
45 lines
2.8 KiB
JavaScript
import { createHash } from 'node:crypto';
|
|
import { mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
import { execFileSync } from 'node:child_process';
|
|
import { createRequire } from 'node:module';
|
|
const version = '3.0.5';
|
|
const integrity = 'N3wmegFHSd23J0+xjotKyBq0ZbLXUbkWZ65E+aSw5pzB/nudhaNHWT2V3CSNaW/LX3s6AxAWB2APpfA0dLXJZQ==';
|
|
const response = await fetch('https://registry.npmjs.org/dsh-web-mobile/-/dsh-web-mobile-3.0.5.tgz', { signal: AbortSignal.timeout(120000) });
|
|
if (!response.ok) throw new Error('mobile plugin download failed');
|
|
const data = Buffer.from(await response.arrayBuffer());
|
|
if (createHash('sha512').update(data).digest('base64') !== integrity) throw new Error('mobile plugin integrity mismatch');
|
|
const destination = '/usr/local/lib/node_modules/@deepseek-ai/dsh/node_modules/dsh-web-mobile';
|
|
mkdirSync(destination, { recursive: true });
|
|
const archive = '/usr/local/lib/dsh-mgr/dsh-web-mobile-3.0.5.tgz';
|
|
writeFileSync(archive, data, { mode: 0o644 });
|
|
execFileSync('tar', ['-xzf', archive, '--strip-components=1', '--no-same-owner', '-C', destination]);
|
|
// Published tar modes can be owner-only; runtime is UID 1000, not build root.
|
|
execFileSync('chmod', ['-R', 'a+rX', destination]);
|
|
const pkg = JSON.parse(readFileSync(destination + '/package.json'));
|
|
if (pkg.version !== version || pkg.name !== 'dsh-web-mobile' || Object.keys(pkg.dependencies || {}).length) throw new Error('unexpected mobile package metadata');
|
|
const require = createRequire('/usr/local/lib/node_modules/@deepseek-ai/dsh/package.json');
|
|
const semver = createRequire('/usr/local/lib/node_modules/npm/package.json')('semver');
|
|
for (const [name, range] of Object.entries(pkg.peerDependencies || {})) {
|
|
// React is provided by the browser shell, not a Node package in DSH.
|
|
// Limit that exception to the upstream-declared, tested RC hosts.
|
|
if (name === 'react') {
|
|
const host = require('./package.json').version;
|
|
if (!['0.2.0-rc.1', '0.2.0-rc.2'].includes(host)) throw new Error('unverified browser React host: ' + host);
|
|
continue;
|
|
}
|
|
let peer;
|
|
try { peer = require(name + '/package.json'); }
|
|
catch (error) {
|
|
if (pkg.peerDependenciesMeta?.[name]?.optional) continue;
|
|
throw new Error('missing required mobile peer: ' + name);
|
|
}
|
|
if (!semver.satisfies(peer.version, range)) throw new Error('incompatible mobile peer: ' + name + '@' + peer.version);
|
|
}
|
|
// DSH runtime resolution traverses the installation manifest, not arbitrary
|
|
// directories in node_modules. Declare the baked package in that graph.
|
|
const hostManifest = '/usr/local/lib/node_modules/@deepseek-ai/dsh/package.json';
|
|
const host = JSON.parse(readFileSync(hostManifest));
|
|
host.dependencies = { ...host.dependencies, 'dsh-web-mobile': version };
|
|
writeFileSync(hostManifest, JSON.stringify(host, null, 2));
|
|
console.log('Installed [email protected] (SHA-512 verified; no lifecycle scripts)');
|