b0f5d6a51c
Split platform admin and ops APIs into standalone admin-server.mjs with network guards; simplify billing to RMB token pricing, refactor user auth, and add rsync deploy plus local-test scripts and docs. Co-authored-by: Cursor <cursoragent@cursor.com>
121 lines
3.6 KiB
JavaScript
121 lines
3.6 KiB
JavaScript
#!/usr/bin/env node
|
||
/**
|
||
* Map local test domains -> 127.0.0.1 for dev (macOS hosts + per-domain resolver).
|
||
*
|
||
* Usage:
|
||
* sudo node scripts/setup-local-test-dns.mjs
|
||
* sudo node scripts/setup-local-test-dns.mjs --remove
|
||
*/
|
||
import fs from 'node:fs';
|
||
import path from 'node:path';
|
||
import { execSync } from 'node:child_process';
|
||
import { DNS_MARKER, DNS_PORT, LOCAL_IP, TEST_HOSTS } from './local-test-config.mjs';
|
||
|
||
const remove = process.argv.includes('--remove');
|
||
const hostsPath = '/etc/hosts';
|
||
const resolverDir = '/etc/resolver';
|
||
const resolverBody = `nameserver 127.0.0.1\nport ${DNS_PORT}\n# ${DNS_MARKER}\n`;
|
||
|
||
function flushDnsCache() {
|
||
try {
|
||
execSync('dscacheutil -flushcache', { stdio: 'ignore' });
|
||
execSync('killall -HUP mDNSResponder', { stdio: 'ignore' });
|
||
} catch {
|
||
// best effort
|
||
}
|
||
}
|
||
|
||
function hostLine(host) {
|
||
return `${LOCAL_IP} ${host} # ${DNS_MARKER}`;
|
||
}
|
||
|
||
function removeHostLines(lines, host) {
|
||
return lines.filter(
|
||
(line) =>
|
||
!line.includes(DNS_MARKER) &&
|
||
!new RegExp(`\\s${host.replace('.', '\\.')}(\\s|$)`).test(line),
|
||
);
|
||
}
|
||
|
||
function hostReady(lines, host) {
|
||
return lines.some(
|
||
(line) =>
|
||
(line.includes(DNS_MARKER) && line.includes(host)) ||
|
||
new RegExp(`\\s${host.replace('.', '\\.')}(\\s|$)`).test(line),
|
||
);
|
||
}
|
||
|
||
if (remove) {
|
||
if (process.getuid?.() !== 0) {
|
||
console.log('需要 root 权限,请执行:');
|
||
console.log(` sudo node ${process.argv[1]} --remove`);
|
||
process.exit(1);
|
||
}
|
||
|
||
let lines = fs.readFileSync(hostsPath, 'utf8').split('\n');
|
||
for (const host of TEST_HOSTS) {
|
||
lines = removeHostLines(lines, host);
|
||
try {
|
||
if (fs.existsSync(path.join(resolverDir, host))) fs.unlinkSync(path.join(resolverDir, host));
|
||
} catch {
|
||
// ignore
|
||
}
|
||
}
|
||
execSync(`tee ${hostsPath}`, {
|
||
input: `${lines.join('\n').replace(/\n?$/, '\n')}`,
|
||
stdio: ['pipe', 'inherit', 'inherit'],
|
||
});
|
||
flushDnsCache();
|
||
console.log(`已移除本地测试域名:${TEST_HOSTS.join(', ')}`);
|
||
process.exit(0);
|
||
}
|
||
|
||
const currentLines = fs.readFileSync(hostsPath, 'utf8').split('\n');
|
||
const allReady = TEST_HOSTS.every((host) => {
|
||
const resolverPath = path.join(resolverDir, host);
|
||
const resolverReady =
|
||
fs.existsSync(resolverPath) && fs.readFileSync(resolverPath, 'utf8').trim() === resolverBody.trim();
|
||
return hostReady(currentLines, host) && resolverReady;
|
||
});
|
||
|
||
if (allReady) {
|
||
console.log(`本地测试域名已配置:${TEST_HOSTS.join(', ')}`);
|
||
process.exit(0);
|
||
}
|
||
|
||
if (process.getuid?.() !== 0) {
|
||
console.log('需要 root 权限写入 /etc/hosts 和 /etc/resolver,请执行:');
|
||
console.log(` sudo pnpm setup:local-dns`);
|
||
process.exit(1);
|
||
}
|
||
|
||
let lines = currentLines;
|
||
for (const host of TEST_HOSTS) {
|
||
if (!hostReady(lines, host)) {
|
||
lines = lines.filter((line) => !line.includes(DNS_MARKER) || !line.includes(host));
|
||
lines.push(hostLine(host));
|
||
console.log(`已添加 hosts:${hostLine(host)}`);
|
||
} else {
|
||
console.log(`${host} 已在 /etc/hosts 中指向 ${LOCAL_IP}`);
|
||
}
|
||
}
|
||
|
||
execSync(`tee ${hostsPath}`, {
|
||
input: `${lines.join('\n').replace(/\n?$/, '\n')}`,
|
||
stdio: ['pipe', 'inherit', 'inherit'],
|
||
});
|
||
|
||
fs.mkdirSync(resolverDir, { recursive: true });
|
||
for (const host of TEST_HOSTS) {
|
||
const resolverPath = path.join(resolverDir, host);
|
||
fs.writeFileSync(resolverPath, resolverBody, 'utf8');
|
||
console.log(`已添加 resolver:${resolverPath} -> 127.0.0.1:${DNS_PORT}`);
|
||
}
|
||
|
||
flushDnsCache();
|
||
console.log('');
|
||
console.log('下一步:');
|
||
console.log(' sudo pnpm setup:local-tls # 生成本地 HTTPS 证书');
|
||
console.log(' pnpm dev # 启动全栈');
|
||
console.log(' sudo pnpm dev:local-proxy # HTTPS :443 统一入口');
|