monastery 3.5.9 → 3.5.11

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 CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [3.5.11](https://github.com/boycce/monastery/compare/3.5.10...3.5.11) (2026-02-02)
6
+
7
+ ### [3.5.10](https://github.com/boycce/monastery/compare/3.5.9...3.5.10) (2026-02-02)
8
+
5
9
  ### [3.5.9](https://github.com/boycce/monastery/compare/3.5.8...3.5.9) (2025-12-23)
6
10
 
7
11
  ### [3.5.8](https://github.com/boycce/monastery/compare/3.5.6...3.5.8) (2025-12-23)
package/lib/manager.js CHANGED
@@ -37,10 +37,10 @@ function Manager(uri, opts, parent) {
37
37
  if (typeof opts.logLevel == 'undefined') opts.logLevel = 2
38
38
 
39
39
  // opts: separate out monastery options
40
- const mongoOpts = Object.keys(opts||{}).reduce((acc, key) => {
40
+ const mongoOpts = Object.keys(opts || {}).reduce((acc, key) => {
41
41
  if (![
42
42
  'databaseName', 'defaultObjects', 'logLevel', 'imagePlugin', 'limit', 'noDefaults', 'nullObjects',
43
- 'promise', 'timestamps', 'useMilliseconds',
43
+ 'promise', 'timestamps', 'useMilliseconds', 'forJest', 'showConnectionInfo',
44
44
  ].includes(key)) {
45
45
  acc[key] = opts[key]
46
46
  }
@@ -57,6 +57,8 @@ function Manager(uri, opts, parent) {
57
57
  that.collections = {}
58
58
  that._openQueue = []
59
59
  that.emitter = new EventEmitter()
60
+ that.forJest = opts.forJest || false
61
+ that.showConnectionInfo = opts.showConnectionInfo || false
60
62
 
61
63
  // If there is no DEBUG= environment variable, we will need to force the debugs on (due to bug on debug@4.3.4)
62
64
  if (!debug.namespaces) {
@@ -283,9 +285,11 @@ Manager.prototype.open = async function() {
283
285
  * @return {Promise(manager)}
284
286
  */
285
287
  try {
288
+ this.openTimestamp = Date.now()
286
289
  this._state = 'opening'
287
290
  this.db = this.client.db()
288
291
  await this.client.connect() // now optional since db().command() will auto-connect
292
+ if (this.showConnectionInfo) console.info(`Connected to MongoDB in ${Date.now() - this.openTimestamp}ms`)
289
293
  this.emitter.emit(this._state = 'open', this)
290
294
  return this
291
295
 
package/lib/model.js CHANGED
@@ -346,7 +346,25 @@ Model.prototype._setupIndexes = async function(fields, opts={}) {
346
346
  const collection = this.collection
347
347
 
348
348
  // Get the collections indexes
349
- const existingIndexes = await collection.indexes() // returns [] if collection doesn't exist
349
+ let existingIndexes = []
350
+ try {
351
+ existingIndexes = await collection.indexes() // returns [] if collection doesn't exist
352
+ } catch (err) {
353
+ // Show a succinct error message for timeout errors, which is due to onOpen() timing out.
354
+ if (err.message.match(/Server selection timed out after/)) {
355
+ const msg = `Unable to create an index on the '${model.name||''}' model, the server selection has timed out already.`
356
+ if (model.manager.forJest) throw new Error(msg)
357
+ else this.error(msg)
358
+ return []
359
+ } else if (err.message.match(/Topology is closed/)) {
360
+ const msg = `Unable to create an index on the '${model.name||''}' model, the 'Topology is closed'. Bad connection URL?`
361
+ if (model.manager.forJest) throw new Error(msg)
362
+ else this.error(msg)
363
+ return []
364
+ } else {
365
+ throw err
366
+ }
367
+ }
350
368
 
351
369
  // Remove any existing text index that has different options as createIndexes will throws error about this
352
370
  if (existingIndexes.length) {
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "monastery",
3
3
  "description": "⛪ A simple, straightforward MongoDB ODM",
4
4
  "author": "Ricky Boyce",
5
- "version": "3.5.9",
5
+ "version": "3.5.11",
6
6
  "license": "MIT",
7
7
  "repository": "github:boycce/monastery",
8
8
  "homepage": "https://boycce.github.io/monastery/",
package/test/manager.js CHANGED
@@ -59,6 +59,17 @@ test('manager > onOpen error', async () => {
59
59
  db.close()
60
60
  })
61
61
 
62
+ test('manager > onOpen timeout error', async () => {
63
+ // Bad connection url, which will hang and timeout after 100ms
64
+ // Related: test/model.js > model index timeout topology closed
65
+ let manager
66
+ const db = monastery.manager('google.com', { serverSelectionTimeoutMS:100, logLevel: 3 }) // should hang
67
+ await expect(db.onOpen((res) => { manager = res })).rejects.toThrow('Server selection timed out after 100 ms')
68
+ expect(manager).toEqual(undefined)
69
+ expect(db).toEqual(expect.any(Object))
70
+ db.close()
71
+ })
72
+
62
73
  test('manager > return a promise', async () => {
63
74
  const db = await monastery.manager('localhost/monastery', { serverSelectionTimeoutMS: 500, promise: true })
64
75
  expect(db).toEqual(expect.any(Object))
package/test/model.js CHANGED
@@ -495,6 +495,27 @@ test('model indexes basic', async () => {
495
495
  }])
496
496
  })
497
497
 
498
+ test('model index timeout topology closed', async () => {
499
+ // 1. For a invalid URL, while a connection is still opening, we should expect a
500
+ // 'topology is closed' error when trying to create an index.
501
+ // 2. For valid connection URL, we should expect a 'server selection timed out' error (which we can't reproduce in tests)
502
+ const db2 = monastery.manager('google.com', { logLevel: 3, serverSelectionTimeoutMS: 50, forJest: true })
503
+ // Attempt to use the collection while the connection is still opening.
504
+ const userIndexErrModel = db2.model('userIndexErr', {
505
+ fields: {
506
+ age: { type: 'number' },
507
+ name: { type: 'string' },
508
+ },
509
+ })
510
+ expect(
511
+ userIndexErrModel._setupIndexes({ age: { type: 'number', index: 'text' }, name: { type: 'string', index: 'text' } })
512
+ ).rejects.toThrow('Unable to create an index on the \'userIndexErr\' model, the \'Topology is closed\'. Bad connection URL?')
513
+ await expect(
514
+ db2.onOpen((res) => { })
515
+ ).rejects.toThrow('Server selection timed out after 50 ms')
516
+ db2.close()
517
+ })
518
+
498
519
  test('model indexes unique', async () => {
499
520
  // Setup: Drop previously tested collections
500
521
  if ((await db.db.listCollections().toArray()).find(o => o.name == 'userUniqueIndex')) {