spaps
Version:
Sweet Potato Authentication & Payment Service CLI - Docker Compose orchestrator for local Python/FastAPI SPAPS server with built-in admin middleware
63 lines (55 loc) • 1.92 kB
JavaScript
// Environment detection for the SPAPS CLI auth flow.
//
// Determines whether we're in a headless context (SSH, no GUI) so the login
// command can print the verification URL for copy-paste instead of trying to
// open a browser that isn't there.
//
// TODO(tier1/tier2): when the backend exposes loopback-PKCE routes, use this to
// pick Tier 1 (browser PKCE) on local GUI and Tier 2 (manual paste PKCE) on
// SSH, keeping Tier 3 (device code) as the fallback.
const { spawn } = require('node:child_process');
function isSsh(env = process.env) {
return Boolean(env.SSH_CLIENT || env.SSH_TTY || env.SSH_CONNECTION);
}
function hasGui(env = process.env, platform = process.platform) {
if (platform === 'darwin' || platform === 'win32') return true;
return Boolean(env.DISPLAY || env.WAYLAND_DISPLAY);
}
function isHeadless(env = process.env, platform = process.platform) {
return isSsh(env) || !hasGui(env, platform);
}
function hasInteractiveTerminal(stdin = process.stdin, stdout = process.stdout) {
return Boolean(stdin && stdin.isTTY && stdout && stdout.isTTY);
}
function tryOpenBrowser(url, { env = process.env, platform = process.platform } = {}) {
if (isHeadless(env, platform)) return false;
try {
let cmd;
let args;
if (platform === 'darwin') {
cmd = 'open';
args = [url];
} else if (platform === 'win32') {
// `start` is a cmd.exe builtin; the empty title "" is required when the
// first quoted arg would otherwise be treated as the window title.
cmd = 'cmd';
args = ['/c', 'start', '""', url];
} else {
cmd = 'xdg-open';
args = [url];
}
const child = spawn(cmd, args, { stdio: 'ignore', detached: true });
child.on('error', () => {});
child.unref();
return true;
} catch {
return false;
}
}
module.exports = {
isSsh,
hasGui,
isHeadless,
hasInteractiveTerminal,
tryOpenBrowser,
};