Skip to content

Commit 7369554

Browse files
authored
fix: correctly classify image errors vs metadata errors (#251)
1 parent c57d963 commit 7369554

File tree

4 files changed

+45
-25
lines changed

4 files changed

+45
-25
lines changed

src/token-processor/util/errors.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,22 +95,22 @@ export class StacksNodeHttpError extends Error {
9595

9696
export function getUserErrorInvalidReason(error: UserError): DbJobInvalidReason {
9797
switch (true) {
98-
case error instanceof MetadataSizeExceededError:
99-
return DbJobInvalidReason.metadataSizeExceeded;
10098
case error instanceof ImageSizeExceededError:
10199
return DbJobInvalidReason.imageSizeExceeded;
102-
case error instanceof MetadataTimeoutError:
103-
return DbJobInvalidReason.metadataTimeout;
100+
case error instanceof MetadataSizeExceededError:
101+
return DbJobInvalidReason.metadataSizeExceeded;
104102
case error instanceof ImageTimeoutError:
105103
return DbJobInvalidReason.imageTimeout;
106-
case error instanceof MetadataParseError:
107-
return DbJobInvalidReason.metadataParseFailed;
104+
case error instanceof MetadataTimeoutError:
105+
return DbJobInvalidReason.metadataTimeout;
108106
case error instanceof ImageParseError:
109107
return DbJobInvalidReason.imageParseFailed;
110-
case error instanceof MetadataHttpError:
111-
return DbJobInvalidReason.metadataHttpError;
108+
case error instanceof MetadataParseError:
109+
return DbJobInvalidReason.metadataParseFailed;
112110
case error instanceof ImageHttpError:
113111
return DbJobInvalidReason.imageHttpError;
112+
case error instanceof MetadataHttpError:
113+
return DbJobInvalidReason.metadataHttpError;
114114
case error instanceof SmartContractClarityError:
115115
return DbJobInvalidReason.tokenContractClarityError;
116116
default:

src/token-processor/util/metadata-helpers.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ export async function fetchAllMetadataLocalesFromBaseUri(
6565
try {
6666
const rawMetadataLocales: RawMetadataLocale[] = [];
6767

68-
const defaultMetadata = await getMetadataFromUri(tokenUri);
68+
const defaultMetadata = await getMetadataFromUri(
69+
tokenUri,
70+
contract.principal,
71+
token.token_number
72+
);
6973
rawMetadataLocales.push({
7074
metadata: defaultMetadata,
7175
default: true,
@@ -83,7 +87,11 @@ export async function fetchAllMetadataLocalesFromBaseUri(
8387
continue;
8488
}
8589
const localeUri = getTokenSpecificUri(uri, token.token_number, locale);
86-
const localeMetadata = await getMetadataFromUri(localeUri);
90+
const localeMetadata = await getMetadataFromUri(
91+
localeUri,
92+
contract.principal,
93+
token.token_number
94+
);
8795
rawMetadataLocales.push({
8896
metadata: localeMetadata,
8997
locale: locale,
@@ -234,9 +242,14 @@ async function parseMetadataForInsertion(
234242
* @param httpUrl - URL to fetch
235243
* @returns Response text
236244
*/
237-
export async function fetchMetadata(httpUrl: URL): Promise<string | undefined> {
245+
export async function fetchMetadata(
246+
httpUrl: URL,
247+
contract_principal: string,
248+
token_number: bigint
249+
): Promise<string | undefined> {
238250
const url = httpUrl.toString();
239251
try {
252+
logger.info(`MetadataFetch for ${contract_principal}#${token_number} from ${url}`);
240253
const result = await request(url, {
241254
method: 'GET',
242255
throwOnError: true,
@@ -266,7 +279,11 @@ export async function fetchMetadata(httpUrl: URL): Promise<string | undefined> {
266279
}
267280
}
268281

269-
export async function getMetadataFromUri(token_uri: string): Promise<RawMetadata> {
282+
export async function getMetadataFromUri(
283+
token_uri: string,
284+
contract_principal: string,
285+
token_number: bigint
286+
): Promise<RawMetadata> {
270287
// Support JSON embedded in a Data URL
271288
if (new URL(token_uri).protocol === 'data:') {
272289
const dataUrl = parseDataUrl(token_uri);
@@ -292,7 +309,7 @@ export async function getMetadataFromUri(token_uri: string): Promise<RawMetadata
292309
// Support HTTP/S URLs otherwise
293310
const httpUrl = getFetchableDecentralizedStorageUrl(token_uri);
294311
const urlStr = httpUrl.toString();
295-
const content = await fetchMetadata(httpUrl);
312+
const content = await fetchMetadata(httpUrl, contract_principal, token_number);
296313
return parseJsonMetadata(urlStr, content);
297314
}
298315

tests/token-queue/image-cache.test.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ import { ENV } from '../../src/env';
22
import { processImageCache } from '../../src/token-processor/images/image-cache';
33
import { closeTestServer, startTestResponseServer, startTimeoutServer } from '../helpers';
44
import {
5-
MetadataHttpError,
6-
MetadataTimeoutError,
5+
ImageHttpError,
6+
ImageTimeoutError,
77
TooManyRequestsHttpError,
88
} from '../../src/token-processor/util/errors';
99

@@ -22,7 +22,7 @@ describe('Image cache', () => {
2222
const server = await startTimeoutServer(100);
2323
await expect(
2424
processImageCache('http://127.0.0.1:9999/', contract, tokenNumber)
25-
).rejects.toThrow(MetadataTimeoutError);
25+
).rejects.toThrow(ImageTimeoutError);
2626
await closeTestServer(server);
2727
}, 10000);
2828

@@ -38,7 +38,7 @@ describe('Image cache', () => {
3838
const server = await startTestResponseServer('not found', 404);
3939
await expect(
4040
processImageCache('http://127.0.0.1:9999/', contract, tokenNumber)
41-
).rejects.toThrow(MetadataHttpError);
41+
).rejects.toThrow(ImageHttpError);
4242
await closeTestServer(server);
4343
}, 10000);
4444
});

tests/token-queue/metadata-helpers.test.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import {
77
getTokenSpecificUri,
88
fetchMetadata,
99
} from '../../src/token-processor/util/metadata-helpers';
10-
import { RetryableJobError } from '../../src/token-processor/queue/errors';
1110

1211
describe('Metadata Helpers', () => {
1312
test('performs timed and limited request', async () => {
@@ -24,7 +23,7 @@ describe('Metadata Helpers', () => {
2423
.reply(200, 'hello');
2524
setGlobalDispatcher(agent);
2625

27-
const result = await fetchMetadata(url);
26+
const result = await fetchMetadata(url, 'ABCD.test', 1n);
2827
expect(result).toBe('hello');
2928
});
3029

@@ -40,7 +39,9 @@ describe('Metadata Helpers', () => {
4039
.reply(200, '[{"test-bad-json": true}]');
4140
setGlobalDispatcher(agent);
4241

43-
await expect(getMetadataFromUri('http://test.io/1.json')).rejects.toThrow(/JSON parse error/);
42+
await expect(getMetadataFromUri('http://test.io/1.json', 'ABCD.test', 1n)).rejects.toThrow(
43+
/JSON parse error/
44+
);
4445
});
4546

4647
test('throws metadata http errors', async () => {
@@ -56,7 +57,7 @@ describe('Metadata Helpers', () => {
5657
.reply(500, { message: 'server error' });
5758
setGlobalDispatcher(agent);
5859

59-
await expect(fetchMetadata(url)).rejects.toThrow(MetadataHttpError);
60+
await expect(fetchMetadata(url, 'ABCD.test', 1n)).rejects.toThrow(MetadataHttpError);
6061
});
6162

6263
test('does not throw on raw metadata with null or stringable values', async () => {
@@ -91,7 +92,9 @@ describe('Metadata Helpers', () => {
9192
.reply(200, crashPunks1);
9293
setGlobalDispatcher(agent);
9394

94-
await expect(getMetadataFromUri('http://test.io/1.json')).resolves.not.toThrow();
95+
await expect(
96+
getMetadataFromUri('http://test.io/1.json', 'ABCD.test', 1n)
97+
).resolves.not.toThrow();
9598
});
9699

97100
test('fetches typed raw metadata', async () => {
@@ -127,7 +130,7 @@ describe('Metadata Helpers', () => {
127130
.reply(200, json);
128131
setGlobalDispatcher(agent);
129132

130-
const metadata = await getMetadataFromUri('http://test.io/1.json');
133+
const metadata = await getMetadataFromUri('http://test.io/1.json', 'ABCD.test', 1n);
131134
expect(metadata.name).toBe('Mutant Monkeys #27');
132135
expect(metadata.image).toBe(
133136
'https://byzantion.mypinata.cloud/ipfs/QmbNC9qvcYZugaeGeReDhyYiNH7oPzrCX1cZUnQeszFz4P'
@@ -154,7 +157,7 @@ describe('Metadata Helpers', () => {
154157
.reply(200, json);
155158
setGlobalDispatcher(agent);
156159

157-
const metadata = await getMetadataFromUri('http://test.io/1.json');
160+
const metadata = await getMetadataFromUri('http://test.io/1.json', 'ABCD.test', 1n);
158161
expect(metadata.name).toBe('Boombox [4th Edition]');
159162
expect(metadata.description).toBe(
160163
'The first ever Boombox to exist IRL, this art was created by 3D printing a model and photographing it under some very Boomerific lighting. 💥'
@@ -228,6 +231,6 @@ describe('Metadata Helpers', () => {
228231
.replyWithError(Object.assign(new TypeError(), { cause: new Error('read ECONNRESET') }));
229232
setGlobalDispatcher(agent);
230233

231-
await expect(fetchMetadata(url)).rejects.toThrow(MetadataHttpError);
234+
await expect(fetchMetadata(url, 'ABCD.test', 1n)).rejects.toThrow(MetadataHttpError);
232235
});
233236
});

0 commit comments

Comments
 (0)