@eventcatalog/core 3.25.6 → 3.26.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 (35) 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-P23BMUBV.js → chunk-6BTN7CY7.js} +1 -1
  6. package/dist/{chunk-ZEOK723Y.js → chunk-EL6ZQNAX.js} +1 -1
  7. package/dist/{chunk-53HXLUNO.js → chunk-LTWPA4SA.js} +1 -1
  8. package/dist/{chunk-R7P4GTFQ.js → chunk-N3QSCVYA.js} +1 -1
  9. package/dist/{chunk-2ILJMBQM.js → chunk-Y736FREK.js} +1 -1
  10. package/dist/constants.cjs +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/eventcatalog.cjs +562 -19
  13. package/dist/eventcatalog.js +576 -31
  14. package/dist/generate.cjs +1 -1
  15. package/dist/generate.js +3 -3
  16. package/dist/utils/cli-logger.cjs +1 -1
  17. package/dist/utils/cli-logger.js +2 -2
  18. package/eventcatalog/astro.config.mjs +2 -1
  19. package/eventcatalog/integrations/eventcatalog-features.ts +13 -0
  20. package/eventcatalog/public/icons/graphql.svg +3 -1
  21. package/eventcatalog/src/components/FieldsExplorer/FieldFilters.tsx +225 -0
  22. package/eventcatalog/src/components/FieldsExplorer/FieldNodeGraph.tsx +521 -0
  23. package/eventcatalog/src/components/FieldsExplorer/FieldsExplorer.tsx +501 -0
  24. package/eventcatalog/src/components/FieldsExplorer/FieldsTable.tsx +236 -0
  25. package/eventcatalog/src/enterprise/fields/field-extractor.test.ts +241 -0
  26. package/eventcatalog/src/enterprise/fields/field-extractor.ts +183 -0
  27. package/eventcatalog/src/enterprise/fields/field-indexer.ts +131 -0
  28. package/eventcatalog/src/enterprise/fields/fields-db.test.ts +186 -0
  29. package/eventcatalog/src/enterprise/fields/fields-db.ts +453 -0
  30. package/eventcatalog/src/enterprise/fields/pages/api/fields.ts +43 -0
  31. package/eventcatalog/src/enterprise/fields/pages/fields.astro +19 -0
  32. package/eventcatalog/src/layouts/VerticalSideBarLayout.astro +23 -3
  33. package/eventcatalog/src/pages/docs/[type]/[id]/[version]/graphql/[filename].astro +14 -16
  34. package/eventcatalog/src/utils/node-graphs/field-node-graph.ts +192 -0
  35. package/package.json +6 -4
@@ -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_process = require("child_process");
32
- var import_node_path7 = require("path");
32
+ var import_node_path8 = require("path");
33
33
  var import_node_http = __toESM(require("http"), 1);
34
34
  var import_fs2 = __toESM(require("fs"), 1);
35
- var import_node_path8 = __toESM(require("path"), 1);
35
+ var import_node_path9 = __toESM(require("path"), 1);
36
36
  var import_node_url = require("url");
37
37
 
38
38
  // src/generate.js
