Skip to content

Commit a1c7add

Browse files
fix: Throw clearer error when the NPM registry returns 404
1 parent bd2ad5d commit a1c7add

File tree

2 files changed

+30
-5
lines changed

2 files changed

+30
-5
lines changed

packages/snaps-controllers/src/snaps/location/npm.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,26 @@ describe('NpmLocation', () => {
246246
);
247247
});
248248

249+
it('throws if NPM returns 404', async () => {
250+
const customFetchMock = jest.fn().mockResolvedValue({
251+
ok: false,
252+
body: null,
253+
status: 404,
254+
} as any);
255+
256+
const location = new NpmLocation(
257+
new URL('npm:@metamask/jsx-example-snap'),
258+
{
259+
versionRange: exampleSnapVersion,
260+
fetch: customFetchMock as typeof fetch,
261+
},
262+
);
263+
264+
await expect(location.manifest()).rejects.toThrow(
265+
'"@metamask/jsx-example-snap" was not found in the NPM registry',
266+
);
267+
});
268+
249269
it('throws if the NPM tarball URL is invalid', async () => {
250270
const customFetchMock = jest.fn();
251271

packages/snaps-controllers/src/snaps/location/npm.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -220,11 +220,15 @@ export class NpmLocation extends BaseNpmLocation {
220220
async fetchNpmTarball(tarballUrl: URL): Promise<Map<string, VirtualFile>> {
221221
// Perform a raw fetch because we want the Response object itself.
222222
const tarballResponse = await this.meta.fetch(tarballUrl.toString());
223-
if (!tarballResponse.ok || !tarballResponse.body) {
224-
throw new Error(
225-
`Failed to fetch tarball for package "${this.meta.packageName}".`,
226-
);
227-
}
223+
224+
assert(
225+
tarballResponse.status !== 404,
226+
`"${this.meta.packageName}" was not found in the NPM registry`,
227+
);
228+
assert(
229+
tarballResponse.ok && tarballResponse.body,
230+
`Failed to fetch tarball for package "${this.meta.packageName}"`,
231+
);
228232

229233
// We assume that NPM is a good actor and provides us with a valid `content-length` header.
230234
const tarballSizeString = tarballResponse.headers.get('content-length');
@@ -234,6 +238,7 @@ export class NpmLocation extends BaseNpmLocation {
234238
tarballSize <= TARBALL_SIZE_SAFETY_LIMIT,
235239
'Snap tarball exceeds size limit',
236240
);
241+
237242
return new Promise((resolve, reject) => {
238243
const files = new Map();
239244

0 commit comments

Comments
 (0)