@xylabs/mongo 5.0.33 → 5.0.35

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xylabs/mongo",
3
- "version": "5.0.33",
3
+ "version": "5.0.35",
4
4
  "description": "Base functionality used throughout XYO TypeScript/JavaScript libraries that access Mongo DB",
5
5
  "keywords": [
6
6
  "mongo",
@@ -45,10 +45,13 @@
45
45
  "types": "./dist/node/index.d.ts",
46
46
  "files": [
47
47
  "dist",
48
- "src"
48
+ "src",
49
+ "!**/*.bench.*",
50
+ "!**/*.spec.*",
51
+ "!**/*.test.*"
49
52
  ],
50
53
  "dependencies": {
51
- "@xylabs/assert": "~5.0.33"
54
+ "@xylabs/assert": "~5.0.35"
52
55
  },
53
56
  "devDependencies": {
54
57
  "@xylabs/ts-scripts-yarn3": "~7.2.8",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=Base.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Base.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/Base.spec.ts"],"names":[],"mappings":""}
@@ -1,14 +0,0 @@
1
- /**
2
- * Starts a heap profiler session.
3
- * @param type 'sampling' or 'snapshot'
4
- * @param outPath Output directory (default: './heap-profiles')
5
- */
6
- export declare function startHeapProfile(type?: 'sampling' | 'snapshot', outPath?: string): Promise<void>;
7
- /**
8
- * Stops the heap profiler and writes the output to file.
9
- * @param fileName Optional output filename
10
- * @param outPath Output directory (default: './heap-profiles')
11
- * @returns Full path to the heap profile file
12
- */
13
- export declare function stopHeapProfile(fileName?: string, outPath?: string): Promise<string>;
14
- //# sourceMappingURL=Wrapper.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Wrapper.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/Wrapper.spec.ts"],"names":[],"mappings":"AAqBA;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,GAAE,UAAU,GAAG,UAAuB,EAC1C,OAAO,GAAE,MAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,GAAE,MAA0B,GAClC,OAAO,CAAC,MAAM,CAAC,CAmBjB"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=Base.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Base.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/Base.spec.ts"],"names":[],"mappings":""}
@@ -1,14 +0,0 @@
1
- /**
2
- * Starts a heap profiler session.
3
- * @param type 'sampling' or 'snapshot'
4
- * @param outPath Output directory (default: './heap-profiles')
5
- */
6
- export declare function startHeapProfile(type?: 'sampling' | 'snapshot', outPath?: string): Promise<void>;
7
- /**
8
- * Stops the heap profiler and writes the output to file.
9
- * @param fileName Optional output filename
10
- * @param outPath Output directory (default: './heap-profiles')
11
- * @returns Full path to the heap profile file
12
- */
13
- export declare function stopHeapProfile(fileName?: string, outPath?: string): Promise<string>;
14
- //# sourceMappingURL=Wrapper.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Wrapper.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/Wrapper.spec.ts"],"names":[],"mappings":"AAqBA;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,GAAE,UAAU,GAAG,UAAuB,EAC1C,OAAO,GAAE,MAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,GAAE,MAA0B,GAClC,OAAO,CAAC,MAAM,CAAC,CAmBjB"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=Base.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Base.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/Base.spec.ts"],"names":[],"mappings":""}
@@ -1,14 +0,0 @@
1
- /**
2
- * Starts a heap profiler session.
3
- * @param type 'sampling' or 'snapshot'
4
- * @param outPath Output directory (default: './heap-profiles')
5
- */
6
- export declare function startHeapProfile(type?: 'sampling' | 'snapshot', outPath?: string): Promise<void>;
7
- /**
8
- * Stops the heap profiler and writes the output to file.
9
- * @param fileName Optional output filename
10
- * @param outPath Output directory (default: './heap-profiles')
11
- * @returns Full path to the heap profile file
12
- */
13
- export declare function stopHeapProfile(fileName?: string, outPath?: string): Promise<string>;
14
- //# sourceMappingURL=Wrapper.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Wrapper.spec.d.ts","sourceRoot":"","sources":["../../../src/spec/Wrapper.spec.ts"],"names":[],"mappings":"AAqBA;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,IAAI,GAAE,UAAU,GAAG,UAAuB,EAC1C,OAAO,GAAE,MAA0B,GAClC,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,QAAQ,CAAC,EAAE,MAAM,EACjB,OAAO,GAAE,MAA0B,GAClC,OAAO,CAAC,MAAM,CAAC,CAmBjB"}
@@ -1,20 +0,0 @@
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
- })
@@ -1,134 +0,0 @@
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
- })