"use strict";
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 __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
));

// ../../node_modules/.pnpm/tsup@8.5.0_jiti@2.7.0_postcss@8.5.15_tsx@4.21.0_typescript@5.9.3_yaml@2.9.0/node_modules/tsup/assets/cjs_shims.js
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.src || new URL("main.js", document.baseURI).href;
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();

// src/eventcatalog.ts
var import_commander = require("commander");
var import_node_child_process = require("child_process");
var import_node_path10 = require("path");
var import_node_http = __toESM(require("http"), 1);
var import_fs3 = __toESM(require("fs"), 1);
var import_node_path11 = __toESM(require("path"), 1);
var import_node_url = require("url");

// src/generate.js
var import_node_path2 = __toESM(require("path"), 1);

// src/eventcatalog-config-file-utils.js
var import_promises = require("fs/promises");
var import_node_fs = require("fs");
var import_node_path = __toESM(require("path"), 1);
var import_uuid = require("uuid");
var import_url = require("url");
var import_node_os = require("os");
var import_gray_matter = __toESM(require("gray-matter"), 1);
async function cleanup(projectDirectory) {
  const filePath = import_node_path.default.join(projectDirectory, "eventcatalog.config.mjs");
  if ((0, import_node_fs.existsSync)(filePath)) {
    await (0, import_promises.rm)(filePath);
  }
}
var findNodeModulesDirectory = (directory) => {
  let currentDirectory = directory;
  while (true) {
    const nodeModulesDirectory = import_node_path.default.join(currentDirectory, "node_modules");
    if ((0, import_node_fs.existsSync)(nodeModulesDirectory)) {
      return nodeModulesDirectory;
    }
    const parentDirectory = import_node_path.default.dirname(currentDirectory);
    if (parentDirectory === currentDirectory) {
      return void 0;
    }
    currentDirectory = parentDirectory;
  }
};
var linkNodeModulesIntoTempDirectory = async ({ projectDirectory, tempDir }) => {
  const nodeModulesDirectory = findNodeModulesDirectory(projectDirectory);
  if (!nodeModulesDirectory) {
    return;
  }
  await (0, import_promises.symlink)(nodeModulesDirectory, import_node_path.default.join(tempDir, "node_modules"), "dir");
};
var createTemporaryConfigDirectory = async (projectDirectory) => {
  const nodeModulesDirectory = findNodeModulesDirectory(projectDirectory);
  if (nodeModulesDirectory) {
    return (0, import_promises.mkdtemp)(import_node_path.default.join(nodeModulesDirectory, ".eventcatalog-config-"));
  }
  const tempDir = await (0, import_promises.mkdtemp)(import_node_path.default.join((0, import_node_os.tmpdir)(), "eventcatalog-config-"));
  await linkNodeModulesIntoTempDirectory({ projectDirectory, tempDir });
  return tempDir;
};
var getEventCatalogConfigFile = async (projectDirectory) => {
  let tempDir;
  try {
    let configFilePath = import_node_path.default.join(projectDirectory, "eventcatalog.config.js");
    const filePath = import_node_path.default.join(projectDirectory, "package.json");
    const packageJson = JSON.parse(await (0, import_promises.readFile)(filePath, "utf-8"));
    if (packageJson?.type !== "module") {
      tempDir = await createTemporaryConfigDirectory(projectDirectory);
      configFilePath = import_node_path.default.join(tempDir, "eventcatalog.config.mjs");
      await (0, import_promises.copyFile)(import_node_path.default.join(projectDirectory, "eventcatalog.config.js"), configFilePath);
    }
    const configFileURL = `${(0, import_url.pathToFileURL)(configFilePath).href}?t=${Date.now()}`;
    const config = await import(
      /* @vite-ignore */
      configFileURL
    );
    return config.default;
  } finally {
    await cleanup(projectDirectory);
    if (tempDir) {
      await (0, import_promises.rm)(tempDir, { recursive: true, force: true });
    }
  }
};
var writeEventCatalogConfigFile = async (projectDirectory, newConfig) => {
  try {
    const configFilePath = import_node_path.default.join(projectDirectory, "eventcatalog.config.js");
    let content = await (0, import_promises.readFile)(configFilePath, "utf8");
    const startIndex = content.indexOf("export default {");
    if (startIndex === -1) {
      return;
    }
    Object.entries(newConfig).forEach(([key, value]) => {
      const valueString = JSON.stringify(value, null, 2).replace(/"/g, "'").replace(/\n/g, "\n  ");
      const keyRegex = new RegExp(`(${key}\\s*:)([^,}]+)`, "g");
      if (content.match(keyRegex)) {
        content = content.replace(keyRegex, `$1 ${valueString}`);
      } else {
        const insertPosition = content.indexOf("{", startIndex) + 1;
        content = content.slice(0, insertPosition) + `
  ${key}: ${valueString},` + content.slice(insertPosition);
      }
    });
    await (0, import_promises.writeFile)(configFilePath, content);
  } finally {
    await cleanup(projectDirectory);
  }
};
var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
  try {
    const config = await getEventCatalogConfigFile(projectDirectory);
    if (!config.cId) {
      await writeEventCatalogConfigFile(projectDirectory, { cId: (0, import_uuid.v4)() });
    }
  } catch (error) {
  }
};

// src/utils/cli-logger.ts
var import_picocolors = __toESM(require("picocolors"), 1);

// package.json
var version = "4.0.6";

// src/constants.ts
var VERSION = version;

// src/utils/cli-logger.ts
var getTimestamp = () => {
  const now = /* @__PURE__ */ new Date();
  return now.toLocaleTimeString("en-US", { hour12: false });
};
var formatMessage = (tag, message, tagColor) => {
  return `${import_picocolors.default.dim(getTimestamp())} ${tagColor(`[${tag}]`)} ${message}`;
};
var logger = {
  welcome: () => {
    console.log();
    console.log(import_picocolors.default.magenta(import_picocolors.default.bold("\u{1F680} EventCatalog")) + import_picocolors.default.dim(`  (v${VERSION})`));
    console.log(import_picocolors.default.dim("https://eventcatalog.dev"));
    console.log();
    console.log(
      import_picocolors.default.dim("If you like the project, we would appreciate a star on GitHub \u2764\uFE0F - ") + import_picocolors.default.bold("https://github.com/event-catalog/eventcatalog/stargazers")
    );
    console.log();
  },
  info: (message, tag = "info") => {
    console.log(formatMessage(tag, message, import_picocolors.default.blue));
  },
  success: (message, tag = "success") => {
    console.log(formatMessage(tag, message, import_picocolors.default.green));
  },
  error: (message, tag = "error") => {
    console.log(formatMessage(tag, message, import_picocolors.default.red));
  },
  warning: (message, tag = "warn") => {
    console.log(formatMessage(tag, message, import_picocolors.default.yellow));
  },
  dim: (message) => {
    console.log(import_picocolors.default.dim(message));
  }
};

// src/generate.js
function getDefaultExport(importedModule) {
  if (importedModule === null || typeof importedModule !== "object") {
    throw new Error("Invalid module");
  }
  if (typeof importedModule.default === "object" && importedModule.default !== null) {
    return importedModule.default.default || importedModule.default;
  }
  if (typeof importedModule.default !== "undefined") {
    return importedModule.default;
  }
  return importedModule;
}
var generate = async (PROJECT_DIRECTORY) => {
  try {
    const config = await getEventCatalogConfigFile(PROJECT_DIRECTORY);
    const { generators = [] } = config;
    if (!generators.length) {
      logger.info("No configured generators found, skipping generation", "generator");
      return;
    }
    const errors = [];
    for (const generator of generators) {
      let plugin = generator[0];
      const pluginConfig = generator[1];
      if (plugin.startsWith("./")) {
        plugin = import_node_path2.default.join(PROJECT_DIRECTORY, plugin);
      }
      if (plugin.includes("<rootDir>")) {
        plugin = plugin.replace("<rootDir>", PROJECT_DIRECTORY);
      }
      try {
        const importedGenerator = await import(plugin);
        const generator2 = getDefaultExport(importedGenerator);
        await generator2({ eventCatalogConfig: {} }, pluginConfig);
      } catch (error) {
        logger.error(`Failed to run generator "${plugin}":`, "generator");
        console.error(error);
        errors.push({ plugin, error });
      }
    }
    await cleanup(PROJECT_DIRECTORY);
    if (errors.length > 0) {
      logger.error(`${errors.length} generator(s) failed:`, "generator");
      for (const { plugin } of errors) {
        logger.error(`  - ${plugin}`, "generator");
      }
    }
  } catch (error) {
    console.error(error);
    await cleanup(PROJECT_DIRECTORY);
  }
};

// src/analytics/analytics.js
var import_os = __toESM(require("os"), 1);
async function raiseEvent(eventData) {
  const url = "https://queue.simpleanalyticscdn.com/events";
  const userAgent = `@eventcatalog/eventcatalog@${VERSION} (${import_os.default.platform()}; ${import_os.default.arch()}; Node/${process.version})`;
  const headers = {
    "Content-Type": "application/json"
  };
  const payload = {
    type: "event",
    hostname: "eventcatalog.dev",
    event: "@eventcatalog/eventcatalog",
    metadata: {
      ...eventData,
      t: `t;${(/* @__PURE__ */ new Date()).toISOString()}`,
      ua: userAgent
    },
    ua: userAgent
  };
  try {
    const response = await fetch(url, {
      method: "POST",
      headers,
      body: JSON.stringify(payload)
    });
    if (!response.ok) {
      throw new Error(`Failed to raise analytics event: ${response.status}`);
    }
  } catch (error) {
  }
}

// src/analytics/count-resources.js
var import_glob = require("glob");
var RESOURCE_PATTERNS = {
  adrs: ["**/adrs/*/index.@(md|mdx)"],
  agents: ["**/agents/*/index.@(md|mdx)"],
  events: ["**/events/*/index.@(md|mdx)"],
  commands: ["**/commands/*/index.@(md|mdx)"],
  queries: ["**/queries/*/index.@(md|mdx)"],
  services: ["**/services/*/index.@(md|mdx)"],
  domains: ["domains/*/index.@(md|mdx)", "domains/*/subdomains/*/index.@(md|mdx)"],
  flows: ["**/flows/*/index.@(md|mdx)"],
  channels: ["**/channels/**/index.@(md|mdx)"],
  entities: ["**/entities/*/index.@(md|mdx)"],
  containers: ["**/containers/**/index.@(md|mdx)"],
  "data-products": ["**/data-products/*/index.@(md|mdx)"],
  teams: ["teams/*.@(md|mdx)"],
  users: ["users/*.@(md|mdx)"],
  designs: ["**/*.ecstudio"],
  diagrams: ["**/diagrams/**/index.@(md|mdx)"],
  ubiquitousLanguages: ["domains/*/ubiquitous-language.@(md|mdx)", "domains/*/subdomains/*/ubiquitous-language.@(md|mdx)"]
};
async function countResources(projectDir) {
  const counts = {};
  for (const [type, patterns] of Object.entries(RESOURCE_PATTERNS)) {
    let total = 0;
    for (const pattern of patterns) {
      const files = await (0, import_glob.glob)(pattern, {
        cwd: projectDir,
        ignore: ["**/versioned/**", "**/dist/**", "**/node_modules/**"]
      });
      total += files.length;
    }
    counts[type] = total;
  }
  return counts;
}
function serializeCounts(counts) {
  return Object.entries(counts).map(([k, v]) => `${k}:${v}`).join(",");
}

