Skip to content

Commit a4c5db8

Browse files
committed
refactor(error): route uncaught CLI errors through typed-error display
The typed-error classes in `utils/error/errors.mts` (AuthError, InputError, ConfigError, NetworkError, FileSystemError, RateLimitError) plus the matching `formatErrorForDisplay`/`formatErrorForTerminal`/`formatErrorForJson` helpers were only ever exercised by tests — the CLI entry point used its own inline `if/else` dispatch that handled AuthError/InputError/Error. - Replace the inline dispatch in `cli-entry.mts` with calls to `formatErrorForTerminal` and `formatErrorForJson`, so any typed error now thrown in production gets consistent titles, recovery suggestions, and JSON/text formatting. - Convert `queryApi`'s "Socket API base URL is not configured" throw from a generic Error to a ConfigError keyed on CONFIG_KEY_API_BASE_URL. Users now see recovery suggestions directing them to `socket config set` instead of a bare stack trace. The remaining typed classes (NetworkError, FileSystemError, RateLimitError) stay parked. Forcing them into current CResult-returning sites would be a larger refactor and isn't needed for the display wiring itself to work — they slot in automatically the moment any throw site adopts them.
1 parent 64a14c5 commit a4c5db8

File tree

2 files changed

+12
-36
lines changed

2 files changed

+12
-36
lines changed

packages/cli/src/cli-entry.mts

Lines changed: 7 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ process.emitWarning = function (warning, ...args) {
2828
return Reflect.apply(originalEmitWarning, this, [warning, ...args])
2929
}
3030

31-
import { messageWithCauses, stackWithCauses } from 'pony-cause'
3231
import lookupRegistryAuthToken from 'registry-auth-token'
3332
import lookupRegistryUrl from 'registry-url'
3433

@@ -53,11 +52,10 @@ import { VITEST } from './env/vitest.mts'
5352
import meow from './meow.mts'
5453
import { meowWithSubcommands } from './utils/cli/with-subcommands.mts'
5554
import {
56-
AuthError,
57-
captureException,
58-
InputError,
59-
} from './utils/error/errors.mts'
60-
import { failMsgWithBadge } from './utils/error/fail-msg-with-badge.mts'
55+
formatErrorForJson,
56+
formatErrorForTerminal,
57+
} from './utils/error/display.mts'
58+
import { captureException } from './utils/error/errors.mts'
6159
import { serializeResultJson } from './utils/output/result-json.mts'
6260
import { runPreflightDownloads } from './utils/preflight/downloads.mts'
6361
import { isSeaBinary } from './utils/sea/detect.mts'
@@ -181,24 +179,6 @@ void (async () => {
181179
debug('CLI uncaught error')
182180
debugDir(e)
183181

184-
let errorBody: string | undefined
185-
let errorTitle: string
186-
let errorMessage = ''
187-
if (e instanceof AuthError) {
188-
errorTitle = 'Authentication error'
189-
errorMessage = e.message
190-
} else if (e instanceof InputError) {
191-
errorTitle = 'Invalid input'
192-
errorMessage = e.message
193-
errorBody = e.body
194-
} else if (e instanceof Error) {
195-
errorTitle = 'Unexpected error'
196-
errorMessage = messageWithCauses(e)
197-
errorBody = stackWithCauses(e)
198-
} else {
199-
errorTitle = 'Unexpected error with no details'
200-
}
201-
202182
// Try to parse the flags, find out if --json is set.
203183
const isJson = (() => {
204184
const cli = meow({
@@ -213,20 +193,12 @@ void (async () => {
213193
})()
214194

215195
if (isJson) {
216-
logger.log(
217-
serializeResultJson({
218-
ok: false,
219-
message: errorTitle,
220-
cause: errorMessage,
221-
}),
222-
)
196+
logger.log(serializeResultJson(formatErrorForJson(e)))
223197
} else {
224198
// Add 2 newlines in stderr to bump below any spinner.
225199
logger.error('\n')
226-
logger.fail(failMsgWithBadge(errorTitle, errorMessage))
227-
if (errorBody) {
228-
debugDirNs('inspect', { errorBody })
229-
}
200+
logger.error(formatErrorForTerminal(e))
201+
debugDirNs('inspect', { error: e })
230202
}
231203

232204
await captureException(e)

packages/cli/src/utils/socket/api.mts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import {
5555
} from '../ecosystem/requirements.mts'
5656
import {
5757
buildErrorCause,
58+
ConfigError,
5859
getNetworkErrorDiagnostics,
5960
} from '../error/errors.mts'
6061

@@ -383,7 +384,10 @@ export async function handleApiCallNoSpinner<T extends SocketSdkOperations>(
383384
export async function queryApi(path: string, apiToken: string) {
384385
const baseUrl = getDefaultApiBaseUrl()
385386
if (!baseUrl) {
386-
throw new Error('Socket API base URL is not configured.')
387+
throw new ConfigError(
388+
'Socket API base URL is not configured.',
389+
CONFIG_KEY_API_BASE_URL,
390+
)
387391
}
388392

389393
return await socketHttpRequest(

0 commit comments

Comments
 (0)