aegisnode 0.0.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.
@@ -0,0 +1,195 @@
1
+ import QueryMesh from 'querymesh';
2
+
3
+ const SQL_DIALECTS = new Set(['mysql', 'pg', 'postgres', 'postgresql', 'sqlite', 'mssql', 'oracle']);
4
+ const NOSQL_DIALECTS = new Set(['mongo', 'mongodb', 'mongoose']);
5
+
6
+ function isPlainObject(value) {
7
+ return Boolean(value) && Object.prototype.toString.call(value) === '[object Object]';
8
+ }
9
+
10
+ function asNonEmptyString(value, fallback = '') {
11
+ if (typeof value !== 'string') {
12
+ return fallback;
13
+ }
14
+ const trimmed = value.trim();
15
+ return trimmed.length > 0 ? trimmed : fallback;
16
+ }
17
+
18
+ function normalizeSqlDialect(dialect) {
19
+ const normalized = String(dialect || '').toLowerCase();
20
+ if (normalized === 'postgres' || normalized === 'postgresql') {
21
+ return 'pg';
22
+ }
23
+ return normalized;
24
+ }
25
+
26
+ function normalizeNoSqlDialect(dialect) {
27
+ const normalized = String(dialect || '').toLowerCase();
28
+ if (normalized === 'mongodb' || normalized === 'mongoose') {
29
+ return 'mongo';
30
+ }
31
+ return normalized;
32
+ }
33
+
34
+ function buildMongoUriFromConfig(mongoConfig) {
35
+ const connectionString = asNonEmptyString(mongoConfig.connectionString, asNonEmptyString(mongoConfig.uri));
36
+ if (connectionString) {
37
+ return connectionString;
38
+ }
39
+
40
+ const host = asNonEmptyString(mongoConfig.server, asNonEmptyString(mongoConfig.host, 'localhost'));
41
+ const rawPort = mongoConfig.port;
42
+ const hasPort = rawPort !== undefined && rawPort !== null && String(rawPort).trim().length > 0;
43
+ const port = hasPort ? `:${String(rawPort).trim()}` : '';
44
+ const databaseName = asNonEmptyString(mongoConfig.database, asNonEmptyString(mongoConfig.dbName, 'appdb'));
45
+ const username = asNonEmptyString(mongoConfig.user, asNonEmptyString(mongoConfig.username));
46
+ const password = asNonEmptyString(mongoConfig.password);
47
+ const credentials = username
48
+ ? `${encodeURIComponent(username)}${password ? `:${encodeURIComponent(password)}` : ''}@`
49
+ : '';
50
+
51
+ return `mongodb://${credentials}${host}${port}/${encodeURIComponent(databaseName)}`;
52
+ }
53
+
54
+ function resolveMongoOptions(databaseConfig, mongoConfig) {
55
+ if (isPlainObject(databaseConfig?.options)) {
56
+ return databaseConfig.options;
57
+ }
58
+
59
+ if (isPlainObject(mongoConfig?.options)) {
60
+ return mongoConfig.options;
61
+ }
62
+
63
+ if (isPlainObject(mongoConfig?.clientOptions)) {
64
+ return mongoConfig.clientOptions;
65
+ }
66
+
67
+ return {};
68
+ }
69
+
70
+ function redactConnectionUri(uri) {
71
+ try {
72
+ const parsed = new URL(uri);
73
+ if (parsed.username || parsed.password) {
74
+ parsed.username = parsed.username ? '***' : '';
75
+ parsed.password = parsed.password ? '***' : '';
76
+ }
77
+ return parsed.toString();
78
+ } catch {
79
+ return String(uri || '');
80
+ }
81
+ }
82
+
83
+ function buildQueryMeshMongoConfig(databaseConfig) {
84
+ const mongoConfig = isPlainObject(databaseConfig?.config) ? { ...databaseConfig.config } : {};
85
+
86
+ const legacyUri = asNonEmptyString(databaseConfig?.uri);
87
+ if (legacyUri
88
+ && !asNonEmptyString(mongoConfig.connectionString)
89
+ && !asNonEmptyString(mongoConfig.uri)) {
90
+ mongoConfig.connectionString = legacyUri;
91
+ }
92
+
93
+ const hasDirectConnectionHandle = Boolean(
94
+ mongoConfig.db
95
+ || mongoConfig.connection
96
+ || mongoConfig.mongooseConnection
97
+ || mongoConfig.mongoose,
98
+ );
99
+
100
+ if (
101
+ !asNonEmptyString(mongoConfig.connectionString)
102
+ && !asNonEmptyString(mongoConfig.uri)
103
+ && !hasDirectConnectionHandle
104
+ ) {
105
+ mongoConfig.connectionString = buildMongoUriFromConfig(mongoConfig);
106
+ }
107
+
108
+ const options = resolveMongoOptions(databaseConfig, mongoConfig);
109
+ if (
110
+ isPlainObject(options)
111
+ && Object.keys(options).length > 0
112
+ && !isPlainObject(mongoConfig.options)
113
+ && !isPlainObject(mongoConfig.clientOptions)
114
+ ) {
115
+ mongoConfig.options = options;
116
+ }
117
+
118
+ return mongoConfig;
119
+ }
120
+
121
+ function extractMongoConnectionUri(mongoConfig) {
122
+ return asNonEmptyString(
123
+ mongoConfig?.connectionString,
124
+ asNonEmptyString(mongoConfig?.uri),
125
+ );
126
+ }
127
+
128
+ export async function initializeDatabase(databaseConfig, logger) {
129
+ if (!databaseConfig?.enabled) {
130
+ logger.info('Database disabled by configuration.');
131
+ return null;
132
+ }
133
+
134
+ const dialect = String(databaseConfig.dialect || '').toLowerCase();
135
+
136
+ if (SQL_DIALECTS.has(dialect)) {
137
+ const sqlDialect = normalizeSqlDialect(dialect);
138
+ const client = await QueryMesh.connect({
139
+ dialect: sqlDialect,
140
+ config: databaseConfig.config || {},
141
+ });
142
+
143
+ logger.info('SQL database connected with dialect %s', sqlDialect);
144
+
145
+ return {
146
+ type: 'sql',
147
+ dialect: sqlDialect,
148
+ client,
149
+ };
150
+ }
151
+
152
+ if (NOSQL_DIALECTS.has(dialect)) {
153
+ const noSqlDialect = normalizeNoSqlDialect(dialect);
154
+ const mongoConfig = buildQueryMeshMongoConfig(databaseConfig);
155
+ const client = await QueryMesh.connect({
156
+ dialect: noSqlDialect,
157
+ config: mongoConfig,
158
+ });
159
+
160
+ const uri = extractMongoConnectionUri(mongoConfig);
161
+ if (uri) {
162
+ logger.info(
163
+ 'NoSQL database connected with dialect %s via QueryMesh at %s',
164
+ dialect,
165
+ redactConnectionUri(uri),
166
+ );
167
+ } else {
168
+ logger.info('NoSQL database connected with dialect %s via QueryMesh', dialect);
169
+ }
170
+
171
+ return {
172
+ type: 'nosql',
173
+ dialect: noSqlDialect === 'mongo' ? 'mongodb' : noSqlDialect,
174
+ client,
175
+ };
176
+ }
177
+
178
+ throw new Error(`Unsupported database dialect: ${dialect}`);
179
+ }
180
+
181
+ export async function closeDatabase(db) {
182
+ if (!db) {
183
+ return;
184
+ }
185
+
186
+ if (db.client && typeof db.client.close === 'function') {
187
+ await db.client.close();
188
+ return;
189
+ }
190
+
191
+ // Legacy fallback for older runtime return shapes.
192
+ if (db.type === 'nosql' && db.mongoose?.connection?.close) {
193
+ await db.mongoose.connection.close();
194
+ }
195
+ }
@@ -0,0 +1,33 @@
1
+ import { EventEmitter } from 'events';
2
+
3
+ export class EventBus {
4
+ constructor() {
5
+ this.emitter = new EventEmitter();
6
+ }
7
+
8
+ subscribe(eventName, listener) {
9
+ this.emitter.on(eventName, listener);
10
+ return () => this.emitter.off(eventName, listener);
11
+ }
12
+
13
+ once(eventName, listener) {
14
+ this.emitter.once(eventName, listener);
15
+ return () => this.emitter.off(eventName, listener);
16
+ }
17
+
18
+ publish(eventName, payload) {
19
+ this.emitter.emit(eventName, payload);
20
+ }
21
+
22
+ removeAll(eventName) {
23
+ if (eventName) {
24
+ this.emitter.removeAllListeners(eventName);
25
+ return;
26
+ }
27
+ this.emitter.removeAllListeners();
28
+ }
29
+ }
30
+
31
+ export function createEventBus() {
32
+ return new EventBus();
33
+ }