claude overtook and fixes
This commit is contained in:
@@ -55,7 +55,8 @@ export class SessionManager {
|
||||
CompanyDB: this.config.companyDB,
|
||||
UserName: this.config.username,
|
||||
Password: this.config.password,
|
||||
Language: this.config.language
|
||||
// Service Layer expects Language as an integer language code (Edm.Int32).
|
||||
Language: this.normalizeLanguage(this.config.language)
|
||||
},
|
||||
{ skipAuth: true }
|
||||
);
|
||||
@@ -90,8 +91,15 @@ export class SessionManager {
|
||||
return;
|
||||
}
|
||||
|
||||
const cookieHeader = this.buildCookieHeader(this.session);
|
||||
|
||||
try {
|
||||
await this.http.post("/Logout", undefined, { skipAuth: false });
|
||||
// Logout must carry the active session cookie, otherwise the Service Layer
|
||||
// cannot identify which session to terminate and leaves it open until timeout.
|
||||
await this.http.post("/Logout", undefined, {
|
||||
skipAuth: true,
|
||||
headers: { Cookie: cookieHeader }
|
||||
});
|
||||
} finally {
|
||||
this.session = undefined;
|
||||
}
|
||||
@@ -111,6 +119,15 @@ export class SessionManager {
|
||||
this.session = undefined;
|
||||
}
|
||||
|
||||
private normalizeLanguage(language: string | undefined): number | undefined {
|
||||
if (language === undefined || language === "") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const numeric = Number(language);
|
||||
return Number.isInteger(numeric) ? numeric : undefined;
|
||||
}
|
||||
|
||||
private isExpired(session: SapB1Session): boolean {
|
||||
return session.expiresAt !== undefined && session.expiresAt <= Date.now();
|
||||
}
|
||||
|
||||
@@ -91,6 +91,8 @@ export class SapB1Client {
|
||||
}
|
||||
};
|
||||
|
||||
let reloginAttempted = false;
|
||||
|
||||
for (let attempt = 0; attempt <= this.config.retryCount; attempt += 1) {
|
||||
try {
|
||||
if (!requestConfig.skipAuth) {
|
||||
@@ -106,11 +108,15 @@ export class SapB1Client {
|
||||
return options.schema ? options.schema.parse(response.data) : (response.data as T);
|
||||
} catch (error) {
|
||||
const sapError = this.toSapB1Error(error, method, path);
|
||||
const canRelogin = sapError.status === 401 && !requestConfig.skipAuth && attempt === 0;
|
||||
const canRelogin = sapError.status === 401 && !requestConfig.skipAuth && !reloginAttempted;
|
||||
|
||||
if (canRelogin) {
|
||||
// A single re-login on session expiry must not eat into the retry budget,
|
||||
// so step the counter back and retry the request with a fresh session.
|
||||
reloginAttempted = true;
|
||||
this.sessionManager.clearSession();
|
||||
await this.sessionManager.getSession(true);
|
||||
attempt -= 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -162,7 +168,7 @@ export class SapB1Client {
|
||||
private normalizeNextLink(nextLink: string): string {
|
||||
try {
|
||||
const parsed = new URL(nextLink);
|
||||
return parsed.pathname.replace(/^.*\/b1s\/v1\/?/, "");
|
||||
return parsed.pathname.replace(/^.*\/b1s\/v1\/?/, "") + parsed.search;
|
||||
} catch {
|
||||
return nextLink.replace(/^\/?b1s\/v1\/?/, "");
|
||||
}
|
||||
|
||||
+6
-1
@@ -610,7 +610,12 @@ app.get("/openapi.json", (_req, res) => {
|
||||
|
||||
addResourceEndpoints();
|
||||
|
||||
app.use("/docs", swaggerUi.serveFiles(undefined, swaggerOptions("")), swaggerUi.setup(undefined, swaggerOptions("")));
|
||||
// Behind the AppFactory reverse proxy the container is reached via /apps/<app-id> and
|
||||
// the prefix is stripped (handle_path) before requests arrive here. The Swagger UI page is
|
||||
// therefore served at the public /apps/<app-id>/docs, so the OpenAPI document URL and the
|
||||
// "Try it out" base path must carry ROOT_PATH; otherwise the browser would resolve them
|
||||
// against the bare origin and bypass the app.
|
||||
app.use("/docs", swaggerUi.serveFiles(undefined, swaggerOptions(rootPath)), swaggerUi.setup(undefined, swaggerOptions(rootPath)));
|
||||
|
||||
if (rootPath) {
|
||||
app.get(rootPath, (_req, res) => {
|
||||
|
||||
Reference in New Issue
Block a user