@xylabs/mongo 4.13.19 → 4.13.21

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/README.md CHANGED
@@ -12,13 +12,518 @@
12
12
  [![snyk-badge][]][snyk-link]
13
13
  [![socket-badge][]][socket-link]
14
14
 
15
- Version: 4.13.15
16
15
 
17
16
  Base functionality used throughout XYO TypeScript/JavaScript libraries that access Mongo DB
18
17
 
19
- ## Documentation
18
+ ## API Documentation
19
+
20
+ **@xylabs/mongo**
21
+
22
+ ***
23
+
24
+ ## Classes
25
+
26
+ - [BaseMongoSdk](#classes/BaseMongoSdk)
27
+ - [MongoClientWrapper](#classes/MongoClientWrapper)
28
+
29
+ ## Interfaces
30
+
31
+ - [BaseMongoSdkPublicConfig](#interfaces/BaseMongoSdkPublicConfig)
32
+ - [BaseMongoSdkPrivateConfig](#interfaces/BaseMongoSdkPrivateConfig)
33
+
34
+ ## Type Aliases
35
+
36
+ - [BaseMongoSdkConfig](#type-aliases/BaseMongoSdkConfig)
37
+
38
+ ### classes
39
+
40
+ ### <a id="BaseMongoSdk"></a>BaseMongoSdk
41
+
42
+ [**@xylabs/mongo**](#../README)
43
+
44
+ ***
45
+
46
+ ## Type Parameters
47
+
48
+ ### T
49
+
50
+ `T` *extends* `Document`
51
+
52
+ ## Constructors
53
+
54
+ ### Constructor
55
+
56
+ ```ts
57
+ new BaseMongoSdk<T>(config): BaseMongoSdk<T>;
58
+ ```
59
+
60
+ ### Parameters
61
+
62
+ #### config
63
+
64
+ [`BaseMongoSdkConfig`](#../type-aliases/BaseMongoSdkConfig)
65
+
66
+ ### Returns
67
+
68
+ `BaseMongoSdk`\<`T`\>
69
+
70
+ ## Properties
71
+
72
+ ### config
73
+
74
+ ```ts
75
+ config: BaseMongoSdkConfig;
76
+ ```
77
+
78
+ ## Accessors
79
+
80
+ ### uri
81
+
82
+ ### Get Signature
83
+
84
+ ```ts
85
+ get uri(): string;
86
+ ```
87
+
88
+ #### Returns
89
+
90
+ `string`
91
+
92
+ ## Methods
93
+
94
+ ### deleteMany()
95
+
96
+ ```ts
97
+ deleteMany(filter): Promise<DeleteResult>;
98
+ ```
99
+
100
+ ### Parameters
101
+
102
+ #### filter
103
+
104
+ `Filter`\<`T`\>
105
+
106
+ ### Returns
107
+
108
+ `Promise`\<`DeleteResult`\>
109
+
110
+ ***
111
+
112
+ ### deleteOne()
113
+
114
+ ```ts
115
+ deleteOne(filter): Promise<DeleteResult>;
116
+ ```
117
+
118
+ ### Parameters
119
+
120
+ #### filter
121
+
122
+ `Filter`\<`T`\>
123
+
124
+ ### Returns
125
+
126
+ `Promise`\<`DeleteResult`\>
127
+
128
+ ***
129
+
130
+ ### find()
131
+
132
+ ```ts
133
+ find(filter): Promise<FindCursor<WithId<T>>>;
134
+ ```
135
+
136
+ ### Parameters
137
+
138
+ #### filter
139
+
140
+ `Filter`\<`T`\>
141
+
142
+ ### Returns
143
+
144
+ `Promise`\<`FindCursor`\<`WithId`\<`T`\>\>\>
145
+
146
+ ***
147
+
148
+ ### findOne()
149
+
150
+ ```ts
151
+ findOne(filter): Promise<null | WithId<T>>;
152
+ ```
153
+
154
+ ### Parameters
155
+
156
+ #### filter
157
+
158
+ `Filter`\<`T`\>
159
+
160
+ ### Returns
161
+
162
+ `Promise`\<`null` \| `WithId`\<`T`\>\>
163
+
164
+ ***
165
+
166
+ ### insertMany()
167
+
168
+ ```ts
169
+ insertMany(items, options?): Promise<InsertManyResult<T>>;
170
+ ```
171
+
172
+ ### Parameters
173
+
174
+ #### items
175
+
176
+ `OptionalUnlessRequiredId`\<`T`\>[]
177
+
178
+ #### options?
179
+
180
+ `BulkWriteOptions`
181
+
182
+ ### Returns
183
+
184
+ `Promise`\<`InsertManyResult`\<`T`\>\>
185
+
186
+ ***
187
+
188
+ ### insertOne()
189
+
190
+ ```ts
191
+ insertOne(item, options?): Promise<InsertOneResult<T>>;
192
+ ```
193
+
194
+ ### Parameters
195
+
196
+ #### item
197
+
198
+ `OptionalUnlessRequiredId`\<`T`\>
199
+
200
+ #### options?
201
+
202
+ `InsertOneOptions`
203
+
204
+ ### Returns
205
+
206
+ `Promise`\<`InsertOneResult`\<`T`\>\>
207
+
208
+ ***
209
+
210
+ ### replaceOne()
211
+
212
+ ```ts
213
+ replaceOne(
214
+ filter,
215
+ item,
216
+ options?): Promise<UpdateResult<T>>;
217
+ ```
218
+
219
+ ### Parameters
220
+
221
+ #### filter
222
+
223
+ `Filter`\<`T`\>
224
+
225
+ #### item
226
+
227
+ `OptionalUnlessRequiredId`\<`T`\>
228
+
229
+ #### options?
230
+
231
+ `ReplaceOptions`
232
+
233
+ ### Returns
234
+
235
+ `Promise`\<`UpdateResult`\<`T`\>\>
236
+
237
+ ***
238
+
239
+ ### updateOne()
240
+
241
+ ```ts
242
+ updateOne(filter, fields): Promise<UpdateResult<T>>;
243
+ ```
244
+
245
+ ### Parameters
246
+
247
+ #### filter
248
+
249
+ `Filter`\<`T`\>
250
+
251
+ #### fields
252
+
253
+ `UpdateFilter`\<`T`\>
254
+
255
+ ### Returns
256
+
257
+ `Promise`\<`UpdateResult`\<`T`\>\>
258
+
259
+ ***
260
+
261
+ ### upsertOne()
262
+
263
+ ```ts
264
+ upsertOne(filter, fields): Promise<UpdateResult<T>>;
265
+ ```
266
+
267
+ ### Parameters
268
+
269
+ #### filter
270
+
271
+ `Filter`\<`T`\>
272
+
273
+ #### fields
274
+
275
+ `UpdateFilter`\<`T`\>
276
+
277
+ ### Returns
278
+
279
+ `Promise`\<`UpdateResult`\<`T`\>\>
280
+
281
+ ***
282
+
283
+ ### useCollection()
284
+
285
+ ```ts
286
+ useCollection<R>(func): Promise<R>;
287
+ ```
288
+
289
+ ### Type Parameters
290
+
291
+ #### R
292
+
293
+ `R`
294
+
295
+ ### Parameters
296
+
297
+ #### func
298
+
299
+ (`collection`) => `R` \| `Promise`\<`R`\>
300
+
301
+ ### Returns
302
+
303
+ `Promise`\<`R`\>
304
+
305
+ ***
306
+
307
+ ### useMongo()
308
+
309
+ ```ts
310
+ useMongo<R>(func): Promise<R>;
311
+ ```
312
+
313
+ ### Type Parameters
314
+
315
+ #### R
316
+
317
+ `R`
318
+
319
+ ### Parameters
320
+
321
+ #### func
322
+
323
+ (`client`) => `R` \| `Promise`\<`R`\>
324
+
325
+ ### Returns
326
+
327
+ `Promise`\<`R`\>
328
+
329
+ ### <a id="MongoClientWrapper"></a>MongoClientWrapper
330
+
331
+ [**@xylabs/mongo**](#../README)
332
+
333
+ ***
334
+
335
+ ## Constructors
336
+
337
+ ### Constructor
338
+
339
+ ```ts
340
+ new MongoClientWrapper(
341
+ uri,
342
+ maxPoolSize?,
343
+ closeDelay?): MongoClientWrapper;
344
+ ```
345
+
346
+ ### Parameters
347
+
348
+ #### uri
349
+
350
+ `string`
351
+
352
+ #### maxPoolSize?
353
+
354
+ `number`
355
+
356
+ #### closeDelay?
357
+
358
+ `number`
359
+
360
+ ### Returns
361
+
362
+ `MongoClientWrapper`
363
+
364
+ ## Properties
365
+
366
+ ### clients
367
+
368
+ ```ts
369
+ readonly static clients: Map<string, MongoClientWrapper>;
370
+ ```
371
+
372
+ ## Methods
373
+
374
+ ### get()
375
+
376
+ ```ts
377
+ static get(
378
+ uri,
379
+ poolSize?,
380
+ closeDelay?): MongoClientWrapper;
381
+ ```
382
+
383
+ ### Parameters
384
+
385
+ #### uri
386
+
387
+ `string`
388
+
389
+ #### poolSize?
390
+
391
+ `number`
392
+
393
+ #### closeDelay?
394
+
395
+ `number`
396
+
397
+ ### Returns
398
+
399
+ `MongoClientWrapper`
400
+
401
+ ***
402
+
403
+ ### connect()
404
+
405
+ ```ts
406
+ connect(): Promise<MongoClient>;
407
+ ```
408
+
409
+ ### Returns
410
+
411
+ `Promise`\<`MongoClient`\>
412
+
413
+ ***
414
+
415
+ ### disconnect()
416
+
417
+ ```ts
418
+ disconnect(): Promise<number>;
419
+ ```
420
+
421
+ ### Returns
422
+
423
+ `Promise`\<`number`\>
424
+
425
+ ***
426
+
427
+ ### initiateClose()
428
+
429
+ ```ts
430
+ initiateClose(): Promise<void>;
431
+ ```
432
+
433
+ ### Returns
434
+
435
+ `Promise`\<`void`\>
436
+
437
+ ### interfaces
438
+
439
+ ### <a id="BaseMongoSdkPrivateConfig"></a>BaseMongoSdkPrivateConfig
440
+
441
+ [**@xylabs/mongo**](#../README)
442
+
443
+ ***
444
+
445
+ ## Properties
446
+
447
+ ### dbConnectionString?
448
+
449
+ ```ts
450
+ optional dbConnectionString: string;
451
+ ```
452
+
453
+ ***
454
+
455
+ ### dbDomain?
456
+
457
+ ```ts
458
+ optional dbDomain: string;
459
+ ```
460
+
461
+ ***
462
+
463
+ ### dbName?
464
+
465
+ ```ts
466
+ optional dbName: string;
467
+ ```
468
+
469
+ ***
470
+
471
+ ### dbPassword?
472
+
473
+ ```ts
474
+ optional dbPassword: string;
475
+ ```
476
+
477
+ ***
478
+
479
+ ### dbUserName?
480
+
481
+ ```ts
482
+ optional dbUserName: string;
483
+ ```
484
+
485
+ ### <a id="BaseMongoSdkPublicConfig"></a>BaseMongoSdkPublicConfig
486
+
487
+ [**@xylabs/mongo**](#../README)
488
+
489
+ ***
490
+
491
+ ## Properties
492
+
493
+ ### closeDelay?
494
+
495
+ ```ts
496
+ optional closeDelay: number;
497
+ ```
498
+
499
+ ***
500
+
501
+ ### collection
502
+
503
+ ```ts
504
+ collection: string;
505
+ ```
506
+
507
+ ***
508
+
509
+ ### maxPoolSize?
510
+
511
+ ```ts
512
+ optional maxPoolSize: number;
513
+ ```
514
+
515
+ ### type-aliases
516
+
517
+ ### <a id="BaseMongoSdkConfig"></a>BaseMongoSdkConfig
518
+
519
+ [**@xylabs/mongo**](#../README)
520
+
521
+ ***
522
+
523
+ ```ts
524
+ type BaseMongoSdkConfig = BaseMongoSdkPublicConfig & BaseMongoSdkPrivateConfig;
525
+ ```
20
526
 
21
- Coming Soon!
22
527
 
23
528
  Part of [sdk-js](https://www.npmjs.com/package/@xyo-network/sdk-js)
24
529
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xylabs/mongo",
3
- "version": "4.13.19",
3
+ "version": "4.13.21",
4
4
  "description": "Base functionality used throughout XYO TypeScript/JavaScript libraries that access Mongo DB",
5
5
  "keywords": [
6
6
  "mongo",
@@ -26,26 +26,34 @@
26
26
  ".": {
27
27
  "browser": {
28
28
  "types": "./dist/browser/index.d.ts",
29
+ "source": "./src/index.ts",
29
30
  "default": "./dist/browser/index.mjs"
30
31
  },
31
32
  "node": {
32
33
  "types": "./dist/node/index.d.ts",
34
+ "source": "./src/index.ts",
33
35
  "default": "./dist/node/index.mjs"
34
36
  },
35
37
  "types": "./dist/node/index.d.ts",
38
+ "source": "./src/index.ts",
36
39
  "default": "./dist/node/index.mjs"
37
40
  },
38
41
  "./package.json": "./package.json"
39
42
  },
40
- "module": "dist/node/index.mjs",
41
- "types": "dist/node/index.d.ts",
43
+ "module": "./dist/node/index.mjs",
44
+ "source": "./src/index.ts",
45
+ "types": "./dist/node/index.d.ts",
46
+ "files": [
47
+ "dist",
48
+ "src"
49
+ ],
42
50
  "dependencies": {
43
- "@xylabs/assert": "^4.13.19",
51
+ "@xylabs/assert": "^4.13.21",
44
52
  "mongodb": "~6.17.0"
45
53
  },
46
54
  "devDependencies": {
47
- "@xylabs/ts-scripts-yarn3": "^7.0.0-rc.27",
48
- "@xylabs/tsconfig": "^7.0.0-rc.27",
55
+ "@xylabs/ts-scripts-yarn3": "^7.0.0",
56
+ "@xylabs/tsconfig": "^7.0.0",
49
57
  "typescript": "^5.8.3",
50
58
  "vitest": "^3.2.4"
51
59
  },
@@ -0,0 +1,20 @@
1
+ import {
2
+ describe, expect, test,
3
+ } from 'vitest'
4
+
5
+ import { BaseMongoSdk } from '../Base.js'
6
+ import type { BaseMongoSdkConfig } from '../Config.js'
7
+
8
+ describe('Base', () => {
9
+ test('checking happy path', () => {
10
+ const config: BaseMongoSdkConfig = {
11
+ collection: 'test',
12
+ dbDomain: 'test.test.com',
13
+ dbName: 'default',
14
+ dbPassword: 'password',
15
+ dbUserName: 'username',
16
+ }
17
+ const apiStage = new BaseMongoSdk(config)
18
+ expect(apiStage).toBeDefined()
19
+ })
20
+ })
@@ -0,0 +1,134 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ // mongoClientWrapper.memory.test.ts
3
+ import { mkdirSync, writeFileSync } from 'node:fs'
4
+ import inspector from 'node:inspector'
5
+ import path from 'node:path'
6
+
7
+ import {
8
+ afterEach, beforeEach, describe, expect, it,
9
+ } from 'vitest'
10
+
11
+ import { MongoClientWrapper } from '../Wrapper.ts'
12
+
13
+ // function randomIntBetween(min: number, max: number): number {
14
+ // const low = Math.ceil(min)
15
+ // const high = Math.floor(max)
16
+ // return Math.floor(Math.random() * (high - low + 1)) + low
17
+ // }
18
+ let session: inspector.Session | null = null
19
+ let profileType: 'sampling' | 'snapshot' = 'sampling'
20
+ let chunks: string[] = []
21
+
22
+ /**
23
+ * Starts a heap profiler session.
24
+ * @param type 'sampling' or 'snapshot'
25
+ * @param outPath Output directory (default: './heap-profiles')
26
+ */
27
+ export async function startHeapProfile(
28
+ type: 'sampling' | 'snapshot' = 'sampling',
29
+ outPath: string = './heap-profiles',
30
+ ): Promise<void> {
31
+ profileType = type
32
+ session = new inspector.Session()
33
+ session.connect()
34
+ mkdirSync(outPath, { recursive: true })
35
+
36
+ await post('HeapProfiler.enable')
37
+
38
+ if (type === 'sampling') {
39
+ await post('HeapProfiler.startSampling')
40
+ } else if (type === 'snapshot') {
41
+ chunks = []
42
+ session.on('HeapProfiler.addHeapSnapshotChunk', msg => chunks.push(msg.params.chunk))
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Stops the heap profiler and writes the output to file.
48
+ * @param fileName Optional output filename
49
+ * @param outPath Output directory (default: './heap-profiles')
50
+ * @returns Full path to the heap profile file
51
+ */
52
+ export async function stopHeapProfile(
53
+ fileName?: string,
54
+ outPath: string = './heap-profiles',
55
+ ): Promise<string> {
56
+ if (!session) throw new Error('No active profiling session. Call startHeapProfile() first.')
57
+
58
+ const timestamp = Date.now()
59
+ const outFile = path.join(outPath, fileName ?? `heap-${profileType}-${timestamp}.heapprofile`)
60
+
61
+ if (profileType === 'sampling') {
62
+ const result = await post<{ profile: any }>('HeapProfiler.stopSampling')
63
+ writeFileSync(outFile, JSON.stringify(result.profile))
64
+ } else {
65
+ await post('HeapProfiler.takeHeapSnapshot')
66
+ writeFileSync(outFile, chunks.join(''))
67
+ }
68
+
69
+ await post('HeapProfiler.disable')
70
+ session.disconnect()
71
+ session = null
72
+
73
+ return outFile
74
+ }
75
+
76
+ function post<T = void>(method: string, params: object = {}): Promise<T> {
77
+ return new Promise((resolve, reject) => {
78
+ session!.post(method, params, (err, result) => {
79
+ if (err) reject(err)
80
+ else resolve(result as T)
81
+ })
82
+ })
83
+ }
84
+
85
+ describe.skip('MongoClientWrapper memory profiling', () => {
86
+ const TEST_MONGO_URI = process.env.MONGO_CONNECTION_STRING
87
+ beforeEach(() => {
88
+ // Reset static map before each test run
89
+ ;(MongoClientWrapper as any).clients.clear()
90
+ })
91
+
92
+ afterEach(async () => {
93
+ // Disconnect all clients after each test
94
+ for (const client of (MongoClientWrapper as any).clients.values()) {
95
+ await client.disconnect()
96
+ }
97
+ ;(MongoClientWrapper as any).clients.clear()
98
+ globalThis.gc?.() // Only works if Node is run with --expose-gc
99
+ })
100
+
101
+ it('should not leak MongoClientWrapper instances after many connect/disconnect cycles', async () => {
102
+ expect(TEST_MONGO_URI).toBeDefined()
103
+ const uri = `${TEST_MONGO_URI}`
104
+ const cycleCount = 200_000
105
+ await startHeapProfile('sampling')
106
+ await Promise.all(
107
+ Array.from({ length: cycleCount }).map(async () => {
108
+ // await new Promise(r => setTimeout(r, randomIntBetween(1000, 3000)))
109
+ const wrapper = MongoClientWrapper.get(uri, 100, 1)
110
+ const client = await wrapper.connect()
111
+ expect(client).toBeDefined()
112
+ await wrapper.disconnect()
113
+ }),
114
+ )
115
+
116
+ // Trigger GC if available
117
+ globalThis.gc?.()
118
+
119
+ // Wait to allow async cleanup to complete
120
+ await new Promise(r => setTimeout(r, 20_000))
121
+
122
+ const filePath = await stopHeapProfile()
123
+ console.log('Heap profile written to:', filePath)
124
+
125
+ // Check how many entries remain
126
+ const clientMap = (MongoClientWrapper as any).clients as Map<string, any>
127
+ const remaining = [...clientMap.keys()]
128
+
129
+ console.log('Remaining keys in clients map:', remaining)
130
+
131
+ // Assert map doesn't grow without bound
132
+ expect(remaining.length).toBeLessThanOrEqual(5) // Allow a few survivors from timing edge cases
133
+ }, 240_000)
134
+ })
package/typedoc.json DELETED
@@ -1,5 +0,0 @@
1
- {
2
- "$schema": "https://typedoc.org/schema.json",
3
- "entryPoints": ["src/index.ts"],
4
- "tsconfig": "./tsconfig.typedoc.json"
5
- }