@prisma-next/mongo 0.10.0 → 0.11.0

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,12 +1,19 @@
1
1
  # @prisma-next/mongo
2
2
 
3
- One-package MongoDB setup for Prisma Next. Install this single package to get config, runtime, and all transitive type dependencies.
3
+ One-package MongoDB setup for Prisma Next. Install this single package to get config, runtime, contract authoring, control-plane access, and BSON value constructors — no reach-ins to internal packages required.
4
+
5
+ > **Breaking change:** the top-level `@prisma-next/mongo` barrel (`import { ObjectId } from '@prisma-next/mongo'`) has been removed. Move BSON constructor imports to `@prisma-next/mongo/bson`:
6
+ >
7
+ > ```diff
8
+ > - import { ObjectId } from '@prisma-next/mongo';
9
+ > + import { ObjectId } from '@prisma-next/mongo/bson';
10
+ > ```
4
11
 
5
12
  ## Package Classification
6
13
 
7
14
  - **Domain**: extensions
8
15
  - **Layer**: adapters
9
- - **Planes**: shared (config), runtime (runtime)
16
+ - **Planes**: shared (config, contract-builder, bson, family, target), migration (control), runtime (runtime)
10
17
 
11
18
  ## Quick Start
12
19
 
@@ -20,27 +27,83 @@ export default defineConfig({
20
27
  });
21
28
  ```
22
29
 
30
+ ```typescript
31
+ // prisma/contract.ts
32
+ import { defineContract, field, model } from '@prisma-next/mongo/contract-builder';
33
+
34
+ export default defineContract({
35
+ models: {
36
+ User: model('User', { fields: { id: field.objectId() } }),
37
+ },
38
+ });
39
+ ```
40
+
23
41
  ## Exports
24
42
 
25
43
  ### `@prisma-next/mongo/config`
26
44
 
27
- Simplified `defineConfig` that pre-wires all MongoDB internals (family, target, adapter, driver, contract providers). Pass a contract path and optional db config.
45
+ Simplified `defineConfig` that pre-wires all MongoDB internals (family, target, adapter, driver, contract providers). Accepts `contract`, `db`, `extensions`, and `migrations.dir`.
28
46
 
29
- ### `@prisma-next/mongo/runtime`
47
+ ```typescript
48
+ import { defineConfig } from '@prisma-next/mongo/config';
30
49
 