@@ -114,7 +114,7 @@ var verifyRequiredFieldsAreInCatalogConfigFile = async (projectDirectory) => {
114
114
  var import_picocolors = __toESM(require("picocolors"), 1);
115
115
 
116
116
  // package.json
117
- var version = "3.25.6";
117
+ var version = "3.26.1";
118
118
 
119
119
  // src/constants.ts
120
120
  var VERSION = version;
@@ -699,16 +699,533 @@ var runMigrations = async (dir2) => {
699
699
  await message_channels_to_service_channels_default(dir2);
700
700
  };
701
701
 
702
+ // eventcatalog/src/enterprise/fields/field-indexer.ts
703
+ var import_node_path7 = __toESM(require("path"), 1);
704
+ var import_node_fs7 = __toESM(require("fs"), 1);
705
+
706
+ // eventcatalog/src/enterprise/fields/fields-db.ts
707
+ var import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
708
+ var import_node_fs6 = __toESM(require("fs"), 1);
709
+ var SCHEMA_SQL = `
710
+ CREATE TABLE IF NOT EXISTS fields (
711
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
712
+ path TEXT NOT NULL,
713
+ type TEXT NOT NULL,
714
+ description TEXT NOT NULL DEFAULT '',
715
+ required INTEGER NOT NULL DEFAULT 0,
716
+ schema_format TEXT NOT NULL,
717
+ message_id TEXT NOT NULL,
718
+ message_version TEXT NOT NULL,
719
+ message_type TEXT NOT NULL,
720
+ message_name TEXT NOT NULL DEFAULT '',
721
+ message_summary TEXT NOT NULL DEFAULT '',
722
+ message_owners TEXT NOT NULL DEFAULT '[]'
723
+ );
724
+
725
+ CREATE TABLE IF NOT EXISTS message_producers (
726
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
727
+ message_id TEXT NOT NULL,
728
+ message_version TEXT NOT NULL,
729
+ service_id TEXT NOT NULL,
730
+ service_version TEXT NOT NULL,
731
+ service_name TEXT NOT NULL DEFAULT '',
732
+ service_summary TEXT NOT NULL DEFAULT '',
733
+ service_owners TEXT NOT NULL DEFAULT '[]'
734
+ );
735
+
736
+ CREATE TABLE IF NOT EXISTS message_consumers (
737
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
738
+ message_id TEXT NOT NULL,
739
+ message_version TEXT NOT NULL,
740
+ service_id TEXT NOT NULL,
741
+ service_version TEXT NOT NULL,
742
+ service_name TEXT NOT NULL DEFAULT '',
743
+ service_summary TEXT NOT NULL DEFAULT '',
744
+ service_owners TEXT NOT NULL DEFAULT '[]'
745
+ );
746
+
747
+ CREATE INDEX IF NOT EXISTS idx_fields_path ON fields(path);
748
+ CREATE INDEX IF NOT EXISTS idx_fields_message ON fields(message_id, message_version);
749
+ CREATE INDEX IF NOT EXISTS idx_producers_message ON message_producers(message_id, message_version);
750
+ CREATE INDEX IF NOT EXISTS idx_consumers_message ON message_consumers(message_id, message_version);
751
+ `;
752
+ var FTS_SQL = `
753
+ DROP TABLE IF EXISTS fields_fts;
754
+ CREATE VIRTUAL TABLE fields_fts USING fts5(
755
+ path,
756
+ description,
757
+ type,
758
+ content=fields,
759
+ content_rowid=id
760
+ );
761
+ INSERT INTO fields_fts(rowid, path, description, type) SELECT id, path, description, type FROM fields;
762
+ `;
763
+ var FieldsDatabase = class {
764
+ db;
765
+ constructor(dbPath, options) {
766
+ if (options?.recreate && import_node_fs6.default.existsSync(dbPath)) {
767
+ import_node_fs6.default.unlinkSync(dbPath);
768
+ }
769
+ this.db = new import_better_sqlite3.default(dbPath);
770
+ this.db.pragma("journal_mode = WAL");
771
+ this.db.exec(SCHEMA_SQL);
772
+ }
773
+ insertField(field) {
774
+ this.db.prepare(
775
+ `INSERT INTO fields (path, type, description, required, schema_format, message_id, message_version, message_type, message_name, message_summary, message_owners)
776
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
777
+ ).run(
778
+ field.path,
779
+ field.type,
780
+ field.description,
781
+ field.required ? 1 : 0,
782
+ field.schemaFormat,
783
+ field.messageId,
784
+ field.messageVersion,
785
+ field.messageType,
786
+ field.messageName || "",
787
+ field.messageSummary || "",
788
+ JSON.stringify(field.messageOwners || [])
789
+ );
790
+ }
791
+ insertProducer(messageId, messageVersion, serviceId, serviceVersion, serviceName, serviceSummary, serviceOwners) {
792
+ this.db.prepare(
793
+ `INSERT INTO message_producers (message_id, message_version, service_id, service_version, service_name, service_summary, service_owners)
794
+ VALUES (?, ?, ?, ?, ?, ?, ?)`
795
+ ).run(
796
+ messageId,
797
+ messageVersion,
798
+ serviceId,
799
+ serviceVersion,
800
+ serviceName || "",
801
+ serviceSummary || "",
802
+ JSON.stringify(serviceOwners || [])
803
+ );
804
+ }
805
+ insertConsumer(messageId, messageVersion, serviceId, serviceVersion, serviceName, serviceSummary, serviceOwners) {
806
+ this.db.prepare(
807
+ `INSERT INTO message_consumers (message_id, message_version, service_id, service_version, service_name, service_summary, service_owners)
808
+ VALUES (?, ?, ?, ?, ?, ?, ?)`
809
+ ).run(
810
+ messageId,
811
+ messageVersion,
812
+ serviceId,
813
+ serviceVersion,
814
+ serviceName || "",
815
+ serviceSummary || "",
816
+ JSON.stringify(serviceOwners || [])
817
+ );
818
+ }
819
+ rebuildFts() {
820
+ this.db.exec(FTS_SQL);
821
+ }
822
+ queryFields(params) {
823
+ const {
824
+ q,
825
+ shared,
826
+ conflicting,
827
+ format,
828
+ type,
829
+ messageType,
830
+ message,
831
+ producer,
832
+ consumer,
833
+ required,
834
+ path: fieldPath,
835
+ pageSize = 50,
836
+ cursor
837
+ } = params;
838
+ const conditions = [];
839
+ const bindings = [];
840
+ if (fieldPath) {
841
+ conditions.push(`f.path = ?`);
842
+ bindings.push(fieldPath);
843
+ }
844
+ if (q) {
845
+ conditions.push(`f.id IN (SELECT rowid FROM fields_fts WHERE fields_fts MATCH ?)`);
846
+ const escaped = q.replace(/"/g, '""');
847
+ bindings.push(`"${escaped}" *`);
848
+ }
849
+ if (format) {
850
+ const formats2 = format.split(",").map((f) => f.trim()).filter(Boolean);
851
+ conditions.push(`f.schema_format IN (${formats2.map(() => "?").join(", ")})`);
852
+ bindings.push(...formats2);
853
+ }
854
+ if (type) {
855
+ conditions.push(`f.type = ?`);
856
+ bindings.push(type);
857
+ }
858
+ if (messageType) {
859
+ const types2 = messageType.split(",").map((t) => t.trim()).filter(Boolean);
860
+ conditions.push(`f.message_type IN (${types2.map(() => "?").join(", ")})`);
861
+ bindings.push(...types2);
862
+ }
863
+ if (message) {
864
+ conditions.push(`f.message_id = ?`);
865
+ bindings.push(message);
866
+ }
867
+ if (required) {
868
+ conditions.push(`f.required = 1`);
869
+ }
870
+ if (producer) {
871
+ conditions.push(
872
+ `EXISTS (SELECT 1 FROM message_producers p WHERE p.message_id = f.message_id AND p.message_version = f.message_version AND p.service_id = ?)`
873
+ );
874
+ bindings.push(producer);
875
+ }
876
+ if (consumer) {
877
+ conditions.push(
878
+ `EXISTS (SELECT 1 FROM message_consumers c WHERE c.message_id = f.message_id AND c.message_version = f.message_version AND c.service_id = ?)`
879
+ );
880
+ bindings.push(consumer);
881
+ }
882
+ if (shared) {
883
+ const sharedSubquery = `SELECT path FROM fields GROUP BY path HAVING COUNT(DISTINCT message_id || '/' || message_version) > 1`;
884
+ conditions.push(`f.path IN (${sharedSubquery})`);
885
+ }
886
+ if (conflicting) {
887
+ const conflictSubquery = `SELECT path FROM fields GROUP BY path HAVING COUNT(DISTINCT type) > 1`;
888
+ conditions.push(`f.path IN (${conflictSubquery})`);
889
+ }
890
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
891
+ const cursorConditions = [];
892
+ const cursorBindings = [];
893
+ if (cursor) {
894
+ const lastId = decodeCursor(cursor);
895
+ cursorConditions.push(`f.id > ?`);
896
+ cursorBindings.push(lastId);
897
+ }
898
+ const paginationWhere = cursorConditions.length > 0 ? whereClause ? `${whereClause} AND ${cursorConditions.join(" AND ")}` : `WHERE ${cursorConditions.join(" AND ")}` : whereClause;
899
+ const countSql = `SELECT COUNT(*) as cnt FROM fields f ${whereClause}`;
900
+ const total = this.db.prepare(countSql).get(...bindings).cnt;
901
+ const mainSql = `SELECT f.* FROM fields f ${paginationWhere} ORDER BY f.id ASC LIMIT ?`;
902
+ const allBindings = [...bindings, ...cursorBindings, pageSize];
903
+ const rows = this.db.prepare(mainSql).all(...allBindings);
904
+ const usedInStmt = this.db.prepare(
905
+ `SELECT COUNT(DISTINCT message_id || '/' || message_version) as cnt FROM fields WHERE path = ?`
906
+ );
907
+ const conflictsStmt = this.db.prepare(
908
+ `SELECT type, COUNT(DISTINCT message_id || '/' || message_version) as count FROM fields WHERE path = ? GROUP BY type`
909
+ );
910
+ const fields = rows.map((row) => {
911
+ const producers = this.db.prepare(
912
+ `SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_producers WHERE message_id = ? AND message_version = ?`
913
+ ).all(row.message_id, row.message_version);
914
+ const consumers = this.db.prepare(
915
+ `SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_consumers WHERE message_id = ? AND message_version = ?`
916
+ ).all(row.message_id, row.message_version);
917
+ const parseOwners = (raw) => {
918
+ try {
919
+ return JSON.parse(raw || "[]");
920
+ } catch {
921
+ return [];
922
+ }
923
+ };
924
+ const usedInCount = usedInStmt.get(row.path).cnt;
925
+ const typeRows = conflictsStmt.all(row.path);
926
+ const conflicts = typeRows.length > 1 ? typeRows.map((r) => ({ type: r.type, count: r.count })) : void 0;
927
+ return {
928
+ id: row.id,
929
+ path: row.path,
930
+ type: row.type,
931
+ description: row.description,
932
+ required: row.required === 1,
933
+ schemaFormat: row.schema_format,
934
+ messageId: row.message_id,
935
+ messageVersion: row.message_version,
936
+ messageType: row.message_type,
937
+ messageName: row.message_name || row.message_id,
938
+ messageSummary: row.message_summary || "",
939
+ messageOwners: parseOwners(row.message_owners),
940
+ usedInCount,
941
+ conflicts,
942
+ producers: producers.map((p) => ({
943
+ id: p.service_id,
944
+ version: p.service_version,
945
+ name: p.service_name || p.service_id,
946
+ summary: p.service_summary || "",
947
+ owners: parseOwners(p.service_owners)
948
+ })),
949
+ consumers: consumers.map((c) => ({
950
+ id: c.service_id,
951
+ version: c.service_version,
952
+ name: c.service_name || c.service_id,
953
+ summary: c.service_summary || "",
954
+ owners: parseOwners(c.service_owners)
955
+ }))
956
+ };
957
+ });
958
+ const formatsFacetSql = `SELECT f.schema_format as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.schema_format`;
959
+ const formats = this.db.prepare(formatsFacetSql).all(...bindings);
960
+ const typesFacetSql = `SELECT f.type as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.type`;
961
+ const types = this.db.prepare(typesFacetSql).all(...bindings);
962
+ const messageTypesFacetSql = `SELECT f.message_type as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.message_type`;
963
+ const messageTypes = this.db.prepare(messageTypesFacetSql).all(...bindings);
964
+ const lastRow = rows[rows.length - 1];
965
+ const nextCursor = lastRow && rows.length === pageSize ? encodeCursor(lastRow.id) : void 0;
966
+ return {
967
+ fields,
968
+ total,
969
+ cursor: nextCursor,
970
+ facets: { formats, types, messageTypes }
971
+ };
972
+ }
973
+ close() {
974
+ this.db.close();
975
+ }
976
+ };
977
+ function encodeCursor(id) {
978
+ return Buffer.from(String(id)).toString("base64url");
979
+ }
980
+ function decodeCursor(cursor) {
981
+ return parseInt(Buffer.from(cursor, "base64url").toString(), 10);
982
+ }
983
+
984
+ // eventcatalog/src/enterprise/fields/field-extractor.ts
985
+ function extractSchemaFieldsDeep(content, format) {
986
+ if (!content) return [];
987
+ if (format === "json-schema") {
988
+ return extractJsonSchemaFields(content);
989
+ }
990
+ if (format === "avro") {
991
+ return extractAvroFields(content);
992
+ }
993
+ if (format === "proto") {
994
+ return extractProtoFields(content);
995
+ }
996
+ return [];
997
+ }
998
+ function extractProtoFields(content) {
999
+ if (!content) return [];
1000
+ const fields = [];
1001
+ const fieldRegex = /^\s*(repeated\s+|optional\s+|required\s+)?(\w+)\s+(\w+)\s*=\s*\d+\s*;(?:\s*\/\/\s*(.*))?/gm;
1002
+ let match;
1003
+ while ((match = fieldRegex.exec(content)) !== null) {
1004
+ const modifier = (match[1] || "").trim();
1005
+ const type = modifier ? `${modifier} ${match[2]}` : match[2];
1006
+ fields.push({
1007
+ path: match[3],
1008
+ type,
1009
+ description: match[4]?.trim() || "",
1010
+ required: modifier === "required"
1011
+ });
1012
+ }
1013
+ return fields;
1014
+ }
1015
+ function extractAvroFields(content) {
1016
+ try {
1017
+ const schema = JSON.parse(content);
1018
+ const fields = [];
1019
+ walkAvroRecord(schema, "", fields);
1020
+ return fields;
1021
+ } catch {
1022
+ return [];
1023
+ }
1024
+ }
1025
+ function getAvroTypeName(type) {
1026
+ if (typeof type === "string") return type;
1027
+ if (Array.isArray(type)) {
1028
+ return type.map((t) => typeof t === "string" ? t : t.type || "complex").join(" | ");
1029
+ }
1030
+ if (typeof type === "object" && type !== null) {
1031
+ if (type.type === "array" && type.items) return `array<${getAvroTypeName(type.items)}>`;
1032
+ if (type.type === "record") return type.name || "record";
1033
+ return type.type || "complex";
1034
+ }
1035
+ return "unknown";
1036
+ }
1037
+ function walkAvroRecord(schema, prefix, fields) {
1038
+ if (!schema.fields || !Array.isArray(schema.fields)) return;
1039
+ for (const field of schema.fields) {
1040
+ const path9 = prefix ? `${prefix}.${field.name}` : field.name;
1041
+ const isOptional = Array.isArray(field.type) && field.type.includes("null");
1042
+ const typeName = getAvroTypeName(field.type);
1043
+ fields.push({
1044
+ path: path9,
1045
+ type: typeName,
1046
+ description: field.doc || "",
1047
+ required: !isOptional
1048
+ });
1049
+ 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;
1050
+ if (innerType) {
1051
+ walkAvroRecord(innerType, path9, fields);
1052
+ }
1053
+ 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;
1054
+ if (arrayType && typeof arrayType.items === "object" && arrayType.items.type === "record") {
1055
+ walkAvroRecord(arrayType.items, `${path9}[]`, fields);
1056
+ }
1057
+ }
1058
+ }
1059
+ function extractJsonSchemaFields(content) {
1060
+ try {
1061
+ const schema = JSON.parse(content);
1062
+ const fields = [];
1063
+ walkJsonSchema(schema, "", schema.required || [], schema, fields);
1064
+ return fields;
1065
+ } catch {
1066
+ return [];
1067
+ }
1068
+ }
1069
+ function walkJsonSchema(node, prefix, requiredList, rootSchema, fields) {
1070
+ if (node.allOf && Array.isArray(node.allOf)) {
1071
+ const merged = { type: "object", properties: {}, required: [] };
1072
+ for (let sub of node.allOf) {
1073
+ if (sub.$ref) {
1074
+ const resolved = resolveLocalRef(sub.$ref, rootSchema);
1075
+ if (resolved) sub = resolved;
1076
+ else continue;
1077
+ }
1078
+ Object.assign(merged.properties, sub.properties || {});
1079
+ merged.required.push(...sub.required || []);
1080
+ }
1081
+ walkJsonSchema(merged, prefix, merged.required, rootSchema, fields);
1082
+ return;
1083
+ }
1084
+ if (!node.properties) return;
1085
+ for (const [name, prop] of Object.entries(node.properties)) {
1086
+ const path9 = prefix ? `${prefix}.${name}` : name;
1087
+ const isRequired = requiredList.includes(name);
1088
+ if (prop.$ref) {
1089
+ const resolved = resolveLocalRef(prop.$ref, rootSchema);
1090
+ if (resolved) {
1091
+ const type2 = resolved.type || "object";
1092
+ fields.push({ path: path9, type: type2, description: resolved.description || "", required: isRequired });
1093
+ if (resolved.properties) {
1094
+ walkJsonSchema(resolved, path9, resolved.required || [], rootSchema, fields);
1095
+ }
1096
+ } else {
1097
+ fields.push({ path: path9, type: "$ref", description: "", required: isRequired });
1098
+ }
1099
+ continue;
1100
+ }
1101
+ const type = prop.type || (prop.enum ? "enum" : prop.$ref ? "$ref" : "object");
1102
+ fields.push({ path: path9, type, description: prop.description || "", required: isRequired });
1103
+ if (prop.type === "object" && prop.properties) {
1104
+ walkJsonSchema(prop, path9, prop.required || [], rootSchema, fields);
1105
+ }
1106
+ if (prop.type === "array" && prop.items) {
1107
+ if (prop.items.type === "object" && prop.items.properties) {
1108
+ walkJsonSchema(prop.items, `${path9}[]`, prop.items.required || [], rootSchema, fields);
1109
+ }
1110
+ }
1111
+ }
1112
+ }
1113
+ function resolveLocalRef(ref, rootSchema) {
1114
+ if (!ref.startsWith("#/")) return null;
1115
+ const parts = ref.replace("#/", "").split("/");
1116
+ let current = rootSchema;
1117
+ for (const part of parts) {
1118
+ current = current?.[part];
1119
+ if (!current) return null;
1120
+ }
1121
+ return current;
1122
+ }
1123
+
1124
+ // eventcatalog/src/enterprise/fields/field-indexer.ts
1125
+ function detectFormat(fileName) {
1126
+ const ext = import_node_path7.default.extname(fileName).toLowerCase();
1127
+ if (ext === ".proto") return "proto";
1128
+ if (ext === ".avro" || ext === ".avsc") return "avro";
1129
+ return "json-schema";
1130
+ }
1131
+ async function buildFieldsIndex(catalogDir, outputDir) {
1132
+ const sdkModule = await import("@eventcatalog/sdk");
1133
+ const sdk = sdkModule.default(catalogDir);
1134
+ const dbDir = import_node_path7.default.join(outputDir || catalogDir, ".eventcatalog");
1135
+ const dbPath = import_node_path7.default.join(dbDir, "fields.db");
1136
+ if (!import_node_fs7.default.existsSync(dbDir)) {
1137
+ import_node_fs7.default.mkdirSync(dbDir, { recursive: true });
1138
+ }
1139
+ const db = new FieldsDatabase(dbPath, { recreate: true });
1140
+ const warnings = [];
1141
+ try {
1142
+ const [events, commands, queries] = await Promise.all([
1143
+ sdk.getEvents({ latestOnly: true }),
1144
+ sdk.getCommands({ latestOnly: true }),
1145
+ sdk.getQueries({ latestOnly: true })
1146
+ ]);
1147
+ const collections = [
1148
+ { entries: events, type: "event" },
1149
+ { entries: commands, type: "command" },
1150
+ { entries: queries, type: "query" }
1151
+ ];
1152
+ for (const { entries, type } of collections) {
1153
+ for (const entry of entries) {
1154
+ const msgId = entry.id;
1155
+ const msgVersion = entry.version;
1156
+ let schemaData;
1157
+ try {
1158
+ schemaData = await sdk.getSchemaForMessage(msgId, msgVersion);
1159
+ } catch {
1160
+ continue;
1161
+ }
1162
+ if (!schemaData) continue;
1163
+ const { schema: content, fileName } = schemaData;
1164
+ const format = detectFormat(fileName);
1165
+ try {
1166
+ const fields = extractSchemaFieldsDeep(content, format);
1167
+ for (const field of fields) {
1168
+ db.insertField({
1169
+ path: field.path,
1170
+ type: field.type,
1171
+ description: field.description,
1172
+ required: field.required,
1173
+ schemaFormat: format,
1174
+ messageId: msgId,
1175
+ messageVersion: msgVersion,
1176
+ messageType: type,
1177
+ messageName: entry.name || msgId,
1178
+ messageSummary: entry.summary || "",
1179
+ messageOwners: entry.owners || []
1180
+ });
1181
+ }
1182
+ const { producers, consumers } = await sdk.getProducersAndConsumersForMessage(msgId, msgVersion);
1183
+ for (const producer of producers) {
1184
+ db.insertProducer(
1185
+ msgId,
1186
+ msgVersion,
1187
+ producer.id,
1188
+ producer.version,
1189
+ producer.name || producer.id,
1190
+ producer.summary || "",
1191
+ producer.owners || []
1192
+ );
1193
+ }
1194
+ for (const consumer of consumers) {
1195
+ db.insertConsumer(
1196
+ msgId,
1197
+ msgVersion,
1198
+ consumer.id,
1199
+ consumer.version,
1200
+ consumer.name || consumer.id,
1201
+ consumer.summary || "",
1202
+ consumer.owners || []
1203
+ );
1204
+ }
1205
+ } catch (err) {
1206
+ warnings.push({ messageId: msgId, version: msgVersion, error: err.message });
1207
+ }
1208
+ }
1209
+ }
1210
+ db.rebuildFts();
1211
+ db.close();
1212
+ return { dbPath, warnings };
1213
+ } catch (err) {
1214
+ db.close();
1215
+ throw err;
1216
+ }
1217
+ }
1218
+
702
1219
  // src/eventcatalog.ts
703
1220
  var import_license = require("@eventcatalog/license");
704
- var currentDir = import_node_path8.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
1221
+ var currentDir = import_node_path9.default.dirname((0, import_node_url.fileURLToPath)(importMetaUrl));
705
1222
  var program = new import_commander.Command().version(VERSION);
706
- var dir = import_node_path8.default.resolve(process.env.PROJECT_DIR || process.cwd());
707
- var core = import_node_path8.default.resolve(process.env.CATALOG_DIR || (0, import_node_path7.join)(dir, ".eventcatalog-core"));
708
- var eventCatalogDir = import_node_path8.default.resolve((0, import_node_path7.join)(currentDir, "../eventcatalog/"));
1223
+ var dir = import_node_path9.default.resolve(process.env.PROJECT_DIR || process.cwd());
1224
+ var core = import_node_path9.default.resolve(process.env.CATALOG_DIR || (0, import_node_path8.join)(dir, ".eventcatalog-core"));
1225
+ var eventCatalogDir = import_node_path9.default.resolve((0, import_node_path8.join)(currentDir, "../eventcatalog/"));
709
1226
  var getInstalledEventCatalogVersion = () => {
710
1227
  try {
711
- const pkg = import_fs2.default.readFileSync((0, import_node_path7.join)(dir, "package.json"), "utf8");
1228
+ const pkg = import_fs2.default.readFileSync((0, import_node_path8.join)(dir, "package.json"), "utf8");
712
1229
  const json = JSON.parse(pkg);
713
1230
  return json.dependencies["@eventcatalog/core"];
714
1231
  } catch (error) {
@@ -913,8 +1430,8 @@ program.command("dev").description("Run development server of EventCatalog").opt
913
1430
  logger.info("Setting up EventCatalog...", "eventcatalog");
914
1431
  const isServer = await isOutputServer();
915
1432
  logger.info(isServer ? "EventCatalog is running in Server Mode" : "EventCatalog is running in Static Mode", "config");
916
- if (import_fs2.default.existsSync(import_node_path8.default.join(dir, ".env"))) {
917
- import_dotenv.default.config({ path: import_node_path8.default.join(dir, ".env") });
1433
+ if (import_fs2.default.existsSync(import_node_path9.default.join(dir, ".env"))) {
1434
+ import_dotenv.default.config({ path: import_node_path9.default.join(dir, ".env") });
918
1435
  }
919
1436
  if (options.debug) {
920
1437
  logger.info("Debug mode enabled", "debug");
@@ -933,6 +1450,19 @@ program.command("dev").description("Run development server of EventCatalog").opt
933
1450
  );
934
1451
  const isEventCatalogStarter = await (0, import_license.isEventCatalogStarterEnabled)();
935
1452
  const isEventCatalogScale = await (0, import_license.isEventCatalogScaleEnabled)();
1453
+ if (isServer) {
1454
+ try {
1455
+ logger.info("Building fields index...", "fields");
1456
+ const { warnings } = await buildFieldsIndex(dir, core);
1457
+ if (warnings.length > 0) {
1458
+ logger.info(`Fields index built with ${warnings.length} warning(s)`, "fields");
1459
+ } else {
1460
+ logger.info("Fields index built successfully", "fields");
1461
+ }
1462
+ } catch (err) {
1463
+ logger.info(`Failed to build fields index: ${err.message}`, "fields");
1464
+ }
1465
+ }
936
1466
  checkForUpdate();
937
1467
  let watchUnsub;
938
1468
  try {
@@ -973,8 +1503,8 @@ program.command("build").description("Run build of EventCatalog").action(async (
973
1503
  logger.info("Building EventCatalog...", "build");
974
1504
  const isServer = await isOutputServer();
975
1505
  logger.info(isServer ? "EventCatalog is running in Server Mode" : "EventCatalog is running in Static Mode", "config");
976
- if (import_fs2.default.existsSync(import_node_path8.default.join(dir, ".env"))) {
977
- import_dotenv.default.config({ path: import_node_path8.default.join(dir, ".env") });
1506
+ if (import_fs2.default.existsSync(import_node_path9.default.join(dir, ".env"))) {
1507
+ import_dotenv.default.config({ path: import_node_path9.default.join(dir, ".env") });
978
1508
  }
979
1509
  await verifyRequiredFieldsAreInCatalogConfigFile(dir);
980
1510
  copyCore();
@@ -993,6 +1523,19 @@ program.command("build").description("Run build of EventCatalog").action(async (
993
1523
  await resolve_catalog_dependencies_default(dir, core);
994
1524
  await runMigrations(dir);
995
1525
  await catalogToAstro(dir, core);
1526
+ if (isServer) {
1527
+ try {
1528
+ logger.info("Building fields index...", "fields");
1529
+ const { warnings } = await buildFieldsIndex(dir, core);
1530
+ if (warnings.length > 0) {
1531
+ logger.info(`Fields index built with ${warnings.length} warning(s)`, "fields");
1532
+ } else {
1533
+ logger.info("Fields index built successfully", "fields");
1534
+ }
1535
+ } catch (err) {
1536
+ logger.info(`Failed to build fields index: ${err.message}`, "fields");
1537
+ }
1538
+ }
996
1539
  checkForUpdate();
997
1540
  const args = command.args.join(" ").trim();
998
1541
  await runCommandWithFilteredOutput({
@@ -1028,7 +1571,7 @@ var startServerCatalog = ({
1028
1571
  isEventCatalogStarter = false,
1029
1572
  isEventCatalogScale = false
1030
1573
  }) => {
1031
- const serverEntryPath = import_node_path8.default.join(dir, "dist", "server", "entry.mjs");
1574
+ const serverEntryPath = import_node_path9.default.join(dir, "dist", "server", "entry.mjs");
1032
1575
  (0, import_node_child_process.execSync)(
1033
1576
  `cross-env PROJECT_DIR='${dir}' CATALOG_DIR='${core}' ENABLE_EMBED=${canEmbedPages} EVENTCATALOG_STARTER=${isEventCatalogStarter} EVENTCATALOG_SCALE=${isEventCatalogScale} node "${serverEntryPath}"`,
1034
1577
  {
@@ -1040,8 +1583,8 @@ var startServerCatalog = ({
1040
1583
  program.command("preview").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
1041
1584
  logger.welcome();
1042
1585
  logger.info("Starting preview of your build...", "preview");
1043
- if (import_fs2.default.existsSync(import_node_path8.default.join(dir, ".env"))) {
1044
- import_dotenv.default.config({ path: import_node_path8.default.join(dir, ".env") });
1586
+ if (import_fs2.default.existsSync(import_node_path9.default.join(dir, ".env"))) {
1587
+ import_dotenv.default.config({ path: import_node_path9.default.join(dir, ".env") });
1045
1588
  }
1046
1589
  const canEmbedPages = await (0, import_license.isFeatureEnabled)(
1047
1590
  "@eventcatalog/backstage-plugin-eventcatalog",
@@ -1054,8 +1597,8 @@ program.command("preview").description("Serves the contents of your eventcatalog
1054
1597
  program.command("start").description("Serves the contents of your eventcatalog build directory").action(async (options, command) => {
1055
1598
  logger.welcome();
1056
1599
  logger.info("Starting preview of your build...", "preview");
1057
- if (import_fs2.default.existsSync(import_node_path8.default.join(dir, ".env"))) {
1058
- import_dotenv.default.config({ path: import_node_path8.default.join(dir, ".env") });
1600
+ if (import_fs2.default.existsSync(import_node_path9.default.join(dir, ".env"))) {
1601
+ import_dotenv.default.config({ path: import_node_path9.default.join(dir, ".env") });
1059
1602
  }
1060
1603
  const canEmbedPages = await (0, import_license.isFeatureEnabled)(
1061
1604
  "@eventcatalog/backstage-plugin-eventcatalog",
@@ -1081,8 +1624,8 @@ program.command("start").description("Serves the contents of your eventcatalog b
1081
1624
  }
1082
1625
  });
1083
1626
  program.command("generate [siteDir]").description("Start the generator scripts.").action(async () => {
1084
- if (import_fs2.default.existsSync(import_node_path8.default.join(dir, ".env"))) {
1085
- import_dotenv.default.config({ path: import_node_path8.default.join(dir, ".env") });
1627
+ if (import_fs2.default.existsSync(import_node_path9.default.join(dir, ".env"))) {
1628
+ import_dotenv.default.config({ path: import_node_path9.default.join(dir, ".env") });
1086
1629
  }
1087
1630
  await generate(dir);
1088
1631
  });