From 39883f60d7b43b7f3f88f6bd75499060dd1ca60a Mon Sep 17 00:00:00 2001 From: mulahasanovic Date: Mon, 20 Apr 2026 12:54:14 +0200 Subject: [PATCH] fix: re-establish session on ERR_NETWORK before retrying --- src/request/RequestClient.ts | 48 +++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 9 deletions(-) diff --git a/src/request/RequestClient.ts b/src/request/RequestClient.ts index de87541..e377773 100644 --- a/src/request/RequestClient.ts +++ b/src/request/RequestClient.ts @@ -28,6 +28,9 @@ import { import { InvalidSASjsCsrfError } from '../types/errors/InvalidSASjsCsrfError' import { inspect } from 'util' +const getLogger = () => + (typeof process !== 'undefined' && process.logger) || console + export class RequestClient implements HttpClient { private requests: SASjsRequest[] = [] private requestsLimit: number = 10 @@ -79,7 +82,7 @@ export class RequestClient implements HttpClient { } public resetInMemoryAuthState() { - const logger = process.logger || console + const logger = getLogger() const clearedCookies: string[] = [] this.clearCsrfTokens() @@ -385,7 +388,7 @@ export class RequestClient implements HttpClient { const csrfTokenKey = Object.keys(params).find((k) => k?.toLowerCase().includes('csrf') ) - const logger = process.logger || console + const logger = getLogger() if (csrfTokenKey) { this.csrfToken.value = params[csrfTokenKey] @@ -622,7 +625,7 @@ ${resHeaders}${parsedResBody ? `\n\n${parsedResBody}` : ''} protected parseAndSetCsrfToken = (response: AxiosResponse) => { const token = this.parseCsrfToken(response) - const logger = process.logger || console + const logger = getLogger() if (token) { this.csrfToken = token @@ -652,7 +655,7 @@ ${resHeaders}${parsedResBody ? `\n\n${parsedResBody}` : ''} } private logHandleError(step: string, details?: Record) { - const logger = process.logger || console + const logger = getLogger() logger.warn(`[handleError] ${step}`, details || '') } @@ -799,16 +802,43 @@ ${resHeaders}${parsedResBody ? `\n\n${parsedResBody}` : ''} !this.isRecoveringFromNetworkError ) { // Opaque ERR_NETWORK usually means the server rejected stale credentials. - // Wipe in-memory auth state so the retry either succeeds - // or surfaces a clean LoginRequiredError. - this.logHandleError('ERR_NETWORK — clearing all auth state and retrying') + // Wipe in-memory auth state, re-establish session via GET /, + // then retry the original request. + this.logHandleError('ERR_NETWORK — clearing all auth state') this.resetInMemoryAuthState() this.isRecoveringFromNetworkError = true try { + // Re-establish session and CSRF cookie + this.logHandleError('ERR_NETWORK — re-establishing session via GET /') + const rootResponse = await this.httpClient + .get('/', { withXSRFToken: true }) + .catch((err) => { + this.logHandleError('ERR_NETWORK — GET / failed', { + code: err?.code, + status: err?.response?.status, + message: err?.message + }) + return err.response + }) + + if (rootResponse?.data) { + const cookie = + /