31
- Re-exports `createMongoRuntime` from `@prisma-next/mongo-runtime` for composing the MongoDB execution pipeline.
50
+ export default defineConfig({
51
+ contract: './prisma/contract.prisma',
52
+ db: { connection: process.env['MONGODB_URL']! },
53
+ migrations: { dir: 'migrations/app' },
54
+ });
55
+ ```
32
56
 
33
57
  ### `@prisma-next/mongo/contract-builder`
34
58
 
35
- Re-exports the TypeScript contract authoring DSL (`defineContract`, `field`, `model`, `rel`, ...) so a generated `prisma/contract.ts` can author its contract using only this facade package.
59
+ TypeScript contract authoring DSL (`defineContract`, `field`, `model`, `rel`, `index`, `valueObject`, …). The `defineContract` facade pre-binds `family` and `target` callers do not pass those fields.
60
+
61
+ ```typescript
62
+ import { defineContract, field, model } from '@prisma-next/mongo/contract-builder';
63
+
64
+ export default defineContract({
65
+ models: {
66
+ User: model('User', { fields: { id: field.objectId() } }),
67
+ },
68
+ });
69
+ ```
70
+
71
+ ### `@prisma-next/mongo/control`
72
+
73
+ Control-plane client factory. Collapses the family + target + adapter + driver wiring into a single call.
74
+
75
+ ```typescript
76
+ import { createMongoControlClient } from '@prisma-next/mongo/control';
77
+
78
+ const control = createMongoControlClient({
79
+ connection: process.env['MONGODB_URL']!,
80
+ });
81
+ await control.dbUpdate({ migrations: { dir: 'migrations/app' } });
82
+ ```
83
+
84
+ ### `@prisma-next/mongo/bson`
85
+
86
+ BSON value constructors for use in seed scripts, fixtures, and tests.
87
+
88
+ ```typescript
89
+ import { ObjectId } from '@prisma-next/mongo/bson';
90
+
91
+ const id = new ObjectId();
92
+ ```
93
+
94
+ Exports: `Binary`, `Decimal128`, `Long`, `MongoClient`, `ObjectId`, `Timestamp`.
95
+
96
+ ### `@prisma-next/mongo/runtime`
97
+
98
+ Re-exports `createMongoRuntime` from `@prisma-next/mongo-runtime` for composing the MongoDB execution pipeline.
36
99
 
37
100
  ### `@prisma-next/mongo/family`
38
101
 
39
- Re-exports the MongoDB family pack (the value passed as `family:` to `defineContract`).
102
+ Re-exports the MongoDB family pack (only needed when using the low-level API; `defineContract` pre-binds this for you).
40
103
 
41
104
  ### `@prisma-next/mongo/target`
42
105
 
43
- Re-exports the MongoDB target pack (the value passed as `target:` to `defineContract`).
106
+ Re-exports the MongoDB target pack (only needed when using the low-level API; `defineContract` pre-binds this for you).
44
107
 
45
108
  ## Dependencies
46
109
 
package/dist/config.d.mts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { PrismaNextConfig } from "@prisma-next/config/config-types";
2
+ import { ControlExtensionDescriptor } from "@prisma-next/framework-components/control";
2
3
 
3
4
  //#region src/config/define-config.d.ts
4
5
  interface MongoConfigOptions {
@@ -6,6 +7,10 @@ interface MongoConfigOptions {
6
7
  readonly db?: {
7
8
  readonly connection?: string;
8
9
  };
10
+ readonly extensions?: readonly ControlExtensionDescriptor<'mongo', 'mongo'>[];
11
+ readonly migrations?: {
12
+ readonly dir?: string;
13
+ };
9
14
  }
10
15
  declare function defineConfig(options: MongoConfigOptions): PrismaNextConfig<'mongo', 'mongo'>;
11
16
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config/define-config.ts"],"mappings":";;;UAUiB,kBAAA;EAAA,SACN,QAAA;EAAA,SACA,EAAA;IAAA,SACE,UAAA;EAAA;AAAA;AAAA,iBAYG,YAAA,CAAa,OAAA,EAAS,kBAAA,GAAqB,gBAAA"}
1
+ {"version":3,"file":"config.d.mts","names":[],"sources":["../src/config/define-config.ts"],"mappings":";;;;UAYiB,kBAAA;EAAA,SACN,QAAA;EAAA,SACA,EAAA;IAAA,SACE,UAAA;EAAA;EAAA,SAEF,UAAA,YAAsB,0BAAA;EAAA,SACtB,UAAA;IAAA,SACE,GAAA;EAAA;AAAA;AAAA,iBAYG,YAAA,CAAa,OAAA,EAAS,kBAAA,GAAqB,gBAAA"}
package/dist/config.mjs CHANGED
@@ -5,6 +5,7 @@ import { mongoFamilyDescriptor } from "@prisma-next/family-mongo/control";
5
5
  import { mongoContract } from "@prisma-next/mongo-contract-psl/provider";
6
6
  import { typescriptContractFromPath } from "@prisma-next/mongo-contract-ts/config-types";
7
7
  import { mongoTargetDescriptor } from "@prisma-next/target-mongo/control";
8
+ import { ifDefined } from "@prisma-next/utils/defined";
8
9
  import { extname } from "pathe";
9
10
  //#region src/config/define-config.ts
10
11
  function deriveOutputPath(contractPath) {
@@ -13,14 +14,17 @@ function deriveOutputPath(contractPath) {
13
14
  return `${contractPath.slice(0, -ext.length)}.json`;
14
15
  }
15
16
  function defineConfig(options) {
17
+ const extensions = options.extensions ?? [];
16
18
  const output = deriveOutputPath(options.contract);
17
19
  return defineConfig$1({
18
20
  family: mongoFamilyDescriptor,
19
21
  target: mongoTargetDescriptor,
20
22
  adapter: mongoAdapter,
21
23
  driver: mongoDriver,
24
+ extensionPacks: extensions,
22
25
  contract: extname(options.contract) === ".ts" ? typescriptContractFromPath(options.contract, output) : mongoContract(options.contract, { output }),
23
- ...options.db !== void 0 ? { db: options.db } : {}
26
+ ...ifDefined("db", options.db),
27
+ ...ifDefined("migrations", options.migrations)
24
28
  });
25
29
  }
26
30
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"config.mjs","names":["coreDefineConfig"],"sources":["../src/config/define-config.ts"],"sourcesContent":["import mongoAdapter from '@prisma-next/adapter-mongo/control';\nimport type { PrismaNextConfig } from '@prisma-next/config/config-types';\nimport { defineConfig as coreDefineConfig } from '@prisma-next/config/config-types';\nimport mongoDriver from '@prisma-next/driver-mongo/control';\nimport { mongoFamilyDescriptor } from '@prisma-next/family-mongo/control';\nimport { mongoContract } from '@prisma-next/mongo-contract-psl/provider';\nimport { typescriptContractFromPath } from '@prisma-next/mongo-contract-ts/config-types';\nimport { mongoTargetDescriptor } from '@prisma-next/target-mongo/control';\nimport { extname } from 'pathe';\n\nexport interface MongoConfigOptions {\n readonly contract: string;\n readonly db?: {\n readonly connection?: string;\n };\n}\n\nfunction deriveOutputPath(contractPath: string): string {\n const ext = extname(contractPath);\n if (ext.length === 0) {\n return `${contractPath}.json`;\n }\n return `${contractPath.slice(0, -ext.length)}.json`;\n}\n\nexport function defineConfig(options: MongoConfigOptions): PrismaNextConfig<'mongo', 'mongo'> {\n const output = deriveOutputPath(options.contract);\n const ext = extname(options.contract);\n\n const contractConfig =\n ext === '.ts'\n ? typescriptContractFromPath(options.contract, output)\n : mongoContract(options.contract, { output });\n\n return coreDefineConfig({\n family: mongoFamilyDescriptor,\n target: mongoTargetDescriptor,\n adapter: mongoAdapter,\n driver: mongoDriver,\n contract: contractConfig,\n ...(options.db !== undefined ? { db: options.db } : {}),\n });\n}\n"],"mappings":";;;;;;;;;AAiBA,SAAS,iBAAiB,cAA8B;CACtD,MAAM,MAAM,QAAQ,aAAa;CACjC,IAAI,IAAI,WAAW,GACjB,OAAO,GAAG,aAAa;CAEzB,OAAO,GAAG,aAAa,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC;;AAG/C,SAAgB,aAAa,SAAiE;CAC5F,MAAM,SAAS,iBAAiB,QAAQ,SAAS;CAQjD,OAAOA,eAAiB;EACtB,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,QAAQ;EACR,UAZU,QAAQ,QAAQ,SAGvB,KAAK,QACJ,2BAA2B,QAAQ,UAAU,OAAO,GACpD,cAAc,QAAQ,UAAU,EAAE,QAAQ,CAAC;EAQ/C,GAAI,QAAQ,OAAO,KAAA,IAAY,EAAE,IAAI,QAAQ,IAAI,GAAG,EAAE;EACvD,CAAC"}
1
+ {"version":3,"file":"config.mjs","names":["coreDefineConfig"],"sources":["../src/config/define-config.ts"],"sourcesContent":["import mongoAdapter from '@prisma-next/adapter-mongo/control';\nimport type { PrismaNextConfig } from '@prisma-next/config/config-types';\nimport { defineConfig as coreDefineConfig } from '@prisma-next/config/config-types';\nimport mongoDriver from '@prisma-next/driver-mongo/control';\nimport { mongoFamilyDescriptor } from '@prisma-next/family-mongo/control';\nimport type { ControlExtensionDescriptor } from '@prisma-next/framework-components/control';\nimport { mongoContract } from '@prisma-next/mongo-contract-psl/provider';\nimport { typescriptContractFromPath } from '@prisma-next/mongo-contract-ts/config-types';\nimport { mongoTargetDescriptor } from '@prisma-next/target-mongo/control';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport { extname } from 'pathe';\n\nexport interface MongoConfigOptions {\n readonly contract: string;\n readonly db?: {\n readonly connection?: string;\n };\n readonly extensions?: readonly ControlExtensionDescriptor<'mongo', 'mongo'>[];\n readonly migrations?: {\n readonly dir?: string;\n };\n}\n\nfunction deriveOutputPath(contractPath: string): string {\n const ext = extname(contractPath);\n if (ext.length === 0) {\n return `${contractPath}.json`;\n }\n return `${contractPath.slice(0, -ext.length)}.json`;\n}\n\nexport function defineConfig(options: MongoConfigOptions): PrismaNextConfig<'mongo', 'mongo'> {\n const extensions = options.extensions ?? [];\n const output = deriveOutputPath(options.contract);\n const ext = extname(options.contract);\n\n const contractConfig =\n ext === '.ts'\n ? typescriptContractFromPath(options.contract, output)\n : mongoContract(options.contract, { output });\n\n return coreDefineConfig({\n family: mongoFamilyDescriptor,\n target: mongoTargetDescriptor,\n adapter: mongoAdapter,\n driver: mongoDriver,\n extensionPacks: extensions,\n contract: contractConfig,\n ...ifDefined('db', options.db),\n ...ifDefined('migrations', options.migrations),\n });\n}\n"],"mappings":";;;;;;;;;;AAuBA,SAAS,iBAAiB,cAA8B;CACtD,MAAM,MAAM,QAAQ,aAAa;CACjC,IAAI,IAAI,WAAW,GACjB,OAAO,GAAG,aAAa;CAEzB,OAAO,GAAG,aAAa,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC;;AAG/C,SAAgB,aAAa,SAAiE;CAC5F,MAAM,aAAa,QAAQ,cAAc,EAAE;CAC3C,MAAM,SAAS,iBAAiB,QAAQ,SAAS;CAQjD,OAAOA,eAAiB;EACtB,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,QAAQ;EACR,gBAAgB;EAChB,UAbU,QAAQ,QAAQ,SAGvB,KAAK,QACJ,2BAA2B,QAAQ,UAAU,OAAO,GACpD,cAAc,QAAQ,UAAU,EAAE,QAAQ,CAAC;EAS/C,GAAG,UAAU,MAAM,QAAQ,GAAG;EAC9B,GAAG,UAAU,cAAc,QAAQ,WAAW;EAC/C,CAAC"}
@@ -1,2 +1,31 @@
1
- import { ContractDefinition, ContractFactory, ContractScaffold, FieldBuilder, FieldReference, ModelBuilder, MongoContractResult, RelationBuilder, ValueObjectBuilder, defineContract, field, index, model, rel, valueObject } from "@prisma-next/mongo-contract-ts/contract-builder";
2
- export { type ContractDefinition, type ContractFactory, type ContractScaffold, type FieldBuilder, type FieldReference, type ModelBuilder, type MongoContractResult, type RelationBuilder, type ValueObjectBuilder, defineContract, field, index, model, rel, valueObject };
1
+ import { ContractDefinition, ContractDefinition as ContractDefinition$1, ContractFactory, ContractFactory as ContractFactory$1, ContractScaffold, ContractScaffold as ContractScaffold$1, FieldBuilder, FieldReference, ModelBuilder, MongoContractResult, MongoContractResult as MongoContractResult$1, RelationBuilder, ValueObjectBuilder, field, index, model, rel, valueObject } from "@prisma-next/mongo-contract-ts/contract-builder";
2
+ import mongoFamilyPack from "@prisma-next/family-mongo/pack";
3
+ import mongoTargetPack from "@prisma-next/target-mongo/pack";
4
+
5
+ //#region src/contract/define-contract.d.ts
6
+ type MongoFamilyPack = typeof mongoFamilyPack;
7
+ type MongoTargetPack = typeof mongoTargetPack;
8
+ type MongoHelpers = Parameters<ContractFactory$1<Record<never, never>, Record<never, never>, undefined, MongoFamilyPack, MongoTargetPack, undefined>>[0];
9
+ type MongoDefinitionInput = Omit<ContractDefinition$1<MongoFamilyPack, MongoTargetPack>, 'family' | 'target'> & {
10
+ readonly family?: never;
11
+ readonly target?: never;
12
+ };
13
+ type MongoScaffoldInput = Omit<ContractScaffold$1<MongoFamilyPack, MongoTargetPack>, 'family' | 'target'> & {
14
+ readonly family?: never;
15
+ readonly target?: never;
16
+ };
17
+ declare function defineContract<const Definition extends MongoDefinitionInput>(definition: Definition): MongoContractResult$1<Definition & {
18
+ readonly family: MongoFamilyPack;
19
+ readonly target: MongoTargetPack;
20
+ }>;
21
+ declare function defineContract<const Definition extends MongoScaffoldInput, const Built extends {
22
+ readonly models?: Record<string, unknown>;
23
+ readonly valueObjects?: Record<string, unknown>;
24
+ readonly roots?: Record<string, string>;
25
+ }>(scaffold: Definition, factory: (helpers: MongoHelpers) => Built): MongoContractResult$1<Definition & Built & {
26
+ readonly family: MongoFamilyPack;
27
+ readonly target: MongoTargetPack;
28
+ }>;
29
+ //#endregion
30
+ export { type ContractDefinition, type ContractFactory, type ContractScaffold, type FieldBuilder, type FieldReference, type ModelBuilder, type MongoContractResult, type RelationBuilder, type ValueObjectBuilder, defineContract, field, index, model, rel, valueObject };
31
+ //# sourceMappingURL=contract-builder.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-builder.d.mts","names":[],"sources":["../src/contract/define-contract.ts"],"mappings":";;;;;KAUK,eAAA,UAAyB,eAAA;AAAA,KACzB,eAAA,UAAyB,eAAA;AAAA,KAIzB,YAAA,GAAe,UAAA,CAClB,iBAAA,CACE,MAAA,gBACA,MAAA,2BAEA,eAAA,EACA,eAAA;AAAA,KAOC,oBAAA,GAAuB,IAAA,CAC1B,oBAAA,CAAmB,eAAA,EAAiB,eAAA;EAAA,SAG3B,MAAA;EAAA,SACA,MAAA;AAAA;AAAA,KAGN,kBAAA,GAAqB,IAAA,CACxB,kBAAA,CAAiB,eAAA,EAAiB,eAAA;EAAA,SAGzB,MAAA;EAAA,SACA,MAAA;AAAA;AAAA,iBAIK,cAAA,0BAAwC,oBAAA,CAAA,CACtD,UAAA,EAAY,UAAA,GACX,qBAAA,CACD,UAAA;EAAA,SAAwB,MAAA,EAAQ,eAAA;EAAA,SAA0B,MAAA,EAAQ,eAAA;AAAA;AAAA,iBAIpD,cAAA,0BACW,kBAAA;EAAA,SAEd,MAAA,GAAS,MAAA;EAAA,SACT,YAAA,GAAe,MAAA;EAAA,SACf,KAAA,GAAQ,MAAA;AAAA,EAAA,CAGnB,QAAA,EAAU,UAAA,EACV,OAAA,GAAU,OAAA,EAAS,YAAA,KAAiB,KAAA,GACnC,qBAAA,CACD,UAAA,GAAa,KAAA;EAAA,SAAmB,MAAA,EAAQ,eAAA;EAAA,SAA0B,MAAA,EAAQ,eAAA;AAAA"}
@@ -1,2 +1,17 @@
1
- import { defineContract, field, index, model, rel, valueObject } from "@prisma-next/mongo-contract-ts/contract-builder";
1
+ import { defineContract as defineContract$1, field, index, model, rel, valueObject } from "@prisma-next/mongo-contract-ts/contract-builder";
2
+ import mongoFamilyPack from "@prisma-next/family-mongo/pack";
3
+ import mongoTargetPack from "@prisma-next/target-mongo/pack";
4
+ //#region src/contract/define-contract.ts
5
+ function defineContract(definition, factory) {
6
+ const full = {
7
+ ...definition,
8
+ family: mongoFamilyPack,
9
+ target: mongoTargetPack
10
+ };
11
+ if (factory !== void 0) return defineContract$1(full, factory);
12
+ return defineContract$1(full);
13
+ }
14
+ //#endregion
2
15
  export { defineContract, field, index, model, rel, valueObject };
16
+
17
+ //# sourceMappingURL=contract-builder.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract-builder.mjs","names":["baseDefineContract"],"sources":["../src/contract/define-contract.ts"],"sourcesContent":["import mongoFamilyPack from '@prisma-next/family-mongo/pack';\nimport type {\n ContractDefinition,\n ContractFactory,\n ContractScaffold,\n MongoContractResult,\n} from '@prisma-next/mongo-contract-ts/contract-builder';\nimport { defineContract as baseDefineContract } from '@prisma-next/mongo-contract-ts/contract-builder';\nimport mongoTargetPack from '@prisma-next/target-mongo/pack';\n\ntype MongoFamilyPack = typeof mongoFamilyPack;\ntype MongoTargetPack = typeof mongoTargetPack;\n\n// Helpers type derived from the exported ContractFactory rather than the\n// un-exported ContractAuthoringHelpers, so we stay inside the public surface.\ntype MongoHelpers = Parameters<\n ContractFactory<\n Record<never, never>,\n Record<never, never>,\n undefined,\n MongoFamilyPack,\n MongoTargetPack,\n undefined\n >\n>[0];\n\n// Input types omit family + target AND explicitly forbid them so that\n// `@ts-expect-error` tests can verify the fields are rejected.\ntype MongoDefinitionInput = Omit<\n ContractDefinition<MongoFamilyPack, MongoTargetPack>,\n 'family' | 'target'\n> & {\n readonly family?: never;\n readonly target?: never;\n};\n\ntype MongoScaffoldInput = Omit<\n ContractScaffold<MongoFamilyPack, MongoTargetPack>,\n 'family' | 'target'\n> & {\n readonly family?: never;\n readonly target?: never;\n};\n\n// Overload 1: definition form — models / valueObjects inline in the definition object.\nexport function defineContract<const Definition extends MongoDefinitionInput>(\n definition: Definition,\n): MongoContractResult<\n Definition & { readonly family: MongoFamilyPack; readonly target: MongoTargetPack }\n>;\n\n// Overload 2: factory form — models / valueObjects provided by a factory function.\nexport function defineContract<\n const Definition extends MongoScaffoldInput,\n const Built extends {\n readonly models?: Record<string, unknown>;\n readonly valueObjects?: Record<string, unknown>;\n readonly roots?: Record<string, string>;\n },\n>(\n scaffold: Definition,\n factory: (helpers: MongoHelpers) => Built,\n): MongoContractResult<\n Definition & Built & { readonly family: MongoFamilyPack; readonly target: MongoTargetPack }\n>;\n\n// Implementation — pre-binds family and target before delegating to the base.\n// The `as unknown` cast is safe: every declared overload produces a MongoContractResult\n// and the only difference between the public overload signatures and the impl is\n// that we union both call forms here.\nexport function defineContract(\n definition: MongoDefinitionInput,\n factory?: (helpers: MongoHelpers) => {\n readonly models?: Record<string, unknown>;\n readonly valueObjects?: Record<string, unknown>;\n readonly roots?: Record<string, string>;\n },\n): MongoContractResult<\n MongoDefinitionInput & { readonly family: MongoFamilyPack; readonly target: MongoTargetPack }\n> {\n const full = {\n ...definition,\n family: mongoFamilyPack,\n target: mongoTargetPack,\n } as ContractDefinition<MongoFamilyPack, MongoTargetPack>;\n\n if (factory !== undefined) {\n return baseDefineContract(\n full as ContractScaffold<MongoFamilyPack, MongoTargetPack>,\n factory as unknown as Parameters<typeof baseDefineContract>[1],\n ) as unknown as MongoContractResult<\n MongoDefinitionInput & { readonly family: MongoFamilyPack; readonly target: MongoTargetPack }\n >;\n }\n\n return baseDefineContract(full) as unknown as MongoContractResult<\n MongoDefinitionInput & { readonly family: MongoFamilyPack; readonly target: MongoTargetPack }\n >;\n}\n"],"mappings":";;;;AAsEA,SAAgB,eACd,YACA,SAOA;CACA,MAAM,OAAO;EACX,GAAG;EACH,QAAQ;EACR,QAAQ;EACT;CAED,IAAI,YAAY,KAAA,GACd,OAAOA,iBACL,MACA,QACD;CAKH,OAAOA,iBAAmB,KAAK"}
@@ -0,0 +1,11 @@
1
+ import { ControlClient, ControlClientOptions } from "@prisma-next/cli/control-api";
2
+
3
+ //#region src/exports/control.d.ts
4
+ interface MongoControlClientOptions {
5
+ readonly connection?: string;
6
+ readonly extensionPacks?: ControlClientOptions['extensionPacks'];
7
+ }
8
+ declare function createMongoControlClient(options?: MongoControlClientOptions): ControlClient;
9
+ //#endregion
10
+ export { type ControlClient, MongoControlClientOptions, createMongoControlClient };
11
+ //# sourceMappingURL=control.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control.d.mts","names":[],"sources":["../src/exports/control.ts"],"mappings":";;;UAWiB,yBAAA;EAAA,SACN,UAAA;EAAA,SACA,cAAA,GAAiB,oBAAA;AAAA;AAAA,iBAGZ,wBAAA,CAAyB,OAAA,GAAS,yBAAA,GAAiC,aAAA"}
@@ -0,0 +1,21 @@
1
+ import mongoAdapter from "@prisma-next/adapter-mongo/control";
2
+ import mongoDriver from "@prisma-next/driver-mongo/control";
3
+ import { mongoFamilyDescriptor } from "@prisma-next/family-mongo/control";
4
+ import { mongoTargetDescriptor } from "@prisma-next/target-mongo/control";
5
+ import { ifDefined } from "@prisma-next/utils/defined";
6
+ import { createControlClient } from "@prisma-next/cli/control-api";
7
+ //#region src/exports/control.ts
8
+ function createMongoControlClient(options = {}) {
9
+ return createControlClient({
10
+ family: mongoFamilyDescriptor,
11
+ target: mongoTargetDescriptor,
12
+ adapter: mongoAdapter,
13
+ driver: mongoDriver,
14
+ ...ifDefined("connection", options.connection),
15
+ ...ifDefined("extensionPacks", options.extensionPacks)
16
+ });
17
+ }
18
+ //#endregion
19
+ export { createMongoControlClient };
20
+
21
+ //# sourceMappingURL=control.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"control.mjs","names":[],"sources":["../src/exports/control.ts"],"sourcesContent":["import mongoAdapter from '@prisma-next/adapter-mongo/control';\nimport {\n type ControlClient,\n type ControlClientOptions,\n createControlClient,\n} from '@prisma-next/cli/control-api';\nimport mongoDriver from '@prisma-next/driver-mongo/control';\nimport { mongoFamilyDescriptor } from '@prisma-next/family-mongo/control';\nimport { mongoTargetDescriptor } from '@prisma-next/target-mongo/control';\nimport { ifDefined } from '@prisma-next/utils/defined';\n\nexport interface MongoControlClientOptions {\n readonly connection?: string;\n readonly extensionPacks?: ControlClientOptions['extensionPacks'];\n}\n\nexport function createMongoControlClient(options: MongoControlClientOptions = {}): ControlClient {\n const clientOptions: ControlClientOptions = {\n family: mongoFamilyDescriptor,\n target: mongoTargetDescriptor,\n adapter: mongoAdapter,\n driver: mongoDriver,\n ...ifDefined('connection', options.connection),\n ...ifDefined('extensionPacks', options.extensionPacks),\n };\n return createControlClient(clientOptions);\n}\n\nexport type { ControlClient };\n"],"mappings":";;;;;;;AAgBA,SAAgB,yBAAyB,UAAqC,EAAE,EAAiB;CAS/F,OAAO,oBAAoB;EAPzB,QAAQ;EACR,QAAQ;EACR,SAAS;EACT,QAAQ;EACR,GAAG,UAAU,cAAc,QAAQ,WAAW;EAC9C,GAAG,UAAU,kBAAkB,QAAQ,eAAe;EAEhB,CAAC"}
@@ -50,6 +50,7 @@ interface MongoClient<TContract extends MongoContractWithTypeMaps<MongoContract,
50
50
  connect(bindingInput?: MongoBindingInput): Promise<MongoRuntime>;
51
51
  runtime(): Promise<MongoRuntime>;
52
52
  close(): Promise<void>;
53
+ [Symbol.asyncDispose](): Promise<void>;
53
54
  }
54
55
  interface MongoOptionsBase {
55
56
  readonly mode?: 'strict' | 'permissive';
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.mts","names":[],"sources":["../src/runtime/binding.ts","../src/runtime/mongo.ts"],"mappings":";;;;;;;;KAEY,YAAA;EAAA,SACG,IAAA;EAAA,SAAsB,GAAA;EAAA,SAAsB,MAAA;AAAA;EAAA,SAE5C,IAAA;EAAA,SACA,MAAA,EAAQ,aAAA;EAAA,SACR,MAAA;AAAA;AAAA,KAGH,iBAAA;EAAA,SAEG,OAAA,EAAS,YAAA;EAAA,SACT,GAAA;EAAA,SACA,GAAA;EAAA,SACA,MAAA;EAAA,SACA,WAAA;AAAA;EAAA,SAGA,GAAA;EAAA,SACA,MAAA;EAAA,SACA,OAAA;EAAA,SACA,GAAA;EAAA,SACA,WAAA;AAAA;EAAA,SAGA,GAAA;EAAA,SACA,MAAA;EAAA,SACA,OAAA;EAAA,SACA,GAAA;EAAA,SACA,WAAA;AAAA;EAAA,SAGA,WAAA,EAAa,aAAA;EAAA,SACb,MAAA;EAAA,SACA,OAAA;EAAA,SACA,GAAA;EAAA,SACA,GAAA;AAAA;;;KCVH,aAAA;AAAA,UAEK,WAAA,mBACG,yBAAA,CAA0B,aAAA,EAAe,aAAA;EAAA,SAElD,GAAA,EAAK,cAAA,CAAe,SAAA;EAAA,SACpB,KAAA,EAAO,UAAA,QAAkB,UAAA,CAAW,SAAA;EAAA,SACpC,QAAA,EAAU,SAAA;EACnB,OAAA,CAAQ,YAAA,GAAe,iBAAA,GAAoB,OAAA,CAAQ,YAAA;EACnD,OAAA,IAAW,OAAA,CAAQ,YAAA;EACnB,KAAA,IAAS,OAAA;AAAA;AAAA,UAGM,gBAAA;EAAA,SACN,IAAA;EDnCI;;;EAAA,SCuCJ,UAAA,YAAsB,eAAA;AAAA;AAAA,UAGhB,mBAAA;EAAA,SACN,OAAA,GAAU,YAAA;EAAA,SACV,GAAA;EAAA,SACA,GAAA;EAAA,SACA,MAAA;EAAA,SACA,WAAA,GAJsB,SAAA,CAIU,WAAA;AAAA;AAAA,KAG/B,wBAAA,mBACQ,yBAAA,CAA0B,aAAA,EAAe,aAAA,KACzD,mBAAA,GACF,gBAAA;EAAA,SACW,QAAA,EAAU,SAAA;EAAA,SACV,YAAA;AAAA;;;;;;KAQD,4BAAA,mBACQ,yBAAA,CAA0B,aAAA,EAAe,aAAA,KACzD,mBAAA,GACF,gBAAA;EAAA,SACW,YAAA;EAAA,SACA,QAAA;ED5CE;;;;EAAA,SCiDF,iBAAA,GAAoB,SAAA;AAAA;AAAA,KAGrB,YAAA,mBACQ,yBAAA,CAA0B,aAAA,EAAe,aAAA,KACzD,wBAAA,CAAyB,SAAA,IAAa,4BAAA,CAA6B,SAAA;;;;;;AAzDvE;;;iBAgFwB,KAAA,mBACJ,yBAAA,CAA0B,aAAA,EAAe,aAAA,EAAA,CAC3D,OAAA,EAAS,wBAAA,CAAyB,SAAA,IAAa,WAAA,CAAY,SAAA;AAAA,iBACrC,KAAA,mBACJ,yBAAA,CAA0B,aAAA,EAAe,aAAA,EAAA,CAC3D,OAAA,EAAS,4BAAA,CAA6B,SAAA,IAAa,WAAA,CAAY,SAAA"}
1
+ {"version":3,"file":"runtime.d.mts","names":[],"sources":["../src/runtime/binding.ts","../src/runtime/mongo.ts"],"mappings":";;;;;;;;KAEY,YAAA;EAAA,SACG,IAAA;EAAA,SAAsB,GAAA;EAAA,SAAsB,MAAA;AAAA;EAAA,SAE5C,IAAA;EAAA,SACA,MAAA,EAAQ,aAAA;EAAA,SACR,MAAA;AAAA;AAAA,KAGH,iBAAA;EAAA,SAEG,OAAA,EAAS,YAAA;EAAA,SACT,GAAA;EAAA,SACA,GAAA;EAAA,SACA,MAAA;EAAA,SACA,WAAA;AAAA;EAAA,SAGA,GAAA;EAAA,SACA,MAAA;EAAA,SACA,OAAA;EAAA,SACA,GAAA;EAAA,SACA,WAAA;AAAA;EAAA,SAGA,GAAA;EAAA,SACA,MAAA;EAAA,SACA,OAAA;EAAA,SACA,GAAA;EAAA,SACA,WAAA;AAAA;EAAA,SAGA,WAAA,EAAa,aAAA;EAAA,SACb,MAAA;EAAA,SACA,OAAA;EAAA,SACA,GAAA;EAAA,SACA,GAAA;AAAA;;;KCVH,aAAA;AAAA,UAEK,WAAA,mBACG,yBAAA,CAA0B,aAAA,EAAe,aAAA;EAAA,SAElD,GAAA,EAAK,cAAA,CAAe,SAAA;EAAA,SACpB,KAAA,EAAO,UAAA,QAAkB,UAAA,CAAW,SAAA;EAAA,SACpC,QAAA,EAAU,SAAA;EACnB,OAAA,CAAQ,YAAA,GAAe,iBAAA,GAAoB,OAAA,CAAQ,YAAA;EACnD,OAAA,IAAW,OAAA,CAAQ,YAAA;EACnB,KAAA,IAAS,OAAA;EAAA,CACR,MAAA,CAAO,YAAP,KAAwB,OAAA;AAAA;AAAA,UAGV,gBAAA;EAAA,SACN,IAAA;EDpCY;;;EAAA,SCwCZ,UAAA,YAAsB,eAAA;AAAA;AAAA,UAGhB,mBAAA;EAAA,SACN,OAAA,GAAU,YAAA;EAAA,SACV,GAAA;EAAA,SACA,GAAA;EAAA,SACA,MAAA;EAAA,SACA,WAAA,GAJsB,SAAA,CAIU,WAAA;AAAA;AAAA,KAG/B,wBAAA,mBACQ,yBAAA,CAA0B,aAAA,EAAe,aAAA,KACzD,mBAAA,GACF,gBAAA;EAAA,SACW,QAAA,EAAU,SAAA;EAAA,SACV,YAAA;AAAA;;;;;;KAQD,4BAAA,mBACQ,yBAAA,CAA0B,aAAA,EAAe,aAAA,KACzD,mBAAA,GACF,gBAAA;EAAA,SACW,YAAA;EAAA,SACA,QAAA;ED1CE;;;;EAAA,SC+CF,iBAAA,GAAoB,SAAA;AAAA;AAAA,KAGrB,YAAA,mBACQ,yBAAA,CAA0B,aAAA,EAAe,aAAA,KACzD,wBAAA,CAAyB,SAAA,IAAa,4BAAA,CAA6B,SAAA;;;;;AA1DvE;;;;iBAiFwB,KAAA,mBACJ,yBAAA,CAA0B,aAAA,EAAe,aAAA,EAAA,CAC3D,OAAA,EAAS,wBAAA,CAAyB,SAAA,IAAa,WAAA,CAAY,SAAA;AAAA,iBACrC,KAAA,mBACJ,yBAAA,CAA0B,aAAA,EAAe,aAAA,EAAA,CAC3D,OAAA,EAAS,4BAAA,CAA6B,SAAA,IAAa,WAAA,CAAY,SAAA"}
package/dist/runtime.mjs CHANGED
@@ -1,3 +1,4 @@
1
+ import { ifDefined } from "@prisma-next/utils/defined";
1
2
  import mongoRuntimeAdapter from "@prisma-next/adapter-mongo/runtime";
2
3
  import { MongoDriverImpl } from "@prisma-next/driver-mongo";
3
4
  import { MongoContractSerializer } from "@prisma-next/family-mongo/ir";
@@ -6,7 +7,6 @@ import { mongoOrm } from "@prisma-next/mongo-orm";
6
7
  import { mongoQuery } from "@prisma-next/mongo-query-builder";
7
8
  import { createMongoExecutionContext, createMongoExecutionStack, createMongoRuntime } from "@prisma-next/mongo-runtime";
8
9
  import mongoRuntimeTarget from "@prisma-next/target-mongo/runtime";
9
- import { ifDefined } from "@prisma-next/utils/defined";
10
10
  //#region src/runtime/binding.ts
11
11
  function validateMongoUrl(url) {
12
12
  const trimmed = url.trim();
@@ -95,16 +95,20 @@ function mongo(options) {
95
95
  const query = mongoQuery({ contractJson: contract });
96
96
  let runtimePromise;
97
97
  let closed = false;
98
+ let ownedDispose;
98
99
  const buildRuntime = async (resolvedBinding) => {
100
+ const context = createMongoExecutionContext({
101
+ contract,
102
+ stack: createMongoExecutionStack({
103
+ target: mongoRuntimeTarget,
104
+ adapter: mongoRuntimeAdapter
105
+ })
106
+ });
107
+ const driver = resolvedBinding.kind === "url" ? await MongoDriverImpl.fromConnection(resolvedBinding.url, resolvedBinding.dbName) : MongoDriverImpl.fromDb(resolvedBinding.client.db(resolvedBinding.dbName));
108
+ if (resolvedBinding.kind === "url") ownedDispose = () => driver.close();
99
109
  return createMongoRuntime({
100
- context: createMongoExecutionContext({
101
- contract,
102
- stack: createMongoExecutionStack({
103
- target: mongoRuntimeTarget,
104
- adapter: mongoRuntimeAdapter
105
- })
106
- }),
107
- driver: resolvedBinding.kind === "url" ? await MongoDriverImpl.fromConnection(resolvedBinding.url, resolvedBinding.dbName) : MongoDriverImpl.fromDb(resolvedBinding.client.db(resolvedBinding.dbName)),
110
+ context,
111
+ driver,
108
112
  ...options.mode !== void 0 ? { mode: options.mode } : {},
109
113
  ...ifDefined("middleware", options.middleware)
110
114
  });
@@ -146,8 +150,14 @@ function mongo(options) {
146
150
  closed = true;
147
151
  if (runtimePromise === void 0) return;
148
152
  try {
149
- await (await runtimePromise).close();
153
+ await runtimePromise;
150
154
  } catch {}
155
+ const dispose = ownedDispose;
156
+ ownedDispose = void 0;
157
+ await dispose?.();
158
+ },
159
+ [Symbol.asyncDispose]() {
160
+ return this.close();
151
161
  }
152
162
  };
153
163
  }
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.mjs","names":[],"sources":["../src/runtime/binding.ts","../src/runtime/mongo.ts"],"sourcesContent":["import type { MongoClient as MongoDriverClient } from 'mongodb';\n\nexport type MongoBinding =\n | { readonly kind: 'url'; readonly url: string; readonly dbName: string }\n | {\n readonly kind: 'mongoClient';\n readonly client: MongoDriverClient;\n readonly dbName: string;\n };\n\nexport type MongoBindingInput =\n | {\n readonly binding: MongoBinding;\n readonly url?: never;\n readonly uri?: never;\n readonly dbName?: never;\n readonly mongoClient?: never;\n }\n | {\n readonly url: string;\n readonly dbName?: string;\n readonly binding?: never;\n readonly uri?: never;\n readonly mongoClient?: never;\n }\n | {\n readonly uri: string;\n readonly dbName: string;\n readonly binding?: never;\n readonly url?: never;\n readonly mongoClient?: never;\n }\n | {\n readonly mongoClient: MongoDriverClient;\n readonly dbName: string;\n readonly binding?: never;\n readonly url?: never;\n readonly uri?: never;\n };\n\ntype MongoBindingFields = {\n readonly binding?: MongoBinding;\n readonly url?: string;\n readonly uri?: string;\n readonly dbName?: string;\n readonly mongoClient?: MongoDriverClient;\n};\n\nfunction validateMongoUrl(url: string): URL {\n const trimmed = url.trim();\n if (trimmed.length === 0) {\n throw new Error('Mongo URL must be a non-empty string');\n }\n\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new Error('Mongo URL must be a valid URL');\n }\n\n if (parsed.protocol !== 'mongodb:' && parsed.protocol !== 'mongodb+srv:') {\n throw new Error('Mongo URL must use mongodb:// or mongodb+srv://');\n }\n\n return parsed;\n}\n\nfunction extractDbNameFromUrl(parsed: URL): string | undefined {\n // pathname is \"/dbname\" or \"\" — strip the leading slash. Anything past\n // a second slash is invalid for our purposes (auth-source style paths).\n const path = parsed.pathname.startsWith('/') ? parsed.pathname.slice(1) : parsed.pathname;\n if (path.length === 0) {\n return undefined;\n }\n const slash = path.indexOf('/');\n return slash === -1 ? path : path.slice(0, slash);\n}\n\nexport function resolveMongoBinding(options: MongoBindingInput): MongoBinding {\n const providedCount =\n Number(options.binding !== undefined) +\n Number(options.url !== undefined) +\n Number(options.uri !== undefined) +\n Number(options.mongoClient !== undefined);\n\n if (providedCount !== 1) {\n throw new Error('Provide one binding input: binding, url, uri+dbName, or mongoClient+dbName');\n }\n\n if (options.binding !== undefined) {\n return options.binding;\n }\n\n if (options.url !== undefined) {\n const parsed = validateMongoUrl(options.url);\n // An explicit, whitespace-only `dbName` is a user-error we'd rather\n // surface loudly: silently falling back to the URL path would mask\n // a typo or empty-template-string bug. Treat it the same as the\n // `{ uri, dbName }` and `{ mongoClient, dbName }` paths, where an\n // empty trimmed dbName is already a fast failure.\n if (options.dbName !== undefined && options.dbName.trim().length === 0) {\n throw new Error('Mongo binding via { url, dbName } requires a non-empty dbName');\n }\n const explicitDbName = options.dbName?.trim();\n const dbName =\n explicitDbName !== undefined && explicitDbName.length > 0\n ? explicitDbName\n : extractDbNameFromUrl(parsed);\n if (dbName === undefined || dbName.length === 0) {\n throw new Error(\n 'Mongo URL must include a database name in its path (e.g. mongodb://host:27017/mydb), or pass dbName explicitly',\n );\n }\n return { kind: 'url', url: options.url.trim(), dbName };\n }\n\n if (options.uri !== undefined) {\n validateMongoUrl(options.uri);\n const dbName = options.dbName?.trim();\n if (dbName === undefined || dbName.length === 0) {\n throw new Error('Mongo binding via { uri, dbName } requires a non-empty dbName');\n }\n return { kind: 'url', url: options.uri.trim(), dbName };\n }\n\n const mongoClient = options.mongoClient;\n if (mongoClient === undefined) {\n throw new Error('Invariant violation: expected mongo binding after validation');\n }\n const dbName = options.dbName?.trim();\n if (dbName === undefined || dbName.length === 0) {\n throw new Error('Mongo binding via { mongoClient, dbName } requires a non-empty dbName');\n }\n return { kind: 'mongoClient', client: mongoClient, dbName };\n}\n\nexport function resolveOptionalMongoBinding(options: MongoBindingFields): MongoBinding | undefined {\n const providedCount =\n Number(options.binding !== undefined) +\n Number(options.url !== undefined) +\n Number(options.uri !== undefined) +\n Number(options.mongoClient !== undefined);\n\n if (providedCount === 0) {\n return undefined;\n }\n // Defer the \"exactly one\" enforcement to `resolveMongoBinding`. We call it\n // through a single branch per input field so the matching union member of\n // `MongoBindingInput` is constructed explicitly — the previous\n // `options as MongoBindingInput` cast hid drift between `MongoBindingFields`\n // (any combination of optional inputs) and `MongoBindingInput` (exactly one).\n if (providedCount !== 1) {\n throw new Error('Provide one binding input: binding, url, uri+dbName, or mongoClient+dbName');\n }\n if (options.binding !== undefined) {\n return resolveMongoBinding({ binding: options.binding });\n }\n if (options.url !== undefined) {\n return resolveMongoBinding(\n options.dbName !== undefined\n ? { url: options.url, dbName: options.dbName }\n : { url: options.url },\n );\n }\n if (options.uri !== undefined) {\n return resolveMongoBinding({ uri: options.uri, dbName: options.dbName ?? '' });\n }\n if (options.mongoClient !== undefined) {\n return resolveMongoBinding({\n mongoClient: options.mongoClient,\n dbName: options.dbName ?? '',\n });\n }\n // Unreachable: the `providedCount === 1` guard above plus the four\n // branch checks cover every shape of `MongoBindingFields`. A bare\n // `return undefined` here would silently mask a future\n // `MongoBindingFields` extension that adds a fifth input, so we\n // surface it as an invariant rather than a missing binding.\n throw new Error('Invariant violation: expected one mongo binding branch');\n}\n","import mongoRuntimeAdapter from '@prisma-next/adapter-mongo/runtime';\nimport { MongoDriverImpl } from '@prisma-next/driver-mongo';\nimport { MongoContractSerializer } from '@prisma-next/family-mongo/ir';\nimport { AsyncIterableResult } from '@prisma-next/framework-components/runtime';\nimport type {\n MongoContract,\n MongoContractWithTypeMaps,\n MongoTypeMaps,\n} from '@prisma-next/mongo-contract';\nimport type { MongoOrmClient, MongoQueryPlan } from '@prisma-next/mongo-orm';\nimport { mongoOrm } from '@prisma-next/mongo-orm';\nimport { mongoQuery } from '@prisma-next/mongo-query-builder';\nimport type { MongoMiddleware, MongoRuntime } from '@prisma-next/mongo-runtime';\nimport {\n createMongoExecutionContext,\n createMongoExecutionStack,\n createMongoRuntime,\n} from '@prisma-next/mongo-runtime';\nimport mongoRuntimeTarget from '@prisma-next/target-mongo/runtime';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport {\n type MongoBinding,\n type MongoBindingInput,\n resolveMongoBinding,\n resolveOptionalMongoBinding,\n} from './binding';\n\nexport type MongoTargetId = 'mongo';\n\nexport interface MongoClient<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n> {\n readonly orm: MongoOrmClient<TContract>;\n readonly query: ReturnType<typeof mongoQuery<TContract>>;\n readonly contract: TContract;\n connect(bindingInput?: MongoBindingInput): Promise<MongoRuntime>;\n runtime(): Promise<MongoRuntime>;\n close(): Promise<void>;\n}\n\nexport interface MongoOptionsBase {\n readonly mode?: 'strict' | 'permissive';\n /**\n * Optional middleware chain applied to every Mongo execution.\n */\n readonly middleware?: readonly MongoMiddleware[];\n}\n\nexport interface MongoBindingOptions {\n readonly binding?: MongoBinding;\n readonly url?: string;\n readonly uri?: string;\n readonly dbName?: string;\n readonly mongoClient?: import('mongodb').MongoClient;\n}\n\nexport type MongoOptionsWithContract<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n> = MongoBindingOptions &\n MongoOptionsBase & {\n readonly contract: TContract;\n readonly contractJson?: never;\n };\n\n/**\n * `TContract` is a phantom parameter that drives explicit-type inference at the\n * call site (e.g. `mongo<Contract>({ contractJson })`). It is not referenced in\n * the type body — the contract value comes through `contractJson` at runtime.\n */\nexport type MongoOptionsWithContractJson<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n> = MongoBindingOptions &\n MongoOptionsBase & {\n readonly contractJson: unknown;\n readonly contract?: never;\n /**\n * @internal phantom field; never set at runtime, only references TContract\n * so that strict tsc/biome don't flag the type parameter as unused.\n */\n readonly __contractPhantom?: TContract;\n };\n\nexport type MongoOptions<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n> = MongoOptionsWithContract<TContract> | MongoOptionsWithContractJson<TContract>;\n\nfunction hasContractJson<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>>(\n options: MongoOptions<TContract>,\n): options is MongoOptionsWithContractJson<TContract> {\n return 'contractJson' in options;\n}\n\nfunction resolveContract<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>>(\n options: MongoOptions<TContract>,\n): TContract {\n const contractInput = hasContractJson(options) ? options.contractJson : options.contract;\n return new MongoContractSerializer().deserializeContract(contractInput) as TContract;\n}\n\n/**\n * Creates a lazy Mongo client from either `contractJson` or a TypeScript-authored `contract`.\n * The `orm` and `query` surfaces are available immediately; the underlying driver is connected\n * on the first query (or the first explicit `connect()` call), mirroring the Postgres facade.\n *\n * - No-emit: pass a TypeScript-authored contract. Example: `mongo({ contract, url })`\n * - Emitted: pass `Contract` type explicitly. Example: `mongo<Contract>({ contractJson, url })`\n */\nexport default function mongo<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n>(options: MongoOptionsWithContract<TContract>): MongoClient<TContract>;\nexport default function mongo<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n>(options: MongoOptionsWithContractJson<TContract>): MongoClient<TContract>;\nexport default function mongo<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n>(options: MongoOptions<TContract>): MongoClient<TContract> {\n const contract = resolveContract(options);\n let binding = resolveOptionalMongoBinding(options);\n\n // `mongoQuery` calls its parameter `contractJson`, but accepts the validated\n // contract value here (it normalises both internally).\n const query = mongoQuery<TContract>({ contractJson: contract });\n\n // Single source of truth for the lifecycle. `runtimePromise` is the in-flight\n // or settled build; `closed` is the terminal state set by `close()`. A failed\n // build resets `runtimePromise` so a retry is possible (see test).\n let runtimePromise: Promise<MongoRuntime> | undefined;\n let closed = false;\n\n const buildRuntime = async (resolvedBinding: MongoBinding): Promise<MongoRuntime> => {\n const stack = createMongoExecutionStack({\n target: mongoRuntimeTarget,\n adapter: mongoRuntimeAdapter,\n });\n const context = createMongoExecutionContext({ contract, stack });\n const driver =\n resolvedBinding.kind === 'url'\n ? await MongoDriverImpl.fromConnection(resolvedBinding.url, resolvedBinding.dbName)\n : MongoDriverImpl.fromDb(resolvedBinding.client.db(resolvedBinding.dbName));\n return createMongoRuntime({\n context,\n driver,\n ...(options.mode !== undefined ? { mode: options.mode } : {}),\n ...ifDefined('middleware', options.middleware),\n });\n };\n\n const getRuntime = (): Promise<MongoRuntime> => {\n if (closed) {\n return Promise.reject(new Error('Mongo client is closed'));\n }\n if (runtimePromise !== undefined) {\n return runtimePromise;\n }\n if (binding === undefined) {\n return Promise.reject(\n new Error(\n 'Mongo binding not configured. Pass url/uri+dbName/mongoClient+dbName/binding to mongo(...) or call db.connect({ ... }).',\n ),\n );\n }\n runtimePromise = buildRuntime(binding).catch((err) => {\n // Reset so a later connect()/runtime() can retry rather than always\n // re-throwing the cached failure.\n runtimePromise = undefined;\n throw err;\n });\n return runtimePromise;\n };\n\n const orm = mongoOrm<TContract>({\n contract,\n executor: {\n execute<Row>(plan: MongoQueryPlan<Row>) {\n async function* iterate(): AsyncGenerator<Row, void, unknown> {\n const runtime = await getRuntime();\n yield* runtime.execute(plan);\n }\n return new AsyncIterableResult(iterate());\n },\n },\n });\n\n return {\n orm,\n query,\n contract,\n\n async connect(bindingInput?: MongoBindingInput): Promise<MongoRuntime> {\n if (closed) {\n throw new Error('Mongo client is closed');\n }\n if (runtimePromise !== undefined) {\n throw new Error('Mongo client already connected');\n }\n if (bindingInput !== undefined) {\n binding = resolveMongoBinding(bindingInput);\n }\n if (binding === undefined) {\n throw new Error(\n 'Mongo binding not configured. Pass url/uri+dbName/mongoClient+dbName/binding to mongo(...) or call db.connect({ ... }).',\n );\n }\n return getRuntime();\n },\n\n runtime(): Promise<MongoRuntime> {\n return getRuntime();\n },\n\n async close(): Promise<void> {\n if (closed) return;\n closed = true;\n if (runtimePromise === undefined) return;\n // Await whatever the build resolved to. Swallow build failures because\n // the user's intent is \"release any resources we acquired\" — there is\n // nothing to close if the build never produced a runtime.\n try {\n const runtime = await runtimePromise;\n await runtime.close();\n } catch {\n // build failed; nothing to close.\n }\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"runtime.mjs","names":[],"sources":["../src/runtime/binding.ts","../src/runtime/mongo.ts"],"sourcesContent":["import type { MongoClient as MongoDriverClient } from 'mongodb';\n\nexport type MongoBinding =\n | { readonly kind: 'url'; readonly url: string; readonly dbName: string }\n | {\n readonly kind: 'mongoClient';\n readonly client: MongoDriverClient;\n readonly dbName: string;\n };\n\nexport type MongoBindingInput =\n | {\n readonly binding: MongoBinding;\n readonly url?: never;\n readonly uri?: never;\n readonly dbName?: never;\n readonly mongoClient?: never;\n }\n | {\n readonly url: string;\n readonly dbName?: string;\n readonly binding?: never;\n readonly uri?: never;\n readonly mongoClient?: never;\n }\n | {\n readonly uri: string;\n readonly dbName: string;\n readonly binding?: never;\n readonly url?: never;\n readonly mongoClient?: never;\n }\n | {\n readonly mongoClient: MongoDriverClient;\n readonly dbName: string;\n readonly binding?: never;\n readonly url?: never;\n readonly uri?: never;\n };\n\ntype MongoBindingFields = {\n readonly binding?: MongoBinding;\n readonly url?: string;\n readonly uri?: string;\n readonly dbName?: string;\n readonly mongoClient?: MongoDriverClient;\n};\n\nfunction validateMongoUrl(url: string): URL {\n const trimmed = url.trim();\n if (trimmed.length === 0) {\n throw new Error('Mongo URL must be a non-empty string');\n }\n\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new Error('Mongo URL must be a valid URL');\n }\n\n if (parsed.protocol !== 'mongodb:' && parsed.protocol !== 'mongodb+srv:') {\n throw new Error('Mongo URL must use mongodb:// or mongodb+srv://');\n }\n\n return parsed;\n}\n\nfunction extractDbNameFromUrl(parsed: URL): string | undefined {\n // pathname is \"/dbname\" or \"\" — strip the leading slash. Anything past\n // a second slash is invalid for our purposes (auth-source style paths).\n const path = parsed.pathname.startsWith('/') ? parsed.pathname.slice(1) : parsed.pathname;\n if (path.length === 0) {\n return undefined;\n }\n const slash = path.indexOf('/');\n return slash === -1 ? path : path.slice(0, slash);\n}\n\nexport function resolveMongoBinding(options: MongoBindingInput): MongoBinding {\n const providedCount =\n Number(options.binding !== undefined) +\n Number(options.url !== undefined) +\n Number(options.uri !== undefined) +\n Number(options.mongoClient !== undefined);\n\n if (providedCount !== 1) {\n throw new Error('Provide one binding input: binding, url, uri+dbName, or mongoClient+dbName');\n }\n\n if (options.binding !== undefined) {\n return options.binding;\n }\n\n if (options.url !== undefined) {\n const parsed = validateMongoUrl(options.url);\n // An explicit, whitespace-only `dbName` is a user-error we'd rather\n // surface loudly: silently falling back to the URL path would mask\n // a typo or empty-template-string bug. Treat it the same as the\n // `{ uri, dbName }` and `{ mongoClient, dbName }` paths, where an\n // empty trimmed dbName is already a fast failure.\n if (options.dbName !== undefined && options.dbName.trim().length === 0) {\n throw new Error('Mongo binding via { url, dbName } requires a non-empty dbName');\n }\n const explicitDbName = options.dbName?.trim();\n const dbName =\n explicitDbName !== undefined && explicitDbName.length > 0\n ? explicitDbName\n : extractDbNameFromUrl(parsed);\n if (dbName === undefined || dbName.length === 0) {\n throw new Error(\n 'Mongo URL must include a database name in its path (e.g. mongodb://host:27017/mydb), or pass dbName explicitly',\n );\n }\n return { kind: 'url', url: options.url.trim(), dbName };\n }\n\n if (options.uri !== undefined) {\n validateMongoUrl(options.uri);\n const dbName = options.dbName?.trim();\n if (dbName === undefined || dbName.length === 0) {\n throw new Error('Mongo binding via { uri, dbName } requires a non-empty dbName');\n }\n return { kind: 'url', url: options.uri.trim(), dbName };\n }\n\n const mongoClient = options.mongoClient;\n if (mongoClient === undefined) {\n throw new Error('Invariant violation: expected mongo binding after validation');\n }\n const dbName = options.dbName?.trim();\n if (dbName === undefined || dbName.length === 0) {\n throw new Error('Mongo binding via { mongoClient, dbName } requires a non-empty dbName');\n }\n return { kind: 'mongoClient', client: mongoClient, dbName };\n}\n\nexport function resolveOptionalMongoBinding(options: MongoBindingFields): MongoBinding | undefined {\n const providedCount =\n Number(options.binding !== undefined) +\n Number(options.url !== undefined) +\n Number(options.uri !== undefined) +\n Number(options.mongoClient !== undefined);\n\n if (providedCount === 0) {\n return undefined;\n }\n // Defer the \"exactly one\" enforcement to `resolveMongoBinding`. We call it\n // through a single branch per input field so the matching union member of\n // `MongoBindingInput` is constructed explicitly — the previous\n // `options as MongoBindingInput` cast hid drift between `MongoBindingFields`\n // (any combination of optional inputs) and `MongoBindingInput` (exactly one).\n if (providedCount !== 1) {\n throw new Error('Provide one binding input: binding, url, uri+dbName, or mongoClient+dbName');\n }\n if (options.binding !== undefined) {\n return resolveMongoBinding({ binding: options.binding });\n }\n if (options.url !== undefined) {\n return resolveMongoBinding(\n options.dbName !== undefined\n ? { url: options.url, dbName: options.dbName }\n : { url: options.url },\n );\n }\n if (options.uri !== undefined) {\n return resolveMongoBinding({ uri: options.uri, dbName: options.dbName ?? '' });\n }\n if (options.mongoClient !== undefined) {\n return resolveMongoBinding({\n mongoClient: options.mongoClient,\n dbName: options.dbName ?? '',\n });\n }\n // Unreachable: the `providedCount === 1` guard above plus the four\n // branch checks cover every shape of `MongoBindingFields`. A bare\n // `return undefined` here would silently mask a future\n // `MongoBindingFields` extension that adds a fifth input, so we\n // surface it as an invariant rather than a missing binding.\n throw new Error('Invariant violation: expected one mongo binding branch');\n}\n","import mongoRuntimeAdapter from '@prisma-next/adapter-mongo/runtime';\nimport { MongoDriverImpl } from '@prisma-next/driver-mongo';\nimport { MongoContractSerializer } from '@prisma-next/family-mongo/ir';\nimport { AsyncIterableResult } from '@prisma-next/framework-components/runtime';\nimport type {\n MongoContract,\n MongoContractWithTypeMaps,\n MongoTypeMaps,\n} from '@prisma-next/mongo-contract';\nimport type { MongoOrmClient, MongoQueryPlan } from '@prisma-next/mongo-orm';\nimport { mongoOrm } from '@prisma-next/mongo-orm';\nimport { mongoQuery } from '@prisma-next/mongo-query-builder';\nimport type { MongoMiddleware, MongoRuntime } from '@prisma-next/mongo-runtime';\nimport {\n createMongoExecutionContext,\n createMongoExecutionStack,\n createMongoRuntime,\n} from '@prisma-next/mongo-runtime';\nimport mongoRuntimeTarget from '@prisma-next/target-mongo/runtime';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport {\n type MongoBinding,\n type MongoBindingInput,\n resolveMongoBinding,\n resolveOptionalMongoBinding,\n} from './binding';\n\nexport type MongoTargetId = 'mongo';\n\nexport interface MongoClient<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n> {\n readonly orm: MongoOrmClient<TContract>;\n readonly query: ReturnType<typeof mongoQuery<TContract>>;\n readonly contract: TContract;\n connect(bindingInput?: MongoBindingInput): Promise<MongoRuntime>;\n runtime(): Promise<MongoRuntime>;\n close(): Promise<void>;\n [Symbol.asyncDispose](): Promise<void>;\n}\n\nexport interface MongoOptionsBase {\n readonly mode?: 'strict' | 'permissive';\n /**\n * Optional middleware chain applied to every Mongo execution.\n */\n readonly middleware?: readonly MongoMiddleware[];\n}\n\nexport interface MongoBindingOptions {\n readonly binding?: MongoBinding;\n readonly url?: string;\n readonly uri?: string;\n readonly dbName?: string;\n readonly mongoClient?: import('mongodb').MongoClient;\n}\n\nexport type MongoOptionsWithContract<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n> = MongoBindingOptions &\n MongoOptionsBase & {\n readonly contract: TContract;\n readonly contractJson?: never;\n };\n\n/**\n * `TContract` is a phantom parameter that drives explicit-type inference at the\n * call site (e.g. `mongo<Contract>({ contractJson })`). It is not referenced in\n * the type body — the contract value comes through `contractJson` at runtime.\n */\nexport type MongoOptionsWithContractJson<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n> = MongoBindingOptions &\n MongoOptionsBase & {\n readonly contractJson: unknown;\n readonly contract?: never;\n /**\n * @internal phantom field; never set at runtime, only references TContract\n * so that strict tsc/biome don't flag the type parameter as unused.\n */\n readonly __contractPhantom?: TContract;\n };\n\nexport type MongoOptions<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n> = MongoOptionsWithContract<TContract> | MongoOptionsWithContractJson<TContract>;\n\nfunction hasContractJson<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>>(\n options: MongoOptions<TContract>,\n): options is MongoOptionsWithContractJson<TContract> {\n return 'contractJson' in options;\n}\n\nfunction resolveContract<TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>>(\n options: MongoOptions<TContract>,\n): TContract {\n const contractInput = hasContractJson(options) ? options.contractJson : options.contract;\n return new MongoContractSerializer().deserializeContract(contractInput) as TContract;\n}\n\n/**\n * Creates a lazy Mongo client from either `contractJson` or a TypeScript-authored `contract`.\n * The `orm` and `query` surfaces are available immediately; the underlying driver is connected\n * on the first query (or the first explicit `connect()` call), mirroring the Postgres facade.\n *\n * - No-emit: pass a TypeScript-authored contract. Example: `mongo({ contract, url })`\n * - Emitted: pass `Contract` type explicitly. Example: `mongo<Contract>({ contractJson, url })`\n */\nexport default function mongo<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n>(options: MongoOptionsWithContract<TContract>): MongoClient<TContract>;\nexport default function mongo<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n>(options: MongoOptionsWithContractJson<TContract>): MongoClient<TContract>;\nexport default function mongo<\n TContract extends MongoContractWithTypeMaps<MongoContract, MongoTypeMaps>,\n>(options: MongoOptions<TContract>): MongoClient<TContract> {\n const contract = resolveContract(options);\n let binding = resolveOptionalMongoBinding(options);\n\n // `mongoQuery` calls its parameter `contractJson`, but accepts the validated\n // contract value here (it normalises both internally).\n const query = mongoQuery<TContract>({ contractJson: contract });\n\n // Single source of truth for the lifecycle. `runtimePromise` is the in-flight\n // or settled build; `closed` is the terminal state set by `close()`. A failed\n // build resets `runtimePromise` so a retry is possible (see test).\n let runtimePromise: Promise<MongoRuntime> | undefined;\n let closed = false;\n let ownedDispose: (() => Promise<void>) | undefined;\n\n const buildRuntime = async (resolvedBinding: MongoBinding): Promise<MongoRuntime> => {\n const stack = createMongoExecutionStack({\n target: mongoRuntimeTarget,\n adapter: mongoRuntimeAdapter,\n });\n const context = createMongoExecutionContext({ contract, stack });\n const driver =\n resolvedBinding.kind === 'url'\n ? await MongoDriverImpl.fromConnection(resolvedBinding.url, resolvedBinding.dbName)\n : MongoDriverImpl.fromDb(resolvedBinding.client.db(resolvedBinding.dbName));\n if (resolvedBinding.kind === 'url') {\n ownedDispose = () => driver.close();\n }\n return createMongoRuntime({\n context,\n driver,\n ...(options.mode !== undefined ? { mode: options.mode } : {}),\n ...ifDefined('middleware', options.middleware),\n });\n };\n\n const getRuntime = (): Promise<MongoRuntime> => {\n if (closed) {\n return Promise.reject(new Error('Mongo client is closed'));\n }\n if (runtimePromise !== undefined) {\n return runtimePromise;\n }\n if (binding === undefined) {\n return Promise.reject(\n new Error(\n 'Mongo binding not configured. Pass url/uri+dbName/mongoClient+dbName/binding to mongo(...) or call db.connect({ ... }).',\n ),\n );\n }\n runtimePromise = buildRuntime(binding).catch((err) => {\n // Reset so a later connect()/runtime() can retry rather than always\n // re-throwing the cached failure.\n runtimePromise = undefined;\n throw err;\n });\n return runtimePromise;\n };\n\n const orm = mongoOrm<TContract>({\n contract,\n executor: {\n execute<Row>(plan: MongoQueryPlan<Row>) {\n async function* iterate(): AsyncGenerator<Row, void, unknown> {\n const runtime = await getRuntime();\n yield* runtime.execute(plan);\n }\n return new AsyncIterableResult(iterate());\n },\n },\n });\n\n return {\n orm,\n query,\n contract,\n\n async connect(bindingInput?: MongoBindingInput): Promise<MongoRuntime> {\n if (closed) {\n throw new Error('Mongo client is closed');\n }\n if (runtimePromise !== undefined) {\n throw new Error('Mongo client already connected');\n }\n if (bindingInput !== undefined) {\n binding = resolveMongoBinding(bindingInput);\n }\n if (binding === undefined) {\n throw new Error(\n 'Mongo binding not configured. Pass url/uri+dbName/mongoClient+dbName/binding to mongo(...) or call db.connect({ ... }).',\n );\n }\n return getRuntime();\n },\n\n runtime(): Promise<MongoRuntime> {\n return getRuntime();\n },\n\n async close(): Promise<void> {\n if (closed) return;\n closed = true;\n if (runtimePromise === undefined) return;\n // Await whatever the build resolved to. Swallow build failures because\n // the user's intent is \"release any resources we acquired\" — there is\n // nothing to close if the build never produced a runtime.\n try {\n await runtimePromise;\n } catch {\n // build failed; still attempt disposing any already-acquired owned driver.\n }\n const dispose = ownedDispose;\n ownedDispose = undefined;\n await dispose?.();\n },\n\n [Symbol.asyncDispose](): Promise<void> {\n return this.close();\n },\n };\n}\n"],"mappings":";;;;;;;;;;AAgDA,SAAS,iBAAiB,KAAkB;CAC1C,MAAM,UAAU,IAAI,MAAM;CAC1B,IAAI,QAAQ,WAAW,GACrB,MAAM,IAAI,MAAM,uCAAuC;CAGzD,IAAI;CACJ,IAAI;EACF,SAAS,IAAI,IAAI,QAAQ;SACnB;EACN,MAAM,IAAI,MAAM,gCAAgC;;CAGlD,IAAI,OAAO,aAAa,cAAc,OAAO,aAAa,gBACxD,MAAM,IAAI,MAAM,kDAAkD;CAGpE,OAAO;;AAGT,SAAS,qBAAqB,QAAiC;CAG7D,MAAM,OAAO,OAAO,SAAS,WAAW,IAAI,GAAG,OAAO,SAAS,MAAM,EAAE,GAAG,OAAO;CACjF,IAAI,KAAK,WAAW,GAClB;CAEF,MAAM,QAAQ,KAAK,QAAQ,IAAI;CAC/B,OAAO,UAAU,KAAK,OAAO,KAAK,MAAM,GAAG,MAAM;;AAGnD,SAAgB,oBAAoB,SAA0C;CAO5E,IALE,OAAO,QAAQ,YAAY,KAAA,EAAU,GACrC,OAAO,QAAQ,QAAQ,KAAA,EAAU,GACjC,OAAO,QAAQ,QAAQ,KAAA,EAAU,GACjC,OAAO,QAAQ,gBAAgB,KAAA,EAAU,KAErB,GACpB,MAAM,IAAI,MAAM,6EAA6E;CAG/F,IAAI,QAAQ,YAAY,KAAA,GACtB,OAAO,QAAQ;CAGjB,IAAI,QAAQ,QAAQ,KAAA,GAAW;EAC7B,MAAM,SAAS,iBAAiB,QAAQ,IAAI;EAM5C,IAAI,QAAQ,WAAW,KAAA,KAAa,QAAQ,OAAO,MAAM,CAAC,WAAW,GACnE,MAAM,IAAI,MAAM,gEAAgE;EAElF,MAAM,iBAAiB,QAAQ,QAAQ,MAAM;EAC7C,MAAM,SACJ,mBAAmB,KAAA,KAAa,eAAe,SAAS,IACpD,iBACA,qBAAqB,OAAO;EAClC,IAAI,WAAW,KAAA,KAAa,OAAO,WAAW,GAC5C,MAAM,IAAI,MACR,iHACD;EAEH,OAAO;GAAE,MAAM;GAAO,KAAK,QAAQ,IAAI,MAAM;GAAE;GAAQ;;CAGzD,IAAI,QAAQ,QAAQ,KAAA,GAAW;EAC7B,iBAAiB,QAAQ,IAAI;EAC7B,MAAM,SAAS,QAAQ,QAAQ,MAAM;EACrC,IAAI,WAAW,KAAA,KAAa,OAAO,WAAW,GAC5C,MAAM,IAAI,MAAM,gEAAgE;EAElF,OAAO;GAAE,MAAM;GAAO,KAAK,QAAQ,IAAI,MAAM;GAAE;GAAQ;;CAGzD,MAAM,cAAc,QAAQ;CAC5B,IAAI,gBAAgB,KAAA,GAClB,MAAM,IAAI,MAAM,+DAA+D;CAEjF,MAAM,SAAS,QAAQ,QAAQ,MAAM;CACrC,IAAI,WAAW,KAAA,KAAa,OAAO,WAAW,GAC5C,MAAM,IAAI,MAAM,wEAAwE;CAE1F,OAAO;EAAE,MAAM;EAAe,QAAQ;EAAa;EAAQ;;AAG7D,SAAgB,4BAA4B,SAAuD;CACjG,MAAM,gBACJ,OAAO,QAAQ,YAAY,KAAA,EAAU,GACrC,OAAO,QAAQ,QAAQ,KAAA,EAAU,GACjC,OAAO,QAAQ,QAAQ,KAAA,EAAU,GACjC,OAAO,QAAQ,gBAAgB,KAAA,EAAU;CAE3C,IAAI,kBAAkB,GACpB;CAOF,IAAI,kBAAkB,GACpB,MAAM,IAAI,MAAM,6EAA6E;CAE/F,IAAI,QAAQ,YAAY,KAAA,GACtB,OAAO,oBAAoB,EAAE,SAAS,QAAQ,SAAS,CAAC;CAE1D,IAAI,QAAQ,QAAQ,KAAA,GAClB,OAAO,oBACL,QAAQ,WAAW,KAAA,IACf;EAAE,KAAK,QAAQ;EAAK,QAAQ,QAAQ;EAAQ,GAC5C,EAAE,KAAK,QAAQ,KAAK,CACzB;CAEH,IAAI,QAAQ,QAAQ,KAAA,GAClB,OAAO,oBAAoB;EAAE,KAAK,QAAQ;EAAK,QAAQ,QAAQ,UAAU;EAAI,CAAC;CAEhF,IAAI,QAAQ,gBAAgB,KAAA,GAC1B,OAAO,oBAAoB;EACzB,aAAa,QAAQ;EACrB,QAAQ,QAAQ,UAAU;EAC3B,CAAC;CAOJ,MAAM,IAAI,MAAM,yDAAyD;;;;AC5F3E,SAAS,gBACP,SACoD;CACpD,OAAO,kBAAkB;;AAG3B,SAAS,gBACP,SACW;CACX,MAAM,gBAAgB,gBAAgB,QAAQ,GAAG,QAAQ,eAAe,QAAQ;CAChF,OAAO,IAAI,yBAAyB,CAAC,oBAAoB,cAAc;;AAiBzE,SAAwB,MAEtB,SAA0D;CAC1D,MAAM,WAAW,gBAAgB,QAAQ;CACzC,IAAI,UAAU,4BAA4B,QAAQ;CAIlD,MAAM,QAAQ,WAAsB,EAAE,cAAc,UAAU,CAAC;CAK/D,IAAI;CACJ,IAAI,SAAS;CACb,IAAI;CAEJ,MAAM,eAAe,OAAO,oBAAyD;EAKnF,MAAM,UAAU,4BAA4B;GAAE;GAAU,OAJ1C,0BAA0B;IACtC,QAAQ;IACR,SAAS;IACV,CAC4D;GAAE,CAAC;EAChE,MAAM,SACJ,gBAAgB,SAAS,QACrB,MAAM,gBAAgB,eAAe,gBAAgB,KAAK,gBAAgB,OAAO,GACjF,gBAAgB,OAAO,gBAAgB,OAAO,GAAG,gBAAgB,OAAO,CAAC;EAC/E,IAAI,gBAAgB,SAAS,OAC3B,qBAAqB,OAAO,OAAO;EAErC,OAAO,mBAAmB;GACxB;GACA;GACA,GAAI,QAAQ,SAAS,KAAA,IAAY,EAAE,MAAM,QAAQ,MAAM,GAAG,EAAE;GAC5D,GAAG,UAAU,cAAc,QAAQ,WAAW;GAC/C,CAAC;;CAGJ,MAAM,mBAA0C;EAC9C,IAAI,QACF,OAAO,QAAQ,uBAAO,IAAI,MAAM,yBAAyB,CAAC;EAE5D,IAAI,mBAAmB,KAAA,GACrB,OAAO;EAET,IAAI,YAAY,KAAA,GACd,OAAO,QAAQ,uBACb,IAAI,MACF,0HACD,CACF;EAEH,iBAAiB,aAAa,QAAQ,CAAC,OAAO,QAAQ;GAGpD,iBAAiB,KAAA;GACjB,MAAM;IACN;EACF,OAAO;;CAgBT,OAAO;EACL,KAdU,SAAoB;GAC9B;GACA,UAAU,EACR,QAAa,MAA2B;IACtC,gBAAgB,UAA8C;KAE5D,QAAO,MADe,YAAY,EACnB,QAAQ,KAAK;;IAE9B,OAAO,IAAI,oBAAoB,SAAS,CAAC;MAE5C;GACF,CAGI;EACH;EACA;EAEA,MAAM,QAAQ,cAAyD;GACrE,IAAI,QACF,MAAM,IAAI,MAAM,yBAAyB;GAE3C,IAAI,mBAAmB,KAAA,GACrB,MAAM,IAAI,MAAM,iCAAiC;GAEnD,IAAI,iBAAiB,KAAA,GACnB,UAAU,oBAAoB,aAAa;GAE7C,IAAI,YAAY,KAAA,GACd,MAAM,IAAI,MACR,0HACD;GAEH,OAAO,YAAY;;EAGrB,UAAiC;GAC/B,OAAO,YAAY;;EAGrB,MAAM,QAAuB;GAC3B,IAAI,QAAQ;GACZ,SAAS;GACT,IAAI,mBAAmB,KAAA,GAAW;GAIlC,IAAI;IACF,MAAM;WACA;GAGR,MAAM,UAAU;GAChB,eAAe,KAAA;GACf,MAAM,WAAW;;EAGnB,CAAC,OAAO,gBAA+B;GACrC,OAAO,KAAK,OAAO;;EAEtB"}
package/package.json CHANGED
@@ -1,32 +1,33 @@
1
1
  {
2
2
  "name": "@prisma-next/mongo",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "license": "Apache-2.0",
5
5
  "type": "module",
6
6
  "sideEffects": false,
7
7
  "description": "One-package Mongo setup for Prisma Next",
8
8
  "dependencies": {
9
- "@prisma-next/adapter-mongo": "0.10.0",
10
- "@prisma-next/config": "0.10.0",
11
- "@prisma-next/contract": "0.10.0",
12
- "@prisma-next/driver-mongo": "0.10.0",
13
- "@prisma-next/family-mongo": "0.10.0",
14
- "@prisma-next/framework-components": "0.10.0",
15
- "@prisma-next/mongo-contract": "0.10.0",
16
- "@prisma-next/mongo-contract-psl": "0.10.0",
17
- "@prisma-next/mongo-contract-ts": "0.10.0",
18
- "@prisma-next/mongo-orm": "0.10.0",
19
- "@prisma-next/mongo-query-builder": "0.10.0",
20
- "@prisma-next/mongo-runtime": "0.10.0",
21
- "@prisma-next/target-mongo": "0.10.0",
22
- "@prisma-next/utils": "0.10.0",
9
+ "@prisma-next/adapter-mongo": "0.11.0",
10
+ "@prisma-next/cli": "0.11.0",
11
+ "@prisma-next/config": "0.11.0",
12
+ "@prisma-next/contract": "0.11.0",
13
+ "@prisma-next/driver-mongo": "0.11.0",
14
+ "@prisma-next/family-mongo": "0.11.0",
15
+ "@prisma-next/framework-components": "0.11.0",
16
+ "@prisma-next/mongo-contract": "0.11.0",
17
+ "@prisma-next/mongo-contract-psl": "0.11.0",
18
+ "@prisma-next/mongo-contract-ts": "0.11.0",
19
+ "@prisma-next/mongo-orm": "0.11.0",
20
+ "@prisma-next/mongo-query-builder": "0.11.0",
21
+ "@prisma-next/mongo-runtime": "0.11.0",
22
+ "@prisma-next/target-mongo": "0.11.0",
23
+ "@prisma-next/utils": "0.11.0",
23
24
  "mongodb": "^6.16.0",
24
25
  "pathe": "^2.0.3"
25
26
  },
26
27
  "devDependencies": {
27
- "@prisma-next/test-utils": "0.10.0",
28
- "@prisma-next/tsconfig": "0.10.0",
29
- "@prisma-next/tsdown": "0.10.0",
28
+ "@prisma-next/test-utils": "0.11.0",
29
+ "@prisma-next/tsconfig": "0.11.0",
30
+ "@prisma-next/tsdown": "0.11.0",
30
31
  "mongodb-memory-server": "11.1.0",
31
32
  "tsdown": "0.22.0",
32
33
  "typescript": "5.9.3",
@@ -45,9 +46,10 @@
45
46
  "node": ">=20"
46
47
  },
47
48
  "exports": {
48
- ".": "./dist/index.mjs",
49
+ "./bson": "./dist/bson.mjs",
49
50
  "./config": "./dist/config.mjs",
50
51
  "./contract-builder": "./dist/contract-builder.mjs",
52
+ "./control": "./dist/control.mjs",
51
53
  "./family": "./dist/family.mjs",
52
54
  "./runtime": "./dist/runtime.mjs",
53
55
  "./target": "./dist/target.mjs",
@@ -3,9 +3,11 @@ import type { PrismaNextConfig } from '@prisma-next/config/config-types';
3
3
  import { defineConfig as coreDefineConfig } from '@prisma-next/config/config-types';
4
4
  import mongoDriver from '@prisma-next/driver-mongo/control';
5
5
  import { mongoFamilyDescriptor } from '@prisma-next/family-mongo/control';
6
+ import type { ControlExtensionDescriptor } from '@prisma-next/framework-components/control';
6
7
  import { mongoContract } from '@prisma-next/mongo-contract-psl/provider';
7
8
  import { typescriptContractFromPath } from '@prisma-next/mongo-contract-ts/config-types';
8
9
  import { mongoTargetDescriptor } from '@prisma-next/target-mongo/control';
10
+ import { ifDefined } from '@prisma-next/utils/defined';
9
11
  import { extname } from 'pathe';
10
12
 
11
13
  export interface MongoConfigOptions {
@@ -13,6 +15,10 @@ export interface MongoConfigOptions {
13
15
  readonly db?: {
14
16
  readonly connection?: string;
15
17
  };
18
+ readonly extensions?: readonly ControlExtensionDescriptor<'mongo', 'mongo'>[];
19
+ readonly migrations?: {
20
+ readonly dir?: string;
21
+ };
16
22
  }
17
23
 
18
24
  function deriveOutputPath(contractPath: string): string {
@@ -24,6 +30,7 @@ function deriveOutputPath(contractPath: string): string {
24
30
  }
25
31
 
26
32
  export function defineConfig(options: MongoConfigOptions): PrismaNextConfig<'mongo', 'mongo'> {
33
+ const extensions = options.extensions ?? [];
27
34
  const output = deriveOutputPath(options.contract);
28
35
  const ext = extname(options.contract);
29
36
 
@@ -37,7 +44,9 @@ export function defineConfig(options: MongoConfigOptions): PrismaNextConfig<'mon
37
44
  target: mongoTargetDescriptor,
38
45
  adapter: mongoAdapter,
39
46
  driver: mongoDriver,
47
+ extensionPacks: extensions,
40
48
  contract: contractConfig,
41
- ...(options.db !== undefined ? { db: options.db } : {}),
49
+ ...ifDefined('db', options.db),
50
+ ...ifDefined('migrations', options.migrations),
42
51
  });
43
52
  }
@@ -0,0 +1,99 @@
1
+ import mongoFamilyPack from '@prisma-next/family-mongo/pack';
2
+ import type {
3
+ ContractDefinition,
4
+ ContractFactory,
5
+ ContractScaffold,
6
+ MongoContractResult,
7
+ } from '@prisma-next/mongo-contract-ts/contract-builder';
8
+ import { defineContract as baseDefineContract } from '@prisma-next/mongo-contract-ts/contract-builder';
9
+ import mongoTargetPack from '@prisma-next/target-mongo/pack';
10
+
11
+ type MongoFamilyPack = typeof mongoFamilyPack;
12
+ type MongoTargetPack = typeof mongoTargetPack;
13
+
14
+ // Helpers type derived from the exported ContractFactory rather than the
15
+ // un-exported ContractAuthoringHelpers, so we stay inside the public surface.
16
+ type MongoHelpers = Parameters<
17
+ ContractFactory<
18
+ Record<never, never>,
19
+ Record<never, never>,
20
+ undefined,
21
+ MongoFamilyPack,
22
+ MongoTargetPack,
23
+ undefined
24
+ >
25
+ >[0];
26
+
27
+ // Input types omit family + target AND explicitly forbid them so that
28
+ // `@ts-expect-error` tests can verify the fields are rejected.
29
+ type MongoDefinitionInput = Omit<
30
+ ContractDefinition<MongoFamilyPack, MongoTargetPack>,
31
+ 'family' | 'target'
32
+ > & {
33
+ readonly family?: never;
34
+ readonly target?: never;
35
+ };
36
+
37
+ type MongoScaffoldInput = Omit<
38
+ ContractScaffold<MongoFamilyPack, MongoTargetPack>,
39
+ 'family' | 'target'
40
+ > & {
41
+ readonly family?: never;
42
+ readonly target?: never;
43
+ };
44
+
45
+ // Overload 1: definition form — models / valueObjects inline in the definition object.
46
+ export function defineContract<const Definition extends MongoDefinitionInput>(
47
+ definition: Definition,
48
+ ): MongoContractResult<
49
+ Definition & { readonly family: MongoFamilyPack; readonly target: MongoTargetPack }
50
+ >;
51
+
52
+ // Overload 2: factory form — models / valueObjects provided by a factory function.
53
+ export function defineContract<
54
+ const Definition extends MongoScaffoldInput,
55
+ const Built extends {
56
+ readonly models?: Record<string, unknown>;
57
+ readonly valueObjects?: Record<string, unknown>;
58
+ readonly roots?: Record<string, string>;
59
+ },
60
+ >(
61
+ scaffold: Definition,
62
+ factory: (helpers: MongoHelpers) => Built,
63
+ ): MongoContractResult<
64
+ Definition & Built & { readonly family: MongoFamilyPack; readonly target: MongoTargetPack }
65
+ >;
66
+
67
+ // Implementation — pre-binds family and target before delegating to the base.
68
+ // The `as unknown` cast is safe: every declared overload produces a MongoContractResult
69
+ // and the only difference between the public overload signatures and the impl is
70
+ // that we union both call forms here.
71
+ export function defineContract(
72
+ definition: MongoDefinitionInput,
73
+ factory?: (helpers: MongoHelpers) => {
74
+ readonly models?: Record<string, unknown>;
75
+ readonly valueObjects?: Record<string, unknown>;
76
+ readonly roots?: Record<string, string>;
77
+ },
78
+ ): MongoContractResult<
79
+ MongoDefinitionInput & { readonly family: MongoFamilyPack; readonly target: MongoTargetPack }
80
+ > {
81
+ const full = {
82
+ ...definition,
83
+ family: mongoFamilyPack,
84
+ target: mongoTargetPack,
85
+ } as ContractDefinition<MongoFamilyPack, MongoTargetPack>;
86
+
87
+ if (factory !== undefined) {
88
+ return baseDefineContract(
89
+ full as ContractScaffold<MongoFamilyPack, MongoTargetPack>,
90
+ factory as unknown as Parameters<typeof baseDefineContract>[1],
91
+ ) as unknown as MongoContractResult<
92
+ MongoDefinitionInput & { readonly family: MongoFamilyPack; readonly target: MongoTargetPack }
93
+ >;
94
+ }
95
+
96
+ return baseDefineContract(full) as unknown as MongoContractResult<
97
+ MongoDefinitionInput & { readonly family: MongoFamilyPack; readonly target: MongoTargetPack }
98
+ >;
99
+ }
@@ -0,0 +1 @@
1
+ export { Binary, Decimal128, Long, MongoClient, ObjectId, Timestamp } from 'mongodb';
@@ -10,10 +10,10 @@ export type {
10
10
  ValueObjectBuilder,
11
11
  } from '@prisma-next/mongo-contract-ts/contract-builder';
12
12
  export {
13
- defineContract,
14
13
  field,
15
14
  index,
16
15
  model,
17
16
  rel,
18
17
  valueObject,
19
18
  } from '@prisma-next/mongo-contract-ts/contract-builder';
19
+ export { defineContract } from '../contract/define-contract';
@@ -0,0 +1,29 @@
1
+ import mongoAdapter from '@prisma-next/adapter-mongo/control';
2
+ import {
3
+ type ControlClient,
4
+ type ControlClientOptions,
5
+ createControlClient,
6
+ } from '@prisma-next/cli/control-api';
7
+ import mongoDriver from '@prisma-next/driver-mongo/control';
8
+ import { mongoFamilyDescriptor } from '@prisma-next/family-mongo/control';
9
+ import { mongoTargetDescriptor } from '@prisma-next/target-mongo/control';
10
+ import { ifDefined } from '@prisma-next/utils/defined';
11
+
12
+ export interface MongoControlClientOptions {
13
+ readonly connection?: string;
14
+ readonly extensionPacks?: ControlClientOptions['extensionPacks'];
15
+ }
16
+
17
+ export function createMongoControlClient(options: MongoControlClientOptions = {}): ControlClient {
18
+ const clientOptions: ControlClientOptions = {
19
+ family: mongoFamilyDescriptor,
20
+ target: mongoTargetDescriptor,
21
+ adapter: mongoAdapter,
22
+ driver: mongoDriver,
23
+ ...ifDefined('connection', options.connection),
24
+ ...ifDefined('extensionPacks', options.extensionPacks),
25
+ };
26
+ return createControlClient(clientOptions);
27
+ }
28
+
29
+ export type { ControlClient };
@@ -36,6 +36,7 @@ export interface MongoClient<
36
36
  connect(bindingInput?: MongoBindingInput): Promise<MongoRuntime>;
37
37
  runtime(): Promise<MongoRuntime>;
38
38
  close(): Promise<void>;
39
+ [Symbol.asyncDispose](): Promise<void>;
39
40
  }
40
41
 
41
42
  export interface MongoOptionsBase {
@@ -126,6 +127,7 @@ export default function mongo<
126
127
  // build resets `runtimePromise` so a retry is possible (see test).
127
128
  let runtimePromise: Promise<MongoRuntime> | undefined;
128
129
  let closed = false;
130
+ let ownedDispose: (() => Promise<void>) | undefined;
129
131
 
130
132
  const buildRuntime = async (resolvedBinding: MongoBinding): Promise<MongoRuntime> => {
131
133
  const stack = createMongoExecutionStack({
@@ -137,6 +139,9 @@ export default function mongo<
137
139
  resolvedBinding.kind === 'url'
138
140
  ? await MongoDriverImpl.fromConnection(resolvedBinding.url, resolvedBinding.dbName)
139
141
  : MongoDriverImpl.fromDb(resolvedBinding.client.db(resolvedBinding.dbName));
142
+ if (resolvedBinding.kind === 'url') {
143
+ ownedDispose = () => driver.close();
144
+ }
140
145
  return createMongoRuntime({
141
146
  context,
142
147
  driver,
@@ -216,11 +221,17 @@ export default function mongo<
216
221
  // the user's intent is "release any resources we acquired" — there is
217
222
  // nothing to close if the build never produced a runtime.
218
223
  try {
219
- const runtime = await runtimePromise;
220
- await runtime.close();
224
+ await runtimePromise;
221
225
  } catch {
222
- // build failed; nothing to close.
226
+ // build failed; still attempt disposing any already-acquired owned driver.
223
227
  }
228
+ const dispose = ownedDispose;
229
+ ownedDispose = undefined;
230
+ await dispose?.();
231
+ },
232
+
233
+ [Symbol.asyncDispose](): Promise<void> {
234
+ return this.close();
224
235
  },
225
236
  };
226
237
  }
@@ -1,11 +0,0 @@
1
- /**
2
- * Top-level entry for `@prisma-next/mongo`.
3
- *
4
- * Re-exports the BSON value constructors users reach for when authoring
5
- * seed scripts, fixtures, or relational graphs that need to pre-allocate
6
- * `_id`s before insert (e.g. wiring related rows in a single `createAll`
7
- * call). Routing these through the facade keeps the user's `package.json`
8
- * to a single `@prisma-next/mongo` pin and removes the version-drift risk
9
- * of also declaring `mongodb` directly when the facade already bundles it.
10
- */
11
- export { Binary, Decimal128, Long, MongoClient, ObjectId, Timestamp } from 'mongodb';
File without changes
File without changes