Skip to content

Commit 36b4554

Browse files
angeloashmoreclaude
andcommitted
fix: show friendly error when repo is not found
Catch `NotFoundRequestError` in all commands that call repo-scoped API endpoints and display "Repository not found: <repo>" instead of an unhandled stack trace. Closes #118 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent eb2a83c commit 36b4554

23 files changed

Lines changed: 276 additions & 128 deletions

src/commands/locale-add.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getHost, getToken } from "../auth";
22
import { upsertLocale } from "../clients/locale";
33
import { CommandError, createCommand, type CommandConfig } from "../lib/command";
4-
import { UnknownRequestError } from "../lib/request";
4+
import { NotFoundRequestError, UnknownRequestError } from "../lib/request";
55
import { getRepositoryName } from "../project";
66

77
const config = {
@@ -32,6 +32,9 @@ export default createCommand(config, async ({ positionals, values }) => {
3232
try {
3333
await upsertLocale({ id: code, isMaster: master, customName: name }, { repo, token, host });
3434
} catch (error) {
35+
if (error instanceof NotFoundRequestError) {
36+
throw new CommandError(`Repository not found: ${repo}`);
37+
}
3538
if (error instanceof UnknownRequestError) {
3639
const message = await error.text();
3740
throw new CommandError(`Failed to add locale: ${message}`);

src/commands/locale-list.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { getHost, getToken } from "../auth";
22
import { getLocales } from "../clients/locale";
3-
import { createCommand, type CommandConfig } from "../lib/command";
3+
import { CommandError, createCommand, type CommandConfig } from "../lib/command";
44
import { stringify } from "../lib/json";
5+
import { NotFoundRequestError, UnknownRequestError } from "../lib/request";
56
import { getRepositoryName } from "../project";
67

78
const config = {
@@ -24,7 +25,19 @@ export default createCommand(config, async ({ values }) => {
2425
const token = await getToken();
2526
const host = await getHost();
2627

27-
const locales = await getLocales({ repo, token, host });
28+
let locales;
29+
try {
30+
locales = await getLocales({ repo, token, host });
31+
} catch (error) {
32+
if (error instanceof NotFoundRequestError) {
33+
throw new CommandError(`Repository not found: ${repo}`);
34+
}
35+
if (error instanceof UnknownRequestError) {
36+
const message = await error.text();
37+
throw new CommandError(`Failed to list locales: ${message}`);
38+
}
39+
throw error;
40+
}
2841

2942
if (json) {
3043
console.info(stringify(locales));

src/commands/locale-remove.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getHost, getToken } from "../auth";
22
import { removeLocale } from "../clients/locale";
33
import { CommandError, createCommand, type CommandConfig } from "../lib/command";
4-
import { UnknownRequestError } from "../lib/request";
4+
import { NotFoundRequestError, UnknownRequestError } from "../lib/request";
55
import { getRepositoryName } from "../project";
66

77
const config = {
@@ -30,6 +30,9 @@ export default createCommand(config, async ({ positionals, values }) => {
3030
try {
3131
await removeLocale(code, { repo, token, host });
3232
} catch (error) {
33+
if (error instanceof NotFoundRequestError) {
34+
throw new CommandError(`Repository not found: ${repo}`);
35+
}
3336
if (error instanceof UnknownRequestError) {
3437
const message = await error.text();
3538
throw new CommandError(`Failed to remove locale: ${message}`);

src/commands/locale-set-master.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getHost, getToken } from "../auth";
22
import { getLocales, upsertLocale } from "../clients/locale";
33
import { CommandError, createCommand, type CommandConfig } from "../lib/command";
4-
import { UnknownRequestError } from "../lib/request";
4+
import { NotFoundRequestError, UnknownRequestError } from "../lib/request";
55
import { getRepositoryName } from "../project";
66

77
const config = {
@@ -27,25 +27,28 @@ export default createCommand(config, async ({ positionals, values }) => {
2727
const token = await getToken();
2828
const host = await getHost();
2929

30-
const locales = await getLocales({ repo, token, host });
31-
const locale = locales.find((l) => l.id === code);
30+
try {
31+
const locales = await getLocales({ repo, token, host });
32+
const locale = locales.find((l) => l.id === code);
3233

33-
if (!locale) {
34-
throw new CommandError(
35-
`Locale "${code}" not found. Available locales: ${locales.map((l) => l.id).join(", ")}`,
36-
);
37-
}
34+
if (!locale) {
35+
throw new CommandError(
36+
`Locale "${code}" not found. Available locales: ${locales.map((l) => l.id).join(", ")}`,
37+
);
38+
}
3839

39-
if (locale.isMaster) {
40-
throw new CommandError(`Locale "${code}" is already the master.`);
41-
}
40+
if (locale.isMaster) {
41+
throw new CommandError(`Locale "${code}" is already the master.`);
42+
}
4243

43-
try {
4444
await upsertLocale(
4545
{ id: locale.id, isMaster: true, customName: locale.customName ?? undefined },
4646
{ repo, token, host },
4747
);
4848
} catch (error) {
49+
if (error instanceof NotFoundRequestError) {
50+
throw new CommandError(`Repository not found: ${repo}`);
51+
}
4952
if (error instanceof UnknownRequestError) {
5053
const message = await error.text();
5154
throw new CommandError(`Failed to set master locale: ${message}`);

src/commands/preview-add.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getHost, getToken } from "../auth";
22
import { addPreview } from "../clients/core";
33
import { CommandError, createCommand, type CommandConfig } from "../lib/command";
4-
import { UnknownRequestError } from "../lib/request";
4+
import { NotFoundRequestError, UnknownRequestError } from "../lib/request";
55
import { getRepositoryName } from "../project";
66

77
const config = {
@@ -42,6 +42,9 @@ export default createCommand(config, async ({ positionals, values }) => {
4242
try {
4343
await addPreview({ name: displayName, websiteURL, resolverPath }, { repo, token, host });
4444
} catch (error) {
45+
if (error instanceof NotFoundRequestError) {
46+
throw new CommandError(`Repository not found: ${repo}`);
47+
}
4548
if (error instanceof UnknownRequestError) {
4649
const message = await error.text();
4750
throw new CommandError(`Failed to add preview: ${message}`);

src/commands/preview-list.ts

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { getHost, getToken } from "../auth";
22
import { getPreviews, getSimulatorUrl } from "../clients/core";
3-
import { createCommand, type CommandConfig } from "../lib/command";
3+
import { CommandError, createCommand, type CommandConfig } from "../lib/command";
44
import { stringify } from "../lib/json";
5+
import { NotFoundRequestError, UnknownRequestError } from "../lib/request";
56
import { getRepositoryName } from "../project";
67

78
const config = {
@@ -24,10 +25,23 @@ export default createCommand(config, async ({ values }) => {
2425
const token = await getToken();
2526
const host = await getHost();
2627

27-
const [previews, simulatorUrl] = await Promise.all([
28-
getPreviews({ repo, token, host }),
29-
getSimulatorUrl({ repo, token, host }),
30-
]);
28+
let previews;
29+
let simulatorUrl;
30+
try {
31+
[previews, simulatorUrl] = await Promise.all([
32+
getPreviews({ repo, token, host }),
33+
getSimulatorUrl({ repo, token, host }),
34+
]);
35+
} catch (error) {
36+
if (error instanceof NotFoundRequestError) {
37+
throw new CommandError(`Repository not found: ${repo}`);
38+
}
39+
if (error instanceof UnknownRequestError) {
40+
const message = await error.text();
41+
throw new CommandError(`Failed to list previews: ${message}`);
42+
}
43+
throw error;
44+
}
3145

3246
if (json) {
3347
console.info(

src/commands/preview-remove.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getHost, getToken } from "../auth";
22
import { getPreviews, removePreview } from "../clients/core";
33
import { CommandError, createCommand, type CommandConfig } from "../lib/command";
4-
import { UnknownRequestError } from "../lib/request";
4+
import { NotFoundRequestError, UnknownRequestError } from "../lib/request";
55
import { getRepositoryName } from "../project";
66

77
const config = {
@@ -27,15 +27,18 @@ export default createCommand(config, async ({ positionals, values }) => {
2727
const token = await getToken();
2828
const host = await getHost();
2929

30-
const previews = await getPreviews({ repo, token, host });
31-
const preview = previews.find((p) => p.url === previewUrl);
32-
if (!preview) {
33-
throw new CommandError(`Preview not found: ${previewUrl}`);
34-
}
35-
3630
try {
31+
const previews = await getPreviews({ repo, token, host });
32+
const preview = previews.find((p) => p.url === previewUrl);
33+
if (!preview) {
34+
throw new CommandError(`Preview not found: ${previewUrl}`);
35+
}
36+
3737
await removePreview(preview.id, { repo, token, host });
3838
} catch (error) {
39+
if (error instanceof NotFoundRequestError) {
40+
throw new CommandError(`Repository not found: ${repo}`);
41+
}
3942
if (error instanceof UnknownRequestError) {
4043
const message = await error.text();
4144
throw new CommandError(`Failed to remove preview: ${message}`);

src/commands/preview-set-simulator.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getHost, getToken } from "../auth";
22
import { setSimulatorUrl } from "../clients/core";
33
import { CommandError, createCommand, type CommandConfig } from "../lib/command";
4-
import { UnknownRequestError } from "../lib/request";
4+
import { NotFoundRequestError, UnknownRequestError } from "../lib/request";
55
import { getRepositoryName } from "../project";
66

77
const config = {
@@ -45,6 +45,9 @@ export default createCommand(config, async ({ positionals, values }) => {
4545
try {
4646
await setSimulatorUrl(simulatorUrl, { repo, token, host });
4747
} catch (error) {
48+
if (error instanceof NotFoundRequestError) {
49+
throw new CommandError(`Repository not found: ${repo}`);
50+
}
4851
if (error instanceof UnknownRequestError) {
4952
const message = await error.text();
5053
throw new CommandError(`Failed to set simulator URL: ${message}`);

src/commands/repo-create.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { getAdapter } from "../adapters";
22
import { getHost, getToken } from "../auth";
33
import { checkIsDomainAvailable, createRepository } from "../clients/wroom";
44
import { CommandError, createCommand, type CommandConfig } from "../lib/command";
5-
import { UnknownRequestError } from "../lib/request";
5+
import { NotFoundRequestError, UnknownRequestError } from "../lib/request";
66

77
const MAX_DOMAIN_TRIES = 5;
88

@@ -31,6 +31,9 @@ export default createCommand(config, async ({ values }) => {
3131
try {
3232
await createRepository({ domain, name: name ?? domain, framework, token, host });
3333
} catch (error) {
34+
if (error instanceof NotFoundRequestError) {
35+
throw new CommandError(`Repository not found: ${domain}`);
36+
}
3437
if (error instanceof UnknownRequestError) {
3538
const message = await error.text();
3639
throw new CommandError(`Failed to create repository: ${message}`);

src/commands/repo-set-api-access.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { getHost, getToken } from "../auth";
22
import { type RepositoryAccessLevel, setRepositoryAccess } from "../clients/wroom";
33
import { CommandError, createCommand, type CommandConfig } from "../lib/command";
4-
import { UnknownRequestError } from "../lib/request";
4+
import { NotFoundRequestError, UnknownRequestError } from "../lib/request";
55
import { getRepositoryName } from "../project";
66

77
const VALID_LEVELS: RepositoryAccessLevel[] = ["private", "public", "open"];
@@ -38,6 +38,9 @@ export default createCommand(config, async ({ positionals, values }) => {
3838
try {
3939
await setRepositoryAccess(level as RepositoryAccessLevel, { repo, token, host });
4040
} catch (error) {
41+
if (error instanceof NotFoundRequestError) {
42+
throw new CommandError(`Repository not found: ${repo}`);
43+
}
4144
if (error instanceof UnknownRequestError) {
4245
const message = await error.text();
4346
throw new CommandError(`Failed to set repository access: ${message}`);

0 commit comments

Comments
 (0)