← 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));
});