mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-06 07:12:12 +03:00
fix: prevent false 'Failed to save connection' error when adding providers (#8912)
Validated in local merge-train (devbox-vm-06-dev002) @ combined-tip (FAST gates green: static + changed tests + vitest — only pre-existing audit.test.ts flake). Evidence: /home/diegosouzapw/dev/proxys/OmniRoute/.claude/worktrees/merge-train-20260805-213228-suite.log
This commit is contained in:
@@ -299,6 +299,7 @@ async function checkNativeBinary(rootDir) {
|
||||
"Release",
|
||||
"better_sqlite3.node"
|
||||
),
|
||||
path.join(rootDir, "dist", "node_modules", "better-sqlite3", "build", "Release", "better_sqlite3.node"),
|
||||
path.join(rootDir, "node_modules", "better-sqlite3", "build", "Release", "better_sqlite3.node"),
|
||||
];
|
||||
const binaryPath = candidates.find((candidate) => fs.existsSync(candidate));
|
||||
|
||||
@@ -34,7 +34,14 @@ async function runRepairAction(opts, cmd) {
|
||||
if (ok) {
|
||||
process.stdout.write("✓ better-sqlite3 repaired OK\n");
|
||||
} else {
|
||||
process.stderr.write("✗ Repair failed — check npm availability\n");
|
||||
process.stderr.write("✗ Repair failed\n");
|
||||
process.stderr.write(
|
||||
" Possible causes:\n" +
|
||||
" • npm not available — check that Node.js/npm are on your PATH\n" +
|
||||
" • npm install scripts are blocked — run: npm install-scripts approve better-sqlite3\n" +
|
||||
" • Network issue — check your internet connection\n" +
|
||||
" Try: npm install-scripts ls (to see if better-sqlite3 is blocked)\n"
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,16 @@ export async function runSetupClaudeCommand(opts = {}) {
|
||||
headers,
|
||||
signal: AbortSignal.timeout(10000),
|
||||
});
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
||||
if (!res.ok) {
|
||||
let detail = `HTTP ${res.status}`;
|
||||
try {
|
||||
const errorBody = await res.json();
|
||||
const serverMsg =
|
||||
errorBody?.error?.message || errorBody?.error || errorBody?.message || "";
|
||||
if (serverMsg) detail += ` — ${serverMsg}`;
|
||||
} catch {}
|
||||
throw new Error(detail);
|
||||
}
|
||||
const body = await res.json();
|
||||
models = body.data ?? body.models ?? [];
|
||||
} catch (err) {
|
||||
|
||||
@@ -152,9 +152,18 @@ export function ensureBetterSqliteRuntime({ silent = false, force = false } = {}
|
||||
if (!silent) process.stdout.write("[omniroute][runtime] better-sqlite3 OK\n");
|
||||
return { betterSqlite: true };
|
||||
}
|
||||
if (!silent) {
|
||||
process.stdout.write(
|
||||
`[omniroute][runtime] Installing better-sqlite3@${BETTER_SQLITE3_VERSION} into runtime...\n`
|
||||
);
|
||||
}
|
||||
const ok = npmInstallRuntime([`better-sqlite3@${BETTER_SQLITE3_VERSION}`], { silent });
|
||||
if (!ok && !silent) {
|
||||
process.stderr.write("[omniroute][runtime] better-sqlite3 install failed\n");
|
||||
process.stderr.write(
|
||||
"[omniroute][runtime] better-sqlite3 install failed.\n" +
|
||||
" This usually means npm install scripts are blocked.\n" +
|
||||
" Try: npm install-scripts approve better-sqlite3\n"
|
||||
);
|
||||
}
|
||||
return { betterSqlite: ok && hasModule("better-sqlite3") && isBetterSqliteBinaryValid() };
|
||||
}
|
||||
|
||||
@@ -137,11 +137,17 @@ export function useApiKeySave({
|
||||
}
|
||||
return null;
|
||||
}
|
||||
// Even if the server returned an error, the connection may have been
|
||||
// persisted (e.g. post-commit housekeeping failed after the DB write).
|
||||
// Refresh the list so the UI picks it up on next render.
|
||||
void fetchConnections();
|
||||
const data = await res.json().catch(() => ({}));
|
||||
const errorMsg = data.error?.message || data.error || t("failedSaveConnection");
|
||||
return errorMsg;
|
||||
} catch (error) {
|
||||
console.log("Error saving connection:", error);
|
||||
// The connection may still have been persisted despite the network error.
|
||||
void fetchConnections();
|
||||
return t("failedSaveConnectionRetry");
|
||||
}
|
||||
},
|
||||
|
||||
@@ -243,22 +243,37 @@ export async function POST(request: Request) {
|
||||
);
|
||||
}
|
||||
|
||||
// Auto sync to Cloud if enabled
|
||||
await syncToCloudIfEnabled();
|
||||
// Post-commit housekeeping: sync + audit must never fail the 201 response.
|
||||
// The connection is already persisted; these are non-critical side-effects.
|
||||
try {
|
||||
await syncToCloudIfEnabled();
|
||||
} catch (housekeepingError) {
|
||||
console.log(
|
||||
`[providers] syncToCloudIfEnabled failed after connection creation for ${newConnection.id}:`,
|
||||
housekeepingError
|
||||
);
|
||||
}
|
||||
|
||||
logAuditEvent({
|
||||
action: "provider.credentials.created",
|
||||
actor: "admin",
|
||||
target: getProviderAuditTarget(newConnection),
|
||||
resourceType: "provider_credentials",
|
||||
status: "success",
|
||||
ipAddress: auditContext.ipAddress || undefined,
|
||||
requestId: auditContext.requestId,
|
||||
metadata: {
|
||||
provider: provider,
|
||||
connection: summarizeProviderConnectionForAudit(newConnection),
|
||||
},
|
||||
});
|
||||
try {
|
||||
logAuditEvent({
|
||||
action: "provider.credentials.created",
|
||||
actor: "admin",
|
||||
target: getProviderAuditTarget(newConnection),
|
||||
resourceType: "provider_credentials",
|
||||
status: "success",
|
||||
ipAddress: auditContext.ipAddress || undefined,
|
||||
requestId: auditContext.requestId,
|
||||
metadata: {
|
||||
provider: provider,
|
||||
connection: summarizeProviderConnectionForAudit(newConnection),
|
||||
},
|
||||
});
|
||||
} catch (auditError) {
|
||||
console.log(
|
||||
`[providers] logAuditEvent failed after connection creation for ${newConnection.id}:`,
|
||||
auditError
|
||||
);
|
||||
}
|
||||
|
||||
return NextResponse.json({ connection: result }, { status: 201 });
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user