/** * Translation session management (background). * * Only one translation may be active at a time (SEC-14 / Design.md ยง9). * Starting a new request aborts the previous one. Chunks belonging to a * stale requestId are discarded. */ import { ERROR_CODES } from '../shared/constants.js'; export class TranslationSession { constructor() { /** @type {{requestId: string, controller: AbortController, port: object}|null} */ this.active = null; } /** * @returns {boolean} */ hasActive() { return this.active !== null; } /** * Abort the active request, if any. Notifies its port so the UI can reset. * @returns {void} */ abortActive() { if (!this.active) return; const { controller, port, requestId } = this.active; this.active = null; try { controller.abort(); } catch { // ignore abort errors } if (port) { try { port.postMessage({ type: 'error', requestId, code: ERROR_CODES.REQUEST_ABORTED, message: 'Superseded by a newer request' }); } catch { // port may be gone } } } /** * Register a new active request, aborting any previous one. * @param {string} requestId * @param {object} port runtime.Port owning the request * @returns {AbortController} the controller for the new request */ start(requestId, port) { this.abortActive(); const controller = new AbortController(); this.active = { requestId, controller, port }; return controller; } /** * @param {string} requestId * @returns {boolean} true when the given id is the active request. */ isActive(requestId) { return this.active !== null && this.active.requestId === requestId; } /** * Clear the active session when it matches the id. * @param {string} requestId */ clear(requestId) { if (this.isActive(requestId)) { this.active = null; } } }