@eventcatalog/core 3.26.6 → 3.26.8
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.
- package/dist/analytics/analytics.cjs +1 -1
- package/dist/analytics/analytics.js +2 -2
- package/dist/analytics/log-build.cjs +1 -1
- package/dist/analytics/log-build.js +3 -3
- package/dist/{chunk-2AMPEGVX.js → chunk-4YHMATES.js} +1 -1
- package/dist/{chunk-XNHXKW5W.js → chunk-5S25RP7K.js} +1 -1
- package/dist/{chunk-DYEQDJQB.js → chunk-5WB6S5GZ.js} +1 -1
- package/dist/{chunk-ZCUZPIIK.js → chunk-677ZSR3F.js} +1 -1
- package/dist/{chunk-O4PK4ZY4.js → chunk-TPK3LJWI.js} +1 -1
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/eventcatalog.cjs +114 -85
- package/dist/eventcatalog.js +118 -89
- package/dist/generate.cjs +1 -1
- package/dist/generate.js +3 -3
- package/dist/utils/cli-logger.cjs +1 -1
- package/dist/utils/cli-logger.js +2 -2
- package/eventcatalog/astro.config.mjs +2 -2
- package/eventcatalog/auth.config.ts +1 -0
- package/eventcatalog/src/components/Header.astro +6 -1
- package/eventcatalog/src/enterprise/fields/field-indexer.ts +2 -2
- package/eventcatalog/src/enterprise/fields/fields-db.test.ts +5 -11
- package/eventcatalog/src/enterprise/fields/fields-db.ts +111 -86
- package/eventcatalog/src/enterprise/fields/pages/api/fields.ts +1 -1
- package/package.json +4 -5
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
log_build_default
|
|
3
|
-
} from "../chunk-
|
|
4
|
-
import "../chunk-
|
|
3
|
+
} from "../chunk-TPK3LJWI.js";
|
|
4
|
+
import "../chunk-5WB6S5GZ.js";
|
|
5
5
|
import "../chunk-4UVFXLPI.js";
|
|
6
|
-
import "../chunk-
|
|
6
|
+
import "../chunk-5S25RP7K.js";
|
|
7
7
|
import "../chunk-5T63CXKU.js";
|
|
8
8
|
export {
|
|
9
9
|
log_build_default as default
|
package/dist/constants.cjs
CHANGED
package/dist/constants.js
CHANGED
package/dist/eventcatalog.cjs
CHANGED
|
@@ -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.26.
|
|
117
|
+
var version = "3.26.8";
|
|
118
118
|
|
|
119
119
|
// src/constants.ts
|
|
120
120
|
var VERSION = version;
|
|
@@ -704,7 +704,7 @@ var import_node_path7 = __toESM(require("path"), 1);
|
|
|
704
704
|
var import_node_fs7 = __toESM(require("fs"), 1);
|
|
705
705
|
|
|
706
706
|
// eventcatalog/src/enterprise/fields/fields-db.ts
|
|
707
|
-
var
|
|
707
|
+
var import_sql = __toESM(require("sql.js"), 1);
|
|
708
708
|
var import_node_fs6 = __toESM(require("fs"), 1);
|
|
709
709
|
var SCHEMA_SQL = `
|
|
710
710
|
CREATE TABLE IF NOT EXISTS fields (
|
|
@@ -749,75 +749,99 @@ var SCHEMA_SQL = `
|
|
|
749
749
|
CREATE INDEX IF NOT EXISTS idx_producers_message ON message_producers(message_id, message_version);
|
|
750
750
|
CREATE INDEX IF NOT EXISTS idx_consumers_message ON message_consumers(message_id, message_version);
|
|
751
751
|
`;
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
752
|
+
function queryAll(db, sql, params = []) {
|
|
753
|
+
const stmt = db.prepare(sql);
|
|
754
|
+
stmt.bind(params);
|
|
755
|
+
const rows = [];
|
|
756
|
+
while (stmt.step()) {
|
|
757
|
+
rows.push(stmt.getAsObject());
|
|
758
|
+
}
|
|
759
|
+
stmt.free();
|
|
760
|
+
return rows;
|
|
761
|
+
}
|
|
762
|
+
function queryOne(db, sql, params = []) {
|
|
763
|
+
const stmt = db.prepare(sql);
|
|
764
|
+
stmt.bind(params);
|
|
765
|
+
const result = stmt.step() ? stmt.getAsObject() : null;
|
|
766
|
+
stmt.free();
|
|
767
|
+
return result;
|
|
768
|
+
}
|
|
769
|
+
var FieldsDatabase = class _FieldsDatabase {
|
|
764
770
|
db;
|
|
765
|
-
|
|
771
|
+
dbPath;
|
|
772
|
+
constructor(db, dbPath) {
|
|
773
|
+
this.db = db;
|
|
774
|
+
this.dbPath = dbPath;
|
|
775
|
+
}
|
|
776
|
+
static async create(dbPath, options) {
|
|
766
777
|
if (options?.recreate && import_node_fs6.default.existsSync(dbPath)) {
|
|
767
778
|
import_node_fs6.default.unlinkSync(dbPath);
|
|
768
779
|
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
780
|
+
const SQL = await (0, import_sql.default)();
|
|
781
|
+
let db;
|
|
782
|
+
if (!options?.recreate && import_node_fs6.default.existsSync(dbPath)) {
|
|
783
|
+
const buffer = import_node_fs6.default.readFileSync(dbPath);
|
|
784
|
+
db = new SQL.Database(buffer);
|
|
785
|
+
} else {
|
|
786
|
+
db = new SQL.Database();
|
|
787
|
+
}
|
|
788
|
+
db.run(SCHEMA_SQL);
|
|
789
|
+
return new _FieldsDatabase(db, dbPath);
|
|
772
790
|
}
|
|
773
791
|
insertField(field) {
|
|
774
|
-
this.db.
|
|
792
|
+
this.db.run(
|
|
775
793
|
`INSERT INTO fields (path, type, description, required, schema_format, message_id, message_version, message_type, message_name, message_summary, message_owners)
|
|
776
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
794
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
795
|
+
[
|
|
796
|
+
field.path,
|
|
797
|
+
field.type,
|
|
798
|
+
field.description,
|
|
799
|
+
field.required ? 1 : 0,
|
|
800
|
+
field.schemaFormat,
|
|
801
|
+
field.messageId,
|
|
802
|
+
field.messageVersion,
|
|
803
|
+
field.messageType,
|
|
804
|
+
field.messageName || "",
|
|
805
|
+
field.messageSummary || "",
|
|
806
|
+
JSON.stringify(field.messageOwners || [])
|
|
807
|
+
]
|
|
789
808
|
);
|
|
790
809
|
}
|
|
791
810
|
insertProducer(messageId, messageVersion, serviceId, serviceVersion, serviceName, serviceSummary, serviceOwners) {
|
|
792
|
-
this.db.
|
|
811
|
+
this.db.run(
|
|
793
812
|
`INSERT INTO message_producers (message_id, message_version, service_id, service_version, service_name, service_summary, service_owners)
|
|
794
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
813
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
814
|
+
[
|
|
815
|
+
messageId,
|
|
816
|
+
messageVersion,
|
|
817
|
+
serviceId,
|
|
818
|
+
serviceVersion,
|
|
819
|
+
serviceName || "",
|
|
820
|
+
serviceSummary || "",
|
|
821
|
+
JSON.stringify(serviceOwners || [])
|
|
822
|
+
]
|
|
803
823
|
);
|
|
804
824
|
}
|
|
805
825
|
insertConsumer(messageId, messageVersion, serviceId, serviceVersion, serviceName, serviceSummary, serviceOwners) {
|
|
806
|
-
this.db.
|
|
826
|
+
this.db.run(
|
|
807
827
|
`INSERT INTO message_consumers (message_id, message_version, service_id, service_version, service_name, service_summary, service_owners)
|
|
808
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
828
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
829
|
+
[
|
|
830
|
+
messageId,
|
|
831
|
+
messageVersion,
|
|
832
|
+
serviceId,
|
|
833
|
+
serviceVersion,
|
|
834
|
+
serviceName || "",
|
|
835
|
+
serviceSummary || "",
|
|
836
|
+
JSON.stringify(serviceOwners || [])
|
|
837
|
+
]
|
|
817
838
|
);
|
|
818
839
|
}
|
|
819
|
-
|
|
820
|
-
|
|
840
|
+
/** Save the in-memory database to disk */
|
|
841
|
+
save() {
|
|
842
|
+
const data = this.db.export();
|
|
843
|
+
const buffer = Buffer.from(data);
|
|
844
|
+
import_node_fs6.default.writeFileSync(this.dbPath, buffer);
|
|
821
845
|
}
|
|
822
846
|
queryFields(params) {
|
|
823
847
|
const {
|
|
@@ -842,9 +866,10 @@ var FieldsDatabase = class {
|
|
|
842
866
|
bindings.push(fieldPath);
|
|
843
867
|
}
|
|
844
868
|
if (q) {
|
|
845
|
-
conditions.push(`f.
|
|
846
|
-
const escaped = q.replace(
|
|
847
|
-
|
|
869
|
+
conditions.push(`(f.path LIKE ? ESCAPE '\\' OR f.description LIKE ? ESCAPE '\\' OR f.type LIKE ? ESCAPE '\\')`);
|
|
870
|
+
const escaped = q.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
871
|
+
const term = `%${escaped}%`;
|
|
872
|
+
bindings.push(term, term, term);
|
|
848
873
|
}
|
|
849
874
|
if (format) {
|
|
850
875
|
const formats2 = format.split(",").map((f) => f.trim()).filter(Boolean);
|
|
@@ -897,32 +922,36 @@ var FieldsDatabase = class {
|
|
|
897
922
|
}
|
|
898
923
|
const paginationWhere = cursorConditions.length > 0 ? whereClause ? `${whereClause} AND ${cursorConditions.join(" AND ")}` : `WHERE ${cursorConditions.join(" AND ")}` : whereClause;
|
|
899
924
|
const countSql = `SELECT COUNT(*) as cnt FROM fields f ${whereClause}`;
|
|
900
|
-
const total = this.db
|
|
925
|
+
const total = queryOne(this.db, countSql, bindings).cnt;
|
|
901
926
|
const mainSql = `SELECT f.* FROM fields f ${paginationWhere} ORDER BY f.id ASC LIMIT ?`;
|
|
902
927
|
const allBindings = [...bindings, ...cursorBindings, pageSize];
|
|
903
|
-
const rows = this.db
|
|
904
|
-
const
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
928
|
+
const rows = queryAll(this.db, mainSql, allBindings);
|
|
929
|
+
const parseOwners = (raw) => {
|
|
930
|
+
try {
|
|
931
|
+
return JSON.parse(raw || "[]");
|
|
932
|
+
} catch {
|
|
933
|
+
return [];
|
|
934
|
+
}
|
|
935
|
+
};
|
|
910
936
|
const fields = rows.map((row) => {
|
|
911
|
-
const producers =
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
const
|
|
925
|
-
|
|
937
|
+
const producers = queryAll(
|
|
938
|
+
this.db,
|
|
939
|
+
`SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_producers WHERE message_id = ? AND message_version = ?`,
|
|
940
|
+
[row.message_id, row.message_version]
|
|
941
|
+
);
|
|
942
|
+
const consumers = queryAll(
|
|
943
|
+
this.db,
|
|
944
|
+
`SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_consumers WHERE message_id = ? AND message_version = ?`,
|
|
945
|
+
[row.message_id, row.message_version]
|
|
946
|
+
);
|
|
947
|
+
const usedInCount = queryOne(this.db, `SELECT COUNT(DISTINCT message_id || '/' || message_version) as cnt FROM fields WHERE path = ?`, [
|
|
948
|
+
row.path
|
|
949
|
+
]).cnt;
|
|
950
|
+
const typeRows = queryAll(
|
|
951
|
+
this.db,
|
|
952
|
+
`SELECT type, COUNT(DISTINCT message_id || '/' || message_version) as count FROM fields WHERE path = ? GROUP BY type`,
|
|
953
|
+
[row.path]
|
|
954
|
+
);
|
|
926
955
|
const conflicts = typeRows.length > 1 ? typeRows.map((r) => ({ type: r.type, count: r.count })) : void 0;
|
|
927
956
|
return {
|
|
928
957
|
id: row.id,
|
|
@@ -956,11 +985,11 @@ var FieldsDatabase = class {
|
|
|
956
985
|
};
|
|
957
986
|
});
|
|
958
987
|
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
|
|
988
|
+
const formats = queryAll(this.db, formatsFacetSql, bindings);
|
|
960
989
|
const typesFacetSql = `SELECT f.type as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.type`;
|
|
961
|
-
const types = this.db
|
|
990
|
+
const types = queryAll(this.db, typesFacetSql, bindings);
|
|
962
991
|
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
|
|
992
|
+
const messageTypes = queryAll(this.db, messageTypesFacetSql, bindings);
|
|
964
993
|
const lastRow = rows[rows.length - 1];
|
|
965
994
|
const nextCursor = lastRow && rows.length === pageSize ? encodeCursor(lastRow.id) : void 0;
|
|
966
995
|
return {
|
|
@@ -1136,7 +1165,7 @@ async function buildFieldsIndex(catalogDir, outputDir) {
|
|
|
1136
1165
|
if (!import_node_fs7.default.existsSync(dbDir)) {
|
|
1137
1166
|
import_node_fs7.default.mkdirSync(dbDir, { recursive: true });
|
|
1138
1167
|
}
|
|
1139
|
-
const db =
|
|
1168
|
+
const db = await FieldsDatabase.create(dbPath, { recreate: true });
|
|
1140
1169
|
const warnings = [];
|
|
1141
1170
|
try {
|
|
1142
1171
|
const [events, commands, queries] = await Promise.all([
|
|
@@ -1207,7 +1236,7 @@ async function buildFieldsIndex(catalogDir, outputDir) {
|
|
|
1207
1236
|
}
|
|
1208
1237
|
}
|
|
1209
1238
|
}
|
|
1210
|
-
db.
|
|
1239
|
+
db.save();
|
|
1211
1240
|
db.close();
|
|
1212
1241
|
return { dbPath, warnings };
|
|
1213
1242
|
} catch (err) {
|
package/dist/eventcatalog.js
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
} from "./chunk-PLNJC7NZ.js";
|
|
7
7
|
import {
|
|
8
8
|
log_build_default
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-TPK3LJWI.js";
|
|
10
|
+
import "./chunk-5WB6S5GZ.js";
|
|
11
11
|
import "./chunk-4UVFXLPI.js";
|
|
12
12
|
import {
|
|
13
13
|
runMigrations
|
|
@@ -22,13 +22,13 @@ import {
|
|
|
22
22
|
} from "./chunk-3KXCGYET.js";
|
|
23
23
|
import {
|
|
24
24
|
generate
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-4YHMATES.js";
|
|
26
26
|
import {
|
|
27
27
|
logger
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-677ZSR3F.js";
|
|
29
29
|
import {
|
|
30
30
|
VERSION
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-5S25RP7K.js";
|
|
32
32
|
import {
|
|
33
33
|
getEventCatalogConfigFile,
|
|
34
34
|
verifyRequiredFieldsAreInCatalogConfigFile
|
|
@@ -51,7 +51,7 @@ import path from "path";
|
|
|
51
51
|
import fs2 from "fs";
|
|
52
52
|
|
|
53
53
|
// eventcatalog/src/enterprise/fields/fields-db.ts
|
|
54
|
-
import
|
|
54
|
+
import initSqlJs from "sql.js";
|
|
55
55
|
import fs from "fs";
|
|
56
56
|
var SCHEMA_SQL = `
|
|
57
57
|
CREATE TABLE IF NOT EXISTS fields (
|
|
@@ -96,75 +96,99 @@ var SCHEMA_SQL = `
|
|
|
96
96
|
CREATE INDEX IF NOT EXISTS idx_producers_message ON message_producers(message_id, message_version);
|
|
97
97
|
CREATE INDEX IF NOT EXISTS idx_consumers_message ON message_consumers(message_id, message_version);
|
|
98
98
|
`;
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
99
|
+
function queryAll(db, sql, params = []) {
|
|
100
|
+
const stmt = db.prepare(sql);
|
|
101
|
+
stmt.bind(params);
|
|
102
|
+
const rows = [];
|
|
103
|
+
while (stmt.step()) {
|
|
104
|
+
rows.push(stmt.getAsObject());
|
|
105
|
+
}
|
|
106
|
+
stmt.free();
|
|
107
|
+
return rows;
|
|
108
|
+
}
|
|
109
|
+
function queryOne(db, sql, params = []) {
|
|
110
|
+
const stmt = db.prepare(sql);
|
|
111
|
+
stmt.bind(params);
|
|
112
|
+
const result = stmt.step() ? stmt.getAsObject() : null;
|
|
113
|
+
stmt.free();
|
|
114
|
+
return result;
|
|
115
|
+
}
|
|
116
|
+
var FieldsDatabase = class _FieldsDatabase {
|
|
111
117
|
db;
|
|
112
|
-
|
|
118
|
+
dbPath;
|
|
119
|
+
constructor(db, dbPath) {
|
|
120
|
+
this.db = db;
|
|
121
|
+
this.dbPath = dbPath;
|
|
122
|
+
}
|
|
123
|
+
static async create(dbPath, options) {
|
|
113
124
|
if (options?.recreate && fs.existsSync(dbPath)) {
|
|
114
125
|
fs.unlinkSync(dbPath);
|
|
115
126
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
127
|
+
const SQL = await initSqlJs();
|
|
128
|
+
let db;
|
|
129
|
+
if (!options?.recreate && fs.existsSync(dbPath)) {
|
|
130
|
+
const buffer = fs.readFileSync(dbPath);
|
|
131
|
+
db = new SQL.Database(buffer);
|
|
132
|
+
} else {
|
|
133
|
+
db = new SQL.Database();
|
|
134
|
+
}
|
|
135
|
+
db.run(SCHEMA_SQL);
|
|
136
|
+
return new _FieldsDatabase(db, dbPath);
|
|
119
137
|
}
|
|
120
138
|
insertField(field) {
|
|
121
|
-
this.db.
|
|
139
|
+
this.db.run(
|
|
122
140
|
`INSERT INTO fields (path, type, description, required, schema_format, message_id, message_version, message_type, message_name, message_summary, message_owners)
|
|
123
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
141
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
142
|
+
[
|
|
143
|
+
field.path,
|
|
144
|
+
field.type,
|
|
145
|
+
field.description,
|
|
146
|
+
field.required ? 1 : 0,
|
|
147
|
+
field.schemaFormat,
|
|
148
|
+
field.messageId,
|
|
149
|
+
field.messageVersion,
|
|
150
|
+
field.messageType,
|
|
151
|
+
field.messageName || "",
|
|
152
|
+
field.messageSummary || "",
|
|
153
|
+
JSON.stringify(field.messageOwners || [])
|
|
154
|
+
]
|
|
136
155
|
);
|
|
137
156
|
}
|
|
138
157
|
insertProducer(messageId, messageVersion, serviceId, serviceVersion, serviceName, serviceSummary, serviceOwners) {
|
|
139
|
-
this.db.
|
|
158
|
+
this.db.run(
|
|
140
159
|
`INSERT INTO message_producers (message_id, message_version, service_id, service_version, service_name, service_summary, service_owners)
|
|
141
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
160
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
161
|
+
[
|
|
162
|
+
messageId,
|
|
163
|
+
messageVersion,
|
|
164
|
+
serviceId,
|
|
165
|
+
serviceVersion,
|
|
166
|
+
serviceName || "",
|
|
167
|
+
serviceSummary || "",
|
|
168
|
+
JSON.stringify(serviceOwners || [])
|
|
169
|
+
]
|
|
150
170
|
);
|
|
151
171
|
}
|
|
152
172
|
insertConsumer(messageId, messageVersion, serviceId, serviceVersion, serviceName, serviceSummary, serviceOwners) {
|
|
153
|
-
this.db.
|
|
173
|
+
this.db.run(
|
|
154
174
|
`INSERT INTO message_consumers (message_id, message_version, service_id, service_version, service_name, service_summary, service_owners)
|
|
155
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
175
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
176
|
+
[
|
|
177
|
+
messageId,
|
|
178
|
+
messageVersion,
|
|
179
|
+
serviceId,
|
|
180
|
+
serviceVersion,
|
|
181
|
+
serviceName || "",
|
|
182
|
+
serviceSummary || "",
|
|
183
|
+
JSON.stringify(serviceOwners || [])
|
|
184
|
+
]
|
|
164
185
|
);
|
|
165
186
|
}
|
|
166
|
-
|
|
167
|
-
|
|
187
|
+
/** Save the in-memory database to disk */
|
|
188
|
+
save() {
|
|
189
|
+
const data = this.db.export();
|
|
190
|
+
const buffer = Buffer.from(data);
|
|
191
|
+
fs.writeFileSync(this.dbPath, buffer);
|
|
168
192
|
}
|
|
169
193
|
queryFields(params) {
|
|
170
194
|
const {
|
|
@@ -189,9 +213,10 @@ var FieldsDatabase = class {
|
|
|
189
213
|
bindings.push(fieldPath);
|
|
190
214
|
}
|
|
191
215
|
if (q) {
|
|
192
|
-
conditions.push(`f.
|
|
193
|
-
const escaped = q.replace(
|
|
194
|
-
|
|
216
|
+
conditions.push(`(f.path LIKE ? ESCAPE '\\' OR f.description LIKE ? ESCAPE '\\' OR f.type LIKE ? ESCAPE '\\')`);
|
|
217
|
+
const escaped = q.replace(/\\/g, "\\\\").replace(/%/g, "\\%").replace(/_/g, "\\_");
|
|
218
|
+
const term = `%${escaped}%`;
|
|
219
|
+
bindings.push(term, term, term);
|
|
195
220
|
}
|
|
196
221
|
if (format) {
|
|
197
222
|
const formats2 = format.split(",").map((f) => f.trim()).filter(Boolean);
|
|
@@ -244,32 +269,36 @@ var FieldsDatabase = class {
|
|
|
244
269
|
}
|
|
245
270
|
const paginationWhere = cursorConditions.length > 0 ? whereClause ? `${whereClause} AND ${cursorConditions.join(" AND ")}` : `WHERE ${cursorConditions.join(" AND ")}` : whereClause;
|
|
246
271
|
const countSql = `SELECT COUNT(*) as cnt FROM fields f ${whereClause}`;
|
|
247
|
-
const total = this.db
|
|
272
|
+
const total = queryOne(this.db, countSql, bindings).cnt;
|
|
248
273
|
const mainSql = `SELECT f.* FROM fields f ${paginationWhere} ORDER BY f.id ASC LIMIT ?`;
|
|
249
274
|
const allBindings = [...bindings, ...cursorBindings, pageSize];
|
|
250
|
-
const rows = this.db
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
275
|
+
const rows = queryAll(this.db, mainSql, allBindings);
|
|
276
|
+
const parseOwners = (raw) => {
|
|
277
|
+
try {
|
|
278
|
+
return JSON.parse(raw || "[]");
|
|
279
|
+
} catch {
|
|
280
|
+
return [];
|
|
281
|
+
}
|
|
282
|
+
};
|
|
257
283
|
const fields = rows.map((row) => {
|
|
258
|
-
const producers =
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const
|
|
272
|
-
|
|
284
|
+
const producers = queryAll(
|
|
285
|
+
this.db,
|
|
286
|
+
`SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_producers WHERE message_id = ? AND message_version = ?`,
|
|
287
|
+
[row.message_id, row.message_version]
|
|
288
|
+
);
|
|
289
|
+
const consumers = queryAll(
|
|
290
|
+
this.db,
|
|
291
|
+
`SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_consumers WHERE message_id = ? AND message_version = ?`,
|
|
292
|
+
[row.message_id, row.message_version]
|
|
293
|
+
);
|
|
294
|
+
const usedInCount = queryOne(this.db, `SELECT COUNT(DISTINCT message_id || '/' || message_version) as cnt FROM fields WHERE path = ?`, [
|
|
295
|
+
row.path
|
|
296
|
+
]).cnt;
|
|
297
|
+
const typeRows = queryAll(
|
|
298
|
+
this.db,
|
|
299
|
+
`SELECT type, COUNT(DISTINCT message_id || '/' || message_version) as count FROM fields WHERE path = ? GROUP BY type`,
|
|
300
|
+
[row.path]
|
|
301
|
+
);
|
|
273
302
|
const conflicts = typeRows.length > 1 ? typeRows.map((r) => ({ type: r.type, count: r.count })) : void 0;
|
|
274
303
|
return {
|
|
275
304
|
id: row.id,
|
|
@@ -303,11 +332,11 @@ var FieldsDatabase = class {
|
|
|
303
332
|
};
|
|
304
333
|
});
|
|
305
334
|
const formatsFacetSql = `SELECT f.schema_format as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.schema_format`;
|
|
306
|
-
const formats = this.db
|
|
335
|
+
const formats = queryAll(this.db, formatsFacetSql, bindings);
|
|
307
336
|
const typesFacetSql = `SELECT f.type as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.type`;
|
|
308
|
-
const types = this.db
|
|
337
|
+
const types = queryAll(this.db, typesFacetSql, bindings);
|
|
309
338
|
const messageTypesFacetSql = `SELECT f.message_type as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.message_type`;
|
|
310
|
-
const messageTypes = this.db
|
|
339
|
+
const messageTypes = queryAll(this.db, messageTypesFacetSql, bindings);
|
|
311
340
|
const lastRow = rows[rows.length - 1];
|
|
312
341
|
const nextCursor = lastRow && rows.length === pageSize ? encodeCursor(lastRow.id) : void 0;
|
|
313
342
|
return {
|
|
@@ -483,7 +512,7 @@ async function buildFieldsIndex(catalogDir, outputDir) {
|
|
|
483
512
|
if (!fs2.existsSync(dbDir)) {
|
|
484
513
|
fs2.mkdirSync(dbDir, { recursive: true });
|
|
485
514
|
}
|
|
486
|
-
const db =
|
|
515
|
+
const db = await FieldsDatabase.create(dbPath, { recreate: true });
|
|
487
516
|
const warnings = [];
|
|
488
517
|
try {
|
|
489
518
|
const [events, commands, queries] = await Promise.all([
|
|
@@ -554,7 +583,7 @@ async function buildFieldsIndex(catalogDir, outputDir) {
|
|
|
554
583
|
}
|
|
555
584
|
}
|
|
556
585
|
}
|
|
557
|
-
db.
|
|
586
|
+
db.save();
|
|
558
587
|
db.close();
|
|
559
588
|
return { dbPath, warnings };
|
|
560
589
|
} catch (err) {
|
package/dist/generate.cjs
CHANGED
package/dist/generate.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
generate
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-4YHMATES.js";
|
|
4
|
+
import "./chunk-677ZSR3F.js";
|
|
5
|
+
import "./chunk-5S25RP7K.js";
|
|
6
6
|
import "./chunk-5T63CXKU.js";
|
|
7
7
|
export {
|
|
8
8
|
generate
|
package/dist/utils/cli-logger.js
CHANGED
|
@@ -150,10 +150,10 @@ export default defineConfig({
|
|
|
150
150
|
},
|
|
151
151
|
ssr: {
|
|
152
152
|
noExternal: ['@xyflow/react'],
|
|
153
|
-
external: ['eventcatalog.auth.js', 'eventcatalog.chat.js'
|
|
153
|
+
external: ['eventcatalog.auth.js', 'eventcatalog.chat.js'],
|
|
154
154
|
},
|
|
155
155
|
optimizeDeps: {
|
|
156
|
-
exclude: [
|
|
156
|
+
exclude: [],
|
|
157
157
|
// Pre-bundle heavy dependencies so Vite doesn't discover and transform
|
|
158
158
|
// them lazily on first request. This significantly reduces initial page
|
|
159
159
|
// load time in dev mode.
|
|
@@ -124,6 +124,7 @@ const getAuthConfig = async () => {
|
|
|
124
124
|
const providers = await getAuthProviders();
|
|
125
125
|
|
|
126
126
|
return {
|
|
127
|
+
trustHost: true,
|
|
127
128
|
providers,
|
|
128
129
|
callbacks: {
|
|
129
130
|
async signIn({ user, account, profile }: { user: User; account: Account | null; profile?: Profile }) {
|
|
@@ -256,7 +256,12 @@ const repositoryUrl = catalog?.repositoryUrl || 'https://github.com/event-catalo
|
|
|
256
256
|
});
|
|
257
257
|
|
|
258
258
|
document.getElementById('signout-btn')?.addEventListener('click', async () => {
|
|
259
|
-
|
|
259
|
+
try {
|
|
260
|
+
await signOut();
|
|
261
|
+
} catch (error) {
|
|
262
|
+
console.error('Sign out failed:', error);
|
|
263
|
+
alert('Sign out failed. Please check your AUTH_TRUST_HOST configuration if running behind a reverse proxy.');
|
|
264
|
+
}
|
|
260
265
|
});
|
|
261
266
|
}
|
|
262
267
|
}
|
|
@@ -35,7 +35,7 @@ export async function buildFieldsIndex(catalogDir: string, outputDir?: string):
|
|
|
35
35
|
fs.mkdirSync(dbDir, { recursive: true });
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
const db =
|
|
38
|
+
const db = await FieldsDatabase.create(dbPath, { recreate: true });
|
|
39
39
|
const warnings: Warning[] = [];
|
|
40
40
|
|
|
41
41
|
try {
|
|
@@ -121,7 +121,7 @@ export async function buildFieldsIndex(catalogDir: string, outputDir?: string):
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
db.
|
|
124
|
+
db.save();
|
|
125
125
|
db.close();
|
|
126
126
|
return { dbPath, warnings };
|
|
127
127
|
} catch (err) {
|
|
@@ -8,9 +8,9 @@ describe('FieldsDatabase', () => {
|
|
|
8
8
|
let db: FieldsDatabase;
|
|
9
9
|
let tmpDir: string;
|
|
10
10
|
|
|
11
|
-
beforeEach(() => {
|
|
11
|
+
beforeEach(async () => {
|
|
12
12
|
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'fields-db-'));
|
|
13
|
-
db =
|
|
13
|
+
db = await FieldsDatabase.create(path.join(tmpDir, 'fields.db'), { recreate: true });
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
afterEach(() => {
|
|
@@ -19,8 +19,8 @@ describe('FieldsDatabase', () => {
|
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
it('creates the schema tables on initialization', () => {
|
|
22
|
-
const
|
|
23
|
-
const tableNames =
|
|
22
|
+
const rows = db.db.exec("SELECT name FROM sqlite_master WHERE type='table'");
|
|
23
|
+
const tableNames = rows.length > 0 ? rows[0].values.map((r: any) => r[0]) : [];
|
|
24
24
|
expect(tableNames).toContain('fields');
|
|
25
25
|
expect(tableNames).toContain('message_producers');
|
|
26
26
|
expect(tableNames).toContain('message_consumers');
|
|
@@ -47,13 +47,12 @@ describe('FieldsDatabase', () => {
|
|
|
47
47
|
messageVersion: '1.0.0',
|
|
48
48
|
messageType: 'event',
|
|
49
49
|
});
|
|
50
|
-
db.rebuildFts();
|
|
51
50
|
const result = db.queryFields({});
|
|
52
51
|
expect(result.fields).toHaveLength(2);
|
|
53
52
|
expect(result.total).toBe(2);
|
|
54
53
|
});
|
|
55
54
|
|
|
56
|
-
it('filters fields by
|
|
55
|
+
it('filters fields by text search matching field path', () => {
|
|
57
56
|
db.insertField({
|
|
58
57
|
path: 'orderId',
|
|
59
58
|
type: 'string',
|
|
@@ -74,7 +73,6 @@ describe('FieldsDatabase', () => {
|
|
|
74
73
|
messageVersion: '1.0.0',
|
|
75
74
|
messageType: 'event',
|
|
76
75
|
});
|
|
77
|
-
db.rebuildFts();
|
|
78
76
|
const result = db.queryFields({ q: 'orderId' });
|
|
79
77
|
expect(result.fields).toHaveLength(1);
|
|
80
78
|
expect(result.fields[0].path).toBe('orderId');
|
|
@@ -111,7 +109,6 @@ describe('FieldsDatabase', () => {
|
|
|
111
109
|
messageVersion: '1.0.0',
|
|
112
110
|
messageType: 'event',
|
|
113
111
|
});
|
|
114
|
-
db.rebuildFts();
|
|
115
112
|
const result = db.queryFields({ shared: true });
|
|
116
113
|
expect(result.fields.every((f) => f.path === 'customerId')).toBe(true);
|
|
117
114
|
});
|
|
@@ -137,7 +134,6 @@ describe('FieldsDatabase', () => {
|
|
|
137
134
|
messageVersion: '1.0.0',
|
|
138
135
|
messageType: 'event',
|
|
139
136
|
});
|
|
140
|
-
db.rebuildFts();
|
|
141
137
|
const result = db.queryFields({});
|
|
142
138
|
expect(result.facets.formats).toContainEqual({ value: 'json-schema', count: 1 });
|
|
143
139
|
expect(result.facets.formats).toContainEqual({ value: 'avro', count: 1 });
|
|
@@ -156,7 +152,6 @@ describe('FieldsDatabase', () => {
|
|
|
156
152
|
messageType: 'event',
|
|
157
153
|
});
|
|
158
154
|
}
|
|
159
|
-
db.rebuildFts();
|
|
160
155
|
const page1 = db.queryFields({ pageSize: 2 });
|
|
161
156
|
expect(page1.fields).toHaveLength(2);
|
|
162
157
|
expect(page1.cursor).toBeDefined();
|
|
@@ -178,7 +173,6 @@ describe('FieldsDatabase', () => {
|
|
|
178
173
|
});
|
|
179
174
|
db.insertProducer('OrderCreated', '1.0.0', 'OrderService', '1.0.0');
|
|
180
175
|
db.insertConsumer('OrderCreated', '1.0.0', 'InventoryService', '2.0.0');
|
|
181
|
-
db.rebuildFts();
|
|
182
176
|
const result = db.queryFields({});
|
|
183
177
|
expect(result.fields[0].producers).toEqual([{ id: 'OrderService', version: '1.0.0' }]);
|
|
184
178
|
expect(result.fields[0].consumers).toEqual([{ id: 'InventoryService', version: '2.0.0' }]);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import Database from '
|
|
2
|
-
import type BetterSqlite3 from 'better-sqlite3';
|
|
1
|
+
import initSqlJs, { type Database as SqlJsDatabase } from 'sql.js';
|
|
3
2
|
import fs from 'node:fs';
|
|
4
3
|
|
|
5
4
|
export interface FieldRow {
|
|
@@ -119,37 +118,61 @@ const SCHEMA_SQL = `
|
|
|
119
118
|
CREATE INDEX IF NOT EXISTS idx_consumers_message ON message_consumers(message_id, message_version);
|
|
120
119
|
`;
|
|
121
120
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
|
|
121
|
+
/** Helper: run a SELECT and return rows as plain objects */
|
|
122
|
+
function queryAll(db: SqlJsDatabase, sql: string, params: any[] = []): any[] {
|
|
123
|
+
const stmt = db.prepare(sql);
|
|
124
|
+
stmt.bind(params);
|
|
125
|
+
const rows: any[] = [];
|
|
126
|
+
while (stmt.step()) {
|
|
127
|
+
rows.push(stmt.getAsObject());
|
|
128
|
+
}
|
|
129
|
+
stmt.free();
|
|
130
|
+
return rows;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Helper: run a SELECT and return the first row as a plain object */
|
|
134
|
+
function queryOne(db: SqlJsDatabase, sql: string, params: any[] = []): any {
|
|
135
|
+
const stmt = db.prepare(sql);
|
|
136
|
+
stmt.bind(params);
|
|
137
|
+
const result = stmt.step() ? stmt.getAsObject() : null;
|
|
138
|
+
stmt.free();
|
|
139
|
+
return result;
|
|
140
|
+
}
|
|
133
141
|
|
|
134
142
|
export class FieldsDatabase {
|
|
135
|
-
public db:
|
|
143
|
+
public db: SqlJsDatabase;
|
|
144
|
+
private dbPath: string;
|
|
145
|
+
|
|
146
|
+
private constructor(db: SqlJsDatabase, dbPath: string) {
|
|
147
|
+
this.db = db;
|
|
148
|
+
this.dbPath = dbPath;
|
|
149
|
+
}
|
|
136
150
|
|
|
137
|
-
|
|
151
|
+
static async create(dbPath: string, options?: { recreate?: boolean }): Promise<FieldsDatabase> {
|
|
138
152
|
if (options?.recreate && fs.existsSync(dbPath)) {
|
|
139
153
|
fs.unlinkSync(dbPath);
|
|
140
154
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
155
|
+
|
|
156
|
+
const SQL = await initSqlJs();
|
|
157
|
+
let db: SqlJsDatabase;
|
|
158
|
+
|
|
159
|
+
if (!options?.recreate && fs.existsSync(dbPath)) {
|
|
160
|
+
const buffer = fs.readFileSync(dbPath);
|
|
161
|
+
db = new SQL.Database(buffer);
|
|
162
|
+
} else {
|
|
163
|
+
db = new SQL.Database();
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
db.run(SCHEMA_SQL);
|
|
167
|
+
|
|
168
|
+
return new FieldsDatabase(db, dbPath);
|
|
144
169
|
}
|
|
145
170
|
|
|
146
171
|
insertField(field: FieldRow & { messageName?: string; messageSummary?: string; messageOwners?: string[] }): void {
|
|
147
|
-
this.db
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
)
|
|
152
|
-
.run(
|
|
172
|
+
this.db.run(
|
|
173
|
+
`INSERT INTO fields (path, type, description, required, schema_format, message_id, message_version, message_type, message_name, message_summary, message_owners)
|
|
174
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
175
|
+
[
|
|
153
176
|
field.path,
|
|
154
177
|
field.type,
|
|
155
178
|
field.description,
|
|
@@ -160,8 +183,9 @@ export class FieldsDatabase {
|
|
|
160
183
|
field.messageType,
|
|
161
184
|
field.messageName || '',
|
|
162
185
|
field.messageSummary || '',
|
|
163
|
-
JSON.stringify(field.messageOwners || [])
|
|
164
|
-
|
|
186
|
+
JSON.stringify(field.messageOwners || []),
|
|
187
|
+
]
|
|
188
|
+
);
|
|
165
189
|
}
|
|
166
190
|
|
|
167
191
|
insertProducer(
|
|
@@ -173,20 +197,19 @@ export class FieldsDatabase {
|
|
|
173
197
|
serviceSummary?: string,
|
|
174
198
|
serviceOwners?: string[]
|
|
175
199
|
): void {
|
|
176
|
-
this.db
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
)
|
|
181
|
-
.run(
|
|
200
|
+
this.db.run(
|
|
201
|
+
`INSERT INTO message_producers (message_id, message_version, service_id, service_version, service_name, service_summary, service_owners)
|
|
202
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
203
|
+
[
|
|
182
204
|
messageId,
|
|
183
205
|
messageVersion,
|
|
184
206
|
serviceId,
|
|
185
207
|
serviceVersion,
|
|
186
208
|
serviceName || '',
|
|
187
209
|
serviceSummary || '',
|
|
188
|
-
JSON.stringify(serviceOwners || [])
|
|
189
|
-
|
|
210
|
+
JSON.stringify(serviceOwners || []),
|
|
211
|
+
]
|
|
212
|
+
);
|
|
190
213
|
}
|
|
191
214
|
|
|
192
215
|
insertConsumer(
|
|
@@ -198,24 +221,26 @@ export class FieldsDatabase {
|
|
|
198
221
|
serviceSummary?: string,
|
|
199
222
|
serviceOwners?: string[]
|
|
200
223
|
): void {
|
|
201
|
-
this.db
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
)
|
|
206
|
-
.run(
|
|
224
|
+
this.db.run(
|
|
225
|
+
`INSERT INTO message_consumers (message_id, message_version, service_id, service_version, service_name, service_summary, service_owners)
|
|
226
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)`,
|
|
227
|
+
[
|
|
207
228
|
messageId,
|
|
208
229
|
messageVersion,
|
|
209
230
|
serviceId,
|
|
210
231
|
serviceVersion,
|
|
211
232
|
serviceName || '',
|
|
212
233
|
serviceSummary || '',
|
|
213
|
-
JSON.stringify(serviceOwners || [])
|
|
214
|
-
|
|
234
|
+
JSON.stringify(serviceOwners || []),
|
|
235
|
+
]
|
|
236
|
+
);
|
|
215
237
|
}
|
|
216
238
|
|
|
217
|
-
|
|
218
|
-
|
|
239
|
+
/** Save the in-memory database to disk */
|
|
240
|
+
save(): void {
|
|
241
|
+
const data = this.db.export();
|
|
242
|
+
const buffer = Buffer.from(data);
|
|
243
|
+
fs.writeFileSync(this.dbPath, buffer);
|
|
219
244
|
}
|
|
220
245
|
|
|
221
246
|
queryFields(params: QueryFieldsParams): QueryFieldsResult {
|
|
@@ -244,11 +269,12 @@ export class FieldsDatabase {
|
|
|
244
269
|
bindings.push(fieldPath);
|
|
245
270
|
}
|
|
246
271
|
|
|
247
|
-
//
|
|
272
|
+
// Text search using LIKE (replaces FTS5)
|
|
248
273
|
if (q) {
|
|
249
|
-
conditions.push(`f.
|
|
250
|
-
const escaped = q.replace(/
|
|
251
|
-
|
|
274
|
+
conditions.push(`(f.path LIKE ? ESCAPE '\\' OR f.description LIKE ? ESCAPE '\\' OR f.type LIKE ? ESCAPE '\\')`);
|
|
275
|
+
const escaped = q.replace(/\\/g, '\\\\').replace(/%/g, '\\%').replace(/_/g, '\\_');
|
|
276
|
+
const term = `%${escaped}%`;
|
|
277
|
+
bindings.push(term, term, term);
|
|
252
278
|
}
|
|
253
279
|
|
|
254
280
|
// Facet filters (support comma-separated multi-select)
|
|
@@ -324,47 +350,46 @@ export class FieldsDatabase {
|
|
|
324
350
|
|
|
325
351
|
// Total count (without pagination)
|
|
326
352
|
const countSql = `SELECT COUNT(*) as cnt FROM fields f ${whereClause}`;
|
|
327
|
-
const total = (this.db
|
|
353
|
+
const total = (queryOne(this.db, countSql, bindings) as any).cnt;
|
|
328
354
|
|
|
329
355
|
// Main query with pagination
|
|
330
356
|
const mainSql = `SELECT f.* FROM fields f ${paginationWhere} ORDER BY f.id ASC LIMIT ?`;
|
|
331
357
|
const allBindings = [...bindings, ...cursorBindings, pageSize];
|
|
332
|
-
const rows = this.db
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
`SELECT type, COUNT(DISTINCT message_id || '/' || message_version) as count FROM fields WHERE path = ? GROUP BY type`
|
|
342
|
-
);
|
|
358
|
+
const rows = queryAll(this.db, mainSql, allBindings);
|
|
359
|
+
|
|
360
|
+
const parseOwners = (raw: string) => {
|
|
361
|
+
try {
|
|
362
|
+
return JSON.parse(raw || '[]');
|
|
363
|
+
} catch {
|
|
364
|
+
return [];
|
|
365
|
+
}
|
|
366
|
+
};
|
|
343
367
|
|
|
344
368
|
// Gather producers and consumers for the returned fields
|
|
345
369
|
const fields: FieldResult[] = rows.map((row) => {
|
|
346
|
-
const producers =
|
|
347
|
-
.
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
const consumers = this.db
|
|
353
|
-
.prepare(
|
|
354
|
-
`SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_consumers WHERE message_id = ? AND message_version = ?`
|
|
355
|
-
)
|
|
356
|
-
.all(row.message_id, row.message_version) as any[];
|
|
357
|
-
|
|
358
|
-
const parseOwners = (raw: string) => {
|
|
359
|
-
try {
|
|
360
|
-
return JSON.parse(raw || '[]');
|
|
361
|
-
} catch {
|
|
362
|
-
return [];
|
|
363
|
-
}
|
|
364
|
-
};
|
|
370
|
+
const producers = queryAll(
|
|
371
|
+
this.db,
|
|
372
|
+
`SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_producers WHERE message_id = ? AND message_version = ?`,
|
|
373
|
+
[row.message_id, row.message_version]
|
|
374
|
+
);
|
|
365
375
|
|
|
366
|
-
const
|
|
367
|
-
|
|
376
|
+
const consumers = queryAll(
|
|
377
|
+
this.db,
|
|
378
|
+
`SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_consumers WHERE message_id = ? AND message_version = ?`,
|
|
379
|
+
[row.message_id, row.message_version]
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
const usedInCount = (
|
|
383
|
+
queryOne(this.db, `SELECT COUNT(DISTINCT message_id || '/' || message_version) as cnt FROM fields WHERE path = ?`, [
|
|
384
|
+
row.path,
|
|
385
|
+
]) as any
|
|
386
|
+
).cnt;
|
|
387
|
+
|
|
388
|
+
const typeRows = queryAll(
|
|
389
|
+
this.db,
|
|
390
|
+
`SELECT type, COUNT(DISTINCT message_id || '/' || message_version) as count FROM fields WHERE path = ? GROUP BY type`,
|
|
391
|
+
[row.path]
|
|
392
|
+
);
|
|
368
393
|
const conflicts =
|
|
369
394
|
typeRows.length > 1 ? typeRows.map((r) => ({ type: r.type as string, count: r.count as number })) : undefined;
|
|
370
395
|
|
|
@@ -402,13 +427,13 @@ export class FieldsDatabase {
|
|
|
402
427
|
|
|
403
428
|
// Facets (computed from filtered set, not paginated)
|
|
404
429
|
const formatsFacetSql = `SELECT f.schema_format as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.schema_format`;
|
|
405
|
-
const formats = this.db
|
|
430
|
+
const formats = queryAll(this.db, formatsFacetSql, bindings) as FacetEntry[];
|
|
406
431
|
|
|
407
432
|
const typesFacetSql = `SELECT f.type as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.type`;
|
|
408
|
-
const types = this.db
|
|
433
|
+
const types = queryAll(this.db, typesFacetSql, bindings) as FacetEntry[];
|
|
409
434
|
|
|
410
435
|
const messageTypesFacetSql = `SELECT f.message_type as value, COUNT(*) as count FROM fields f ${whereClause} GROUP BY f.message_type`;
|
|
411
|
-
const messageTypes = this.db
|
|
436
|
+
const messageTypes = queryAll(this.db, messageTypesFacetSql, bindings) as FacetEntry[];
|
|
412
437
|
|
|
413
438
|
// Build cursor for next page
|
|
414
439
|
const lastRow = rows[rows.length - 1];
|
|
@@ -438,9 +463,9 @@ function decodeCursor(cursor: string): number {
|
|
|
438
463
|
// Singleton management
|
|
439
464
|
let instance: FieldsDatabase | null = null;
|
|
440
465
|
|
|
441
|
-
export function getFieldsDatabase(dbPath: string): FieldsDatabase {
|
|
466
|
+
export async function getFieldsDatabase(dbPath: string): Promise<FieldsDatabase> {
|
|
442
467
|
if (!instance) {
|
|
443
|
-
instance =
|
|
468
|
+
instance = await FieldsDatabase.create(dbPath);
|
|
444
469
|
}
|
|
445
470
|
return instance;
|
|
446
471
|
}
|
|
@@ -13,7 +13,7 @@ app.get('/', async (c) => {
|
|
|
13
13
|
const url = new URL(c.req.raw.url);
|
|
14
14
|
const sp = url.searchParams;
|
|
15
15
|
|
|
16
|
-
const db = getFieldsDatabase(dbPath);
|
|
16
|
+
const db = await getFieldsDatabase(dbPath);
|
|
17
17
|
const params = {
|
|
18
18
|
q: sp.get('q') || undefined,
|
|
19
19
|
format: sp.get('format') || undefined,
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"url": "https://github.com/event-catalog/eventcatalog.git"
|
|
7
7
|
},
|
|
8
8
|
"type": "module",
|
|
9
|
-
"version": "3.26.
|
|
9
|
+
"version": "3.26.8",
|
|
10
10
|
"publishConfig": {
|
|
11
11
|
"access": "public"
|
|
12
12
|
},
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"astro-seo": "^0.8.4",
|
|
57
57
|
"auth-astro": "^4.2.0",
|
|
58
58
|
"axios": "^1.13.5",
|
|
59
|
-
"
|
|
59
|
+
"sql.js": "^1.12.0",
|
|
60
60
|
"boxen": "^8.0.1",
|
|
61
61
|
"commander": "^12.1.0",
|
|
62
62
|
"concurrently": "^8.2.2",
|
|
@@ -103,12 +103,11 @@
|
|
|
103
103
|
"uuid": "^10.0.0",
|
|
104
104
|
"zod": "^4.3.6",
|
|
105
105
|
"@eventcatalog/linter": "1.0.17",
|
|
106
|
-
"@eventcatalog/
|
|
107
|
-
"@eventcatalog/
|
|
106
|
+
"@eventcatalog/sdk": "2.18.2",
|
|
107
|
+
"@eventcatalog/visualiser": "^3.16.1"
|
|
108
108
|
},
|
|
109
109
|
"devDependencies": {
|
|
110
110
|
"@astrojs/check": "^0.9.8",
|
|
111
|
-
"@types/better-sqlite3": "^7.6.13",
|
|
112
111
|
"@types/dagre": "^0.7.52",
|
|
113
112
|
"@types/diff": "^5.2.2",
|
|
114
113
|
"@types/js-yaml": "^4.0.9",
|