Logging (GstService):
- JSON-structured log lines: { ts, level, msg, ...ctx } — one per line,
machine-parseable by any log aggregator (datadog, loki, etc.)
- LOG_LEVEL env var (DEBUG|INFO|WARN|ERROR, default INFO) — set DEBUG to
see every captcha fetch, raw GST response body, and page console event
- WARN and ERROR lines go to stderr; INFO/DEBUG go to stdout so process
supervisors can separate them
- Every log line carries relevant context: reqId, sessionId, gstin, ms, etc.
- errCtx() helper extracts errName, errMsg, and first 6 stack frames from
any thrown value — no more bare String(e)
- elapsed() helper records wall-clock ms for every expensive step:
browser launch, page navigation, captcha fetch, GST API call
- Request/response middleware: every HTTP request logs method, path,
reqId, status, and duration; status >= 500 logs at ERROR, >= 400 at WARN
- Playwright page listeners: console errors/warnings, pageerror,
requestfailed, and HTTP 4xx/5xx on GST portal endpoints
- process.on(uncaughtException) and process.on(unhandledRejection) so
unexpected crashes surface in logs instead of silently dying
- Browser "disconnected" event logged; _browser reset so next request
auto-relaunches without manual restart
- SESSION_TTL_MS configurable via env (default 3 min)
- closeSession() logs the reason (success / errorCode / exception / etc.)
- GET /health now returns browserConnected, per-session captchaCount,
expiresInMs, and lastUsedMsAgo for operational visibility
Multiple captchas per session:
- Session now holds captchas: CaptchaEntry[] (ordered oldest→newest)
so every image fetched in a session is kept for traceability
- GET /captcha/:sessionId — new endpoint that calls /services/captcha
again within the SAME browser context (no page reload, ~200ms vs ~5s)
and appends a new CaptchaEntry; resets TTL; returns totalCaptchas
- POST /search on SWEB_9034 (wrong captcha) no longer closes the session —
returns { canRefresh: true, sessionId } so the caller can hit
GET /captcha/:sessionId for a fresh image and retry immediately
- All other error paths (SWEB_9000, network error, no data) still close
the session as before
Next.js proxy (app/api/gst/captcha/route.ts):
- GET /api/gst/captcha?refresh=<sessionId> proxies to the new
GET /captcha/:sessionId endpoint on GstService
- Plain GET /api/gst/captcha still creates a new session as before
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>