// src/analytics/log-build.js
var getFeatures = async (configFile) => {
  return {
    llmsTxt: configFile.llmsTxt?.enabled || false,
    rss: configFile.rss?.enabled || false,
    chat: configFile.chat?.enabled || false,
    changelog: configFile.changelog?.enabled || false,
    auth: configFile.auth?.enabled || false,
    environments: Array.isArray(configFile.environments) && configFile.environments.length > 0,
    output: configFile.output || "static"
  };
};
var getDirectoryProvider = (source) => {
  if (!source?.name || typeof source.name !== "string") return "unknown";
  return source.name.split(":")[0] || "unknown";
};
var serializeDirectorySources = (configFile) => {
  const sources = configFile.directory?.sources;
  if (!Array.isArray(sources) || sources.length === 0) return "none";
  const providerCounts = sources.reduce((counts, source) => {
    const provider = getDirectoryProvider(source);
    counts[provider] = (counts[provider] || 0) + 1;
    return counts;
  }, {});
  const providers = Object.keys(providerCounts).sort().map((provider) => `${provider}:${providerCounts[provider]}`).join(",");
  const hasUsers = sources.some((source) => typeof source?.loadUsers === "function");
  const hasTeams = sources.some((source) => typeof source?.loadTeams === "function");
  return `sources:${sources.length},providers:${providers},users:${hasUsers},teams:${hasTeams}`;
};
var CLOUD_ANALYTICS_ENDPOINT = "https://api.ecingest.dev/v1/analytics/ingest";
var toCloudResourceCounts = (counts) => ({
  adrs: counts.adrs || 0,
  agents: counts.agents || 0,
  domains: counts.domains || 0,
  services: counts.services || 0,
  events: counts.events || 0,
  commands: counts.commands || 0,
  queries: counts.queries || 0,
  flows: counts.flows || 0,
  channels: counts.channels || 0,
  entities: counts.entities || 0,
  containers: counts.containers || 0,
  dataProducts: counts["data-products"] || 0,
  teams: counts.teams || 0,
  users: counts.users || 0,
  designs: counts.designs || 0,
  diagrams: counts.diagrams || 0,
  ubiquitousLanguages: counts.ubiquitousLanguages || 0
});
var reportCloudResourceInventory = async (configFile, resourceCounts) => {
  const analytics = configFile.cloud?.analytics;
  if (!analytics?.enabled || !analytics.trackingId || !analytics.writeKey) return;
  const endpoint = analytics.endpoint || CLOUD_ANALYTICS_ENDPOINT;
  await fetch(endpoint, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-EventCatalog-Analytics-Key": analytics.writeKey
    },
    body: JSON.stringify({
      trackingId: analytics.trackingId,
      event: "catalog.resource_inventory_reported",
      timestamp: (/* @__PURE__ */ new Date()).toISOString(),
      counts: toCloudResourceCounts(resourceCounts)
    })
  });
};
var main = async (projectDir, { isEventCatalogStarterEnabled: isEventCatalogStarterEnabled2, isEventCatalogScaleEnabled: isEventCatalogScaleEnabled2, isBackstagePluginEnabled }) => {
  try {
    await verifyRequiredFieldsAreInCatalogConfigFile(projectDir);
    const configFile = await getEventCatalogConfigFile(projectDir);
    const { cId, organizationName, generators = [] } = configFile;
    let generatorNames = generators.length > 0 ? generators.map((generator) => generator[0]) : ["none"];
    if (isEventCatalogStarterEnabled2) {
      generatorNames.push("@eventcatalog/eventcatalog-starter");
    }
    if (isEventCatalogScaleEnabled2) {
      generatorNames.push("@eventcatalog/eventcatalog-scale");
    }
    if (isBackstagePluginEnabled) {
      generatorNames.push("@eventcatalog/backstage-plugin-eventcatalog");
    }
    const features = await getFeatures(configFile);
    const resourceCounts = await countResources(projectDir);
    await reportCloudResourceInventory(configFile, resourceCounts);
    await raiseEvent({
      command: "build",
      org: organizationName,
      cId,
      generators: generatorNames.toString(),
      features: Object.keys(features).map((feature) => `${feature}:${features[feature]}`).join(","),
      directorySources: serializeDirectorySources(configFile),
      resources: serializeCounts(resourceCounts)
    });
  } catch (error) {
  }
};
var log_build_default = main;

// src/watcher.js
var import_watcher = __toESM(require("@parcel/watcher"), 1);
var import_node_fs2 = __toESM(require("fs"), 1);

// src/map-catalog-to-astro.js
var import_node_path3 = __toESM(require("path"), 1);
var COLLECTION_KEYS = [
  "agents",
  "events",
  "commands",
  "services",
  "domains",
  "flows",
  "pages",
  "changelogs",
  "queries",
  "channels",
  "ubiquitousLanguages",
  "dependencies"
];
function mapCatalogToAstro({ filePath, astroDir, projectDir }) {
  const relativeFilePath = removeBasePath(filePath, projectDir);
  if (isLikeC4Source(relativeFilePath)) {
    return [];
  }
  if (!isCatalogRelated(relativeFilePath)) {
    return [];
  }
  const baseTargetPaths = getBaseTargetPaths(relativeFilePath);
  const relativeTargetPath = getRelativeTargetPath(relativeFilePath);
  return baseTargetPaths.map((base) => import_node_path3.default.join(astroDir, base, relativeTargetPath));
}
function removeBasePath(fullPath, basePath) {
  const relativePath = import_node_path3.default.relative(basePath, fullPath);
  return relativePath.startsWith("..") ? fullPath : relativePath;
}
function isCollectionKey(key) {
  return COLLECTION_KEYS.includes(key);
}
function isLikeC4Source(filePath) {
  return filePath.endsWith(".c4") || filePath.endsWith(".likec4");
}
function isCatalogRelated(filePath) {
  const filePathArr = filePath.split(import_node_path3.default.sep).filter(Boolean);
  if ([
    "eventcatalog.config.js",
    // config file at root
    "eventcatalog.styles.css",
    // custom styles file at root
    "components",
    // custom components
    "snippets",
    // custom snippets
    "public",
    // public assets
    ".env",
    // env file
    ...COLLECTION_KEYS
  ].includes(filePathArr[0])) {
    return true;
  }
  return false;
}
function getBaseTargetPaths(filePath) {
  const filePathArr = filePath.split(import_node_path3.default.sep).filter(Boolean);
  if (isCollectionKey(filePathArr[0])) {
    const hasExtension = (str) => /\.[a-zA-Z0-9]{2,}$/.test(str);
    if (hasExtension(filePath)) {
      return [import_node_path3.default.join("public", "generated")];
    }
    return [import_node_path3.default.join("public", "generated")];
  }
  if (filePathArr[0] == "components") {
    return [import_node_path3.default.join("src", "custom-defined-components")];
  }
  if (filePathArr[0] == "snippets") {
    return [import_node_path3.default.join("src")];
  }
  if (filePathArr[0] == "public") {
    return [import_node_path3.default.join("public")];
  }
  return [import_node_path3.default.join("/")];
}
function getRelativeTargetPath(filePath) {
  const filePathArr = filePath.split(import_node_path3.default.sep).filter(Boolean);
  if (filePathArr[0] == "public" || filePathArr[0] == "components") {
    filePathArr.shift();
  }
  if (filePathArr[0] == "snippets") {
    return import_node_path3.default.join("snippets", ...filePathArr.slice(1));
  }
  const relativePath = [];
  for (let i = filePathArr.length - 1; i >= 0; i--) {
    relativePath.unshift(filePathArr[i]);
    if (isCollectionKey(filePathArr[i]) && filePathArr[i] != "snippets") break;
  }
  return import_node_path3.default.join(...relativePath);
}

// src/watcher.js
var import_rimraf = require("rimraf");
async function watch(projectDirectory, catalogDirectory, callback = void 0) {
  const subscription = await import_watcher.default.subscribe(
    projectDirectory,
    compose(
      /**
       * @param {Error|null} err
       * @param {Event[]} events
       * @returns {unknown}
       */
      (err, events) => {
        if (err) {
          return;
        }
        for (let event of events) {
          const { path: filePath, type } = event;
          if (filePath.endsWith(".lock")) {
            continue;
          }
          if ((filePath.endsWith(".mdx") || filePath.endsWith(".md")) && !filePath.includes("snippets")) {
            continue;
          }
          const astroPaths = mapCatalogToAstro({
            filePath,
            astroDir: catalogDirectory,
            projectDir: projectDirectory
          });
          for (const astroPath of astroPaths) {
            switch (type) {
              case "create":
              case "update": {
                let stat;
                try {
                  stat = import_node_fs2.default.statSync(filePath);
                } catch (err2) {
                  if (err2.code === "ENOENT") break;
                  throw err2;
                }
                if (stat.isDirectory()) {
                  import_node_fs2.default.mkdirSync(astroPath, { recursive: true });
                } else {
                  retryEPERM(import_node_fs2.default.cpSync)(filePath, astroPath);
                }
                break;
              }
              case "delete":
                retryEPERM(import_rimraf.rimrafSync)(astroPath);
                break;
            }
          }
        }
      },
      callback
    ),
    {
      ignore: [`**/${catalogDirectory}/!(${projectDirectory})**`]
    }
  );
  return () => subscription.unsubscribe();
}
function compose(...fns) {
  return function(err, events) {
    fns.filter(Boolean).forEach((fn, i) => {
      try {
        fn(err, events);
      } catch (error) {
        console.error({ error });
        throw error;
      }
    });
  };
}
var MAX_RETRIES = 5;
var DELAY_MS = 100;
function retryEPERM(fn) {
  return (...args) => {
    let retries = 0;
    while (retries < MAX_RETRIES) {
      try {
        return fn(...args);
      } catch (err) {
        if (err.code !== "EPERM") throw err;
        setTimeout(() => {
        }, DELAY_MS);
        retries += 1;
      }
    }
  };
}

