mirror of
https://github.com/OpenRouterTeam/spawn.git
synced 2026-05-23 04:24:39 +00:00
fix(cli): use tryCatch instead of tryCatchIf for JSON.parse callsites (#2770)
tryCatchIf(isFileError) only catches filesystem errors (ENOENT, EACCES), but JSON.parse throws SyntaxError on corrupted input. Since tryCatchIf rethrows non-matching errors, a corrupted config file crashes the CLI instead of returning the intended null/false fallback. Affected: readCache(), local manifest loader, loadApiToken(), loadSavedOpenRouterKey(), hasCloudConfigCredentials() Agent: code-health Co-authored-by: B <6723574+louisgv@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
fc98700a24
commit
16a2f1807c
4 changed files with 9 additions and 9 deletions
|
|
@ -11,7 +11,7 @@ import { validateIdentifier, validatePrompt } from "../security.js";
|
||||||
import { hasSavedOpenRouterKey } from "../shared/oauth.js";
|
import { hasSavedOpenRouterKey } from "../shared/oauth.js";
|
||||||
import { PkgVersionSchema, parseJsonObj } from "../shared/parse.js";
|
import { PkgVersionSchema, parseJsonObj } from "../shared/parse.js";
|
||||||
import { getSpawnCloudConfigPath } from "../shared/paths.js";
|
import { getSpawnCloudConfigPath } from "../shared/paths.js";
|
||||||
import { asyncTryCatch, isFileError, tryCatch, tryCatchIf, unwrapOr } from "../shared/result.js";
|
import { asyncTryCatch, tryCatch, unwrapOr } from "../shared/result.js";
|
||||||
|
|
||||||
// ── Constants ────────────────────────────────────────────────────────────────
|
// ── Constants ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
@ -507,7 +507,7 @@ export function formatCredStatusLine(varName: string, urlHint?: string): string
|
||||||
/** Check if credentials are saved in ~/.config/spawn/{cloud}.json */
|
/** Check if credentials are saved in ~/.config/spawn/{cloud}.json */
|
||||||
function hasCloudConfigCredentials(cloud: string): boolean {
|
function hasCloudConfigCredentials(cloud: string): boolean {
|
||||||
return unwrapOr(
|
return unwrapOr(
|
||||||
tryCatchIf(isFileError, () => {
|
tryCatch(() => {
|
||||||
const configPath = getSpawnCloudConfigPath(cloud);
|
const configPath = getSpawnCloudConfigPath(cloud);
|
||||||
if (!fs.existsSync(configPath)) {
|
if (!fs.existsSync(configPath)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ import { join } from "node:path";
|
||||||
import { getErrorMessage, isPlainObject } from "@openrouter/spawn-shared";
|
import { getErrorMessage, isPlainObject } from "@openrouter/spawn-shared";
|
||||||
import { parseJsonObj } from "./shared/parse.js";
|
import { parseJsonObj } from "./shared/parse.js";
|
||||||
import { getCacheDir, getCacheFile } from "./shared/paths.js";
|
import { getCacheDir, getCacheFile } from "./shared/paths.js";
|
||||||
import { asyncTryCatch, isFileError, tryCatchIf, unwrapOr } from "./shared/result.js";
|
import { asyncTryCatch, isFileError, tryCatch, tryCatchIf, unwrapOr } from "./shared/result.js";
|
||||||
|
|
||||||
// ── Types ──────────────────────────────────────────────────────────────────────
|
// ── Types ──────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
|
@ -94,7 +94,7 @@ function logError(message: string, err?: unknown): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
function readCache(): Manifest | null {
|
function readCache(): Manifest | null {
|
||||||
const result = tryCatchIf(isFileError, () => {
|
const result = tryCatch(() => {
|
||||||
const raw = parseJsonObj(readFileSync(getCacheFile(), "utf-8"));
|
const raw = parseJsonObj(readFileSync(getCacheFile(), "utf-8"));
|
||||||
if (!raw) {
|
if (!raw) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -213,7 +213,7 @@ function tryLoadLocalManifest(): Manifest | null {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = tryCatchIf(isFileError, () => {
|
const result = tryCatch(() => {
|
||||||
const localPath = join(process.cwd(), "manifest.json");
|
const localPath = join(process.cwd(), "manifest.json");
|
||||||
if (existsSync(localPath)) {
|
if (existsSync(localPath)) {
|
||||||
const raw = parseJsonObj(readFileSync(localPath, "utf-8"));
|
const raw = parseJsonObj(readFileSync(localPath, "utf-8"));
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import * as v from "valibot";
|
||||||
import { OAUTH_CODE_REGEX } from "./oauth-constants";
|
import { OAUTH_CODE_REGEX } from "./oauth-constants";
|
||||||
import { parseJsonObj, parseJsonWith } from "./parse";
|
import { parseJsonObj, parseJsonWith } from "./parse";
|
||||||
import { getSpawnCloudConfigPath } from "./paths";
|
import { getSpawnCloudConfigPath } from "./paths";
|
||||||
import { asyncTryCatchIf, isFileError, isNetworkError, tryCatch, tryCatchIf } from "./result.js";
|
import { asyncTryCatchIf, isFileError, isNetworkError, tryCatch } from "./result.js";
|
||||||
import { logDebug, logError, logInfo, logStep, logWarn, openBrowser, prompt } from "./ui";
|
import { logDebug, logError, logInfo, logStep, logWarn, openBrowser, prompt } from "./ui";
|
||||||
|
|
||||||
// ─── Schemas ─────────────────────────────────────────────────────────────────
|
// ─── Schemas ─────────────────────────────────────────────────────────────────
|
||||||
|
|
@ -286,7 +286,7 @@ export function hasSavedOpenRouterKey(): boolean {
|
||||||
|
|
||||||
/** Load a previously saved OpenRouter API key from ~/.config/spawn/openrouter.json. */
|
/** Load a previously saved OpenRouter API key from ~/.config/spawn/openrouter.json. */
|
||||||
function loadSavedOpenRouterKey(): string | null {
|
function loadSavedOpenRouterKey(): string | null {
|
||||||
const result = tryCatchIf(isFileError, () => {
|
const result = tryCatch(() => {
|
||||||
const configPath = getSpawnCloudConfigPath("openrouter");
|
const configPath = getSpawnCloudConfigPath("openrouter");
|
||||||
const data = parseJsonObj(readFileSync(configPath, "utf-8"));
|
const data = parseJsonObj(readFileSync(configPath, "utf-8"));
|
||||||
if (!data) {
|
if (!data) {
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import * as p from "@clack/prompts";
|
||||||
import { isString } from "@openrouter/spawn-shared";
|
import { isString } from "@openrouter/spawn-shared";
|
||||||
import { parseJsonObj } from "./parse";
|
import { parseJsonObj } from "./parse";
|
||||||
import { getSpawnCloudConfigPath } from "./paths";
|
import { getSpawnCloudConfigPath } from "./paths";
|
||||||
import { asyncTryCatch, isFileError, tryCatch, tryCatchIf, unwrapOr } from "./result.js";
|
import { asyncTryCatch, tryCatch, unwrapOr } from "./result.js";
|
||||||
|
|
||||||
const RED = "\x1b[0;31m";
|
const RED = "\x1b[0;31m";
|
||||||
const GREEN = "\x1b[0;32m";
|
const GREEN = "\x1b[0;32m";
|
||||||
|
|
@ -242,7 +242,7 @@ export async function withRetry<T>(
|
||||||
*/
|
*/
|
||||||
export function loadApiToken(cloud: string): string | null {
|
export function loadApiToken(cloud: string): string | null {
|
||||||
return unwrapOr(
|
return unwrapOr(
|
||||||
tryCatchIf(isFileError, () => {
|
tryCatch(() => {
|
||||||
const data = parseJsonObj(readFileSync(getSpawnCloudConfigPath(cloud), "utf-8"));
|
const data = parseJsonObj(readFileSync(getSpawnCloudConfigPath(cloud), "utf-8"));
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue