Files
dsh-web/image/install-mobile.mjs
T

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)');