// src/catalog-to-astro-content-directory.js
var import_glob2 = require("glob");
var path4 = __toESM(require("path"), 1);
var import_fs = __toESM(require("fs"), 1);
var import_url2 = require("url");
var import_node_os2 = __toESM(require("os"), 1);
var __filename2 = (0, import_url2.fileURLToPath)(importMetaUrl);
var rootPkg = path4.resolve(path4.dirname(__filename2), "../");
var copyFiles = async (source, target) => {
  const files = await (0, import_glob2.glob)(path4.join(source, "**"), {
    nodir: true,
    windowsPathsNoEscape: import_node_os2.default.platform() == "win32",
    ignore: ["node_modules/**", "**/dist/**", "**/teams", "**/users", "**/*.mdx", "**/*.md", "**/package.json", "**/Dockerfile"]
  });
  const snippets = await (0, import_glob2.glob)(path4.join(source, "snippets/**/*.mdx"), {
    nodir: true,
    windowsPathsNoEscape: import_node_os2.default.platform() == "win32"
  });
  if (snippets.length > 0) {
    files.push(...snippets);
  }
  if (import_fs.default.existsSync(path4.join(source, ".env"))) {
    files.push(path4.join(source, ".env"));
  }
  for (const file of files) {
    mapCatalogToAstro({
      filePath: file,
      astroDir: target,
      projectDir: source
    }).map((astroPath) => {
      import_fs.default.cpSync(file, astroPath);
      return { oldPath: file, newPath: astroPath };
    });
  }
};
var removeGeneratedLikeC4Sources = async (target) => {
  const generatedDir = path4.join(target, "public", "generated");
  const files = await (0, import_glob2.glob)(path4.join(generatedDir, "**/*.{c4,likec4}"), {
    nodir: true,
    windowsPathsNoEscape: import_node_os2.default.platform() == "win32"
  });
  for (const file of files) {
    import_fs.default.rmSync(file);
  }
};
var catalogToAstro = async (source, astroDir) => {
  const astroContentDir = path4.join(astroDir, "src/content/");
  if (import_fs.default.existsSync(astroContentDir)) import_fs.default.rmSync(astroContentDir, { recursive: true });
  import_fs.default.mkdirSync(astroContentDir);
  await verifyRequiredFieldsAreInCatalogConfigFile(source);
  if (!import_fs.default.existsSync(path4.join(source, "eventcatalog.styles.css"))) {
    import_fs.default.writeFileSync(path4.join(source, "eventcatalog.styles.css"), "");
  }
  await removeGeneratedLikeC4Sources(astroDir);
  await copyFiles(source, astroDir);
};

// src/resolve-catalog-dependencies.js
var import_node_path4 = __toESM(require("path"), 1);
var import_node_fs3 = __toESM(require("fs"), 1);
var import_gray_matter2 = __toESM(require("gray-matter"), 1);
var resolve_catalog_dependencies_default = async (catalogDir, core2) => {
  const catalogConfig = await getEventCatalogConfigFile(catalogDir);
  const dependencies = catalogConfig?.dependencies ?? null;
  if (!dependencies) {
    return;
  }
  const dependenciesDir = import_node_path4.default.join(catalogDir, "dependencies");
  if (import_node_fs3.default.existsSync(dependenciesDir)) {
    import_node_fs3.default.rmSync(dependenciesDir, { recursive: true, force: true });
  }
  import_node_fs3.default.mkdirSync(dependenciesDir, { recursive: true });
  const resourceTypes = Object.keys(dependencies);
  for (const resourceType of resourceTypes) {
    for (const dependency of dependencies[resourceType]) {
      const frontmatter = {
        id: dependency.id,
        name: dependency.id,
        version: dependency.version || "1.0.0"
      };
      const markdown = import_gray_matter2.default.stringify(
        {
          content: [
            ":::warning",
            "You are running EventCatalog with dependencies enabled.",
            "This resource is mocked and is a dependency. This means that the resource is managed and owned by another catalog.",
            ":::"
          ].join("\n\n")
        },
        frontmatter
      );
      const resourceFile = import_node_path4.default.join(dependenciesDir, resourceType, dependency.id, `index.md`);
      import_node_fs3.default.mkdirSync(import_node_path4.default.dirname(resourceFile), { recursive: true });
      import_node_fs3.default.writeFileSync(resourceFile, markdown);
    }
  }
  return;
};

// src/eventcatalog.ts
var import_boxen = __toESM(require("boxen"), 1);

// src/features.ts
var import_node_path5 = require("path");
var import_node_fs4 = __toESM(require("fs"), 1);
var getProjectOutDir = async () => {
  const config = await getEventCatalogConfigFile(process.env.PROJECT_DIR || "");
  return config?.outDir || "dist";
};
var isOutputServer = async () => {
  const config = await getEventCatalogConfigFile(process.env.PROJECT_DIR || "");
  return config?.output === "server";
};
var isIndexedSearchEnabled = async () => {
  const config = await getEventCatalogConfigFile(process.env.PROJECT_DIR || "");
  return config?.search?.type === "indexed";
};
var isAuthEnabled = async () => {
  const directory = process.env.PROJECT_DIR || process.cwd();
  const hasAuthConfig = import_node_fs4.default.existsSync((0, import_node_path5.join)(directory, "eventcatalog.auth.js"));
  return hasAuthConfig;
};

// src/eventcatalog.ts
var import_update_notifier = __toESM(require("update-notifier"), 1);
var import_dotenv = __toESM(require("dotenv"), 1);

// src/migrations/message-channels-to-service-channels.ts
var import_node_fs5 = __toESM(require("fs"), 1);
var import_glob3 = require("glob");
var import_node_os3 = __toESM(require("os"), 1);
var import_gray_matter3 = __toESM(require("gray-matter"), 1);
var import_node_path6 = __toESM(require("path"), 1);
var DISABLE_CHANNEL_MIGRATION_ENV = "EVENTCATALOG_DISABLE_CHANNEL_MIGRATION";
var isChannelMigrationDisabled = () => {
  return ["true", "1", "yes"].includes((process.env[DISABLE_CHANNEL_MIGRATION_ENV] ?? "").toLowerCase());
};
var message_channels_to_service_channels_default = async (dir2) => {
  if (isChannelMigrationDisabled()) {
    return { status: "skipped", message: `Channel migration disabled by ${DISABLE_CHANNEL_MIGRATION_ENV}` };
  }
  const PROJECT_DIR = import_node_path6.default.join(dir2 || process.env.PROJECT_DIR);
  const messages = await (0, import_glob3.glob)(
    [
      "**/events/*/index.mdx",
      "**/events/*/index.md",
      "**/events/*/versioned/*/index.mdx",
      "**/events/*/versioned/*/index.md",
      // commands
      "**/commands/*/index.mdx",
      "**/commands/*/index.md",
      "**/commands/*/versioned/*/index.mdx",
      "**/commands/*/versioned/*/index.md",
      // queries
      "**/queries/*/index.mdx",
      "**/queries/*/index.md",
      "**/queries/*/versioned/*/index.mdx",
      "**/queries/*/versioned/*/index.md"
    ],
    {
      // const events = await glob(['**/events/*/index.(md|mdx)', '**/events/*/versioned/*/index.(md|mdx)'], {
      cwd: PROJECT_DIR,
      absolute: true,
      nodir: true,
      windowsPathsNoEscape: import_node_os3.default.platform() == "win32",
      ignore: ["node_modules/**", "**/dist/**", "**/teams", "**/users", "**/package.json", "**/Dockerfile"]
    }
  );
  const services = await (0, import_glob3.glob)(
    [
      "**/services/*/index.mdx",
      "**/services/*/index.md",
      "**/services/*/versioned/*/index.mdx",
      "**/services/*/versioned/*/index.md"
    ],
    {
      cwd: PROJECT_DIR,
      absolute: true
    }
  );
  const messagesWithChannels = messages.reduce((acc, message) => {
    const file = import_node_fs5.default.readFileSync(message, "utf8");
    const { data } = (0, import_gray_matter3.default)(file);
    if (data.channels?.length > 0) {
      acc.push({
        ...data,
        path: message
      });
    }
    return acc;
  }, []);
  if (messagesWithChannels.length === 0) {
    return { status: "success", message: "No messages with channels found in the catalog" };
  }
  const servicesWithChannels = services.reduce((acc, service) => {
    const file = import_node_fs5.default.readFileSync(service, "utf8");
    const { data } = (0, import_gray_matter3.default)(file);
    const isSending = data.sends?.some((send) => messagesWithChannels.some((message) => message.id === send.id));
    const isReceiving = data.receives?.some(
      (receive) => messagesWithChannels.some((message) => message.id === receive.id)
    );
    if (isSending || isReceiving) {
      acc.push({
        ...data,
        path: service
      });
    }
    return acc;
  }, []);
  for (const service of servicesWithChannels) {
    const file = import_node_fs5.default.readFileSync(service.path, "utf8");
    const { data } = (0, import_gray_matter3.default)(file);
    const messagesTheServiceSendsThatNeedUpdating = data.sends?.filter((send) => messagesWithChannels.some((message) => message.id === send.id)) ?? [];
    const messagesTheServiceReceivesThatNeedUpdating = data.receives?.filter((receive) => messagesWithChannels.some((message) => message.id === receive.id)) ?? [];
    if (messagesTheServiceSendsThatNeedUpdating.length > 0 || messagesTheServiceReceivesThatNeedUpdating.length > 0) {
      const newSends = (data.sends ?? []).map((send) => {
        const match = messagesWithChannels.find((message) => message.id === send.id);
        if (!match) return send;
        return { ...send, to: (match.channels ?? []).filter((channel) => channel !== null) };
      });
      const newReceives = (data.receives ?? []).map((receive) => {
        const match = messagesWithChannels.find((message) => message.id === receive.id);
        if (!match) return receive;
        return { ...receive, from: (match.channels ?? []).filter((channel) => channel !== null) };
      });
      const newData = {
        ...data,
        ...newSends.length > 0 ? { sends: newSends } : {},
        ...newReceives.length > 0 ? { receives: newReceives } : {}
      };
      import_node_fs5.default.writeFileSync(service.path, import_gray_matter3.default.stringify(file, newData));
    }
  }
  for (const message of messagesWithChannels) {
    const file = import_node_fs5.default.readFileSync(message.path, "utf8");
    const parsed = (0, import_gray_matter3.default)(file);
    const { channels, ...newData } = parsed.data;
    import_node_fs5.default.writeFileSync(message.path, import_gray_matter3.default.stringify(parsed.content, newData));
  }
  console.log("\u2714 Channels migrated to new services API");
};

// src/migrations/index.ts
var runMigrations = async (dir2) => {
  await message_channels_to_service_channels_default(dir2);
};

// eventcatalog/src/enterprise/fields/field-indexer.ts
var import_node_path7 = __toESM(require("path"), 1);
var import_node_fs7 = __toESM(require("fs"), 1);

