@eventcatalog/core 4.11.0 → 4.11.1

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 (60) 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/astro-output.cjs +60 -1
  6. package/dist/astro-output.js +1 -1
  7. package/dist/{chunk-U52FCZQ6.js → chunk-2YJRF4ZX.js} +1 -1
  8. package/dist/chunk-634NFV5U.js +75 -0
  9. package/dist/{chunk-SW7SJZIX.js → chunk-AXDNSGAN.js} +1 -1
  10. package/dist/chunk-DHH5U5PF.js +53 -0
  11. package/dist/{chunk-H3324DNT.js → chunk-DSCIWCX2.js} +1 -1
  12. package/dist/chunk-FWXEV4LF.js +19 -0
  13. package/dist/{chunk-XJOKK5ZO.js → chunk-GZVDXCYF.js} +1 -1
  14. package/dist/{chunk-W4LDIMUI.js → chunk-RYNPEIHQ.js} +1 -1
  15. package/dist/{chunk-DWC5GRFX.js → chunk-YYVW4DCO.js} +1 -1
  16. package/dist/constants.cjs +1 -1
  17. package/dist/constants.js +1 -1
  18. package/dist/copy-core.cjs +88 -0
  19. package/dist/copy-core.d.cts +4 -0
  20. package/dist/copy-core.d.ts +4 -0
  21. package/dist/copy-core.js +8 -0
  22. package/dist/eventcatalog.cjs +234 -115
  23. package/dist/eventcatalog.js +36 -30
  24. package/dist/federation/federate.js +3 -3
  25. package/dist/federation/source-provider.js +2 -2
  26. package/dist/generate.cjs +1 -1
  27. package/dist/generate.js +3 -3
  28. package/dist/update-check.cjs +44 -0
  29. package/dist/update-check.d.cts +18 -0
  30. package/dist/update-check.d.ts +18 -0
  31. package/dist/update-check.js +8 -0
  32. package/dist/utils/cli-logger.cjs +1 -1
  33. package/dist/utils/cli-logger.js +2 -2
  34. package/eventcatalog/astro.config.mjs +6 -0
  35. package/eventcatalog/src/plugins/empty-collection-warning.d.ts +21 -0
  36. package/eventcatalog/src/plugins/empty-collection-warning.mjs +107 -0
  37. package/eventcatalog/src/plugins/quiet-empty-collections-logger.mjs +11 -0
  38. package/eventcatalog/src/utils/collections/channels.ts +12 -4
  39. package/eventcatalog/src/utils/node-graphs/message-node-graph.ts +17 -15
  40. package/package.json +2 -1
  41. package/dist/chunk-RDYYZQYU.js +0 -18
  42. package/eventcatalog/src/components/EnvironmentDropdown.test.ts +0 -64
  43. package/eventcatalog/src/components/Grids/message-link.spec.ts +0 -59
  44. package/eventcatalog/src/components/MDX/CodeGroup/code-group.spec.tsx +0 -89
  45. package/eventcatalog/src/components/MDX/Columns/columns.spec.tsx +0 -66
  46. package/eventcatalog/src/components/MDX/CustomProperties/custom-properties.spec.ts +0 -38
  47. package/eventcatalog/src/components/MDX/SchemaViewer/schema-viewer-utils.spec.ts +0 -116
  48. package/eventcatalog/src/components/SchemaExplorer/JSONSchemaViewer.test.tsx +0 -114
  49. package/eventcatalog/src/components/SchemaExplorer/ProtobufSchemaViewer.test.tsx +0 -91
  50. package/eventcatalog/src/components/SchemaExplorer/SchemaViewerHover.test.tsx +0 -33
  51. package/eventcatalog/src/components/SchemaExplorer/protobuf-validation.test.ts +0 -84
  52. package/eventcatalog/src/components/Search/search-utils.spec.ts +0 -173
  53. package/eventcatalog/src/components/SideNav/NestedSideBar/utils.spec.ts +0 -105
  54. package/eventcatalog/src/components/navigation-progress.spec.ts +0 -68
  55. package/eventcatalog/src/enterprise/directory/user-team-directory.spec.ts +0 -527
  56. package/eventcatalog/src/enterprise/fields/field-extractor.test.ts +0 -302
  57. package/eventcatalog/src/enterprise/fields/fields-db.test.ts +0 -185
  58. package/eventcatalog/src/stores/eventcatalog-store.spec.ts +0 -60
  59. package/eventcatalog/src/utils/collections/glob-loader.spec.ts +0 -87
  60. package/dist/{chunk-6K7XZAYI.js → chunk-A2RZR3U4.js} +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_path18 = require("path");
32
+ var import_node_path19 = 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_path19 = __toESM(require("path"), 1);
35
+ var import_node_path20 = __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.11.0";
147
+ var version = "4.11.1";
148
148
 
149
149
  // src/constants.ts
150
150
  var VERSION = version;
