Files
system_update/server/cli/createApiClient.ts
T
gilles 08919752e3 feat: socle BDD (tâche 1.9 Phase 1-2) + moteur APT (tâche 2 SJ-0→3) + WIP capabilities/auth/Rust
Checkpoint multi-chantiers (arbre vert : tsc 0 erreur, 70 tests, build OK).
- tâche 1.9 Phase 1 : schéma socle (machine_state/events/reports/raw_artifacts/
  hardware/metrics + colonnes étendues) + wiring refresh/execute. Migration 0002.
- tâche 1.9 Phase 2 : machine_credentials + machine_host_keys (non destructif,
  dual-read + backfill). Migration 0003. Fix séquence journal de migration.
- tâche 2 : SJ-0 (types étendus rétro-compatibles, réducteur Docker, resolveTemplate),
  SJ-1 (update-analyze enrichi), SJ-2 (apply + diff dpkg + timeout inactivité SSH),
  SJ-3 (reboot vérifié boot_id).
- WIP parallèle inclus : /api/capabilities, auth/apiTokens/apiClients, system metrics,
  scaffold app_rust, ajustements frontend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-05 19:50:25 +02:00

79 lines
2.3 KiB
TypeScript

// server/cli/createApiClient.ts
import { pathToFileURL } from "node:url";
import type { ApiClientScope } from "@shared/types.js";
import { runMigrations } from "../db/migrate.js";
import { createApiClient } from "../services/apiClients.js";
export interface CreateApiClientCliOptions {
name: string;
scopes: ApiClientScope[];
}
const ALLOWED_SCOPES: ApiClientScope[] = ["read", "operate", "admin", "debug"];
export function parseCreateApiClientArgs(args: string[]): CreateApiClientCliOptions {
let name = "";
let scopes: ApiClientScope[] = ["read"];
for (let i = 0; i < args.length; i += 1) {
const arg = args[i];
if (arg === "--name") {
i += 1;
name = args[i] ?? "";
} else if (arg === "--scopes") {
i += 1;
scopes = parseScopes(args[i] ?? "");
} else if (arg === "--help" || arg === "-h") {
throw new Error(helpText());
} else {
throw new Error(`Argument inconnu: ${arg}\n\n${helpText()}`);
}
}
if (!name.trim()) throw new Error(`--name est obligatoire\n\n${helpText()}`);
return { name: name.trim(), scopes };
}
function parseScopes(raw: string): ApiClientScope[] {
const scopes = raw
.split(",")
.map((scope) => scope.trim())
.filter(Boolean) as ApiClientScope[];
if (scopes.length === 0) return ["read"];
for (const scope of scopes) {
if (!ALLOWED_SCOPES.includes(scope)) {
throw new Error(`Scope invalide: ${scope}. Scopes valides: ${ALLOWED_SCOPES.join(", ")}`);
}
}
return [...new Set(scopes)];
}
function helpText(): string {
return [
"Usage:",
" pnpm api-client:create -- --name \"App Rust\" --scopes read,operate",
"",
"Variables requises:",
" SU_MASTER_KEY clé hex 64 caractères",
" SU_DB_PATH chemin SQLite optionnel",
].join("\n");
}
async function main(): Promise<void> {
const options = parseCreateApiClientArgs(process.argv.slice(2));
runMigrations();
const created = createApiClient(options);
console.log(JSON.stringify(created, null, 2));
}
const entrypoint = process.argv[1] ? pathToFileURL(process.argv[1]).href : "";
if (import.meta.url === entrypoint) {
main().catch((err) => {
console.error((err as Error).message);
process.exitCode = 1;
});
}
export const createApiClientCliInternals = { parseScopes, helpText };