@eventcatalog/core 3.26.5 → 3.26.7

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.
@@ -37,7 +37,7 @@ var import_axios = __toESM(require("axios"), 1);
37
37
  var import_os = __toESM(require("os"), 1);
38
38
 
39
39
  // package.json
40
- var version = "3.26.5";
40
+ var version = "3.26.7";
41
41
 
42
42
  // src/constants.ts
43
43
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "../chunk-CAY4Z5KS.js";
4
- import "../chunk-GS43QEM5.js";
3
+ } from "../chunk-MZ3EFCJ3.js";
4
+ import "../chunk-WA7DUXXY.js";
5
5
  export {
6
6
  raiseEvent
7
7
  };
@@ -111,7 +111,7 @@ var import_axios = __toESM(require("axios"), 1);
111
111
  var import_os = __toESM(require("os"), 1);
112
112
 
113
113
  // package.json
114
- var version = "3.26.5";
114
+ var version = "3.26.7";
115
115
 
116
116
  // src/constants.ts
117
117
  var VERSION = version;
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  log_build_default
3
- } from "../chunk-OATSS5PW.js";
4
- import "../chunk-CAY4Z5KS.js";
3
+ } from "../chunk-QOKBVPDA.js";
4
+ import "../chunk-MZ3EFCJ3.js";
5
5
  import "../chunk-4UVFXLPI.js";
6
- import "../chunk-GS43QEM5.js";
6
+ import "../chunk-WA7DUXXY.js";
7
7
  import "../chunk-5T63CXKU.js";
8
8
  export {
9
9
  log_build_default as default
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-GS43QEM5.js";
3
+ } from "./chunk-WA7DUXXY.js";
4
4
 
5
5
  // src/utils/cli-logger.ts
6
6
  import pc from "picocolors";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-GS43QEM5.js";
3
+ } from "./chunk-WA7DUXXY.js";
4
4
 
5
5
  // src/analytics/analytics.js