@@ -1361,22 +1361,22 @@ function getAvroTypeName(type) {
1361
1361
  function walkAvroRecord(schema, prefix, fields) {
1362
1362
  if (!schema.fields || !Array.isArray(schema.fields)) return;
1363
1363
  for (const field of schema.fields) {
1364
- const path19 = prefix ? `${prefix}.${field.name}` : field.name;
1364
+ const path20 = prefix ? `${prefix}.${field.name}` : field.name;
1365
1365
  const isOptional = Array.isArray(field.type) && field.type.includes("null");
1366
1366
  const typeName = getAvroTypeName(field.type);
1367
1367
  fields.push({
1368
- path: path19,
1368
+ path: path20,
1369
1369
  type: typeName,
1370
1370
  description: field.doc || "",
1371
1371
  required: !isOptional
1372
1372
  });
1373
1373
  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;
1374
1374
  if (innerType) {
1375
- walkAvroRecord(innerType, path19, fields);
1375
+ walkAvroRecord(innerType, path20, fields);
1376
1376
  }
1377
1377
  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;
1378
1378
  if (arrayType && typeof arrayType.items === "object" && arrayType.items.type === "record") {
1379
- walkAvroRecord(arrayType.items, `${path19}[]`, fields);
1379
+ walkAvroRecord(arrayType.items, `${path20}[]`, fields);
1380
1380
  }
1381
1381
  }
1382
1382
  }
@@ -1407,32 +1407,32 @@ function walkJsonSchema(node, prefix, requiredList, rootSchema, fields) {
1407
1407
  }
1408
1408
  if (!node.properties) return;
1409
1409
  for (const [name, prop] of Object.entries(node.properties)) {
1410
- const path19 = prefix ? `${prefix}.${name}` : name;
1410
+ const path20 = prefix ? `${prefix}.${name}` : name;
1411
1411
  const isRequired = requiredList.includes(name);
1412
1412
  if (prop.$ref) {
1413
1413
  const resolved = resolveLocalRef(prop.$ref, rootSchema);
1414
1414
  if (resolved) {
1415
1415
  const rawRefType = resolved.type || "object";
1416
1416
  const type2 = Array.isArray(rawRefType) ? [...rawRefType].sort().join(" | ") : rawRefType;
1417
- fields.push({ path: path19, type: type2, description: resolved.description || "", required: isRequired });
1417
+ fields.push({ path: path20, type: type2, description: resolved.description || "", required: isRequired });
1418
1418
  if (resolved.properties) {
1419
- walkJsonSchema(resolved, path19, resolved.required || [], rootSchema, fields);
1419
+ walkJsonSchema(resolved, path20, resolved.required || [], rootSchema, fields);
1420
1420
  }
1421
1421
  } else {
1422
- fields.push({ path: path19, type: "$ref", description: "", required: isRequired });
1422
+ fields.push({ path: path20, type: "$ref", description: "", required: isRequired });
1423
1423
  }
1424
1424
  continue;
1425
1425
  }
1426
1426
  const rawType = prop.type || (prop.enum ? "enum" : prop.$ref ? "$ref" : "object");
1427
1427
  const typeList = Array.isArray(rawType) ? rawType : [rawType];
1428
1428
  const type = Array.isArray(rawType) ? [...rawType].sort().join(" | ") : rawType;
1429
- fields.push({ path: path19, type, description: prop.description || "", required: isRequired });
1429
+ fields.push({ path: path20, type, description: prop.description || "", required: isRequired });
1430
1430
  if (typeList.includes("object") && prop.properties) {
1431
- walkJsonSchema(prop, path19, prop.required || [], rootSchema, fields);
1431
+ walkJsonSchema(prop, path20, prop.required || [], rootSchema, fields);
1432
1432
  }
1433
1433
  if (typeList.includes("array") && prop.items) {
1434
1434
  if (prop.items.type === "object" && prop.items.properties) {
1435
- walkJsonSchema(prop.items, `${path19}[]`, prop.items.required || [], rootSchema, fields);
1435
+ walkJsonSchema(prop.items, `${path20}[]`, prop.items.required || [], rootSchema, fields);
1436
1436
  }
1437
1437
  }
1438
1438
  }
@@ -1941,11 +1941,117 @@ var linkCoreNodeModules = ({
1941
1941
  import_fs2.default.symlinkSync(installedCoreNodeModules, coreNodeModules, process.platform === "win32" ? "junction" : "dir");
1942
1942
  };
1943
1943
 
1944
+ // src/copy-core.ts
1945
+ var import_node_fs8 = __toESM(require("fs"), 1);
1946
+ var import_node_path12 = __toESM(require("path"), 1);
1947
+ var IGNORED_CORE_DIRECTORIES = /* @__PURE__ */ new Set([".astro", "dist", "node_modules", "__tests__"]);
1948
+ var COLOCATED_TEST_SUFFIXES = [
1949
+ ".spec.js",
1950
+ ".spec.jsx",
1951
+ ".spec.cjs",
1952
+ ".spec.mjs",
1953
+ ".spec.ts",
1954
+ ".spec.tsx",
1955
+ ".spec.cts",
1956
+ ".spec.mts",
1957
+ ".test.js",
1958
+ ".test.jsx",
1959
+ ".test.cjs",
1960
+ ".test.mjs",
1961
+ ".test.ts",
1962
+ ".test.tsx",
1963
+ ".test.cts",
1964
+ ".test.mts"
1965
+ ];
1966
+ var isColocatedTestFile = (fileName) => COLOCATED_TEST_SUFFIXES.some((suffix) => fileName.endsWith(suffix));
1967
+ var shouldCopyCoreEntry = (sourceRoot, sourcePath) => {
1968
+ const relativePath = import_node_path12.default.relative(sourceRoot, sourcePath);
1969
+ if (relativePath === "") return true;
1970
+ const pathParts = relativePath.split(import_node_path12.default.sep);
1971
+ if (pathParts.some((part) => IGNORED_CORE_DIRECTORIES.has(part))) return false;
1972
+ const fileName = pathParts[pathParts.length - 1] ?? "";
1973
+ return !isColocatedTestFile(fileName);
1974
+ };
1975
+ var PRUNE_SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([".astro", "dist", "node_modules"]);
1976
+ var pruneExcludedCoreEntries = (coreDir) => {
1977
+ if (!import_node_fs8.default.existsSync(coreDir)) return;
1978
+ const visit = (directory) => {
1979
+ for (const entry of import_node_fs8.default.readdirSync(directory, { withFileTypes: true })) {
1980
+ const entryPath = import_node_path12.default.join(directory, entry.name);
1981
+ if (entry.name === "__tests__" || isColocatedTestFile(entry.name)) {
1982
+ import_node_fs8.default.rmSync(entryPath, { recursive: true, force: true });
1983
+ continue;
1984
+ }
1985
+ if (entry.isDirectory() && !PRUNE_SKIPPED_DIRECTORIES.has(entry.name)) {
1986
+ visit(entryPath);
1987
+ }
1988
+ }
1989
+ };
1990
+ visit(coreDir);
1991
+ };
1992
+
1993
+ // eventcatalog/src/plugins/empty-collection-warning.mjs
1994
+ var KNOWN_EVENTCATALOG_COLLECTIONS = /* @__PURE__ */ new Set([
1995
+ "events",
1996
+ "commands",
1997
+ "queries",
1998
+ "examples",
1999
+ "services",
2000
+ "agents",
2001
+ "adrs",
2002
+ "channels",
2003
+ "users",
2004
+ "teams",
2005
+ "domains",
2006
+ "systems",
2007
+ "flows",
2008
+ "pages",
2009
+ "changelogs",
2010
+ "containers",
2011
+ "data-products",
2012
+ "ubiquitousLanguages",
2013
+ "entities",
2014
+ "customPages",
2015
+ "resourceDocs",
2016
+ "resourceDocCategories",
2017
+ "designs",
2018
+ "diagrams",
2019
+ "schemas",
2020
+ "sidebars"
2021
+ ]);
2022
+ var EMPTY_COLLECTION_MESSAGE = /^The collection ("(?:\\.|[^"\\])*") does not exist or is empty\. Please check your content config file for errors\.$/;
2023
+ var ANSI_PATTERN = /\u001B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g;
2024
+ var ASTRO_CONTENT_WARN_PREFIX = /^[^[\]]*\[WARN\]\s+\[content\](?:\s+\[[^\]]+\])*\s*$/;
2025
+ function collectionNameFromEmptyWarning(message) {
2026
+ const match = message.match(EMPTY_COLLECTION_MESSAGE);
2027
+ if (!match) return null;
2028
+ try {
2029
+ const name = JSON.parse(match[1]);
2030
+ return typeof name === "string" ? name : null;
2031
+ } catch {
2032
+ return null;
2033
+ }
2034
+ }
2035
+ function isIntentionalEmptyCollectionMessage(message) {
2036
+ const name = collectionNameFromEmptyWarning(message);
2037
+ return name !== null && KNOWN_EVENTCATALOG_COLLECTIONS.has(name);
2038
+ }
2039
+ function isIntentionalEmptyCollectionLine(line) {
2040
+ const plain = line.replace(ANSI_PATTERN, "").replace(/\r/g, "").trim();
2041
+ const marker = 'The collection "';
2042
+ const start = plain.indexOf(marker);
2043
+ if (start === -1) return false;
2044
+ const message = plain.slice(start).trim();
2045
+ if (!isIntentionalEmptyCollectionMessage(message)) return false;
2046
+ const before = plain.slice(0, start).trim();
2047
+ return before.length === 0 || ASTRO_CONTENT_WARN_PREFIX.test(before);
2048
+ }
2049
+
1944
2050
  // src/astro-output.ts
