Files
OmniRoute/bin/cli/runtime.mjs
diegosouzapw 2e494f8f07 feat(cli): Fase 0.3 — helpers base + convenções (api, i18n, output, runtime)
- bin/cli/CONVENTIONS.md: fonte normativa de flags, exit codes, output,
  retry/backoff, i18n, secrets, auditoria de ações destrutivas
- bin/cli/api.mjs: apiFetch() com retry/backoff, Retry-After, ApiError,
  statusToExitCode, isServerUp; computeBackoff/shouldRetryStatus exportados
- bin/cli/runtime.mjs: withRuntime/withHttp/withDb — server-first / DB-fallback;
  ServerOfflineError com exitCode 3
- bin/cli/i18n.mjs: t() com Map achatado (sem bracket em prototype), interpolação
  {vars}, setLocale/detectLocale/resetForTests; hardened contra __proto__ traversal
- bin/cli/output.mjs: emit() (table/json/jsonl/csv), EXIT_CODES, maskSecret,
  printSuccess/printError/printWarning/exitWith; output → stdout, diagnóstico → stderr
- bin/cli/locales/en.json + pt-BR.json: strings base (setup/doctor/providers/
  keys/combo/serve/backup/update/health/mcp/tunnel)
- bin/cli/README.md: mapa da estrutura e guia de uso dos helpers
- tests/unit/cli-exit-codes.test.ts: 10 casos — EXIT_CODES, statusToExitCode,
  backoff exponencial, jitter ±25%, t() i18n com pt-BR e anti-__proto__
- .env.example + docs/reference/ENVIRONMENT.md: documentar 4 novas env vars CLI
  (OMNIROUTE_LANG, OMNIROUTE_CLI_TOKEN, OMNIROUTE_HTTP_TIMEOUT_MS, OMNIROUTE_VERBOSE)
- scripts/check/check-env-doc-sync.mjs: adicionar LC_MESSAGES ao allowlist de sistema
2026-05-14 21:42:57 -03:00

73 lines
1.5 KiB
JavaScript

import { apiFetch, isServerUp } from "./api.mjs";
import { openOmniRouteDb } from "./sqlite.mjs";
export class ServerOfflineError extends Error {
constructor(message = "Server is offline and operation requires HTTP runtime") {
super(message);
this.name = "ServerOfflineError";
this.exitCode = 3;
}
}
function makeHttpContext(opts) {
return {
kind: "http",
api: (path, fetchOpts = {}) => apiFetch(path, { ...opts, ...fetchOpts }),
baseUrl: opts.baseUrl,
};
}
async function makeDbContext() {
const { db, dataDir, dbPath } = await openOmniRouteDb();
return {
kind: "db",
db,
dataDir,
dbPath,
close: () => {
try {
db.close();
} catch {
// best-effort
}
},
};
}
export async function withRuntime(fn, opts = {}) {
const requireServer = opts.requireServer === true;
const preferDb = opts.preferDb === true;
if (!preferDb) {
const up = await isServerUp(opts);
if (up) {
return await fn(makeHttpContext(opts));
}
if (requireServer) {
throw new ServerOfflineError();
}
}
const ctx = await makeDbContext();
try {
return await fn(ctx);
} finally {
ctx.close?.();
}
}
export async function withHttp(fn, opts = {}) {
const up = await isServerUp(opts);
if (!up) throw new ServerOfflineError();
return fn(makeHttpContext(opts));
}
export async function withDb(fn) {
const ctx = await makeDbContext();
try {
return await fn(ctx);
} finally {
ctx.close?.();
}
}