Skip to content

Commit 694324d

Browse files
committed
feat(cli): add withErrorHandling utility and refactor account command
1 parent 647a586 commit 694324d

2 files changed

Lines changed: 44 additions & 12 deletions

File tree

packages/cli/src/commands/account.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import type { Command } from "commander";
22
import {
33
getAccountProfile,
4-
handleApiError,
54
updateAccountProfile,
5+
withErrorHandling,
66
} from "../lib/api-client.ts";
77
import { dim, formatKeyValue, success } from "../lib/output.ts";
88

@@ -19,13 +19,13 @@ export function registerAccountCommand(program: Command): void {
1919
.option("--slug <slug>", "Set public URL slug")
2020
.option("--json", "Output as JSON")
2121
.action(
22-
async (options: {
23-
name?: string;
24-
bio?: string;
25-
slug?: string;
26-
json?: boolean;
27-
}) => {
28-
try {
22+
withErrorHandling(
23+
async (options: {
24+
name?: string;
25+
bio?: string;
26+
slug?: string;
27+
json?: boolean;
28+
}) => {
2929
const hasUpdates = options.name || options.bio || options.slug;
3030

3131
if (hasUpdates) {
@@ -73,9 +73,8 @@ export function registerAccountCommand(program: Command): void {
7373
["Slug", profile.slug ?? dim("—")],
7474
]),
7575
);
76-
} catch (err) {
77-
handleApiError(err, "manage profile");
78-
}
79-
},
76+
},
77+
{ action: "manage profile" },
78+
),
8079
);
8180
}

packages/cli/src/lib/api-client.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,39 @@ export function handleApiError(err: unknown, action: string): never {
5555
process.exit(1);
5656
}
5757

58+
/**
59+
* Wraps an async function with standardized error handling for CLI actions.
60+
* Eliminates repetitive try/catch boilerplate in command definitions.
61+
*
62+
* @example
63+
* ```typescript
64+
* .action(withErrorHandling(async (options) => {
65+
* // command logic without try/catch
66+
* }, { action: "update profile" }))
67+
* ```
68+
*/
69+
export function withErrorHandling<TArgs extends unknown[]>(
70+
fn: (...args: TArgs) => Promise<void>,
71+
options?: {
72+
/** Action description for error messages (e.g., "deploy workflow") */
73+
action?: string;
74+
/** Optional custom error handler (defaults to handleApiError) */
75+
onError?: (err: unknown) => void;
76+
},
77+
): (...args: TArgs) => Promise<void> {
78+
return async (...args: TArgs) => {
79+
try {
80+
await fn(...args);
81+
} catch (err) {
82+
if (options?.onError) {
83+
options.onError(err);
84+
} else {
85+
handleApiError(err, options?.action ?? "execute command");
86+
}
87+
}
88+
};
89+
}
90+
5891
async function getClient(): Promise<SecondLayer> {
5992
const config = await loadConfig();
6093
const baseUrl = resolveApiUrl(config);

0 commit comments

Comments
 (0)