// eventcatalog/src/enterprise/fields/fields-db.ts
var import_sql = __toESM(require("sql.js"), 1);
var import_node_fs6 = __toESM(require("fs"), 1);
var SCHEMA_SQL = `
  CREATE TABLE IF NOT EXISTS fields (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    path TEXT NOT NULL,
    type TEXT NOT NULL,
    description TEXT NOT NULL DEFAULT '',
    required INTEGER NOT NULL DEFAULT 0,
    schema_format TEXT NOT NULL,
    message_id TEXT NOT NULL,
    message_version TEXT NOT NULL,
    message_type TEXT NOT NULL,
    message_name TEXT NOT NULL DEFAULT '',
    message_summary TEXT NOT NULL DEFAULT '',
    message_owners TEXT NOT NULL DEFAULT '[]'
  );

  CREATE TABLE IF NOT EXISTS message_producers (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    message_id TEXT NOT NULL,
    message_version TEXT NOT NULL,
    service_id TEXT NOT NULL,
    service_version TEXT NOT NULL,
    service_name TEXT NOT NULL DEFAULT '',
    service_summary TEXT NOT NULL DEFAULT '',
    service_owners TEXT NOT NULL DEFAULT '[]'
  );

  CREATE TABLE IF NOT EXISTS message_consumers (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    message_id TEXT NOT NULL,
    message_version TEXT NOT NULL,
    service_id TEXT NOT NULL,
    service_version TEXT NOT NULL,
    service_name TEXT NOT NULL DEFAULT '',
    service_summary TEXT NOT NULL DEFAULT '',
    service_owners TEXT NOT NULL DEFAULT '[]'
  );

  CREATE INDEX IF NOT EXISTS idx_fields_path ON fields(path);
  CREATE INDEX IF NOT EXISTS idx_fields_message ON fields(message_id, message_version);
  CREATE INDEX IF NOT EXISTS idx_producers_message ON message_producers(message_id, message_version);
  CREATE INDEX IF NOT EXISTS idx_consumers_message ON message_consumers(message_id, message_version);
`;
function queryAll(db, sql, params = []) {
  const stmt = db.prepare(sql);
  stmt.bind(params);
  const rows = [];
  while (stmt.step()) {
    rows.push(stmt.getAsObject());
  }
  stmt.free();
  return rows;
}
function queryOne(db, sql, params = []) {
  const stmt = db.prepare(sql);
  stmt.bind(params);
  const result = stmt.step() ? stmt.getAsObject() : null;
  stmt.free();
  return result;
}
var FieldsDatabase = class _FieldsDatabase {
  db;
  dbPath;
  constructor(db, dbPath) {
    this.db = db;
    this.dbPath = dbPath;
  }
  static async create(dbPath, options) {
    if (options?.recreate && import_node_fs6.default.existsSync(dbPath)) {
      import_node_fs6.default.unlinkSync(dbPath);
    }
    const SQL = await (0, import_sql.default)();
    let db;
    if (!options?.recreate && import_node_fs6.default.existsSync(dbPath)) {
      const buffer = import_node_fs6.default.readFileSync(dbPath);
      db = new SQL.Database(buffer);
    } else {
      db = new SQL.Database();
    }
    db.run(SCHEMA_SQL);
    return new _FieldsDatabase(db, dbPath);
  }
  insertField(field) {
    this.db.run(
      `INSERT INTO fields (path, type, description, required, schema_format, message_id, message_version, message_type, message_name, message_summary, message_owners)
       VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
      [
        field.path,
        field.type,
        field.description,
        field.required ? 1 : 0,
        field.schemaFormat,
        field.messageId,
        field.messageVersion,
        field.messageType,
        field.messageName || "",
        field.messageSummary || "",
        JSON.stringify(field.messageOwners || [])
      ]
    );
  }
  insertProducer(messageId, messageVersion, serviceId, serviceVersion, serviceName, serviceSummary, serviceOwners) {
    this.db.run(
      `INSERT INTO message_producers (message_id, message_version, service_id, service_version, service_name, service_summary, service_owners)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [
        messageId,
        messageVersion,
        serviceId,
        serviceVersion,
        serviceName || "",
        serviceSummary || "",
        JSON.stringify(serviceOwners || [])
      ]
    );
  }
  insertConsumer(messageId, messageVersion, serviceId, serviceVersion, serviceName, serviceSummary, serviceOwners) {
    this.db.run(
      `INSERT INTO message_consumers (message_id, message_version, service_id, service_version, service_name, service_summary, service_owners)
       VALUES (?, ?, ?, ?, ?, ?, ?)`,
      [
        messageId,
        messageVersion,
        serviceId,
        serviceVersion,
        serviceName || "",
        serviceSummary || "",
        JSON.stringify(serviceOwners || [])
      ]
    );
  }
  /** Save the in-memory database to disk */
  save() {
    const data = this.db.export();
    const buffer = Buffer.from(data);
    import_node_fs6.default.writeFileSync(this.dbPath, buffer);
  }
  queryFields(params) {
    const {
      q,
      shared,
      conflicting,
      format,
      type,
      messageType,
      message,
      producer,
      consumer,
      required,
      path: fieldPath,
      pageSize = 50,
      cursor
    } = params;
    const conditions = [];
    const bindings = [];
    if (fieldPath) {
      conditions.push(`f.path = ?`);
      bindings.push(fieldPath);
    }
    if (q) {
      conditions.push(`(f.path LIKE ? ESCAPE '\\' OR f.description LIKE ? ESCAPE '\\' OR f.type LIKE ? ESCAPE '\\')`);
      const escaped = q.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
      const term = `%${escaped}%`;
      bindings.push(term, term, term);
    }
    if (format) {
      const formats2 = format.split(",").map((f) => f.trim()).filter(Boolean);
      conditions.push(`f.schema_format IN (${formats2.map(() => "?").join(", ")})`);
      bindings.push(...formats2);
    }
    if (type) {
      conditions.push(`f.type = ?`);
      bindings.push(type);
    }
    if (messageType) {
      const types2 = messageType.split(",").map((t) => t.trim()).filter(Boolean);
      conditions.push(`f.message_type IN (${types2.map(() => "?").join(", ")})`);
      bindings.push(...types2);
    }
    if (message) {
      conditions.push(`f.message_id = ?`);
      bindings.push(message);
    }
    if (required) {
      conditions.push(`f.required = 1`);
    }
    if (producer) {
      conditions.push(
        `EXISTS (SELECT 1 FROM message_producers p WHERE p.message_id = f.message_id AND p.message_version = f.message_version AND p.service_id = ?)`
      );
      bindings.push(producer);
    }
    if (consumer) {
      conditions.push(
        `EXISTS (SELECT 1 FROM message_consumers c WHERE c.message_id = f.message_id AND c.message_version = f.message_version AND c.service_id = ?)`
      );
      bindings.push(consumer);
    }
    if (shared) {
      const sharedSubquery = `SELECT path FROM fields GROUP BY path HAVING COUNT(DISTINCT message_id || '/' || message_version) > 1`;
      conditions.push(`f.path IN (${sharedSubquery})`);
    }
    if (conflicting) {
      const conflictSubquery = `SELECT path FROM fields GROUP BY path HAVING COUNT(DISTINCT type) > 1`;
      conditions.push(`f.path IN (${conflictSubquery})`);
    }
    const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
    const cursorConditions = [];
    const cursorBindings = [];
    if (cursor) {
      const lastId = decodeCursor(cursor);
      cursorConditions.push(`f.id > ?`);
      cursorBindings.push(lastId);
    }
    const paginationWhere = cursorConditions.length > 0 ? whereClause ? `${whereClause} AND ${cursorConditions.join(" AND ")}` : `WHERE ${cursorConditions.join(" AND ")}` : whereClause;
    const countSql = `SELECT COUNT(*) as cnt FROM fields f ${whereClause}`;
    const total = queryOne(this.db, countSql, bindings).cnt;
    const mainSql = `SELECT f.* FROM fields f ${paginationWhere} ORDER BY f.id ASC LIMIT ?`;
    const allBindings = [...bindings, ...cursorBindings, pageSize];
    const rows = queryAll(this.db, mainSql, allBindings);
    const parseOwners = (raw) => {
      try {
        return JSON.parse(raw || "[]");
      } catch {
        return [];
      }
    };
    const fields = rows.map((row) => {
      const producers = queryAll(
        this.db,
        `SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_producers WHERE message_id = ? AND message_version = ?`,
        [row.message_id, row.message_version]
      );
      const consumers = queryAll(
        this.db,
        `SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_consumers WHERE message_id = ? AND message_version = ?`,
        [row.message_id, row.message_version]
      );
      const usedInCount = queryOne(this.db, `SELECT COUNT(DISTINCT message_id || '/' || message_version) as cnt FROM fields WHERE path = ?`, [
        row.path
      ]).cnt;
      const typeRows = queryAll(
        this.db,
        `SELECT type, COUNT(DISTINCT message_id || '/' || message_version) as count FROM fields WHERE path = ? GROUP BY type`,
        [row.path]
      );
      const conflicts = typeRows.length > 1 ? typeRows.map((r) => ({ type: r.type, count: r.count })) : void 0;
      return {
        id: row.id,
        path: row.path,
        type: row.type,
        description: row.description,
        required: row.required === 1,
        schemaFormat: row.schema_format,
        messageId: row.message_id,
        messageVersion: row.message_version,
        messageType: row.message_type,
        messageName: row.message_name || row.message_id,
        messageSummary: row.message_summary || "",
        messageOwners: parseOwners(row.message_owners),
        usedInCount,
        conflicts,
        producers: producers.map((p) => ({
          id: p.service_id,
          version: p.service_version,
          name: p.service_name || p.service_id,
          summary: p.service_summary || "",
          owners: parseOwners(p.service_owners)
        })),
        consumers: consumers.map((c) => ({
          id: c.service_id,
          version: c.service_version,
          name: c.service_name || c.service_id,
          summary: c.service_summary || "",
          owners: parseOwners(c.service_owners)
        }))
      };
    });
    const formatsFacetSql = `SELECT f.schema_format as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.schema_format`;
    const formats = queryAll(this.db, formatsFacetSql, bindings);
    const typesFacetSql = `SELECT f.type as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.type`;
    const types = queryAll(this.db, typesFacetSql, bindings);
    const messageTypesFacetSql = `SELECT f.message_type as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.message_type`;
    const messageTypes = queryAll(this.db, messageTypesFacetSql, bindings);
    const lastRow = rows[rows.length - 1];
    const nextCursor = lastRow && rows.length === pageSize ? encodeCursor(lastRow.id) : void 0;
    return {
      fields,
      total,
      cursor: nextCursor,
      facets: { formats, types, messageTypes }
    };
  }
  close() {
    this.db.close();
  }
};
function encodeCursor(id) {
  return Buffer.from(String(id)).toString("base64url");
}
function decodeCursor(cursor) {
  return parseInt(Buffer.from(cursor, "base64url").toString(), 10);
}

