@eventcatalog/core 4.7.3 → 4.7.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/dist/analytics/analytics.cjs +1 -1
  2. package/dist/analytics/analytics.js +2 -2
  3. package/dist/analytics/log-build.cjs +1 -1
  4. package/dist/analytics/log-build.js +3 -3
  5. package/dist/{chunk-XXJX3WWF.js → chunk-7QTCSRAC.js} +1 -1
  6. package/dist/chunk-A2RZR3U4.js +29 -0
  7. package/dist/{chunk-SMDTRRED.js → chunk-FDXJIZ74.js} +1 -1
  8. package/dist/{chunk-ZR6AH5Z2.js → chunk-RIUHZZRA.js} +4 -4
  9. package/dist/chunk-SDZQJTJW.js +90 -0
  10. package/dist/{chunk-V4FAVGI7.js → chunk-TLWM7WRZ.js} +1 -1
  11. package/dist/{chunk-GINIJSFI.js → chunk-ZIABX6SP.js} +1 -1
  12. package/dist/{chunk-IALEXWSE.js → chunk-ZXVQXBTT.js} +1 -1
  13. package/dist/constants.cjs +1 -1
  14. package/dist/constants.js +1 -1
  15. package/dist/eventcatalog.cjs +315 -209
  16. package/dist/eventcatalog.config.d.cts +3 -3
  17. package/dist/eventcatalog.config.d.ts +3 -3
  18. package/dist/eventcatalog.js +11 -9
  19. package/dist/federation/federate.cjs +269 -163
  20. package/dist/federation/federate.js +3 -1
  21. package/dist/federation/filesystem-source-provider.cjs +124 -0
  22. package/dist/federation/filesystem-source-provider.d.cts +7 -0
  23. package/dist/federation/filesystem-source-provider.d.ts +7 -0
  24. package/dist/federation/filesystem-source-provider.js +6 -0
  25. package/dist/federation/source-provider.cjs +265 -0
  26. package/dist/federation/source-provider.d.cts +11 -0
  27. package/dist/federation/source-provider.d.ts +11 -0
  28. package/dist/federation/source-provider.js +8 -0
  29. package/dist/generate.cjs +1 -1
  30. package/dist/generate.js +3 -3
  31. package/dist/utils/cli-logger.cjs +1 -1
  32. package/dist/utils/cli-logger.js +2 -2
  33. package/package.json +3 -3
@@ -29,10 +29,10 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
29
29
  // src/eventcatalog.ts
30
30
  var import_commander = require("commander");
31
31
  var import_node_child_process2 = require("child_process");
32
- var import_node_path15 = require("path");
32
+ var import_node_path16 = require("path");
33
33
  var import_node_http = __toESM(require("http"), 1);
34
34
  var import_fs3 = __toESM(require("fs"), 1);
35
- var import_node_path16 = __toESM(require("path"), 1);
35
+ var import_node_path17 = __toESM(require("path"), 1);
36
36
  var import_node_url = require("url");
37
37
 
38
38
  // src/generate.js
@@ -144,7 +144,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
144
144
  var import_picocolors = __toESM(require("picocolors"), 1);
145
145
 
146
146
  // package.json
147
- var version = "4.7.3";
147
+ var version = "4.7.4";
148
148
 
149
149
  // src/constants.ts
150
150
  var VERSION = version;
@@ -1310,22 +1310,22 @@ function getAvroTypeName(type) {
1310
1310
  function walkAvroRecord(schema, prefix, fields) {
1311
1311
  if (!schema.fields || !Array.isArray(schema.fields)) return;
1312
1312
  for (const field of schema.fields) {
1313
- const path16 = prefix ? `${prefix}.${field.name}` : field.name;
1313
+ const path17 = prefix ? `${prefix}.${field.name}` : field.name;
1314
1314
  const isOptional = Array.isArray(field.type) && field.type.includes("null");
1315
1315
  const typeName = getAvroTypeName(field.type);
1316
1316
  fields.push({
1317
- path: path16,
1317
+ path: path17,
1318
1318
  type: typeName,
1319
1319
  description: field.doc || "",
1320
1320
  required: !isOptional
1321
1321
  });
1322
1322
  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;
1323
1323
  if (innerType) {
1324
- walkAvroRecord(innerType, path16, fields);
1324
+ walkAvroRecord(innerType, path17, fields);
1325
1325
  }
1326
1326
  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;
1327
1327
  if (arrayType && typeof arrayType.items === "object" && arrayType.items.type === "record") {
1328
- walkAvroRecord(arrayType.items, `${path16}[]`, fields);
1328
+ walkAvroRecord(arrayType.items, `${path17}[]`, fields);
1329
1329
  }
1330
1330
  }
1331
1331
  }
@@ -1356,32 +1356,32 @@ function walkJsonSchema(node, prefix, requiredList, rootSchema, fields) {
1356
1356
  }
1357
1357
  if (!node.properties) return;
1358
1358
  for (const [name, prop] of Object.entries(node.properties)) {
1359
- const path16 = prefix ? `${prefix}.${name}` : name;
1359
+ const path17 = prefix ? `${prefix}.${name}` : name;
1360
1360
  const isRequired = requiredList.includes(name);
1361
1361
  if (prop.$ref) {
1362
1362
  const resolved = resolveLocalRef(prop.$ref, rootSchema);
1363
1363
  if (resolved) {
1364
1364
  const rawRefType = resolved.type || "object";
1365
1365
  const type2 = Array.isArray(rawRefType) ? [...rawRefType].sort().join(" | ") : rawRefType;
1366
- fields.push({ path: path16, type: type2, description: resolved.description || "", required: isRequired });
1366
+ fields.push({ path: path17, type: type2, description: resolved.description || "", required: isRequired });
1367
1367
  if (resolved.properties) {
1368
- walkJsonSchema(resolved, path16, resolved.required || [], rootSchema, fields);
1368
+ walkJsonSchema(resolved, path17, resolved.required || [], rootSchema, fields);
1369
1369
  }
1370
1370
  } else {
1371
- fields.push({ path: path16, type: "$ref", description: "", required: isRequired });
1371
+ fields.push({ path: path17, type: "$ref", description: "", required: isRequired });
1372
1372
  }
1373
1373
  continue;
1374
1374
  }
1375
1375
  const rawType = prop.type || (prop.enum ? "enum" : prop.$ref ? "$ref" : "object");
1376
1376
  const typeList = Array.isArray(rawType) ? rawType : [rawType];
1377
1377
  const type = Array.isArray(rawType) ? [...rawType].sort().join(" | ") : rawType;
1378
- fields.push({ path: path16, type, description: prop.description || "", required: isRequired });
1378
+ fields.push({ path: path17, type, description: prop.description || "", required: isRequired });
1379
1379
  if (typeList.includes("object") && prop.properties) {
1380
- walkJsonSchema(prop, path16, prop.required || [], rootSchema, fields);
1380
+ walkJsonSchema(prop, path17, prop.required || [], rootSchema, fields);
1381
1381
  }
1382
1382
  if (typeList.includes("array") && prop.items) {
1383
1383
  if (prop.items.type === "object" && prop.items.properties) {
1384
- walkJsonSchema(prop.items, `${path16}[]`, prop.items.required || [], rootSchema, fields);
1384
+ walkJsonSchema(prop.items, `${path17}[]`, prop.items.required || [], rootSchema, fields);
1385
1385
  }
1386
1386
  }
1387
1387
  }
@@ -1900,10 +1900,10 @@ var createAstroDevLineFilter = () => {
1900
1900
  };
1901
1901
 
1902
1902
  // src/federation/federate.ts
1903
- var import_node_crypto3 = require("crypto");
1904
- var import_promises7 = __toESM(require("fs/promises"), 1);
1905
- var import_node_path14 = __toESM(require("path"), 1);
1906
- var import_sdk2 = __toESM(require("@eventcatalog/sdk"), 1);
1903
+ var import_node_crypto4 = require("crypto");
1904
+ var import_promises8 = __toESM(require("fs/promises"), 1);
1905
+ var import_node_path15 = __toESM(require("path"), 1);
1906
+ var import_sdk3 = __toESM(require("@eventcatalog/sdk"), 1);
1907
1907
 
1908
1908
  // src/federation/content-cache.ts
1909
1909
  var import_node_crypto = require("crypto");
@@ -1946,13 +1946,230 @@ var createFederationContentCache = (projectDirectory, options = {}) => {
1946
1946
  };
1947
1947
  };
