From c8e00efa38c59f4d9251ae0f2cdd05510a278cac Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Tue, 11 Jun 2024 22:52:22 +0200 Subject: [PATCH 1/2] fix: axios error transformation on network errors #5644 --- CHANGELOG.md | 6 ++++ TestingApp/test/axios2.spec.js | 57 ++++++++++++++++++++++++++++++++++ lib/build/axiosError.js | 44 ++++++++++++++------------ lib/build/version.d.ts | 2 +- lib/build/version.js | 2 +- lib/ts/axiosError.ts | 46 ++++++++++++++------------- lib/ts/version.ts | 2 +- package-lock.json | 4 +-- package.json | 2 +- 9 files changed, 118 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92d48ca..65e6ada 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [unreleased] +## [5.1.1] - 2024-06-12 + +### Fixes + +- Fixed an issue in the Axios interceptor that caused it to throw when encountering a network error + ## [5.1.0] - 2024-06-04 ### Changes diff --git a/TestingApp/test/axios2.spec.js b/TestingApp/test/axios2.spec.js index 19e741c..e5bac8b 100644 --- a/TestingApp/test/axios2.spec.js +++ b/TestingApp/test/axios2.spec.js @@ -298,6 +298,63 @@ describe("Axios AuthHttpRequest class tests", function() { assert(idRefreshInCookies.length === 0); }); + it("should throw error if refresh fails with a network error", async function() { + await startST(); + AuthHttpRequest.addAxiosInterceptors(axiosInstance); + const origFetch = global.fetch; + global.fetch = async (...input) => { + try { + if (input[0].endsWith("/auth/session/refresh")) { + input[0] = "http://localhost:1234/nope"; + } + return await origFetch(...input); + } catch (err) { + throw err; + } + }; + AuthHttpRequest.init({ + apiDomain: BASE_URL, + tokenTransferMethod: "cookie" + }); + + let userId = "testing-supertokens-react-native"; + + let loginResponse = await axiosInstance.post(`${BASE_URL}/login`, JSON.stringify({ userId }), { + headers: { + Accept: "application/json", + "Content-Type": "application/json" + } + }); + let userIdFromResponse = loginResponse.data; + assertEqual(userId, userIdFromResponse); + + cookieJar.setCookieSync("sIdRefreshToken=asdf", `${BASE_URL}/`); + + // This is to verify that the cookie is correctly set + let currentCookies = cookieJar.getCookiesSync(`${BASE_URL}/`); + let idRefreshInCookies = currentCookies.filter(i => i.key === "sIdRefreshToken"); + let accessTokenInCookies = currentCookies.filter(i => i.key === "sAccessToken"); + + assert(idRefreshInCookies.length !== 0); + assert(accessTokenInCookies.length !== 0); + + //check that the number of times the refreshAPI was called is 0 + assert((await getNumberOfTimesRefreshCalled()) === 0); + + try { + await axiosInstance("http://localhost:1234/asdf"); + await axiosInstance({ + url: `${BASE_URL}/`, + method: "GET", + headers: { "Cache-Control": "no-cache, private" } + }); + } catch (err) { + assert(err.isAxiosError); + assert.strictEqual(err.code, "ECONNREFUSED"); + assert.strictEqual(err.response, undefined); + } + }); + it("test that interception happens based on the return value of shouldDoInterceptionBasedOnUrl override", async function() { await startST(); AuthHttpRequest.addAxiosInterceptors(axiosInstance); diff --git a/lib/build/axiosError.js b/lib/build/axiosError.js index 66080c1..cac6537 100644 --- a/lib/build/axiosError.js +++ b/lib/build/axiosError.js @@ -74,31 +74,35 @@ export function createAxiosErrorFromFetchResp(response) { url: response.url, headers: response.headers }; - const contentType = response.headers.get("content-type"); - let data; - if (!contentType || contentType.includes("application/json")) { - try { - data = yield response.json(); - } catch (_a) { + const isProperResponse = "status" in response; + let axiosResponse; + if (isProperResponse) { + let data; + const contentType = response.headers.get("content-type"); + if (!contentType || contentType.includes("application/json")) { + try { + data = yield response.json(); + } catch (_a) { + data = yield response.text(); + } + } else if (contentType.includes("text/")) { data = yield response.text(); + } else { + data = yield response.blob(); } - } else if (contentType.includes("text/")) { - data = yield response.text(); - } else { - data = yield response.blob(); + axiosResponse = { + data, + status: response.status, + statusText: response.statusText, + headers: response.headers, + config: config, + request: undefined + }; } - const axiosResponse = { - data, - status: response.status, - statusText: response.statusText, - headers: response.headers, - config: config, - request: undefined - }; return enhanceAxiosError( - new Error("Request failed with status code " + response.status), + "status" in response ? new Error("Request failed with status code " + response.status) : response, config, - undefined, + response.code, undefined, axiosResponse ); diff --git a/lib/build/version.d.ts b/lib/build/version.d.ts index 5c73ca8..8c57f62 100644 --- a/lib/build/version.d.ts +++ b/lib/build/version.d.ts @@ -1,2 +1,2 @@ -export declare const package_version = "5.1.0"; +export declare const package_version = "5.1.1"; export declare const supported_fdi: string[]; diff --git a/lib/build/version.js b/lib/build/version.js index 10fa84e..b084971 100644 --- a/lib/build/version.js +++ b/lib/build/version.js @@ -12,5 +12,5 @@ * License for the specific language governing permissions and limitations * under the License. */ -export const package_version = "5.1.0"; +export const package_version = "5.1.1"; export const supported_fdi = ["1.16", "1.17", "1.18", "1.19", "2.0", "3.0"]; diff --git a/lib/ts/axiosError.ts b/lib/ts/axiosError.ts index b74e2c9..cf10a23 100644 --- a/lib/ts/axiosError.ts +++ b/lib/ts/axiosError.ts @@ -67,32 +67,36 @@ export async function createAxiosErrorFromFetchResp(response: Response): Promise url: response.url, headers: response.headers }; - const contentType = response.headers.get("content-type"); - let data; - if (!contentType || contentType.includes("application/json")) { - try { - data = await response.json(); - } catch { + const isProperResponse = "status" in response; + let axiosResponse; + if (isProperResponse) { + let data; + const contentType = response.headers.get("content-type"); + if (!contentType || contentType.includes("application/json")) { + try { + data = await response.json(); + } catch { + data = await response.text(); + } + } else if (contentType.includes("text/")) { data = await response.text(); + } else { + data = await response.blob(); } - } else if (contentType.includes("text/")) { - data = await response.text(); - } else { - data = await response.blob(); - } - const axiosResponse = { - data, - status: response.status, - statusText: response.statusText, - headers: response.headers, - config: config, - request: undefined - }; + axiosResponse = { + data, + status: response.status, + statusText: response.statusText, + headers: response.headers, + config: config, + request: undefined + }; + } return enhanceAxiosError( - new Error("Request failed with status code " + response.status), + "status" in response ? new Error("Request failed with status code " + response.status) : response, config, - undefined, + (response as any).code, undefined, axiosResponse ); diff --git a/lib/ts/version.ts b/lib/ts/version.ts index 5546fba..4c77d10 100644 --- a/lib/ts/version.ts +++ b/lib/ts/version.ts @@ -12,6 +12,6 @@ * License for the specific language governing permissions and limitations * under the License. */ -export const package_version = "5.1.0"; +export const package_version = "5.1.1"; export const supported_fdi = ["1.16", "1.17", "1.18", "1.19", "2.0", "3.0"]; diff --git a/package-lock.json b/package-lock.json index a2877f4..75653a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "supertokens-react-native", - "version": "5.1.0", + "version": "5.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "supertokens-react-native", - "version": "5.1.0", + "version": "5.1.1", "license": "Apache 2.0", "dependencies": { "base-64": "^1.0.0", diff --git a/package.json b/package.json index 293561f..691c6b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "supertokens-react-native", - "version": "5.1.0", + "version": "5.1.1", "description": "React Native SDK for SuperTokens", "main": "index.js", "scripts": { From 1c0fcfe46fe58f53e554725b6f621cf01b3916fb Mon Sep 17 00:00:00 2001 From: Mihaly Lengyel Date: Thu, 13 Jun 2024 10:47:19 +0200 Subject: [PATCH 2/2] refactor: rename variables for clarity --- lib/build/axiosError.d.ts | 2 +- lib/build/axiosError.js | 32 +++++++++++++++++--------------- lib/ts/axiosError.ts | 32 +++++++++++++++++--------------- 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/lib/build/axiosError.d.ts b/lib/build/axiosError.d.ts index 625d61f..4a75440 100644 --- a/lib/build/axiosError.d.ts +++ b/lib/build/axiosError.d.ts @@ -1,2 +1,2 @@ import { AxiosError } from "axios"; -export declare function createAxiosErrorFromFetchResp(response: Response): Promise; +export declare function createAxiosErrorFromFetchResp(responseOrError: Response): Promise; diff --git a/lib/build/axiosError.js b/lib/build/axiosError.js index cac6537..6970ae6 100644 --- a/lib/build/axiosError.js +++ b/lib/build/axiosError.js @@ -68,41 +68,43 @@ function enhanceAxiosError(error, config, code, request, response) { }; return error; } -export function createAxiosErrorFromFetchResp(response) { +export function createAxiosErrorFromFetchResp(responseOrError) { return __awaiter(this, void 0, void 0, function*() { const config = { - url: response.url, - headers: response.headers + url: responseOrError.url, + headers: responseOrError.headers }; - const isProperResponse = "status" in response; + const isResponse = "status" in responseOrError; let axiosResponse; - if (isProperResponse) { + if (isResponse) { let data; - const contentType = response.headers.get("content-type"); + const contentType = responseOrError.headers.get("content-type"); if (!contentType || contentType.includes("application/json")) { try { - data = yield response.json(); + data = yield responseOrError.json(); } catch (_a) { - data = yield response.text(); + data = yield responseOrError.text(); } } else if (contentType.includes("text/")) { - data = yield response.text(); + data = yield responseOrError.text(); } else { - data = yield response.blob(); + data = yield responseOrError.blob(); } axiosResponse = { data, - status: response.status, - statusText: response.statusText, - headers: response.headers, + status: responseOrError.status, + statusText: responseOrError.statusText, + headers: responseOrError.headers, config: config, request: undefined }; } return enhanceAxiosError( - "status" in response ? new Error("Request failed with status code " + response.status) : response, + "status" in responseOrError + ? new Error("Request failed with status code " + responseOrError.status) + : responseOrError, config, - response.code, + responseOrError.code, undefined, axiosResponse ); diff --git a/lib/ts/axiosError.ts b/lib/ts/axiosError.ts index cf10a23..fdbfef1 100644 --- a/lib/ts/axiosError.ts +++ b/lib/ts/axiosError.ts @@ -62,41 +62,43 @@ function enhanceAxiosError( return error; } -export async function createAxiosErrorFromFetchResp(response: Response): Promise { +export async function createAxiosErrorFromFetchResp(responseOrError: Response): Promise { const config = { - url: response.url, - headers: response.headers + url: responseOrError.url, + headers: responseOrError.headers }; - const isProperResponse = "status" in response; + const isResponse = "status" in responseOrError; let axiosResponse; - if (isProperResponse) { + if (isResponse) { let data; - const contentType = response.headers.get("content-type"); + const contentType = responseOrError.headers.get("content-type"); if (!contentType || contentType.includes("application/json")) { try { - data = await response.json(); + data = await responseOrError.json(); } catch { - data = await response.text(); + data = await responseOrError.text(); } } else if (contentType.includes("text/")) { - data = await response.text(); + data = await responseOrError.text(); } else { - data = await response.blob(); + data = await responseOrError.blob(); } axiosResponse = { data, - status: response.status, - statusText: response.statusText, - headers: response.headers, + status: responseOrError.status, + statusText: responseOrError.statusText, + headers: responseOrError.headers, config: config, request: undefined }; } return enhanceAxiosError( - "status" in response ? new Error("Request failed with status code " + response.status) : response, + "status" in responseOrError + ? new Error("Request failed with status code " + responseOrError.status) + : responseOrError, config, - (response as any).code, + (responseOrError as any).code, undefined, axiosResponse );