// eventcatalog/src/enterprise/fields/field-extractor.ts
function extractSchemaFieldsDeep(content, format) {
  if (!content) return [];
  if (format === "json-schema") {
    return extractJsonSchemaFields(content);
  }
  if (format === "avro") {
    return extractAvroFields(content);
  }
  if (format === "proto") {
    return extractProtoFields(content);
  }
  return [];
}
function extractProtoFields(content) {
  if (!content) return [];
  const fields = [];
  const fieldRegex = /^\s*(repeated\s+|optional\s+|required\s+)?(\w+)\s+(\w+)\s*=\s*\d+\s*;(?:\s*\/\/\s*(.*))?/gm;
  let match;
  while ((match = fieldRegex.exec(content)) !== null) {
    const modifier = (match[1] || "").trim();
    const type = modifier ? `${modifier} ${match[2]}` : match[2];
    fields.push({
      path: match[3],
      type,
      description: match[4]?.trim() || "",
      required: modifier === "required"
    });
  }
  return fields;
}
function extractAvroFields(content) {
  try {
    const schema = JSON.parse(content);
    const fields = [];
    walkAvroRecord(schema, "", fields);
    return fields;
  } catch {
    return [];
  }
}
function getAvroTypeName(type) {
  if (typeof type === "string") return type;
  if (Array.isArray(type)) {
    return type.map((t) => typeof t === "string" ? t : t.type || "complex").join(" | ");
  }
  if (typeof type === "object" && type !== null) {
    if (type.type === "array" && type.items) return `array<${getAvroTypeName(type.items)}>`;
    if (type.type === "record") return type.name || "record";
    return type.type || "complex";
  }
  return "unknown";
}
function walkAvroRecord(schema, prefix, fields) {
  if (!schema.fields || !Array.isArray(schema.fields)) return;
  for (const field of schema.fields) {
    const path11 = prefix ? `${prefix}.${field.name}` : field.name;
    const isOptional = Array.isArray(field.type) && field.type.includes("null");
    const typeName = getAvroTypeName(field.type);
    fields.push({
      path: path11,
      type: typeName,
      description: field.doc || "",
      required: !isOptional
    });
    const innerType = Array.isArray(field.type) ? field.type.find((t) => typeof t === "object" && t.type === "record") : typeof field.type === "object" && field.type.type === "record" ? field.type : null;
    if (innerType) {
      walkAvroRecord(innerType, path11, fields);
    }
    const arrayType = Array.isArray(field.type) ? field.type.find((t) => typeof t === "object" && t.type === "array") : typeof field.type === "object" && field.type.type === "array" ? field.type : null;
    if (arrayType && typeof arrayType.items === "object" && arrayType.items.type === "record") {
      walkAvroRecord(arrayType.items, `${path11}[]`, fields);
    }
  }
}
function extractJsonSchemaFields(content) {
  try {
    const schema = JSON.parse(content);
    const fields = [];
    walkJsonSchema(schema, "", schema.required || [], schema, fields);
    return fields;
  } catch {
    return [];
  }
}
function walkJsonSchema(node, prefix, requiredList, rootSchema, fields) {
  if (node.allOf && Array.isArray(node.allOf)) {
    const merged = { type: "object", properties: {}, required: [] };
    for (let sub of node.allOf) {
      if (sub.$ref) {
        const resolved = resolveLocalRef(sub.$ref, rootSchema);
        if (resolved) sub = resolved;
        else continue;
      }
      Object.assign(merged.properties, sub.properties || {});
      merged.required.push(...sub.required || []);
    }
    walkJsonSchema(merged, prefix, merged.required, rootSchema, fields);
    return;
  }
  if (!node.properties) return;
  for (const [name, prop] of Object.entries(node.properties)) {
    const path11 = prefix ? `${prefix}.${name}` : name;
    const isRequired = requiredList.includes(name);
    if (prop.$ref) {
      const resolved = resolveLocalRef(prop.$ref, rootSchema);
      if (resolved) {
        const rawRefType = resolved.type || "object";
        const type2 = Array.isArray(rawRefType) ? [...rawRefType].sort().join(" | ") : rawRefType;
        fields.push({ path: path11, type: type2, description: resolved.description || "", required: isRequired });
        if (resolved.properties) {
          walkJsonSchema(resolved, path11, resolved.required || [], rootSchema, fields);
        }
      } else {
        fields.push({ path: path11, type: "$ref", description: "", required: isRequired });
      }
      continue;
    }
    const rawType = prop.type || (prop.enum ? "enum" : prop.$ref ? "$ref" : "object");
    const typeList = Array.isArray(rawType) ? rawType : [rawType];
    const type = Array.isArray(rawType) ? [...rawType].sort().join(" | ") : rawType;
    fields.push({ path: path11, type, description: prop.description || "", required: isRequired });
    if (typeList.includes("object") && prop.properties) {
      walkJsonSchema(prop, path11, prop.required || [], rootSchema, fields);
    }
    if (typeList.includes("array") && prop.items) {
      if (prop.items.type === "object" && prop.items.properties) {
        walkJsonSchema(prop.items, `${path11}[]`, prop.items.required || [], rootSchema, fields);
      }
    }
  }
}
function resolveLocalRef(ref, rootSchema) {
  if (!ref.startsWith("#/")) return null;
  const parts = ref.replace("#/", "").split("/");
  let current = rootSchema;
  for (const part of parts) {
    current = current?.[part];
    if (!current) return null;
  }
  return current;
}

// eventcatalog/src/enterprise/fields/field-indexer.ts
function detectFormat(fileName) {
  const ext = import_node_path7.default.extname(fileName).toLowerCase();
  if (ext === ".proto") return "proto";
  if (ext === ".avro" || ext === ".avsc") return "avro";
  return "json-schema";
}
async function buildFieldsIndex(catalogDir, outputDir) {
  const sdkModule = await import("@eventcatalog/sdk");
  const sdk = sdkModule.default(catalogDir);
  const dbDir = import_node_path7.default.join(outputDir || catalogDir, ".eventcatalog");
  const dbPath = import_node_path7.default.join(dbDir, "fields.db");
  if (!import_node_fs7.default.existsSync(dbDir)) {
    import_node_fs7.default.mkdirSync(dbDir, { recursive: true });
  }
  const db = await FieldsDatabase.create(dbPath, { recreate: true });
  const warnings = [];
  try {
    const [events, commands, queries] = await Promise.all([
      sdk.getEvents({ latestOnly: true }),
      sdk.getCommands({ latestOnly: true }),
      sdk.getQueries({ latestOnly: true })
    ]);
    const collections = [
      { entries: events || [], type: "event" },
      { entries: commands || [], type: "command" },
      { entries: queries || [], type: "query" }
    ];
    for (const { entries, type } of collections) {
      for (const entry of entries) {
        const msgId = entry.id;
        const msgVersion = entry.version;
        let schemaData;
        try {
          schemaData = await sdk.getSchemaForMessage(msgId, msgVersion);
        } catch {
          continue;
        }
        if (!schemaData) continue;
        const { schema: content, fileName } = schemaData;
        const format = detectFormat(fileName);
        try {
          const fields = extractSchemaFieldsDeep(content, format);
          for (const field of fields) {
            db.insertField({
              path: field.path,
              type: field.type,
              description: field.description,
              required: field.required,
              schemaFormat: format,
              messageId: msgId,
              messageVersion: msgVersion,
              messageType: type,
              messageName: entry.name || msgId,
              messageSummary: entry.summary || "",
              messageOwners: entry.owners || []
            });
          }
          const { producers, consumers } = await sdk.getProducersAndConsumersForMessage(msgId, msgVersion);
          for (const producer of producers) {
            db.insertProducer(
              msgId,
              msgVersion,
              producer.id,
              producer.version,
              producer.name || producer.id,
              producer.summary || "",
              producer.owners || []
            );
          }
          for (const consumer of consumers) {
            db.insertConsumer(
              msgId,
              msgVersion,
              consumer.id,
              consumer.version,
              consumer.name || consumer.id,
              consumer.summary || "",
              consumer.owners || []
            );
          }
        } catch (err) {
          warnings.push({ messageId: msgId, version: msgVersion, error: err.message });
        }
      }
    }
    db.save();
    db.close();
    return { dbPath, warnings };
  } catch (err) {
    db.close();
    throw err;
  }
}