1948
1948
 
1949
+ // src/federation/public-assets.ts
1950
+ var import_node_crypto2 = require("crypto");
1951
+ var import_promises5 = __toESM(require("fs/promises"), 1);
1952
+ var import_node_path12 = __toESM(require("path"), 1);
1953
+ var getContentHash2 = (content) => `sha256:${(0, import_node_crypto2.createHash)("sha256").update(content).digest("hex")}`;
1954
+ var getFileHash = async (filePath) => {
1955
+ try {
1956
+ const stat = await import_promises5.default.lstat(filePath);
1957
+ return stat.isFile() ? getContentHash2(await import_promises5.default.readFile(filePath)) : void 0;
1958
+ } catch (error) {
1959
+ if (error.code === "ENOENT") return void 0;
1960
+ throw error;
1961
+ }
1962
+ };
1963
+ var getSafePath = (directory, relativePath) => {
1964
+ const normalizedPath = import_node_path12.default.posix.normalize(relativePath);
1965
+ const unsafe = relativePath.length === 0 || relativePath.includes("\0") || relativePath.includes("\\") || import_node_path12.default.posix.isAbsolute(relativePath) || /^[a-zA-Z]:\//.test(relativePath) || normalizedPath !== relativePath || normalizedPath === ".." || normalizedPath.startsWith("../");
1966
+ if (unsafe) return void 0;
1967
+ const resolvedDirectory = import_node_path12.default.resolve(directory);
1968
+ const resolvedPath = import_node_path12.default.resolve(resolvedDirectory, relativePath);
1969
+ const relativeResolvedPath = import_node_path12.default.relative(resolvedDirectory, resolvedPath);
1970
+ if (relativeResolvedPath === "" || relativeResolvedPath === ".." || relativeResolvedPath.startsWith(`..${import_node_path12.default.sep}`) || import_node_path12.default.isAbsolute(relativeResolvedPath)) {
1971
+ return void 0;
1972
+ }
1973
+ return resolvedPath;
1974
+ };
1975
+ var listFiles = async (directory, relativeDirectory = "") => {
1976
+ let entries;
1977
+ try {
1978
+ entries = await import_promises5.default.readdir(import_node_path12.default.join(directory, relativeDirectory), { withFileTypes: true });
1979
+ } catch (error) {
1980
+ if (error.code === "ENOENT") return [];
1981
+ throw error;
1982
+ }
1983
+ const files = await Promise.all(
1984
+ entries.map(async (entry) => {
1985
+ const relativePath = import_node_path12.default.join(relativeDirectory, entry.name);
1986
+ if (entry.isDirectory()) return listFiles(directory, relativePath);
1987
+ return entry.isFile() ? [relativePath.split(import_node_path12.default.sep).join("/")] : [];
1988
+ })
1989
+ );
1990
+ return files.flat().sort();
1991
+ };
1992
+ var pathExists = async (filePath) => {
1993
+ try {
1994
+ await import_promises5.default.lstat(filePath);
1995
+ return true;
1996
+ } catch (error) {
1997
+ if (error.code === "ENOENT") return false;
1998
+ throw error;
1999
+ }
2000
+ };
2001
+ var hasBlockingParent = async (publicDirectory, destinationPath) => {
2002
+ let currentPath = import_node_path12.default.dirname(destinationPath);
2003
+ while (currentPath !== publicDirectory) {
2004
+ try {
2005
+ if (!(await import_promises5.default.lstat(currentPath)).isDirectory()) return true;
2006
+ } catch (error) {
2007
+ if (error.code !== "ENOENT") throw error;
2008
+ }
2009
+ currentPath = import_node_path12.default.dirname(currentPath);
2010
+ }
2011
+ return false;
2012
+ };
2013
+ var pruneEmptyDirectories = async (publicDirectory, filePath) => {
2014
+ let currentPath = import_node_path12.default.dirname(filePath);
2015
+ while (currentPath !== publicDirectory) {
2016
+ try {
2017
+ await import_promises5.default.rmdir(currentPath);
2018
+ } catch (error) {
2019
+ if (!["ENOENT", "ENOTEMPTY"].includes(error.code ?? "")) throw error;
2020
+ if (error.code === "ENOTEMPTY") return;
2021
+ }
2022
+ currentPath = import_node_path12.default.dirname(currentPath);
2023
+ }
2024
+ };
2025
+ var composePublicAssets = async ({
2026
+ projectDirectory,
2027
+ federatedDirectory,
2028
+ assets,
2029
+ previousFiles = {},
2030
+ collisionPaths = /* @__PURE__ */ new Set()
2031
+ }) => {
2032
+ const publicDirectory = import_node_path12.default.resolve(projectDirectory, "public");
2033
+ const federatedPublicDirectory = import_node_path12.default.resolve(federatedDirectory, "public");
2034
+ const sourceFiles = await listFiles(federatedPublicDirectory);
2035
+ const sourceFileSet = new Set(sourceFiles);
2036
+ const managedFiles = /* @__PURE__ */ new Set();
2037
+ for (const [relativePath, previousFile] of Object.entries(previousFiles)) {
2038
+ const destinationPath = getSafePath(publicDirectory, relativePath);
2039
+ if (destinationPath && await getFileHash(destinationPath) === previousFile.hash) managedFiles.add(relativePath);
2040
+ }
2041
+ let removed = 0;
2042
+ for (const relativePath of managedFiles) {
2043
+ if (sourceFileSet.has(relativePath)) continue;
2044
+ const destinationPath = getSafePath(publicDirectory, relativePath);
2045
+ if (!destinationPath) continue;
2046
+ await import_promises5.default.rm(destinationPath, { force: true });
2047
+ await pruneEmptyDirectories(publicDirectory, destinationPath);
2048
+ removed += 1;
2049
+ }
2050
+ const publicAssetsByPath = new Map(
2051
+ assets.filter((asset) => asset.path.startsWith("public/")).map((asset) => [asset.path.slice("public/".length), asset])
2052
+ );
2053
+ const files = {};
2054
+ let copied = 0;
2055
+ let skipped = 0;
2056
+ let overwritten = 0;
2057
+ for (const relativePath of sourceFiles) {
2058
+ const sourcePath = getSafePath(federatedPublicDirectory, relativePath);
2059
+ const destinationPath = getSafePath(publicDirectory, relativePath);
2060
+ if (!sourcePath || !destinationPath) throw new Error(`Unsafe federated public asset path "${relativePath}"`);
2061
+ const mainCatalogOwnsPath = await pathExists(destinationPath) && !managedFiles.has(relativePath) || await hasBlockingParent(publicDirectory, destinationPath);
2062
+ if (mainCatalogOwnsPath) {
2063
+ skipped += 1;
2064
+ continue;
2065
+ }
2066
+ const asset = publicAssetsByPath.get(relativePath);
2067
+ if (!asset) throw new Error(`Cannot identify the source of federated public asset "${relativePath}"`);
2068
+ const content = await import_promises5.default.readFile(sourcePath);
2069
+ await import_promises5.default.mkdir(import_node_path12.default.dirname(destinationPath), { recursive: true });
2070
+ await import_promises5.default.writeFile(destinationPath, content);
2071
+ files[relativePath] = { source: asset.resolvedFrom.source, hash: getContentHash2(content) };
2072
+ copied += 1;
2073
+ if (collisionPaths.has(`public/${relativePath}`)) overwritten += 1;
2074
+ }
2075
+ await import_promises5.default.rm(federatedPublicDirectory, { recursive: true, force: true });
2076
+ return { files, copied, skipped, overwritten, removed };
2077
+ };
2078
+
2079
+ // src/federation/filesystem-source-provider.ts
2080
+ var import_node_crypto3 = require("crypto");
2081
+ var import_promises6 = __toESM(require("fs/promises"), 1);
2082
+ var import_node_path13 = __toESM(require("path"), 1);
2083
+ var import_sdk = __toESM(require("@eventcatalog/sdk"), 1);
2084
+ var FILESYSTEM_SOURCE_PREFIX = "file:";
2085
+ var isWithinDirectory = (directory, target) => {
2086
+ const relativePath = import_node_path13.default.relative(directory, target);
2087
+ return relativePath === "" || !relativePath.startsWith(`..${import_node_path13.default.sep}`) && relativePath !== ".." && !import_node_path13.default.isAbsolute(relativePath);
2088
+ };
2089
+ var assertPortableRelativePath = (filePath, label, allowRoot = true) => {
2090
+ const portablePath = filePath.replaceAll("\\", "/");
2091
+ const normalizedPath = import_node_path13.default.posix.normalize(portablePath);
2092
+ const isUnsafe = filePath.includes("\\") || filePath.includes("\0") || import_node_path13.default.posix.isAbsolute(normalizedPath) || /^[a-zA-Z]:\//.test(normalizedPath) || normalizedPath === ".." || normalizedPath.startsWith("../") || !allowRoot && (normalizedPath === "." || normalizedPath === "");
2093
+ if (isUnsafe) throw new Error(`${label} "${filePath}" escapes its filesystem source`);
2094
+ return normalizedPath;
2095
+ };
2096
+ var getSourceRoot = (projectDirectory, source) => {
2097
+ if (!source.source.startsWith(FILESYSTEM_SOURCE_PREFIX)) {
2098
+ throw new Error(`Unsupported federation source "${source.source}". Expected file:path/to/catalog.`);
2099
+ }
2100
+ const locator = source.source.slice(FILESYSTEM_SOURCE_PREFIX.length);
2101
+ if (!locator.trim()) throw new Error(`Filesystem federation source "${source.id}" requires a path after "file:".`);
2102
+ return import_node_path13.default.resolve(projectDirectory, locator);
2103
+ };
2104
+ var getCatalogDirectory = async (projectDirectory, source) => {
2105
+ if (source.ref) throw new Error(`Filesystem federation source "${source.id}" does not support "ref".`);
2106
+ const sourceRoot = getSourceRoot(projectDirectory, source);
2107
+ const catalogPath = assertPortableRelativePath(source.path ?? ".", "Catalog path");
2108
+ const catalogDirectory = import_node_path13.default.resolve(sourceRoot, ...catalogPath.split("/"));
2109
+ if (!isWithinDirectory(sourceRoot, catalogDirectory)) {
2110
+ throw new Error(`Catalog path "${source.path}" escapes source "${source.id}"`);
2111
+ }
2112
+ try {
2113
+ const [realSourceRoot, realCatalogDirectory] = await Promise.all([import_promises6.default.realpath(sourceRoot), import_promises6.default.realpath(catalogDirectory)]);
2114
+ if (!isWithinDirectory(realSourceRoot, realCatalogDirectory)) {
2115
+ throw new Error(`Catalog path "${source.path}" escapes source "${source.id}"`);
2116
+ }
2117
+ if (!(await import_promises6.default.stat(realCatalogDirectory)).isDirectory()) {
2118
+ throw new Error(`Filesystem federation source "${source.id}" is not a directory: ${catalogDirectory}`);
2119
+ }
2120
+ return realCatalogDirectory;
2121
+ } catch (error) {
2122
+ if (error.code === "ENOENT") {
2123
+ throw new Error(`Filesystem federation source "${source.id}" does not exist: ${catalogDirectory}`, { cause: error });
2124
+ }
2125
+ throw error;
2126
+ }
2127
+ };
2128
+ var getArtifactPath = async (catalogDirectory, source, artifactPath) => {
2129
+ const normalizedPath = assertPortableRelativePath(artifactPath, "Federated artifact path", false);
2130
+ const filePath = import_node_path13.default.resolve(catalogDirectory, ...normalizedPath.split("/"));
2131
+ if (!isWithinDirectory(catalogDirectory, filePath)) {
2132
+ throw new Error(`Federated artifact path "${artifactPath}" escapes source "${source.id}"`);
2133
+ }
2134
+ try {
2135
+ const realFilePath = await import_promises6.default.realpath(filePath);
2136
+ if (!isWithinDirectory(catalogDirectory, realFilePath)) {
2137
+ throw new Error(`Federated artifact path "${artifactPath}" escapes source "${source.id}"`);
2138
+ }
2139
+ return realFilePath;
2140
+ } catch (error) {
2141
+ if (error.code === "ENOENT") {
2142
+ throw new Error(`Federated artifact not found for "${source.id}": ${artifactPath}`, { cause: error });
2143
+ }
2144
+ throw error;
2145
+ }
2146
+ };
2147
+ var createFileSystemSourceProvider = (projectDirectory) => ({
2148
+ async resolve(source) {
2149
+ const catalogDirectory = await getCatalogDirectory(projectDirectory, source);
2150
+ const localIndex = await (0, import_sdk.default)(catalogDirectory).buildIndex({
2151
+ source: source.id,
2152
+ commit: "local",
2153
+ includeFederated: false
2154
+ });
2155
+ const snapshot = (0, import_node_crypto3.createHash)("sha256").update(JSON.stringify(localIndex)).digest("hex").slice(0, 12);
2156
+ const index = { ...localIndex, commit: `local:${snapshot}` };
2157
+ const bytes = Buffer.from(JSON.stringify(index));
2158
+ return { bytes, index, commit: index.commit, generated: true };
2159
+ },
2160
+ async fetchContent({ source, path: artifactPath }) {
2161
+ const catalogDirectory = await getCatalogDirectory(projectDirectory, source);
2162
+ return import_promises6.default.readFile(await getArtifactPath(catalogDirectory, source, artifactPath));
2163
+ }
2164
+ });
2165
+
1949
2166
  // src/federation/github-source-provider.ts
