@tulipes/mongoose 0.1.0-rc.1
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/LICENSE +21 -0
- package/README.md +70 -0
- package/dist/database.d.ts +36 -0
- package/dist/database.js +101 -0
- package/dist/database.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/model-store.d.ts +37 -0
- package/dist/model-store.js +38 -0
- package/dist/model-store.js.map +1 -0
- package/dist/provider.d.ts +12 -0
- package/dist/provider.js +33 -0
- package/dist/provider.js.map +1 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TulipesJS contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="https://cdn.jsdelivr.net/npm/@tulipes/core@0.7.1/assets/tulipesjs-logo.png" alt="TulipesJs" width="340">
|
|
4
|
+
|
|
5
|
+
</div>
|
|
6
|
+
|
|
7
|
+
# @tulipes/mongoose
|
|
8
|
+
|
|
9
|
+
The Mongoose **models provider** for [Tulipes](https://www.npmjs.com/package/@tulipes/core)
|
|
10
|
+
apps. It connects, compiles every module's `models/*.model.ts` on the boot's
|
|
11
|
+
own connection, runs `bootstrap/*.bootstrap.ts`, and closes the connection
|
|
12
|
+
under core's shutdown deadline. Core itself no longer installs or imports
|
|
13
|
+
Mongoose; an app without a database declares no provider and never pays for one.
|
|
14
|
+
|
|
15
|
+
Requires Node 24.x, `mongoose@^8` as the app's own dependency (peer — the app's
|
|
16
|
+
schemas and this provider must share one instance) and a core that ships the
|
|
17
|
+
provider contract.
|
|
18
|
+
|
|
19
|
+
## Select it
|
|
20
|
+
|
|
21
|
+
One line in the app's root `package.json`:
|
|
22
|
+
|
|
23
|
+
```jsonc
|
|
24
|
+
{ "tulipes": { "providers": { "models": "@tulipes/mongoose" } } }
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
and `MONGO_URI` declared by the app's sys `core` module (`meta.variables.json`)
|
|
28
|
+
and set. Modules with `models/` or `bootstrap/` directories require the
|
|
29
|
+
provider automatically; a module that only reads models declares
|
|
30
|
+
`"tulipes": { "requires": ["models"] }` in its own manifest. Boot refuses an
|
|
31
|
+
unmet requirement before any module code is imported. Installing this package
|
|
32
|
+
without the declaration selects nothing; a `MONGO_URI` on its own connects
|
|
33
|
+
nothing.
|
|
34
|
+
|
|
35
|
+
## Use it
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
// modules/users/models/user.model.ts
|
|
39
|
+
import { Schema } from "mongoose";
|
|
40
|
+
import type { ModelDef } from "@tulipes/mongoose";
|
|
41
|
+
|
|
42
|
+
const userSchema = new Schema({ email: { type: String, required: true } });
|
|
43
|
+
export default { name: "User", schema: userSchema } satisfies ModelDef;
|
|
44
|
+
|
|
45
|
+
// anywhere after phase 8
|
|
46
|
+
const User = requireModels(ctx).get<UserDoc>("User"); // typed once this package is in the compilation
|
|
47
|
+
ctx.models.connection; // the boot's own mongoose Connection
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`ModelDef`, `BootstrapFn` and `ModelStore` moved here from `@tulipes/core/db`;
|
|
51
|
+
`ctx.models`, `requireModels` and `DatabaseCtx` stay in `@tulipes/core/boot`.
|
|
52
|
+
|
|
53
|
+
## Behavior
|
|
54
|
+
|
|
55
|
+
- One connection per boot, `serverSelectionTimeoutMS: 5000`; ownership is
|
|
56
|
+
registered with core before the connection is awaited, so a database that
|
|
57
|
+
never answers is still closed by the failed-boot cleanup.
|
|
58
|
+
- Models register in module load order; a second module registering the same
|
|
59
|
+
name is a boot error naming both. `def.schema` must be a `Schema` from the
|
|
60
|
+
same `mongoose` instance.
|
|
61
|
+
- Bootstrap tasks run in backend and worker processes, never in `script` mode
|
|
62
|
+
or runtime inspection, and only when registration reported nothing.
|
|
63
|
+
- Global plugins (`mongoose.plugin(...)`) remain application code and apply
|
|
64
|
+
because the app and this provider share the instance.
|
|
65
|
+
|
|
66
|
+
## Versions
|
|
67
|
+
|
|
68
|
+
`0.1.0-rc.1` requires core `^0.10.0-rc.1`, the candidate that introduced the
|
|
69
|
+
provider seam; install both with `@next`. See core's
|
|
70
|
+
[MIGRATING.md](https://github.com/kemora13conf/bp-backend-express/blob/v0.10.0-rc.1/packages/core/MIGRATING.md#0100-rc1--declare-the-models-provider).
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Schema, type Connection } from "mongoose";
|
|
2
|
+
import { type Ctx, type DatabaseCtx } from "@tulipes/core/boot";
|
|
3
|
+
import type { BootReport } from "@tulipes/core/errors";
|
|
4
|
+
import type { ModuleFiles } from "@tulipes/core/modules";
|
|
5
|
+
/**
|
|
6
|
+
* Model files are pure definitions — no factory, no ctx. The loader turns
|
|
7
|
+
* them into live models on the shared connection.
|
|
8
|
+
*/
|
|
9
|
+
export interface ModelDef {
|
|
10
|
+
name: string;
|
|
11
|
+
schema: Schema;
|
|
12
|
+
/** Override mongoose's automatic collection naming when needed. */
|
|
13
|
+
collection?: string;
|
|
14
|
+
}
|
|
15
|
+
/** Default export of `bootstrap/*.bootstrap.ts` — post-DB, pre-server init. */
|
|
16
|
+
export type BootstrapFn = (ctx: DatabaseCtx) => void | Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Boot phase 8, run by the provider below: connect, register every model in
|
|
19
|
+
* load order, then run every bootstrap task in load order (indexes, seed
|
|
20
|
+
* roles, default records).
|
|
21
|
+
*
|
|
22
|
+
* Reached only when the app declared this provider, so a missing connection
|
|
23
|
+
* string is a contradiction the boot must refuse — an app without a database
|
|
24
|
+
* simply declares no provider.
|
|
25
|
+
*/
|
|
26
|
+
export interface InitDatabaseOptions {
|
|
27
|
+
/**
|
|
28
|
+
* Bootstrap tasks seed and ensure indexes for a process about to serve.
|
|
29
|
+
* A one-shot script skips them: they are somebody else's startup work,
|
|
30
|
+
* and running them on every `ls`-style script is wasted writes.
|
|
31
|
+
*/
|
|
32
|
+
runBootstrap?: boolean;
|
|
33
|
+
/** Register ownership before connecting or compiling models can fail. */
|
|
34
|
+
onConnection?: (connection: Connection) => void;
|
|
35
|
+
}
|
|
36
|
+
export declare function initDatabase(explored: readonly ModuleFiles[], ctx: Ctx, report: BootReport, options?: InitDatabaseOptions): Promise<Connection | undefined>;
|
package/dist/database.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { createConnection, Schema } from "mongoose";
|
|
2
|
+
import { importFile } from "@tulipes/core/boot";
|
|
3
|
+
import { ModelStore } from "./model-store.js";
|
|
4
|
+
/** Well-known infra variable, declared by the app's sys core module. */
|
|
5
|
+
const MONGO_URI = "MONGO_URI";
|
|
6
|
+
export async function initDatabase(explored, ctx, report, options = {}) {
|
|
7
|
+
const uri = ctx.Environment.store.has(MONGO_URI)
|
|
8
|
+
? String(ctx.Environment.get(MONGO_URI))
|
|
9
|
+
: undefined;
|
|
10
|
+
if (!uri) {
|
|
11
|
+
report.add({
|
|
12
|
+
scope: "providers",
|
|
13
|
+
message: `provider "mongoose" is selected but "${MONGO_URI}" is not declared/set — declare it in a sys module's meta.variables.json and set it`,
|
|
14
|
+
});
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
let connection;
|
|
18
|
+
try {
|
|
19
|
+
// Fail fast: default server selection waits 30s before reporting an
|
|
20
|
+
// unreachable database — far too long for a boot-time verdict.
|
|
21
|
+
connection = createConnection(uri, {
|
|
22
|
+
serverSelectionTimeoutMS: 5_000,
|
|
23
|
+
});
|
|
24
|
+
options.onConnection?.(connection);
|
|
25
|
+
await connection.asPromise();
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
report.add({
|
|
29
|
+
scope: "boot",
|
|
30
|
+
message: `database connection failed (${MONGO_URI}): ${error.message}`,
|
|
31
|
+
});
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
34
|
+
const store = new ModelStore(connection);
|
|
35
|
+
ctx.models = store;
|
|
36
|
+
await registerModels(explored, connection, store, report);
|
|
37
|
+
// Bootstrap tasks only make sense against a fully-populated model store,
|
|
38
|
+
// and only when nothing above them failed.
|
|
39
|
+
if ((options.runBootstrap ?? true) && report.issues.length === 0) {
|
|
40
|
+
await runBootstrapTasks(explored, ctx, report);
|
|
41
|
+
}
|
|
42
|
+
return connection;
|
|
43
|
+
}
|
|
44
|
+
async function registerModels(explored, connection, store, report) {
|
|
45
|
+
for (const { module, modelFiles } of explored) {
|
|
46
|
+
for (const file of modelFiles) {
|
|
47
|
+
const exported = await importFile(file, "boot", module.name, report);
|
|
48
|
+
if (!exported)
|
|
49
|
+
continue;
|
|
50
|
+
const def = exported.default;
|
|
51
|
+
if (typeof def?.name !== "string" ||
|
|
52
|
+
!(def.schema instanceof Schema)) {
|
|
53
|
+
report.add({
|
|
54
|
+
scope: "boot",
|
|
55
|
+
module: module.name,
|
|
56
|
+
message: `${file} must default-export { name, schema } (a ModelDef)`,
|
|
57
|
+
});
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const owner = store.ownerOf(def.name);
|
|
61
|
+
if (owner) {
|
|
62
|
+
report.add({
|
|
63
|
+
scope: "boot",
|
|
64
|
+
module: module.name,
|
|
65
|
+
message: `model "${def.name}" is already registered by module "${owner}"`,
|
|
66
|
+
});
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const model = connection.model(def.name, def.schema, def.collection);
|
|
70
|
+
store.register_(def.name, model, module.name);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function runBootstrapTasks(explored, ctx, report) {
|
|
75
|
+
for (const { module, bootstrapFiles } of explored) {
|
|
76
|
+
for (const file of bootstrapFiles) {
|
|
77
|
+
const exported = await importFile(file, "boot", module.name, report);
|
|
78
|
+
if (!exported)
|
|
79
|
+
continue;
|
|
80
|
+
if (typeof exported.default !== "function") {
|
|
81
|
+
report.add({
|
|
82
|
+
scope: "boot",
|
|
83
|
+
module: module.name,
|
|
84
|
+
message: `${file} must default-export a bootstrap function (ctx) => void`,
|
|
85
|
+
});
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
await exported.default(ctx);
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
report.add({
|
|
93
|
+
scope: "boot",
|
|
94
|
+
module: module.name,
|
|
95
|
+
message: `bootstrap task ${file} threw: ${error.message}`,
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../src/database.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAmC,MAAM,eAAe,CAAC;AAC9E,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,QAAQ,IAAI,OAAO,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Connection, Model } from "mongoose";
|
|
2
|
+
import type { ModelsCapability } from "@tulipes/core/boot";
|
|
3
|
+
/**
|
|
4
|
+
* What `ctx.models` is once this provider is in the compilation. Core's
|
|
5
|
+
* ModelsCapability is empty; an app that imports anything from this package
|
|
6
|
+
* (its model files do, for ModelDef) sees these members typed.
|
|
7
|
+
*/
|
|
8
|
+
declare module "@tulipes/core/boot" {
|
|
9
|
+
interface ModelsCapability {
|
|
10
|
+
has(name: string): boolean;
|
|
11
|
+
ownerOf(name: string): string | undefined;
|
|
12
|
+
names(): string[];
|
|
13
|
+
get<T = unknown>(name: string): Model<T>;
|
|
14
|
+
/** The boot's own connection, for scripts and tests that need the driver. */
|
|
15
|
+
readonly connection: Connection;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Model registry for one boot, populated from every module's
|
|
20
|
+
* `models/*.model.ts` during phase 8.
|
|
21
|
+
*
|
|
22
|
+
* Same fail-closed read contract as the variable store: asking for a model
|
|
23
|
+
* nobody registered throws at the call site — a typo'd model name must never
|
|
24
|
+
* travel as an undefined into query code.
|
|
25
|
+
*/
|
|
26
|
+
export declare class ModelStore implements ModelsCapability {
|
|
27
|
+
#private;
|
|
28
|
+
readonly connection: Connection;
|
|
29
|
+
constructor(connection: Connection);
|
|
30
|
+
/** @internal Database loader only. */
|
|
31
|
+
register_(name: string, model: Model<never>, owner: string): void;
|
|
32
|
+
has(name: string): boolean;
|
|
33
|
+
ownerOf(name: string): string | undefined;
|
|
34
|
+
names(): string[];
|
|
35
|
+
/** The generic is a caller-side assertion — the store can't verify it. */
|
|
36
|
+
get<T = unknown>(name: string): Model<T>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model registry for one boot, populated from every module's
|
|
3
|
+
* `models/*.model.ts` during phase 8.
|
|
4
|
+
*
|
|
5
|
+
* Same fail-closed read contract as the variable store: asking for a model
|
|
6
|
+
* nobody registered throws at the call site — a typo'd model name must never
|
|
7
|
+
* travel as an undefined into query code.
|
|
8
|
+
*/
|
|
9
|
+
export class ModelStore {
|
|
10
|
+
connection;
|
|
11
|
+
/** name → { model, owning module } */
|
|
12
|
+
#models = new Map();
|
|
13
|
+
constructor(connection) {
|
|
14
|
+
this.connection = connection;
|
|
15
|
+
}
|
|
16
|
+
/** @internal Database loader only. */
|
|
17
|
+
register_(name, model, owner) {
|
|
18
|
+
this.#models.set(name, { model, owner });
|
|
19
|
+
}
|
|
20
|
+
has(name) {
|
|
21
|
+
return this.#models.has(name);
|
|
22
|
+
}
|
|
23
|
+
ownerOf(name) {
|
|
24
|
+
return this.#models.get(name)?.owner;
|
|
25
|
+
}
|
|
26
|
+
names() {
|
|
27
|
+
return [...this.#models.keys()];
|
|
28
|
+
}
|
|
29
|
+
/** The generic is a caller-side assertion — the store can't verify it. */
|
|
30
|
+
get(name) {
|
|
31
|
+
const stored = this.#models.get(name);
|
|
32
|
+
if (!stored) {
|
|
33
|
+
throw new Error(`Model "${name}" was never registered by any module (known: ${this.names().join(", ") || "none"})`);
|
|
34
|
+
}
|
|
35
|
+
return stored.model;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=model-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-store.js","sourceRoot":"","sources":["../src/model-store.ts"],"names":[],"mappings":"AAoBA;;;;;;;GAOG;AACH,MAAM,OAAO,UAAU;IAIA,UAAU;IAH/B,sCAAsC;IAC7B,OAAO,GAAG,IAAI,GAAG,EAAkD,CAAC;IAE7E,YAAqB,UAAsB;0BAAtB,UAAU;IAAe,CAAC;IAE/C,sCAAsC;IACtC,SAAS,CAAC,IAAY,EAAE,KAAmB,EAAE,KAAa;QACxD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,IAAY;QAClB,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,CAAC;IACvC,CAAC;IAED,KAAK;QACH,OAAO,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,0EAA0E;IAC1E,GAAG,CAAc,IAAY;QAC3B,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,UAAU,IAAI,gDAAgD,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,GAAG,CACnG,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,CAAC,KAA4B,CAAC;IAC7C,CAAC;CACF"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Provider } from "@tulipes/core/boot";
|
|
2
|
+
/**
|
|
3
|
+
* The "models" provider an app selects with
|
|
4
|
+
* `"tulipes": { "providers": { "models": "@tulipes/mongoose" } }`.
|
|
5
|
+
*
|
|
6
|
+
* Core owns the phase order, the shutdown deadline and the aggregate boot
|
|
7
|
+
* report; this package owns the connection, model compilation, bootstrap
|
|
8
|
+
* policy and the driver's own close/force-close. `mongoose` is a peer
|
|
9
|
+
* dependency on purpose: the app's schemas and this provider must share one
|
|
10
|
+
* instance, or `instanceof Schema` and the app's global plugins stop applying.
|
|
11
|
+
*/
|
|
12
|
+
export declare const provider: Provider<"models">;
|
package/dist/provider.js
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { initDatabase } from "./database.js";
|
|
2
|
+
/**
|
|
3
|
+
* The "models" provider an app selects with
|
|
4
|
+
* `"tulipes": { "providers": { "models": "@tulipes/mongoose" } }`.
|
|
5
|
+
*
|
|
6
|
+
* Core owns the phase order, the shutdown deadline and the aggregate boot
|
|
7
|
+
* report; this package owns the connection, model compilation, bootstrap
|
|
8
|
+
* policy and the driver's own close/force-close. `mongoose` is a peer
|
|
9
|
+
* dependency on purpose: the app's schemas and this provider must share one
|
|
10
|
+
* instance, or `instanceof Schema` and the app's global plugins stop applying.
|
|
11
|
+
*/
|
|
12
|
+
export const provider = {
|
|
13
|
+
contract: 1,
|
|
14
|
+
capability: "models",
|
|
15
|
+
name: "mongoose",
|
|
16
|
+
async acquire({ ctx, files, runBootstrap }, report, own) {
|
|
17
|
+
const connection = await initDatabase(files, ctx, report, {
|
|
18
|
+
runBootstrap,
|
|
19
|
+
// Registered before the connection is awaited: a database that never
|
|
20
|
+
// answers is still closed by core's failed-boot cleanup.
|
|
21
|
+
onConnection: (connection) => own({
|
|
22
|
+
dispose: () => connection.close(),
|
|
23
|
+
forceDispose: () => connection.destroy(true),
|
|
24
|
+
status: () => ({
|
|
25
|
+
label: `mongodb://${connection.host}:${connection.port}/${connection.name}`,
|
|
26
|
+
ready: connection.readyState === 1,
|
|
27
|
+
}),
|
|
28
|
+
}),
|
|
29
|
+
});
|
|
30
|
+
return connection ? ctx.models : undefined;
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAuB;IAC1C,QAAQ,EAAE,CAAC;IACX,UAAU,EAAE,QAAQ;IACpB,IAAI,EAAE,UAAU;IAChB,KAAK,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,YAAY,EAAE,EAAE,MAAM,EAAE,GAAG;QACrD,MAAM,UAAU,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE;YACxD,YAAY;YACZ,qEAAqE;YACrE,yDAAyD;YACzD,YAAY,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,GAAG,CAAC;gBAChC,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE;gBACjC,YAAY,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC5C,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;oBACb,KAAK,EAAE,aAAa,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,IAAI,IAAI,UAAU,CAAC,IAAI,EAAE;oBAC3E,KAAK,EAAE,UAAU,CAAC,UAAU,KAAK,CAAC;iBACnC,CAAC;aACH,CAAC;SACH,CAAC,CAAC;QACH,OAAO,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC;IAC7C,CAAC;CACF,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tulipes/mongoose",
|
|
3
|
+
"version": "0.1.0-rc.1",
|
|
4
|
+
"description": "Mongoose models provider for Tulipes apps: connection, model registration and bootstrap behind core's models capability",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md",
|
|
12
|
+
"LICENSE"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"typecheck": "tsc --noEmit",
|
|
16
|
+
"build": "node -e \"fs.rmSync('dist',{recursive:true,force:true})\" && tsc -p tsconfig.json",
|
|
17
|
+
"prepack": "yarn build"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"@tulipes/core": "^0.10.0-rc.1",
|
|
27
|
+
"mongoose": "^8"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@tulipes/core": "0.10.0-rc.1",
|
|
31
|
+
"@types/node": "^24.2.0",
|
|
32
|
+
"mongoose": "^8",
|
|
33
|
+
"typescript": "^7.0.2"
|
|
34
|
+
},
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/kemora13conf/bp-backend-express.git",
|
|
38
|
+
"directory": "packages/mongoose"
|
|
39
|
+
},
|
|
40
|
+
"keywords": [
|
|
41
|
+
"tulipes",
|
|
42
|
+
"mongoose",
|
|
43
|
+
"mongodb",
|
|
44
|
+
"express"
|
|
45
|
+
],
|
|
46
|
+
"license": "MIT",
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=24.0.0 <25"
|
|
49
|
+
},
|
|
50
|
+
"homepage": "https://github.com/kemora13conf/bp-backend-express/tree/master/packages/mongoose#readme",
|
|
51
|
+
"bugs": {
|
|
52
|
+
"url": "https://github.com/kemora13conf/bp-backend-express/issues"
|
|
53
|
+
}
|
|
54
|
+
}
|