@furystack/mongodb-store 11.0.3 → 11.0.5

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
@@ -1,51 +1,51 @@
1
- # @furystack/mongodb-store
2
-
3
- MongoDB physical store implementation for FuryStack.
4
-
5
- ## Installation
6
-
7
- ```bash
8
- npm install @furystack/mongodb-store
9
- # or
10
- yarn add @furystack/mongodb-store
11
- ```
12
-
13
- ## Initialization
14
-
15
- `defineMongoDbStore` mints a `StoreToken` backed by a MongoDB collection.
16
- The shared `MongoClientFactory` singleton pools `MongoClient` instances by
17
- URL and closes them when the owning injector is disposed.
18
-
19
- ```ts
20
- import { createInjector } from '@furystack/inject'
21
- import { defineMongoDbStore } from '@furystack/mongodb-store'
22
- import { defineDataSet } from '@furystack/repository'
23
-
24
- export class TestEntry {
25
- declare _id: string
26
- declare value: string
27
- }
28
-
29
- export const TestEntryStore = defineMongoDbStore<TestEntry, '_id'>({
30
- name: 'my-app/TestEntryStore',
31
- model: TestEntry,
32
- primaryKey: '_id',
33
- url: 'mongodb://localhost:27017',
34
- db: 'test',
35
- collection: 'TestEntries',
36
- })
37
-
38
- export const TestEntryDataSet = defineDataSet({
39
- name: 'my-app/TestEntryDataSet',
40
- store: TestEntryStore,
41
- })
42
-
43
- const myInjector = createInjector()
44
- const dataSet = myInjector.get(TestEntryDataSet)
45
- ```
46
-
47
- > **Tip:** For application-level data access, always go through a
48
- > `DataSetToken` rather than resolving the `StoreToken` directly. The
49
- > DataSet layer runs authorization, modification hooks, and entity-sync
50
- > events; a direct store access skips all of them. The
51
- > `furystack/no-direct-store-token` lint rule guards against this.
1
+ # @furystack/mongodb-store
2
+
3
+ MongoDB physical store implementation for FuryStack.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @furystack/mongodb-store
9
+ # or
10
+ yarn add @furystack/mongodb-store
11
+ ```
12
+
13
+ ## Initialization
14
+
15
+ `defineMongoDbStore` mints a `StoreToken` backed by a MongoDB collection.
16
+ The shared `MongoClientFactory` singleton pools `MongoClient` instances by
17
+ URL and closes them when the owning injector is disposed.
18
+
19
+ ```ts
20
+ import { createInjector } from '@furystack/inject'
21
+ import { defineMongoDbStore } from '@furystack/mongodb-store'
22
+ import { defineDataSet } from '@furystack/repository'
23
+
24
+ export class TestEntry {
25
+ declare _id: string
26
+ declare value: string
27
+ }
28
+
29
+ export const TestEntryStore = defineMongoDbStore<TestEntry, '_id'>({
30
+ name: 'my-app/TestEntryStore',
31
+ model: TestEntry,
32
+ primaryKey: '_id',
33
+ url: 'mongodb://localhost:27017',
34
+ db: 'test',
35
+ collection: 'TestEntries',
36
+ })
37
+
38
+ export const TestEntryDataSet = defineDataSet({
39
+ name: 'my-app/TestEntryDataSet',
40
+ store: TestEntryStore,
41
+ })
42
+
43
+ const myInjector = createInjector()
44
+ const dataSet = myInjector.get(TestEntryDataSet)
45
+ ```
46
+
47
+ > **Tip:** For application-level data access, always go through a
48
+ > `DataSetToken` rather than resolving the `StoreToken` directly. The
49
+ > DataSet layer runs authorization, modification hooks, and entity-sync
50
+ > events; a direct store access skips all of them. The
51
+ > `furystack/no-direct-store-token` lint rule guards against this.
@@ -0,0 +1,33 @@
1
+ import type { Constructable, Injector } from '@furystack/inject';
2
+ import type { MongoClientOptions } from 'mongodb';
3
+ export declare const useMongoDb: <T extends object>({ injector, model, primaryKey, db, collection, url, options, }: {
4
+ /**
5
+ * The Injector instance to use
6
+ */
7
+ injector: Injector;
8
+ /**
9
+ * The constructable model class
10
+ */
11
+ model: Constructable<T>;
12
+ /**
13
+ * The name of the Primary Key property
14
+ */
15
+ primaryKey: keyof T;
16
+ /**
17
+ * Url of the MongoDb repository
18
+ */
19
+ url: string;
20
+ /**
21
+ * MongoDb Database name
22
+ */
23
+ db: string;
24
+ /**
25
+ * MongoDb Collection name
26
+ */
27
+ collection: string;
28
+ /**
29
+ * Optional options for the MongoDb Client
30
+ */
31
+ options?: MongoClientOptions;
32
+ }) => void;
33
+ //# sourceMappingURL=store-manager-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-manager-helpers.d.ts","sourceRoot":"","sources":["../src/store-manager-helpers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAIjD,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,MAAM,EAAE,gEAQ1C;IACD;;OAEG;IACH,QAAQ,EAAE,QAAQ,CAAA;IAClB;;OAEG;IACH,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,CAAA;IACvB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,CAAA;IACnB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAA;IACX;;OAEG;IACH,EAAE,EAAE,MAAM,CAAA;IACV;;OAEG;IACH,UAAU,EAAE,MAAM,CAAA;IAElB;;OAEG;IACH,OAAO,CAAC,EAAE,kBAAkB,CAAA;CAC7B,SAUA,CAAA"}
@@ -0,0 +1,15 @@
1
+ import { addStore } from '@furystack/core';
2
+ import { MongoClientFactory } from './mongo-client-factory.js';
3
+ import { MongodbStore } from './mongodb-store.js';
4
+ export const useMongoDb = ({ injector, model, primaryKey, db, collection, url, options, }) => {
5
+ const clientFactory = injector.getInstance(MongoClientFactory);
6
+ const store = new MongodbStore({
7
+ model,
8
+ primaryKey,
9
+ db,
10
+ collection,
11
+ mongoClient: () => clientFactory.getClientFor(url, options),
12
+ });
13
+ addStore(injector, store);
14
+ };
15
+ //# sourceMappingURL=store-manager-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store-manager-helpers.js","sourceRoot":"","sources":["../src/store-manager-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAA;AAG1C,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAA;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAEjD,MAAM,CAAC,MAAM,UAAU,GAAG,CAAmB,EAC3C,QAAQ,EACR,KAAK,EACL,UAAU,EACV,EAAE,EACF,UAAU,EACV,GAAG,EACH,OAAO,GA+BR,EAAE,EAAE;IACH,MAAM,aAAa,GAAG,QAAQ,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAA;IAC9D,MAAM,KAAK,GAAG,IAAI,YAAY,CAAC;QAC7B,KAAK;QACL,UAAU;QACV,EAAE;QACF,UAAU;QACV,WAAW,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,YAAY,CAAC,GAAG,EAAE,OAAO,CAAC;KAC5D,CAAC,CAAA;IACF,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAA;AAC3B,CAAC,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@furystack/mongodb-store",
3
- "version": "11.0.3",
3
+ "version": "11.0.5",
4
4
  "description": "MongoDB Store implementation for FuryStack",
5
5
  "type": "module",
6
6
  "scripts": {
@@ -38,15 +38,15 @@
38
38
  },
39
39
  "homepage": "https://github.com/furystack/furystack",
40
40
  "dependencies": {
41
- "@furystack/core": "^17.1.2",
42
- "@furystack/inject": "^13.0.3",
43
- "@furystack/utils": "^9.0.3",
44
- "mongodb": "7.6.0"
41
+ "@furystack/core": "^17.1.4",
42
+ "@furystack/inject": "^13.0.5",
43
+ "@furystack/utils": "^9.0.5",
44
+ "mongodb": "7.8.0"
45
45
  },
46
46
  "devDependencies": {
47
- "@types/node": "^26.3.0",
47
+ "@types/node": "^26.6.6",
48
48
  "typescript": "^7.0.2",
49
- "vitest": "^4.1.11"
49
+ "vitest": "^5.1.0"
50
50
  },
51
51
  "engines": {
52
52
  "node": ">=24.0.0"
@@ -1,108 +1,108 @@
1
- import { createInjector } from '@furystack/inject'
2
- import type { MongoClient } from 'mongodb'
3
- import { describe, expect, it, vi } from 'vitest'
4
- import { defineMongoDbStore } from './define-mongodb-store.js'
5
- import { MongoClientFactory } from './mongo-client-factory.js'
6
- import { MongodbStore } from './mongodb-store.js'
7
-
8
- class Item {
9
- declare id: string
10
- declare value: string
11
- }
12
-
13
- describe('defineMongoDbStore (metadata)', () => {
14
- it('propagates name, lifetime, model and primaryKey onto the returned token', () => {
15
- const token = defineMongoDbStore<Item, 'id'>({
16
- name: 'test/MongoItems',
17
- model: Item,
18
- primaryKey: 'id',
19
- url: 'mongodb://localhost:27017',
20
- db: 'unit-test',
21
- collection: 'items',
22
- })
23
- expect(token.name).toBe('test/MongoItems')
24
- expect(token.lifetime).toBe('singleton')
25
- expect(token.model).toBe(Item)
26
- expect(token.primaryKey).toBe('id')
27
- })
28
-
29
- it('mints a distinct token identity per call even when options match -- declare once at module scope', () => {
30
- const options = {
31
- name: 'test/MongoDupe',
32
- model: Item,
33
- primaryKey: 'id' as const,
34
- url: 'mongodb://localhost:27017',
35
- db: 'unit-test',
36
- collection: 'items',
37
- }
38
- const a = defineMongoDbStore<Item, 'id'>(options)
39
- const b = defineMongoDbStore<Item, 'id'>(options)
40
- expect(a.id).not.toBe(b.id)
41
- })
42
- })
43
-
44
- describe('defineMongoDbStore (factory + disposal)', () => {
45
- const buildClientStub = () => {
46
- const createIndex = vi.fn<() => Promise<string>>(() => Promise.resolve('id_1'))
47
- const collection = vi.fn(() => ({ createIndex }))
48
- const db = vi.fn(() => ({ collection }))
49
- const client = { db } as unknown as MongoClient
50
- return { client, db, collection, createIndex }
51
- }
52
-
53
- it('instantiates a MongodbStore whose lazy client pulls from the injected MongoClientFactory with the right url', async () => {
54
- const { client, db, collection, createIndex } = buildClientStub()
55
- const getClientFor = vi.fn(() => client)
56
-
57
- const Token = defineMongoDbStore<Item, 'id'>({
58
- name: 'test/MongoFactory',
59
- model: Item,
60
- primaryKey: 'id',
61
- url: 'mongodb://stub-host:1234',
62
- db: 'unit-db',
63
- collection: 'unit-coll',
64
- options: { appName: 'spec' },
65
- })
66
-
67
- const injector = createInjector()
68
- injector.bind(MongoClientFactory, () => ({ getClientFor }))
69
-
70
- try {
71
- const store = injector.get(Token) as MongodbStore<Item, 'id'>
72
- expect(store).toBeInstanceOf(MongodbStore)
73
- expect(store.model).toBe(Item)
74
- expect(store.primaryKey).toBe('id')
75
- expect(getClientFor).not.toHaveBeenCalled()
76
-
77
- await store.getCollection()
78
-
79
- expect(getClientFor).toHaveBeenCalledTimes(1)
80
- expect(getClientFor).toHaveBeenCalledWith('mongodb://stub-host:1234', { appName: 'spec' })
81
- expect(db).toHaveBeenCalledWith('unit-db')
82
- expect(collection).toHaveBeenCalledWith('unit-coll')
83
- expect(createIndex).toHaveBeenCalledWith({ id: 1 }, { unique: true })
84
- } finally {
85
- await injector[Symbol.asyncDispose]()
86
- }
87
- })
88
-
89
- it('disposing the injector tears down the bound MongoClientFactory', async () => {
90
- const { client } = buildClientStub()
91
- const getClientFor = vi.fn(() => client)
92
-
93
- const Token = defineMongoDbStore<Item, 'id'>({
94
- name: 'test/MongoDispose',
95
- model: Item,
96
- primaryKey: 'id',
97
- url: 'mongodb://stub-host:1234',
98
- db: 'unit-db',
99
- collection: 'unit-coll',
100
- })
101
-
102
- const injector = createInjector()
103
- injector.bind(MongoClientFactory, () => ({ getClientFor }))
104
-
105
- injector.get(Token)
106
- await expect(injector[Symbol.asyncDispose]()).resolves.toBeUndefined()
107
- })
108
- })
1
+ import { createInjector } from '@furystack/inject'
2
+ import type { MongoClient } from 'mongodb'
3
+ import { describe, expect, it, vi } from 'vitest'
4
+ import { defineMongoDbStore } from './define-mongodb-store.js'
5
+ import { MongoClientFactory } from './mongo-client-factory.js'
6
+ import { MongodbStore } from './mongodb-store.js'
7
+
8
+ class Item {
9
+ declare id: string
10
+ declare value: string
11
+ }
12
+
13
+ describe('defineMongoDbStore (metadata)', () => {
14
+ it('propagates name, lifetime, model and primaryKey onto the returned token', () => {
15
+ const token = defineMongoDbStore<Item, 'id'>({
16
+ name: 'test/MongoItems',
17
+ model: Item,
18
+ primaryKey: 'id',
19
+ url: 'mongodb://localhost:27017',
20
+ db: 'unit-test',
21
+ collection: 'items',
22
+ })
23
+ expect(token.name).toBe('test/MongoItems')
24
+ expect(token.lifetime).toBe('singleton')
25
+ expect(token.model).toBe(Item)
26
+ expect(token.primaryKey).toBe('id')
27
+ })
28
+
29
+ it('mints a distinct token identity per call even when options match -- declare once at module scope', () => {
30
+ const options = {
31
+ name: 'test/MongoDupe',
32
+ model: Item,
33
+ primaryKey: 'id' as const,
34
+ url: 'mongodb://localhost:27017',
35
+ db: 'unit-test',
36
+ collection: 'items',
37
+ }
38
+ const a = defineMongoDbStore<Item, 'id'>(options)
39
+ const b = defineMongoDbStore<Item, 'id'>(options)
40
+ expect(a.id).not.toBe(b.id)
41
+ })
42
+ })
43
+
44
+ describe('defineMongoDbStore (factory + disposal)', () => {
45
+ const buildClientStub = () => {
46
+ const createIndex = vi.fn<() => Promise<string>>(() => Promise.resolve('id_1'))
47
+ const collection = vi.fn(() => ({ createIndex }))
48
+ const db = vi.fn(() => ({ collection }))
49
+ const client = { db } as unknown as MongoClient
50
+ return { client, db, collection, createIndex }
51
+ }
52
+
53
+ it('instantiates a MongodbStore whose lazy client pulls from the injected MongoClientFactory with the right url', async () => {
54
+ const { client, db, collection, createIndex } = buildClientStub()
55
+ const getClientFor = vi.fn(() => client)
56
+
57
+ const Token = defineMongoDbStore<Item, 'id'>({
58
+ name: 'test/MongoFactory',
59
+ model: Item,
60
+ primaryKey: 'id',
61
+ url: 'mongodb://stub-host:1234',
62
+ db: 'unit-db',
63
+ collection: 'unit-coll',
64
+ options: { appName: 'spec' },
65
+ })
66
+
67
+ const injector = createInjector()
68
+ injector.bind(MongoClientFactory, () => ({ getClientFor }))
69
+
70
+ try {
71
+ const store = injector.get(Token) as MongodbStore<Item, 'id'>
72
+ expect(store).toBeInstanceOf(MongodbStore)
73
+ expect(store.model).toBe(Item)
74
+ expect(store.primaryKey).toBe('id')
75
+ expect(getClientFor).not.toHaveBeenCalled()
76
+
77
+ await store.getCollection()
78
+
79
+ expect(getClientFor).toHaveBeenCalledTimes(1)
80
+ expect(getClientFor).toHaveBeenCalledWith('mongodb://stub-host:1234', { appName: 'spec' })
81
+ expect(db).toHaveBeenCalledWith('unit-db')
82
+ expect(collection).toHaveBeenCalledWith('unit-coll')
83
+ expect(createIndex).toHaveBeenCalledWith({ id: 1 }, { unique: true })
84
+ } finally {
85
+ await injector[Symbol.asyncDispose]()
86
+ }
87
+ })
88
+
89
+ it('disposing the injector tears down the bound MongoClientFactory', async () => {
90
+ const { client } = buildClientStub()
91
+ const getClientFor = vi.fn(() => client)
92
+
93
+ const Token = defineMongoDbStore<Item, 'id'>({
94
+ name: 'test/MongoDispose',
95
+ model: Item,
96
+ primaryKey: 'id',
97
+ url: 'mongodb://stub-host:1234',
98
+ db: 'unit-db',
99
+ collection: 'unit-coll',
100
+ })
101
+
102
+ const injector = createInjector()
103
+ injector.bind(MongoClientFactory, () => ({ getClientFor }))
104
+
105
+ injector.get(Token)
106
+ await expect(injector[Symbol.asyncDispose]()).resolves.toBeUndefined()
107
+ })
108
+ })
@@ -1,58 +1,58 @@
1
- import type { Constructable, StoreToken } from '@furystack/core'
2
- import { defineStore } from '@furystack/core'
3
- import type { MongoClient, MongoClientOptions } from 'mongodb'
4
- import { MongoClientFactory } from './mongo-client-factory.js'
5
- import { MongodbStore } from './mongodb-store.js'
6
-
7
- /**
8
- * Options accepted by {@link defineMongoDbStore}.
9
- */
10
- export type DefineMongoDbStoreOptions<T extends object, TPrimaryKey extends keyof T> = {
11
- name: string
12
- model: Constructable<T>
13
- primaryKey: TPrimaryKey
14
- /** MongoDB deployment URL (e.g. `mongodb://localhost:27017`) — also acts as the pool key. */
15
- url: string
16
- db: string
17
- collection: string
18
- options?: MongoClientOptions
19
- }
20
-
21
- /**
22
- * Mints a singleton {@link StoreToken} backed by a {@link MongodbStore}.
23
- *
24
- * Internally resolves the singleton {@link MongoClientFactory} so every store
25
- * declared against the same `url` shares one {@link MongoClient}. Declare the
26
- * token once at module scope — inline calls mint new identities and defeat
27
- * singleton caching.
28
- *
29
- * @example
30
- * ```ts
31
- * export const UserStore = defineMongoDbStore({
32
- * name: 'my-app/UserStore',
33
- * model: User,
34
- * primaryKey: 'username',
35
- * url: 'mongodb://localhost:27017',
36
- * db: 'my-app',
37
- * collection: 'users',
38
- * })
39
- * ```
40
- */
41
- export const defineMongoDbStore = <T extends object, const TPrimaryKey extends keyof T>(
42
- options: DefineMongoDbStoreOptions<T, TPrimaryKey>,
43
- ): StoreToken<T, TPrimaryKey> =>
44
- defineStore<T, TPrimaryKey>({
45
- name: options.name,
46
- model: options.model,
47
- primaryKey: options.primaryKey,
48
- factory: ({ inject }) => {
49
- const factory = inject(MongoClientFactory)
50
- return new MongodbStore<T, TPrimaryKey>({
51
- model: options.model,
52
- primaryKey: options.primaryKey,
53
- db: options.db,
54
- collection: options.collection,
55
- mongoClient: () => factory.getClientFor(options.url, options.options),
56
- })
57
- },
58
- })
1
+ import type { Constructable, StoreToken } from '@furystack/core'
2
+ import { defineStore } from '@furystack/core'
3
+ import type { MongoClient, MongoClientOptions } from 'mongodb'
4
+ import { MongoClientFactory } from './mongo-client-factory.js'
5
+ import { MongodbStore } from './mongodb-store.js'
6
+
7
+ /**
8
+ * Options accepted by {@link defineMongoDbStore}.
9
+ */
10
+ export type DefineMongoDbStoreOptions<T extends object, TPrimaryKey extends keyof T> = {
11
+ name: string
12
+ model: Constructable<T>
13
+ primaryKey: TPrimaryKey
14
+ /** MongoDB deployment URL (e.g. `mongodb://localhost:27017`) — also acts as the pool key. */
15
+ url: string
16
+ db: string
17
+ collection: string
18
+ options?: MongoClientOptions
19
+ }
20
+
21
+ /**
22
+ * Mints a singleton {@link StoreToken} backed by a {@link MongodbStore}.
23
+ *
24
+ * Internally resolves the singleton {@link MongoClientFactory} so every store
25
+ * declared against the same `url` shares one {@link MongoClient}. Declare the
26
+ * token once at module scope — inline calls mint new identities and defeat
27
+ * singleton caching.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * export const UserStore = defineMongoDbStore({
32
+ * name: 'my-app/UserStore',
33
+ * model: User,
34
+ * primaryKey: 'username',
35
+ * url: 'mongodb://localhost:27017',
36
+ * db: 'my-app',
37
+ * collection: 'users',
38
+ * })
39
+ * ```
40
+ */
41
+ export const defineMongoDbStore = <T extends object, const TPrimaryKey extends keyof T>(
42
+ options: DefineMongoDbStoreOptions<T, TPrimaryKey>,
43
+ ): StoreToken<T, TPrimaryKey> =>
44
+ defineStore<T, TPrimaryKey>({
45
+ name: options.name,
46
+ model: options.model,
47
+ primaryKey: options.primaryKey,
48
+ factory: ({ inject }) => {
49
+ const factory = inject(MongoClientFactory)
50
+ return new MongodbStore<T, TPrimaryKey>({
51
+ model: options.model,
52
+ primaryKey: options.primaryKey,
53
+ db: options.db,
54
+ collection: options.collection,
55
+ mongoClient: () => factory.getClientFor(options.url, options.options),
56
+ })
57
+ },
58
+ })
package/src/index.ts CHANGED
@@ -1,3 +1,3 @@
1
- export * from './define-mongodb-store.js'
2
- export * from './mongo-client-factory.js'
3
- export * from './mongodb-store.js'
1
+ export * from './define-mongodb-store.js'
2
+ export * from './mongo-client-factory.js'
3
+ export * from './mongodb-store.js'
@@ -1,45 +1,45 @@
1
- import type { Token } from '@furystack/inject'
2
- import { defineService } from '@furystack/inject'
3
- import type { MongoClientOptions } from 'mongodb'
4
- import { MongoClient } from 'mongodb'
5
-
6
- import type { defineMongoDbStore } from './define-mongodb-store.js'
7
-
8
- /**
9
- * Pools {@link MongoClient} instances by URL so every store that targets the
10
- * same MongoDB deployment shares a single connection.
11
- *
12
- * Application code rarely calls this directly — {@link defineMongoDbStore}
13
- * resolves the factory token internally. Exported for tests and advanced
14
- * integrations that need raw client access (e.g. dropping a test database).
15
- */
16
- export interface MongoClientFactory {
17
- getClientFor(url: string, options?: MongoClientOptions): MongoClient
18
- }
19
-
20
- /**
21
- * Singleton token for the {@link MongoClientFactory}. Closes every pooled
22
- * client when the owning injector is disposed.
23
- */
24
- export const MongoClientFactory: Token<MongoClientFactory, 'singleton'> = defineService({
25
- name: '@furystack/mongodb-store/MongoClientFactory',
26
- lifetime: 'singleton',
27
- factory: ({ onDispose }) => {
28
- const connections = new Map<string, MongoClient>()
29
- onDispose(async () => {
30
- await Promise.all([...connections.values()].map((c) => c.close(true)))
31
- connections.clear()
32
- })
33
- return {
34
- getClientFor(url: string, options?: MongoClientOptions): MongoClient {
35
- const existing = connections.get(url)
36
- if (existing) {
37
- return existing
38
- }
39
- const client = new MongoClient(url, options)
40
- connections.set(url, client)
41
- return client
42
- },
43
- }
44
- },
45
- })
1
+ import type { Token } from '@furystack/inject'
2
+ import { defineService } from '@furystack/inject'
3
+ import type { MongoClientOptions } from 'mongodb'
4
+ import { MongoClient } from 'mongodb'
5
+
6
+ import type { defineMongoDbStore } from './define-mongodb-store.js'
7
+
8
+ /**
9
+ * Pools {@link MongoClient} instances by URL so every store that targets the
10
+ * same MongoDB deployment shares a single connection.
11
+ *
12
+ * Application code rarely calls this directly — {@link defineMongoDbStore}
13
+ * resolves the factory token internally. Exported for tests and advanced
14
+ * integrations that need raw client access (e.g. dropping a test database).
15
+ */
16
+ export interface MongoClientFactory {
17
+ getClientFor(url: string, options?: MongoClientOptions): MongoClient
18
+ }
19
+
20
+ /**
21
+ * Singleton token for the {@link MongoClientFactory}. Closes every pooled
22
+ * client when the owning injector is disposed.
23
+ */
24
+ export const MongoClientFactory: Token<MongoClientFactory, 'singleton'> = defineService({
25
+ name: '@furystack/mongodb-store/MongoClientFactory',
26
+ lifetime: 'singleton',
27
+ factory: ({ onDispose }) => {
28
+ const connections = new Map<string, MongoClient>()
29
+ onDispose(async () => {
30
+ await Promise.all([...connections.values()].map((c) => c.close(true)))
31
+ connections.clear()
32
+ })
33
+ return {
34
+ getClientFor(url: string, options?: MongoClientOptions): MongoClient {
35
+ const existing = connections.get(url)
36
+ if (existing) {
37
+ return existing
38
+ }
39
+ const client = new MongoClient(url, options)
40
+ connections.set(url, client)
41
+ return client
42
+ },
43
+ }
44
+ },
45
+ })