summaryrefslogtreecommitdiff
path: root/src/background/translation-session.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/background/translation-session.js')
-rw-r--r--src/background/translation-session.js76
1 files changed, 76 insertions, 0 deletions
diff --git a/src/background/translation-session.js b/src/background/translation-session.js
new file mode 100644
index 0000000..1d02974
--- /dev/null
+++ b/src/background/translation-session.js
@@ -0,0 +1,76 @@
+/**
+ * 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;
+ }
+ }
+} \ No newline at end of file