1945
2051
  var createAstroLineFilter = () => {
1946
2052
  return (line) => {
1947
2053
  const isIgnoredGetStaticPathsWarning = line.includes("[router]") && line.includes("getStaticPaths() ignored in dynamic page");
1948
- return line.includes("[glob-loader]") || isIgnoredGetStaticPathsWarning || /^\s*The collection ".*" does not exist or is empty\. Please check your content config file for errors\.\s*$/.test(line);
2054
+ return line.includes("[glob-loader]") || isIgnoredGetStaticPathsWarning || isIntentionalEmptyCollectionLine(line);
1949
2055
  };
1950
2056
  };
1951
2057
  var createAstroDevLineFilter = () => {
@@ -1958,18 +2064,18 @@ var createAstroDevLineFilter = () => {
1958
2064
  // src/federation/federate.ts
1959
2065
  var import_node_crypto5 = require("crypto");
1960
2066
  var import_promises10 = __toESM(require("fs/promises"), 1);
1961
- var import_node_path17 = __toESM(require("path"), 1);
2067
+ var import_node_path18 = __toESM(require("path"), 1);
1962
2068
  var import_sdk3 = __toESM(require("@eventcatalog/sdk"), 1);
1963
2069
 
1964
2070
  // src/federation/content-cache.ts
1965
2071
  var import_node_crypto2 = require("crypto");
1966
2072
  var import_promises5 = __toESM(require("fs/promises"), 1);
1967
- var import_node_path12 = __toESM(require("path"), 1);
2073
+ var import_node_path13 = __toESM(require("path"), 1);
1968
2074
  var getContentHash = (content) => `sha256:${(0, import_node_crypto2.createHash)("sha256").update(content).digest("hex")}`;
1969
2075
  var isContentHash = (key) => /^sha256:[a-f0-9]{64}$/i.test(key);
1970
2076
  var createFederationContentCache = (projectDirectory, options = {}) => {
1971
- const cacheDirectory = import_node_path12.default.join(projectDirectory, ".eventcatalog-cache", "federation", "content");
1972
- const getCachePath = (key) => import_node_path12.default.join(cacheDirectory, encodeURIComponent(key));
2077
+ const cacheDirectory = import_node_path13.default.join(projectDirectory, ".eventcatalog-cache", "federation", "content");
2078
+ const getCachePath = (key) => import_node_path13.default.join(cacheDirectory, encodeURIComponent(key));
1973
2079
  return {
1974
2080
  async get(key) {
1975
2081
  if (options.read === false || !isContentHash(key)) return void 0;
@@ -2160,20 +2266,20 @@ var isFederationEnabled = () => (0, import_license.isEventCatalogEnterpriseEnabl
2160
2266
 
2161
2267
  // src/federation/output-transaction.ts
2162
2268
  var import_promises6 = __toESM(require("fs/promises"), 1);
2163
- var import_node_path13 = __toESM(require("path"), 1);
2269
+ var import_node_path14 = __toESM(require("path"), 1);
2164
2270
  var getSafePublicPath = (publicDirectory, relativePath) => {
2165
- const normalizedPath = import_node_path13.default.posix.normalize(relativePath);
2166
- 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("../");
2271
+ const normalizedPath = import_node_path14.default.posix.normalize(relativePath);
2272
+ const unsafe = relativePath.length === 0 || relativePath.includes("\0") || relativePath.includes("\\") || import_node_path14.default.posix.isAbsolute(relativePath) || /^[a-zA-Z]:\//.test(relativePath) || normalizedPath !== relativePath || normalizedPath === ".." || normalizedPath.startsWith("../");
2167
2273
  if (unsafe) return void 0;
2168
- const destinationPath = import_node_path13.default.resolve(publicDirectory, relativePath);
2169
- const relativeDestinationPath = import_node_path13.default.relative(publicDirectory, destinationPath);
2170
- return relativeDestinationPath !== "" && relativeDestinationPath !== ".." && !relativeDestinationPath.startsWith(`..${import_node_path13.default.sep}`) && !import_node_path13.default.isAbsolute(relativeDestinationPath) ? destinationPath : void 0;
2274
+ const destinationPath = import_node_path14.default.resolve(publicDirectory, relativePath);
2275
+ const relativeDestinationPath = import_node_path14.default.relative(publicDirectory, destinationPath);
2276
+ return relativeDestinationPath !== "" && relativeDestinationPath !== ".." && !relativeDestinationPath.startsWith(`..${import_node_path14.default.sep}`) && !import_node_path14.default.isAbsolute(relativeDestinationPath) ? destinationPath : void 0;
2171
2277
  };
2172
2278
  var beginFederationOutputTransaction = async (projectDirectory, outDir, relativePublicPaths) => {
2173
- const transactionDirectory = await import_promises6.default.mkdtemp(import_node_path13.default.join(projectDirectory, ".eventcatalog-federation-transaction-"));
2174
- const previousOutDir = import_node_path13.default.join(transactionDirectory, "federated");
2175
- const publicBackupDirectory = import_node_path13.default.join(transactionDirectory, "public");
2176
- const publicDirectory = import_node_path13.default.resolve(projectDirectory, "public");
2279
+ const transactionDirectory = await import_promises6.default.mkdtemp(import_node_path14.default.join(projectDirectory, ".eventcatalog-federation-transaction-"));
2280
+ const previousOutDir = import_node_path14.default.join(transactionDirectory, "federated");
2281
+ const publicBackupDirectory = import_node_path14.default.join(transactionDirectory, "public");
2282
+ const publicDirectory = import_node_path14.default.resolve(projectDirectory, "public");
2177
2283
  const publicSnapshots = [];
2178
2284
  const missingPublicDirectories = /* @__PURE__ */ new Set();
2179
2285
  let hadPreviousOutDir = false;
@@ -2184,8 +2290,8 @@ var beginFederationOutputTransaction = async (projectDirectory, outDir, relative
2184
2290
  try {
2185
2291
  const stat = await import_promises6.default.lstat(destinationPath);
2186
2292
  if (!stat.isFile()) continue;
2187
- const backupPath = import_node_path13.default.join(publicBackupDirectory, `${publicSnapshots.length}`);
2188
- await import_promises6.default.mkdir(import_node_path13.default.dirname(backupPath), { recursive: true });
2293
+ const backupPath = import_node_path14.default.join(publicBackupDirectory, `${publicSnapshots.length}`);
2294
+ await import_promises6.default.mkdir(import_node_path14.default.dirname(backupPath), { recursive: true });
2189
2295
  await import_promises6.default.copyFile(destinationPath, backupPath);
2190
2296
  publicSnapshots.push({ backupPath, destinationPath, state: "file" });
2191
2297
  } catch (error) {
@@ -2193,7 +2299,7 @@ var beginFederationOutputTransaction = async (projectDirectory, outDir, relative
2193
2299
  if (code === "ENOTDIR") continue;
2194
2300
  if (code !== "ENOENT") throw error;
2195
2301
  publicSnapshots.push({ destinationPath, state: "missing" });
2196
- let directory = import_node_path13.default.dirname(destinationPath);
2302
+ let directory = import_node_path14.default.dirname(destinationPath);
2197
2303
  while (directory !== publicDirectory) {
2198
2304
  try {
2199
2305
  await import_promises6.default.lstat(directory);
@@ -2203,7 +2309,7 @@ var beginFederationOutputTransaction = async (projectDirectory, outDir, relative
2203
2309
  if (directoryCode === "ENOTDIR") break;
2204
2310
  if (directoryCode !== "ENOENT") throw directoryError;
2205
2311
  missingPublicDirectories.add(directory);
2206
- directory = import_node_path13.default.dirname(directory);
2312
+ directory = import_node_path14.default.dirname(directory);
2207
2313
  }
2208
2314
  }
2209
2315
  }
@@ -2239,7 +2345,7 @@ var beginFederationOutputTransaction = async (projectDirectory, outDir, relative
2239
2345
  continue;
2240
2346
  }
2241
2347
  await attempt(async () => {
2242
- await import_promises6.default.mkdir(import_node_path13.default.dirname(snapshot.destinationPath), { recursive: true });
2348
+ await import_promises6.default.mkdir(import_node_path14.default.dirname(snapshot.destinationPath), { recursive: true });
2243
2349
  await import_promises6.default.copyFile(snapshot.backupPath, snapshot.destinationPath);
2244
2350
  });
2245
2351
  }
@@ -2276,7 +2382,7 @@ var withFederationOutputTransaction = async (projectDirectory, outDir, relativeP
2276
2382
  // src/federation/public-assets.ts
2277
2383
  var import_node_crypto3 = require("crypto");
2278
2384
  var import_promises7 = __toESM(require("fs/promises"), 1);
2279
- var import_node_path14 = __toESM(require("path"), 1);
2385
+ var import_node_path15 = __toESM(require("path"), 1);
2280
2386
  var getContentHash2 = (content) => `sha256:${(0, import_node_crypto3.createHash)("sha256").update(content).digest("hex")}`;
2281
2387
  var getFileHash = async (filePath) => {
2282
2388
  try {
@@ -2288,13 +2394,13 @@ var getFileHash = async (filePath) => {
2288
2394
  }
2289
2395
  };
2290
2396
  var getSafePath = (directory, relativePath) => {
2291
- const normalizedPath = import_node_path14.default.posix.normalize(relativePath);
2292
- const unsafe = relativePath.length === 0 || relativePath.includes("\0") || relativePath.includes("\\") || import_node_path14.default.posix.isAbsolute(relativePath) || /^[a-zA-Z]:\//.test(relativePath) || normalizedPath !== relativePath || normalizedPath === ".." || normalizedPath.startsWith("../");
2397
+ const normalizedPath = import_node_path15.default.posix.normalize(relativePath);
2398
+ const unsafe = relativePath.length === 0 || relativePath.includes("\0") || relativePath.includes("\\") || import_node_path15.default.posix.isAbsolute(relativePath) || /^[a-zA-Z]:\//.test(relativePath) || normalizedPath !== relativePath || normalizedPath === ".." || normalizedPath.startsWith("../");
2293
2399
  if (unsafe) return void 0;
2294
- const resolvedDirectory = import_node_path14.default.resolve(directory);
2295
- const resolvedPath = import_node_path14.default.resolve(resolvedDirectory, relativePath);
2296
- const relativeResolvedPath = import_node_path14.default.relative(resolvedDirectory, resolvedPath);
2297
- if (relativeResolvedPath === "" || relativeResolvedPath === ".." || relativeResolvedPath.startsWith(`..${import_node_path14.default.sep}`) || import_node_path14.default.isAbsolute(relativeResolvedPath)) {
2400
+ const resolvedDirectory = import_node_path15.default.resolve(directory);
2401
+ const resolvedPath = import_node_path15.default.resolve(resolvedDirectory, relativePath);
2402
+ const relativeResolvedPath = import_node_path15.default.relative(resolvedDirectory, resolvedPath);
2403
+ if (relativeResolvedPath === "" || relativeResolvedPath === ".." || relativeResolvedPath.startsWith(`..${import_node_path15.default.sep}`) || import_node_path15.default.isAbsolute(relativeResolvedPath)) {
2298
2404
  return void 0;
2299
2405
  }
2300
2406
  return resolvedPath;
@@ -2302,16 +2408,16 @@ var getSafePath = (directory, relativePath) => {
2302
2408
  var listFiles = async (directory, relativeDirectory = "") => {
2303
2409
  let entries;
2304
2410
  try {
2305
- entries = await import_promises7.default.readdir(import_node_path14.default.join(directory, relativeDirectory), { withFileTypes: true });
2411
+ entries = await import_promises7.default.readdir(import_node_path15.default.join(directory, relativeDirectory), { withFileTypes: true });
2306
2412
  } catch (error) {
2307
2413
  if (error.code === "ENOENT") return [];
2308
2414
  throw error;
2309
2415
  }
2310
2416
  const files = await Promise.all(
2311
2417
  entries.map(async (entry) => {
2312
- const relativePath = import_node_path14.default.join(relativeDirectory, entry.name);
2418
+ const relativePath = import_node_path15.default.join(relativeDirectory, entry.name);
2313
2419
  if (entry.isDirectory()) return listFiles(directory, relativePath);
2314
- return entry.isFile() ? [relativePath.split(import_node_path14.default.sep).join("/")] : [];
2420
+ return entry.isFile() ? [relativePath.split(import_node_path15.default.sep).join("/")] : [];
2315
2421
  })
2316
2422
  );
2317
2423
  return files.flat().sort();
@@ -2326,19 +2432,19 @@ var pathExists = async (filePath) => {
2326
2432
  }
2327
2433
  };
2328
2434
  var hasBlockingParent = async (publicDirectory, destinationPath) => {
2329
- let currentPath = import_node_path14.default.dirname(destinationPath);
2435
+ let currentPath = import_node_path15.default.dirname(destinationPath);
2330
2436
  while (currentPath !== publicDirectory) {
2331
2437
  try {
2332
2438
  if (!(await import_promises7.default.lstat(currentPath)).isDirectory()) return true;
2333
2439
  } catch (error) {
2334
2440
  if (error.code !== "ENOENT") throw error;
2335
2441
  }
2336
- currentPath = import_node_path14.default.dirname(currentPath);
2442
+ currentPath = import_node_path15.default.dirname(currentPath);
2337
2443
  }
2338
2444
  return false;
2339
2445
  };
2340
2446
  var pruneEmptyDirectories = async (publicDirectory, filePath) => {
2341
- let currentPath = import_node_path14.default.dirname(filePath);
2447
+ let currentPath = import_node_path15.default.dirname(filePath);
2342
2448
  while (currentPath !== publicDirectory) {
2343
2449
  try {
2344
2450
  await import_promises7.default.rmdir(currentPath);
@@ -2346,7 +2452,7 @@ var pruneEmptyDirectories = async (publicDirectory, filePath) => {
2346
2452
  if (!["ENOENT", "ENOTEMPTY"].includes(error.code ?? "")) throw error;
2347
2453
  if (error.code === "ENOTEMPTY") return;
2348
2454
  }
2349
- currentPath = import_node_path14.default.dirname(currentPath);
2455
+ currentPath = import_node_path15.default.dirname(currentPath);
2350
2456
  }
2351
2457
  };
2352
2458
  var composePublicAssets = async ({
@@ -2356,8 +2462,8 @@ var composePublicAssets = async ({
2356
2462
  previousFiles = {},
2357
2463
  collisionPaths = /* @__PURE__ */ new Set()
2358
2464
  }) => {
2359
- const publicDirectory = import_node_path14.default.resolve(projectDirectory, "public");
2360
- const federatedPublicDirectory = import_node_path14.default.resolve(federatedDirectory, "public");
2465
+ const publicDirectory = import_node_path15.default.resolve(projectDirectory, "public");
2466
+ const federatedPublicDirectory = import_node_path15.default.resolve(federatedDirectory, "public");
2361
2467
  const sourceFiles = await listFiles(federatedPublicDirectory);
2362
2468
  const sourceFileSet = new Set(sourceFiles);
2363
2469
  const managedFiles = /* @__PURE__ */ new Set();
@@ -2393,7 +2499,7 @@ var composePublicAssets = async ({
2393
2499
  const asset = publicAssetsByPath.get(relativePath);
2394
2500
  if (!asset) throw new Error(`Cannot identify the source of federated public asset "${relativePath}"`);
2395
2501
  const content = await import_promises7.default.readFile(sourcePath);
2396
- await import_promises7.default.mkdir(import_node_path14.default.dirname(destinationPath), { recursive: true });
2502
+ await import_promises7.default.mkdir(import_node_path15.default.dirname(destinationPath), { recursive: true });
2397
2503
  await import_promises7.default.writeFile(destinationPath, content);
2398
2504
  files[relativePath] = { source: asset.resolvedFrom.source, hash: getContentHash2(content) };
2399
2505
  copied += 1;
@@ -2406,17 +2512,17 @@ var composePublicAssets = async ({
2406
2512
  // src/federation/filesystem-source-provider.ts
2407
2513
  var import_node_crypto4 = require("crypto");
2408
2514
  var import_promises8 = __toESM(require("fs/promises"), 1);
2409
- var import_node_path15 = __toESM(require("path"), 1);
2515
+ var import_node_path16 = __toESM(require("path"), 1);
2410
2516
  var import_sdk = __toESM(require("@eventcatalog/sdk"), 1);
2411
2517
  var FILESYSTEM_SOURCE_PREFIX = "file:";
2412
2518
  var isWithinDirectory = (directory, target) => {
2413
- const relativePath = import_node_path15.default.relative(directory, target);
2414
- return relativePath === "" || !relativePath.startsWith(`..${import_node_path15.default.sep}`) && relativePath !== ".." && !import_node_path15.default.isAbsolute(relativePath);
2519
+ const relativePath = import_node_path16.default.relative(directory, target);
2520
+ return relativePath === "" || !relativePath.startsWith(`..${import_node_path16.default.sep}`) && relativePath !== ".." && !import_node_path16.default.isAbsolute(relativePath);
2415
2521
  };
2416
2522
  var assertPortableRelativePath = (filePath, label, allowRoot = true) => {
2417
2523
  const portablePath = filePath.replaceAll("\\", "/");
2418
- const normalizedPath = import_node_path15.default.posix.normalize(portablePath);
2419
- const isUnsafe = filePath.includes("\\") || filePath.includes("\0") || import_node_path15.default.posix.isAbsolute(normalizedPath) || /^[a-zA-Z]:\//.test(normalizedPath) || normalizedPath === ".." || normalizedPath.startsWith("../") || !allowRoot && (normalizedPath === "." || normalizedPath === "");
2524
+ const normalizedPath = import_node_path16.default.posix.normalize(portablePath);
2525
+ const isUnsafe = filePath.includes("\\") || filePath.includes("\0") || import_node_path16.default.posix.isAbsolute(normalizedPath) || /^[a-zA-Z]:\//.test(normalizedPath) || normalizedPath === ".." || normalizedPath.startsWith("../") || !allowRoot && (normalizedPath === "." || normalizedPath === "");
2420
2526
  if (isUnsafe) throw new Error(`${label} "${filePath}" escapes its filesystem source`);
2421
2527
  return normalizedPath;
2422
2528
  };
@@ -2426,13 +2532,13 @@ var getSourceRoot = (projectDirectory, source) => {
2426
2532
  }
2427
2533
  const locator = source.source.slice(FILESYSTEM_SOURCE_PREFIX.length);
2428
2534
  if (!locator.trim()) throw new Error(`Filesystem federation source "${source.id}" requires a path after "file:".`);
2429
- return import_node_path15.default.resolve(projectDirectory, locator);
2535
+ return import_node_path16.default.resolve(projectDirectory, locator);
2430
2536
  };
2431
2537
  var getCatalogDirectory = async (projectDirectory, source) => {
2432
2538
  if (source.ref) throw new Error(`Filesystem federation source "${source.id}" does not support "ref".`);
2433
2539
  const sourceRoot = getSourceRoot(projectDirectory, source);
2434
2540
  const catalogPath = assertPortableRelativePath(source.path ?? ".", "Catalog path");
2435
- const catalogDirectory = import_node_path15.default.resolve(sourceRoot, ...catalogPath.split("/"));
2541
+ const catalogDirectory = import_node_path16.default.resolve(sourceRoot, ...catalogPath.split("/"));
2436
2542
  if (!isWithinDirectory(sourceRoot, catalogDirectory)) {
2437
2543
  throw new Error(`Catalog path "${source.path}" escapes source "${source.id}"`);
2438
2544
  }
@@ -2454,7 +2560,7 @@ var getCatalogDirectory = async (projectDirectory, source) => {
2454
2560
  };
2455
2561
  var getArtifactPath = async (catalogDirectory, source, artifactPath) => {
2456
2562
  const normalizedPath = assertPortableRelativePath(artifactPath, "Federated artifact path", false);
2457
- const filePath = import_node_path15.default.resolve(catalogDirectory, ...normalizedPath.split("/"));
2563
+ const filePath = import_node_path16.default.resolve(catalogDirectory, ...normalizedPath.split("/"));
2458
2564
  if (!isWithinDirectory(catalogDirectory, filePath)) {
2459
2565
  throw new Error(`Federated artifact path "${artifactPath}" escapes source "${source.id}"`);
2460
2566
  }
@@ -2494,7 +2600,7 @@ var createFileSystemSourceProvider = (projectDirectory) => ({
2494
2600
  var import_node_child_process = require("child_process");
2495
2601
  var import_promises9 = __toESM(require("fs/promises"), 1);
2496
2602
  var import_node_os4 = __toESM(require("os"), 1);
2497
- var import_node_path16 = __toESM(require("path"), 1);
2603
+ var import_node_path17 = __toESM(require("path"), 1);
2498
2604
  var import_node_util = require("util");
2499
2605
  var import_sdk2 = __toESM(require("@eventcatalog/sdk"), 1);
2500
2606
  var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
@@ -2505,8 +2611,8 @@ var parseGitHubSource = (source) => {
2505
2611
  };
2506
2612
  var assertSafeCatalogPath = (source) => {
2507
2613
  const catalogPath = source.path ?? ".";
2508
- const normalized = import_node_path16.default.posix.normalize(catalogPath.replaceAll("\\", "/"));
2509
- if (catalogPath.includes("\\") || import_node_path16.default.posix.isAbsolute(normalized) || normalized === ".." || normalized.startsWith("../")) {
2614
+ const normalized = import_node_path17.default.posix.normalize(catalogPath.replaceAll("\\", "/"));
2615
+ if (catalogPath.includes("\\") || import_node_path17.default.posix.isAbsolute(normalized) || normalized === ".." || normalized.startsWith("../")) {
2510
2616
  throw new Error(`Catalog path "${catalogPath}" escapes source "${source.id}"`);
2511
2617
  }
2512
2618
  };
@@ -2549,8 +2655,8 @@ var getGitEnvironment = (token) => {
2549
2655
  };
2550
2656
  var createCheckout = (executeFile, token) => async (source, ref, callback) => {
2551
2657
  const { owner, repository } = parseGitHubSource(source);
2552
- const catalogPath = import_node_path16.default.posix.normalize(source.path ?? ".");
2553
- const directory = await import_promises9.default.mkdtemp(import_node_path16.default.join(import_node_os4.default.tmpdir(), "eventcatalog-federation-"));
2658
+ const catalogPath = import_node_path17.default.posix.normalize(source.path ?? ".");
2659
+ const directory = await import_promises9.default.mkdtemp(import_node_path17.default.join(import_node_os4.default.tmpdir(), "eventcatalog-federation-"));
2554
2660
  const env = getGitEnvironment(token);
2555
2661
  try {
2556
2662
  const git = (args) => executeFile("git", args, { cwd: directory, env, encoding: "utf8" });
@@ -2570,16 +2676,16 @@ var createCheckout = (executeFile, token) => async (source, ref, callback) => {
2570
2676
  var generateIndex = async (source, ref, checkout, executeFile) => checkout(source, ref, async (directory) => {
2571
2677
  const { stdout } = await executeFile("git", ["rev-parse", "HEAD"], { cwd: directory, encoding: "utf8" });
2572
2678
  const commit = stdout.trim();
2573
- const catalogDirectory = import_node_path16.default.resolve(directory, source.path ?? ".");
2574
- const relativeCatalogDirectory = import_node_path16.default.relative(directory, catalogDirectory);
2575
- if (relativeCatalogDirectory.startsWith("..") || import_node_path16.default.isAbsolute(relativeCatalogDirectory)) {
2679
+ const catalogDirectory = import_node_path17.default.resolve(directory, source.path ?? ".");
2680
+ const relativeCatalogDirectory = import_node_path17.default.relative(directory, catalogDirectory);
2681
+ if (relativeCatalogDirectory.startsWith("..") || import_node_path17.default.isAbsolute(relativeCatalogDirectory)) {
2576
2682
  throw new Error(`Catalog path "${source.path}" escapes source "${source.id}"`);
2577
2683
  }
2578
2684
  const index = await (0, import_sdk2.default)(catalogDirectory).buildIndex({ source: source.id, commit });
2579
2685
  return { bytes: Buffer.from(JSON.stringify(index)), index, commit, generated: true };
2580
2686
  });
2581
2687
  var fetchPublishedIndex = async (source, ref, fetcher, token) => {
2582
- const indexPath = import_node_path16.default.posix.join(source.path ?? ".", "catalog.index.json");
2688
+ const indexPath = import_node_path17.default.posix.join(source.path ?? ".", "catalog.index.json");
2583
2689
  const bytes = await fetchBytes(source, ref, indexPath, fetcher, token);
2584
2690
  if (!bytes) return void 0;
2585
2691
  const index = (0, import_sdk2.parseIndex)(JSON.parse(bytes.toString("utf8")));
@@ -2602,7 +2708,7 @@ var createGitHubSourceProvider = (options = {}) => {
2602
2708
  },
2603
2709
  async fetchContent({ source, commit, path: artifactPath }) {
2604
2710
  assertSafeCatalogPath(source);
2605
- const catalogPath = import_node_path16.default.posix.join(source.path ?? ".", artifactPath);
2711
+ const catalogPath = import_node_path17.default.posix.join(source.path ?? ".", artifactPath);
2606
2712
  const content = await fetchBytes(source, commit, catalogPath, fetcher, token);
2607
2713
  if (!content) throw new Error(`Federated artifact not found for "${source.id}": ${artifactPath}`);
2608
2714
  return content;
@@ -2713,8 +2819,8 @@ var pathExists2 = async (filePath) => {
2713
2819
  }
2714
2820
  };
2715
2821
  var cleanupPreviousFederation = async (projectDirectory, onProgress) => {
2716
- const outDir = import_node_path17.default.join(projectDirectory, "federated");
2717
- const lockPath = import_node_path17.default.join(projectDirectory, "eventcatalog.lock");
2822
+ const outDir = import_node_path18.default.join(projectDirectory, "federated");
2823
+ const lockPath = import_node_path18.default.join(projectDirectory, "eventcatalog.lock");
2718
2824
  const previousLock = await readLock(lockPath);
2719
2825
  const hadFederatedOutput = await pathExists2(outDir);
2720
2826
  const hadLock = previousLock !== void 0;
@@ -2779,8 +2885,8 @@ var federateCatalog = async (projectDirectory, options = {}) => {
2779
2885
  throw new Error(`Failed to federate source "${source.id}": ${message}`, { cause: error });
2780
2886
  }
2781
2887
  }
2782
- const outDir = import_node_path17.default.join(projectDirectory, "federated");
2783
- const lockPath = import_node_path17.default.join(projectDirectory, "eventcatalog.lock");
2888
+ const outDir = import_node_path18.default.join(projectDirectory, "federated");
2889
+ const lockPath = import_node_path18.default.join(projectDirectory, "eventcatalog.lock");
2784
2890
  const previousLock = await readLock(lockPath);
2785
2891
  const resources = resolvedSources.reduce((total, source) => total + source.resolved.index.resources.length, 0);
2786
2892
  const remoteIndexes = resolvedSources.map(({ resolved }) => resolved.index);
@@ -2876,16 +2982,31 @@ var federateCatalog = async (projectDirectory, options = {}) => {
2876
2982
  return result;
2877
2983
  };
2878
2984
 
2985
+ // src/update-check.ts
2986
+ var import_semver = require("semver");
2987
+ var resolveInstalledCoreVersion = (runningVersion, declaredDependency) => {
2988
+ if ((0, import_semver.valid)(runningVersion)) return runningVersion;
2989
+ if (declaredDependency && (0, import_semver.valid)(declaredDependency)) return declaredDependency;
2990
+ return null;
2991
+ };
2992
+ var getEventCatalogUpdateMessage = (current, latest) => {
2993
+ if (!latest || !(0, import_semver.valid)(current) || !(0, import_semver.valid)(latest) || !(0, import_semver.gt)(latest, current)) {
2994
+ return null;
2995
+ }
2996
+ return `EventCatalog update available ${current} \u2192 ${latest}
2997
+ Run npm i @eventcatalog/core to update`;
2998
+ };
2999
+
2879
3000
  // src/eventcatalog.ts
2880
3001
  var import_license2 = require("@eventcatalog/license");
2881
- var currentDir = import_node_path19.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
3002
+ var currentDir = import_node_path20.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
2882
3003
  var program = new import_commander.Command().version(VERSION);
2883
- var dir = import_node_path19.default.resolve(process.env.PROJECT_DIR || process.cwd());
2884
- var core = import_node_path19.default.resolve(process.env.CATALOG_DIR || (0, import_node_path18.join)(dir, ".eventcatalog-core"));
2885
- var eventCatalogDir = import_node_path19.default.resolve((0, import_node_path18.join)(currentDir, "../eventcatalog/"));
3004
+ var dir = import_node_path20.default.resolve(process.env.PROJECT_DIR || process.cwd());
3005
+ var core = import_node_path20.default.resolve(process.env.CATALOG_DIR || (0, import_node_path19.join)(dir, ".eventcatalog-core"));
3006
+ var eventCatalogDir = import_node_path20.default.resolve((0, import_node_path19.join)(currentDir, "../eventcatalog/"));
2886
3007
  var getInstalledEventCatalogVersion = () => {
2887
3008
  try {
2888
- const pkg = import_fs3.default.readFileSync((0, import_node_path18.join)(dir, "package.json"), "utf8");
3009
+ const pkg = import_fs3.default.readFileSync((0, import_node_path19.join)(dir, "package.json"), "utf8");
2889
3010
  const json = JSON.parse(pkg);
2890
3011
  return json.dependencies["@eventcatalog/core"];
2891
3012
  } catch (error) {
@@ -2951,12 +3072,12 @@ var startDevPrewarm = ({
2951
3072
  var buildDevSearchIndex = async ({ config }) => {
2952
3073
  const result = await buildSearchIndex({
2953
3074
  projectDir: dir,
2954
- outDir: import_node_path19.default.join(core, "public"),
2955
- searchOutputPath: import_node_path19.default.join(core, "public", "pagefind"),
3075
+ outDir: import_node_path20.default.join(core, "public"),
3076
+ searchOutputPath: import_node_path20.default.join(core, "public", "pagefind"),
2956
3077
  config,
2957
3078
  isServer: false
2958
3079
  });
2959
- logger.info(`Indexed ${result.records} page(s) into ${import_node_path19.default.relative(core, result.outputPath)}`, "search");
3080
+ logger.info(`Indexed ${result.records} page(s) into ${import_node_path20.default.relative(core, result.outputPath)}`, "search");
2960
3081
  };
2961
3082
  var warnIfIndexedSearchUsesAuth = async () => {
2962
3083
  if (!await isAuthEnabled()) {
@@ -3070,13 +3191,10 @@ var copyCore = () => {
3070
3191
  }
3071
3192
  import_fs3.default.cpSync(eventCatalogDir, core, {
3072
3193
  recursive: true,
3073
- filter: (src) => {
3074
- const relativePath = import_node_path19.default.relative(eventCatalogDir, src);
3075
- const pathParts = relativePath.split(import_node_path19.default.sep);
3076
- return !pathParts.some((part) => [".astro", "dist", "node_modules"].includes(part));
3077
- }
3194
+ filter: (src) => shouldCopyCoreEntry(eventCatalogDir, src)
3078
3195
  });
3079
- const coreNodeModules = import_node_path19.default.join(core, "node_modules");
3196
+ pruneExcludedCoreEntries(core);
3197
+ const coreNodeModules = import_node_path20.default.join(core, "node_modules");
3080
3198
  const installedCoreNodeModules = resolveInstalledCoreNodeModules(currentDir);
3081
3199
  linkCoreNodeModules({ coreNodeModules, installedCoreNodeModules });
3082
3200
  };
@@ -3084,13 +3202,13 @@ var clearCore = () => {
3084
3202
  if (import_fs3.default.existsSync(core)) import_fs3.default.rmSync(core, { recursive: true });
3085
3203
  };
3086
3204
  var checkForUpdate = () => {
3087
- const installedVersion = getInstalledEventCatalogVersion();
3088
- if (!installedVersion) return;
3089
- const majorVersion = parseInt(installedVersion.replace(/[^0-9.]/g, "").split(".")[0], 10);
3205
+ const declaredVersion = getInstalledEventCatalogVersion();
3206
+ if (!declaredVersion) return;
3207
+ const majorVersion = parseInt(declaredVersion.replace(/[^0-9.]/g, "").split(".")[0], 10);
3090
3208
  if (majorVersion < 3) {
3091
3209
  const v3Message = `\u{1F680} EventCatalog V3 is now available in beta!
3092
3210
 
3093
- You are currently on version ${installedVersion}.
3211
+ You are currently on version ${declaredVersion}.
3094
3212
  V3 brings exciting new features and improvements.
3095
3213
 
3096
3214
  Upgrade now: npm i @eventcatalog/core@beta`;
@@ -3105,11 +3223,12 @@ Upgrade now: npm i @eventcatalog/core@beta`;
3105
3223
  );
3106
3224
  return;
3107
3225
  }
3226
+ const installedVersion = resolveInstalledCoreVersion(VERSION, declaredVersion);
3227
+ if (!installedVersion) return;
3108
3228
  const pkg = { name: "@eventcatalog/core", version: installedVersion };
3109
3229
  const notifier = (0, import_update_notifier.default)({ pkg, updateCheckInterval: 0 });
3110
- if (notifier.update) {
3111
- const message = `EventCatalog update available ${notifier.update.current} \u2192 ${notifier.update.latest}
3112
- Run npm i @eventcatalog/core to update`;
3230
+ const message = getEventCatalogUpdateMessage(installedVersion, notifier.update?.latest);
3231
+ if (message) {
3113
3232
  console.log(
3114
3233
  (0, import_boxen.default)(message, {
3115
3234
  padding: 1,
@@ -3135,8 +3254,8 @@ program.command("dev").description("Run development server of EventCatalog").opt
3135
3254
  logger.info("Setting up EventCatalog...", "eventcatalog");
3136
3255
  const isServer = await isOutputServer();
3137
3256
  logger.info(isServer ? "EventCatalog is running in Server Mode" : "EventCatalog is running in Static Mode", "config");
3138
- if (import_fs3.default.existsSync(import_node_path19.default.join(dir, ".env"))) {
3139
- import_dotenv.default.config({ path: import_node_path19.default.join(dir, ".env") });
3257
+ if (import_fs3.default.existsSync(import_node_path20.default.join(dir, ".env"))) {
3258
+ import_dotenv.default.config({ path: import_node_path20.default.join(dir, ".env") });
3140
3259
  }
3141
3260
  if (options.debug) {
3142
3261
  logger.info("Debug mode enabled", "debug");
@@ -3222,8 +3341,8 @@ program.command("build").description("Run build of EventCatalog").action(async (
3222
3341
  logger.info("Building EventCatalog...", "build");
3223
3342
  const isServer = await isOutputServer();
3224
3343
  logger.info(isServer ? "EventCatalog is running in Server Mode" : "EventCatalog is running in Static Mode", "config");
3225
- if (import_fs3.default.existsSync(import_node_path19.default.join(dir, ".env"))) {
3226
- import_dotenv.default.config({ path: import_node_path19.default.join(dir, ".env") });
3344
+ if (import_fs3.default.existsSync(import_node_path20.default.join(dir, ".env"))) {
3345
+ import_dotenv.default.config({ path: import_node_path20.default.join(dir, ".env") });
3227
3346
  }
3228
3347
  await verifyRequiredFieldsAreInCatalogConfigFile(dir);
3229
3348
  copyCore();
@@ -3274,7 +3393,7 @@ program.command("build").description("Run build of EventCatalog").action(async (
3274
3393
  if (await isIndexedSearchEnabled()) {
3275
3394
  await warnIfIndexedSearchUsesAuth();
3276
3395
  const config = await getEventCatalogConfigFile(dir);
3277
- const outDir = import_node_path19.default.resolve(dir, await getProjectOutDir());
3396
+ const outDir = import_node_path20.default.resolve(dir, await getProjectOutDir());
3278
3397
  logger.info("Building indexed search...", "search");
3279
3398
  const result = await buildSearchIndex({
3280
3399
  projectDir: dir,
@@ -3282,7 +3401,7 @@ program.command("build").description("Run build of EventCatalog").action(async (
3282
3401
  config,
3283
3402
  isServer
3284
3403
  });
3285
- logger.info(`Indexed ${result.records} page(s) into ${import_node_path19.default.relative(dir, result.outputPath)}`, "search");
3404
+ logger.info(`Indexed ${result.records} page(s) into ${import_node_path20.default.relative(dir, result.outputPath)}`, "search");
3286
3405
  }
3287
3406
  });
3288
3407
  var previewCatalog = async ({
@@ -3309,7 +3428,7 @@ var startServerCatalog = async ({
3309
3428
  isEventCatalogStarter = false,
3310
3429
  isEventCatalogScale = false
3311
3430
  }) => {
3312
- const serverEntryPath = import_node_path19.default.join(dir, "dist", "server", "entry.mjs");
3431
+ const serverEntryPath = import_node_path20.default.join(dir, "dist", "server", "entry.mjs");
3313
3432
  await runCommandWithFilteredOutput({
3314
3433
  command: `node "${serverEntryPath}"`,
3315
3434
  cwd: core,
@@ -3326,8 +3445,8 @@ var startServerCatalog = async ({
3326
3445
  program.command("preview").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
3327
3446
  logger.welcome();
3328
3447
  logger.info("Starting preview of your build...", "preview");
3329
- if (import_fs3.default.existsSync(import_node_path19.default.join(dir, ".env"))) {
3330
- import_dotenv.default.config({ path: import_node_path19.default.join(dir, ".env") });
3448
+ if (import_fs3.default.existsSync(import_node_path20.default.join(dir, ".env"))) {
3449
+ import_dotenv.default.config({ path: import_node_path20.default.join(dir, ".env") });
3331
3450
  }
3332
3451
  const canEmbedPages = await (0, import_license2.isFeatureEnabled)(
3333
3452
  "@eventcatalog/backstage-plugin-eventcatalog",
@@ -3345,8 +3464,8 @@ program.command("preview").description("Serves the contents of your eventcatalog
3345
3464
  program.command("start").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
3346
3465
  logger.welcome();
3347
3466
  logger.info("Starting preview of your build...", "preview");
3348
- if (import_fs3.default.existsSync(import_node_path19.default.join(dir, ".env"))) {
3349
- import_dotenv.default.config({ path: import_node_path19.default.join(dir, ".env") });
3467
+ if (import_fs3.default.existsSync(import_node_path20.default.join(dir, ".env"))) {
3468
+ import_dotenv.default.config({ path: import_node_path20.default.join(dir, ".env") });
3350
3469
  }
3351
3470
  const canEmbedPages = await (0, import_license2.isFeatureEnabled)(
3352
3471
  "@eventcatalog/backstage-plugin-eventcatalog",
@@ -3373,22 +3492,22 @@ program.command("start").description("Serves the contents of your eventcatalog b
3373
3492
  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) => {
3374
3493
  logger.welcome();
3375
3494
  logger.info("Exporting EventCatalog...", "export");
3376
- if (import_fs3.default.existsSync(import_node_path19.default.join(dir, ".env"))) {
3377
- import_dotenv.default.config({ path: import_node_path19.default.join(dir, ".env") });
3495
+ if (import_fs3.default.existsSync(import_node_path20.default.join(dir, ".env"))) {
3496
+ import_dotenv.default.config({ path: import_node_path20.default.join(dir, ".env") });
3378
3497
  }
3379
3498
  const { default: initSDK } = await import("@eventcatalog/sdk");
3380
3499
  const sdk = initSDK(dir);
3381
3500
  const catalog = await sdk.dumpCatalog({ includeMarkdown: options.includeMarkdown });
3382
- const exportsDir = import_node_path19.default.join(dir, "exports");
3501
+ const exportsDir = import_node_path20.default.join(dir, "exports");
3383
3502
  ensureDir(exportsDir);
3384
3503
  const date = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
3385
- const exportFile = import_node_path19.default.join(exportsDir, `catalog-${date}.json`);
3504
+ const exportFile = import_node_path20.default.join(exportsDir, `catalog-${date}.json`);
3386
3505
  import_fs3.default.writeFileSync(exportFile, JSON.stringify(catalog, null, 2), "utf-8");
3387
3506
  logger.info(`Catalog exported to ${exportFile}`, "export");
3388
3507
  });
3389
3508
  program.command("generate [siteDir]").description("Start the generator scripts.").action(async () => {
3390
- if (import_fs3.default.existsSync(import_node_path19.default.join(dir, ".env"))) {
3391
- import_dotenv.default.config({ path: import_node_path19.default.join(dir, ".env") });
3509
+ if (import_fs3.default.existsSync(import_node_path20.default.join(dir, ".env"))) {
3510
+ import_dotenv.default.config({ path: import_node_path20.default.join(dir, ".env") });
3392
3511
  }
3393
3512
  await generate(dir);
3394
3513
  });
@@ -3461,7 +3580,7 @@ var reportFederationProgress = (event, verbose = false) => {
3461
3580
  }
3462
3581
  return;
3463
3582
  case "hydrating":
3464
- logger.info(`Hydrating federated content into ${import_node_path19.default.relative(dir, event.outDir)}/...`, "federation");
3583
+ logger.info(`Hydrating federated content into ${import_node_path20.default.relative(dir, event.outDir)}/...`, "federation");
3465
3584
  return;
3466
3585
  case "hydrate:cache":
3467
3586
  if (event.files === 1 || event.files % 25 === 0) {
@@ -3484,13 +3603,13 @@ var reportFederationProgress = (event, verbose = false) => {
3484
3603
  `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)`,
3485
3604
  "federation"
3486
3605
  );
3487
- logger.info(`Recorded resolved source state in ${import_node_path19.default.relative(dir, event.result.lockPath)}`, "federation");
3606
+ logger.info(`Recorded resolved source state in ${import_node_path20.default.relative(dir, event.result.lockPath)}`, "federation");
3488
3607
  }
3489
3608
  };
3490
3609
  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.").option("-v, --verbose", "Show detailed federation diagnostics.").action(async (commandOptions) => {
3491
3610
  logger.welcome();
3492
- if (import_fs3.default.existsSync(import_node_path19.default.join(dir, ".env"))) {
3493
- import_dotenv.default.config({ path: import_node_path19.default.join(dir, ".env") });
3611
+ if (import_fs3.default.existsSync(import_node_path20.default.join(dir, ".env"))) {
3612
+ import_dotenv.default.config({ path: import_node_path20.default.join(dir, ".env") });
3494
3613
  }
3495
3614
  logger.info("Starting federation...", "federation");
3496
3615
  let cleanedPreviousOutput = false;