@seedcord/plugins 0.3.2 → 0.3.3
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/dist/index.cjs +8 -8
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -11
- package/dist/index.d.ts +15 -11
- package/dist/index.mjs +8 -8
- package/dist/index.mjs.map +1 -1
- package/package.json +7 -6
package/dist/index.cjs
CHANGED
|
@@ -33,10 +33,10 @@ function DatabaseService(key) {
|
|
|
33
33
|
}
|
|
34
34
|
__name(DatabaseService, "DatabaseService");
|
|
35
35
|
|
|
36
|
-
// src/mongo/
|
|
37
|
-
var
|
|
36
|
+
// src/mongo/MongoService.ts
|
|
37
|
+
var MongoService = class {
|
|
38
38
|
static {
|
|
39
|
-
__name(this, "
|
|
39
|
+
__name(this, "MongoService");
|
|
40
40
|
}
|
|
41
41
|
db;
|
|
42
42
|
core;
|
|
@@ -63,9 +63,9 @@ var Mongo = class extends seedcord.Plugin {
|
|
|
63
63
|
isInitialised = false;
|
|
64
64
|
uri;
|
|
65
65
|
/**
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
* Map of all loaded services.
|
|
67
|
+
* Keys come from `@DatabaseService('key')`
|
|
68
|
+
*/
|
|
69
69
|
services = {};
|
|
70
70
|
constructor(core, options) {
|
|
71
71
|
super(core), this.core = core, this.options = options;
|
|
@@ -109,7 +109,7 @@ var Mongo = class extends seedcord.Plugin {
|
|
|
109
109
|
this.logger.info(`${chalk__default.default.bold.green("Loaded")}: ${chalk__default.default.magenta(Object.keys(this.services).length)} services`);
|
|
110
110
|
}
|
|
111
111
|
isServiceClass(obj) {
|
|
112
|
-
return typeof obj === "function" && obj.prototype instanceof
|
|
112
|
+
return typeof obj === "function" && obj.prototype instanceof MongoService && Reflect.hasMetadata(ServiceMetadataKey, obj);
|
|
113
113
|
}
|
|
114
114
|
_register(key, instance) {
|
|
115
115
|
this.services[key] = instance;
|
|
@@ -136,12 +136,12 @@ function DBCatchable(errorMessage) {
|
|
|
136
136
|
}
|
|
137
137
|
__name(DBCatchable, "DBCatchable");
|
|
138
138
|
|
|
139
|
-
exports.BaseService = BaseService;
|
|
140
139
|
exports.DBCatchable = DBCatchable;
|
|
141
140
|
exports.DatabaseModel = DatabaseModel;
|
|
142
141
|
exports.DatabaseService = DatabaseService;
|
|
143
142
|
exports.ModelMetadataKey = ModelMetadataKey;
|
|
144
143
|
exports.Mongo = Mongo;
|
|
144
|
+
exports.MongoService = MongoService;
|
|
145
145
|
exports.ServiceMetadataKey = ServiceMetadataKey;
|
|
146
146
|
//# sourceMappingURL=index.cjs.map
|
|
147
147
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mongo/decorators/DatabaseModel.ts","../src/mongo/decorators/DatabaseService.ts","../src/mongo/BaseService.ts","../src/mongo/Mongo.ts","../src/mongo/decorators/DBCatchable.ts"],"names":["ModelMetadataKey","Symbol","DatabaseModel","collection","target","propertyKey","schema","name","String","model","mongoose","Reflect","defineMetadata","ServiceMetadataKey","DatabaseService","key","ctor","BaseService","db","core","getMetadata","Error","_register","Mongo","Plugin","logger","Logger","isInitialised","uri","services","options","shutdown","addTask","ShutdownPhase","ExternalResources","stop","init","connect","loadServices","disconnect","dbName","Envapter","isProduction","tls","ssl","then","i","info","chalk","bold","magenta","connection","catch","err","red","error","message","servicesDir","dir","traverseDirectory","_full","rel","mod","Service","Object","values","isServiceClass","instance","italic","yellow","gray","green","keys","length","obj","prototype","hasMetadata","DBCatchable","errorMessage","_target","_propertyKey","descriptor","originalMethod","value","args","apply","CustomError","throwCustomError","DatabaseError"],"mappings":"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","file":"index.cjs","sourcesContent":["import mongoose from 'mongoose';\n\nimport type { ServiceKeys } from '../types/Services';\n\nexport const ModelMetadataKey = Symbol('db:model');\n\n/**\n * Associates a Mongoose model with a database service\n *\n * Creates a Mongoose model from the decorated static schema property and stores it\n * for service registration. The model becomes available as `this.model` in the service.\n * Must be applied to a `public static schema` property in the service class.\n *\n * @param collection - Collection name for the Mongoose model\n * @decorator\n * @example\n * ```typescript\n * \\@DatabaseService('users')\n * export class Users extends BaseService<IUser> {\n * \\@DatabaseModel('users')\n * public static schema = new mongoose.Schema<IUser>({\n * username: { type: String, required: true, unique: true }\n * });\n * }\n * ```\n */\nexport function DatabaseModel<TService extends ServiceKeys>(collection: TService) {\n return <\n SchemaObj extends Record<KeyOfSchema, mongoose.Schema>,\n KeyOfSchema extends keyof SchemaObj & (string | symbol)\n >(\n target: SchemaObj,\n propertyKey: KeyOfSchema\n ): void => {\n const schema = target[propertyKey];\n const name = String(collection);\n const model = mongoose.model(name, schema);\n Reflect.defineMetadata(ModelMetadataKey, model, target);\n };\n}\n","import type { BaseService } from '../BaseService';\nimport type { ServiceKeys } from '../types/Services';\nimport type { ConstructorFunction } from '@seedcord/types';\n\nexport const ServiceMetadataKey = Symbol('db:serviceKey');\n\n/**\n * Registers a database service with a typed key\n *\n * Associates a service class with a key for dependency injection.\n * The service becomes available via `core.db.services[key]`.\n *\n * @param key - Service key for registration and type-safe access\n * @decorator\n * @example\n * ```typescript\n * \\@DatabaseService('users')\n * export class Users<Doc extends IUser = IUser> extends BaseService<Doc> {\n * // Some code\n * }\n * ```\n */\nexport function DatabaseService<TService extends ServiceKeys>(key: TService) {\n return <DatabaseCtor extends ConstructorFunction & { prototype: BaseService }>(ctor: DatabaseCtor): void => {\n Reflect.defineMetadata(ServiceMetadataKey, key, ctor);\n };\n}\n","import { ModelMetadataKey } from './decorators/DatabaseModel';\nimport { ServiceMetadataKey } from './decorators/DatabaseService';\n\nimport type { Mongo } from './Mongo';\nimport type { IDocument } from './types/Document';\nimport type { Services } from './types/Services';\nimport type { TypedConstructor } from '@seedcord/types';\nimport type mongoose from 'mongoose';\nimport type { Core } from 'seedcord';\n\n/**\n * Base class for MongoDB service layers\n *\n * Provides typed access to MongoDB collections through Mongoose models.\n * Services are automatically registered with the Mongo plugin when instantiated.\n *\n * @typeParam Doc - The document type this service manages\n * @example\n * ```typescript\n * \\@DatabaseService('users')\n * export class Users extends BaseService<IUser> {\n * \\@DatabaseModel('users')\n * public static schema = new mongoose.Schema<IUser>({\n * username: { type: String, required: true, unique: true }\n * });\n *\n * // Custom methods here\n * public async findByUsername(username: string) {\n * return this.model.findOne({ username });\n * }\n * }\n * ```\n */\nexport abstract class BaseService<Doc extends IDocument = IDocument> {\n public readonly model: mongoose.Model<Doc>;\n\n public constructor(\n protected readonly db: Mongo,\n protected readonly core: Core\n ) {\n const ctor = this.constructor;\n\n const key = Reflect.getMetadata(ServiceMetadataKey, ctor) as string | undefined;\n if (!key) throw new Error(`Missing @DatabaseService on ${ctor.name}`);\n\n const model = Reflect.getMetadata(ModelMetadataKey, ctor) as mongoose.Model<Doc> | undefined;\n if (!model) throw new Error(`Missing @DatabaseModel on ${ctor.name}`);\n\n this.model = model;\n\n db._register(key as keyof Services, this as unknown as Services[keyof Services]);\n }\n}\n\n/** Constructor type for BaseService classes */\nexport type BaseServiceConstructor = TypedConstructor<typeof BaseService>;\n","import 'reflect-metadata';\n\nimport chalk from 'chalk';\nimport { Envapter } from 'envapt';\nimport mongoose from 'mongoose';\nimport { Logger, Plugin, ShutdownPhase, traverseDirectory } from 'seedcord';\n\nimport { BaseService } from './BaseService';\nimport { ServiceMetadataKey } from './decorators/DatabaseService';\n\nimport type { BaseServiceConstructor } from './BaseService';\nimport type { Services } from './types/Services';\nimport type { Core } from 'seedcord';\n\n/**\n * Configuration options for MongoDB connection and service loading.\n */\ninterface MongoOptions {\n /** Directory path containing database service classes */\n dir: string;\n /** MongoDB connection URI */\n uri: string;\n /** Database name to use */\n name: string;\n}\n\n/**\n * MongoDB integration plugin for Seedcord.\n *\n * Manages MongoDB connections, service loading, and provides type-safe\n * access to database services through service registration decorators.\n */\nexport class Mongo extends Plugin {\n public readonly logger = new Logger('MongoDB');\n private isInitialised = false;\n private readonly uri: string;\n\n /**\n * Map of all loaded services.\n * Keys come from `@DatabaseService('key')`\n */\n public readonly services: Services = {} as Services;\n\n constructor(\n public readonly core: Core,\n private readonly options: MongoOptions\n ) {\n super(core);\n this.uri = options.uri;\n\n this.core.shutdown.addTask(ShutdownPhase.ExternalResources, 'stop-database', async () => await this.stop());\n }\n\n public async init(): Promise<void> {\n if (this.isInitialised) return;\n this.isInitialised = true;\n\n await this.connect();\n await this.loadServices();\n }\n\n public async stop(): Promise<void> {\n await this.disconnect();\n }\n\n private async connect(): Promise<void> {\n await mongoose\n .connect(this.uri, {\n dbName: this.options.name,\n ...(Envapter.isProduction && { tls: true, ssl: true })\n })\n .then((i) => this.logger.info(`Connected to MongoDB: ${chalk.bold.magenta(i.connection.name)}`))\n .catch((err) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n throw new Error(`Could not connect to MongoDB`, err);\n });\n }\n\n private async disconnect(): Promise<void> {\n await mongoose\n .disconnect()\n .then(() => this.logger.info(chalk.red.bold('Disconnected from MongoDB')))\n .catch((err) => this.logger.error(`Could not disconnect from MongoDB: ${(err as Error).message}`));\n }\n\n private async loadServices(): Promise<void> {\n const servicesDir = this.options.dir;\n this.logger.info(chalk.bold(servicesDir));\n\n await traverseDirectory(\n servicesDir,\n (_full, rel, mod) => {\n for (const Service of Object.values(mod)) {\n if (this.isServiceClass(Service)) {\n const instance = new Service(this, this.core);\n this.logger.info(\n `${chalk.italic('Registered')} ${chalk.bold.yellow(instance.constructor.name)} from ${chalk.gray(rel)}`\n );\n }\n }\n },\n this.logger\n );\n\n this.logger.info(`${chalk.bold.green('Loaded')}: ${chalk.magenta(Object.keys(this.services).length)} services`);\n }\n\n private isServiceClass(obj: unknown): obj is BaseServiceConstructor {\n return (\n typeof obj === 'function' && obj.prototype instanceof BaseService && Reflect.hasMetadata(ServiceMetadataKey, obj)\n );\n }\n\n _register<SKey extends keyof Services>(key: SKey, instance: Services[SKey]): void {\n this.services[key] = instance;\n }\n}\n","import { CustomError, throwCustomError, DatabaseError } from 'seedcord';\n\n/**\n * Catches and wraps database operation errors.\n *\n * Automatically wraps non-CustomError exceptions in DatabaseError instances\n * with UUID tracking. Should be applied to database service methods.\n *\n * @param errorMessage - Message to include when wrapping errors\n * @decorator\n * @example\n * ```typescript\n * class UserService extends BaseService {\n * \\@DBCatchable('Failed to find user')\n * async findById(id: string) {\n * return this.model.findById(id);\n * }\n * }\n * ```\n */\nexport function DBCatchable<TypeReturn>(errorMessage: string) {\n return function (\n _target: unknown,\n _propertyKey: string,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise<TypeReturn>>\n ): void {\n const originalMethod = descriptor.value;\n\n descriptor.value = async function (...args: any[]): Promise<TypeReturn> {\n if (!originalMethod) {\n throw new Error('Method not found');\n }\n\n try {\n return await originalMethod.apply(this, args);\n } catch (error) {\n if (!(error instanceof CustomError)) {\n throwCustomError(error, errorMessage, DatabaseError);\n } else {\n throw error;\n }\n }\n };\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/mongo/decorators/DatabaseModel.ts","../src/mongo/decorators/DatabaseService.ts","../src/mongo/MongoService.ts","../src/mongo/Mongo.ts","../src/mongo/decorators/DBCatchable.ts"],"names":["ModelMetadataKey","Symbol","DatabaseModel","collection","target","propertyKey","schema","name","String","model","mongoose","Reflect","defineMetadata","ServiceMetadataKey","DatabaseService","key","ctor","MongoService","db","core","getMetadata","Error","_register","Mongo","Plugin","logger","Logger","isInitialised","uri","services","options","shutdown","addTask","ShutdownPhase","ExternalResources","stop","init","connect","loadServices","disconnect","dbName","Envapter","isProduction","tls","ssl","then","i","info","chalk","bold","magenta","connection","catch","err","red","error","message","servicesDir","dir","traverseDirectory","_full","rel","mod","Service","Object","values","isServiceClass","instance","italic","yellow","gray","green","keys","length","obj","prototype","hasMetadata","DBCatchable","errorMessage","_target","_propertyKey","descriptor","originalMethod","value","args","apply","CustomError","throwCustomError","DatabaseError"],"mappings":"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","file":"index.cjs","sourcesContent":["import mongoose from 'mongoose';\n\nimport type { ServiceKeys } from '../types/Services';\n\nexport const ModelMetadataKey = Symbol('db:model');\n\n/**\n * Associates a Mongoose model with a database service\n *\n * Creates a Mongoose model from the decorated static schema property and stores it\n * for service registration. The model becomes available as `this.model` in the service.\n * Must be applied to a `public static schema` property in the service class.\n *\n * @typeParam TService - The service key type\n * @param collection - Collection name for the Mongoose model\n * @decorator\n * @example\n * ```typescript\n * \\@DatabaseService('users')\n * export class Users extends MongoService<IUser> {\n * \\@DatabaseModel('users')\n * public static schema = new mongoose.Schema<IUser>({\n * username: { type: String, required: true, unique: true }\n * });\n * }\n * ```\n */\nexport function DatabaseModel<TService extends ServiceKeys>(collection: TService) {\n return <\n SchemaObj extends Record<KeyOfSchema, mongoose.Schema>,\n KeyOfSchema extends keyof SchemaObj & (string | symbol)\n >(\n target: SchemaObj,\n propertyKey: KeyOfSchema\n ): void => {\n const schema = target[propertyKey];\n const name = String(collection);\n const model = mongoose.model(name, schema);\n Reflect.defineMetadata(ModelMetadataKey, model, target);\n };\n}\n","import type { MongoService } from '../MongoService';\nimport type { ServiceKeys } from '../types/Services';\nimport type { Constructor } from 'type-fest';\n\nexport const ServiceMetadataKey = Symbol('db:serviceKey');\n\n/**\n * Registers a database service with a typed key\n *\n * Associates a service class with a key for dependency injection.\n * The service becomes available via `core.db.services[key]`.\n *\n * @typeParam TService - The service key type\n * @param key - Service key for registration and type-safe access\n * @decorator\n * @example\n * ```typescript\n * \\@DatabaseService('users')\n * export class Users<Doc extends IUser = IUser> extends MongoService<Doc> {\n * // Some code\n * }\n * ```\n */\nexport function DatabaseService<TService extends ServiceKeys>(key: TService) {\n return <DatabaseCtor extends Constructor<unknown> & { prototype: MongoService }>(ctor: DatabaseCtor): void => {\n Reflect.defineMetadata(ServiceMetadataKey, key, ctor);\n };\n}\n","import { ModelMetadataKey } from './decorators/DatabaseModel';\nimport { ServiceMetadataKey } from './decorators/DatabaseService';\n\nimport type { Mongo } from './Mongo';\nimport type { IDocument } from './types/Document';\nimport type { Services } from './types/Services';\nimport type { TypedConstructor } from '@seedcord/types';\nimport type mongoose from 'mongoose';\nimport type { Core } from 'seedcord';\n\n/**\n * Base class for MongoDB service layers\n *\n * Provides typed access to MongoDB collections through Mongoose models.\n * Services are automatically registered with the Mongo plugin when instantiated.\n *\n * @typeParam Doc - The document type this service manages\n * @example\n * ```typescript\n * \\@DatabaseService('users')\n * export class Users extends MongoService<IUser> {\n * \\@DatabaseModel('users')\n * public static schema = new mongoose.Schema<IUser>({\n * username: { type: String, required: true, unique: true }\n * });\n *\n * // Custom methods here\n * public async findByUsername(username: string) {\n * return this.model.findOne({ username });\n * }\n * }\n * ```\n */\nexport abstract class MongoService<Doc extends IDocument = IDocument> {\n public readonly model: mongoose.Model<Doc>;\n\n public constructor(\n protected readonly db: Mongo,\n protected readonly core: Core\n ) {\n const ctor = this.constructor;\n\n const key = Reflect.getMetadata(ServiceMetadataKey, ctor) as string | undefined;\n if (!key) throw new Error(`Missing @DatabaseService on ${ctor.name}`);\n\n const model = Reflect.getMetadata(ModelMetadataKey, ctor) as mongoose.Model<Doc> | undefined;\n if (!model) throw new Error(`Missing @DatabaseModel on ${ctor.name}`);\n\n this.model = model;\n\n db._register(key as keyof Services, this as unknown as Services[keyof Services]);\n }\n}\n\n/** Constructor type for MongoService classes */\nexport type MongoServiceConstructor = TypedConstructor<typeof MongoService>;\n","import 'reflect-metadata';\n\nimport chalk from 'chalk';\nimport { Envapter } from 'envapt';\nimport mongoose from 'mongoose';\nimport { Logger, Plugin, ShutdownPhase, traverseDirectory } from 'seedcord';\n\nimport { ServiceMetadataKey } from './decorators/DatabaseService';\nimport { MongoService } from './MongoService';\n\nimport type { MongoServiceConstructor } from './MongoService';\nimport type { Services } from './types/Services';\nimport type { Core } from 'seedcord';\n\n/**\n * Configuration options for MongoDB connection and service loading.\n */\nexport interface MongoOptions {\n /** Directory path containing database service classes */\n dir: string;\n /** MongoDB connection URI */\n uri: string;\n /** Database name to use */\n name: string;\n}\n\n/**\n * MongoDB integration plugin for Seedcord.\n *\n * Manages MongoDB connections, service loading, and provides type-safe\n * access to database services through service registration decorators.\n */\nexport class Mongo extends Plugin {\n public readonly logger = new Logger('MongoDB');\n private isInitialised = false;\n private readonly uri: string;\n\n /**\n * Map of all loaded services.\n * Keys come from `@DatabaseService('key')`\n */\n public readonly services: Services = {} as Services;\n\n constructor(\n public readonly core: Core,\n private readonly options: MongoOptions\n ) {\n super(core);\n this.uri = options.uri;\n\n this.core.shutdown.addTask(ShutdownPhase.ExternalResources, 'stop-database', async () => await this.stop());\n }\n\n public async init(): Promise<void> {\n if (this.isInitialised) return;\n this.isInitialised = true;\n\n await this.connect();\n await this.loadServices();\n }\n\n public async stop(): Promise<void> {\n await this.disconnect();\n }\n\n private async connect(): Promise<void> {\n await mongoose\n .connect(this.uri, {\n dbName: this.options.name,\n ...(Envapter.isProduction && { tls: true, ssl: true })\n })\n .then((i) => this.logger.info(`Connected to MongoDB: ${chalk.bold.magenta(i.connection.name)}`))\n .catch((err) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n throw new Error(`Could not connect to MongoDB`, err);\n });\n }\n\n private async disconnect(): Promise<void> {\n await mongoose\n .disconnect()\n .then(() => this.logger.info(chalk.red.bold('Disconnected from MongoDB')))\n .catch((err) => this.logger.error(`Could not disconnect from MongoDB: ${(err as Error).message}`));\n }\n\n private async loadServices(): Promise<void> {\n const servicesDir = this.options.dir;\n this.logger.info(chalk.bold(servicesDir));\n\n await traverseDirectory(\n servicesDir,\n (_full, rel, mod) => {\n for (const Service of Object.values(mod)) {\n if (this.isServiceClass(Service)) {\n const instance = new Service(this, this.core);\n this.logger.info(\n `${chalk.italic('Registered')} ${chalk.bold.yellow(instance.constructor.name)} from ${chalk.gray(rel)}`\n );\n }\n }\n },\n this.logger\n );\n\n this.logger.info(`${chalk.bold.green('Loaded')}: ${chalk.magenta(Object.keys(this.services).length)} services`);\n }\n\n private isServiceClass(obj: unknown): obj is MongoServiceConstructor {\n return (\n typeof obj === 'function' &&\n obj.prototype instanceof MongoService &&\n Reflect.hasMetadata(ServiceMetadataKey, obj)\n );\n }\n\n _register<SKey extends keyof Services>(key: SKey, instance: Services[SKey]): void {\n this.services[key] = instance;\n }\n}\n","import { CustomError, throwCustomError, DatabaseError } from 'seedcord';\n\n/**\n * Catches and wraps database operation errors.\n *\n * Automatically wraps non-CustomError exceptions in DatabaseError instances\n * with UUID tracking. Should be applied to database service methods.\n *\n * @typeParam TypeReturn - The return type of the decorated method\n * @param errorMessage - Message to include when wrapping errors\n * @decorator\n * @example\n * ```typescript\n * class UserService extends MongoService<IUser> {\n * \\@DBCatchable('Failed to find user')\n * async findById(id: string) {\n * return this.model.findById(id);\n * }\n * }\n * ```\n */\nexport function DBCatchable<TypeReturn>(errorMessage: string) {\n return function (\n _target: unknown,\n _propertyKey: string,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise<TypeReturn>>\n ): void {\n const originalMethod = descriptor.value;\n\n descriptor.value = async function (...args: any[]): Promise<TypeReturn> {\n if (!originalMethod) {\n throw new Error('Method not found');\n }\n\n try {\n return await originalMethod.apply(this, args);\n } catch (error) {\n if (!(error instanceof CustomError)) {\n throwCustomError(error, errorMessage, DatabaseError);\n } else {\n throw error;\n }\n }\n };\n };\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Plugin, Core, Logger } from 'seedcord';
|
|
2
|
-
import { TypedConstructor
|
|
2
|
+
import { TypedConstructor } from '@seedcord/types';
|
|
3
3
|
import mongoose from 'mongoose';
|
|
4
|
+
import { Constructor } from 'type-fest';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Registry of available database services.
|
|
@@ -90,7 +91,7 @@ declare class Mongo extends Plugin {
|
|
|
90
91
|
* @example
|
|
91
92
|
* ```typescript
|
|
92
93
|
* \@DatabaseService('users')
|
|
93
|
-
* export class Users extends
|
|
94
|
+
* export class Users extends MongoService<IUser> {
|
|
94
95
|
* \@DatabaseModel('users')
|
|
95
96
|
* public static schema = new mongoose.Schema<IUser>({
|
|
96
97
|
* username: { type: String, required: true, unique: true }
|
|
@@ -103,14 +104,14 @@ declare class Mongo extends Plugin {
|
|
|
103
104
|
* }
|
|
104
105
|
* ```
|
|
105
106
|
*/
|
|
106
|
-
declare abstract class
|
|
107
|
+
declare abstract class MongoService<Doc extends IDocument = IDocument> {
|
|
107
108
|
protected readonly db: Mongo;
|
|
108
109
|
protected readonly core: Core;
|
|
109
110
|
readonly model: mongoose.Model<Doc>;
|
|
110
111
|
constructor(db: Mongo, core: Core);
|
|
111
112
|
}
|
|
112
|
-
/** Constructor type for
|
|
113
|
-
type
|
|
113
|
+
/** Constructor type for MongoService classes */
|
|
114
|
+
type MongoServiceConstructor = TypedConstructor<typeof MongoService>;
|
|
114
115
|
|
|
115
116
|
/**
|
|
116
117
|
* Catches and wraps database operation errors.
|
|
@@ -118,11 +119,12 @@ type BaseServiceConstructor = TypedConstructor<typeof BaseService>;
|
|
|
118
119
|
* Automatically wraps non-CustomError exceptions in DatabaseError instances
|
|
119
120
|
* with UUID tracking. Should be applied to database service methods.
|
|
120
121
|
*
|
|
122
|
+
* @typeParam TypeReturn - The return type of the decorated method
|
|
121
123
|
* @param errorMessage - Message to include when wrapping errors
|
|
122
124
|
* @decorator
|
|
123
125
|
* @example
|
|
124
126
|
* ```typescript
|
|
125
|
-
* class UserService extends
|
|
127
|
+
* class UserService extends MongoService<IUser> {
|
|
126
128
|
* \@DBCatchable('Failed to find user')
|
|
127
129
|
* async findById(id: string) {
|
|
128
130
|
* return this.model.findById(id);
|
|
@@ -140,12 +142,13 @@ declare const ModelMetadataKey: unique symbol;
|
|
|
140
142
|
* for service registration. The model becomes available as `this.model` in the service.
|
|
141
143
|
* Must be applied to a `public static schema` property in the service class.
|
|
142
144
|
*
|
|
145
|
+
* @typeParam TService - The service key type
|
|
143
146
|
* @param collection - Collection name for the Mongoose model
|
|
144
147
|
* @decorator
|
|
145
148
|
* @example
|
|
146
149
|
* ```typescript
|
|
147
150
|
* \@DatabaseService('users')
|
|
148
|
-
* export class Users extends
|
|
151
|
+
* export class Users extends MongoService<IUser> {
|
|
149
152
|
* \@DatabaseModel('users')
|
|
150
153
|
* public static schema = new mongoose.Schema<IUser>({
|
|
151
154
|
* username: { type: String, required: true, unique: true }
|
|
@@ -162,18 +165,19 @@ declare const ServiceMetadataKey: unique symbol;
|
|
|
162
165
|
* Associates a service class with a key for dependency injection.
|
|
163
166
|
* The service becomes available via `core.db.services[key]`.
|
|
164
167
|
*
|
|
168
|
+
* @typeParam TService - The service key type
|
|
165
169
|
* @param key - Service key for registration and type-safe access
|
|
166
170
|
* @decorator
|
|
167
171
|
* @example
|
|
168
172
|
* ```typescript
|
|
169
173
|
* \@DatabaseService('users')
|
|
170
|
-
* export class Users<Doc extends IUser = IUser> extends
|
|
174
|
+
* export class Users<Doc extends IUser = IUser> extends MongoService<Doc> {
|
|
171
175
|
* // Some code
|
|
172
176
|
* }
|
|
173
177
|
* ```
|
|
174
178
|
*/
|
|
175
|
-
declare function DatabaseService<TService extends ServiceKeys>(key: TService): <DatabaseCtor extends
|
|
176
|
-
prototype:
|
|
179
|
+
declare function DatabaseService<TService extends ServiceKeys>(key: TService): <DatabaseCtor extends Constructor<unknown> & {
|
|
180
|
+
prototype: MongoService;
|
|
177
181
|
}>(ctor: DatabaseCtor) => void;
|
|
178
182
|
|
|
179
|
-
export {
|
|
183
|
+
export { DBCatchable, DatabaseModel, DatabaseService, type IDocument, ModelMetadataKey, Mongo, type MongoOptions, MongoService, type MongoServiceConstructor, type ServiceKeys, ServiceMetadataKey, type Services, type TypeOfIDocument };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Plugin, Core, Logger } from 'seedcord';
|
|
2
|
-
import { TypedConstructor
|
|
2
|
+
import { TypedConstructor } from '@seedcord/types';
|
|
3
3
|
import mongoose from 'mongoose';
|
|
4
|
+
import { Constructor } from 'type-fest';
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Registry of available database services.
|
|
@@ -90,7 +91,7 @@ declare class Mongo extends Plugin {
|
|
|
90
91
|
* @example
|
|
91
92
|
* ```typescript
|
|
92
93
|
* \@DatabaseService('users')
|
|
93
|
-
* export class Users extends
|
|
94
|
+
* export class Users extends MongoService<IUser> {
|
|
94
95
|
* \@DatabaseModel('users')
|
|
95
96
|
* public static schema = new mongoose.Schema<IUser>({
|
|
96
97
|
* username: { type: String, required: true, unique: true }
|
|
@@ -103,14 +104,14 @@ declare class Mongo extends Plugin {
|
|
|
103
104
|
* }
|
|
104
105
|
* ```
|
|
105
106
|
*/
|
|
106
|
-
declare abstract class
|
|
107
|
+
declare abstract class MongoService<Doc extends IDocument = IDocument> {
|
|
107
108
|
protected readonly db: Mongo;
|
|
108
109
|
protected readonly core: Core;
|
|
109
110
|
readonly model: mongoose.Model<Doc>;
|
|
110
111
|
constructor(db: Mongo, core: Core);
|
|
111
112
|
}
|
|
112
|
-
/** Constructor type for
|
|
113
|
-
type
|
|
113
|
+
/** Constructor type for MongoService classes */
|
|
114
|
+
type MongoServiceConstructor = TypedConstructor<typeof MongoService>;
|
|
114
115
|
|
|
115
116
|
/**
|
|
116
117
|
* Catches and wraps database operation errors.
|
|
@@ -118,11 +119,12 @@ type BaseServiceConstructor = TypedConstructor<typeof BaseService>;
|
|
|
118
119
|
* Automatically wraps non-CustomError exceptions in DatabaseError instances
|
|
119
120
|
* with UUID tracking. Should be applied to database service methods.
|
|
120
121
|
*
|
|
122
|
+
* @typeParam TypeReturn - The return type of the decorated method
|
|
121
123
|
* @param errorMessage - Message to include when wrapping errors
|
|
122
124
|
* @decorator
|
|
123
125
|
* @example
|
|
124
126
|
* ```typescript
|
|
125
|
-
* class UserService extends
|
|
127
|
+
* class UserService extends MongoService<IUser> {
|
|
126
128
|
* \@DBCatchable('Failed to find user')
|
|
127
129
|
* async findById(id: string) {
|
|
128
130
|
* return this.model.findById(id);
|
|
@@ -140,12 +142,13 @@ declare const ModelMetadataKey: unique symbol;
|
|
|
140
142
|
* for service registration. The model becomes available as `this.model` in the service.
|
|
141
143
|
* Must be applied to a `public static schema` property in the service class.
|
|
142
144
|
*
|
|
145
|
+
* @typeParam TService - The service key type
|
|
143
146
|
* @param collection - Collection name for the Mongoose model
|
|
144
147
|
* @decorator
|
|
145
148
|
* @example
|
|
146
149
|
* ```typescript
|
|
147
150
|
* \@DatabaseService('users')
|
|
148
|
-
* export class Users extends
|
|
151
|
+
* export class Users extends MongoService<IUser> {
|
|
149
152
|
* \@DatabaseModel('users')
|
|
150
153
|
* public static schema = new mongoose.Schema<IUser>({
|
|
151
154
|
* username: { type: String, required: true, unique: true }
|
|
@@ -162,18 +165,19 @@ declare const ServiceMetadataKey: unique symbol;
|
|
|
162
165
|
* Associates a service class with a key for dependency injection.
|
|
163
166
|
* The service becomes available via `core.db.services[key]`.
|
|
164
167
|
*
|
|
168
|
+
* @typeParam TService - The service key type
|
|
165
169
|
* @param key - Service key for registration and type-safe access
|
|
166
170
|
* @decorator
|
|
167
171
|
* @example
|
|
168
172
|
* ```typescript
|
|
169
173
|
* \@DatabaseService('users')
|
|
170
|
-
* export class Users<Doc extends IUser = IUser> extends
|
|
174
|
+
* export class Users<Doc extends IUser = IUser> extends MongoService<Doc> {
|
|
171
175
|
* // Some code
|
|
172
176
|
* }
|
|
173
177
|
* ```
|
|
174
178
|
*/
|
|
175
|
-
declare function DatabaseService<TService extends ServiceKeys>(key: TService): <DatabaseCtor extends
|
|
176
|
-
prototype:
|
|
179
|
+
declare function DatabaseService<TService extends ServiceKeys>(key: TService): <DatabaseCtor extends Constructor<unknown> & {
|
|
180
|
+
prototype: MongoService;
|
|
177
181
|
}>(ctor: DatabaseCtor) => void;
|
|
178
182
|
|
|
179
|
-
export {
|
|
183
|
+
export { DBCatchable, DatabaseModel, DatabaseService, type IDocument, ModelMetadataKey, Mongo, type MongoOptions, MongoService, type MongoServiceConstructor, type ServiceKeys, ServiceMetadataKey, type Services, type TypeOfIDocument };
|
package/dist/index.mjs
CHANGED
|
@@ -26,10 +26,10 @@ function DatabaseService(key) {
|
|
|
26
26
|
}
|
|
27
27
|
__name(DatabaseService, "DatabaseService");
|
|
28
28
|
|
|
29
|
-
// src/mongo/
|
|
30
|
-
var
|
|
29
|
+
// src/mongo/MongoService.ts
|
|
30
|
+
var MongoService = class {
|
|
31
31
|
static {
|
|
32
|
-
__name(this, "
|
|
32
|
+
__name(this, "MongoService");
|
|
33
33
|
}
|
|
34
34
|
db;
|
|
35
35
|
core;
|
|
@@ -56,9 +56,9 @@ var Mongo = class extends Plugin {
|
|
|
56
56
|
isInitialised = false;
|
|
57
57
|
uri;
|
|
58
58
|
/**
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
59
|
+
* Map of all loaded services.
|
|
60
|
+
* Keys come from `@DatabaseService('key')`
|
|
61
|
+
*/
|
|
62
62
|
services = {};
|
|
63
63
|
constructor(core, options) {
|
|
64
64
|
super(core), this.core = core, this.options = options;
|
|
@@ -102,7 +102,7 @@ var Mongo = class extends Plugin {
|
|
|
102
102
|
this.logger.info(`${chalk.bold.green("Loaded")}: ${chalk.magenta(Object.keys(this.services).length)} services`);
|
|
103
103
|
}
|
|
104
104
|
isServiceClass(obj) {
|
|
105
|
-
return typeof obj === "function" && obj.prototype instanceof
|
|
105
|
+
return typeof obj === "function" && obj.prototype instanceof MongoService && Reflect.hasMetadata(ServiceMetadataKey, obj);
|
|
106
106
|
}
|
|
107
107
|
_register(key, instance) {
|
|
108
108
|
this.services[key] = instance;
|
|
@@ -129,6 +129,6 @@ function DBCatchable(errorMessage) {
|
|
|
129
129
|
}
|
|
130
130
|
__name(DBCatchable, "DBCatchable");
|
|
131
131
|
|
|
132
|
-
export {
|
|
132
|
+
export { DBCatchable, DatabaseModel, DatabaseService, ModelMetadataKey, Mongo, MongoService, ServiceMetadataKey };
|
|
133
133
|
//# sourceMappingURL=index.mjs.map
|
|
134
134
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/mongo/decorators/DatabaseModel.ts","../src/mongo/decorators/DatabaseService.ts","../src/mongo/BaseService.ts","../src/mongo/Mongo.ts","../src/mongo/decorators/DBCatchable.ts"],"names":["ModelMetadataKey","Symbol","DatabaseModel","collection","target","propertyKey","schema","name","String","model","mongoose","Reflect","defineMetadata","ServiceMetadataKey","DatabaseService","key","ctor","BaseService","db","core","getMetadata","Error","_register","Mongo","Plugin","logger","Logger","isInitialised","uri","services","options","shutdown","addTask","ShutdownPhase","ExternalResources","stop","init","connect","loadServices","disconnect","dbName","Envapter","isProduction","tls","ssl","then","i","info","chalk","bold","magenta","connection","catch","err","red","error","message","servicesDir","dir","traverseDirectory","_full","rel","mod","Service","Object","values","isServiceClass","instance","italic","yellow","gray","green","keys","length","obj","prototype","hasMetadata","DBCatchable","errorMessage","_target","_propertyKey","descriptor","originalMethod","value","args","apply","CustomError","throwCustomError","DatabaseError"],"mappings":"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","file":"index.mjs","sourcesContent":["import mongoose from 'mongoose';\n\nimport type { ServiceKeys } from '../types/Services';\n\nexport const ModelMetadataKey = Symbol('db:model');\n\n/**\n * Associates a Mongoose model with a database service\n *\n * Creates a Mongoose model from the decorated static schema property and stores it\n * for service registration. The model becomes available as `this.model` in the service.\n * Must be applied to a `public static schema` property in the service class.\n *\n * @param collection - Collection name for the Mongoose model\n * @decorator\n * @example\n * ```typescript\n * \\@DatabaseService('users')\n * export class Users extends BaseService<IUser> {\n * \\@DatabaseModel('users')\n * public static schema = new mongoose.Schema<IUser>({\n * username: { type: String, required: true, unique: true }\n * });\n * }\n * ```\n */\nexport function DatabaseModel<TService extends ServiceKeys>(collection: TService) {\n return <\n SchemaObj extends Record<KeyOfSchema, mongoose.Schema>,\n KeyOfSchema extends keyof SchemaObj & (string | symbol)\n >(\n target: SchemaObj,\n propertyKey: KeyOfSchema\n ): void => {\n const schema = target[propertyKey];\n const name = String(collection);\n const model = mongoose.model(name, schema);\n Reflect.defineMetadata(ModelMetadataKey, model, target);\n };\n}\n","import type { BaseService } from '../BaseService';\nimport type { ServiceKeys } from '../types/Services';\nimport type { ConstructorFunction } from '@seedcord/types';\n\nexport const ServiceMetadataKey = Symbol('db:serviceKey');\n\n/**\n * Registers a database service with a typed key\n *\n * Associates a service class with a key for dependency injection.\n * The service becomes available via `core.db.services[key]`.\n *\n * @param key - Service key for registration and type-safe access\n * @decorator\n * @example\n * ```typescript\n * \\@DatabaseService('users')\n * export class Users<Doc extends IUser = IUser> extends BaseService<Doc> {\n * // Some code\n * }\n * ```\n */\nexport function DatabaseService<TService extends ServiceKeys>(key: TService) {\n return <DatabaseCtor extends ConstructorFunction & { prototype: BaseService }>(ctor: DatabaseCtor): void => {\n Reflect.defineMetadata(ServiceMetadataKey, key, ctor);\n };\n}\n","import { ModelMetadataKey } from './decorators/DatabaseModel';\nimport { ServiceMetadataKey } from './decorators/DatabaseService';\n\nimport type { Mongo } from './Mongo';\nimport type { IDocument } from './types/Document';\nimport type { Services } from './types/Services';\nimport type { TypedConstructor } from '@seedcord/types';\nimport type mongoose from 'mongoose';\nimport type { Core } from 'seedcord';\n\n/**\n * Base class for MongoDB service layers\n *\n * Provides typed access to MongoDB collections through Mongoose models.\n * Services are automatically registered with the Mongo plugin when instantiated.\n *\n * @typeParam Doc - The document type this service manages\n * @example\n * ```typescript\n * \\@DatabaseService('users')\n * export class Users extends BaseService<IUser> {\n * \\@DatabaseModel('users')\n * public static schema = new mongoose.Schema<IUser>({\n * username: { type: String, required: true, unique: true }\n * });\n *\n * // Custom methods here\n * public async findByUsername(username: string) {\n * return this.model.findOne({ username });\n * }\n * }\n * ```\n */\nexport abstract class BaseService<Doc extends IDocument = IDocument> {\n public readonly model: mongoose.Model<Doc>;\n\n public constructor(\n protected readonly db: Mongo,\n protected readonly core: Core\n ) {\n const ctor = this.constructor;\n\n const key = Reflect.getMetadata(ServiceMetadataKey, ctor) as string | undefined;\n if (!key) throw new Error(`Missing @DatabaseService on ${ctor.name}`);\n\n const model = Reflect.getMetadata(ModelMetadataKey, ctor) as mongoose.Model<Doc> | undefined;\n if (!model) throw new Error(`Missing @DatabaseModel on ${ctor.name}`);\n\n this.model = model;\n\n db._register(key as keyof Services, this as unknown as Services[keyof Services]);\n }\n}\n\n/** Constructor type for BaseService classes */\nexport type BaseServiceConstructor = TypedConstructor<typeof BaseService>;\n","import 'reflect-metadata';\n\nimport chalk from 'chalk';\nimport { Envapter } from 'envapt';\nimport mongoose from 'mongoose';\nimport { Logger, Plugin, ShutdownPhase, traverseDirectory } from 'seedcord';\n\nimport { BaseService } from './BaseService';\nimport { ServiceMetadataKey } from './decorators/DatabaseService';\n\nimport type { BaseServiceConstructor } from './BaseService';\nimport type { Services } from './types/Services';\nimport type { Core } from 'seedcord';\n\n/**\n * Configuration options for MongoDB connection and service loading.\n */\ninterface MongoOptions {\n /** Directory path containing database service classes */\n dir: string;\n /** MongoDB connection URI */\n uri: string;\n /** Database name to use */\n name: string;\n}\n\n/**\n * MongoDB integration plugin for Seedcord.\n *\n * Manages MongoDB connections, service loading, and provides type-safe\n * access to database services through service registration decorators.\n */\nexport class Mongo extends Plugin {\n public readonly logger = new Logger('MongoDB');\n private isInitialised = false;\n private readonly uri: string;\n\n /**\n * Map of all loaded services.\n * Keys come from `@DatabaseService('key')`\n */\n public readonly services: Services = {} as Services;\n\n constructor(\n public readonly core: Core,\n private readonly options: MongoOptions\n ) {\n super(core);\n this.uri = options.uri;\n\n this.core.shutdown.addTask(ShutdownPhase.ExternalResources, 'stop-database', async () => await this.stop());\n }\n\n public async init(): Promise<void> {\n if (this.isInitialised) return;\n this.isInitialised = true;\n\n await this.connect();\n await this.loadServices();\n }\n\n public async stop(): Promise<void> {\n await this.disconnect();\n }\n\n private async connect(): Promise<void> {\n await mongoose\n .connect(this.uri, {\n dbName: this.options.name,\n ...(Envapter.isProduction && { tls: true, ssl: true })\n })\n .then((i) => this.logger.info(`Connected to MongoDB: ${chalk.bold.magenta(i.connection.name)}`))\n .catch((err) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n throw new Error(`Could not connect to MongoDB`, err);\n });\n }\n\n private async disconnect(): Promise<void> {\n await mongoose\n .disconnect()\n .then(() => this.logger.info(chalk.red.bold('Disconnected from MongoDB')))\n .catch((err) => this.logger.error(`Could not disconnect from MongoDB: ${(err as Error).message}`));\n }\n\n private async loadServices(): Promise<void> {\n const servicesDir = this.options.dir;\n this.logger.info(chalk.bold(servicesDir));\n\n await traverseDirectory(\n servicesDir,\n (_full, rel, mod) => {\n for (const Service of Object.values(mod)) {\n if (this.isServiceClass(Service)) {\n const instance = new Service(this, this.core);\n this.logger.info(\n `${chalk.italic('Registered')} ${chalk.bold.yellow(instance.constructor.name)} from ${chalk.gray(rel)}`\n );\n }\n }\n },\n this.logger\n );\n\n this.logger.info(`${chalk.bold.green('Loaded')}: ${chalk.magenta(Object.keys(this.services).length)} services`);\n }\n\n private isServiceClass(obj: unknown): obj is BaseServiceConstructor {\n return (\n typeof obj === 'function' && obj.prototype instanceof BaseService && Reflect.hasMetadata(ServiceMetadataKey, obj)\n );\n }\n\n _register<SKey extends keyof Services>(key: SKey, instance: Services[SKey]): void {\n this.services[key] = instance;\n }\n}\n","import { CustomError, throwCustomError, DatabaseError } from 'seedcord';\n\n/**\n * Catches and wraps database operation errors.\n *\n * Automatically wraps non-CustomError exceptions in DatabaseError instances\n * with UUID tracking. Should be applied to database service methods.\n *\n * @param errorMessage - Message to include when wrapping errors\n * @decorator\n * @example\n * ```typescript\n * class UserService extends BaseService {\n * \\@DBCatchable('Failed to find user')\n * async findById(id: string) {\n * return this.model.findById(id);\n * }\n * }\n * ```\n */\nexport function DBCatchable<TypeReturn>(errorMessage: string) {\n return function (\n _target: unknown,\n _propertyKey: string,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise<TypeReturn>>\n ): void {\n const originalMethod = descriptor.value;\n\n descriptor.value = async function (...args: any[]): Promise<TypeReturn> {\n if (!originalMethod) {\n throw new Error('Method not found');\n }\n\n try {\n return await originalMethod.apply(this, args);\n } catch (error) {\n if (!(error instanceof CustomError)) {\n throwCustomError(error, errorMessage, DatabaseError);\n } else {\n throw error;\n }\n }\n };\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/mongo/decorators/DatabaseModel.ts","../src/mongo/decorators/DatabaseService.ts","../src/mongo/MongoService.ts","../src/mongo/Mongo.ts","../src/mongo/decorators/DBCatchable.ts"],"names":["ModelMetadataKey","Symbol","DatabaseModel","collection","target","propertyKey","schema","name","String","model","mongoose","Reflect","defineMetadata","ServiceMetadataKey","DatabaseService","key","ctor","MongoService","db","core","getMetadata","Error","_register","Mongo","Plugin","logger","Logger","isInitialised","uri","services","options","shutdown","addTask","ShutdownPhase","ExternalResources","stop","init","connect","loadServices","disconnect","dbName","Envapter","isProduction","tls","ssl","then","i","info","chalk","bold","magenta","connection","catch","err","red","error","message","servicesDir","dir","traverseDirectory","_full","rel","mod","Service","Object","values","isServiceClass","instance","italic","yellow","gray","green","keys","length","obj","prototype","hasMetadata","DBCatchable","errorMessage","_target","_propertyKey","descriptor","originalMethod","value","args","apply","CustomError","throwCustomError","DatabaseError"],"mappings":"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","file":"index.mjs","sourcesContent":["import mongoose from 'mongoose';\n\nimport type { ServiceKeys } from '../types/Services';\n\nexport const ModelMetadataKey = Symbol('db:model');\n\n/**\n * Associates a Mongoose model with a database service\n *\n * Creates a Mongoose model from the decorated static schema property and stores it\n * for service registration. The model becomes available as `this.model` in the service.\n * Must be applied to a `public static schema` property in the service class.\n *\n * @typeParam TService - The service key type\n * @param collection - Collection name for the Mongoose model\n * @decorator\n * @example\n * ```typescript\n * \\@DatabaseService('users')\n * export class Users extends MongoService<IUser> {\n * \\@DatabaseModel('users')\n * public static schema = new mongoose.Schema<IUser>({\n * username: { type: String, required: true, unique: true }\n * });\n * }\n * ```\n */\nexport function DatabaseModel<TService extends ServiceKeys>(collection: TService) {\n return <\n SchemaObj extends Record<KeyOfSchema, mongoose.Schema>,\n KeyOfSchema extends keyof SchemaObj & (string | symbol)\n >(\n target: SchemaObj,\n propertyKey: KeyOfSchema\n ): void => {\n const schema = target[propertyKey];\n const name = String(collection);\n const model = mongoose.model(name, schema);\n Reflect.defineMetadata(ModelMetadataKey, model, target);\n };\n}\n","import type { MongoService } from '../MongoService';\nimport type { ServiceKeys } from '../types/Services';\nimport type { Constructor } from 'type-fest';\n\nexport const ServiceMetadataKey = Symbol('db:serviceKey');\n\n/**\n * Registers a database service with a typed key\n *\n * Associates a service class with a key for dependency injection.\n * The service becomes available via `core.db.services[key]`.\n *\n * @typeParam TService - The service key type\n * @param key - Service key for registration and type-safe access\n * @decorator\n * @example\n * ```typescript\n * \\@DatabaseService('users')\n * export class Users<Doc extends IUser = IUser> extends MongoService<Doc> {\n * // Some code\n * }\n * ```\n */\nexport function DatabaseService<TService extends ServiceKeys>(key: TService) {\n return <DatabaseCtor extends Constructor<unknown> & { prototype: MongoService }>(ctor: DatabaseCtor): void => {\n Reflect.defineMetadata(ServiceMetadataKey, key, ctor);\n };\n}\n","import { ModelMetadataKey } from './decorators/DatabaseModel';\nimport { ServiceMetadataKey } from './decorators/DatabaseService';\n\nimport type { Mongo } from './Mongo';\nimport type { IDocument } from './types/Document';\nimport type { Services } from './types/Services';\nimport type { TypedConstructor } from '@seedcord/types';\nimport type mongoose from 'mongoose';\nimport type { Core } from 'seedcord';\n\n/**\n * Base class for MongoDB service layers\n *\n * Provides typed access to MongoDB collections through Mongoose models.\n * Services are automatically registered with the Mongo plugin when instantiated.\n *\n * @typeParam Doc - The document type this service manages\n * @example\n * ```typescript\n * \\@DatabaseService('users')\n * export class Users extends MongoService<IUser> {\n * \\@DatabaseModel('users')\n * public static schema = new mongoose.Schema<IUser>({\n * username: { type: String, required: true, unique: true }\n * });\n *\n * // Custom methods here\n * public async findByUsername(username: string) {\n * return this.model.findOne({ username });\n * }\n * }\n * ```\n */\nexport abstract class MongoService<Doc extends IDocument = IDocument> {\n public readonly model: mongoose.Model<Doc>;\n\n public constructor(\n protected readonly db: Mongo,\n protected readonly core: Core\n ) {\n const ctor = this.constructor;\n\n const key = Reflect.getMetadata(ServiceMetadataKey, ctor) as string | undefined;\n if (!key) throw new Error(`Missing @DatabaseService on ${ctor.name}`);\n\n const model = Reflect.getMetadata(ModelMetadataKey, ctor) as mongoose.Model<Doc> | undefined;\n if (!model) throw new Error(`Missing @DatabaseModel on ${ctor.name}`);\n\n this.model = model;\n\n db._register(key as keyof Services, this as unknown as Services[keyof Services]);\n }\n}\n\n/** Constructor type for MongoService classes */\nexport type MongoServiceConstructor = TypedConstructor<typeof MongoService>;\n","import 'reflect-metadata';\n\nimport chalk from 'chalk';\nimport { Envapter } from 'envapt';\nimport mongoose from 'mongoose';\nimport { Logger, Plugin, ShutdownPhase, traverseDirectory } from 'seedcord';\n\nimport { ServiceMetadataKey } from './decorators/DatabaseService';\nimport { MongoService } from './MongoService';\n\nimport type { MongoServiceConstructor } from './MongoService';\nimport type { Services } from './types/Services';\nimport type { Core } from 'seedcord';\n\n/**\n * Configuration options for MongoDB connection and service loading.\n */\nexport interface MongoOptions {\n /** Directory path containing database service classes */\n dir: string;\n /** MongoDB connection URI */\n uri: string;\n /** Database name to use */\n name: string;\n}\n\n/**\n * MongoDB integration plugin for Seedcord.\n *\n * Manages MongoDB connections, service loading, and provides type-safe\n * access to database services through service registration decorators.\n */\nexport class Mongo extends Plugin {\n public readonly logger = new Logger('MongoDB');\n private isInitialised = false;\n private readonly uri: string;\n\n /**\n * Map of all loaded services.\n * Keys come from `@DatabaseService('key')`\n */\n public readonly services: Services = {} as Services;\n\n constructor(\n public readonly core: Core,\n private readonly options: MongoOptions\n ) {\n super(core);\n this.uri = options.uri;\n\n this.core.shutdown.addTask(ShutdownPhase.ExternalResources, 'stop-database', async () => await this.stop());\n }\n\n public async init(): Promise<void> {\n if (this.isInitialised) return;\n this.isInitialised = true;\n\n await this.connect();\n await this.loadServices();\n }\n\n public async stop(): Promise<void> {\n await this.disconnect();\n }\n\n private async connect(): Promise<void> {\n await mongoose\n .connect(this.uri, {\n dbName: this.options.name,\n ...(Envapter.isProduction && { tls: true, ssl: true })\n })\n .then((i) => this.logger.info(`Connected to MongoDB: ${chalk.bold.magenta(i.connection.name)}`))\n .catch((err) => {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n throw new Error(`Could not connect to MongoDB`, err);\n });\n }\n\n private async disconnect(): Promise<void> {\n await mongoose\n .disconnect()\n .then(() => this.logger.info(chalk.red.bold('Disconnected from MongoDB')))\n .catch((err) => this.logger.error(`Could not disconnect from MongoDB: ${(err as Error).message}`));\n }\n\n private async loadServices(): Promise<void> {\n const servicesDir = this.options.dir;\n this.logger.info(chalk.bold(servicesDir));\n\n await traverseDirectory(\n servicesDir,\n (_full, rel, mod) => {\n for (const Service of Object.values(mod)) {\n if (this.isServiceClass(Service)) {\n const instance = new Service(this, this.core);\n this.logger.info(\n `${chalk.italic('Registered')} ${chalk.bold.yellow(instance.constructor.name)} from ${chalk.gray(rel)}`\n );\n }\n }\n },\n this.logger\n );\n\n this.logger.info(`${chalk.bold.green('Loaded')}: ${chalk.magenta(Object.keys(this.services).length)} services`);\n }\n\n private isServiceClass(obj: unknown): obj is MongoServiceConstructor {\n return (\n typeof obj === 'function' &&\n obj.prototype instanceof MongoService &&\n Reflect.hasMetadata(ServiceMetadataKey, obj)\n );\n }\n\n _register<SKey extends keyof Services>(key: SKey, instance: Services[SKey]): void {\n this.services[key] = instance;\n }\n}\n","import { CustomError, throwCustomError, DatabaseError } from 'seedcord';\n\n/**\n * Catches and wraps database operation errors.\n *\n * Automatically wraps non-CustomError exceptions in DatabaseError instances\n * with UUID tracking. Should be applied to database service methods.\n *\n * @typeParam TypeReturn - The return type of the decorated method\n * @param errorMessage - Message to include when wrapping errors\n * @decorator\n * @example\n * ```typescript\n * class UserService extends MongoService<IUser> {\n * \\@DBCatchable('Failed to find user')\n * async findById(id: string) {\n * return this.model.findById(id);\n * }\n * }\n * ```\n */\nexport function DBCatchable<TypeReturn>(errorMessage: string) {\n return function (\n _target: unknown,\n _propertyKey: string,\n descriptor: TypedPropertyDescriptor<(...args: any[]) => Promise<TypeReturn>>\n ): void {\n const originalMethod = descriptor.value;\n\n descriptor.value = async function (...args: any[]): Promise<TypeReturn> {\n if (!originalMethod) {\n throw new Error('Method not found');\n }\n\n try {\n return await originalMethod.apply(this, args);\n } catch (error) {\n if (!(error instanceof CustomError)) {\n throwCustomError(error, errorMessage, DatabaseError);\n } else {\n throw error;\n }\n }\n };\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@seedcord/plugins",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.3",
|
|
5
5
|
"description": "Official plugins for Seedcord Discord bot framework",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -28,14 +28,15 @@
|
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"chalk": "5.6.2",
|
|
31
|
-
"
|
|
32
|
-
"
|
|
31
|
+
"envapt": "4.0.1",
|
|
32
|
+
"mongoose": "8.19.2",
|
|
33
33
|
"reflect-metadata": "0.2.2",
|
|
34
|
-
"
|
|
35
|
-
"seedcord": "^0.
|
|
34
|
+
"type-fest": "5.1.0",
|
|
35
|
+
"@seedcord/types": "^0.3.0",
|
|
36
|
+
"seedcord": "^0.5.0"
|
|
36
37
|
},
|
|
37
38
|
"devDependencies": {
|
|
38
|
-
"@seedcord/eslint-config": "^1.2.
|
|
39
|
+
"@seedcord/eslint-config": "^1.2.3",
|
|
39
40
|
"@seedcord/tsconfig": "^1.0.5",
|
|
40
41
|
"@seedcord/tsup-config": "^1.0.5"
|
|
41
42
|
},
|