/**
 * This file is part of the NocoBase (R) project.
 * Copyright (c) 2020-2024 NocoBase Co., Ltd.
 * Authors: NocoBase Team.
 *
 * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
 * For more information, please refer to: https://www.nocobase.com/agreement.
 */

const { parentPort, workerData } = require("node:worker_threads");
const { Script } = require("node:vm");
const Path = require("node:path");
let timer = null;
function customRequire(m) {
  var _a;
  const configuredModules = (((_a = process.env.WORKFLOW_SCRIPT_MODULES) == null ? void 0 : _a.split(",")) ?? []).filter(Boolean);
  let mainName;
  if (Path.isAbsolute(m)) {
    mainName = m;
  } else if (m.startsWith(".")) {
    mainName = m;
    m = Path.resolve(process.cwd(), m);
  } else {
    mainName = m.split("/").slice(0, m.startsWith("@") ? 2 : 1).join("/");
  }
  if (configuredModules.includes(mainName)) {
    return require(m);
  }
  throw new Error(`module "${m}" not supported`);
}
function hardenFunction(fn) {
  Object.setPrototypeOf(fn, null);
  Object.defineProperty(fn, "constructor", {
    value: null,
    writable: false,
    enumerable: false,
    configurable: false
  });
  return fn;
}
hardenFunction(customRequire);
function createSafeConsole(originalConsole) {
  const safe = /* @__PURE__ */ Object.create(null);
  const allowedMethods = [
    "log",
    "info",
    "warn",
    "error",
    "debug",
    "trace",
    "dir",
    "dirxml",
    "table",
    "time",
    "timeEnd",
    "timeLog",
    "count",
    "countReset",
    "group",
    "groupCollapsed",
    "groupEnd",
    "clear",
    "assert"
  ];
  for (const key of allowedMethods) {
    if (typeof originalConsole[key] === "function") {
      const bound = originalConsole[key].bind(originalConsole);
      hardenFunction(bound);
      Object.defineProperty(safe, key, {
        value: bound,
        writable: false,
        enumerable: true,
        configurable: false
      });
    }
  }
  Object.defineProperty(safe, "constructor", {
    value: null,
    writable: false,
    enumerable: false,
    configurable: false
  });
  return Object.freeze(safe);
}
async function main() {
  const { source, args = {}, options = {} } = workerData;
  const code = `
    this.constructor = null;
    async function __main() {
      ${source}
    }
    __main();
  `;
  const script = new Script(code);
  const context = {
    ...args,
    require: customRequire,
    console: createSafeConsole(console)
  };
  if (options.timeout) {
    timer = setTimeout(() => {
      throw new Error(`Script execution timed out after ${options.timeout}ms`);
    }, options.timeout);
  }
  const result = script.runInNewContext(context, { timeout: options.timeout });
  return result;
}
main().then((result) => {
  parentPort.postMessage({ type: "result", result });
}).catch((error) => {
  throw error;
}).finally(() => {
  clearTimeout(timer);
  timer = null;
});