1950
2167
  var import_node_child_process = require("child_process");
1951
- var import_promises5 = __toESM(require("fs/promises"), 1);
2168
+ var import_promises7 = __toESM(require("fs/promises"), 1);
1952
2169
  var import_node_os4 = __toESM(require("os"), 1);
1953
- var import_node_path12 = __toESM(require("path"), 1);
2170
+ var import_node_path14 = __toESM(require("path"), 1);
1954
2171
  var import_node_util = require("util");
1955
- var import_sdk = __toESM(require("@eventcatalog/sdk"), 1);
2172
+ var import_sdk2 = __toESM(require("@eventcatalog/sdk"), 1);
1956
2173
  var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
1957
2174
  var parseGitHubSource = (source) => {
1958
2175
  const match = /^github:([^/]+)\/(.+)$/.exec(source.source);
@@ -1961,8 +2178,8 @@ var parseGitHubSource = (source) => {
1961
2178
  };
1962
2179
  var assertSafeCatalogPath = (source) => {
1963
2180
  const catalogPath = source.path ?? ".";
1964
- const normalized = import_node_path12.default.posix.normalize(catalogPath.replaceAll("\\", "/"));
1965
- if (catalogPath.includes("\\") || import_node_path12.default.posix.isAbsolute(normalized) || normalized === ".." || normalized.startsWith("../")) {
2181
+ const normalized = import_node_path14.default.posix.normalize(catalogPath.replaceAll("\\", "/"));
2182
+ if (catalogPath.includes("\\") || import_node_path14.default.posix.isAbsolute(normalized) || normalized === ".." || normalized.startsWith("../")) {
1966
2183
  throw new Error(`Catalog path "${catalogPath}" escapes source "${source.id}"`);
1967
2184
  }
1968
2185
  };
@@ -2005,8 +2222,8 @@ var getGitEnvironment = (token) => {
2005
2222
  };
2006
2223
  var createCheckout = (executeFile, token) => async (source, ref, callback) => {
2007
2224
  const { owner, repository } = parseGitHubSource(source);
2008
- const catalogPath = import_node_path12.default.posix.normalize(source.path ?? ".");
2009
- const directory = await import_promises5.default.mkdtemp(import_node_path12.default.join(import_node_os4.default.tmpdir(), "eventcatalog-federation-"));
2225
+ const catalogPath = import_node_path14.default.posix.normalize(source.path ?? ".");
2226
+ const directory = await import_promises7.default.mkdtemp(import_node_path14.default.join(import_node_os4.default.tmpdir(), "eventcatalog-federation-"));
2010
2227
  const env = getGitEnvironment(token);
2011
2228
  try {
2012
2229
  const git = (args) => executeFile("git", args, { cwd: directory, env, encoding: "utf8" });
@@ -2020,25 +2237,25 @@ var createCheckout = (executeFile, token) => async (source, ref, callback) => {
2020
2237
  await git(["checkout", "--quiet", "--detach", "FETCH_HEAD"]);
2021
2238
  return await callback(directory);
2022
2239
  } finally {
2023
- await import_promises5.default.rm(directory, { recursive: true, force: true });
2240
+ await import_promises7.default.rm(directory, { recursive: true, force: true });
2024
2241
  }
2025
2242
  };
2026
2243
  var generateIndex = async (source, ref, checkout, executeFile) => checkout(source, ref, async (directory) => {
2027
2244
  const { stdout } = await executeFile("git", ["rev-parse", "HEAD"], { cwd: directory, encoding: "utf8" });
2028
2245
  const commit = stdout.trim();
2029
- const catalogDirectory = import_node_path12.default.resolve(directory, source.path ?? ".");
2030
- const relativeCatalogDirectory = import_node_path12.default.relative(directory, catalogDirectory);
2031
- if (relativeCatalogDirectory.startsWith("..") || import_node_path12.default.isAbsolute(relativeCatalogDirectory)) {
2246
+ const catalogDirectory = import_node_path14.default.resolve(directory, source.path ?? ".");
2247
+ const relativeCatalogDirectory = import_node_path14.default.relative(directory, catalogDirectory);
2248
+ if (relativeCatalogDirectory.startsWith("..") || import_node_path14.default.isAbsolute(relativeCatalogDirectory)) {
2032
2249
  throw new Error(`Catalog path "${source.path}" escapes source "${source.id}"`);
2033
2250
  }
2034
- const index = await (0, import_sdk.default)(catalogDirectory).buildIndex({ source: source.id, commit });
2251
+ const index = await (0, import_sdk2.default)(catalogDirectory).buildIndex({ source: source.id, commit });
2035
2252
  return { bytes: Buffer.from(JSON.stringify(index)), index, commit, generated: true };
2036
2253
  });
2037
2254
  var fetchPublishedIndex = async (source, ref, fetcher, token) => {
2038
- const indexPath = import_node_path12.default.posix.join(source.path ?? ".", "catalog.index.json");
2255
+ const indexPath = import_node_path14.default.posix.join(source.path ?? ".", "catalog.index.json");
2039
2256
  const bytes = await fetchBytes(source, ref, indexPath, fetcher, token);
2040
2257
  if (!bytes) return void 0;
2041
- const index = (0, import_sdk.parseIndex)(JSON.parse(bytes.toString("utf8")));
2258
+ const index = (0, import_sdk2.parseIndex)(JSON.parse(bytes.toString("utf8")));
2042
2259
  if (index.source !== source.id) {
2043
2260
  throw new Error(`Published index source "${index.source}" does not match configured id "${source.id}"`);
2044
2261
  }
@@ -2058,7 +2275,7 @@ var createGitHubSourceProvider = (options = {}) => {
2058
2275
  },
2059
2276
  async fetchContent({ source, commit, path: artifactPath }) {
2060
2277
  assertSafeCatalogPath(source);
2061
- const catalogPath = import_node_path12.default.posix.join(source.path ?? ".", artifactPath);
2278
+ const catalogPath = import_node_path14.default.posix.join(source.path ?? ".", artifactPath);
2062
2279
  const content = await fetchBytes(source, commit, catalogPath, fetcher, token);
2063
2280
  if (!content) throw new Error(`Federated artifact not found for "${source.id}": ${artifactPath}`);
2064
2281
  return content;
@@ -2066,134 +2283,23 @@ var createGitHubSourceProvider = (options = {}) => {
2066
2283
  };
2067
2284
  };
2068
2285
 
2069
- // src/federation/public-assets.ts
2070
- var import_node_crypto2 = require("crypto");
2071
- var import_promises6 = __toESM(require("fs/promises"), 1);
2072
- var import_node_path13 = __toESM(require("path"), 1);
2073
- var getContentHash2 = (content) => `sha256:${(0, import_node_crypto2.createHash)("sha256").update(content).digest("hex")}`;
2074
- var getFileHash = async (filePath) => {
2075
- try {
2076
- const stat = await import_promises6.default.lstat(filePath);
2077
- return stat.isFile() ? getContentHash2(await import_promises6.default.readFile(filePath)) : void 0;
2078
- } catch (error) {
2079
- if (error.code === "ENOENT") return void 0;
2080
- throw error;
2081
- }
2082
- };
2083
- var getSafePath = (directory, relativePath) => {
2084
- const normalizedPath = import_node_path13.default.posix.normalize(relativePath);
2085
- const unsafe = relativePath.length === 0 || relativePath.includes("\0") || relativePath.includes("\\") || import_node_path13.default.posix.isAbsolute(relativePath) || /^[a-zA-Z]:\//.test(relativePath) || normalizedPath !== relativePath || normalizedPath === ".." || normalizedPath.startsWith("../");
2086
- if (unsafe) return void 0;
2087
- const resolvedDirectory = import_node_path13.default.resolve(directory);
2088
- const resolvedPath = import_node_path13.default.resolve(resolvedDirectory, relativePath);
2089
- const relativeResolvedPath = import_node_path13.default.relative(resolvedDirectory, resolvedPath);
2090
- if (relativeResolvedPath === "" || relativeResolvedPath === ".." || relativeResolvedPath.startsWith(`..${import_node_path13.default.sep}`) || import_node_path13.default.isAbsolute(relativeResolvedPath)) {
2091
- return void 0;
2092
- }
2093
- return resolvedPath;
2094
- };
2095
- var listFiles = async (directory, relativeDirectory = "") => {
2096
- let entries;
2097
- try {
2098
- entries = await import_promises6.default.readdir(import_node_path13.default.join(directory, relativeDirectory), { withFileTypes: true });
2099
- } catch (error) {
2100
- if (error.code === "ENOENT") return [];
2101
- throw error;
2102
- }
2103
- const files = await Promise.all(
2104
- entries.map(async (entry) => {
2105
- const relativePath = import_node_path13.default.join(relativeDirectory, entry.name);
2106
- if (entry.isDirectory()) return listFiles(directory, relativePath);
2107
- return entry.isFile() ? [relativePath.split(import_node_path13.default.sep).join("/")] : [];
2108
- })
2109
- );
2110
- return files.flat().sort();
2111
- };
2112
- var pathExists = async (filePath) => {
2113
- try {
2114
- await import_promises6.default.lstat(filePath);
2115
- return true;
2116
- } catch (error) {
2117
- if (error.code === "ENOENT") return false;
2118
- throw error;
2119
- }
2120
- };
2121
- var hasBlockingParent = async (publicDirectory, destinationPath) => {
2122
- let currentPath = import_node_path13.default.dirname(destinationPath);
2123
- while (currentPath !== publicDirectory) {
2124
- try {
2125
- if (!(await import_promises6.default.lstat(currentPath)).isDirectory()) return true;
2126
- } catch (error) {
2127
- if (error.code !== "ENOENT") throw error;
2128
- }
2129
- currentPath = import_node_path13.default.dirname(currentPath);
2130
- }
2131
- return false;
2132
- };
2133
- var pruneEmptyDirectories = async (publicDirectory, filePath) => {
2134
- let currentPath = import_node_path13.default.dirname(filePath);
2135
- while (currentPath !== publicDirectory) {
2136
- try {
2137
- await import_promises6.default.rmdir(currentPath);
2138
- } catch (error) {
2139
- if (!["ENOENT", "ENOTEMPTY"].includes(error.code ?? "")) throw error;
2140
- if (error.code === "ENOTEMPTY") return;
2141
- }
2142
- currentPath = import_node_path13.default.dirname(currentPath);
2143
- }
2144
- };
2145
- var composePublicAssets = async ({
2146
- projectDirectory,
2147
- federatedDirectory,
2148
- assets,
2149
- previousFiles = {},
2150
- collisionPaths = /* @__PURE__ */ new Set()
2151
- }) => {
2152
- const publicDirectory = import_node_path13.default.resolve(projectDirectory, "public");
2153
- const federatedPublicDirectory = import_node_path13.default.resolve(federatedDirectory, "public");
2154
- const sourceFiles = await listFiles(federatedPublicDirectory);
2155
- const sourceFileSet = new Set(sourceFiles);
2156
- const managedFiles = /* @__PURE__ */ new Set();
2157
- for (const [relativePath, previousFile] of Object.entries(previousFiles)) {
2158
- const destinationPath = getSafePath(publicDirectory, relativePath);
2159
- if (destinationPath && await getFileHash(destinationPath) === previousFile.hash) managedFiles.add(relativePath);
2160
- }
2161
- let removed = 0;
2162
- for (const relativePath of managedFiles) {
2163
- if (sourceFileSet.has(relativePath)) continue;
2164
- const destinationPath = getSafePath(publicDirectory, relativePath);
2165
- if (!destinationPath) continue;
2166
- await import_promises6.default.rm(destinationPath, { force: true });
2167
- await pruneEmptyDirectories(publicDirectory, destinationPath);
2168
- removed += 1;
2169
- }
2170
- const publicAssetsByPath = new Map(
2171
- assets.filter((asset) => asset.path.startsWith("public/")).map((asset) => [asset.path.slice("public/".length), asset])
2172
- );
2173
- const files = {};
2174
- let copied = 0;
2175
- let skipped = 0;
2176
- let overwritten = 0;
2177
- for (const relativePath of sourceFiles) {
2178
- const sourcePath = getSafePath(federatedPublicDirectory, relativePath);
2179
- const destinationPath = getSafePath(publicDirectory, relativePath);
2180
- if (!sourcePath || !destinationPath) throw new Error(`Unsafe federated public asset path "${relativePath}"`);
2181
- const mainCatalogOwnsPath = await pathExists(destinationPath) && !managedFiles.has(relativePath) || await hasBlockingParent(publicDirectory, destinationPath);
2182
- if (mainCatalogOwnsPath) {
2183
- skipped += 1;
2184
- continue;
2286
+ // src/federation/source-provider.ts
2287
+ var createFederationSourceProvider = (projectDirectory, providers = {}) => {
2288
+ const github = providers.github ?? createGitHubSourceProvider();
2289
+ const filesystem = providers.filesystem ?? createFileSystemSourceProvider(projectDirectory);
2290
+ const getProvider = (source) => {
2291
+ if (source.source.startsWith("github:")) return github;
2292
+ if (source.source.startsWith("file:")) return filesystem;
2293
+ throw new Error(`Unsupported federation source "${source.source}" for "${source.id}". Supported protocols: github:, file:.`);
2294
+ };
2295
+ return {
2296
+ async resolve(source) {
2297
+ return getProvider(source).resolve(source);
2298
+ },
2299
+ async fetchContent(request) {
2300
+ return getProvider(request.source).fetchContent(request);
2185
2301
  }
2186
- const asset = publicAssetsByPath.get(relativePath);
2187
- if (!asset) throw new Error(`Cannot identify the source of federated public asset "${relativePath}"`);
2188
- const content = await import_promises6.default.readFile(sourcePath);
2189
- await import_promises6.default.mkdir(import_node_path13.default.dirname(destinationPath), { recursive: true });
2190
- await import_promises6.default.writeFile(destinationPath, content);
2191
- files[relativePath] = { source: asset.resolvedFrom.source, hash: getContentHash2(content) };
2192
- copied += 1;
2193
- if (collisionPaths.has(`public/${relativePath}`)) overwritten += 1;
2194
- }
2195
- await import_promises6.default.rm(federatedPublicDirectory, { recursive: true, force: true });
2196
- return { files, copied, skipped, overwritten, removed };
2302
+ };
2197
2303
  };
2198
2304
 
2199
2305
  // src/federation/federate.ts
@@ -2218,16 +2324,16 @@ var validateSources = (sources) => {
2218
2324
  var writeLock = async (lockPath, lock) => {
2219
2325
  const temporaryPath = `${lockPath}.tmp-${process.pid}`;
2220
2326
  try {
2221
- await import_promises7.default.writeFile(temporaryPath, `${JSON.stringify(lock, null, 2)}
2327
+ await import_promises8.default.writeFile(temporaryPath, `${JSON.stringify(lock, null, 2)}
2222
2328
  `, "utf8");
2223
- await import_promises7.default.rename(temporaryPath, lockPath);
2329
+ await import_promises8.default.rename(temporaryPath, lockPath);
2224
2330
  } finally {
2225
- await import_promises7.default.rm(temporaryPath, { force: true });
2331
+ await import_promises8.default.rm(temporaryPath, { force: true });
2226
2332
  }
2227
2333
  };
2228
2334
  var readLock = async (lockPath) => {
2229
2335
  try {
2230
- return JSON.parse(await import_promises7.default.readFile(lockPath, "utf8"));
2336
+ return JSON.parse(await import_promises8.default.readFile(lockPath, "utf8"));
2231
2337
  } catch (error) {
2232
2338
  if (error.code === "ENOENT") return void 0;
2233
2339
  throw new Error(`Cannot read federation lock at "${lockPath}"`, { cause: error });
@@ -2235,7 +2341,7 @@ var readLock = async (lockPath) => {
2235
2341
  };
2236
2342
  var pathExists2 = async (filePath) => {
2237
2343
  try {
2238
- await import_promises7.default.access(filePath);
2344
+ await import_promises8.default.access(filePath);
2239
2345
  return true;
2240
2346
  } catch (error) {
2241
2347
  if (error.code === "ENOENT") return false;
@@ -2243,20 +2349,20 @@ var pathExists2 = async (filePath) => {
2243
2349
  }
2244
2350
  };
2245
2351
  var cleanupPreviousFederation = async (projectDirectory, onProgress) => {
2246
- const outDir = import_node_path14.default.join(projectDirectory, "federated");
2247
- const lockPath = import_node_path14.default.join(projectDirectory, "eventcatalog.lock");
2352
+ const outDir = import_node_path15.default.join(projectDirectory, "federated");
2353
+ const lockPath = import_node_path15.default.join(projectDirectory, "eventcatalog.lock");
2248
2354
  const previousLock = await readLock(lockPath);
2249
2355
  const hadFederatedOutput = await pathExists2(outDir);
2250
2356
  const hadLock = previousLock !== void 0;
2251
2357
  if (!hadFederatedOutput && !hadLock) return;
2252
- await import_promises7.default.rm(outDir, { recursive: true, force: true });
2358
+ await import_promises8.default.rm(outDir, { recursive: true, force: true });
2253
2359
  const publicResult = await composePublicAssets({
2254
2360
  projectDirectory,
2255
2361
  federatedDirectory: outDir,
2256
2362
  assets: [],
2257
2363
  previousFiles: previousLock?.publicFiles
2258
2364
  });
2259
- await import_promises7.default.rm(lockPath, { force: true });
2365
+ await import_promises8.default.rm(lockPath, { force: true });
2260
2366
  onProgress?.({
2261
2367
  type: "cleanup:complete",
2262
2368
  federated: hadFederatedOutput,
@@ -2279,7 +2385,7 @@ var federateCatalog = async (projectDirectory, options = {}) => {
2279
2385
  }
2280
2386
  validateSources(sources);
2281
2387
  if (options.useCache === false) options.onProgress?.({ type: "cache:disabled" });
2282
- const provider = options.provider ?? createGitHubSourceProvider();
2388
+ const provider = options.provider ?? createFederationSourceProvider(projectDirectory);
2283
2389
  const resolvedSources = [];
2284
2390
  for (const [index, source] of sources.entries()) {
2285
2391
  const current = index + 1;
@@ -2301,13 +2407,13 @@ var federateCatalog = async (projectDirectory, options = {}) => {
2301
2407
  throw new Error(`Failed to federate source "${source.id}": ${message}`, { cause: error });
2302
2408
  }
2303
2409
  }
2304
- const outDir = import_node_path14.default.join(projectDirectory, "federated");
2305
- const lockPath = import_node_path14.default.join(projectDirectory, "eventcatalog.lock");
2410
+ const outDir = import_node_path15.default.join(projectDirectory, "federated");
2411
+ const lockPath = import_node_path15.default.join(projectDirectory, "eventcatalog.lock");
2306
2412
  const previousLock = await readLock(lockPath);
2307
2413
  const resources = resolvedSources.reduce((total, source) => total + source.resolved.index.resources.length, 0);
2308
2414
  const remoteIndexes = resolvedSources.map(({ resolved }) => resolved.index);
2309
2415
  options.onProgress?.({ type: "local:start" });
2310
- const localIndex = await (0, import_sdk2.default)(projectDirectory).buildIndex({
2416
+ const localIndex = await (0, import_sdk3.default)(projectDirectory).buildIndex({
2311
2417
  source: config.cId,
2312
2418
  commit: "local",
2313
2419
  hashContent: false,
@@ -2315,18 +2421,18 @@ var federateCatalog = async (projectDirectory, options = {}) => {
2315
2421
  });
2316
2422
  options.onProgress?.({ type: "local:complete", resources: localIndex.resources.length });
2317
2423
  options.onProgress?.({ type: "resolving", resources, localResources: localIndex.resources.length });
2318
- const ownershipGraph = (0, import_sdk2.resolve)([localIndex, ...remoteIndexes]);
2424
+ const ownershipGraph = (0, import_sdk3.resolve)([localIndex, ...remoteIndexes]);
2319
2425
  if (ownershipGraph.conflicts.length > 0) {
2320
2426
  options.onProgress?.({ type: "resolved", graph: ownershipGraph });
2321
2427
  throw new FederationConflictError(ownershipGraph.conflicts);
2322
2428
  }
2323
- const graph = (0, import_sdk2.resolve)(remoteIndexes);
2429
+ const graph = (0, import_sdk3.resolve)(remoteIndexes);
2324
2430
  options.onProgress?.({ type: "resolved", graph });
2325
2431
  const sourcesById = new Map(sources.map((source) => [source.id, source]));
2326
2432
  options.onProgress?.({ type: "hydrating", outDir });
2327
2433
  let hydratedFiles = 0;
2328
2434
  let cachedFiles = 0;
2329
- const hydrateResult = await (0, import_sdk2.hydrate)(graph, {
2435
+ const hydrateResult = await (0, import_sdk3.hydrate)(graph, {
2330
2436
  outDir,
2331
2437
  cache: createFederationContentCache(projectDirectory, {
2332
2438
  read: options.useCache !== false,
@@ -2360,7 +2466,7 @@ var federateCatalog = async (projectDirectory, options = {}) => {
2360
2466
  lockVersion: 1,
2361
2467
  sources: resolvedSources.map(({ config: source, resolved }) => ({
2362
2468
  id: source.id,
2363
- digest: `sha256:${(0, import_node_crypto3.createHash)("sha256").update(resolved.bytes).digest("hex")}`,
2469
+ digest: `sha256:${(0, import_node_crypto4.createHash)("sha256").update(resolved.bytes).digest("hex")}`,
2364
2470
  commit: resolved.commit,
2365
2471
  resolvedAt
2366
2472
  })).sort((left, right) => left.id.localeCompare(right.id)),
@@ -2381,14 +2487,14 @@ var federateCatalog = async (projectDirectory, options = {}) => {
2381
2487
 
2382
2488
  // src/eventcatalog.ts
2383
2489
  var import_license = require("@eventcatalog/license");
2384
- var currentDir = import_node_path16.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
2490
+ var currentDir = import_node_path17.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
2385
2491
  var program = new import_commander.Command().version(VERSION);
2386
- var dir = import_node_path16.default.resolve(process.env.PROJECT_DIR || process.cwd());
2387
- var core = import_node_path16.default.resolve(process.env.CATALOG_DIR || (0, import_node_path15.join)(dir, ".eventcatalog-core"));
2388
- var eventCatalogDir = import_node_path16.default.resolve((0, import_node_path15.join)(currentDir, "../eventcatalog/"));
2492
+ var dir = import_node_path17.default.resolve(process.env.PROJECT_DIR || process.cwd());
2493
+ var core = import_node_path17.default.resolve(process.env.CATALOG_DIR || (0, import_node_path16.join)(dir, ".eventcatalog-core"));
2494
+ var eventCatalogDir = import_node_path17.default.resolve((0, import_node_path16.join)(currentDir, "../eventcatalog/"));
2389
2495
  var getInstalledEventCatalogVersion = () => {
2390
2496
  try {
2391
- const pkg = import_fs3.default.readFileSync((0, import_node_path15.join)(dir, "package.json"), "utf8");
2497
+ const pkg = import_fs3.default.readFileSync((0, import_node_path16.join)(dir, "package.json"), "utf8");
2392
2498
  const json = JSON.parse(pkg);
2393
2499
  return json.dependencies["@eventcatalog/core"];
2394
2500
  } catch (error) {
@@ -2454,12 +2560,12 @@ var startDevPrewarm = ({
2454
2560
  var buildDevSearchIndex = async ({ config }) => {
2455
2561
  const result = await buildSearchIndex({
2456
2562
  projectDir: dir,
2457
- outDir: import_node_path16.default.join(core, "public"),
2458
- searchOutputPath: import_node_path16.default.join(core, "public", "pagefind"),
2563
+ outDir: import_node_path17.default.join(core, "public"),
2564
+ searchOutputPath: import_node_path17.default.join(core, "public", "pagefind"),
2459
2565
  config,
2460
2566
  isServer: false
2461
2567
  });
2462
- logger.info(`Indexed ${result.records} page(s) into ${import_node_path16.default.relative(core, result.outputPath)}`, "search");
2568
+ logger.info(`Indexed ${result.records} page(s) into ${import_node_path17.default.relative(core, result.outputPath)}`, "search");
2463
2569
  };
2464
2570
  var warnIfIndexedSearchUsesAuth = async () => {
2465
2571
  if (!await isAuthEnabled()) {
@@ -2574,12 +2680,12 @@ var copyCore = () => {
2574
2680
  import_fs3.default.cpSync(eventCatalogDir, core, {
2575
2681
  recursive: true,
2576
2682
  filter: (src) => {
2577
- const relativePath = import_node_path16.default.relative(eventCatalogDir, src);
2578
- const pathParts = relativePath.split(import_node_path16.default.sep);
2683
+ const relativePath = import_node_path17.default.relative(eventCatalogDir, src);
2684
+ const pathParts = relativePath.split(import_node_path17.default.sep);
2579
2685
  return !pathParts.some((part) => [".astro", "dist", "node_modules"].includes(part));
2580
2686
  }
2581
2687
  });
2582
- const coreNodeModules = import_node_path16.default.join(core, "node_modules");
2688
+ const coreNodeModules = import_node_path17.default.join(core, "node_modules");
2583
2689
  const installedCoreNodeModules = resolveInstalledCoreNodeModules(currentDir);
2584
2690
  linkCoreNodeModules({ coreNodeModules, installedCoreNodeModules });
2585
2691
  };
@@ -2638,8 +2744,8 @@ program.command("dev").description("Run development server of EventCatalog").opt
2638
2744
  logger.info("Setting up EventCatalog...", "eventcatalog");
2639
2745
  const isServer = await isOutputServer();
2640
2746
  logger.info(isServer ? "EventCatalog is running in Server Mode" : "EventCatalog is running in Static Mode", "config");
2641
- if (import_fs3.default.existsSync(import_node_path16.default.join(dir, ".env"))) {
2642
- import_dotenv.default.config({ path: import_node_path16.default.join(dir, ".env") });
2747
+ if (import_fs3.default.existsSync(import_node_path17.default.join(dir, ".env"))) {
2748
+ import_dotenv.default.config({ path: import_node_path17.default.join(dir, ".env") });
2643
2749
  }
2644
2750
  if (options.debug) {
2645
2751
  logger.info("Debug mode enabled", "debug");
@@ -2719,8 +2825,8 @@ program.command("build").description("Run build of EventCatalog").action(async (
2719
2825
  logger.info("Building EventCatalog...", "build");
2720
2826
  const isServer = await isOutputServer();
2721
2827
  logger.info(isServer ? "EventCatalog is running in Server Mode" : "EventCatalog is running in Static Mode", "config");
2722
- if (import_fs3.default.existsSync(import_node_path16.default.join(dir, ".env"))) {
2723
- import_dotenv.default.config({ path: import_node_path16.default.join(dir, ".env") });
2828
+ if (import_fs3.default.existsSync(import_node_path17.default.join(dir, ".env"))) {
2829
+ import_dotenv.default.config({ path: import_node_path17.default.join(dir, ".env") });
2724
2830
  }
2725
2831
  await verifyRequiredFieldsAreInCatalogConfigFile(dir);
2726
2832
  copyCore();
@@ -2770,7 +2876,7 @@ program.command("build").description("Run build of EventCatalog").action(async (
2770
2876
  if (await isIndexedSearchEnabled()) {
2771
2877
  await warnIfIndexedSearchUsesAuth();
2772
2878
  const config = await getEventCatalogConfigFile(dir);
2773
- const outDir = import_node_path16.default.resolve(dir, await getProjectOutDir());
2879
+ const outDir = import_node_path17.default.resolve(dir, await getProjectOutDir());
2774
2880
  logger.info("Building indexed search...", "search");
2775
2881
  const result = await buildSearchIndex({
2776
2882
  projectDir: dir,
@@ -2778,7 +2884,7 @@ program.command("build").description("Run build of EventCatalog").action(async (
2778
2884
  config,
2779
2885
  isServer
2780
2886
  });
2781
- logger.info(`Indexed ${result.records} page(s) into ${import_node_path16.default.relative(dir, result.outputPath)}`, "search");
2887
+ logger.info(`Indexed ${result.records} page(s) into ${import_node_path17.default.relative(dir, result.outputPath)}`, "search");
2782
2888
  }
2783
2889
  });
2784
2890
  var previewCatalog = async ({
@@ -2805,7 +2911,7 @@ var startServerCatalog = async ({
2805
2911
  isEventCatalogStarter = false,
2806
2912
  isEventCatalogScale = false
2807
2913
  }) => {
2808
- const serverEntryPath = import_node_path16.default.join(dir, "dist", "server", "entry.mjs");
2914
+ const serverEntryPath = import_node_path17.default.join(dir, "dist", "server", "entry.mjs");
2809
2915
  await runCommandWithFilteredOutput({
2810
2916
  command: `node "${serverEntryPath}"`,
2811
2917
  cwd: core,
@@ -2822,8 +2928,8 @@ var startServerCatalog = async ({
2822
2928
  program.command("preview").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
2823
2929
  logger.welcome();
2824
2930
  logger.info("Starting preview of your build...", "preview");
2825
- if (import_fs3.default.existsSync(import_node_path16.default.join(dir, ".env"))) {
2826
- import_dotenv.default.config({ path: import_node_path16.default.join(dir, ".env") });
2931
+ if (import_fs3.default.existsSync(import_node_path17.default.join(dir, ".env"))) {
2932
+ import_dotenv.default.config({ path: import_node_path17.default.join(dir, ".env") });
2827
2933
  }
2828
2934
  const canEmbedPages = await (0, import_license.isFeatureEnabled)(
2829
2935
  "@eventcatalog/backstage-plugin-eventcatalog",
@@ -2841,8 +2947,8 @@ program.command("preview").description("Serves the contents of your eventcatalog
2841
2947
  program.command("start").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
2842
2948
  logger.welcome();
2843
2949
  logger.info("Starting preview of your build...", "preview");
2844
- if (import_fs3.default.existsSync(import_node_path16.default.join(dir, ".env"))) {
2845
- import_dotenv.default.config({ path: import_node_path16.default.join(dir, ".env") });
2950
+ if (import_fs3.default.existsSync(import_node_path17.default.join(dir, ".env"))) {
2951
+ import_dotenv.default.config({ path: import_node_path17.default.join(dir, ".env") });
2846
2952
  }
2847
2953
  const canEmbedPages = await (0, import_license.isFeatureEnabled)(
2848
2954
  "@eventcatalog/backstage-plugin-eventcatalog",
@@ -2869,22 +2975,22 @@ program.command("start").description("Serves the contents of your eventcatalog b
2869
2975
  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) => {
2870
2976
  logger.welcome();
2871
2977
  logger.info("Exporting EventCatalog...", "export");
2872
- if (import_fs3.default.existsSync(import_node_path16.default.join(dir, ".env"))) {
2873
- import_dotenv.default.config({ path: import_node_path16.default.join(dir, ".env") });
2978
+ if (import_fs3.default.existsSync(import_node_path17.default.join(dir, ".env"))) {
2979
+ import_dotenv.default.config({ path: import_node_path17.default.join(dir, ".env") });
2874
2980
  }
2875
2981
  const { default: initSDK } = await import("@eventcatalog/sdk");
2876
2982
  const sdk = initSDK(dir);
2877
2983
  const catalog = await sdk.dumpCatalog({ includeMarkdown: options.includeMarkdown });
2878
- const exportsDir = import_node_path16.default.join(dir, "exports");
2984
+ const exportsDir = import_node_path17.default.join(dir, "exports");
2879
2985
  ensureDir(exportsDir);
2880
2986
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
2881
- const exportFile = import_node_path16.default.join(exportsDir, `catalog-${date}.json`);
2987
+ const exportFile = import_node_path17.default.join(exportsDir, `catalog-${date}.json`);
2882
2988
  import_fs3.default.writeFileSync(exportFile, JSON.stringify(catalog, null, 2), "utf-8");
2883
2989
  logger.info(`Catalog exported to ${exportFile}`, "export");
2884
2990
  });
2885
2991
  program.command("generate [siteDir]").description("Start the generator scripts.").action(async () => {
2886
- if (import_fs3.default.existsSync(import_node_path16.default.join(dir, ".env"))) {
2887
- import_dotenv.default.config({ path: import_node_path16.default.join(dir, ".env") });
2992
+ if (import_fs3.default.existsSync(import_node_path17.default.join(dir, ".env"))) {
2993
+ import_dotenv.default.config({ path: import_node_path17.default.join(dir, ".env") });
2888
2994
  }
2889
2995
  await generate(dir);
2890
2996
  });
@@ -2959,7 +3065,7 @@ var reportFederationProgress = (event) => {
2959
3065
  }
2960
3066
  return;
2961
3067
  case "hydrating":
2962
- logger.info(`Hydrating federated content into ${import_node_path16.default.relative(dir, event.outDir)}/...`, "federation");
3068
+ logger.info(`Hydrating federated content into ${import_node_path17.default.relative(dir, event.outDir)}/...`, "federation");
2963
3069
  return;
2964
3070
  case "hydrate:cache":
2965
3071
  if (event.files === 1 || event.files % 25 === 0) {
@@ -2988,13 +3094,13 @@ var reportFederationProgress = (event) => {
2988
3094
  `Federation complete: ${event.result.sources} sources, ${event.result.resources} remote resources, ${event.result.hydrate.written} files written (${event.result.hydrate.fetched} downloaded, ${event.result.hydrate.written - event.result.hydrate.fetched} cached)`,
2989
3095
  "federation"
2990
3096
  );
2991
- logger.info(`Pinned source commits in ${import_node_path16.default.relative(dir, event.result.lockPath)}`, "federation");
3097
+ logger.info(`Pinned source commits in ${import_node_path17.default.relative(dir, event.result.lockPath)}`, "federation");
2992
3098
  }
2993
3099
  };
2994
3100
  program.command("federate").description("Fetch, resolve, and hydrate the catalogs configured in federation.sources.").option("--no-cache", "Download all federation content and refresh the cache.").action(async (commandOptions) => {
2995
3101
  logger.welcome();
2996
- if (import_fs3.default.existsSync(import_node_path16.default.join(dir, ".env"))) {
2997
- import_dotenv.default.config({ path: import_node_path16.default.join(dir, ".env") });
3102
+ if (import_fs3.default.existsSync(import_node_path17.default.join(dir, ".env"))) {
3103
+ import_dotenv.default.config({ path: import_node_path17.default.join(dir, ".env") });
2998
3104
  }
2999
3105
  logger.info("Starting federation...", "federation");
3000
3106
  let cleanedPreviousOutput = false;