← back to Tk11438 Postgres Migration
runtime.cjs
32 lines
// Direct read-only PM2 RPC; no API startup or daemon-launch fallback.
const fs = require('node:fs');
const path = require('node:path');
const deps = '/Users/macstudio3/.npm-global/lib/node_modules/pm2/node_modules/';
const axon = require(deps+'pm2-axon'), rpc = require(deps+'pm2-axon-rpc');
const req = axon.socket('req'), client = new rpc.Client(req);
const out = path.join(__dirname, 'verification/runtime.json');
if (!fs.existsSync('/Users/macstudio3/.pm2/rpc.sock')) throw Error('Existing PM2 socket required');
const timeout = setTimeout(() => { req.close(); process.exit(2); }, 15000);
req.on('error', () => { clearTimeout(timeout); req.close(); process.exitCode=1; });
req.connect('/Users/macstudio3/.pm2/rpc.sock');
client.call('getMonitorData', {}, (err, list) => {
req.close(); clearTimeout(timeout);
if (err) throw err;
const rows = list.map(p => {
const e = p.pm2_env || {};
const targets = [];
for (const [key, value] of Object.entries(e)) {
if (typeof value !== 'string') continue;
if (/^postgres(?:ql)?:\/\//.test(value)) {
try {
const u = new URL(value);
targets.push({key, host:u.hostname, port:u.port || '5432', database:u.pathname.slice(1), socketHost:u.searchParams.get('host')});
} catch { targets.push({key, parse:'unresolved'}); }
} else if (['PGHOST','DB_HOST','PGPORT','PGDATABASE','PORT'].includes(key)) targets.push({key, value});
}
return {name:p.name, pid:p.pid, status:e.status, cwd:e.pm_cwd, script:e.pm_exec_path, targets};
});
fs.writeFileSync(out, JSON.stringify({timestamp:new Date().toISOString(), services:rows}, null, 2)+'\n');
console.log(JSON.stringify({services:rows.length, relevant:rows.filter(r=>/interiordesignershowroom|patterndesign|norma/i.test(r.name+' '+r.cwd)), evidence:out},null,2));
});