import type { Guard } from "auth"; import { SchemaObject } from "core"; import type { EventManager } from "core/events"; import type { Static, TSchema } from "core/utils"; import type { Connection, EntityManager } from "data"; import type { Hono } from "hono"; export type ModuleBuildContext = { connection: Connection; server: Hono; em: EntityManager; emgr: EventManager; guard: Guard; }; export abstract class Module> { private _built = false; private _schema: SchemaObject>; private _listener: any = () => null; constructor( initial?: Partial>, protected _ctx?: ModuleBuildContext ) { this._schema = new SchemaObject(this.getSchema(), initial, { forceParse: this.useForceParse(), onUpdate: async (c) => { await this._listener(c); }, restrictPaths: this.getRestrictedPaths(), overwritePaths: this.getOverwritePaths(), onBeforeUpdate: this.onBeforeUpdate.bind(this) }); } onBeforeUpdate(from: ConfigSchema, to: ConfigSchema): ConfigSchema | Promise { return to; } setListener(listener: (c: ReturnType<(typeof this)["getSchema"]>) => void | Promise) { this._listener = listener; return this; } // @todo: test all getSchema() for additional properties abstract getSchema(); useForceParse() { return false; } getRestrictedPaths(): string[] | undefined { return undefined; } /** * These paths will be overwritten, even when "patch" is called. * This is helpful if there are keys that contains records, which always be sent in full. */ getOverwritePaths(): (RegExp | string)[] | undefined { return undefined; } get configDefault(): Static> { return this._schema.default(); } get config(): Static> { return this._schema.get(); } setContext(ctx: ModuleBuildContext) { this._ctx = ctx; return this; } schema() { return this._schema; } get ctx() { if (!this._ctx) { throw new Error("Context not set"); } return this._ctx; } async build() { throw new Error("Not implemented"); } setBuilt() { this._built = true; this._schema = new SchemaObject(this.getSchema(), this.toJSON(true), { onUpdate: async (c) => { await this._listener(c); }, forceParse: this.useForceParse(), restrictPaths: this.getRestrictedPaths(), overwritePaths: this.getOverwritePaths(), onBeforeUpdate: this.onBeforeUpdate.bind(this) }); } isBuilt() { return this._built; } throwIfNotBuilt() { if (!this._built) { throw new Error("Config not built: " + this.constructor.name); } } toJSON(secrets?: boolean): Static> { return this.config; } }