Files
ArchiTools/src/app/api/eterra/session/route.ts
T
AI Assistant b7a236c45a feat(parcel-sync): eTerra health check + maintenance detection
- New eterra-health.ts service: pings eTerra periodically (3min),
  detects maintenance (503, keywords), tracks consecutive failures
- New /api/eterra/health endpoint for explicit health queries
- Session route blocks login when eTerra is in maintenance (503 response)
- GET /api/eterra/session now includes eterraAvailable/eterraMaintenance
- ConnectionPill shows amber 'Mentenanță' state with AlertTriangle icon
  instead of confusing red error when eTerra is down
- Auto-connect skips when maintenance detected, retries when back online
- 30s session poll auto-detects recovery and re-enables auto-connect
2026-03-08 10:28:30 +02:00

117 lines
3.2 KiB
TypeScript

import { NextResponse } from "next/server";
import { EterraClient } from "@/modules/parcel-sync/services/eterra-client";
import {
createSession,
destroySession,
forceDestroySession,
getSessionCredentials,
getSessionStatus,
} from "@/modules/parcel-sync/services/session-store";
import { getEterraHealth } from "@/modules/parcel-sync/services/eterra-health";
export const runtime = "nodejs";
export const dynamic = "force-dynamic";
/**
* GET /api/eterra/session — returns current server-side session status
* enriched with eTerra platform health info.
*/
export async function GET() {
const status = getSessionStatus();
const health = getEterraHealth();
return NextResponse.json({
...status,
eterraAvailable: health.available,
eterraMaintenance: health.maintenance,
eterraHealthMessage: health.message,
});
}
/**
* POST /api/eterra/session — connect or disconnect.
*
* Connect: { action: "connect", username?, password? }
* Disconnect: { action: "disconnect", force?: boolean }
*/
export async function POST(req: Request) {
try {
const body = (await req.json()) as {
action?: string;
username?: string;
password?: string;
force?: boolean;
};
const action = body.action ?? "connect";
if (action === "disconnect") {
if (body.force) {
forceDestroySession();
return NextResponse.json({ success: true, disconnected: true });
}
const result = destroySession();
if (!result.destroyed) {
return NextResponse.json(
{ success: false, error: result.reason },
{ status: 409 },
);
}
return NextResponse.json({ success: true, disconnected: true });
}
// Connect
const username = (
body.username ??
process.env.ETERRA_USERNAME ??
""
).trim();
const password = (
body.password ??
process.env.ETERRA_PASSWORD ??
""
).trim();
if (!username || !password) {
return NextResponse.json(
{ error: "Credențiale eTerra lipsă" },
{ status: 400 },
);
}
// Block login when eTerra is in maintenance
const health = getEterraHealth();
if (!health.available && health.maintenance) {
return NextResponse.json(
{
error:
"eTerra este în mentenanță — conectarea este dezactivată temporar",
maintenance: true,
},
{ status: 503 },
);
}
// Check if already connected with same credentials
const existing = getSessionCredentials();
if (existing && existing.username === username) {
// Already connected — verify session is still alive by pinging
try {
await EterraClient.create(username, password);
return NextResponse.json({ success: true, alreadyConnected: true });
} catch {
// Session expired, re-login below
}
}
// Attempt login
await EterraClient.create(username, password);
createSession(username, password);
return NextResponse.json({ success: true });
} catch (error) {
const message = error instanceof Error ? error.message : "Eroare server";
const status = message.toLowerCase().includes("login") ? 401 : 500;
return NextResponse.json({ error: message }, { status });
}
}