From 97accdd7a462329f9a0ce698b0b48c0bd61adad6 Mon Sep 17 00:00:00 2001 From: iammatthias Date: Wed, 20 Aug 2025 14:03:04 -0700 Subject: [PATCH 1/2] feat: Implement retry logic for createSignedUploadURL function --- .../uploads/createSignedUploadURL.ts | 104 +++++++++++------- 1 file changed, 65 insertions(+), 39 deletions(-) diff --git a/src/core/functions/uploads/createSignedUploadURL.ts b/src/core/functions/uploads/createSignedUploadURL.ts index 3077517..45f134b 100644 --- a/src/core/functions/uploads/createSignedUploadURL.ts +++ b/src/core/functions/uploads/createSignedUploadURL.ts @@ -84,49 +84,75 @@ export const createSignedUploadURL = async ( }; } - try { - const request = await fetch(`${endpoint}/files/sign`, { - method: "POST", - headers: headers, - cache: "no-store", - body: JSON.stringify(payload), - }); - - if (!request.ok) { - const errorData = await request.text(); - if (request.status === 401 || request.status === 403) { - throw new AuthenticationError( - `Authentication Failed: ${errorData}`, - request.status, - { - error: errorData, - code: "AUTH_ERROR", - metadata: { - requestUrl: request.url, + const maxRetries = 3; + + for (let attempt = 0; attempt <= maxRetries; attempt++) { + try { + const request = await fetch(`${endpoint}/files/sign`, { + method: "POST", + headers: headers, + cache: "no-store", + body: JSON.stringify(payload), + }); + + if (!request.ok) { + const errorData = await request.text(); + if (request.status === 401 || request.status === 403) { + throw new AuthenticationError( + `Authentication Failed: ${errorData}`, + request.status, + { + error: errorData, + code: "AUTH_ERROR", + metadata: { + requestUrl: request.url, + }, }, + ); + } + throw new NetworkError(`HTTP error: ${errorData}`, request.status, { + error: errorData, + code: "HTTP_ERROR", + metadata: { + requestUrl: request.url, }, - ); + }); } - throw new NetworkError(`HTTP error: ${errorData}`, request.status, { - error: errorData, - code: "HTTP_ERROR", - metadata: { - requestUrl: request.url, - }, - }); - } - const res = await request.json(); - return res.data; - } catch (error) { - if (error instanceof PinataError) { - throw error; - } - if (error instanceof Error) { - throw new PinataError( - `Error processing createSignedURL: ${error.message}`, - ); + const res = await request.json(); + return res.data; + } catch (error) { + // Don't retry auth errors or client errors (except 429) + if (error instanceof AuthenticationError) { + throw error; + } + if (error instanceof NetworkError && + error.statusCode && + error.statusCode >= 400 && + error.statusCode < 500 && + error.statusCode !== 429) { + throw error; + } + + // If we've exhausted retries, throw the error + if (attempt === maxRetries) { + if (error instanceof PinataError) { + throw error; + } + if (error instanceof Error) { + throw new PinataError( + `Error processing createSignedURL: ${error.message}`, + ); + } + throw new PinataError("An unknown error occurred while getting signed url"); + } + + // Wait before retrying (exponential backoff: 1s, 2s, 4s) + const delay = Math.min(1000 * Math.pow(2, attempt), 4000); + await new Promise((resolve) => setTimeout(resolve, delay)); } - throw new PinataError("An unknown error occurred while getting signed url"); } + + // This should never be reached, but TypeScript requires it + throw new PinataError("An unknown error occurred while getting signed url"); }; From 816f727591e3be1e6bc9695975ea55aa5b5b1b45 Mon Sep 17 00:00:00 2001 From: iammatthias Date: Wed, 20 Aug 2025 14:16:20 -0700 Subject: [PATCH 2/2] Biome --- .../uploads/createSignedUploadURL.ts | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/core/functions/uploads/createSignedUploadURL.ts b/src/core/functions/uploads/createSignedUploadURL.ts index 45f134b..19da059 100644 --- a/src/core/functions/uploads/createSignedUploadURL.ts +++ b/src/core/functions/uploads/createSignedUploadURL.ts @@ -85,7 +85,7 @@ export const createSignedUploadURL = async ( } const maxRetries = 3; - + for (let attempt = 0; attempt <= maxRetries; attempt++) { try { const request = await fetch(`${endpoint}/files/sign`, { @@ -126,14 +126,16 @@ export const createSignedUploadURL = async ( if (error instanceof AuthenticationError) { throw error; } - if (error instanceof NetworkError && - error.statusCode && - error.statusCode >= 400 && - error.statusCode < 500 && - error.statusCode !== 429) { + if ( + error instanceof NetworkError && + error.statusCode && + error.statusCode >= 400 && + error.statusCode < 500 && + error.statusCode !== 429 + ) { throw error; } - + // If we've exhausted retries, throw the error if (attempt === maxRetries) { if (error instanceof PinataError) { @@ -144,15 +146,17 @@ export const createSignedUploadURL = async ( `Error processing createSignedURL: ${error.message}`, ); } - throw new PinataError("An unknown error occurred while getting signed url"); + throw new PinataError( + "An unknown error occurred while getting signed url", + ); } - + // Wait before retrying (exponential backoff: 1s, 2s, 4s) const delay = Math.min(1000 * Math.pow(2, attempt), 4000); await new Promise((resolve) => setTimeout(resolve, delay)); } } - + // This should never be reached, but TypeScript requires it throw new PinataError("An unknown error occurred while getting signed url"); };