/**
 * 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.
 */

var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var resolver_exports = {};
__export(resolver_exports, {
  preprocessExpression: () => preprocessExpression,
  resolveJsonTemplate: () => resolveJsonTemplate
});
module.exports = __toCommonJS(resolver_exports);
var import_ses = require("ses");
var import_lodash = __toESM(require("lodash"));
var import_utils = require("@nocobase/utils");
var import_contexts = require("./contexts");
const BLOCKED_SANDBOX_KEYS = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
const sandboxProxyCache = /* @__PURE__ */ new WeakMap();
const sandboxProxyMeta = /* @__PURE__ */ new WeakMap();
const EMPTY_SANDBOX_CONTEXT = {
  getSandboxKeys: () => [],
  getSandboxValue: () => void 0
};
let resolverLockdownReady = false;
async function resolveJsonTemplate(template, ctx) {
  const compile = async (source) => {
    if (typeof source === "string" && /\{\{.*?\}\}/.test(source)) {
      return await replacePlaceholders(source, ctx);
    }
    if (Array.isArray(source)) return Promise.all(source.map(compile));
    if (source && typeof source === "object") {
      const out = {};
      for (const [k, v] of Object.entries(source)) out[k] = await compile(v);
      return out;
    }
    return source;
  };
  return compile(template);
}
async function replacePlaceholders(input, ctx) {
  const single = input.match(/^\{\{\s*(.+)\s*\}\}$/);
  if (single) {
    const val = await evaluate(single[1], ctx);
    return typeof val === "undefined" ? input : val;
  }
  const regex = /\{\{\s*(.+?)\s*\}\}/g;
  let result = input;
  const matches = [...input.matchAll(regex)];
  for (const [full, inner] of matches) {
    const value = await evaluate(inner, ctx);
    if (typeof value !== "undefined") {
      const replacement = typeof value === "object" && value !== null ? JSON.stringify(value) : String(value);
      result = result.replace(full, replacement);
    }
  }
  return result;
}
function isObjectLike(value) {
  return value !== null && (typeof value === "object" || typeof value === "function");
}
function isTrustedPromise(value) {
  return value instanceof Promise;
}
function isBlockedSandboxKey(key) {
  return typeof key === "string" && BLOCKED_SANDBOX_KEYS.has(key);
}
function getSandboxDataDescriptor(source, key) {
  if (isBlockedSandboxKey(key) || typeof key === "symbol") return void 0;
  const descriptor = Reflect.getOwnPropertyDescriptor(source, key);
  if (!descriptor || !("value" in descriptor)) return void 0;
  if (key === "then" && typeof descriptor.value === "function") return void 0;
  return descriptor;
}
function getPrimitiveDataDescriptor(source, key) {
  if (source == null || isObjectLike(source)) return void 0;
  return getSandboxDataDescriptor(Object(source), key);
}
function isSandboxContextSource(value) {
  return value === EMPTY_SANDBOX_CONTEXT || value instanceof import_contexts.ServerBaseContext;
}
function wrapSandboxValue(value) {
  if (isTrustedPromise(value)) {
    return Promise.prototype.then.call(value, (resolved) => wrapSandboxValue(resolved));
  }
  if (!isObjectLike(value)) return value;
  if (sandboxProxyMeta.has(value)) return value;
  const cached = sandboxProxyCache.get(value);
  if (cached) return cached;
  const kind = isSandboxContextSource(value) ? "context" : typeof value === "function" ? "function" : "data";
  const proxy = kind === "context" ? createSandboxContextProxy(value) : kind === "function" ? createSandboxFunctionProxy(value) : createSandboxDataProxy(value);
  sandboxProxyCache.set(value, proxy);
  sandboxProxyMeta.set(proxy, { kind, source: value });
  return proxy;
}
function wrapRootSandboxContext(ctx) {
  return wrapSandboxValue(isSandboxContextSource(ctx) ? ctx : EMPTY_SANDBOX_CONTEXT);
}
function ensureResolverLockdown() {
  if (resolverLockdownReady) return;
  (0, import_utils.lockdownSes)({
    consoleTaming: "unsafe",
    errorTaming: "unsafe",
    overrideTaming: "moderate",
    stackFiltering: "verbose"
  });
  resolverLockdownReady = true;
}
function createSandboxContextProxy(source) {
  return new Proxy(/* @__PURE__ */ Object.create(null), {
    get: (_target, key) => {
      if (isBlockedSandboxKey(key) || typeof key !== "string") return void 0;
      if (!source.getSandboxKeys().includes(key)) return void 0;
      return wrapSandboxValue(source.getSandboxValue(key));
    },
    has: (_target, key) => typeof key === "string" && source.getSandboxKeys().includes(key),
    ownKeys: () => source.getSandboxKeys(),
    getOwnPropertyDescriptor: (_target, key) => {
      if (isBlockedSandboxKey(key) || typeof key !== "string" || !source.getSandboxKeys().includes(key)) {
        return void 0;
      }
      return {
        configurable: true,
        enumerable: true,
        value: wrapSandboxValue(source.getSandboxValue(key))
      };
    },
    getPrototypeOf: () => null,
    set: () => false,
    defineProperty: () => false,
    deleteProperty: () => false
  });
}
function createSandboxFunctionProxy(source) {
  const callable = (...args) => Reflect.apply(source, void 0, args);
  return new Proxy(callable, {
    apply: (_target, _thisArg, argArray) => wrapSandboxValue(Reflect.apply(source, void 0, argArray)),
    get: (_target, key) => {
      if (key === "length" || key === "name") return Reflect.get(source, key);
      return void 0;
    },
    has: (_target, key) => key === "length" || key === "name",
    ownKeys: () => [],
    getOwnPropertyDescriptor: () => void 0,
    getPrototypeOf: () => null,
    set: () => false,
    defineProperty: () => false,
    deleteProperty: () => false
  });
}
function createSandboxDataProxy(source) {
  const target = Array.isArray(source) ? new Array(source.length) : /* @__PURE__ */ Object.create(null);
  return new Proxy(target, {
    get: (_target, key) => {
      const descriptor = getSandboxDataDescriptor(source, key);
      if (!descriptor) return void 0;
      const value = descriptor.value;
      return typeof value === "function" ? wrapSandboxValue(value.bind(source)) : wrapSandboxValue(value);
    },
    has: (_target, key) => {
      if (isBlockedSandboxKey(key) || typeof key !== "string") return false;
      return !!getSandboxDataDescriptor(source, key);
    },
    ownKeys: () => {
      const keys = Reflect.ownKeys(source).filter((key) => {
        if (typeof key !== "string" || isBlockedSandboxKey(key)) return false;
        return !!getSandboxDataDescriptor(source, key);
      });
      if (Array.isArray(source) && !keys.includes("length")) keys.push("length");
      return keys;
    },
    getOwnPropertyDescriptor: (proxyTarget, key) => {
      if (isBlockedSandboxKey(key) || typeof key === "symbol") return void 0;
      if (Array.isArray(source) && key === "length") {
        return Reflect.getOwnPropertyDescriptor(proxyTarget, key);
      }
      const descriptor = getSandboxDataDescriptor(source, key);
      if (!descriptor) return void 0;
      return {
        configurable: true,
        enumerable: descriptor.enumerable,
        writable: false,
        value: wrapSandboxValue(descriptor.value)
      };
    },
    getPrototypeOf: () => null,
    set: () => false,
    defineProperty: () => false,
    deleteProperty: () => false
  });
}
async function unwrapSandboxValue(value, seen = /* @__PURE__ */ new WeakMap()) {
  const resolved = isTrustedPromise(value) ? await value : value;
  if (!isObjectLike(resolved)) return resolved;
  const meta = sandboxProxyMeta.get(resolved);
  if ((meta == null ? void 0 : meta.kind) === "function" || typeof resolved === "function") return void 0;
  const source = (meta == null ? void 0 : meta.source) ?? resolved;
  if (!isObjectLike(source)) return source;
  if (seen.has(source)) return seen.get(source);
  if (isSandboxContextSource(source)) {
    const out2 = {};
    seen.set(source, out2);
    for (const key of source.getSandboxKeys()) {
      if (BLOCKED_SANDBOX_KEYS.has(key)) continue;
      out2[key] = await unwrapSandboxValue(wrapSandboxValue(source.getSandboxValue(key)), seen);
    }
    return out2;
  }
  if (Array.isArray(source)) {
    const out2 = [];
    seen.set(source, out2);
    const lengthDescriptor = Reflect.getOwnPropertyDescriptor(source, "length");
    const length = typeof (lengthDescriptor == null ? void 0 : lengthDescriptor.value) === "number" ? lengthDescriptor.value : 0;
    for (let index = 0; index < length; index++) {
      const descriptor = Reflect.getOwnPropertyDescriptor(source, String(index));
      if (!descriptor || !("value" in descriptor)) continue;
      out2.push(await unwrapSandboxValue(descriptor.value, seen));
    }
    return out2;
  }
  if (source instanceof Date) return source;
  const out = {};
  seen.set(source, out);
  for (const key of Object.keys(source)) {
    if (BLOCKED_SANDBOX_KEYS.has(key)) continue;
    const descriptor = getSandboxDataDescriptor(source, key);
    if (!descriptor) continue;
    out[key] = await unwrapSandboxValue(descriptor.value, seen);
  }
  return out;
}
function getRootSandboxValue(ctx, key) {
  if (BLOCKED_SANDBOX_KEYS.has(key)) return void 0;
  if (isSandboxContextSource(ctx)) {
    if (!ctx.getSandboxKeys().includes(key)) return void 0;
    return wrapSandboxValue(ctx.getSandboxValue(key));
  }
  return void 0;
}
async function getSandboxProperty(value, key) {
  if (BLOCKED_SANDBOX_KEYS.has(key)) return void 0;
  const resolved = isTrustedPromise(value) ? await value : value;
  if (resolved == null) return void 0;
  const meta = isObjectLike(resolved) ? sandboxProxyMeta.get(resolved) : void 0;
  const source = (meta == null ? void 0 : meta.source) ?? resolved;
  if (isSandboxContextSource(source)) {
    if (!source.getSandboxKeys().includes(key)) return void 0;
    return wrapSandboxValue(source.getSandboxValue(key));
  }
  if (typeof source === "function") {
    return key === "length" || key === "name" ? Reflect.get(source, key) : void 0;
  }
  if (!isObjectLike(source)) {
    const descriptor2 = getPrimitiveDataDescriptor(source, key);
    if (!descriptor2 || typeof descriptor2.value === "function") return void 0;
    return wrapSandboxValue(descriptor2.value);
  }
  const descriptor = getSandboxDataDescriptor(source, key);
  if (!descriptor) return void 0;
  const current = descriptor.value;
  return typeof current === "function" ? wrapSandboxValue(current.bind(source)) : wrapSandboxValue(current);
}
async function evaluate(expr, ctx) {
  try {
    const raw = expr.trim();
    const dotOnly = raw.match(
      /^ctx\.([a-zA-Z_$][a-zA-Z0-9_$]*)(?:\.([a-zA-Z_$][a-zA-Z0-9_$-]*(?:\.[a-zA-Z_$][a-zA-Z0-9_$-]*)*))?$/
    );
    if (dotOnly) {
      const first = dotOnly[1];
      const rest = dotOnly[2];
      const base = getRootSandboxValue(ctx, first);
      if (!rest) return await unwrapSandboxValue(wrapSandboxValue(base));
      const resolved = await asyncGetValuesByPath(base, rest);
      if (typeof resolved !== "undefined" || !rest.includes("-")) {
        return await unwrapSandboxValue(resolved);
      }
    }
    const transformed = preprocessExpression(raw);
    ensureResolverLockdown();
    const compartment = new Compartment({
      ctx: wrapRootSandboxContext(ctx),
      __get: wrapSandboxValue((varName, path) => getAtPath(ctx, varName, path))
    });
    const wrapped = `(async () => { try { return ${transformed}; } catch (e) { return undefined; } })()`;
    return await unwrapSandboxValue(await compartment.evaluate(wrapped));
  } catch (_2) {
    return void 0;
  }
}
async function getAtPath(ctx, varName, path) {
  try {
    let current = getRootSandboxValue(ctx, varName);
    if (!path) return current;
    const norm = String(path || "").replace(/^\./, "");
    const segments = import_lodash.default.toPath(norm);
    for (const seg of segments) {
      if (current == null) return void 0;
      current = await getSandboxProperty(current, seg);
    }
    return wrapSandboxValue(current);
  } catch (_2) {
    return void 0;
  }
}
async function asyncGetValuesByPath(obj, path, defaultValue) {
  try {
    let currentValue = await obj;
    if (!currentValue) return defaultValue;
    const keys = String(path || "").split(".");
    let result = [];
    let shouldReturnArray = false;
    for (let i = 0; i < keys.length; i++) {
      const key = keys[i];
      if (Array.isArray(currentValue)) {
        shouldReturnArray = true;
        const rest = keys.slice(i).join(".");
        const parts = await Promise.all(
          Array.prototype.map.call(currentValue, (el) => asyncGetValuesByPath(el, rest, defaultValue))
        );
        for (const p of parts) {
          if (Array.isArray(p)) {
            for (let index = 0; index < p.length; index++) {
              if (typeof p[index] !== "undefined") result.push(p[index]);
            }
          } else if (typeof p !== "undefined") result.push(p);
        }
        break;
      }
      currentValue = await getSandboxProperty(currentValue, key);
      if (i === keys.length - 1) {
        result.push(currentValue);
      }
    }
    result = result.filter((item) => typeof item !== "undefined");
    if (result.length === 0) return defaultValue;
    if (shouldReturnArray) return result.filter((item) => item !== null);
    return result[0];
  } catch (_2) {
    return defaultValue;
  }
}
function preprocessExpression(expression) {
  let out = "";
  let i = 0;
  const n = expression.length;
  while (i < n) {
    const dotIdx = expression.indexOf("ctx.", i);
    const brkIdx = expression.indexOf("ctx[", i);
    let idx = -1;
    if (dotIdx === -1) idx = brkIdx;
    else if (brkIdx === -1) idx = dotIdx;
    else idx = Math.min(dotIdx, brkIdx);
    if (idx === -1) {
      out += expression.slice(i);
      break;
    }
    out += expression.slice(i, idx);
    let j = idx + 3;
    let varName = null;
    let pathStr = "";
    if (expression[j] === ".") {
      j += 1;
      const varMatch = /^[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(expression.slice(j));
      if (!varMatch) {
        out += "ctx.";
        i = j;
        continue;
      }
      varName = varMatch[0];
      j += varName.length;
    } else if (expression[j] === "[") {
      const m = /^\[("((?:[^"\\]|\\.)*)"|'((?:[^'\\]|\\.)*)')\]/.exec(expression.slice(j));
      if (!m) {
        out += "ctx[";
        i = j;
        continue;
      }
      varName = m[2] ?? m[3];
      j += m[0].length;
    } else {
      out += expression.slice(idx, idx + 3);
      i = idx + 3;
      continue;
    }
    while (j < n) {
      if (expression[j] === ".") {
        const m = /^\.[a-zA-Z_$][a-zA-Z0-9_$]*/.exec(expression.slice(j));
        if (!m) break;
        pathStr += m[0];
        j += m[0].length;
      } else if (expression[j] === "[") {
        const m = /^(\[(?:\d+|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*')\])/.exec(expression.slice(j));
        if (!m) break;
        pathStr += m[1];
        j += m[1].length;
      } else {
        break;
      }
    }
    const argPath = pathStr ? `, ${JSON.stringify(pathStr)}` : "";
    out += `(await __get(${JSON.stringify(varName)}${argPath}))`;
    i = j;
  }
  return out;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  preprocessExpression,
  resolveJsonTemplate
});