// src/search-indexer.ts
var import_promises2 = __toESM(require("fs/promises"), 1);
var import_node_path8 = __toESM(require("path"), 1);
var import_glob4 = require("glob");
var import_gray_matter4 = __toESM(require("gray-matter"), 1);
var RESOURCE_COLLECTIONS = {
  adrs: { docsPath: "adrs", type: "Architecture Decision" },
  agents: { docsPath: "agents", type: "Agent" },
  channels: { docsPath: "channels", type: "Channel" },
  commands: { docsPath: "commands", type: "Command" },
  containers: { docsPath: "containers", type: "Container" },
  "data-products": { docsPath: "data-products", type: "Data Product" },
  domains: { docsPath: "domains", type: "Domain" },
  entities: { docsPath: "entities", type: "Entity" },
  events: { docsPath: "events", type: "Event" },
  flows: { docsPath: "flows", type: "Flow" },
  queries: { docsPath: "queries", type: "Query" },
  services: { docsPath: "services", type: "Service" },
  subdomains: { docsPath: "domains", type: "Domain" }
};
var IGNORED_GLOBS = [
  "**/.git/**",
  "**/.eventcatalog-core/**",
  "**/dist/**",
  "**/node_modules/**",
  "**/public/**",
  "**/snippets/**",
  "**/chat-prompts/**"
];
var trimSlashes = (value) => value.replace(/^\/+|\/+$/g, "");
var normalizePath = (value) => value.replace(/\\/g, "/");
var removeExtension = (value) => value.replace(/\.(md|mdx)$/i, "");
var stripNumericPrefix = (value) => value.replace(/^\d+(?:[-_.\s]+)?/, "") || value;
var normalizeUrlPath = (value) => {
  const withoutIndex = value.replace(/\/index$/i, "");
  return withoutIndex || "";
};
var buildUrl = (pathname, config) => {
  const base = config.base ? `/${trimSlashes(config.base)}` : "";
  const cleanPath = `/${trimSlashes(pathname)}`;
  const url = `${base}${cleanPath}`.replace(/\/{2,}/g, "/");
  if (config.trailingSlash === true && !url.endsWith("/")) {
    return `${url}/`;
  }
  return url || "/";
};
var valueToSearchText = (value) => {
  if (value === null || value === void 0) return "";
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
  if (Array.isArray(value)) return value.map(valueToSearchText).filter(Boolean).join(" ");
  if (typeof value === "object") return Object.values(value).map(valueToSearchText).filter(Boolean).join(" ");
  return "";
};
var markdownToSearchText = (content) => {
  return content.replace(/<!--[\s\S]*?-->/g, " ").replace(/^\s*import\s+.*$/gm, " ").replace(/^\s*export\s+.*$/gm, " ").replace(/```[\s\S]*?```/g, (match) => match.replace(/```[a-zA-Z0-9-]*\n?/g, " ").replace(/```/g, " ")).replace(/<([A-Z][A-Za-z0-9.]*)\b([^>]*)\/?>/g, (_match, _component, attributes) => {
    const quotedValues = [...String(attributes).matchAll(/(?:title|label|description|alt|summary)=["'`]([^"'`]+)["'`]/g)];
    return quotedValues.map((entry) => entry[1]).join(" ");
  }).replace(/<\/?[A-Za-z][^>]*>/g, " ").replace(/\[\[([^|\]]+)\|([^\]]+)\]\]/g, "$2").replace(/\[([^\]]+)\]\([^)]+\)/g, "$1").replace(/[`*_~>#|{}[\]():]/g, " ").replace(/\s+/g, " ").trim();
};
var inferDocIdFromFile = (relativePath, frontmatterId) => {
  if (frontmatterId) return frontmatterId;
  const fileName = import_node_path8.default.posix.basename(removeExtension(relativePath));
  if (fileName.toLowerCase() === "index") {
    return import_node_path8.default.posix.basename(import_node_path8.default.posix.dirname(relativePath));
  }
  return stripNumericPrefix(fileName);
};
var findResourceSegment = (segments) => {
  let match = null;
  for (let index = 0; index < segments.length - 1; index++) {
    const segment = segments[index];
    if (segments[index - 1] === "docs") {
      continue;
    }
    if (RESOURCE_COLLECTIONS[segment] && segments[index + 1]) {
      match = { index, segment };
    }
  }
  return match;
};
var readResourceFrontmatter = async (projectDir, resourcePath) => {
  const candidates = [import_node_path8.default.join(projectDir, resourcePath, "index.mdx"), import_node_path8.default.join(projectDir, resourcePath, "index.md")];
  for (const candidate of candidates) {
    try {
      const file = await import_promises2.default.readFile(candidate, "utf8");
      return (0, import_gray_matter4.default)(file).data;
    } catch {
    }
  }
  return {};
};
var deriveRecordFromPath = async ({
  projectDir,
  relativePath,
  data,
  config
}) => {
  const normalizedRelativePath = normalizePath(relativePath);
  const segments = normalizedRelativePath.split("/").filter(Boolean);
  const fileName = segments[segments.length - 1] || "";
  const fileNameWithoutExtension = removeExtension(fileName);
  if (data.hidden === true || data.draft) {
    return null;
  }
  if (segments[0] === "docs") {
    const customPath = normalizeUrlPath(removeExtension(segments.slice(1).join("/")));
    const title = data.title || data.label || import_node_path8.default.posix.basename(customPath) || "Custom docs";
    return {
      url: buildUrl(`/docs/custom/${customPath}`, config),
      title,
      summary: data.summary,
      type: "Custom Doc",
      collection: "custom-docs",
      id: customPath
    };
  }
  if (segments[0] === "users" || segments[0] === "teams") {
    const id = data.id || (fileNameWithoutExtension === "index" ? segments[1] : fileNameWithoutExtension);
    const type = segments[0] === "users" ? "User" : "Team";
    return {
      url: buildUrl(`/docs/${segments[0]}/${id}`, config),
      title: data.name || data.title || id,
      summary: data.summary,
      type,
      collection: segments[0],
      id
    };
  }
  const resourceMatch = findResourceSegment(segments);
  if (!resourceMatch) {
    return null;
  }
  const resourceConfig = RESOURCE_COLLECTIONS[resourceMatch.segment];
  const resourceFolderId = segments[resourceMatch.index + 1];
  const resourcePathSegments = segments.slice(0, resourceMatch.index + 2);
  const versionFromPath = segments[resourceMatch.index + 2] === "versioned" && segments[resourceMatch.index + 3] ? segments[resourceMatch.index + 3] : void 0;
  if (versionFromPath) {
    resourcePathSegments.push("versioned", versionFromPath);
  }
  const resourcePath = resourcePathSegments.join("/");
  const resourceData = fileNameWithoutExtension === "index" ? data : await readResourceFrontmatter(projectDir, resourcePath);
  const resourceId = resourceData.id || data.resourceId || resourceFolderId;
  const resourceVersion = versionFromPath || resourceData.version || data.resourceVersion || data.version;
  if (!resourceVersion) {
    return null;
  }
  if (fileNameWithoutExtension === "index") {
    return {
      url: buildUrl(`/docs/${resourceConfig.docsPath}/${resourceId}/${resourceVersion}`, config),
      title: data.name || data.title || resourceId,
      summary: data.summary,
      type: resourceConfig.type,
      collection: resourceConfig.docsPath,
      id: resourceId,
      version: resourceVersion
    };
  }
  if (fileNameWithoutExtension === "ubiquitous-language") {
    return {
      url: buildUrl(`/docs/${resourceConfig.docsPath}/${resourceId}/language`, config),
      title: data.title || `${resourceData.name || resourceId} ubiquitous language`,
      summary: data.summary,
      type: "Language",
      collection: "language",
      id: resourceId,
      version: resourceVersion
    };
  }
  if (fileNameWithoutExtension === "changelog") {
    return {
      url: buildUrl(`/docs/${resourceConfig.docsPath}/${resourceId}/${resourceVersion}/changelog`, config),
      title: data.title || `${resourceData.name || resourceId} changelog`,
      summary: data.summary,
      type: "Changelog",
      collection: "changelog",
      id: resourceId,
      version: resourceVersion
    };
  }
  const docsIndex = segments.indexOf("docs");
  if (docsIndex > resourceMatch.index) {
    const docType = data.type || segments[docsIndex + 1] || "pages";
    const docId = inferDocIdFromFile(normalizedRelativePath, data.id);
    const title = data.title || stripNumericPrefix(removeExtension(fileName));
    return {
      url: buildUrl(`/docs/${resourceConfig.docsPath}/${resourceId}/${resourceVersion}/${docType}/${docId}`, config),
      title,
      summary: data.summary,
      type: "Resource Doc",
      collection: docType,
      id: docId,
      version: data.version || resourceVersion
    };
  }
  if (segments[0] === "diagrams") {
    const id = data.id || resourceFolderId;
    const version2 = data.version || resourceVersion;
    return {
      url: buildUrl(`/diagrams/${id}/${version2}`, config),
      title: data.name || data.title || id,
      summary: data.summary,
      type: "Design",
      collection: "diagrams",
      id,
      version: version2
    };
  }
  return null;
};
var collectSearchRecords = async ({
  projectDir,
  config
}) => {
  const files = await (0, import_glob4.glob)("**/*.{md,mdx}", {
    cwd: projectDir,
    absolute: true,
    nodir: true,
    ignore: IGNORED_GLOBS,
    windowsPathsNoEscape: process.platform === "win32"
  });
  const records = await Promise.all(
    files.map(async (file) => {
      const raw = await import_promises2.default.readFile(file, "utf8");
      const parsed = (0, import_gray_matter4.default)(raw);
      const relativePath = normalizePath(import_node_path8.default.relative(projectDir, file));
      const baseRecord = await deriveRecordFromPath({
        projectDir,
        relativePath,
        data: parsed.data,
        config
      });
      if (!baseRecord) {
        return null;
      }
      const frontmatterText = valueToSearchText({
        id: baseRecord.id,
        title: baseRecord.title,
        summary: baseRecord.summary,
        version: baseRecord.version,
        owners: parsed.data.owners,
        status: parsed.data.status,
        date: parsed.data.date,
        decisionMakers: parsed.data.decisionMakers,
        appliesTo: parsed.data.appliesTo,
        badges: parsed.data.badges
      });
      const content = [frontmatterText, markdownToSearchText(parsed.content)].filter(Boolean).join("\n\n");
      if (!content.trim()) {
        return null;
      }
      return {
        ...baseRecord,
        content
      };
    })
  );
  const uniqueRecords = /* @__PURE__ */ new Map();
  for (const record of records) {
    if (!record) continue;
    uniqueRecords.set(record.url, record);
  }
  return [...uniqueRecords.values()].sort((a, b) => a.url.localeCompare(b.url));
};
var getSearchOutputPath = ({
  outDir,
  isServer,
  searchOutputPath
}) => {
  if (searchOutputPath) {
    return searchOutputPath;
  }
  return import_node_path8.default.join(outDir, isServer ? "client" : "", "pagefind");
};
var buildSearchIndex = async ({ projectDir, outDir, config, isServer, searchOutputPath }) => {
  const records = await collectSearchRecords({ projectDir, config });
  if (records.length === 0) {
    throw new Error("No searchable Markdown or MDX content was found.");
  }
  const pagefind = await import("pagefind");
  const { index } = await pagefind.createIndex({
    keepIndexUrl: false,
    writePlayground: false
  });
  const errors = [];
  for (const record of records) {
    const result = await index.addCustomRecord({
      url: record.url,
      content: record.content,
      language: "en",
      meta: {
        title: record.title,
        summary: record.summary || "",
        type: record.type,
        collection: record.collection,
        id: record.id || "",
        version: record.version || ""
      },
      filters: {
        type: [record.type],
        collection: [record.collection]
      }
    });
    if (result.errors?.length) {
      errors.push(...result.errors.map((error) => `${record.url}: ${error.message || error}`));
    }
  }
  const outputPath = getSearchOutputPath({ outDir, isServer, searchOutputPath });
  await import_promises2.default.rm(outputPath, { recursive: true, force: true });
  const writeResult = await index.writeFiles({ outputPath });
  if (writeResult.errors?.length) {
    errors.push(...writeResult.errors.map((error) => error.message || String(error)));
  }
  await index.deleteIndex?.();
  await pagefind.close?.();
  if (errors.length > 0) {
    throw new Error(`Failed to build indexed search:
${errors.join("\n")}`);
  }
  return {
    records: records.length,
    outputPath
  };
};

// src/core-node-modules.ts
var import_fs2 = __toESM(require("fs"), 1);
var import_node_path9 = __toESM(require("path"), 1);
var isDirectory = (directory) => {
  try {
    return import_fs2.default.statSync(directory).isDirectory();
  } catch (error) {
    return false;
  }
};
var hasAstroDependency = (nodeModulesDirectory) => {
  const astroBin = process.platform === "win32" ? "astro.cmd" : "astro";
  return import_fs2.default.existsSync(import_node_path9.default.join(nodeModulesDirectory, "astro", "package.json")) || import_fs2.default.existsSync(import_node_path9.default.join(nodeModulesDirectory, ".bin", astroBin));
};
var isSymbolicLink = (targetPath) => {
  try {
    return import_fs2.default.lstatSync(targetPath).isSymbolicLink();
  } catch (error) {
    return false;
  }
};
var isSameDirectory = (a, b) => {
  try {
    return import_fs2.default.realpathSync.native(a) === import_fs2.default.realpathSync.native(b);
  } catch (error) {
    return false;
  }
};
var resolveInstalledCoreNodeModules = (currentDir2) => {
  const candidates = [];
  const seen = /* @__PURE__ */ new Set();
  const addCandidate = (candidate) => {
    const resolvedCandidate = import_node_path9.default.resolve(candidate);
    if (!seen.has(resolvedCandidate)) {
      candidates.push(resolvedCandidate);
      seen.add(resolvedCandidate);
    }
  };
  addCandidate(import_node_path9.default.resolve(currentDir2, "..", "node_modules"));
  let directory = import_node_path9.default.resolve(currentDir2);
  while (true) {
    if (import_node_path9.default.basename(directory) === "node_modules") {
      addCandidate(directory);
    }
    addCandidate(import_node_path9.default.join(directory, "node_modules"));
    const parentDirectory = import_node_path9.default.dirname(directory);
    if (parentDirectory === directory) {
      break;
    }
    directory = parentDirectory;
  }
  return candidates.find((candidate) => isDirectory(candidate) && hasAstroDependency(candidate)) ?? candidates.find(isDirectory);
};
var linkCoreNodeModules = ({
  coreNodeModules,
  installedCoreNodeModules
}) => {
  if (!installedCoreNodeModules) return;
  if (isSymbolicLink(coreNodeModules)) {
    if (isSameDirectory(coreNodeModules, installedCoreNodeModules)) {
      return;
    }
    import_fs2.default.unlinkSync(coreNodeModules);
  } else if (import_fs2.default.existsSync(coreNodeModules)) {
    return;
  }
  import_fs2.default.symlinkSync(installedCoreNodeModules, coreNodeModules, process.platform === "win32" ? "junction" : "dir");
};

// src/eventcatalog.ts
var import_license = require("@eventcatalog/license");
var currentDir = import_node_path11.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
var program = new import_commander.Command().version(VERSION);
var dir = import_node_path11.default.resolve(process.env.PROJECT_DIR || process.cwd());
var core = import_node_path11.default.resolve(process.env.CATALOG_DIR || (0, import_node_path10.join)(dir, ".eventcatalog-core"));
var eventCatalogDir = import_node_path11.default.resolve((0, import_node_path10.join)(currentDir, "../eventcatalog/"));
var getInstalledEventCatalogVersion = () => {
  try {
    const pkg = import_fs3.default.readFileSync((0, import_node_path10.join)(dir, "package.json"), "utf8");
    const json = JSON.parse(pkg);
    return json.dependencies["@eventcatalog/core"];
  } catch (error) {
    return null;
  }
};
program.name("eventcatalog").description("Documentation tool for event-driven architectures");
var ensureDir = (dir2) => {
  if (!import_fs3.default.existsSync(dir2)) {
    import_fs3.default.mkdirSync(dir2);
  }
};
var resolveDevPort = async ({ projectDir }) => {
  try {
    const config = await getEventCatalogConfigFile(projectDir);
    const fromConfig = Number(config?.port);
    if (Number.isFinite(fromConfig) && fromConfig > 0) return fromConfig;
  } catch (error) {
  }
  return 3e3;
};
var startDevPrewarm = ({
  port = 3e3,
  paths = ["/ping", "/"],
  retries = 80,
  intervalMs = 250,
  initialDelayMs = 500
}) => {
  let attempt = 0;
  const hit = (requestPath) => new Promise((resolve2) => {
    const req = import_node_http.default.get(
      {
        hostname: "127.0.0.1",
        port,
        path: requestPath,
        timeout: 1200
      },
      (res) => {
        res.resume();
        resolve2(true);
      }
    );
    req.on("error", () => resolve2(false));
    req.on("timeout", () => {
      req.destroy();
      resolve2(false);
    });
  });
  const tick = async () => {
    attempt += 1;
    for (const requestPath of paths) {
      const ok = await hit(requestPath);
      if (ok) {
        return;
      }
    }
    if (attempt < retries) {
      setTimeout(tick, intervalMs);
    }
  };
  setTimeout(tick, initialDelayMs);
};
var createAstroLineFilter = () => {
  return (line) => {
    return line.includes("[glob-loader]") || /The collection.*does not exist/.test(line);
  };
};
var createAstroDevLineFilter = () => {
  const shouldFilterAstroLine = createAstroLineFilter();
  return (line) => {
    return shouldFilterAstroLine(line) || line.includes("[router]");
  };
};
var buildDevSearchIndex = async ({ config }) => {
  const result = await buildSearchIndex({
    projectDir: dir,
    outDir: import_node_path11.default.join(core, "public"),
    searchOutputPath: import_node_path11.default.join(core, "public", "pagefind"),
    config,
    isServer: false
  });
  logger.info(`Indexed ${result.records} page(s) into ${import_node_path11.default.relative(core, result.outputPath)}`, "search");
};
var warnIfIndexedSearchUsesAuth = async () => {
  if (!await isAuthEnabled()) {
    return;
  }
  logger.info(
    "Indexed search creates client-readable search files. Make sure your deployment protects /pagefind assets if your catalog is private.",
    "search"
  );
};
var createDevSearchIndexWatcher = ({ config }) => {
  let timeout;
  let isBuilding = false;
  let queued = false;
  const run = async () => {
    if (isBuilding) {
      queued = true;
      return;
    }
    isBuilding = true;
    try {
      await buildDevSearchIndex({ config });
    } catch (err) {
      logger.info(`Failed to rebuild indexed search: ${err.message}`, "search");
    } finally {
      isBuilding = false;
      if (queued) {
        queued = false;
        run();
      }
    }
  };
  return (_err, events) => {
    if (!events.some((event) => event.path.endsWith(".md") || event.path.endsWith(".mdx"))) {
      return;
    }
    if (timeout) {
      clearTimeout(timeout);
    }
    timeout = setTimeout(run, 500);
  };
};
var replaceAstroReadyVersionLine = (line) => {
  const matches = line.match(/^(\s*)astro(\s+)v\S+(\s+ready.*)$/i);
  if (!matches) {
    return line;
  }
  return `${matches[1]}eventcatalog${matches[2]}v${VERSION}${matches[3]}`;
};
var runCommandWithFilteredOutput = async ({
  command,
  cwd,
  env,
  shouldFilterLine,
  transformLine = (line) => line
}) => {
  await new Promise((resolve2, reject) => {
    const child = (0, import_node_child_process.spawn)(command, {
      cwd,
      env: {
        ...process.env,
        ...env
      },
      shell: true,
      stdio: ["inherit", "pipe", "pipe"]
    });
    let stdoutBuffer = "";
    let stderrBuffer = "";
    const flush = (buffer, writer, isFinal = false) => {
      const lines = buffer.split("\n");
      const remaining = isFinal ? "" : lines.pop() ?? "";
      for (const rawLine of lines) {
        const line = rawLine.replace(/\r/g, "");
        if (line.length === 0) {
          writer.write("\n");
          continue;
        }
        if (!shouldFilterLine(line)) {
          writer.write(`${transformLine(rawLine)}
`);
        }
      }
      return remaining;
    };
    child.stdout.on("data", (chunk) => {
      stdoutBuffer += chunk.toString();
      stdoutBuffer = flush(stdoutBuffer, process.stdout);
    });
    child.stderr.on("data", (chunk) => {
      stderrBuffer += chunk.toString();
      stderrBuffer = flush(stderrBuffer, process.stderr);
    });
    child.on("error", (error) => {
      reject(error);
    });
    child.on("close", (code) => {
      stdoutBuffer = flush(stdoutBuffer, process.stdout, true);
      stderrBuffer = flush(stderrBuffer, process.stderr, true);
      if (code === 0) {
        resolve2();
        return;
      }
      reject(new Error(`Command failed with exit code ${code}: ${command}`));
    });
  });
};
var copyCore = () => {
  ensureDir(core);
  if (eventCatalogDir === core) {
    return;
  }
  import_fs3.default.cpSync(eventCatalogDir, core, {
    recursive: true,
    filter: (src) => {
      const relativePath = import_node_path11.default.relative(eventCatalogDir, src);
      const pathParts = relativePath.split(import_node_path11.default.sep);
      return !pathParts.some((part) => [".astro", "dist", "node_modules"].includes(part));
    }
  });
  const coreNodeModules = import_node_path11.default.join(core, "node_modules");
  const installedCoreNodeModules = resolveInstalledCoreNodeModules(currentDir);
  linkCoreNodeModules({ coreNodeModules, installedCoreNodeModules });
};
var clearCore = () => {
  if (import_fs3.default.existsSync(core)) import_fs3.default.rmSync(core, { recursive: true });
};
var checkForUpdate = () => {
  const installedVersion = getInstalledEventCatalogVersion();
  if (!installedVersion) return;
  const majorVersion = parseInt(installedVersion.replace(/[^0-9.]/g, "").split(".")[0], 10);
  if (majorVersion < 3) {
    const v3Message = `\u{1F680} EventCatalog V3 is now available in beta!

You are currently on version ${installedVersion}.
V3 brings exciting new features and improvements.

Upgrade now: npm i @eventcatalog/core@beta`;
    console.log(
      (0, import_boxen.default)(v3Message, {
        padding: 1,
        margin: 1,
        align: "center",
        borderColor: "magenta",
        borderStyle: "round"
      })
    );
    return;
  }
  const pkg = { name: "@eventcatalog/core", version: installedVersion };
  const notifier = (0, import_update_notifier.default)({ pkg, updateCheckInterval: 0 });
  if (notifier.update) {
    const message = `EventCatalog update available ${notifier.update.current} \u2192 ${notifier.update.latest}
Run npm i @eventcatalog/core to update`;
    console.log(
      (0, import_boxen.default)(message, {
        padding: 1,
        margin: 1,
        align: "center",
        borderColor: "yellow",
        borderStyle: {
          topLeft: " ",
          topRight: " ",
          bottomLeft: " ",
          bottomRight: " ",
          right: " ",
          top: "-",
          bottom: "-",
          left: " "
        }
      })
    );
  }
};
program.command("dev").description("Run development server of EventCatalog").option("-d, --debug", "Output EventCatalog application information into your terminal").option("--force-recreate", "Recreate the eventcatalog-core directory", false).option("--no-prewarm", "Disable automatic dev prewarm request").action(async (options, command) => {
  logger.welcome();
  logger.info("Setting up EventCatalog...", "eventcatalog");
  const isServer = await isOutputServer();
  logger.info(isServer ? "EventCatalog is running in Server Mode" : "EventCatalog is running in Static Mode", "config");
  if (import_fs3.default.existsSync(import_node_path11.default.join(dir, ".env"))) {
    import_dotenv.default.config({ path: import_node_path11.default.join(dir, ".env") });
  }
  if (options.debug) {
    logger.info("Debug mode enabled", "debug");
    logger.info(`PROJECT_DIR: ${dir}`, "debug");
    logger.info(`CATALOG_DIR: ${core}`, "debug");
  }
  if (options.forceRecreate) clearCore();
  await verifyRequiredFieldsAreInCatalogConfigFile(dir);
  copyCore();
  await resolve_catalog_dependencies_default(dir, core);
  await runMigrations(dir);
  await catalogToAstro(dir, core);
  const config = await getEventCatalogConfigFile(dir);
  const canEmbedPages = await (0, import_license.isFeatureEnabled)(
    "@eventcatalog/backstage-plugin-eventcatalog",
    process.env.EVENTCATALOG_LICENSE_KEY_BACKSTAGE
  );
  const isEventCatalogStarter = await (0, import_license.isEventCatalogStarterEnabled)();
  const isEventCatalogScale = await (0, import_license.isEventCatalogScaleEnabled)();
  if (isServer) {
    try {
      logger.info("Building fields index...", "fields");
      const { warnings } = await buildFieldsIndex(dir, core);
      if (warnings.length > 0) {
        logger.info(`Fields index built with ${warnings.length} warning(s)`, "fields");
      } else {
        logger.info("Fields index built successfully", "fields");
      }
    } catch (err) {
      logger.info(`Failed to build fields index: ${err.message}`, "fields");
    }
  }
  const shouldBuildIndexedSearch = await isIndexedSearchEnabled();
  if (shouldBuildIndexedSearch) {
    await warnIfIndexedSearchUsesAuth();
    logger.info("Building indexed search for local development...", "search");
    await buildDevSearchIndex({ config });
  }
  checkForUpdate();
  let watchUnsub;
  try {
    watchUnsub = await watch(dir, core, shouldBuildIndexedSearch ? createDevSearchIndexWatcher({ config }) : void 0);
    const args = command.args.join(" ").trim();
    if (options.prewarm) {
      const prewarmPort = await resolveDevPort({
        projectDir: dir
      });
      startDevPrewarm({
        port: prewarmPort,
        paths: ["/ping", "/"]
      });
    }
    await runCommandWithFilteredOutput({
      command: `npx astro dev ${args}`,
      cwd: core,
      env: {
        PROJECT_DIR: dir,
        CATALOG_DIR: core,
        ENABLE_EMBED: String(canEmbedPages || isEventCatalogScale),
        EVENTCATALOG_STARTER: String(isEventCatalogStarter),
        EVENTCATALOG_SCALE: String(isEventCatalogScale),
        EVENTCATALOG_DEV_MODE: "true",
        IGNORE_BUILD_ARTIFACTS: "true",
        NODE_NO_WARNINGS: "1"
      },
      shouldFilterLine: createAstroDevLineFilter(),
      transformLine: replaceAstroReadyVersionLine
    });
  } catch (err) {
    console.error(err);
  } finally {
    await watchUnsub?.();
  }
});
program.command("build").description("Run build of EventCatalog").action(async (options, command) => {
  logger.welcome();
  logger.info("Building EventCatalog...", "build");
  const isServer = await isOutputServer();
  logger.info(isServer ? "EventCatalog is running in Server Mode" : "EventCatalog is running in Static Mode", "config");
  if (import_fs3.default.existsSync(import_node_path11.default.join(dir, ".env"))) {
    import_dotenv.default.config({ path: import_node_path11.default.join(dir, ".env") });
  }
  await verifyRequiredFieldsAreInCatalogConfigFile(dir);
  copyCore();
  const isBackstagePluginEnabled = await (0, import_license.isFeatureEnabled)(
    "@eventcatalog/backstage-plugin-eventcatalog",
    process.env.EVENTCATALOG_LICENSE_KEY_BACKSTAGE
  );
  const isEventCatalogStarter = await (0, import_license.isEventCatalogStarterEnabled)();
  const isEventCatalogScale = await (0, import_license.isEventCatalogScaleEnabled)();
  const canEmbedPages = isBackstagePluginEnabled || isEventCatalogScale;
  await log_build_default(dir, {
    isEventCatalogStarterEnabled: isEventCatalogStarter,
    isEventCatalogScaleEnabled: isEventCatalogScale,
    isBackstagePluginEnabled: canEmbedPages || isEventCatalogScale
  });
  await resolve_catalog_dependencies_default(dir, core);
  await runMigrations(dir);
  await catalogToAstro(dir, core);
  if (isServer) {
    try {
      logger.info("Building fields index...", "fields");
      const { warnings } = await buildFieldsIndex(dir, core);
      if (warnings.length > 0) {
        logger.info(`Fields index built with ${warnings.length} warning(s)`, "fields");
      } else {
        logger.info("Fields index built successfully", "fields");
      }
    } catch (err) {
      logger.info(`Failed to build fields index: ${err.message}`, "fields");
    }
  }
  checkForUpdate();
  const args = command.args.join(" ").trim();
  await runCommandWithFilteredOutput({
    command: `npx astro build ${args}`,
    cwd: core,
    env: {
      PROJECT_DIR: dir,
      CATALOG_DIR: core,
      ENABLE_EMBED: String(canEmbedPages),
      EVENTCATALOG_STARTER: String(isEventCatalogStarter),
      EVENTCATALOG_SCALE: String(isEventCatalogScale),
      IGNORE_BUILD_ARTIFACTS: "true"
    },
    shouldFilterLine: createAstroLineFilter()
  });
  if (await isIndexedSearchEnabled()) {
    await warnIfIndexedSearchUsesAuth();
    const config = await getEventCatalogConfigFile(dir);
    const outDir = import_node_path11.default.resolve(dir, await getProjectOutDir());
    logger.info("Building indexed search...", "search");
    const result = await buildSearchIndex({
      projectDir: dir,
      outDir,
      config,
      isServer
    });
    logger.info(`Indexed ${result.records} page(s) into ${import_node_path11.default.relative(dir, result.outputPath)}`, "search");
  }
});
var previewCatalog = ({
  command,
  canEmbedPages = false,
  isEventCatalogStarter = false,
  isEventCatalogScale = false
}) => {
  (0, import_node_child_process.execSync)(
    `cross-env PROJECT_DIR='${dir}' CATALOG_DIR='${core}' ENABLE_EMBED=${canEmbedPages} EVENTCATALOG_STARTER=${isEventCatalogStarter} EVENTCATALOG_SCALE=${isEventCatalogScale} npx astro preview ${command.args.join(" ").trim()}`,
    {
      cwd: core,
      stdio: "inherit"
    }
  );
};
var startServerCatalog = ({
  command,
  canEmbedPages = false,
  isEventCatalogStarter = false,
  isEventCatalogScale = false
}) => {
  const serverEntryPath = import_node_path11.default.join(dir, "dist", "server", "entry.mjs");
  (0, import_node_child_process.execSync)(
    `cross-env PROJECT_DIR='${dir}' CATALOG_DIR='${core}' ENABLE_EMBED=${canEmbedPages} EVENTCATALOG_STARTER=${isEventCatalogStarter} EVENTCATALOG_SCALE=${isEventCatalogScale} node "${serverEntryPath}"`,
    {
      cwd: core,
      stdio: "inherit"
    }
  );
};
program.command("preview").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
  logger.welcome();
  logger.info("Starting preview of your build...", "preview");
  if (import_fs3.default.existsSync(import_node_path11.default.join(dir, ".env"))) {
    import_dotenv.default.config({ path: import_node_path11.default.join(dir, ".env") });
  }
  const canEmbedPages = await (0, import_license.isFeatureEnabled)(
    "@eventcatalog/backstage-plugin-eventcatalog",
    process.env.EVENTCATALOG_LICENSE_KEY_BACKSTAGE
  );
  const isEventCatalogStarter = await (0, import_license.isEventCatalogStarterEnabled)();
  const isEventCatalogScale = await (0, import_license.isEventCatalogScaleEnabled)();
  previewCatalog({ command, canEmbedPages: canEmbedPages || isEventCatalogScale, isEventCatalogStarter, isEventCatalogScale });
});
program.command("start").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
  logger.welcome();
  logger.info("Starting preview of your build...", "preview");
  if (import_fs3.default.existsSync(import_node_path11.default.join(dir, ".env"))) {
    import_dotenv.default.config({ path: import_node_path11.default.join(dir, ".env") });
  }
  const canEmbedPages = await (0, import_license.isFeatureEnabled)(
    "@eventcatalog/backstage-plugin-eventcatalog",
    process.env.EVENTCATALOG_LICENSE_KEY_BACKSTAGE
  );
  const isEventCatalogStarter = await (0, import_license.isEventCatalogStarterEnabled)();
  const isEventCatalogScale = await (0, import_license.isEventCatalogScaleEnabled)();
  const isServerOutput = await isOutputServer();
  if (isServerOutput) {
    startServerCatalog({
      command,
      canEmbedPages: canEmbedPages || isEventCatalogScale,
      isEventCatalogStarter,
      isEventCatalogScale
    });
  } else {
    previewCatalog({
      command,
      canEmbedPages: canEmbedPages || isEventCatalogScale,
      isEventCatalogStarter,
      isEventCatalogScale
    });
  }
});
program.command("export").description("Export your EventCatalog using the SDK dumpCatalog function").option("--include-markdown", "Include markdown content in the export", false).action(async (options) => {
  logger.welcome();
  logger.info("Exporting EventCatalog...", "export");
  if (import_fs3.default.existsSync(import_node_path11.default.join(dir, ".env"))) {
    import_dotenv.default.config({ path: import_node_path11.default.join(dir, ".env") });
  }
  const { default: initSDK } = await import("@eventcatalog/sdk");
  const sdk = initSDK(dir);
  const catalog = await sdk.dumpCatalog({ includeMarkdown: options.includeMarkdown });
  const exportsDir = import_node_path11.default.join(dir, "exports");
  ensureDir(exportsDir);
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
  const exportFile = import_node_path11.default.join(exportsDir, `catalog-${date}.json`);
  import_fs3.default.writeFileSync(exportFile, JSON.stringify(catalog, null, 2), "utf-8");
  logger.info(`Catalog exported to ${exportFile}`, "export");
});
program.command("generate [siteDir]").description("Start the generator scripts.").action(async () => {
  if (import_fs3.default.existsSync(import_node_path11.default.join(dir, ".env"))) {
    import_dotenv.default.config({ path: import_node_path11.default.join(dir, ".env") });
  }
  await generate(dir);
});
program.addHelpText(
  "after",
  `
  Passing Extra Arguments:
    Use the -- delimiter to forward arguments to the underlying process.
    Example: npx eventcatalog dev --debug -- --env=production --port=3000
  `
);
program.parseAsync().then(() => process.exit(0)).catch((err) => {
  console.error(err);
  process.exit(1);
});
