@pioneer-platform/default-mongo-v2 1.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @pioneer-platform/default-mongo-v2
2
+
3
+ ## 1.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Automated patch version bump for all packages
package/package.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "@pioneer-platform/default-mongo-v2",
3
+ "version": "1.0.1",
4
+ "description": "Bun & ts-node compatible MongoDB client wrapper (no monk)",
5
+ "main": "src/index.ts",
6
+ "dependencies": {
7
+ "mongodb": "^6.10.0",
8
+ "dotenv": "^16.0.0"
9
+ },
10
+ "devDependencies": {
11
+ "@types/node": "^20.0.0"
12
+ }
13
+ }
package/src/index.ts ADDED
@@ -0,0 +1,237 @@
1
+ /*
2
+ MongoDB Client V2 - Bun & ts-node Compatible
3
+
4
+ Modern MongoDB driver (v6) compatible with both Bun and Node.js runtimes.
5
+ Provides a simple interface similar to monk for backward compatibility.
6
+ No top-level await - lazy initialization on first use.
7
+ */
8
+
9
+ import { MongoClient, Db, Collection, Document, Filter, FindOptions, UpdateFilter } from 'mongodb';
10
+
11
+ const TAG = ' | mongo-v2 | ';
12
+
13
+ // MongoDB connection singleton
14
+ let client: MongoClient | null = null;
15
+ let defaultDb: Db | null = null;
16
+ let initializationPromise: Promise<void> | null = null;
17
+ let isInitialized = false;
18
+
19
+ // Get connection string from environment
20
+ const getConnectionString = (): string => {
21
+ let connectionString = process.env.MONGO_CONNECTION;
22
+
23
+ if (!connectionString) {
24
+ console.log(TAG, "Looking for mongo on: 127.0.0.1:27017/pioneer");
25
+ connectionString = "mongodb://127.0.0.1:27017/pioneer";
26
+ } else if (!connectionString.startsWith('mongodb://') && !connectionString.startsWith('mongodb+srv://')) {
27
+ // Convert old format to new format
28
+ if (connectionString.includes('@')) {
29
+ const [auth, hosts] = connectionString.split('@');
30
+ const [username, password] = auth.split(':');
31
+
32
+ if (hosts && hosts.includes('/')) {
33
+ const [hostList, dbAndParams] = hosts.split('/', 2);
34
+ const [dbName, ...params] = dbAndParams ? dbAndParams.split('?') : ['pioneer'];
35
+ const paramsStr = params.length ? `?${params.join('?')}` : '';
36
+
37
+ connectionString = `mongodb://${username}:${password}@${hostList}/${dbName}${paramsStr}`;
38
+ console.log(TAG, "Reformatted MongoDB connection string to new format");
39
+ }
40
+ } else {
41
+ // Simple format without auth
42
+ connectionString = `mongodb://${connectionString}`;
43
+ }
44
+ }
45
+
46
+ return connectionString;
47
+ };
48
+
49
+ // Initialize MongoDB connection (async, called lazily)
50
+ const connect = async (): Promise<MongoClient> => {
51
+ if (client) {
52
+ return client;
53
+ }
54
+
55
+ try {
56
+ const connectionString = getConnectionString();
57
+ client = new MongoClient(connectionString);
58
+
59
+ await client.connect();
60
+ console.log(TAG, "Connected to MongoDB successfully");
61
+
62
+ // Extract database name from connection string
63
+ const url = new URL(connectionString);
64
+ const dbName = url.pathname.slice(1).split('?')[0] || 'pioneer';
65
+ defaultDb = client.db(dbName);
66
+ isInitialized = true;
67
+
68
+ return client;
69
+ } catch (error) {
70
+ console.error(TAG, "Failed to connect to MongoDB:", error);
71
+ console.error(TAG, "Server will continue but database operations may fail");
72
+ throw error;
73
+ }
74
+ };
75
+
76
+ // Collection wrapper with monk-like interface
77
+ class CollectionWrapper<T extends Document = Document> {
78
+ private collection: Collection<T>;
79
+
80
+ constructor(collection: Collection<T>) {
81
+ this.collection = collection;
82
+ }
83
+
84
+ // Find documents (returns array like monk)
85
+ async find(query: Filter<T> = {}, options: FindOptions = {}): Promise<T[]> {
86
+ return await this.collection.find(query, options).toArray();
87
+ }
88
+
89
+ // Find one document
90
+ async findOne(query: Filter<T>): Promise<T | null> {
91
+ return await this.collection.findOne(query);
92
+ }
93
+
94
+ // Insert one document
95
+ async insert(doc: Partial<T>): Promise<T> {
96
+ const result = await this.collection.insertOne(doc as any);
97
+ return { ...doc, _id: result.insertedId } as T;
98
+ }
99
+
100
+ // Update documents
101
+ async update(query: Filter<T>, update: UpdateFilter<T> | Partial<T>, options: any = {}): Promise<any> {
102
+ const updateDoc = ('$set' in update || '$inc' in update || '$push' in update)
103
+ ? update as UpdateFilter<T>
104
+ : { $set: update };
105
+
106
+ if (options.multi) {
107
+ return await this.collection.updateMany(query, updateDoc);
108
+ } else {
109
+ return await this.collection.updateOne(query, updateDoc);
110
+ }
111
+ }
112
+
113
+ // Remove documents
114
+ async remove(query: Filter<T>): Promise<any> {
115
+ return await this.collection.deleteMany(query);
116
+ }
117
+
118
+ // Count documents
119
+ async count(query: Filter<T> = {}): Promise<number> {
120
+ return await this.collection.countDocuments(query);
121
+ }
122
+
123
+ // Create index
124
+ async createIndex(keys: any, options: any = {}): Promise<string> {
125
+ return await this.collection.createIndex(keys, options);
126
+ }
127
+
128
+ // Drop collection
129
+ async drop(): Promise<boolean> {
130
+ return await this.collection.drop();
131
+ }
132
+
133
+ // Access native collection for advanced operations
134
+ async native(): Promise<Collection<T>> {
135
+ return this.collection;
136
+ }
137
+ }
138
+
139
+ // Connection object with monk-like interface
140
+ class MongoConnection {
141
+ private client: MongoClient | null = null;
142
+ private defaultDb: Db | null = null;
143
+ private connections: Map<string, Db> = new Map();
144
+ private initPromise: Promise<void> | null = null;
145
+
146
+ // Initialize connection (idempotent)
147
+ async init(): Promise<void> {
148
+ if (this.initPromise) {
149
+ return this.initPromise;
150
+ }
151
+
152
+ this.initPromise = (async () => {
153
+ if (this.client) return; // Already initialized
154
+
155
+ this.client = await connect();
156
+ const connectionString = getConnectionString();
157
+ const url = new URL(connectionString);
158
+ const dbName = url.pathname.slice(1).split('?')[0] || 'pioneer';
159
+ this.defaultDb = this.client.db(dbName);
160
+ })();
161
+
162
+ return this.initPromise;
163
+ }
164
+
165
+ // Get collection from default database (monk-compatible - synchronous)
166
+ get<T extends Document = Document>(collectionName: string, dbName?: string): CollectionWrapper<T> {
167
+ // Trigger lazy initialization (non-blocking)
168
+ if (!isInitialized && !initializationPromise) {
169
+ initializationPromise = this.init().catch(err => {
170
+ console.error(TAG, "Lazy initialization failed:", err);
171
+ });
172
+ }
173
+
174
+ // Return wrapper immediately (will fail gracefully if not connected)
175
+ if (!defaultDb && !dbName) {
176
+ // Create a stub that will work once initialized
177
+ const self = this;
178
+ const stub = new Proxy({} as CollectionWrapper<T>, {
179
+ get(target, prop) {
180
+ if (!self.defaultDb && !dbName) {
181
+ console.warn(TAG, `MongoDB not yet initialized, operation '${String(prop)}' may fail`);
182
+ }
183
+ const db = dbName ? self.getDb(dbName) : self.defaultDb!;
184
+ const collection = db.collection<T>(collectionName);
185
+ const wrapper = new CollectionWrapper<T>(collection);
186
+ return (wrapper as any)[prop];
187
+ }
188
+ });
189
+ return stub;
190
+ }
191
+
192
+ const db = dbName ? this.getDb(dbName) : this.defaultDb!;
193
+ const collection = db.collection<T>(collectionName);
194
+ return new CollectionWrapper<T>(collection);
195
+ }
196
+
197
+ // Get database by name
198
+ getDb(dbName: string): Db {
199
+ if (!this.client) {
200
+ throw new Error("MongoDB client not initialized");
201
+ }
202
+
203
+ if (!this.connections.has(dbName)) {
204
+ this.connections.set(dbName, this.client.db(dbName));
205
+ }
206
+
207
+ return this.connections.get(dbName)!;
208
+ }
209
+
210
+ // Get collection from specific database (monk-like getFromDb)
211
+ getFromDb<T extends Document = Document>(collectionName: string, dbName: string): CollectionWrapper<T> {
212
+ return this.get<T>(collectionName, dbName);
213
+ }
214
+
215
+ // Close connection
216
+ async close(): Promise<void> {
217
+ if (this.client) {
218
+ await this.client.close();
219
+ this.client = null;
220
+ this.defaultDb = null;
221
+ this.connections.clear();
222
+ this.initPromise = null;
223
+ }
224
+ }
225
+
226
+ // Get native MongoDB client for advanced operations
227
+ get native(): MongoClient | null {
228
+ return this.client;
229
+ }
230
+ }
231
+
232
+ // Create and export connection instance (no top-level await)
233
+ const connection = new MongoConnection();
234
+
235
+ // ES module export (Bun handles both import and require automatically)
236
+ export default connection;
237
+ export { MongoConnection, CollectionWrapper };