6
6
  import axios from "axios";
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  raiseEvent
3
- } from "./chunk-CAY4Z5KS.js";
3
+ } from "./chunk-MZ3EFCJ3.js";
4
4
  import {
5
5
  countResources,
6
6
  serializeCounts
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  logger
3
- } from "./chunk-WL3ZBI7D.js";
3
+ } from "./chunk-C7P46YYR.js";
4
4
  import {
5
5
  cleanup,
6
6
  getEventCatalogConfigFile
@@ -1,5 +1,5 @@
1
1
  // package.json
2
- var version = "3.26.5";
2
+ var version = "3.26.7";
3
3
 
4
4
  // src/constants.ts
5
5
  var VERSION = version;
@@ -25,7 +25,7 @@ __export(constants_exports, {
25
25
  module.exports = __toCommonJS(constants_exports);
26
26
 
27
27
  // package.json
28
- var version = "3.26.5";
28
+ var version = "3.26.7";
29
29
 
30
30
  // src/constants.ts
31
31
  var VERSION = version;
package/dist/constants.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  VERSION
3
- } from "./chunk-GS43QEM5.js";
3
+ } from "./chunk-WA7DUXXY.js";
4
4
  export {
5
5
  VERSION
6
6
  };
@@ -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.5";
117
+ var version = "3.26.7";
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 import_better_sqlite3 = __toESM(require("better-sqlite3"), 1);
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
- 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 {
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
- constructor(dbPath, options) {
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
- this.db = new import_better_sqlite3.default(dbPath);
770
- this.db.pragma("journal_mode = WAL");
771
- this.db.exec(SCHEMA_SQL);
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.prepare(
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
- ).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 || [])
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.prepare(
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
- ).run(
796
- messageId,
797
- messageVersion,
798
- serviceId,
799
- serviceVersion,
800
- serviceName || "",
801
- serviceSummary || "",
802
- JSON.stringify(serviceOwners || [])
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.prepare(
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
- ).run(
810
- messageId,
811
- messageVersion,
812
- serviceId,
813
- serviceVersion,
814
- serviceName || "",
815
- serviceSummary || "",
816
- JSON.stringify(serviceOwners || [])
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
- rebuildFts() {
820
- this.db.exec(FTS_SQL);
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.id IN (SELECT rowid FROM fields_fts WHERE fields_fts MATCH ?)`);
846
- const escaped = q.replace(/"/g, '""');
847
- bindings.push(`"${escaped}" *`);
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.prepare(countSql).get(...bindings).cnt;
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.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
- );
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 = 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);
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.prepare(formatsFacetSql).all(...bindings);
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.prepare(typesFacetSql).all(...bindings);
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.prepare(messageTypesFacetSql).all(...bindings);
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 = new FieldsDatabase(dbPath, { recreate: true });
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.rebuildFts();
1239
+ db.save();
1211
1240
  db.close();
1212
1241
  return { dbPath, warnings };
1213
1242
  } catch (err) {
@@ -6,8 +6,8 @@ import {
6
6
  } from "./chunk-PLNJC7NZ.js";
7
7
  import {
8
8
  log_build_default
9
- } from "./chunk-OATSS5PW.js";
10
- import "./chunk-CAY4Z5KS.js";
9
+ } from "./chunk-QOKBVPDA.js";
10
+ import "./chunk-MZ3EFCJ3.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-LUSVWRNC.js";
25
+ } from "./chunk-QU7VBI7O.js";
26
26
  import {
27
27
  logger
28
- } from "./chunk-WL3ZBI7D.js";
28
+ } from "./chunk-C7P46YYR.js";
29
29
  import {
30
30
  VERSION
31
- } from "./chunk-GS43QEM5.js";
31
+ } from "./chunk-WA7DUXXY.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 Database from "better-sqlite3";
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
- var FTS_SQL = `
100
- DROP TABLE IF EXISTS fields_fts;
101
- CREATE VIRTUAL TABLE fields_fts USING fts5(
102
- path,
103
- description,
104
- type,
105
- content=fields,
106
- content_rowid=id
107
- );
108
- INSERT INTO fields_fts(rowid, path, description, type) SELECT id, path, description, type FROM fields;
109
- `;
110
- var FieldsDatabase = class {
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
- constructor(dbPath, options) {
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
- this.db = new Database(dbPath);
117
- this.db.pragma("journal_mode = WAL");
118
- this.db.exec(SCHEMA_SQL);
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.prepare(
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
- ).run(
125
- field.path,
126
- field.type,
127
- field.description,
128
- field.required ? 1 : 0,
129
- field.schemaFormat,
130
- field.messageId,
131
- field.messageVersion,
132
- field.messageType,
133
- field.messageName || "",
134
- field.messageSummary || "",
135
- JSON.stringify(field.messageOwners || [])
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.prepare(
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
- ).run(
143
- messageId,
144
- messageVersion,
145
- serviceId,
146
- serviceVersion,
147
- serviceName || "",
148
- serviceSummary || "",
149
- JSON.stringify(serviceOwners || [])
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.prepare(
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
- ).run(
157
- messageId,
158
- messageVersion,
159
- serviceId,
160
- serviceVersion,
161
- serviceName || "",
162
- serviceSummary || "",
163
- JSON.stringify(serviceOwners || [])
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
- rebuildFts() {
167
- this.db.exec(FTS_SQL);
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.id IN (SELECT rowid FROM fields_fts WHERE fields_fts MATCH ?)`);
193
- const escaped = q.replace(/"/g, '""');
194
- bindings.push(`"${escaped}" *`);
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.prepare(countSql).get(...bindings).cnt;
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.prepare(mainSql).all(...allBindings);
251
- const usedInStmt = this.db.prepare(
252
- `SELECT COUNT(DISTINCT message_id || '/' || message_version) as cnt FROM fields WHERE path = ?`
253
- );
254
- const conflictsStmt = this.db.prepare(
255
- `SELECT type, COUNT(DISTINCT message_id || '/' || message_version) as count FROM fields WHERE path = ? GROUP BY type`
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 = this.db.prepare(
259
- `SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_producers WHERE message_id = ? AND message_version = ?`
260
- ).all(row.message_id, row.message_version);
261
- const consumers = this.db.prepare(
262
- `SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_consumers WHERE message_id = ? AND message_version = ?`
263
- ).all(row.message_id, row.message_version);
264
- const parseOwners = (raw) => {
265
- try {
266
- return JSON.parse(raw || "[]");
267
- } catch {
268
- return [];
269
- }
270
- };
271
- const usedInCount = usedInStmt.get(row.path).cnt;
272
- const typeRows = conflictsStmt.all(row.path);
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.prepare(formatsFacetSql).all(...bindings);
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.prepare(typesFacetSql).all(...bindings);
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.prepare(messageTypesFacetSql).all(...bindings);
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 = new FieldsDatabase(dbPath, { recreate: true });
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.rebuildFts();
586
+ db.save();
558
587
  db.close();
559
588
  return { dbPath, warnings };
560
589
  } catch (err) {
package/dist/generate.cjs CHANGED
@@ -78,7 +78,7 @@ var getEventCatalogConfigFile = async (projectDirectory) => {
78
78
  var import_picocolors = __toESM(require("picocolors"), 1);
79
79
 
80
80
  // package.json
81
- var version = "3.26.5";
81
+ var version = "3.26.7";
82
82
 
83
83
  // src/constants.ts
84
84
  var VERSION = version;
package/dist/generate.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  generate
3
- } from "./chunk-LUSVWRNC.js";
4
- import "./chunk-WL3ZBI7D.js";
5
- import "./chunk-GS43QEM5.js";
3
+ } from "./chunk-QU7VBI7O.js";
4
+ import "./chunk-C7P46YYR.js";
5
+ import "./chunk-WA7DUXXY.js";
6
6
  import "./chunk-5T63CXKU.js";
7
7
  export {
8
8
  generate
@@ -36,7 +36,7 @@ module.exports = __toCommonJS(cli_logger_exports);
36
36
  var import_picocolors = __toESM(require("picocolors"), 1);
37
37
 
38
38
  // package.json
39
- var version = "3.26.5";
39
+ var version = "3.26.7";
40
40
 
41
41
  // src/constants.ts
42
42
  var VERSION = version;
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  logger
3
- } from "../chunk-WL3ZBI7D.js";
4
- import "../chunk-GS43QEM5.js";
3
+ } from "../chunk-C7P46YYR.js";
4
+ import "../chunk-WA7DUXXY.js";
5
5
  export {
6
6
  logger
7
7
  };
@@ -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', 'better-sqlite3'],
153
+ external: ['eventcatalog.auth.js', 'eventcatalog.chat.js'],
154
154
  },
155
155
  optimizeDeps: {
156
- exclude: ['better-sqlite3'],
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.
@@ -12,7 +12,9 @@ import { useCallback, lazy, Suspense, useEffect } from 'react';
12
12
  import type { Node, Edge } from '@xyflow/react';
13
13
  import { buildUrl } from '@utils/url-builder';
14
14
 
15
- const NodeGraph = lazy(() => import('@eventcatalog/visualiser').then((module) => ({ default: module.NodeGraph })));
15
+ const NodeGraph = lazy(() =>
16
+ import('@eventcatalog/visualiser').then((module) => ({ default: module.NodeGraph }))
17
+ ) as React.LazyExoticComponent<React.ComponentType<AstroNodeGraphProps & Record<string, unknown>>>;
16
18
 
17
19
  interface AstroNodeGraphProps {
18
20
  id: string;
@@ -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 = new FieldsDatabase(dbPath, { recreate: true });
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.rebuildFts();
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 = new FieldsDatabase(path.join(tmpDir, 'fields.db'), { recreate: true });
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 tables = db.db.prepare("SELECT name FROM sqlite_master WHERE type='table'").all();
23
- const tableNames = tables.map((t: any) => t.name);
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 full-text search matching field path', () => {
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 'better-sqlite3';
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
- const FTS_SQL = `
123
- DROP TABLE IF EXISTS fields_fts;
124
- CREATE VIRTUAL TABLE fields_fts USING fts5(
125
- path,
126
- description,
127
- type,
128
- content=fields,
129
- content_rowid=id
130
- );
131
- INSERT INTO fields_fts(rowid, path, description, type) SELECT id, path, description, type FROM fields;
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: BetterSqlite3.Database;
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
- constructor(dbPath: string, options?: { recreate?: boolean }) {
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
- this.db = new Database(dbPath);
142
- this.db.pragma('journal_mode = WAL');
143
- this.db.exec(SCHEMA_SQL);
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
- .prepare(
149
- `INSERT INTO fields (path, type, description, required, schema_format, message_id, message_version, message_type, message_name, message_summary, message_owners)
150
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
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
- .prepare(
178
- `INSERT INTO message_producers (message_id, message_version, service_id, service_version, service_name, service_summary, service_owners)
179
- VALUES (?, ?, ?, ?, ?, ?, ?)`
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
- .prepare(
203
- `INSERT INTO message_consumers (message_id, message_version, service_id, service_version, service_name, service_summary, service_owners)
204
- VALUES (?, ?, ?, ?, ?, ?, ?)`
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
- rebuildFts(): void {
218
- this.db.exec(FTS_SQL);
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
- // FTS filter (quote the term so dots/brackets in field paths aren't parsed as FTS syntax)
272
+ // Text search using LIKE (replaces FTS5)
248
273
  if (q) {
249
- conditions.push(`f.id IN (SELECT rowid FROM fields_fts WHERE fields_fts MATCH ?)`);
250
- const escaped = q.replace(/"/g, '""');
251
- bindings.push(`"${escaped}" *`);
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.prepare(countSql).get(...bindings) as any).cnt;
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.prepare(mainSql).all(...allBindings) as any[];
333
-
334
- // Prepare usedInCount query (distinct messages per field path)
335
- const usedInStmt = this.db.prepare(
336
- `SELECT COUNT(DISTINCT message_id || '/' || message_version) as cnt FROM fields WHERE path = ?`
337
- );
338
-
339
- // Prepare conflicts query (distinct types per field path with counts)
340
- const conflictsStmt = this.db.prepare(
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 = this.db
347
- .prepare(
348
- `SELECT service_id, service_version, service_name, service_summary, service_owners FROM message_producers WHERE message_id = ? AND message_version = ?`
349
- )
350
- .all(row.message_id, row.message_version) as any[];
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 usedInCount = (usedInStmt.get(row.path) as any).cnt;
367
- const typeRows = conflictsStmt.all(row.path) as any[];
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.prepare(formatsFacetSql).all(...bindings) as FacetEntry[];
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.prepare(typesFacetSql).all(...bindings) as FacetEntry[];
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.prepare(messageTypesFacetSql).all(...bindings) as FacetEntry[];
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 = new FieldsDatabase(dbPath);
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,
@@ -83,7 +83,7 @@ export const getNodesAndEdges = ({
83
83
  for (const occ of occurrences) {
84
84
  const msgNodeId = `msg-${occ.messageId}-${occ.messageVersion}`;
85
85
  const occType = occ.fieldType || fieldType;
86
- const fieldNodeId = fieldNodeIds.get(occType) || fieldNodeIds.values().next().value;
86
+ const fieldNodeId = fieldNodeIds.get(occType) || fieldNodeIds.values().next().value!;
87
87
 
88
88
  if (!addedNodes.has(msgNodeId)) {
89
89
  nodes.push(
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.5",
9
+ "version": "3.26.7",
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
- "better-sqlite3": "^12.8.0",
59
+ "sql.js": "^1.12.0",
60
60
  "boxen": "^8.0.1",
61
61
  "commander": "^12.1.0",
62
62
  "concurrently": "^8.2.2",
@@ -102,13 +102,12 @@
102
102
  "update-notifier": "^7.3.1",
103
103
  "uuid": "^10.0.0",
104
104
  "zod": "^4.3.6",
105
- "@eventcatalog/linter": "1.0.17",
106
105
  "@eventcatalog/sdk": "2.18.2",
107
- "@eventcatalog/visualiser": "^3.16.0"
106
+ "@eventcatalog/linter": "1.0.17",
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",