"use strict";
/**
 * Worker thread process guard.
 *
 * Components loaded into Harper workers (Next.js, in particular) register
 * their own `unhandledRejection` handler that explicitly calls
 * `process.exit()`. That terminates the entire worker — including
 * replication and unrelated components — for what is logically an
 * application-level error.
 *
 * In worker threads, this module:
 *   - Intercepts `process.exit()` so component code cannot terminate the
 *     worker. The original exit is preserved as `process._realExit` (and
 *     as the exported `realExit()` helper) for Harper internal callers
 *     that legitimately need to terminate the worker (shutdown,
 *     FORCE_EXIT under Bun, etc.).
 *   - Registers an `unhandledRejection` listener so the default Node.js
 *     terminate-on-unhandled-rejection behavior is suppressed when no
 *     other component handler exists.
 *
 * On the main thread this module is a no-op except for exposing
 * `process._realExit` so internal callers can use the same name regardless
 * of thread.
 *
 * Harper-internal callers that intentionally want to terminate should use
 * the exported `realExit()` helper. It falls back to `process.exit` when
 * the guard has not been loaded (e.g., CLI bin scripts), so the helper is
 * always safe to call.
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.realExit = realExit;
const node_worker_threads_1 = require("node:worker_threads");
const harperLogger = __importStar(require("../../utility/logging/harper_logger.js"));
const realExitImpl = process.exit.bind(process);
// Expose the real exit on every thread so internal Harper callers have a
// stable name to use regardless of which thread they run on. Make it
// non-writable so component code cannot accidentally reassign it, but leave
// it configurable so test doubles (sinon, etc.) can stub it.
if (!process._realExit) {
    Object.defineProperty(process, '_realExit', {
        value: realExitImpl,
        writable: false,
        configurable: true,
        enumerable: false,
    });
}
/**
 * Terminate the current process for real, bypassing the worker process
 * guard's `process.exit` override. Safe to call from any thread — falls
 * back to `process.exit` when the guard has not been loaded yet (e.g.,
 * CLI bin scripts).
 */
function realExit(code) {
    // Prefer the (non-writable) `process._realExit` so test doubles that
    // stub `_realExit` can intercept Harper-intentional exits. Fall back
    // to `process.exit` when the guard hasn't been loaded.
    return (process._realExit ?? process.exit)(code);
}
if (!node_worker_threads_1.isMainThread) {
    // Replace the public process.exit. Component code calling this — directly
    // or via a framework's `unhandledRejection` handler — should not be able
    // to terminate the worker.
    const interceptedExit = ((code) => {
        const callSite = new Error('process.exit() intercepted').stack;
        harperLogger.error(`process.exit(${code ?? ''}) called in worker thread ${node_worker_threads_1.threadId} — ignored to keep Harper alive. ` +
            `Use process._realExit() for legitimate internal shutdown.\n${callSite}`);
        // `never` is a structural lie here; we return undefined. Callers that
        // rely on `process.exit` being terminal (e.g. dead-code analysis after
        // the call) will see execution continue, which is the desired
        // resilience behavior.
        return undefined;
    });
    process.exit = interceptedExit;
    // Defense in depth: if no other listener is registered, Node.js terminates
    // the process on an unhandled rejection. Register a logging listener so the
    // worker survives even when no component handler is loaded.
    process.on('unhandledRejection', (reason) => {
        harperLogger.error(`unhandledRejection in worker thread ${node_worker_threads_1.threadId}:`, reason);
    });
}
//# sourceMappingURL=workerProcessGuard.js.map