From e8177e914f0c17ef9a75f964367aa9964910d410 Mon Sep 17 00:00:00 2001 From: mrinc Date: Sat, 22 Jul 2023 11:33:17 +0200 Subject: [PATCH 01/47] prepare for v9 Updated to use yaml instead of json updated pluginClient definitions for more consistent inits Updated templates for new platform Removing default service plugins from final npm package --- .gitignore | 3 + nodejs/.npmignore | 7 + nodejs/package-lock.json | 11 +- nodejs/package.json | 9 +- nodejs/src/interfaces/events.ts | 23 +-- nodejs/src/plugins/config-default/plugin.ts | 22 ++- .../src/plugins/config-default/sec.config.ts | 2 +- nodejs/src/plugins/events-default/plugin.ts | 18 +-- nodejs/src/plugins/service-default0/plugin.ts | 3 - nodejs/src/plugins/service-default1/plugin.ts | 9 +- nodejs/src/plugins/service-default2/plugin.ts | 3 - nodejs/src/plugins/service-default3/plugin.ts | 3 - nodejs/src/service/service.ts | 2 +- nodejs/src/service/serviceClient.ts | 33 ++-- nodejs/src/serviceBase/base.ts | 2 +- nodejs/src/serviceBase/services.ts | 10 +- .../events/emitStreamAndReceiveStream.ts | 2 +- nodejs/templates/events.ts | 142 ++++++++++++++++-- nodejs/templates/logger.ts | 107 +++++++++++-- nodejs/templates/plugin.ts | 15 +- nodejs/templates/pluginClient.ts | 12 ++ nodejs/templates/sec.config.json | 6 - nodejs/templates/sec.config.ts | 6 +- nodejs/templates/sec.config.yaml | 14 ++ 24 files changed, 344 insertions(+), 120 deletions(-) create mode 100644 nodejs/.npmignore create mode 100644 nodejs/templates/pluginClient.ts delete mode 100644 nodejs/templates/sec.config.json create mode 100644 nodejs/templates/sec.config.yaml diff --git a/.gitignore b/.gitignore index 2752735..518c726 100644 --- a/.gitignore +++ b/.gitignore @@ -14,11 +14,14 @@ node_modules /coverage /junit.json /sec.config.json +/sec.config.yaml /nodejs/junit.json /nodejs/sec.config.json +/nodejs/sec.config.yaml /nodejs/node_modules /nodejs/.nyc_output /nodejs/lib +/nodejs/coverage /dotnet/[Dd]ebug/ /dotnet/[Dd]ebugPublic/ /dotnet/[Rr]elease/ diff --git a/nodejs/.npmignore b/nodejs/.npmignore new file mode 100644 index 0000000..ce6e312 --- /dev/null +++ b/nodejs/.npmignore @@ -0,0 +1,7 @@ +/junit.json +/sec.config.json +/sec.config.yaml +/node_modules +/.nyc_output +/lib/plugins/service- +/src \ No newline at end of file diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index a639e72..00b6f78 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -10,7 +10,8 @@ "hasInstallScript": true, "license": "AGPL-3.0-only", "dependencies": { - "@bettercorp/tools": "^2.0.20220714140658" + "@bettercorp/tools": "^2.0.20220714140658", + "yaml": "^2.3.1" }, "bin": { "bsb": "lib/bootstrap.js" @@ -3773,6 +3774,14 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "dev": true }, + "node_modules/yaml": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", + "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/nodejs/package.json b/nodejs/package.json index d1037b1..d0747f5 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -5,8 +5,8 @@ "url": "https://github.com/BetterCorp/better-service-base" }, "engines": { - "npm": ">=8.0.0", - "node": ">=16.0.0" + "npm": ">=9.0.0", + "node": ">=18.0.0" }, "scripts": { "dev": "nodemon --config ./nodemon.json", @@ -29,7 +29,7 @@ "README.md" ], "main": "lib/index.js", - "version": "8.4.0-rc", + "version": "9.0.0-rc0", "devDependencies": { "@types/assert": "^1.5.6", "@types/chai": "^4.3.3", @@ -46,7 +46,8 @@ "yargs": "^17.5.1" }, "dependencies": { - "@bettercorp/tools": "^2.0.20220714140658" + "@bettercorp/tools": "^2.0.20220714140658", + "yaml": "^2.3.1" }, "bsb_project": true } diff --git a/nodejs/src/interfaces/events.ts b/nodejs/src/interfaces/events.ts index 7f2293d..fc08f39 100644 --- a/nodejs/src/interfaces/events.ts +++ b/nodejs/src/interfaces/events.ts @@ -32,11 +32,7 @@ export type DynamicallyReferencedMethodEmitEARIEvents< > = ArgsReference extends true ? Interface[Method] extends (...a: infer Arguments) => infer Return ? ShowTimeout extends true - ? [ - event: Method, - timeoutSeconds?: number, - ...a: Arguments - ] + ? [event: Method, timeoutSeconds?: number, ...a: Arguments] : [event: Method, ...a: Arguments] : [event: Method, noMatchingEvent: never] : Interface[Method] extends (...a: infer Arguments) => infer Return @@ -51,7 +47,7 @@ export interface IServiceEvents< onReturnableEvents, emitReturnableEvents, onBroadcast, - emitBroadcast, + emitBroadcast > { onBroadcast( ...args: DynamicallyReferencedMethodOnIEvents< @@ -73,7 +69,8 @@ export interface IServiceEvents< false > ): Promise; - onEventSpecific(serverId: string, + onEventSpecific( + serverId: string, ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, TA, @@ -86,7 +83,8 @@ export interface IServiceEvents< TA > ): Promise; - emitEventSpecific(serverId: string, + emitEventSpecific( + serverId: string, ...args: DynamicallyReferencedMethodEmitIEvents< DynamicallyReferencedMethodType, TA @@ -99,7 +97,8 @@ export interface IServiceEvents< true > ): Promise; - onReturnableEventSpecific(serverId: string, + onReturnableEventSpecific( + serverId: string, ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, TA, @@ -118,7 +117,8 @@ export interface IServiceEvents< TA, false >; - emitEventAndReturnSpecific(serverId: string, + emitEventAndReturnSpecific( + serverId: string, ...args: DynamicallyReferencedMethodEmitEARIEvents< DynamicallyReferencedMethodType, TA, @@ -142,7 +142,8 @@ export interface IServiceEvents< TA, false >; - emitEventAndReturnTimedSpecific(serverId: string, + emitEventAndReturnTimedSpecific( + serverId: string, ...args: DynamicallyReferencedMethodEmitEARIEvents< DynamicallyReferencedMethodType, TA, diff --git a/nodejs/src/plugins/config-default/plugin.ts b/nodejs/src/plugins/config-default/plugin.ts index ac5163c..984f239 100644 --- a/nodejs/src/plugins/config-default/plugin.ts +++ b/nodejs/src/plugins/config-default/plugin.ts @@ -10,6 +10,7 @@ import { IPluginLogger } from "../../interfaces/logger"; import { ConfigBase } from "../../config/config"; import { PluginConfig } from "./sec.config"; import { IDictionary } from "@bettercorp/tools/lib/Interfaces"; +import { parse, stringify } from "yaml"; export class Config extends ConfigBase { public readonly hehe = "I am a string"; @@ -92,16 +93,16 @@ export class Config extends ConfigBase { plugins: {}, }; if (fs.existsSync(this._secConfigFilePath)) { - defConfig = JSON.parse( - fs.readFileSync(this._secConfigFilePath, "utf8").toString() - ) as ServiceConfig; - defConfig.plugins = defConfig.plugins || {}; - defConfig.deploymentProfiles = defConfig.deploymentProfiles || {}; + let tdefConfig = + parse(fs.readFileSync(this._secConfigFilePath, "utf8").toString()) ?? + ({} as ServiceConfig); + defConfig.plugins = tdefConfig.plugins ?? {}; + defConfig.deploymentProfiles = tdefConfig.deploymentProfiles ?? {}; defConfig.deploymentProfiles.default = - defConfig.deploymentProfiles.default || {}; + defConfig.deploymentProfiles.default ?? {}; } else { await this.log.debug( - "! sec.config.json CAN`T BE FOUND ... we will try create one / work in memory! {secFile}", + "! sec.config.yaml CAN`T BE FOUND ... we will try create one / work in memory! {secFile}", { secFile: this._secConfigFilePath } ); } @@ -124,10 +125,7 @@ export class Config extends ConfigBase { try { if (fs.existsSync(this._secConfigFilePath)) fs.accessSync(this._secConfigFilePath, fs.constants.W_OK); - fs.writeFileSync( - this._secConfigFilePath, - JSON.stringify(this._appConfig, "" as any, 2) // todo: replace this with typesafe formatting version - ); + fs.writeFileSync(this._secConfigFilePath, stringify(this._appConfig)); this._canWriteChanges = true; } catch (e) { await this.log.warn( @@ -166,7 +164,7 @@ export class Config extends ConfigBase { } fs.writeFileSync( this._secConfigFilePath, - JSON.stringify(this._appConfig, "" as any, 2) // todo: replace this with typesafe formatting version + stringify(this._appConfig) // todo: replace this with typesafe formatting version ); } } diff --git a/nodejs/src/plugins/config-default/sec.config.ts b/nodejs/src/plugins/config-default/sec.config.ts index 431612b..c859494 100644 --- a/nodejs/src/plugins/config-default/sec.config.ts +++ b/nodejs/src/plugins/config-default/sec.config.ts @@ -14,7 +14,7 @@ export class Config extends SecConfig { ConfigFile: existingConfig.ConfigFile || process.env.BSB_SEC_JSON || - "./sec.config.json", + "./sec.config.yaml", }; } } diff --git a/nodejs/src/plugins/events-default/plugin.ts b/nodejs/src/plugins/events-default/plugin.ts index 82dcf1e..39a3785 100644 --- a/nodejs/src/plugins/events-default/plugin.ts +++ b/nodejs/src/plugins/events-default/plugin.ts @@ -27,14 +27,14 @@ export class Events extends EventsBase { this.eas = new emitStreamAndReceiveStream(log); } - public dispose() { + public override dispose() { this.broadcast.dispose(); this.emit.dispose(); this.ear.dispose(); this.eas.dispose(); } - public async onBroadcast( + public override async onBroadcast( callerPluginName: string, pluginName: string, event: string, @@ -42,7 +42,7 @@ export class Events extends EventsBase { ): Promise { await this.broadcast.onBroadcast(callerPluginName, pluginName, event, listener); } - public async emitBroadcast( + public override async emitBroadcast( callerPluginName: string, pluginName: string, event: string, @@ -51,7 +51,7 @@ export class Events extends EventsBase { await this.broadcast.emitBroadcast(callerPluginName, pluginName, event, args); } - public async onEvent( + public override async onEvent( callerPluginName: string, pluginName: string, event: string, @@ -59,7 +59,7 @@ export class Events extends EventsBase { ): Promise { await this.emit.onEvent(callerPluginName, pluginName, event, listener); } - public async emitEvent( + public override async emitEvent( callerPluginName: string, pluginName: string, event: string, @@ -68,7 +68,7 @@ export class Events extends EventsBase { await this.emit.emitEvent(callerPluginName, pluginName, event, args); } - public async onReturnableEvent( + public override async onReturnableEvent( callerPluginName: string, pluginName: string, event: string, @@ -81,7 +81,7 @@ export class Events extends EventsBase { listener ); } - public async emitEventAndReturn( + public override async emitEventAndReturn( callerPluginName: string, pluginName: string, event: string, @@ -97,14 +97,14 @@ export class Events extends EventsBase { ); } - public async receiveStream( + public override async receiveStream( callerPluginName: string, listener: { (error: Error | null, stream: Readable): Promise }, timeoutSeconds?: number ): Promise { return this.eas.receiveStream(callerPluginName, listener, timeoutSeconds); } - public async sendStream( + public override async sendStream( callerPluginName: string, streamId: string, stream: Readable diff --git a/nodejs/src/plugins/service-default0/plugin.ts b/nodejs/src/plugins/service-default0/plugin.ts index e979e93..b30b17b 100644 --- a/nodejs/src/plugins/service-default0/plugin.ts +++ b/nodejs/src/plugins/service-default0/plugin.ts @@ -9,9 +9,6 @@ export class Service extends ServicesBase { super(pluginName, cwd, pluginCwd, log); this.testClient = new testClient(this); } - public override async init() { - await this.testClient.init(); - } public override async run() { await this.testClient.abc(); } diff --git a/nodejs/src/plugins/service-default1/plugin.ts b/nodejs/src/plugins/service-default1/plugin.ts index b59bb29..586aa61 100644 --- a/nodejs/src/plugins/service-default1/plugin.ts +++ b/nodejs/src/plugins/service-default1/plugin.ts @@ -58,13 +58,8 @@ export class testClient extends ServicesClient< testCallable, any > { - public readonly _pluginName: string = "service-default1"; - constructor( - self: ServicesBase - ) { - super(self); - } - public async init(): Promise { + public override readonly pluginName: string = "service-default1"; + public override async init(): Promise { const self = this; this._plugin.onEvent("onEmittable", async (a: number, b: number) => { await self._plugin.log.warn("onEmittable ({a},{b})", { a, b }); diff --git a/nodejs/src/plugins/service-default2/plugin.ts b/nodejs/src/plugins/service-default2/plugin.ts index 406d044..c0a439a 100644 --- a/nodejs/src/plugins/service-default2/plugin.ts +++ b/nodejs/src/plugins/service-default2/plugin.ts @@ -9,9 +9,6 @@ export class Service extends ServicesBase { super(pluginName, cwd, pluginCwd, log); this.testClient = new testClient(this); } - public override async init() { - await this.testClient.init(); - } public override async run() { await this.testClient.abc(); } diff --git a/nodejs/src/plugins/service-default3/plugin.ts b/nodejs/src/plugins/service-default3/plugin.ts index e44914f..207c210 100644 --- a/nodejs/src/plugins/service-default3/plugin.ts +++ b/nodejs/src/plugins/service-default3/plugin.ts @@ -9,9 +9,6 @@ export class Service extends ServicesBase { super(pluginName, cwd, pluginCwd, log); this.testClient = new testClient(this); } - public override async init() { - await this.testClient.init(); - } public override async run() { await this.testClient.abc(); } diff --git a/nodejs/src/service/service.ts b/nodejs/src/service/service.ts index d0fe198..6dd629e 100644 --- a/nodejs/src/service/service.ts +++ b/nodejs/src/service/service.ts @@ -46,7 +46,7 @@ export class ServicesBase< async run(): Promise {} - public registerPluginClient< + public initPluginClient< pluginClientOnEvents, pluginClientEmitEvents, pluginClientOnReturnableEvents, diff --git a/nodejs/src/service/serviceClient.ts b/nodejs/src/service/serviceClient.ts index 5244f6c..6984c80 100644 --- a/nodejs/src/service/serviceClient.ts +++ b/nodejs/src/service/serviceClient.ts @@ -19,6 +19,7 @@ import { ServiceCallable, ServiceBroadcasts, } from "./base"; +import { Tools } from '@bettercorp/tools'; export class RegisteredPlugin< onEvents, @@ -76,7 +77,8 @@ export class RegisteredPlugin< ): Promise { throw ErrorMessages.BSBNotInit; } - onEventSpecific(serverId: string, + onEventSpecific( + serverId: string, ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, TA, @@ -93,7 +95,8 @@ export class RegisteredPlugin< ): Promise { throw ErrorMessages.BSBNotInit; } - emitEventSpecific(serverId: string, + emitEventSpecific( + serverId: string, ...args: DynamicallyReferencedMethodEmitIEvents< DynamicallyReferencedMethodType, TA @@ -110,7 +113,8 @@ export class RegisteredPlugin< ): Promise { throw ErrorMessages.BSBNotInit; } - onReturnableEventSpecific(serverId: string, + onReturnableEventSpecific( + serverId: string, ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, TA, @@ -133,7 +137,8 @@ export class RegisteredPlugin< > { throw ErrorMessages.BSBNotInit; } - emitEventAndReturnSpecific(serverId: string, + emitEventAndReturnSpecific( + serverId: string, ...args: DynamicallyReferencedMethodEmitEARIEvents< DynamicallyReferencedMethodType, TA, @@ -161,7 +166,8 @@ export class RegisteredPlugin< > { throw ErrorMessages.BSBNotInit; } - emitEventAndReturnTimedSpecific(serverId: string, + emitEventAndReturnTimedSpecific( + serverId: string, ...args: DynamicallyReferencedMethodEmitEARIEvents< DynamicallyReferencedMethodType, TA, @@ -198,7 +204,7 @@ export class ServicesClient< onBroadcast = ServiceBroadcasts, emitBroadcast = ServiceBroadcasts > { - public readonly _pluginName!: string; + public readonly pluginName!: string; public readonly initBeforePlugins?: Array; public readonly initAfterPlugins?: Array; public readonly runBeforePlugins?: Array; @@ -215,7 +221,12 @@ export class ServicesClient< onBroadcast, emitBroadcast >; - protected async _register(): Promise { + + public async _init(): Promise { + if (!Tools.isString(this.pluginName) || this.pluginName === "") { + throw 'pluginName is not set in this client. Please update the clients definition ' + } + // We must add the inits/runs list to the referenced service in order to change the init and run order (this._referencedPlugin as any).initBeforePlugins = ( this._referencedPlugin.initBeforePlugins || [] @@ -229,8 +240,9 @@ export class ServicesClient< (this._referencedPlugin as any).runAfterPlugins = ( this._referencedPlugin.runAfterPlugins || [] ).concat(this.runAfterPlugins || []); + if (this._plugin === undefined) { - this._plugin = await this._referencedPlugin.registerPluginClient< + this._plugin = await this._referencedPlugin.initPluginClient< onEvents, emitEvents, onReturnableEvents, @@ -239,9 +251,12 @@ export class ServicesClient< any, onBroadcast, emitBroadcast - >(this._pluginName); + >(this.pluginName); } } + + public async init(): Promise { + } constructor(self: ServicesBase) { this._referencedPlugin = self; diff --git a/nodejs/src/serviceBase/base.ts b/nodejs/src/serviceBase/base.ts index e726307..f151ec3 100644 --- a/nodejs/src/serviceBase/base.ts +++ b/nodejs/src/serviceBase/base.ts @@ -99,7 +99,7 @@ export class SBBase { } ): void { SBBase.setupServicePluginSpecific(plugin, events); - (plugin as unknown as ServicesBase).registerPluginClient = async ( + (plugin as unknown as ServicesBase).initPluginClient = async ( pluginName: string ): Promise> => { let mappedPluginName = await config.getAppPluginMappedName(pluginName); diff --git a/nodejs/src/serviceBase/services.ts b/nodejs/src/serviceBase/services.ts index 0c4c7cf..c78733a 100644 --- a/nodejs/src/serviceBase/services.ts +++ b/nodejs/src/serviceBase/services.ts @@ -5,6 +5,7 @@ import { SBBase } from "./base"; import { ServicesBase } from "../service/service"; import { ConfigBase } from "../config/config"; import { ErrorMessages } from "../interfaces/static"; +import { ServicesClient } from '../'; export class SBServices { private _activeServices: Array = []; @@ -112,16 +113,19 @@ export class SBServices { } ); - for (let client of (servicePlugin as any)._clients) { + for (let client of ((servicePlugin as any)._clients as Array)) { await this.log.info( "Setup {pluginName} ({mappedName}) references {clientPlugin}", { pluginName: plugin.name, mappedName: plugin.mappedName, - clientPlugin: client._pluginName, + clientPlugin: client.pluginName, } ); - await client._register(); + await client._init(); + (client as any)._init = undefined; // specifically remove this method from the client so it cannot be re-called / removes from ram + await client.init(); + (client as any).init = undefined; // specifically remove this method from the client so it cannot be re-called / removes from ram } await this.log.info( diff --git a/nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts b/nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts index d40fd5b..165d375 100644 --- a/nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts +++ b/nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts @@ -246,7 +246,7 @@ export function emitStreamAndReceiveStream( runTest("512KB"); runTest("1MB"); runTest("16MB"); - runTest("128MB", 1); + //runTest("128MB", 1); //runTest("128MB", 4); //runTest('512MB', 16); diff --git a/nodejs/templates/events.ts b/nodejs/templates/events.ts index 3338508..8056d37 100644 --- a/nodejs/templates/events.ts +++ b/nodejs/templates/events.ts @@ -1,23 +1,135 @@ -import { CEvents } from "@bettercorp/service-base/lib/interfaces/events"; -import { MyPluginConfig } from './sec.config'; +import { EventsBase, IPluginLogger } from "@bettercorp/service-base"; +import { Readable } from "stream"; +import { PluginConfig } from "./sec.config"; -export class Events extends CEvents { - init(): Promise { - return new Promise((resolve) => { - resolve(); - }); +export class Events extends EventsBase { + constructor( + pluginName: string, + cwd: string, + pluginCwd: string, + log: IPluginLogger + ) { + super(pluginName, cwd, pluginCwd, log); + /** + * Add any other constructor code here } - async onEvent(callerPluginName: string, pluginName: string, event: string, listener: { (data: ArgsDataType): Promise; }): Promise { - throw 'onEvent not setup'; + public dispose() { + /** + * TODO: dispose of all events + * + * Cleanup/close connections that are not needed. + */ } - async emitEvent(callerPluginName: string, pluginName: string, event: string, data?: ArgsDataType): Promise { - throw 'emitEvent not setup'; + + public override async onBroadcast( + callerPluginName: string, + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to listen to events that are emitted by other plugins + * The difference between an emitEvent and an emitBroadcast is that an emitEvent is only + * handled by a single plugin whereas an emitBroadcast is handled by all plugins listening + * for that event + */ + } + public override async emitBroadcast( + callerPluginName: string, + pluginName: string, + event: string, + args: Array + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to emit an event that is handled by all plugins listening + * for that event + */ + } + + public override async onEvent( + callerPluginName: string, + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to listen to events that are emitted by other plugins + * The difference between an emitEvent and an emitBroadcast is that an emitEvent is only + * handled by a single plugin + */ + } + + public override async emitEvent( + callerPluginName: string, + pluginName: string, + event: string, + args: Array + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to emit an event that is handled by a single plugin + */ } - async onReturnableEvent(callerPluginName: string, pluginName: string, event: string, listener: { (data: ArgsDataType): Promise; }): Promise { - throw 'onReturnableEvent not setup'; + + public override async onReturnableEvent( + callerPluginName: string, + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to listen to events that are emitted by other plugins + * and return a value to the caller + */ + } + + public override async emitEventAndReturn( + callerPluginName: string, + pluginName: string, + event: string, + timeoutSeconds: number, + args: Array + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to emit an event that is handled by a single plugin + * and returns a value to the caller + */ } - async emitEventAndReturn(callerPluginName: string, pluginName: string, event: string, data?: ArgsDataType, timeoutSeconds?: number): Promise { - throw 'emitEventAndReturn not setup'; + + public override async receiveStream( + callerPluginName: string, + listener: { (error: Error | null, stream: Readable): Promise }, + timeoutSeconds?: number + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to receive a stream from another plugin + * and returns a streamId that can be used to send data back to the caller + */ + } + + public override async sendStream( + callerPluginName: string, + streamId: string, + stream: Readable + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to send a stream to another plugin + */ } } diff --git a/nodejs/templates/logger.ts b/nodejs/templates/logger.ts index e39f61a..3df4cd6 100644 --- a/nodejs/templates/logger.ts +++ b/nodejs/templates/logger.ts @@ -1,20 +1,99 @@ -import { CLogger } from "@bettercorp/service-base/lib/interfaces/logger"; -import { MyPluginConfig } from './sec.config'; +import { LoggerBase, IPluginLogger, LogMeta } from "@bettercorp/service-base"; +import { PluginConfig } from './sec.config'; -export class Logger extends CLogger { - async debug(plugin: string, ...data: any[]): Promise { - throw 'debug not setup'; +export class Logger extends LoggerBase { + constructor( + pluginName: string, + cwd: string, + pluginCwd: string, + defaultLogger: IPluginLogger + ) { + super(pluginName, cwd, pluginCwd, defaultLogger); } - async info(plugin: string, ...data: any[]): Promise { - throw 'info not setup'; + + public async reportStat( + plugin: string, + key: string, + value: number + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to report a stat to your logging platform + */ + } + + public async reportTextStat( + plugin: string, + message: T, + meta?: LogMeta, + hasPIData?: boolean + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to report a stat in text to your logging platform + */ + } + + public async debug( + plugin: string, + message: T, + meta?: LogMeta, + hasPIData?: boolean + ): Promise { + if (!this.runningDebug) return; + /** + * TODO: implement + * + * This function allows for a plugin to report a debug message to your logging platform + */ } - async warn(plugin: string, ...data: any[]): Promise { - throw 'warn not setup'; + + public async info( + plugin: string, + message: T, + meta?: LogMeta, + hasPIData?: boolean + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to report an info message to your logging platform + */ } - async error(plugin: string, ...data: any[]): Promise { - throw 'error not setup'; + + public async warn( + plugin: string, + message: T, + meta?: LogMeta, + hasPIData?: boolean + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to report a warning message to your logging platform + */ } - async fatal(plugin: string, ...data: any[]): Promise { - throw 'fatal not setup'; + + public async error( + plugin: string, + message: T, + meta?: LogMeta, + hasPIData?: boolean + ): Promise; + public async error(plugin: string, error: Error): Promise; + public async error( + plugin: string, + messageOrError: T | Error, + meta?: LogMeta, + hasPIData?: boolean + ): Promise { + /** + * TODO: implement + * + * This function allows for a plugin to report an error message to your logging platform + * log.fatal() calls this method first before terminating the process + */ } -} \ No newline at end of file +} diff --git a/nodejs/templates/plugin.ts b/nodejs/templates/plugin.ts index b5468a0..178d44d 100644 --- a/nodejs/templates/plugin.ts +++ b/nodejs/templates/plugin.ts @@ -1,18 +1,7 @@ import { CPlugin, CPluginClient } from "@bettercorp/service-base/lib/interfaces/plugins"; -import { MyPluginConfig } from './sec.config'; +import { PluginConfig } from './sec.config'; -export class demo extends CPluginClient { - public readonly _pluginName: string = "demo"; - - async triggerServerOnEvent(data: any): Promise { - await this.emitEvent("exampleOnEvent", data); - } - async triggerServerMethod(data: any): Promise { - return this.emitEventAndReturn("exampleServerMethod", data); - } -} - -export class Plugin extends CPlugin { +export class Plugin extends CPlugin { async init(): Promise { await this.onEvent(null, "exampleOnEvent", x => self.exampleOnEvent(x)); await this.onReturnableEvent(null, "exampleServerMethod", self.exampleServerMethod); diff --git a/nodejs/templates/pluginClient.ts b/nodejs/templates/pluginClient.ts new file mode 100644 index 0000000..457a036 --- /dev/null +++ b/nodejs/templates/pluginClient.ts @@ -0,0 +1,12 @@ +import { CPlugin, CPluginClient } from "@bettercorp/service-base/lib/interfaces/plugins"; + +export class demo extends CPluginClient { + public readonly pluginName: string = "demo"; + + async triggerServerOnEvent(data: any): Promise { + await this.emitEvent("exampleOnEvent", data); + } + async triggerServerMethod(data: any): Promise { + return this.emitEventAndReturn("exampleServerMethod", data); + } +} diff --git a/nodejs/templates/sec.config.json b/nodejs/templates/sec.config.json deleted file mode 100644 index da3c32f..0000000 --- a/nodejs/templates/sec.config.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "plugins": {}, - "deploymentProfiles": { - "default": {} - } -} \ No newline at end of file diff --git a/nodejs/templates/sec.config.ts b/nodejs/templates/sec.config.ts index b701205..4e6244c 100644 --- a/nodejs/templates/sec.config.ts +++ b/nodejs/templates/sec.config.ts @@ -1,9 +1,9 @@ -export interface MyPluginConfig { +export interface PluginConfig { } -export default (pluginName: string, existingPluginConfig: any): MyPluginConfig => { - let newConfig: MyPluginConfig = { +export default (pluginName: string, existingPluginConfig: any): PluginConfig => { + let newConfig: PluginConfig = { }; return newConfig; diff --git a/nodejs/templates/sec.config.yaml b/nodejs/templates/sec.config.yaml new file mode 100644 index 0000000..df3d5ef --- /dev/null +++ b/nodejs/templates/sec.config.yaml @@ -0,0 +1,14 @@ +deploymentProfiles: + default: + config-default: + mappedName: config-default + enabled: true + events-default: + mappedName: events-default + enabled: true + log-default: + mappedName: log-default + enabled: true +plugins: + log-default: {} + events-default: {} From 18e8f30fd32bdd58bf22b8331775e8c511100dab Mon Sep 17 00:00:00 2001 From: mrinc Date: Sat, 22 Jul 2023 18:05:13 +0200 Subject: [PATCH 02/47] Added a generic client Added more tests Added more documentation on methods Updated templates -1 --- nodejs/src/clients/service-generic/plugin.ts | 132 ++++++++ nodejs/src/events/events.ts | 118 ++++++- nodejs/src/index.ts | 1 + nodejs/src/interfaces/events.ts | 332 ++++++++++++++++++- nodejs/src/logger/logger.ts | 2 +- nodejs/src/service/serviceClient.ts | 330 +++++++++++++++++- nodejs/src/tests/events/events.ts | 105 ++++++ nodejs/src/tests/interfaces/base.ts | 26 ++ nodejs/src/tests/interfaces/static.ts | 63 ++++ nodejs/src/tests/logger/logger.ts | 177 ++++++++++ nodejs/templates/plugin.ts | 4 +- nodejs/templates/pluginClient.ts | 4 +- 12 files changed, 1263 insertions(+), 31 deletions(-) create mode 100644 nodejs/src/clients/service-generic/plugin.ts create mode 100644 nodejs/src/tests/events/events.ts create mode 100644 nodejs/src/tests/interfaces/base.ts create mode 100644 nodejs/src/tests/interfaces/static.ts create mode 100644 nodejs/src/tests/logger/logger.ts diff --git a/nodejs/src/clients/service-generic/plugin.ts b/nodejs/src/clients/service-generic/plugin.ts new file mode 100644 index 0000000..acac416 --- /dev/null +++ b/nodejs/src/clients/service-generic/plugin.ts @@ -0,0 +1,132 @@ +import { Readable } from "stream"; +import { ServicesBase, ServicesClient } from "../../index"; + +export class GenericClient extends ServicesClient< + any, + any, + any, + any, + any, + any, + any +> { + public override pluginName: string = ""; + public constructor(self: ServicesBase, pluginName: string) { + super(self); + this.pluginName = pluginName; + } + + public override async init(): Promise { + await this._plugin.log.warn( + "Generic client ({pluginName}) is active. Generic client does not any type safety.", + { + pluginName: this.pluginName, + } + ); + } + + async emitEvent(event: string, ...data: Array): Promise { + return await this._plugin.emitEvent(event, ...data); + } + async onEvent( + event: string, + listener: { (...data: Array): Promise } + ): Promise { + return await this._plugin.onEvent(event, listener); + } + + async emitEventSpecific( + event: string, + serverId: string, + ...data: Array + ): Promise { + return await this._plugin.emitEventSpecific(serverId, event, ...data); + } + async onEventSpecific( + event: string, + serverId: string, + listener: { (...data: Array): Promise } + ): Promise { + return await this._plugin.onEventSpecific(serverId, event, listener); + } + + async emitEventAndReturn( + event: string, + ...data: Array + ): Promise { + return (await this._plugin.emitEventAndReturn(event, ...data)) as T; + } + async emitEventAndReturnTimed( + event: string, + timeoutSeconds: number, + ...data: Array + ): Promise { + return (await this._plugin.emitEventAndReturnTimed( + event, + timeoutSeconds, + ...data + )) as T; + } + async onReturnableEvent( + event: string, + listener: { (...data: Array): Promise } + ): Promise { + return await this._plugin.onReturnableEvent(event, listener); + } + + async emitEventAndReturnSpecific( + event: string, + serverId: string, + ...data: Array + ): Promise { + return (await this._plugin.emitEventAndReturnSpecific( + serverId, + event, + ...data + )) as T; + } + async emitEventAndReturnTimedSpecific( + event: string, + serverId: string, + timeoutSeconds: number, + ...data: Array + ): Promise { + return (await this._plugin.emitEventAndReturnTimedSpecific( + serverId, + event, + timeoutSeconds, + ...data + )) as T; + } + async onReturnableEventSpecific( + event: string, + serverId: string, + listener: { (...data: Array): Promise } + ): Promise { + return await this._plugin.onReturnableEventSpecific( + serverId, + event, + listener + ); + } + + async emitBroadcast(event: string, ...data: Array): Promise { + return await this._plugin.emitBroadcast(event, ...data); + } + async onBroadcast( + event: string, + listener: { (...data: Array): Promise } + ): Promise { + return await this._plugin.onBroadcast(event, listener); + } + + async receiveStream( + listener: { (error: Error | null, stream: Readable): Promise }, + timeoutSeconds: number + ): Promise { + return await this._plugin.receiveStream(listener, timeoutSeconds); + } + async sendStream(streamId: string, stream: Readable): Promise { + return await this._plugin.sendStream(streamId, stream); + } +} diff --git a/nodejs/src/events/events.ts b/nodejs/src/events/events.ts index 043bc4d..1bdc0ec 100644 --- a/nodejs/src/events/events.ts +++ b/nodejs/src/events/events.ts @@ -4,12 +4,30 @@ import { IPluginConfig } from "../interfaces/config"; import { DefaultBase } from "../interfaces/base"; import { ErrorMessages } from "../interfaces/static"; -export class EventsBase - extends DefaultBase -{ - constructor(pluginName: string, cwd: string,pluginCwd: string, log: IPluginLogger) { +export class EventsBase< + PluginConfigType extends IPluginConfig = any +> extends DefaultBase { + constructor( + pluginName: string, + cwd: string, + pluginCwd: string, + log: IPluginLogger + ) { super(pluginName, cwd, pluginCwd, log); } + /** + * Listens for events that are emitted by other plugins + * Broadcast events are emitted and received by all plugins + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param pluginName - The name of the plugin that is being listened to + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ public async onBroadcast( callerPluginName: string, pluginName: string, @@ -18,6 +36,18 @@ export class EventsBase ): Promise { throw ErrorMessages.EventsNotImplementedProperly; } + /** + * Emits an event that is received by all plugins + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param pluginName - The name of the plugin that is emitting the event + * @param event - The event to emit + * @param args - The arguments to pass to the event listener + * @returns Promise that resolves when the event has been emitted + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ public async emitBroadcast( callerPluginName: string, pluginName: string, @@ -26,6 +56,21 @@ export class EventsBase ): Promise { throw ErrorMessages.EventsNotImplementedProperly; } + + /** + * Listens for events that are emitted by other plugins + * Events are emitted and received by a single plugin + * Make sure to use the built in tests + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param pluginName - The name of the plugin that is being listened to + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ public async onEvent( callerPluginName: string, pluginName: string, @@ -34,6 +79,19 @@ export class EventsBase ): Promise { throw ErrorMessages.EventsNotImplementedProperly; } + /** + * Emits an event that is received by a single plugin + * Make sure to use the built in tests + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param pluginName - The name of the plugin that is emitting the event + * @param event - The event to emit + * @param args - The arguments to pass to the event listener + * @returns Promise that resolves when the event has been emitted + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ public async emitEvent( callerPluginName: string, pluginName: string, @@ -42,6 +100,21 @@ export class EventsBase ): Promise { throw ErrorMessages.EventsNotImplementedProperly; } + + /** + * Listens for events that are emitted by other plugins and return a value + * Events are emitted and received by a single plugin + * Make sure to use the built in tests + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param pluginName - The name of the plugin that is being listened to + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ public async onReturnableEvent( callerPluginName: string, pluginName: string, @@ -50,6 +123,20 @@ export class EventsBase ): Promise { throw ErrorMessages.EventsNotImplementedProperly; } + /** + * Emits an event that is received by a single plugin and returns a value + * Make sure to use the built in tests + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param pluginName - The name of the plugin that is emitting the event + * @param event - The event to emit + * @param timeoutSeconds - The number of seconds to wait for the value to be returned + * @param args - The arguments to pass to the event listener + * @returns Promise that resolves when the event has been emitted and the value has been returned + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ public async emitEventAndReturn( callerPluginName: string, pluginName: string, @@ -59,6 +146,18 @@ export class EventsBase ): Promise { throw ErrorMessages.EventsNotImplementedProperly; } + + /** + * Sets up a receive stream to receive a stream from another plugin + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param listener - The function to call when the stream is received + * @param timeoutSeconds - The number of seconds to wait for the stream to be received + * @returns Promise that resolves with the stream id that can be used to stream data to the listener + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ public async receiveStream( callerPluginName: string, listener: (error: Error | null, stream: Readable) => Promise, @@ -66,6 +165,17 @@ export class EventsBase ): Promise { throw ErrorMessages.EventsNotImplementedProperly; } + /** + * Sets up a send stream to send a stream to another plugin that created a receive stream + * + * @param callerPluginName - The name of the plugin that is calling this function + * @param streamId - The id of the stream to send data to + * @param stream - The stream to send data from + * @returns Promise that resolves when the stream has been sent + * + * @see BSB events-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} + */ sendStream( callerPluginName: string, streamId: string, diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts index 1899c4a..6df8c0b 100644 --- a/nodejs/src/index.ts +++ b/nodejs/src/index.ts @@ -12,3 +12,4 @@ export { LoggerBase } from "./logger/logger"; export { ServiceCallable } from "./service/base"; export { ServicesBase } from "./service/service"; export { ServicesClient } from "./service/serviceClient"; +export { GenericClient } from "./clients/service-generic/plugin"; diff --git a/nodejs/src/interfaces/events.ts b/nodejs/src/interfaces/events.ts index fc08f39..74af9ae 100644 --- a/nodejs/src/interfaces/events.ts +++ b/nodejs/src/interfaces/events.ts @@ -49,6 +49,26 @@ export interface IServiceEvents< onBroadcast, emitBroadcast > { + /** + * Listens for events that are emitted by other plugins + * Broadcast events are emitted and received by all plugins + * + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using broadcast events + * ```ts + * /// Plugin that emits a broadcast event + * await this.emitBroadcast('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a broadcast event + * await this.onBroadcast('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + * ``` + */ onBroadcast( ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, @@ -56,12 +76,49 @@ export interface IServiceEvents< false > ): Promise; + /** + * Emits a broadcast event that is received by all plugins that are listening for that event + * + * @param event - The event to emit + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted + * + * @example + * Basic example of using broadcast events + * ```ts + * /// Plugin that emits a broadcast event + * await this.emitBroadcast('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a broadcast event + * await this.onBroadcast('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ emitBroadcast( ...args: DynamicallyReferencedMethodEmitIEvents< DynamicallyReferencedMethodType, TA > ): Promise; + + /** + * Listens for events that are emitted by other plugins (the first plugin to receive the event will handle it) + * + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using events + * ```ts + * /// Plugin that emits an event + * await this.emitEvent('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives an event + * await this.onEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ onEvent( ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, @@ -69,6 +126,51 @@ export interface IServiceEvents< false > ): Promise; + /** + * Emits an event that is received by the first plugin that is listening for that event (depends on events service) + * + * @param event - The event to emit + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted + * + * @example + * Basic example of using events + * ```ts + * /// Plugin that emits an event + * await this.emitEvent('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives an event + * await this.onEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ + emitEvent( + ...args: DynamicallyReferencedMethodEmitIEvents< + DynamicallyReferencedMethodType, + TA + > + ): Promise; + + /** + * Listens for events that are emitted by other plugins (the first plugin to receive the event will handle it) + * The serverId allows for the event to be handled by a specific plugin + * + * @param serverId - The server ID to listen for the event on + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using events + * ```ts + * /// Plugin that emits an event + * await this.emitEventSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives an event + * await this.onEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ onEventSpecific( serverId: string, ...args: DynamicallyReferencedMethodOnIEvents< @@ -77,12 +179,26 @@ export interface IServiceEvents< false > ): Promise; - emitEvent( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise; + /** + * Emits an event that is received by the first plugin that is listening for that event (depends on events service) + * The serverId allows for the event to be handled by a specific plugin + * + * @param serverId - The server ID to emit the event on + * @param event - The event to emit + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted + * + * @example + * Basic example of using events + * ```ts + * /// Plugin that emits an event + * await this.emitEventSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives an event + * await this.onEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ emitEventSpecific( serverId: string, ...args: DynamicallyReferencedMethodEmitIEvents< @@ -90,6 +206,27 @@ export interface IServiceEvents< TA > ): Promise; + + /** + * Listens for events and retuns a value to the plugin that emitted the event + * + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * - @returns The value to return to the plugin that emitted the event + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using returnable events + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturn('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a returnable event + * await this.onReturnableEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ onReturnableEvent( ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, @@ -97,14 +234,25 @@ export interface IServiceEvents< true > ): Promise; - onReturnableEventSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise; + /** + * Emits a returnable event that is received by the first plugin that is listening for that event (depends on events service) + * + * @param event - The event listen to + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted and the value has been returned + * + * @example + * Basic example of using returnable events + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturn('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a returnable event + * await this.onReturnableEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ emitEventAndReturn( ...args: DynamicallyReferencedMethodEmitEARIEvents< DynamicallyReferencedMethodType, @@ -117,6 +265,57 @@ export interface IServiceEvents< TA, false >; + + /** + * Listens for events and retuns a value to the plugin that emitted the event + * The serverId allows for the event to be handled by a specific plugin + * + * @param serverId - The server ID to listen for the event on + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using returnable events + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturnSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a returnable event + * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ + onReturnableEventSpecific( + serverId: string, + ...args: DynamicallyReferencedMethodOnIEvents< + DynamicallyReferencedMethodType, + TA, + true + > + ): Promise; + /** + * Emits a returnable event that is received by the first plugin that is listening for that event (depends on events service) + * The serverId allows for the event to be handled by a specific plugin + * + * @param serverId - The server ID to emit the event on + * @param event - The event emit + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted and the value has been returned + * + * @example + * Basic example of using returnable events + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturnSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a returnable event + * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ emitEventAndReturnSpecific( serverId: string, ...args: DynamicallyReferencedMethodEmitEARIEvents< @@ -130,6 +329,29 @@ export interface IServiceEvents< TA, false >; + + /** + * Emits a returnable event with a custom timeout. + * + * @param event - The event to emit + * @param timeoutSeconds - How long to wait for the event to be received before timing out + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted and the value has been returned + * + * @example + * Basic example of using returnable events with timeouts + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturnTimed('myEvent', 5, 'some', 'data'); // This will be typesafe + * /// This will wait 5 seconds for the event to be received before timing out + * /// If the event is not received within 5 seconds, the promise will reject + * + * /// Plugin that receives a returnable event + * await this.onReturnableEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ emitEventAndReturnTimed( ...args: DynamicallyReferencedMethodEmitEARIEvents< DynamicallyReferencedMethodType, @@ -142,6 +364,30 @@ export interface IServiceEvents< TA, false >; + /** + * Emits a returnable event with a specific serverId and a custom timeout. + * + * @param serverId - The server ID to emit the event on + * @param event - The event to emit + * @param timeoutSeconds - How long to wait for the event to be received before timing out + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted and the value has been returned + * + * @example + * Basic example of using returnable events with timeouts + * ```ts + * /// Plugin that emits a returnable event + * + * let result = await this.emitEventAndReturnTimedSpecific('serverId', 'myEvent', 5, 'some', 'data'); // This will be typesafe + * /// This will wait 5 seconds for the event to be received before timing out + * /// If the event is not received within 5 seconds, the promise will reject + * + * /// Plugin that receives a returnable event + * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ emitEventAndReturnTimedSpecific( serverId: string, ...args: DynamicallyReferencedMethodEmitEARIEvents< @@ -155,9 +401,67 @@ export interface IServiceEvents< TA, false >; + + /** + * Gets a stream ID for another plugin to stream data to it. + * + * @param listener - Function that is called when the stream is received + * @param timeoutSeconds - How long to wait for the stream to be fully received before timing out + * @returns The stream ID that the other plugin should use to stream data to this plugin + * + * @example + * Basic example of using streams + * ```ts + * /// Plugin that receives a stream + * let streamId = await this.receiveStream( + * async (err: Error | null, stream: Readable) => { + * pipeline(stream, fs.createWriteStream('./fileout.txt'), (errf) => { + * if (errf) throw errf; + * }); + * }, + * 5 // seconds + * ); + * /// Send stream ID to other plugin + * /// you can use emitEventAndReturn to send the stream ID to the other plugin and await for the stream to finish + * + * /// Plugin that sends a stream + * /// This would listen to the event that the other plugin emits + * await this.sendStream(streamId, fs.createReadStream('./filein.txt')); + * /// and then returns OK to the other plugin + * ``` + */ receiveStream( listener: { (error: Error | null, stream: Readable): Promise }, timeoutSeconds?: number ): Promise; + + /** + * Sends a stream to another plugin + * + * @param streamId - The stream ID to stream data too + * @param stream - The stream to send + * @returns Promise that resolves when the stream has been fully sent + * + * @example + * Basic example of using streams + * ```ts + * /// Plugin that receives a stream + * let streamId = await this.receiveStream( + * async (err: Error | null, stream: Readable) => { + * pipeline(stream, fs.createWriteStream('./fileout.txt'), (errf) => { + * if (errf) throw errf; + * }); + * }, + * 5 // seconds + * ); + * /// Send stream ID to other plugin + * /// you can use emitEventAndReturn to send the stream ID to the other plugin and await for the stream to finish + * + * /// Plugin that sends a stream + * /// This would listen to the event that the other plugin emits + * await this.sendStream(streamId, fs.createReadStream('./filein.txt')); + * /// and then returns OK to the other plugin + * ``` + */ sendStream(streamId: string, stream: Readable): Promise; } diff --git a/nodejs/src/logger/logger.ts b/nodejs/src/logger/logger.ts index 099485e..ffdca8d 100644 --- a/nodejs/src/logger/logger.ts +++ b/nodejs/src/logger/logger.ts @@ -30,7 +30,7 @@ export class LoggerBase ) .join(","); else if (Tools.isDate(referencedVar)) - referencedVar = (referencedVar as Date).toISOString(); + referencedVar = referencedVar.toISOString(); else if ( Tools.isObject(referencedVar) || !Tools.isFunction(referencedVar.toString) diff --git a/nodejs/src/service/serviceClient.ts b/nodejs/src/service/serviceClient.ts index 6984c80..b9af8c3 100644 --- a/nodejs/src/service/serviceClient.ts +++ b/nodejs/src/service/serviceClient.ts @@ -42,15 +42,92 @@ export class RegisteredPlugin< onBroadcast > { + /** + * Gets a stream ID for another plugin to stream data to it. + * + * @param listener - Function that is called when the stream is received + * @param timeoutSeconds - How long to wait for the stream to be fully received before timing out + * @returns The stream ID that the other plugin should use to stream data to this plugin + * + * @example + * Basic example of using streams + * ```ts + * /// Plugin that receives a stream + * let streamId = await this.receiveStream( + * async (err: Error | null, stream: Readable) => { + * pipeline(stream, fs.createWriteStream('./fileout.txt'), (errf) => { + * if (errf) throw errf; + * }); + * }, + * 5 // seconds + * ); + * /// Send stream ID to other plugin + * /// you can use emitEventAndReturn to send the stream ID to the other plugin and await for the stream to finish + * + * /// Plugin that sends a stream + * /// This would listen to the event that the other plugin emits + * await this.sendStream(streamId, fs.createReadStream('./filein.txt')); + * /// and then returns OK to the other plugin + * ``` + */ receiveStream( listener: (error: Error | null, stream: Readable) => Promise, timeoutSeconds?: number ): Promise { throw ErrorMessages.BSBNotInit; } + /** + * Sends a stream to another plugin + * + * @param streamId - The stream ID to stream data too + * @param stream - The stream to send + * @returns Promise that resolves when the stream has been fully sent + * + * @example + * Basic example of using streams + * ```ts + * /// Plugin that receives a stream + * let streamId = await this.receiveStream( + * async (err: Error | null, stream: Readable) => { + * pipeline(stream, fs.createWriteStream('./fileout.txt'), (errf) => { + * if (errf) throw errf; + * }); + * }, + * 5 // seconds + * ); + * /// Send stream ID to other plugin + * /// you can use emitEventAndReturn to send the stream ID to the other plugin and await for the stream to finish + * + * /// Plugin that sends a stream + * /// This would listen to the event that the other plugin emits + * await this.sendStream(streamId, fs.createReadStream('./filein.txt')); + * /// and then returns OK to the other plugin + * ``` + */ sendStream(streamId: string, stream: Readable): Promise { throw ErrorMessages.BSBNotInit; } + + /** + * Listens for events that are emitted by other plugins + * Broadcast events are emitted and received by all plugins + * + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using broadcast events + * ```ts + * /// Plugin that emits a broadcast event + * await this.emitBroadcast('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a broadcast event + * await this.onBroadcast('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + * ``` + */ onBroadcast( ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, @@ -60,6 +137,24 @@ export class RegisteredPlugin< ): Promise { throw ErrorMessages.BSBNotInit; } + /** + * Emits a broadcast event that is received by all plugins that are listening for that event + * + * @param event - The event to emit + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted + * + * @example + * Basic example of using broadcast events + * ```ts + * /// Plugin that emits a broadcast event + * await this.emitBroadcast('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a broadcast event + * await this.onBroadcast('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ emitBroadcast( ...args: DynamicallyReferencedMethodEmitIEvents< DynamicallyReferencedMethodType, @@ -68,6 +163,25 @@ export class RegisteredPlugin< ): Promise { throw ErrorMessages.BSBNotInit; } + + /** + * Listens for events that are emitted by other plugins (the first plugin to receive the event will handle it) + * + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using events + * ```ts + * /// Plugin that emits an event + * await this.emitEvent('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives an event + * await this.onEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ onEvent( ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, @@ -77,6 +191,54 @@ export class RegisteredPlugin< ): Promise { throw ErrorMessages.BSBNotInit; } + + /** + * Emits an event that is received by the first plugin that is listening for that event (depends on events service) + * + * @param event - The event to emit + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted + * + * @example + * Basic example of using events + * ```ts + * /// Plugin that emits an event + * await this.emitEvent('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives an event + * await this.onEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ + emitEvent( + ...args: DynamicallyReferencedMethodEmitIEvents< + DynamicallyReferencedMethodType, + TA + > + ): Promise { + throw ErrorMessages.BSBNotInit; + } + + /** + * Listens for events that are emitted by other plugins (the first plugin to receive the event will handle it) + * The serverId allows for the event to be handled by a specific plugin + * + * @param serverId - The server ID to listen for the event on + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using events + * ```ts + * /// Plugin that emits an event + * await this.emitEventSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives an event + * await this.onEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ onEventSpecific( serverId: string, ...args: DynamicallyReferencedMethodOnIEvents< @@ -87,14 +249,26 @@ export class RegisteredPlugin< ): Promise { throw ErrorMessages.BSBNotInit; } - emitEvent( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } + /** + * Emits an event that is received by the first plugin that is listening for that event (depends on events service) + * The serverId allows for the event to be handled by a specific plugin + * + * @param serverId - The server ID to emit the event on + * @param event - The event to emit + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted + * + * @example + * Basic example of using events + * ```ts + * /// Plugin that emits an event + * await this.emitEventSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives an event + * await this.onEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * }); + */ emitEventSpecific( serverId: string, ...args: DynamicallyReferencedMethodEmitIEvents< @@ -104,6 +278,26 @@ export class RegisteredPlugin< ): Promise { throw ErrorMessages.BSBNotInit; } + /** + * Listens for events and retuns a value to the plugin that emitted the event + * + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * - @returns The value to return to the plugin that emitted the event + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using returnable events + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturn('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a returnable event + * await this.onReturnableEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ onReturnableEvent( ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, @@ -113,6 +307,27 @@ export class RegisteredPlugin< ): Promise { throw ErrorMessages.BSBNotInit; } + /** + * Listens for events and retuns a value to the plugin that emitted the event + * The serverId allows for the event to be handled by a specific plugin + * + * @param serverId - The server ID to listen for the event on + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered + * + * @example + * Basic example of using returnable events + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturnSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a returnable event + * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ onReturnableEventSpecific( serverId: string, ...args: DynamicallyReferencedMethodOnIEvents< @@ -123,6 +338,25 @@ export class RegisteredPlugin< ): Promise { throw ErrorMessages.BSBNotInit; } + /** + * Emits a returnable event that is received by the first plugin that is listening for that event (depends on events service) + * + * @param event - The event listen to + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted and the value has been returned + * + * @example + * Basic example of using returnable events + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturn('myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a returnable event + * await this.onReturnableEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ emitEventAndReturn( ...args: DynamicallyReferencedMethodEmitEARIEvents< DynamicallyReferencedMethodType, @@ -137,6 +371,27 @@ export class RegisteredPlugin< > { throw ErrorMessages.BSBNotInit; } + /** + * Emits a returnable event that is received by the first plugin that is listening for that event (depends on events service) + * The serverId allows for the event to be handled by a specific plugin + * + * @param serverId - The server ID to emit the event on + * @param event - The event emit + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted and the value has been returned + * + * @example + * Basic example of using returnable events + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturnSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * + * /// Plugin that receives a returnable event + * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ emitEventAndReturnSpecific( serverId: string, ...args: DynamicallyReferencedMethodEmitEARIEvents< @@ -152,6 +407,28 @@ export class RegisteredPlugin< > { throw ErrorMessages.BSBNotInit; } + /** + * Emits a returnable event with a custom timeout. + * + * @param event - The event to emit + * @param timeoutSeconds - How long to wait for the event to be received before timing out + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted and the value has been returned + * + * @example + * Basic example of using returnable events with timeouts + * ```ts + * /// Plugin that emits a returnable event + * let result = await this.emitEventAndReturnTimed('myEvent', 5, 'some', 'data'); // This will be typesafe + * /// This will wait 5 seconds for the event to be received before timing out + * /// If the event is not received within 5 seconds, the promise will reject + * + * /// Plugin that receives a returnable event + * await this.onReturnableEvent('myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ emitEventAndReturnTimed( ...args: DynamicallyReferencedMethodEmitEARIEvents< DynamicallyReferencedMethodType, @@ -166,6 +443,30 @@ export class RegisteredPlugin< > { throw ErrorMessages.BSBNotInit; } + /** + * Emits a returnable event with a specific serverId and a custom timeout. + * + * @param serverId - The server ID to emit the event on + * @param event - The event to emit + * @param timeoutSeconds - How long to wait for the event to be received before timing out + * @param args - The arguments to pass to the event + * @returns Promise that resolves when the event has been emitted and the value has been returned + * + * @example + * Basic example of using returnable events with timeouts + * ```ts + * /// Plugin that emits a returnable event + * + * let result = await this.emitEventAndReturnTimedSpecific('serverId', 'myEvent', 5, 'some', 'data'); // This will be typesafe + * /// This will wait 5 seconds for the event to be received before timing out + * /// If the event is not received within 5 seconds, the promise will reject + * + * /// Plugin that receives a returnable event + * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { + * /// Do something with the data + * return 'some result'; + * }); + */ emitEventAndReturnTimedSpecific( serverId: string, ...args: DynamicallyReferencedMethodEmitEARIEvents< @@ -181,6 +482,19 @@ export class RegisteredPlugin< > { throw ErrorMessages.BSBNotInit; } + /** + * Calls a method on another plugin + * + * @param method - The method to call + * @param args - The arguments to pass to the method + * @returns Promise that resolves when the method has been called + * + * @example + * Basic example of using callable methods + * ```ts + * /// Plugin that calls a method + * await this.callPluginMethod('myMethod', 'some', 'data'); // This will be typesafe + */ callPluginMethod( ...args: DynamicallyReferencedMethod< DynamicallyReferencedMethodType, diff --git a/nodejs/src/tests/events/events.ts b/nodejs/src/tests/events/events.ts new file mode 100644 index 0000000..b2645f7 --- /dev/null +++ b/nodejs/src/tests/events/events.ts @@ -0,0 +1,105 @@ +import assert from "assert"; +import { EventsBase } from "../../../src/events/events"; +import { ErrorMessages } from "../../../src/interfaces/static"; + +describe("EventsBase", function () { + describe("Constructor", async function () { + it("Should construct correctly [pluginName]", async () => { + let myobj = new EventsBase("pluginNameX", "cwd", "pluginCwd", {} as any); + assert.strictEqual(myobj.pluginName, "pluginNameX"); + }); + it("Should construct correctly [cwd]", async () => { + let myobj = new EventsBase("pluginNameX", "cwdD", "pluginCwd", {} as any); + assert.strictEqual((myobj as any).cwd, "cwdD"); + }); + it("Should construct correctly [pluginCwd]", async () => { + let myobj = new EventsBase( + "pluginNameX", + "cwdD", + "pluginCwdY", + {} as any + ); + assert.strictEqual((myobj as any).pluginCwd, "pluginCwdY"); + }); + it("Should construct correctly [logger]", async () => { + let myobj = new EventsBase("pluginNameX", "cwdD", "pluginCwdY", { + alog: true, + } as any); + assert.strictEqual((myobj as any).log.alog, true); + }); + }); + describe("Default methods", function () { + it("onBroadcast should throw", async () => { + try { + let myobj = new EventsBase("a", "b", "c", {} as any); + await myobj.onBroadcast("a", "b", "c", async () => {}); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); + } + }); + it("emitBroadcast should throw", async () => { + try { + let myobj = new EventsBase("a", "b", "c", {} as any); + await myobj.emitBroadcast("a", "b", "c", []); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); + } + }); + it("onEvent should throw", async () => { + try { + let myobj = new EventsBase("a", "b", "c", {} as any); + await myobj.onEvent("a", "b", "c", async () => {}); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); + } + }); + it("emitEvent should throw", async () => { + try { + let myobj = new EventsBase("a", "b", "c", {} as any); + await myobj.emitEvent("a", "b", "c", []); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); + } + }); + it("onReturnableEvent should throw", async () => { + try { + let myobj = new EventsBase("a", "b", "c", {} as any); + await myobj.onReturnableEvent("a", "b", "c", async () => {}); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); + } + }); + it("emitEventAndReturn should throw", async () => { + try { + let myobj = new EventsBase("a", "b", "c", {} as any); + await myobj.emitEventAndReturn("a", "b", "c", 1, []); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); + } + }); + it("receiveStream should throw", async () => { + try { + let myobj = new EventsBase("a", "b", "c", {} as any); + await myobj.receiveStream("a", async () => {}); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); + } + }); + it("sendStream should throw", async () => { + try { + let myobj = new EventsBase("a", "b", "c", {} as any); + await myobj.sendStream("a", "", {} as any); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); + } + }); + }); +}); diff --git a/nodejs/src/tests/interfaces/base.ts b/nodejs/src/tests/interfaces/base.ts new file mode 100644 index 0000000..28fd302 --- /dev/null +++ b/nodejs/src/tests/interfaces/base.ts @@ -0,0 +1,26 @@ +import assert from "assert"; +import { DefaultBase } from "../../../src/interfaces/base"; +import { ErrorMessages } from "../../../src/interfaces/static"; + +describe("DefaultBase", function () { + describe("Default methods", function () { + it("getPluginConfig should throw", async () => { + try { + let myobj = new DefaultBase("a", "b", "c", {} as any); + (myobj as any).getPluginConfig(); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.BSBNotInit); + } + }); + it("getPluginState should throw", async () => { + try { + let myobj = new DefaultBase("a", "b", "c", {} as any); + await (myobj as any).getPluginState(); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.BSBNotInit); + } + }); + }); +}); diff --git a/nodejs/src/tests/interfaces/static.ts b/nodejs/src/tests/interfaces/static.ts new file mode 100644 index 0000000..54aef1e --- /dev/null +++ b/nodejs/src/tests/interfaces/static.ts @@ -0,0 +1,63 @@ +import assert from "assert"; +import { ErrorMessages } from "../../../src/interfaces/static"; + +describe("ErrorMessages", function () { + describe("Throw errors", async function () { + it("BSBNotInit should throw", async () => { + try { + throw ErrorMessages.BSBNotInit; + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.BSBNotInit); + } + }); + it("EventsNotImplementedProperly should throw", async () => { + try { + throw ErrorMessages.EventsNotImplementedProperly; + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); + } + }); + it("PluginNotImplementedProperly should throw", async () => { + try { + throw ErrorMessages.PluginNotImplementedProperly; + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.PluginNotImplementedProperly); + } + }); + it("LoggerNotImplementedProperly should throw", async () => { + try { + throw ErrorMessages.LoggerNotImplementedProperly; + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); + } + }); + it("ConfigNotImplementedProperly should throw", async () => { + try { + throw ErrorMessages.ConfigNotImplementedProperly; + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.ConfigNotImplementedProperly); + } + }); + it("PluginClientNotImplementedProperly should throw", async () => { + try { + throw ErrorMessages.PluginClientNotImplementedProperly; + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.PluginClientNotImplementedProperly); + } + }); + it("PluginConfigNotSetupToGenerateConfig should throw", async () => { + try { + throw ErrorMessages.PluginConfigNotSetupToGenerateConfig; + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.PluginConfigNotSetupToGenerateConfig); + } + }); + it("ServicePluginNotCallableMethod should throw", async () => { + try { + throw ErrorMessages.ServicePluginNotCallableMethod; + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.ServicePluginNotCallableMethod); + } + }); + }); +}); diff --git a/nodejs/src/tests/logger/logger.ts b/nodejs/src/tests/logger/logger.ts new file mode 100644 index 0000000..7c35f4d --- /dev/null +++ b/nodejs/src/tests/logger/logger.ts @@ -0,0 +1,177 @@ +import assert from "assert"; +import { LoggerBase } from "../../../src/logger/logger"; +import { ErrorMessages } from "../../../src/interfaces/static"; + +describe("LoggerBase", function () { + describe("formatLog", function () { + it("Should return string when meta is undefined", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + assert.strictEqual(ojb.formatLog("TEST"), "TEST"); + }); + it("Should return string when meta is null", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + assert.strictEqual(ojb.formatLog("TEST", null), "TEST"); + }); + it("Should return string when meta is a string", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + assert.strictEqual(ojb.formatLog("TEST", ""), "TEST"); + }); + it("Should return string when meta is a number", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + assert.strictEqual(ojb.formatLog("TEST", 5), "TEST"); + }); + it("Should format correctly", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + assert.strictEqual(ojb.formatLog("HTEST {a}", { a: "B" }), "HTEST B"); + }); + it("Should format *null/undefined* when a value found doesnt exist", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + assert.strictEqual( + ojb.formatLog("HTEST {a}", {}), + "HTEST *null/undefined*" + ); + }); + it("Should format *null/undefined* when a value found is undefined", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + assert.strictEqual( + ojb.formatLog("HTEST {a}", { a: undefined }), + "HTEST *null/undefined*" + ); + }); + it("Should format DT in ISO when a value found is a date", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f}", { f: dt }), + "HTEST 2023-07-22T15:38:30.000Z" + ); + }); + it("Should format DT in ISO when a value found is a date 2", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f}@{e}", { e: "DD", f: dt }), + "HTEST 2023-07-22T15:38:30.000Z@DD" + ); + }); + it("Should format DT in ISO when a value found is a date 3", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + let dt = new Date(1689694710000); // 18 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f.y}@{e}", { e: "DD", f: { y: dt } }), + "HTEST 2023-07-18T15:38:30.000Z@DD" + ); + }); + it("Should format DT in ISO when a value found is a date 4", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + let dt2 = new Date(1689694710000); // 18 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f.y}@{e}:{a.0}:{a.1}", { + a: ["E", dt2], + e: "DD", + f: { y: dt }, + }), + "HTEST 2023-07-22T15:38:30.000Z@DD:E:2023-07-18T15:38:30.000Z" + ); + }); + it("Should format json when a value found is an object", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f}@{e}", { e: "DD", f: { y: dt } }), + 'HTEST {"y":"2023-07-22T15:38:30.000Z"}@DD' + ); + }); + it("Should format direct date", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("{y}", { y: dt }), + "2023-07-22T15:38:30.000Z" + ); + }); + it("Should format iso date", async () => { + const isIsoDate = (str: string) => { + if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(str)) + return false; + const d = new Date(str); + return ( + d instanceof Date && !isNaN(d.getTime()) && d.toISOString() === str + ); // valid date + }; + let ojb = new LoggerBase("", "", "", {} as any) as any; + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual(isIsoDate(ojb.formatLog("{y}", { y: dt })), true); + }); + it("Should format json when a value found is an array", async () => { + let ojb = new LoggerBase("", "", "", {} as any) as any; + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f}@{e}:{a.0}", { + a: ["E", "F"], + e: "DD", + f: { y: dt }, + }), + 'HTEST {"y":"2023-07-22T15:38:30.000Z"}@DD:E' + ); + }); + }); + + describe("Default methods", function () { + it("reportStat should throw", async () => { + try { + let myobj = new LoggerBase("a", "b", "c", {} as any); + await myobj.reportStat("a", "b", 1); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); + } + }); + it("reportTextStat should throw", async () => { + try { + let myobj = new LoggerBase("a", "b", "c", {} as any); + await myobj.reportTextStat("a", "b", 1); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); + } + }); + it("debug should throw", async () => { + try { + let myobj = new LoggerBase("a", "b", "c", {} as any); + await myobj.debug("a", "b", 1); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); + } + }); + it("info should throw", async () => { + try { + let myobj = new LoggerBase("a", "b", "c", {} as any); + await myobj.info("a", "b", 1); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); + } + }); + it("warn should throw", async () => { + try { + let myobj = new LoggerBase("a", "b", "c", {} as any); + await myobj.warn("a", "b", 1); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); + } + }); + it("error should throw", async () => { + try { + let myobj = new LoggerBase("a", "b", "c", {} as any); + await myobj.error("a", "b", 1); + assert.fail("Should have thrown"); + } catch (e: any) { + assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); + } + }); + }); +}); diff --git a/nodejs/templates/plugin.ts b/nodejs/templates/plugin.ts index 178d44d..e3ab865 100644 --- a/nodejs/templates/plugin.ts +++ b/nodejs/templates/plugin.ts @@ -1,7 +1,7 @@ -import { CPlugin, CPluginClient } from "@bettercorp/service-base/lib/interfaces/plugins"; +import { ServicesBase } from '../src/index' //"@bettercorp/service-base"; import { PluginConfig } from './sec.config'; -export class Plugin extends CPlugin { +export class Plugin extends ServicesBase { async init(): Promise { await this.onEvent(null, "exampleOnEvent", x => self.exampleOnEvent(x)); await this.onReturnableEvent(null, "exampleServerMethod", self.exampleServerMethod); diff --git a/nodejs/templates/pluginClient.ts b/nodejs/templates/pluginClient.ts index 457a036..7de695c 100644 --- a/nodejs/templates/pluginClient.ts +++ b/nodejs/templates/pluginClient.ts @@ -1,6 +1,6 @@ -import { CPlugin, CPluginClient } from "@bettercorp/service-base/lib/interfaces/plugins"; +import { ServicesClient } from '../src/index' //"@bettercorp/service-base"; -export class demo extends CPluginClient { +export class demo extends ServicesClient { public readonly pluginName: string = "demo"; async triggerServerOnEvent(data: any): Promise { From e77de17e674ecac7e3345232d6c879de0da01148 Mon Sep 17 00:00:00 2001 From: mrinc Date: Mon, 24 Jul 2023 01:10:36 +0200 Subject: [PATCH 03/47] Updated documentation --- documentation/README.md | 65 ++++++++++++++++++------------ nodejs/templates/plugin.ts | 82 ++++++++++++++++++++++++++++++-------- 2 files changed, 104 insertions(+), 43 deletions(-) diff --git a/documentation/README.md b/documentation/README.md index f5c3a8e..0d77d95 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -2,7 +2,7 @@ home: true heroText: Better-Service-Base tagline: A simple yet scalable microservice base -features: +featuresx: - title: Start Simple details: Get started quickly, expand infinitely - title: Event Based @@ -12,44 +12,57 @@ features: footer: Copyright © 2016-present BetterCorp (PTY) Ltd - All rights reserved --- -
THIS DOCUMENTATION IS A WORK IN PROGRESS
+
BSB v9 DOCUMENTATION
-[![Docker Image Size](https://img.shields.io/docker/image-size/betterweb/service-base/latest)](https://hub.docker.com/r/betterweb/service-base) -[![Docker Pulls](https://img.shields.io/docker/pulls/betterweb/service-base)](https://hub.docker.com/r/betterweb/service-base) -[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/betterweb/service-base?sort=semver)](https://hub.docker.com/r/betterweb/service-base) +# About + +BSB (Better-Service-Base) is an event-bus based microservice framework. +It is completely opensource and can work as a single node, or geo-scaled cluster. +Simplicity, flexibility and expandability were the key points when developing this framework. +*(currently only in nodejs, however it is ready for several other languages)* + +[![Intro 1](http://img.youtube.com/vi/-ulXL44D_ZI/0.jpg)](http://www.youtube.com/watch?v=-ulXL44D_ZI) +`#Sales pitch` + +## Source/Github [![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) -[![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) -[![GitHub last commit (branch)](https://img.shields.io/github/last-commit/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) [![GitHub Repo stars](https://img.shields.io/github/stars/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) -[![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/pulls) [![GitHub issues](https://img.shields.io/github/issues-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/issues) +[![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/pulls) +[![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) +[![GitHub last commit (branch)](https://img.shields.io/github/last-commit/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) [![GitHub Workflow Status](https://img.shields.io/github/workflow/status/BetterCorp/better-service-base/Build%20and%20Publish%20Containers%20(LIVE))](https://github.com/BetterCorp/better-service-base/actions/workflows/tags.yml) [![Build and Publish (EA)](https://github.com/BetterCorp/better-service-base/actions/workflows/develop.yml/badge.svg?branch=develop)](https://github.com/BetterCorp/better-service-base/actions/workflows/develop.yml) [![Build and Publish (RC)](https://github.com/BetterCorp/better-service-base/actions/workflows/master.yml/badge.svg?branch=master)](https://github.com/BetterCorp/better-service-base/actions/workflows/master.yml) + +## Container/Docker +[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) +[![Docker Image Size](https://img.shields.io/docker/image-size/betterweb/service-base/latest)](https://hub.docker.com/r/betterweb/service-base) +[![Docker Pulls](https://img.shields.io/docker/pulls/betterweb/service-base)](https://hub.docker.com/r/betterweb/service-base) +[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/betterweb/service-base?sort=semver)](https://hub.docker.com/r/betterweb/service-base) + +## NodeJS +[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) [![codecov](https://codecov.io/gh/BetterCorp/better-service-base/branch/master/graph/badge.svg)](https://codecov.io/gh/BetterCorp/better-service-base) -[![node-current (scoped)](https://img.shields.io/node/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) +[![node-current (scoped)](https://img.shields.io/node/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) [![npm](https://img.shields.io/npm/dt/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) [![npm bundle size (scoped)](https://img.shields.io/bundlephobia/min/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm (scoped)](https://img.shields.io/npm/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![Docker Sponsored Open Source](./assets/hub.docker.com_r_betterweb_service-base.png)](https://hub.docker.com/r/betterweb/service-base) +[![npm (scoped)](https://img.shields.io/npm/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) +### - Plugins +[![NodeJS Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.total&label=NodeJS%20Plugins)](https://bsbcode.dev/Market/) +[![Service Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.services&label=Service%20Plugins&color=a200ff)](https://bsbcode.dev/Market/Service/) +[![Config Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.config&label=Config%20Plugins&color=03A9F4)](https://bsbcode.dev/Market/Config/) +[![Events Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.events&label=Events%20Plugins&color=FB8C00)](https://bsbcode.dev/Market/Events/) +[![Logging Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.logging&label=Logging%20Plugins&color=43A047)](https://bsbcode.dev/Market/Logging/) -## About -BSB was designed to be a simple, expandable and server agnostic platform for simple, scalable microservice projects. - -From v8 of the BSB, a single container can be deployed with a linked volume to minize the storage space required for deployment. -See [Docker Deployment](/Deployment) for deployment configurations - - -## Getting started - -- run the docker image with the required configuration. +## Sponsors +[![Static Badge](https://img.shields.io/badge/BetterCorp-Open%20Source%20Initiative-19b5fe?logo=browserstack)](https://bettercorp.dev/?ref=better-service-base-s-os) +[![Static Badge](https://img.shields.io/badge/Docker-Sponsored%20Open%20Source-0db7ed)](https://hub.docker.com/r/betterweb/service-base?ref=better-service-base-s-os) +[![Static Badge](https://img.shields.io/badge/BrowserStack-Sponsored%20Open%20Source-0070F0?logo=browserstack)](https://www.browserstack.com/?ref=better-service-base-s-os) -Look at the [Market](/Market) for a list of active plugins and how to use them -## Sponsors +## Documentation/Usage -[BetterCorp](https://www.bettercorp.dev) -[Docker](https://www.docker.com) -[BrowserStack](https://www.browserstack.com/) \ No newline at end of file +See [Getting Started](https://bsbcode.dev/GettingStarted/) for more details \ No newline at end of file diff --git a/nodejs/templates/plugin.ts b/nodejs/templates/plugin.ts index e3ab865..540140c 100644 --- a/nodejs/templates/plugin.ts +++ b/nodejs/templates/plugin.ts @@ -1,21 +1,69 @@ -import { ServicesBase } from '../src/index' //"@bettercorp/service-base"; -import { PluginConfig } from './sec.config'; +import { ServicesBase } from "../src/index"; //"@bettercorp/service-base"; +import { + ServiceBroadcasts, + ServiceCallable, + ServiceEvents, + ServiceReturnableEvents, +} from "../src/service/base"; +import { PluginConfig } from "./sec.config"; -export class Plugin extends ServicesBase { - async init(): Promise { - await this.onEvent(null, "exampleOnEvent", x => self.exampleOnEvent(x)); - await this.onReturnableEvent(null, "exampleServerMethod", self.exampleServerMethod); - } +/// TODO: Move these interfaces to your index.ts file so your client plugins can reference them +/// The reason for the index.ts file is if you are publishing any dist-clients, they will need to reference these interfaces +export interface OnEvents extends ServiceEvents {} +export interface EmitEvents extends ServiceEvents {} +export interface OnReturnableEvents extends ServiceReturnableEvents {} +export interface EmitReturnableEvents extends ServiceReturnableEvents {} +export interface CallableMethods extends ServiceCallable {} +export interface OnBroadcastEvents extends ServiceBroadcasts {} +export interface EmitBroadcastEvents extends ServiceBroadcasts {} +/// TODO: Move these interfaces to your index.ts file so your client plugins can reference them - async exampleOnEvent(data: any): Promise { - this.log.info("Received exampleOnEvent"); - } +export class Plugin + extends ServicesBase< + PluginConfig, + OnEvents, + EmitEvents, + OnReturnableEvents, + EmitReturnableEvents, + CallableMethods, + OnBroadcastEvents, + EmitBroadcastEvents + > + implements CallableMethods +{ + /** + * initAfterPlugins is a list of plugins that must be initialized before this plugin + * This is useful if you need to initialize a plugin before/after another plugin + * For example, if you have a plugin that requires a database connection, you can + * add the database plugin to this list so that it is initialized before your plugin + * is initialized + */ + public override initAfterPlugins: string[] = []; + /** + * initBeforePlugins is a list of plugins that must be initialized after this plugin + * This is useful if you need to initialize a plugin before/after another plugin + * For example, another plugin may require your plugin to be initialized before it + * is initialized + */ + public override initBeforePlugins: string[] = []; + /** + * runAfterPlugins is a list of plugins that must be run before this plugin + */ + public override runAfterPlugins: string[] = []; + /** + * runBeforePlugins is a list of plugins that must be run after this plugin + */ + public override runBeforePlugins: string[] = []; - async exampleServerMethod(data: any): Promise { - return data; - }; + /** + * This method is called to setup the plugin + * Add all your on event handlers here + * Init is called before run + */ + public override async init(): Promise {} - async loaded(): Promise { - await this.emitEvent('another-plugin-name', 'another-plugin-on-event', '0'); - } -} \ No newline at end of file + /** + * This method is called once the plugin is loaded and ready to run + */ + public override async run(): Promise {} +} From 05be1a72644d342b0b2acad76f9abc81b000dd0a Mon Sep 17 00:00:00 2001 From: mrinc Date: Mon, 24 Jul 2023 01:12:15 +0200 Subject: [PATCH 04/47] Updated main readme --- README.md | 83 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 60 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index f945ea4..8566584 100644 --- a/README.md +++ b/README.md @@ -1,31 +1,68 @@ -[![Docker Image Size](https://img.shields.io/docker/image-size/betterweb/service-base/latest)](https://hub.docker.com/r/betterweb/service-base) -[![Docker Pulls](https://img.shields.io/docker/pulls/betterweb/service-base)](https://hub.docker.com/r/betterweb/service-base) -[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/betterweb/service-base?sort=semver)](https://hub.docker.com/r/betterweb/service-base) -[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) -[![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) -[![GitHub last commit (branch)](https://img.shields.io/github/last-commit/bettercorp/better-service-base/develop)](https://github.com/BetterCorp/better-service-base) -[![GitHub Repo stars](https://img.shields.io/github/stars/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) -[![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/pulls) -[![GitHub issues](https://img.shields.io/github/issues-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/issues) +--- +home: true +heroText: Better-Service-Base +tagline: A simple yet scalable microservice base +featuresx: +- title: Start Simple + details: Get started quickly, expand infinitely +- title: Event Based + details: BSB is completely event based. Choose the event broker that suites your needs, or build one if it doesn't exist yet. +- title: Scalable + details: Services are designed to be containerized and scaled to meet demand. +footer: Copyright © 2016-present BetterCorp (PTY) Ltd - All rights reserved +--- + +
BSB v9 DOCUMENTATION
+ +# About + +BSB (Better-Service-Base) is an event-bus based microservice framework. +It is completely opensource and can work as a single node, or geo-scaled cluster. +Simplicity, flexibility and expandability were the key points when developing this framework. +*(currently only in nodejs, however it is ready for several other languages)* + +[![Intro 1](http://img.youtube.com/vi/-ulXL44D_ZI/0.jpg)](http://www.youtube.com/watch?v=-ulXL44D_ZI) +`#Sales pitch` + +## Source/Github +[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) +[![GitHub Repo stars](https://img.shields.io/github/stars/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) +[![GitHub issues](https://img.shields.io/github/issues-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/issues) +[![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/pulls) +[![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) +[![GitHub last commit (branch)](https://img.shields.io/github/last-commit/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) +[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/BetterCorp/better-service-base/Build%20and%20Publish%20Containers%20(LIVE))](https://github.com/BetterCorp/better-service-base/actions/workflows/tags.yml) [![Build and Publish (EA)](https://github.com/BetterCorp/better-service-base/actions/workflows/develop.yml/badge.svg?branch=develop)](https://github.com/BetterCorp/better-service-base/actions/workflows/develop.yml) [![Build and Publish (RC)](https://github.com/BetterCorp/better-service-base/actions/workflows/master.yml/badge.svg?branch=master)](https://github.com/BetterCorp/better-service-base/actions/workflows/master.yml) -[![codecov](https://codecov.io/gh/BetterCorp/better-service-base/branch/master/graph/badge.svg)](https://codecov.io/gh/BetterCorp/better-service-base) -[![node-current (scoped)](https://img.shields.io/node/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm](https://img.shields.io/npm/dt/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm bundle size (scoped)](https://img.shields.io/bundlephobia/min/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm (scoped)](https://img.shields.io/npm/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![Docker Sponsored Open Source](data:image/png;base64,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)](https://hub.docker.com/r/betterweb/service-base) -# Better-Service-base for distributed Micro-Services +## Container/Docker +[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) +[![Docker Image Size](https://img.shields.io/docker/image-size/betterweb/service-base/latest)](https://hub.docker.com/r/betterweb/service-base) +[![Docker Pulls](https://img.shields.io/docker/pulls/betterweb/service-base)](https://hub.docker.com/r/betterweb/service-base) +[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/betterweb/service-base?sort=semver)](https://hub.docker.com/r/betterweb/service-base) -This base allows for easy distributed service platform development. +## NodeJS +[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) +[![codecov](https://codecov.io/gh/BetterCorp/better-service-base/branch/master/graph/badge.svg)](https://codecov.io/gh/BetterCorp/better-service-base) +[![node-current (scoped)](https://img.shields.io/node/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) +[![npm](https://img.shields.io/npm/dt/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) +[![npm bundle size (scoped)](https://img.shields.io/bundlephobia/min/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) +[![npm (scoped)](https://img.shields.io/npm/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) +### - Plugins +[![NodeJS Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.total&label=NodeJS%20Plugins)](https://bsbcode.dev/Market/) +[![Service Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.services&label=Service%20Plugins&color=a200ff)](https://bsbcode.dev/Market/Service/) +[![Config Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.config&label=Config%20Plugins&color=03A9F4)](https://bsbcode.dev/Market/Config/) +[![Events Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.events&label=Events%20Plugins&color=FB8C00)](https://bsbcode.dev/Market/Events/) +[![Logging Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.logging&label=Logging%20Plugins&color=43A047)](https://bsbcode.dev/Market/Logging/) -## Getting started - -View the docs here: [https://bsbcode.dev/](https://bsbcode.dev/) ## Sponsors +[![Static Badge](https://img.shields.io/badge/BetterCorp-Open%20Source%20Initiative-19b5fe?logo=browserstack)](https://bettercorp.dev/?ref=better-service-base-s-os) +[![Static Badge](https://img.shields.io/badge/Docker-Sponsored%20Open%20Source-0db7ed)](https://hub.docker.com/r/betterweb/service-base?ref=better-service-base-s-os) +[![Static Badge](https://img.shields.io/badge/BrowserStack-Sponsored%20Open%20Source-0070F0?logo=browserstack)](https://www.browserstack.com/?ref=better-service-base-s-os) + + + +## Documentation/Usage -[BetterCorp](https://www.bettercorp.dev) -[Docker](https://www.docker.com) -[BrowserStack](https://www.browserstack.com/) \ No newline at end of file +See [Getting Started](https://bsbcode.dev/GettingStarted/) for more details \ No newline at end of file From 498235084705669d97e799baad57b515bb679570 Mon Sep 17 00:00:00 2001 From: mrinc Date: Mon, 24 Jul 2023 01:12:53 +0200 Subject: [PATCH 05/47] Updated main readme --- README.md | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/README.md b/README.md index 8566584..70473f7 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,3 @@ ---- -home: true -heroText: Better-Service-Base -tagline: A simple yet scalable microservice base -featuresx: -- title: Start Simple - details: Get started quickly, expand infinitely -- title: Event Based - details: BSB is completely event based. Choose the event broker that suites your needs, or build one if it doesn't exist yet. -- title: Scalable - details: Services are designed to be containerized and scaled to meet demand. -footer: Copyright © 2016-present BetterCorp (PTY) Ltd - All rights reserved ---- - -
BSB v9 DOCUMENTATION
- # About BSB (Better-Service-Base) is an event-bus based microservice framework. From c7982f55afb2871079a3c8713a8b3a55f9c22102 Mon Sep 17 00:00:00 2001 From: mrinc Date: Mon, 24 Jul 2023 06:45:10 +0200 Subject: [PATCH 06/47] Added plugin cache ability to optimize load speed - 16% improvement from initial tests --- nodejs/src/serviceBase/plugins.ts | 215 +++++++++++++++++----- nodejs/src/tests/plugins/events/plugin.ts | 89 ++++++++- 2 files changed, 252 insertions(+), 52 deletions(-) diff --git a/nodejs/src/serviceBase/plugins.ts b/nodejs/src/serviceBase/plugins.ts index 0e1ebc4..1b7643a 100644 --- a/nodejs/src/serviceBase/plugins.ts +++ b/nodejs/src/serviceBase/plugins.ts @@ -1,7 +1,14 @@ -import { readdirSync, statSync, existsSync, readFileSync } from "fs"; +import { + readdirSync, + statSync, + existsSync, + readFileSync, + writeFileSync, +} from "fs"; import { join } from "path"; import { IPluginLogger } from "../interfaces/logger"; import { IPluginDefinition, IReadyPlugin } from "../interfaces/service"; +import { Tools } from "@bettercorp/tools"; export class SBPlugins { public static getPluginType(name: string): IPluginDefinition | null { @@ -95,11 +102,100 @@ export class SBPlugins { return arrOfPlugins; } + + private static async findDependentPlugins( + plugin: string, + coreLogger: IPluginLogger, + pluginJson: any, + npmPluginsDir: string, + knownDependencies: Record = {} + ) { + let arrOfPlugins: Array = []; + for (let dependency of Object.keys(pluginJson.dependencies || {})) { + if (knownDependencies[dependency] !== undefined) { + await coreLogger.info( + `FIND: CHECK [{plugin}] DEPENDENCY [{dependency}] IGNORED BECAUSE [{reason}]`, + { + dependency, + plugin, + reason: + knownDependencies[dependency] === true ? "EXISTS" : "INVALID", + } + ); + + continue; + } + await coreLogger.info( + `FIND: CHECK [{plugin}] DEPENDENCY [{dependency}]`, + { dependency, plugin } + ); + let path = dependency.split("/"); + let dependencyPath = join(npmPluginsDir, ...path); + await coreLogger.debug(`FIND: CHECK [{dependency}] {dependencyPath}`, { + dependency, + dependencyPath, + }); + if (statSync(dependencyPath).isDirectory()) { + let response = await SBPlugins.findPluginsInBase( + coreLogger, + dependencyPath, + true, + npmPluginsDir, + knownDependencies + ); + if (Tools.isArray(response)) { + knownDependencies[dependency] = false; + arrOfPlugins = arrOfPlugins.concat( + response as any as Array + ); + } else { + knownDependencies[dependency] = response.plugins.length > 0; + arrOfPlugins = arrOfPlugins.concat(response.plugins); + knownDependencies = { + ...knownDependencies, + ...(response.knownDependencies ?? {}), + }; + } + } + } + + return { + plugins: arrOfPlugins, + knownDependencies: knownDependencies, + }; + } + private static async findPluginsInBase( coreLogger: IPluginLogger, path: string, - libOnly = false - ): Promise> { + libOnly: boolean + ): Promise>; + private static async findPluginsInBase( + coreLogger: IPluginLogger, + path: string, + libOnly: boolean, + findLinkedPluginsNpmDir: string, + knownDependencies: Record + ): Promise< + | { + plugins: Array; + knownDependencies: Record; + } + | Array + >; + private static async findPluginsInBase( + coreLogger: IPluginLogger, + path: string, + libOnly = false, + findLinkedPluginsNpmDir?: string, + knownDependencies?: Record + ): Promise< + | Array + | { + plugins: Array; + knownDependencies: Record; + } + > { const pluginJson = JSON.parse( readFileSync(join(path, "./package.json"), "utf8").toString() ); @@ -139,27 +235,45 @@ export class SBPlugins { } const packageVersion = pluginJson.version; - return await SBPlugins.findPluginsFiles( + let returnableListOfPlugins = await SBPlugins.findPluginsFiles( coreLogger, innerPluginLibPlugin, packageVersion, libOnly, path ); + if (Tools.isString(findLinkedPluginsNpmDir)) { + let response = await SBPlugins.findDependentPlugins( + pluginJson.name, + coreLogger, + pluginJson, + findLinkedPluginsNpmDir, + knownDependencies + ); + returnableListOfPlugins = returnableListOfPlugins.concat( + response.plugins + ); + return { + plugins: returnableListOfPlugins, + knownDependencies: response.knownDependencies ?? {}, + }; + } + + return returnableListOfPlugins; } public static async findNPMPlugins( coreLogger: IPluginLogger, cwd: string ): Promise> { - let arrOfPlugins: Array = []; - - if (!existsSync(join(cwd, "./package.json"))) { + const pkgJsonFile = join(cwd, "./package.json"); + if (!existsSync(pkgJsonFile)) { await coreLogger.error(`Unable to find package.json in {pakDir}`, { - pakDir: join(cwd, "./package.json"), + pakDir: pkgJsonFile, }); return []; } + const pluginJson = JSON.parse(readFileSync(pkgJsonFile, "utf8").toString()); const npmPluginsDir = join(cwd, "./node_modules"); await coreLogger.info(`FIND: NPM plugins in: {npmPluginsDir}`, { @@ -172,53 +286,60 @@ export class SBPlugins { ); return []; } - for (const dirFileWhat of readdirSync(npmPluginsDir)) { + const knownDependenciesCacheFile = join( + npmPluginsDir, + "./.bsb-known-dependencies.json" + ); + + let arrOfPlugins: Array = []; + if (existsSync(knownDependenciesCacheFile)) { try { - const pluginPath = join(npmPluginsDir, dirFileWhat); - if (dirFileWhat.indexOf(".") === 0) { - continue; - } - if (dirFileWhat.indexOf("@") === 0) { - await coreLogger.debug(`FIND: GROUP [{dirFileWhat}] {pluginPath}`, { - dirFileWhat, - pluginPath, - }); - for (const groupPluginName of readdirSync(pluginPath)) { - if (groupPluginName.indexOf(".") === 0) { + let knownDependencies = JSON.parse( + readFileSync(knownDependenciesCacheFile, "utf8").toString() + ); + if (Object.keys(knownDependencies).length > 0) { + for (let dependency of Object.keys(knownDependencies)) { + if (knownDependencies[dependency] !== true) { continue; } - const groupPluginPath = join(pluginPath, groupPluginName); - await coreLogger.debug( - `FIND: CHECK [{dirFileWhat}/{groupPluginName}] {groupPluginPath}`, - { dirFileWhat, groupPluginName, groupPluginPath } - ); - if (statSync(groupPluginPath).isDirectory()) { - arrOfPlugins = arrOfPlugins.concat( - await SBPlugins.findPluginsInBase( - coreLogger, - groupPluginPath, - true - ) - ); - } - } - } else { - await coreLogger.debug(`FIND: CHECK [{dirFileWhat}] {pluginPath}`, { - dirFileWhat, - pluginPath, - }); - if (statSync(pluginPath).isDirectory()) { - arrOfPlugins = arrOfPlugins.concat( - await SBPlugins.findPluginsInBase(coreLogger, pluginPath, true) + let response = await SBPlugins.findPluginsInBase( + coreLogger, + join(npmPluginsDir, dependency), + true ); + arrOfPlugins = arrOfPlugins.concat(response); } } - } catch (err: any) { - await coreLogger.error("{message}", { - message: err.message || err.toString(), - }); + } catch (e: any) { + await coreLogger.error( + `Cannot read known dependencies: {knownDependenciesCacheFile}`, + { knownDependenciesCacheFile } + ); } } + if (arrOfPlugins.length === 0) { + let response = await SBPlugins.findDependentPlugins( + "self", + coreLogger, + pluginJson, + npmPluginsDir, + {} + ); + setTimeout(async () => { + try { + writeFileSync( + knownDependenciesCacheFile, + JSON.stringify(response.knownDependencies, null, 2) + ); + } catch (e: any) { + await coreLogger.warn( + `Cannot cache known dependencies: {knownDependenciesCacheFile}`, + { knownDependenciesCacheFile } + ); + } + }, 1000); + arrOfPlugins = response.plugins; + } return arrOfPlugins; } diff --git a/nodejs/src/tests/plugins/events/plugin.ts b/nodejs/src/tests/plugins/events/plugin.ts index a53b0ae..a5dad5b 100644 --- a/nodejs/src/tests/plugins/events/plugin.ts +++ b/nodejs/src/tests/plugins/events/plugin.ts @@ -1,11 +1,13 @@ import assert from "assert"; //import { Logger } from "./test-logger"; import { Events as events } from "../../../plugins/events-default/plugin"; +import * as emitDirect from "../../../plugins/events-default/events/emit"; import { broadcast } from "./events/broadcast"; import { emit } from "./events/emit"; import { emitAndReturn } from "./events/emitAndReturn"; import { emitStreamAndReceiveStream } from "./events/emitStreamAndReceiveStream"; import { IPluginLogger, LogMeta } from "../../../interfaces/logger"; +import { randomUUID } from "crypto"; //const fakeCLogger = new Logger("test-plugin", process.cwd(), {} as any); //const debug = console.log; @@ -53,29 +55,106 @@ const fakeLogger: IPluginLogger = { const getPluginConfig = async () => { return {}; -} +}; describe("plugins/events-default", () => { + describe("Events Emit", async () => { + it("_lastReceivedMessageIds should be empty on init", async () => { + let emit = new emitDirect.default(fakeLogger); + assert.equal((emit as any)._lastReceivedMessageIds.length, 0); + }); + it("_lastReceivedMessageIds should contain latest emit ID", async () => { + let emit = new emitDirect.default(fakeLogger); + await emit.onEvent("a", "b", "c", async () => {}); + await emit.emitEvent("a", "b", "c", []); + assert.equal((emit as any)._lastReceivedMessageIds.length, 1); + }); + it("_lastReceivedMessageIds should call only once", async () => { + let emit = new emitDirect.default(fakeLogger); + let testID = randomUUID(); + let called = 0; + await emit.onEvent("a", "b", "c", async () => { + called++; + }); + emit.emit(`b-c`, { + msgID: testID, + data: [], + }); + assert.equal(called, 1); + }); + it("_lastReceivedMessageIds should call only once, per id", async () => { + let emit = new emitDirect.default(fakeLogger); + let testID1 = randomUUID(); + let testID2 = randomUUID(); + let called = 0; + await emit.onEvent("a", "b", "c", async () => { + called++; + }); + emit.emit(`b-c`, { + msgID: testID1, + data: [], + }); + emit.emit(`b-c`, { + msgID: testID2, + data: [], + }); + assert.equal(called, 2); + }); + it("_lastReceivedMessageIds should cycle ids > 50", async () => { + let emit = new emitDirect.default(fakeLogger); + let testIDs: Array = "." + .repeat(100) + .split("") + .map(() => randomUUID()); + await emit.onEvent("a", "b", "c", async () => {}); + for (let emitID of testIDs) + emit.emit(`b-c`, { + msgID: emitID, + data: [], + }); + assert.equal((emit as any)._lastReceivedMessageIds.length, 51); + }); + }); broadcast(async () => { - const refP = new events("test-plugin", process.cwd(), process.cwd(), fakeLogger); + const refP = new events( + "test-plugin", + process.cwd(), + process.cwd(), + fakeLogger + ); (refP as any).getPluginConfig = getPluginConfig; if (refP.init !== undefined) await refP.init(); return refP; }, 10); emit(async () => { - const refP = new events("test-plugin", process.cwd(), process.cwd(), fakeLogger); + const refP = new events( + "test-plugin", + process.cwd(), + process.cwd(), + fakeLogger + ); (refP as any).getPluginConfig = getPluginConfig; if (refP.init !== undefined) await refP.init(); return refP; }, 10); emitAndReturn(async () => { - const refP = new events("test-plugin", process.cwd(), process.cwd(), fakeLogger); + const refP = new events( + "test-plugin", + process.cwd(), + process.cwd(), + fakeLogger + ); (refP as any).getPluginConfig = getPluginConfig; if (refP.init !== undefined) await refP.init(); return refP; }, 10); emitStreamAndReceiveStream(async () => { - const refP = new events("test-plugin", process.cwd(), process.cwd(), fakeLogger); + const refP = new events( + "test-plugin", + process.cwd(), + process.cwd(), + fakeLogger + ); (refP as any).getPluginConfig = getPluginConfig; if (refP.init !== undefined) await refP.init(); //refP.eas.staticCommsTimeout = 25; From ed8f2a6d15ca656e6edf98872f5c3ee84ebd2c63 Mon Sep 17 00:00:00 2001 From: mrinc Date: Wed, 26 Jul 2023 01:16:18 +0200 Subject: [PATCH 07/47] Adding current state of docs --- README.md | 2 +- .../Deployment/{README.md => _index.en.md} | 8 +-- documentation/Deployment/mac/_index.en.md | 12 ++++ documentation/Deployment/mac/_index.fr.md | 12 ++++ documentation/README.md | 68 ------------------- documentation/_index.en.md | 37 ++++++++++ documentation/get-started/_index.en.md | 22 ++++++ documentation/get-started/nodejs/_index.en.md | 8 +++ .../get-started/nodejs/step1/_index.en.md | 6 ++ 9 files changed, 102 insertions(+), 73 deletions(-) rename documentation/Deployment/{README.md => _index.en.md} (94%) create mode 100644 documentation/Deployment/mac/_index.en.md create mode 100644 documentation/Deployment/mac/_index.fr.md delete mode 100644 documentation/README.md create mode 100644 documentation/_index.en.md create mode 100644 documentation/get-started/_index.en.md create mode 100644 documentation/get-started/nodejs/_index.en.md create mode 100644 documentation/get-started/nodejs/step1/_index.en.md diff --git a/README.md b/README.md index 70473f7..4f4e2d5 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Simplicity, flexibility and expandability were the key points when developing th ## Sponsors -[![Static Badge](https://img.shields.io/badge/BetterCorp-Open%20Source%20Initiative-19b5fe?logo=browserstack)](https://bettercorp.dev/?ref=better-service-base-s-os) +[![Static Badge](https://img.shields.io/badge/BetterCorp-Open%20Source%20Initiative-19b5fe?logo)](https://bettercorp.dev/?ref=better-service-base-s-os) [![Static Badge](https://img.shields.io/badge/Docker-Sponsored%20Open%20Source-0db7ed)](https://hub.docker.com/r/betterweb/service-base?ref=better-service-base-s-os) [![Static Badge](https://img.shields.io/badge/BrowserStack-Sponsored%20Open%20Source-0070F0?logo=browserstack)](https://www.browserstack.com/?ref=better-service-base-s-os) diff --git a/documentation/Deployment/README.md b/documentation/Deployment/_index.en.md similarity index 94% rename from documentation/Deployment/README.md rename to documentation/Deployment/_index.en.md index e7c313f..a13ea9e 100644 --- a/documentation/Deployment/README.md +++ b/documentation/Deployment/_index.en.md @@ -1,8 +1,8 @@ --- -lang: en-US -title: Deployment -description: BSB Deployment -footer: Copyright © 2016-present BetterCorp (PTY) Ltd - All rights reserved +title: "Deployment" +date: 2018-12-29T11:02:05+06:00 +weight: 2 +draft: false --- # BSB Deployment diff --git a/documentation/Deployment/mac/_index.en.md b/documentation/Deployment/mac/_index.en.md new file mode 100644 index 0000000..85b737a --- /dev/null +++ b/documentation/Deployment/mac/_index.en.md @@ -0,0 +1,12 @@ +--- +title: "Mac OS" +date: 2018-12-29T11:02:05+06:00 +weight: 2 +draft: false +--- + +Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna turpis. + +> Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet + +Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna, et dapibus turpis.Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna, et dapibus turpis. \ No newline at end of file diff --git a/documentation/Deployment/mac/_index.fr.md b/documentation/Deployment/mac/_index.fr.md new file mode 100644 index 0000000..85b737a --- /dev/null +++ b/documentation/Deployment/mac/_index.fr.md @@ -0,0 +1,12 @@ +--- +title: "Mac OS" +date: 2018-12-29T11:02:05+06:00 +weight: 2 +draft: false +--- + +Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna turpis. + +> Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet + +Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna, et dapibus turpis.Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna, et dapibus turpis. \ No newline at end of file diff --git a/documentation/README.md b/documentation/README.md deleted file mode 100644 index 0d77d95..0000000 --- a/documentation/README.md +++ /dev/null @@ -1,68 +0,0 @@ ---- -home: true -heroText: Better-Service-Base -tagline: A simple yet scalable microservice base -featuresx: -- title: Start Simple - details: Get started quickly, expand infinitely -- title: Event Based - details: BSB is completely event based. Choose the event broker that suites your needs, or build one if it doesn't exist yet. -- title: Scalable - details: Services are designed to be containerized and scaled to meet demand. -footer: Copyright © 2016-present BetterCorp (PTY) Ltd - All rights reserved ---- - -
BSB v9 DOCUMENTATION
- -# About - -BSB (Better-Service-Base) is an event-bus based microservice framework. -It is completely opensource and can work as a single node, or geo-scaled cluster. -Simplicity, flexibility and expandability were the key points when developing this framework. -*(currently only in nodejs, however it is ready for several other languages)* - -[![Intro 1](http://img.youtube.com/vi/-ulXL44D_ZI/0.jpg)](http://www.youtube.com/watch?v=-ulXL44D_ZI) -`#Sales pitch` - -## Source/Github -[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) -[![GitHub Repo stars](https://img.shields.io/github/stars/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) -[![GitHub issues](https://img.shields.io/github/issues-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/issues) -[![GitHub pull requests](https://img.shields.io/github/issues-pr-raw/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base/pulls) -[![GitHub commit activity (branch)](https://img.shields.io/github/commit-activity/m/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) -[![GitHub last commit (branch)](https://img.shields.io/github/last-commit/bettercorp/better-service-base/master)](https://github.com/BetterCorp/better-service-base) -[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/BetterCorp/better-service-base/Build%20and%20Publish%20Containers%20(LIVE))](https://github.com/BetterCorp/better-service-base/actions/workflows/tags.yml) -[![Build and Publish (EA)](https://github.com/BetterCorp/better-service-base/actions/workflows/develop.yml/badge.svg?branch=develop)](https://github.com/BetterCorp/better-service-base/actions/workflows/develop.yml) -[![Build and Publish (RC)](https://github.com/BetterCorp/better-service-base/actions/workflows/master.yml/badge.svg?branch=master)](https://github.com/BetterCorp/better-service-base/actions/workflows/master.yml) - -## Container/Docker -[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) -[![Docker Image Size](https://img.shields.io/docker/image-size/betterweb/service-base/latest)](https://hub.docker.com/r/betterweb/service-base) -[![Docker Pulls](https://img.shields.io/docker/pulls/betterweb/service-base)](https://hub.docker.com/r/betterweb/service-base) -[![Docker Image Version (latest semver)](https://img.shields.io/docker/v/betterweb/service-base?sort=semver)](https://hub.docker.com/r/betterweb/service-base) - -## NodeJS -[![GitHub](https://img.shields.io/github/license/BetterCorp/better-service-base)](https://github.com/BetterCorp/better-service-base) -[![codecov](https://codecov.io/gh/BetterCorp/better-service-base/branch/master/graph/badge.svg)](https://codecov.io/gh/BetterCorp/better-service-base) -[![node-current (scoped)](https://img.shields.io/node/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm](https://img.shields.io/npm/dt/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm bundle size (scoped)](https://img.shields.io/bundlephobia/min/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -[![npm (scoped)](https://img.shields.io/npm/v/@bettercorp/service-base)](https://www.npmjs.com/package/@bettercorp/service-base) -### - Plugins -[![NodeJS Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.total&label=NodeJS%20Plugins)](https://bsbcode.dev/Market/) -[![Service Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.services&label=Service%20Plugins&color=a200ff)](https://bsbcode.dev/Market/Service/) -[![Config Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.config&label=Config%20Plugins&color=03A9F4)](https://bsbcode.dev/Market/Config/) -[![Events Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.events&label=Events%20Plugins&color=FB8C00)](https://bsbcode.dev/Market/Events/) -[![Logging Plugins](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.nodejs.logging&label=Logging%20Plugins&color=43A047)](https://bsbcode.dev/Market/Logging/) - - -## Sponsors -[![Static Badge](https://img.shields.io/badge/BetterCorp-Open%20Source%20Initiative-19b5fe?logo=browserstack)](https://bettercorp.dev/?ref=better-service-base-s-os) -[![Static Badge](https://img.shields.io/badge/Docker-Sponsored%20Open%20Source-0db7ed)](https://hub.docker.com/r/betterweb/service-base?ref=better-service-base-s-os) -[![Static Badge](https://img.shields.io/badge/BrowserStack-Sponsored%20Open%20Source-0070F0?logo=browserstack)](https://www.browserstack.com/?ref=better-service-base-s-os) - - - -## Documentation/Usage - -See [Getting Started](https://bsbcode.dev/GettingStarted/) for more details \ No newline at end of file diff --git a/documentation/_index.en.md b/documentation/_index.en.md new file mode 100644 index 0000000..b392f3d --- /dev/null +++ b/documentation/_index.en.md @@ -0,0 +1,37 @@ +--- +# banner +banner : + title : "Event-bus based microservice framework." + subtitle : "Simplicity, flexibility and expandability were the key points when developing this framework. " + #image : "images/BSB-Def-1.drawio.svg" + image : "https://content.betterweb.co.za/better-service-base/bsb-intro-1.gif" + statements : + - https://img.shields.io/github/license/BetterCorp/better-service-base + - https://img.shields.io/github/stars/BetterCorp/better-service-base + - https://img.shields.io/github/issues-raw/BetterCorp/better-service-base + - https://img.shields.io/github/issues-pr-raw/BetterCorp/better-service-base + - https://img.shields.io/github/last-commit/bettercorp/better-service-base/master + - https://img.shields.io/docker/image-size/betterweb/service-base/latest + - https://codecov.io/gh/BetterCorp/better-service-base/branch/master/graph/badge.svg + - https://img.shields.io/node/v/@bettercorp/service-base + - https://img.shields.io/npm/dt/@bettercorp/service-base + - https://img.shields.io/bundlephobia/min/@bettercorp/service-base + - https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2FBetterCorp%2Fbetter-service-base%2Fdocumentation%2Fplugin-stats.json&query=%24.total&label=Plugins + +banner_button : + enable : "true" + label : "Get Started" + link : "get-started/" + +# call to action +call_to_action : + enable : true + title : "Still not sure?" + image : "images/AdobeStock_587427658.svg" + content : "Just give it a bash and see what you think!" + + button : + enable : "true" + label : "Just have a peek" + link : "get-started/" +--- diff --git a/documentation/get-started/_index.en.md b/documentation/get-started/_index.en.md new file mode 100644 index 0000000..884ec03 --- /dev/null +++ b/documentation/get-started/_index.en.md @@ -0,0 +1,22 @@ +--- +title: "Get Started" +date: 2018-12-29T11:02:05+06:00 +weight: 1 +draft: false +type : "single" +--- + +BSB (Better-Service-Base) is an event-bus based microservice framework. +It is completely opensource and can work as a single node, or geo-scaled cluster. +Simplicity, flexibility and expandability were the key points when developing this framework. +_(currently only in nodejs, however it is ready for several other languages)_ + +[![Intro 1](https://content.betterweb.co.za/better-service-base/bsb-intro-1.gif)](http://www.youtube.com/watch?v=-ulXL44D_ZI) + + +### Pick your language of choice + +[Node JS](/get-started/nodejs) +dot NET `(coming soon)` +go `(coming soon)` +python `(coming soon)` \ No newline at end of file diff --git a/documentation/get-started/nodejs/_index.en.md b/documentation/get-started/nodejs/_index.en.md new file mode 100644 index 0000000..1d08c1e --- /dev/null +++ b/documentation/get-started/nodejs/_index.en.md @@ -0,0 +1,8 @@ +--- +title: "Node JS" +date: 2018-12-29T11:02:05+06:00 +weight: 1 +draft: false +--- + +##### So let's get started with writing a service plugin in NodeJS diff --git a/documentation/get-started/nodejs/step1/_index.en.md b/documentation/get-started/nodejs/step1/_index.en.md new file mode 100644 index 0000000..f085d82 --- /dev/null +++ b/documentation/get-started/nodejs/step1/_index.en.md @@ -0,0 +1,6 @@ +--- +title: "Step 1 : Write your service" +date: 2018-12-29T11:02:05+06:00 +weight: 1 +draft: false +--- From 95ddb7a0f1dc3d1e265088cda16c3e1ae4ece46f Mon Sep 17 00:00:00 2001 From: mrinc Date: Tue, 1 Aug 2023 21:40:27 +0200 Subject: [PATCH 08/47] Updated lotadocs --- documentation/Deployment/_index.en.md | 77 ------------------- documentation/Deployment/mac/_index.en.md | 12 --- documentation/Deployment/mac/_index.fr.md | 12 --- documentation/Development/README.md | 20 ----- documentation/_index.en.md | 6 +- documentation/get-started/_index.en.md | 13 +--- .../get-started/architecture/_index.en.md | 35 +++++++++ documentation/get-started/basics/_index.en.md | 40 ++++++++++ documentation/get-started/nodejs/_index.en.md | 8 -- .../get-started/nodejs/step1/_index.en.md | 6 -- documentation/languages/_index.en.md | 12 +++ documentation/languages/nodejs/_index.en.md | 22 ++++++ .../nodejs/prerequisites/_index.en.md | 15 ++++ .../languages/nodejs/step1/_index.en.md | 8 ++ .../languages/nodejs/step2/_index.en.md | 8 ++ .../languages/nodejs/step3/_index.en.md | 8 ++ .../languages/nodejs/step4/_index.en.md | 8 ++ .../languages/nodejs/step5/_index.en.md | 8 ++ documentation/pdk/_index.en.md | 12 +++ documentation/pdk/get-started/_index.en.md | 9 +++ nodejs/package.json | 70 ++++++++++++++++- 21 files changed, 259 insertions(+), 150 deletions(-) delete mode 100644 documentation/Deployment/_index.en.md delete mode 100644 documentation/Deployment/mac/_index.en.md delete mode 100644 documentation/Deployment/mac/_index.fr.md delete mode 100644 documentation/Development/README.md create mode 100644 documentation/get-started/architecture/_index.en.md create mode 100644 documentation/get-started/basics/_index.en.md delete mode 100644 documentation/get-started/nodejs/_index.en.md delete mode 100644 documentation/get-started/nodejs/step1/_index.en.md create mode 100644 documentation/languages/_index.en.md create mode 100644 documentation/languages/nodejs/_index.en.md create mode 100644 documentation/languages/nodejs/prerequisites/_index.en.md create mode 100644 documentation/languages/nodejs/step1/_index.en.md create mode 100644 documentation/languages/nodejs/step2/_index.en.md create mode 100644 documentation/languages/nodejs/step3/_index.en.md create mode 100644 documentation/languages/nodejs/step4/_index.en.md create mode 100644 documentation/languages/nodejs/step5/_index.en.md create mode 100644 documentation/pdk/_index.en.md create mode 100644 documentation/pdk/get-started/_index.en.md diff --git a/documentation/Deployment/_index.en.md b/documentation/Deployment/_index.en.md deleted file mode 100644 index a13ea9e..0000000 --- a/documentation/Deployment/_index.en.md +++ /dev/null @@ -1,77 +0,0 @@ ---- -title: "Deployment" -date: 2018-12-29T11:02:05+06:00 -weight: 2 -draft: false ---- - -# BSB Deployment - -## Docker - -[betterweb/service-base](https://hub.docker.com/r/betterweb/service-base) - -This is the base docker image. -This image contains basically nothing except the default plugins (log-default, events-default, config-default) - - -### Environment variables - -- BSB_SEC_JSON = `./sec.config.json` -Specifically define the location to the `default-config` `sec.config.json` file - -- BSB_PROFILE = `default` -Sets the deployment profile of the service. -This defines the specific containers profile and what service(s) that will be running in the container. - -- BSB_CONFIG_PLUGIN = ` ` (not set) -Defines the config plugin to use. -When not set, it will use the `sec.config.json` file. -The config plugin is the only plugin that may have additional environment variables to set. -The rest of the plugins configuration is set in the config plugins definition. *(see config plugin docs for more info)* - -- BSB_PLUGINS = ` ` (comma seperated list of plugins) -If defined, we'll automatically install the plugins if not already installed. -What this allows you to do is have a seperate container to manage deployments/versions, and then a lightweight main container for the actual services themselves. -Or for a simpler deployment (like below), a single container that will set itself up if the plugins aren't setup/installed. - - -## Deployment - -An example docker compose file for a service. - -```yaml - service: - image: betterweb/service-base:node - volumes: - - /etc/localtime:/etc/localtime:ro - - /home/bsb/config.json:/home/bsb/sec.config.json:ro - environment: - - BSB_PROFILE=my-service - - BSB_PLUGINS=@bettercorp/service-base-plugin-web-server - deploy: - replicas: 2 - update_config: - parallelism: 1 - order: start-first -``` - -This installs web-server plugin on boot. However it doesn't do much else *(we'll add a demo plugin in the future)* -You can list your plugins, or have a seperate container to do the installation of your plugins. - -## Requirements - -- A server running docker (docker swarm/kubernetes/nomad) -- An events service (should you want to run more than 1 service...) - - Example: RabbitMQ/Pubnub/Kafka - - -## Directories (in the container) - -- `/home/bsb/sec.config.json` - The config file - -- `/mnt/bsb-plugins` - package like directory which will contain all the installed plugins. -This allows you to mount the dir for multiple containers (or use a shared volume) thus allowing the saving of storage space and A/B testing. - - - \ No newline at end of file diff --git a/documentation/Deployment/mac/_index.en.md b/documentation/Deployment/mac/_index.en.md deleted file mode 100644 index 85b737a..0000000 --- a/documentation/Deployment/mac/_index.en.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: "Mac OS" -date: 2018-12-29T11:02:05+06:00 -weight: 2 -draft: false ---- - -Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna turpis. - -> Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet - -Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna, et dapibus turpis.Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna, et dapibus turpis. \ No newline at end of file diff --git a/documentation/Deployment/mac/_index.fr.md b/documentation/Deployment/mac/_index.fr.md deleted file mode 100644 index 85b737a..0000000 --- a/documentation/Deployment/mac/_index.fr.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: "Mac OS" -date: 2018-12-29T11:02:05+06:00 -weight: 2 -draft: false ---- - -Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna turpis. - -> Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet - -Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna, et dapibus turpis.Etiam vestibulum risus vel arcu elementum eleifend. Cras at dolor eget urna varius faucibus tempus in elit. Cras a dui imperdiet, tempus metus quis, pharetra turpis. Phasellus at massa sit amet ante semper fermentum sed eget lectus. Quisque id dictum magna, et dapibus turpis. \ No newline at end of file diff --git a/documentation/Development/README.md b/documentation/Development/README.md deleted file mode 100644 index cb54853..0000000 --- a/documentation/Development/README.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -lang: en-US -title: Getting Started -description: Using the BSB -footer: Copyright © 2016-present BetterCorp (PTY) Ltd - All rights reserved ---- - -# BSB Getting Started - -## About - -The BSB is designed to be setup in a blank repo/project and cannot be added to an existing project. - -## Getting started - -
THIS DOCUMENTATION IS A WORK IN PROGRESS
- -We've just removed the old docs as they no longer pertain to v8. - -You can look at the source of one of the plugins in the plugin marketplace for reference for now. \ No newline at end of file diff --git a/documentation/_index.en.md b/documentation/_index.en.md index b392f3d..9f22e75 100644 --- a/documentation/_index.en.md +++ b/documentation/_index.en.md @@ -26,12 +26,12 @@ banner_button : # call to action call_to_action : enable : true - title : "Still not sure?" + title : "Simplicity over complexity" image : "images/AdobeStock_587427658.svg" - content : "Just give it a bash and see what you think!" + content : "Think of kubernetes vs nomad, we're nomad for simplicity" button : enable : "true" - label : "Just have a peek" + label : "Get started" link : "get-started/" --- diff --git a/documentation/get-started/_index.en.md b/documentation/get-started/_index.en.md index 884ec03..8218ab7 100644 --- a/documentation/get-started/_index.en.md +++ b/documentation/get-started/_index.en.md @@ -1,9 +1,9 @@ --- title: "Get Started" -date: 2018-12-29T11:02:05+06:00 +date: 2023-07-27T13:03:00+02:00 weight: 1 draft: false -type : "single" +type : "docs" --- BSB (Better-Service-Base) is an event-bus based microservice framework. @@ -11,12 +11,5 @@ It is completely opensource and can work as a single node, or geo-scaled cluster Simplicity, flexibility and expandability were the key points when developing this framework. _(currently only in nodejs, however it is ready for several other languages)_ -[![Intro 1](https://content.betterweb.co.za/better-service-base/bsb-intro-1.gif)](http://www.youtube.com/watch?v=-ulXL44D_ZI) +![Intro 1](https://content.betterweb.co.za/better-service-base/bsb-intro-1.gif "image") - -### Pick your language of choice - -[Node JS](/get-started/nodejs) -dot NET `(coming soon)` -go `(coming soon)` -python `(coming soon)` \ No newline at end of file diff --git a/documentation/get-started/architecture/_index.en.md b/documentation/get-started/architecture/_index.en.md new file mode 100644 index 0000000..a74a73a --- /dev/null +++ b/documentation/get-started/architecture/_index.en.md @@ -0,0 +1,35 @@ +--- +title: "Architecture" +date: 2023-07-27T13:03:00+02:00 +weight: 2 +draft: false +type : "docs" +--- + +##### Single container/service +![Arch 1](https://content.betterweb.co.za/better-service-base/BSB-def-2.drawio.svg) + +
+
+
+ +##### 3 container cluster +Frontend contains the entrypoint/API +The scheduler never scales to more than 1 running container - this handles all the scheduled tasks +The backend container handles the logic, so called backend code +![Arch 1](https://content.betterweb.co.za/better-service-base/BSB-Def-1.drawio.svg) + +
+
+
+ +##### Fully scaled cluster +Each container has a single service and can be individually scaled up/down + +![Arch 1](https://content.betterweb.co.za/better-service-base/BSB-def-3.drawio.svg) + +
+
+ +Example with scaled containers (`4x frontend containers`) +![Arch 1](https://content.betterweb.co.za/better-service-base/BSB-def-4.drawio.svg) diff --git a/documentation/get-started/basics/_index.en.md b/documentation/get-started/basics/_index.en.md new file mode 100644 index 0000000..a763842 --- /dev/null +++ b/documentation/get-started/basics/_index.en.md @@ -0,0 +1,40 @@ +--- +title: "Basics" +date: 2023-07-27T13:03:00+02:00 +weight: 1 +draft: false +type : "single" +--- + +###### Events plugins + +These plugins are used to connect the BSB to your events broker. +An example would be: `rabbitMQ` + +###### Logging plugins + +These plugins are used to connect an external logging platform. +An example would be: `graylog` + +###### Config plugins + +These plugins allow you to connect an external configuration service for the BSB. +An example would be: `1password` + + +###### Service plugins + +These plugins are the main code, the secret sauce of the BSB. +You'll write your code in these for the actual logic. +An example would be: `fastify` or `express` + + +###### PDK + +PDK is the Plugin Development Kit + + +{{< notice "tip" >}} +The PDK is an app to configure and manage the BSB. +We did this because it is much easier than doing it in a CLI because of the options/choices available. - [see more](/pdk) +{{< /notice >}} diff --git a/documentation/get-started/nodejs/_index.en.md b/documentation/get-started/nodejs/_index.en.md deleted file mode 100644 index 1d08c1e..0000000 --- a/documentation/get-started/nodejs/_index.en.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Node JS" -date: 2018-12-29T11:02:05+06:00 -weight: 1 -draft: false ---- - -##### So let's get started with writing a service plugin in NodeJS diff --git a/documentation/get-started/nodejs/step1/_index.en.md b/documentation/get-started/nodejs/step1/_index.en.md deleted file mode 100644 index f085d82..0000000 --- a/documentation/get-started/nodejs/step1/_index.en.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: "Step 1 : Write your service" -date: 2018-12-29T11:02:05+06:00 -weight: 1 -draft: false ---- diff --git a/documentation/languages/_index.en.md b/documentation/languages/_index.en.md new file mode 100644 index 0000000..23dbb19 --- /dev/null +++ b/documentation/languages/_index.en.md @@ -0,0 +1,12 @@ +--- +title: "Languages" +date: 2023-07-27T13:03:00+02:00 +weight: 3 +draft: false +type : "docs" +--- + +[NodeJS](/get-started/languages/nodejs) +dot NET `(coming soon)` +go `(coming soon)` +python `(coming soon)` \ No newline at end of file diff --git a/documentation/languages/nodejs/_index.en.md b/documentation/languages/nodejs/_index.en.md new file mode 100644 index 0000000..9919937 --- /dev/null +++ b/documentation/languages/nodejs/_index.en.md @@ -0,0 +1,22 @@ +--- +title: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 1 +draft: false +type : "docs" +--- + +##### Write your own service plugin +[Step 1: Write your service](/get-started/languages/nodejs/step1) + +##### Then select the config plugin (or use the default one) +[Step 2 : Select your config platform](/get-started/languages/nodejs/step2) + +##### Then select the events plugin (or use the default one) +[Step 3 : Select your events platform](/get-started/languages/nodejs/step3) + +##### Then select the logging/stats plugin (or use the default one) +[Step 4 : Select your log/stats platform](/get-started/languages/nodejs/step4) + +##### Send your platform live +[Step 5 : Deploy your platform](/get-started/languages/nodejs/step5) diff --git a/documentation/languages/nodejs/prerequisites/_index.en.md b/documentation/languages/nodejs/prerequisites/_index.en.md new file mode 100644 index 0000000..f37149b --- /dev/null +++ b/documentation/languages/nodejs/prerequisites/_index.en.md @@ -0,0 +1,15 @@ +--- +title: "Prerequisites" +subsection: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 1 +draft: false +type : "single" +--- + +###### NodeJS + +You need to have NodeJS, NPM installed on your machine. + +Node min version: `18` +NPM min version: `9` \ No newline at end of file diff --git a/documentation/languages/nodejs/step1/_index.en.md b/documentation/languages/nodejs/step1/_index.en.md new file mode 100644 index 0000000..076be40 --- /dev/null +++ b/documentation/languages/nodejs/step1/_index.en.md @@ -0,0 +1,8 @@ +--- +title: "Write your service" +subsection: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 2 +draft: false +type : "single" +--- diff --git a/documentation/languages/nodejs/step2/_index.en.md b/documentation/languages/nodejs/step2/_index.en.md new file mode 100644 index 0000000..8381bc0 --- /dev/null +++ b/documentation/languages/nodejs/step2/_index.en.md @@ -0,0 +1,8 @@ +--- +title: "Select your config platform" +subsection: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 4 +draft: false +type : "single" +--- diff --git a/documentation/languages/nodejs/step3/_index.en.md b/documentation/languages/nodejs/step3/_index.en.md new file mode 100644 index 0000000..41ad837 --- /dev/null +++ b/documentation/languages/nodejs/step3/_index.en.md @@ -0,0 +1,8 @@ +--- +title: "Select your events platform" +subsection: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 3 +draft: false +type : "single" +--- diff --git a/documentation/languages/nodejs/step4/_index.en.md b/documentation/languages/nodejs/step4/_index.en.md new file mode 100644 index 0000000..b8d8796 --- /dev/null +++ b/documentation/languages/nodejs/step4/_index.en.md @@ -0,0 +1,8 @@ +--- +title: "Select your log/stats platform" +subsection: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 5 +draft: false +type : "single" +--- diff --git a/documentation/languages/nodejs/step5/_index.en.md b/documentation/languages/nodejs/step5/_index.en.md new file mode 100644 index 0000000..aa2c5d5 --- /dev/null +++ b/documentation/languages/nodejs/step5/_index.en.md @@ -0,0 +1,8 @@ +--- +title: "Deploy your platform" +subsection: "NodeJS" +date: 2023-07-27T13:03:00+02:00 +weight: 6 +draft: false +type: "single" +--- diff --git a/documentation/pdk/_index.en.md b/documentation/pdk/_index.en.md new file mode 100644 index 0000000..a6121f4 --- /dev/null +++ b/documentation/pdk/_index.en.md @@ -0,0 +1,12 @@ +--- +title: "PDK" +description: "BSB PDK is the Better-Service-Base Plugin-Development-Kit" +date: 2023-07-27T13:03:00+02:00 +weight: 2 +draft: false +type : "single" +--- + +### BSB Plugin Development Kit + +We've built a PDK app to help with managing your BSB plugins, generating/building new plugins \ No newline at end of file diff --git a/documentation/pdk/get-started/_index.en.md b/documentation/pdk/get-started/_index.en.md new file mode 100644 index 0000000..05200bd --- /dev/null +++ b/documentation/pdk/get-started/_index.en.md @@ -0,0 +1,9 @@ +--- +title: "Getting started" +date: 2023-07-27T13:03:00+02:00 +weight: 1 +draft: false +type : "docs" +--- + +##### Single container/service \ No newline at end of file diff --git a/nodejs/package.json b/nodejs/package.json index d0747f5..cdf14f8 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -49,5 +49,71 @@ "@bettercorp/tools": "^2.0.20220714140658", "yaml": "^2.3.1" }, - "bsb_project": true -} + "bsb_project": true, + "bsbInit": { + "project": { + "dependencies": { + "@bettercorp/tools": "latest" + }, + "devDependencies": { + "@types/assert": "^1.5.6", + "@types/chai": "^4.3.3", + "@types/mocha": "^9.1.1", + "@types/node": "^18.7.16", + "@typescript-eslint/eslint-plugin": "^5.31.0", + "@typescript-eslint/parser": "^5.31.0", + "eslint": "^8.20.0", + "mocha": "^10.0.0", + "nyc": "^15.1.0", + "ts-node": "^10.9.1", + "typescript": "^4.7.4" + }, + "files": [ + "lib/**/*" + ], + "scripts": { + "build": "npm run build-plugin && npm run build-clients", + "build-plugin": "rm -rfv ./lib && tsc", + "build-clients": "node node_modules/@bettercorp/service-base/build-lib-clients.js", + "dev": "nodemon --config node_modules/@bettercorp/service-base/development/nodemon.json", + "start": "ts-node node_modules/@bettercorp/service-base/lib/cli.js", + "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx", + "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js --reporter json --reporter lcov ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts' --reporter json --reporter-options output=junit.json", + "testDev": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts'", + }, + "main": "lib/index.js" + }, + "gitignore": [ + "/lib", + "/node_modules", + "/sec.config.json", + "/junit.xml", + "/test-file-*", + "/dist-clients" + ], + "files": [ + { + "src": "tsconfig.json", + "dst": "tsconfig.json", + "canOverwrite": true + }, + { + "src": "eslintrc.js", + "dst": ".eslintrc.js", + "canOverwrite": true + }, + { + "src": "eslintignore", + "dst": ".eslintignore", + "canOverwrite": true + } + ], + "directories": [ + "src", + "src/clients", + "src/plugins", + "src/shared", + "src/tests" + ] + } +} \ No newline at end of file From 6044016c380a0b774014419f4a22dc94f6e0d4bc Mon Sep 17 00:00:00 2001 From: mrinc Date: Tue, 1 Aug 2023 21:42:26 +0200 Subject: [PATCH 09/47] Updated packagejson --- nodejs/package-lock.json | 8 ++++---- nodejs/package.json | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 00b6f78..6184262 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bettercorp/service-base", - "version": "8.4.0-rc", + "version": "9.0.0-alpha", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bettercorp/service-base", - "version": "8.4.0-rc", + "version": "9.0.0-alpha", "hasInstallScript": true, "license": "AGPL-3.0-only", "dependencies": { @@ -32,8 +32,8 @@ "yargs": "^17.5.1" }, "engines": { - "node": ">=16.0.0", - "npm": ">=8.0.0" + "node": ">=18.0.0", + "npm": ">=9.0.0" } }, "node_modules/@ampproject/remapping": { diff --git a/nodejs/package.json b/nodejs/package.json index cdf14f8..09f5b95 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -29,7 +29,7 @@ "README.md" ], "main": "lib/index.js", - "version": "9.0.0-rc0", + "version": "9.0.0-alpha", "devDependencies": { "@types/assert": "^1.5.6", "@types/chai": "^4.3.3", @@ -79,7 +79,7 @@ "start": "ts-node node_modules/@bettercorp/service-base/lib/cli.js", "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx", "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js --reporter json --reporter lcov ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts' --reporter json --reporter-options output=junit.json", - "testDev": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts'", + "testDev": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts'" }, "main": "lib/index.js" }, From 148ef4082db7108fc9685a8fdebae1fa08a3cdbf Mon Sep 17 00:00:00 2001 From: mrinc Date: Tue, 1 Aug 2023 21:45:37 +0200 Subject: [PATCH 10/47] dit-tag - v9 --- nodejs/package-lock.json | 4 ++-- nodejs/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 6184262..1e84243 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bettercorp/service-base", - "version": "9.0.0-alpha", + "version": "9.0.0+v9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bettercorp/service-base", - "version": "9.0.0-alpha", + "version": "9.0.0+v9", "hasInstallScript": true, "license": "AGPL-3.0-only", "dependencies": { diff --git a/nodejs/package.json b/nodejs/package.json index 09f5b95..dbe64d8 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -29,7 +29,7 @@ "README.md" ], "main": "lib/index.js", - "version": "9.0.0-alpha", + "version": "9.0.0+v9", "devDependencies": { "@types/assert": "^1.5.6", "@types/chai": "^4.3.3", From a09514642f79fc6778e0bad7405e5d93077eac8a Mon Sep 17 00:00:00 2001 From: mrinc Date: Wed, 9 Aug 2023 04:05:42 +0200 Subject: [PATCH 11/47] chore(package.json): update build script to include running testDev after tsc chore(package.json): update file paths in files array to point to build directory chore(service.ts): change IPluginDefinition enum to PluginDefinitions object chore(colours.ts): change ConsoleColours enum to CONSOLE_COLOURS object fix(plugin.ts): change import statement for ConsoleColours enum feat(plugin.ts): add LOG_LEVELS constant and LogLevels type fix(config.ts): change import statements for PluginDefinitions and PluginDefinition types refactor(plugins.ts): change interface names to match updated interface names refactor(serviceBase.ts): change enum to const enum and add type for enum values refactor(services.ts): change interface names to match updated interface names fix(plugin.ts): import LOG_LEVELS constant from log-default plugin fix(plugin.ts): change parameter type from number to LogLevels in fakeLogFunc function --- nodejs/package.json | 8 +-- nodejs/src/interfaces/service.ts | 16 +++-- nodejs/src/plugins/log-default/colours.ts | 52 +++++++-------- nodejs/src/plugins/log-default/plugin.ts | 64 ++++++++++--------- nodejs/src/serviceBase/config.ts | 14 ++-- nodejs/src/serviceBase/plugins.ts | 12 ++-- nodejs/src/serviceBase/serviceBase.ts | 37 ++++++----- nodejs/src/serviceBase/services.ts | 4 +- .../src/tests/plugins/log-default/plugin.ts | 38 +++++------ 9 files changed, 127 insertions(+), 118 deletions(-) diff --git a/nodejs/package.json b/nodejs/package.json index dbe64d8..74bd6b1 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -11,7 +11,7 @@ "scripts": { "dev": "nodemon --config ./nodemon.json", "start": "node lib/cli.js", - "build": "tsc", + "build": "tsc && npm run testDev", "postinstall": "node ./postinstall.js", "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx", "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js --reporter json --reporter lcov ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts' --reporter json --reporter-options output=junit.json", @@ -93,17 +93,17 @@ ], "files": [ { - "src": "tsconfig.json", + "src": "build/tsconfig.json", "dst": "tsconfig.json", "canOverwrite": true }, { - "src": "eslintrc.js", + "src": "build/eslintrc.js", "dst": ".eslintrc.js", "canOverwrite": true }, { - "src": "eslintignore", + "src": "build/eslintignore", "dst": ".eslintignore", "canOverwrite": true } diff --git a/nodejs/src/interfaces/service.ts b/nodejs/src/interfaces/service.ts index 13d081d..dc017ba 100644 --- a/nodejs/src/interfaces/service.ts +++ b/nodejs/src/interfaces/service.ts @@ -21,15 +21,17 @@ export interface IService< loaded?(): Promise; } -export enum IPluginDefinition { - config = "config", - events = "events", - logging = "logging", - service = "service", -} +export const PluginDefinitions = { + config: "config", + events: "events", + logging: "logging", + service: "service", +} as const; +export type PluginDefinition = + (typeof PluginDefinitions)[keyof typeof PluginDefinitions]; export interface IReadyPlugin { - pluginDefinition: IPluginDefinition; + pluginDefinition: PluginDefinition; name: string; mappedName: string; version: string; diff --git a/nodejs/src/plugins/log-default/colours.ts b/nodejs/src/plugins/log-default/colours.ts index a0bceaf..c88c5e0 100644 --- a/nodejs/src/plugins/log-default/colours.ts +++ b/nodejs/src/plugins/log-default/colours.ts @@ -1,27 +1,29 @@ -export enum ConsoleColours { - Reset = "\x1b[0m", - Bright = "\x1b[1m", - Dim = "\x1b[2m", - Underscore = "\x1b[4m", - Blink = "\x1b[5m", - Reverse = "\x1b[7m", - Hidden = "\x1b[8m", +export const CONSOLE_COLOURS = { + Reset: "\x1b[0m", + Bright: "\x1b[1m", + Dim: "\x1b[2m", + Underscore: "\x1b[4m", + Blink: "\x1b[5m", + Reverse: "\x1b[7m", + Hidden: "\x1b[8m", - FgBlack = "\x1b[30m", - FgRed = "\x1b[31m", - FgGreen = "\x1b[32m", - FgYellow = "\x1b[33m", - FgBlue = "\x1b[34m", - FgMagenta = "\x1b[35m", - FgCyan = "\x1b[36m", - FgWhite = "\x1b[37m", + FgBlack: "\x1b[30m", + FgRed: "\x1b[31m", + FgGreen: "\x1b[32m", + FgYellow: "\x1b[33m", + FgBlue: "\x1b[34m", + FgMagenta: "\x1b[35m", + FgCyan: "\x1b[36m", + FgWhite: "\x1b[37m", - BgBlack = "\x1b[40m", - BgRed = "\x1b[41m", - BgGreen = "\x1b[42m", - BgYellow = "\x1b[43m", - BgBlue = "\x1b[44m", - BgMagenta = "\x1b[45m", - BgCyan = "\x1b[46m", - BgWhite = "\x1b[47m", -} + BgBlack: "\x1b[40m", + BgRed: "\x1b[41m", + BgGreen: "\x1b[42m", + BgYellow: "\x1b[43m", + BgBlue: "\x1b[44m", + BgMagenta: "\x1b[45m", + BgCyan: "\x1b[46m", + BgWhite: "\x1b[47m", +} as const; +export type ConsoleColours = + (typeof CONSOLE_COLOURS)[keyof typeof CONSOLE_COLOURS]; diff --git a/nodejs/src/plugins/log-default/plugin.ts b/nodejs/src/plugins/log-default/plugin.ts index ec11a34..feb8707 100644 --- a/nodejs/src/plugins/log-default/plugin.ts +++ b/nodejs/src/plugins/log-default/plugin.ts @@ -1,25 +1,27 @@ import { IPluginLogger, LogMeta } from "../../interfaces/logger"; import { LoggerBase } from "../../logger/logger"; -import { ConsoleColours } from "./colours"; +import { CONSOLE_COLOURS, ConsoleColours } from "./colours"; import { PluginConfig } from "./sec.config"; -export enum LogLevels { - TSTAT = -3, - STAT = -2, - DEBUG = -1, - INFO = 0, - WARN = 1, - ERROR = 2, -} +export const LOG_LEVELS = { + TSTAT: "Text Statistic", + STAT: "Statistic", + DEBUG: "Debug", + INFO: "Info", + WARN: "Warn", + ERROR: "Error", +} as const; +export type LogLevels = (typeof LOG_LEVELS)[keyof typeof LOG_LEVELS]; + export class Logger extends LoggerBase { - private _mockedConsole?: { (level: number, message: string): void }; + private _mockedConsole?: { (level: LogLevels, message: string): void }; private _mockConsole: boolean = false; constructor( pluginName: string, cwd: string, pluginCwd: string, defaultLogger: IPluginLogger, - mockConsole?: { (level: number, message: string): void } + mockConsole?: { (level: LogLevels, message: string): void } ) { super(pluginName, cwd, pluginCwd, defaultLogger); this._mockedConsole = mockConsole; @@ -36,38 +38,38 @@ export class Logger extends LoggerBase { formattedMessage = `[${plugin.toUpperCase()}] ${formattedMessage}`; let func: any = console.debug; let colour: Array = [ - ConsoleColours.BgBlack, - ConsoleColours.FgWhite, + CONSOLE_COLOURS.BgBlack, + CONSOLE_COLOURS.FgWhite, ]; - if (level === LogLevels.STAT) { + if (level === LOG_LEVELS.STAT) { formattedMessage = `[STAT] ${formattedMessage}`; - colour = [ConsoleColours.BgYellow, ConsoleColours.FgBlack]; + colour = [CONSOLE_COLOURS.BgYellow, CONSOLE_COLOURS.FgBlack]; } - if (level === LogLevels.TSTAT) { + if (level === LOG_LEVELS.TSTAT) { formattedMessage = `[STAT] ${formattedMessage}`; - colour = [ConsoleColours.BgCyan, ConsoleColours.FgWhite]; + colour = [CONSOLE_COLOURS.BgCyan, CONSOLE_COLOURS.FgWhite]; } - if (level === LogLevels.DEBUG) { + if (level === LOG_LEVELS.DEBUG) { formattedMessage = `[DEBUG] ${formattedMessage}`; - colour = [ConsoleColours.BgBlue, ConsoleColours.FgWhite]; + colour = [CONSOLE_COLOURS.BgBlue, CONSOLE_COLOURS.FgWhite]; } - if (level === LogLevels.INFO) { + if (level === LOG_LEVELS.INFO) { formattedMessage = `[INFO] ${formattedMessage}`; func = console.log; colour = []; } - if (level === LogLevels.WARN) { + if (level === LOG_LEVELS.WARN) { formattedMessage = `[WARN] ${formattedMessage}`; func = console.warn; - colour = [ConsoleColours.BgBlack, ConsoleColours.FgRed]; + colour = [CONSOLE_COLOURS.BgBlack, CONSOLE_COLOURS.FgRed]; } - if (level === LogLevels.ERROR) { + if (level === LOG_LEVELS.ERROR) { formattedMessage = `[ERROR] ${formattedMessage}`; func = console.error; - colour = [ConsoleColours.BgRed, ConsoleColours.FgBlack]; + colour = [CONSOLE_COLOURS.BgRed, CONSOLE_COLOURS.FgBlack]; } if (this._mockConsole) return this._mockedConsole!(level, formattedMessage); - func(colour.join("") + "%s" + ConsoleColours.Reset, formattedMessage); + func(colour.join("") + "%s" + CONSOLE_COLOURS.Reset, formattedMessage); } public async reportStat( @@ -76,7 +78,7 @@ export class Logger extends LoggerBase { value: number ): Promise { if (!this.runningDebug) return; - this.logEvent(LogLevels.STAT, plugin, "[{key}={value}]", { key, value }); + this.logEvent(LOG_LEVELS.STAT, plugin, "[{key}={value}]", { key, value }); } public async reportTextStat( plugin: string, @@ -85,7 +87,7 @@ export class Logger extends LoggerBase { hasPIData?: boolean ): Promise { if (!this.runningDebug) return; - this.logEvent(LogLevels.TSTAT, plugin, message as T, meta); + this.logEvent(LOG_LEVELS.TSTAT, plugin, message as T, meta); } public async debug( plugin: string, @@ -94,7 +96,7 @@ export class Logger extends LoggerBase { hasPIData?: boolean ): Promise { if (!this.runningDebug) return; - this.logEvent(LogLevels.DEBUG, plugin, message as T, meta); + this.logEvent(LOG_LEVELS.DEBUG, plugin, message as T, meta); } public async info( plugin: string, @@ -103,7 +105,7 @@ export class Logger extends LoggerBase { hasPIData?: boolean ): Promise { if (this.runningLive && hasPIData === true) return; - this.logEvent(LogLevels.INFO, plugin, message as T, meta); + this.logEvent(LOG_LEVELS.INFO, plugin, message as T, meta); } public async warn( plugin: string, @@ -112,7 +114,7 @@ export class Logger extends LoggerBase { hasPIData?: boolean ): Promise { if (this.runningLive && hasPIData === true) return; - this.logEvent(LogLevels.WARN, plugin, message as T, meta); + this.logEvent(LOG_LEVELS.WARN, plugin, message as T, meta); } public async error( plugin: string, @@ -132,7 +134,7 @@ export class Logger extends LoggerBase { ? messageOrError : messageOrError.message; if (this.runningLive && hasPIData === true) return; - this.logEvent(LogLevels.ERROR, plugin, message as T, meta); + this.logEvent(LOG_LEVELS.ERROR, plugin, message as T, meta); if ( typeof messageOrError !== "string" && messageOrError.stack !== undefined diff --git a/nodejs/src/serviceBase/config.ts b/nodejs/src/serviceBase/config.ts index b2a676a..cd05c42 100644 --- a/nodejs/src/serviceBase/config.ts +++ b/nodejs/src/serviceBase/config.ts @@ -1,7 +1,7 @@ import { Tools } from "@bettercorp/tools/lib/Tools"; import { existsSync, readFileSync } from "fs"; import { join } from "path"; -import { IPluginDefinition, IReadyPlugin } from "../interfaces/service"; +import { PluginDefinitions, IReadyPlugin, PluginDefinition } from "../interfaces/service"; import { IPluginLogger } from "../interfaces/logger"; import { ConfigBase } from "../config/config"; import { SecConfig } from "../interfaces/serviceConfig"; @@ -52,7 +52,7 @@ export class SBConfig { pluginName, }); for (const plugin of plugins) { - if (plugin.pluginDefinition === IPluginDefinition.config) { + if (plugin.pluginDefinition === PluginDefinitions.config) { if (pluginName !== plugin.name) continue; await this.log.info(`PLUGIN {name}v{version}`, { name: plugin.name, @@ -79,15 +79,15 @@ export class SBConfig { let mappedPlugins: Array = []; for (let plugin of _plugins) { - if (plugin.pluginDefinition !== IPluginDefinition.config) continue; + if (plugin.pluginDefinition !== PluginDefinitions.config) continue; if (plugin.name !== this.configPlugin.plugin.name) continue; mappedPlugins.push(plugin); } for (let plugin of _plugins) { if ( - plugin.pluginDefinition === IPluginDefinition.config || - plugin.pluginDefinition === IPluginDefinition.service + plugin.pluginDefinition === PluginDefinitions.config || + plugin.pluginDefinition === PluginDefinitions.service ) continue; //if (!await this.appConfig.getAppPluginState(plugin.name)) continue; @@ -98,7 +98,7 @@ export class SBConfig { } for (let plugin of _plugins) { - if (plugin.pluginDefinition !== IPluginDefinition.service) continue; + if (plugin.pluginDefinition !== PluginDefinitions.service) continue; if (!(await this.appConfig.getAppPluginState(plugin.name))) continue; plugin.mappedName = await this.appConfig.getAppPluginMappedName( plugin.name @@ -112,7 +112,7 @@ export class SBConfig { public async findPluginByType( plugins: Array, defaultPlugin: string, - type: IPluginDefinition + type: PluginDefinition ): Promise { for (const plugin of plugins) { if (plugin.pluginDefinition === type) { diff --git a/nodejs/src/serviceBase/plugins.ts b/nodejs/src/serviceBase/plugins.ts index 1b7643a..321c836 100644 --- a/nodejs/src/serviceBase/plugins.ts +++ b/nodejs/src/serviceBase/plugins.ts @@ -7,17 +7,17 @@ import { } from "fs"; import { join } from "path"; import { IPluginLogger } from "../interfaces/logger"; -import { IPluginDefinition, IReadyPlugin } from "../interfaces/service"; +import { PluginDefinitions, IReadyPlugin, PluginDefinition } from "../interfaces/service"; import { Tools } from "@bettercorp/tools"; export class SBPlugins { - public static getPluginType(name: string): IPluginDefinition | null { + public static getPluginType(name: string): PluginDefinition | null { const pluginLow = name.toLowerCase(); - if (pluginLow.indexOf("service-") === 0) return IPluginDefinition.service; - if (pluginLow.indexOf("config-") === 0) return IPluginDefinition.config; - if (pluginLow.indexOf("events-") === 0) return IPluginDefinition.events; + if (pluginLow.indexOf("service-") === 0) return PluginDefinitions.service; + if (pluginLow.indexOf("config-") === 0) return PluginDefinitions.config; + if (pluginLow.indexOf("events-") === 0) return PluginDefinitions.events; if (pluginLow.indexOf("log-") === 0 || pluginLow.indexOf("logs-") === 0) - return IPluginDefinition.logging; + return PluginDefinitions.logging; return null; } diff --git a/nodejs/src/serviceBase/serviceBase.ts b/nodejs/src/serviceBase/serviceBase.ts index d241c99..5b0700d 100644 --- a/nodejs/src/serviceBase/serviceBase.ts +++ b/nodejs/src/serviceBase/serviceBase.ts @@ -1,6 +1,6 @@ import { IPluginLogger, LogMeta } from "../interfaces/logger"; import { SBLogger } from "./logger"; -import { IPluginDefinition, IReadyPlugin } from "../interfaces/service"; +import { PluginDefinitions, IReadyPlugin } from "../interfaces/service"; import { SBPlugins } from "./plugins"; import { SBServices } from "./services"; import { IDictionary } from "@bettercorp/tools/lib/Interfaces"; @@ -12,17 +12,18 @@ import { randomUUID } from "crypto"; import { hostname } from "os"; import { Tools } from "@bettercorp/tools/lib/Tools"; -export enum BOOT_STAT_KEYS { - BSB = "BSB", - SELF = "SELF", - PLUGINS = "PLUGINS", - CONFIG = "CONFIG", - LOGGER = "LOGGER", - EVENTS = "EVENTS", - SERVICES = "SERVICES", - INIT = "INIT", - RUN = "RUN", -} +export const BOOT_STAT_KEYS = { + BSB: "BSB", + SELF: "SELF", + PLUGINS: "PLUGINS", + CONFIG: "CONFIG", + LOGGER: "LOGGER", + EVENTS: "EVENTS", + SERVICES: "SERVICES", + INIT: "INIT", + RUN: "RUN", +} as const; +export type BootStatKeys = (typeof BOOT_STAT_KEYS)[keyof typeof BOOT_STAT_KEYS]; export const NS_PER_SEC = 1e9; export const MS_PER_NS = 1e-6; @@ -50,12 +51,12 @@ export class ServiceBase { private _keeps: IDictionary<[number, number]> = {}; private _heartbeat!: NodeJS.Timer; - private _startKeep(stepName: BOOT_STAT_KEYS) { + private _startKeep(stepName: BootStatKeys) { if (this.log !== undefined) this.log.debug("Starting timer for {log}", { log: stepName }); this._keeps[stepName] = process.hrtime(); } - private async _outputKeep(stepName: BOOT_STAT_KEYS) { + private async _outputKeep(stepName: BootStatKeys) { let diff = process.hrtime(this._keeps[stepName] || undefined); let logMeta: LogMeta = { nsTime: diff[0] * NS_PER_SEC + diff[1], @@ -118,7 +119,9 @@ export class ServiceBase { this._packJsonFile = path.join(this.cwd, "./package.json"); if (!fs.existsSync(this._packJsonFile)) { - await this.log.fatal("PACKAGE.JSON FILE NOT FOUND IN {cwd}", { cwd: this.cwd }); + await this.log.fatal("PACKAGE.JSON FILE NOT FOUND IN {cwd}", { + cwd: this.cwd, + }); return; } this._appVersion = JSON.parse( @@ -214,7 +217,7 @@ export class ServiceBase { let loggingPlugin = await this._config.findPluginByType( this.plugins, "log-default", - IPluginDefinition.logging + PluginDefinitions.logging ); await this._config.ImportAndMigratePluginConfig(loggingPlugin); await this._logger.setupLogger( @@ -232,7 +235,7 @@ export class ServiceBase { let eventsPlugin = await this._config.findPluginByType( this.plugins, "events-default", - IPluginDefinition.events + PluginDefinitions.events ); await this._config.ImportAndMigratePluginConfig(eventsPlugin); await this._events.setupEvents( diff --git a/nodejs/src/serviceBase/services.ts b/nodejs/src/serviceBase/services.ts index c78733a..82f8bd7 100644 --- a/nodejs/src/serviceBase/services.ts +++ b/nodejs/src/serviceBase/services.ts @@ -1,5 +1,5 @@ import { IPluginLogger } from "../interfaces/logger"; -import { IPluginDefinition, IReadyPlugin } from "../interfaces/service"; +import { PluginDefinitions, IReadyPlugin } from "../interfaces/service"; import { IServiceEvents } from "../interfaces/events"; import { SBBase } from "./base"; import { ServicesBase } from "../service/service"; @@ -41,7 +41,7 @@ export class SBServices { generateLoggerForPlugin: { (pluginName: string): IPluginLogger } ) { for (let plugin of plugins) { - if (plugin.pluginDefinition !== IPluginDefinition.service) continue; + if (plugin.pluginDefinition !== PluginDefinitions.service) continue; await this.log.debug(`Import service plugin: {name} from {file}`, { name: plugin.name, diff --git a/nodejs/src/tests/plugins/log-default/plugin.ts b/nodejs/src/tests/plugins/log-default/plugin.ts index 03c3dc5..ba13d0a 100644 --- a/nodejs/src/tests/plugins/log-default/plugin.ts +++ b/nodejs/src/tests/plugins/log-default/plugin.ts @@ -1,5 +1,5 @@ import assert from "assert"; -import { Logger, LogLevels } from "../../../plugins/log-default/plugin"; +import { Logger, LOG_LEVELS, LogLevels } from "../../../plugins/log-default/plugin"; describe("plugins/log-default", () => { describe("console.x", () => { @@ -299,8 +299,8 @@ describe("plugins/log-default", () => { }); describe("console mocked/overriden", () => { it("should mocked a stat event", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.STAT) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.STAT) return assert.fail(new Error(message)); assert.equal(message, "[STAT] [DEFAULT-STAT] [val=2]"); }; @@ -315,8 +315,8 @@ describe("plugins/log-default", () => { }); it("should mocked a debug event", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.DEBUG) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.DEBUG) return assert.fail(new Error(message)); assert.equal(message, "[DEBUG] [DEFAULT-DBG] My Msg"); }; @@ -330,8 +330,8 @@ describe("plugins/log-default", () => { await plugin.debug("default-DbG", "My Msg"); }); it("should mocked a debug event (meta)", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.DEBUG) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.DEBUG) return assert.fail(new Error(message)); assert.equal( message, "[DEBUG] [DEFAULT-DBG] My Msg cHEESE and a,b (5)" @@ -353,8 +353,8 @@ describe("plugins/log-default", () => { }); it("should mocked a info event", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.INFO) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.INFO) return assert.fail(new Error(message)); assert.equal(message, "[INFO] [INFO-DBG] My Msg"); }; @@ -368,8 +368,8 @@ describe("plugins/log-default", () => { await plugin.info("info-DbG", "My Msg"); }); it("should mocked a info event (meta)", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.INFO) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.INFO) return assert.fail(new Error(message)); assert.equal(message, "[INFO] [INFO-DBG] My Msg cHEESE and a,b (5)"); }; @@ -388,8 +388,8 @@ describe("plugins/log-default", () => { }); it("should mocked a error event", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.ERROR) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.ERROR) return assert.fail(new Error(message)); assert.equal(message, "[ERROR] [INFEE-DBG] My Msg"); }; @@ -403,8 +403,8 @@ describe("plugins/log-default", () => { await plugin.error("infee-DbG", "My Msg"); }); it("should mocked a error event (meta)", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.ERROR) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.ERROR) return assert.fail(new Error(message)); assert.equal(message, "[ERROR] [INFE-DBG] My Msg cHEESE and a,b (5)"); }; @@ -423,8 +423,8 @@ describe("plugins/log-default", () => { }); it("should mocked a warn event", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.WARN) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.WARN) return assert.fail(new Error(message)); assert.equal(message, "[WARN] [INFOW-DBG] My Msg"); }; @@ -438,8 +438,8 @@ describe("plugins/log-default", () => { await plugin.warn("infoW-DbG", "My Msg"); }); it("should mocked a warn event (meta)", async () => { - const fakeLogFunc = (level: number, message: string): any => { - if (level !== LogLevels.WARN) return assert.fail(new Error(message)); + const fakeLogFunc = (level: LogLevels, message: string): any => { + if (level !== LOG_LEVELS.WARN) return assert.fail(new Error(message)); assert.equal(message, "[WARN] [INFW-DBG] My Msg cHEESE and a,b (5)"); }; From d5f48401889f015f6cf77a88027cc87e42f8acaa Mon Sep 17 00:00:00 2001 From: mrinc Date: Wed, 13 Dec 2023 18:04:37 +0200 Subject: [PATCH 12/47] Added dotnet base --- dotnet/.dockerignore | 25 +++++++ dotnet/.idea/.idea.BSB/.idea/.gitignore | 13 ++++ dotnet/.idea/.idea.BSB/.idea/.name | 1 + dotnet/.idea/.idea.BSB/.idea/encodings.xml | 4 ++ dotnet/.idea/.idea.BSB/.idea/indexLayout.xml | 8 +++ dotnet/.idea/.idea.BSB/.idea/vcs.xml | 6 ++ dotnet/BSB.sln | 22 ++++++ dotnet/BSB/BSB.csproj | 9 +++ dotnet/BSB/Class1.cs | 5 ++ dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json | 61 ++++++++++++++++ dotnet/BSB/obj/BSB.csproj.nuget.g.props | 15 ++++ dotnet/BSB/obj/BSB.csproj.nuget.g.targets | 2 + ...CoreApp,Version=v6.0.AssemblyAttributes.cs | 4 ++ .../BSB/obj/Debug/net6.0/BSB.AssemblyInfo.cs | 22 ++++++ .../Debug/net6.0/BSB.AssemblyInfoInputs.cache | 1 + ....GeneratedMSBuildEditorConfig.editorconfig | 10 +++ .../obj/Debug/net6.0/BSB.GlobalUsings.g.cs | 8 +++ dotnet/BSB/obj/Debug/net6.0/BSB.assets.cache | Bin 0 -> 141 bytes .../net6.0/BSB.csproj.AssemblyReference.cache | Bin 0 -> 71759 bytes dotnet/BSB/obj/project.assets.json | 66 ++++++++++++++++++ dotnet/BSB/obj/project.nuget.cache | 8 +++ dotnet/BSB/obj/project.packagespec.json | 1 + dotnet/BSB/obj/rider.project.restore.info | 1 + dotnet/BetterServiceBase.csproj | 9 --- .../BetterServiceBase.csproj | 17 +++++ dotnet/BetterServiceBase/Dockerfile | 18 +++++ dotnet/BetterServiceBase/Program.cs | 3 + .../bin/Debug/net6.0/BetterServiceBase | Bin 0 -> 142840 bytes .../Debug/net6.0/BetterServiceBase.deps.json | 23 ++++++ .../bin/Debug/net6.0/BetterServiceBase.dll | Bin 0 -> 4608 bytes .../bin/Debug/net6.0/BetterServiceBase.pdb | Bin 0 -> 10356 bytes .../BetterServiceBase.runtimeconfig.json | 9 +++ ...BetterServiceBase.csproj.nuget.dgspec.json | 61 ++++++++++++++++ .../BetterServiceBase.csproj.nuget.g.props | 15 ++++ .../BetterServiceBase.csproj.nuget.g.targets | 2 + ...CoreApp,Version=v6.0.AssemblyAttributes.cs | 4 ++ .../net6.0/BetterServiceBase.AssemblyInfo.cs | 22 ++++++ ...BetterServiceBase.AssemblyInfoInputs.cache | 1 + ....GeneratedMSBuildEditorConfig.editorconfig | 10 +++ .../BetterServiceBase.GlobalUsings.g.cs | 8 +++ .../net6.0/BetterServiceBase.assets.cache | Bin 0 -> 141 bytes ...ServiceBase.csproj.AssemblyReference.cache | Bin 0 -> 71759 bytes ...ServiceBase.csproj.CoreCompileInputs.cache | 1 + ...terServiceBase.csproj.FileListAbsolute.txt | 15 ++++ .../obj/Debug/net6.0/BetterServiceBase.dll | Bin 0 -> 4608 bytes .../BetterServiceBase.genruntimeconfig.cache | 1 + .../obj/Debug/net6.0/BetterServiceBase.pdb | Bin 0 -> 10356 bytes .../obj/Debug/net6.0/apphost | Bin 0 -> 142840 bytes .../Debug/net6.0/ref/BetterServiceBase.dll | Bin 0 -> 5120 bytes .../Debug/net6.0/refint/BetterServiceBase.dll | Bin 0 -> 5120 bytes .../BetterServiceBase/obj/project.assets.json | 66 ++++++++++++++++++ .../BetterServiceBase/obj/project.nuget.cache | 8 +++ .../obj/project.packagespec.json | 1 + .../obj/rider.project.restore.info | 1 + dotnet/Class1.cs | 5 -- 55 files changed, 578 insertions(+), 14 deletions(-) create mode 100644 dotnet/.dockerignore create mode 100644 dotnet/.idea/.idea.BSB/.idea/.gitignore create mode 100644 dotnet/.idea/.idea.BSB/.idea/.name create mode 100644 dotnet/.idea/.idea.BSB/.idea/encodings.xml create mode 100644 dotnet/.idea/.idea.BSB/.idea/indexLayout.xml create mode 100644 dotnet/.idea/.idea.BSB/.idea/vcs.xml create mode 100644 dotnet/BSB.sln create mode 100644 dotnet/BSB/BSB.csproj create mode 100644 dotnet/BSB/Class1.cs create mode 100644 dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json create mode 100644 dotnet/BSB/obj/BSB.csproj.nuget.g.props create mode 100644 dotnet/BSB/obj/BSB.csproj.nuget.g.targets create mode 100644 dotnet/BSB/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs create mode 100644 dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfo.cs create mode 100644 dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfoInputs.cache create mode 100644 dotnet/BSB/obj/Debug/net6.0/BSB.GeneratedMSBuildEditorConfig.editorconfig create mode 100644 dotnet/BSB/obj/Debug/net6.0/BSB.GlobalUsings.g.cs create mode 100644 dotnet/BSB/obj/Debug/net6.0/BSB.assets.cache create mode 100644 dotnet/BSB/obj/Debug/net6.0/BSB.csproj.AssemblyReference.cache create mode 100644 dotnet/BSB/obj/project.assets.json create mode 100644 dotnet/BSB/obj/project.nuget.cache create mode 100644 dotnet/BSB/obj/project.packagespec.json create mode 100644 dotnet/BSB/obj/rider.project.restore.info delete mode 100644 dotnet/BetterServiceBase.csproj create mode 100644 dotnet/BetterServiceBase/BetterServiceBase.csproj create mode 100644 dotnet/BetterServiceBase/Dockerfile create mode 100644 dotnet/BetterServiceBase/Program.cs create mode 100755 dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase create mode 100644 dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.deps.json create mode 100644 dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.dll create mode 100644 dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.pdb create mode 100644 dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.runtimeconfig.json create mode 100644 dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.dgspec.json create mode 100644 dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.props create mode 100644 dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.targets create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfo.cs create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GlobalUsings.g.cs create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.assets.cache create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.AssemblyReference.cache create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.CoreCompileInputs.cache create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.FileListAbsolute.txt create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.dll create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.genruntimeconfig.cache create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.pdb create mode 100755 dotnet/BetterServiceBase/obj/Debug/net6.0/apphost create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/ref/BetterServiceBase.dll create mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/refint/BetterServiceBase.dll create mode 100644 dotnet/BetterServiceBase/obj/project.assets.json create mode 100644 dotnet/BetterServiceBase/obj/project.nuget.cache create mode 100644 dotnet/BetterServiceBase/obj/project.packagespec.json create mode 100644 dotnet/BetterServiceBase/obj/rider.project.restore.info delete mode 100644 dotnet/Class1.cs diff --git a/dotnet/.dockerignore b/dotnet/.dockerignore new file mode 100644 index 0000000..38bece4 --- /dev/null +++ b/dotnet/.dockerignore @@ -0,0 +1,25 @@ +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/.idea +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/dotnet/.idea/.idea.BSB/.idea/.gitignore b/dotnet/.idea/.idea.BSB/.idea/.gitignore new file mode 100644 index 0000000..b5b97e7 --- /dev/null +++ b/dotnet/.idea/.idea.BSB/.idea/.gitignore @@ -0,0 +1,13 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Rider ignored files +/projectSettingsUpdater.xml +/.idea.BSB.iml +/modules.xml +/contentModel.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/dotnet/.idea/.idea.BSB/.idea/.name b/dotnet/.idea/.idea.BSB/.idea/.name new file mode 100644 index 0000000..41e2ca1 --- /dev/null +++ b/dotnet/.idea/.idea.BSB/.idea/.name @@ -0,0 +1 @@ +BSB \ No newline at end of file diff --git a/dotnet/.idea/.idea.BSB/.idea/encodings.xml b/dotnet/.idea/.idea.BSB/.idea/encodings.xml new file mode 100644 index 0000000..df87cf9 --- /dev/null +++ b/dotnet/.idea/.idea.BSB/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/dotnet/.idea/.idea.BSB/.idea/indexLayout.xml b/dotnet/.idea/.idea.BSB/.idea/indexLayout.xml new file mode 100644 index 0000000..7b08163 --- /dev/null +++ b/dotnet/.idea/.idea.BSB/.idea/indexLayout.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/dotnet/.idea/.idea.BSB/.idea/vcs.xml b/dotnet/.idea/.idea.BSB/.idea/vcs.xml new file mode 100644 index 0000000..6c0b863 --- /dev/null +++ b/dotnet/.idea/.idea.BSB/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/dotnet/BSB.sln b/dotnet/BSB.sln new file mode 100644 index 0000000..bce70b8 --- /dev/null +++ b/dotnet/BSB.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BSB", "BSB\BSB.csproj", "{B613E86E-57C5-49ED-9AE4-56B2F5CC9E52}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BetterServiceBase", "BetterServiceBase\BetterServiceBase.csproj", "{8F3AD3A2-8E2D-488F-ACA3-B16518C2A4EE}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {B613E86E-57C5-49ED-9AE4-56B2F5CC9E52}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B613E86E-57C5-49ED-9AE4-56B2F5CC9E52}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B613E86E-57C5-49ED-9AE4-56B2F5CC9E52}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B613E86E-57C5-49ED-9AE4-56B2F5CC9E52}.Release|Any CPU.Build.0 = Release|Any CPU + {8F3AD3A2-8E2D-488F-ACA3-B16518C2A4EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F3AD3A2-8E2D-488F-ACA3-B16518C2A4EE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F3AD3A2-8E2D-488F-ACA3-B16518C2A4EE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F3AD3A2-8E2D-488F-ACA3-B16518C2A4EE}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/dotnet/BSB/BSB.csproj b/dotnet/BSB/BSB.csproj new file mode 100644 index 0000000..eb2460e --- /dev/null +++ b/dotnet/BSB/BSB.csproj @@ -0,0 +1,9 @@ + + + + net6.0 + enable + enable + + + diff --git a/dotnet/BSB/Class1.cs b/dotnet/BSB/Class1.cs new file mode 100644 index 0000000..f468f22 --- /dev/null +++ b/dotnet/BSB/Class1.cs @@ -0,0 +1,5 @@ +namespace BSB; + +public class Class1 +{ +} \ No newline at end of file diff --git a/dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json b/dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json new file mode 100644 index 0000000..8efc835 --- /dev/null +++ b/dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json @@ -0,0 +1,61 @@ +{ + "format": 1, + "restore": { + "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj": {} + }, + "projects": { + "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj", + "projectName": "BSB", + "projectPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj", + "packagesPath": "/home/mitchellr/.nuget/packages/", + "outputPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/home/mitchellr/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/home/mitchellr/.dotnet/sdk/6.0.404/RuntimeIdentifierGraph.json" + } + } + } + } +} \ No newline at end of file diff --git a/dotnet/BSB/obj/BSB.csproj.nuget.g.props b/dotnet/BSB/obj/BSB.csproj.nuget.g.props new file mode 100644 index 0000000..84ab64a --- /dev/null +++ b/dotnet/BSB/obj/BSB.csproj.nuget.g.props @@ -0,0 +1,15 @@ + + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /home/mitchellr/.nuget/packages/ + /home/mitchellr/.nuget/packages/ + PackageReference + 6.6.0 + + + + + \ No newline at end of file diff --git a/dotnet/BSB/obj/BSB.csproj.nuget.g.targets b/dotnet/BSB/obj/BSB.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/dotnet/BSB/obj/BSB.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/dotnet/BSB/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/dotnet/BSB/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs new file mode 100644 index 0000000..f795be5 --- /dev/null +++ b/dotnet/BSB/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfo.cs b/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfo.cs new file mode 100644 index 0000000..c17b5f3 --- /dev/null +++ b/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("BSB")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("BSB")] +[assembly: System.Reflection.AssemblyTitleAttribute("BSB")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfoInputs.cache b/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfoInputs.cache new file mode 100644 index 0000000..1862044 --- /dev/null +++ b/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +06c03cd1a62928a8792c4baac24a35040fa8a3ca diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.GeneratedMSBuildEditorConfig.editorconfig b/dotnet/BSB/obj/Debug/net6.0/BSB.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..b5b2b53 --- /dev/null +++ b/dotnet/BSB/obj/Debug/net6.0/BSB.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,10 @@ +is_global = true +build_property.TargetFramework = net6.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = BSB +build_property.ProjectDir = /home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/ diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.GlobalUsings.g.cs b/dotnet/BSB/obj/Debug/net6.0/BSB.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/dotnet/BSB/obj/Debug/net6.0/BSB.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.assets.cache b/dotnet/BSB/obj/Debug/net6.0/BSB.assets.cache new file mode 100644 index 0000000000000000000000000000000000000000..e89ac286856a615cd6e38cbfc4b405f4ec0088ed GIT binary patch literal 141 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 literal 0 HcmV?d00001 diff --git a/dotnet/BSB/obj/project.assets.json b/dotnet/BSB/obj/project.assets.json new file mode 100644 index 0000000..440014c --- /dev/null +++ b/dotnet/BSB/obj/project.assets.json @@ -0,0 +1,66 @@ +{ + "version": 3, + "targets": { + "net6.0": {} + }, + "libraries": {}, + "projectFileDependencyGroups": { + "net6.0": [] + }, + "packageFolders": { + "/home/mitchellr/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj", + "projectName": "BSB", + "projectPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj", + "packagesPath": "/home/mitchellr/.nuget/packages/", + "outputPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/home/mitchellr/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/home/mitchellr/.dotnet/sdk/6.0.404/RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/dotnet/BSB/obj/project.nuget.cache b/dotnet/BSB/obj/project.nuget.cache new file mode 100644 index 0000000..9861e36 --- /dev/null +++ b/dotnet/BSB/obj/project.nuget.cache @@ -0,0 +1,8 @@ +{ + "version": 2, + "dgSpecHash": "846PNqqcp/UMPpefQDVjVUSUeNezpWFigUdhxsBKbP6tN51Jgx6AT8hBftcsek+nliyefWyALGeK9gslUv2uNA==", + "success": true, + "projectFilePath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj", + "expectedPackageFiles": [], + "logs": [] +} \ No newline at end of file diff --git a/dotnet/BSB/obj/project.packagespec.json b/dotnet/BSB/obj/project.packagespec.json new file mode 100644 index 0000000..95f26ab --- /dev/null +++ b/dotnet/BSB/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj","projectName":"BSB","projectPath":"/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj","outputPath":"/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net6.0"],"sources":{"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net6.0":{"targetAlias":"net6.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]}}"frameworks":{"net6.0":{"targetAlias":"net6.0","imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/home/mitchellr/.dotnet/sdk/6.0.404/RuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/dotnet/BSB/obj/rider.project.restore.info b/dotnet/BSB/obj/rider.project.restore.info new file mode 100644 index 0000000..4a89f78 --- /dev/null +++ b/dotnet/BSB/obj/rider.project.restore.info @@ -0,0 +1 @@ +16993920343007420 \ No newline at end of file diff --git a/dotnet/BetterServiceBase.csproj b/dotnet/BetterServiceBase.csproj deleted file mode 100644 index bafd05b..0000000 --- a/dotnet/BetterServiceBase.csproj +++ /dev/null @@ -1,9 +0,0 @@ - - - - net6.0 - enable - enable - - - diff --git a/dotnet/BetterServiceBase/BetterServiceBase.csproj b/dotnet/BetterServiceBase/BetterServiceBase.csproj new file mode 100644 index 0000000..ec44a9e --- /dev/null +++ b/dotnet/BetterServiceBase/BetterServiceBase.csproj @@ -0,0 +1,17 @@ + + + + Exe + net6.0 + enable + enable + Linux + + + + + .dockerignore + + + + diff --git a/dotnet/BetterServiceBase/Dockerfile b/dotnet/BetterServiceBase/Dockerfile new file mode 100644 index 0000000..b912583 --- /dev/null +++ b/dotnet/BetterServiceBase/Dockerfile @@ -0,0 +1,18 @@ +FROM mcr.microsoft.com/dotnet/runtime:6.0 AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build +WORKDIR /src +COPY ["BetterServiceBase/BetterServiceBase.csproj", "BetterServiceBase/"] +RUN dotnet restore "BetterServiceBase/BetterServiceBase.csproj" +COPY . . +WORKDIR "/src/BetterServiceBase" +RUN dotnet build "BetterServiceBase.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "BetterServiceBase.csproj" -c Release -o /app/publish /p:UseAppHost=false + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "BetterServiceBase.dll"] diff --git a/dotnet/BetterServiceBase/Program.cs b/dotnet/BetterServiceBase/Program.cs new file mode 100644 index 0000000..e5dff12 --- /dev/null +++ b/dotnet/BetterServiceBase/Program.cs @@ -0,0 +1,3 @@ +// See https://aka.ms/new-console-template for more information + +Console.WriteLine("Hello, World!"); \ No newline at end of file diff --git a/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase new file mode 100755 index 0000000000000000000000000000000000000000..c288946f56fa0006a3b6e7101b0c0f3e432887a2 GIT binary patch literal 142840 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 literal 0 HcmV?d00001 diff --git a/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.deps.json b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.deps.json new file mode 100644 index 0000000..78e150b --- /dev/null +++ b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.deps.json @@ -0,0 +1,23 @@ +{ + "runtimeTarget": { + "name": ".NETCoreApp,Version=v6.0", + "signature": "" + }, + "compilationOptions": {}, + "targets": { + ".NETCoreApp,Version=v6.0": { + "BetterServiceBase/1.0.0": { + "runtime": { + "BetterServiceBase.dll": {} + } + } + } + }, + "libraries": { + "BetterServiceBase/1.0.0": { + "type": "project", + "serviceable": false, + "sha512": "" + } + } +} \ No newline at end of file diff --git a/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.dll b/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.dll new file mode 100644 index 0000000000000000000000000000000000000000..0141408fdcd45663aad4383c3d1e12264f0becf2 GIT binary patch literal 4608 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 Mv(<7-)N + + + True + NuGet + $(MSBuildThisFileDirectory)project.assets.json + /home/mitchellr/.nuget/packages/ + /home/mitchellr/.nuget/packages/ + PackageReference + 6.6.0 + + + + + \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.targets b/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.targets new file mode 100644 index 0000000..3dc06ef --- /dev/null +++ b/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.targets @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/dotnet/BetterServiceBase/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs new file mode 100644 index 0000000..f795be5 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs @@ -0,0 +1,4 @@ +// +using System; +using System.Reflection; +[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")] diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfo.cs b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfo.cs new file mode 100644 index 0000000..b60dc30 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfo.cs @@ -0,0 +1,22 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +using System; +using System.Reflection; + +[assembly: System.Reflection.AssemblyCompanyAttribute("BetterServiceBase")] +[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] +[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] +[assembly: System.Reflection.AssemblyProductAttribute("BetterServiceBase")] +[assembly: System.Reflection.AssemblyTitleAttribute("BetterServiceBase")] +[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] + +// Generated by the MSBuild WriteCodeFragment class. + diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache new file mode 100644 index 0000000..8926452 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache @@ -0,0 +1 @@ +a9f474a87d2cc37e3df94bbe95f0b40bbfd0df92 diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig new file mode 100644 index 0000000..8b6cd16 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig @@ -0,0 +1,10 @@ +is_global = true +build_property.TargetFramework = net6.0 +build_property.TargetPlatformMinVersion = +build_property.UsingMicrosoftNETSdkWeb = +build_property.ProjectTypeGuids = +build_property.InvariantGlobalization = +build_property.PlatformNeutralAssembly = +build_property._SupportedPlatformList = Linux,macOS,Windows +build_property.RootNamespace = BetterServiceBase +build_property.ProjectDir = /home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/ diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GlobalUsings.g.cs b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GlobalUsings.g.cs new file mode 100644 index 0000000..8578f3d --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GlobalUsings.g.cs @@ -0,0 +1,8 @@ +// +global using global::System; +global using global::System.Collections.Generic; +global using global::System.IO; +global using global::System.Linq; +global using global::System.Net.Http; +global using global::System.Threading; +global using global::System.Threading.Tasks; diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.assets.cache b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.assets.cache new file mode 100644 index 0000000000000000000000000000000000000000..0d222a20f6cbd5deb0d55f4ff64ba683b4a6112d GIT binary patch literal 141 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 literal 0 HcmV?d00001 diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.CoreCompileInputs.cache b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.CoreCompileInputs.cache new file mode 100644 index 0000000..bfb0f84 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.CoreCompileInputs.cache @@ -0,0 +1 @@ +e8bb740154712d00dcb2031232868fc210f0e54b diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.FileListAbsolute.txt b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.FileListAbsolute.txt new file mode 100644 index 0000000..039a136 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.FileListAbsolute.txt @@ -0,0 +1,15 @@ +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.deps.json +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.runtimeconfig.json +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.dll +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/bin/Debug/net6.0/BetterServiceBase.pdb +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.AssemblyReference.cache +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfo.cs +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.CoreCompileInputs.cache +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.dll +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/refint/BetterServiceBase.dll +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.pdb +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.genruntimeconfig.cache +/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/Debug/net6.0/ref/BetterServiceBase.dll diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.dll b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.dll new file mode 100644 index 0000000000000000000000000000000000000000..0141408fdcd45663aad4383c3d1e12264f0becf2 GIT binary patch literal 4608 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 literal 0 HcmV?d00001 diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/ref/BetterServiceBase.dll b/dotnet/BetterServiceBase/obj/Debug/net6.0/ref/BetterServiceBase.dll new file mode 100644 index 0000000000000000000000000000000000000000..32cd7b8565140391307b1fb14221d4395ca33d48 GIT binary patch literal 5120 zcmeHKO>7%g5T4B+soR7ELP!Oat<#F1wi}1Es4a2pBu>(l{1LlBEfURo{p@VJKkmM@ z8>0$xfkRJlMI6e7UO@DKPyrz>9C|4d2PBU4h7eLOaN$7t-rL>St^+L`Dpd73JMYcB z*_m(V?aplGPQ6R5MAU}s)-9r|n8ip*`p;w?+ucup*-f8qxxVwNGJAbzcGcu+$#aXI zZmWjwIIgeenCg`s)pXSKLPoXSJkz?mV!J}qi<3mNN*n!tqxxIq?I()URwY5y0ZA;7 zz7IVKN)>#HNX#t(ZmcAJG1DbnA{dNTT6vqONB-63kPTGm80;>H^$Kon4~6y9I?*=p zd!hGaz5Gt=6j5iLPAB+db-ZR*%shCY+lVE?9jT>=#xtnUpP&m13DLJOkKRQ78LZ6q-= zd`K8%08ns%aw~oJ!i3+ zY>abe=d5bh^y|f0-77MG3Lh8jyz8B9)}MlpW#)0yb(%M4oPz7wx{poW`dh6D*D09A zGC(#M2?CJ9C1&Ysa>bjSEP6i;l~E)8LUPgrh}=7#=JS zj}D&k957A`xihdBJT*;yrA<|o&Q_I_b}V{(1>4=|RdVh!=?o`5$r5)l8$+q;r z>glC<*O^>1SV>^au6piyu0Zc0`ChdNdO)E8ZGJL4;d*SWRN5P6B3XG+OTbEZ-^P=Y zHhIa?tMhnps2{Ie^8-pTh1%t#h≪!zfw!;rkPE$pmplRDQQb4CYc;M}_F3Sf|9Q zc|`R#*f|a8lWS~FHyyIMfjF2vGO>GWH>Fa6+C8H!vev3Z>jUt)h`G^qP|Xf*A{TnM zDMJ$IuQqK3weeCb(Yq_C@0g>})4CtaWz?n9pp&$O)eP#=Jop*Vso-m!zHYnuXHcmE zTT#_I8X7{IfcM6cma=8i$%7peeTc!PLj`iB;w}<*WwEP6%CWDL4?P!LFs`(f&>0k9 z@}XryUfjgetkg+R^xIE4tclY2&{j}qU9zbpeN+*V4vtCl$Q7C?uoA8 zf3;ug9^{)}eKUG=&9>A^(B_hH6sNd~2IJ;Yh?DUX*{OX8<0|)cC$C$s!;iT4k~UkK37F~woF4dO-(PA;zNN2-z#%p^yRz6^FmzS2j83- zWe+|>9ukk8D+4FXFM4JL-vLF&@6zf>WL3qe*+F48%A)zqvI?_QOVDIo=QB>lJpj(`UK}jP+o1lrH4>e#P9ok3&6h?=l6FP#!zZWAFd>4Ok;9fX;;N$<6 GfxiGYG@axC literal 0 HcmV?d00001 diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/refint/BetterServiceBase.dll b/dotnet/BetterServiceBase/obj/Debug/net6.0/refint/BetterServiceBase.dll new file mode 100644 index 0000000000000000000000000000000000000000..32cd7b8565140391307b1fb14221d4395ca33d48 GIT binary patch literal 5120 zcmeHKO>7%g5T4B+soR7ELP!Oat<#F1wi}1Es4a2pBu>(l{1LlBEfURo{p@VJKkmM@ z8>0$xfkRJlMI6e7UO@DKPyrz>9C|4d2PBU4h7eLOaN$7t-rL>St^+L`Dpd73JMYcB z*_m(V?aplGPQ6R5MAU}s)-9r|n8ip*`p;w?+ucup*-f8qxxVwNGJAbzcGcu+$#aXI zZmWjwIIgeenCg`s)pXSKLPoXSJkz?mV!J}qi<3mNN*n!tqxxIq?I()URwY5y0ZA;7 zz7IVKN)>#HNX#t(ZmcAJG1DbnA{dNTT6vqONB-63kPTGm80;>H^$Kon4~6y9I?*=p zd!hGaz5Gt=6j5iLPAB+db-ZR*%shCY+lVE?9jT>=#xtnUpP&m13DLJOkKRQ78LZ6q-= zd`K8%08ns%aw~oJ!i3+ zY>abe=d5bh^y|f0-77MG3Lh8jyz8B9)}MlpW#)0yb(%M4oPz7wx{poW`dh6D*D09A zGC(#M2?CJ9C1&Ysa>bjSEP6i;l~E)8LUPgrh}=7#=JS zj}D&k957A`xihdBJT*;yrA<|o&Q_I_b}V{(1>4=|RdVh!=?o`5$r5)l8$+q;r z>glC<*O^>1SV>^au6piyu0Zc0`ChdNdO)E8ZGJL4;d*SWRN5P6B3XG+OTbEZ-^P=Y zHhIa?tMhnps2{Ie^8-pTh1%t#h≪!zfw!;rkPE$pmplRDQQb4CYc;M}_F3Sf|9Q zc|`R#*f|a8lWS~FHyyIMfjF2vGO>GWH>Fa6+C8H!vev3Z>jUt)h`G^qP|Xf*A{TnM zDMJ$IuQqK3weeCb(Yq_C@0g>})4CtaWz?n9pp&$O)eP#=Jop*Vso-m!zHYnuXHcmE zTT#_I8X7{IfcM6cma=8i$%7peeTc!PLj`iB;w}<*WwEP6%CWDL4?P!LFs`(f&>0k9 z@}XryUfjgetkg+R^xIE4tclY2&{j}qU9zbpeN+*V4vtCl$Q7C?uoA8 zf3;ug9^{)}eKUG=&9>A^(B_hH6sNd~2IJ;Yh?DUX*{OX8<0|)cC$C$s!;iT4k~UkK37F~woF4dO-(PA;zNN2-z#%p^yRz6^FmzS2j83- zWe+|>9ukk8D+4FXFM4JL-vLF&@6zf>WL3qe*+F48%A)zqvI?_QOVDIo=QB>lJpj(`UK}jP+o1lrH4>e#P9ok3&6h?=l6FP#!zZWAFd>4Ok;9fX;;N$<6 GfxiGYG@axC literal 0 HcmV?d00001 diff --git a/dotnet/BetterServiceBase/obj/project.assets.json b/dotnet/BetterServiceBase/obj/project.assets.json new file mode 100644 index 0000000..1d8f4ce --- /dev/null +++ b/dotnet/BetterServiceBase/obj/project.assets.json @@ -0,0 +1,66 @@ +{ + "version": 3, + "targets": { + "net6.0": {} + }, + "libraries": {}, + "projectFileDependencyGroups": { + "net6.0": [] + }, + "packageFolders": { + "/home/mitchellr/.nuget/packages/": {} + }, + "project": { + "version": "1.0.0", + "restore": { + "projectUniqueName": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "projectName": "BetterServiceBase", + "projectPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "packagesPath": "/home/mitchellr/.nuget/packages/", + "outputPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/", + "projectStyle": "PackageReference", + "configFilePaths": [ + "/home/mitchellr/.nuget/NuGet/NuGet.Config" + ], + "originalTargetFrameworks": [ + "net6.0" + ], + "sources": { + "https://api.nuget.org/v3/index.json": {} + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "projectReferences": {} + } + }, + "warningProperties": { + "warnAsError": [ + "NU1605" + ] + } + }, + "frameworks": { + "net6.0": { + "targetAlias": "net6.0", + "imports": [ + "net461", + "net462", + "net47", + "net471", + "net472", + "net48", + "net481" + ], + "assetTargetFallback": true, + "warn": true, + "frameworkReferences": { + "Microsoft.NETCore.App": { + "privateAssets": "all" + } + }, + "runtimeIdentifierGraphPath": "/home/mitchellr/.dotnet/sdk/6.0.404/RuntimeIdentifierGraph.json" + } + } + } +} \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/project.nuget.cache b/dotnet/BetterServiceBase/obj/project.nuget.cache new file mode 100644 index 0000000..9931131 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/project.nuget.cache @@ -0,0 +1,8 @@ +{ + "version": 2, + "dgSpecHash": "6C02A27v8AIrUk/f091ZNYiEh48VbXOUQkuaEttX9wfVc34nMPwErZXuzusJkAClEFjsHwfoNcI7Ft7y/aamYw==", + "success": true, + "projectFilePath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "expectedPackageFiles": [], + "logs": [] +} \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/project.packagespec.json b/dotnet/BetterServiceBase/obj/project.packagespec.json new file mode 100644 index 0000000..11a81e0 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/project.packagespec.json @@ -0,0 +1 @@ +"restore":{"projectUniqueName":"/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj","projectName":"BetterServiceBase","projectPath":"/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj","outputPath":"/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/","projectStyle":"PackageReference","originalTargetFrameworks":["net6.0"],"sources":{"https://api.nuget.org/v3/index.json":{}},"frameworks":{"net6.0":{"targetAlias":"net6.0","projectReferences":{}}},"warningProperties":{"warnAsError":["NU1605"]}}"frameworks":{"net6.0":{"targetAlias":"net6.0","imports":["net461","net462","net47","net471","net472","net48","net481"],"assetTargetFallback":true,"warn":true,"frameworkReferences":{"Microsoft.NETCore.App":{"privateAssets":"all"}},"runtimeIdentifierGraphPath":"/home/mitchellr/.dotnet/sdk/6.0.404/RuntimeIdentifierGraph.json"}} \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/rider.project.restore.info b/dotnet/BetterServiceBase/obj/rider.project.restore.info new file mode 100644 index 0000000..b052fc6 --- /dev/null +++ b/dotnet/BetterServiceBase/obj/rider.project.restore.info @@ -0,0 +1 @@ +16993920754842324 \ No newline at end of file diff --git a/dotnet/Class1.cs b/dotnet/Class1.cs deleted file mode 100644 index 0abd266..0000000 --- a/dotnet/Class1.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace BetterServiceBase; -public class Class1 -{ - -} From 7c61b8b0214e939abe887ee0c7df3eb34e82b697 Mon Sep 17 00:00:00 2001 From: mrinc Date: Thu, 14 Dec 2023 02:05:43 +0200 Subject: [PATCH 13/47] V9 initial code migration Changed config to be yaml instead of json Changed config format for simpler configuration Changed config format for multi-plugin services running concurrently with different names for monilith deployments Multi-log handler functionality added Logs can filter between different log plugins - allowing for log/plugin direction logging/stats - eg: logs to graylog but stats to grafana Added multi-events ability as well - you can route specific plugins/events over specific event plugins Starting migration away from sec.config.ts definitions for config of plugins More type-safety built into all elements callable methods are now a type safe object on the service - and a function to call them that is type linked events are now in the events object on the BSB service class for a cleaner plugin. init and run can be sync/async initial setup of a BSB plugin invoked abstract classes for more type-safety Split logging/events/plugins/services from SB into extendable classes for unique cases where the standard classes do not work the way you need them too - so you can extend and change what is needed without hacking around the problem Initial setup speed from from +1s to ~40ms Included cleanups during the setup to optimize memory usage config plugins are simplified even more for less data transfer from the config plugin to other services/ or the BSB itself Plugin search algorithim now uses defined info in config instead of trying to search for plugins - initial setup will require PDK for easier configuration prepped for zod - config validation prepped for future expansion with interoperability between languages with zod for input and output data from events. client setup is minified as well for simpler use clients get their own logging defition so you can identify what is creating logs PI data in logs are removed since it is more complex to handle in client code - so rather just control the data coming into logs better logging is now sync - but pushed to an events bus which then pushes to the logging plugins config plugin is disposed after use for memory and safety Plugin constructors now just have a single object passed in just to make it easier to setup/create a plugin Added more comments/ts info to functions to make use easier Simplified the setup of plugins for logging/events/config/services and moved them to their own classes Overall big cleanup and optimize as well as additional features for more flexibility in deployments --- nodejs/package-lock.json | 747 ++++++----- nodejs/package.json | 11 +- nodejs/sec-config.yaml | 20 + .../serviceClient.ts => base/PluginEvents.ts} | 563 ++++----- nodejs/src/base/PluginLogger.ts | 43 + nodejs/src/base/base.ts | 212 ++++ nodejs/src/base/config.ts | 91 ++ nodejs/src/base/errorMessages.ts | 39 + nodejs/src/{events => base}/events.ts | 168 ++- nodejs/src/base/functions.ts | 29 + nodejs/src/base/index.ts | 10 + nodejs/src/base/logFormatter.ts | 50 + nodejs/src/base/logging.ts | 183 +++ nodejs/src/base/service.ts | 85 ++ nodejs/src/base/serviceClient.ts | 49 + nodejs/src/cli.ts | 16 +- nodejs/src/clients/service-generic/plugin.ts | 132 -- nodejs/src/config/config.ts | 56 - nodejs/src/dev.ts | 10 +- nodejs/src/index.ts | 18 +- nodejs/src/initAppConfig.ts | 42 +- nodejs/src/install.ts | 488 ++++---- nodejs/src/interfaces/base.ts | 47 - nodejs/src/interfaces/config.ts | 35 - nodejs/src/interfaces/events.ts | 481 +------- nodejs/src/interfaces/index.ts | 5 + nodejs/src/interfaces/logger.ts | 76 -- nodejs/src/interfaces/logging.ts | 50 + nodejs/src/interfaces/plugins.ts | 94 ++ nodejs/src/interfaces/service.ts | 43 +- nodejs/src/interfaces/serviceConfig.ts | 29 +- nodejs/src/interfaces/static.ts | 57 - nodejs/src/logger/logger.ts | 103 -- .../src/plugins/config-default/interfaces.ts | 82 ++ nodejs/src/plugins/config-default/plugin.ts | 328 ++--- .../src/plugins/config-default/sec.config.ts | 20 - .../events-default/events/broadcast.ts | 20 +- .../src/plugins/events-default/events/emit.ts | 20 +- .../events-default/events/emitAndReturn.ts | 18 +- .../events/emitStreamAndReceiveStream.ts | 21 +- nodejs/src/plugins/events-default/plugin.ts | 73 +- .../src/plugins/events-default/sec.config.ts | 13 - nodejs/src/plugins/log-default/sec.config.ts | 13 - .../colours.ts | 0 .../plugin.ts | 82 +- nodejs/src/plugins/service-default0/plugin.ts | 45 +- .../plugins/service-default0/sec.config.ts | 34 +- nodejs/src/plugins/service-default1/plugin.ts | 143 ++- nodejs/src/plugins/service-default2/plugin.ts | 17 +- .../plugins/service-default2/sec.config.ts | 34 +- nodejs/src/plugins/service-default3/plugin.ts | 17 +- .../plugins/service-default3/sec.config.ts | 34 +- nodejs/src/postinstall.ts | 26 +- nodejs/src/service/base.ts | 4 - nodejs/src/service/service.ts | 223 ---- nodejs/src/serviceBase/base.ts | 156 --- nodejs/src/serviceBase/config.ts | 341 ++--- nodejs/src/serviceBase/events.ts | 1099 ++++++++++------- nodejs/src/serviceBase/index.ts | 7 + nodejs/src/serviceBase/logger.ts | 252 ---- nodejs/src/serviceBase/logging.ts | 324 +++++ nodejs/src/serviceBase/plugins.ts | 443 ++----- nodejs/src/serviceBase/serviceBase.ts | 292 ++--- nodejs/src/serviceBase/services.ts | 455 ++++--- nodejs/src/tests/base/PluginEvents.ts | 42 + nodejs/src/tests/events/events.ts | 206 ++- nodejs/src/tests/interfaces/base.ts | 50 +- nodejs/src/tests/interfaces/static.ts | 124 +- nodejs/src/tests/logger/logFormatter.ts | 119 ++ nodejs/src/tests/logger/logger.ts | 237 +--- .../tests/plugins/events/events/broadcast.ts | 219 +--- .../src/tests/plugins/events/events/emit.ts | 253 ++-- .../plugins/events/events/emitAndReturn.ts | 88 +- .../events/emitStreamAndReceiveStream.ts | 14 +- nodejs/src/tests/plugins/events/plugin.ts | 125 +- .../src/tests/plugins/log-default/plugin.ts | 243 ++-- nodejs/src/tests/serviceBase/services.ts | 536 ++++---- nodejs/src/tests/test-logger.ts | 88 +- nodejs/tsconfig-release.json | 44 + nodejs/tsconfig.json | 3 +- 80 files changed, 5358 insertions(+), 5751 deletions(-) create mode 100644 nodejs/sec-config.yaml rename nodejs/src/{service/serviceClient.ts => base/PluginEvents.ts} (59%) create mode 100644 nodejs/src/base/PluginLogger.ts create mode 100644 nodejs/src/base/base.ts create mode 100644 nodejs/src/base/config.ts create mode 100644 nodejs/src/base/errorMessages.ts rename nodejs/src/{events => base}/events.ts (69%) create mode 100644 nodejs/src/base/functions.ts create mode 100644 nodejs/src/base/index.ts create mode 100644 nodejs/src/base/logFormatter.ts create mode 100644 nodejs/src/base/logging.ts create mode 100644 nodejs/src/base/service.ts create mode 100644 nodejs/src/base/serviceClient.ts delete mode 100644 nodejs/src/clients/service-generic/plugin.ts delete mode 100644 nodejs/src/config/config.ts delete mode 100644 nodejs/src/interfaces/base.ts delete mode 100644 nodejs/src/interfaces/config.ts create mode 100644 nodejs/src/interfaces/index.ts delete mode 100644 nodejs/src/interfaces/logger.ts create mode 100644 nodejs/src/interfaces/logging.ts create mode 100644 nodejs/src/interfaces/plugins.ts delete mode 100644 nodejs/src/interfaces/static.ts delete mode 100644 nodejs/src/logger/logger.ts create mode 100644 nodejs/src/plugins/config-default/interfaces.ts delete mode 100644 nodejs/src/plugins/config-default/sec.config.ts delete mode 100644 nodejs/src/plugins/events-default/sec.config.ts delete mode 100644 nodejs/src/plugins/log-default/sec.config.ts rename nodejs/src/plugins/{log-default => logging-default}/colours.ts (100%) rename nodejs/src/plugins/{log-default => logging-default}/plugin.ts (66%) delete mode 100644 nodejs/src/service/base.ts delete mode 100644 nodejs/src/service/service.ts delete mode 100644 nodejs/src/serviceBase/base.ts create mode 100644 nodejs/src/serviceBase/index.ts delete mode 100644 nodejs/src/serviceBase/logger.ts create mode 100644 nodejs/src/serviceBase/logging.ts create mode 100644 nodejs/src/tests/base/PluginEvents.ts create mode 100644 nodejs/src/tests/logger/logFormatter.ts create mode 100644 nodejs/tsconfig-release.json diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 1e84243..3e572ea 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -11,7 +11,8 @@ "license": "AGPL-3.0-only", "dependencies": { "@bettercorp/tools": "^2.0.20220714140658", - "yaml": "^2.3.1" + "yaml": "^2.3.1", + "zod": "^3.21.4" }, "bin": { "bsb": "lib/bootstrap.js" @@ -20,10 +21,11 @@ "@types/assert": "^1.5.6", "@types/chai": "^4.3.3", "@types/mocha": "^9.1.1", - "@types/node": "^18.7.16", + "@types/node": "^18.19.3", "@types/yargs": "^17.0.12", "@typescript-eslint/eslint-plugin": "^5.31.0", "@typescript-eslint/parser": "^5.31.0", + "chai": "^4.3.10", "eslint": "^8.20.0", "mocha": "^10.0.0", "nyc": "^15.1.0", @@ -36,6 +38,15 @@ "npm": ">=9.0.0" } }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/@ampproject/remapping": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", @@ -50,47 +61,119 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", + "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.10", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/compat-data": { - "version": "7.21.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.7.tgz", - "integrity": "sha512-KYMqFYTaenzMK4yUtf4EW9wc4N9ef80FsbMtkwool5zpwl4YrT1SdWYSTRcT94KO4hannogdS+LxY7L+arP3gA==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", + "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.21.8", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.8.tgz", - "integrity": "sha512-YeM22Sondbo523Sz0+CirSPnbj9bG3P0CdHcBZdqUuaeOaYEFbOLoGU7lebvGP6P5J/WE9wOn7u7C4J9HvS1xQ==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.10.tgz", + "integrity": "sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-compilation-targets": "^7.21.5", - "@babel/helper-module-transforms": "^7.21.5", - "@babel/helpers": "^7.21.5", - "@babel/parser": "^7.21.8", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5", + "@babel/code-frame": "^7.22.10", + "@babel/generator": "^7.22.10", + "@babel/helper-compilation-targets": "^7.22.10", + "@babel/helper-module-transforms": "^7.22.9", + "@babel/helpers": "^7.22.10", + "@babel/parser": "^7.22.10", + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.10", + "@babel/types": "^7.22.10", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.2", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" @@ -101,21 +184,21 @@ } }, "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/generator": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.5.tgz", - "integrity": "sha512-SrKK/sRv8GesIW1bDagf9cCG38IOMYZusoe1dfg0D8aiUe3Amvoj1QtjTPAWcfrZFvIwlleLb0gxzQidL9w14w==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", + "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", "dev": true, "dependencies": { - "@babel/types": "^7.21.5", + "@babel/types": "^7.22.10", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -125,171 +208,168 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.5.tgz", - "integrity": "sha512-1RkbFGUKex4lvsB9yhIfWltJM5cZKUftB2eNajaDv3dCMEp49iBG0K14uH8NnX9IPux2+mK7JGEOB0jn48/J6w==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", + "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.21.5", - "@babel/helper-validator-option": "^7.21.0", - "browserslist": "^4.21.3", + "@babel/compat-data": "^7.22.9", + "@babel/helper-validator-option": "^7.22.5", + "browserslist": "^4.21.9", "lru-cache": "^5.1.1", - "semver": "^6.3.0" + "semver": "^6.3.1" }, "engines": { "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.21.5.tgz", - "integrity": "sha512-IYl4gZ3ETsWocUWgsFZLM5i1BYx9SoemminVEXadgLBa9TdeorzgLKm8wWLA6J1N/kT3Kch8XIk1laNzYoHKvQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", + "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", + "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", "dev": true, "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", - "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", + "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", "dev": true, "dependencies": { - "@babel/types": "^7.21.4" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.21.5.tgz", - "integrity": "sha512-bI2Z9zBGY2q5yMHoBvJ2a9iX3ZOAzJPm7Q8Yz6YeoUjU/Cvhmi2G4QyTNyPBqqXSgTjUxRg3L0xV45HvkNWWBw==", + "version": "7.22.9", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", + "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.21.5", - "@babel/helper-module-imports": "^7.21.4", - "@babel/helper-simple-access": "^7.21.5", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/helper-validator-identifier": "^7.19.1", - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5" + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.5" }, "engines": { "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz", - "integrity": "sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", "dev": true, "dependencies": { - "@babel/types": "^7.21.5" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dev": true, "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz", - "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", + "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", - "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.21.5.tgz", - "integrity": "sha512-BSY+JSlHxOmGsPTydUkPf1MdMQ3M81x5xGCOVgWM3G8XH77sJ292Y2oqcp0CbbgxhqBuI46iUz1tT7hqP7EfgA==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.10.tgz", + "integrity": "sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw==", "dev": true, "dependencies": { - "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.5", - "@babel/types": "^7.21.5" + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.10", + "@babel/types": "^7.22.10" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", + "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -368,9 +448,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.8", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.8.tgz", - "integrity": "sha512-6zavDGdzG3gUqAdWvlLFfk+36RilI+Pwyuuh7HItyeScCWP3k6i8vKclAQ0bM/0y/Kz/xiwvxhMv9MgTJP5gmA==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz", + "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -380,33 +460,33 @@ } }, "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", + "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.5", + "@babel/parser": "^7.22.5", + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.5.tgz", - "integrity": "sha512-AhQoI3YjWi6u/y/ntv7k48mcrCXmus0t79J9qPNlk/lAsFlCiJ047RmbfMOawySTHtywXhbXgpx/8nXMYd+oFw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.5", - "@babel/helper-environment-visitor": "^7.21.5", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.5", - "@babel/types": "^7.21.5", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz", + "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.22.10", + "@babel/generator": "^7.22.10", + "@babel/helper-environment-visitor": "^7.22.5", + "@babel/helper-function-name": "^7.22.5", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.22.10", + "@babel/types": "^7.22.10", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -424,13 +504,13 @@ } }, "node_modules/@babel/types": { - "version": "7.21.5", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.5.tgz", - "integrity": "sha512-m4AfNvVF2mVC/F7fDEdH2El3HzUg9It/XsCxZiOTTA3m3qYfcSVSbTfM6Q9xG+hYDniZssYhlXKKUMD5m8tF4Q==", + "version": "7.22.10", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz", + "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.21.5", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.5", "to-fast-properties": "^2.0.0" }, "engines": { @@ -486,23 +566,23 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.1.tgz", - "integrity": "sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", + "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.3.tgz", - "integrity": "sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==", + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", - "espree": "^9.5.2", + "espree": "^9.6.0", "globals": "^13.19.0", "ignore": "^5.2.0", "import-fresh": "^3.2.1", @@ -518,18 +598,18 @@ } }, "node_modules/@eslint/js": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.41.0.tgz", - "integrity": "sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==", + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz", + "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.8", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", - "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", + "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", @@ -682,9 +762,9 @@ } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", - "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", "dev": true, "engines": { "node": ">=6.0.0" @@ -706,21 +786,15 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", - "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "3.1.0", - "@jridgewell/sourcemap-codec": "1.4.14" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -793,9 +867,9 @@ "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.11", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", - "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", "dev": true }, "node_modules/@types/mocha": { @@ -805,9 +879,12 @@ "dev": true }, "node_modules/@types/node": { - "version": "18.16.13", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.13.tgz", - "integrity": "sha512-uZRomboV1vBL61EBXneL4j9/hEn+1Yqa4LQdpGrKmXFyJmVfWc9JV9+yb2AlnOnuaDnb2PDO3hC6/LKmzJxP1A==" + "version": "18.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", + "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/semver": { "version": "7.5.0", @@ -831,17 +908,17 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.6.tgz", - "integrity": "sha512-sXtOgJNEuRU5RLwPUb1jxtToZbgvq3M6FPpY4QENxoOggK+UpTxUBpj6tD8+Qh2g46Pi9We87E+eHnUw8YcGsw==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", + "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.59.6", - "@typescript-eslint/type-utils": "5.59.6", - "@typescript-eslint/utils": "5.59.6", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/type-utils": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", - "grapheme-splitter": "^1.0.4", + "graphemer": "^1.4.0", "ignore": "^5.2.0", "natural-compare-lite": "^1.4.0", "semver": "^7.3.7", @@ -865,14 +942,14 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.59.6.tgz", - "integrity": "sha512-7pCa6al03Pv1yf/dUg/s1pXz/yGMUBAw5EeWqNTFiSueKvRNonze3hma3lhdsOrQcaOXhbk5gKu2Fludiho9VA==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", + "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.59.6", - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/typescript-estree": "5.59.6", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "debug": "^4.3.4" }, "engines": { @@ -892,13 +969,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.59.6.tgz", - "integrity": "sha512-gLbY3Le9Dxcb8KdpF0+SJr6EQ+hFGYFl6tVY8VxLPFDfUZC7BHFw+Vq7bM5lE9DwWPfx4vMWWTLGXgpc0mAYyQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/visitor-keys": "5.59.6" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -909,13 +986,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.59.6.tgz", - "integrity": "sha512-A4tms2Mp5yNvLDlySF+kAThV9VTBPCvGf0Rp8nl/eoDX9Okun8byTKoj3fJ52IJitjWOk0fKPNQhXEB++eNozQ==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", + "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.59.6", - "@typescript-eslint/utils": "5.59.6", + "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/utils": "5.62.0", "debug": "^4.3.4", "tsutils": "^3.21.0" }, @@ -936,9 +1013,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.59.6.tgz", - "integrity": "sha512-tH5lBXZI7T2MOUgOWFdVNUILsI02shyQvfzG9EJkoONWugCG77NDDa1EeDGw7oJ5IvsTAAGVV8I3Tk2PNu9QfA==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -949,13 +1026,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.6.tgz", - "integrity": "sha512-vW6JP3lMAs/Tq4KjdI/RiHaaJSO7IUsbkz17it/Rl9Q+WkQ77EOuOnlbaU8kKfVIOJxMhnRiBG+olE7f3M16DA==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/visitor-keys": "5.59.6", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -976,17 +1053,17 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.59.6.tgz", - "integrity": "sha512-vzaaD6EXbTS29cVH0JjXBdzMt6VBlv+hE31XktDRMX1j3462wZCJa7VzO2AxXEXcIl8GQqZPcOPuW/Z1tZVogg==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@types/json-schema": "^7.0.9", "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.59.6", - "@typescript-eslint/types": "5.59.6", - "@typescript-eslint/typescript-estree": "5.59.6", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", "eslint-scope": "^5.1.1", "semver": "^7.3.7" }, @@ -1002,12 +1079,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.59.6", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.6.tgz", - "integrity": "sha512-zEfbFLzB9ETcEJ4HZEEsCR9HHeNku5/Qw1jSS5McYJv5BR+ftYXwFFAH5Al+xkGaZEqowMwl7uoJjQb1YSPF8Q==", + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.59.6", + "@typescript-eslint/types": "5.62.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -1019,9 +1096,9 @@ } }, "node_modules/acorn": { - "version": "8.8.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", - "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1162,6 +1239,15 @@ "node": ">=8" } }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1206,9 +1292,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.21.5", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.5.tgz", - "integrity": "sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w==", + "version": "4.21.10", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", + "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", "dev": true, "funding": [ { @@ -1218,13 +1304,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001449", - "electron-to-chromium": "^1.4.284", - "node-releases": "^2.0.8", - "update-browserslist-db": "^1.0.10" + "caniuse-lite": "^1.0.30001517", + "electron-to-chromium": "^1.4.477", + "node-releases": "^2.0.13", + "update-browserslist-db": "^1.0.11" }, "bin": { "browserslist": "cli.js" @@ -1267,9 +1357,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001488", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001488.tgz", - "integrity": "sha512-NORIQuuL4xGpIy6iCCQGN4iFjlBXtfKWIenlUuyZJumLRIindLb7wXM+GO8erEhb7vXfcnf4BAg2PrSDN5TNLQ==", + "version": "1.0.30001520", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001520.tgz", + "integrity": "sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA==", "dev": true, "funding": [ { @@ -1286,6 +1376,24 @@ } ] }, + "node_modules/chai": { + "version": "4.3.10", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", + "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", + "dev": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1302,6 +1410,18 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -1451,6 +1571,18 @@ "node": ">=0.10.0" } }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -1506,9 +1638,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.402", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.402.tgz", - "integrity": "sha512-gWYvJSkohOiBE6ecVYXkrDgNaUjo47QEKK0kQzmWyhkH+yoYiG44bwuicTGNSIQRG3WDMsWVZJLRnJnLNkbWvA==", + "version": "1.4.490", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz", + "integrity": "sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A==", "dev": true }, "node_modules/emoji-regex": { @@ -1545,27 +1677,27 @@ } }, "node_modules/eslint": { - "version": "8.41.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.41.0.tgz", - "integrity": "sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==", + "version": "8.47.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz", + "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.4.0", - "@eslint/eslintrc": "^2.0.3", - "@eslint/js": "8.41.0", - "@humanwhocodes/config-array": "^0.11.8", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "^8.47.0", + "@humanwhocodes/config-array": "^0.11.10", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", - "ajv": "^6.10.0", + "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", "debug": "^4.3.2", "doctrine": "^3.0.0", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.0", - "eslint-visitor-keys": "^3.4.1", - "espree": "^9.5.2", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", "esquery": "^1.4.2", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", @@ -1575,7 +1707,6 @@ "globals": "^13.19.0", "graphemer": "^1.4.0", "ignore": "^5.2.0", - "import-fresh": "^3.0.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "is-path-inside": "^3.0.3", @@ -1585,9 +1716,8 @@ "lodash.merge": "^4.6.2", "minimatch": "^3.1.2", "natural-compare": "^1.4.0", - "optionator": "^0.9.1", + "optionator": "^0.9.3", "strip-ansi": "^6.0.1", - "strip-json-comments": "^3.1.0", "text-table": "^0.2.0" }, "bin": { @@ -1614,9 +1744,9 @@ } }, "node_modules/eslint-visitor-keys": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz", - "integrity": "sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==", + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -1626,9 +1756,9 @@ } }, "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.0.tgz", - "integrity": "sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==", + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { "esrecurse": "^4.3.0", @@ -1651,12 +1781,12 @@ } }, "node_modules/espree": { - "version": "9.5.2", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.2.tgz", - "integrity": "sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==", + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, "dependencies": { - "acorn": "^8.8.0", + "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", "eslint-visitor-keys": "^3.4.1" }, @@ -1747,9 +1877,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", + "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -1951,6 +2081,15 @@ "node": "6.* || 8.* || >= 10.*" } }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/get-package-type": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", @@ -1993,9 +2132,9 @@ } }, "node_modules/globals": { - "version": "13.20.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", - "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2033,12 +2172,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "dev": true - }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -2304,9 +2437,9 @@ } }, "node_modules/istanbul-lib-instrument/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -2330,17 +2463,32 @@ } }, "node_modules/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "dependencies": { "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", + "make-dir": "^4.0.0", "supports-color": "^7.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report/node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/istanbul-lib-source-maps": { @@ -2358,9 +2506,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", - "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", + "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -2485,6 +2633,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -2510,9 +2667,9 @@ } }, "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, "bin": { "semver": "bin/semver.js" @@ -2720,9 +2877,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.11.tgz", - "integrity": "sha512-+M0PwXeU80kRohZ3aT4J/OnR+l9/KD2nVLNNoRgFtnf+umQVFdGBAO2N8+nCnEi0xlh/Wk3zOGC+vNNx+uM79Q==", + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, "node_modules/normalize-path": { @@ -2912,17 +3069,17 @@ } }, "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" @@ -3042,6 +3199,15 @@ "node": ">=8" } }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -3300,9 +3466,9 @@ ] }, "node_modules/semver": { - "version": "7.5.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.1.tgz", - "integrity": "sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==", + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -3600,6 +3766,15 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -3634,6 +3809,11 @@ "node": ">=4.2.0" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/update-browserslist-db": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", @@ -3709,15 +3889,6 @@ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "dev": true }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/workerpool": { "version": "6.2.1", "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", @@ -3877,6 +4048,14 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zod": { + "version": "3.21.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", + "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } } } } diff --git a/nodejs/package.json b/nodejs/package.json index 74bd6b1..3485001 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -11,7 +11,8 @@ "scripts": { "dev": "nodemon --config ./nodemon.json", "start": "node lib/cli.js", - "build": "tsc && npm run testDev", + "build": "rm -rfv ./lib && tsc && npm run testDev", + "build-release": "rm -rfv ./lib && tsc && npm run test && rm -rfv ./lib && tsc --p ./tsconfig-release.json", "postinstall": "node ./postinstall.js", "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx", "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js --reporter json --reporter lcov ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts' --reporter json --reporter-options output=junit.json", @@ -34,10 +35,11 @@ "@types/assert": "^1.5.6", "@types/chai": "^4.3.3", "@types/mocha": "^9.1.1", - "@types/node": "^18.7.16", + "@types/node": "^18.19.3", "@types/yargs": "^17.0.12", "@typescript-eslint/eslint-plugin": "^5.31.0", "@typescript-eslint/parser": "^5.31.0", + "chai": "^4.3.10", "eslint": "^8.20.0", "mocha": "^10.0.0", "nyc": "^15.1.0", @@ -47,7 +49,8 @@ }, "dependencies": { "@bettercorp/tools": "^2.0.20220714140658", - "yaml": "^2.3.1" + "yaml": "^2.3.1", + "zod": "^3.21.4" }, "bsb_project": true, "bsbInit": { @@ -116,4 +119,4 @@ "src/tests" ] } -} \ No newline at end of file +} diff --git a/nodejs/sec-config.yaml b/nodejs/sec-config.yaml new file mode 100644 index 0000000..43bc808 --- /dev/null +++ b/nodejs/sec-config.yaml @@ -0,0 +1,20 @@ +default: + logging: + events: + rabbit: + plugin: events-rabbitMQ + package: "@bettercorp/bsb-rabbitmq" + enabled: false + services: + service-default0X: + plugin: service-default0 + enabled: false + service-default1X: + plugin: service-default1 + enabled: false + service-default2X: + plugin: service-default2 + enabled: false + service-default3X: + plugin: service-default3 + enabled: false diff --git a/nodejs/src/service/serviceClient.ts b/nodejs/src/base/PluginEvents.ts similarity index 59% rename from nodejs/src/service/serviceClient.ts rename to nodejs/src/base/PluginEvents.ts index b9af8c3..ce69d84 100644 --- a/nodejs/src/service/serviceClient.ts +++ b/nodejs/src/base/PluginEvents.ts @@ -1,222 +1,156 @@ +import { Readable } from "stream"; import { DynamicallyReferencedMethodEmitEARIEvents, DynamicallyReferencedMethodEmitIEvents, DynamicallyReferencedMethodOnIEvents, - IServiceEvents, } from "../interfaces/events"; -import { ServicesBase } from "./service"; -import { Readable } from "stream"; -import { IPluginConfig } from "../interfaces/config"; -import { DefaultBase } from "../interfaces/base"; -import { ErrorMessages } from "../interfaces/static"; -import { - DynamicallyReferencedMethod, - DynamicallyReferencedMethodType, -} from "@bettercorp/tools/lib/Interfaces"; -import { - ServiceEvents, - ServiceReturnableEvents, - ServiceCallable, - ServiceBroadcasts, -} from "./base"; -import { Tools } from '@bettercorp/tools'; +import { ServiceEventsBase } from "../interfaces/service"; +import { DEBUG_MODE } from "../interfaces/logging"; +import { DynamicallyReferencedMethodType } from "@bettercorp/tools/lib/Interfaces"; +import { SBEvents } from "../serviceBase/events"; +import { BSBService } from "./service"; +import { BSBServiceClient } from "./serviceClient"; -export class RegisteredPlugin< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - callableMethods, - PluginConfigType extends IPluginConfig, - onBroadcast, - emitBroadcast - > - extends DefaultBase - implements - IServiceEvents< - emitEvents, - onEvents, - emitReturnableEvents, - onReturnableEvents, - emitBroadcast, - onBroadcast - > -{ - /** - * Gets a stream ID for another plugin to stream data to it. - * - * @param listener - Function that is called when the stream is received - * @param timeoutSeconds - How long to wait for the stream to be fully received before timing out - * @returns The stream ID that the other plugin should use to stream data to this plugin - * - * @example - * Basic example of using streams - * ```ts - * /// Plugin that receives a stream - * let streamId = await this.receiveStream( - * async (err: Error | null, stream: Readable) => { - * pipeline(stream, fs.createWriteStream('./fileout.txt'), (errf) => { - * if (errf) throw errf; - * }); - * }, - * 5 // seconds - * ); - * /// Send stream ID to other plugin - * /// you can use emitEventAndReturn to send the stream ID to the other plugin and await for the stream to finish - * - * /// Plugin that sends a stream - * /// This would listen to the event that the other plugin emits - * await this.sendStream(streamId, fs.createReadStream('./filein.txt')); - * /// and then returns OK to the other plugin - * ``` - */ - receiveStream( - listener: (error: Error | null, stream: Readable) => Promise, - timeoutSeconds?: number - ): Promise { - throw ErrorMessages.BSBNotInit; - } - /** - * Sends a stream to another plugin - * - * @param streamId - The stream ID to stream data too - * @param stream - The stream to send - * @returns Promise that resolves when the stream has been fully sent - * - * @example - * Basic example of using streams - * ```ts - * /// Plugin that receives a stream - * let streamId = await this.receiveStream( - * async (err: Error | null, stream: Readable) => { - * pipeline(stream, fs.createWriteStream('./fileout.txt'), (errf) => { - * if (errf) throw errf; - * }); - * }, - * 5 // seconds - * ); - * /// Send stream ID to other plugin - * /// you can use emitEventAndReturn to send the stream ID to the other plugin and await for the stream to finish - * - * /// Plugin that sends a stream - * /// This would listen to the event that the other plugin emits - * await this.sendStream(streamId, fs.createReadStream('./filein.txt')); - * /// and then returns OK to the other plugin - * ``` - */ - sendStream(streamId: string, stream: Readable): Promise { - throw ErrorMessages.BSBNotInit; +export class PluginEvents< + onEvents = ServiceEventsBase, + emitEvents = ServiceEventsBase, + onReturnableEvents = ServiceEventsBase, + emitReturnableEvents = ServiceEventsBase, + onBroadcast = ServiceEventsBase, + emitBroadcast = ServiceEventsBase +> { + private events: SBEvents; + private service: BSBService | BSBServiceClient; + constructor( + mode: DEBUG_MODE, + events: SBEvents, + context: BSBService | BSBServiceClient + ) { + this.events = events; + this.service = context; } - /** * Listens for events that are emitted by other plugins * Broadcast events are emitted and received by all plugins - * + * * @param event - The event to listen for * @param listener - The function to call when the event is received * @returns Promise that resolves when the event listener has been registered - * + * * @example * Basic example of using broadcast events * ```ts * /// Plugin that emits a broadcast event * await this.emitBroadcast('myEvent', 'some', 'data'); // This will be typesafe - * + * * /// Plugin that receives a broadcast event * await this.onBroadcast('myEvent', async (some: string, data: string) => { * /// Do something with the data * }); * ``` */ - onBroadcast( + public async onBroadcast( ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, + DynamicallyReferencedMethodType, TA, false > ): Promise { - throw ErrorMessages.BSBNotInit; + const event = args.splice(0, 1)[0] as string; + await this.events.onBroadcast( + this.service, + this.service.pluginName, + event, + args[0] as unknown as (...args: any[]) => void | Promise + ); } /** * Emits a broadcast event that is received by all plugins that are listening for that event - * + * * @param event - The event to emit * @param args - The arguments to pass to the event * @returns Promise that resolves when the event has been emitted - * + * * @example * Basic example of using broadcast events * ```ts * /// Plugin that emits a broadcast event * await this.emitBroadcast('myEvent', 'some', 'data'); // This will be typesafe - * + * * /// Plugin that receives a broadcast event * await this.onBroadcast('myEvent', async (some: string, data: string) => { * /// Do something with the data * }); */ - emitBroadcast( + async emitBroadcast( ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, + DynamicallyReferencedMethodType, TA > ): Promise { - throw ErrorMessages.BSBNotInit; + const event = args.splice(0, 1)[0] as string; + await this.events.emitBroadcast(this.service.pluginName, event, ...args); } /** * Listens for events that are emitted by other plugins (the first plugin to receive the event will handle it) - * + * * @param event - The event to listen for * @param listener - The function to call when the event is received * @returns Promise that resolves when the event listener has been registered - * + * * @example * Basic example of using events * ```ts * /// Plugin that emits an event * await this.emitEvent('myEvent', 'some', 'data'); // This will be typesafe - * + * * /// Plugin that receives an event * await this.onEvent('myEvent', async (some: string, data: string) => { - * /// Do something with the data + * /// Do something with the data * }); */ - onEvent( + public async onEvent( ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, + DynamicallyReferencedMethodType, TA, false > ): Promise { - throw ErrorMessages.BSBNotInit; + const event = args.splice(0, 1)[0] as string; + await this.events.onEvent( + this.service, + this.service.pluginName, + event, + args[0] as unknown as (...args: any[]) => void | Promise + ); } - /** * Emits an event that is received by the first plugin that is listening for that event (depends on events service) - * + * * @param event - The event to emit * @param args - The arguments to pass to the event * @returns Promise that resolves when the event has been emitted - * + * * @example * Basic example of using events * ```ts * /// Plugin that emits an event * await this.emitEvent('myEvent', 'some', 'data'); // This will be typesafe - * + * * /// Plugin that receives an event * await this.onEvent('myEvent', async (some: string, data: string) => { - * /// Do something with the data + * /// Do something with the data * }); */ - emitEvent( + public async emitEvent( ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, + DynamicallyReferencedMethodType, TA > ): Promise { - throw ErrorMessages.BSBNotInit; + const event = args.splice(0, 1)[0] as string; + await this.events.emitEvent(this.service.pluginName, event, ...args); } /** @@ -239,15 +173,22 @@ export class RegisteredPlugin< * /// Do something with the data * }); */ - onEventSpecific( + public async onEventSpecific( serverId: string, ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, + DynamicallyReferencedMethodType, TA, false > ): Promise { - throw ErrorMessages.BSBNotInit; + const event = args.splice(0, 1)[0] as string; + await this.events.onEventSpecific( + serverId, + this.service, + this.service.pluginName, + event, + args[0] as unknown as (...args: any[]) => void | Promise + ); } /** * Emits an event that is received by the first plugin that is listening for that event (depends on events service) @@ -269,15 +210,22 @@ export class RegisteredPlugin< * /// Do something with the data * }); */ - emitEventSpecific( + public async emitEventSpecific( serverId: string, ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, + DynamicallyReferencedMethodType, TA > ): Promise { - throw ErrorMessages.BSBNotInit; + const event = args.splice(0, 1)[0] as string; + await this.events.emitEventSpecific( + serverId, + this.service.pluginName, + event, + ...args + ); } + /** * Listens for events and retuns a value to the plugin that emitted the event * @@ -298,45 +246,20 @@ export class RegisteredPlugin< * return 'some result'; * }); */ - onReturnableEvent( + public async onReturnableEvent( ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - /** - * Listens for events and retuns a value to the plugin that emitted the event - * The serverId allows for the event to be handled by a specific plugin - * - * @param serverId - The server ID to listen for the event on - * @param event - The event to listen for - * @param listener - The function to call when the event is received - * @returns Promise that resolves when the event listener has been registered - * - * @example - * Basic example of using returnable events - * ```ts - * /// Plugin that emits a returnable event - * let result = await this.emitEventAndReturnSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe - * - * /// Plugin that receives a returnable event - * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { - * /// Do something with the data - * return 'some result'; - * }); - */ - onReturnableEventSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, + DynamicallyReferencedMethodType, TA, true > ): Promise { - throw ErrorMessages.BSBNotInit; + const event = args.splice(0, 1)[0] as string; + return await this.events.onReturnableEvent( + this.service, + this.service.pluginName, + event, + args[0] as unknown as (...args: any[]) => void | Promise + ); } /** * Emits a returnable event that is received by the first plugin that is listening for that event (depends on events service) @@ -357,28 +280,39 @@ export class RegisteredPlugin< * return 'some result'; * }); */ - emitEventAndReturn( + public async emitEventAndReturn( ...args: DynamicallyReferencedMethodEmitEARIEvents< + DynamicallyReferencedMethodType, + TA, + true //, + //false + > + ): Promise< + DynamicallyReferencedMethodEmitEARIEvents< DynamicallyReferencedMethodType, TA, - true, false > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false > { - throw ErrorMessages.BSBNotInit; + const event = args.splice(0, 1)[0] as string; + const timeoutSeconds = + args.length > 0 ? (args.splice(0, 1)[0] as number) : 5; + return await this.events.emitEventAndReturn( + this.service.pluginName, + event, + timeoutSeconds, + ...args + ); } + /** - * Emits a returnable event that is received by the first plugin that is listening for that event (depends on events service) + * Listens for events and retuns a value to the plugin that emitted the event * The serverId allows for the event to be handled by a specific plugin * - * @param serverId - The server ID to emit the event on - * @param event - The event emit - * @param args - The arguments to pass to the event - * @returns Promise that resolves when the event has been emitted and the value has been returned + * @param serverId - The server ID to listen for the event on + * @param event - The event to listen for + * @param listener - The function to call when the event is received + * @returns Promise that resolves when the event listener has been registered * * @example * Basic example of using returnable events @@ -392,188 +326,151 @@ export class RegisteredPlugin< * return 'some result'; * }); */ - emitEventAndReturnSpecific( + public async onReturnableEventSpecific( serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } - /** - * Emits a returnable event with a custom timeout. - * - * @param event - The event to emit - * @param timeoutSeconds - How long to wait for the event to be received before timing out - * @param args - The arguments to pass to the event - * @returns Promise that resolves when the event has been emitted and the value has been returned - * - * @example - * Basic example of using returnable events with timeouts - * ```ts - * /// Plugin that emits a returnable event - * let result = await this.emitEventAndReturnTimed('myEvent', 5, 'some', 'data'); // This will be typesafe - * /// This will wait 5 seconds for the event to be received before timing out - * /// If the event is not received within 5 seconds, the promise will reject - * - * /// Plugin that receives a returnable event - * await this.onReturnableEvent('myEvent', async (some: string, data: string) => { - * /// Do something with the data - * return 'some result'; - * }); - */ - emitEventAndReturnTimed( - ...args: DynamicallyReferencedMethodEmitEARIEvents< + ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, TA, - true, true > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; + ): Promise { + const event = args.splice(0, 1)[0] as string; + return await this.events.onReturnableEventSpecific( + serverId, + this.service, + this.service.pluginName, + event, + args[0] as unknown as (...args: any[]) => void | Promise + ); } /** - * Emits a returnable event with a specific serverId and a custom timeout. - * + * Emits a returnable event that is received by the first plugin that is listening for that event (depends on events service) + * The serverId allows for the event to be handled by a specific plugin + * * @param serverId - The server ID to emit the event on - * @param event - The event to emit - * @param timeoutSeconds - How long to wait for the event to be received before timing out + * @param event - The event emit * @param args - The arguments to pass to the event * @returns Promise that resolves when the event has been emitted and the value has been returned - * + * * @example - * Basic example of using returnable events with timeouts + * Basic example of using returnable events * ```ts * /// Plugin that emits a returnable event - * - * let result = await this.emitEventAndReturnTimedSpecific('serverId', 'myEvent', 5, 'some', 'data'); // This will be typesafe - * /// This will wait 5 seconds for the event to be received before timing out - * /// If the event is not received within 5 seconds, the promise will reject - * + * let result = await this.emitEventAndReturnSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe + * * /// Plugin that receives a returnable event * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { * /// Do something with the data * return 'some result'; * }); */ - emitEventAndReturnTimedSpecific( + public async emitEventAndReturnSpecific( serverId: string, ...args: DynamicallyReferencedMethodEmitEARIEvents< + DynamicallyReferencedMethodType, + TA, + true /*, + false*/ + > + ): Promise< + DynamicallyReferencedMethodEmitEARIEvents< DynamicallyReferencedMethodType, TA, - true, - true + false > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false > { - throw ErrorMessages.BSBNotInit; + const event = args.splice(0, 1)[0] as string; + const timeoutSeconds = + args.length > 0 ? (args.splice(0, 1)[0] as number) : 5; + return await this.events.emitEventAndReturnSpecific( + serverId, + this.service.pluginName, + event, + timeoutSeconds, + ...args + ); } + /** - * Calls a method on another plugin - * - * @param method - The method to call - * @param args - The arguments to pass to the method - * @returns Promise that resolves when the method has been called - * + * Gets a stream ID for another plugin to stream data to it. + * + * @param listener - Function that is called when the stream is received + * @param timeoutSeconds - How long to wait for the stream to be fully received before timing out + * @returns The stream ID that the other plugin should use to stream data to this plugin + * * @example - * Basic example of using callable methods + * Basic example of using streams * ```ts - * /// Plugin that calls a method - * await this.callPluginMethod('myMethod', 'some', 'data'); // This will be typesafe + * /// Plugin that receives a stream + * let streamId = await this.receiveStream( + * async (err: Error | null, stream: Readable) => { + * pipeline(stream, fs.createWriteStream('./fileout.txt'), (errf) => { + * if (errf) throw errf; + * }); + * }, + * 5 // seconds + * ); + * /// Send stream ID to other plugin + * /// you can use emitEventAndReturn to send the stream ID to the other plugin and await for the stream to finish + * + * /// Plugin that sends a stream + * /// This would listen to the event that the other plugin emits + * await this.sendStream(streamId, fs.createReadStream('./filein.txt')); + * /// and then returns OK to the other plugin + * ``` */ - callPluginMethod( - ...args: DynamicallyReferencedMethod< - DynamicallyReferencedMethodType, - TA - > - ): DynamicallyReferencedMethod< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } -} - -export class ServicesClient< - onEvents = ServiceEvents, - emitEvents = ServiceEvents, - onReturnableEvents = ServiceReturnableEvents, - emitReturnableEvents = ServiceReturnableEvents, - callableMethods = ServiceCallable, - onBroadcast = ServiceBroadcasts, - emitBroadcast = ServiceBroadcasts -> { - public readonly pluginName!: string; - public readonly initBeforePlugins?: Array; - public readonly initAfterPlugins?: Array; - public readonly runBeforePlugins?: Array; - public readonly runAfterPlugins?: Array; - - private _referencedPlugin: ServicesBase; - protected _plugin!: RegisteredPlugin< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - callableMethods, - any, - onBroadcast, - emitBroadcast - >; - - public async _init(): Promise { - if (!Tools.isString(this.pluginName) || this.pluginName === "") { - throw 'pluginName is not set in this client. Please update the clients definition ' - } - - // We must add the inits/runs list to the referenced service in order to change the init and run order - (this._referencedPlugin as any).initBeforePlugins = ( - this._referencedPlugin.initBeforePlugins || [] - ).concat(this.initBeforePlugins || []); - (this._referencedPlugin as any).initAfterPlugins = ( - this._referencedPlugin.initAfterPlugins || [] - ).concat(this.initAfterPlugins || []); - (this._referencedPlugin as any).runBeforePlugins = ( - this._referencedPlugin.runBeforePlugins || [] - ).concat(this.runBeforePlugins || []); - (this._referencedPlugin as any).runAfterPlugins = ( - this._referencedPlugin.runAfterPlugins || [] - ).concat(this.runAfterPlugins || []); - - if (this._plugin === undefined) { - this._plugin = await this._referencedPlugin.initPluginClient< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - callableMethods, - any, - onBroadcast, - emitBroadcast - >(this.pluginName); - } - } - - public async init(): Promise { + public async receiveStream( + event: string, + listener: { (error: Error | null, stream: Readable): Promise }, + timeoutSeconds?: number + ): Promise { + return await this.events.receiveStream( + this.service, + this.service.pluginName, + event, + listener, + timeoutSeconds + ); } - constructor(self: ServicesBase) { - this._referencedPlugin = self; - (self as any)._clients.push(this); + /** + * Sends a stream to another plugin + * + * @param streamId - The stream ID to stream data too + * @param stream - The stream to send + * @returns Promise that resolves when the stream has been fully sent + * + * @example + * Basic example of using streams + * ```ts + * /// Plugin that receives a stream + * let streamId = await this.receiveStream( + * async (err: Error | null, stream: Readable) => { + * pipeline(stream, fs.createWriteStream('./fileout.txt'), (errf) => { + * if (errf) throw errf; + * }); + * }, + * 5 // seconds + * ); + * /// Send stream ID to other plugin + * /// you can use emitEventAndReturn to send the stream ID to the other plugin and await for the stream to finish + * + * /// Plugin that sends a stream + * /// This would listen to the event that the other plugin emits + * await this.sendStream(streamId, fs.createReadStream('./filein.txt')); + * /// and then returns OK to the other plugin + * ``` + */ + public async sendStream( + event: string, + streamId: string, + stream: Readable + ): Promise { + return await this.events.sendStream( + this.service.pluginName, + event, + streamId, + stream + ); } } diff --git a/nodejs/src/base/PluginLogger.ts b/nodejs/src/base/PluginLogger.ts new file mode 100644 index 0000000..82b1862 --- /dev/null +++ b/nodejs/src/base/PluginLogger.ts @@ -0,0 +1,43 @@ +import { DEBUG_MODE, SmartLogMeta } from "../interfaces/logging"; +import { IPluginLogger } from "../interfaces/logging"; +import { SBLogging } from "../serviceBase/logging"; + +export class PluginLogger implements IPluginLogger { + private logging: SBLogging; + private pluginName: string; + private canDebug = false; + constructor(mode: DEBUG_MODE, plugin: string, logging: SBLogging) { + this.logging = logging; + this.pluginName = plugin; + if (mode !== "production") { + this.canDebug = true; + } + } + public debug(message: T, ...meta: SmartLogMeta): void { + if (this.canDebug) + this.logging.logBus.emit("debug", this.pluginName, message, meta[0]); + } + public reportStat(key: string, value: number): void { + this.logging.logBus.emit("reportStat", this.pluginName, key, value); + } + public reportTextStat( + message: T, + ...meta: SmartLogMeta + ): void { + this.logging.logBus.emit( + "reportTextStat", + this.pluginName, + message, + meta[0] + ); + } + public info(message: T, ...meta: SmartLogMeta): void { + this.logging.logBus.emit("info", this.pluginName, message, meta[0]); + } + public warn(message: T, ...meta: SmartLogMeta): void { + this.logging.logBus.emit("warn", this.pluginName, message, meta[0]); + } + public error(message: T, ...meta: SmartLogMeta): void { + this.logging.logBus.emit("error", this.pluginName, message, meta[0]); + } +} diff --git a/nodejs/src/base/base.ts b/nodejs/src/base/base.ts new file mode 100644 index 0000000..4097c68 --- /dev/null +++ b/nodejs/src/base/base.ts @@ -0,0 +1,212 @@ +import { DEBUG_MODE, IPluginLogger } from "../interfaces/logging"; +import { PluginLogger } from "./PluginLogger"; +import { SBLogging } from "../serviceBase/logging"; +import { z } from "zod"; + +export abstract class MainBase { + /** + * The unique app id of the app that is running + * @readonly + * @type {string} + */ + protected readonly appId: string = "tbd"; + + /** + * The mode the app is running in + * @readonly + * @type {DEBUG_MODE} + * @example production (production mode - no debug) + * @example production-debug (production mode - debug) + * @example development (development mode - debug) + */ + protected readonly mode: DEBUG_MODE = "development"; + /** + * The current working directory of the app + */ + protected readonly cwd: string; + /** + * The current working directory of the plugin + */ + protected readonly pluginCwd: string; + /** + * The name of the plugin + * This is also the mapped name, or the name defined in the config rather than it's original defined name + */ + public readonly pluginName!: string; + + constructor( + appId: string, + mode: DEBUG_MODE, + pluginName: string, + cwd: string, + pluginCwd: string + ) { + this.appId = appId; + this.mode = mode; + if (pluginName !== "") this.pluginName = pluginName; + this.cwd = cwd; + this.pluginCwd = pluginCwd; + } + + /** + * Dispose + * Optional function to be called when the plugin is being disposed + * + * @example dispose?(): void; //to not use it + * @example dispose() { your code here }; + */ + dispose?(): void; +} + +export abstract class Base extends MainBase { + constructor( + appId: string, + mode: DEBUG_MODE, + pluginName: string, + cwd: string, + pluginCwd: string + ) { + super(appId, mode, pluginName, cwd, pluginCwd); + } + + /** + * Dispose + * Optional function to be called when the plugin is being disposed + * + * @example dispose?(): void; //to not use it + * @example dispose() { your code here }; + */ + abstract dispose?(): void; + + /** + * Init + * Optional function to be called when the plugin is being initialized + * Can be sync or async + * + * @example init?(): void; //to not use it + * @example init() { your code here }; + * @example async init() { await your code here }; + */ + abstract init?(): Promise | void; + + /** + * Run + * Optional function to be called when the plugin is being run + * Can be sync or async + * + * @example run?(): void; //to not use it + * @example run() { your code here }; + * @example async run() { await your code here }; + */ + abstract run?(): Promise | void; +} + +/** + * The definition of the config with zod validation + * @example + * const configDefinition = z.object({ + * a: z.string(), + * }); + */ +export type BSBConfigDefinition = z.AnyZodObject | undefined; +/** + * Config migration handler, allows for config migrations when the plugin version changes or a new plugin setup is done + * @example simple version change and basic setup + * const configMigration = async (versionFrom: string | null, versionTo: string, existingConfig?: z.infer) => { + * if (versionFrom === null) { + * return { + * a: "a", + * }; + * } + * return { + * a: "b", + * }; + * @example basic setup and no version change handling + * const configMigration = async (versionFrom: string | null, versionTo: string, existingConfig?: z.infer) => { + * if (versionFrom === null || existingConfig === undefined) { + * return { + * a: "a", + * }; + * } + * return existingConfig; + */ +export type BSBConfigMigration = ( + versionFrom: string | null, + versionTo: string, + existingConfig?: z.infer> +) => Promise>>; + +export type BSBConfigDefintionReference< + T extends BSBConfigDefinition, + AS = undefined +> = T extends undefined ? AS : z.infer>; + +// used by logging plugins (does not need events or logging since logging logs its own logs) +export abstract class BaseWithConfig< + ReferencedConfig extends BSBConfigDefinition +> extends Base { + /** + * The config of the plugin + * @type {PluginConfig} + * @readonly + */ + protected readonly config: BSBConfigDefintionReference< + ReferencedConfig, + null + >; + + constructor( + appId: string, + mode: DEBUG_MODE, + pluginName: string, + cwd: string, + pluginCwd: string, + config: any + ) { + super(appId, mode, pluginName, cwd, pluginCwd); + this.config = config; + } +} + +// used by config plugins (does not need events) +export abstract class BaseWithLogging extends Base { + protected log: IPluginLogger; + //protected createNewLogger: { (plugin: string): IPluginLogger }; + + constructor( + appId: string, + mode: DEBUG_MODE, + pluginName: string, + cwd: string, + pluginCwd: string, + sbLogging: SBLogging + ) { + super(appId, mode, pluginName, cwd, pluginCwd); + this.log = new PluginLogger(mode, pluginName, sbLogging); + /*this.createNewLogger = (plugin: string) => + new PluginLogger(mode, `${pluginName}-${plugin}`, sbLogging);*/ + } +} + +// used by events plugins (does not need events) +export abstract class BaseWithLoggingAndConfig< + ReferencedConfig extends BSBConfigDefinition +> extends BaseWithConfig { + protected log: IPluginLogger; + protected createNewLogger: { (plugin: string): IPluginLogger }; + + constructor( + appId: string, + mode: DEBUG_MODE, + pluginName: string, + cwd: string, + pluginCwd: string, + config: any, + sbLogging: SBLogging + ) { + super(appId, mode, pluginName, cwd, pluginCwd, config); + this.log = new PluginLogger(mode, pluginName, sbLogging); + this.createNewLogger = (plugin: string) => + new PluginLogger(mode, `${pluginName}-${plugin}`, sbLogging); + } +} diff --git a/nodejs/src/base/config.ts b/nodejs/src/base/config.ts new file mode 100644 index 0000000..d731fc0 --- /dev/null +++ b/nodejs/src/base/config.ts @@ -0,0 +1,91 @@ +import { DEBUG_MODE } from "../interfaces/logging"; +import { SBLogging } from "../serviceBase/logging"; +import { + EventsConfig, + LoggingConfig, + PluginDefition, + PluginType, +} from "../interfaces/plugins"; +import { BaseWithLogging } from "./base"; +import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./errorMessages"; + +/** + * Abstract class representing the configuration for the Better Service Base. + * @template T - The type of config for the plugin + */ +export abstract class BSBConfig extends BaseWithLogging { + constructor( + appId: string, + mode: DEBUG_MODE, + pluginName: string, + cwd: string, + pluginCwd: string, + logging: SBLogging + ) { + super(appId, mode, pluginName, cwd, pluginCwd, logging); + } + /** + * Returns the logging plugins configuration. + * @returns Promise resolving to an object containing the logging configuration for each plugin. + */ + abstract getLoggingPlugins(): Promise>; + + /** + * Returns the events plugins configuration. + * @returns Promise resolving to an object containing the events configuration for each plugin. + */ + abstract getEventsPlugins(): Promise>; + + /** + * Returns the service plugins configuration. + * @returns Promise resolving to an object containing the configuration for each plugin. + */ + abstract getServicePlugins(): Promise>; + + /** + * Returns a mapped plugin name and whether the plugin is enabled or not + * @returns string of the plugin name and if it is enabled or not + */ + abstract getServicePluginDefinition(pluginName: string): Promise<{name:string,enabled:boolean}>; + + /** + * Returns the configuration for a specific plugin. + * @template T - The type of the configuration object. + * @param plugin - The name of the plugin to retrieve the configuration for. + * @returns Promise resolving to the configuration object for the specified plugin, or null if the plugin is not found. + */ + abstract getPluginConfig( + pluginType: PluginType, + plugin: string + ): Promise; +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBConfigRef extends BSBConfig { + getLoggingPlugins(): Promise> { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBConfigRef", "getLoggingPlugins"); + } + getEventsPlugins(): Promise> { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBConfigRef", "getEventsPlugins"); + } + getServicePlugins(): Promise> { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBConfigRef", "getServicePlugins"); + } + getPluginConfig( + pluginType: PluginType, + plugin: string + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBConfigRef", "getPluginConfig"); + } + getServicePluginDefinition(pluginName: string): Promise<{name:string,enabled:boolean}> { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED( + "BSBConfigRef", + "getServicePluginName" + ); + } + dispose?(): void; + init?(): void; + run?(): void; +} diff --git a/nodejs/src/base/errorMessages.ts b/nodejs/src/base/errorMessages.ts new file mode 100644 index 0000000..78a922c --- /dev/null +++ b/nodejs/src/base/errorMessages.ts @@ -0,0 +1,39 @@ +import { LogMeta } from "../interfaces/logging"; +import { LogFormatter } from "./logFormatter"; + +export class BSBError extends Error { + constructor(errorKey: string, message: T, meta: LogMeta); + constructor(message: T, meta: LogMeta); + constructor( + errorKeyOrMessage: string | T, + messageOrMeta: T | LogMeta, + meta?: LogMeta + ) { + const formatter = new LogFormatter(); + if (meta === undefined && typeof messageOrMeta === "object") { + super(formatter.formatLog(errorKeyOrMessage, messageOrMeta)); + this.name = "BSBError-Generic"; + } else if (typeof messageOrMeta === "string" && typeof meta === "object") { + super(formatter.formatLog(messageOrMeta, meta)); + this.name = "BSBError-" + errorKeyOrMessage; + } + } + + public toString(): string { + return this.message; + } +} + +export function BSB_ERROR_METHOD_NOT_IMPLEMENTED( + className: string, + method: string +) { + return new BSBError( + "INCORRECT_REFERENCE", + "Method not implemented: {class}.{method}", + { + class: className, + method: method, + } + ); +} diff --git a/nodejs/src/events/events.ts b/nodejs/src/base/events.ts similarity index 69% rename from nodejs/src/events/events.ts rename to nodejs/src/base/events.ts index 1bdc0ec..5e29e44 100644 --- a/nodejs/src/events/events.ts +++ b/nodejs/src/base/events.ts @@ -1,19 +1,32 @@ -import { IPluginLogger } from "../interfaces/logger"; import { Readable } from "stream"; -import { IPluginConfig } from "../interfaces/config"; -import { DefaultBase } from "../interfaces/base"; -import { ErrorMessages } from "../interfaces/static"; +import { BSBConfigDefinition, BaseWithLoggingAndConfig } from "./base"; +import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./errorMessages"; +import { DEBUG_MODE } from '../interfaces'; +import { SBLogging } from '../serviceBase'; -export class EventsBase< - PluginConfigType extends IPluginConfig = any -> extends DefaultBase { - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - log: IPluginLogger - ) { - super(pluginName, cwd, pluginCwd, log); +export interface BSBEventsConstructor { + appId: string; + mode: DEBUG_MODE; + pluginName: string; + cwd: string; + pluginCwd: string; + config: any; + sbLogging: SBLogging; +} + +export abstract class BSBEvents< + PluginConfigType extends BSBConfigDefinition = any +> extends BaseWithLoggingAndConfig { + constructor(config: BSBEventsConstructor) { + super( + config.appId, + config.mode, + config.pluginName, + config.cwd, + config.pluginCwd, + config.config, + config.sbLogging + ); } /** * Listens for events that are emitted by other plugins @@ -28,14 +41,12 @@ export class EventsBase< * @see BSB events-default plugin for an example of how to use this function * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} */ - public async onBroadcast( - callerPluginName: string, + public abstract onBroadcast( pluginName: string, event: string, listener: { (args: Array): Promise } - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } + ): Promise; + /** * Emits an event that is received by all plugins * @@ -48,14 +59,11 @@ export class EventsBase< * @see BSB events-default plugin for an example of how to use this function * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} */ - public async emitBroadcast( - callerPluginName: string, + public abstract emitBroadcast( pluginName: string, event: string, args: Array - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } + ): Promise; /** * Listens for events that are emitted by other plugins @@ -71,14 +79,12 @@ export class EventsBase< * @see BSB events-default plugin for an example of how to use this function * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} */ - public async onEvent( - callerPluginName: string, + public abstract onEvent( pluginName: string, event: string, listener: { (args: Array): Promise } - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } + ): Promise; + /** * Emits an event that is received by a single plugin * Make sure to use the built in tests @@ -92,14 +98,11 @@ export class EventsBase< * @see BSB events-default plugin for an example of how to use this function * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} */ - public async emitEvent( - callerPluginName: string, + public abstract emitEvent( pluginName: string, event: string, args: Array - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } + ): Promise; /** * Listens for events that are emitted by other plugins and return a value @@ -115,14 +118,12 @@ export class EventsBase< * @see BSB events-default plugin for an example of how to use this function * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} */ - public async onReturnableEvent( - callerPluginName: string, + public abstract onReturnableEvent( pluginName: string, event: string, listener: { (args: Array): Promise } - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } + ): Promise; + /** * Emits an event that is received by a single plugin and returns a value * Make sure to use the built in tests @@ -137,15 +138,12 @@ export class EventsBase< * @see BSB events-default plugin for an example of how to use this function * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} */ - public async emitEventAndReturn( - callerPluginName: string, + public abstract emitEventAndReturn( pluginName: string, event: string, timeoutSeconds: number, args: Array - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } + ): Promise; /** * Sets up a receive stream to receive a stream from another plugin @@ -158,13 +156,12 @@ export class EventsBase< * @see BSB events-default plugin for an example of how to use this function * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} */ - public async receiveStream( - callerPluginName: string, + public abstract receiveStream( + event: string, listener: (error: Error | null, stream: Readable) => Promise, timeoutSeconds?: number - ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; - } + ): Promise; + /** * Sets up a send stream to send a stream to another plugin that created a receive stream * @@ -176,11 +173,78 @@ export class EventsBase< * @see BSB events-default plugin for an example of how to use this function * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/events-default | Default Events Plugin} */ - sendStream( - callerPluginName: string, + public abstract sendStream( + event: string, + streamId: string, + stream: Readable + ): Promise; +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBEventsRef extends BSBEvents { + public onBroadcast( + pluginName: string, + event: string, + listener: (args: any[]) => Promise + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "onBroadcast"); + } + public emitBroadcast( + pluginName: string, + event: string, + args: any[] + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "emitBroadcast"); + } + public onEvent( + pluginName: string, + event: string, + listener: (args: any[]) => Promise + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "onEvent"); + } + public emitEvent( + pluginName: string, + event: string, + args: any[] + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "emitEvent"); + } + public onReturnableEvent( + pluginName: string, + event: string, + listener: (args: any[]) => Promise + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "onReturnableEvent"); + } + public emitEventAndReturn( + pluginName: string, + event: string, + timeoutSeconds: number, + args: any[] + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED( + "BSBEventsRef", + "emitEventAndReturn" + ); + } + public receiveStream( + event: string, + listener: (error: Error | null, stream: Readable) => Promise, + timeoutSeconds?: number | undefined + ): Promise { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "receiveStream"); + } + public sendStream( + event: string, streamId: string, stream: Readable ): Promise { - throw ErrorMessages.EventsNotImplementedProperly; + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBEventsRef", "sendStream"); } + dispose?(): void; + init?(): void | Promise; + run?(): void | Promise; } diff --git a/nodejs/src/base/functions.ts b/nodejs/src/base/functions.ts new file mode 100644 index 0000000..b913193 --- /dev/null +++ b/nodejs/src/base/functions.ts @@ -0,0 +1,29 @@ +import { BSBError } from "."; + +type SmartFunctionCallFunc = { + [Symbol.toStringTag]?: string; + (...args: any[]): any; +}; +export async function SmartFunctionCallAsync( + context: any, + input: T | undefined, + ...params: Parameters +): Promise | void> { + if (typeof input !== "function") return; + if (typeof context !== "object") + throw new BSBError("INCORRECT_REFERENCE", "SmartFunctionCallAsync: context is not an object"); + if (input[Symbol.toStringTag] === "AsyncFunction") { + return await input.call(context, ...params); + } + return input.call(context, ...params); +} +export function SmartFunctionCallSync( + context: any, + input: T | undefined, + ...params: Parameters +): ReturnType | void { + if (typeof input !== "function") return; + if (typeof context !== "object") + throw new BSBError("INCORRECT_REFERENCE", "SmartFunctionCallSync: context is not an object"); + return input.call(context, ...params); +} diff --git a/nodejs/src/base/index.ts b/nodejs/src/base/index.ts new file mode 100644 index 0000000..e3a6d0c --- /dev/null +++ b/nodejs/src/base/index.ts @@ -0,0 +1,10 @@ +export * from "./base"; +export * from "./config"; +export * from "./errorMessages"; +export * from "./events"; +export * from "./logFormatter"; +export * from "./logging"; +export * from "./PluginEvents"; +export * from "./PluginLogger"; +export * from "./service"; +export * from "./serviceClient"; diff --git a/nodejs/src/base/logFormatter.ts b/nodejs/src/base/logFormatter.ts new file mode 100644 index 0000000..57ba3bb --- /dev/null +++ b/nodejs/src/base/logFormatter.ts @@ -0,0 +1,50 @@ +import { Tools } from "@bettercorp/tools"; +import { LogMeta, SafeLogData, UnsafeLogData } from "../interfaces/logging"; + +export class LogFormatter { + private isUnsafeLogData(value: any): value is UnsafeLogData { + return Tools.isObject(value) && !Tools.isNullOrUndefined(value.safeValue); + } + private getSafeData(data: LogMeta, key: string) { + if (Tools.isNullOrUndefined(data)) return null; + const dataFromKeyVP = (data as Record)[ + key + ]; + if (this.isUnsafeLogData(dataFromKeyVP)) return dataFromKeyVP.safeValue; + return dataFromKeyVP; + } + private formatData(meta: any, key: string) { + let referencedVar = this.getSafeData(meta, key); + if (Tools.isNullOrUndefined(referencedVar)) return "*null/undefined*"; + if (Tools.isDate(referencedVar)) return referencedVar.toISOString(); + if (Tools.isString(referencedVar)) return referencedVar; + if (Tools.isArray(referencedVar)) + return (referencedVar as Array) + .map((x) => + Tools.isSimpleType(x) + ? Tools.isString(x) + ? x + : x.toString() + : JSON.stringify(x) + ) + .join(","); + /*if ( + Tools.isObject(referencedVar) && + Tools.isFunction(referencedVar.toString) + ) + return referencedVar.toString();*/ + return JSON.stringify(referencedVar); + } + public formatLog(message: T, meta?: LogMeta): string { + //console.log(`_${message}:${Tools.isObject(meta)}`); + if (!Tools.isObject(meta)) return message; + + let dataToParse = message.split("{"); + let outString = dataToParse[0]; + for (let i = 1; i < dataToParse.length; i++) { + let removedVar = dataToParse[i].split("}"); + outString += this.formatData(meta, removedVar[0]) + removedVar[1]; + } + return outString; + } +} diff --git a/nodejs/src/base/logging.ts b/nodejs/src/base/logging.ts new file mode 100644 index 0000000..952c896 --- /dev/null +++ b/nodejs/src/base/logging.ts @@ -0,0 +1,183 @@ +import { BaseWithConfig } from "./base"; +import { DEBUG_MODE, LogMeta } from "../interfaces/logging"; +import { z } from "zod"; +import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./errorMessages"; + +export interface BSBLoggingConstructor { + appId: string; + mode: DEBUG_MODE; + pluginName: string; + cwd: string; + pluginCwd: string; + config: any; +} + +export abstract class BSBLogging< + ReferencedConfig extends z.AnyZodObject | undefined +> extends BaseWithConfig { + constructor(config: BSBLoggingConstructor) { + super( + config.appId, + config.mode, + config.pluginName, + config.cwd, + config.pluginCwd, + config.config + ); + } + /** + * Report stat + * Reports a value(number) to the logging system + * + * @param plugin - The name of the plugin that wants to report a stat + * @param key - The key of the stat to report + * @param value - The value of the stat to report + * @returns nothing + * + * @see BSB logging-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/logging-default | Default Logging Plugin} + */ + public abstract reportStat( + plugin: string, + key: string, + value: number + ): Promise | void; + + /** + * Report text stat + * Reports a value(string) to the logging system with additional information that is interpolateable + * Like a log, but for stats + * + * @param plugin - The name of the plugin that wants to report a stat + * @param message - The stat to report + * @param meta - Additional information to report with the stat + * @returns nothing + * + * @see BSB logging-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/logging-default | Default Logging Plugin} + */ + public abstract reportTextStat( + plugin: string, + message: T, + meta?: LogMeta + ): Promise | void; + + /** + * Debug + * Logs an debug message + * + * @param plugin - The name of the plugin that wants to log + * @param message - The message to log + * @param meta - Additional information to log with the message + * @returns nothing + * + * @see BSB logging-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/logging-default | Default Logging Plugin} + */ + public abstract debug( + plugin: string, + message: T, + meta?: LogMeta + ): Promise | void; + + /** + * Info + * Logs an info message + * + * @param plugin - The name of the plugin that wants to log + * @param message - The message to log + * @param meta - Additional information to log with the message + * @returns nothing + * + * @see BSB logging-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/logging-default | Default Logging Plugin} + */ + public abstract info( + plugin: string, + message: T, + meta?: LogMeta + ): Promise | void; + + /** + * Warn + * Logs an warn message + * + * @param plugin - The name of the plugin that wants to log + * @param message - The message to log + * @param meta - Additional information to log with the message + * @returns nothing + * + * @see BSB logging-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/logging-default | Default Logging Plugin} + */ + public abstract warn( + plugin: string, + message: T, + meta?: LogMeta + ): Promise | void; + + /** + * Error + * Logs an error message + * + * @param plugin - The name of the plugin that wants to log + * @param message - The message to log + * @param meta - Additional information to log with the message + * @returns nothing + * + * @see BSB logging-default plugin for an example of how to use this function + * @see {@link https://github.com/BetterCorp/better-service-base/tree/master/nodejs/src/plugins/logging-default | Default Logging Plugin} + */ + public abstract error( + plugin: string, + message: T, + meta?: LogMeta + ): Promise | void; +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBLoggingRef extends BSBLogging { + public reportStat(plugin: string, key: string, value: number): void { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "reportStat"); + } + public reportTextStat( + plugin: string, + message: T, + meta?: LogMeta | undefined + ): void { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "reportTextStat"); + } + public debug( + plugin: string, + message: T, + meta?: LogMeta | undefined + ): void { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "debug"); + } + public info( + plugin: string, + message: T, + meta?: LogMeta | undefined + ): void { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "info"); + } + public warn( + plugin: string, + message: T, + meta?: LogMeta | undefined + ): void { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "warn"); + } + public error( + plugin: string, + message: T, + meta?: LogMeta | undefined + ): void { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "error"); + } + dispose?(): void; + init?(): void; + run?(): void; +} diff --git a/nodejs/src/base/service.ts b/nodejs/src/base/service.ts new file mode 100644 index 0000000..efdf0c2 --- /dev/null +++ b/nodejs/src/base/service.ts @@ -0,0 +1,85 @@ +import { BSBConfigDefinition, BaseWithLoggingAndConfig } from "./base"; +import { ServiceEventsBase, ServiceEventsDefault } from "../interfaces/service"; +import { DEBUG_MODE } from "../interfaces/logging"; +import { SBLogging } from "../serviceBase/logging"; +import { PluginEvents } from "./PluginEvents"; +import { SBEvents } from "../serviceBase/events"; +import { BSBServiceClient } from "./serviceClient"; + +export interface BSBServiceTypes { + onEvents: ServiceEventsBase; + emitEvents: ServiceEventsBase; + onReturnableEvents: ServiceEventsBase; + emitReturnableEvents: ServiceEventsBase; + onBroadcast: ServiceEventsBase; + emitBroadcast: ServiceEventsBase; + methods: ServiceEventsBase; +} +export interface BSBServiceTypesDefault extends BSBServiceTypes { + onEvents: ServiceEventsDefault; + emitEvents: ServiceEventsDefault; + onReturnableEvents: ServiceEventsDefault; + emitReturnableEvents: ServiceEventsDefault; + onBroadcast: ServiceEventsDefault; + emitBroadcast: ServiceEventsDefault; + methods: {}; +} +export interface BSBServiceConstructor { + appId: string; + mode: DEBUG_MODE; + pluginName: string; + cwd: string; + pluginCwd: string; + config: any; + sbLogging: SBLogging; + sbEvents: SBEvents; +} +export abstract class BSBService< + PluginConfigType extends BSBConfigDefinition = any, + Events extends BSBServiceTypes = BSBServiceTypesDefault +> extends BaseWithLoggingAndConfig { + public abstract readonly initBeforePlugins?: Array; + public abstract readonly initAfterPlugins?: Array; + public abstract readonly runBeforePlugins?: Array; + public abstract readonly runAfterPlugins?: Array; + public abstract readonly methods: Events["methods"]; + public readonly events: PluginEvents< + Events["onEvents"], + Events["emitEvents"], + Events["onReturnableEvents"], + Events["emitReturnableEvents"], + Events["onBroadcast"], + Events["emitBroadcast"] + >; + public _clients: Array> = []; + + constructor(config: BSBServiceConstructor) { + super( + config.appId, + config.mode, + config.pluginName, + config.cwd, + config.pluginCwd, + config.config, + config.sbLogging + ); + this.events = new PluginEvents(config.mode, config.sbEvents, this); + } +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBServiceRef extends BSBService { + public initBeforePlugins?: string[] | undefined; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public methods = {}; + dispose?(): void; + init?(): void | Promise; + run?(): void | Promise; + constructor(config: BSBServiceConstructor) { + super(config); + } +} diff --git a/nodejs/src/base/serviceClient.ts b/nodejs/src/base/serviceClient.ts new file mode 100644 index 0000000..056ca48 --- /dev/null +++ b/nodejs/src/base/serviceClient.ts @@ -0,0 +1,49 @@ +import { PluginEvents } from "./PluginEvents"; +import { IPluginLogger } from "../interfaces/logging"; +import { BSBService, BSBServiceTypes, BSBServiceTypesDefault } from "./service"; +import { DynamicallyReferencedMethodCallable } from "../interfaces/events"; +import { DynamicallyReferencedMethodType } from "@bettercorp/tools/lib/Interfaces"; +import { BSBError } from "./errorMessages"; + +export abstract class BSBServiceClient< + Events extends BSBServiceTypes = BSBServiceTypesDefault +> { + protected readonly log!: IPluginLogger; + protected readonly events!: PluginEvents< + Events["emitEvents"], + Events["onEvents"], + Events["emitReturnableEvents"], + Events["onReturnableEvents"], + Events["emitBroadcast"], + Events["onBroadcast"] + >; + public callMethod( + ...args: DynamicallyReferencedMethodCallable< + DynamicallyReferencedMethodType, + TA + > + ): DynamicallyReferencedMethodCallable< + DynamicallyReferencedMethodType, + TA, + false + > { + throw new BSBError( + "The plugin {plugin} is not enabled so you cannot call methods from it", + { + plugin: this.pluginName, + } + ); + } + constructor(context: BSBService) { + context._clients.push(this); + } + public abstract readonly pluginName: string; + public abstract readonly initBeforePlugins?: Array; + public abstract readonly initAfterPlugins?: Array; + public abstract readonly runBeforePlugins?: Array; + public abstract readonly runAfterPlugins?: Array; + + public abstract dispose?(): void; + public abstract init?(): Promise; + public abstract run?(): Promise; +} diff --git a/nodejs/src/cli.ts b/nodejs/src/cli.ts index 36b5aa9..2149e73 100644 --- a/nodejs/src/cli.ts +++ b/nodejs/src/cli.ts @@ -1,15 +1,9 @@ -import {ServiceBase} from "./serviceBase/serviceBase"; +import { ServiceBase } from "./serviceBase/serviceBase"; + const runApp = async () => { const CWD = process.env.APP_DIR || process.cwd(); - const SB = new ServiceBase(false, false, CWD); - await SB.setupSelf(); - await SB.setupPlugins(CWD, true); - await SB.setupConfig(); - await SB.setupLogger(); - await SB.setupEvents(); - await SB.setupServices(); - await SB.initPlugins(); - await SB.runPlugins(); + const SB = new ServiceBase(false, true, CWD); + await SB.init(); await SB.run(); }; -runApp(); \ No newline at end of file +runApp(); diff --git a/nodejs/src/clients/service-generic/plugin.ts b/nodejs/src/clients/service-generic/plugin.ts deleted file mode 100644 index acac416..0000000 --- a/nodejs/src/clients/service-generic/plugin.ts +++ /dev/null @@ -1,132 +0,0 @@ -import { Readable } from "stream"; -import { ServicesBase, ServicesClient } from "../../index"; - -export class GenericClient extends ServicesClient< - any, - any, - any, - any, - any, - any, - any -> { - public override pluginName: string = ""; - public constructor(self: ServicesBase, pluginName: string) { - super(self); - this.pluginName = pluginName; - } - - public override async init(): Promise { - await this._plugin.log.warn( - "Generic client ({pluginName}) is active. Generic client does not any type safety.", - { - pluginName: this.pluginName, - } - ); - } - - async emitEvent(event: string, ...data: Array): Promise { - return await this._plugin.emitEvent(event, ...data); - } - async onEvent( - event: string, - listener: { (...data: Array): Promise } - ): Promise { - return await this._plugin.onEvent(event, listener); - } - - async emitEventSpecific( - event: string, - serverId: string, - ...data: Array - ): Promise { - return await this._plugin.emitEventSpecific(serverId, event, ...data); - } - async onEventSpecific( - event: string, - serverId: string, - listener: { (...data: Array): Promise } - ): Promise { - return await this._plugin.onEventSpecific(serverId, event, listener); - } - - async emitEventAndReturn( - event: string, - ...data: Array - ): Promise { - return (await this._plugin.emitEventAndReturn(event, ...data)) as T; - } - async emitEventAndReturnTimed( - event: string, - timeoutSeconds: number, - ...data: Array - ): Promise { - return (await this._plugin.emitEventAndReturnTimed( - event, - timeoutSeconds, - ...data - )) as T; - } - async onReturnableEvent( - event: string, - listener: { (...data: Array): Promise } - ): Promise { - return await this._plugin.onReturnableEvent(event, listener); - } - - async emitEventAndReturnSpecific( - event: string, - serverId: string, - ...data: Array - ): Promise { - return (await this._plugin.emitEventAndReturnSpecific( - serverId, - event, - ...data - )) as T; - } - async emitEventAndReturnTimedSpecific( - event: string, - serverId: string, - timeoutSeconds: number, - ...data: Array - ): Promise { - return (await this._plugin.emitEventAndReturnTimedSpecific( - serverId, - event, - timeoutSeconds, - ...data - )) as T; - } - async onReturnableEventSpecific( - event: string, - serverId: string, - listener: { (...data: Array): Promise } - ): Promise { - return await this._plugin.onReturnableEventSpecific( - serverId, - event, - listener - ); - } - - async emitBroadcast(event: string, ...data: Array): Promise { - return await this._plugin.emitBroadcast(event, ...data); - } - async onBroadcast( - event: string, - listener: { (...data: Array): Promise } - ): Promise { - return await this._plugin.onBroadcast(event, listener); - } - - async receiveStream( - listener: { (error: Error | null, stream: Readable): Promise }, - timeoutSeconds: number - ): Promise { - return await this._plugin.receiveStream(listener, timeoutSeconds); - } - async sendStream(streamId: string, stream: Readable): Promise { - return await this._plugin.sendStream(streamId, stream); - } -} diff --git a/nodejs/src/config/config.ts b/nodejs/src/config/config.ts deleted file mode 100644 index 805dba4..0000000 --- a/nodejs/src/config/config.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Tools } from "@bettercorp/tools/lib/Tools"; -import { - DeploymentProfile, - IPluginConfig, - IConfig, -} from "../interfaces/config"; -import { IPluginLogger } from "../interfaces/logger"; -import { DefaultBase } from '../interfaces/base'; -import { ErrorMessages } from '../interfaces/static'; - -export class ConfigBase -extends DefaultBase implements IConfig { - readonly _deploymentProfile: string; - constructor(pluginName: string, cwd: string, pluginCwd: string, log: IPluginLogger, deploymentProfile: string) { - super(pluginName, cwd, pluginCwd, log); - this._deploymentProfile = deploymentProfile; - } - async createAppConfig(listOfKnownPlugins: Array): Promise { - throw ErrorMessages.ConfigNotImplementedProperly; - } - async migrateAppPluginConfig( - pluginName: string, - mappedPluginName: string, - config: IPluginConfig - ): Promise { - throw ErrorMessages.ConfigNotImplementedProperly; - } - public async getAppMappedPluginConfig( - mappedPluginName: string - ): Promise { - throw ErrorMessages.ConfigNotImplementedProperly; - } - public async getAppPluginDeploymentProfile( - pluginName: string - ): Promise { - throw ErrorMessages.ConfigNotImplementedProperly; - } - public async getAppMappedPluginDeploymentProfile( - mappedPluginName: string - ): Promise { - throw ErrorMessages.ConfigNotImplementedProperly; - } - public async getAppPluginMappedName(pluginName: string): Promise { - const mappedDeploymentProfile = await this.getAppPluginDeploymentProfile( - pluginName - ); - if (Tools.isNullOrUndefined(mappedDeploymentProfile)) return pluginName; - return mappedDeploymentProfile.mappedName || pluginName; - } - public async getAppPluginState(pluginName: string): Promise { - return (await this.getAppPluginDeploymentProfile(pluginName)).enabled || false; - } - public async getAppMappedPluginState(mappedPluginName: string): Promise { - return (await this.getAppMappedPluginDeploymentProfile(mappedPluginName)).enabled || false; - } -} diff --git a/nodejs/src/dev.ts b/nodejs/src/dev.ts index 8f22205..9da4e29 100644 --- a/nodejs/src/dev.ts +++ b/nodejs/src/dev.ts @@ -1,15 +1,9 @@ import { ServiceBase } from "./serviceBase/serviceBase"; + const runApp = async () => { const CWD = process.env.APP_DIR || process.cwd(); const SB = new ServiceBase(true, false, CWD); - await SB.setupSelf(); - await SB.setupPlugins(CWD); - await SB.setupConfig(); - await SB.setupLogger(); - await SB.setupEvents(); - await SB.setupServices(); - await SB.initPlugins(); - await SB.runPlugins(); + await SB.init(); await SB.run(); }; runApp(); diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts index 6df8c0b..672fd2a 100644 --- a/nodejs/src/index.ts +++ b/nodejs/src/index.ts @@ -1,15 +1,3 @@ -export { SecConfig } from "./interfaces/serviceConfig"; -export { - ServiceConfig, - DeploymentProfiles, - DeploymentProfile, - IPluginConfig, -} from "./interfaces/config"; -export { IPluginLogger, LogMeta } from "./interfaces/logger"; -export { ConfigBase } from "./config/config"; -export { EventsBase } from "./events/events"; -export { LoggerBase } from "./logger/logger"; -export { ServiceCallable } from "./service/base"; -export { ServicesBase } from "./service/service"; -export { ServicesClient } from "./service/serviceClient"; -export { GenericClient } from "./clients/service-generic/plugin"; +export * from "./base/index"; +export * from "./interfaces/index"; +export * from "./serviceBase/index"; diff --git a/nodejs/src/initAppConfig.ts b/nodejs/src/initAppConfig.ts index 3484a7b..ac88bf5 100644 --- a/nodejs/src/initAppConfig.ts +++ b/nodejs/src/initAppConfig.ts @@ -1,25 +1,25 @@ -import * as fs from "fs"; -import { cwd } from 'process'; -import * as path from 'path'; +// import * as fs from "fs"; +// import { cwd } from 'process'; +// import * as path from 'path'; -(async () => { - const SBBaseDir = path.join(cwd(), "./node_modules/@bettercorp/service-base"); - const secConfigFile = path.join(path.join(cwd(), './sec.config.json')); - if (!fs.existsSync(secConfigFile)) { - console.log("INIT: Copy new sec.config.json"); - fs.copyFileSync(path.join(SBBaseDir, 'templates', 'sec.config.json'), secConfigFile); - console.log("INIT: Copy new sec.config.json - Completed"); +// (async () => { +// const SBBaseDir = path.join(cwd(), "./node_modules/@bettercorp/service-base"); +// const secConfigFile = path.join(path.join(cwd(), './sec.config.json')); +// if (!fs.existsSync(secConfigFile)) { +// console.log("INIT: Copy new sec.config.json"); +// fs.copyFileSync(path.join(SBBaseDir, 'templates', 'sec.config.json'), secConfigFile); +// console.log("INIT: Copy new sec.config.json - Completed"); - await (new Promise((r) => setTimeout(r, 1000))); +// await (new Promise((r) => setTimeout(r, 1000))); - const installer = path.join(SBBaseDir, "./lib/ServiceBase.js"); - console.log("INSTALL FINAL : AUTOLOAD: " + installer); - const ServiceBase = require(installer); // eslint-disable-line @typescript-eslint/no-var-requires - const SB = new ServiceBase.default(cwd()); - SB.config().then(() => console.log("INSTALL COMPLETE FOR @bettercorp/service-base")).catch(() => process.exit(1)); +// const installer = path.join(SBBaseDir, "./lib/ServiceBase.js"); +// console.log("INSTALL FINAL : AUTOLOAD: " + installer); +// const ServiceBase = require(installer); // eslint-disable-line @typescript-eslint/no-var-requires +// const SB = new ServiceBase.default(cwd()); +// SB.config().then(() => console.log("INSTALL COMPLETE FOR @bettercorp/service-base")).catch(() => process.exit(1)); - console.log(`sec.config.json ready to go`); - } else { - console.warn('sec.config.json already found... we`re not going to do anything'); - } -})(); \ No newline at end of file +// console.log(`sec.config.json ready to go`); +// } else { +// console.warn('sec.config.json already found... we`re not going to do anything'); +// } +// })(); \ No newline at end of file diff --git a/nodejs/src/install.ts b/nodejs/src/install.ts index 96609d5..6c22424 100644 --- a/nodejs/src/install.ts +++ b/nodejs/src/install.ts @@ -1,244 +1,244 @@ -//import { Tools } from "@bettercorp/tools/lib/Tools"; -import * as fs from "fs"; -//import * as crypto from "crypto"; -import * as path from "path"; -import * as os from "os"; -export default (CWD: string) => { - console.log(`Install CWD: ${ CWD }`); - - if (CWD.indexOf("@bettercorp") >= 0) { - CWD = path.join(CWD, "../../../"); - } - - console.log(`INSTALL SCRIPT FOR @bettercorp/service-base in ${ CWD }`); - - /*const srcDir = path.join(CWD, `./src`); - if (!fs.existsSync(srcDir)) { - console.log(`Creating src dir... (${ srcDir })`); - fs.mkdirSync(srcDir); - } - - const pluginsDir = path.join(CWD, `./src/plugins`); - if (!fs.existsSync(pluginsDir)) { - console.log(`Creating plugins dir... (${ pluginsDir })`); - fs.mkdirSync(pluginsDir); - } - - const filesToCopyToDest = [ - { - src: path.join(CWD, './node_modules/@bettercorp/service-base/build/gitlab-ci.yml'), - dst: path.join(CWD, './.gitlab-ci.yml'), - name: 'gitlab-ci' - }, - { - src: path.join(CWD, './node_modules/@bettercorp/service-base/build/eslintignore'), - dst: path.join(CWD, './.eslintignore'), - name: 'eslintignore' - }, - { - src: path.join(CWD, './node_modules/@bettercorp/service-base/build/eslintrc.js'), - dst: path.join(CWD, './.eslintrc.js'), - name: 'eslintrc' - }, - { - src: path.join(CWD, './node_modules/@bettercorp/service-base/build/tsconfig.json'), - dst: path.join(CWD, './tsconfig.json'), - name: 'tsconfig' - }, - { - src: path.join(CWD, './node_modules/@bettercorp/service-base/build/gitignore'), - dst: path.join(CWD, './.gitignore'), - name: '.gitignore', - merge: true - }, - - // old build files - { - dst: path.join(CWD, './tslint.json'), - remove: true - } - ]; - - for (const fileInfo of filesToCopyToDest) { - if (fileInfo.remove === true) { - if (fs.existsSync(fileInfo.dst)) - fs.unlinkSync(fileInfo.dst); - } else { - if (!fs.existsSync(fileInfo.dst)) { - console.log(`Creating ${ fileInfo.name } build file... (${ fileInfo.src } -> ${ fileInfo.dst })`); - fs.copyFileSync(fileInfo.src!, fileInfo.dst!); - } - if (fileInfo.merge === true) { - const srcBuffer = fs.readFileSync(fileInfo.src!).toString().split('\n'); - const dstBuffer = fs.readFileSync(fileInfo.dst!).toString().split('\n'); - for (let line of dstBuffer) { - if (srcBuffer.indexOf(line) >= 0) - srcBuffer.splice(srcBuffer.indexOf(line), 1); - } - for (let line of srcBuffer) { - dstBuffer.push(line); - } - fs.writeFileSync(fileInfo.dst!, dstBuffer.join('\n')); - } else { - const srcBuffer = fs.readFileSync(fileInfo.src!); - const srcHash = crypto.createHash('sha256'); - srcHash.update(srcBuffer); - const dstBuffer = fs.readFileSync(fileInfo.dst!); - const dstHash = crypto.createHash('sha256'); - dstHash.update(dstBuffer); - if (srcHash.digest('hex') !== dstHash.digest('hex')) { - console.log(`Updating ${ fileInfo.name } build file... (${ fileInfo.src } -> ${ fileInfo.dst })`); - fs.copyFileSync(fileInfo.src!, fileInfo.dst!); - } - } - } - }*/ - - if (process.env.NODE_ENV === 'production') { - const packaggeJSONFile = path.join(CWD, "./package.json"); - console.log(`Updating package scripts... (${ packaggeJSONFile })`); - const readPackageJsonFile = JSON.parse(fs.readFileSync(packaggeJSONFile).toString()); - readPackageJsonFile.scripts = readPackageJsonFile.scripts || {}; - readPackageJsonFile.scripts.start = "node node_modules/@bettercorp/service-base/lib/index.js"; - fs.writeFileSync(packaggeJSONFile, JSON.stringify(readPackageJsonFile)); - } - - /*const defaultScripts: any = { - build: "tsc", - dev: "nodemon --config node_modules/@bettercorp/service-base/build/nodemon.json", - start: "ts-node node_modules/@bettercorp/service-base/lib/index.js", - create: "ts-node node_modules/@bettercorp/service-base/lib/bootstrap.js $0", - version: "node ./node_modules/@bettercorp/service-base/build/version-ci.js $0", - }; - const internalAppScripts: any = { - ...defaultScripts, - version: "node ./node_modules/@bettercorp/service-base/build/version-internal.js $0" - }; - const bcorpLibScripts: any = { - ...defaultScripts, - version: "node ./node_modules/@bettercorp/service-base/build/version-bcorp.js $0" - }; - - let coreAppInstall = false; - let libInstall = false; - let selfInstall = false; - - const packaggeJSONFile = path.join(CWD, "./package.json"); - let todoList: Array = []; - if (fs.existsSync(packaggeJSONFile)) { - const readPackageJsonFile = JSON.parse(fs.readFileSync(packaggeJSONFile).toString()); - - const arrOfDevDepts = Object.keys(readPackageJsonFile.devDependencies || {}); - let paksToRemove: Array = ['tslint']; - let devPaksToInstall: Array = ['eslint', 'typescript', '@typescript-eslint/parser', '@typescript-eslint/eslint-plugin']; - for (let i = paksToRemove.length - 1; i >= 0; i--) - if (arrOfDevDepts.indexOf(paksToRemove[i]) < 0) { - paksToRemove.splice(i, 1); - } - for (let i = devPaksToInstall.length - 1; i >= 0; i--) - if (arrOfDevDepts.indexOf(devPaksToInstall[i]) >= 0) { - devPaksToInstall.splice(i, 1); - } - - if (paksToRemove.length > 0 || devPaksToInstall.length > 0) { - todoList.push('You are missing some packages / have depreciated ones. Please run the following commands to clean things up:'); - if (paksToRemove.length > 0) - todoList.push(`npm remove ${ paksToRemove.join(' ') }`); - if (devPaksToInstall.length > 0) - todoList.push(`npm install --save-dev ${ devPaksToInstall.join(' ') }`); - } - - if (readPackageJsonFile.name == "@bettercorp/service-base") { - console.log("Self install. ignoring install script."); - process.exit(0); - } - - if (readPackageJsonFile.name.indexOf("@bettercorp/core-internal-") === 0) - coreAppInstall = true; - if (readPackageJsonFile.name.indexOf("@bettercorp/service-base-") === 0) - libInstall = true; - if (readPackageJsonFile.name === "@bettercorp/service-base") - selfInstall = true; - - let scripts = defaultScripts; - if (coreAppInstall) { - scripts = internalAppScripts; - } else if (libInstall) { - scripts = bcorpLibScripts; - } - if (Tools.isNullOrUndefined(readPackageJsonFile.scripts)) { - readPackageJsonFile.scripts = {}; - } - let pakUpdates = false; - for (const key of Object.keys(scripts)) { - if (Tools.isNullOrUndefined(scripts[key])) continue; - - if (readPackageJsonFile.scripts[key] !== scripts[key]) { - readPackageJsonFile.scripts[key] = scripts[key]; - pakUpdates = true; - } - } - if (Tools.isNullOrUndefined(readPackageJsonFile.files)) { - readPackageJsonFile.files = ["lib/**[REMOVE" "this]/*"]; - pakUpdates = true; - } - if (readPackageJsonFile.scripts.publish !== undefined && readPackageJsonFile.scripts.publish.indexOf("npm publish") >= 0) { - pakUpdates = true; - if (readPackageJsonFile.scripts.publish == "npm publish") - delete readPackageJsonFile.scripts.publish; - else - readPackageJsonFile.scripts.publish = `${ readPackageJsonFile.scripts.publish }`.replace("npm publish", ""); - } - if (typeof readPackageJsonFile.bsb_project !== "boolean") { - readPackageJsonFile.bsb_project = true; - pakUpdates = true; - } - if (pakUpdates) { - console.log(`Updating package scripts for you... (${ packaggeJSONFile })`); - fs.writeFileSync(packaggeJSONFile, JSON.stringify(readPackageJsonFile)); - } - - if (selfInstall) { - console.log("Package install. ignoring app install script."); - process.exit(0); - } - }*/ - - const configFile = path.join(CWD, "./sec.config.json"); - if (!fs.existsSync(configFile)) { - console.log(`Creating config file... (${ configFile })`); - fs.writeFileSync(configFile, `{"identity":"${ os.hostname }","debug":true,"deploymentProfiles": {"default":{}}, "plugins": {}}`); - } else { - const tSec = JSON.parse(fs.readFileSync(configFile).toString()); - const tBefore = JSON.stringify(tSec); - tSec.identity = tSec.identity || os.hostname; - tSec.debug = tSec.debug || true; - tSec.deploymentProfiles = tSec.deploymentProfiles || {}; - tSec.plugins = tSec.plugins || {}; - const tAfter = JSON.stringify(tSec); - if (tBefore != tAfter) - fs.writeFileSync(configFile, tAfter); - } - const installer = path.join(CWD, "./node_modules/@bettercorp/service-base/lib/ServiceBase.js"); - console.log("INSTALL FINAL : AUTOLOAD: " + installer); - const ServiceBase = require(installer); // eslint-disable-line @typescript-eslint/no-var-requires - const SB = new ServiceBase.default(CWD); - let completedInstaller = false; - SB.config().then(() => { - console.log("INSTALL COMPLETE FOR @bettercorp/service-base"); - - console.log(""); - console.log(""); - console.log(""); - - //for (const todoItem of todoList) console.warn(todoItem); - completedInstaller = true; - }).catch((e: any) => { - console.error(e); - process.exit(1); - }); - let timeoutHandle = setTimeout(() => { - if (completedInstaller) - clearTimeout(timeoutHandle); - }, 100); -}; +// //import { Tools } from "@bettercorp/tools/lib/Tools"; +// import * as fs from "fs"; +// //import * as crypto from "crypto"; +// import * as path from "path"; +// import * as os from "os"; +// export default (CWD: string) => { +// console.log(`Install CWD: ${ CWD }`); + +// if (CWD.indexOf("@bettercorp") >= 0) { +// CWD = path.join(CWD, "../../../"); +// } + +// console.log(`INSTALL SCRIPT FOR @bettercorp/service-base in ${ CWD }`); + +// /*const srcDir = path.join(CWD, `./src`); +// if (!fs.existsSync(srcDir)) { +// console.log(`Creating src dir... (${ srcDir })`); +// fs.mkdirSync(srcDir); +// } + +// const pluginsDir = path.join(CWD, `./src/plugins`); +// if (!fs.existsSync(pluginsDir)) { +// console.log(`Creating plugins dir... (${ pluginsDir })`); +// fs.mkdirSync(pluginsDir); +// } + +// const filesToCopyToDest = [ +// { +// src: path.join(CWD, './node_modules/@bettercorp/service-base/build/gitlab-ci.yml'), +// dst: path.join(CWD, './.gitlab-ci.yml'), +// name: 'gitlab-ci' +// }, +// { +// src: path.join(CWD, './node_modules/@bettercorp/service-base/build/eslintignore'), +// dst: path.join(CWD, './.eslintignore'), +// name: 'eslintignore' +// }, +// { +// src: path.join(CWD, './node_modules/@bettercorp/service-base/build/eslintrc.js'), +// dst: path.join(CWD, './.eslintrc.js'), +// name: 'eslintrc' +// }, +// { +// src: path.join(CWD, './node_modules/@bettercorp/service-base/build/tsconfig.json'), +// dst: path.join(CWD, './tsconfig.json'), +// name: 'tsconfig' +// }, +// { +// src: path.join(CWD, './node_modules/@bettercorp/service-base/build/gitignore'), +// dst: path.join(CWD, './.gitignore'), +// name: '.gitignore', +// merge: true +// }, + +// // old build files +// { +// dst: path.join(CWD, './tslint.json'), +// remove: true +// } +// ]; + +// for (const fileInfo of filesToCopyToDest) { +// if (fileInfo.remove === true) { +// if (fs.existsSync(fileInfo.dst)) +// fs.unlinkSync(fileInfo.dst); +// } else { +// if (!fs.existsSync(fileInfo.dst)) { +// console.log(`Creating ${ fileInfo.name } build file... (${ fileInfo.src } -> ${ fileInfo.dst })`); +// fs.copyFileSync(fileInfo.src!, fileInfo.dst!); +// } +// if (fileInfo.merge === true) { +// const srcBuffer = fs.readFileSync(fileInfo.src!).toString().split('\n'); +// const dstBuffer = fs.readFileSync(fileInfo.dst!).toString().split('\n'); +// for (let line of dstBuffer) { +// if (srcBuffer.indexOf(line) >= 0) +// srcBuffer.splice(srcBuffer.indexOf(line), 1); +// } +// for (let line of srcBuffer) { +// dstBuffer.push(line); +// } +// fs.writeFileSync(fileInfo.dst!, dstBuffer.join('\n')); +// } else { +// const srcBuffer = fs.readFileSync(fileInfo.src!); +// const srcHash = crypto.createHash('sha256'); +// srcHash.update(srcBuffer); +// const dstBuffer = fs.readFileSync(fileInfo.dst!); +// const dstHash = crypto.createHash('sha256'); +// dstHash.update(dstBuffer); +// if (srcHash.digest('hex') !== dstHash.digest('hex')) { +// console.log(`Updating ${ fileInfo.name } build file... (${ fileInfo.src } -> ${ fileInfo.dst })`); +// fs.copyFileSync(fileInfo.src!, fileInfo.dst!); +// } +// } +// } +// }*/ + +// if (process.env.NODE_ENV === 'production') { +// const packaggeJSONFile = path.join(CWD, "./package.json"); +// console.log(`Updating package scripts... (${ packaggeJSONFile })`); +// const readPackageJsonFile = JSON.parse(fs.readFileSync(packaggeJSONFile).toString()); +// readPackageJsonFile.scripts = readPackageJsonFile.scripts || {}; +// readPackageJsonFile.scripts.start = "node node_modules/@bettercorp/service-base/lib/index.js"; +// fs.writeFileSync(packaggeJSONFile, JSON.stringify(readPackageJsonFile)); +// } + +// /*const defaultScripts: any = { +// build: "tsc", +// dev: "nodemon --config node_modules/@bettercorp/service-base/build/nodemon.json", +// start: "ts-node node_modules/@bettercorp/service-base/lib/index.js", +// create: "ts-node node_modules/@bettercorp/service-base/lib/bootstrap.js $0", +// version: "node ./node_modules/@bettercorp/service-base/build/version-ci.js $0", +// }; +// const internalAppScripts: any = { +// ...defaultScripts, +// version: "node ./node_modules/@bettercorp/service-base/build/version-internal.js $0" +// }; +// const bcorpLibScripts: any = { +// ...defaultScripts, +// version: "node ./node_modules/@bettercorp/service-base/build/version-bcorp.js $0" +// }; + +// let coreAppInstall = false; +// let libInstall = false; +// let selfInstall = false; + +// const packaggeJSONFile = path.join(CWD, "./package.json"); +// let todoList: Array = []; +// if (fs.existsSync(packaggeJSONFile)) { +// const readPackageJsonFile = JSON.parse(fs.readFileSync(packaggeJSONFile).toString()); + +// const arrOfDevDepts = Object.keys(readPackageJsonFile.devDependencies || {}); +// let paksToRemove: Array = ['tslint']; +// let devPaksToInstall: Array = ['eslint', 'typescript', '@typescript-eslint/parser', '@typescript-eslint/eslint-plugin']; +// for (let i = paksToRemove.length - 1; i >= 0; i--) +// if (arrOfDevDepts.indexOf(paksToRemove[i]) < 0) { +// paksToRemove.splice(i, 1); +// } +// for (let i = devPaksToInstall.length - 1; i >= 0; i--) +// if (arrOfDevDepts.indexOf(devPaksToInstall[i]) >= 0) { +// devPaksToInstall.splice(i, 1); +// } + +// if (paksToRemove.length > 0 || devPaksToInstall.length > 0) { +// todoList.push('You are missing some packages / have depreciated ones. Please run the following commands to clean things up:'); +// if (paksToRemove.length > 0) +// todoList.push(`npm remove ${ paksToRemove.join(' ') }`); +// if (devPaksToInstall.length > 0) +// todoList.push(`npm install --save-dev ${ devPaksToInstall.join(' ') }`); +// } + +// if (readPackageJsonFile.name == "@bettercorp/service-base") { +// console.log("Self install. ignoring install script."); +// process.exit(0); +// } + +// if (readPackageJsonFile.name.indexOf("@bettercorp/core-internal-") === 0) +// coreAppInstall = true; +// if (readPackageJsonFile.name.indexOf("@bettercorp/service-base-") === 0) +// libInstall = true; +// if (readPackageJsonFile.name === "@bettercorp/service-base") +// selfInstall = true; + +// let scripts = defaultScripts; +// if (coreAppInstall) { +// scripts = internalAppScripts; +// } else if (libInstall) { +// scripts = bcorpLibScripts; +// } +// if (Tools.isNullOrUndefined(readPackageJsonFile.scripts)) { +// readPackageJsonFile.scripts = {}; +// } +// let pakUpdates = false; +// for (const key of Object.keys(scripts)) { +// if (Tools.isNullOrUndefined(scripts[key])) continue; + +// if (readPackageJsonFile.scripts[key] !== scripts[key]) { +// readPackageJsonFile.scripts[key] = scripts[key]; +// pakUpdates = true; +// } +// } +// if (Tools.isNullOrUndefined(readPackageJsonFile.files)) { +// readPackageJsonFile.files = ["lib/**[REMOVE" "this]/*"]; +// pakUpdates = true; +// } +// if (readPackageJsonFile.scripts.publish !== undefined && readPackageJsonFile.scripts.publish.indexOf("npm publish") >= 0) { +// pakUpdates = true; +// if (readPackageJsonFile.scripts.publish == "npm publish") +// delete readPackageJsonFile.scripts.publish; +// else +// readPackageJsonFile.scripts.publish = `${ readPackageJsonFile.scripts.publish }`.replace("npm publish", ""); +// } +// if (typeof readPackageJsonFile.bsb_project !== "boolean") { +// readPackageJsonFile.bsb_project = true; +// pakUpdates = true; +// } +// if (pakUpdates) { +// console.log(`Updating package scripts for you... (${ packaggeJSONFile })`); +// fs.writeFileSync(packaggeJSONFile, JSON.stringify(readPackageJsonFile)); +// } + +// if (selfInstall) { +// console.log("Package install. ignoring app install script."); +// process.exit(0); +// } +// }*/ + +// const configFile = path.join(CWD, "./sec.config.json"); +// if (!fs.existsSync(configFile)) { +// console.log(`Creating config file... (${ configFile })`); +// fs.writeFileSync(configFile, `{"identity":"${ os.hostname }","debug":true,"deploymentProfiles": {"default":{}}, "plugins": {}}`); +// } else { +// const tSec = JSON.parse(fs.readFileSync(configFile).toString()); +// const tBefore = JSON.stringify(tSec); +// tSec.identity = tSec.identity || os.hostname; +// tSec.debug = tSec.debug || true; +// tSec.deploymentProfiles = tSec.deploymentProfiles || {}; +// tSec.plugins = tSec.plugins || {}; +// const tAfter = JSON.stringify(tSec); +// if (tBefore != tAfter) +// fs.writeFileSync(configFile, tAfter); +// } +// const installer = path.join(CWD, "./node_modules/@bettercorp/service-base/lib/ServiceBase.js"); +// console.log("INSTALL FINAL : AUTOLOAD: " + installer); +// const ServiceBase = require(installer); // eslint-disable-line @typescript-eslint/no-var-requires +// const SB = new ServiceBase.default(CWD); +// let completedInstaller = false; +// SB.config().then(() => { +// console.log("INSTALL COMPLETE FOR @bettercorp/service-base"); + +// console.log(""); +// console.log(""); +// console.log(""); + +// //for (const todoItem of todoList) console.warn(todoItem); +// completedInstaller = true; +// }).catch((e: any) => { +// console.error(e); +// process.exit(1); +// }); +// let timeoutHandle = setTimeout(() => { +// if (completedInstaller) +// clearTimeout(timeoutHandle); +// }, 100); +// }; diff --git a/nodejs/src/interfaces/base.ts b/nodejs/src/interfaces/base.ts deleted file mode 100644 index 7a427be..0000000 --- a/nodejs/src/interfaces/base.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { IPluginConfig } from "./config"; -import { IPluginLogger } from "./logger"; -import { ErrorMessages } from "./static"; - -export interface FakeConfigBase { - appId: string; - runningDebug: boolean; - runningLive: boolean; - getPluginConfig(): Promise; - getPluginState(): Promise; -} - -export class DefaultBaseCore { - protected readonly appId: string = "tbd"; - protected readonly runningDebug: boolean = true; - protected readonly runningLive: boolean = false; - public readonly pluginName: string; - public log: IPluginLogger; - protected cwd: string; - protected pluginCwd: string; - - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - log: IPluginLogger - ) { - this.pluginName = pluginName; - this.cwd = cwd; - this.pluginCwd = pluginCwd; - this.log = log; - } - - dispose() {} - async init(): Promise {} -} - -export class DefaultBase< - PluginConfigType extends IPluginConfig = any -> extends DefaultBaseCore { - protected getPluginConfig(): Promise { - throw ErrorMessages.BSBNotInit; - } - protected async getPluginState(): Promise { - throw ErrorMessages.BSBNotInit; - } -} diff --git a/nodejs/src/interfaces/config.ts b/nodejs/src/interfaces/config.ts deleted file mode 100644 index 81b7f8c..0000000 --- a/nodejs/src/interfaces/config.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { IDictionary } from "@bettercorp/tools/lib/Interfaces"; - -export interface IPluginConfig {} // eslint-disable-line @typescript-eslint/no-empty-interface - -export interface DeploymentProfiles extends IDictionary { - default: T; -} -export interface ServiceConfig { - plugins: IDictionary; - deploymentProfiles: DeploymentProfiles>; -} - -export interface DeploymentProfile { - mappedName: string; - enabled: boolean; -} - -export interface IConfig { - createAppConfig(listOfKnownPlugins: Array): Promise; - migrateAppPluginConfig( - pluginName: string, - mappedPluginName: string, - config: IPluginConfig - ): Promise; - getAppMappedPluginConfig( - mappedPluginName: string - ): Promise; - getAppPluginDeploymentProfile(pluginName: string): Promise; - getAppMappedPluginDeploymentProfile( - mappedPluginName: string - ): Promise; - getAppPluginMappedName(pluginName: string): Promise; - getAppPluginState(pluginName: string): Promise; - getAppMappedPluginState(mappedPluginName: string): Promise; -} diff --git a/nodejs/src/interfaces/events.ts b/nodejs/src/interfaces/events.ts index 74af9ae..86d49f4 100644 --- a/nodejs/src/interfaces/events.ts +++ b/nodejs/src/interfaces/events.ts @@ -1,8 +1,19 @@ -import { - DynamicallyReferencedMethodBase, - DynamicallyReferencedMethodType, -} from "@bettercorp/tools/lib/Interfaces"; -import { Readable } from "stream"; +import { DynamicallyReferencedMethodBase } from "@bettercorp/tools/lib/Interfaces"; + +export type DynamicallyReferencedMethodCallable< + Interface extends DynamicallyReferencedMethodBase, + Method extends string, + ArgsReference extends boolean = true + //ShowTimeout extends boolean = true +> = ArgsReference extends true + ? Interface[Method] extends (...a: infer Arguments) => infer Return + ? [event: Method, ...a: Arguments] + : [event: Method, noMatchingEvent: never] + : Interface[Method] extends (...a: infer Arguments) => infer Return + ? Return extends Promise + ? Return + : Promise + : Promise; export type DynamicallyReferencedMethodOnIEvents< Interface extends DynamicallyReferencedMethodBase, @@ -12,7 +23,9 @@ export type DynamicallyReferencedMethodOnIEvents< ? [ event: Method, listener: { - (...a: Arguments): hasReturnable extends true ? Return : Promise; + (...a: Arguments): hasReturnable extends true + ? Return + : void | Promise; } ] : [event: Method, noMatchingEvent: never]; @@ -27,441 +40,37 @@ export type DynamicallyReferencedMethodEmitIEvents< export type DynamicallyReferencedMethodEmitEARIEvents< Interface extends DynamicallyReferencedMethodBase, Method extends string, - ArgsReference extends boolean = true, - ShowTimeout extends boolean = true + ArgsReference extends boolean = true + //ShowTimeout extends boolean = true > = ArgsReference extends true ? Interface[Method] extends (...a: infer Arguments) => infer Return - ? ShowTimeout extends true - ? [event: Method, timeoutSeconds?: number, ...a: Arguments] - : [event: Method, ...a: Arguments] - : [event: Method, noMatchingEvent: never] + ? //? ShowTimeout extends true + [event: Method, timeoutSeconds?: number, ...a: Arguments] + : //: [event: Method, ...a: Arguments] + [event: Method, noMatchingEvent: never] : Interface[Method] extends (...a: infer Arguments) => infer Return ? Return extends Promise ? Return : Promise : Promise; -export interface IServiceEvents< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - onBroadcast, - emitBroadcast -> { - /** - * Listens for events that are emitted by other plugins - * Broadcast events are emitted and received by all plugins - * - * @param event - The event to listen for - * @param listener - The function to call when the event is received - * @returns Promise that resolves when the event listener has been registered - * - * @example - * Basic example of using broadcast events - * ```ts - * /// Plugin that emits a broadcast event - * await this.emitBroadcast('myEvent', 'some', 'data'); // This will be typesafe - * - * /// Plugin that receives a broadcast event - * await this.onBroadcast('myEvent', async (some: string, data: string) => { - * /// Do something with the data - * }); - * ``` - */ - onBroadcast( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise; - /** - * Emits a broadcast event that is received by all plugins that are listening for that event - * - * @param event - The event to emit - * @param args - The arguments to pass to the event - * @returns Promise that resolves when the event has been emitted - * - * @example - * Basic example of using broadcast events - * ```ts - * /// Plugin that emits a broadcast event - * await this.emitBroadcast('myEvent', 'some', 'data'); // This will be typesafe - * - * /// Plugin that receives a broadcast event - * await this.onBroadcast('myEvent', async (some: string, data: string) => { - * /// Do something with the data - * }); - */ - emitBroadcast( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise; - - /** - * Listens for events that are emitted by other plugins (the first plugin to receive the event will handle it) - * - * @param event - The event to listen for - * @param listener - The function to call when the event is received - * @returns Promise that resolves when the event listener has been registered - * - * @example - * Basic example of using events - * ```ts - * /// Plugin that emits an event - * await this.emitEvent('myEvent', 'some', 'data'); // This will be typesafe - * - * /// Plugin that receives an event - * await this.onEvent('myEvent', async (some: string, data: string) => { - * /// Do something with the data - * }); - */ - onEvent( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise; - /** - * Emits an event that is received by the first plugin that is listening for that event (depends on events service) - * - * @param event - The event to emit - * @param args - The arguments to pass to the event - * @returns Promise that resolves when the event has been emitted - * - * @example - * Basic example of using events - * ```ts - * /// Plugin that emits an event - * await this.emitEvent('myEvent', 'some', 'data'); // This will be typesafe - * - * /// Plugin that receives an event - * await this.onEvent('myEvent', async (some: string, data: string) => { - * /// Do something with the data - * }); - */ - emitEvent( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise; - - /** - * Listens for events that are emitted by other plugins (the first plugin to receive the event will handle it) - * The serverId allows for the event to be handled by a specific plugin - * - * @param serverId - The server ID to listen for the event on - * @param event - The event to listen for - * @param listener - The function to call when the event is received - * @returns Promise that resolves when the event listener has been registered - * - * @example - * Basic example of using events - * ```ts - * /// Plugin that emits an event - * await this.emitEventSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe - * - * /// Plugin that receives an event - * await this.onEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { - * /// Do something with the data - * }); - */ - onEventSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise; - /** - * Emits an event that is received by the first plugin that is listening for that event (depends on events service) - * The serverId allows for the event to be handled by a specific plugin - * - * @param serverId - The server ID to emit the event on - * @param event - The event to emit - * @param args - The arguments to pass to the event - * @returns Promise that resolves when the event has been emitted - * - * @example - * Basic example of using events - * ```ts - * /// Plugin that emits an event - * await this.emitEventSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe - * - * /// Plugin that receives an event - * await this.onEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { - * /// Do something with the data - * }); - */ - emitEventSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise; - - /** - * Listens for events and retuns a value to the plugin that emitted the event - * - * @param event - The event to listen for - * @param listener - The function to call when the event is received - * - @returns The value to return to the plugin that emitted the event - * @returns Promise that resolves when the event listener has been registered - * - * @example - * Basic example of using returnable events - * ```ts - * /// Plugin that emits a returnable event - * let result = await this.emitEventAndReturn('myEvent', 'some', 'data'); // This will be typesafe - * - * /// Plugin that receives a returnable event - * await this.onReturnableEvent('myEvent', async (some: string, data: string) => { - * /// Do something with the data - * return 'some result'; - * }); - */ - onReturnableEvent( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise; - /** - * Emits a returnable event that is received by the first plugin that is listening for that event (depends on events service) - * - * @param event - The event listen to - * @param args - The arguments to pass to the event - * @returns Promise that resolves when the event has been emitted and the value has been returned - * - * @example - * Basic example of using returnable events - * ```ts - * /// Plugin that emits a returnable event - * let result = await this.emitEventAndReturn('myEvent', 'some', 'data'); // This will be typesafe - * - * /// Plugin that receives a returnable event - * await this.onReturnableEvent('myEvent', async (some: string, data: string) => { - * /// Do something with the data - * return 'some result'; - * }); - */ - emitEventAndReturn( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - >; - - /** - * Listens for events and retuns a value to the plugin that emitted the event - * The serverId allows for the event to be handled by a specific plugin - * - * @param serverId - The server ID to listen for the event on - * @param event - The event to listen for - * @param listener - The function to call when the event is received - * @returns Promise that resolves when the event listener has been registered - * - * @example - * Basic example of using returnable events - * ```ts - * /// Plugin that emits a returnable event - * let result = await this.emitEventAndReturnSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe - * - * /// Plugin that receives a returnable event - * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { - * /// Do something with the data - * return 'some result'; - * }); - */ - onReturnableEventSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise; - /** - * Emits a returnable event that is received by the first plugin that is listening for that event (depends on events service) - * The serverId allows for the event to be handled by a specific plugin - * - * @param serverId - The server ID to emit the event on - * @param event - The event emit - * @param args - The arguments to pass to the event - * @returns Promise that resolves when the event has been emitted and the value has been returned - * - * @example - * Basic example of using returnable events - * ```ts - * /// Plugin that emits a returnable event - * let result = await this.emitEventAndReturnSpecific('serverId', 'myEvent', 'some', 'data'); // This will be typesafe - * - * /// Plugin that receives a returnable event - * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { - * /// Do something with the data - * return 'some result'; - * }); - */ - emitEventAndReturnSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - >; - - /** - * Emits a returnable event with a custom timeout. - * - * @param event - The event to emit - * @param timeoutSeconds - How long to wait for the event to be received before timing out - * @param args - The arguments to pass to the event - * @returns Promise that resolves when the event has been emitted and the value has been returned - * - * @example - * Basic example of using returnable events with timeouts - * ```ts - * /// Plugin that emits a returnable event - * let result = await this.emitEventAndReturnTimed('myEvent', 5, 'some', 'data'); // This will be typesafe - * /// This will wait 5 seconds for the event to be received before timing out - * /// If the event is not received within 5 seconds, the promise will reject - * - * /// Plugin that receives a returnable event - * await this.onReturnableEvent('myEvent', async (some: string, data: string) => { - * /// Do something with the data - * return 'some result'; - * }); - */ - emitEventAndReturnTimed( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - >; - /** - * Emits a returnable event with a specific serverId and a custom timeout. - * - * @param serverId - The server ID to emit the event on - * @param event - The event to emit - * @param timeoutSeconds - How long to wait for the event to be received before timing out - * @param args - The arguments to pass to the event - * @returns Promise that resolves when the event has been emitted and the value has been returned - * - * @example - * Basic example of using returnable events with timeouts - * ```ts - * /// Plugin that emits a returnable event - * - * let result = await this.emitEventAndReturnTimedSpecific('serverId', 'myEvent', 5, 'some', 'data'); // This will be typesafe - * /// This will wait 5 seconds for the event to be received before timing out - * /// If the event is not received within 5 seconds, the promise will reject - * - * /// Plugin that receives a returnable event - * await this.onReturnableEventSpecific('serverId', 'myEvent', async (some: string, data: string) => { - * /// Do something with the data - * return 'some result'; - * }); - */ - emitEventAndReturnTimedSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - >; - - /** - * Gets a stream ID for another plugin to stream data to it. - * - * @param listener - Function that is called when the stream is received - * @param timeoutSeconds - How long to wait for the stream to be fully received before timing out - * @returns The stream ID that the other plugin should use to stream data to this plugin - * - * @example - * Basic example of using streams - * ```ts - * /// Plugin that receives a stream - * let streamId = await this.receiveStream( - * async (err: Error | null, stream: Readable) => { - * pipeline(stream, fs.createWriteStream('./fileout.txt'), (errf) => { - * if (errf) throw errf; - * }); - * }, - * 5 // seconds - * ); - * /// Send stream ID to other plugin - * /// you can use emitEventAndReturn to send the stream ID to the other plugin and await for the stream to finish - * - * /// Plugin that sends a stream - * /// This would listen to the event that the other plugin emits - * await this.sendStream(streamId, fs.createReadStream('./filein.txt')); - * /// and then returns OK to the other plugin - * ``` - */ - receiveStream( - listener: { (error: Error | null, stream: Readable): Promise }, - timeoutSeconds?: number - ): Promise; - - /** - * Sends a stream to another plugin - * - * @param streamId - The stream ID to stream data too - * @param stream - The stream to send - * @returns Promise that resolves when the stream has been fully sent - * - * @example - * Basic example of using streams - * ```ts - * /// Plugin that receives a stream - * let streamId = await this.receiveStream( - * async (err: Error | null, stream: Readable) => { - * pipeline(stream, fs.createWriteStream('./fileout.txt'), (errf) => { - * if (errf) throw errf; - * }); - * }, - * 5 // seconds - * ); - * /// Send stream ID to other plugin - * /// you can use emitEventAndReturn to send the stream ID to the other plugin and await for the stream to finish - * - * /// Plugin that sends a stream - * /// This would listen to the event that the other plugin emits - * await this.sendStream(streamId, fs.createReadStream('./filein.txt')); - * /// and then returns OK to the other plugin - * ``` - */ - sendStream(streamId: string, stream: Readable): Promise; -} +export const EventsEventTypesBase = { + onBroadcast: "onBroadcast", + emitBroadcast: "emitBroadcast", + onEvent: "onEvent", + emitEvent: "emitEvent", + onReturnableEvent: "onReturnableEvent", + emitEventAndReturn: "emitEventAndReturn", + emitEventAndReturnTimed: "emitEventAndReturnTimed", + receiveStream: "receiveStream", + sendStream: "sendStream", +} as const; +export type EventsEventBaseTypes = + (typeof EventsEventTypesBase)[keyof typeof EventsEventTypesBase]; +export type EventsEventTypes = + | "onEventSpecific" + | "emitEventSpecific" + | "onReturnableEventSpecific" + | "emitEventAndReturnSpecific" + | "emitEventAndReturnTimedSpecific" + | EventsEventBaseTypes; diff --git a/nodejs/src/interfaces/index.ts b/nodejs/src/interfaces/index.ts new file mode 100644 index 0000000..2c9cafe --- /dev/null +++ b/nodejs/src/interfaces/index.ts @@ -0,0 +1,5 @@ +export * from "./events"; +export * from "./logging"; +export * from "./plugins"; +export * from "./service"; +export * from "./serviceConfig"; diff --git a/nodejs/src/interfaces/logger.ts b/nodejs/src/interfaces/logger.ts deleted file mode 100644 index 3f1e262..0000000 --- a/nodejs/src/interfaces/logger.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { ParamsFromString } from "@bettercorp/tools/lib/Interfaces"; - -export type LogMeta = Record< - ParamsFromString, - string | number | boolean | Array ->; - -export interface IPluginLogger { - reportStat(key: string, value: number): Promise; - reportTextStat( - message: T, - meta?: LogMeta, - hasPIData?: boolean): Promise; - info( - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - warn( - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - debug( - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - error( - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - error(error: Error): Promise; - fatal( - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - fatal(error: Error): Promise; -} - -export interface ILogger { - init?(): Promise; - reportStat(plugin: string, key: string, value: number): Promise; - reportTextStat( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean): Promise; - info( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - warn( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - error( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - error(plugin: string, error: Error): Promise; - debug( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; -} diff --git a/nodejs/src/interfaces/logging.ts b/nodejs/src/interfaces/logging.ts new file mode 100644 index 0000000..d7ad871 --- /dev/null +++ b/nodejs/src/interfaces/logging.ts @@ -0,0 +1,50 @@ +import { ParamsFromString } from "@bettercorp/tools/lib/Interfaces"; + +export type DEBUG_MODE = "production" | "production-debug" | "development"; + +export type SafeLogData = + | string + | number + | boolean + | Array + | Object; +export type UnsafeLogData = { + value: string | number | boolean | Array | Object; // Unsafe and unsanitized data + safeValue: SafeLogData; // Safe and sanitized data +}; // Data can contain sensitive information + +export type LogMeta = Record< + ParamsFromString, + UnsafeLogData | SafeLogData +>; + +/** + * If you are going to make an object or something, use LogMeta instead. + */ +export type SmartLogMeta = ParamsFromString extends never + ? [undefined?] + : [meta: Record, UnsafeLogData | SafeLogData>]; + +export interface IPluginLogger { + reportStat(key: string, value: number): void; + reportTextStat(message: T, ...meta: SmartLogMeta): void; + info(message: T, ...meta: SmartLogMeta): void; + warn(message: T, ...meta: SmartLogMeta): void; + debug(message: T, ...meta: SmartLogMeta): void; + error(message: T, ...meta: SmartLogMeta): void; +} + +export const LoggingEventTypesBase = { + reportStat: "reportStat", + reportTextStat: "reportTextStat", + debug: "debug", + info: "info", + warn: "warn", + error: "error", +} as const; +export type LoggingEventTypesExlReportStat = Exclude< + LoggingEventTypes, + "reportStat" +>; +export type LoggingEventTypes = + (typeof LoggingEventTypesBase)[keyof typeof LoggingEventTypesBase]; diff --git a/nodejs/src/interfaces/plugins.ts b/nodejs/src/interfaces/plugins.ts new file mode 100644 index 0000000..aaa36e1 --- /dev/null +++ b/nodejs/src/interfaces/plugins.ts @@ -0,0 +1,94 @@ +import { BSBService, BSBServiceRef } from "../base/service"; +import { LoggingEventTypes } from "./logging"; +import { BSBLogging, BSBLoggingRef } from "../base/logging"; +import { BSBConfig, BSBConfigRef } from "../base/config"; +import { EventsEventTypes } from "./events"; +import { BSBEvents } from "../base/events"; +import { BSBEventsRef } from "../base/events"; + +export const PluginTypes = { + config: "config", + events: "events", + logging: "logging", + service: "service", +} as const; +export type PluginType = (typeof PluginTypes)[keyof typeof PluginTypes]; + +export type DeepReadonly = { + readonly [P in keyof T]: T[P] extends (infer R)[] ? DeepReadonlyArray : + T[P] extends Function ? T[P] : + T[P] extends object ? DeepReadonly : T[P]; +}; +export interface DeepReadonlyArray extends ReadonlyArray> {} +export interface IPluginDefinition { + package?: string | null; + plugin: string; + name: string; + version: string; +} +export interface IPluginBuilder { + name: string; + pluginName: string; + version: string; + pluginFile: string; + pluginDir: string; + installerFile: string | null; +} +export type PluginTypeDefinition = + T extends typeof PluginTypes.service + ? BSBService + : T extends typeof PluginTypes.logging + ? BSBLogging + : T extends typeof PluginTypes.config + ? BSBConfig + : T extends typeof PluginTypes.events + ? BSBEvents + : never; +export type PluginTypeDefinitionRef = + T extends typeof PluginTypes.service + ? typeof BSBServiceRef + : T extends typeof PluginTypes.logging + ? typeof BSBLoggingRef + : T extends typeof PluginTypes.config + ? typeof BSBConfigRef + : T extends typeof PluginTypes.events + ? typeof BSBEventsRef + : never; + +export interface IPluginBuit extends IPluginBuilder { + config: any; + plugin: PluginTypeDefinition; +} +export interface PluginDefition { + package?: string | null; + plugin: string; + //name: string; + enabled: boolean; +} +export type FilterDetailed = Record< + T, + { + plugins: Array; + enabled: boolean; + } +>; +export type LoggingFilterDetailed = FilterDetailed; +export type LoggingFilter = + | LoggingFilterDetailed // eventsDetailed + | Record // eventsState + | Record> // eventsPlugins + | Array; // events +export interface LoggingConfig extends PluginDefition { + filter?: LoggingFilter; +} +export type EventsFilterDetailed = FilterDetailed; +export type EventsFilter = + | EventsFilterDetailed // eventsDetailed + | Record // eventsState + | Record> // eventsPlugins + | Array; // events +export interface EventsConfig extends PluginDefition { + filter?: EventsFilter; +} +export type FilterOnType = // see EventsFilter and LoggingFilter for more details + "all" | "events" | "eventsState" | "eventsPlugins" | "eventsDetailed"; diff --git a/nodejs/src/interfaces/service.ts b/nodejs/src/interfaces/service.ts index dc017ba..446c3ff 100644 --- a/nodejs/src/interfaces/service.ts +++ b/nodejs/src/interfaces/service.ts @@ -1,41 +1,6 @@ -import { IServiceEvents } from "./events"; - -export interface IService< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - onBroadcast, - emitBroadcast -> extends IServiceEvents< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - onBroadcast, - emitBroadcast - > { - initIndex?: number; - init?(): Promise; - loadedIndex?: number; - loaded?(): Promise; +export interface ServiceEventsBase { + [key: string]: (...args: any[]) => Promise | any; } - -export const PluginDefinitions = { - config: "config", - events: "events", - logging: "logging", - service: "service", -} as const; -export type PluginDefinition = - (typeof PluginDefinitions)[keyof typeof PluginDefinitions]; - -export interface IReadyPlugin { - pluginDefinition: PluginDefinition; - name: string; - mappedName: string; - version: string; - pluginFile: string; - pluginDir: string; - installerFile: string | null; +export interface ServiceEventsDefault { + [key: string]: () => never; } diff --git a/nodejs/src/interfaces/serviceConfig.ts b/nodejs/src/interfaces/serviceConfig.ts index 0feb548..f8beee0 100644 --- a/nodejs/src/interfaces/serviceConfig.ts +++ b/nodejs/src/interfaces/serviceConfig.ts @@ -1,20 +1,13 @@ -import { ErrorMessages } from "./static"; -import { IPluginConfig } from "./config"; +import { z } from "zod"; -export class pluginConfig { - static getConfig( - pluginName: string, - existingConfig: IPluginConfig - ): IPluginConfig { - throw ErrorMessages.PluginConfigNotSetupToGenerateConfig; - } -} - -export class SecConfig { - public migrate( - mappedPluginName: string, - existingConfig: MyPluginConfig - ): MyPluginConfig { - throw ErrorMessages.BSBNotInit; - } +export abstract class SecConfig< + MyPluginConfig extends any, + MyValidationSchema = z.ZodSchema +> { + abstract validationSchema: MyValidationSchema; + abstract init( + cwd: string, + plugin: any, + existingConfig?: MyPluginConfig + ): MyPluginConfig; } diff --git a/nodejs/src/interfaces/static.ts b/nodejs/src/interfaces/static.ts deleted file mode 100644 index 722a41f..0000000 --- a/nodejs/src/interfaces/static.ts +++ /dev/null @@ -1,57 +0,0 @@ -export class ErrorMessages { - // [BSB-E000001] The method/get property is initialized when the BSB starts up and is overridden. So if you are seeing this error, it means the function was not overridden correctly. - public static get BSBNotInit() { - return new Error( - "[BSB-E000001] Plugins aren`t being initialized properly or you`re trying to call this function directly" - ); - } - - // [BSB-E000002] The events plugin in use does not implement all methods required for the BSB to function normally. - public static get EventsNotImplementedProperly() { - return new Error( - "[BSB-E000002] Events plugin not properly implementing all methods." - ); - } - - // [BSB-E000003] A plugin in use does not implement all methods required for the BSB to function normally. - public static get PluginNotImplementedProperly() { - return new Error( - "[BSB-E000003] Plugin not properly implementing all methods." - ); - } - - // [BSB-E000004] The logger plugin in use does not implement all methods required for the BSB to function normally. - public static get LoggerNotImplementedProperly() { - return new Error( - "[BSB-E000004] Logger plugin not properly implementing all methods." - ); - } - - // [BSB-E000005] The config plugin in use does not implement all methods required for the BSB to function normally. - public static get ConfigNotImplementedProperly() { - return new Error( - "[BSB-E000005] Config plugin not properly implementing all methods." - ); - } - - // [BSB-E000006] The logger plugin in use does not implement all methods required for the BSB to function normally. - public static get PluginClientNotImplementedProperly() { - return new Error( - "[BSB-E000006] An extended plugin client must call this.construct(plugin); in the constructor!" - ); - } - - // [BSB-E000007] Plugin sec.config not interfaced correctly - public static get PluginConfigNotSetupToGenerateConfig() { - return new Error( - "[BSB-E000007] Plugin sec.config not interfaced correctly" - ); - } - - // [BSB-E000008] Cannot call service plugin method because plugin is not running, or setup to handle it - public static get ServicePluginNotCallableMethod() { - return new Error( - "[BSB-E000008] Cannot call service plugin method because plugin is not running, or setup to handle it" - ); - } -} diff --git a/nodejs/src/logger/logger.ts b/nodejs/src/logger/logger.ts deleted file mode 100644 index ffdca8d..0000000 --- a/nodejs/src/logger/logger.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { Tools } from "@bettercorp/tools/lib/Tools"; -import { ErrorMessages } from "../interfaces/static"; -import { DefaultBase } from "../interfaces/base"; -import { IPluginConfig } from "../interfaces/config"; -import { ILogger, IPluginLogger, LogMeta } from "../interfaces/logger"; - -export class LoggerBase - extends DefaultBase - implements ILogger -{ - protected formatLog(message: T, meta?: LogMeta): string { - //console.log(`_${message}:${Tools.isObject(meta)}`); - if (!Tools.isObject(meta)) return message; - - let dataToParse = message.split("{"); - let outString = dataToParse[0]; - for (let i = 1; i < dataToParse.length; i++) { - let removedVar = dataToParse[i].split("}"); - let referencedVar = Tools.GetValueFromObjectBasedOnStringPath( - meta, - removedVar[0] - ); - //console.log(`:${removedVar[0]}:${referencedVar}`, meta); - if (Tools.isNullOrUndefined(referencedVar)) - referencedVar = "*null/undefined*"; - else if (Tools.isArray(referencedVar)) - referencedVar = (referencedVar as Array) - .map((x) => - Tools.isSimpleType(x) ? x.toString() : JSON.stringify(x) - ) - .join(","); - else if (Tools.isDate(referencedVar)) - referencedVar = referencedVar.toISOString(); - else if ( - Tools.isObject(referencedVar) || - !Tools.isFunction(referencedVar.toString) - ) - referencedVar = JSON.stringify(referencedVar); - else { - referencedVar = referencedVar.toString(); - } - outString += referencedVar + removedVar[1]; - } - return outString; - } - - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - defaultLogger: IPluginLogger - ) { - super(pluginName, cwd, pluginCwd, defaultLogger); - } - - public async reportStat( - plugin: string, - key: string, - value: number - ): Promise { - throw ErrorMessages.LoggerNotImplementedProperly; - } - public async reportTextStat( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - throw ErrorMessages.LoggerNotImplementedProperly; - } - public async debug( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - throw ErrorMessages.LoggerNotImplementedProperly; - } - public async info( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - throw ErrorMessages.LoggerNotImplementedProperly; - } - public async warn( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - throw ErrorMessages.LoggerNotImplementedProperly; - } - public async error( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - throw ErrorMessages.LoggerNotImplementedProperly; - } -} diff --git a/nodejs/src/plugins/config-default/interfaces.ts b/nodejs/src/plugins/config-default/interfaces.ts new file mode 100644 index 0000000..82ba40b --- /dev/null +++ b/nodejs/src/plugins/config-default/interfaces.ts @@ -0,0 +1,82 @@ +import { + LoggingConfig, + EventsConfig, + PluginDefition as ServiceConfig, +} from "../../interfaces/plugins"; + +export interface DeploymentProfile { + /** + * @name NPM Package name + * @description The NPM package that holds the plugin + * @example @bettercorp/service-base-plugin-web-server + * @example @bettercorp/service-base-plugin-graphql + */ + package: string; + /** + * @name NPM Package version + * @description The NPM package version that holds the plugin + * @example 1.0.0 + * @example 1.0.1 + */ + //version: string; + /** + * @name Plugin name + * @description The name of the plugin + * @example service-fastify + * @example service-graphql + * @example logging-graylog + */ + plugin: string; + /** + * @name Plugin enabled + * @description If the plugin is enabled or not + * @example true + * @example false + */ + enabled: boolean; +} + +/** + * @name Plugin name + * @description The name of the plugin + * @example service-fastify + */ +export type PluginName = string; + +/** + * @name Deployment profile name + * @description The name of the deployment profile + * @example default + * @example server1 + * @example frontend + * @example backend + */ +export type DeploymentProfileName = string; + +export interface DeploymentProfiles extends Record { + /** + * @name Default deployment profile + * @description The default deployment profile + */ + default: T; +} + +export interface ConfigProfile { + logging: Record; + events: Record; + services: Record; +} +export interface DefaultProfile { + default: ConfigProfile; +} +export interface ConfigDefinition + extends Record, + DefaultProfile {} + +export interface PluginConfig { + package?: string | null; + plugin: string; + name: string; + enabled: boolean; + config: INCLCONF extends true ? any : never; +} diff --git a/nodejs/src/plugins/config-default/plugin.ts b/nodejs/src/plugins/config-default/plugin.ts index 984f239..58613b2 100644 --- a/nodejs/src/plugins/config-default/plugin.ts +++ b/nodejs/src/plugins/config-default/plugin.ts @@ -1,170 +1,210 @@ import * as path from "path"; import * as fs from "fs"; +import { ConfigDefinition } from "./interfaces"; +import { parse } from "yaml"; +import { BSBConfig } from "../../base/config"; import { - ServiceConfig, - DeploymentProfiles, - DeploymentProfile, - IPluginConfig, -} from "../../interfaces/config"; -import { IPluginLogger } from "../../interfaces/logger"; -import { ConfigBase } from "../../config/config"; -import { PluginConfig } from "./sec.config"; -import { IDictionary } from "@bettercorp/tools/lib/Interfaces"; -import { parse, stringify } from "yaml"; + EventsConfig, + LoggingConfig, + PluginDefition, + PluginType, + PluginTypes, +} from "../../interfaces/plugins"; +import { Tools } from "@bettercorp/tools"; +import { SBLogging } from "../../serviceBase/logging"; +import { DEBUG_MODE } from "../../interfaces/logging"; +import { BSBError } from "../../base/errorMessages"; -export class Config extends ConfigBase { - public readonly hehe = "I am a string"; - private _appConfig!: ServiceConfig; - private _secConfigFilePath!: string; - private _canWriteChanges: boolean = false; +export class Plugin extends BSBConfig { + async getServicePluginDefinition(pluginName: string): Promise<{name:string,enabled:boolean}> { + const keydPlugins = Object.keys( + this._appConfig[this._deploymentProfile].services ?? {} + ); + const keydWithMap = keydPlugins.map((x) => { + return { + mappedName: x, + ...this._appConfig[this._deploymentProfile].services[x], + }; + }); + let plugin = keydWithMap.find((x) => { + return x.plugin === pluginName && x.enabled === true; + }); + if (plugin !== undefined) { + return { + name: plugin.mappedName, + enabled: plugin.enabled, + }; + } + plugin = keydWithMap.find((x) => { + return x.plugin === pluginName; + }); + if (plugin !== undefined) { + return { + name: plugin.mappedName, + enabled: plugin.enabled, + }; + } - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - log: IPluginLogger, - deploymentProfile: string - ) { - super(pluginName, cwd, pluginCwd, log, deploymentProfile); - } - private get activeDeploymentProfile(): DeploymentProfiles { - return (this._appConfig.deploymentProfiles as IDictionary)[ - this._deploymentProfile - ]; - } - public override async getAppPluginDeploymentProfile( - pluginName: string - ): Promise { - return this.activeDeploymentProfile[pluginName!]; + throw new BSBError( + "DEFAULT_CONFIG_GET_SERVICE_PLUGIN_NAME", + "Cannot find the plugin {plugin} in the config", + { + plugin: pluginName, + } + ); } - - public override async getAppMappedPluginConfig( - mappedPluginName: string - ): Promise { - return (this._appConfig.plugins[mappedPluginName] || {}) as T; + async getLoggingPlugins(): Promise> { + let plugins = Object.keys( + this._appConfig[this._deploymentProfile].logging ?? {} + ).filter((x) => { + return ( + this._appConfig[this._deploymentProfile].logging[x].enabled === true + ); + }); + return plugins.reduce((acc, x) => { + acc[x] = { + //name: this._appConfig[this._deploymentProfile].logging[x].name, + plugin: this._appConfig[this._deploymentProfile].logging[x].plugin, + package: this._appConfig[this._deploymentProfile].logging[x].package, + enabled: this._appConfig[this._deploymentProfile].logging[x].enabled, + filter: this._appConfig[this._deploymentProfile].logging[x].filter, + }; + return acc; + }, {} as Record); } - public override async getAppMappedPluginDeploymentProfile( - mappedPluginName: string - ): Promise { - for (let dpPlugin of Object.keys(this.activeDeploymentProfile)) { - if ( - this.activeDeploymentProfile[dpPlugin].mappedName === mappedPluginName - ) - return this.activeDeploymentProfile[dpPlugin]; - } - await this.log.fatal("Cannot find mapped plugin {mappedPluginName}", { - mappedPluginName, + async getEventsPlugins(): Promise> { + let plugins = Object.keys( + this._appConfig[this._deploymentProfile].events ?? {} + ).filter((x) => { + return ( + this._appConfig[this._deploymentProfile].events[x].enabled === true + ); }); - return undefined as any; // will not reach + return plugins.reduce((acc, x) => { + acc[x] = { + //name: this._appConfig[this._deploymentProfile].events[x].name, + plugin: this._appConfig[this._deploymentProfile].events[x].plugin, + package: this._appConfig[this._deploymentProfile].events[x].package, + enabled: this._appConfig[this._deploymentProfile].events[x].enabled, + filter: this._appConfig[this._deploymentProfile].events[x].filter, + }; + return acc; + }, {} as Record); } - - public override async getAppPluginMappedName( - pluginName: string - ): Promise { - return ( - (this.activeDeploymentProfile[pluginName] || {}).mappedName || pluginName - ); + async getServicePlugins(): Promise> { + let plugins = Object.keys( + this._appConfig[this._deploymentProfile].services ?? {} + ).filter((x) => { + return ( + this._appConfig[this._deploymentProfile].services[x].enabled === true + ); + }); + return plugins.reduce((acc, x) => { + acc[x] = { + //name: this._appConfig[this._deploymentProfile].services[x].name, + plugin: this._appConfig[this._deploymentProfile].services[x].plugin, + package: this._appConfig[this._deploymentProfile].services[x].package, + enabled: this._appConfig[this._deploymentProfile].services[x].enabled, + }; + return acc; + }, {} as Record); } - public override async getAppPluginState( - pluginName: string - ): Promise { - return (this.activeDeploymentProfile[pluginName] || {}).enabled || false; + async getPluginConfig( + pluginType: PluginType, + plugin: string + ): Promise { + if (pluginType === PluginTypes.config) return null; + let configKey: "services" | "logging" | "events" = "services"; + if (pluginType === PluginTypes.events) configKey = "events"; + if (pluginType === PluginTypes.logging) configKey = "logging"; + return this._appConfig[this._deploymentProfile][configKey][plugin]; } - public override async getAppMappedPluginState( - mappedPluginName: string - ): Promise { - return (await this.getAppMappedPluginDeploymentProfile(mappedPluginName)) - .enabled; + dispose() { + this._appConfig = undefined!; } + run?(): void; + private _appConfig!: ConfigDefinition; + private _secConfigFilePath: string; + private _deploymentProfile: string = "default"; - public override async createAppConfig( - listOfKnownPlugins: Array - ): Promise { - const config = await this.getPluginConfig(); + constructor( + appId: string, + mode: DEBUG_MODE, + pluginName: string, + cwd: string, + pluginCwd: string, + logging: SBLogging + ) { + super(appId, mode, pluginName, cwd, pluginCwd, logging); + this._secConfigFilePath = path.join(this.cwd, "./sec-config.yaml"); + } - this._secConfigFilePath = - config.ConfigFile.indexOf(".") === 0 - ? path.join(this.cwd, config.ConfigFile) - : config.ConfigFile; - let defConfig: ServiceConfig = { - deploymentProfiles: { - default: {}, + init(): void { + if ( + Tools.isString(process.env.BSB_PROFILE) && + process.env.BSB_PROFILE.length > 2 + ) { + this._deploymentProfile = process.env.BSB_PROFILE!; + } + if ( + Tools.isString(process.env.BSB_CONFIG_FILE) && + process.env.BSB_CONFIG_FILE.length > 2 + ) { + this._secConfigFilePath = process.env.BSB_CONFIG_FILE!; + } + this._appConfig = { + default: { + logging: {}, + events: {}, + services: {}, }, - plugins: {}, }; if (fs.existsSync(this._secConfigFilePath)) { - let tdefConfig = + this._appConfig = parse(fs.readFileSync(this._secConfigFilePath, "utf8").toString()) ?? - ({} as ServiceConfig); - defConfig.plugins = tdefConfig.plugins ?? {}; - defConfig.deploymentProfiles = tdefConfig.deploymentProfiles ?? {}; - defConfig.deploymentProfiles.default = - defConfig.deploymentProfiles.default ?? {}; + this._appConfig; } else { - await this.log.debug( - "! sec.config.yaml CAN`T BE FOUND ... we will try create one / work in memory! {secFile}", - { secFile: this._secConfigFilePath } + throw new BSBError( + "DEFAULT_CONFIG_SETUP_CONFIG", + "Cannot find config file at {filepath}", + { + filepath: this._secConfigFilePath, + } ); } - - let existingDefinedPlugins = Object.keys( - defConfig.deploymentProfiles.default - ); - let pluginsToAdd = listOfKnownPlugins.filter( - (x) => existingDefinedPlugins.indexOf(x) < 0 - ); - for (let pluginName of pluginsToAdd) { - defConfig.deploymentProfiles.default[pluginName] = { - mappedName: pluginName, - enabled: false, - }; - } - - this._appConfig = defConfig; - if (!this.runningLive) { - try { - if (fs.existsSync(this._secConfigFilePath)) - fs.accessSync(this._secConfigFilePath, fs.constants.W_OK); - fs.writeFileSync(this._secConfigFilePath, stringify(this._appConfig)); - this._canWriteChanges = true; - } catch (e) { - await this.log.warn( - "We're running non-production, but {secFile} is not writable, not we're not going to create it.", - { secFile: this._secConfigFilePath } - ); - } - } - } - public override async migrateAppPluginConfig( - pluginName: string, - mappedPluginName: string, - config: IPluginConfig - ): Promise { - this._appConfig.deploymentProfiles[this._deploymentProfile][pluginName] = - this._appConfig.deploymentProfiles[this._deploymentProfile][ - pluginName - ] || { - mappedName: mappedPluginName, - enabled: true, - }; - this._appConfig.deploymentProfiles[this._deploymentProfile][ - pluginName - ].enabled = true; - this._appConfig.plugins[mappedPluginName] = config; - if (!this._canWriteChanges) { - if (!this.runningLive) - return await this.log.warn( - "We're running non-production, but {secFile} is not writable, not we're not going to change it.", - { secFile: this._secConfigFilePath } - ); - return await this.log.debug( - "We're running production, we're not going to write to {secFile}.", - { secFile: this._secConfigFilePath } + if (Tools.isNullOrUndefined(this._appConfig[this._deploymentProfile])) { + throw new BSBError( + "DEFAULT_CONFIG_SETUP_DEFINITION", + "unknown deployment profile ({deploymentProfile}), please create it first.", + { + deploymentProfile: this._deploymentProfile, + } ); } - fs.writeFileSync( - this._secConfigFilePath, - stringify(this._appConfig) // todo: replace this with typesafe formatting version + this.log.debug("Config ready, using profile: {profile}", { + profile: this._deploymentProfile, + }); + } + async getPlugins(): Promise< + { + npmPackage: string | undefined | null; + plugin: string; + name: string; + enabled: boolean; + }[] + > { + return Object.keys(this._appConfig[this._deploymentProfile].services).map( + (x) => { + return { + npmPackage: + this._appConfig[this._deploymentProfile].services[x].package, + plugin: this._appConfig[this._deploymentProfile].services[x].plugin, + name: x, + enabled: + this._appConfig[this._deploymentProfile].services[x].enabled === + true, + }; + } ); } } diff --git a/nodejs/src/plugins/config-default/sec.config.ts b/nodejs/src/plugins/config-default/sec.config.ts deleted file mode 100644 index c859494..0000000 --- a/nodejs/src/plugins/config-default/sec.config.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { SecConfig } from "../../interfaces/serviceConfig"; -import { IPluginConfig } from "../../interfaces/config"; - -export interface PluginConfig extends IPluginConfig { - ConfigFile: string; -} - -export class Config extends SecConfig { - public override migrate( - mappedPluginName: string, - existingConfig: PluginConfig - ): PluginConfig { - return { - ConfigFile: - existingConfig.ConfigFile || - process.env.BSB_SEC_JSON || - "./sec.config.yaml", - }; - } -} diff --git a/nodejs/src/plugins/events-default/events/broadcast.ts b/nodejs/src/plugins/events-default/events/broadcast.ts index b35e854..1749e53 100644 --- a/nodejs/src/plugins/events-default/events/broadcast.ts +++ b/nodejs/src/plugins/events-default/events/broadcast.ts @@ -1,5 +1,5 @@ import { EventEmitter } from "events"; -import { IPluginLogger } from '../../../interfaces/logger'; +import { IPluginLogger } from "../../../interfaces/logging"; export default class broadcast extends EventEmitter { private log: IPluginLogger; @@ -13,28 +13,26 @@ export default class broadcast extends EventEmitter { } public async onBroadcast( - callerPluginName: string, pluginName: string, event: string, listener: { (args: Array): Promise } ): Promise { - await this.log.debug( - "onBroadcast: {callerPluginName} listening to {pluginName}-{event}", - { callerPluginName, pluginName, event } - ); + this.log.debug("onBroadcast:listening to {pluginName}-{event}", { + pluginName, + event, + }); this.on(`${pluginName}-${event}`, listener); } public async emitBroadcast( - callerPluginName: string, pluginName: string, event: string, args: Array ): Promise { - await this.log.debug( - "emitBroadcast: {callerPluginName} emitting {pluginName}-{event}", - { callerPluginName, pluginName, event } - ); + this.log.debug("emitBroadcast: emitting {pluginName}-{event}", { + pluginName, + event, + }); this.emit(`${pluginName}-${event}`, args); } } diff --git a/nodejs/src/plugins/events-default/events/emit.ts b/nodejs/src/plugins/events-default/events/emit.ts index f736dde..b5fbc9a 100644 --- a/nodejs/src/plugins/events-default/events/emit.ts +++ b/nodejs/src/plugins/events-default/events/emit.ts @@ -1,5 +1,5 @@ import { EventEmitter } from "events"; -import { IPluginLogger } from "../../../interfaces/logger"; +import { IPluginLogger } from "../../../interfaces/logging"; import { randomUUID } from "crypto"; export default class emit extends EventEmitter { @@ -22,15 +22,14 @@ export default class emit extends EventEmitter { } public async onEvent( - callerPluginName: string, pluginName: string, event: string, listener: { (args: Array): Promise } ): Promise { - await this.log.debug( - "onEvent: {callerPluginName} listening to {pluginName}-{event}", - { callerPluginName, pluginName, event } - ); + this.log.debug("onEvent: listening to {pluginName}-{event}", { + pluginName, + event, + }); this.on(`${pluginName}-${event}`, (args: any) => { if (this._lastReceivedMessageIds.includes(args.msgID)) { return; @@ -41,15 +40,14 @@ export default class emit extends EventEmitter { } public async emitEvent( - callerPluginName: string, pluginName: string, event: string, args: Array ): Promise { - await this.log.debug( - "emitEvent: {callerPluginName} emitting {pluginName}-{event}", - { callerPluginName, pluginName, event } - ); + this.log.debug("emitEvent: emitting {pluginName}-{event}", { + pluginName, + event, + }); this.emit(`${pluginName}-${event}`, { msgID: randomUUID(), data: args, diff --git a/nodejs/src/plugins/events-default/events/emitAndReturn.ts b/nodejs/src/plugins/events-default/events/emitAndReturn.ts index 153f304..29caeaa 100644 --- a/nodejs/src/plugins/events-default/events/emitAndReturn.ts +++ b/nodejs/src/plugins/events-default/events/emitAndReturn.ts @@ -1,5 +1,5 @@ import { EventEmitter } from "events"; -import { IPluginLogger } from "../../../interfaces/logger"; +import { IPluginLogger } from "../../../interfaces/logging"; export default class emitAndReturn extends EventEmitter { private log: IPluginLogger; @@ -13,14 +13,13 @@ export default class emitAndReturn extends EventEmitter { } public async onReturnableEvent( - callerPluginName: string, pluginName: string, event: string, listener: { (args: Array): Promise } ): Promise { - await this.log.debug( - "onReturnableEvent: {callerPluginName} listening to {pluginName}-{event}", - { callerPluginName, pluginName, event } + this.log.debug( + "onReturnableEvent: listening to {pluginName}-{event}", + { pluginName, event } ); this.on(event, async (resolve, reject, data) => { try { @@ -32,16 +31,15 @@ export default class emitAndReturn extends EventEmitter { } public async emitEventAndReturn( - callerPluginName: string, pluginName: string, event: string, timeoutSeconds: number, args: Array ): Promise { - await this.log.debug( - "emitReturnableEvent: {callerPluginName} emitting {pluginName}-{event}", - { callerPluginName, pluginName, event } - ); + this.log.debug("emitReturnableEvent: emitting {pluginName}-{event}", { + pluginName, + event, + }); const self = this; return new Promise((resolve, reject) => { let timeoutHandler = setTimeout(() => { diff --git a/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts b/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts index b0a4d16..41cf1d5 100644 --- a/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts +++ b/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts @@ -1,7 +1,7 @@ import { EventEmitter } from "events"; import { Readable } from "stream"; import { randomUUID } from "crypto"; -import { IPluginLogger } from '../../../interfaces/logger'; +import { IPluginLogger } from "../../../interfaces/logging"; export default class emitStreamAndReceiveStream extends EventEmitter { // If we try receive or send a stream and the other party is not ready for some reason, we will automatically timeout in 5s. @@ -17,18 +17,14 @@ export default class emitStreamAndReceiveStream extends EventEmitter { } async receiveStream( - callerPluginName: string, + event: string, listener: { (error: Error | null, stream: Readable): Promise }, timeoutSeconds: number = 60 ): Promise { const streamId = `${randomUUID()}=${timeoutSeconds}`; - await this.log.debug( - "receiveStream: {callerPluginName} listening to {streamId}", - { - callerPluginName, - streamId, - } - ); + this.log.debug("receiveStream: listening to {streamId}", { + streamId, + }); const self = this; return new Promise((resolve) => { let receiptTimeoutHandler: NodeJS.Timeout = setTimeout(() => { @@ -53,15 +49,12 @@ export default class emitStreamAndReceiveStream extends EventEmitter { } async sendStream( - callerPluginName: string, + event: string, streamId: string, stream: Readable ): Promise { const self = this; - await this.log.debug( - "sendStream: {callerPluginName} emitting _self-{streamId}", - { callerPluginName, streamId } - ); + this.log.debug("sendStream: emitting _self-{streamId}", { streamId }); return new Promise((resolve, rejectI) => { const timeout = Number.parseInt(streamId.split("=")[1]); const clearSessions = (e?: Error) => { diff --git a/nodejs/src/plugins/events-default/plugin.ts b/nodejs/src/plugins/events-default/plugin.ts index 39a3785..705010c 100644 --- a/nodejs/src/plugins/events-default/plugin.ts +++ b/nodejs/src/plugins/events-default/plugin.ts @@ -1,95 +1,80 @@ -import { IPluginLogger } from "../../interfaces/logger"; import { Readable } from "stream"; import emit from "./events/emit"; import emitAndReturn from "./events/emitAndReturn"; import emitStreamAndReceiveStream from "./events/emitStreamAndReceiveStream"; -import { EventsBase } from "../../events/events"; -import { PluginConfig } from "./sec.config"; -import broadcast from './events/broadcast'; +import broadcast from "./events/broadcast"; +import { BSBEvents, BSBEventsConstructor } from "../../base/events"; -export class Events extends EventsBase { +export class Plugin extends BSBEvents { + init?(): void; + run?(): void; protected broadcast!: broadcast; protected emit!: emit; protected ear!: emitAndReturn; protected eas!: emitStreamAndReceiveStream; constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - log: IPluginLogger + config: BSBEventsConstructor ) { - super(pluginName, cwd, pluginCwd, log); + super(config); - this.broadcast = new broadcast(log); - this.emit = new emit(log); - this.ear = new emitAndReturn(log); - this.eas = new emitStreamAndReceiveStream(log); + this.broadcast = new broadcast(this.createNewLogger("broadcast")); + this.emit = new emit(this.createNewLogger("emit")); + this.ear = new emitAndReturn(this.createNewLogger("emitAndReturn")); + this.eas = new emitStreamAndReceiveStream(this.createNewLogger("stream")); } - public override dispose() { + public dispose() { this.broadcast.dispose(); this.emit.dispose(); this.ear.dispose(); this.eas.dispose(); } - public override async onBroadcast( - callerPluginName: string, + public async onBroadcast( pluginName: string, event: string, listener: { (args: Array): Promise } ): Promise { - await this.broadcast.onBroadcast(callerPluginName, pluginName, event, listener); + await this.broadcast.onBroadcast(pluginName, event, listener); } - public override async emitBroadcast( - callerPluginName: string, + public async emitBroadcast( pluginName: string, event: string, args: Array ): Promise { - await this.broadcast.emitBroadcast(callerPluginName, pluginName, event, args); + await this.broadcast.emitBroadcast(pluginName, event, args); } - public override async onEvent( - callerPluginName: string, + public async onEvent( pluginName: string, event: string, listener: { (args: Array): Promise } ): Promise { - await this.emit.onEvent(callerPluginName, pluginName, event, listener); + await this.emit.onEvent(pluginName, event, listener); } - public override async emitEvent( - callerPluginName: string, + public async emitEvent( pluginName: string, event: string, args: Array ): Promise { - await this.emit.emitEvent(callerPluginName, pluginName, event, args); + await this.emit.emitEvent(pluginName, event, args); } - public override async onReturnableEvent( - callerPluginName: string, + public async onReturnableEvent( pluginName: string, event: string, listener: { (args: Array): Promise } ): Promise { - await this.ear.onReturnableEvent( - callerPluginName, - pluginName, - event, - listener - ); + await this.ear.onReturnableEvent(pluginName, event, listener); } - public override async emitEventAndReturn( - callerPluginName: string, + public async emitEventAndReturn( pluginName: string, event: string, timeoutSeconds: number, args: Array ): Promise { return await this.ear.emitEventAndReturn( - callerPluginName, pluginName, event, timeoutSeconds, @@ -97,18 +82,18 @@ export class Events extends EventsBase { ); } - public override async receiveStream( - callerPluginName: string, + public async receiveStream( + event: string, listener: { (error: Error | null, stream: Readable): Promise }, timeoutSeconds?: number ): Promise { - return this.eas.receiveStream(callerPluginName, listener, timeoutSeconds); + return this.eas.receiveStream(event, listener, timeoutSeconds); } - public override async sendStream( - callerPluginName: string, + public async sendStream( + event: string, streamId: string, stream: Readable ): Promise { - return this.eas.sendStream(callerPluginName, streamId, stream); + return this.eas.sendStream(event, streamId, stream); } } diff --git a/nodejs/src/plugins/events-default/sec.config.ts b/nodejs/src/plugins/events-default/sec.config.ts deleted file mode 100644 index 300c3a9..0000000 --- a/nodejs/src/plugins/events-default/sec.config.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { SecConfig } from "../../interfaces/serviceConfig"; -import { IPluginConfig } from "../../interfaces/config"; - -export interface PluginConfig extends IPluginConfig {} - -export class Config extends SecConfig { - migrate( - mappedPluginName: string, - existingConfig: PluginConfig - ): PluginConfig { - return {}; - } -} diff --git a/nodejs/src/plugins/log-default/sec.config.ts b/nodejs/src/plugins/log-default/sec.config.ts deleted file mode 100644 index 300c3a9..0000000 --- a/nodejs/src/plugins/log-default/sec.config.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { SecConfig } from "../../interfaces/serviceConfig"; -import { IPluginConfig } from "../../interfaces/config"; - -export interface PluginConfig extends IPluginConfig {} - -export class Config extends SecConfig { - migrate( - mappedPluginName: string, - existingConfig: PluginConfig - ): PluginConfig { - return {}; - } -} diff --git a/nodejs/src/plugins/log-default/colours.ts b/nodejs/src/plugins/logging-default/colours.ts similarity index 100% rename from nodejs/src/plugins/log-default/colours.ts rename to nodejs/src/plugins/logging-default/colours.ts diff --git a/nodejs/src/plugins/log-default/plugin.ts b/nodejs/src/plugins/logging-default/plugin.ts similarity index 66% rename from nodejs/src/plugins/log-default/plugin.ts rename to nodejs/src/plugins/logging-default/plugin.ts index feb8707..9346c8a 100644 --- a/nodejs/src/plugins/log-default/plugin.ts +++ b/nodejs/src/plugins/logging-default/plugin.ts @@ -1,7 +1,7 @@ -import { IPluginLogger, LogMeta } from "../../interfaces/logger"; -import { LoggerBase } from "../../logger/logger"; +import { BSBLogging, BSBLoggingConstructor } from "../../base/logging"; +import { LogMeta } from "../../interfaces/logging"; import { CONSOLE_COLOURS, ConsoleColours } from "./colours"; -import { PluginConfig } from "./sec.config"; +import { LogFormatter } from "../../base/logFormatter"; export const LOG_LEVELS = { TSTAT: "Text Statistic", @@ -13,17 +13,20 @@ export const LOG_LEVELS = { } as const; export type LogLevels = (typeof LOG_LEVELS)[keyof typeof LOG_LEVELS]; -export class Logger extends LoggerBase { +export class Plugin extends BSBLogging { + dispose?(): void; + init?(): void; + run?(): void; private _mockedConsole?: { (level: LogLevels, message: string): void }; private _mockConsole: boolean = false; + private logFormatter: LogFormatter = new LogFormatter(); + + //private mode: DEBUG_MODE = "development"; constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - defaultLogger: IPluginLogger, + config: BSBLoggingConstructor, mockConsole?: { (level: LogLevels, message: string): void } ) { - super(pluginName, cwd, pluginCwd, defaultLogger); + super(config); this._mockedConsole = mockConsole; if (this._mockedConsole !== undefined) this._mockConsole = true; } @@ -34,7 +37,7 @@ export class Logger extends LoggerBase { message: T, meta?: LogMeta ) { - let formattedMessage = this.formatLog(message, meta); + let formattedMessage = this.logFormatter.formatLog(message, meta); formattedMessage = `[${plugin.toUpperCase()}] ${formattedMessage}`; let func: any = console.debug; let colour: Array = [ @@ -72,68 +75,55 @@ export class Logger extends LoggerBase { func(colour.join("") + "%s" + CONSOLE_COLOURS.Reset, formattedMessage); } - public async reportStat( - plugin: string, - key: string, - value: number - ): Promise { - if (!this.runningDebug) return; + public reportStat(plugin: string, key: string, value: number): void { + if (!this.mode) return; this.logEvent(LOG_LEVELS.STAT, plugin, "[{key}={value}]", { key, value }); } - public async reportTextStat( + public reportTextStat( plugin: string, message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - if (!this.runningDebug) return; + meta: LogMeta + ): void { + if (!this.mode) return; this.logEvent(LOG_LEVELS.TSTAT, plugin, message as T, meta); } - public async debug( + public debug( plugin: string, message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - if (!this.runningDebug) return; + meta: LogMeta + ): void { + if (this.mode === "production") return; this.logEvent(LOG_LEVELS.DEBUG, plugin, message as T, meta); } - public async info( + public info( plugin: string, message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - if (this.runningLive && hasPIData === true) return; + meta: LogMeta + ): void { this.logEvent(LOG_LEVELS.INFO, plugin, message as T, meta); } - public async warn( + public warn( plugin: string, message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - if (this.runningLive && hasPIData === true) return; + meta: LogMeta + ): void { this.logEvent(LOG_LEVELS.WARN, plugin, message as T, meta); } - public async error( + public error( plugin: string, message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise; - public async error(plugin: string, error: Error): Promise; - public async error( + meta: LogMeta + ): void; + public error(plugin: string, error: Error): void; + public error( plugin: string, messageOrError: T | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { + meta?: LogMeta + ): void { let message = typeof messageOrError === "string" ? messageOrError : messageOrError.message; - if (this.runningLive && hasPIData === true) return; this.logEvent(LOG_LEVELS.ERROR, plugin, message as T, meta); if ( typeof messageOrError !== "string" && diff --git a/nodejs/src/plugins/service-default0/plugin.ts b/nodejs/src/plugins/service-default0/plugin.ts index b30b17b..ba715a5 100644 --- a/nodejs/src/plugins/service-default0/plugin.ts +++ b/nodejs/src/plugins/service-default0/plugin.ts @@ -1,15 +1,44 @@ -import { IPluginLogger } from '../../interfaces/logger'; -import { ServicesBase } from "../../service/service"; +import { + BSBService, + BSBServiceConstructor, + BSBServiceTypes, +} from "../../base/service"; import { testClient } from "../service-default1/plugin"; -export class Service extends ServicesBase { - public override initAfterPlugins: string[] = ["service-default3"]; +export interface ServiceTypes extends BSBServiceTypes { + methods: { + abc: () => Promise; + }; + emitEvents: { + test: (a: string, b: string) => Promise; + }; + onEvents: {}; + emitReturnableEvents: {}; + onReturnableEvents: {}; + emitBroadcast: {}; + onBroadcast: {}; +} +export class Plugin extends BSBService { + public initBeforePlugins?: string[] | undefined; + //public initAfterPlugins: string[] = ["service-default3"]; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public init?(): Promise; + public dispose?(): void; + public readonly methods = { + abc: async () => { + console.log("abc called"); + }, + }; private testClient: testClient; - constructor(pluginName: string, cwd: string, pluginCwd: string, log: IPluginLogger) { - super(pluginName, cwd, pluginCwd, log); + constructor(config: BSBServiceConstructor) { + super(config); this.testClient = new testClient(this); } - public override async run() { - await this.testClient.abc(); + public async run() { + this.log.info("aa"); + this.events.emitEvent("test", "test", "test"); + await this.testClient.abc(1, 5, 2, 6); } } diff --git a/nodejs/src/plugins/service-default0/sec.config.ts b/nodejs/src/plugins/service-default0/sec.config.ts index ecd2525..8a34438 100644 --- a/nodejs/src/plugins/service-default0/sec.config.ts +++ b/nodejs/src/plugins/service-default0/sec.config.ts @@ -1,19 +1,19 @@ -import { SecConfig } from "../../interfaces/serviceConfig"; -import { IPluginConfig } from "../../interfaces/config"; +// import { SecConfig } from "../../interfaces/serviceConfig"; +// import { IPluginConfig } from "../../interfaces/config"; -export interface PluginConfig extends IPluginConfig { - testa: number - testb: number -} +// export interface PluginConfig extends IPluginConfig { +// testa: number +// testb: number +// } -export class Config extends SecConfig { - migrate( - mappedPluginName: string, - existingConfig: PluginConfig - ): PluginConfig { - return { - testa: existingConfig.testa || 6, // this value gets a default value - testb: 5 // this value is unchangable - }; - } -} +// export class Config extends SecConfig { +// migrate( +// mappedPluginName: string, +// existingConfig: PluginConfig +// ): PluginConfig { +// return { +// testa: existingConfig.testa || 6, // this value gets a default value +// testb: 5 // this value is unchangable +// }; +// } +// } diff --git a/nodejs/src/plugins/service-default1/plugin.ts b/nodejs/src/plugins/service-default1/plugin.ts index 586aa61..4b0260c 100644 --- a/nodejs/src/plugins/service-default1/plugin.ts +++ b/nodejs/src/plugins/service-default1/plugin.ts @@ -1,84 +1,99 @@ -import { ServiceCallable } from "../../service/base"; -import { ServicesBase } from "../../service/service"; -import { ServicesClient } from "../../service/serviceClient"; +import { BSBService, BSBServiceTypes } from "../../base/service"; +import { BSBServiceClient } from "../../base/serviceClient"; -export interface testCallable extends ServiceCallable { - callableMethod(a: number, b: number): Promise; +export interface ServiceTypes extends BSBServiceTypes { + methods: { + callableMethod(a: number, b: number): Promise; + }; + emitEvents: { + onEmittable(a: number, b: number): Promise; + }; + onEvents: { + onReceivable(a: number, b: number): Promise; + }; + emitReturnableEvents: { + onReverseReturnable(a: number, b: number): Promise; + }; + onReturnableEvents: { + onReturnable(a: number, b: number): Promise; + }; + emitBroadcast: {}; + onBroadcast: {}; } -export interface testEvents extends ServiceCallable { - onReceivable(a: number, b: number): Promise; -} -export interface testEmitEvents extends ServiceCallable { - onEmittable(a: number, b: number): Promise; -} - -export interface testRetEvents extends ServiceCallable { - onReturnable(a: number, b: number): Promise; -} -export interface testEmitRetEvents extends ServiceCallable { - onReverseReturnable(a: number, b: number): Promise; -} +export class Plugin extends BSBService { + public initBeforePlugins?: string[] | undefined; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public methods = { + callableMethod: async (a: number, b: number) => { + this.log.warn("callableMethod ({a},{b})", { a, b }); + this.events.emitEvent("onEmittable", a, b); + return a * b; + }, + }; + dispose?(): void; + run?(): void | Promise; -export class Service - extends ServicesBase< - testEvents, - testEmitEvents, - testRetEvents, - testEmitRetEvents, - testCallable, - any - > - implements testCallable -{ - async callableMethod(a: number, b: number): Promise { - await this.log.warn("RECEIVED CALL ({a},{b})", { a, b }); - this.emitEvent("onEmittable", a, b); - return a * b; - } + private count = 0; public override async init() { - const self = this; - this.onEvent("onReceivable", async (a: number, b: number) => { - await self.log.warn("received onReceivable ({a},{b}", { a, b }); - }); - this.onReturnableEvent("onReturnable", async (a: number, b: number) => { - await self.log.warn("RECEIVED onReturnable ({a},{b})", { a, b }); - let result = await self.emitEventAndReturn("onReverseReturnable", a, b); - await self.log.warn("RETURNED onReverseReturnable ({result})", { result }); - return result; + this.log.info("INIT SERVICE"); + this.events.onEvent("onReceivable", async (a: number, b: number) => { + this.count++; + console.log('calledI: ' + this.count); + this.log.warn("received onReceivable ({a},{b}", { a, b }); + //process.exit(3); }); + this.events.onReturnableEvent( + "onReturnable", + async (a: number, b: number) => { + this.log.warn("RECEIVED onReturnable ({a},{b})", { a, b }); + let result = await this.events.emitEventAndReturn( + "onReverseReturnable", + 5, + a, + b + ); + this.log.warn("RETURNED onReverseReturnable ({result})", { + result, + }); + return result; + } + ); } } -export class testClient extends ServicesClient< - testEvents, - testEmitEvents, - testRetEvents, - testEmitRetEvents, - testCallable, - any -> { - public override readonly pluginName: string = "service-default1"; - public override async init(): Promise { - const self = this; - this._plugin.onEvent("onEmittable", async (a: number, b: number) => { - await self._plugin.log.warn("onEmittable ({a},{b})", { a, b }); +export class testClient extends BSBServiceClient { + public initBeforePlugins?: string[] | undefined; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public dispose?(): void; + public run?(): Promise; + public readonly pluginName: string = "service-default1"; + private count = 0; + public async init(): Promise { + this.events.onEvent("onEmittable", async (a: number, b: number) => { + this.log.warn("onEmittable ({a},{b})", { a, b }); }); - this._plugin.onReturnableEvent( + this.events.onReturnableEvent( "onReverseReturnable", async (a: number, b: number) => { - await self._plugin.log.warn("onReverseReturnable ({a},{b})", { a, b }); + this.count++; + console.log('called: ' + this.count); + this.log.warn("onReverseReturnable ({a},{b})", { a, b }); return a * b; } ); - this._plugin.emitEvent("onReceivable", 56, 7); + await this.events.emitEvent("onReceivable", 56, 7); } - async abc(): Promise { - await this._plugin.log.warn("TESTING ABC CALL ({result})", { - result: await this._plugin.callPluginMethod("callableMethod", 5, 8), + async abc(a: number, b: number, c: number, d: number): Promise { + this.log.warn("TESTING ABC CALL ({result})", { + result: await this.callMethod("callableMethod", a, b), }); - await this._plugin.log.warn("TESTING onReturnable ({result})", { - result: await this._plugin.emitEventAndReturn("onReturnable", 12, 8), + this.log.warn("TESTING onReturnable ({result})", { + result: await this.events.emitEventAndReturn("onReturnable", 5, c, d), }); } } diff --git a/nodejs/src/plugins/service-default2/plugin.ts b/nodejs/src/plugins/service-default2/plugin.ts index c0a439a..a1dcb1a 100644 --- a/nodejs/src/plugins/service-default2/plugin.ts +++ b/nodejs/src/plugins/service-default2/plugin.ts @@ -1,15 +1,20 @@ -import { IPluginLogger } from '../../interfaces/logger'; -import { ServicesBase } from "../../service/service"; +import { BSBService, BSBServiceConstructor } from "../../base/service"; import { testClient } from "../service-default1/plugin"; -export class Service extends ServicesBase { +export class Plugin extends BSBService { + public initBeforePlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public methods = {}; + dispose?(): void; + init?(): void | Promise; public override initAfterPlugins: string[] = ["service-default1"]; private testClient: testClient; - constructor(pluginName: string, cwd: string, pluginCwd: string, log: IPluginLogger) { - super(pluginName, cwd, pluginCwd, log); + constructor(config: BSBServiceConstructor) { + super(config); this.testClient = new testClient(this); } public override async run() { - await this.testClient.abc(); + await this.testClient.abc(10, 12, 11, 13); } } diff --git a/nodejs/src/plugins/service-default2/sec.config.ts b/nodejs/src/plugins/service-default2/sec.config.ts index ecd2525..8a34438 100644 --- a/nodejs/src/plugins/service-default2/sec.config.ts +++ b/nodejs/src/plugins/service-default2/sec.config.ts @@ -1,19 +1,19 @@ -import { SecConfig } from "../../interfaces/serviceConfig"; -import { IPluginConfig } from "../../interfaces/config"; +// import { SecConfig } from "../../interfaces/serviceConfig"; +// import { IPluginConfig } from "../../interfaces/config"; -export interface PluginConfig extends IPluginConfig { - testa: number - testb: number -} +// export interface PluginConfig extends IPluginConfig { +// testa: number +// testb: number +// } -export class Config extends SecConfig { - migrate( - mappedPluginName: string, - existingConfig: PluginConfig - ): PluginConfig { - return { - testa: existingConfig.testa || 6, // this value gets a default value - testb: 5 // this value is unchangable - }; - } -} +// export class Config extends SecConfig { +// migrate( +// mappedPluginName: string, +// existingConfig: PluginConfig +// ): PluginConfig { +// return { +// testa: existingConfig.testa || 6, // this value gets a default value +// testb: 5 // this value is unchangable +// }; +// } +// } diff --git a/nodejs/src/plugins/service-default3/plugin.ts b/nodejs/src/plugins/service-default3/plugin.ts index 207c210..11a0021 100644 --- a/nodejs/src/plugins/service-default3/plugin.ts +++ b/nodejs/src/plugins/service-default3/plugin.ts @@ -1,15 +1,20 @@ -import { IPluginLogger } from '../../interfaces/logger'; -import { ServicesBase } from "../../service/service"; +import { BSBService, BSBServiceConstructor } from "../../base/service"; import { testClient } from "../service-default1/plugin"; -export class Service extends ServicesBase { +export class Plugin extends BSBService { + public initBeforePlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public methods = {}; + dispose?(): void; + init?(): void | Promise; public override initAfterPlugins: string[] = ["service-default2"]; private testClient: testClient; - constructor(pluginName: string, cwd: string, pluginCwd: string, log: IPluginLogger) { - super(pluginName, cwd, pluginCwd, log); + constructor(config: BSBServiceConstructor) { + super(config); this.testClient = new testClient(this); } public override async run() { - await this.testClient.abc(); + await this.testClient.abc(18, 19, 20, 21); } } diff --git a/nodejs/src/plugins/service-default3/sec.config.ts b/nodejs/src/plugins/service-default3/sec.config.ts index ecd2525..8a34438 100644 --- a/nodejs/src/plugins/service-default3/sec.config.ts +++ b/nodejs/src/plugins/service-default3/sec.config.ts @@ -1,19 +1,19 @@ -import { SecConfig } from "../../interfaces/serviceConfig"; -import { IPluginConfig } from "../../interfaces/config"; +// import { SecConfig } from "../../interfaces/serviceConfig"; +// import { IPluginConfig } from "../../interfaces/config"; -export interface PluginConfig extends IPluginConfig { - testa: number - testb: number -} +// export interface PluginConfig extends IPluginConfig { +// testa: number +// testb: number +// } -export class Config extends SecConfig { - migrate( - mappedPluginName: string, - existingConfig: PluginConfig - ): PluginConfig { - return { - testa: existingConfig.testa || 6, // this value gets a default value - testb: 5 // this value is unchangable - }; - } -} +// export class Config extends SecConfig { +// migrate( +// mappedPluginName: string, +// existingConfig: PluginConfig +// ): PluginConfig { +// return { +// testa: existingConfig.testa || 6, // this value gets a default value +// testb: 5 // this value is unchangable +// }; +// } +// } diff --git a/nodejs/src/postinstall.ts b/nodejs/src/postinstall.ts index 70a9314..bb08a1e 100644 --- a/nodejs/src/postinstall.ts +++ b/nodejs/src/postinstall.ts @@ -1,13 +1,13 @@ -import { ServiceBase } from "./serviceBase/serviceBase"; -const runApp = async () => { - const CWD = process.env.APP_DIR || process.cwd(); - const SB = new ServiceBase(true, false, CWD); - await SB.setupSelf(); - await SB.setupPlugins(CWD); - await SB.setupConfig(); - await SB.setupLogger(); - await SB.setupEvents(); - await SB.setupServices(); - SB.dispose(0, "OK") -}; -runApp(); +// import { ServiceBase } from "./serviceBase/serviceBase"; +// const runApp = async () => { +// const CWD = process.env.APP_DIR || process.cwd(); +// const SB = new ServiceBase(true, false, CWD); +// await SB.setupSelf(); +// await SB.setupPlugins(CWD); +// await SB.setupConfig(); +// await SB.setupLogger(); +// await SB.setupEvents(); +// await SB.setupServices(); +// SB.dispose(0, "OK") +// }; +// runApp(); diff --git a/nodejs/src/service/base.ts b/nodejs/src/service/base.ts deleted file mode 100644 index 93ce375..0000000 --- a/nodejs/src/service/base.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface ServiceEvents {} -export interface ServiceBroadcasts {} -export interface ServiceReturnableEvents {} -export interface ServiceCallable {} diff --git a/nodejs/src/service/service.ts b/nodejs/src/service/service.ts deleted file mode 100644 index 6dd629e..0000000 --- a/nodejs/src/service/service.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { IPluginConfig } from "../interfaces/config"; -import { IPluginLogger } from "../interfaces/logger"; -import { IService } from "../interfaces/service"; -import { Readable } from "stream"; -import { DefaultBase } from "../interfaces/base"; -import { RegisteredPlugin, ServicesClient } from "./serviceClient"; -import { ErrorMessages } from "../interfaces/static"; -import { DynamicallyReferencedMethodType } from "@bettercorp/tools/lib/Interfaces"; -import { - DynamicallyReferencedMethodOnIEvents, - DynamicallyReferencedMethodEmitIEvents, - DynamicallyReferencedMethodEmitEARIEvents, -} from "../interfaces/events"; -import { - ServiceCallable, - ServiceEvents, - ServiceBroadcasts, - ServiceReturnableEvents, -} from "./base"; - -export class ServicesBase< - onEvents = ServiceEvents, - emitEvents = ServiceEvents, - onReturnableEvents = ServiceReturnableEvents, - emitReturnableEvents = ServiceReturnableEvents, - callableMethods = ServiceCallable, - pluginConfigType extends IPluginConfig = any, - onBroadcast = ServiceBroadcasts, - emitBroadcast = ServiceBroadcasts - > - extends DefaultBase - implements - IService< - onEvents, - emitEvents, - onReturnableEvents, - emitReturnableEvents, - onBroadcast, - emitBroadcast - > -{ - public readonly initBeforePlugins?: Array; - public readonly initAfterPlugins?: Array; - public readonly runBeforePlugins?: Array; - public readonly runAfterPlugins?: Array; - - async run(): Promise {} - - public initPluginClient< - pluginClientOnEvents, - pluginClientEmitEvents, - pluginClientOnReturnableEvents, - pluginClientEmitReturnableEvents, - pluginCallableMethods, - pluginClientConfigType extends IPluginConfig, - pluginClientOnBroadcast, - pluginClientEmitBroadcast - >( - pluginName: string - ): Promise< - RegisteredPlugin< - pluginClientOnEvents, - pluginClientEmitEvents, - pluginClientOnReturnableEvents, - pluginClientEmitReturnableEvents, - pluginCallableMethods, - pluginClientConfigType, - pluginClientOnBroadcast, - pluginClientEmitBroadcast - > - > { - throw ErrorMessages.BSBNotInit; - } - - protected _clients: Array = []; - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - log: IPluginLogger - ) { - super(pluginName, cwd, pluginCwd, log); - } - receiveStream( - listener: (error: Error | null, stream: Readable) => Promise, - timeoutSeconds?: number - ): Promise { - throw ErrorMessages.BSBNotInit; - } - sendStream(streamId: string, stream: Readable): Promise { - throw ErrorMessages.BSBNotInit; - } - onBroadcast( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - emitBroadcast( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - onEvent( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - onEventSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - emitEvent( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - emitEventSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - onReturnableEvent( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - onReturnableEventSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise { - throw ErrorMessages.BSBNotInit; - } - emitEventAndReturn( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } - emitEventAndReturnSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } - emitEventAndReturnTimed( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } - emitEventAndReturnTimedSpecific( - serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - false - > { - throw ErrorMessages.BSBNotInit; - } -} diff --git a/nodejs/src/serviceBase/base.ts b/nodejs/src/serviceBase/base.ts deleted file mode 100644 index f151ec3..0000000 --- a/nodejs/src/serviceBase/base.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { ServicesBase } from "../service/service"; -import { ConfigBase } from "../config/config"; -import { DefaultBase, FakeConfigBase } from "../interfaces/base"; -import { IPluginConfig } from "../interfaces/config"; -import { IServiceEvents } from "../interfaces/events"; -import { RegisteredPlugin } from "../service/serviceClient"; -import { IPluginLogger } from "../interfaces/logger"; -import { - DynamicallyReferencedMethod, - DynamicallyReferencedMethodType, -} from "@bettercorp/tools/lib/Interfaces"; - -export class SBBase { - static setupPlugin( - appId: string, - runningDebug: boolean, - runningLive: boolean, - plugin: DefaultBase, - config: ConfigBase - ): void { - (plugin as unknown as FakeConfigBase).appId = appId; - (plugin as unknown as FakeConfigBase).runningDebug = runningDebug; - (plugin as unknown as FakeConfigBase).runningLive = runningLive; - (plugin as unknown as FakeConfigBase).getPluginConfig = - async (): Promise => { - return await config.getAppMappedPluginConfig(plugin.pluginName); - }; - (plugin as unknown as FakeConfigBase).getPluginState = - async (): Promise => { - return await config.getAppMappedPluginState(plugin.pluginName); - }; - } - - static setupServicePluginSpecific< - PluginConfigType extends IPluginConfig = any - >( - plugin: - | ServicesBase - | RegisteredPlugin, - events: IServiceEvents - ): void { - ( - plugin as unknown as IServiceEvents - ).emitBroadcast = events.emitBroadcast; - ( - plugin as unknown as IServiceEvents - ).onBroadcast = events.onBroadcast; - ( - plugin as unknown as IServiceEvents - ).emitEvent = events.emitEvent; - ( - plugin as unknown as IServiceEvents - ).emitEventSpecific = events.emitEventSpecific; - ( - plugin as unknown as IServiceEvents - ).onEvent = events.onEvent; - ( - plugin as unknown as IServiceEvents - ).onEventSpecific = events.onEventSpecific; - ( - plugin as unknown as IServiceEvents - ).emitEventAndReturnTimed = events.emitEventAndReturnTimed; - ( - plugin as unknown as IServiceEvents - ).emitEventAndReturnTimedSpecific = events.emitEventAndReturnTimedSpecific; - ( - plugin as unknown as IServiceEvents - ).emitEventAndReturn = events.emitEventAndReturn; - ( - plugin as unknown as IServiceEvents - ).emitEventAndReturnSpecific = events.emitEventAndReturnSpecific; - ( - plugin as unknown as IServiceEvents - ).onReturnableEvent = events.onReturnableEvent; - ( - plugin as unknown as IServiceEvents - ).onReturnableEventSpecific = events.onReturnableEventSpecific; - ( - plugin as unknown as IServiceEvents - ).receiveStream = events.receiveStream; - ( - plugin as unknown as IServiceEvents - ).sendStream = events.sendStream; - } - static setupServicePlugin( - plugin: ServicesBase, - events: IServiceEvents, - config: ConfigBase, - cwd: string, - pluginCwd: string, - generateEventsForService: ( - pluginName: string, - mappedPluginName: string - ) => IServiceEvents, - generateLoggerForPlugin: { (pluginName: string): IPluginLogger }, - log: IPluginLogger, - callPluginMethod: { - (pluginName: string, method: string, args: Array): Promise; - } - ): void { - SBBase.setupServicePluginSpecific(plugin, events); - (plugin as unknown as ServicesBase).initPluginClient = async ( - pluginName: string - ): Promise> => { - let mappedPluginName = await config.getAppPluginMappedName(pluginName); - await log.debug( - "Registering new plugin client in {callerPlugin} for {pluginName} as {mappedPluginName}", - { - callerPlugin: plugin.pluginName, - pluginName, - mappedPluginName, - } - ); - let tPlugin = new RegisteredPlugin< - any, - any, - any, - any, - any, - any, - any, - any - >( - pluginName, - cwd, - pluginCwd, - generateLoggerForPlugin(pluginName + "-client") - ); - SBBase.setupServicePluginSpecific( - tPlugin, - generateEventsForService(pluginName, mappedPluginName) - ); - ( - tPlugin as unknown as RegisteredPlugin< - any, - any, - any, - any, - any, - any, - any, - any - > - ).callPluginMethod = async ( - ...args: DynamicallyReferencedMethod< - DynamicallyReferencedMethodType, - TA - > - ) => { - const method = args.splice(0, 1)[0] as string; - return await callPluginMethod(mappedPluginName, method, args); - }; - return tPlugin; - }; - } -} diff --git a/nodejs/src/serviceBase/config.ts b/nodejs/src/serviceBase/config.ts index cd05c42..719eaeb 100644 --- a/nodejs/src/serviceBase/config.ts +++ b/nodejs/src/serviceBase/config.ts @@ -1,260 +1,141 @@ -import { Tools } from "@bettercorp/tools/lib/Tools"; -import { existsSync, readFileSync } from "fs"; -import { join } from "path"; -import { PluginDefinitions, IReadyPlugin, PluginDefinition } from "../interfaces/service"; -import { IPluginLogger } from "../interfaces/logger"; -import { ConfigBase } from "../config/config"; -import { SecConfig } from "../interfaces/serviceConfig"; -import { SBBase } from "./base"; +import { DEBUG_MODE, IPluginLogger } from "../interfaces/logging"; +import { Plugin as Config } from "../plugins/config-default/plugin"; +import { SBPlugins } from "./plugins"; +import { SBLogging } from "./logging"; +import { PluginLogger } from "../base/PluginLogger"; +import { BSBConfig } from "../base/config"; +import { Tools } from "@bettercorp/tools"; +import { SmartFunctionCallSync, SmartFunctionCallAsync } from "../base/functions"; +import { + EventsConfig, + LoggingConfig, + PluginDefition, + PluginType, +} from "../interfaces/plugins"; export class SBConfig { + private mode: DEBUG_MODE = "development"; + private appId: string; + private cwd: string; + private sbPlugins: SBPlugins; + private sbLogging: SBLogging; private log: IPluginLogger; - private cwd!: string; - private configPlugin!: { - plugin: IReadyPlugin; - deploymentProfile: string; - }; - public appConfig!: ConfigBase; - constructor(log: IPluginLogger, cwd: string) { - this.log = log; + private configPlugin: BSBConfig; + constructor( + appId: string, + mode: DEBUG_MODE, + cwd: string, + sbLogging: SBLogging, + sbPlugins: SBPlugins + ) { + this.appId = appId; + this.mode = mode; this.cwd = cwd; + this.sbLogging = sbLogging; + this.sbPlugins = sbPlugins; + this.log = new PluginLogger(mode, "sb-config", sbLogging); + this.configPlugin = new Config( + appId, + mode, + "sb-config", + cwd, + cwd, + sbLogging + ); } + public async getPluginConfig(pluginType: PluginType, name: string) { + return await this.configPlugin.getPluginConfig(pluginType, name); + } + public async getServicePlugins(): Promise> { + return await this.configPlugin.getServicePlugins(); + } + public async getEventsPlugins(): Promise> { + return await this.configPlugin.getEventsPlugins(); + } + public async getLoggingPlugins(): Promise> { + return await this.configPlugin.getLoggingPlugins(); + } + public async getServicePluginDefinition( + pluginName: string + ): Promise<{ name: string; enabled: boolean }> { + return await this.configPlugin.getServicePluginDefinition(pluginName); + } public dispose() { - this.appConfig.dispose(); + SmartFunctionCallSync(this.configPlugin, this.configPlugin.dispose); } - public async findConfigPlugin(plugins: Array): Promise { - let deploymentProfile = "default"; - if (!Tools.isNullOrUndefined(process.env.BSB_PROFILE)) { - deploymentProfile = process.env.BSB_PROFILE!; - } + private loggerPackage: string | undefined; + private loggerPlugin = "config-default"; - await this.log.info( - "config load with profile: {deploymentProfile}, against {len} plugins", - { - deploymentProfile, - len: plugins.length, - } - ); - let pluginName = "config-default"; + public async init(): Promise { if ( - (!Tools.isNullOrUndefined(process.env.BSB_CONFIG_PLUGIN) && - process.env.BSB_CONFIG_PLUGIN !== "") || - existsSync(join(this.cwd, "./BSB_CONFIG_PLUGIN")) + Tools.isString(process.env.BSB_LOGGER_PLUGIN) && + process.env.BSB_LOGGER_PLUGIN.startsWith("config-") ) { - pluginName = - process.env.BSB_CONFIG_PLUGIN || - readFileSync(join(this.cwd, "./BSB_CONFIG_PLUGIN")).toString() || - "config-default"; - } - await this.log.info(`PLUGIN {pluginName} check`, { - pluginName, - }); - for (const plugin of plugins) { - if (plugin.pluginDefinition === PluginDefinitions.config) { - if (pluginName !== plugin.name) continue; - await this.log.info(`PLUGIN {name}v{version}`, { - name: plugin.name, - version: plugin.version, - }); - this.configPlugin = { - deploymentProfile, - plugin, - }; - await this.log.info(`PLUGIN {name}v{version} [SETUP FOR CONFIG]`, { - name: plugin!.name, - version: plugin.version, - }); - return; + this.loggerPlugin = process.env.BSB_LOGGER_PLUGIN; + if (Tools.isString(process.env.BSB_LOGGER_PLUGIN_PACKAGE)) { + this.loggerPackage = process.env.BSB_LOGGER_PLUGIN_PACKAGE; } } - - await this.log.fatal("Unable to setup default config plugin."); - } - - public async mapPlugins( - _plugins: Array - ): Promise> { - let mappedPlugins: Array = []; - - for (let plugin of _plugins) { - if (plugin.pluginDefinition !== PluginDefinitions.config) continue; - if (plugin.name !== this.configPlugin.plugin.name) continue; - mappedPlugins.push(plugin); - } - - for (let plugin of _plugins) { - if ( - plugin.pluginDefinition === PluginDefinitions.config || - plugin.pluginDefinition === PluginDefinitions.service - ) - continue; - //if (!await this.appConfig.getAppPluginState(plugin.name)) continue; - plugin.mappedName = await this.appConfig.getAppPluginMappedName( - plugin.name - ); - mappedPlugins.push(plugin); + this.log.debug("Add config {name} from ({package})", { + package: this.loggerPackage ?? "this project", + name: this.loggerPlugin, + }); + if (this.loggerPlugin === "config-default") { + await SmartFunctionCallAsync(this.configPlugin, this.configPlugin.init); + return; } + this.log.debug(`Import config plugin: {name} from ({package})`, { + package: this.loggerPackage ?? "this project", + name: this.loggerPlugin, + }); - for (let plugin of _plugins) { - if (plugin.pluginDefinition !== PluginDefinitions.service) continue; - if (!(await this.appConfig.getAppPluginState(plugin.name))) continue; - plugin.mappedName = await this.appConfig.getAppPluginMappedName( - plugin.name + const newPlugin = await this.sbPlugins.loadPlugin<"config">( + this.log, + this.loggerPackage ?? null, + this.loggerPlugin, + this.loggerPlugin + ); + if (newPlugin === null) { + this.log.error( + "Failed to import config plugin: {name} from ({package})", + { + package: this.loggerPackage ?? "this project", + name: this.loggerPlugin, + } ); - mappedPlugins.push(plugin); + return; } - return mappedPlugins; - } - - public async findPluginByType( - plugins: Array, - defaultPlugin: string, - type: PluginDefinition - ): Promise { - for (const plugin of plugins) { - if (plugin.pluginDefinition === type) { - if (await this.appConfig.getAppPluginState(plugin.name)) return plugin; - } - } - for (const plugin of plugins) { - if (plugin.name === defaultPlugin) { - return plugin; - } - } - await this.log.fatal( - "Cannot find plugin type {type} or default {defaultPlugin}", - { - type, - defaultPlugin, - } + this.configPlugin = new newPlugin.plugin( + this.appId, + this.mode, + newPlugin.name, + this.cwd, + newPlugin.pluginCWD, + this.sbLogging ); - return undefined as any; // should not reach this - } - - public getPluginName(): string { - return this.configPlugin.plugin.name; - } - - public async setupConfigPlugin( - logger: IPluginLogger, - appId: string, - runningDebug: boolean, - runningLive: boolean, - plugins: Array - ): Promise { - let appConfig: ConfigBase | undefined = undefined; - - await this.log.debug(`Import config plugin: {name} from {file}`, { - name: this.configPlugin.plugin.name, - file: this.configPlugin.plugin!.pluginFile, + this.log.info("Adding {pluginName} as config", { + pluginName: newPlugin.name, }); - const importedPlugin = await import(this.configPlugin.plugin!.pluginFile); - await this.log.debug(`Construct config plugin: {name}`, { - name: this.configPlugin.plugin.name, + this.log.debug(`Init: {name}`, { + name: this.loggerPlugin, }); + await SmartFunctionCallAsync(this.configPlugin, this.configPlugin.init); - appConfig = new (importedPlugin.Config as unknown as typeof ConfigBase)( - this.configPlugin.plugin.mappedName, - this.cwd, - this.configPlugin.plugin.pluginDir, - logger, - this.configPlugin.deploymentProfile - ); - await this.log.debug(`Create config plugin: {name}`, { - name: this.configPlugin.plugin.name, + this.log.info(`Init: {name}: OK`, { + name: this.loggerPlugin, }); - let pluginInstaller: SecConfig | null = - await this.ImportAndCreatePluginConfig(this.configPlugin.plugin); - let pluginConfig = {}; - if (pluginInstaller !== null) { - pluginConfig = pluginInstaller.migrate( - this.configPlugin.plugin.name, - pluginConfig - ); - } - - SBBase.setupPlugin(appId, runningDebug, runningLive, appConfig, { - getAppMappedPluginConfig: async () => { - return pluginConfig; - }, - getAppMappedPluginState: async () => { - return true; - }, - } as any); - await appConfig.createAppConfig(plugins.map((x) => x.name)); - this.appConfig = appConfig!; - await appConfig.init(); - await this.log.info(`Config plugin ready: {name}`, { - name: this.configPlugin.plugin.name, + this.log.debug(`Run: {name}`, { + name: this.loggerPlugin, }); - } - - public async ImportAndMigratePluginConfig(plugin: IReadyPlugin) { - let existingConfig = await this.appConfig.getAppMappedPluginConfig( - plugin.mappedName - ); - let secConfig = await this.ImportAndCreatePluginConfig(plugin); - let config = - secConfig !== null - ? secConfig.migrate(plugin.mappedName, existingConfig || {}) - : {}; - await this.appConfig.migrateAppPluginConfig( - plugin.name, - plugin.mappedName, - config - ); - return config; - } - - private async ImportAndCreatePluginConfig( - plugin: IReadyPlugin - ): Promise { - let config: SecConfig | null = null; + await SmartFunctionCallAsync(this.configPlugin, this.configPlugin.run); - if (plugin.installerFile !== null && existsSync(plugin.installerFile)) { - await this.log.debug( - `Import plugin config (sec.config.ts/js): {name} -> {installerFile}`, - { - name: plugin.name, - installerFile: plugin.installerFile, - } - ); - const importedInstaller = await import(plugin.installerFile); - await this.log.debug(`Create plugin config (sec.config.ts/js): {name}`, { - name: plugin.name, - }); - config = new (importedInstaller.Config as unknown as typeof SecConfig)(); - } else { - await this.log.debug(`No plugin config (sec.config.ts/js): {name}`, { - name: plugin.name, - }); - } - return config; - } - - /*public async configAllPlugins(): Promise { - await this._coreLogger.info(`CONFIG: {length} plugins`, { - length: this._plugins.length, + this.log.info(`Run: {name}: OK`, { + name: this.loggerPlugin, }); - for (const plugin of this._plugins) { - if (plugin.pluginDefinition === IPluginDefinition.config) continue; - const mappedPlugin = await this._appConfig.getMappedPluginName( - plugin.name - ); - await this._coreLogger.info( - `CONFIG: PLUGIN {name}v{version} AS {mappedPlugin}`, - { name: plugin.name, version: plugin.version, mappedPlugin } - ); - this.getReadyPluginConfig(plugin.pluginDefinition, plugin, mappedPlugin); - await this._coreLogger.info( - `CONFIG: PLUGIN {name}v{version} [CONFIGURED]`, - { name: plugin!.name, version: plugin.version } - ); - } - }*/ + } } diff --git a/nodejs/src/serviceBase/events.ts b/nodejs/src/serviceBase/events.ts index 54e20a3..ad13e55 100644 --- a/nodejs/src/serviceBase/events.ts +++ b/nodejs/src/serviceBase/events.ts @@ -1,467 +1,704 @@ -import { IPluginLogger } from "../interfaces/logger"; -import { SBBase } from "./base"; -import { ConfigBase } from "../config/config"; -import { IReadyPlugin } from "../interfaces/service"; -import { EventsBase } from "../events/events"; -import { - DynamicallyReferencedMethodEmitEARIEvents, - DynamicallyReferencedMethodEmitIEvents, - DynamicallyReferencedMethodOnIEvents, - IServiceEvents, -} from "../interfaces/events"; -import { DynamicallyReferencedMethodType } from "@bettercorp/tools/lib/Interfaces"; +import { DEBUG_MODE, IPluginLogger } from "../interfaces/logging"; +import { PluginLogger } from "../base/PluginLogger"; import { Readable } from "stream"; -import { MS_PER_NS, NS_PER_SEC } from "./serviceBase"; +import { Plugin as DefaultEvents } from "../plugins/events-default/plugin"; +import { + EventsFilter, + EventsFilterDetailed, + FilterOnType, + IPluginDefinition, +} from "../interfaces/plugins"; +import { SBPlugins } from "./plugins"; +import { SBConfig } from "./config"; +import { Tools } from "@bettercorp/tools"; +import { + SmartFunctionCallAsync, + SmartFunctionCallSync, +} from "../base/functions"; +import { BSBEvents } from "../base/events"; +import { SBLogging } from "./logging"; +import { EventsEventTypes, EventsEventTypesBase } from "../interfaces/events"; +import { BSBError } from "../base/errorMessages"; +import { NS_PER_SEC, MS_PER_NS } from "./serviceBase"; +import { BSBService } from "../base/service"; +import { BSBServiceClient } from "../base/serviceClient"; export class SBEvents { + private events: Array<{ + name: string; + plugin: BSBEvents; + on?: EventsFilter; + onTypeof: FilterOnType; + }> = []; + private mode: DEBUG_MODE = "development"; + private appId: string; + private cwd: string; + private sbPlugins: SBPlugins; private log: IPluginLogger; - private _activeEvents: EventsBase | undefined; - constructor(log: IPluginLogger) { - this.log = log; + + constructor( + appId: string, + mode: DEBUG_MODE, + cwd: string, + sbPlugins: SBPlugins, + sbLogging: SBLogging + ) { + this.appId = appId; + this.mode = mode; + this.cwd = cwd; + this.sbPlugins = sbPlugins; + const eventsPluginName = "core-events"; + this.log = new PluginLogger(this.mode, eventsPluginName, sbLogging); } public dispose() { - if (this._activeEvents !== undefined) this._activeEvents.dispose(); + for (let eventsIndex = 0; eventsIndex < this.events.length; eventsIndex++) { + if (this.events[eventsIndex].plugin.dispose !== undefined) + SmartFunctionCallSync( + this.events[eventsIndex].plugin, + this.events[eventsIndex].plugin.dispose + ); + } } - async setupEvents( - appId: string, - runningDebug: boolean, - runningLive: boolean, - cwd: string, - config: ConfigBase, - plugin: IReadyPlugin, - pluginLog: IPluginLogger + private getPluginsMatchingTriggerEvent( + event: EventsEventTypes, + plugin: string ) { - await this.log.debug(`Import events plugin: {name} from {file}`, { - name: plugin.name, - file: plugin.pluginFile, + return this.events.find((eventPlugin) => { + if (Tools.isNullOrUndefined(eventPlugin.plugin)) return false; + if (Tools.isNullOrUndefined(eventPlugin.on)) return true; + switch (eventPlugin.onTypeof) { + case "all": + return true; + case "events": + return (eventPlugin.on as Array).includes(event); + case "eventsState": + if ( + Tools.isNullOrUndefined( + (eventPlugin.on as Record)[event] + ) + ) + return false; + return (eventPlugin.on as Record)[event]; + case "eventsPlugins": + if ( + Tools.isNullOrUndefined( + (eventPlugin.on as Record>)[event] + ) + ) + return false; + return (eventPlugin.on as Record>)[ + event + ].includes(plugin); + case "eventsDetailed": + if ( + Tools.isNullOrUndefined( + (eventPlugin.on as EventsFilterDetailed)[event] + ) + ) + return false; + if ((eventPlugin.on as EventsFilterDetailed)[event].enabled !== true) + return false; + return (eventPlugin.on as EventsFilterDetailed)[ + event + ].plugins.includes(plugin); + } + }); + } + + private getPluginForEvent( + eventAs: EventsEventTypes, + plugin: string, + event: string + ): { + pluginName: string; + plugin: BSBEvents; + } { + let matchingEvent = this.getPluginsMatchingTriggerEvent(eventAs, plugin); + if (matchingEvent === undefined) + throw new BSBError( + "SBEvents-triggerEvent", + "No plugins found to match event: plugin: {plugin} - eventAs: {eventAs} - event: {event}", + { eventAs, plugin, event } + ); + return { + plugin: matchingEvent.plugin, + pluginName: matchingEvent.name, + }; + } + public async init(sbConfig: SBConfig, sbLogging: SBLogging) { + this.log.debug("INIT SBEvents"); + let plugins = await sbConfig.getEventsPlugins(); + for (let plugin of Object.keys(plugins)) { + await this.addEvents( + sbConfig, + sbLogging, + { + name: plugin, + package: plugins[plugin].package, + plugin: plugins[plugin].plugin, + version: "", + }, + plugins[plugin].filter + ); + } + this.log.info('Adding "events-default" as events'); + this.events.push({ + name: "events-default", + plugin: new DefaultEvents({ + appId: this.appId, + mode: this.mode, + pluginName: "events-default", + cwd: this.cwd, + pluginCwd: this.cwd, + config: {}, + sbLogging, + }), + on: undefined, + onTypeof: "all", }); - const importedPlugin = await import(plugin.pluginFile); + } - await this.log.debug(`Construct events plugin: {name}`, { + private async addEvents( + sbConfig: SBConfig, + sbLogging: SBLogging, + plugin: IPluginDefinition, + filter?: EventsFilter + ) { + this.log.debug("Add events {name} from ({package}){file}", { + package: plugin.package ?? "this project", name: plugin.name, + file: plugin.plugin, + }); + if (plugin.name === "events-default") return; + this.log.debug(`Import events plugin: {name} from ({package}){file}`, { + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, }); - let eventsPlugin = - new (importedPlugin.Events as unknown as typeof EventsBase)( - plugin.mappedName, - cwd, - plugin.pluginDir, - pluginLog + const newPlugin = await this.sbPlugins.loadPlugin<"events">( + this.log, + plugin.package ?? null, + plugin.plugin, + plugin.name + ); + if (newPlugin === null) { + this.log.error( + "Failed to import events plugin: {name} from ({package}){file}", + { + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, + } ); - await this.log.debug(`Create events plugin: {name}`, { + return; + } + + this.log.debug(`Get plugin config: {name}`, { name: plugin.name, }); - await this.log.info( - "Setting up {pluginName} ({mappedName}) as new base events platform", - { - pluginName: plugin.name, - mappedName: plugin.mappedName, - } - ); - await this.log.info("Builing {pluginName} as new base events platform", { + const pluginConfig = await sbConfig.getPluginConfig("events", plugin.name); + + this.log.debug(`Construct events plugin: {name}`, { + name: plugin.name, + }); + + let eventsPlugin = new newPlugin.plugin({ + appId: this.appId, + mode: this.mode, + pluginName: newPlugin.name, + cwd: this.cwd, + pluginCwd: newPlugin.pluginCWD, + config: pluginConfig, + sbLogging, + }); + this.log.info("Adding {pluginName} as events with filter: ", { pluginName: plugin.name, + //filters: filter }); - SBBase.setupPlugin(appId, runningDebug, runningLive, eventsPlugin, config); + let eventAsType: FilterOnType = "all"; - this._activeEvents = eventsPlugin; - await this._activeEvents.init(); - await this.log.info( - "Ready {pluginName} ({mappedName}) as new base events platform", - { - pluginName: plugin.name, - mappedName: plugin.mappedName, + if (filter) { + if (Array.isArray(filter)) { + eventAsType = "events"; + } else if (typeof filter === "object") { + const methods = Object.keys(EventsEventTypesBase); + for (let method of methods) { + if (filter.hasOwnProperty(method)) { + const methodValue = filter[method as keyof typeof filter]; + if (typeof methodValue === "boolean") { + eventAsType = "eventsState"; + } else if (Array.isArray(methodValue)) { + eventAsType = "eventsPlugins"; + } else if (typeof methodValue === "object") { + eventAsType = "eventsDetailed"; + } + } + } } - ); - if (this._activeEvents === null) { - console.log("x"); } + this.events.unshift({ + plugin: eventsPlugin, + on: filter, + onTypeof: eventAsType, + name: plugin.name, + }); + + this.log.info("Ready {pluginName} ({mappedName})", { + pluginName: plugin.plugin, + mappedName: plugin.name, + }); + + await SmartFunctionCallAsync(eventsPlugin, eventsPlugin.init); } - generateEventsForService( + private async handleOnBroadcast( + eventsPluginName: string, pluginName: string, - mappedPluginName: string - ): IServiceEvents { + event: string, + context: BSBService | BSBServiceClient, + listener: { (...args: Array): Promise | void }, + iargs: Array + ) { + const start = process.hrtime(); + try { + await SmartFunctionCallAsync(context, listener, ...iargs); + let diff = process.hrtime(start); + this.log.reportStat( + `on-broadcast-${eventsPluginName}-${pluginName}-${event}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + } catch (exc: any) { + this.log.reportStat( + `on-broadcast-${eventsPluginName}-${pluginName}-${event}`, + -1 + ); + this.log.error("handleOnBroadcast error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } + } + public async onBroadcast( + context: BSBService | BSBServiceClient, + pluginName: string, + event: string, + listener: { (...args: Array): Promise | void } + ): Promise { const self = this; - return { - onBroadcast: async ( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise => { - await self._activeEvents!.onBroadcast( + const plugin = await this.getPluginForEvent( + "onBroadcast", + pluginName, + event + ); + plugin.plugin.onBroadcast(pluginName, event, async (iargs: Array) => + self.handleOnBroadcast.call( + self, + plugin.pluginName, + pluginName, + event, + context, + listener, + iargs + ) + ); + } + + public async emitBroadcast( + pluginName: string, + event: string, + ...args: Array + ): Promise { + const plugin = await this.getPluginForEvent( + "emitBroadcast", + pluginName, + event + ); + this.log.reportStat( + `emit-broadcast-${plugin.pluginName}-${pluginName}-${event}`, + 1 + ); + await SmartFunctionCallAsync( + plugin.plugin, + plugin.plugin.emitBroadcast, + pluginName, + event, + args + ); + } + + private async handleOnEvent( + eventsPluginName: string, + pluginName: string, + event: string, + context: BSBService | BSBServiceClient, + listener: { (...args: Array): Promise | void }, + iargs: Array + ) { + const start = process.hrtime(); + try { + //console.log("CALL ON EVENT", context, listener, iargs); + await SmartFunctionCallAsync(context, listener, ...iargs); + let diff = process.hrtime(start); + this.log.reportStat( + `on-event-${eventsPluginName}-${pluginName}-${event}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + } catch (exc: any) { + this.log.reportStat( + `on-event-${eventsPluginName}-${pluginName}-${event}`, + -1 + ); + this.log.error("handleOnEvent error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } + } + public async onEvent( + context: BSBService | BSBServiceClient, + pluginName: string, + event: string, + listener: { (...args: Array): Promise | void } + ): Promise { + const self = this; + const plugin = await this.getPluginForEvent("onEvent", pluginName, event); + plugin.plugin.onEvent(pluginName, event, async (iargs: Array) => + self.handleOnEvent.call( + self, + plugin.pluginName, + pluginName, + event, + context, + listener, + iargs + ) + ); + } + public async onEventSpecific( + serverId: string, + context: BSBService | BSBServiceClient, + pluginName: string, + event: string, + listener: { (...args: Array): Promise | void } + ): Promise { + const self = this; + const plugin = await this.getPluginForEvent("onEvent", pluginName, event); + plugin.plugin.onEvent( + pluginName, + event + "-" + serverId, + async (iargs: Array) => + self.handleOnEvent.call( + self, + plugin.pluginName, pluginName, - mappedPluginName, - args[0], - async (iargs: Array) => { - const start = process.hrtime(); - try { - await args[1](...iargs); - let diff = process.hrtime(start); - await self.log.reportStat( - `on-broadcast-${mappedPluginName}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - } catch (exc: any) { - await self.log.reportStat( - `on-broadcast-${mappedPluginName}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - } - ); - }, - emitBroadcast: async ( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise => { - let event = args.splice(0, 1)[0] as string; - await self._activeEvents!.emitBroadcast( + event + "-" + serverId, + context, + listener, + iargs + ) + ); + } + + public async emitEvent( + pluginName: string, + event: string, + ...args: Array + ): Promise { + const plugin = await this.getPluginForEvent("emitEvent", pluginName, event); + this.log.reportStat( + `emit-event-${plugin.pluginName}-${pluginName}-${event}`, + 1 + ); + await SmartFunctionCallAsync( + plugin.plugin, + plugin.plugin.emitEvent, + pluginName, + event, + args + ); + } + public async emitEventSpecific( + serverId: string, + pluginName: string, + event: string, + ...args: Array + ): Promise { + const plugin = await this.getPluginForEvent("emitEvent", pluginName, event); + this.log.reportStat( + `emit-event-${plugin.pluginName}-${pluginName}-${event}-${serverId}`, + 1 + ); + await SmartFunctionCallAsync( + plugin.plugin, + plugin.plugin.emitEvent, + pluginName, + event + "-" + serverId, + args + ); + } + + private async handleOnReturnableEvent( + eventsPluginName: string, + pluginName: string, + event: string, + context: BSBService | BSBServiceClient, + listener: { (...args: Array): Promise | any }, + iargs: Array + ) { + const start = process.hrtime(); + try { + const resp = await SmartFunctionCallAsync(context, listener, ...iargs); + let diff = process.hrtime(start); + this.log.reportStat( + `on-returnableevent-${eventsPluginName}-${pluginName}-${event}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + return resp; + } catch (exc: any) { + this.log.reportStat( + `on-returnableevent-${eventsPluginName}-${pluginName}-${event}`, + -1 + ); + this.log.error("handleOnReturnableEvent error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } + } + public async onReturnableEvent( + context: BSBService | BSBServiceClient, + pluginName: string, + event: string, + listener: { (...args: Array): Promise | void } + ): Promise { + const self = this; + const plugin = await this.getPluginForEvent( + "onReturnableEvent", + pluginName, + event + ); + plugin.plugin.onReturnableEvent( + pluginName, + event, + async (iargs: Array) => + self.handleOnReturnableEvent.call( + self, + plugin.pluginName, pluginName, - mappedPluginName, event, - args - ); - }, - onEvent: async ( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise => { - await self._activeEvents!.onEvent( - pluginName, - mappedPluginName, - args[0], - async (iargs: Array) => { - const start = process.hrtime(); - try { - await args[1](...iargs); - let diff = process.hrtime(start); - await self.log.reportStat( - `on-event-${mappedPluginName}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - } catch (exc: any) { - await self.log.reportStat( - `on-event-${mappedPluginName}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - } - ); - }, - onEventSpecific: async (serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ): Promise => { - await self._activeEvents!.onEvent( - pluginName, - `${mappedPluginName}-${serverId}`, - args[0], - async (iargs: Array) => { - const start = process.hrtime(); - try { - await args[1](...iargs); - let diff = process.hrtime(start); - await self.log.reportStat( - `on-event-${mappedPluginName}-${serverId}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - } catch (exc: any) { - await self.log.reportStat( - `on-event-${mappedPluginName}-${serverId}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - } - ); - }, - emitEvent: async ( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise => { - let event = args.splice(0, 1)[0] as string; - await self._activeEvents!.emitEvent( + context, + listener, + iargs + ) + ); + } + public async onReturnableEventSpecific( + serverId: string, + context: BSBService | BSBServiceClient, + pluginName: string, + event: string, + listener: { (...args: Array): Promise | void } + ): Promise { + const self = this; + const plugin = await this.getPluginForEvent( + "onReturnableEvent", + pluginName, + event + ); + plugin.plugin.onReturnableEvent( + pluginName, + event + "-" + serverId, + async (iargs: Array) => + self.handleOnReturnableEvent.call( + self, + plugin.pluginName, pluginName, - mappedPluginName, - event, - args - ); - }, - emitEventSpecific: async (serverId: string, - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ): Promise => { - let event = args.splice(0, 1)[0] as string; - await self._activeEvents!.emitEvent( + event + "-" + serverId, + context, + listener, + iargs + ) + ); + } + public async emitEventAndReturn( + pluginName: string, + event: string, + timeoutSeconds: number, + ...args: Array + ): Promise { + const start = process.hrtime(); + const plugin = await this.getPluginForEvent( + "emitEventAndReturn", + pluginName, + event + ); + try { + const resp = await SmartFunctionCallAsync( + plugin.plugin, + plugin.plugin.emitEventAndReturn, + pluginName, + event, + timeoutSeconds, + args + ); + let diff = process.hrtime(start); + this.log.reportStat( + `emit-eventandreturn-${plugin.pluginName}-${pluginName}-${event}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + return resp; + } catch (exc: any) { + this.log.reportStat( + `emit-eventandreturn-${plugin.pluginName}-${pluginName}-${event}`, + -1 + ); + this.log.error("emitEventAndReturn error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } + } + public async emitEventAndReturnSpecific( + serverId: string, + pluginName: string, + event: string, + timeoutSeconds: number, + ...args: Array + ): Promise { + const start = process.hrtime(); + const plugin = await this.getPluginForEvent( + "emitEventAndReturn", + pluginName, + event + ); + try { + const resp = await SmartFunctionCallAsync( + plugin.plugin, + plugin.plugin.emitEventAndReturn, + pluginName, + event + "-" + serverId, + timeoutSeconds, + args + ); + let diff = process.hrtime(start); + this.log.reportStat( + `emit-eventandreturn-${plugin.pluginName}-${pluginName}-${event}-${serverId}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + return resp; + } catch (exc: any) { + this.log.reportStat( + `emit-eventandreturn-${plugin.pluginName}-${pluginName}-${event}-${serverId}`, + -1 + ); + this.log.error("emitEventAndReturnSpecific error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } + } + + private async handleOnReceiveStream( + eventsPluginName: string, + pluginName: string, + event: string, + context: BSBService | BSBServiceClient, + listener: { (error: Error | null, stream: Readable): Promise }, + error: Error | null, + stream: Readable + ) { + const start = process.hrtime(); + try { + const resp = await SmartFunctionCallAsync( + context, + listener, + error, + stream + ); + let diff = process.hrtime(start); + this.log.reportStat( + `receivestream-${eventsPluginName}-${pluginName}-${event}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + return resp; + } catch (exc: any) { + this.log.reportStat( + `receivestream-${eventsPluginName}-${pluginName}-${event}`, + -1 + ); + this.log.error("handleOnReceiveStream error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } + } + public async receiveStream( + context: BSBService | BSBServiceClient, + pluginName: string, + event: string, + listener: { (error: Error | null, stream: Readable): Promise }, + timeoutSeconds?: number + ): Promise { + const self = this; + const plugin = await this.getPluginForEvent( + "receiveStream", + pluginName, + event + ); + return await plugin.plugin.receiveStream( + event, + async (error: Error | null, stream: Readable) => + self.handleOnReceiveStream.call( + self, + plugin.pluginName, pluginName, - `${mappedPluginName}-${serverId}`, event, - args - ); - }, - onReturnableEvent: async ( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise => { - this._activeEvents!.onReturnableEvent( - pluginName, - mappedPluginName, - args[0], - async (iargs: Array) => { - const start = process.hrtime(); - try { - const data = await args[1](...iargs); - let diff = process.hrtime(start); - await self.log.reportStat( - `on-revent-${mappedPluginName}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat( - `on-revent-${mappedPluginName}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - } - ); - }, - onReturnableEventSpecific: async (serverId: string, - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ): Promise => { - this._activeEvents!.onReturnableEvent( - pluginName, - `${mappedPluginName}-${serverId}`, - args[0], - async (iargs: Array) => { - const start = process.hrtime(); - try { - const data = await args[1](...iargs); - let diff = process.hrtime(start); - await self.log.reportStat( - `on-revent-${mappedPluginName}-${serverId}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat( - `on-revent-${mappedPluginName}-${serverId}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - } - ); - }, - emitEventAndReturn: async ( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): Promise => { - const start = process.hrtime(); - try { - let event = args.splice(0, 1)[0] as string; - const data = this._activeEvents!.emitEventAndReturn( - pluginName, - mappedPluginName, - event, - 15, - args - ); - let diff = process.hrtime(start); - await self.log.reportStat( - `emit-revent-${mappedPluginName}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat( - `emit-revent-${mappedPluginName}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - }, - emitEventAndReturnSpecific: async (serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ): Promise => { - const start = process.hrtime(); - try { - let event = args.splice(0, 1)[0] as string; - const data = this._activeEvents!.emitEventAndReturn( - pluginName, - `${mappedPluginName}-${serverId}`, - event, - 15, - args - ); - let diff = process.hrtime(start); - await self.log.reportStat( - `emit-revent-${mappedPluginName}-${serverId}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat( - `emit-revent-${mappedPluginName}-${serverId}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - }, - emitEventAndReturnTimed: async ( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): Promise => { - const start = process.hrtime(); - try { - let event = args.splice(0, 1)[0] as string; - let timeoutSeconds = args.splice(0, 1)[0] as number; - const data = this._activeEvents!.emitEventAndReturn( - pluginName, - mappedPluginName, - event, - timeoutSeconds, - args - ); - let diff = process.hrtime(start); - await self.log.reportStat( - `emit-rtevent-${mappedPluginName}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat( - `emit-rtevent-${mappedPluginName}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - }, - emitEventAndReturnTimedSpecific: async (serverId: string, - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ): Promise => { - const start = process.hrtime(); - try { - let event = args.splice(0, 1)[0] as string; - let timeoutSeconds = args.splice(0, 1)[0] as number; - const data = this._activeEvents!.emitEventAndReturn( - pluginName, - `${mappedPluginName}-${serverId}`, - event, - timeoutSeconds, - args - ); - let diff = process.hrtime(start); - await self.log.reportStat( - `emit-rtevent-${mappedPluginName}-${serverId}-${args[0]}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat( - `emit-rtevent-${mappedPluginName}-${serverId}-${args[0]}`, - -1 - ); - await self.log.error(exc); - throw exc; - } - }, - receiveStream: async ( - listener: { (error: Error | null, stream: Readable): Promise }, - timeoutSeconds?: number - ): Promise => { - const start = process.hrtime(); - try { - const data = await self._activeEvents!.receiveStream( - mappedPluginName, - listener, - timeoutSeconds - ); - let diff = process.hrtime(start); - await self.log.reportStat( - `receive-stream-${mappedPluginName}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return data; - } catch (exc: any) { - await self.log.reportStat(`receive-stream-${mappedPluginName}`, -1); - await self.log.error(exc); - throw exc; - } - }, - sendStream: async (streamId: string, stream: Readable): Promise => { - const start = process.hrtime(); - try { - await self._activeEvents!.sendStream( - mappedPluginName, - streamId, - stream - ); - let diff = process.hrtime(start); - await self.log.reportStat( - `receive-stream-${mappedPluginName}`, - (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS - ); - return; - } catch (exc: any) { - await self.log.reportStat(`receive-stream-${mappedPluginName}`, -1); - await self.log.error(exc); - throw exc; - } - }, - }; + context, + listener, + error, + stream + ), + timeoutSeconds + ); + } + public async sendStream( + pluginName: string, + event: string, + streamId: string, + stream: Readable + ): Promise { + const start = process.hrtime(); + const plugin = await this.getPluginForEvent( + "sendStream", + pluginName, + event + ); + try { + await SmartFunctionCallAsync( + plugin.plugin, + plugin.plugin.sendStream, + event, + streamId, + stream + ); + let diff = process.hrtime(start); + this.log.reportStat( + `sendstream-${plugin.pluginName}-${pluginName}-${event}`, + (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS + ); + } catch (exc: any) { + this.log.reportStat( + `sendstream-${plugin.pluginName}-${pluginName}-${event}`, + -1 + ); + this.log.error("sendStream error occured: ${error}", { + error: exc.message ?? exc, + }); + throw exc; + } } } diff --git a/nodejs/src/serviceBase/index.ts b/nodejs/src/serviceBase/index.ts new file mode 100644 index 0000000..db215d0 --- /dev/null +++ b/nodejs/src/serviceBase/index.ts @@ -0,0 +1,7 @@ +export * from "./config"; +export * from "./events"; +export * from "../base/functions"; +export * from "./logging"; +export * from "./plugins"; +export * from "./serviceBase"; +export * from "./services"; diff --git a/nodejs/src/serviceBase/logger.ts b/nodejs/src/serviceBase/logger.ts deleted file mode 100644 index 59d0982..0000000 --- a/nodejs/src/serviceBase/logger.ts +++ /dev/null @@ -1,252 +0,0 @@ -import { LoggerBase } from "../logger/logger"; -import { IPluginLogger, LogMeta } from "../interfaces/logger"; -import { Logger as DefaultLogger } from "../plugins/log-default/plugin"; -import { SBBase } from "./base"; -import { ConfigBase } from "../config/config"; -import { Events as DefaultEvents } from "../plugins/events-default/plugin"; -import { IReadyPlugin } from "../interfaces/service"; - -export class SBLogger { - private log: IPluginLogger; - private _logger: DefaultLogger; - public _loggerEvents: DefaultEvents; - private _activeLogger: LoggerBase | undefined; - constructor( - appId: string, - runningDebug: boolean, - runningLive: boolean, - CORE_PLUGIN_NAME: string - ) { - this._logger = new DefaultLogger("default-logger", "./", "./", undefined!); - SBBase.setupPlugin( - appId, - runningDebug, - runningLive, - this._logger, - {} as any - ); - this._loggerEvents = new DefaultEvents( - "default-logger-events", - "./", - "./", - this.generateNullLoggerForPlugin() - ); - this.log = this.generateLoggerForPlugin(`${CORE_PLUGIN_NAME}-logger`); - } - - public dispose() { - if (this._activeLogger !== undefined) this._activeLogger.dispose(); - this._logger.dispose(); - } - - public async setupSelf() { - const self = this; - this._loggerEvents.onEvent( - "d", - "l", - "reportStat", - async (args: Array) => { - await (self._activeLogger || self._logger).reportStat( - args[0], - args[1], - args[2] - ); - } - ); - this._loggerEvents.onEvent( - "d", - "l", - "textStat", - async (args: Array) => { - await (self._activeLogger || self._logger).reportTextStat( - args[0], - args[1], - args[2], - args[3] - ); - } - ); - this._loggerEvents.onEvent("d", "l", "debug", async (args: Array) => { - await (self._activeLogger || self._logger).debug( - args[0], - args[1], - args[2], - args[3] - ); - }); - this._loggerEvents.onEvent("d", "l", "info", async (args: Array) => { - await (self._activeLogger || self._logger).info( - args[0], - args[1], - args[2], - args[3] - ); - }); - this._loggerEvents.onEvent("d", "l", "warn", async (args: Array) => { - await (self._activeLogger || self._logger).warn( - args[0], - args[1], - args[2], - args[3] - ); - }); - this._loggerEvents.onEvent("d", "l", "error", async (args: Array) => { - await (self._activeLogger || self._logger).error( - args[0], - args[1], - args[2], - args[3] - ); - }); - this._loggerEvents.onReturnableEvent( - "d", - "l", - "fatal", - async (args: Array) => { - await (self._activeLogger || self._logger).error( - args[0], - args[1], - args[2], - args[3] - ); - console.error("FATAL: EXIT"); - self._loggerEvents.emitEvent("d", "l", "fatal-e", []); - } - ); - await this.log.info("Logger event core ready."); - } - - async setupLogger( - appId: string, - runningDebug: boolean, - runningLive: boolean, - cwd: string, - config: ConfigBase, - plugin: IReadyPlugin - ) { - if (plugin.name === "log-default") return; - await this.log.debug(`Import logging plugin: {name} from {file}`, { - name: plugin.name, - file: plugin.pluginFile, - }); - const importedPlugin = await import(plugin.pluginFile); - - await this.log.debug(`Construct logging plugin: {name}`, { - name: plugin.name, - }); - - let loggerPlugin = - new (importedPlugin.Logger as unknown as typeof LoggerBase)( - plugin.mappedName, - cwd, - plugin.pluginDir, - this.generateLoggerForPlugin(plugin.mappedName) - ); - await this.log.debug(`Create logging plugin: {name}`, { - name: plugin.name, - }); - //const importedPlugin = await import(plugin.pluginFile); - await this.log.info( - "Setting up {pluginName} ({mappedName}) as new base logging platform", - { - pluginName: plugin.name, - mappedName: plugin.mappedName, - } - ); - await this.log.info("Builing {pluginName} as new base logging platform", { - pluginName: plugin.name, - }); - SBBase.setupPlugin(appId, runningDebug, runningLive, loggerPlugin, config); - - this._activeLogger = loggerPlugin; - await this._activeLogger.init(); - await this.log.info( - "Ready {pluginName} ({mappedName}) as new base logging platform", - { - pluginName: plugin.name, - mappedName: plugin.mappedName, - } - ); - } - private generateNullLoggerForPlugin(): IPluginLogger { - return { - reportStat: async (key, value): Promise => {}, - reportTextStat: async (message, meta, hasPIData): Promise => {}, - info: async (message, meta, hasPIData): Promise => {}, - warn: async (message, meta, hasPIData): Promise => {}, - error: async ( - message: any, - meta?: any, - hasPIData?: any - ): Promise => {}, - fatal: async ( - message: any, - meta?: any, - hasPIData?: any - ): Promise => {}, - debug: async (message, meta, hasPIData): Promise => {}, - }; - } - generateLoggerForPlugin(pluginName: string): IPluginLogger { - const self = this; - return { - reportStat: async (key, value): Promise => - await self._loggerEvents.emitEvent("d", "l", "reportStat", [ - pluginName, - key, - value, - ]), - reportTextStat: async (message, meta, hasPIData): Promise => - await self._loggerEvents.emitEvent("d", "l", "textStat", [ - pluginName, - message, - meta, - hasPIData, - ]), - info: async (message, meta, hasPIData): Promise => - await self._loggerEvents.emitEvent("d", "l", "info", [ - pluginName, - message, - meta, - hasPIData, - ]), - warn: async (message, meta, hasPIData): Promise => - await self._loggerEvents.emitEvent("d", "l", "warn", [ - pluginName, - message, - meta, - hasPIData, - ]), - error: async ( - messageOrError: string | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise => - await self._loggerEvents.emitEvent("d", "l", "error", [ - pluginName, - messageOrError, - meta, - hasPIData, - ]), - fatal: async ( - messageOrError: string | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise => { - await self._loggerEvents.emitEventAndReturn("d", "l", "fatal", 5, [ - pluginName, - messageOrError, - meta, - hasPIData, - ]); - }, - debug: async (message, meta, hasPIData): Promise => - await self._loggerEvents.emitEvent("d", "l", "debug", [ - pluginName, - message, - meta, - hasPIData, - ]), - }; - } -} diff --git a/nodejs/src/serviceBase/logging.ts b/nodejs/src/serviceBase/logging.ts new file mode 100644 index 0000000..8321b27 --- /dev/null +++ b/nodejs/src/serviceBase/logging.ts @@ -0,0 +1,324 @@ +import { + DEBUG_MODE, + IPluginLogger, + LogMeta, + LoggingEventTypes, + LoggingEventTypesBase, + LoggingEventTypesExlReportStat, +} from "../interfaces/logging"; +import { Plugin as DefaultLogger } from "../plugins/logging-default/plugin"; +import { BSBLogging } from "../base/logging"; +import { PluginLogger } from "../base/PluginLogger"; +import { EventEmitter } from "stream"; +import { + FilterOnType, + IPluginDefinition, + LoggingFilter, + LoggingFilterDetailed, +} from "../interfaces/plugins"; +import { SBPlugins } from "./plugins"; +import { SBConfig } from "./config"; +import { Tools } from "@bettercorp/tools"; +import { + SmartFunctionCallAsync, + SmartFunctionCallSync, +} from "../base/functions"; + +export class SBLogging { + private loggers: Array<{ + plugin: BSBLogging; + on?: LoggingFilter; + onTypeof: FilterOnType; + }> = []; + public logBus: EventEmitter = new EventEmitter(); + private mode: DEBUG_MODE = "development"; + private appId: string; + private cwd: string; + private sbPlugins: SBPlugins; + private log: IPluginLogger; + + constructor( + appId: string, + mode: DEBUG_MODE, + cwd: string, + sbPlugins: SBPlugins + ) { + this.appId = appId; + this.mode = mode; + this.cwd = cwd; + this.sbPlugins = sbPlugins; + this.loggers.push({ + plugin: new DefaultLogger({ + appId: this.appId, + mode: this.mode, + pluginName: "logging-default", + cwd: this.cwd, + pluginCwd: this.cwd, + config: {}, + }), + onTypeof: "all", + }); + const loggingPluginName = "core-logging"; + this.log = new PluginLogger(this.mode, loggingPluginName, this); + + if (this.mode !== "production") { + this.logBus.on("debug", (plugin, message, meta) => { + this.triggerLogEvent("debug", plugin, message, meta); + }); + } + this.logBus.on("reportStat", (plugin, key, value) => { + this.triggerLogEvent("reportStat", plugin, key, value); + }); + this.logBus.on("reportTextStat", (plugin, message, meta) => { + this.triggerLogEvent("reportTextStat", plugin, message, meta); + }); + this.logBus.on("info", (plugin, message, meta) => { + this.triggerLogEvent("info", plugin, message, meta); + }); + this.logBus.on("warn", (plugin, message, meta) => { + this.triggerLogEvent("warn", plugin, message, meta); + }); + this.logBus.on("error", (plugin, message, meta) => { + this.triggerLogEvent("error", plugin, message, meta); + }); + } + + public dispose() { + for ( + let loggerIndex = 0; + loggerIndex < this.loggers.length; + loggerIndex++ + ) { + if (this.loggers[loggerIndex].plugin.dispose !== undefined) + SmartFunctionCallSync( + this.loggers[loggerIndex].plugin, + this.loggers[loggerIndex].plugin.dispose + ); + } + this.logBus.removeAllListeners(); + } + + private getPluginsMatchingLogEvent(log: LoggingEventTypes, plugin: string) { + return this.loggers.filter((logger) => { + if (Tools.isNullOrUndefined(logger.plugin)) return false; + if (Tools.isNullOrUndefined(logger.on)) return true; + switch (logger.onTypeof) { + case "all": + return true; + case "events": + return (logger.on as Array).includes(log); + case "eventsState": + if ( + Tools.isNullOrUndefined( + (logger.on as Record)[log] + ) + ) + return false; + return (logger.on as Record)[log]; + case "eventsPlugins": + if ( + Tools.isNullOrUndefined( + (logger.on as Record>)[log] + ) + ) + return false; + return (logger.on as Record>)[ + log + ].includes(plugin); + case "eventsDetailed": + if ( + Tools.isNullOrUndefined((logger.on as LoggingFilterDetailed)[log]) + ) + return false; + if ((logger.on as LoggingFilterDetailed)[log].enabled !== true) + return false; + return (logger.on as LoggingFilterDetailed)[log].plugins.includes( + plugin + ); + } + }); + } + + private async triggerLogEventReportStat( + loggerPlugin: BSBLogging, + plugin: string, + key: string, + value: number + ): Promise { + await SmartFunctionCallAsync( + loggerPlugin, + loggerPlugin.reportStat, + plugin, + key, + value + ); + } + + private async triggerLogEvent( + logAs: "reportStat", + plugin: string, + key: string, + value: number + ): Promise; + private async triggerLogEvent( + logAs: LoggingEventTypesExlReportStat, + plugin: string, + message: T, + meta: LogMeta + ): Promise; + private async triggerLogEvent( + logAs: LoggingEventTypes, + plugin: string, + messageOrKey: T | string, + metaOrValue: LogMeta | number + ): Promise { + for (let logger of this.getPluginsMatchingLogEvent(logAs, plugin)) { + if (logAs === "reportStat") { + await this.triggerLogEventReportStat( + logger.plugin, + plugin, + messageOrKey as string, + metaOrValue as number + ); + continue; + } + + let method; + switch (logAs) { + case "reportTextStat": + method = logger.plugin.reportTextStat; + break; + case "debug": + method = logger.plugin.debug; + break; + case "info": + method = logger.plugin.info; + break; + case "warn": + method = logger.plugin.warn; + break; + case "error": + method = logger.plugin.error; + break; + } + + if (method) { + await SmartFunctionCallAsync( + logger.plugin, + method, + plugin, + messageOrKey as string, + metaOrValue as LogMeta + ); + } + } + } + public async init(sbConfig: SBConfig) { + this.log.debug("INIT SBLogging"); + let plugins = await sbConfig.getLoggingPlugins(); + for (let plugin of Object.keys(plugins)) { + await this.addLogger( + sbConfig, + { + name: plugin, + package: plugins[plugin].package, + plugin: plugins[plugin].plugin, + version: "", + }, + plugins[plugin].filter + ); + } + } + + private async addLogger( + sbConfig: SBConfig, + plugin: IPluginDefinition, + filter?: LoggingFilter + ) { + this.log.debug("Add logger {name} from ({package}){file}", { + package: plugin.package ?? "-", + name: plugin.name, + file: plugin.plugin, + }); + if (plugin.name === "logging-default") return; + this.log.debug(`Import logging plugin: {name} from ({package}){file}`, { + package: plugin.package ?? "-", + name: plugin.name, + file: plugin.plugin, + }); + + const newPlugin = await this.sbPlugins.loadPlugin<"logging">( + this.log, + plugin.package ?? null, + plugin.plugin, + plugin.name + ); + if (newPlugin === null) { + this.log.error( + "Failed to import logging plugin: {name} from ({package}){file}", + { + package: plugin.package ?? "-", + name: plugin.name, + file: plugin.plugin, + } + ); + return; + } + + this.log.debug(`Get plugin config: {name}`, { + name: plugin.name, + }); + + const pluginConfig = await sbConfig.getPluginConfig("logging", plugin.name); + + this.log.debug(`Construct logging plugin: {name}`, { + name: plugin.name, + }); + + let loggerPlugin = new newPlugin.plugin({ + appId: this.appId, + mode: this.mode, + pluginName: newPlugin.name, + cwd: this.cwd, + pluginCwd: newPlugin.pluginCWD, + config: pluginConfig, + }); + this.log.info("Adding {pluginName} as logger with filter: ", { + pluginName: plugin.name, + //filters: filter + }); + let logAsType: FilterOnType = "all"; + + if (filter) { + if (Array.isArray(filter)) { + logAsType = "events"; + } else if (typeof filter === "object") { + const methods = Object.keys(LoggingEventTypesBase); + for (let method of methods) { + if (filter.hasOwnProperty(method)) { + const methodValue = filter[method as keyof typeof filter]; + if (typeof methodValue === "boolean") { + logAsType = "eventsState"; + } else if (Array.isArray(methodValue)) { + logAsType = "eventsPlugins"; + } else if (typeof methodValue === "object") { + logAsType = "eventsDetailed"; + } + } + } + } + } + this.loggers.push({ + plugin: loggerPlugin, + on: filter, + onTypeof: logAsType, + }); + + this.log.info("Ready {pluginName} ({mappedName})", { + pluginName: plugin.plugin, + mappedName: plugin.name, + }); + + await SmartFunctionCallAsync(loggerPlugin, loggerPlugin.init); + } +} diff --git a/nodejs/src/serviceBase/plugins.ts b/nodejs/src/serviceBase/plugins.ts index 321c836..521f3a2 100644 --- a/nodejs/src/serviceBase/plugins.ts +++ b/nodejs/src/serviceBase/plugins.ts @@ -1,354 +1,141 @@ -import { - readdirSync, - statSync, - existsSync, - readFileSync, - writeFileSync, -} from "fs"; +import { existsSync, readFileSync } from "fs"; import { join } from "path"; -import { IPluginLogger } from "../interfaces/logger"; -import { PluginDefinitions, IReadyPlugin, PluginDefinition } from "../interfaces/service"; -import { Tools } from "@bettercorp/tools"; +import { PluginType, PluginTypeDefinitionRef } from "../interfaces/plugins"; +import { IPluginLogger } from "../interfaces/logging"; +import { BSBError } from "../base/errorMessages"; export class SBPlugins { - public static getPluginType(name: string): PluginDefinition | null { - const pluginLow = name.toLowerCase(); - if (pluginLow.indexOf("service-") === 0) return PluginDefinitions.service; - if (pluginLow.indexOf("config-") === 0) return PluginDefinitions.config; - if (pluginLow.indexOf("events-") === 0) return PluginDefinitions.events; - if (pluginLow.indexOf("log-") === 0 || pluginLow.indexOf("logs-") === 0) - return PluginDefinitions.logging; - return null; - } - - private static async findPluginsFiles( - coreLogger: IPluginLogger, - path: string, - version: string, - libOnly = false, - pluginDir: string - ): Promise> { - const arrOfPlugins: Array = []; + protected cwd: string; + protected pluginDir: string; + protected devMode: boolean; - await coreLogger.debug(`FIND: FIND plugins in [{path}]`, { path }); - for (const dirPluginFolderName of readdirSync(path)) { - const thisFullPath = join(path, dirPluginFolderName); - if (!statSync(thisFullPath).isDirectory()) { - await coreLogger.debug(`FIND: IGNORE [{thisFullPath}] Not a DIR`, { - thisFullPath, - }); - continue; - } - if (dirPluginFolderName.indexOf("-") === 0) { - await coreLogger.debug( - `FIND: IGNORE [{thisFullPath}] Defined disabled`, - { thisFullPath } - ); - continue; - } - if (libOnly) { - if (dirPluginFolderName.indexOf("-test") >= 0) { - await coreLogger.debug( - `FIND: IGNORE [{thisFullPath}] Defined test plugin to ignore`, - { thisFullPath } - ); - continue; - } - } - - let pluginDef = SBPlugins.getPluginType(dirPluginFolderName); - if (pluginDef === null) { - await coreLogger.debug( - `FIND: NOT VALID [{dirPluginFolderName}] in: {thisFullPath}`, - { dirPluginFolderName, thisFullPath } - ); - continue; - } - - let pluginFile = join(thisFullPath, "plugin.js"); - if (!existsSync(pluginFile)) pluginFile = join(thisFullPath, "plugin.ts"); - - if (!existsSync(pluginFile)) { - await coreLogger.debug( - `FIND: IGNORE [{thisFullPath}] Not a valid plugin`, - { thisFullPath } - ); - continue; - } - - let pluginInstallerFile: string | null = join( - thisFullPath, - "sec.config.js" - ); - - if (!existsSync(pluginInstallerFile)) - pluginInstallerFile = join(thisFullPath, "sec.config.ts"); - - if (!existsSync(pluginInstallerFile)) pluginInstallerFile = null; - await coreLogger.debug( - `FIND: READY [{dirPluginFolderName}] in: {thisFullPath}`, - { dirPluginFolderName, thisFullPath } - ); - arrOfPlugins.push({ - pluginDefinition: pluginDef, - name: dirPluginFolderName, - mappedName: dirPluginFolderName, - version: version, - pluginFile, - installerFile: pluginInstallerFile, - pluginDir: pluginDir, - }); + constructor(cwd: string, devMode: boolean) { + this.cwd = cwd; + this.devMode = devMode; + if ( + typeof process.env.PLUGIN_DIR == "string" && + process.env.PLUGIN_DIR.length > 3 + ) { + this.pluginDir = process.env.PLUGIN_DIR; + } else { + this.pluginDir = join(this.cwd, "./node_modules/"); } - - return arrOfPlugins; } - private static async findDependentPlugins( + public async loadPlugin< + NamedType extends PluginType, + ClassType extends PluginTypeDefinitionRef = PluginTypeDefinitionRef + >( + log: IPluginLogger, + npmPackage: string | null, plugin: string, - coreLogger: IPluginLogger, - pluginJson: any, - npmPluginsDir: string, - knownDependencies: Record = {} - ) { - let arrOfPlugins: Array = []; - for (let dependency of Object.keys(pluginJson.dependencies || {})) { - if (knownDependencies[dependency] !== undefined) { - await coreLogger.info( - `FIND: CHECK [{plugin}] DEPENDENCY [{dependency}] IGNORED BECAUSE [{reason}]`, - { - dependency, - plugin, - reason: - knownDependencies[dependency] === true ? "EXISTS" : "INVALID", - } - ); - - continue; + name: string + ): Promise<{ + name: string; + ref: string; + version: string; + pluginFile: string; + installerFile: string | null; + plugin: ClassType; + pluginCWD: string; + pluginPath: string; + } | null> { + log.info(`PLUGIN {name} from {package} try load as {pluginName}`, { + name: plugin, + pluginName: name, + package: npmPackage ?? "self", + }); + const nodeModulesLib = npmPackage !== null; + let pluginPath = ""; + let pluginCWD = this.cwd; + let version = "0.0.0"; + if (!nodeModulesLib) { + if (this.devMode) { + pluginPath = join(this.cwd, "./src/plugins/" + plugin); + if (!existsSync(pluginPath)) pluginPath = ""; } - await coreLogger.info( - `FIND: CHECK [{plugin}] DEPENDENCY [{dependency}]`, - { dependency, plugin } + if (pluginPath == "") { + pluginPath = join(this.cwd, "./lib/plugins/" + plugin); + } + } else { + pluginCWD = join(this.pluginDir, npmPackage); + pluginPath = join(pluginCWD, "./lib/plugins/", plugin); + + const packageJsonPath = join(pluginCWD, "./package.json"); + const packageJSON = JSON.parse( + readFileSync(packageJsonPath, "utf-8").toString() ); - let path = dependency.split("/"); - let dependencyPath = join(npmPluginsDir, ...path); - await coreLogger.debug(`FIND: CHECK [{dependency}] {dependencyPath}`, { - dependency, - dependencyPath, + version = packageJSON.version; + } + if (!existsSync(pluginPath)) { + log.error(`PLUGIN {name} in {package} not found`, { + name: plugin, + package: npmPackage ?? "self", }); - if (statSync(dependencyPath).isDirectory()) { - let response = await SBPlugins.findPluginsInBase( - coreLogger, - dependencyPath, - true, - npmPluginsDir, - knownDependencies - ); - if (Tools.isArray(response)) { - knownDependencies[dependency] = false; - arrOfPlugins = arrOfPlugins.concat( - response as any as Array - ); - } else { - knownDependencies[dependency] = response.plugins.length > 0; - arrOfPlugins = arrOfPlugins.concat(response.plugins); - knownDependencies = { - ...knownDependencies, - ...(response.knownDependencies ?? {}), - }; - } - } + return null; } - return { - plugins: arrOfPlugins, - knownDependencies: knownDependencies, - }; - } + log.info(`Plugin {name}: attempt to load from {path} as {pluginName}`, { + name: plugin, + path: pluginPath, + pluginName: name, + }); - private static async findPluginsInBase( - coreLogger: IPluginLogger, - path: string, - libOnly: boolean - ): Promise>; - private static async findPluginsInBase( - coreLogger: IPluginLogger, - path: string, - libOnly: boolean, - findLinkedPluginsNpmDir: string, - knownDependencies: Record - ): Promise< - | { - plugins: Array; - knownDependencies: Record; + let pluginFile = join(pluginPath, "./plugin.js"); + let installerFile: string | null = null; + if (this.devMode) { + const tsPluginFile = join(pluginPath, "./plugin.ts"); + if (existsSync(tsPluginFile)) { + log.debug("PLUGIN {pluginName} running in development mode", { + pluginName: name, + }); + pluginFile = tsPluginFile; } - | Array - >; - private static async findPluginsInBase( - coreLogger: IPluginLogger, - path: string, - libOnly = false, - findLinkedPluginsNpmDir?: string, - knownDependencies?: Record - ): Promise< - | Array - | { - plugins: Array; - knownDependencies: Record; + // sec.config.ts + installerFile = join(pluginPath, "./sec.config.js"); + const tsInstallerFile = join(pluginPath, "./sec.config.ts"); + if (existsSync(tsInstallerFile)) { + log.debug("PLUGIN {pluginName} running development mode installer", { + pluginName: name, + }); + installerFile = tsInstallerFile; + } else if (!existsSync(installerFile)) { + log.debug("PLUGIN {pluginName} does not have an installer file", { + pluginName: name, + }); + installerFile = null; + } else { + log.debug("PLUGIN {pluginName} does not have an installer file", { + pluginName: name, + }); } - > { - const pluginJson = JSON.parse( - readFileSync(join(path, "./package.json"), "utf8").toString() - ); - if (pluginJson.bsb_project !== true) { - await coreLogger.debug("FIND: IGNORE AS NOT BSB PROJECT"); - return []; } - let innerPluginLib = join(path, "./src"); - if ( - libOnly || - !existsSync(innerPluginLib) || - !statSync(innerPluginLib).isDirectory() - ) { - innerPluginLib = join(path, "./lib"); - } - if ( - !existsSync(innerPluginLib) || - !statSync(innerPluginLib).isDirectory() - ) { - await coreLogger.debug( - `FIND: IGNORE [{innerPluginLib}] No src/lib dir in package`, - { innerPluginLib } - ); - return []; - } - const innerPluginLibPlugin = join(innerPluginLib, "./plugins"); - if ( - !existsSync(innerPluginLibPlugin) || - !statSync(innerPluginLibPlugin).isDirectory() - ) { - await coreLogger.debug( - `FIND: IGNORE [{innerPluginLibPlugin}] No inner plugins dir`, - { innerPluginLibPlugin } - ); - return []; - } - - const packageVersion = pluginJson.version; - let returnableListOfPlugins = await SBPlugins.findPluginsFiles( - coreLogger, - innerPluginLibPlugin, - packageVersion, - libOnly, - path - ); - if (Tools.isString(findLinkedPluginsNpmDir)) { - let response = await SBPlugins.findDependentPlugins( - pluginJson.name, - coreLogger, - pluginJson, - findLinkedPluginsNpmDir, - knownDependencies - ); - returnableListOfPlugins = returnableListOfPlugins.concat( - response.plugins - ); - return { - plugins: returnableListOfPlugins, - knownDependencies: response.knownDependencies ?? {}, - }; - } - - return returnableListOfPlugins; - } - - public static async findNPMPlugins( - coreLogger: IPluginLogger, - cwd: string - ): Promise> { - const pkgJsonFile = join(cwd, "./package.json"); - if (!existsSync(pkgJsonFile)) { - await coreLogger.error(`Unable to find package.json in {pakDir}`, { - pakDir: pkgJsonFile, + if (!existsSync(pluginFile)) + throw new BSBError("PLUGIN {pluginName} not found at {location}", { + pluginName: name, + location: pluginFile, }); - return []; - } - const pluginJson = JSON.parse(readFileSync(pkgJsonFile, "utf8").toString()); - const npmPluginsDir = join(cwd, "./node_modules"); - await coreLogger.info(`FIND: NPM plugins in: {npmPluginsDir}`, { - npmPluginsDir, - }); - if (!existsSync(npmPluginsDir)) { - await coreLogger.error( - `FIND: NPM plugins dir does not exist: {npmPluginsDir}`, - { npmPluginsDir } - ); - return []; - } - const knownDependenciesCacheFile = join( - npmPluginsDir, - "./.bsb-known-dependencies.json" - ); + const importedPlugin = await import(pluginFile); - let arrOfPlugins: Array = []; - if (existsSync(knownDependenciesCacheFile)) { - try { - let knownDependencies = JSON.parse( - readFileSync(knownDependenciesCacheFile, "utf8").toString() - ); - if (Object.keys(knownDependencies).length > 0) { - for (let dependency of Object.keys(knownDependencies)) { - if (knownDependencies[dependency] !== true) { - continue; - } - let response = await SBPlugins.findPluginsInBase( - coreLogger, - join(npmPluginsDir, dependency), - true - ); - arrOfPlugins = arrOfPlugins.concat(response); - } + if (importedPlugin.Plugin === undefined) + throw new BSBError( + "PLUGIN {pluginName} does not export a Plugin class - so possibly not a valid BSB Plugin", + { + pluginName: name, } - } catch (e: any) { - await coreLogger.error( - `Cannot read known dependencies: {knownDependenciesCacheFile}`, - { knownDependenciesCacheFile } - ); - } - } - if (arrOfPlugins.length === 0) { - let response = await SBPlugins.findDependentPlugins( - "self", - coreLogger, - pluginJson, - npmPluginsDir, - {} ); - setTimeout(async () => { - try { - writeFileSync( - knownDependenciesCacheFile, - JSON.stringify(response.knownDependencies, null, 2) - ); - } catch (e: any) { - await coreLogger.warn( - `Cannot cache known dependencies: {knownDependenciesCacheFile}`, - { knownDependenciesCacheFile } - ); - } - }, 1000); - arrOfPlugins = response.plugins; - } - return arrOfPlugins; - } - - public static async findLocalPlugins( - coreLogger: IPluginLogger, - cwd: string, - CLIONLY: boolean - ): Promise> { - return await SBPlugins.findPluginsInBase(coreLogger, cwd, CLIONLY); + return { + name: name, + ref: plugin, + version: version, + pluginFile, + installerFile: installerFile, + plugin: importedPlugin.Plugin, + pluginCWD: pluginCWD, + pluginPath: pluginPath, + }; } } diff --git a/nodejs/src/serviceBase/serviceBase.ts b/nodejs/src/serviceBase/serviceBase.ts index 5b0700d..e7675ab 100644 --- a/nodejs/src/serviceBase/serviceBase.ts +++ b/nodejs/src/serviceBase/serviceBase.ts @@ -1,16 +1,16 @@ -import { IPluginLogger, LogMeta } from "../interfaces/logger"; -import { SBLogger } from "./logger"; -import { PluginDefinitions, IReadyPlugin } from "../interfaces/service"; +import { DEBUG_MODE, IPluginLogger, LogMeta } from "../interfaces/logging"; +import { SBLogging } from "./logging"; import { SBPlugins } from "./plugins"; import { SBServices } from "./services"; import { IDictionary } from "@bettercorp/tools/lib/Interfaces"; import { SBConfig } from "./config"; -import path from "path"; -import fs from "fs"; -import { SBEvents } from "./events"; +//import { SBEvents } from "./events"; import { randomUUID } from "crypto"; import { hostname } from "os"; import { Tools } from "@bettercorp/tools/lib/Tools"; +import { PluginLogger } from "../base/PluginLogger"; +import { SmartFunctionCallSync } from "../base/functions"; +import { SBEvents } from "./events"; export const BOOT_STAT_KEYS = { BSB: "BSB", @@ -30,27 +30,27 @@ export const MS_PER_NS = 1e-6; const TIMEKEEPLOG = "[TIMER] {timerName} took ({nsTime}ns) ({msTime}ms)"; export class ServiceBase { - private _packJsonFile!: string; + /*private _packJsonFile!: string; private _bsbPackJsonFile!: string; private _appVersion: string = "0.0.1-debug"; - private _bsbVersion: string = "0.0.1-debug"; + private _bsbVersion: string = "0.0.1-debug";*/ - private _runningDebug: boolean = true; - private _runningLive: boolean = false; + private mode: DEBUG_MODE = "development"; private readonly _CORE_PLUGIN_NAME = "core"; private readonly _appId; - private _logger: SBLogger; - private _config!: SBConfig; - private _events!: SBEvents; - private _services!: SBServices; - - private plugins: Array = []; + private logging: SBLogging; + private plugins: SBPlugins; + private config: SBConfig; + private events: SBEvents; + private log: IPluginLogger; + private services!: SBServices; private cwd!: string; - private log!: IPluginLogger; - private _keeps: IDictionary<[number, number]> = {}; - private _heartbeat!: NodeJS.Timer; + private _keeps: IDictionary<[number, number]> = { + BSB: process.hrtime(), + }; + private _heartbeat!: ReturnType; private _startKeep(stepName: BootStatKeys) { if (this.log !== undefined) this.log.debug("Starting timer for {log}", { log: stepName }); @@ -66,19 +66,53 @@ export class ServiceBase { await this.log.info(TIMEKEEPLOG, logMeta); await this.log.reportStat(stepName, logMeta.nsTime as number); } - constructor(debug: boolean = true, live: boolean = false, cwd: string) { + constructor( + debug: boolean = true, // Enable debug logging (true): disabled debug logging + live: boolean = false, // Disable development mode (true): changes the way plugins are imported + cwd: string, // Current working directory: The current directory where you are running from + config: typeof SBConfig = SBConfig, // Config handler: Allows you to override default behavour, + plugins: typeof SBPlugins = SBPlugins, // Plugins handler: Allows you to override default behavour, + logging: typeof SBLogging = SBLogging, // Logging handler: Allows you to override default behavour, + events: typeof SBEvents = SBEvents, // Events handler: Allows you to override default behavour, + services: typeof SBServices = SBServices // Services handler: Allows you to override default behavour + ) { + this._startKeep(BOOT_STAT_KEYS.SELF); this.cwd = cwd; - this._runningDebug = debug; - this._runningLive = live; + if (live === false) this.mode = "development"; + else if (debug === true) this.mode = "production-debug"; + else this.mode = "production"; + this._appId = `${hostname()}-${randomUUID()}`; - this._startKeep(BOOT_STAT_KEYS.BSB); - // Initial boot will use the default logger which doesn't require anything special. - // Once plugin search has been completed, then we can find the defined logger, or re-create the default logger with the correct config definition. - this._logger = new SBLogger( + + this.plugins = new plugins(this.cwd, this.mode === "development"); + this.logging = new logging(this._appId, this.mode, this.cwd, this.plugins); + this.events = new events( + this._appId, + this.mode, + this.cwd, + this.plugins, + this.logging + ); + this.config = new config( this._appId, - this._runningDebug, - this._runningLive, - this._CORE_PLUGIN_NAME + this.mode, + this.cwd, + this.logging, + this.plugins + ); + + this.log = new PluginLogger( + this.mode, + this._CORE_PLUGIN_NAME, + this.logging + ); + this.log.info("Starting BSB"); + this.services = new services( + this._appId, + this.mode, + this.cwd, + this.plugins, + this.logging ); process.stdin.resume(); //so the program will not close instantly @@ -99,202 +133,54 @@ export class ServiceBase { process.on("uncaughtException", (e) => self.dispose(3, "uncaught exception", e) ); - } - public async setupSelf() { - this._startKeep(BOOT_STAT_KEYS.SELF); - await this._logger.setupSelf(); - const self = this; - await this._logger._loggerEvents.onEvent("d", "l", "fatal-e", async () => - self.dispose(4, "fatal event") - ); - this.log = this._logger.generateLoggerForPlugin(this._CORE_PLUGIN_NAME); - this._config = new SBConfig(this.log, this.cwd); - this._events = new SBEvents( - this._logger.generateLoggerForPlugin(this._CORE_PLUGIN_NAME + "-events") - ); - this._services = new SBServices( - this._logger.generateLoggerForPlugin(this._CORE_PLUGIN_NAME + "-services") - ); - await this.log.info("BOOT IN: {local}", { local: this.cwd }); - - this._packJsonFile = path.join(this.cwd, "./package.json"); - if (!fs.existsSync(this._packJsonFile)) { - await this.log.fatal("PACKAGE.JSON FILE NOT FOUND IN {cwd}", { - cwd: this.cwd, - }); - return; - } - this._appVersion = JSON.parse( - fs.readFileSync(this._packJsonFile, "utf8").toString() - ).version; - - this._bsbPackJsonFile = path.join( - this.cwd, - "./node_modules/@bettercorp/service-base/package.json" - ); - if (fs.existsSync(this._bsbPackJsonFile)) { - this._bsbVersion = JSON.parse( - fs.readFileSync(this._bsbPackJsonFile, "utf8").toString() - ).version; - } - - await this.log.info( - `BOOT UP: @{version} with BSB@{BSBVersion} and debugging {debugMode} while running {runningLive}`, - { - version: this._appVersion, - BSBVersion: this._bsbVersion, - debugMode: this._runningDebug, - runningLive: this._runningLive, - } - ); this._outputKeep(BOOT_STAT_KEYS.SELF); } - public async setupPlugins(cwd: string, CLIONLY = false): Promise { - this._startKeep(BOOT_STAT_KEYS.PLUGINS); - await this.log.info("INIT PLUGIN LOCATOR"); - let dirsToSearch: Array = [this.cwd]; - this.plugins = []; - if ( - process.env.BSB_CONTAINER == "true" && - `${process.env.BSB_PLUGIN_DIR || ""}` !== "" - ) { - await this.log.info( - "NOTE: RUNNING IN BSB CONTAINER - PLUGIN LOCATION ALTERED" - ); - dirsToSearch = dirsToSearch.concat( - (process.env.BSB_PLUGIN_DIR || "").split(",") - ); - } - if (dirsToSearch.length > 0) { - await this.log.info("Find all plugins: {dirs}", { - dirs: dirsToSearch, - }); - - for (let dir of dirsToSearch) { - await this.log.info("Find plugins: {dir}", { dir }); - this.plugins = this.plugins.concat( - await SBPlugins.findNPMPlugins(this.log, dir) - ); - } - } - await this.log.info(`Performing a node_modules local search.`); - this.plugins = this.plugins.concat( - await SBPlugins.findLocalPlugins(this.log, cwd, CLIONLY) - ); - - await this.log.info(`{len} plugins found: {plugins}`, { - len: this.plugins.length, - plugins: this.plugins.map((x) => x.name).join(","), - }); - for (let plugin of this.plugins) { - await this.log.debug(`Plugin {pluginName}: {pluginDir}`, { - pluginName: plugin.name, - pluginDir: plugin.pluginDir, - }); - } - - this._outputKeep(BOOT_STAT_KEYS.PLUGINS); - this.cwd = cwd; - } - - public async setupConfig() { + public async init() { this._startKeep(BOOT_STAT_KEYS.CONFIG); - await this._config.findConfigPlugin(this.plugins); - let configPluginName = this._config.getPluginName(); - await this._config.setupConfigPlugin( - this._logger.generateLoggerForPlugin(configPluginName), - this._appId, - this._runningDebug, - this._runningLive, - this.plugins - ); - this.plugins = await this._config.mapPlugins(this.plugins); + await this.config.init(); this._outputKeep(BOOT_STAT_KEYS.CONFIG); - } - public async setupLogger() { this._startKeep(BOOT_STAT_KEYS.LOGGER); - let loggingPlugin = await this._config.findPluginByType( - this.plugins, - "log-default", - PluginDefinitions.logging - ); - await this._config.ImportAndMigratePluginConfig(loggingPlugin); - await this._logger.setupLogger( - this._appId, - this._runningDebug, - this._runningLive, - this.cwd, - this._config.appConfig, - loggingPlugin - ); + await this.logging.init(this.config); this._outputKeep(BOOT_STAT_KEYS.LOGGER); - } - public async setupEvents() { this._startKeep(BOOT_STAT_KEYS.EVENTS); - let eventsPlugin = await this._config.findPluginByType( - this.plugins, - "events-default", - PluginDefinitions.events - ); - await this._config.ImportAndMigratePluginConfig(eventsPlugin); - await this._events.setupEvents( - this._appId, - this._runningDebug, - this._runningLive, - this.cwd, - this._config.appConfig, - eventsPlugin, - this._logger.generateLoggerForPlugin(eventsPlugin.mappedName) - ); + await this.events.init(this.config, this.logging); this._outputKeep(BOOT_STAT_KEYS.EVENTS); - } - public async setupServices() { + // SERVICES ORDERING this._startKeep(BOOT_STAT_KEYS.SERVICES); - const self = this; - await this._services.setupServicePlugins( - this._appId, - this._runningDebug, - this._runningLive, - this.cwd, - this.plugins, - this._config.appConfig, - (a) => self._config.ImportAndMigratePluginConfig(a), - (a, b) => self._events.generateEventsForService(a, b), - (a) => self._logger.generateLoggerForPlugin(a) - ); + await this.services.setup(this.config, this.logging, this.events); this._outputKeep(BOOT_STAT_KEYS.SERVICES); - } - public async initPlugins() { this._startKeep(BOOT_STAT_KEYS.INIT); - await this._services.servicesInit(this._config.appConfig); + await this.services.init(this.config); this._outputKeep(BOOT_STAT_KEYS.INIT); } - public async runPlugins() { + public async run() { this._startKeep(BOOT_STAT_KEYS.RUN); - await this._services.servicesRun(this._config.appConfig); + await this.services.run(this.config); + this.log.info("Disposing config for memory cleanup and safety"); + this.config.dispose(); this._outputKeep(BOOT_STAT_KEYS.RUN); + + this._heartbeat = setInterval( + async () => await this.heartBeat(), + 60 * 60 * 1000 + ); + await this.heartBeat(); + this._outputKeep(BOOT_STAT_KEYS.BSB); } private async heartBeat() { - await this.log.debug("[HEARTBEAT] ({appId}) ({time})", { + this.log.debug("[HEARTBEAT] ({appId}) ({time})", { appId: this._appId, time: new Date().toISOString(), }); } - async run() { - const self = this; - this._heartbeat = setInterval( - async () => await self.heartBeat(), - 60 * 60 * 1000 - ); - await self.heartBeat(); - this._outputKeep(BOOT_STAT_KEYS.BSB); - } + private _disposing: boolean = false; async dispose(eCode: number = 0, reason: string, extraData?: any) { + console.error(reason, extraData); if (this._disposing) return; this._disposing = true; @@ -319,18 +205,18 @@ export class ServiceBase { reason, } ); - if (!Tools.isNullOrUndefined(extraData)) await this.log.error(extraData); + //if (!Tools.isNullOrUndefined(extraData)) this.log.error(extraData); } clearInterval(this._heartbeat); try { await this.log.warn("Disposing services"); - this._services.dispose(); + SmartFunctionCallSync(this.services, this.services.dispose); await this.log.warn("Disposing events"); - this._events.dispose(); + //this.events.dispose(); await this.log.warn("Disposing config"); - this._config.dispose(); + //SmartFunctionCall(this.config.dispose); await this.log.warn("Disposing logger"); - this._logger.dispose(); + //SmartFunctionCall(this.logging.dispose); } catch (exc) { console.error(exc); console.error("Disposing forcefully!"); diff --git a/nodejs/src/serviceBase/services.ts b/nodejs/src/serviceBase/services.ts index 82f8bd7..dfde37b 100644 --- a/nodejs/src/serviceBase/services.ts +++ b/nodejs/src/serviceBase/services.ts @@ -1,153 +1,287 @@ -import { IPluginLogger } from "../interfaces/logger"; -import { PluginDefinitions, IReadyPlugin } from "../interfaces/service"; -import { IServiceEvents } from "../interfaces/events"; -import { SBBase } from "./base"; -import { ServicesBase } from "../service/service"; -import { ConfigBase } from "../config/config"; -import { ErrorMessages } from "../interfaces/static"; -import { ServicesClient } from '../'; +import { BSBService } from "../base/service"; +import { PluginLogger } from "../base/PluginLogger"; +import { IPluginLogger } from "../interfaces/logging"; +import { DEBUG_MODE } from "../interfaces/logging"; +import { SBConfig } from "./config"; +import { SBEvents } from "./events"; +import { SmartFunctionCallAsync, SmartFunctionCallSync } from "../base/functions"; +import { SBLogging } from "./logging"; +import { SBPlugins } from "./plugins"; +import { IPluginDefinition } from "../interfaces/plugins"; +import { BSBError } from "../base/errorMessages"; +import { BSBServiceClient } from "../base/serviceClient"; +import { PluginEvents } from "../base/PluginEvents"; export class SBServices { - private _activeServices: Array = []; + private _activeServices: Array = []; + + private mode: DEBUG_MODE = "development"; + private appId: string; + private cwd: string; + private sbPlugins: SBPlugins; private log: IPluginLogger; - constructor(log: IPluginLogger) { - this.log = log; + constructor( + appId: string, + mode: DEBUG_MODE, + cwd: string, + sbPlugins: SBPlugins, + sbLogging: SBLogging + ) { + this.appId = appId; + this.mode = mode; + this.cwd = cwd; + this.sbPlugins = sbPlugins; + const eventsPluginName = "core-services"; + this.log = new PluginLogger(this.mode, eventsPluginName, sbLogging); } + public dispose() { for (let service of this._activeServices) { this.log.warn("disposing {service}", { service: service.pluginName }); - if (service !== undefined) service.dispose(); + for (let client of service._clients) { + SmartFunctionCallSync(client, client.dispose); + } + SmartFunctionCallSync(service, service.dispose); } } - async setupServicePlugins( - appId: string, - runningDebug: boolean, - runningLive: boolean, - cwd: string, - plugins: Array, - appConfig: ConfigBase, - ImportAndMigratePluginConfig: { (plugin: IReadyPlugin): Promise }, - generateEventsForService: { - (pluginName: string, mappedPluginName: string): IServiceEvents< - any, - any, - any, - any, - any, - any - >; - }, - generateLoggerForPlugin: { (pluginName: string): IPluginLogger } + public async setup( + sbConfig: SBConfig, + sbLogging: SBLogging, + sbEvents: SBEvents ) { - for (let plugin of plugins) { - if (plugin.pluginDefinition !== PluginDefinitions.service) continue; - - await this.log.debug(`Import service plugin: {name} from {file}`, { - name: plugin.name, - file: plugin.pluginFile, + this.log.debug("SETUP SBServices"); + let plugins = await sbConfig.getServicePlugins(); + for (let plugin of Object.keys(plugins)) { + await this.addService(sbConfig, sbLogging, sbEvents, { + name: plugin, + package: plugins[plugin].package, + plugin: plugins[plugin].plugin, + version: "", }); - const importedPlugin = await import(plugin.pluginFile); + } + this.log.debug("SETUP SBServices: Completed"); + } - await this.log.debug(`Construct service plugin: {name}`, { - name: plugin.name, - }); + private setupPluginClient = async ( + sbConfig: SBConfig, + sbLogging: SBLogging, + sbEvents: SBEvents, + context: BSBService, + clientContext: BSBServiceClient + ): Promise => { + const contextPlugin = await sbConfig.getServicePluginDefinition( + clientContext.pluginName + ); + (clientContext as any)._pluginName = clientContext.pluginName; + (clientContext as any).pluginName = contextPlugin.name; + (clientContext as any).pluginEnabled = contextPlugin.enabled; + (clientContext as any).log = new PluginLogger( + this.mode, + contextPlugin.name, + sbLogging + ); + (clientContext as any).events = new PluginEvents( + this.mode, + sbEvents, + clientContext + ); + (context as any).initBeforePlugins = ( + context.initBeforePlugins ?? [] + ).concat(clientContext.initBeforePlugins ?? []); + (context as any).initAfterPlugins = (context.initAfterPlugins ?? []).concat( + clientContext.initAfterPlugins ?? [] + ); + (context as any).runBeforePlugins = (context.runBeforePlugins ?? []).concat( + clientContext.runBeforePlugins ?? [] + ); + (context as any).runAfterPlugins = (context.runAfterPlugins ?? []).concat( + clientContext.runAfterPlugins ?? [] + ); + }; - let servicePlugin = - new (importedPlugin.Service as unknown as typeof ServicesBase)( - plugin.mappedName, - cwd, - plugin.pluginDir, - generateLoggerForPlugin(plugin.mappedName) - ); - await this.log.debug(`Create service plugin: {name}`, { - name: plugin.name, - }); - //const importedPlugin = await import(plugin.pluginFile); - await this.log.info( - "Setting up {pluginName} ({mappedName}) as new base service platform", + private async mapServicePlugins( + sbConfig: SBConfig, + referencedPluginName: string, + ...sourcePluginsList: Array | undefined> + ): Promise> { + let outlist = []; + for (let pluginArr of sourcePluginsList.filter((x) => x !== undefined)) { + for (let plugin of pluginArr!) { + const pluginDef = await sbConfig.getServicePluginDefinition(plugin); + if (pluginDef.enabled !== true) + throw new BSBError( + "PLUGIN_NOT_ENABLED", + "The plugin {plugin} is not enabled for {pluginNeeded} to work.", + { + plugin: plugin, + pluginNeeded: referencedPluginName, + } + ); + outlist.push(pluginDef.name); + } + } + return outlist; + } + private async addService( + sbConfig: SBConfig, + sbLogging: SBLogging, + sbEvents: SBEvents, + plugin: IPluginDefinition + ) { + this.log.debug("Add service {name} from ({package}){file}", { + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, + }); + this.log.debug(`Import service plugin: {name} from ({package}){file}`, { + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, + }); + + const newPlugin = await this.sbPlugins.loadPlugin<"service">( + this.log, + plugin.package ?? null, + plugin.plugin, + plugin.name + ); + if (newPlugin === null) { + this.log.error( + "Failed to import service plugin: {name} from ({package}){file}", { - pluginName: plugin.name, - mappedName: plugin.mappedName, + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, } ); - await this.log.info("Builing {pluginName} as new base service platform", { + return; + } + + this.log.debug(`Get plugin config: {name}`, { + name: plugin.name, + }); + + const pluginConfig = await sbConfig.getPluginConfig("service", plugin.name); + + this.log.debug(`Construct service plugin: {name}`, { + name: plugin.name, + }); + + let servicePlugin = new newPlugin.plugin({ + appId: this.appId, + mode: this.mode, + pluginName: newPlugin.name, + cwd: this.cwd, + pluginCwd: newPlugin.pluginCWD, + config: pluginConfig, + sbLogging: sbLogging, + sbEvents: sbEvents, + }); + this.log.info("Adding {pluginName} as service", { + pluginName: plugin.name, + }); + + for (let client of servicePlugin._clients) { + this.log.info("Construct {pluginName} client {clientName}", { pluginName: plugin.name, + clientName: client.pluginName, }); - const self = this; - SBBase.setupPlugin( - appId, - runningDebug, - runningLive, + await this.setupPluginClient( + sbConfig, + sbLogging, + sbEvents, servicePlugin, - appConfig + client ); - await SBBase.setupServicePlugin( - servicePlugin, - await generateEventsForService(plugin.name, plugin.mappedName), - appConfig, - cwd, - plugin.pluginDir, - generateEventsForService, - generateLoggerForPlugin, - this.log, - async (pluginName: string, method: string, args: Array) => { - for (let plugin of self._activeServices) { - if (plugin.pluginName === pluginName) { - return await (plugin as any)[method](...args); - } - } - await self.log.error( - "Enable {pluginName} in order to call ({method}) from it", - { pluginName, method } - ); - throw ErrorMessages.ServicePluginNotCallableMethod; - } - ); - - await this.log.info( - "Setup {pluginName} ({mappedName}) referenced clients", + this.log.info( + "Setup {pluginName} client {asOriginalPluginName} as {clientName}", { pluginName: plugin.name, - mappedName: plugin.mappedName, + clientName: client.pluginName, + asOriginalPluginName: (client as any)._pluginName, } ); + } - for (let client of ((servicePlugin as any)._clients as Array)) { - await this.log.info( - "Setup {pluginName} ({mappedName}) references {clientPlugin}", + this._activeServices.push(servicePlugin); + + this.log.info("Ready {pluginName} ({mappedName})", { + pluginName: plugin.plugin, + mappedName: plugin.name, + }); + } + + private initPluginClient = async ( + sbConfig: SBConfig, + clientContext: BSBServiceClient + ): Promise => { + const contextPlugin = await sbConfig.getServicePluginDefinition( + (clientContext as any)._pluginName + ); + if (contextPlugin.enabled) { + const referencedServiceContext = this._activeServices.find( + (x) => x.pluginName === contextPlugin.name + ) as BSBService; + if (referencedServiceContext === undefined) { + throw new BSBError( + "The plugin {plugin} is not enabled so you cannot call methods from it", { - pluginName: plugin.name, - mappedName: plugin.mappedName, - clientPlugin: client.pluginName, + plugin: contextPlugin.name, } ); - await client._init(); - (client as any)._init = undefined; // specifically remove this method from the client so it cannot be re-called / removes from ram - await client.init(); - (client as any).init = undefined; // specifically remove this method from the client so it cannot be re-called / removes from ram } - - await this.log.info( - "Ready {pluginName} ({mappedName}) as new base service platform", - { - pluginName: plugin.name, - mappedName: plugin.mappedName, + if (referencedServiceContext.methods === null) { + throw new BSBError( + "The plugin {plugin} does not have any callable methods", + { + plugin: contextPlugin.name, + } + ); + } + (clientContext as any).callMethod = async ( + method: string, + ...args: Array + ) => { + if (referencedServiceContext.methods[method] === undefined) { + throw new BSBError( + "The plugin {plugin} does not have a method called {method}", + { + plugin: contextPlugin.name, + method, + } + ); } - ); - - await ImportAndMigratePluginConfig(plugin); - - this._activeServices.push(servicePlugin); + return SmartFunctionCallAsync( + referencedServiceContext, + referencedServiceContext.methods[method], + ...args + ); + }; } - } + await SmartFunctionCallSync(clientContext, clientContext.init); + }; - public async servicesInit(config: ConfigBase) { - await this.log.info("Init all services"); + public async init(sbConfig: SBConfig) { + this.log.info("Init all services"); + for (let service of this._activeServices) { + this.log.info("Mapping required plugins list for {plugin}", { + plugin: service.pluginName, + }); + (service as any).initBeforePlugins = await this.mapServicePlugins( + sbConfig, + service.pluginName, + service.initBeforePlugins + ); + (service as any).initAfterPlugins = await this.mapServicePlugins( + sbConfig, + service.pluginName, + service.initAfterPlugins ?? [] + ); + } + this.log.info("Defining service order"); let orderOfPlugins = await this.makeAfterRequired( - config, await this.makeBeforeRequired( - config, this._activeServices.map((x) => { return { name: x.pluginName, @@ -158,7 +292,7 @@ export class SBServices { }) ) ); - await this.log.debug("Services init default order: {initOrder}", { + this.log.debug("Services init default order: {initOrder}", { initOrder: this._activeServices .map( (x) => @@ -168,34 +302,33 @@ export class SBServices { ) .join(","), }); - await this.log.debug("Services init order: {initOrder}", { + this.log.debug("Services init order: {initOrder}", { initOrder: orderOfPlugins .map((x) => `[(${x.after.join(",")})${x.name}(${x.before.join(",")})]`) .join(","), }); for (let service of orderOfPlugins) { - await this.log.debug(`{plugin} init`, { + this.log.debug(`Init {plugin}`, { plugin: service.name, }); - await service.ref.init(); + for (let client of service.ref._clients) { + await this.initPluginClient(sbConfig, client); + } + SmartFunctionCallAsync(service.ref, service.ref.init); } } public async makeBeforeRequired( - config: ConfigBase, orderOfPlugins: { name: string; after: string[]; before: string[]; - ref: ServicesBase; + ref: BSBService; }[] ) { for (let i = 0; i < orderOfPlugins.length; i++) { if (orderOfPlugins[i].before.length === 0) continue; - for (let bPlugin of await this.parsePluginNamesToMappedNames( - config, - orderOfPlugins[i].before - )) + for (let bPlugin of orderOfPlugins[i].before) for (let j = 0; j < orderOfPlugins.length; j++) { if (orderOfPlugins[j].name == bPlugin) { orderOfPlugins[j].after.push(orderOfPlugins[i].name); @@ -204,38 +337,17 @@ export class SBServices { } return orderOfPlugins; } - private async parsePluginNamesToMappedNames( - config: ConfigBase, - plugins: Array - ): Promise> { - for (let pIndex = 0; pIndex < plugins.length; pIndex++) { - plugins[pIndex] = await config.getAppPluginMappedName(plugins[pIndex]); - } - return plugins; - } public async makeAfterRequired( - config: ConfigBase, orderOfPlugins: { name: string; after: string[]; before: string[]; - ref: ServicesBase; + ref: BSBService; }[] ) { for (let i = 0; i < orderOfPlugins.length - 1; i++) { for (let j = i + 1; j < orderOfPlugins.length; j++) { - if ( - ( - await this.parsePluginNamesToMappedNames( - config, - orderOfPlugins[i].after - ) - ).indexOf(orderOfPlugins[j].name) >= 0 - ) { - await this.log.debug(`{plugin} run after {reqName}`, { - plugin: orderOfPlugins[i].name, - reqName: orderOfPlugins[j].name, - }); + if (orderOfPlugins[i].after.indexOf(orderOfPlugins[j].name) >= 0) { const temp = orderOfPlugins[i]; orderOfPlugins[i] = orderOfPlugins[j]; orderOfPlugins[j] = temp; @@ -245,42 +357,59 @@ export class SBServices { return orderOfPlugins; } - public async servicesRun(config: ConfigBase) { - await this.log.info("Run all services"); + public async run(sbConfig: SBConfig) { + this.log.info("Run all services"); + for (let service of this._activeServices) { + this.log.info("Mapping required plugins list for {plugin}", { + plugin: service.pluginName, + }); + (service as any).runBeforePlugins = await this.mapServicePlugins( + sbConfig, + service.pluginName, + service.runBeforePlugins ?? [] + ); + (service as any).runAfterPlugins = await this.mapServicePlugins( + sbConfig, + service.pluginName, + service.runAfterPlugins ?? [] + ); + } + this.log.info("Defining service order"); let orderOfPlugins = await this.makeAfterRequired( - config, await this.makeBeforeRequired( - config, this._activeServices.map((x) => { return { name: x.pluginName, - after: x.runAfterPlugins || [], - before: x.runBeforePlugins || [], + after: x.runBeforePlugins || [], + before: x.runAfterPlugins || [], ref: x, }; }) ) ); - await this.log.debug("Services run default order: {initOrder}", { - initOrder: this._activeServices + this.log.debug("Services run default order: {runOrder}", { + runOrder: this._activeServices .map( (x) => - `[(${(x.runAfterPlugins || []).join(",")})${x.pluginName}(${( - x.runBeforePlugins || [] + `[(${(x.runBeforePlugins || []).join(",")})${x.pluginName}(${( + x.runAfterPlugins || [] ).join(",")})]` ) .join(","), }); - await this.log.debug("Services run order: {initOrder}", { - initOrder: orderOfPlugins - .map((x) => `[${x.after.join(",")}=>${x.name}=>${x.before.join(",")}]`) + this.log.debug("Services run order: {runOrder}", { + runOrder: orderOfPlugins + .map((x) => `[(${x.after.join(",")})${x.name}(${x.before.join(",")})]`) .join(","), }); for (let service of orderOfPlugins) { - await this.log.debug(`{plugin} run`, { + this.log.debug(`Run {plugin}`, { plugin: service.name, }); - await service.ref.run(); + for (let client of service.ref._clients) { + SmartFunctionCallAsync(client, client.run); + } + SmartFunctionCallAsync(service.ref, service.ref.run); } } } diff --git a/nodejs/src/tests/base/PluginEvents.ts b/nodejs/src/tests/base/PluginEvents.ts new file mode 100644 index 0000000..f7f61f6 --- /dev/null +++ b/nodejs/src/tests/base/PluginEvents.ts @@ -0,0 +1,42 @@ +// import { PluginEvents, BSBService } from '../../base'; +// import { SBEvents } from '../../serviceBase'; + + +// describe('PluginEvents', () => { +// let pluginEvents: PluginEvents; +// let sbEvents: SBEvents; +// let bsbService: BSBService; + +// beforeEach(() => { +// // Initialize your SBEvents and BSBService here +// sbEvents = new SBEvents(); +// bsbService = new BSBService(); +// pluginEvents = new PluginEvents("development",); +// }); + +// describe('onBroadcast', () => { +// it('should register an event listener', async () => { +// const event = 'testEvent'; +// const listener = async () => {}; + +// await pluginEvents.onBroadcast(event, listener); + +// // Here you need to check if the listener has been registered correctly +// // This depends on your implementation of SBEvents and BSBService +// }); +// }); + +// describe('emitBroadcast', () => { +// it('should emit an event', async () => { +// const event = 'testEvent'; +// const args = ['arg1', 'arg2']; + +// await pluginEvents.emitBroadcast(event, ...args); + +// // Here you need to check if the event has been emitted correctly +// // This depends on your implementation of SBEvents and BSBService +// }); +// }); + +// // Similar tests can be written for onEvent, emitEvent, onEventSpecific, emitEventSpecific +// }); diff --git a/nodejs/src/tests/events/events.ts b/nodejs/src/tests/events/events.ts index b2645f7..14a4c72 100644 --- a/nodejs/src/tests/events/events.ts +++ b/nodejs/src/tests/events/events.ts @@ -1,105 +1,103 @@ -import assert from "assert"; -import { EventsBase } from "../../../src/events/events"; -import { ErrorMessages } from "../../../src/interfaces/static"; +// import assert from "assert"; -describe("EventsBase", function () { - describe("Constructor", async function () { - it("Should construct correctly [pluginName]", async () => { - let myobj = new EventsBase("pluginNameX", "cwd", "pluginCwd", {} as any); - assert.strictEqual(myobj.pluginName, "pluginNameX"); - }); - it("Should construct correctly [cwd]", async () => { - let myobj = new EventsBase("pluginNameX", "cwdD", "pluginCwd", {} as any); - assert.strictEqual((myobj as any).cwd, "cwdD"); - }); - it("Should construct correctly [pluginCwd]", async () => { - let myobj = new EventsBase( - "pluginNameX", - "cwdD", - "pluginCwdY", - {} as any - ); - assert.strictEqual((myobj as any).pluginCwd, "pluginCwdY"); - }); - it("Should construct correctly [logger]", async () => { - let myobj = new EventsBase("pluginNameX", "cwdD", "pluginCwdY", { - alog: true, - } as any); - assert.strictEqual((myobj as any).log.alog, true); - }); - }); - describe("Default methods", function () { - it("onBroadcast should throw", async () => { - try { - let myobj = new EventsBase("a", "b", "c", {} as any); - await myobj.onBroadcast("a", "b", "c", async () => {}); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); - } - }); - it("emitBroadcast should throw", async () => { - try { - let myobj = new EventsBase("a", "b", "c", {} as any); - await myobj.emitBroadcast("a", "b", "c", []); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); - } - }); - it("onEvent should throw", async () => { - try { - let myobj = new EventsBase("a", "b", "c", {} as any); - await myobj.onEvent("a", "b", "c", async () => {}); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); - } - }); - it("emitEvent should throw", async () => { - try { - let myobj = new EventsBase("a", "b", "c", {} as any); - await myobj.emitEvent("a", "b", "c", []); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); - } - }); - it("onReturnableEvent should throw", async () => { - try { - let myobj = new EventsBase("a", "b", "c", {} as any); - await myobj.onReturnableEvent("a", "b", "c", async () => {}); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); - } - }); - it("emitEventAndReturn should throw", async () => { - try { - let myobj = new EventsBase("a", "b", "c", {} as any); - await myobj.emitEventAndReturn("a", "b", "c", 1, []); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); - } - }); - it("receiveStream should throw", async () => { - try { - let myobj = new EventsBase("a", "b", "c", {} as any); - await myobj.receiveStream("a", async () => {}); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); - } - }); - it("sendStream should throw", async () => { - try { - let myobj = new EventsBase("a", "b", "c", {} as any); - await myobj.sendStream("a", "", {} as any); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); - } - }); - }); -}); +// describe("EventsBase", function () { +// describe("Constructor", async function () { +// it("Should construct correctly [pluginName]", async () => { +// let myobj = new EventsBase("pluginNameX", "cwd", "pluginCwd", {} as any); +// assert.strictEqual(myobj.pluginName, "pluginNameX"); +// }); +// it("Should construct correctly [cwd]", async () => { +// let myobj = new EventsBase("pluginNameX", "cwdD", "pluginCwd", {} as any); +// assert.strictEqual((myobj as any).cwd, "cwdD"); +// }); +// it("Should construct correctly [pluginCwd]", async () => { +// let myobj = new EventsBase( +// "pluginNameX", +// "cwdD", +// "pluginCwdY", +// {} as any +// ); +// assert.strictEqual((myobj as any).pluginCwd, "pluginCwdY"); +// }); +// it("Should construct correctly [logger]", async () => { +// let myobj = new EventsBase("pluginNameX", "cwdD", "pluginCwdY", { +// alog: true, +// } as any); +// assert.strictEqual((myobj as any).log.alog, true); +// }); +// }); +// describe("Default methods", function () { +// it("onBroadcast should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.onBroadcast("a", "b", "c", async () => {}); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("emitBroadcast should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.emitBroadcast("a", "b", "c", []); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("onEvent should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.onEvent("a", "b", "c", async () => {}); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("emitEvent should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.emitEvent("a", "b", "c", []); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("onReturnableEvent should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.onReturnableEvent("a", "b", "c", async () => {}); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("emitEventAndReturn should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.emitEventAndReturn("a", "b", "c", 1, []); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("receiveStream should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.receiveStream("a", async () => {}); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("sendStream should throw", async () => { +// try { +// let myobj = new EventsBase("a", "b", "c", {} as any); +// await myobj.sendStream("a", "", {} as any); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// }); +// }); diff --git a/nodejs/src/tests/interfaces/base.ts b/nodejs/src/tests/interfaces/base.ts index 28fd302..6dc8623 100644 --- a/nodejs/src/tests/interfaces/base.ts +++ b/nodejs/src/tests/interfaces/base.ts @@ -1,26 +1,26 @@ -import assert from "assert"; -import { DefaultBase } from "../../../src/interfaces/base"; -import { ErrorMessages } from "../../../src/interfaces/static"; +// import assert from "assert"; +// import { BaseWithLogging } from "../../base/base"; +// import { ErrorMessages } from "../../base/errorMessages"; -describe("DefaultBase", function () { - describe("Default methods", function () { - it("getPluginConfig should throw", async () => { - try { - let myobj = new DefaultBase("a", "b", "c", {} as any); - (myobj as any).getPluginConfig(); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.BSBNotInit); - } - }); - it("getPluginState should throw", async () => { - try { - let myobj = new DefaultBase("a", "b", "c", {} as any); - await (myobj as any).getPluginState(); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.BSBNotInit); - } - }); - }); -}); +// describe("DefaultBase", function () { +// describe("Default methods", function () { +// it("getPluginConfig should throw", async () => { +// try { +// let myobj = new BaseWithLogging("a", "b", "c", {} as any); +// (myobj as any).getPluginConfig(); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.BSBNotInit); +// } +// }); +// it("getPluginState should throw", async () => { +// try { +// let myobj = new BaseWithLogging("a", "b", "c", {} as any); +// await (myobj as any).getPluginState(); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.BSBNotInit); +// } +// }); +// }); +// }); diff --git a/nodejs/src/tests/interfaces/static.ts b/nodejs/src/tests/interfaces/static.ts index 54aef1e..4abb119 100644 --- a/nodejs/src/tests/interfaces/static.ts +++ b/nodejs/src/tests/interfaces/static.ts @@ -1,63 +1,63 @@ -import assert from "assert"; -import { ErrorMessages } from "../../../src/interfaces/static"; +// import assert from "assert"; +// import { ErrorMessages } from "../../base/errorMessages"; -describe("ErrorMessages", function () { - describe("Throw errors", async function () { - it("BSBNotInit should throw", async () => { - try { - throw ErrorMessages.BSBNotInit; - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.BSBNotInit); - } - }); - it("EventsNotImplementedProperly should throw", async () => { - try { - throw ErrorMessages.EventsNotImplementedProperly; - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); - } - }); - it("PluginNotImplementedProperly should throw", async () => { - try { - throw ErrorMessages.PluginNotImplementedProperly; - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.PluginNotImplementedProperly); - } - }); - it("LoggerNotImplementedProperly should throw", async () => { - try { - throw ErrorMessages.LoggerNotImplementedProperly; - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); - } - }); - it("ConfigNotImplementedProperly should throw", async () => { - try { - throw ErrorMessages.ConfigNotImplementedProperly; - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.ConfigNotImplementedProperly); - } - }); - it("PluginClientNotImplementedProperly should throw", async () => { - try { - throw ErrorMessages.PluginClientNotImplementedProperly; - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.PluginClientNotImplementedProperly); - } - }); - it("PluginConfigNotSetupToGenerateConfig should throw", async () => { - try { - throw ErrorMessages.PluginConfigNotSetupToGenerateConfig; - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.PluginConfigNotSetupToGenerateConfig); - } - }); - it("ServicePluginNotCallableMethod should throw", async () => { - try { - throw ErrorMessages.ServicePluginNotCallableMethod; - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.ServicePluginNotCallableMethod); - } - }); - }); -}); +// describe("ErrorMessages", function () { +// describe("Throw errors", async function () { +// it("BSBNotInit should throw", async () => { +// try { +// throw ErrorMessages.BSBNotInit; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.BSBNotInit); +// } +// }); +// it("EventsNotImplementedProperly should throw", async () => { +// try { +// throw ErrorMessages.EventsNotImplementedProperly; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.EventsNotImplementedProperly); +// } +// }); +// it("PluginNotImplementedProperly should throw", async () => { +// try { +// throw ErrorMessages.PluginNotImplementedProperly; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.PluginNotImplementedProperly); +// } +// }); +// it("LoggerNotImplementedProperly should throw", async () => { +// try { +// throw ErrorMessages.LoggerNotImplementedProperly; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// it("ConfigNotImplementedProperly should throw", async () => { +// try { +// throw ErrorMessages.ConfigNotImplementedProperly; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.ConfigNotImplementedProperly); +// } +// }); +// it("PluginClientNotImplementedProperly should throw", async () => { +// try { +// throw ErrorMessages.PluginClientNotImplementedProperly; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.PluginClientNotImplementedProperly); +// } +// }); +// it("PluginConfigNotSetupToGenerateConfig should throw", async () => { +// try { +// throw ErrorMessages.PluginConfigNotSetupToGenerateConfig; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.PluginConfigNotSetupToGenerateConfig); +// } +// }); +// it("ServicePluginNotCallableMethod should throw", async () => { +// try { +// throw ErrorMessages.ServicePluginNotCallableMethod; +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.ServicePluginNotCallableMethod); +// } +// }); +// }); +// }); diff --git a/nodejs/src/tests/logger/logFormatter.ts b/nodejs/src/tests/logger/logFormatter.ts new file mode 100644 index 0000000..37e3a1d --- /dev/null +++ b/nodejs/src/tests/logger/logFormatter.ts @@ -0,0 +1,119 @@ +import { assert } from "chai"; +import { LogFormatter } from "../../base"; + +describe("logFormatter", function () { + describe("formatLog", function () { + it("Should return string when meta is undefined", async () => { + let ojb = new LogFormatter(); + assert.strictEqual(ojb.formatLog("TEST"), "TEST"); + }); + it("Should return string when meta is null", async () => { + let ojb = new LogFormatter(); + assert.strictEqual(ojb.formatLog("TEST", null as any), "TEST"); // ts picks up this issue + }); + it("Should return string when meta is a string", async () => { + let ojb = new LogFormatter(); + assert.strictEqual(ojb.formatLog("TEST", ""), "TEST"); + }); + it("Should return string when meta is a number", async () => { + let ojb = new LogFormatter(); + assert.strictEqual(ojb.formatLog("TEST", 5), "TEST"); + }); + it("Should format correctly", async () => { + let ojb = new LogFormatter(); + assert.strictEqual(ojb.formatLog("HTEST {a}", { a: "B" }), "HTEST B"); + }); + it("Should format *null/undefined* when a value found doesnt exist", async () => { + let ojb = new LogFormatter(); + assert.strictEqual( + ojb.formatLog("HTEST {a}", {} as any), // ts picks up this issue + "HTEST *null/undefined*" + ); + }); + it("Should format *null/undefined* when a value found is undefined", async () => { + let ojb = new LogFormatter(); + assert.strictEqual( + ojb.formatLog("HTEST {a}", { a: undefined } as any), // ts picks up this issue + "HTEST *null/undefined*" + ); + }); + it("Should format DT in ISO when a value found is a date", async () => { + let ojb = new LogFormatter(); + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f}", { f: dt }), + "HTEST 2023-07-22T15:38:30.000Z" + ); + }); + it("Should format DT in ISO when a value found is a date 2", async () => { + let ojb = new LogFormatter(); + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f}@{e}", { e: "DD", f: dt }), + "HTEST 2023-07-22T15:38:30.000Z@DD" + ); + }); + it("Should fail to format DT when a value found is inside an object", async () => { + let ojb = new LogFormatter(); + let dt = new Date(1689694710000); // 18 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f.y}@{e}", { e: "DD", f: { y: dt } } as any), // ts picks up this issue + "HTEST *null/undefined*@DD" + ); + }); + // it("Should format DT in ISO when a value found is a date 4", async () => { + // let ojb = new LogFormatter(); + // let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + // let dt2 = new Date(1689694710000); // 18 Jul 2023 15:38:30 GMT + // assert.strictEqual( + // ojb.formatLog("HTEST {f.y}@{e}:{a.0}:{a.1}", { + // a: ["E", dt2], + // e: "DD", + // f: { y: dt }, + // } as any), + // "HTEST 2023-07-22T15:38:30.000Z@DD:E:2023-07-18T15:38:30.000Z" + // ); // ts picks up this issue + // }); + it("Should format json when a value found is an object", async () => { + let ojb = new LogFormatter(); + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f}@{e}", { e: "DD", f: { y: dt } }), + 'HTEST {"y":"2023-07-22T15:38:30.000Z"}@DD' + ); + }); + it("Should format direct date", async () => { + let ojb = new LogFormatter(); + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("{y}", { y: dt }), + "2023-07-22T15:38:30.000Z" + ); + }); + it("Should format iso date", async () => { + const isIsoDate = (str: string) => { + if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(str)) + return false; + const d = new Date(str); + return ( + d instanceof Date && !isNaN(d.getTime()) && d.toISOString() === str + ); // valid date + }; + let ojb = new LogFormatter(); + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual(isIsoDate(ojb.formatLog("{y}", { y: dt })), true); + }); + it("Should format json when a value found is an array", async () => { + let ojb = new LogFormatter(); + let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + assert.strictEqual( + ojb.formatLog("HTEST {f}@{e}:{a}", { + a: ["E", "F"], + e: "DD", + f: { y: dt }, + } as any), + 'HTEST {"y":"2023-07-22T15:38:30.000Z"}@DD:E,F' + ); // ts picks up this issue + }); + }); +}); diff --git a/nodejs/src/tests/logger/logger.ts b/nodejs/src/tests/logger/logger.ts index 7c35f4d..4381b17 100644 --- a/nodejs/src/tests/logger/logger.ts +++ b/nodejs/src/tests/logger/logger.ts @@ -1,177 +1,62 @@ -import assert from "assert"; -import { LoggerBase } from "../../../src/logger/logger"; -import { ErrorMessages } from "../../../src/interfaces/static"; +// import assert from "assert"; +// import { LoggerBase } from "../../../src/logger/logger"; +// import { ErrorMessages } from "../../base/errorMessages"; -describe("LoggerBase", function () { - describe("formatLog", function () { - it("Should return string when meta is undefined", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - assert.strictEqual(ojb.formatLog("TEST"), "TEST"); - }); - it("Should return string when meta is null", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - assert.strictEqual(ojb.formatLog("TEST", null), "TEST"); - }); - it("Should return string when meta is a string", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - assert.strictEqual(ojb.formatLog("TEST", ""), "TEST"); - }); - it("Should return string when meta is a number", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - assert.strictEqual(ojb.formatLog("TEST", 5), "TEST"); - }); - it("Should format correctly", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - assert.strictEqual(ojb.formatLog("HTEST {a}", { a: "B" }), "HTEST B"); - }); - it("Should format *null/undefined* when a value found doesnt exist", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - assert.strictEqual( - ojb.formatLog("HTEST {a}", {}), - "HTEST *null/undefined*" - ); - }); - it("Should format *null/undefined* when a value found is undefined", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - assert.strictEqual( - ojb.formatLog("HTEST {a}", { a: undefined }), - "HTEST *null/undefined*" - ); - }); - it("Should format DT in ISO when a value found is a date", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT - assert.strictEqual( - ojb.formatLog("HTEST {f}", { f: dt }), - "HTEST 2023-07-22T15:38:30.000Z" - ); - }); - it("Should format DT in ISO when a value found is a date 2", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT - assert.strictEqual( - ojb.formatLog("HTEST {f}@{e}", { e: "DD", f: dt }), - "HTEST 2023-07-22T15:38:30.000Z@DD" - ); - }); - it("Should format DT in ISO when a value found is a date 3", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - let dt = new Date(1689694710000); // 18 Jul 2023 15:38:30 GMT - assert.strictEqual( - ojb.formatLog("HTEST {f.y}@{e}", { e: "DD", f: { y: dt } }), - "HTEST 2023-07-18T15:38:30.000Z@DD" - ); - }); - it("Should format DT in ISO when a value found is a date 4", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT - let dt2 = new Date(1689694710000); // 18 Jul 2023 15:38:30 GMT - assert.strictEqual( - ojb.formatLog("HTEST {f.y}@{e}:{a.0}:{a.1}", { - a: ["E", dt2], - e: "DD", - f: { y: dt }, - }), - "HTEST 2023-07-22T15:38:30.000Z@DD:E:2023-07-18T15:38:30.000Z" - ); - }); - it("Should format json when a value found is an object", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT - assert.strictEqual( - ojb.formatLog("HTEST {f}@{e}", { e: "DD", f: { y: dt } }), - 'HTEST {"y":"2023-07-22T15:38:30.000Z"}@DD' - ); - }); - it("Should format direct date", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT - assert.strictEqual( - ojb.formatLog("{y}", { y: dt }), - "2023-07-22T15:38:30.000Z" - ); - }); - it("Should format iso date", async () => { - const isIsoDate = (str: string) => { - if (!/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z/.test(str)) - return false; - const d = new Date(str); - return ( - d instanceof Date && !isNaN(d.getTime()) && d.toISOString() === str - ); // valid date - }; - let ojb = new LoggerBase("", "", "", {} as any) as any; - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT - assert.strictEqual(isIsoDate(ojb.formatLog("{y}", { y: dt })), true); - }); - it("Should format json when a value found is an array", async () => { - let ojb = new LoggerBase("", "", "", {} as any) as any; - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT - assert.strictEqual( - ojb.formatLog("HTEST {f}@{e}:{a.0}", { - a: ["E", "F"], - e: "DD", - f: { y: dt }, - }), - 'HTEST {"y":"2023-07-22T15:38:30.000Z"}@DD:E' - ); - }); - }); - - describe("Default methods", function () { - it("reportStat should throw", async () => { - try { - let myobj = new LoggerBase("a", "b", "c", {} as any); - await myobj.reportStat("a", "b", 1); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); - } - }); - it("reportTextStat should throw", async () => { - try { - let myobj = new LoggerBase("a", "b", "c", {} as any); - await myobj.reportTextStat("a", "b", 1); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); - } - }); - it("debug should throw", async () => { - try { - let myobj = new LoggerBase("a", "b", "c", {} as any); - await myobj.debug("a", "b", 1); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); - } - }); - it("info should throw", async () => { - try { - let myobj = new LoggerBase("a", "b", "c", {} as any); - await myobj.info("a", "b", 1); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); - } - }); - it("warn should throw", async () => { - try { - let myobj = new LoggerBase("a", "b", "c", {} as any); - await myobj.warn("a", "b", 1); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); - } - }); - it("error should throw", async () => { - try { - let myobj = new LoggerBase("a", "b", "c", {} as any); - await myobj.error("a", "b", 1); - assert.fail("Should have thrown"); - } catch (e: any) { - assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); - } - }); - }); -}); +// describe("LoggerBase", function () { +// describe("Default methods", function () { +// it("reportStat should throw", async () => { +// try { +// let myobj = new LoggerBase("a", "b", "c", {} as any); +// await myobj.reportStat("a", "b", 1); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// it("reportTextStat should throw", async () => { +// try { +// let myobj = new LoggerBase("a", "b", "c", {} as any); +// await myobj.reportTextStat("a", "b", 1); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// it("debug should throw", async () => { +// try { +// let myobj = new LoggerBase("a", "b", "c", {} as any); +// await myobj.debug("a", "b", 1); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// it("info should throw", async () => { +// try { +// let myobj = new LoggerBase("a", "b", "c", {} as any); +// await myobj.info("a", "b", 1); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// it("warn should throw", async () => { +// try { +// let myobj = new LoggerBase("a", "b", "c", {} as any); +// await myobj.warn("a", "b", 1); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// it("error should throw", async () => { +// try { +// let myobj = new LoggerBase("a", "b", "c", {} as any); +// await myobj.error("a", "b", 1); +// assert.fail("Should have thrown"); +// } catch (e: any) { +// assert.deepEqual(e, ErrorMessages.LoggerNotImplementedProperly); +// } +// }); +// }); +// }); diff --git a/nodejs/src/tests/plugins/events/events/broadcast.ts b/nodejs/src/tests/plugins/events/events/broadcast.ts index 2130ea2..02f6ca1 100644 --- a/nodejs/src/tests/plugins/events/events/broadcast.ts +++ b/nodejs/src/tests/plugins/events/events/broadcast.ts @@ -1,19 +1,19 @@ -import { EventsBase } from "../../../../events/events"; import assert from "assert"; import { randomUUID } from "crypto"; +import { BSBEvents, SmartFunctionCallSync } from "../../../../"; const randomName = () => randomUUID(); export function broadcast( - genNewPlugin: { (): Promise }, + genNewPlugin: { (): Promise }, maxTimeoutToExpectAResponse: number ) { - let emitter: EventsBase; + let emitter: BSBEvents; beforeEach(async () => { emitter = await genNewPlugin(); }); afterEach(function () { - emitter.dispose(); + SmartFunctionCallSync(emitter, emitter.dispose); }); describe("EmitBroadcast", async function () { this.timeout(maxTimeoutToExpectAResponse + 10); @@ -21,54 +21,35 @@ export function broadcast( describe("emitBroadcast", async () => { const emitData = true; it("all plugins should receive the event", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); //console.log(emitter) let receiveCounter = 0; setTimeout(() => { - if (receiveCounter === 2) return assert.ok(receiveCounter); + if (receiveCounter === 2) return assert.ok(receiveCounter); if (receiveCounter === 0) return assert.fail("Event not received"); assert.fail("Received " + receiveCounter + " events"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - receiveCounter++; - } - ); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - receiveCounter++; - } - ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent, [emitData]); + await emitter.onBroadcast(thisPlugin, thisEvent, async (data: any) => { + receiveCounter++; + }); + await emitter.onBroadcast(thisPlugin, thisEvent, async (data: any) => { + receiveCounter++; + }); + await emitter.emitBroadcast(thisPlugin, thisEvent, [emitData]); }); it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); //console.log(emitter) const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); - assert.ok(data[0]); - } - ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent, [ - emitData, - ]); + await emitter.onBroadcast(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); + assert.ok(data[0]); + }); + await emitter.emitBroadcast(thisPlugin, thisEvent, [emitData]); }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); @@ -77,19 +58,12 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.ok(data[0]); - } - ); - await emitter.emitBroadcast(thisCaller, thisCaller, thisEvent, [ - emitData, - ]); + assert.ok(data[0]); + }); + await emitter.emitBroadcast(thisCaller, thisEvent, [emitData]); }); it("should be able to emit to events with self multi-args", async () => { const thisCaller = randomName(); @@ -98,28 +72,17 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], 0); - assert.deepEqual(data[1], 1); - assert.deepEqual(data[2], 2); - assert.deepEqual(data[3], 3); - } - ); - await emitter.emitBroadcast( - thisCaller, - thisCaller, - thisEvent, - [0, 1, 2, 3] - ); + assert.deepEqual(data[0], 0); + assert.deepEqual(data[1], 1); + assert.deepEqual(data[2], 2); + assert.deepEqual(data[3], 3); + }); + await emitter.emitBroadcast(thisCaller, thisEvent, [0, 1, 2, 3]); }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); @@ -127,19 +90,12 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent2, [ - emitData, - ]); + assert.fail("Event received"); + }); + await emitter.emitBroadcast(thisPlugin, thisEvent2, [emitData]); }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); @@ -149,44 +105,29 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitBroadcast(thisCaller, thisCaller, thisEvent2, [ - emitData, - ]); + assert.fail("Event received"); + }); + await emitter.emitBroadcast(thisCaller, thisEvent2, [emitData]); }); }); describe("onBroadcast", async () => { const emitData = "ABCD"; it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], emitData); - } - ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent, [ - emitData, - ]); + assert.deepEqual(data[0], emitData); + }); + await emitter.emitBroadcast(thisPlugin, thisEvent, [emitData]); }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); @@ -195,22 +136,14 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], emitData); - } - ); - await emitter.emitBroadcast(thisCaller, thisCaller, thisEvent, [ - emitData, - ]); + assert.deepEqual(data[0], emitData); + }); + await emitter.emitBroadcast(thisCaller, thisEvent, [emitData]); }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); @@ -218,19 +151,12 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent2, [ - emitData, - ]); + assert.fail("Event received"); + }); + await emitter.emitBroadcast(thisPlugin, thisEvent2, [emitData]); }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); @@ -240,19 +166,12 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitBroadcast(thisCaller, thisCaller, thisEvent2, [ - emitData, - ]); + assert.fail("Event received"); + }); + await emitter.emitBroadcast(thisCaller, thisEvent2, [emitData]); }); }); const typesToTest = [ @@ -299,7 +218,6 @@ export function broadcast( for (let typeToTest of typesToTest) describe(`emitBroadcast ${typeToTest.name}`, async () => { it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); @@ -307,7 +225,6 @@ export function broadcast( assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); await emitter.onBroadcast( - thisCaller, thisPlugin, thisEvent, async (data: any) => { @@ -316,9 +233,7 @@ export function broadcast( assert.deepEqual(data[0], typeToTest.data); } ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent, [ - typeToTest.data, - ]); + await emitter.emitBroadcast(thisPlugin, thisEvent, [typeToTest.data]); }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); @@ -328,7 +243,6 @@ export function broadcast( assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); await emitter.onBroadcast( - thisCaller, thisCaller, thisEvent, async (data: any) => { @@ -337,12 +251,9 @@ export function broadcast( assert.deepEqual(data[0], typeToTest.data); } ); - await emitter.emitBroadcast(thisCaller, thisCaller, thisEvent, [ - typeToTest.data, - ]); + await emitter.emitBroadcast(thisCaller, thisEvent, [typeToTest.data]); }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); @@ -351,7 +262,6 @@ export function broadcast( assert.ok(true); }, maxTimeoutToExpectAResponse); await emitter.onBroadcast( - thisCaller, thisPlugin, thisEvent, async (data: any) => { @@ -360,7 +270,7 @@ export function broadcast( assert.fail("Event received"); } ); - await emitter.emitBroadcast(thisCaller, thisPlugin, thisEvent2, [ + await emitter.emitBroadcast(thisPlugin, thisEvent2, [ typeToTest.data, ]); }); @@ -373,7 +283,6 @@ export function broadcast( assert.ok(true); }, maxTimeoutToExpectAResponse); await emitter.onBroadcast( - thisCaller, thisCaller, thisEvent, async (data: any) => { @@ -382,7 +291,7 @@ export function broadcast( assert.fail("Event received"); } ); - await emitter.emitBroadcast(thisCaller, thisCaller, thisEvent2, [ + await emitter.emitBroadcast(thisCaller, thisEvent2, [ typeToTest.data, ]); }); diff --git a/nodejs/src/tests/plugins/events/events/emit.ts b/nodejs/src/tests/plugins/events/events/emit.ts index 073d6a2..7980010 100644 --- a/nodejs/src/tests/plugins/events/events/emit.ts +++ b/nodejs/src/tests/plugins/events/events/emit.ts @@ -1,19 +1,19 @@ -import { EventsBase } from "../../../../events/events"; import assert from "assert"; import { randomUUID } from "crypto"; +import { BSBEvents, SmartFunctionCallSync } from "../../../../"; const randomName = () => randomUUID(); export function emit( - genNewPlugin: { (): Promise }, + genNewPlugin: { (): Promise }, maxTimeoutToExpectAResponse: number ) { - let emitter: EventsBase; + let emitter: BSBEvents; beforeEach(async () => { emitter = await genNewPlugin(); }); afterEach(function () { - emitter.dispose(); + SmartFunctionCallSync(emitter, emitter.dispose); }); describe("Emit", async function () { this.timeout(maxTimeoutToExpectAResponse + 10); @@ -21,7 +21,6 @@ export function emit( describe("emitEvent", async () => { const emitData = true; it("only one plugin should receive the event", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); //console.log(emitter) @@ -31,42 +30,26 @@ export function emit( if (receiveCounter === 0) return assert.fail("Event not received"); assert.fail("Received " + receiveCounter + " events"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - receiveCounter++; - } - ); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - receiveCounter++; - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent, [emitData]); + await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + receiveCounter++; + }); + await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + receiveCounter++; + }); + await emitter.emitEvent(thisPlugin, thisEvent, [emitData]); }); it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); //console.log(emitter) const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); - assert.ok(data[0]); - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent, [emitData]); + await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); + assert.ok(data[0]); + }); + await emitter.emitEvent(thisPlugin, thisEvent, [emitData]); }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); @@ -75,17 +58,12 @@ export function emit( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.ok(data[0]); - } - ); - await emitter.emitEvent(thisCaller, thisCaller, thisEvent, [emitData]); + assert.ok(data[0]); + }); + await emitter.emitEvent(thisCaller, thisEvent, [emitData]); }); it("should be able to emit to events with self multi-args", async () => { const thisCaller = randomName(); @@ -94,28 +72,17 @@ export function emit( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], 0); - assert.deepEqual(data[1], 1); - assert.deepEqual(data[2], 2); - assert.deepEqual(data[3], 3); - } - ); - await emitter.emitEvent( - thisCaller, - thisCaller, - thisEvent, - [0, 1, 2, 3] - ); + assert.deepEqual(data[0], 0); + assert.deepEqual(data[1], 1); + assert.deepEqual(data[2], 2); + assert.deepEqual(data[3], 3); + }); + await emitter.emitEvent(thisCaller, thisEvent, [0, 1, 2, 3]); }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); @@ -123,17 +90,12 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent2, [emitData]); + assert.fail("Event received"); + }); + await emitter.emitEvent(thisPlugin, thisEvent2, [emitData]); }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); @@ -143,40 +105,29 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitEvent(thisCaller, thisCaller, thisEvent2, [emitData]); + assert.fail("Event received"); + }); + await emitter.emitEvent(thisCaller, thisEvent2, [emitData]); }); }); describe("onEvent", async () => { const emitData = "ABCD"; it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], emitData); - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent, [emitData]); + assert.deepEqual(data[0], emitData); + }); + await emitter.emitEvent(thisPlugin, thisEvent, [emitData]); }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); @@ -185,20 +136,14 @@ export function emit( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], emitData); - } - ); - await emitter.emitEvent(thisCaller, thisCaller, thisEvent, [emitData]); + assert.deepEqual(data[0], emitData); + }); + await emitter.emitEvent(thisCaller, thisEvent, [emitData]); }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); @@ -206,17 +151,12 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent2, [emitData]); + assert.fail("Event received"); + }); + await emitter.emitEvent(thisPlugin, thisEvent2, [emitData]); }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); @@ -226,17 +166,12 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitEvent(thisCaller, thisCaller, thisEvent2, [emitData]); + assert.fail("Event received"); + }); + await emitter.emitEvent(thisCaller, thisEvent2, [emitData]); }); }); const typesToTest = [ @@ -283,26 +218,18 @@ export function emit( for (let typeToTest of typesToTest) describe(`emitEvent ${typeToTest.name}`, async () => { it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], typeToTest.data); - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent, [ - typeToTest.data, - ]); + assert.deepEqual(data[0], typeToTest.data); + }); + await emitter.emitEvent(thisPlugin, thisEvent, [typeToTest.data]); }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); @@ -311,22 +238,14 @@ export function emit( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.deepEqual(data[0], typeToTest.data); - } - ); - await emitter.emitEvent(thisCaller, thisCaller, thisEvent, [ - typeToTest.data, - ]); + assert.deepEqual(data[0], typeToTest.data); + }); + await emitter.emitEvent(thisCaller, thisEvent, [typeToTest.data]); }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); @@ -334,19 +253,12 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitEvent(thisCaller, thisPlugin, thisEvent2, [ - typeToTest.data, - ]); + assert.fail("Event received"); + }); + await emitter.emitEvent(thisPlugin, thisEvent2, [typeToTest.data]); }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); @@ -356,19 +268,12 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent( - thisCaller, - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); - await emitter.emitEvent(thisCaller, thisCaller, thisEvent2, [ - typeToTest.data, - ]); + assert.fail("Event received"); + }); + await emitter.emitEvent(thisCaller, thisEvent2, [typeToTest.data]); }); }); }); diff --git a/nodejs/src/tests/plugins/events/events/emitAndReturn.ts b/nodejs/src/tests/plugins/events/events/emitAndReturn.ts index 7880ba7..6921ddd 100644 --- a/nodejs/src/tests/plugins/events/events/emitAndReturn.ts +++ b/nodejs/src/tests/plugins/events/events/emitAndReturn.ts @@ -1,21 +1,21 @@ -import { EventsBase } from '../../../../events/events'; +import { BSBEvents, SmartFunctionCallSync } from "../../../../"; import assert from "assert"; import { randomUUID } from "crypto"; const randomName = () => randomUUID(); export function emitAndReturn( - genNewPlugin: { (): Promise }, + genNewPlugin: { (): Promise }, maxTimeoutToExpectAResponse: number, a = true, b = true ) { - let emitter: EventsBase; + let emitter: BSBEvents; beforeEach(async () => { emitter = await genNewPlugin(); }); afterEach(function () { - emitter.dispose(); + SmartFunctionCallSync(emitter, emitter.dispose); }); describe("EmitAndReturn", async () => { //if (a) this.timeout(maxTimeoutToExpectAResponse + 20); @@ -25,15 +25,13 @@ export function emitAndReturn( const emitData = true; const emitData2 = false; it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); await emitter.onReturnableEvent( - thisCaller, thisPlugin, thisEvent, async (data: Array) => { @@ -46,7 +44,6 @@ export function emitAndReturn( ); console.log("!!Received onEvent"); await emitter.emitEventAndReturn( - thisCaller, thisPlugin, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -55,17 +52,15 @@ export function emitAndReturn( console.log("++Received onEvent"); clearTimeout(emitTimeout); assert.ok(true, "Received Response"); - }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); await emitter.onReturnableEvent( - thisCaller, thisCaller, thisEvent, async (data: Array) => { @@ -74,7 +69,6 @@ export function emitAndReturn( } ); await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -82,19 +76,16 @@ export function emitAndReturn( ); clearTimeout(emitTimeout); assert.ok(true, "Received Response"); - }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); - + const emitTimeout = setTimeout(() => { assert.ok(true); }, timermaxTimeoutToExpectAResponse); await emitter.onReturnableEvent( - thisCaller, thisPlugin, thisEvent, (data: Array) => { @@ -103,7 +94,6 @@ export function emitAndReturn( ); try { await emitter.emitEventAndReturn( - thisCaller, thisPlugin, thisEvent2, maxTimeoutToExpectAResponse / 1000, @@ -115,18 +105,16 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); - + const emitTimeout = setTimeout(() => { assert.ok(true); }, timermaxTimeoutToExpectAResponse); await emitter.onReturnableEvent( - thisCaller, thisCaller, thisEvent, (data: Array) => { @@ -135,7 +123,6 @@ export function emitAndReturn( ); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent2, maxTimeoutToExpectAResponse / 1000, @@ -147,24 +134,21 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should timeout correctly", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); await emitter.onReturnableEvent( - thisCaller, thisCaller, thisEvent, async (data: Array) => {} ); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -176,17 +160,15 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should response error correctly", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); await emitter.onReturnableEvent( - thisCaller, thisCaller, thisEvent, (data: Array) => { @@ -195,7 +177,6 @@ export function emitAndReturn( ); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -208,7 +189,6 @@ export function emitAndReturn( assert.ok("EEAR"); assert.strictEqual(exc, "THISISANERROR"); } - }); }); const typesToTest = [ @@ -260,23 +240,22 @@ export function emitAndReturn( for (let typeToTest of typesToTest) { describe(`emitEventAndReturn ${typeToTest.name}`, async () => { it("should be able to emit to events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); await emitter.onReturnableEvent( - thisCaller, thisPlugin, thisEvent, async (data: Array) => { - return typeToTest.rData !== undefined ? typeToTest.rData: typeToTest.data; + return typeToTest.rData !== undefined + ? typeToTest.rData + : typeToTest.data; } ); const resp = await emitter.emitEventAndReturn( - thisCaller, thisPlugin, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -285,21 +264,21 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.strictEqual( JSON.stringify(resp), - JSON.stringify(typeToTest.rData !== undefined - ? typeToTest.rData - : typeToTest.data) + JSON.stringify( + typeToTest.rData !== undefined + ? typeToTest.rData + : typeToTest.data + ) ); - }); it("should be able to emit to events with self", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received - timeout"); }, timermaxTimeoutToExpectAResponse); await emitter.onReturnableEvent( - thisCaller, thisCaller, thisEvent, async (data: Array) => { @@ -315,7 +294,6 @@ export function emitAndReturn( assert.strictEqual( JSON.stringify( await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -326,19 +304,16 @@ export function emitAndReturn( "Returned data" ); clearTimeout(emitTimeout); - }); it("should not be able to emit to other events with plugin name defined", async () => { - const thisCaller = randomName(); const thisPlugin = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); - + const emitTimeout = setTimeout(() => { assert.ok(true); }, timermaxTimeoutToExpectAResponse); await emitter.onReturnableEvent( - thisCaller, thisPlugin, thisEvent, (data: Array) => { @@ -347,7 +322,6 @@ export function emitAndReturn( ); try { await emitter.emitEventAndReturn( - thisCaller, thisPlugin, thisEvent2, maxTimeoutToExpectAResponse / 1000, @@ -359,18 +333,16 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should not be able to emit to other events with self", async () => { const thisCaller = randomName(); const thisEvent = randomName(); const thisEvent2 = randomName(); - + const emitTimeout = setTimeout(() => { assert.ok(true); }, timermaxTimeoutToExpectAResponse); await emitter.onReturnableEvent( - thisCaller, thisCaller, thisEvent, (data: Array) => { @@ -379,7 +351,6 @@ export function emitAndReturn( ); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent2, maxTimeoutToExpectAResponse / 1000, @@ -391,24 +362,21 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should timeout correctly - general timeout", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse + 10); await emitter.onReturnableEvent( - thisCaller, thisCaller, thisEvent, async (data: Array) => {} ); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -420,18 +388,16 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should timeout correctly - no receipt", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse + 10); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -443,17 +409,15 @@ export function emitAndReturn( clearTimeout(emitTimeout); assert.ok("Timeout of EEAR"); } - }); it("should response error correctly", async () => { const thisCaller = randomName(); const thisEvent = randomName(); - + const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); await emitter.onReturnableEvent( - thisCaller, thisCaller, thisEvent, (data: Array) => { @@ -462,7 +426,6 @@ export function emitAndReturn( ); try { await emitter.emitEventAndReturn( - thisCaller, thisCaller, thisEvent, maxTimeoutToExpectAResponse / 1000, @@ -478,7 +441,6 @@ export function emitAndReturn( JSON.stringify(typeToTest.rData || typeToTest.data) ); } - }); }); } diff --git a/nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts b/nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts index 165d375..2637343 100644 --- a/nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts +++ b/nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts @@ -3,7 +3,7 @@ import * as crypto from "crypto"; import { exec } from "child_process"; import { pipeline } from "stream"; import assert from "assert"; -import { EventsBase } from '../../../../events/events'; +import { BSBEvents, SmartFunctionCallSync } from "../../../../"; const randomName = () => crypto.randomUUID(); @@ -73,15 +73,15 @@ const convertBytes = ( }; export function emitStreamAndReceiveStream( - genNewPlugin: { (): Promise }, + genNewPlugin: { (): Promise }, maxTimeoutToExpectAResponse: number ) { - let emitter: EventsBase; + let emitter: BSBEvents; beforeEach(async () => { emitter = await genNewPlugin(); }); afterEach(function () { - emitter.dispose(); + SmartFunctionCallSync(emitter, emitter.dispose); }); describe("EmitStreamAndReceiveStream", async () => { //this.timeout(maxTimeoutToExpectAResponse + 20); @@ -125,7 +125,7 @@ export function emitStreamAndReceiveStream( ); try { await emitter.sendStream(thisCaller, uuid, mockBareFakeStream()); - console.log('endededed') + console.log("endededed"); } catch (xx) {} }); describe("sendStream triggers receiveStream listener passing in the stream", async () => { @@ -203,7 +203,7 @@ export function emitStreamAndReceiveStream( }, timermaxTimeoutToExpectAResponse); let uuid = await emitter.receiveStream( thisCaller, - async (err: any, stream: any):Promise => { + async (err: any, stream: any): Promise => { if (err) return assert.fail(err); clearTimeout(emitTimeout); pipeline(stream, fs.createWriteStream(fileNameOut), (errf) => { @@ -247,7 +247,7 @@ export function emitStreamAndReceiveStream( runTest("1MB"); runTest("16MB"); //runTest("128MB", 1); - + //runTest("128MB", 4); //runTest('512MB', 16); //runTest('1GB', 32); diff --git a/nodejs/src/tests/plugins/events/plugin.ts b/nodejs/src/tests/plugins/events/plugin.ts index a5dad5b..fca99c7 100644 --- a/nodejs/src/tests/plugins/events/plugin.ts +++ b/nodejs/src/tests/plugins/events/plugin.ts @@ -1,79 +1,58 @@ import assert from "assert"; //import { Logger } from "./test-logger"; -import { Events as events } from "../../../plugins/events-default/plugin"; +import { Plugin as events } from "../../../plugins/events-default/plugin"; import * as emitDirect from "../../../plugins/events-default/events/emit"; import { broadcast } from "./events/broadcast"; import { emit } from "./events/emit"; import { emitAndReturn } from "./events/emitAndReturn"; import { emitStreamAndReceiveStream } from "./events/emitStreamAndReceiveStream"; -import { IPluginLogger, LogMeta } from "../../../interfaces/logger"; import { randomUUID } from "crypto"; +import { BSBEventsConstructor, PluginLogger } from "../../../base"; +import { SBLogging } from "../../../serviceBase"; -//const fakeCLogger = new Logger("test-plugin", process.cwd(), {} as any); -//const debug = console.log; -//const debug = console.log; -const debug = (...a: any) => {}; -const fakeLogger: IPluginLogger = { - reportStat: async (key, value): Promise => {}, - reportTextStat: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, - info: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, - warn: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, - error: async ( - messageOrError: string | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise => { - debug(messageOrError, meta); - assert.fail( - typeof messageOrError === "string" - ? new Error(messageOrError) - : messageOrError - ); - }, - fatal: async ( - messageOrError: string | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise => { - debug(messageOrError, meta); - assert.fail( - typeof messageOrError === "string" - ? new Error(messageOrError) - : messageOrError - ); - }, - debug: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, +const newSBLogging = () => { + const sbLogging = new SBLogging( + "test-app", + "development", + process.cwd(), + {} as any + ); + sbLogging.logBus.removeAllListeners(); + return sbLogging; }; - -const getPluginConfig = async () => { - return {}; +const generateNullLogging = () => { + const sbLogging = newSBLogging(); + return new PluginLogger("development", "test-plugin", sbLogging); +}; +const getEventsConstructorConfig = (): BSBEventsConstructor => { + return { + appId: "test-app", + pluginCwd: process.cwd(), + cwd: process.cwd(), + mode: "development", + pluginName: "test-plugin", + sbLogging: newSBLogging(), + config: {}, + }; }; describe("plugins/events-default", () => { describe("Events Emit", async () => { it("_lastReceivedMessageIds should be empty on init", async () => { - let emit = new emitDirect.default(fakeLogger); + let emit = new emitDirect.default(generateNullLogging()); assert.equal((emit as any)._lastReceivedMessageIds.length, 0); }); it("_lastReceivedMessageIds should contain latest emit ID", async () => { - let emit = new emitDirect.default(fakeLogger); - await emit.onEvent("a", "b", "c", async () => {}); - await emit.emitEvent("a", "b", "c", []); + let emit = new emitDirect.default(generateNullLogging()); + await emit.onEvent("b", "c", async () => {}); + await emit.emitEvent("b", "c", []); assert.equal((emit as any)._lastReceivedMessageIds.length, 1); }); it("_lastReceivedMessageIds should call only once", async () => { - let emit = new emitDirect.default(fakeLogger); + let emit = new emitDirect.default(generateNullLogging()); let testID = randomUUID(); let called = 0; - await emit.onEvent("a", "b", "c", async () => { + await emit.onEvent("b", "c", async () => { called++; }); emit.emit(`b-c`, { @@ -83,11 +62,11 @@ describe("plugins/events-default", () => { assert.equal(called, 1); }); it("_lastReceivedMessageIds should call only once, per id", async () => { - let emit = new emitDirect.default(fakeLogger); + let emit = new emitDirect.default(generateNullLogging()); let testID1 = randomUUID(); let testID2 = randomUUID(); let called = 0; - await emit.onEvent("a", "b", "c", async () => { + await emit.onEvent("b", "c", async () => { called++; }); emit.emit(`b-c`, { @@ -101,12 +80,12 @@ describe("plugins/events-default", () => { assert.equal(called, 2); }); it("_lastReceivedMessageIds should cycle ids > 50", async () => { - let emit = new emitDirect.default(fakeLogger); + let emit = new emitDirect.default(generateNullLogging()); let testIDs: Array = "." .repeat(100) .split("") .map(() => randomUUID()); - await emit.onEvent("a", "b", "c", async () => {}); + await emit.onEvent("b", "c", async () => {}); for (let emitID of testIDs) emit.emit(`b-c`, { msgID: emitID, @@ -116,46 +95,22 @@ describe("plugins/events-default", () => { }); }); broadcast(async () => { - const refP = new events( - "test-plugin", - process.cwd(), - process.cwd(), - fakeLogger - ); - (refP as any).getPluginConfig = getPluginConfig; + const refP = new events(getEventsConstructorConfig()); if (refP.init !== undefined) await refP.init(); return refP; }, 10); emit(async () => { - const refP = new events( - "test-plugin", - process.cwd(), - process.cwd(), - fakeLogger - ); - (refP as any).getPluginConfig = getPluginConfig; + const refP = new events(getEventsConstructorConfig()); if (refP.init !== undefined) await refP.init(); return refP; }, 10); emitAndReturn(async () => { - const refP = new events( - "test-plugin", - process.cwd(), - process.cwd(), - fakeLogger - ); - (refP as any).getPluginConfig = getPluginConfig; + const refP = new events(getEventsConstructorConfig()); if (refP.init !== undefined) await refP.init(); return refP; }, 10); emitStreamAndReceiveStream(async () => { - const refP = new events( - "test-plugin", - process.cwd(), - process.cwd(), - fakeLogger - ); - (refP as any).getPluginConfig = getPluginConfig; + const refP = new events(getEventsConstructorConfig()); if (refP.init !== undefined) await refP.init(); //refP.eas.staticCommsTimeout = 25; return refP; diff --git a/nodejs/src/tests/plugins/log-default/plugin.ts b/nodejs/src/tests/plugins/log-default/plugin.ts index ba13d0a..827b7f1 100644 --- a/nodejs/src/tests/plugins/log-default/plugin.ts +++ b/nodejs/src/tests/plugins/log-default/plugin.ts @@ -1,5 +1,24 @@ import assert from "assert"; -import { Logger, LOG_LEVELS, LogLevels } from "../../../plugins/log-default/plugin"; +import { + Plugin, + LOG_LEVELS, + LogLevels, +} from "../../../plugins/logging-default/plugin"; +import { BSBLoggingConstructor } from "../../../base"; +import { DEBUG_MODE } from "../../../interfaces"; + +const getLoggingConstructorConfig = ( + mode: DEBUG_MODE = "development" +): BSBLoggingConstructor => { + return { + appId: "test-app", + pluginCwd: process.cwd(), + cwd: process.cwd(), + mode: mode, + pluginName: "test-plugin", + config: {}, + }; +}; describe("plugins/log-default", () => { describe("console.x", () => { @@ -95,25 +114,25 @@ describe("plugins/log-default", () => { consoleExpectMessageContent = null; }; it("should console a stat event", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("debug", [null, "[STAT] [DEFAULT-STAT] [val=2]"]); await plugin.reportStat("default-stat", "val", 2); restoreConsole(); }); it("should console a text stat event", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("debug", [null, "[STAT] [DEFAULT-DBG] My Msg"]); - await plugin.reportTextStat("default-DbG", "My Msg"); + await plugin.reportTextStat("default-DbG", "My Msg", undefined as any); restoreConsole(); }); it("should console a debug event", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("debug", [null, "[DEBUG] [DEFAULT-DBG] My Msg"]); - await plugin.debug("default-DbG", "My Msg"); + await plugin.debug("default-DbG", "My Msg", undefined as any); restoreConsole(); }); it("should console a debug event (meta)", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("debug", [ null, "[DEBUG] [DEFAULT-DBG] My Msg cHEESE and a,b (5)", @@ -127,13 +146,13 @@ describe("plugins/log-default", () => { }); it("should console a info event", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("log", [null, "[INFO] [INFO-DBG] My Msg"]); - await plugin.info("info-DbG", "My Msg"); + await plugin.info("info-DbG", "My Msg", undefined as any); restoreConsole(); }); it("should console a info event (meta)", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("log", [ null, "[INFO] [INFO-DBG] My Msg cHEESE and a,b (5)", @@ -147,13 +166,13 @@ describe("plugins/log-default", () => { }); it("should console a error event", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("error", [null, "[ERROR] [INFEE-DBG] My Msg"]); - await plugin.error("infee-DbG", "My Msg"); + await plugin.error("infee-DbG", "My Msg", undefined as any); restoreConsole(); }); it("should console a error event (meta)", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("error", [ null, "[ERROR] [INFE-DBG] My Msg cHEESE and a,b (5)", @@ -167,13 +186,13 @@ describe("plugins/log-default", () => { }); it("should console a warn event", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("warn", [null, "[WARN] [INFOW-DBG] My Msg"]); - await plugin.warn("infoW-DbG", "My Msg"); + await plugin.warn("infoW-DbG", "My Msg", undefined as any); restoreConsole(); }); it("should console a warn event (meta)", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("warn", [ null, "[WARN] [INFW-DBG] My Msg cHEESE and a,b (5)", @@ -187,9 +206,7 @@ describe("plugins/log-default", () => { }); it("running debug, should debug everything", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = true; - (plugin as any).runningLive = false; + const plugin = new Plugin(getLoggingConstructorConfig("development")); storeConsole("debug", [ null, "[DEBUG] [DEFAULT-DBG] My Msg cHEESE and a,b (5)", @@ -202,9 +219,7 @@ describe("plugins/log-default", () => { restoreConsole(); }); it("running non-debug, should not debug anything", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = false; - (plugin as any).runningLive = false; + const plugin = new Plugin(getLoggingConstructorConfig("production")); storeConsole("debug"); await plugin.debug("infW-DbG", "My Msg {che} and {chi} ({te})", { che: "cHEESE", @@ -213,11 +228,14 @@ describe("plugins/log-default", () => { }); restoreConsole(); }); - it("running live-debug, should not debug anything", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = false; - (plugin as any).runningLive = true; - storeConsole("debug"); + it("running live-debug, should debug", async () => { + const plugin = new Plugin( + getLoggingConstructorConfig("production-debug") + ); + storeConsole("debug", [ + null, + "[DEBUG] [INFW-DBG] My Msg cHEESE and a,b (5)", + ]); await plugin.debug("infW-DbG", "My Msg {che} and {chi} ({te})", { che: "cHEESE", chi: ["a", "b"], @@ -226,69 +244,46 @@ describe("plugins/log-default", () => { restoreConsole(); }); - it("running non-debug, should not stat anything", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); + /*it("running non-debug, should not stat anything", async () => { + const plugin = new Plugin(getLoggingConstructorConfig("")); (plugin as any).runningDebug = false; (plugin as any).runningLive = false; storeConsole("debug"); await plugin.reportStat("infW-DbG", "a", 3); restoreConsole(); - }); - it("running live, should not output PI info", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = false; - (plugin as any).runningLive = true; - storeConsole("log"); - await plugin.info( - "infW-DbG", - "My Msg {che} and {chi} ({te})", - { - che: "cHEESE", - chi: ["a", "b"], - te: 5, - }, - true - ); - restoreConsole(); - }); - it("running live, should not output PI warn", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = false; - (plugin as any).runningLive = true; - storeConsole("warn"); - await plugin.warn( - "infW-DbG", - "My Msg {che} and {chi} ({te})", - { - che: "cHEESE", - chi: ["a", "b"], - te: 5, - }, - true - ); - restoreConsole(); - }); - it("running live, should not output PI error", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = false; - (plugin as any).runningLive = true; - storeConsole("error"); - await plugin.error( - "infW-DbG", - "My Msg {che} and {chi} ({te})", - { - che: "cHEESE", - chi: ["a", "b"], - te: 5, - }, - true - ); - restoreConsole(); - }); + });*/ + // it("running live, should not output PI info", async () => { + // const plugin = new Plugin(getLoggingConstructorConfig("production")); + // storeConsole("log"); + // await plugin.info("infW-DbG", "My Msg {che} and {chi} ({te})", { + // che: "cHEESE", + // chi: ["a", "b"], + // te: 5, + // }); + // restoreConsole(); + // }); + // it("running live, should not output PI warn", async () => { + // const plugin = new Plugin(getLoggingConstructorConfig("production")); + // storeConsole("warn"); + // await plugin.warn("infW-DbG", "My Msg {che} and {chi} ({te})", { + // che: "cHEESE", + // chi: ["a", "b"], + // te: 5, + // }); + // restoreConsole(); + // }); + // it("running live, should not output PI error", async () => { + // const plugin = new Plugin(getLoggingConstructorConfig("production")); + // storeConsole("error"); + // await plugin.error("infW-DbG", "My Msg {che} and {chi} ({te})", { + // che: "cHEESE", + // chi: ["a", "b"], + // te: 5, + // }); + // restoreConsole(); + // }); it("Stack report", async () => { - const plugin = new Logger("default-logger", "./", "./", null as any); - (plugin as any).runningDebug = true; - (plugin as any).runningLive = false; + const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("error", undefined, [ "test-error", "src/tests/plugins/log-default/plugin.ts:", @@ -304,13 +299,7 @@ describe("plugins/log-default", () => { assert.equal(message, "[STAT] [DEFAULT-STAT] [val=2]"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); await plugin.reportStat("default-stat", "val", 2); }); @@ -320,14 +309,8 @@ describe("plugins/log-default", () => { assert.equal(message, "[DEBUG] [DEFAULT-DBG] My Msg"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); - await plugin.debug("default-DbG", "My Msg"); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); + await plugin.debug("default-DbG", "My Msg", undefined as any); }); it("should mocked a debug event (meta)", async () => { const fakeLogFunc = (level: LogLevels, message: string): any => { @@ -338,13 +321,7 @@ describe("plugins/log-default", () => { ); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); await plugin.debug("default-DbG", "My Msg {che} and {chi} ({te})", { che: "cHEESE", chi: ["a", "b"], @@ -358,14 +335,8 @@ describe("plugins/log-default", () => { assert.equal(message, "[INFO] [INFO-DBG] My Msg"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); - await plugin.info("info-DbG", "My Msg"); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); + await plugin.info("info-DbG", "My Msg", undefined as any); }); it("should mocked a info event (meta)", async () => { const fakeLogFunc = (level: LogLevels, message: string): any => { @@ -373,13 +344,7 @@ describe("plugins/log-default", () => { assert.equal(message, "[INFO] [INFO-DBG] My Msg cHEESE and a,b (5)"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); await plugin.info("info-DbG", "My Msg {che} and {chi} ({te})", { che: "cHEESE", chi: ["a", "b"], @@ -393,14 +358,8 @@ describe("plugins/log-default", () => { assert.equal(message, "[ERROR] [INFEE-DBG] My Msg"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); - await plugin.error("infee-DbG", "My Msg"); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); + await plugin.error("infee-DbG", "My Msg", undefined as any); }); it("should mocked a error event (meta)", async () => { const fakeLogFunc = (level: LogLevels, message: string): any => { @@ -408,13 +367,7 @@ describe("plugins/log-default", () => { assert.equal(message, "[ERROR] [INFE-DBG] My Msg cHEESE and a,b (5)"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); await plugin.error("infe-DbG", "My Msg {che} and {chi} ({te})", { che: "cHEESE", chi: ["a", "b"], @@ -428,14 +381,8 @@ describe("plugins/log-default", () => { assert.equal(message, "[WARN] [INFOW-DBG] My Msg"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); - await plugin.warn("infoW-DbG", "My Msg"); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); + await plugin.warn("infoW-DbG", "My Msg", undefined as any); }); it("should mocked a warn event (meta)", async () => { const fakeLogFunc = (level: LogLevels, message: string): any => { @@ -443,13 +390,7 @@ describe("plugins/log-default", () => { assert.equal(message, "[WARN] [INFW-DBG] My Msg cHEESE and a,b (5)"); }; - const plugin = new Logger( - "default-logger", - "./", - "./", - null as any, - fakeLogFunc - ); + const plugin = new Plugin(getLoggingConstructorConfig(), fakeLogFunc); await plugin.warn("infW-DbG", "My Msg {che} and {chi} ({te})", { che: "cHEESE", chi: ["a", "b"], diff --git a/nodejs/src/tests/serviceBase/services.ts b/nodejs/src/tests/serviceBase/services.ts index 4caefb0..f07b370 100644 --- a/nodejs/src/tests/serviceBase/services.ts +++ b/nodejs/src/tests/serviceBase/services.ts @@ -1,271 +1,271 @@ -import assert from "assert"; -import { IPluginLogger, LogMeta } from "../../interfaces/logger"; -import { ServicesBase } from "../../service/service"; -import { SBServices } from "../../serviceBase/services"; +// import assert from "assert"; +// import { IPluginLogger, LogMeta } from "../../interfaces/logging"; +// import { ServicesBase } from "../../service/service"; +// import { SBServices } from "../../serviceBase/services"; -//const debug = console.log; -const debug = (...a: any) => {}; -const fakeLogger: IPluginLogger = { - reportStat: async (key, value): Promise => {}, - reportTextStat: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, - info: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, - warn: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, - error: async ( - messageOrError: string | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise => { - debug(messageOrError, meta); - assert.fail( - typeof messageOrError === "string" - ? new Error(messageOrError) - : messageOrError - ); - }, - fatal: async ( - messageOrError: string | Error, - meta?: LogMeta, - hasPIData?: boolean - ): Promise => { - debug(messageOrError, meta); - assert.fail( - typeof messageOrError === "string" - ? new Error(messageOrError) - : messageOrError - ); - }, - debug: async (message, meta, hasPIData): Promise => { - debug(message, meta); - }, -}; +// //const debug = console.log; +// const debug = (...a: any) => {}; +// const fakeLogger: IPluginLogger = { +// reportStat: async (key, value): Promise => {}, +// reportTextStat: async (message, meta, hasPIData): Promise => { +// debug(message, meta); +// }, +// info: async (message, meta, hasPIData): Promise => { +// debug(message, meta); +// }, +// warn: async (message, meta, hasPIData): Promise => { +// debug(message, meta); +// }, +// error: async ( +// messageOrError: string | Error, +// meta?: LogMeta, +// hasPIData?: boolean +// ): Promise => { +// debug(messageOrError, meta); +// assert.fail( +// typeof messageOrError === "string" +// ? new Error(messageOrError) +// : messageOrError +// ); +// }, +// fatal: async ( +// messageOrError: string | Error, +// meta?: LogMeta, +// hasPIData?: boolean +// ): Promise => { +// debug(messageOrError, meta); +// assert.fail( +// typeof messageOrError === "string" +// ? new Error(messageOrError) +// : messageOrError +// ); +// }, +// debug: async (message, meta, hasPIData): Promise => { +// debug(message, meta); +// }, +// }; -describe("serviceBase/services", () => { - it("Should re-order plugins that require other plugins", async () => { - let services = new SBServices(fakeLogger); - let plugins: { - name: string; - after: string[]; - before: string[]; - ref: ServicesBase; - }[] = [ - { - name: "plugin1", - after: ["plugin2"], - before: [], - ref: {} as any, - }, - { - name: "plugin2", - after: [], - before: [], - ref: {} as any, - }, - { - name: "plugin3", - after: [], - before: [], - ref: {} as any, - }, - ]; - plugins = await services.makeAfterRequired( - { - getAppPluginMappedName: async (x: string) => { - return x; - }, - } as any, - plugins - ); - services.dispose(); - assert.equal(plugins[0].name, "plugin2"); - assert.equal(plugins[1].name, "plugin1"); - assert.equal(plugins[2].name, "plugin3"); - }); - it("Should re-order plugins that before other plugins", async () => { - let services = new SBServices(fakeLogger); - let plugins: { - name: string; - after: string[]; - before: string[]; - ref: ServicesBase; - }[] = [ - { - name: "plugin1", - after: ["plugin2"], - before: [], - ref: {} as any, - }, - { - name: "plugin2", - after: [], - before: [], - ref: {} as any, - }, - { - name: "plugin3", - after: [], - before: ["plugin1"], - ref: {} as any, - }, - ]; - plugins = await services.makeBeforeRequired( - { - getAppPluginMappedName: async (x: string) => { - return x; - }, - } as any, - plugins - ); - assert.equal(plugins[0].after.length, 2); - assert.equal(plugins[0].after[0], "plugin2"); - assert.equal(plugins[0].after[1], "plugin3"); - assert.equal(plugins[1].after.length, 0); - assert.equal(plugins[2].after.length, 0); - plugins = await services.makeAfterRequired( - { - getAppPluginMappedName: async (x: string) => { - return x; - }, - } as any, - plugins - ); - services.dispose(); - assert.equal(plugins[0].name, "plugin2"); - assert.equal(plugins[1].name, "plugin3"); - assert.equal(plugins[2].name, "plugin1"); - }); - it("Should re-order plugins that before or require other plugins", async () => { - let services = new SBServices(fakeLogger); - let plugins: { - name: string; - after: string[]; - before: string[]; - ref: ServicesBase; - }[] = [ - { - name: "plugin1", - after: ["plugin2"], - before: [], - ref: {} as any, - }, - { - name: "plugin2", - after: [], - before: [], - ref: {} as any, - }, - { - name: "plugin3", - after: [], - before: ["plugin1"], - ref: {} as any, - }, - { - name: "plugin4", - after: ["plugin3"], - before: ["plugin1"], - ref: {} as any, - }, - ]; - plugins = await services.makeBeforeRequired( - { - getAppPluginMappedName: async (x: string) => { - return x; - }, - } as any, - plugins - ); - plugins = await services.makeAfterRequired( - { - getAppPluginMappedName: async (x: string) => { - return x; - }, - } as any, - plugins - ); - services.dispose(); - assert.equal(plugins[3].name, "plugin1", "plugin 1 not last"); - assert.equal(plugins[3].after.length, 3, "length of after does not match"); - assert.equal(plugins[3].after[0], "plugin2", "plugin 1 required plugin 2"); - assert.equal(plugins[3].after[1], "plugin3", "plugin 1 required plugin 3"); - assert.equal(plugins[3].after[2], "plugin4", "plugin 1 required plugin 4"); - assert.equal(plugins[0].after.length, 0, "plugin 2 after nothing"); - assert.equal(plugins[1].after.length, 0, "plugin 3 after nothing"); - assert.equal(plugins[0].name, "plugin2"); - assert.equal(plugins[1].name, "plugin3"); - assert.equal(plugins[2].name, "plugin4"); - assert.equal(plugins[3].name, "plugin1"); - }); +// describe("serviceBase/services", () => { +// it("Should re-order plugins that require other plugins", async () => { +// let services = new SBServices(fakeLogger); +// let plugins: { +// name: string; +// after: string[]; +// before: string[]; +// ref: ServicesBase; +// }[] = [ +// { +// name: "plugin1", +// after: ["plugin2"], +// before: [], +// ref: {} as any, +// }, +// { +// name: "plugin2", +// after: [], +// before: [], +// ref: {} as any, +// }, +// { +// name: "plugin3", +// after: [], +// before: [], +// ref: {} as any, +// }, +// ]; +// plugins = await services.makeAfterRequired( +// { +// getAppPluginMappedName: async (x: string) => { +// return x; +// }, +// } as any, +// plugins +// ); +// services.dispose(); +// assert.equal(plugins[0].name, "plugin2"); +// assert.equal(plugins[1].name, "plugin1"); +// assert.equal(plugins[2].name, "plugin3"); +// }); +// it("Should re-order plugins that before other plugins", async () => { +// let services = new SBServices(fakeLogger); +// let plugins: { +// name: string; +// after: string[]; +// before: string[]; +// ref: ServicesBase; +// }[] = [ +// { +// name: "plugin1", +// after: ["plugin2"], +// before: [], +// ref: {} as any, +// }, +// { +// name: "plugin2", +// after: [], +// before: [], +// ref: {} as any, +// }, +// { +// name: "plugin3", +// after: [], +// before: ["plugin1"], +// ref: {} as any, +// }, +// ]; +// plugins = await services.makeBeforeRequired( +// { +// getAppPluginMappedName: async (x: string) => { +// return x; +// }, +// } as any, +// plugins +// ); +// assert.equal(plugins[0].after.length, 2); +// assert.equal(plugins[0].after[0], "plugin2"); +// assert.equal(plugins[0].after[1], "plugin3"); +// assert.equal(plugins[1].after.length, 0); +// assert.equal(plugins[2].after.length, 0); +// plugins = await services.makeAfterRequired( +// { +// getAppPluginMappedName: async (x: string) => { +// return x; +// }, +// } as any, +// plugins +// ); +// services.dispose(); +// assert.equal(plugins[0].name, "plugin2"); +// assert.equal(plugins[1].name, "plugin3"); +// assert.equal(plugins[2].name, "plugin1"); +// }); +// it("Should re-order plugins that before or require other plugins", async () => { +// let services = new SBServices(fakeLogger); +// let plugins: { +// name: string; +// after: string[]; +// before: string[]; +// ref: ServicesBase; +// }[] = [ +// { +// name: "plugin1", +// after: ["plugin2"], +// before: [], +// ref: {} as any, +// }, +// { +// name: "plugin2", +// after: [], +// before: [], +// ref: {} as any, +// }, +// { +// name: "plugin3", +// after: [], +// before: ["plugin1"], +// ref: {} as any, +// }, +// { +// name: "plugin4", +// after: ["plugin3"], +// before: ["plugin1"], +// ref: {} as any, +// }, +// ]; +// plugins = await services.makeBeforeRequired( +// { +// getAppPluginMappedName: async (x: string) => { +// return x; +// }, +// } as any, +// plugins +// ); +// plugins = await services.makeAfterRequired( +// { +// getAppPluginMappedName: async (x: string) => { +// return x; +// }, +// } as any, +// plugins +// ); +// services.dispose(); +// assert.equal(plugins[3].name, "plugin1", "plugin 1 not last"); +// assert.equal(plugins[3].after.length, 3, "length of after does not match"); +// assert.equal(plugins[3].after[0], "plugin2", "plugin 1 required plugin 2"); +// assert.equal(plugins[3].after[1], "plugin3", "plugin 1 required plugin 3"); +// assert.equal(plugins[3].after[2], "plugin4", "plugin 1 required plugin 4"); +// assert.equal(plugins[0].after.length, 0, "plugin 2 after nothing"); +// assert.equal(plugins[1].after.length, 0, "plugin 3 after nothing"); +// assert.equal(plugins[0].name, "plugin2"); +// assert.equal(plugins[1].name, "plugin3"); +// assert.equal(plugins[2].name, "plugin4"); +// assert.equal(plugins[3].name, "plugin1"); +// }); - it("Should re-order plugins that before or require other plugins (mapped names)", async () => { - let services = new SBServices(fakeLogger); - let plugins: { - name: string; - after: string[]; - before: string[]; - ref: ServicesBase; - _mappedName: string; - }[] = [ - { - name: "pligin1", - after: ["plugin2"], - before: [], - ref: {} as any, - _mappedName: "plugin1", - }, - { - name: "pligin2", - after: [], - before: [], - ref: {} as any, - _mappedName: "plugin2", - }, - { - name: "pligin3", - after: [], - before: ["plugin1"], - ref: {} as any, - _mappedName: "plugin3", - }, - { - name: "pligin4", - after: ["plugin3"], - before: ["plugin1"], - ref: {} as any, - _mappedName: "plugin4", - }, - ]; - const appConfigPass = { - getAppPluginMappedName: async (x: string) => { - for (let plugin of plugins) { - if (plugin._mappedName === x) { - return plugin.name; - } - } - return x; - }, - } as any; - plugins = (await services.makeBeforeRequired( - appConfigPass, - plugins - )) as any; - plugins = (await services.makeAfterRequired(appConfigPass, plugins)) as any; - services.dispose(); - assert.equal(plugins[3].name, "pligin1", "plugin 1 not last"); - assert.equal(plugins[3].after.length, 3, "length of after does not match"); - assert.equal(plugins[3].after[0], "pligin2", "plugin 1 required plugin 2"); - assert.equal(plugins[3].after[1], "pligin3", "plugin 1 required plugin 3"); - assert.equal(plugins[3].after[2], "pligin4", "plugin 1 required plugin 4"); - assert.equal(plugins[0].after.length, 0, "plugin 2 after nothing"); - assert.equal(plugins[1].after.length, 0, "plugin 3 after nothing"); - assert.equal(plugins[0].name, "pligin2"); - assert.equal(plugins[1].name, "pligin3"); - assert.equal(plugins[2].name, "pligin4"); - assert.equal(plugins[3].name, "pligin1"); - }); -}); +// it("Should re-order plugins that before or require other plugins (mapped names)", async () => { +// let services = new SBServices(fakeLogger); +// let plugins: { +// name: string; +// after: string[]; +// before: string[]; +// ref: ServicesBase; +// _mappedName: string; +// }[] = [ +// { +// name: "pligin1", +// after: ["plugin2"], +// before: [], +// ref: {} as any, +// _mappedName: "plugin1", +// }, +// { +// name: "pligin2", +// after: [], +// before: [], +// ref: {} as any, +// _mappedName: "plugin2", +// }, +// { +// name: "pligin3", +// after: [], +// before: ["plugin1"], +// ref: {} as any, +// _mappedName: "plugin3", +// }, +// { +// name: "pligin4", +// after: ["plugin3"], +// before: ["plugin1"], +// ref: {} as any, +// _mappedName: "plugin4", +// }, +// ]; +// const appConfigPass = { +// getAppPluginMappedName: async (x: string) => { +// for (let plugin of plugins) { +// if (plugin._mappedName === x) { +// return plugin.name; +// } +// } +// return x; +// }, +// } as any; +// plugins = (await services.makeBeforeRequired( +// appConfigPass, +// plugins +// )) as any; +// plugins = (await services.makeAfterRequired(appConfigPass, plugins)) as any; +// services.dispose(); +// assert.equal(plugins[3].name, "pligin1", "plugin 1 not last"); +// assert.equal(plugins[3].after.length, 3, "length of after does not match"); +// assert.equal(plugins[3].after[0], "pligin2", "plugin 1 required plugin 2"); +// assert.equal(plugins[3].after[1], "pligin3", "plugin 1 required plugin 3"); +// assert.equal(plugins[3].after[2], "pligin4", "plugin 1 required plugin 4"); +// assert.equal(plugins[0].after.length, 0, "plugin 2 after nothing"); +// assert.equal(plugins[1].after.length, 0, "plugin 3 after nothing"); +// assert.equal(plugins[0].name, "pligin2"); +// assert.equal(plugins[1].name, "pligin3"); +// assert.equal(plugins[2].name, "pligin4"); +// assert.equal(plugins[3].name, "pligin1"); +// }); +// }); diff --git a/nodejs/src/tests/test-logger.ts b/nodejs/src/tests/test-logger.ts index dae6519..71a2021 100644 --- a/nodejs/src/tests/test-logger.ts +++ b/nodejs/src/tests/test-logger.ts @@ -1,46 +1,46 @@ -import assert from "assert"; -import { IPluginLogger, LogMeta } from "../interfaces/logger"; -import { LoggerBase } from "../logger/logger"; +// import assert from "assert"; +// import { IPluginLogger, LogMeta } from "../interfaces/logging"; +// import { LoggerBase } from "../logger/logger"; -export class Logger extends LoggerBase { - constructor( - pluginName: string, - cwd: string, - pluginCwd: string, - defaultLogger: IPluginLogger - ) { - super(pluginName, cwd, pluginCwd, defaultLogger); - } +// export class Logger extends LoggerBase { +// constructor( +// pluginName: string, +// cwd: string, +// pluginCwd: string, +// defaultLogger: IPluginLogger +// ) { +// super(pluginName, cwd, pluginCwd, defaultLogger); +// } - public async reportStat( - plugin: string, - key: string, - value: number - ): Promise {} - public async debug( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise {} - public async info( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise {} - public async warn( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise {} - public async error( - plugin: string, - message: T, - meta?: LogMeta, - hasPIData?: boolean - ): Promise { - assert.fail(new Error(message)); - } -} +// public async reportStat( +// plugin: string, +// key: string, +// value: number +// ): Promise {} +// public async debug( +// plugin: string, +// message: T, +// meta?: LogMeta, +// hasPIData?: boolean +// ): Promise {} +// public async info( +// plugin: string, +// message: T, +// meta?: LogMeta, +// hasPIData?: boolean +// ): Promise {} +// public async warn( +// plugin: string, +// message: T, +// meta?: LogMeta, +// hasPIData?: boolean +// ): Promise {} +// public async error( +// plugin: string, +// message: T, +// meta?: LogMeta, +// hasPIData?: boolean +// ): Promise { +// assert.fail(new Error(message)); +// } +// } diff --git a/nodejs/tsconfig-release.json b/nodejs/tsconfig-release.json new file mode 100644 index 0000000..e064aaf --- /dev/null +++ b/nodejs/tsconfig-release.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": ["types/*"] + }, + "module": "commonjs", + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "sourceMap": true, + "outDir": "lib", + "rootDir": "src", + "strict": true, + "target": "es2021", + "lib": ["es2021"], + "declaration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node" + }, + "linterOptions": { + "exclude": [ + "src/plugins/-*/**/*.*", + "src/tests/**/*.*" + ] + }, + "compileOnSave": true, + "include": [ + "src" + ], + "exclude": [ + "node_modules/**", + "src/plugins/*-test*/**/*.*", + "src/plugins/-*/**/*.*", + "src/plugins/service-*/**/*.*", + "src/tests/**/*.*" + ] +} \ No newline at end of file diff --git a/nodejs/tsconfig.json b/nodejs/tsconfig.json index fe15773..cb80be8 100644 --- a/nodejs/tsconfig.json +++ b/nodejs/tsconfig.json @@ -36,7 +36,6 @@ "exclude": [ "node_modules/**", "src/plugins/*-test*/**/*.*", - "src/plugins/-*/**/*.*", - "src/plugins/service-*/**/*.*" + "src/plugins/-*/**/*.*" ] } \ No newline at end of file From 24913de39a2c73a35b5b379da09473091a9d6979 Mon Sep 17 00:00:00 2001 From: mrinc Date: Thu, 14 Dec 2023 19:58:50 +0200 Subject: [PATCH 14/47] feat(sec-config.yaml): enable service-default0X, service-default1X, service-default2X, and service-default3X plugins feat(base.ts): import BSBServiceConfig from serviceConfig feat(base.ts): change BSBConfigDefinition to BSBConfigType feat(base.ts): add BSBConfigDefinition type alias for BSBServiceConfig feat(config.ts): add run() function to BSBConfigRef class feat(events.ts): add run() function to BSBEventsRef class feat(logging.ts): add run() function to BSBLoggingRef class feat(serviceConfig.ts): create BSBServiceConfig abstract class feat(serviceConfig.ts): create BSBServiceConfigRef class refactor(index.ts): update import path for serviceConfig refactor(serviceConfig.ts): move serviceConfig interface to base folder and rename to BSBServiceConfig chore(interfaces.ts): add ExtendedConfig interface to extend logging, events, and services config interfaces chore(interfaces.ts): update logging, events, and services config interfaces to include ExtendedConfig chore(plugin.ts): remove unused run method in Plugin class chore(plugin.ts): update return value of getConfig method in Plugin class to handle undefined config chore(plugin.ts): remove unused run method in Plugin class chore(plugin.ts): remove unused dispose method in Plugin class chore(plugin.ts): remove unused run method in Plugin class chore(plugin.ts): remove unused dispose method in Plugin class chore(plugin.ts): remove unused run method in Plugin class chore(plugin.ts): remove unused dispose method in Plugin class chore(plugin.ts): remove unused run method in Plugin class chore(plugin.ts): remove unused dispose method in Plugin class chore(plugin.ts): remove unused run method in Plugin class chore(plugin.ts): remove fix(config.ts): change variable names from loggerPackage to configPackage and loggerPlugin to configPluginName feat(config.ts): add support for process.env.BSB_LOGGER_PLUGIN and process.env.BSB_LOGGER_PLUGIN_PACKAGE environment variables fix(config.ts): update log messages to use the new variable names fix(config.ts): update plugin loading to use the new variable names fix(config.ts): update log messages to use the new variable names fix(config.ts): update log messages to use the new variable names fix(config.ts): update log messages to use the new variable names fix(config.ts): update log messages to use the new variable names fix(config.ts): update log messages to use the new variable names fix(config.ts): update log messages to use the new variable names fix(config.ts): update log messages to use the new variable names fix(config.ts): update log messages to use the new variable names fix(config.ts): update log messages to use the new fix(plugins.ts): fix import statement for BSBServiceConfig fix(plugins.ts): fix variable name from installerFile to configDefFile fix(plugins.ts): fix variable name from importedConfig.Config to importedConfig.ConfigRef fix(plugins.ts): fix variable name from serviceConfigDef to serviceConfig fix(plugins.ts): fix condition for importing serviceConfig fix(plugins.ts): fix error message for missing Config class in sec-config.ts/js fix(serviceBase.ts): add missing await statements for logging and events fix(services.ts): fix import statement for SmartFunctionCallAsync and SmartFunctionCallSync fix(services.ts): fix indentation fix(services.ts): fix variable name from pluginConfig to newPlugin.serviceConfig fix(services.ts): fix condition for parsing pluginConfig fix(services.ts): fix log level for adding service plugin fix(services.ts): fix log level for constructing service plugin client fix(services.ts): --- nodejs/package-lock.json | 423 ++++++++++-------- nodejs/sec-config.yaml | 11 +- nodejs/src/base/base.ts | 10 +- nodejs/src/base/config.ts | 15 +- nodejs/src/base/events.ts | 8 +- nodejs/src/base/logging.ts | 15 +- nodejs/src/base/serviceConfig.ts | 23 + nodejs/src/interfaces/index.ts | 2 +- nodejs/src/interfaces/serviceConfig.ts | 13 - .../src/plugins/config-default/interfaces.ts | 24 +- nodejs/src/plugins/config-default/plugin.ts | 3 +- nodejs/src/plugins/events-default/plugin.ts | 8 +- nodejs/src/plugins/logging-default/plugin.ts | 4 +- nodejs/src/plugins/service-default0/plugin.ts | 10 +- .../plugins/service-default0/sec-config.ts | 30 ++ .../plugins/service-default0/sec.config.ts | 19 - nodejs/src/serviceBase/config.ts | 46 +- nodejs/src/serviceBase/events.ts | 26 +- nodejs/src/serviceBase/logging.ts | 32 +- nodejs/src/serviceBase/plugins.ts | 85 ++-- nodejs/src/serviceBase/serviceBase.ts | 2 + nodejs/src/serviceBase/services.ts | 24 +- 22 files changed, 496 insertions(+), 337 deletions(-) create mode 100644 nodejs/src/base/serviceConfig.ts delete mode 100644 nodejs/src/interfaces/serviceConfig.ts create mode 100644 nodejs/src/plugins/service-default0/sec-config.ts delete mode 100644 nodejs/src/plugins/service-default0/sec.config.ts diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 3e572ea..98022c0 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -61,12 +61,12 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz", - "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.10", + "@babel/highlight": "^7.23.4", "chalk": "^2.4.2" }, "engines": { @@ -145,34 +145,34 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.10.tgz", - "integrity": "sha512-fTmqbbUBAwCcre6zPzNngvsI0aNrPZe77AeqvDxWM9Nm+04RrJ3CAmGHA9f7lJQY6ZMhRztNemy4uslDxTX4Qw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz", + "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-compilation-targets": "^7.22.10", - "@babel/helper-module-transforms": "^7.22.9", - "@babel/helpers": "^7.22.10", - "@babel/parser": "^7.22.10", - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.6", + "@babel/parser": "^7.23.6", + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.6", + "@babel/types": "^7.23.6", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", - "json5": "^2.2.2", + "json5": "^2.2.3", "semver": "^6.3.1" }, "engines": { @@ -183,6 +183,12 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, "node_modules/@babel/core/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -193,12 +199,12 @@ } }, "node_modules/@babel/generator": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.10.tgz", - "integrity": "sha512-79KIf7YiWjjdZ81JnLujDRApWtl7BxTqWD88+FFdQEIOG8LJ0etDOM7CXuIgGJa55sGOwZVwuEsaLEm0PJ5/+A==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", "dev": true, "dependencies": { - "@babel/types": "^7.22.10", + "@babel/types": "^7.23.6", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -208,14 +214,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.10.tgz", - "integrity": "sha512-JMSwHD4J7SLod0idLq5PKgI+6g/hLD/iuWBq08ZX49xE14VpVEojJ5rHWptpirV2j020MvypRLAXAO50igCJ5Q==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.5", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -233,22 +239,22 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dev": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" @@ -267,28 +273,28 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.5.tgz", - "integrity": "sha512-8Dl6+HD/cKifutF5qGd/8ZJi84QeAKh+CEe1sBzz8UayBBGg1dAIJrdHOcOM5b2MpzWL2yuotJTtGjETq0qjXg==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.9.tgz", - "integrity": "sha512-t+WA2Xn5K+rTeGtC8jCsdAH52bjggG5TKRuRrAGNM/mjIbO4GxvlLMFOEz9wXY5I2XQ60PMFsAG2WIcG82dQMQ==", + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", "@babel/helper-simple-access": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.5" + "@babel/helper-validator-identifier": "^7.22.20" }, "engines": { "node": ">=6.9.0" @@ -322,53 +328,53 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz", - "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.10.tgz", - "integrity": "sha512-a41J4NW8HyZa1I1vAndrraTlPZ/eZoga2ZgS7fEr0tZJGVU4xqdE80CEm0CcNjha5EZ8fTBYLKHF0kqDUuAwQw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", + "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", "dev": true, "dependencies": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.10", - "@babel/types": "^7.22.10" + "@babel/template": "^7.22.15", + "@babel/traverse": "^7.23.6", + "@babel/types": "^7.23.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz", - "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==", + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, @@ -448,9 +454,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.10.tgz", - "integrity": "sha512-lNbdGsQb9ekfsnjFGhEiF4hfFqGgfOP3H3d27re3n+CGhNuTSUEQdfWk556sTLNTloczcdM5TYF2LhzmDQKyvQ==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -460,34 +466,34 @@ } }, "node_modules/@babel/template": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.5.tgz", - "integrity": "sha512-X7yV7eiwAxdj9k94NEylvbVHLiVG1nvzCV2EAowhxLTwODV1jl9UzZ48leOC0sH7OnuHrIkllaBgneUykIcZaw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.5", - "@babel/parser": "^7.22.5", - "@babel/types": "^7.22.5" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.10.tgz", - "integrity": "sha512-Q/urqV4pRByiNNpb/f5OSv28ZlGJiFiiTh+GAHktbIrkPhPbl90+uW6SmpoLyZqutrg9AEaEf3Q/ZBRHBXgxig==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", + "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.10", - "@babel/generator": "^7.22.10", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", "@babel/helper-hoist-variables": "^7.22.5", "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.10", - "@babel/types": "^7.22.10", - "debug": "^4.1.0", + "@babel/parser": "^7.23.6", + "@babel/types": "^7.23.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -504,13 +510,13 @@ } }, "node_modules/@babel/types": { - "version": "7.22.10", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.10.tgz", - "integrity": "sha512-obaoigiLrlDZ7TUQln/8m4mSqIW2QFeOrCQc9r+xsaHGNoplVNYlRVpsfE8Vj35GEm2ZH4ZhrNYogs/3fj85kg==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", + "integrity": "sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -566,18 +572,18 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.6.2.tgz", - "integrity": "sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==", + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -598,21 +604,21 @@ } }, "node_modules/@eslint/js": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.47.0.tgz", - "integrity": "sha512-P6omY1zv5MItm93kLM8s2vr1HICJH8v0dvddDhysbIuZ+vcjOHg5Zbkf1mTkcmi2JA9oBG2anOkRnW8WJTS8Og==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", + "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@humanwhocodes/config-array": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz", - "integrity": "sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -634,9 +640,9 @@ } }, "node_modules/@humanwhocodes/object-schema": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { @@ -786,9 +792,9 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.20", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz", + "integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -855,21 +861,21 @@ "dev": true }, "node_modules/@types/assert": { - "version": "1.5.6", - "resolved": "https://registry.npmjs.org/@types/assert/-/assert-1.5.6.tgz", - "integrity": "sha512-Y7gDJiIqb9qKUHfBQYOWGngUpLORtirAVPuj/CWJrU2C6ZM4/y3XLwuwfGMF8s7QzW746LQZx23m0+1FSgjfug==", + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/@types/assert/-/assert-1.5.10.tgz", + "integrity": "sha512-qEO+AUgYab7GVbeDDgUNCU3o0aZUoIMpNAe+w5LDbRxfxQX7vQAdDgwj1AroX+i8KaV56FWg0srXlSZROnsrIQ==", "dev": true }, "node_modules/@types/chai": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz", - "integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng==", + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", + "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", "dev": true }, "node_modules/@types/json-schema": { - "version": "7.0.12", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", - "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/mocha": { @@ -887,24 +893,24 @@ } }, "node_modules/@types/semver": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.0.tgz", - "integrity": "sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "node_modules/@types/yargs": { - "version": "17.0.24", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", - "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "version": "17.0.32", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.32.tgz", + "integrity": "sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==", "dev": true, "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { @@ -1095,10 +1101,16 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1117,9 +1129,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.1.tgz", + "integrity": "sha512-TgUZgYvqZprrl7YldZNoa9OciCAyZR+Ejm9eXzKCmjsF5IKp/wgQ7Z/ZpjpGTIUPwrHQIcYeI8qDh4PsEwxMbw==", "dev": true, "engines": { "node": ">=0.4.0" @@ -1292,9 +1304,9 @@ "dev": true }, "node_modules/browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", "dev": true, "funding": [ { @@ -1311,10 +1323,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -1357,9 +1369,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001520", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001520.tgz", - "integrity": "sha512-tahF5O9EiiTzwTUqAeFjIZbn4Dnqxzz7ktrgGlMYNLH43Ul26IgTMH/zvL3DG0lZxBYnlT04axvInszUsZULdA==", + "version": "1.0.30001570", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz", + "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==", "dev": true, "funding": [ { @@ -1541,9 +1553,9 @@ } }, "node_modules/crypto-js": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.1.1.tgz", - "integrity": "sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw==" + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" }, "node_modules/debug": { "version": "4.3.4", @@ -1638,9 +1650,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.490", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.490.tgz", - "integrity": "sha512-6s7NVJz+sATdYnIwhdshx/N/9O6rvMxmhVoDSDFdj6iA45gHR8EQje70+RYsF4GeB+k0IeNSBnP7yG9ZXJFr7A==", + "version": "1.4.612", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.612.tgz", + "integrity": "sha512-dM8BMtXtlH237ecSMnYdYuCkib2QHq0kpWfUnavjdYsyr/6OsAwg5ZGUfnQ9KD1Ga4QgB2sqXlB2NT8zy2GnVg==", "dev": true }, "node_modules/emoji-regex": { @@ -1677,18 +1689,19 @@ } }, "node_modules/eslint": { - "version": "8.47.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.47.0.tgz", - "integrity": "sha512-spUQWrdPt+pRVP1TTJLmfRNJJHHZryFmptzcafwSvHsceV81djHOdnEeDmkdotZyLNjDhrOasNK8nikkoG1O8Q==", + "version": "8.55.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", + "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "^8.47.0", - "@humanwhocodes/config-array": "^0.11.10", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.55.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -1877,9 +1890,9 @@ "dev": true }, "node_modules/fast-glob": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", - "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -1992,12 +2005,13 @@ } }, "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", "dev": true, "dependencies": { - "flatted": "^3.1.0", + "flatted": "^3.2.9", + "keyv": "^4.5.3", "rimraf": "^3.0.2" }, "engines": { @@ -2005,9 +2019,9 @@ } }, "node_modules/flatted": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", - "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, "node_modules/foreground-child": { @@ -2050,9 +2064,9 @@ "dev": true }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, "hasInstallScript": true, "optional": true, @@ -2132,9 +2146,9 @@ } }, "node_modules/globals": { - "version": "13.21.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", - "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "dependencies": { "type-fest": "^0.20.2" @@ -2228,9 +2242,9 @@ "dev": true }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "dev": true, "engines": { "node": ">= 4" @@ -2401,9 +2415,9 @@ "dev": true }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "engines": { "node": ">=8" @@ -2548,6 +2562,12 @@ "node": ">=4" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -2577,6 +2597,15 @@ "resolved": "https://registry.npmjs.org/just-clone/-/just-clone-6.2.0.tgz", "integrity": "sha512-1IynUYEc/HAwxhi3WDpIpxJbZpMCvvrrmZVqvj9EhpvbH8lls7HhdhiByjL7DkAaWlLIzpC0Xc/VPvy/UxLNjA==" }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -2877,9 +2906,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, "node_modules/normalize-path": { @@ -3312,9 +3341,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -3682,9 +3711,9 @@ } }, "node_modules/ts-node": { - "version": "10.9.1", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", - "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", @@ -3815,9 +3844,9 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "dev": true, "funding": [ { @@ -3946,9 +3975,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.1.tgz", - "integrity": "sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "engines": { "node": ">= 14" } @@ -4050,9 +4079,9 @@ } }, "node_modules/zod": { - "version": "3.21.4", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz", - "integrity": "sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw==", + "version": "3.22.4", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz", + "integrity": "sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==", "funding": { "url": "https://github.com/sponsors/colinhacks" } diff --git a/nodejs/sec-config.yaml b/nodejs/sec-config.yaml index 43bc808..c3975f4 100644 --- a/nodejs/sec-config.yaml +++ b/nodejs/sec-config.yaml @@ -8,13 +8,16 @@ default: services: service-default0X: plugin: service-default0 - enabled: false + enabled: true + config: + testa: 5 + testb: 6 service-default1X: plugin: service-default1 - enabled: false + enabled: true service-default2X: plugin: service-default2 - enabled: false + enabled: true service-default3X: plugin: service-default3 - enabled: false + enabled: true diff --git a/nodejs/src/base/base.ts b/nodejs/src/base/base.ts index 4097c68..95c6c57 100644 --- a/nodejs/src/base/base.ts +++ b/nodejs/src/base/base.ts @@ -2,6 +2,7 @@ import { DEBUG_MODE, IPluginLogger } from "../interfaces/logging"; import { PluginLogger } from "./PluginLogger"; import { SBLogging } from "../serviceBase/logging"; import { z } from "zod"; +import { BSBServiceConfig } from "./serviceConfig"; export abstract class MainBase { /** @@ -108,7 +109,8 @@ export abstract class Base extends MainBase { * a: z.string(), * }); */ -export type BSBConfigDefinition = z.AnyZodObject | undefined; +export type BSBConfigType = z.AnyZodObject | undefined; +export type BSBConfigDefinition = BSBServiceConfig; /** * Config migration handler, allows for config migrations when the plugin version changes or a new plugin setup is done * @example simple version change and basic setup @@ -130,14 +132,14 @@ export type BSBConfigDefinition = z.AnyZodObject | undefined; * } * return existingConfig; */ -export type BSBConfigMigration = ( +export type BSBConfigMigration = ( versionFrom: string | null, versionTo: string, existingConfig?: z.infer> ) => Promise>>; export type BSBConfigDefintionReference< - T extends BSBConfigDefinition, + T extends BSBConfigType, AS = undefined > = T extends undefined ? AS : z.infer>; @@ -151,7 +153,7 @@ export abstract class BaseWithConfig< * @readonly */ protected readonly config: BSBConfigDefintionReference< - ReferencedConfig, + ReferencedConfig["validationSchema"], null >; diff --git a/nodejs/src/base/config.ts b/nodejs/src/base/config.ts index d731fc0..29309f2 100644 --- a/nodejs/src/base/config.ts +++ b/nodejs/src/base/config.ts @@ -24,6 +24,12 @@ export abstract class BSBConfig extends BaseWithLogging { ) { super(appId, mode, pluginName, cwd, pluginCwd, logging); } + /** + * This function is never used for events plugins. + * @ignore @deprecated + */ + public run() {} + /** * Returns the logging plugins configuration. * @returns Promise resolving to an object containing the logging configuration for each plugin. @@ -46,7 +52,9 @@ export abstract class BSBConfig extends BaseWithLogging { * Returns a mapped plugin name and whether the plugin is enabled or not * @returns string of the plugin name and if it is enabled or not */ - abstract getServicePluginDefinition(pluginName: string): Promise<{name:string,enabled:boolean}>; + abstract getServicePluginDefinition( + pluginName: string + ): Promise<{ name: string; enabled: boolean }>; /** * Returns the configuration for a specific plugin. @@ -79,7 +87,9 @@ export class BSBConfigRef extends BSBConfig { ): Promise { throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBConfigRef", "getPluginConfig"); } - getServicePluginDefinition(pluginName: string): Promise<{name:string,enabled:boolean}> { + getServicePluginDefinition( + pluginName: string + ): Promise<{ name: string; enabled: boolean }> { throw BSB_ERROR_METHOD_NOT_IMPLEMENTED( "BSBConfigRef", "getServicePluginName" @@ -87,5 +97,4 @@ export class BSBConfigRef extends BSBConfig { } dispose?(): void; init?(): void; - run?(): void; } diff --git a/nodejs/src/base/events.ts b/nodejs/src/base/events.ts index 5e29e44..adfc0bc 100644 --- a/nodejs/src/base/events.ts +++ b/nodejs/src/base/events.ts @@ -28,6 +28,13 @@ export abstract class BSBEvents< config.sbLogging ); } + + /** + * This function is never used for events plugins. + * @ignore @deprecated + */ + public run() {} + /** * Listens for events that are emitted by other plugins * Broadcast events are emitted and received by all plugins @@ -246,5 +253,4 @@ export class BSBEventsRef extends BSBEvents { } dispose?(): void; init?(): void | Promise; - run?(): void | Promise; } diff --git a/nodejs/src/base/logging.ts b/nodejs/src/base/logging.ts index 952c896..d325c7a 100644 --- a/nodejs/src/base/logging.ts +++ b/nodejs/src/base/logging.ts @@ -1,6 +1,5 @@ -import { BaseWithConfig } from "./base"; +import { BSBConfigDefinition, BaseWithConfig } from "./base"; import { DEBUG_MODE, LogMeta } from "../interfaces/logging"; -import { z } from "zod"; import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./errorMessages"; export interface BSBLoggingConstructor { @@ -13,7 +12,7 @@ export interface BSBLoggingConstructor { } export abstract class BSBLogging< - ReferencedConfig extends z.AnyZodObject | undefined + ReferencedConfig extends BSBConfigDefinition > extends BaseWithConfig { constructor(config: BSBLoggingConstructor) { super( @@ -25,6 +24,13 @@ export abstract class BSBLogging< config.config ); } + + /** + * This function is never used for events plugins. + * @ignore @deprecated + */ + public run() {} + /** * Report stat * Reports a value(number) to the logging system @@ -138,7 +144,7 @@ export abstract class BSBLogging< /** * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS */ -export class BSBLoggingRef extends BSBLogging { +export class BSBLoggingRef extends BSBLogging { public reportStat(plugin: string, key: string, value: number): void { throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "reportStat"); } @@ -179,5 +185,4 @@ export class BSBLoggingRef extends BSBLogging { } dispose?(): void; init?(): void; - run?(): void; } diff --git a/nodejs/src/base/serviceConfig.ts b/nodejs/src/base/serviceConfig.ts new file mode 100644 index 0000000..165b35d --- /dev/null +++ b/nodejs/src/base/serviceConfig.ts @@ -0,0 +1,23 @@ +import { z } from "zod"; +import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./errorMessages"; +import { BSBConfigType } from './base'; + +export abstract class BSBServiceConfig> { + constructor(cwd: string, pluginCwd: string, pluginName: string) {} + abstract validationSchema: MyPluginConfig; + abstract migrate( + toVersion: string, + fromVersion: string | null, + fromConfig: any | null + ): z.infer; +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBServiceConfigRef extends BSBServiceConfig { + validationSchema = {}; + migrate(toVersion: string, fromVersion: string | null, fromConfig: any) { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBServiceConfigRef", "migrate"); + } +} diff --git a/nodejs/src/interfaces/index.ts b/nodejs/src/interfaces/index.ts index 2c9cafe..3ec8c27 100644 --- a/nodejs/src/interfaces/index.ts +++ b/nodejs/src/interfaces/index.ts @@ -2,4 +2,4 @@ export * from "./events"; export * from "./logging"; export * from "./plugins"; export * from "./service"; -export * from "./serviceConfig"; +export * from "../base/serviceConfig"; diff --git a/nodejs/src/interfaces/serviceConfig.ts b/nodejs/src/interfaces/serviceConfig.ts deleted file mode 100644 index f8beee0..0000000 --- a/nodejs/src/interfaces/serviceConfig.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { z } from "zod"; - -export abstract class SecConfig< - MyPluginConfig extends any, - MyValidationSchema = z.ZodSchema -> { - abstract validationSchema: MyValidationSchema; - abstract init( - cwd: string, - plugin: any, - existingConfig?: MyPluginConfig - ): MyPluginConfig; -} diff --git a/nodejs/src/plugins/config-default/interfaces.ts b/nodejs/src/plugins/config-default/interfaces.ts index 82ba40b..541e806 100644 --- a/nodejs/src/plugins/config-default/interfaces.ts +++ b/nodejs/src/plugins/config-default/interfaces.ts @@ -60,11 +60,13 @@ export interface DeploymentProfiles extends Record { */ default: T; } - +export interface ExtendedConfig { + config: any | undefined; +} export interface ConfigProfile { - logging: Record; - events: Record; - services: Record; + logging: Record; + events: Record; + services: Record; } export interface DefaultProfile { default: ConfigProfile; @@ -73,10 +75,10 @@ export interface ConfigDefinition extends Record, DefaultProfile {} -export interface PluginConfig { - package?: string | null; - plugin: string; - name: string; - enabled: boolean; - config: INCLCONF extends true ? any : never; -} +// export interface PluginConfig { +// package?: string | null; +// plugin: string; +// name: string; +// enabled: boolean; +// config: INCLCONF extends true ? any : never; +// } diff --git a/nodejs/src/plugins/config-default/plugin.ts b/nodejs/src/plugins/config-default/plugin.ts index 58613b2..b87899a 100644 --- a/nodejs/src/plugins/config-default/plugin.ts +++ b/nodejs/src/plugins/config-default/plugin.ts @@ -117,12 +117,11 @@ export class Plugin extends BSBConfig { let configKey: "services" | "logging" | "events" = "services"; if (pluginType === PluginTypes.events) configKey = "events"; if (pluginType === PluginTypes.logging) configKey = "logging"; - return this._appConfig[this._deploymentProfile][configKey][plugin]; + return this._appConfig[this._deploymentProfile][configKey][plugin].config ?? null; } dispose() { this._appConfig = undefined!; } - run?(): void; private _appConfig!: ConfigDefinition; private _secConfigFilePath: string; private _deploymentProfile: string = "default"; diff --git a/nodejs/src/plugins/events-default/plugin.ts b/nodejs/src/plugins/events-default/plugin.ts index 705010c..8401ae2 100644 --- a/nodejs/src/plugins/events-default/plugin.ts +++ b/nodejs/src/plugins/events-default/plugin.ts @@ -4,18 +4,16 @@ import emitAndReturn from "./events/emitAndReturn"; import emitStreamAndReceiveStream from "./events/emitStreamAndReceiveStream"; import broadcast from "./events/broadcast"; import { BSBEvents, BSBEventsConstructor } from "../../base/events"; +import { BSBConfigDefinition } from "../../"; -export class Plugin extends BSBEvents { +export class Plugin extends BSBEvents { init?(): void; - run?(): void; protected broadcast!: broadcast; protected emit!: emit; protected ear!: emitAndReturn; protected eas!: emitStreamAndReceiveStream; - constructor( - config: BSBEventsConstructor - ) { + constructor(config: BSBEventsConstructor) { super(config); this.broadcast = new broadcast(this.createNewLogger("broadcast")); diff --git a/nodejs/src/plugins/logging-default/plugin.ts b/nodejs/src/plugins/logging-default/plugin.ts index 9346c8a..6ee0d91 100644 --- a/nodejs/src/plugins/logging-default/plugin.ts +++ b/nodejs/src/plugins/logging-default/plugin.ts @@ -2,6 +2,7 @@ import { BSBLogging, BSBLoggingConstructor } from "../../base/logging"; import { LogMeta } from "../../interfaces/logging"; import { CONSOLE_COLOURS, ConsoleColours } from "./colours"; import { LogFormatter } from "../../base/logFormatter"; +import { BSBConfigDefinition } from '../../'; export const LOG_LEVELS = { TSTAT: "Text Statistic", @@ -13,10 +14,9 @@ export const LOG_LEVELS = { } as const; export type LogLevels = (typeof LOG_LEVELS)[keyof typeof LOG_LEVELS]; -export class Plugin extends BSBLogging { +export class Plugin extends BSBLogging { dispose?(): void; init?(): void; - run?(): void; private _mockedConsole?: { (level: LogLevels, message: string): void }; private _mockConsole: boolean = false; private logFormatter: LogFormatter = new LogFormatter(); diff --git a/nodejs/src/plugins/service-default0/plugin.ts b/nodejs/src/plugins/service-default0/plugin.ts index ba715a5..e7886dd 100644 --- a/nodejs/src/plugins/service-default0/plugin.ts +++ b/nodejs/src/plugins/service-default0/plugin.ts @@ -4,6 +4,7 @@ import { BSBServiceTypes, } from "../../base/service"; import { testClient } from "../service-default1/plugin"; +import { Config } from "./sec-config"; export interface ServiceTypes extends BSBServiceTypes { methods: { @@ -18,7 +19,7 @@ export interface ServiceTypes extends BSBServiceTypes { emitBroadcast: {}; onBroadcast: {}; } -export class Plugin extends BSBService { +export class Plugin extends BSBService { public initBeforePlugins?: string[] | undefined; //public initAfterPlugins: string[] = ["service-default3"]; public initAfterPlugins?: string[] | undefined; @@ -39,6 +40,11 @@ export class Plugin extends BSBService { public async run() { this.log.info("aa"); this.events.emitEvent("test", "test", "test"); - await this.testClient.abc(1, 5, 2, 6); + await this.testClient.abc( + this.config.testa, + this.config.testb, + this.config.testa, + this.config.testb + ); } } diff --git a/nodejs/src/plugins/service-default0/sec-config.ts b/nodejs/src/plugins/service-default0/sec-config.ts new file mode 100644 index 0000000..137030e --- /dev/null +++ b/nodejs/src/plugins/service-default0/sec-config.ts @@ -0,0 +1,30 @@ +import { BSBServiceConfig } from "../../interfaces"; +import { z } from "zod"; + +export const secSchema = z.object({ + testa: z.number(), + testb: z.number(), +}); +export class Config extends BSBServiceConfig { + validationSchema = secSchema; + + migrate( + toVersion: string, + fromVersion: string | null, + fromConfig: any | null + ) { + if (fromConfig === null) { + // defaults + return { + testa: 1, + testb: 2, + }; + } else { + // migrate + return { + testa: fromConfig.testa, + testb: fromConfig.testb, + }; + } + } +} diff --git a/nodejs/src/plugins/service-default0/sec.config.ts b/nodejs/src/plugins/service-default0/sec.config.ts deleted file mode 100644 index 8a34438..0000000 --- a/nodejs/src/plugins/service-default0/sec.config.ts +++ /dev/null @@ -1,19 +0,0 @@ -// import { SecConfig } from "../../interfaces/serviceConfig"; -// import { IPluginConfig } from "../../interfaces/config"; - -// export interface PluginConfig extends IPluginConfig { -// testa: number -// testb: number -// } - -// export class Config extends SecConfig { -// migrate( -// mappedPluginName: string, -// existingConfig: PluginConfig -// ): PluginConfig { -// return { -// testa: existingConfig.testa || 6, // this value gets a default value -// testb: 5 // this value is unchangable -// }; -// } -// } diff --git a/nodejs/src/serviceBase/config.ts b/nodejs/src/serviceBase/config.ts index 719eaeb..ec52191 100644 --- a/nodejs/src/serviceBase/config.ts +++ b/nodejs/src/serviceBase/config.ts @@ -5,7 +5,10 @@ import { SBLogging } from "./logging"; import { PluginLogger } from "../base/PluginLogger"; import { BSBConfig } from "../base/config"; import { Tools } from "@bettercorp/tools"; -import { SmartFunctionCallSync, SmartFunctionCallAsync } from "../base/functions"; +import { + SmartFunctionCallSync, + SmartFunctionCallAsync, +} from "../base/functions"; import { EventsConfig, LoggingConfig, @@ -65,44 +68,44 @@ export class SBConfig { SmartFunctionCallSync(this.configPlugin, this.configPlugin.dispose); } - private loggerPackage: string | undefined; - private loggerPlugin = "config-default"; + private configPackage: string | undefined; + private configPluginName = "config-default"; public async init(): Promise { if ( Tools.isString(process.env.BSB_LOGGER_PLUGIN) && process.env.BSB_LOGGER_PLUGIN.startsWith("config-") ) { - this.loggerPlugin = process.env.BSB_LOGGER_PLUGIN; + this.configPluginName = process.env.BSB_LOGGER_PLUGIN; if (Tools.isString(process.env.BSB_LOGGER_PLUGIN_PACKAGE)) { - this.loggerPackage = process.env.BSB_LOGGER_PLUGIN_PACKAGE; + this.configPackage = process.env.BSB_LOGGER_PLUGIN_PACKAGE; } } this.log.debug("Add config {name} from ({package})", { - package: this.loggerPackage ?? "this project", - name: this.loggerPlugin, + package: this.configPackage ?? "this project", + name: this.configPluginName, }); - if (this.loggerPlugin === "config-default") { + if (this.configPluginName === "config-default") { await SmartFunctionCallAsync(this.configPlugin, this.configPlugin.init); return; } this.log.debug(`Import config plugin: {name} from ({package})`, { - package: this.loggerPackage ?? "this project", - name: this.loggerPlugin, + package: this.configPackage ?? "this project", + name: this.configPluginName, }); const newPlugin = await this.sbPlugins.loadPlugin<"config">( this.log, - this.loggerPackage ?? null, - this.loggerPlugin, - this.loggerPlugin + this.configPackage ?? null, + this.configPluginName, + this.configPluginName ); if (newPlugin === null) { this.log.error( "Failed to import config plugin: {name} from ({package})", { - package: this.loggerPackage ?? "this project", - name: this.loggerPlugin, + package: this.configPackage ?? "this project", + name: this.configPluginName, } ); return; @@ -121,21 +124,12 @@ export class SBConfig { }); this.log.debug(`Init: {name}`, { - name: this.loggerPlugin, + name: this.configPluginName, }); await SmartFunctionCallAsync(this.configPlugin, this.configPlugin.init); this.log.info(`Init: {name}: OK`, { - name: this.loggerPlugin, - }); - - this.log.debug(`Run: {name}`, { - name: this.loggerPlugin, - }); - await SmartFunctionCallAsync(this.configPlugin, this.configPlugin.run); - - this.log.info(`Run: {name}: OK`, { - name: this.loggerPlugin, + name: this.configPluginName, }); } } diff --git a/nodejs/src/serviceBase/events.ts b/nodejs/src/serviceBase/events.ts index ad13e55..82f5e70 100644 --- a/nodejs/src/serviceBase/events.ts +++ b/nodejs/src/serviceBase/events.ts @@ -159,6 +159,23 @@ export class SBEvents { onTypeof: "all", }); } + public async run() { + if (this.events.length === 1) return; + // we want to see if any plugins (ignore events-default) are listening to all events - it so, there is no reason to keep the events-default plugin, so we can dispose and remove it + const events = this.events.filter((x) => x.name !== "events-default"); + const allEvents = events.filter((x) => x.onTypeof === "all"); + if (allEvents.length > 0) { + const defaultEvents = this.events.find((x) => x.name === "events-default"); + if (defaultEvents !== undefined) { + if (defaultEvents.plugin.dispose !== undefined) + SmartFunctionCallSync( + defaultEvents.plugin, + defaultEvents.plugin.dispose + ); + this.events = this.events.filter((x) => x.name !== "events-default"); + } + } + } private async addEvents( sbConfig: SBConfig, @@ -200,7 +217,14 @@ export class SBEvents { name: plugin.name, }); - const pluginConfig = await sbConfig.getPluginConfig("events", plugin.name); + let pluginConfig = await sbConfig.getPluginConfig("events", plugin.name); + + if (newPlugin.serviceConfig !== null) { + pluginConfig = + newPlugin.serviceConfig.validationSchema.parse(pluginConfig); + } else if (pluginConfig === null) { + pluginConfig = {}; + } this.log.debug(`Construct events plugin: {name}`, { name: plugin.name, diff --git a/nodejs/src/serviceBase/logging.ts b/nodejs/src/serviceBase/logging.ts index 8321b27..bf3f533 100644 --- a/nodejs/src/serviceBase/logging.ts +++ b/nodejs/src/serviceBase/logging.ts @@ -230,6 +230,29 @@ export class SBLogging { } } + public async run() { + if (this.loggers.length === 1) return; + // we want to see if any plugins (ignore logging-default) are listening to all logs - it so, there is no reason to keep the logging-default plugin, so we can dispose and remove it + const pluginsListeningToAll = this.loggers.filter((logger) => { + if (Tools.isNullOrUndefined(logger.on)) return false; + if (logger.onTypeof === "all") return true; + return false; + }); + if (pluginsListeningToAll.length > 0) { + const loggerIndex = this.loggers.findIndex((logger) => { + return logger.plugin.pluginName === "logging-default"; + }); + if (loggerIndex !== -1) { + if (this.loggers[loggerIndex].plugin.dispose !== undefined) + SmartFunctionCallSync( + this.loggers[loggerIndex].plugin, + this.loggers[loggerIndex].plugin.dispose + ); + this.loggers.splice(loggerIndex, 1); + } + } + } + private async addLogger( sbConfig: SBConfig, plugin: IPluginDefinition, @@ -269,7 +292,14 @@ export class SBLogging { name: plugin.name, }); - const pluginConfig = await sbConfig.getPluginConfig("logging", plugin.name); + let pluginConfig = await sbConfig.getPluginConfig("logging", plugin.name); + + if (newPlugin.serviceConfig !== null) { + pluginConfig = + newPlugin.serviceConfig.validationSchema.parse(pluginConfig); + } else if (pluginConfig === null) { + pluginConfig = {}; + } this.log.debug(`Construct logging plugin: {name}`, { name: plugin.name, diff --git a/nodejs/src/serviceBase/plugins.ts b/nodejs/src/serviceBase/plugins.ts index 521f3a2..c38c8a4 100644 --- a/nodejs/src/serviceBase/plugins.ts +++ b/nodejs/src/serviceBase/plugins.ts @@ -3,6 +3,7 @@ import { join } from "path"; import { PluginType, PluginTypeDefinitionRef } from "../interfaces/plugins"; import { IPluginLogger } from "../interfaces/logging"; import { BSBError } from "../base/errorMessages"; +import { BSBServiceConfig, BSBServiceConfigRef } from "../interfaces"; export class SBPlugins { protected cwd: string; @@ -34,13 +35,14 @@ export class SBPlugins { name: string; ref: string; version: string; - pluginFile: string; - installerFile: string | null; + serviceConfig: BSBServiceConfig | null; + //pluginFile: string; + //installerFile: string | null; plugin: ClassType; pluginCWD: string; pluginPath: string; } | null> { - log.info(`PLUGIN {name} from {package} try load as {pluginName}`, { + log.debug(`PLUGIN {name} from {package} try load as {pluginName}`, { name: plugin, pluginName: name, package: npmPackage ?? "self", @@ -75,41 +77,59 @@ export class SBPlugins { return null; } - log.info(`Plugin {name}: attempt to load from {path} as {pluginName}`, { + log.debug(`Plugin {name}: attempt to load from {path} as {pluginName}`, { name: plugin, path: pluginPath, pluginName: name, }); let pluginFile = join(pluginPath, "./plugin.js"); - let installerFile: string | null = null; - if (this.devMode) { - const tsPluginFile = join(pluginPath, "./plugin.ts"); - if (existsSync(tsPluginFile)) { - log.debug("PLUGIN {pluginName} running in development mode", { - pluginName: name, - }); - pluginFile = tsPluginFile; - } - // sec.config.ts - installerFile = join(pluginPath, "./sec.config.js"); - const tsInstallerFile = join(pluginPath, "./sec.config.ts"); - if (existsSync(tsInstallerFile)) { - log.debug("PLUGIN {pluginName} running development mode installer", { - pluginName: name, - }); - installerFile = tsInstallerFile; - } else if (!existsSync(installerFile)) { - log.debug("PLUGIN {pluginName} does not have an installer file", { - pluginName: name, - }); - installerFile = null; - } else { - log.debug("PLUGIN {pluginName} does not have an installer file", { - pluginName: name, - }); - } + let configDefFile: string | null = null; + let serviceConfigDef: BSBServiceConfig | null = null; + //if (this.devMode) { + const tsPluginFile = join(pluginPath, "./plugin.ts"); + if (existsSync(tsPluginFile)) { + log.debug("PLUGIN {pluginName} running in development mode", { + pluginName: name, + }); + pluginFile = tsPluginFile; + } + // sec-.ts + configDefFile = join(pluginPath, "./sec-config.js"); + const tsInstallerFile = join(pluginPath, "./sec-config.ts"); + if (existsSync(tsInstallerFile)) { + log.debug("PLUGIN {pluginName} running development mode installer", { + pluginName: name, + }); + configDefFile = tsInstallerFile; + } else if (!existsSync(configDefFile)) { + log.debug("PLUGIN {pluginName} does not have an installer file", { + pluginName: name, + }); + configDefFile = null; + } else { + log.debug("PLUGIN {pluginName} does not have an installer file", { + pluginName: name, + }); + } + + if (configDefFile !== null) { + const importedConfig = await import(configDefFile); + if (importedConfig.Config === undefined) + throw new BSBError( + "PLUGIN {pluginName} sec-config.ts/js does not export a Config class - so possibly not a valid BSB Plugin Config", + { + pluginName: name, + } + ); + serviceConfigDef = + new (importedConfig.Config as typeof BSBServiceConfigRef)( + this.cwd, + pluginCWD, + name + ); } + //} if (!existsSync(pluginFile)) throw new BSBError("PLUGIN {pluginName} not found at {location}", { @@ -131,8 +151,7 @@ export class SBPlugins { name: name, ref: plugin, version: version, - pluginFile, - installerFile: installerFile, + serviceConfig: serviceConfigDef, plugin: importedPlugin.Plugin, pluginCWD: pluginCWD, pluginPath: pluginPath, diff --git a/nodejs/src/serviceBase/serviceBase.ts b/nodejs/src/serviceBase/serviceBase.ts index e7675ab..e0f1432 100644 --- a/nodejs/src/serviceBase/serviceBase.ts +++ b/nodejs/src/serviceBase/serviceBase.ts @@ -158,6 +158,8 @@ export class ServiceBase { public async run() { this._startKeep(BOOT_STAT_KEYS.RUN); + await this.logging.run(); + await this.events.run(); await this.services.run(this.config); this.log.info("Disposing config for memory cleanup and safety"); this.config.dispose(); diff --git a/nodejs/src/serviceBase/services.ts b/nodejs/src/serviceBase/services.ts index dfde37b..e64e418 100644 --- a/nodejs/src/serviceBase/services.ts +++ b/nodejs/src/serviceBase/services.ts @@ -4,7 +4,10 @@ import { IPluginLogger } from "../interfaces/logging"; import { DEBUG_MODE } from "../interfaces/logging"; import { SBConfig } from "./config"; import { SBEvents } from "./events"; -import { SmartFunctionCallAsync, SmartFunctionCallSync } from "../base/functions"; +import { + SmartFunctionCallAsync, + SmartFunctionCallSync, +} from "../base/functions"; import { SBLogging } from "./logging"; import { SBPlugins } from "./plugins"; import { IPluginDefinition } from "../interfaces/plugins"; @@ -162,7 +165,14 @@ export class SBServices { name: plugin.name, }); - const pluginConfig = await sbConfig.getPluginConfig("service", plugin.name); + let pluginConfig = await sbConfig.getPluginConfig("service", plugin.name); + + if (newPlugin.serviceConfig !== null) { + pluginConfig = + newPlugin.serviceConfig.validationSchema.parse(pluginConfig); + } else if (pluginConfig === null) { + pluginConfig = {}; + } this.log.debug(`Construct service plugin: {name}`, { name: plugin.name, @@ -178,12 +188,12 @@ export class SBServices { sbLogging: sbLogging, sbEvents: sbEvents, }); - this.log.info("Adding {pluginName} as service", { + this.log.debug("Adding {pluginName} as service", { pluginName: plugin.name, }); for (let client of servicePlugin._clients) { - this.log.info("Construct {pluginName} client {clientName}", { + this.log.debug("Construct {pluginName} client {clientName}", { pluginName: plugin.name, clientName: client.pluginName, }); @@ -194,7 +204,7 @@ export class SBServices { servicePlugin, client ); - this.log.info( + this.log.debug( "Setup {pluginName} client {asOriginalPluginName} as {clientName}", { pluginName: plugin.name, @@ -265,7 +275,7 @@ export class SBServices { public async init(sbConfig: SBConfig) { this.log.info("Init all services"); for (let service of this._activeServices) { - this.log.info("Mapping required plugins list for {plugin}", { + this.log.debug("Mapping required plugins list for {plugin}", { plugin: service.pluginName, }); (service as any).initBeforePlugins = await this.mapServicePlugins( @@ -360,7 +370,7 @@ export class SBServices { public async run(sbConfig: SBConfig) { this.log.info("Run all services"); for (let service of this._activeServices) { - this.log.info("Mapping required plugins list for {plugin}", { + this.log.debug("Mapping required plugins list for {plugin}", { plugin: service.pluginName, }); (service as any).runBeforePlugins = await this.mapServicePlugins( From 84fd21ad03ab11c25a234c4a0cdf60eb9aa02b01 Mon Sep 17 00:00:00 2001 From: mrinc Date: Fri, 15 Dec 2023 21:56:38 +0200 Subject: [PATCH 15/47] Updated deps --- nodejs/package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 98022c0..5e3deff 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1650,9 +1650,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.612", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.612.tgz", - "integrity": "sha512-dM8BMtXtlH237ecSMnYdYuCkib2QHq0kpWfUnavjdYsyr/6OsAwg5ZGUfnQ9KD1Ga4QgB2sqXlB2NT8zy2GnVg==", + "version": "1.4.614", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.614.tgz", + "integrity": "sha512-X4ze/9Sc3QWs6h92yerwqv7aB/uU8vCjZcrMjA8N9R1pjMFRe44dLsck5FzLilOYvcXuDn93B+bpGYyufc70gQ==", "dev": true }, "node_modules/emoji-regex": { From 4cd53037e1040b3f7bf2c0a95c272d462bbf47c8 Mon Sep 17 00:00:00 2001 From: mrinc Date: Fri, 15 Dec 2023 22:16:05 +0200 Subject: [PATCH 16/47] Publishing beta package --- nodejs/package-lock.json | 4 ++-- nodejs/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 5e3deff..9b9d494 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bettercorp/service-base", - "version": "9.0.0+v9", + "version": "9.0.0-beta", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bettercorp/service-base", - "version": "9.0.0+v9", + "version": "9.0.0-beta", "hasInstallScript": true, "license": "AGPL-3.0-only", "dependencies": { diff --git a/nodejs/package.json b/nodejs/package.json index 3485001..f8c2cdd 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -30,7 +30,7 @@ "README.md" ], "main": "lib/index.js", - "version": "9.0.0+v9", + "version": "9.0.0-beta", "devDependencies": { "@types/assert": "^1.5.6", "@types/chai": "^4.3.3", From 73ef6fcb1a40c30b2753e6462f3b2bd68299d40e Mon Sep 17 00:00:00 2001 From: mrinc Date: Fri, 15 Dec 2023 22:18:23 +0200 Subject: [PATCH 17/47] Publishing beta package --- nodejs/package.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/nodejs/package.json b/nodejs/package.json index f8c2cdd..d1276c4 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -13,7 +13,7 @@ "start": "node lib/cli.js", "build": "rm -rfv ./lib && tsc && npm run testDev", "build-release": "rm -rfv ./lib && tsc && npm run test && rm -rfv ./lib && tsc --p ./tsconfig-release.json", - "postinstall": "node ./postinstall.js", + "xpostinstall": "node ./postinstall.js", "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx", "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js --reporter json --reporter lcov ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts' --reporter json --reporter-options output=junit.json", "testDev": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts'" @@ -23,10 +23,7 @@ }, "files": [ "lib/**/*", - "development/**/*", "tsconfig.json", - "postinstall.js", - "build-lib-clients.js", "README.md" ], "main": "lib/index.js", From fdb7185b997b1079384d2a388215068f8caa411a Mon Sep 17 00:00:00 2001 From: mrinc Date: Fri, 15 Dec 2023 22:25:24 +0200 Subject: [PATCH 18/47] Publishing beta package - updated files --- nodejs/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/nodejs/package.json b/nodejs/package.json index d1276c4..5db1631 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -13,7 +13,7 @@ "start": "node lib/cli.js", "build": "rm -rfv ./lib && tsc && npm run testDev", "build-release": "rm -rfv ./lib && tsc && npm run test && rm -rfv ./lib && tsc --p ./tsconfig-release.json", - "xpostinstall": "node ./postinstall.js", + "xZpostinstall": "node ./postinstall.js", "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx", "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js --reporter json --reporter lcov ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts' --reporter json --reporter-options output=junit.json", "testDev": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts'" @@ -23,6 +23,7 @@ }, "files": [ "lib/**/*", + "development/**/*", "tsconfig.json", "README.md" ], From 92dacfdae879231b3cdecd6cc587a8de79ccfcbe Mon Sep 17 00:00:00 2001 From: mrinc Date: Sat, 16 Dec 2023 01:42:09 +0200 Subject: [PATCH 19/47] Updated BSB with the ability to do direct calls and dynamic addition of services/events/logging/config - added the ability to setup a client like a standard lib while getting the BSB featureset --- nodejs/development/nodemon.json | 8 +- nodejs/nodemon.json | 10 +- nodejs/package.json | 2 +- nodejs/src/ServiceBase.ts | 3 - nodejs/src/base/serviceClient.ts | 20 ++++ nodejs/src/client.ts | 83 +++++++++++++++++ nodejs/src/index.ts | 1 + nodejs/src/interfaces/plugins.ts | 24 ++++- nodejs/src/serviceBase/config.ts | 47 ++++++---- nodejs/src/serviceBase/events.ts | 107 ++++++++++++--------- nodejs/src/serviceBase/logging.ts | 110 ++++++++++++---------- nodejs/src/serviceBase/plugins.ts | 18 ++-- nodejs/src/serviceBase/serviceBase.ts | 129 ++++++++++++++++++++++++-- nodejs/src/serviceBase/services.ts | 113 +++++++++++++--------- 14 files changed, 476 insertions(+), 199 deletions(-) delete mode 100644 nodejs/src/ServiceBase.ts create mode 100644 nodejs/src/client.ts diff --git a/nodejs/development/nodemon.json b/nodejs/development/nodemon.json index de7f160..9539f27 100644 --- a/nodejs/development/nodemon.json +++ b/nodejs/development/nodemon.json @@ -4,14 +4,14 @@ ".git", "lib", "node_modules", - "src/plugins/-*/**/*.ts", - "sec.config.json" + "src/plugins/-*/**/*.ts" ], "delay": 2000, "signal": "SIGHUP", "exec": "ts-node node_modules/@bettercorp/service-base/lib/dev.js", "watch": [ - "src/**/*.ts" + "src/**/*.ts", + "sec-config.yaml" ], - "ext": "ts,json" + "ext": "ts,json,yaml" } \ No newline at end of file diff --git a/nodejs/nodemon.json b/nodejs/nodemon.json index a30b845..8e85973 100644 --- a/nodejs/nodemon.json +++ b/nodejs/nodemon.json @@ -4,14 +4,14 @@ ".git", "lib", "node_modules", - "src/plugins/-*/**/*.ts", - "sec.config.json" + "src/plugins/-*/**/*.ts" ], "delay": 2000, "signal": "SIGHUP", - "exec": "ts-node src/dev.ts", + "exec": "ts-node src/dev.js", "watch": [ - "src/**/*.ts" + "src/**/*.ts", + "sec-config.yaml" ], - "ext": "ts,json" + "ext": "ts,json,yaml" } \ No newline at end of file diff --git a/nodejs/package.json b/nodejs/package.json index 5db1631..a952cb3 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -28,7 +28,7 @@ "README.md" ], "main": "lib/index.js", - "version": "9.0.0-beta", + "version": "9.0.2-beta", "devDependencies": { "@types/assert": "^1.5.6", "@types/chai": "^4.3.3", diff --git a/nodejs/src/ServiceBase.ts b/nodejs/src/ServiceBase.ts deleted file mode 100644 index e5fa452..0000000 --- a/nodejs/src/ServiceBase.ts +++ /dev/null @@ -1,3 +0,0 @@ -// import { IPluginLogger, LogMeta } from "./interfaces/logger"; -// import { LoggerBase } from "./logger/logger"; -// import { Plugins } from "./plugins/plugins"; diff --git a/nodejs/src/base/serviceClient.ts b/nodejs/src/base/serviceClient.ts index 056ca48..95b6310 100644 --- a/nodejs/src/base/serviceClient.ts +++ b/nodejs/src/base/serviceClient.ts @@ -47,3 +47,23 @@ export abstract class BSBServiceClient< public abstract init?(): Promise; public abstract run?(): Promise; } + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBServiceClientRef extends BSBServiceClient { + public pluginName: string = ""; + public initBeforePlugins?: string[] | undefined; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public dispose?(): void { + throw new Error("Method not implemented."); + } + public init?(): Promise { + throw new Error("Method not implemented."); + } + public run?(): Promise { + throw new Error("Method not implemented."); + } +} diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts new file mode 100644 index 0000000..1df8176 --- /dev/null +++ b/nodejs/src/client.ts @@ -0,0 +1,83 @@ +import { + BSBConfig, + BSBService, + BSBServiceClient, + BSBServiceConstructor, +} from "./base"; +import { LoggingConfig, EventsConfig, PluginDefition, PluginType, DEBUG_MODE } from './interfaces'; +import { SBLogging, ServiceBase } from "./serviceBase"; +import {Plugin as DefaultConfig} from './plugins/config-default/plugin'; + +export class SBClient { + private serviceBase: ServiceBase; + public client!: Client; + + private useDefaultConfigPlugin: boolean; + constructor(useDefaultConfigPlugin: boolean = false) { + this.useDefaultConfigPlugin = useDefaultConfigPlugin; + const CWD = process.env.APP_DIR || process.cwd(); + this.serviceBase = new ServiceBase(false, true, CWD); + } + + public async initAndRun(client: typeof BSBServiceClient, ...args: any[]) { + if (!this.useDefaultConfigPlugin) + this.serviceBase.setConfigPlugin("config-bsb-internal-client", FakeServiceConfig); + + const service = this.serviceBase.addService( + "service-bsb-internal-client", + FakeServiceClient, + {} + ); + this.client = new (client as any)(service, ...args); + + await this.serviceBase.init(); + await this.serviceBase.run(); + } +} + +class FakeServiceClient extends BSBService { + public initBeforePlugins?: string[] | undefined; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public methods = {}; + dispose?(): void; + init?(): void | Promise { + throw new Error("Method not implemented."); + } + run?(): void | Promise { + throw new Error("Method not implemented."); + } + constructor(config: BSBServiceConstructor) { + super(config); + } +} + +class FakeServiceConfig extends BSBConfig { + private config: DefaultConfig; + constructor(appId: string, mode: DEBUG_MODE, pluginName: string, cwd: string, pluginCwd: string, logging: SBLogging) { + super(appId, mode, pluginName, cwd, pluginCwd, logging) + this.config = new DefaultConfig(appId, mode, pluginName, cwd, pluginCwd, logging); + } + async getLoggingPlugins(): Promise> { + return this.config.getLoggingPlugins(); + } + async getEventsPlugins(): Promise> { + return this.config.getEventsPlugins(); + } + async getServicePlugins(): Promise> { + return this.config.getServicePlugins(); + } + async getServicePluginDefinition(pluginName: string): Promise<{ name: string; enabled: boolean; }> { + return this.config.getServicePluginDefinition(pluginName); + } + async getPluginConfig(pluginType: PluginType, plugin: string): Promise { + return this.config.getPluginConfig(pluginType, plugin); + } + dispose() { + this.config.dispose(); + } + init() { + this.config.init(); + } +} diff --git a/nodejs/src/index.ts b/nodejs/src/index.ts index 672fd2a..9e2b55e 100644 --- a/nodejs/src/index.ts +++ b/nodejs/src/index.ts @@ -1,3 +1,4 @@ export * from "./base/index"; export * from "./interfaces/index"; export * from "./serviceBase/index"; +export { SBClient } from "./client"; diff --git a/nodejs/src/interfaces/plugins.ts b/nodejs/src/interfaces/plugins.ts index aaa36e1..6ea6a50 100644 --- a/nodejs/src/interfaces/plugins.ts +++ b/nodejs/src/interfaces/plugins.ts @@ -5,6 +5,7 @@ import { BSBConfig, BSBConfigRef } from "../base/config"; import { EventsEventTypes } from "./events"; import { BSBEvents } from "../base/events"; import { BSBEventsRef } from "../base/events"; +import { BSBServiceConfig } from "."; export const PluginTypes = { config: "config", @@ -15,9 +16,13 @@ export const PluginTypes = { export type PluginType = (typeof PluginTypes)[keyof typeof PluginTypes]; export type DeepReadonly = { - readonly [P in keyof T]: T[P] extends (infer R)[] ? DeepReadonlyArray : - T[P] extends Function ? T[P] : - T[P] extends object ? DeepReadonly : T[P]; + readonly [P in keyof T]: T[P] extends (infer R)[] + ? DeepReadonlyArray + : T[P] extends Function + ? T[P] + : T[P] extends object + ? DeepReadonly + : T[P]; }; export interface DeepReadonlyArray extends ReadonlyArray> {} export interface IPluginDefinition { @@ -92,3 +97,16 @@ export interface EventsConfig extends PluginDefition { } export type FilterOnType = // see EventsFilter and LoggingFilter for more details "all" | "events" | "eventsState" | "eventsPlugins" | "eventsDetailed"; + +export interface LoadedPlugin< + NamedType extends PluginType, + ClassType extends PluginTypeDefinitionRef = PluginTypeDefinitionRef +> { + name: string; + ref: string; + version: string; + serviceConfig: BSBServiceConfig | null; + plugin: ClassType; + pluginCWD: string; + pluginPath: string; +} diff --git a/nodejs/src/serviceBase/config.ts b/nodejs/src/serviceBase/config.ts index ec52191..3c899b9 100644 --- a/nodejs/src/serviceBase/config.ts +++ b/nodejs/src/serviceBase/config.ts @@ -11,6 +11,7 @@ import { } from "../base/functions"; import { EventsConfig, + LoadedPlugin, LoggingConfig, PluginDefition, PluginType, @@ -71,6 +72,31 @@ export class SBConfig { private configPackage: string | undefined; private configPluginName = "config-default"; + public async setConfigPlugin(reference: LoadedPlugin<"config">) { + this.configPlugin = new reference.plugin( + this.appId, + this.mode, + reference.name, + this.cwd, + reference.pluginCWD, + this.sbLogging + ); + this.log.info("Adding {pluginName} as config", { + pluginName: reference.name, + }); + + this.log.debug(`Init: {name}`, { + name: this.configPluginName, + }); + await SmartFunctionCallAsync(this.configPlugin, this.configPlugin.init); + + this.log.info(`Init: {name}: OK`, { + name: this.configPluginName, + }); + + return this.configPlugin; + } + public async init(): Promise { if ( Tools.isString(process.env.BSB_LOGGER_PLUGIN) && @@ -111,25 +137,6 @@ export class SBConfig { return; } - this.configPlugin = new newPlugin.plugin( - this.appId, - this.mode, - newPlugin.name, - this.cwd, - newPlugin.pluginCWD, - this.sbLogging - ); - this.log.info("Adding {pluginName} as config", { - pluginName: newPlugin.name, - }); - - this.log.debug(`Init: {name}`, { - name: this.configPluginName, - }); - await SmartFunctionCallAsync(this.configPlugin, this.configPlugin.init); - - this.log.info(`Init: {name}: OK`, { - name: this.configPluginName, - }); + await this.setConfigPlugin(newPlugin); } } diff --git a/nodejs/src/serviceBase/events.ts b/nodejs/src/serviceBase/events.ts index 82f5e70..68af434 100644 --- a/nodejs/src/serviceBase/events.ts +++ b/nodejs/src/serviceBase/events.ts @@ -22,6 +22,7 @@ import { BSBError } from "../base/errorMessages"; import { NS_PER_SEC, MS_PER_NS } from "./serviceBase"; import { BSBService } from "../base/service"; import { BSBServiceClient } from "../base/serviceClient"; +import { LoadedPlugin } from "../interfaces"; export class SBEvents { private events: Array<{ @@ -165,7 +166,9 @@ export class SBEvents { const events = this.events.filter((x) => x.name !== "events-default"); const allEvents = events.filter((x) => x.onTypeof === "all"); if (allEvents.length > 0) { - const defaultEvents = this.events.find((x) => x.name === "events-default"); + const defaultEvents = this.events.find( + (x) => x.name === "events-default" + ); if (defaultEvents !== undefined) { if (defaultEvents.plugin.dispose !== undefined) SmartFunctionCallSync( @@ -177,66 +180,28 @@ export class SBEvents { } } - private async addEvents( - sbConfig: SBConfig, + public async addPlugin( sbLogging: SBLogging, plugin: IPluginDefinition, + reference: LoadedPlugin<"events">, + config: object | null, filter?: EventsFilter ) { - this.log.debug("Add events {name} from ({package}){file}", { - package: plugin.package ?? "this project", - name: plugin.name, - file: plugin.plugin, - }); - if (plugin.name === "events-default") return; - this.log.debug(`Import events plugin: {name} from ({package}){file}`, { - package: plugin.package ?? "this project", - name: plugin.name, - file: plugin.plugin, - }); - - const newPlugin = await this.sbPlugins.loadPlugin<"events">( - this.log, - plugin.package ?? null, - plugin.plugin, - plugin.name - ); - if (newPlugin === null) { - this.log.error( - "Failed to import events plugin: {name} from ({package}){file}", - { - package: plugin.package ?? "this project", - name: plugin.name, - file: plugin.plugin, - } - ); - return; - } - this.log.debug(`Get plugin config: {name}`, { name: plugin.name, }); - let pluginConfig = await sbConfig.getPluginConfig("events", plugin.name); - - if (newPlugin.serviceConfig !== null) { - pluginConfig = - newPlugin.serviceConfig.validationSchema.parse(pluginConfig); - } else if (pluginConfig === null) { - pluginConfig = {}; - } - this.log.debug(`Construct events plugin: {name}`, { name: plugin.name, }); - let eventsPlugin = new newPlugin.plugin({ + let eventsPlugin = new reference.plugin({ appId: this.appId, mode: this.mode, - pluginName: newPlugin.name, + pluginName: reference.name, cwd: this.cwd, - pluginCwd: newPlugin.pluginCWD, - config: pluginConfig, + pluginCwd: reference.pluginCWD, + config: config, sbLogging, }); this.log.info("Adding {pluginName} as events with filter: ", { @@ -277,6 +242,56 @@ export class SBEvents { }); await SmartFunctionCallAsync(eventsPlugin, eventsPlugin.init); + + return eventsPlugin; + } + + private async addEvents( + sbConfig: SBConfig, + sbLogging: SBLogging, + plugin: IPluginDefinition, + filter?: EventsFilter + ) { + this.log.debug("Add events {name} from ({package}){file}", { + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, + }); + if (plugin.name === "events-default") return; + this.log.debug(`Import events plugin: {name} from ({package}){file}`, { + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, + }); + + const newPlugin = await this.sbPlugins.loadPlugin<"events">( + this.log, + plugin.package ?? null, + plugin.plugin, + plugin.name + ); + if (newPlugin === null) { + this.log.error( + "Failed to import events plugin: {name} from ({package}){file}", + { + package: plugin.package ?? "this project", + name: plugin.name, + file: plugin.plugin, + } + ); + return; + } + + let pluginConfig = await sbConfig.getPluginConfig("events", plugin.name); + + if (newPlugin.serviceConfig !== null) { + pluginConfig = + newPlugin.serviceConfig.validationSchema.parse(pluginConfig); + } else if (pluginConfig === null) { + pluginConfig = {}; + } + + await this.addPlugin(sbLogging, plugin, newPlugin, pluginConfig, filter); } private async handleOnBroadcast( diff --git a/nodejs/src/serviceBase/logging.ts b/nodejs/src/serviceBase/logging.ts index bf3f533..253c13b 100644 --- a/nodejs/src/serviceBase/logging.ts +++ b/nodejs/src/serviceBase/logging.ts @@ -23,6 +23,7 @@ import { SmartFunctionCallAsync, SmartFunctionCallSync, } from "../base/functions"; +import { LoadedPlugin } from "../interfaces"; export class SBLogging { private loggers: Array<{ @@ -253,65 +254,23 @@ export class SBLogging { } } - private async addLogger( - sbConfig: SBConfig, + public async addPlugin( plugin: IPluginDefinition, + reference: LoadedPlugin<"logging">, + config: object | null, filter?: LoggingFilter ) { - this.log.debug("Add logger {name} from ({package}){file}", { - package: plugin.package ?? "-", - name: plugin.name, - file: plugin.plugin, - }); - if (plugin.name === "logging-default") return; - this.log.debug(`Import logging plugin: {name} from ({package}){file}`, { - package: plugin.package ?? "-", - name: plugin.name, - file: plugin.plugin, - }); - - const newPlugin = await this.sbPlugins.loadPlugin<"logging">( - this.log, - plugin.package ?? null, - plugin.plugin, - plugin.name - ); - if (newPlugin === null) { - this.log.error( - "Failed to import logging plugin: {name} from ({package}){file}", - { - package: plugin.package ?? "-", - name: plugin.name, - file: plugin.plugin, - } - ); - return; - } - - this.log.debug(`Get plugin config: {name}`, { - name: plugin.name, - }); - - let pluginConfig = await sbConfig.getPluginConfig("logging", plugin.name); - - if (newPlugin.serviceConfig !== null) { - pluginConfig = - newPlugin.serviceConfig.validationSchema.parse(pluginConfig); - } else if (pluginConfig === null) { - pluginConfig = {}; - } - this.log.debug(`Construct logging plugin: {name}`, { name: plugin.name, }); - let loggerPlugin = new newPlugin.plugin({ + let loggerPlugin = new reference.plugin({ appId: this.appId, mode: this.mode, - pluginName: newPlugin.name, + pluginName: reference.name, cwd: this.cwd, - pluginCwd: newPlugin.pluginCWD, - config: pluginConfig, + pluginCwd: reference.pluginCWD, + config: config, }); this.log.info("Adding {pluginName} as logger with filter: ", { pluginName: plugin.name, @@ -350,5 +309,58 @@ export class SBLogging { }); await SmartFunctionCallAsync(loggerPlugin, loggerPlugin.init); + + return loggerPlugin; + } + + private async addLogger( + sbConfig: SBConfig, + plugin: IPluginDefinition, + filter?: LoggingFilter + ) { + this.log.debug("Add logger {name} from ({package}){file}", { + package: plugin.package ?? "-", + name: plugin.name, + file: plugin.plugin, + }); + if (plugin.name === "logging-default") return; + this.log.debug(`Import logging plugin: {name} from ({package}){file}`, { + package: plugin.package ?? "-", + name: plugin.name, + file: plugin.plugin, + }); + + const newPlugin = await this.sbPlugins.loadPlugin<"logging">( + this.log, + plugin.package ?? null, + plugin.plugin, + plugin.name + ); + if (newPlugin === null) { + this.log.error( + "Failed to import logging plugin: {name} from ({package}){file}", + { + package: plugin.package ?? "-", + name: plugin.name, + file: plugin.plugin, + } + ); + return; + } + + this.log.debug(`Get plugin config: {name}`, { + name: plugin.name, + }); + + let pluginConfig = await sbConfig.getPluginConfig("logging", plugin.name); + + if (newPlugin.serviceConfig !== null) { + pluginConfig = + newPlugin.serviceConfig.validationSchema.parse(pluginConfig); + } else if (pluginConfig === null) { + pluginConfig = {}; + } + + await this.addPlugin(plugin, newPlugin, pluginConfig, filter); } } diff --git a/nodejs/src/serviceBase/plugins.ts b/nodejs/src/serviceBase/plugins.ts index c38c8a4..c69c252 100644 --- a/nodejs/src/serviceBase/plugins.ts +++ b/nodejs/src/serviceBase/plugins.ts @@ -3,7 +3,11 @@ import { join } from "path"; import { PluginType, PluginTypeDefinitionRef } from "../interfaces/plugins"; import { IPluginLogger } from "../interfaces/logging"; import { BSBError } from "../base/errorMessages"; -import { BSBServiceConfig, BSBServiceConfigRef } from "../interfaces"; +import { + BSBServiceConfig, + BSBServiceConfigRef, + LoadedPlugin, +} from "../interfaces"; export class SBPlugins { protected cwd: string; @@ -31,17 +35,7 @@ export class SBPlugins { npmPackage: string | null, plugin: string, name: string - ): Promise<{ - name: string; - ref: string; - version: string; - serviceConfig: BSBServiceConfig | null; - //pluginFile: string; - //installerFile: string | null; - plugin: ClassType; - pluginCWD: string; - pluginPath: string; - } | null> { + ): Promise | null> { log.debug(`PLUGIN {name} from {package} try load as {pluginName}`, { name: plugin, pluginName: name, diff --git a/nodejs/src/serviceBase/serviceBase.ts b/nodejs/src/serviceBase/serviceBase.ts index e0f1432..fe1b928 100644 --- a/nodejs/src/serviceBase/serviceBase.ts +++ b/nodejs/src/serviceBase/serviceBase.ts @@ -4,20 +4,23 @@ import { SBPlugins } from "./plugins"; import { SBServices } from "./services"; import { IDictionary } from "@bettercorp/tools/lib/Interfaces"; import { SBConfig } from "./config"; -//import { SBEvents } from "./events"; import { randomUUID } from "crypto"; import { hostname } from "os"; import { Tools } from "@bettercorp/tools/lib/Tools"; import { PluginLogger } from "../base/PluginLogger"; import { SmartFunctionCallSync } from "../base/functions"; import { SBEvents } from "./events"; +import { PluginTypeDefinitionRef } from "../interfaces"; +import { BSBConfig, BSBError, BSBLogging } from "../base"; +import { BSBEvents } from "../base"; +import { BSBService } from "../base"; export const BOOT_STAT_KEYS = { BSB: "BSB", SELF: "SELF", PLUGINS: "PLUGINS", CONFIG: "CONFIG", - LOGGER: "LOGGER", + LOGGING: "LOGGER", EVENTS: "EVENTS", SERVICES: "SERVICES", INIT: "INIT", @@ -30,11 +33,6 @@ export const MS_PER_NS = 1e-6; const TIMEKEEPLOG = "[TIMER] {timerName} took ({nsTime}ns) ({msTime}ms)"; export class ServiceBase { - /*private _packJsonFile!: string; - private _bsbPackJsonFile!: string; - private _appVersion: string = "0.0.1-debug"; - private _bsbVersion: string = "0.0.1-debug";*/ - private mode: DEBUG_MODE = "development"; private readonly _CORE_PLUGIN_NAME = "core"; @@ -100,7 +98,7 @@ export class ServiceBase { this.logging, this.plugins ); - + this.log = new PluginLogger( this.mode, this._CORE_PLUGIN_NAME, @@ -140,9 +138,9 @@ export class ServiceBase { this._startKeep(BOOT_STAT_KEYS.CONFIG); await this.config.init(); this._outputKeep(BOOT_STAT_KEYS.CONFIG); - this._startKeep(BOOT_STAT_KEYS.LOGGER); + this._startKeep(BOOT_STAT_KEYS.LOGGING); await this.logging.init(this.config); - this._outputKeep(BOOT_STAT_KEYS.LOGGER); + this._outputKeep(BOOT_STAT_KEYS.LOGGING); this._startKeep(BOOT_STAT_KEYS.EVENTS); await this.events.init(this.config, this.logging); this._outputKeep(BOOT_STAT_KEYS.EVENTS); @@ -227,5 +225,116 @@ export class ServiceBase { console.warn("BSB Disposed successfully. exiting code " + eCode); process.exit(eCode); } + + public async setConfigPlugin(name: string, reference: typeof BSBConfig) { + if (this._keeps[BOOT_STAT_KEYS.CONFIG] !== undefined) + throw new BSBError( + "Cannot add config plugin as config already initialized", + {} + ); + return this.config.setConfigPlugin({ + serviceConfig: null, + plugin: reference as unknown as PluginTypeDefinitionRef<"config">, + pluginCWD: this.cwd, + pluginPath: "", + version: "0.0.0", + ref: name, + name, + }); + } + + public async addService( + name: string, + plugin: typeof BSBService, + config: object | any + ) { + if (this._keeps[BOOT_STAT_KEYS.SERVICES] !== undefined) + throw new BSBError( + "Cannot add service plugin as service already called", + {} + ); + return await this.services.addPlugin( + this.config, + this.logging, + this.events, + { + name, + plugin: name, + package: null, + version: "0.0.0", + }, + { + serviceConfig: config, + plugin: plugin as unknown as PluginTypeDefinitionRef<"service">, + pluginCWD: this.cwd, + pluginPath: "", + version: "0.0.0", + ref: name, + name, + }, + config + ); + } + + public async addEvents( + name: string, + plugin: typeof BSBEvents, + config: object | any + ) { + if (this._keeps[BOOT_STAT_KEYS.EVENTS] !== undefined) + throw new BSBError( + "Cannot add events plugin as events already initialized", + {} + ); + return await this.events.addPlugin( + this.logging, + { + name, + plugin: name, + package: null, + version: "0.0.0", + }, + { + serviceConfig: config, + plugin: plugin as unknown as PluginTypeDefinitionRef<"events">, + pluginCWD: this.cwd, + pluginPath: "", + version: "0.0.0", + ref: name, + name, + }, + config + ); + } + + public async addLogging( + name: string, + plugin: typeof BSBLogging, + config: object | any + ) { + if (this._keeps[BOOT_STAT_KEYS.LOGGING] !== undefined) + throw new BSBError( + "Cannot add logging plugin as logging already initialized", + {} + ); + return await this.logging.addPlugin( + { + name, + plugin: name, + package: null, + version: "0.0.0", + }, + { + serviceConfig: config, + plugin: plugin as unknown as PluginTypeDefinitionRef<"logging">, + pluginCWD: this.cwd, + pluginPath: "", + version: "0.0.0", + ref: name, + name, + }, + config + ); + } } export default ServiceBase; diff --git a/nodejs/src/serviceBase/services.ts b/nodejs/src/serviceBase/services.ts index e64e418..423ef49 100644 --- a/nodejs/src/serviceBase/services.ts +++ b/nodejs/src/serviceBase/services.ts @@ -14,6 +14,7 @@ import { IPluginDefinition } from "../interfaces/plugins"; import { BSBError } from "../base/errorMessages"; import { BSBServiceClient } from "../base/serviceClient"; import { PluginEvents } from "../base/PluginEvents"; +import { LoadedPlugin } from "../interfaces"; export class SBServices { private _activeServices: Array = []; @@ -126,6 +127,64 @@ export class SBServices { } return outlist; } + public async addPlugin( + sbConfig: SBConfig, + sbLogging: SBLogging, + sbEvents: SBEvents, + plugin: IPluginDefinition, + reference: LoadedPlugin<"service">, + config: object | null + ) { + this.log.debug(`Construct service plugin: {name}`, { + name: plugin.name, + }); + + let servicePlugin = new reference.plugin({ + appId: this.appId, + mode: this.mode, + pluginName: reference.name, + cwd: this.cwd, + pluginCwd: reference.pluginCWD, + config: config, + sbLogging: sbLogging, + sbEvents: sbEvents, + }); + this.log.debug("Adding {pluginName} as service", { + pluginName: plugin.name, + }); + + for (let client of servicePlugin._clients) { + this.log.debug("Construct {pluginName} client {clientName}", { + pluginName: plugin.name, + clientName: client.pluginName, + }); + await this.setupPluginClient( + sbConfig, + sbLogging, + sbEvents, + servicePlugin, + client + ); + this.log.debug( + "Setup {pluginName} client {asOriginalPluginName} as {clientName}", + { + pluginName: plugin.name, + clientName: client.pluginName, + asOriginalPluginName: (client as any)._pluginName, + } + ); + } + + this._activeServices.push(servicePlugin); + + this.log.info("Ready {pluginName} ({mappedName})", { + pluginName: plugin.plugin, + mappedName: plugin.name, + }); + + return servicePlugin; + } + private async addService( sbConfig: SBConfig, sbLogging: SBLogging, @@ -174,52 +233,14 @@ export class SBServices { pluginConfig = {}; } - this.log.debug(`Construct service plugin: {name}`, { - name: plugin.name, - }); - - let servicePlugin = new newPlugin.plugin({ - appId: this.appId, - mode: this.mode, - pluginName: newPlugin.name, - cwd: this.cwd, - pluginCwd: newPlugin.pluginCWD, - config: pluginConfig, - sbLogging: sbLogging, - sbEvents: sbEvents, - }); - this.log.debug("Adding {pluginName} as service", { - pluginName: plugin.name, - }); - - for (let client of servicePlugin._clients) { - this.log.debug("Construct {pluginName} client {clientName}", { - pluginName: plugin.name, - clientName: client.pluginName, - }); - await this.setupPluginClient( - sbConfig, - sbLogging, - sbEvents, - servicePlugin, - client - ); - this.log.debug( - "Setup {pluginName} client {asOriginalPluginName} as {clientName}", - { - pluginName: plugin.name, - clientName: client.pluginName, - asOriginalPluginName: (client as any)._pluginName, - } - ); - } - - this._activeServices.push(servicePlugin); - - this.log.info("Ready {pluginName} ({mappedName})", { - pluginName: plugin.plugin, - mappedName: plugin.name, - }); + await this.addPlugin( + sbConfig, + sbLogging, + sbEvents, + plugin, + newPlugin, + pluginConfig + ); } private initPluginClient = async ( From e73b9b3b7b57de8f7c8dabe8118011885cf417b5 Mon Sep 17 00:00:00 2001 From: mrinc Date: Sat, 16 Dec 2023 01:48:50 +0200 Subject: [PATCH 20/47] Updated client code --- nodejs/src/client.ts | 75 ++++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 27 deletions(-) diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts index 1df8176..42af88b 100644 --- a/nodejs/src/client.ts +++ b/nodejs/src/client.ts @@ -4,38 +4,53 @@ import { BSBServiceClient, BSBServiceConstructor, } from "./base"; -import { LoggingConfig, EventsConfig, PluginDefition, PluginType, DEBUG_MODE } from './interfaces'; +import { + LoggingConfig, + EventsConfig, + PluginDefition, + PluginType, + DEBUG_MODE, +} from "./interfaces"; import { SBLogging, ServiceBase } from "./serviceBase"; -import {Plugin as DefaultConfig} from './plugins/config-default/plugin'; +import { randomUUID } from "crypto"; export class SBClient { private serviceBase: ServiceBase; public client!: Client; private useDefaultConfigPlugin: boolean; + private configSetup: boolean = false; constructor(useDefaultConfigPlugin: boolean = false) { this.useDefaultConfigPlugin = useDefaultConfigPlugin; const CWD = process.env.APP_DIR || process.cwd(); this.serviceBase = new ServiceBase(false, true, CWD); } - public async initAndRun(client: typeof BSBServiceClient, ...args: any[]) { - if (!this.useDefaultConfigPlugin) - this.serviceBase.setConfigPlugin("config-bsb-internal-client", FakeServiceConfig); - + public async addClient(client: typeof BSBServiceClient, ...args: any[]) { + if (!this.useDefaultConfigPlugin && !this.configSetup) { + this.configSetup = true; + this.serviceBase.setConfigPlugin( + "config-bsb-internal-client", + FakeServiceConfig + ); + } const service = this.serviceBase.addService( - "service-bsb-internal-client", + "service-bsb-internal-client-" + randomUUID(), FakeServiceClient, {} ); - this.client = new (client as any)(service, ...args); + return new (client as any)(service, ...args); + } + public async init() { await this.serviceBase.init(); + } + public async run() { await this.serviceBase.run(); } } -class FakeServiceClient extends BSBService { +export class FakeServiceClient extends BSBService { public initBeforePlugins?: string[] | undefined; public initAfterPlugins?: string[] | undefined; public runBeforePlugins?: string[] | undefined; @@ -53,31 +68,37 @@ class FakeServiceClient extends BSBService { } } -class FakeServiceConfig extends BSBConfig { - private config: DefaultConfig; - constructor(appId: string, mode: DEBUG_MODE, pluginName: string, cwd: string, pluginCwd: string, logging: SBLogging) { - super(appId, mode, pluginName, cwd, pluginCwd, logging) - this.config = new DefaultConfig(appId, mode, pluginName, cwd, pluginCwd, logging); +export class FakeServiceConfig extends BSBConfig { + constructor( + appId: string, + mode: DEBUG_MODE, + pluginName: string, + cwd: string, + pluginCwd: string, + logging: SBLogging + ) { + super(appId, mode, pluginName, cwd, pluginCwd, logging); } async getLoggingPlugins(): Promise> { - return this.config.getLoggingPlugins(); + return {}; } async getEventsPlugins(): Promise> { - return this.config.getEventsPlugins(); + return {}; } async getServicePlugins(): Promise> { - return this.config.getServicePlugins(); + return {}; } - async getServicePluginDefinition(pluginName: string): Promise<{ name: string; enabled: boolean; }> { - return this.config.getServicePluginDefinition(pluginName); + async getServicePluginDefinition( + pluginName: string + ): Promise<{ name: string; enabled: boolean }> { + return { name: pluginName, enabled: false }; } - async getPluginConfig(pluginType: PluginType, plugin: string): Promise { - return this.config.getPluginConfig(pluginType, plugin); - } - dispose() { - this.config.dispose(); - } - init() { - this.config.init(); + async getPluginConfig( + pluginType: PluginType, + plugin: string + ): Promise { + return null; } + dispose?(): void; + init?(): void; } From 9ff1d26f9ba878cd3ba644997ed4d84d9afa27e3 Mon Sep 17 00:00:00 2001 From: mrinc Date: Sun, 17 Dec 2023 00:37:25 +0200 Subject: [PATCH 21/47] Updated zod type --- nodejs/package.json | 2 +- nodejs/src/base/base.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nodejs/package.json b/nodejs/package.json index a952cb3..45bf6ea 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -28,7 +28,7 @@ "README.md" ], "main": "lib/index.js", - "version": "9.0.2-beta", + "version": "9.0.3-beta", "devDependencies": { "@types/assert": "^1.5.6", "@types/chai": "^4.3.3", diff --git a/nodejs/src/base/base.ts b/nodejs/src/base/base.ts index 95c6c57..26afa74 100644 --- a/nodejs/src/base/base.ts +++ b/nodejs/src/base/base.ts @@ -109,7 +109,7 @@ export abstract class Base extends MainBase { * a: z.string(), * }); */ -export type BSBConfigType = z.AnyZodObject | undefined; +export type BSBConfigType = z.ZodTypeAny | undefined; export type BSBConfigDefinition = BSBServiceConfig; /** * Config migration handler, allows for config migrations when the plugin version changes or a new plugin setup is done From 3430f2751c8e35342cfddfbcbe9552e1baed255f Mon Sep 17 00:00:00 2001 From: mrinc Date: Sun, 17 Dec 2023 03:58:15 +0200 Subject: [PATCH 22/47] Updated zod types --- nodejs/package.json | 2 +- nodejs/src/base/base.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nodejs/package.json b/nodejs/package.json index 45bf6ea..147509b 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -28,7 +28,7 @@ "README.md" ], "main": "lib/index.js", - "version": "9.0.3-beta", + "version": "9.0.4-beta", "devDependencies": { "@types/assert": "^1.5.6", "@types/chai": "^4.3.3", diff --git a/nodejs/src/base/base.ts b/nodejs/src/base/base.ts index 26afa74..86ffd2b 100644 --- a/nodejs/src/base/base.ts +++ b/nodejs/src/base/base.ts @@ -110,7 +110,7 @@ export abstract class Base extends MainBase { * }); */ export type BSBConfigType = z.ZodTypeAny | undefined; -export type BSBConfigDefinition = BSBServiceConfig; +export type BSBConfigDefinition = BSBServiceConfig; /** * Config migration handler, allows for config migrations when the plugin version changes or a new plugin setup is done * @example simple version change and basic setup From 2887b6d94f7b1143cedc14a3a27321e26a8bacbd Mon Sep 17 00:00:00 2001 From: mrinc Date: Sun, 17 Dec 2023 15:40:13 +0200 Subject: [PATCH 23/47] Updated github build scripts node versions --- .github/workflows/build.yml | 14 +++++++------- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/develop.yml | 22 +++++++++++----------- .github/workflows/master.yml | 22 +++++++++++----------- .github/workflows/tags.yml | 20 ++++++++++---------- .github/workflows/updatePlugins.yml | 6 +++--- 6 files changed, 43 insertions(+), 43 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 48f2558..55dfdd4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,13 +16,13 @@ jobs: strategy: matrix: - node-version: [16.x, 18.x] + node-version: [18.x, 20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: "npm" @@ -47,7 +47,7 @@ jobs: reporter: mocha-json - name: Upload coverage reports to Codecov - if: contains(matrix.node-version, '18.x') + if: contains(matrix.node-version, '20.x') uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -62,17 +62,17 @@ jobs: strategy: matrix: - node-version: [16.x] + node-version: [20.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: "npm" diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 7be83a7..b10f84b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -38,7 +38,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml index 9e514ed..8f0a3e7 100644 --- a/.github/workflows/develop.yml +++ b/.github/workflows/develop.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: - node-version: [16.x, 18.x] + node-version: [18.x, 20.x] #experimental: [false] #include: # - node-version: 19.x @@ -22,12 +22,12 @@ jobs: outputs: version: ${{ steps.semver.outputs.version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: "npm" @@ -42,7 +42,7 @@ jobs: - name: semver id: semver - uses: paulhatch/semantic-version@v4.0.3 + uses: paulhatch/semantic-version@v5.3.0 with: tag_prefix: "v" branch: develop @@ -79,7 +79,7 @@ jobs: reporter: mocha-json - name: Upload coverage reports to Codecov - if: contains(matrix.node-version, '18.x') + if: contains(matrix.node-version, '20.x') uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -89,14 +89,14 @@ jobs: - run: npm publish --tag ea working-directory: ./nodejs - if: contains(matrix.node-version, '18.x') + if: contains(matrix.node-version, '20.x') - run: npm pack working-directory: ./nodejs - if: contains(matrix.node-version, '18.x') + if: contains(matrix.node-version, '20.x') - uses: actions/upload-artifact@v2 - if: contains(matrix.node-version, '18.x') + if: contains(matrix.node-version, '20.x') with: name: published-package path: ./nodejs/*.tgz @@ -151,17 +151,17 @@ jobs: strategy: matrix: - node-version: [16.x] + node-version: [20.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: "npm" diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index af36366..5ffd928 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -11,7 +11,7 @@ jobs: strategy: matrix: - node-version: [16.x, 18.x] + node-version: [18.x, 20.x] #experimental: [false] #include: # - node-version: 19.x @@ -22,12 +22,12 @@ jobs: outputs: version: ${{ steps.semver.outputs.version }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: "npm" @@ -42,7 +42,7 @@ jobs: - name: semver id: semver - uses: paulhatch/semantic-version@v4.0.3 + uses: paulhatch/semantic-version@v5.3.0 with: tag_prefix: "v" branch: master @@ -79,7 +79,7 @@ jobs: reporter: mocha-json - name: Upload coverage reports to Codecov - if: contains(matrix.node-version, '18.x') + if: contains(matrix.node-version, '20.x') uses: codecov/codecov-action@v3 with: token: ${{ secrets.CODECOV_TOKEN }} @@ -89,14 +89,14 @@ jobs: - run: npm publish --tag rc working-directory: ./nodejs - if: contains(matrix.node-version, '18.x') + if: contains(matrix.node-version, '20.x') - run: npm pack working-directory: ./nodejs - if: contains(matrix.node-version, '18.x') + if: contains(matrix.node-version, '20.x') - uses: actions/upload-artifact@v2 - if: contains(matrix.node-version, '18.x') + if: contains(matrix.node-version, '20.x') with: name: published-package path: nodejs/bettercorp-service-base-*.tgz @@ -151,17 +151,17 @@ jobs: strategy: matrix: - node-version: [16.x] + node-version: [20.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: "npm" diff --git a/.github/workflows/tags.yml b/.github/workflows/tags.yml index 3006b10..39dd69c 100644 --- a/.github/workflows/tags.yml +++ b/.github/workflows/tags.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: - node-version: [16.x, 18.x] + node-version: [18.x, 20.x] #experimental: [false] #include: # - node-version: 19.x @@ -24,12 +24,12 @@ jobs: version: ${{ steps.semver.outputs.version }} major: ${{ steps.semver.outputs.major }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: "npm" @@ -44,7 +44,7 @@ jobs: - name: semver id: semver - uses: paulhatch/semantic-version@v4.0.3 + uses: paulhatch/semantic-version@v5.3.0 with: tag_prefix: "v" # branch: master @@ -84,14 +84,14 @@ jobs: - run: npm publish working-directory: ./nodejs - if: contains(matrix.node-version, '18.x') + if: contains(matrix.node-version, '20.x') - run: npm pack working-directory: ./nodejs - if: contains(matrix.node-version, '18.x') + if: contains(matrix.node-version, '20.x') - uses: actions/upload-artifact@v2 - if: contains(matrix.node-version, '18.x') + if: contains(matrix.node-version, '20.x') with: name: published-package path: nodejs/bettercorp-service-base-*.tgz @@ -148,17 +148,17 @@ jobs: strategy: matrix: - node-version: [16.x] + node-version: [20.x] # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: fetch-depth: 0 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} cache: "npm" diff --git a/.github/workflows/updatePlugins.yml b/.github/workflows/updatePlugins.yml index a358380..85134a5 100644 --- a/.github/workflows/updatePlugins.yml +++ b/.github/workflows/updatePlugins.yml @@ -20,16 +20,16 @@ jobs: strategy: matrix: - node-version: [18.x] + node-version: [20.x] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: fetch-depth: 0 ref: documentation - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v3 + uses: actions/setup-node@v4 with: node-version: ${{ matrix.node-version }} From e32ca3de3243b842baa2c03f3c51f2671b1251f8 Mon Sep 17 00:00:00 2001 From: mrinc Date: Tue, 19 Dec 2023 00:12:31 +0200 Subject: [PATCH 24/47] Updated workflow, env name for bsb plugins and docker scripts --- .github/dependabot.yml | 19 +- .github/workflows/-build.yml | 85 ++++ .github/workflows/-develop.yml | 181 ++++++++ .github/workflows/-master.yml | 181 ++++++++ .github/workflows/-tags.yml | 178 ++++++++ .github/workflows/-updatePlugins.yml | 59 +++ .github/workflows/build.yml | 105 ++--- .github/workflows/develop.yml | 181 -------- .github/workflows/master.yml | 181 -------- .github/workflows/release.yml | 86 ++++ .github/workflows/tags.yml | 178 -------- .github/workflows/updatePlugins.yml | 59 --- nodejs/Dockerfile | 26 +- nodejs/LICENSE | 661 +++++++++++++++++++++++++++ nodejs/entrypoint.sh | 22 +- nodejs/package.json | 25 +- nodejs/src/serviceBase/plugins.ts | 6 +- 17 files changed, 1522 insertions(+), 711 deletions(-) create mode 100644 .github/workflows/-build.yml create mode 100644 .github/workflows/-develop.yml create mode 100644 .github/workflows/-master.yml create mode 100644 .github/workflows/-tags.yml create mode 100644 .github/workflows/-updatePlugins.yml delete mode 100644 .github/workflows/develop.yml delete mode 100644 .github/workflows/master.yml create mode 100644 .github/workflows/release.yml delete mode 100644 .github/workflows/tags.yml delete mode 100644 .github/workflows/updatePlugins.yml create mode 100644 nodejs/LICENSE diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 1ae01be..278bddc 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,9 +1,14 @@ version: 2 updates: -- package-ecosystem: npm - directory: "/ui" - target-branch: "develop" - schedule: - interval: monthly - time: "03:00" - open-pull-requests-limit: 10 + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + time: "04:00" + - package-ecosystem: npm + directory: "/nodejs" + target-branch: "develop" + schedule: + interval: weekly + time: "03:00" + open-pull-requests-limit: 3 diff --git a/.github/workflows/-build.yml b/.github/workflows/-build.yml new file mode 100644 index 0000000..5827903 --- /dev/null +++ b/.github/workflows/-build.yml @@ -0,0 +1,85 @@ +# name: Build Framework + +# on: +# pull_request: +# push: +# branches: +# - "**" +# - "!develop" +# - "!master" +# tags-ignore: +# - "**" + +# jobs: +# build-framework-nodejs: +# runs-on: ubuntu-latest + +# strategy: +# matrix: +# node-version: [18.x, 20.x] + +# steps: +# - uses: actions/checkout@v4 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: nodejs/package-lock.json + +# - run: npm i -g typescript ts-node +# working-directory: ./nodejs +# - run: tsc -v ; ts-node -v +# working-directory: ./nodejs +# - run: npm ci +# working-directory: ./nodejs +# - run: npm run build +# working-directory: ./nodejs +# - run: npm run test +# working-directory: ./nodejs + +# - name: Test Report ${{ matrix.node-version }} +# uses: dorny/test-reporter@v1.5.0 +# with: +# name: Tests +# path: nodejs/junit.json +# reporter: mocha-json + +# - name: Upload coverage reports to Codecov +# if: contains(matrix.node-version, '20.x') +# uses: codecov/codecov-action@v3 +# with: +# token: ${{ secrets.CODECOV_TOKEN }} +# directory: nodejs/coverage + +# - name: cleanup +# if: always() +# run: rm -f ~/.npmrc ; rm -f ./.npmrc; + +# docs_build_: +# runs-on: ubuntu-latest + +# strategy: +# matrix: +# node-version: [20.x] +# # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + +# steps: +# - name: Checkout +# uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: documentation/package-lock.json + +# - run: npm ci +# working-directory: documentation/ + +# - run: npm run build +# working-directory: documentation/ diff --git a/.github/workflows/-develop.yml b/.github/workflows/-develop.yml new file mode 100644 index 0000000..881d607 --- /dev/null +++ b/.github/workflows/-develop.yml @@ -0,0 +1,181 @@ +# name: Build and Publish (EA) + +# on: +# push: +# branches: +# - "develop" + +# jobs: +# build_and_publish_ea_nodejs: +# runs-on: ubuntu-latest + +# strategy: +# matrix: +# node-version: [18.x, 20.x] +# #experimental: [false] +# #include: +# # - node-version: 19.x +# # experimental: true + +# #continue-on-error: ${{ matrix.experimental }} + +# outputs: +# version: ${{ steps.semver.outputs.version }} +# steps: +# - uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: nodejs/package-lock.json + +# - run: npm i -g typescript ts-node +# working-directory: ./nodejs +# - run: tsc -v ; ts-node -v +# working-directory: ./nodejs +# - run: npm ci +# working-directory: ./nodejs + +# - name: semver +# id: semver +# uses: paulhatch/semantic-version@v5.3.0 +# with: +# tag_prefix: "v" +# branch: develop +# major_pattern: "(MAJOR)" +# minor_pattern: "(MINOR)" +# format: "${major}.${minor}.${patch}-ea.${increment}" +# change_path: "./" +# bump_each_commit: true +# namespace: "" + +# - run: rm -f ~/.npmrc ; rm -f ./.npmrc ; echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM2_TOKEN_PUB }}" > ./.npmrc +# working-directory: ./nodejs +# - run: | +# git config user.name "${{ secrets.NPM_NAME }}"; +# git config user.email "${{ secrets.NPM_EMAIL }}"; +# echo "Hello $(git config --get user.name)"; + +# - name: output version +# run: | +# echo "Setting version too: ${{ steps.semver.outputs.version }}"; + +# - run: npm version ${{ steps.semver.outputs.version }} +# working-directory: ./nodejs +# - run: npm run build +# working-directory: ./nodejs +# - run: npm run test +# working-directory: ./nodejs + +# - name: Test Report ${{ matrix.node-version }} +# uses: dorny/test-reporter@v1.5.0 +# with: +# name: Tests +# path: nodejs/junit.json +# reporter: mocha-json + +# - name: Upload coverage reports to Codecov +# if: contains(matrix.node-version, '20.x') +# uses: codecov/codecov-action@v3 +# with: +# token: ${{ secrets.CODECOV_TOKEN }} +# directory: nodejs/coverage + +# - run: cp README.md ./nodejs/README.md + +# - run: npm publish --tag ea +# working-directory: ./nodejs +# if: contains(matrix.node-version, '20.x') + +# - run: npm pack +# working-directory: ./nodejs +# if: contains(matrix.node-version, '20.x') + +# - uses: actions/upload-artifact@v2 +# if: contains(matrix.node-version, '20.x') +# with: +# name: published-package +# path: ./nodejs/*.tgz + +# - name: cleanup +# if: always() +# run: rm -f ~/.npmrc ; rm -f ./.npmrc; + +# docker_build_ea_nodejs: +# needs: [build_and_publish_ea_nodejs, docs_build_ea] +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v2 + +# - uses: actions/download-artifact@v2 +# with: +# name: published-package +# path: ./nodejs + +# - name: Set up QEMU +# uses: docker/setup-qemu-action@master +# with: +# platforms: all + +# - name: Set up Docker Buildx +# id: buildx +# uses: docker/setup-buildx-action@master + +# - name: Login to DockerHub +# if: github.event_name != 'pull_request' +# uses: docker/login-action@v1 +# with: +# username: ${{ secrets.DOCKER_HUB_USER }} +# password: ${{ secrets.DOCKER_HUB_TOKEN }} + +# - name: Build +# uses: docker/build-push-action@v2 +# with: +# builder: ${{ steps.buildx.outputs.name }} +# context: ./nodejs/ +# file: ./nodejs/Dockerfile +# platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x +# push: true +# tags: | +# betterweb/service-base:ea-node +# betterweb/service-base:node-${{ needs.build_and_publish_ea_nodejs.outputs.version }} + +# docs_build_ea: +# runs-on: ubuntu-latest +# needs: [build_and_publish_ea_nodejs] + +# strategy: +# matrix: +# node-version: [20.x] +# # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + +# steps: +# - name: Checkout +# uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: documentation/package-lock.json + +# - run: npm ci +# working-directory: documentation/ + +# - run: npm run build +# working-directory: documentation/ + +# - name: Update site +# uses: cloudflare/wrangler-action@2.0.0 +# with: +# apiToken: ${{ secrets.CF_API_TOKEN }} +# accountId: ${{ secrets.CF_ACCOUNT_ID }} +# command: pages publish documentation/.vuepress/dist --project-name=bsb-documentation --commit-dirty=true --branch=ea diff --git a/.github/workflows/-master.yml b/.github/workflows/-master.yml new file mode 100644 index 0000000..7aa312a --- /dev/null +++ b/.github/workflows/-master.yml @@ -0,0 +1,181 @@ +# name: Build and Publish (RC) + +# on: +# push: +# branches: +# - "master" + +# jobs: +# build_and_publish_rc_nodejs: +# runs-on: ubuntu-latest + +# strategy: +# matrix: +# node-version: [18.x, 20.x] +# #experimental: [false] +# #include: +# # - node-version: 19.x +# # experimental: true + +# #continue-on-error: ${{ matrix.experimental }} + +# outputs: +# version: ${{ steps.semver.outputs.version }} +# steps: +# - uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: nodejs/package-lock.json + +# - run: npm i -g typescript ts-node +# working-directory: ./nodejs +# - run: tsc -v ; ts-node -v +# working-directory: ./nodejs +# - run: npm ci +# working-directory: ./nodejs + +# - name: semver +# id: semver +# uses: paulhatch/semantic-version@v5.3.0 +# with: +# tag_prefix: "v" +# branch: master +# major_pattern: "(MAJOR)" +# minor_pattern: "(MINOR)" +# format: "${major}.${minor}.${patch}-rc.${increment}" +# change_path: "./" +# bump_each_commit: true +# namespace: "" + +# - run: rm -f ~/.npmrc ; rm -f ./.npmrc ; echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM2_TOKEN_PUB }}" > ./.npmrc +# working-directory: ./nodejs +# - run: | +# git config user.name "${{ secrets.NPM_NAME }}"; +# git config user.email "${{ secrets.NPM_EMAIL }}"; +# echo "Hello $(git config --get user.name)"; + +# - name: output version +# run: | +# echo "Setting version too: ${{ steps.semver.outputs.version }}"; + +# - run: npm version ${{ steps.semver.outputs.version }} +# working-directory: ./nodejs +# - run: npm run build +# working-directory: ./nodejs +# - run: npm run test +# working-directory: ./nodejs + +# - name: Test Report ${{ matrix.node-version }} +# uses: dorny/test-reporter@v1.5.0 +# with: +# name: Tests +# path: nodejs/junit.json +# reporter: mocha-json + +# - name: Upload coverage reports to Codecov +# if: contains(matrix.node-version, '20.x') +# uses: codecov/codecov-action@v3 +# with: +# token: ${{ secrets.CODECOV_TOKEN }} +# directory: nodejs/coverage + +# - run: cp README.md ./nodejs/README.md + +# - run: npm publish --tag rc +# working-directory: ./nodejs +# if: contains(matrix.node-version, '20.x') + +# - run: npm pack +# working-directory: ./nodejs +# if: contains(matrix.node-version, '20.x') + +# - uses: actions/upload-artifact@v2 +# if: contains(matrix.node-version, '20.x') +# with: +# name: published-package +# path: nodejs/bettercorp-service-base-*.tgz + +# - name: cleanup +# if: always() +# run: rm -f ~/.npmrc ; rm -f ./.npmrc; + +# docker_build_rc_nodejs: +# needs: [build_and_publish_rc_nodejs, docs_build_rc] +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v2 + +# - uses: actions/download-artifact@v2 +# with: +# name: published-package +# path: ./nodejs + +# - name: Set up QEMU +# uses: docker/setup-qemu-action@master +# with: +# platforms: all + +# - name: Set up Docker Buildx +# id: buildx +# uses: docker/setup-buildx-action@master + +# - name: Login to DockerHub +# if: github.event_name != 'pull_request' +# uses: docker/login-action@v1 +# with: +# username: ${{ secrets.DOCKER_HUB_USER }} +# password: ${{ secrets.DOCKER_HUB_TOKEN }} + +# - name: Build +# uses: docker/build-push-action@v2 +# with: +# builder: ${{ steps.buildx.outputs.name }} +# context: ./nodejs/ +# file: ./nodejs/Dockerfile +# platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x +# push: true +# tags: | +# betterweb/service-base:rc-node +# betterweb/service-base:node-${{ needs.build_and_publish_rc_nodejs.outputs.version }} + +# docs_build_rc: +# runs-on: ubuntu-latest +# needs: [build_and_publish_rc_nodejs] + +# strategy: +# matrix: +# node-version: [20.x] +# # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + +# steps: +# - name: Checkout +# uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: documentation/package-lock.json + +# - run: npm ci +# working-directory: documentation/ + +# - run: npm run build +# working-directory: documentation/ + +# - name: Update site +# uses: cloudflare/wrangler-action@2.0.0 +# with: +# apiToken: ${{ secrets.CF_API_TOKEN }} +# accountId: ${{ secrets.CF_ACCOUNT_ID }} +# command: pages publish documentation/.vuepress/dist --project-name=bsb-documentation --commit-dirty=true --branch=master diff --git a/.github/workflows/-tags.yml b/.github/workflows/-tags.yml new file mode 100644 index 0000000..89d24b2 --- /dev/null +++ b/.github/workflows/-tags.yml @@ -0,0 +1,178 @@ +# name: Build and Publish (LIVE) + +# on: +# create: +# tags: +# - "*" +# workflow_dispatch: + +# jobs: +# build_and_publish_prod_nodejs: +# runs-on: ubuntu-latest + +# strategy: +# matrix: +# node-version: [18.x, 20.x] +# #experimental: [false] +# #include: +# # - node-version: 19.x +# # experimental: true + +# #continue-on-error: ${{ matrix.experimental }} + +# outputs: +# version: ${{ steps.semver.outputs.version }} +# major: ${{ steps.semver.outputs.major }} +# steps: +# - uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: nodejs/package-lock.json + +# - run: npm i -g typescript ts-node +# working-directory: ./nodejs +# - run: tsc -v ; ts-node -v +# working-directory: ./nodejs +# - run: npm ci +# working-directory: ./nodejs + +# - name: semver +# id: semver +# uses: paulhatch/semantic-version@v5.3.0 +# with: +# tag_prefix: "v" +# # branch: master +# major_pattern: "(MAJOR)" +# minor_pattern: "(MINOR)" +# format: "${major}.${minor}.${patch}" +# change_path: "./" +# bump_each_commit: true +# namespace: "" + +# - run: rm -f ~/.npmrc ; rm -f ./.npmrc ; echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM2_TOKEN_PUB }}" > ./.npmrc +# working-directory: ./nodejs +# - run: | +# git config user.name "${{ secrets.NPM_NAME }}"; +# git config user.email "${{ secrets.NPM_EMAIL }}"; +# echo "Hello $(git config --get user.name)"; + +# - name: output version +# run: | +# echo "Setting version too: ${{ steps.semver.outputs.version }}"; + +# - run: npm version --no-git-tag-version ${{ steps.semver.outputs.version }} +# working-directory: ./nodejs +# - run: npm run build +# working-directory: ./nodejs +# - run: npm run test +# working-directory: ./nodejs + +# - name: Test Report ${{ matrix.node-version }} +# uses: dorny/test-reporter@v1.5.0 +# with: +# name: Tests +# path: nodejs/junit.json +# reporter: mocha-json + +# - run: cp README.md ./nodejs/README.md + +# - run: npm publish +# working-directory: ./nodejs +# if: contains(matrix.node-version, '20.x') + +# - run: npm pack +# working-directory: ./nodejs +# if: contains(matrix.node-version, '20.x') + +# - uses: actions/upload-artifact@v2 +# if: contains(matrix.node-version, '20.x') +# with: +# name: published-package +# path: nodejs/bettercorp-service-base-*.tgz + +# - name: cleanup +# if: always() +# run: rm -f ~/.npmrc ; rm -f ./.npmrc; + +# docker_build_prod_nodejs: +# needs: [build_and_publish_prod_nodejs, docs_build_prod] +# runs-on: ubuntu-latest +# steps: +# - name: Checkout +# uses: actions/checkout@v2 + +# - uses: actions/download-artifact@v2 +# with: +# name: published-package +# path: ./nodejs + +# - name: Set up QEMU +# uses: docker/setup-qemu-action@master +# with: +# platforms: all + +# - name: Set up Docker Buildx +# id: buildx +# uses: docker/setup-buildx-action@master + +# - name: Login to DockerHub +# if: github.event_name != 'pull_request' +# uses: docker/login-action@v1 +# with: +# username: ${{ secrets.DOCKER_HUB_USER }} +# password: ${{ secrets.DOCKER_HUB_TOKEN }} + +# - name: Build +# uses: docker/build-push-action@v2 +# with: +# builder: ${{ steps.buildx.outputs.name }} +# context: ./nodejs/ +# file: ./nodejs/Dockerfile +# platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x +# push: true +# tags: | +# betterweb/service-base:latest-node +# betterweb/service-base:node +# betterweb/service-base:node-${{ needs.build_and_publish_prod_nodejs.outputs.version }} +# betterweb/service-base:node-v${{ needs.build_and_publish_prod_nodejs.outputs.major }} + +# docs_build_prod: +# runs-on: ubuntu-latest +# needs: [build_and_publish_prod_nodejs] + +# strategy: +# matrix: +# node-version: [20.x] +# # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + +# steps: +# - name: Checkout +# uses: actions/checkout@v4 +# with: +# fetch-depth: 0 + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} +# cache: "npm" +# cache-dependency-path: documentation/package-lock.json + +# - run: npm ci +# working-directory: documentation/ + +# - run: npm run build +# working-directory: documentation/ + +# - name: Update site +# uses: cloudflare/wrangler-action@2.0.0 +# with: +# apiToken: ${{ secrets.CF_API_TOKEN }} +# accountId: ${{ secrets.CF_ACCOUNT_ID }} +# command: pages publish documentation/.vuepress/dist --project-name=bsb-documentation --commit-dirty=true --branch=master diff --git a/.github/workflows/-updatePlugins.yml b/.github/workflows/-updatePlugins.yml new file mode 100644 index 0000000..c63ff90 --- /dev/null +++ b/.github/workflows/-updatePlugins.yml @@ -0,0 +1,59 @@ +# name: Update documentation plugins + +# on: +# push: +# branches: +# - "master" +# # - "documentation" # Specifically disabled to stop infinite build loop +# - "develop" +# create: +# tags: +# - "*" +# schedule: +# - cron: "0 0/6 1/1 * *" +# workflow_dispatch: +# branches: [documentation] + +# jobs: +# build_and_update_plugins: +# runs-on: ubuntu-latest + +# strategy: +# matrix: +# node-version: [20.x] + +# steps: +# - uses: actions/checkout@v4 +# with: +# fetch-depth: 0 +# ref: documentation + +# - name: Use Node.js ${{ matrix.node-version }} +# uses: actions/setup-node@v4 +# with: +# node-version: ${{ matrix.node-version }} + +# - name: Plugin def generation +# id: plugin_generation +# run: node generatePluginData.js + +# - uses: EndBug/add-and-commit@v9 # You can change this to use a specific version. +# if: ${{ steps.plugin_generation.outputs.changes == 'true' }} +# with: +# add: "plugins.json" +# committer_name: GitHub Actions +# committer_email: actions@github.com +# message: "Updated known plugins" +# pull: "" +# push: true + +# - run: mkdir _tempCDN +# - run: cp ./plugins.json _tempCDN/plugins.json + +# - name: Update site +# if: ${{ steps.plugin_generation.outputs.changes == 'true' }} +# uses: cloudflare/wrangler-action@2.0.0 +# with: +# apiToken: ${{ secrets.CF_API_TOKEN }} +# accountId: ${{ secrets.CF_ACCOUNT_ID }} +# command: pages publish _tempCDN --project-name=bsb-cdn --commit-dirty=true --branch=master diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 55dfdd4..671e47b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,85 +1,54 @@ -name: Build Framework +name: Build Plugin on: pull_request: - push: - branches: - - "**" - - "!develop" - - "!master" - tags-ignore: - - "**" + workflow_dispatch: jobs: - build-framework-nodejs: + build_nodejs_plugin: + uses: BetterCorp/service-base-build-workflows/.github/workflows/node.yml@master + with: + WORKING_DIR: ./nodejs + PUBLISH: false + + docker_nodejs_plugin: + needs: [build_nodejs_plugin] runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [18.x, 20.x] - steps: - - uses: actions/checkout@v4 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: nodejs/package-lock.json + - name: Checkout + uses: actions/checkout@v2 - - run: npm i -g typescript ts-node - working-directory: ./nodejs - - run: tsc -v ; ts-node -v - working-directory: ./nodejs - - run: npm ci - working-directory: ./nodejs - - run: npm run build - working-directory: ./nodejs - - run: npm run test + - run: ./ci-build-dist working-directory: ./nodejs - - name: Test Report ${{ matrix.node-version }} - uses: dorny/test-reporter@v1.5.0 + - name: Download artifact + uses: actions/download-artifact@v2 with: - name: Tests - path: nodejs/junit.json - reporter: mocha-json + name: node-${{ needs.build_nodejs_plugin.outputs.tag }}-${{ needs.build_nodejs_plugin.outputs.version }} + path: ./nodejs/ci-build-dist/ - - name: Upload coverage reports to Codecov - if: contains(matrix.node-version, '20.x') - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: nodejs/coverage - - - name: cleanup - if: always() - run: rm -f ~/.npmrc ; rm -f ./.npmrc; - - docs_build_: - runs-on: ubuntu-latest + - name: Extract artifact + working-directory: ./nodejs + run: | + tar -xzf ./ci-build-dist/as-built.tar.gz -C ./ - strategy: - matrix: - node-version: [20.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ + - run: rm -rfv ./ci-build-dist + working-directory: ./nodejs - steps: - - name: Checkout - uses: actions/checkout@v4 + - name: Set up QEMU + uses: docker/setup-qemu-action@master with: - fetch-depth: 0 + platforms: all - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: documentation/package-lock.json - - - run: npm ci - working-directory: documentation/ + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@master - - run: npm run build - working-directory: documentation/ + - name: Build + uses: docker/build-push-action@v2 + with: + builder: ${{ steps.buildx.outputs.name }} + context: ./nodejs/ + file: ./nodejs/Dockerfile + platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + push: false diff --git a/.github/workflows/develop.yml b/.github/workflows/develop.yml deleted file mode 100644 index 8f0a3e7..0000000 --- a/.github/workflows/develop.yml +++ /dev/null @@ -1,181 +0,0 @@ -name: Build and Publish (EA) - -on: - push: - branches: - - "develop" - -jobs: - build_and_publish_ea_nodejs: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [18.x, 20.x] - #experimental: [false] - #include: - # - node-version: 19.x - # experimental: true - - #continue-on-error: ${{ matrix.experimental }} - - outputs: - version: ${{ steps.semver.outputs.version }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: nodejs/package-lock.json - - - run: npm i -g typescript ts-node - working-directory: ./nodejs - - run: tsc -v ; ts-node -v - working-directory: ./nodejs - - run: npm ci - working-directory: ./nodejs - - - name: semver - id: semver - uses: paulhatch/semantic-version@v5.3.0 - with: - tag_prefix: "v" - branch: develop - major_pattern: "(MAJOR)" - minor_pattern: "(MINOR)" - format: "${major}.${minor}.${patch}-ea.${increment}" - change_path: "./" - bump_each_commit: true - namespace: "" - - - run: rm -f ~/.npmrc ; rm -f ./.npmrc ; echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM2_TOKEN_PUB }}" > ./.npmrc - working-directory: ./nodejs - - run: | - git config user.name "${{ secrets.NPM_NAME }}"; - git config user.email "${{ secrets.NPM_EMAIL }}"; - echo "Hello $(git config --get user.name)"; - - - name: output version - run: | - echo "Setting version too: ${{ steps.semver.outputs.version }}"; - - - run: npm version ${{ steps.semver.outputs.version }} - working-directory: ./nodejs - - run: npm run build - working-directory: ./nodejs - - run: npm run test - working-directory: ./nodejs - - - name: Test Report ${{ matrix.node-version }} - uses: dorny/test-reporter@v1.5.0 - with: - name: Tests - path: nodejs/junit.json - reporter: mocha-json - - - name: Upload coverage reports to Codecov - if: contains(matrix.node-version, '20.x') - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: nodejs/coverage - - - run: cp README.md ./nodejs/README.md - - - run: npm publish --tag ea - working-directory: ./nodejs - if: contains(matrix.node-version, '20.x') - - - run: npm pack - working-directory: ./nodejs - if: contains(matrix.node-version, '20.x') - - - uses: actions/upload-artifact@v2 - if: contains(matrix.node-version, '20.x') - with: - name: published-package - path: ./nodejs/*.tgz - - - name: cleanup - if: always() - run: rm -f ~/.npmrc ; rm -f ./.npmrc; - - docker_build_ea_nodejs: - needs: [build_and_publish_ea_nodejs, docs_build_ea] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - uses: actions/download-artifact@v2 - with: - name: published-package - path: ./nodejs - - - name: Set up QEMU - uses: docker/setup-qemu-action@master - with: - platforms: all - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@master - - - name: Login to DockerHub - if: github.event_name != 'pull_request' - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_HUB_USER }} - password: ${{ secrets.DOCKER_HUB_TOKEN }} - - - name: Build - uses: docker/build-push-action@v2 - with: - builder: ${{ steps.buildx.outputs.name }} - context: ./nodejs/ - file: ./nodejs/Dockerfile - platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x - push: true - tags: | - betterweb/service-base:ea-node - betterweb/service-base:node-${{ needs.build_and_publish_ea_nodejs.outputs.version }} - - docs_build_ea: - runs-on: ubuntu-latest - needs: [build_and_publish_ea_nodejs] - - strategy: - matrix: - node-version: [20.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: documentation/package-lock.json - - - run: npm ci - working-directory: documentation/ - - - run: npm run build - working-directory: documentation/ - - - name: Update site - uses: cloudflare/wrangler-action@2.0.0 - with: - apiToken: ${{ secrets.CF_API_TOKEN }} - accountId: ${{ secrets.CF_ACCOUNT_ID }} - command: pages publish documentation/.vuepress/dist --project-name=bsb-documentation --commit-dirty=true --branch=ea diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml deleted file mode 100644 index 5ffd928..0000000 --- a/.github/workflows/master.yml +++ /dev/null @@ -1,181 +0,0 @@ -name: Build and Publish (RC) - -on: - push: - branches: - - "master" - -jobs: - build_and_publish_rc_nodejs: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [18.x, 20.x] - #experimental: [false] - #include: - # - node-version: 19.x - # experimental: true - - #continue-on-error: ${{ matrix.experimental }} - - outputs: - version: ${{ steps.semver.outputs.version }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: nodejs/package-lock.json - - - run: npm i -g typescript ts-node - working-directory: ./nodejs - - run: tsc -v ; ts-node -v - working-directory: ./nodejs - - run: npm ci - working-directory: ./nodejs - - - name: semver - id: semver - uses: paulhatch/semantic-version@v5.3.0 - with: - tag_prefix: "v" - branch: master - major_pattern: "(MAJOR)" - minor_pattern: "(MINOR)" - format: "${major}.${minor}.${patch}-rc.${increment}" - change_path: "./" - bump_each_commit: true - namespace: "" - - - run: rm -f ~/.npmrc ; rm -f ./.npmrc ; echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM2_TOKEN_PUB }}" > ./.npmrc - working-directory: ./nodejs - - run: | - git config user.name "${{ secrets.NPM_NAME }}"; - git config user.email "${{ secrets.NPM_EMAIL }}"; - echo "Hello $(git config --get user.name)"; - - - name: output version - run: | - echo "Setting version too: ${{ steps.semver.outputs.version }}"; - - - run: npm version ${{ steps.semver.outputs.version }} - working-directory: ./nodejs - - run: npm run build - working-directory: ./nodejs - - run: npm run test - working-directory: ./nodejs - - - name: Test Report ${{ matrix.node-version }} - uses: dorny/test-reporter@v1.5.0 - with: - name: Tests - path: nodejs/junit.json - reporter: mocha-json - - - name: Upload coverage reports to Codecov - if: contains(matrix.node-version, '20.x') - uses: codecov/codecov-action@v3 - with: - token: ${{ secrets.CODECOV_TOKEN }} - directory: nodejs/coverage - - - run: cp README.md ./nodejs/README.md - - - run: npm publish --tag rc - working-directory: ./nodejs - if: contains(matrix.node-version, '20.x') - - - run: npm pack - working-directory: ./nodejs - if: contains(matrix.node-version, '20.x') - - - uses: actions/upload-artifact@v2 - if: contains(matrix.node-version, '20.x') - with: - name: published-package - path: nodejs/bettercorp-service-base-*.tgz - - - name: cleanup - if: always() - run: rm -f ~/.npmrc ; rm -f ./.npmrc; - - docker_build_rc_nodejs: - needs: [build_and_publish_rc_nodejs, docs_build_rc] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - uses: actions/download-artifact@v2 - with: - name: published-package - path: ./nodejs - - - name: Set up QEMU - uses: docker/setup-qemu-action@master - with: - platforms: all - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@master - - - name: Login to DockerHub - if: github.event_name != 'pull_request' - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_HUB_USER }} - password: ${{ secrets.DOCKER_HUB_TOKEN }} - - - name: Build - uses: docker/build-push-action@v2 - with: - builder: ${{ steps.buildx.outputs.name }} - context: ./nodejs/ - file: ./nodejs/Dockerfile - platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x - push: true - tags: | - betterweb/service-base:rc-node - betterweb/service-base:node-${{ needs.build_and_publish_rc_nodejs.outputs.version }} - - docs_build_rc: - runs-on: ubuntu-latest - needs: [build_and_publish_rc_nodejs] - - strategy: - matrix: - node-version: [20.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: documentation/package-lock.json - - - run: npm ci - working-directory: documentation/ - - - run: npm run build - working-directory: documentation/ - - - name: Update site - uses: cloudflare/wrangler-action@2.0.0 - with: - apiToken: ${{ secrets.CF_API_TOKEN }} - accountId: ${{ secrets.CF_ACCOUNT_ID }} - command: pages publish documentation/.vuepress/dist --project-name=bsb-documentation --commit-dirty=true --branch=master diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..38f4e94 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,86 @@ +name: Build and Publish Plugin + +on: + create: + tags: + - "*" + push: + branches: + - "**" + tags-ignore: + - "**" + +jobs: + build_nodejs_plugin_release: + uses: BetterCorp/service-base-build-workflows/.github/workflows/node.yml@master + with: + PUBLISH: true + WORKING_DIR: ./nodejs + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + NPM_PUBLISH_TOKEN: ${{ secrets.NPM2_TOKEN_PUB }} + NPM_EMAIL: ${{ secrets.NPM_EMAIL }} + NPM_NAME: ${{ secrets.NPM_NAME }} + + docker_nodejs_plugin_release: + needs: [build_nodejs_plugin_release] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + - run: ./ci-build-dist + working-directory: ./nodejs + + - name: Download artifact + uses: actions/download-artifact@v2 + with: + name: node-${{ needs.build_nodejs_plugin_release.outputs.tag }}-${{ needs.build_nodejs_plugin_release.outputs.version }} + path: ./nodejs/ci-build-dist/ + + - name: Extract artifact + working-directory: ./nodejs + run: | + tar -xzf ./ci-build-dist/as-built.tar.gz -C ./ + + - run: rm -rfv ./ci-build-dist + working-directory: ./nodejs + + - name: Set up QEMU + uses: docker/setup-qemu-action@master + with: + platforms: all + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@master + + - name: Login to DockerHub + uses: docker/login-action@v1 + with: + username: ${{ secrets.DOCKER_HUB_USER }} + password: ${{ secrets.DOCKER_HUB_TOKEN }} + + - name: Build + uses: docker/build-push-action@v2 + with: + builder: ${{ steps.buildx.outputs.name }} + context: ./nodejs/ + file: ./nodejs/Dockerfile + platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + push: true + tags: | + betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.tag }} + betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.version }} + + - name: Build + uses: docker/build-push-action@v2 + if: needs.build_nodejs_plugin_release.outputs.tag == 'latest' + with: + builder: ${{ steps.buildx.outputs.name }} + context: ./nodejs/ + file: ./nodejs/Dockerfile + platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + push: true + tags: | + betterweb/service-base:node \ No newline at end of file diff --git a/.github/workflows/tags.yml b/.github/workflows/tags.yml deleted file mode 100644 index 39dd69c..0000000 --- a/.github/workflows/tags.yml +++ /dev/null @@ -1,178 +0,0 @@ -name: Build and Publish (LIVE) - -on: - create: - tags: - - "*" - workflow_dispatch: - -jobs: - build_and_publish_prod_nodejs: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [18.x, 20.x] - #experimental: [false] - #include: - # - node-version: 19.x - # experimental: true - - #continue-on-error: ${{ matrix.experimental }} - - outputs: - version: ${{ steps.semver.outputs.version }} - major: ${{ steps.semver.outputs.major }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: nodejs/package-lock.json - - - run: npm i -g typescript ts-node - working-directory: ./nodejs - - run: tsc -v ; ts-node -v - working-directory: ./nodejs - - run: npm ci - working-directory: ./nodejs - - - name: semver - id: semver - uses: paulhatch/semantic-version@v5.3.0 - with: - tag_prefix: "v" - # branch: master - major_pattern: "(MAJOR)" - minor_pattern: "(MINOR)" - format: "${major}.${minor}.${patch}" - change_path: "./" - bump_each_commit: true - namespace: "" - - - run: rm -f ~/.npmrc ; rm -f ./.npmrc ; echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM2_TOKEN_PUB }}" > ./.npmrc - working-directory: ./nodejs - - run: | - git config user.name "${{ secrets.NPM_NAME }}"; - git config user.email "${{ secrets.NPM_EMAIL }}"; - echo "Hello $(git config --get user.name)"; - - - name: output version - run: | - echo "Setting version too: ${{ steps.semver.outputs.version }}"; - - - run: npm version --no-git-tag-version ${{ steps.semver.outputs.version }} - working-directory: ./nodejs - - run: npm run build - working-directory: ./nodejs - - run: npm run test - working-directory: ./nodejs - - - name: Test Report ${{ matrix.node-version }} - uses: dorny/test-reporter@v1.5.0 - with: - name: Tests - path: nodejs/junit.json - reporter: mocha-json - - - run: cp README.md ./nodejs/README.md - - - run: npm publish - working-directory: ./nodejs - if: contains(matrix.node-version, '20.x') - - - run: npm pack - working-directory: ./nodejs - if: contains(matrix.node-version, '20.x') - - - uses: actions/upload-artifact@v2 - if: contains(matrix.node-version, '20.x') - with: - name: published-package - path: nodejs/bettercorp-service-base-*.tgz - - - name: cleanup - if: always() - run: rm -f ~/.npmrc ; rm -f ./.npmrc; - - docker_build_prod_nodejs: - needs: [build_and_publish_prod_nodejs, docs_build_prod] - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v2 - - - uses: actions/download-artifact@v2 - with: - name: published-package - path: ./nodejs - - - name: Set up QEMU - uses: docker/setup-qemu-action@master - with: - platforms: all - - - name: Set up Docker Buildx - id: buildx - uses: docker/setup-buildx-action@master - - - name: Login to DockerHub - if: github.event_name != 'pull_request' - uses: docker/login-action@v1 - with: - username: ${{ secrets.DOCKER_HUB_USER }} - password: ${{ secrets.DOCKER_HUB_TOKEN }} - - - name: Build - uses: docker/build-push-action@v2 - with: - builder: ${{ steps.buildx.outputs.name }} - context: ./nodejs/ - file: ./nodejs/Dockerfile - platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x - push: true - tags: | - betterweb/service-base:latest-node - betterweb/service-base:node - betterweb/service-base:node-${{ needs.build_and_publish_prod_nodejs.outputs.version }} - betterweb/service-base:node-v${{ needs.build_and_publish_prod_nodejs.outputs.major }} - - docs_build_prod: - runs-on: ubuntu-latest - needs: [build_and_publish_prod_nodejs] - - strategy: - matrix: - node-version: [20.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: "npm" - cache-dependency-path: documentation/package-lock.json - - - run: npm ci - working-directory: documentation/ - - - run: npm run build - working-directory: documentation/ - - - name: Update site - uses: cloudflare/wrangler-action@2.0.0 - with: - apiToken: ${{ secrets.CF_API_TOKEN }} - accountId: ${{ secrets.CF_ACCOUNT_ID }} - command: pages publish documentation/.vuepress/dist --project-name=bsb-documentation --commit-dirty=true --branch=master diff --git a/.github/workflows/updatePlugins.yml b/.github/workflows/updatePlugins.yml deleted file mode 100644 index 85134a5..0000000 --- a/.github/workflows/updatePlugins.yml +++ /dev/null @@ -1,59 +0,0 @@ -name: Update documentation plugins - -on: - push: - branches: - - "master" - # - "documentation" # Specifically disabled to stop infinite build loop - - "develop" - create: - tags: - - "*" - schedule: - - cron: "0 0/6 1/1 * *" - workflow_dispatch: - branches: [documentation] - -jobs: - build_and_update_plugins: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [20.x] - - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - ref: documentation - - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - - - name: Plugin def generation - id: plugin_generation - run: node generatePluginData.js - - - uses: EndBug/add-and-commit@v9 # You can change this to use a specific version. - if: ${{ steps.plugin_generation.outputs.changes == 'true' }} - with: - add: "plugins.json" - committer_name: GitHub Actions - committer_email: actions@github.com - message: "Updated known plugins" - pull: "" - push: true - - - run: mkdir _tempCDN - - run: cp ./plugins.json _tempCDN/plugins.json - - - name: Update site - if: ${{ steps.plugin_generation.outputs.changes == 'true' }} - uses: cloudflare/wrangler-action@2.0.0 - with: - apiToken: ${{ secrets.CF_API_TOKEN }} - accountId: ${{ secrets.CF_ACCOUNT_ID }} - command: pages publish _tempCDN --project-name=bsb-cdn --commit-dirty=true --branch=master diff --git a/nodejs/Dockerfile b/nodejs/Dockerfile index 3deafe0..bf1c73d 100644 --- a/nodejs/Dockerfile +++ b/nodejs/Dockerfile @@ -12,27 +12,31 @@ ENV BSB_PLUGIN_DIR /mnt/bsb-plugins # NPM repo defaults #RUN pnpm config set auto-install-peers true -RUN npm init -y -RUN echo '{"deploymentProfiles":{"default":{}},"plugins":{}}' >> ./sec.config.json +#RUN npm init -y +#RUN echo '{"deploymentProfiles":{"default":{}},"plugins":{}}' >> ./sec.config.json # RUN pushd /mnt/bsb-plugins && npm init -y && pushd # Add core BSB lib (from local) -RUN mkdir /home/bsb-build -COPY *.tgz /home/bsb-build/ +ADD package.json /home/bsb/package.json +ADD package-lock.json /home/bsb/package-lock.json +ADD lib/ /home/bsb/lib/ + +#RUN mkdir /home/bsb-build +#COPY *.tgz /home/bsb-build/ COPY entrypoint.sh /root/entrypoint.sh -COPY entrypoint.js /root/entrypoint.js -RUN chmod 550 /root/entrypoint.sh +#COPY entrypoint.js /root/entrypoint.js +#RUN chmod 550 /root/entrypoint.sh # Default plugins/setup -RUN ls -la /home/bsb-build/ -RUN pnpm add "/home/bsb-build/$(ls /home/bsb-build/ | grep .tgz | head -1)" +#RUN ls -la /home/bsb-build/ +#RUN pnpm add "/home/bsb-build/$(ls /home/bsb-build/ | grep .tgz | head -1)" # RUN pnpm i --prod --fix-lockfile "/home/bsb-build/$(ls /home/bsb-build/ | grep .tgz | head -1)" -RUN node ./node_modules/@bettercorp/service-base/postinstall.js --cwd=$(pwd) +#RUN node ./node_modules/@bettercorp/service-base/postinstall.js --cwd=$(pwd) -RUN cat ./package.json +#RUN cat ./package.json # Cleanup -RUN rm -rfv /home/bsb-build +#RUN rm -rfv /home/bsb-build RUN chown -R root:node /home/bsb RUN chmod -R 650 /home/bsb diff --git a/nodejs/LICENSE b/nodejs/LICENSE new file mode 100644 index 0000000..1f84167 --- /dev/null +++ b/nodejs/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. \ No newline at end of file diff --git a/nodejs/entrypoint.sh b/nodejs/entrypoint.sh index f2a9d72..92249c1 100644 --- a/nodejs/entrypoint.sh +++ b/nodejs/entrypoint.sh @@ -1,20 +1,20 @@ #!/bin/sh -if [ "$BSB_CONTAINER" == "true" ]; then - cd /mnt/bsb-plugins - node /root/entrypoint.js - cd /home/bsb - # node ./node_modules/@bettercorp/service-base/postinstall.js --cwd=$(pwd) -fi +# if [ "$BSB_CONTAINER" == "true" ]; then +# cd /mnt/bsb-plugins +# node /root/entrypoint.js +# cd /home/bsb +# # node ./node_modules/@bettercorp/service-base/postinstall.js --cwd=$(pwd) +# fi -if [ "$BSB_DIALOUT" == "true" ]; then - addgroup node dialout; -fi +addgroup node dialout; chown -R root:node /home/bsb chmod -R 650 /home/bsb -chown node:node /home/bsb/sec.config.json +mkdir /home/bsb/.temp +chmod -R 660 /home/bsb/.temp +chown node:node /home/bsb/sec-config.yaml chown -R root:node /mnt/bsb-plugins -chmod -R 650 /mnt/bsb-plugins +chmod -R 660 /mnt/bsb-plugins exec gosu node "$@" diff --git a/nodejs/package.json b/nodejs/package.json index 147509b..08f5ad9 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -25,24 +25,25 @@ "lib/**/*", "development/**/*", "tsconfig.json", - "README.md" + "README.md", + "LICENSE" ], "main": "lib/index.js", "version": "9.0.4-beta", "devDependencies": { - "@types/assert": "^1.5.6", - "@types/chai": "^4.3.3", - "@types/mocha": "^9.1.1", - "@types/node": "^18.19.3", - "@types/yargs": "^17.0.12", - "@typescript-eslint/eslint-plugin": "^5.31.0", - "@typescript-eslint/parser": "^5.31.0", + "@types/assert": "^1.5.10", + "@types/chai": "^4.3.11", + "@types/mocha": "^10.0.6", + "@types/node": "^20.10.5", + "@types/yargs": "^17.0.32", + "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/parser": "^6.14.0", "chai": "^4.3.10", - "eslint": "^8.20.0", - "mocha": "^10.0.0", + "eslint": "^8.56.0", + "mocha": "^10.2.0", "nyc": "^15.1.0", - "ts-node": "^10.9.1", - "typescript": "^4.7.4", + "ts-node": "^10.9.2", + "typescript": "^5.3.3", "yargs": "^17.5.1" }, "dependencies": { diff --git a/nodejs/src/serviceBase/plugins.ts b/nodejs/src/serviceBase/plugins.ts index c69c252..0c75fcd 100644 --- a/nodejs/src/serviceBase/plugins.ts +++ b/nodejs/src/serviceBase/plugins.ts @@ -18,10 +18,10 @@ export class SBPlugins { this.cwd = cwd; this.devMode = devMode; if ( - typeof process.env.PLUGIN_DIR == "string" && - process.env.PLUGIN_DIR.length > 3 + typeof process.env.BSB_PLUGIN_DIR == "string" && + process.env.BSB_PLUGIN_DIR.length > 3 ) { - this.pluginDir = process.env.PLUGIN_DIR; + this.pluginDir = process.env.BSB_PLUGIN_DIR; } else { this.pluginDir = join(this.cwd, "./node_modules/"); } From 2a9372b6adcda4e88d2e59e84d88b293d8a29b23 Mon Sep 17 00:00:00 2001 From: mrinc Date: Tue, 19 Dec 2023 00:16:28 +0200 Subject: [PATCH 25/47] Fixed package json ref --- nodejs/package-lock.json | 314 +++++++++++++++++---------------------- 1 file changed, 134 insertions(+), 180 deletions(-) diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 9b9d494..3aa1179 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -1,13 +1,12 @@ { "name": "@bettercorp/service-base", - "version": "9.0.0-beta", + "version": "9.0.4-beta", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bettercorp/service-base", - "version": "9.0.0-beta", - "hasInstallScript": true, + "version": "9.0.4-beta", "license": "AGPL-3.0-only", "dependencies": { "@bettercorp/tools": "^2.0.20220714140658", @@ -18,19 +17,19 @@ "bsb": "lib/bootstrap.js" }, "devDependencies": { - "@types/assert": "^1.5.6", - "@types/chai": "^4.3.3", - "@types/mocha": "^9.1.1", - "@types/node": "^18.19.3", - "@types/yargs": "^17.0.12", - "@typescript-eslint/eslint-plugin": "^5.31.0", - "@typescript-eslint/parser": "^5.31.0", + "@types/assert": "^1.5.10", + "@types/chai": "^4.3.11", + "@types/mocha": "^10.0.6", + "@types/node": "^20.10.5", + "@types/yargs": "^17.0.32", + "@typescript-eslint/eslint-plugin": "^6.14.0", + "@typescript-eslint/parser": "^6.14.0", "chai": "^4.3.10", - "eslint": "^8.20.0", - "mocha": "^10.0.0", + "eslint": "^8.56.0", + "mocha": "^10.2.0", "nyc": "^15.1.0", - "ts-node": "^10.9.1", - "typescript": "^4.7.4", + "ts-node": "^10.9.2", + "typescript": "^5.3.3", "yargs": "^17.5.1" }, "engines": { @@ -534,6 +533,14 @@ "moment": "^2.29.4" } }, + "node_modules/@bettercorp/tools/node_modules/@types/node": { + "version": "18.19.3", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", + "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", @@ -604,9 +611,9 @@ } }, "node_modules/@eslint/js": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz", - "integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -879,15 +886,16 @@ "dev": true }, "node_modules/@types/mocha": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", - "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.6.tgz", + "integrity": "sha512-dJvrYWxP/UcXm36Qn36fxhUKu8A/xMRXVT2cliFF1Z7UA9liG5Psj3ezNSZw+5puH2czDXRLcXQxf8JbJt0ejg==", "dev": true }, "node_modules/@types/node": { - "version": "18.19.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", - "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", + "version": "20.10.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", + "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "dev": true, "dependencies": { "undici-types": "~5.26.4" } @@ -914,32 +922,33 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", - "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.15.0.tgz", + "integrity": "sha512-j5qoikQqPccq9QoBAupOP+CBu8BaJ8BLjaXSioDISeTZkVO3ig7oSIKh3H+rEpee7xCXtWwSB4KIL5l6hWZzpg==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.15.0", + "@typescript-eslint/type-utils": "6.15.0", + "@typescript-eslint/utils": "6.15.0", + "@typescript-eslint/visitor-keys": "6.15.0", "debug": "^4.3.4", "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -948,25 +957,26 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.15.0.tgz", + "integrity": "sha512-MkgKNnsjC6QwcMdlNAel24jjkEO/0hQaMDLqP4S9zq5HBAUJNQB6y+3DwLjX7b3l2b37eNAxMPLwb3/kh8VKdA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", + "@typescript-eslint/scope-manager": "6.15.0", + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/typescript-estree": "6.15.0", + "@typescript-eslint/visitor-keys": "6.15.0", "debug": "^4.3.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -975,16 +985,16 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.15.0.tgz", + "integrity": "sha512-+BdvxYBltqrmgCNu4Li+fGDIkW9n//NrruzG9X1vBzaNK+ExVXPoGB71kneaVw/Jp+4rH/vaMAGC6JfMbHstVg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/visitor-keys": "6.15.0" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -992,25 +1002,25 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.15.0.tgz", + "integrity": "sha512-CnmHKTfX6450Bo49hPg2OkIm/D/TVYV7jO1MCfPYGwf6x3GO0VU8YMO5AYMn+u3X05lRRxA4fWCz87GFQV6yVQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", + "@typescript-eslint/typescript-estree": "6.15.0", + "@typescript-eslint/utils": "6.15.0", "debug": "^4.3.4", - "tsutils": "^3.21.0" + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "*" + "eslint": "^7.0.0 || ^8.0.0" }, "peerDependenciesMeta": { "typescript": { @@ -1019,12 +1029,12 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.15.0.tgz", + "integrity": "sha512-yXjbt//E4T/ee8Ia1b5mGlbNj9fB9lJP4jqLbZualwpP2BCQ5is6BcWwxpIsY4XKAhmdv3hrW92GdtJbatC6dQ==", "dev": true, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -1032,21 +1042,21 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.15.0.tgz", + "integrity": "sha512-7mVZJN7Hd15OmGuWrp2T9UvqR2Ecg+1j/Bp1jXUEY2GZKV6FXlOIoqVDmLpBiEiq3katvj/2n2mR0SDwtloCew==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/visitor-keys": "6.15.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -1059,42 +1069,41 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.15.0.tgz", + "integrity": "sha512-eF82p0Wrrlt8fQSRL0bGXzK5nWPRV2dYQZdajcfzOD9+cQz9O7ugifrJxclB+xVOvWvagXfqS4Es7vpLP4augw==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.15.0", + "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/typescript-estree": "6.15.0", + "semver": "^7.5.4" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0" } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.15.0.tgz", + "integrity": "sha512-1zvtdC1a9h5Tb5jU9x3ADNXO9yjP8rXlaoChu0DQX40vf5ACVpYIVIZhIMZ6d5sDXH7vq4dsZBT1fEGj8D2n2w==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" + "@typescript-eslint/types": "6.15.0", + "eslint-visitor-keys": "^3.4.1" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": "^16.0.0 || >=18.0.0" }, "funding": { "type": "opencollective", @@ -1650,9 +1659,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.614", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.614.tgz", - "integrity": "sha512-X4ze/9Sc3QWs6h92yerwqv7aB/uU8vCjZcrMjA8N9R1pjMFRe44dLsck5FzLilOYvcXuDn93B+bpGYyufc70gQ==", + "version": "1.4.615", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.615.tgz", + "integrity": "sha512-/bKPPcgZVUziECqDc+0HkT87+0zhaWSZHNXqF8FLd2lQcptpmUFwoCSWjCdOng9Gdq+afKArPdEg/0ZW461Eng==", "dev": true }, "node_modules/emoji-regex": { @@ -1689,15 +1698,15 @@ } }, "node_modules/eslint": { - "version": "8.55.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz", - "integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.55.0", + "@eslint/js": "8.56.0", "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", @@ -1744,31 +1753,6 @@ } }, "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", @@ -1784,13 +1768,16 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "engines": { - "node": ">=4.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, "node_modules/espree": { @@ -1835,15 +1822,6 @@ "node": ">=0.10" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -1856,7 +1834,7 @@ "node": ">=4.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { + "node_modules/estraverse": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", @@ -1865,15 +1843,6 @@ "node": ">=4.0" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -1930,9 +1899,9 @@ "dev": true }, "node_modules/fastq": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", - "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.16.0.tgz", + "integrity": "sha512-ifCoaXsDrsdkWTtiNJX5uzHDsrck5TzfKKDcuFFTIrrc/BS076qgEIfoIy1VeZqViznfKiysPYTh/QeHtnIsYA==", "dev": true, "dependencies": { "reusify": "^1.0.4" @@ -2887,12 +2856,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, "node_modules/node-preload": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz", @@ -3710,6 +3673,18 @@ "node": ">=8.0" } }, + "node_modules/ts-api-utils": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.3.tgz", + "integrity": "sha512-wNMeqtMz5NtwpT/UZGY5alT+VoKdSsOOP/kqHFcUW1P/VRhH2wJ48+DN2WwUliNbQ976ETwDL0Ifd2VVvgonvg==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", @@ -3762,27 +3737,6 @@ "node": ">=0.3.1" } }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -3826,16 +3780,16 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/undici-types": { From 4ec0bf5b5822241467263b796ab88d2815e3e64c Mon Sep 17 00:00:00 2001 From: mrinc Date: Tue, 19 Dec 2023 00:30:36 +0200 Subject: [PATCH 26/47] Fixing lint issues --- nodejs/.eslintignore | 1 + nodejs/src/base/config.ts | 1 + nodejs/src/base/events.ts | 5 +-- nodejs/src/base/logFormatter.ts | 6 ++-- nodejs/src/base/logging.ts | 2 ++ nodejs/src/base/service.ts | 1 + nodejs/src/base/serviceClient.ts | 1 + nodejs/src/base/serviceConfig.ts | 2 ++ nodejs/src/client.ts | 2 ++ nodejs/src/interfaces/events.ts | 3 ++ nodejs/src/plugins/config-default/plugin.ts | 6 ++-- .../events-default/events/emitAndReturn.ts | 2 +- .../events/emitStreamAndReceiveStream.ts | 4 +-- nodejs/src/plugins/logging-default/plugin.ts | 2 +- nodejs/src/plugins/service-default1/plugin.ts | 2 +- nodejs/src/serviceBase/events.ts | 28 ++++++++------- nodejs/src/serviceBase/logging.ts | 14 ++++---- nodejs/src/serviceBase/serviceBase.ts | 4 +-- nodejs/src/serviceBase/services.ts | 36 +++++++++---------- 19 files changed, 70 insertions(+), 52 deletions(-) diff --git a/nodejs/.eslintignore b/nodejs/.eslintignore index fbee89d..e323a2b 100644 --- a/nodejs/.eslintignore +++ b/nodejs/.eslintignore @@ -4,6 +4,7 @@ node_modules lib _exports src/plugins/-*/*.* +src/tests/**/*.* templates docker build \ No newline at end of file diff --git a/nodejs/src/base/config.ts b/nodejs/src/base/config.ts index 29309f2..8c1d32f 100644 --- a/nodejs/src/base/config.ts +++ b/nodejs/src/base/config.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import { DEBUG_MODE } from "../interfaces/logging"; import { SBLogging } from "../serviceBase/logging"; import { diff --git a/nodejs/src/base/events.ts b/nodejs/src/base/events.ts index adfc0bc..0e8bf8f 100644 --- a/nodejs/src/base/events.ts +++ b/nodejs/src/base/events.ts @@ -1,8 +1,9 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import { Readable } from "stream"; import { BSBConfigDefinition, BaseWithLoggingAndConfig } from "./base"; import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./errorMessages"; -import { DEBUG_MODE } from '../interfaces'; -import { SBLogging } from '../serviceBase'; +import { DEBUG_MODE } from "../interfaces"; +import { SBLogging } from "../serviceBase"; export interface BSBEventsConstructor { appId: string; diff --git a/nodejs/src/base/logFormatter.ts b/nodejs/src/base/logFormatter.ts index 57ba3bb..d148b67 100644 --- a/nodejs/src/base/logFormatter.ts +++ b/nodejs/src/base/logFormatter.ts @@ -14,7 +14,7 @@ export class LogFormatter { return dataFromKeyVP; } private formatData(meta: any, key: string) { - let referencedVar = this.getSafeData(meta, key); + const referencedVar = this.getSafeData(meta, key); if (Tools.isNullOrUndefined(referencedVar)) return "*null/undefined*"; if (Tools.isDate(referencedVar)) return referencedVar.toISOString(); if (Tools.isString(referencedVar)) return referencedVar; @@ -39,10 +39,10 @@ export class LogFormatter { //console.log(`_${message}:${Tools.isObject(meta)}`); if (!Tools.isObject(meta)) return message; - let dataToParse = message.split("{"); + const dataToParse = message.split("{"); let outString = dataToParse[0]; for (let i = 1; i < dataToParse.length; i++) { - let removedVar = dataToParse[i].split("}"); + const removedVar = dataToParse[i].split("}"); outString += this.formatData(meta, removedVar[0]) + removedVar[1]; } return outString; diff --git a/nodejs/src/base/logging.ts b/nodejs/src/base/logging.ts index d325c7a..fe1746f 100644 --- a/nodejs/src/base/logging.ts +++ b/nodejs/src/base/logging.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import { BSBConfigDefinition, BaseWithConfig } from "./base"; import { DEBUG_MODE, LogMeta } from "../interfaces/logging"; import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./errorMessages"; @@ -145,6 +146,7 @@ export abstract class BSBLogging< * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS */ export class BSBLoggingRef extends BSBLogging { + // eslint-disable-next-line @typescript-eslint/no-unused-vars public reportStat(plugin: string, key: string, value: number): void { throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "reportStat"); } diff --git a/nodejs/src/base/service.ts b/nodejs/src/base/service.ts index efdf0c2..066cfb0 100644 --- a/nodejs/src/base/service.ts +++ b/nodejs/src/base/service.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import { BSBConfigDefinition, BaseWithLoggingAndConfig } from "./base"; import { ServiceEventsBase, ServiceEventsDefault } from "../interfaces/service"; import { DEBUG_MODE } from "../interfaces/logging"; diff --git a/nodejs/src/base/serviceClient.ts b/nodejs/src/base/serviceClient.ts index 95b6310..e2729ad 100644 --- a/nodejs/src/base/serviceClient.ts +++ b/nodejs/src/base/serviceClient.ts @@ -18,6 +18,7 @@ export abstract class BSBServiceClient< Events["onBroadcast"] >; public callMethod( + // eslint-disable-next-line @typescript-eslint/no-unused-vars ...args: DynamicallyReferencedMethodCallable< DynamicallyReferencedMethodType, TA diff --git a/nodejs/src/base/serviceConfig.ts b/nodejs/src/base/serviceConfig.ts index 165b35d..b50c540 100644 --- a/nodejs/src/base/serviceConfig.ts +++ b/nodejs/src/base/serviceConfig.ts @@ -3,6 +3,7 @@ import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./errorMessages"; import { BSBConfigType } from './base'; export abstract class BSBServiceConfig> { + // eslint-disable-next-line @typescript-eslint/no-unused-vars constructor(cwd: string, pluginCwd: string, pluginName: string) {} abstract validationSchema: MyPluginConfig; abstract migrate( @@ -17,6 +18,7 @@ export abstract class BSBServiceConfig { validationSchema = {}; + // eslint-disable-next-line @typescript-eslint/no-unused-vars migrate(toVersion: string, fromVersion: string | null, fromConfig: any) { throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBServiceConfigRef", "migrate"); } diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts index 42af88b..63d0d71 100644 --- a/nodejs/src/client.ts +++ b/nodejs/src/client.ts @@ -94,7 +94,9 @@ export class FakeServiceConfig extends BSBConfig { return { name: pluginName, enabled: false }; } async getPluginConfig( + // eslint-disable-next-line @typescript-eslint/no-unused-vars pluginType: PluginType, + // eslint-disable-next-line @typescript-eslint/no-unused-vars plugin: string ): Promise { return null; diff --git a/nodejs/src/interfaces/events.ts b/nodejs/src/interfaces/events.ts index 86d49f4..356d356 100644 --- a/nodejs/src/interfaces/events.ts +++ b/nodejs/src/interfaces/events.ts @@ -6,6 +6,7 @@ export type DynamicallyReferencedMethodCallable< ArgsReference extends boolean = true //ShowTimeout extends boolean = true > = ArgsReference extends true +// eslint-disable-next-line @typescript-eslint/no-unused-vars ? Interface[Method] extends (...a: infer Arguments) => infer Return ? [event: Method, ...a: Arguments] : [event: Method, noMatchingEvent: never] @@ -33,6 +34,7 @@ export type DynamicallyReferencedMethodOnIEvents< export type DynamicallyReferencedMethodEmitIEvents< Interface extends DynamicallyReferencedMethodBase, Method extends string + // eslint-disable-next-line @typescript-eslint/no-unused-vars > = Interface[Method] extends (...a: infer Arguments) => infer Return ? [event: Method, ...a: Arguments] : [noMatchingEvent: never]; @@ -43,6 +45,7 @@ export type DynamicallyReferencedMethodEmitEARIEvents< ArgsReference extends boolean = true //ShowTimeout extends boolean = true > = ArgsReference extends true +// eslint-disable-next-line @typescript-eslint/no-unused-vars ? Interface[Method] extends (...a: infer Arguments) => infer Return ? //? ShowTimeout extends true [event: Method, timeoutSeconds?: number, ...a: Arguments] diff --git a/nodejs/src/plugins/config-default/plugin.ts b/nodejs/src/plugins/config-default/plugin.ts index b87899a..a68abca 100644 --- a/nodejs/src/plugins/config-default/plugin.ts +++ b/nodejs/src/plugins/config-default/plugin.ts @@ -54,7 +54,7 @@ export class Plugin extends BSBConfig { ); } async getLoggingPlugins(): Promise> { - let plugins = Object.keys( + const plugins = Object.keys( this._appConfig[this._deploymentProfile].logging ?? {} ).filter((x) => { return ( @@ -73,7 +73,7 @@ export class Plugin extends BSBConfig { }, {} as Record); } async getEventsPlugins(): Promise> { - let plugins = Object.keys( + const plugins = Object.keys( this._appConfig[this._deploymentProfile].events ?? {} ).filter((x) => { return ( @@ -92,7 +92,7 @@ export class Plugin extends BSBConfig { }, {} as Record); } async getServicePlugins(): Promise> { - let plugins = Object.keys( + const plugins = Object.keys( this._appConfig[this._deploymentProfile].services ?? {} ).filter((x) => { return ( diff --git a/nodejs/src/plugins/events-default/events/emitAndReturn.ts b/nodejs/src/plugins/events-default/events/emitAndReturn.ts index 29caeaa..fb36bbe 100644 --- a/nodejs/src/plugins/events-default/events/emitAndReturn.ts +++ b/nodejs/src/plugins/events-default/events/emitAndReturn.ts @@ -42,7 +42,7 @@ export default class emitAndReturn extends EventEmitter { }); const self = this; return new Promise((resolve, reject) => { - let timeoutHandler = setTimeout(() => { + const timeoutHandler = setTimeout(() => { reject("Timeout"); }, timeoutSeconds * 1000); self.emit( diff --git a/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts b/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts index 41cf1d5..19e1784 100644 --- a/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts +++ b/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts @@ -27,7 +27,7 @@ export default class emitStreamAndReceiveStream extends EventEmitter { }); const self = this; return new Promise((resolve) => { - let receiptTimeoutHandler: NodeJS.Timeout = setTimeout(() => { + const receiptTimeoutHandler: NodeJS.Timeout = setTimeout(() => { const err = new Error("Receive Receipt Timeout"); listener(err, null!); self.emit(`${streamId}-error`, err); @@ -73,7 +73,7 @@ export default class emitStreamAndReceiveStream extends EventEmitter { let receiptTimeoutHandler: NodeJS.Timeout | null = setTimeout(() => { reject(new Error("Send Receipt Timeout")); }, self.staticCommsTimeout); - let timeoutHandler = setTimeout(() => { + const timeoutHandler = setTimeout(() => { reject(new Error("Stream Timeout")); }, timeout * 1000); self.once(`${streamId}-emit`, () => { diff --git a/nodejs/src/plugins/logging-default/plugin.ts b/nodejs/src/plugins/logging-default/plugin.ts index 6ee0d91..4c20a5c 100644 --- a/nodejs/src/plugins/logging-default/plugin.ts +++ b/nodejs/src/plugins/logging-default/plugin.ts @@ -120,7 +120,7 @@ export class Plugin extends BSBLogging { messageOrError: T | Error, meta?: LogMeta ): void { - let message = + const message = typeof messageOrError === "string" ? messageOrError : messageOrError.message; diff --git a/nodejs/src/plugins/service-default1/plugin.ts b/nodejs/src/plugins/service-default1/plugin.ts index 4b0260c..1420536 100644 --- a/nodejs/src/plugins/service-default1/plugin.ts +++ b/nodejs/src/plugins/service-default1/plugin.ts @@ -49,7 +49,7 @@ export class Plugin extends BSBService { "onReturnable", async (a: number, b: number) => { this.log.warn("RECEIVED onReturnable ({a},{b})", { a, b }); - let result = await this.events.emitEventAndReturn( + const result = await this.events.emitEventAndReturn( "onReverseReturnable", 5, a, diff --git a/nodejs/src/serviceBase/events.ts b/nodejs/src/serviceBase/events.ts index 68af434..3995a47 100644 --- a/nodejs/src/serviceBase/events.ts +++ b/nodejs/src/serviceBase/events.ts @@ -116,7 +116,7 @@ export class SBEvents { pluginName: string; plugin: BSBEvents; } { - let matchingEvent = this.getPluginsMatchingTriggerEvent(eventAs, plugin); + const matchingEvent = this.getPluginsMatchingTriggerEvent(eventAs, plugin); if (matchingEvent === undefined) throw new BSBError( "SBEvents-triggerEvent", @@ -130,8 +130,8 @@ export class SBEvents { } public async init(sbConfig: SBConfig, sbLogging: SBLogging) { this.log.debug("INIT SBEvents"); - let plugins = await sbConfig.getEventsPlugins(); - for (let plugin of Object.keys(plugins)) { + const plugins = await sbConfig.getEventsPlugins(); + for (const plugin of Object.keys(plugins)) { await this.addEvents( sbConfig, sbLogging, @@ -195,7 +195,7 @@ export class SBEvents { name: plugin.name, }); - let eventsPlugin = new reference.plugin({ + const eventsPlugin = new reference.plugin({ appId: this.appId, mode: this.mode, pluginName: reference.name, @@ -215,8 +215,10 @@ export class SBEvents { eventAsType = "events"; } else if (typeof filter === "object") { const methods = Object.keys(EventsEventTypesBase); - for (let method of methods) { - if (filter.hasOwnProperty(method)) { + for (const method of methods) { + if ( + (filter as unknown as Record)[method] !== undefined + ) { const methodValue = filter[method as keyof typeof filter]; if (typeof methodValue === "boolean") { eventAsType = "eventsState"; @@ -305,7 +307,7 @@ export class SBEvents { const start = process.hrtime(); try { await SmartFunctionCallAsync(context, listener, ...iargs); - let diff = process.hrtime(start); + const diff = process.hrtime(start); this.log.reportStat( `on-broadcast-${eventsPluginName}-${pluginName}-${event}`, (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS @@ -381,7 +383,7 @@ export class SBEvents { try { //console.log("CALL ON EVENT", context, listener, iargs); await SmartFunctionCallAsync(context, listener, ...iargs); - let diff = process.hrtime(start); + const diff = process.hrtime(start); this.log.reportStat( `on-event-${eventsPluginName}-${pluginName}-${event}`, (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS @@ -491,7 +493,7 @@ export class SBEvents { const start = process.hrtime(); try { const resp = await SmartFunctionCallAsync(context, listener, ...iargs); - let diff = process.hrtime(start); + const diff = process.hrtime(start); this.log.reportStat( `on-returnableevent-${eventsPluginName}-${pluginName}-${event}`, (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS @@ -584,7 +586,7 @@ export class SBEvents { timeoutSeconds, args ); - let diff = process.hrtime(start); + const diff = process.hrtime(start); this.log.reportStat( `emit-eventandreturn-${plugin.pluginName}-${pluginName}-${event}`, (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS @@ -623,7 +625,7 @@ export class SBEvents { timeoutSeconds, args ); - let diff = process.hrtime(start); + const diff = process.hrtime(start); this.log.reportStat( `emit-eventandreturn-${plugin.pluginName}-${pluginName}-${event}-${serverId}`, (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS @@ -658,7 +660,7 @@ export class SBEvents { error, stream ); - let diff = process.hrtime(start); + const diff = process.hrtime(start); this.log.reportStat( `receivestream-${eventsPluginName}-${pluginName}-${event}`, (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS @@ -724,7 +726,7 @@ export class SBEvents { streamId, stream ); - let diff = process.hrtime(start); + const diff = process.hrtime(start); this.log.reportStat( `sendstream-${plugin.pluginName}-${pluginName}-${event}`, (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS diff --git a/nodejs/src/serviceBase/logging.ts b/nodejs/src/serviceBase/logging.ts index 253c13b..df82205 100644 --- a/nodejs/src/serviceBase/logging.ts +++ b/nodejs/src/serviceBase/logging.ts @@ -173,7 +173,7 @@ export class SBLogging { messageOrKey: T | string, metaOrValue: LogMeta | number ): Promise { - for (let logger of this.getPluginsMatchingLogEvent(logAs, plugin)) { + for (const logger of this.getPluginsMatchingLogEvent(logAs, plugin)) { if (logAs === "reportStat") { await this.triggerLogEventReportStat( logger.plugin, @@ -216,8 +216,8 @@ export class SBLogging { } public async init(sbConfig: SBConfig) { this.log.debug("INIT SBLogging"); - let plugins = await sbConfig.getLoggingPlugins(); - for (let plugin of Object.keys(plugins)) { + const plugins = await sbConfig.getLoggingPlugins(); + for (const plugin of Object.keys(plugins)) { await this.addLogger( sbConfig, { @@ -264,7 +264,7 @@ export class SBLogging { name: plugin.name, }); - let loggerPlugin = new reference.plugin({ + const loggerPlugin = new reference.plugin({ appId: this.appId, mode: this.mode, pluginName: reference.name, @@ -283,8 +283,10 @@ export class SBLogging { logAsType = "events"; } else if (typeof filter === "object") { const methods = Object.keys(LoggingEventTypesBase); - for (let method of methods) { - if (filter.hasOwnProperty(method)) { + for (const method of methods) { + if ( + (filter as unknown as Record)[method] !== undefined + ) { const methodValue = filter[method as keyof typeof filter]; if (typeof methodValue === "boolean") { logAsType = "eventsState"; diff --git a/nodejs/src/serviceBase/serviceBase.ts b/nodejs/src/serviceBase/serviceBase.ts index fe1b928..aa42ac7 100644 --- a/nodejs/src/serviceBase/serviceBase.ts +++ b/nodejs/src/serviceBase/serviceBase.ts @@ -55,8 +55,8 @@ export class ServiceBase { this._keeps[stepName] = process.hrtime(); } private async _outputKeep(stepName: BootStatKeys) { - let diff = process.hrtime(this._keeps[stepName] || undefined); - let logMeta: LogMeta = { + const diff = process.hrtime(this._keeps[stepName] || undefined); + const logMeta: LogMeta = { nsTime: diff[0] * NS_PER_SEC + diff[1], msTime: (diff[0] * NS_PER_SEC + diff[1]) * MS_PER_NS, timerName: stepName, diff --git a/nodejs/src/serviceBase/services.ts b/nodejs/src/serviceBase/services.ts index 423ef49..33b12d4 100644 --- a/nodejs/src/serviceBase/services.ts +++ b/nodejs/src/serviceBase/services.ts @@ -40,9 +40,9 @@ export class SBServices { } public dispose() { - for (let service of this._activeServices) { + for (const service of this._activeServices) { this.log.warn("disposing {service}", { service: service.pluginName }); - for (let client of service._clients) { + for (const client of service._clients) { SmartFunctionCallSync(client, client.dispose); } SmartFunctionCallSync(service, service.dispose); @@ -55,8 +55,8 @@ export class SBServices { sbEvents: SBEvents ) { this.log.debug("SETUP SBServices"); - let plugins = await sbConfig.getServicePlugins(); - for (let plugin of Object.keys(plugins)) { + const plugins = await sbConfig.getServicePlugins(); + for (const plugin of Object.keys(plugins)) { await this.addService(sbConfig, sbLogging, sbEvents, { name: plugin, package: plugins[plugin].package, @@ -109,9 +109,9 @@ export class SBServices { referencedPluginName: string, ...sourcePluginsList: Array | undefined> ): Promise> { - let outlist = []; - for (let pluginArr of sourcePluginsList.filter((x) => x !== undefined)) { - for (let plugin of pluginArr!) { + const outlist = []; + for (const pluginArr of sourcePluginsList.filter((x) => x !== undefined)) { + for (const plugin of pluginArr!) { const pluginDef = await sbConfig.getServicePluginDefinition(plugin); if (pluginDef.enabled !== true) throw new BSBError( @@ -139,7 +139,7 @@ export class SBServices { name: plugin.name, }); - let servicePlugin = new reference.plugin({ + const servicePlugin = new reference.plugin({ appId: this.appId, mode: this.mode, pluginName: reference.name, @@ -153,7 +153,7 @@ export class SBServices { pluginName: plugin.name, }); - for (let client of servicePlugin._clients) { + for (const client of servicePlugin._clients) { this.log.debug("Construct {pluginName} client {clientName}", { pluginName: plugin.name, clientName: client.pluginName, @@ -295,7 +295,7 @@ export class SBServices { public async init(sbConfig: SBConfig) { this.log.info("Init all services"); - for (let service of this._activeServices) { + for (const service of this._activeServices) { this.log.debug("Mapping required plugins list for {plugin}", { plugin: service.pluginName, }); @@ -311,7 +311,7 @@ export class SBServices { ); } this.log.info("Defining service order"); - let orderOfPlugins = await this.makeAfterRequired( + const orderOfPlugins = await this.makeAfterRequired( await this.makeBeforeRequired( this._activeServices.map((x) => { return { @@ -338,11 +338,11 @@ export class SBServices { .map((x) => `[(${x.after.join(",")})${x.name}(${x.before.join(",")})]`) .join(","), }); - for (let service of orderOfPlugins) { + for (const service of orderOfPlugins) { this.log.debug(`Init {plugin}`, { plugin: service.name, }); - for (let client of service.ref._clients) { + for (const client of service.ref._clients) { await this.initPluginClient(sbConfig, client); } SmartFunctionCallAsync(service.ref, service.ref.init); @@ -359,7 +359,7 @@ export class SBServices { ) { for (let i = 0; i < orderOfPlugins.length; i++) { if (orderOfPlugins[i].before.length === 0) continue; - for (let bPlugin of orderOfPlugins[i].before) + for (const bPlugin of orderOfPlugins[i].before) for (let j = 0; j < orderOfPlugins.length; j++) { if (orderOfPlugins[j].name == bPlugin) { orderOfPlugins[j].after.push(orderOfPlugins[i].name); @@ -390,7 +390,7 @@ export class SBServices { public async run(sbConfig: SBConfig) { this.log.info("Run all services"); - for (let service of this._activeServices) { + for (const service of this._activeServices) { this.log.debug("Mapping required plugins list for {plugin}", { plugin: service.pluginName, }); @@ -406,7 +406,7 @@ export class SBServices { ); } this.log.info("Defining service order"); - let orderOfPlugins = await this.makeAfterRequired( + const orderOfPlugins = await this.makeAfterRequired( await this.makeBeforeRequired( this._activeServices.map((x) => { return { @@ -433,11 +433,11 @@ export class SBServices { .map((x) => `[(${x.after.join(",")})${x.name}(${x.before.join(",")})]`) .join(","), }); - for (let service of orderOfPlugins) { + for (const service of orderOfPlugins) { this.log.debug(`Run {plugin}`, { plugin: service.name, }); - for (let client of service.ref._clients) { + for (const client of service.ref._clients) { SmartFunctionCallAsync(client, client.run); } SmartFunctionCallAsync(service.ref, service.ref.run); From b2a0878801b684632c0a79844d926f591d9e0f84 Mon Sep 17 00:00:00 2001 From: mrinc Date: Tue, 19 Dec 2023 00:38:24 +0200 Subject: [PATCH 27/47] Fixing build issues --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 38f4e94..abe5eed 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,7 +29,7 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - run: ./ci-build-dist + - run: mkdir ./ci-build-dist working-directory: ./nodejs - name: Download artifact From 0a6eb2a450247f2a7310ff0697f378e18c69e4c0 Mon Sep 17 00:00:00 2001 From: mrinc Date: Tue, 19 Dec 2023 00:45:31 +0200 Subject: [PATCH 28/47] Fixing build issues --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index abe5eed..03cca80 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,7 +33,7 @@ jobs: working-directory: ./nodejs - name: Download artifact - uses: actions/download-artifact@v2 + uses: actions/download-artifact@v4 with: name: node-${{ needs.build_nodejs_plugin_release.outputs.tag }}-${{ needs.build_nodejs_plugin_release.outputs.version }} path: ./nodejs/ci-build-dist/ From ec924ecddb9a6ab141e1ec5c13045f877a4a3ff4 Mon Sep 17 00:00:00 2001 From: mrinc Date: Tue, 19 Dec 2023 00:47:57 +0200 Subject: [PATCH 29/47] Fixing build issues --- .github/workflows/release.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 03cca80..2357cc6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -56,13 +56,13 @@ jobs: uses: docker/setup-buildx-action@master - name: Login to DockerHub - uses: docker/login-action@v1 + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_HUB_USER }} password: ${{ secrets.DOCKER_HUB_TOKEN }} - name: Build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 with: builder: ${{ steps.buildx.outputs.name }} context: ./nodejs/ @@ -74,7 +74,7 @@ jobs: betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.version }} - name: Build - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v5 if: needs.build_nodejs_plugin_release.outputs.tag == 'latest' with: builder: ${{ steps.buildx.outputs.name }} From d8eb75e6ddb880a49f2454d1e622b13b83993038 Mon Sep 17 00:00:00 2001 From: mrinc Date: Tue, 19 Dec 2023 01:01:09 +0200 Subject: [PATCH 30/47] Fixing build issues --- nodejs/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nodejs/Dockerfile b/nodejs/Dockerfile index bf1c73d..a40fc97 100644 --- a/nodejs/Dockerfile +++ b/nodejs/Dockerfile @@ -1,4 +1,4 @@ -FROM betterweb/node:latest +FROM node:20-bullseye # RUN npm i -g typescript ts-node VOLUME /mnt/bsb-plugins @@ -40,7 +40,8 @@ COPY entrypoint.sh /root/entrypoint.sh RUN chown -R root:node /home/bsb RUN chmod -R 650 /home/bsb -RUN chown node:node /home/bsb/sec.config.json +RUN touch /home/bsb/sec-config.yaml +RUN chown node:node /home/bsb/sec-config.yaml ENTRYPOINT [ "/root/entrypoint.sh" ] CMD node node_modules/@bettercorp/service-base/lib/cli.js \ No newline at end of file From 50ef3542e600e0fc102fb5c2a566cf613cde618d Mon Sep 17 00:00:00 2001 From: mrinc Date: Tue, 19 Dec 2023 01:05:48 +0200 Subject: [PATCH 31/47] Fixing build issues --- .github/workflows/release.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 2357cc6..6482b44 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -67,7 +67,9 @@ jobs: builder: ${{ steps.buildx.outputs.name }} context: ./nodejs/ file: ./nodejs/Dockerfile - platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + #platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + # amd64, arm32v6, arm32v7, arm64v8, ppc64le, s390x + platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x push: true tags: | betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.tag }} From dbec48c7b8204a93b8dd1ec7a7067d9464453d75 Mon Sep 17 00:00:00 2001 From: mrinc Date: Wed, 20 Dec 2023 15:31:51 +0200 Subject: [PATCH 32/47] Some config based fixes. Updated all libs. General cleanup --- documentation/package-lock.json | 619 ++++++++++-------- dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json | 22 +- dotnet/BSB/obj/BSB.csproj.nuget.g.props | 2 +- .../Debug/net6.0/BSB.AssemblyInfoInputs.cache | 2 +- ....GeneratedMSBuildEditorConfig.editorconfig | 5 +- dotnet/BSB/obj/Debug/net6.0/BSB.assets.cache | Bin 141 -> 153 bytes .../net6.0/BSB.csproj.AssemblyReference.cache | Bin 71759 -> 0 bytes dotnet/BSB/obj/project.assets.json | 18 +- dotnet/BSB/obj/project.nuget.cache | 9 +- ...BetterServiceBase.csproj.nuget.dgspec.json | 26 +- .../BetterServiceBase.csproj.nuget.g.props | 2 +- ...BetterServiceBase.AssemblyInfoInputs.cache | 2 +- ....GeneratedMSBuildEditorConfig.editorconfig | 5 +- .../net6.0/BetterServiceBase.assets.cache | Bin 141 -> 153 bytes ...ServiceBase.csproj.AssemblyReference.cache | Bin 71759 -> 0 bytes .../BetterServiceBase/obj/project.assets.json | 22 +- .../BetterServiceBase/obj/project.nuget.cache | 10 +- nodejs/package-lock.json | 65 +- nodejs/package.json | 44 +- nodejs/src/base/logFormatter.ts | 2 +- nodejs/src/plugins/config-default/plugin.ts | 10 +- nodejs/src/serviceBase/config.ts | 2 +- nodejs/src/serviceBase/events.ts | 11 +- nodejs/src/serviceBase/logging.ts | 11 +- nodejs/src/serviceBase/services.ts | 10 +- 25 files changed, 503 insertions(+), 396 deletions(-) delete mode 100644 dotnet/BSB/obj/Debug/net6.0/BSB.csproj.AssemblyReference.cache delete mode 100644 dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.AssemblyReference.cache diff --git a/documentation/package-lock.json b/documentation/package-lock.json index ca60f66..ae644c5 100644 --- a/documentation/package-lock.json +++ b/documentation/package-lock.json @@ -13,9 +13,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.20.13", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.20.13.tgz", - "integrity": "sha512-gFDLKMfpiXCsjt4za2JA9oTMn70CeseCehb11kRZgvd7+F67Hih3OHOK24cRrWECJ/ljfPGac6ygXAs/C8kIvw==", + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.6.tgz", + "integrity": "sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ==", "bin": { "parser": "bin/babel-parser.js" }, @@ -353,6 +353,11 @@ "node": ">=12" } }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, "node_modules/@mdit-vue/plugin-component": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/@mdit-vue/plugin-component/-/plugin-component-0.11.2.tgz", @@ -464,9 +469,9 @@ } }, "node_modules/@types/debug": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.7.tgz", - "integrity": "sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==", + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", "dependencies": { "@types/ms": "*" } @@ -480,14 +485,14 @@ } }, "node_modules/@types/hash-sum": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.0.tgz", - "integrity": "sha512-FdLBT93h3kcZ586Aee66HPCVJ6qvxVjBlDWNmxSGSbCZe9hTsjRKdSsl4y1T+3zfujxo9auykQMnFsfyHWD7wg==" + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/hash-sum/-/hash-sum-1.0.2.tgz", + "integrity": "sha512-UP28RddqY8xcU0SCEp9YKutQICXpaAq9N8U2klqF5hegGha7KzTOL8EdhIIV3bOSGBzjEpN9bU/d+nNZBdJYVw==" }, "node_modules/@types/linkify-it": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.2.tgz", - "integrity": "sha512-HZQYqbiFVWufzCwexrvh694SOim8z2d+xJl5UNamcvQFejLY/2YUtzXHYi3cHdI7PMlS8ejH2slRAOJQ32aNbA==" + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-3.0.5.tgz", + "integrity": "sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==" }, "node_modules/@types/markdown-it": { "version": "12.2.3", @@ -499,27 +504,30 @@ } }, "node_modules/@types/markdown-it-emoji": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@types/markdown-it-emoji/-/markdown-it-emoji-2.0.2.tgz", - "integrity": "sha512-2ln8Wjbcj/0oRi/6VnuMeWEHHuK8uapFttvcLmDIe1GKCsFBLOLBX+D+xhDa9oWOQV0IpvxwrSfKKssAqqroog==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/markdown-it-emoji/-/markdown-it-emoji-2.0.4.tgz", + "integrity": "sha512-H6ulk/ZmbDxOayPwI/leJzrmoW1YKX1Z+MVSCHXuYhvqckV4I/c+hPTf6UiqJyn2avWugfj30XroheEb6/Ekqg==", "dependencies": { "@types/markdown-it": "*" } }, "node_modules/@types/mdurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.2.tgz", - "integrity": "sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==" + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-1.0.5.tgz", + "integrity": "sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==" }, "node_modules/@types/ms": { - "version": "0.7.31", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.31.tgz", - "integrity": "sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==" + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" }, "node_modules/@types/node": { - "version": "18.11.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.18.tgz", - "integrity": "sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==" + "version": "20.10.4", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.4.tgz", + "integrity": "sha512-D08YG6rr8X90YB56tSIuBaddy/UXAA9RKJoFvrsnogAum/0pmjkgi4+2nx96A330FmioegBWmEYQ+syqCFaveg==", + "dependencies": { + "undici-types": "~5.26.4" + } }, "node_modules/@types/web-bluetooth": { "version": "0.0.16", @@ -527,123 +535,123 @@ "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==" }, "node_modules/@vitejs/plugin-vue": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.0.0.tgz", - "integrity": "sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA==", + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-4.5.2.tgz", + "integrity": "sha512-UGR3DlzLi/SaVBPX0cnSyE37vqxU3O6chn8l0HJNzQzDia6/Au2A4xKv+iIJW8w2daf80G7TYHhi1pAUjdZ0bQ==", "engines": { "node": "^14.18.0 || >=16.0.0" }, "peerDependencies": { - "vite": "^4.0.0", + "vite": "^4.0.0 || ^5.0.0", "vue": "^3.2.25" } }, "node_modules/@vue/compiler-core": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.2.45.tgz", - "integrity": "sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.3.11.tgz", + "integrity": "sha512-h97/TGWBilnLuRaj58sxNrsUU66fwdRKLOLQ9N/5iNDfp+DZhYH9Obhe0bXxhedl8fjAgpRANpiZfbgWyruQ0w==", "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/shared": "3.2.45", + "@babel/parser": "^7.23.5", + "@vue/shared": "3.3.11", "estree-walker": "^2.0.2", - "source-map": "^0.6.1" + "source-map-js": "^1.0.2" } }, "node_modules/@vue/compiler-dom": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.2.45.tgz", - "integrity": "sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.3.11.tgz", + "integrity": "sha512-zoAiUIqSKqAJ81WhfPXYmFGwDRuO+loqLxvXmfUdR5fOitPoUiIeFI9cTTyv9MU5O1+ZZglJVTusWzy+wfk5hw==", "dependencies": { - "@vue/compiler-core": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/compiler-core": "3.3.11", + "@vue/shared": "3.3.11" } }, "node_modules/@vue/compiler-sfc": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.2.45.tgz", - "integrity": "sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==", - "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.45", - "@vue/compiler-dom": "3.2.45", - "@vue/compiler-ssr": "3.2.45", - "@vue/reactivity-transform": "3.2.45", - "@vue/shared": "3.2.45", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.3.11.tgz", + "integrity": "sha512-U4iqPlHO0KQeK1mrsxCN0vZzw43/lL8POxgpzcJweopmqtoYy9nljJzWDIQS3EfjiYhfdtdk9Gtgz7MRXnz3GA==", + "dependencies": { + "@babel/parser": "^7.23.5", + "@vue/compiler-core": "3.3.11", + "@vue/compiler-dom": "3.3.11", + "@vue/compiler-ssr": "3.3.11", + "@vue/reactivity-transform": "3.3.11", + "@vue/shared": "3.3.11", "estree-walker": "^2.0.2", - "magic-string": "^0.25.7", - "postcss": "^8.1.10", - "source-map": "^0.6.1" + "magic-string": "^0.30.5", + "postcss": "^8.4.32", + "source-map-js": "^1.0.2" } }, "node_modules/@vue/compiler-ssr": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.2.45.tgz", - "integrity": "sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.3.11.tgz", + "integrity": "sha512-Zd66ZwMvndxRTgVPdo+muV4Rv9n9DwQ4SSgWWKWkPFebHQfVYRrVjeygmmDmPewsHyznCNvJ2P2d6iOOhdv8Qg==", "dependencies": { - "@vue/compiler-dom": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/compiler-dom": "3.3.11", + "@vue/shared": "3.3.11" } }, "node_modules/@vue/devtools-api": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.0.tgz", - "integrity": "sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q==" + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.5.1.tgz", + "integrity": "sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==" }, "node_modules/@vue/reactivity": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.2.45.tgz", - "integrity": "sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.3.11.tgz", + "integrity": "sha512-D5tcw091f0nuu+hXq5XANofD0OXnBmaRqMYl5B3fCR+mX+cXJIGNw/VNawBqkjLNWETrFW0i+xH9NvDbTPVh7g==", "dependencies": { - "@vue/shared": "3.2.45" + "@vue/shared": "3.3.11" } }, "node_modules/@vue/reactivity-transform": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.2.45.tgz", - "integrity": "sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/reactivity-transform/-/reactivity-transform-3.3.11.tgz", + "integrity": "sha512-fPGjH0wqJo68A0wQ1k158utDq/cRyZNlFoxGwNScE28aUFOKFEnCBsvyD8jHn+0kd0UKVpuGuaZEQ6r9FJRqCg==", "dependencies": { - "@babel/parser": "^7.16.4", - "@vue/compiler-core": "3.2.45", - "@vue/shared": "3.2.45", + "@babel/parser": "^7.23.5", + "@vue/compiler-core": "3.3.11", + "@vue/shared": "3.3.11", "estree-walker": "^2.0.2", - "magic-string": "^0.25.7" + "magic-string": "^0.30.5" } }, "node_modules/@vue/runtime-core": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.2.45.tgz", - "integrity": "sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.3.11.tgz", + "integrity": "sha512-g9ztHGwEbS5RyWaOpXuyIVFTschclnwhqEbdy5AwGhYOgc7m/q3NFwr50MirZwTTzX55JY8pSkeib9BX04NIpw==", "dependencies": { - "@vue/reactivity": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/reactivity": "3.3.11", + "@vue/shared": "3.3.11" } }, "node_modules/@vue/runtime-dom": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.2.45.tgz", - "integrity": "sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.3.11.tgz", + "integrity": "sha512-OlhtV1PVpbgk+I2zl+Y5rQtDNcCDs12rsRg71XwaA2/Rbllw6mBLMi57VOn8G0AjOJ4Mdb4k56V37+g8ukShpQ==", "dependencies": { - "@vue/runtime-core": "3.2.45", - "@vue/shared": "3.2.45", - "csstype": "^2.6.8" + "@vue/runtime-core": "3.3.11", + "@vue/shared": "3.3.11", + "csstype": "^3.1.2" } }, "node_modules/@vue/server-renderer": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.2.45.tgz", - "integrity": "sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.3.11.tgz", + "integrity": "sha512-AIWk0VwwxCAm4wqtJyxBylRTXSy1wCLOKbWxHaHiu14wjsNYtiRCSgVuqEPVuDpErOlRdNnuRgipQfXRLjLN5A==", "dependencies": { - "@vue/compiler-ssr": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/compiler-ssr": "3.3.11", + "@vue/shared": "3.3.11" }, "peerDependencies": { - "vue": "3.2.45" + "vue": "3.3.11" } }, "node_modules/@vue/shared": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.2.45.tgz", - "integrity": "sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==" + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.3.11.tgz", + "integrity": "sha512-u2G8ZQ9IhMWTMXaWqZycnK4UthG1fA238CD+DP4Dm4WJi5hdUKKLg0RMRaRpDPNMdkTwIDkp7WtD0Rd9BH9fLw==" }, "node_modules/@vuepress/bundler-vite": { "version": "2.0.0-beta.60", @@ -907,13 +915,13 @@ } }, "node_modules/@vueuse/core": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.11.1.tgz", - "integrity": "sha512-E/cizD1w9ILkq4axYjZrXLkKaBfzloaby2n3NMjUfd6yI/jkfTVgc6iwy/Cw2e++Ld4LphGbO+3MhzizvwUslQ==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz", + "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==", "dependencies": { "@types/web-bluetooth": "^0.0.16", - "@vueuse/metadata": "9.11.1", - "@vueuse/shared": "9.11.1", + "@vueuse/metadata": "9.13.0", + "@vueuse/shared": "9.13.0", "vue-demi": "*" }, "funding": { @@ -921,9 +929,9 @@ } }, "node_modules/@vueuse/core/node_modules/vue-demi": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", - "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", "hasInstallScript": true, "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", @@ -946,17 +954,17 @@ } }, "node_modules/@vueuse/metadata": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.11.1.tgz", - "integrity": "sha512-ABjkrG+VXggNhjfGyw5e/sekxTZfXTwjrYXkkWQmQ7Biyv+Gq9UD6IDNfeGvQZEINI0Qzw6nfuO2UFCd3hlrxQ==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz", + "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==", "funding": { "url": "https://github.com/sponsors/antfu" } }, "node_modules/@vueuse/shared": { - "version": "9.11.1", - "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.11.1.tgz", - "integrity": "sha512-UTZYGAjT96hWn4buf4wstZbeheBVNcKPQuej6qpoSkjF1atdaeCD6kqm9uGL2waHfisSgH9mq0qCRiBOk5C/2w==", + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz", + "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==", "dependencies": { "vue-demi": "*" }, @@ -965,9 +973,9 @@ } }, "node_modules/@vueuse/shared/node_modules/vue-demi": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", - "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", "hasInstallScript": true, "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", @@ -1021,9 +1029,9 @@ } }, "node_modules/autoprefixer": { - "version": "10.4.13", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.13.tgz", - "integrity": "sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==", + "version": "10.4.16", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", + "integrity": "sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==", "funding": [ { "type": "opencollective", @@ -1032,12 +1040,16 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "browserslist": "^4.21.4", - "caniuse-lite": "^1.0.30001426", - "fraction.js": "^4.2.0", + "browserslist": "^4.21.10", + "caniuse-lite": "^1.0.30001538", + "fraction.js": "^4.3.6", "normalize-range": "^0.1.2", "picocolors": "^1.0.0", "postcss-value-parser": "^4.2.0" @@ -1101,9 +1113,9 @@ } }, "node_modules/browserslist": { - "version": "4.21.4", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", - "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "version": "4.22.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz", + "integrity": "sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A==", "funding": [ { "type": "opencollective", @@ -1112,13 +1124,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "caniuse-lite": "^1.0.30001400", - "electron-to-chromium": "^1.4.251", - "node-releases": "^2.0.6", - "update-browserslist-db": "^1.0.9" + "caniuse-lite": "^1.0.30001565", + "electron-to-chromium": "^1.4.601", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" }, "bin": { "browserslist": "cli.js" @@ -1159,9 +1175,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001446", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001446.tgz", - "integrity": "sha512-fEoga4PrImGcwUUGEol/PoFCSBnSkA9drgdkxXkJLsUBOnJ8rs3zDv6ApqYXGQFOyMPsjh79naWhF4DAxbF8rw==", + "version": "1.0.30001570", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz", + "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==", "funding": [ { "type": "opencollective", @@ -1170,13 +1186,17 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ] }, "node_modules/chalk": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", - "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" }, @@ -1225,9 +1245,9 @@ } }, "node_modules/cli-spinners": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.7.0.tgz", - "integrity": "sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==", + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", "engines": { "node": ">=6" }, @@ -1265,9 +1285,9 @@ } }, "node_modules/csstype": { - "version": "2.6.21", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.21.tgz", - "integrity": "sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/debug": { "version": "4.3.4", @@ -1308,9 +1328,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.284", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.284.tgz", - "integrity": "sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==" + "version": "1.4.612", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.612.tgz", + "integrity": "sha512-dM8BMtXtlH237ecSMnYdYuCkib2QHq0kpWfUnavjdYsyr/6OsAwg5ZGUfnQ9KD1Ga4QgB2sqXlB2NT8zy2GnVg==" }, "node_modules/entities": { "version": "3.0.1", @@ -1324,9 +1344,9 @@ } }, "node_modules/envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.11.0.tgz", + "integrity": "sha512-G9/6xF1FPbIw0TtalAMaVPpiq2aDEuKLXM314jPVAO9r2fo2a4BLqMNkmRS7O/xPPZ+COAhGIz3ETvHEV3eUcg==", "bin": { "envinfo": "dist/cli.js" }, @@ -1429,9 +1449,9 @@ } }, "node_modules/fast-glob": { - "version": "3.2.12", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", - "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -1463,21 +1483,21 @@ } }, "node_modules/fraction.js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", - "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "engines": { "node": "*" }, "funding": { "type": "patreon", - "url": "https://www.patreon.com/infusion" + "url": "https://github.com/sponsors/rawify" } }, "node_modules/fs-extra": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", - "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -1488,9 +1508,9 @@ } }, "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "hasInstallScript": true, "optional": true, "os": [ @@ -1501,9 +1521,12 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-stream": { "version": "6.0.1", @@ -1528,13 +1551,13 @@ } }, "node_modules/globby": { - "version": "13.1.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.3.tgz", - "integrity": "sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==", + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", "dependencies": { "dir-glob": "^3.0.1", - "fast-glob": "^3.2.11", - "ignore": "^5.2.0", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", "merge2": "^1.4.1", "slash": "^4.0.0" }, @@ -1546,9 +1569,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/gray-matter": { "version": "4.0.3", @@ -1564,22 +1587,22 @@ "node": ">=6.0" } }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/hash-sum": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-2.0.0.tgz", "integrity": "sha512-WdZTbAByD+pHfl/g9QSsBIIwy8IT+EsPiKDs0KNX+zSHhdDLFKdZu0BQHljvO+0QI/BasbMSUa8wYNCZTvhslg==" }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/human-signals": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-3.0.1.tgz", @@ -1608,17 +1631,17 @@ ] }, "node_modules/ignore": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", - "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz", + "integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==", "engines": { "node": ">= 4" } }, "node_modules/immutable": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.2.2.tgz", - "integrity": "sha512-fTMKDwtbvO5tldky9QZ2fMX7slR0mYpY5nbnFWYp0fOzDhHqhgIw9KoYgxLWsoNTS9ZHGauHj18DTyEw6BK3Og==" + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.4.tgz", + "integrity": "sha512-fsXeu4J4i6WNWSikpI88v/PcVflZz+6kMhUfIwc5SY+poQRPnaf5V7qds6SUyUN3cVxEzuCab7QIoLOQ+DQ1wA==" }, "node_modules/inherits": { "version": "2.0.4", @@ -1637,11 +1660,11 @@ } }, "node_modules/is-core-module": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", - "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1752,11 +1775,11 @@ } }, "node_modules/lilconfig": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", - "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", "engines": { - "node": ">=10" + "node": ">=14" } }, "node_modules/linkify-it": { @@ -1783,17 +1806,20 @@ } }, "node_modules/magic-string": { - "version": "0.25.9", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.9.tgz", - "integrity": "sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==", + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", "dependencies": { - "sourcemap-codec": "^1.4.8" + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" } }, "node_modules/markdown-it": { - "version": "13.0.1", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.1.tgz", - "integrity": "sha512-lTlxriVoy2criHP0JKRhO2VDG9c2ypWCsT237eDiLqi09rmbKoUetyGHq2uOIRoRS//kfoJckS0eUzzkDR+k2Q==", + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-13.0.2.tgz", + "integrity": "sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==", "dependencies": { "argparse": "^2.0.1", "entities": "~3.0.1", @@ -1806,9 +1832,9 @@ } }, "node_modules/markdown-it-anchor": { - "version": "8.6.6", - "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.6.tgz", - "integrity": "sha512-jRW30YGywD2ESXDc+l17AiritL0uVaSnWsb26f+68qaW9zgbIIr1f4v2Nsvc0+s0Z2N3uX6t/yAw7BwCQ1wMsA==", + "version": "8.6.7", + "resolved": "https://registry.npmjs.org/markdown-it-anchor/-/markdown-it-anchor-8.6.7.tgz", + "integrity": "sha512-FlCHFwNnutLgVTflOYHPW2pPcl2AACqVzExlkGQNsi4CJgqOHN7YTgDd4LuhgN1BFO3TS0vLAruV1Td6dwWPJA==", "peerDependencies": { "@types/markdown-it": "*", "markdown-it": "*" @@ -1835,9 +1861,9 @@ "integrity": "sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==" }, "node_modules/medium-zoom": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.0.8.tgz", - "integrity": "sha512-CjFVuFq/IfrdqesAXfg+hzlDKu6A2n80ZIq0Kl9kWjoHh9j1N9Uvk5X0/MmN0hOfm5F9YBswlClhcwnmtwz7gA==" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/medium-zoom/-/medium-zoom-1.1.0.tgz", + "integrity": "sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==" }, "node_modules/merge-stream": { "version": "2.0.0", @@ -1881,9 +1907,15 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/nanoid": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", - "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -1892,9 +1924,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", - "integrity": "sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==" + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" }, "node_modules/normalize-path": { "version": "3.0.0", @@ -1952,17 +1984,17 @@ } }, "node_modules/ora": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/ora/-/ora-6.1.2.tgz", - "integrity": "sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-6.3.1.tgz", + "integrity": "sha512-ERAyNnZOfqM+Ao3RAvIXkYh5joP220yf59gVe2X/cI6SiCxIdi4c9HZKZD8R6q/RDXEje1THBju6iExiSsgJaQ==", "dependencies": { - "bl": "^5.0.0", "chalk": "^5.0.0", "cli-cursor": "^4.0.0", "cli-spinners": "^2.6.1", "is-interactive": "^2.0.0", "is-unicode-supported": "^1.1.0", "log-symbols": "^5.1.0", + "stdin-discarder": "^0.1.0", "strip-ansi": "^7.0.1", "wcwidth": "^1.0.1" }, @@ -2011,9 +2043,9 @@ } }, "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "version": "8.4.32", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.32.tgz", + "integrity": "sha512-D/kj5JNu6oo2EIy+XL/26JEDTlIbB8hw85G8StOE6L74RQAVVP5rej6wxCNqyMbR4RkPfqvezVbPw81Ngd6Kcw==", "funding": [ { "type": "opencollective", @@ -2022,10 +2054,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.7", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" }, @@ -2034,20 +2070,26 @@ } }, "node_modules/postcss-load-config": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.1.tgz", - "integrity": "sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" }, "engines": { "node": ">= 14" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" @@ -2094,9 +2136,9 @@ ] }, "node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", "dependencies": { "inherits": "^2.0.3", "string_decoder": "^1.1.1", @@ -2118,11 +2160,11 @@ } }, "node_modules/resolve": { - "version": "1.22.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", - "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dependencies": { - "is-core-module": "^2.9.0", + "is-core-module": "^2.13.0", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -2180,9 +2222,9 @@ } }, "node_modules/rollup": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.10.1.tgz", - "integrity": "sha512-3Er+yel3bZbZX1g2kjVM+FW+RUWDxbG87fcqFM5/9HbPCTpbVp6JOLn7jlxnNlbu7s/N/uDA4EV/91E2gWnxzw==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "bin": { "rollup": "dist/bin/rollup" }, @@ -2236,9 +2278,9 @@ ] }, "node_modules/sass": { - "version": "1.57.1", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.57.1.tgz", - "integrity": "sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==", + "version": "1.69.5", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.5.tgz", + "integrity": "sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -2248,7 +2290,7 @@ "sass": "sass.js" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/section-matter": { @@ -2298,14 +2340,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -2314,17 +2348,25 @@ "node": ">=0.10.0" } }, - "node_modules/sourcemap-codec": { - "version": "1.4.8", - "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", - "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==", - "deprecated": "Please use @jridgewell/sourcemap-codec instead" - }, "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, + "node_modules/stdin-discarder": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", + "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", + "dependencies": { + "bl": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -2334,9 +2376,9 @@ } }, "node_modules/strip-ansi": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz", - "integrity": "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw==", + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -2398,10 +2440,15 @@ "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==" }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + }, "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "engines": { "node": ">= 10.0.0" } @@ -2416,9 +2463,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", - "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", "funding": [ { "type": "opencollective", @@ -2427,6 +2474,10 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { @@ -2434,7 +2485,7 @@ "picocolors": "^1.0.0" }, "bin": { - "browserslist-lint": "cli.js" + "update-browserslist-db": "cli.js" }, "peerDependencies": { "browserslist": ">= 4.21.0" @@ -2446,9 +2497,9 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" }, "node_modules/vite": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.4.tgz", - "integrity": "sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.0.5.tgz", + "integrity": "sha512-7m87RC+caiAxG+8j3jObveRLqaWA/neAdCat6JAZwMkSWqFHOvg8MYe5fAQxVBRAuKAQ1S6XDh3CBQuLNbY33w==", "dependencies": { "esbuild": "^0.16.3", "postcss": "^8.4.20", @@ -2494,23 +2545,31 @@ } }, "node_modules/vue": { - "version": "3.2.45", - "resolved": "https://registry.npmjs.org/vue/-/vue-3.2.45.tgz", - "integrity": "sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==", + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/vue/-/vue-3.3.11.tgz", + "integrity": "sha512-d4oBctG92CRO1cQfVBZp6WJAs0n8AK4Xf5fNjQCBeKCvMI1efGQ5E3Alt1slFJS9fZuPcFoiAiqFvQlv1X7t/w==", "dependencies": { - "@vue/compiler-dom": "3.2.45", - "@vue/compiler-sfc": "3.2.45", - "@vue/runtime-dom": "3.2.45", - "@vue/server-renderer": "3.2.45", - "@vue/shared": "3.2.45" + "@vue/compiler-dom": "3.3.11", + "@vue/compiler-sfc": "3.3.11", + "@vue/runtime-dom": "3.3.11", + "@vue/server-renderer": "3.3.11", + "@vue/shared": "3.3.11" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/vue-router": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.1.6.tgz", - "integrity": "sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-4.2.5.tgz", + "integrity": "sha512-DIUpKcyg4+PTQKfFPX88UWhlagBEBEfJ5A8XDXRJLUnZOvcpMF8o/dnL90vpVkGaPbjvXazV/rC1qBKrZlFugw==", "dependencies": { - "@vue/devtools-api": "^6.4.5" + "@vue/devtools-api": "^6.5.0" }, "funding": { "url": "https://github.com/sponsors/posva" @@ -2572,9 +2631,9 @@ } }, "node_modules/yaml": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", - "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", "engines": { "node": ">= 14" } diff --git a/dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json b/dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json index 8efc835..98933b5 100644 --- a/dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json +++ b/dotnet/BSB/obj/BSB.csproj.nuget.dgspec.json @@ -1,17 +1,17 @@ { "format": 1, "restore": { - "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj": {} + "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj": {} }, "projects": { - "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj": { + "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj": { "version": "1.0.0", "restore": { - "projectUniqueName": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj", + "projectUniqueName": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj", "projectName": "BSB", - "projectPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj", + "projectPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj", "packagesPath": "/home/mitchellr/.nuget/packages/", - "outputPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/obj/", + "outputPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/obj/", "projectStyle": "PackageReference", "configFilePaths": [ "/home/mitchellr/.nuget/NuGet/NuGet.Config" @@ -48,12 +48,22 @@ ], "assetTargetFallback": true, "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + } + ], "frameworkReferences": { "Microsoft.NETCore.App": { "privateAssets": "all" } }, - "runtimeIdentifierGraphPath": "/home/mitchellr/.dotnet/sdk/6.0.404/RuntimeIdentifierGraph.json" + "runtimeIdentifierGraphPath": "/usr/lib64/dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" } } } diff --git a/dotnet/BSB/obj/BSB.csproj.nuget.g.props b/dotnet/BSB/obj/BSB.csproj.nuget.g.props index 84ab64a..027c5df 100644 --- a/dotnet/BSB/obj/BSB.csproj.nuget.g.props +++ b/dotnet/BSB/obj/BSB.csproj.nuget.g.props @@ -7,7 +7,7 @@ /home/mitchellr/.nuget/packages/ /home/mitchellr/.nuget/packages/ PackageReference - 6.6.0 + 6.8.0 diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfoInputs.cache b/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfoInputs.cache index 1862044..2079379 100644 --- a/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfoInputs.cache +++ b/dotnet/BSB/obj/Debug/net6.0/BSB.AssemblyInfoInputs.cache @@ -1 +1 @@ -06c03cd1a62928a8792c4baac24a35040fa8a3ca +2085b2250a84c1a9be6acaafd097d28d33ef39aa77ab12890538e72b283745b8 diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.GeneratedMSBuildEditorConfig.editorconfig b/dotnet/BSB/obj/Debug/net6.0/BSB.GeneratedMSBuildEditorConfig.editorconfig index b5b2b53..22c25e0 100644 --- a/dotnet/BSB/obj/Debug/net6.0/BSB.GeneratedMSBuildEditorConfig.editorconfig +++ b/dotnet/BSB/obj/Debug/net6.0/BSB.GeneratedMSBuildEditorConfig.editorconfig @@ -5,6 +5,9 @@ build_property.UsingMicrosoftNETSdkWeb = build_property.ProjectTypeGuids = build_property.InvariantGlobalization = build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = build_property._SupportedPlatformList = Linux,macOS,Windows build_property.RootNamespace = BSB -build_property.ProjectDir = /home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/ +build_property.ProjectDir = /home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = diff --git a/dotnet/BSB/obj/Debug/net6.0/BSB.assets.cache b/dotnet/BSB/obj/Debug/net6.0/BSB.assets.cache index e89ac286856a615cd6e38cbfc4b405f4ec0088ed..d83dd60a9cc259503e1fac2335839a1c8d887ed7 100644 GIT binary patch delta 58 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 diff --git a/dotnet/BSB/obj/project.assets.json b/dotnet/BSB/obj/project.assets.json index 440014c..ff91902 100644 --- a/dotnet/BSB/obj/project.assets.json +++ b/dotnet/BSB/obj/project.assets.json @@ -13,11 +13,11 @@ "project": { "version": "1.0.0", "restore": { - "projectUniqueName": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj", + "projectUniqueName": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj", "projectName": "BSB", - "projectPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj", + "projectPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj", "packagesPath": "/home/mitchellr/.nuget/packages/", - "outputPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/obj/", + "outputPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/obj/", "projectStyle": "PackageReference", "configFilePaths": [ "/home/mitchellr/.nuget/NuGet/NuGet.Config" @@ -54,12 +54,22 @@ ], "assetTargetFallback": true, "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + } + ], "frameworkReferences": { "Microsoft.NETCore.App": { "privateAssets": "all" } }, - "runtimeIdentifierGraphPath": "/home/mitchellr/.dotnet/sdk/6.0.404/RuntimeIdentifierGraph.json" + "runtimeIdentifierGraphPath": "/usr/lib64/dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" } } } diff --git a/dotnet/BSB/obj/project.nuget.cache b/dotnet/BSB/obj/project.nuget.cache index 9861e36..674b07d 100644 --- a/dotnet/BSB/obj/project.nuget.cache +++ b/dotnet/BSB/obj/project.nuget.cache @@ -1,8 +1,11 @@ { "version": 2, - "dgSpecHash": "846PNqqcp/UMPpefQDVjVUSUeNezpWFigUdhxsBKbP6tN51Jgx6AT8hBftcsek+nliyefWyALGeK9gslUv2uNA==", + "dgSpecHash": "m/mmZmgs6qi/4eqAiuSIdbou0BI1C15Z5VAJ274ZbPbs/O2jjmEhryyyoIOMW/uat6AecIhRT+0RvyiiWJABwQ==", "success": true, - "projectFilePath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BSB/BSB.csproj", - "expectedPackageFiles": [], + "projectFilePath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BSB/BSB.csproj", + "expectedPackageFiles": [ + "/home/mitchellr/.nuget/packages/microsoft.netcore.app.ref/6.0.25/microsoft.netcore.app.ref.6.0.25.nupkg.sha512", + "/home/mitchellr/.nuget/packages/microsoft.aspnetcore.app.ref/6.0.25/microsoft.aspnetcore.app.ref.6.0.25.nupkg.sha512" + ], "logs": [] } \ No newline at end of file diff --git a/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.dgspec.json b/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.dgspec.json index 9d47168..2bd714c 100644 --- a/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.dgspec.json +++ b/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.dgspec.json @@ -1,17 +1,17 @@ { "format": 1, "restore": { - "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj": {} + "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj": {} }, "projects": { - "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj": { + "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj": { "version": "1.0.0", "restore": { - "projectUniqueName": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "projectUniqueName": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", "projectName": "BetterServiceBase", - "projectPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "projectPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", "packagesPath": "/home/mitchellr/.nuget/packages/", - "outputPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/", + "outputPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/obj/", "projectStyle": "PackageReference", "configFilePaths": [ "/home/mitchellr/.nuget/NuGet/NuGet.Config" @@ -48,12 +48,26 @@ ], "assetTargetFallback": true, "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + }, + { + "name": "Microsoft.NETCore.App.Host.linux-x64", + "version": "[6.0.25, 6.0.25]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + } + ], "frameworkReferences": { "Microsoft.NETCore.App": { "privateAssets": "all" } }, - "runtimeIdentifierGraphPath": "/home/mitchellr/.dotnet/sdk/6.0.404/RuntimeIdentifierGraph.json" + "runtimeIdentifierGraphPath": "/usr/lib64/dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" } } } diff --git a/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.props b/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.props index 84ab64a..027c5df 100644 --- a/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.props +++ b/dotnet/BetterServiceBase/obj/BetterServiceBase.csproj.nuget.g.props @@ -7,7 +7,7 @@ /home/mitchellr/.nuget/packages/ /home/mitchellr/.nuget/packages/ PackageReference - 6.6.0 + 6.8.0 diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache index 8926452..98ea8e3 100644 --- a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.AssemblyInfoInputs.cache @@ -1 +1 @@ -a9f474a87d2cc37e3df94bbe95f0b40bbfd0df92 +e7e3a6a74e3831cb483e5b6d4f4da9eb38d87e11319a20fef308246f7b07ad29 diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig index 8b6cd16..869834c 100644 --- a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig +++ b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.GeneratedMSBuildEditorConfig.editorconfig @@ -5,6 +5,9 @@ build_property.UsingMicrosoftNETSdkWeb = build_property.ProjectTypeGuids = build_property.InvariantGlobalization = build_property.PlatformNeutralAssembly = +build_property.EnforceExtendedAnalyzerRules = build_property._SupportedPlatformList = Linux,macOS,Windows build_property.RootNamespace = BetterServiceBase -build_property.ProjectDir = /home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/ +build_property.ProjectDir = /home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/ +build_property.EnableComHosting = +build_property.EnableGeneratedComInterfaceComImportInterop = diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.assets.cache b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.assets.cache index 0d222a20f6cbd5deb0d55f4ff64ba683b4a6112d..3e0cbad34873de8160750ac7f6bb90b25dcb4ad0 100644 GIT binary patch delta 58 zcmV-A0LA}}0hs|QP)kQa3;+NCbj2zCdR#ogvu<_gjqM1T+4#Ja7PV!ciujpqfUIRf Qm635Ak$?@6N<)!A1jT?ESO5S3 delta 49 zcmbQq*vqIH;O*|n#lXOj*j_FYl_X!cDm&#RXTaL7!i(mMg;z9x7rFcD<-g4=F`W|) FQvjk_6cPXc diff --git a/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.AssemblyReference.cache b/dotnet/BetterServiceBase/obj/Debug/net6.0/BetterServiceBase.csproj.AssemblyReference.cache deleted file mode 100644 index d5c351291701ad64ba1985f8bfc5e84253ec72bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71759 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 diff --git a/dotnet/BetterServiceBase/obj/project.assets.json b/dotnet/BetterServiceBase/obj/project.assets.json index 1d8f4ce..6d2c9ae 100644 --- a/dotnet/BetterServiceBase/obj/project.assets.json +++ b/dotnet/BetterServiceBase/obj/project.assets.json @@ -13,11 +13,11 @@ "project": { "version": "1.0.0", "restore": { - "projectUniqueName": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "projectUniqueName": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", "projectName": "BetterServiceBase", - "projectPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "projectPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", "packagesPath": "/home/mitchellr/.nuget/packages/", - "outputPath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/obj/", + "outputPath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/obj/", "projectStyle": "PackageReference", "configFilePaths": [ "/home/mitchellr/.nuget/NuGet/NuGet.Config" @@ -54,12 +54,26 @@ ], "assetTargetFallback": true, "warn": true, + "downloadDependencies": [ + { + "name": "Microsoft.AspNetCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + }, + { + "name": "Microsoft.NETCore.App.Host.linux-x64", + "version": "[6.0.25, 6.0.25]" + }, + { + "name": "Microsoft.NETCore.App.Ref", + "version": "[6.0.25, 6.0.25]" + } + ], "frameworkReferences": { "Microsoft.NETCore.App": { "privateAssets": "all" } }, - "runtimeIdentifierGraphPath": "/home/mitchellr/.dotnet/sdk/6.0.404/RuntimeIdentifierGraph.json" + "runtimeIdentifierGraphPath": "/usr/lib64/dotnet/sdk/8.0.100/RuntimeIdentifierGraph.json" } } } diff --git a/dotnet/BetterServiceBase/obj/project.nuget.cache b/dotnet/BetterServiceBase/obj/project.nuget.cache index 9931131..e4eca4d 100644 --- a/dotnet/BetterServiceBase/obj/project.nuget.cache +++ b/dotnet/BetterServiceBase/obj/project.nuget.cache @@ -1,8 +1,12 @@ { "version": 2, - "dgSpecHash": "6C02A27v8AIrUk/f091ZNYiEh48VbXOUQkuaEttX9wfVc34nMPwErZXuzusJkAClEFjsHwfoNcI7Ft7y/aamYw==", + "dgSpecHash": "SW8YGRI76SDK6Rzixpf1lnLQTQcTM4BP9qYzPPFryONlPOp6Z3dM/zeNTcfSTKfEQFHXckkCwaRCXWRcRxgYCA==", "success": true, - "projectFilePath": "/home/mitchellr/_repos/BetterCorp/better-service-base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", - "expectedPackageFiles": [], + "projectFilePath": "/home/mitchellr/_repos/BSB-BetterPortal/BSB/_base/service-base/dotnet/BetterServiceBase/BetterServiceBase.csproj", + "expectedPackageFiles": [ + "/home/mitchellr/.nuget/packages/microsoft.netcore.app.ref/6.0.25/microsoft.netcore.app.ref.6.0.25.nupkg.sha512", + "/home/mitchellr/.nuget/packages/microsoft.aspnetcore.app.ref/6.0.25/microsoft.aspnetcore.app.ref.6.0.25.nupkg.sha512", + "/home/mitchellr/.nuget/packages/microsoft.netcore.app.host.linux-x64/6.0.25/microsoft.netcore.app.host.linux-x64.6.0.25.nupkg.sha512" + ], "logs": [] } \ No newline at end of file diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 3aa1179..b113a7e 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -9,9 +9,10 @@ "version": "9.0.4-beta", "license": "AGPL-3.0-only", "dependencies": { - "@bettercorp/tools": "^2.0.20220714140658", - "yaml": "^2.3.1", - "zod": "^3.21.4" + "@bettercorp/tools": "^3.6.0", + "yaml": "^2.3.4", + "yargs": "^17.7.2", + "zod": "^3.22.4" }, "bin": { "bsb": "lib/bootstrap.js" @@ -22,15 +23,14 @@ "@types/mocha": "^10.0.6", "@types/node": "^20.10.5", "@types/yargs": "^17.0.32", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", + "@typescript-eslint/eslint-plugin": "^6.15.0", + "@typescript-eslint/parser": "^6.15.0", "chai": "^4.3.10", "eslint": "^8.56.0", "mocha": "^10.2.0", "nyc": "^15.1.0", "ts-node": "^10.9.2", - "typescript": "^5.3.3", - "yargs": "^17.5.1" + "typescript": "^5.3.3" }, "engines": { "node": ">=18.0.0", @@ -523,22 +523,12 @@ } }, "node_modules/@bettercorp/tools": { - "version": "2.1.30", - "resolved": "https://registry.npmjs.org/@bettercorp/tools/-/tools-2.1.30.tgz", - "integrity": "sha512-MrRB57PQJ5bgz6D+jCTbcizH7A8PfKuyqu3MucekQN0qJ+E2ltdHeV5+3LapOqq5RZJH0N8gmf9qx3kzzy3CPw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/@bettercorp/tools/-/tools-3.6.0.tgz", + "integrity": "sha512-mNwDemxBoNoL9yWokSsQNqWSP69pePz5pKu4qkPZGepWJb0wFLenmNXO8BQnulRx7+K5rWyw2FsLq3TtM3RSNA==", "dependencies": { - "@types/node": "^18.11.10", - "crypto-js": "^4.1.1", - "just-clone": "^6.1.1", - "moment": "^2.29.4" - } - }, - "node_modules/@bettercorp/tools/node_modules/@types/node": { - "version": "18.19.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.3.tgz", - "integrity": "sha512-k5fggr14DwAytoA/t8rPrIz++lXK7/DqckthCmoZOKNsEbJkId4Z//BqgApXBUGrGddrigYa1oqheo/7YmW4rg==", - "dependencies": { - "undici-types": "~5.26.4" + "crypto-js": "^4.2.0", + "just-clone": "^6.2.0" } }, "node_modules/@cspotcode/source-map-support": { @@ -1188,7 +1178,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1197,7 +1186,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -1495,7 +1483,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -1509,7 +1496,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -1520,8 +1506,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/commondir": { "version": "1.0.1", @@ -1667,8 +1652,7 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/es6-error": { "version": "4.1.1", @@ -1680,7 +1664,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -2059,7 +2042,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -2294,7 +2276,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -2824,14 +2805,6 @@ "node": ">=10" } }, - "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "engines": { - "node": "*" - } - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -3369,7 +3342,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -3577,7 +3549,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -3591,7 +3562,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -3795,7 +3765,8 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true }, "node_modules/update-browserslist-db": { "version": "1.0.13", @@ -3882,7 +3853,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -3917,7 +3887,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "engines": { "node": ">=10" } @@ -3940,7 +3909,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "dev": true, "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -4006,7 +3974,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "engines": { "node": ">=12" } diff --git a/nodejs/package.json b/nodejs/package.json index 08f5ad9..ce87a5f 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -30,27 +30,6 @@ ], "main": "lib/index.js", "version": "9.0.4-beta", - "devDependencies": { - "@types/assert": "^1.5.10", - "@types/chai": "^4.3.11", - "@types/mocha": "^10.0.6", - "@types/node": "^20.10.5", - "@types/yargs": "^17.0.32", - "@typescript-eslint/eslint-plugin": "^6.14.0", - "@typescript-eslint/parser": "^6.14.0", - "chai": "^4.3.10", - "eslint": "^8.56.0", - "mocha": "^10.2.0", - "nyc": "^15.1.0", - "ts-node": "^10.9.2", - "typescript": "^5.3.3", - "yargs": "^17.5.1" - }, - "dependencies": { - "@bettercorp/tools": "^2.0.20220714140658", - "yaml": "^2.3.1", - "zod": "^3.21.4" - }, "bsb_project": true, "bsbInit": { "project": { @@ -117,5 +96,26 @@ "src/shared", "src/tests" ] + }, + "devDependencies": { + "@types/assert": "^1.5.10", + "@types/chai": "^4.3.11", + "@types/mocha": "^10.0.6", + "@types/node": "^20.10.5", + "@types/yargs": "^17.0.32", + "@typescript-eslint/eslint-plugin": "^6.15.0", + "@typescript-eslint/parser": "^6.15.0", + "chai": "^4.3.10", + "eslint": "^8.56.0", + "mocha": "^10.2.0", + "nyc": "^15.1.0", + "ts-node": "^10.9.2", + "typescript": "^5.3.3" + }, + "dependencies": { + "@bettercorp/tools": "^3.6.0", + "yaml": "^2.3.4", + "zod": "^3.22.4", + "yargs": "^17.7.2" } -} +} \ No newline at end of file diff --git a/nodejs/src/base/logFormatter.ts b/nodejs/src/base/logFormatter.ts index d148b67..a896367 100644 --- a/nodejs/src/base/logFormatter.ts +++ b/nodejs/src/base/logFormatter.ts @@ -1,4 +1,4 @@ -import { Tools } from "@bettercorp/tools"; +import { Tools } from "@bettercorp/tools/lib/Tools"; import { LogMeta, SafeLogData, UnsafeLogData } from "../interfaces/logging"; export class LogFormatter { diff --git a/nodejs/src/plugins/config-default/plugin.ts b/nodejs/src/plugins/config-default/plugin.ts index a68abca..bb14879 100644 --- a/nodejs/src/plugins/config-default/plugin.ts +++ b/nodejs/src/plugins/config-default/plugin.ts @@ -10,13 +10,15 @@ import { PluginType, PluginTypes, } from "../../interfaces/plugins"; -import { Tools } from "@bettercorp/tools"; +import { Tools } from "@bettercorp/tools/lib/Tools"; import { SBLogging } from "../../serviceBase/logging"; import { DEBUG_MODE } from "../../interfaces/logging"; import { BSBError } from "../../base/errorMessages"; export class Plugin extends BSBConfig { - async getServicePluginDefinition(pluginName: string): Promise<{name:string,enabled:boolean}> { + async getServicePluginDefinition( + pluginName: string + ): Promise<{ name: string; enabled: boolean }> { const keydPlugins = Object.keys( this._appConfig[this._deploymentProfile].services ?? {} ); @@ -117,7 +119,9 @@ export class Plugin extends BSBConfig { let configKey: "services" | "logging" | "events" = "services"; if (pluginType === PluginTypes.events) configKey = "events"; if (pluginType === PluginTypes.logging) configKey = "logging"; - return this._appConfig[this._deploymentProfile][configKey][plugin].config ?? null; + return ( + this._appConfig[this._deploymentProfile][configKey][plugin].config ?? null + ); } dispose() { this._appConfig = undefined!; diff --git a/nodejs/src/serviceBase/config.ts b/nodejs/src/serviceBase/config.ts index 3c899b9..f4fc380 100644 --- a/nodejs/src/serviceBase/config.ts +++ b/nodejs/src/serviceBase/config.ts @@ -4,7 +4,6 @@ import { SBPlugins } from "./plugins"; import { SBLogging } from "./logging"; import { PluginLogger } from "../base/PluginLogger"; import { BSBConfig } from "../base/config"; -import { Tools } from "@bettercorp/tools"; import { SmartFunctionCallSync, SmartFunctionCallAsync, @@ -16,6 +15,7 @@ import { PluginDefition, PluginType, } from "../interfaces/plugins"; +import { Tools } from "@bettercorp/tools/lib/Tools"; export class SBConfig { private mode: DEBUG_MODE = "development"; diff --git a/nodejs/src/serviceBase/events.ts b/nodejs/src/serviceBase/events.ts index 3995a47..8e87632 100644 --- a/nodejs/src/serviceBase/events.ts +++ b/nodejs/src/serviceBase/events.ts @@ -10,7 +10,6 @@ import { } from "../interfaces/plugins"; import { SBPlugins } from "./plugins"; import { SBConfig } from "./config"; -import { Tools } from "@bettercorp/tools"; import { SmartFunctionCallAsync, SmartFunctionCallSync, @@ -23,6 +22,7 @@ import { NS_PER_SEC, MS_PER_NS } from "./serviceBase"; import { BSBService } from "../base/service"; import { BSBServiceClient } from "../base/serviceClient"; import { LoadedPlugin } from "../interfaces"; +import { Tools } from "@bettercorp/tools/lib/Tools"; export class SBEvents { private events: Array<{ @@ -286,10 +286,15 @@ export class SBEvents { let pluginConfig = await sbConfig.getPluginConfig("events", plugin.name); - if (newPlugin.serviceConfig !== null) { + if ( + !Tools.isNullOrUndefined(newPlugin) && + !Tools.isNullOrUndefined(newPlugin.serviceConfig) && + Tools.isObject(newPlugin.serviceConfig) && + !Tools.isNullOrUndefined(newPlugin.serviceConfig.validationSchema) + ) { pluginConfig = newPlugin.serviceConfig.validationSchema.parse(pluginConfig); - } else if (pluginConfig === null) { + } else if (Tools.isNullOrUndefined(pluginConfig)) { pluginConfig = {}; } diff --git a/nodejs/src/serviceBase/logging.ts b/nodejs/src/serviceBase/logging.ts index df82205..1a2ec0b 100644 --- a/nodejs/src/serviceBase/logging.ts +++ b/nodejs/src/serviceBase/logging.ts @@ -18,12 +18,12 @@ import { } from "../interfaces/plugins"; import { SBPlugins } from "./plugins"; import { SBConfig } from "./config"; -import { Tools } from "@bettercorp/tools"; import { SmartFunctionCallAsync, SmartFunctionCallSync, } from "../base/functions"; import { LoadedPlugin } from "../interfaces"; +import { Tools } from '@bettercorp/tools/lib/Tools'; export class SBLogging { private loggers: Array<{ @@ -356,10 +356,15 @@ export class SBLogging { let pluginConfig = await sbConfig.getPluginConfig("logging", plugin.name); - if (newPlugin.serviceConfig !== null) { + if ( + !Tools.isNullOrUndefined(newPlugin) && + !Tools.isNullOrUndefined(newPlugin.serviceConfig) && + Tools.isObject(newPlugin.serviceConfig) && + !Tools.isNullOrUndefined(newPlugin.serviceConfig.validationSchema) + ) { pluginConfig = newPlugin.serviceConfig.validationSchema.parse(pluginConfig); - } else if (pluginConfig === null) { + } else if (Tools.isNullOrUndefined(pluginConfig)) { pluginConfig = {}; } diff --git a/nodejs/src/serviceBase/services.ts b/nodejs/src/serviceBase/services.ts index 33b12d4..91b2015 100644 --- a/nodejs/src/serviceBase/services.ts +++ b/nodejs/src/serviceBase/services.ts @@ -15,6 +15,7 @@ import { BSBError } from "../base/errorMessages"; import { BSBServiceClient } from "../base/serviceClient"; import { PluginEvents } from "../base/PluginEvents"; import { LoadedPlugin } from "../interfaces"; +import { Tools } from "@bettercorp/tools/lib/Tools"; export class SBServices { private _activeServices: Array = []; @@ -226,10 +227,15 @@ export class SBServices { let pluginConfig = await sbConfig.getPluginConfig("service", plugin.name); - if (newPlugin.serviceConfig !== null) { + if ( + !Tools.isNullOrUndefined(newPlugin) && + !Tools.isNullOrUndefined(newPlugin.serviceConfig) && + Tools.isObject(newPlugin.serviceConfig) && + !Tools.isNullOrUndefined(newPlugin.serviceConfig.validationSchema) + ) { pluginConfig = newPlugin.serviceConfig.validationSchema.parse(pluginConfig); - } else if (pluginConfig === null) { + } else if (Tools.isNullOrUndefined(pluginConfig)) { pluginConfig = {}; } From 62ce5c95a9d319ee24bbac9bd55f6194650e9775 Mon Sep 17 00:00:00 2001 From: mrinc Date: Wed, 20 Dec 2023 15:50:25 +0200 Subject: [PATCH 33/47] Updated tools dep --- nodejs/package-lock.json | 14 ++++---------- nodejs/package.json | 8 ++++---- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index b113a7e..05a10f1 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -9,7 +9,7 @@ "version": "9.0.4-beta", "license": "AGPL-3.0-only", "dependencies": { - "@bettercorp/tools": "^3.6.0", + "@bettercorp/tools": "^3.7.0", "yaml": "^2.3.4", "yargs": "^17.7.2", "zod": "^3.22.4" @@ -523,11 +523,10 @@ } }, "node_modules/@bettercorp/tools": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/@bettercorp/tools/-/tools-3.6.0.tgz", - "integrity": "sha512-mNwDemxBoNoL9yWokSsQNqWSP69pePz5pKu4qkPZGepWJb0wFLenmNXO8BQnulRx7+K5rWyw2FsLq3TtM3RSNA==", + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/@bettercorp/tools/-/tools-3.7.0.tgz", + "integrity": "sha512-UJQeelcmwq0De1J7N6pIKAL93xx/ABC1p0au0h/lmPEiOPXFRIaS3xH1Yq8/GBMqVbbHzi7gjbTCiF0Hfsju6A==", "dependencies": { - "crypto-js": "^4.2.0", "just-clone": "^6.2.0" } }, @@ -1546,11 +1545,6 @@ "node": ">= 8" } }, - "node_modules/crypto-js": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", - "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", diff --git a/nodejs/package.json b/nodejs/package.json index ce87a5f..db0700c 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -113,9 +113,9 @@ "typescript": "^5.3.3" }, "dependencies": { - "@bettercorp/tools": "^3.6.0", + "@bettercorp/tools": "^3.7.0", "yaml": "^2.3.4", - "zod": "^3.22.4", - "yargs": "^17.7.2" + "yargs": "^17.7.2", + "zod": "^3.22.4" } -} \ No newline at end of file +} From 16bff1c230aec880a85d97f7566d3d83f9f473e9 Mon Sep 17 00:00:00 2001 From: mrinc Date: Wed, 20 Dec 2023 19:30:29 +0200 Subject: [PATCH 34/47] Updated package --- nodejs/{ => development}/tsconfig-release.json | 0 nodejs/package.json | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename nodejs/{ => development}/tsconfig-release.json (100%) diff --git a/nodejs/tsconfig-release.json b/nodejs/development/tsconfig-release.json similarity index 100% rename from nodejs/tsconfig-release.json rename to nodejs/development/tsconfig-release.json diff --git a/nodejs/package.json b/nodejs/package.json index db0700c..d9aa653 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -12,7 +12,7 @@ "dev": "nodemon --config ./nodemon.json", "start": "node lib/cli.js", "build": "rm -rfv ./lib && tsc && npm run testDev", - "build-release": "rm -rfv ./lib && tsc && npm run test && rm -rfv ./lib && tsc --p ./tsconfig-release.json", + "build-release": "rm -rfv ./lib && tsc --p ./development/tsconfig-release.json", "xZpostinstall": "node ./postinstall.js", "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx", "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js --reporter json --reporter lcov ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts' --reporter json --reporter-options output=junit.json", From 19131b4b58a22d5acd5feab9ffad4d6d4eb5b3ae Mon Sep 17 00:00:00 2001 From: mrinc Date: Wed, 20 Dec 2023 19:33:15 +0200 Subject: [PATCH 35/47] Build specifically for BSB core --- nodejs/development/tsconfig-release.json | 1 - nodejs/package.json | 2 +- nodejs/tsconfig-release.json | 44 ++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 nodejs/tsconfig-release.json diff --git a/nodejs/development/tsconfig-release.json b/nodejs/development/tsconfig-release.json index e064aaf..a224c0f 100644 --- a/nodejs/development/tsconfig-release.json +++ b/nodejs/development/tsconfig-release.json @@ -38,7 +38,6 @@ "node_modules/**", "src/plugins/*-test*/**/*.*", "src/plugins/-*/**/*.*", - "src/plugins/service-*/**/*.*", "src/tests/**/*.*" ] } \ No newline at end of file diff --git a/nodejs/package.json b/nodejs/package.json index d9aa653..884f61c 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -12,7 +12,7 @@ "dev": "nodemon --config ./nodemon.json", "start": "node lib/cli.js", "build": "rm -rfv ./lib && tsc && npm run testDev", - "build-release": "rm -rfv ./lib && tsc --p ./development/tsconfig-release.json", + "build-release": "rm -rfv ./lib && tsc --p ./tsconfig-release.json", "xZpostinstall": "node ./postinstall.js", "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx", "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js --reporter json --reporter lcov ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts' --reporter json --reporter-options output=junit.json", diff --git a/nodejs/tsconfig-release.json b/nodejs/tsconfig-release.json new file mode 100644 index 0000000..e064aaf --- /dev/null +++ b/nodejs/tsconfig-release.json @@ -0,0 +1,44 @@ +{ + "compilerOptions": { + "baseUrl": ".", + "paths": { + "*": ["types/*"] + }, + "module": "commonjs", + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "noImplicitReturns": true, + "noUnusedLocals": true, + "sourceMap": true, + "outDir": "lib", + "rootDir": "src", + "strict": true, + "target": "es2021", + "lib": ["es2021"], + "declaration": true, + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "moduleResolution": "node" + }, + "linterOptions": { + "exclude": [ + "src/plugins/-*/**/*.*", + "src/tests/**/*.*" + ] + }, + "compileOnSave": true, + "include": [ + "src" + ], + "exclude": [ + "node_modules/**", + "src/plugins/*-test*/**/*.*", + "src/plugins/-*/**/*.*", + "src/plugins/service-*/**/*.*", + "src/tests/**/*.*" + ] +} \ No newline at end of file From cefee6a8416b89e9fd01936a5d3d4b40d7aabcc2 Mon Sep 17 00:00:00 2001 From: mrinc Date: Wed, 20 Dec 2023 19:36:23 +0200 Subject: [PATCH 36/47] forcing build --- nodejs/package-lock.json | 2 +- nodejs/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index 05a10f1..f410441 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -15,7 +15,7 @@ "zod": "^3.22.4" }, "bin": { - "bsb": "lib/bootstrap.js" + "bsb": "lib/cli.js" }, "devDependencies": { "@types/assert": "^1.5.10", diff --git a/nodejs/package.json b/nodejs/package.json index 884f61c..92a8b29 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -19,7 +19,7 @@ "testDev": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts'" }, "bin": { - "bsb": "lib/bootstrap.js" + "bsb": "lib/cli.js" }, "files": [ "lib/**/*", From 3fc23f077883904c6b07e4688437d65a0c86f7f0 Mon Sep 17 00:00:00 2001 From: mrinc Date: Fri, 22 Dec 2023 22:03:43 +0200 Subject: [PATCH 37/47] Updated docker build --- .github/workflows/release.yml | 4 +-- nodejs/Dockerfile | 51 +++++++++++++++-------------------- nodejs/entrypoint.sh | 3 +-- 3 files changed, 24 insertions(+), 34 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6482b44..beeb54d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -69,7 +69,7 @@ jobs: file: ./nodejs/Dockerfile #platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x # amd64, arm32v6, arm32v7, arm64v8, ppc64le, s390x - platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8 push: true tags: | betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.tag }} @@ -82,7 +82,7 @@ jobs: builder: ${{ steps.buildx.outputs.name }} context: ./nodejs/ file: ./nodejs/Dockerfile - platforms: linux/386,linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x + platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8 push: true tags: | betterweb/service-base:node \ No newline at end of file diff --git a/nodejs/Dockerfile b/nodejs/Dockerfile index a40fc97..020f392 100644 --- a/nodejs/Dockerfile +++ b/nodejs/Dockerfile @@ -1,8 +1,24 @@ -FROM node:20-bullseye -# RUN npm i -g typescript ts-node +# BSB Build +FROM betterweb/node:20 as builder + +RUN set -eux && mkdir /home/bsb && npm i -g typescript ts-node + +WORKDIR /home/bsb + +ADD tsconfig-release.json /home/bsb/tsconfig-release.json +ADD package.json /home/bsb/package.json +ADD package-lock.json /home/bsb/package-lock.json +ADD src/ /home/bsb/src/ +RUN npm ci +RUN npm run build-release + +# Final image +FROM betterweb/node:20 + +COPY --from=builder /home/bsb/lib /home/bsb/lib +COPY --from=builder /home/bsb/node_modules /home/bsb/node_modules VOLUME /mnt/bsb-plugins -RUN mkdir /home/bsb WORKDIR /home/bsb ENV NODE_ENV production @@ -10,38 +26,13 @@ ENV BSB_LIVE true ENV BSB_CONTAINER true ENV BSB_PLUGIN_DIR /mnt/bsb-plugins -# NPM repo defaults -#RUN pnpm config set auto-install-peers true -#RUN npm init -y -#RUN echo '{"deploymentProfiles":{"default":{}},"plugins":{}}' >> ./sec.config.json -# RUN pushd /mnt/bsb-plugins && npm init -y && pushd - -# Add core BSB lib (from local) ADD package.json /home/bsb/package.json ADD package-lock.json /home/bsb/package-lock.json ADD lib/ /home/bsb/lib/ -#RUN mkdir /home/bsb-build -#COPY *.tgz /home/bsb-build/ COPY entrypoint.sh /root/entrypoint.sh -#COPY entrypoint.js /root/entrypoint.js -#RUN chmod 550 /root/entrypoint.sh - -# Default plugins/setup -#RUN ls -la /home/bsb-build/ -#RUN pnpm add "/home/bsb-build/$(ls /home/bsb-build/ | grep .tgz | head -1)" -# RUN pnpm i --prod --fix-lockfile "/home/bsb-build/$(ls /home/bsb-build/ | grep .tgz | head -1)" -#RUN node ./node_modules/@bettercorp/service-base/postinstall.js --cwd=$(pwd) - -#RUN cat ./package.json - -# Cleanup -#RUN rm -rfv /home/bsb-build -RUN chown -R root:node /home/bsb -RUN chmod -R 650 /home/bsb -RUN touch /home/bsb/sec-config.yaml -RUN chown node:node /home/bsb/sec-config.yaml +RUN addgroup node dialout && touch /home/bsb/sec-config.yaml && chown -R root:node /home/bsb && chmod -R 650 /home/bsb && chown node:node /home/bsb/sec-config.yaml && chmod +x /root/entrypoint.sh && npm ci ENTRYPOINT [ "/root/entrypoint.sh" ] -CMD node node_modules/@bettercorp/service-base/lib/cli.js \ No newline at end of file +CMD node lib/cli.js \ No newline at end of file diff --git a/nodejs/entrypoint.sh b/nodejs/entrypoint.sh index 92249c1..25587c0 100644 --- a/nodejs/entrypoint.sh +++ b/nodejs/entrypoint.sh @@ -7,8 +7,6 @@ # # node ./node_modules/@bettercorp/service-base/postinstall.js --cwd=$(pwd) # fi -addgroup node dialout; - chown -R root:node /home/bsb chmod -R 650 /home/bsb mkdir /home/bsb/.temp @@ -17,4 +15,5 @@ chown node:node /home/bsb/sec-config.yaml chown -R root:node /mnt/bsb-plugins chmod -R 660 /mnt/bsb-plugins +#exec gosu node "$@" exec gosu node "$@" From 38e7ad16f2c4cde07fa3dfbdcc6be9c4a21db502 Mon Sep 17 00:00:00 2001 From: mrinc Date: Fri, 22 Dec 2023 22:19:59 +0200 Subject: [PATCH 38/47] Build updates for nodejs --- .github/workflows/release.yml | 7 +++++-- nodejs/Dockerfile | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index beeb54d..633c936 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -63,6 +63,7 @@ jobs: - name: Build uses: docker/build-push-action@v5 + if: needs.build_nodejs_plugin_release.outputs.tag != 'latest' with: builder: ${{ steps.buildx.outputs.name }} context: ./nodejs/ @@ -75,7 +76,7 @@ jobs: betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.tag }} betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.version }} - - name: Build + - name: Build Latest uses: docker/build-push-action@v5 if: needs.build_nodejs_plugin_release.outputs.tag == 'latest' with: @@ -85,4 +86,6 @@ jobs: platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8 push: true tags: | - betterweb/service-base:node \ No newline at end of file + betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.tag }} + betterweb/service-base:node-${{ needs.build_nodejs_plugin_release.outputs.version }} + betterweb/service-base:node diff --git a/nodejs/Dockerfile b/nodejs/Dockerfile index 020f392..fb709fa 100644 --- a/nodejs/Dockerfile +++ b/nodejs/Dockerfile @@ -32,7 +32,7 @@ ADD lib/ /home/bsb/lib/ COPY entrypoint.sh /root/entrypoint.sh -RUN addgroup node dialout && touch /home/bsb/sec-config.yaml && chown -R root:node /home/bsb && chmod -R 650 /home/bsb && chown node:node /home/bsb/sec-config.yaml && chmod +x /root/entrypoint.sh && npm ci +RUN addgroup node dialout && touch /home/bsb/sec-config.yaml && chown -R root:node /home/bsb && chmod -R 650 /home/bsb && chown node:node /home/bsb/sec-config.yaml && chmod +x /root/entrypoint.sh ENTRYPOINT [ "/root/entrypoint.sh" ] CMD node lib/cli.js \ No newline at end of file From 3027709044c0625d748491e487b5cc1dc925567d Mon Sep 17 00:00:00 2001 From: mrinc Date: Fri, 22 Dec 2023 22:28:18 +0200 Subject: [PATCH 39/47] Updated build scripts for docker --- .github/workflows/release.yml | 30 +++++++++++++++++------------- nodejs/Dockerfile | 11 +++++------ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 633c936..5a158c0 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -29,22 +29,22 @@ jobs: - name: Checkout uses: actions/checkout@v2 - - run: mkdir ./ci-build-dist - working-directory: ./nodejs + # - run: mkdir ./ci-build-dist + # working-directory: ./nodejs - - name: Download artifact - uses: actions/download-artifact@v4 - with: - name: node-${{ needs.build_nodejs_plugin_release.outputs.tag }}-${{ needs.build_nodejs_plugin_release.outputs.version }} - path: ./nodejs/ci-build-dist/ + # - name: Download artifact + # uses: actions/download-artifact@v4 + # with: + # name: node-${{ needs.build_nodejs_plugin_release.outputs.tag }}-${{ needs.build_nodejs_plugin_release.outputs.version }} + # path: ./nodejs/ci-build-dist/ - - name: Extract artifact - working-directory: ./nodejs - run: | - tar -xzf ./ci-build-dist/as-built.tar.gz -C ./ + # - name: Extract artifact + # working-directory: ./nodejs + # run: | + # tar -xzf ./ci-build-dist/as-built.tar.gz -C ./ - - run: rm -rfv ./ci-build-dist - working-directory: ./nodejs + # - run: rm -rfv ./ci-build-dist + # working-directory: ./nodejs - name: Set up QEMU uses: docker/setup-qemu-action@master @@ -65,6 +65,8 @@ jobs: uses: docker/build-push-action@v5 if: needs.build_nodejs_plugin_release.outputs.tag != 'latest' with: + build-args: | + BSB_VERSION=${{ needs.build_nodejs_plugin_release.outputs.version }} builder: ${{ steps.buildx.outputs.name }} context: ./nodejs/ file: ./nodejs/Dockerfile @@ -80,6 +82,8 @@ jobs: uses: docker/build-push-action@v5 if: needs.build_nodejs_plugin_release.outputs.tag == 'latest' with: + build-args: | + BSB_VERSION=${{ needs.build_nodejs_plugin_release.outputs.version }} builder: ${{ steps.buildx.outputs.name }} context: ./nodejs/ file: ./nodejs/Dockerfile diff --git a/nodejs/Dockerfile b/nodejs/Dockerfile index fb709fa..af01806 100644 --- a/nodejs/Dockerfile +++ b/nodejs/Dockerfile @@ -1,6 +1,8 @@ # BSB Build FROM betterweb/node:20 as builder +ARG BSB_VERSION=0.0.0 + RUN set -eux && mkdir /home/bsb && npm i -g typescript ts-node WORKDIR /home/bsb @@ -9,14 +11,15 @@ ADD tsconfig-release.json /home/bsb/tsconfig-release.json ADD package.json /home/bsb/package.json ADD package-lock.json /home/bsb/package-lock.json ADD src/ /home/bsb/src/ -RUN npm ci -RUN npm run build-release +RUN npm ci && npm version $BSB_VERSION --allow-same-version --no-git-tag-version && npm run build-release # Final image FROM betterweb/node:20 COPY --from=builder /home/bsb/lib /home/bsb/lib COPY --from=builder /home/bsb/node_modules /home/bsb/node_modules +COPY --from=builder /home/bsb/package.json /home/bsb/package.json +COPY --from=builder /home/bsb/package-lock.json /home/bsb/package-lock.json VOLUME /mnt/bsb-plugins WORKDIR /home/bsb @@ -26,10 +29,6 @@ ENV BSB_LIVE true ENV BSB_CONTAINER true ENV BSB_PLUGIN_DIR /mnt/bsb-plugins -ADD package.json /home/bsb/package.json -ADD package-lock.json /home/bsb/package-lock.json -ADD lib/ /home/bsb/lib/ - COPY entrypoint.sh /root/entrypoint.sh RUN addgroup node dialout && touch /home/bsb/sec-config.yaml && chown -R root:node /home/bsb && chmod -R 650 /home/bsb && chown node:node /home/bsb/sec-config.yaml && chmod +x /root/entrypoint.sh From ec4dac6d0b5aed4ccc63818e045048ba00e61e42 Mon Sep 17 00:00:00 2001 From: mrinc Date: Fri, 22 Dec 2023 23:21:22 +0200 Subject: [PATCH 40/47] Temp fix for nodejs multi-arch builds - reverting to nodejs 18 for now --- nodejs/Dockerfile | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/nodejs/Dockerfile b/nodejs/Dockerfile index af01806..448ccc7 100644 --- a/nodejs/Dockerfile +++ b/nodejs/Dockerfile @@ -1,5 +1,6 @@ # BSB Build -FROM betterweb/node:20 as builder +# Using 18 until nodejs fixes a bug with v20 - https://github.com/nodejs/docker-node/issues/1829 +FROM betterweb/node:18 as builder ARG BSB_VERSION=0.0.0 @@ -14,7 +15,7 @@ ADD src/ /home/bsb/src/ RUN npm ci && npm version $BSB_VERSION --allow-same-version --no-git-tag-version && npm run build-release # Final image -FROM betterweb/node:20 +FROM betterweb/node:18 COPY --from=builder /home/bsb/lib /home/bsb/lib COPY --from=builder /home/bsb/node_modules /home/bsb/node_modules From 785225fc01b9ee84cf6af0cd7709587481276b23 Mon Sep 17 00:00:00 2001 From: mrinc Date: Fri, 22 Dec 2023 23:22:26 +0200 Subject: [PATCH 41/47] Moving workflows into temp folder while cleanup occurs --- .github/{workflows => _tocleanup}/-build.yml | 0 .github/{workflows => _tocleanup}/-develop.yml | 0 .github/{workflows => _tocleanup}/-master.yml | 0 .github/{workflows => _tocleanup}/-tags.yml | 0 .github/{workflows => _tocleanup}/-updatePlugins.yml | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename .github/{workflows => _tocleanup}/-build.yml (100%) rename .github/{workflows => _tocleanup}/-develop.yml (100%) rename .github/{workflows => _tocleanup}/-master.yml (100%) rename .github/{workflows => _tocleanup}/-tags.yml (100%) rename .github/{workflows => _tocleanup}/-updatePlugins.yml (100%) diff --git a/.github/workflows/-build.yml b/.github/_tocleanup/-build.yml similarity index 100% rename from .github/workflows/-build.yml rename to .github/_tocleanup/-build.yml diff --git a/.github/workflows/-develop.yml b/.github/_tocleanup/-develop.yml similarity index 100% rename from .github/workflows/-develop.yml rename to .github/_tocleanup/-develop.yml diff --git a/.github/workflows/-master.yml b/.github/_tocleanup/-master.yml similarity index 100% rename from .github/workflows/-master.yml rename to .github/_tocleanup/-master.yml diff --git a/.github/workflows/-tags.yml b/.github/_tocleanup/-tags.yml similarity index 100% rename from .github/workflows/-tags.yml rename to .github/_tocleanup/-tags.yml diff --git a/.github/workflows/-updatePlugins.yml b/.github/_tocleanup/-updatePlugins.yml similarity index 100% rename from .github/workflows/-updatePlugins.yml rename to .github/_tocleanup/-updatePlugins.yml From dffd8f72c98b8c5bc21c89837836251e082cafb7 Mon Sep 17 00:00:00 2001 From: mrinc Date: Sat, 23 Dec 2023 00:03:46 +0200 Subject: [PATCH 42/47] Updated entrypoint/docker script --- nodejs/Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nodejs/Dockerfile b/nodejs/Dockerfile index 448ccc7..ff818b8 100644 --- a/nodejs/Dockerfile +++ b/nodejs/Dockerfile @@ -30,9 +30,9 @@ ENV BSB_LIVE true ENV BSB_CONTAINER true ENV BSB_PLUGIN_DIR /mnt/bsb-plugins -COPY entrypoint.sh /root/entrypoint.sh +COPY entrypoint.sh /home/bsb/entrypoint.s RUN addgroup node dialout && touch /home/bsb/sec-config.yaml && chown -R root:node /home/bsb && chmod -R 650 /home/bsb && chown node:node /home/bsb/sec-config.yaml && chmod +x /root/entrypoint.sh -ENTRYPOINT [ "/root/entrypoint.sh" ] -CMD node lib/cli.js \ No newline at end of file +ENTRYPOINT [ "/home/bsb/entrypoint.sh" ] +CMD lib/cli.js \ No newline at end of file From 204225a8dcb67134838d04041ae04e28d8eb30c1 Mon Sep 17 00:00:00 2001 From: mrinc Date: Sat, 23 Dec 2023 00:09:36 +0200 Subject: [PATCH 43/47] Updating build permissions setup --- nodejs/Dockerfile | 4 ++-- nodejs/entrypoint.sh | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/nodejs/Dockerfile b/nodejs/Dockerfile index ff818b8..f0e351b 100644 --- a/nodejs/Dockerfile +++ b/nodejs/Dockerfile @@ -30,9 +30,9 @@ ENV BSB_LIVE true ENV BSB_CONTAINER true ENV BSB_PLUGIN_DIR /mnt/bsb-plugins -COPY entrypoint.sh /home/bsb/entrypoint.s +COPY entrypoint.sh /home/bsb/entrypoint.sh -RUN addgroup node dialout && touch /home/bsb/sec-config.yaml && chown -R root:node /home/bsb && chmod -R 650 /home/bsb && chown node:node /home/bsb/sec-config.yaml && chmod +x /root/entrypoint.sh +RUN addgroup node dialout && chown -R node:node /home/bsb && chmod -R 440 /home/bsb && chmod +x /home/bsb/entrypoint.sh ENTRYPOINT [ "/home/bsb/entrypoint.sh" ] CMD lib/cli.js \ No newline at end of file diff --git a/nodejs/entrypoint.sh b/nodejs/entrypoint.sh index 25587c0..9364361 100644 --- a/nodejs/entrypoint.sh +++ b/nodejs/entrypoint.sh @@ -7,13 +7,13 @@ # # node ./node_modules/@bettercorp/service-base/postinstall.js --cwd=$(pwd) # fi -chown -R root:node /home/bsb -chmod -R 650 /home/bsb +chown -R node:node /home/bsb +chmod -R 440 /home/bsb mkdir /home/bsb/.temp -chmod -R 660 /home/bsb/.temp +chmod -R 440 /home/bsb/.temp chown node:node /home/bsb/sec-config.yaml -chown -R root:node /mnt/bsb-plugins -chmod -R 660 /mnt/bsb-plugins +chown -R node:node /mnt/bsb-plugins +chmod -R 440 /mnt/bsb-plugins #exec gosu node "$@" exec gosu node "$@" From ec89c3d62ae69ed3d34cbbe91585c2aaa961e327 Mon Sep 17 00:00:00 2001 From: mrinc Date: Sat, 23 Dec 2023 11:25:09 +0200 Subject: [PATCH 44/47] Updated docker scripts --- nodejs/Dockerfile | 4 ++-- nodejs/entrypoint.sh | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nodejs/Dockerfile b/nodejs/Dockerfile index f0e351b..8531901 100644 --- a/nodejs/Dockerfile +++ b/nodejs/Dockerfile @@ -32,7 +32,7 @@ ENV BSB_PLUGIN_DIR /mnt/bsb-plugins COPY entrypoint.sh /home/bsb/entrypoint.sh -RUN addgroup node dialout && chown -R node:node /home/bsb && chmod -R 440 /home/bsb && chmod +x /home/bsb/entrypoint.sh +RUN addgroup node dialout && chown -R node:node /home/bsb && chmod -R 440 /home/bsb && chmod 111 /home/bsb/entrypoint.sh ENTRYPOINT [ "/home/bsb/entrypoint.sh" ] -CMD lib/cli.js \ No newline at end of file +CMD - \ No newline at end of file diff --git a/nodejs/entrypoint.sh b/nodejs/entrypoint.sh index 9364361..e43d925 100644 --- a/nodejs/entrypoint.sh +++ b/nodejs/entrypoint.sh @@ -15,5 +15,5 @@ chown node:node /home/bsb/sec-config.yaml chown -R node:node /mnt/bsb-plugins chmod -R 440 /mnt/bsb-plugins -#exec gosu node "$@" -exec gosu node "$@" + +exec gosu node:node lib/cli.js From c9c5c254df40c6096726ec59cfebdeabefe5aab4 Mon Sep 17 00:00:00 2001 From: mrinc Date: Sat, 23 Dec 2023 11:51:13 +0200 Subject: [PATCH 45/47] Fixing file permissions --- nodejs/entrypoint.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/nodejs/entrypoint.sh b/nodejs/entrypoint.sh index e43d925..e2c62f5 100644 --- a/nodejs/entrypoint.sh +++ b/nodejs/entrypoint.sh @@ -7,13 +7,15 @@ # # node ./node_modules/@bettercorp/service-base/postinstall.js --cwd=$(pwd) # fi -chown -R node:node /home/bsb -chmod -R 440 /home/bsb mkdir /home/bsb/.temp -chmod -R 440 /home/bsb/.temp -chown node:node /home/bsb/sec-config.yaml + +chown -R node:node /home/bsb chown -R node:node /mnt/bsb-plugins -chmod -R 440 /mnt/bsb-plugins + +chmod -R 444 /home/bsb +chmod -R 644 /home/bsb/.temp +chmod -R 444 /mnt/bsb-plugins +chmod 600 /home/bsb/sec-config.yaml -exec gosu node:node lib/cli.js +exec gosu node:node node lib/cli.js From a03dba645c54a8d33057095ff7929c00f5e9937c Mon Sep 17 00:00:00 2001 From: mrinc Date: Sat, 23 Dec 2023 12:14:29 +0200 Subject: [PATCH 46/47] Added CMD based debugging. Using CMD instead of an ENV --- nodejs/entrypoint.sh | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/nodejs/entrypoint.sh b/nodejs/entrypoint.sh index e2c62f5..f4504c5 100644 --- a/nodejs/entrypoint.sh +++ b/nodejs/entrypoint.sh @@ -17,5 +17,17 @@ chmod -R 644 /home/bsb/.temp chmod -R 444 /mnt/bsb-plugins chmod 600 /home/bsb/sec-config.yaml - -exec gosu node:node node lib/cli.js +# Check if the first argument is BSBDEBUG for debugging purposes +if [ "$1" = "BSBDEBUG" ]; then + shift + echo "WARNING: RUNNING IN DEBUG MODE" + echo "IN THIS MODE, ANY COMMAND CAN BE RUN" + echo "IT WILL BE RUN AS THE NODE USER" + echo "DO NOT USE IN PRODUCTION" + echo " - THERE WILL BE A 15s DELAY NOW" + sleep 15s + echo " - RUNNING YOUR COMMAND [$@]" + exec gosu node:node "$@" +else + exec gosu node:node node lib/cli.js +fi From 9767049e246e77da40f923478bab9071a12f3f1f Mon Sep 17 00:00:00 2001 From: mrinc Date: Sat, 6 Jan 2024 22:58:16 +0200 Subject: [PATCH 47/47] Uhm... lots of fixes and cleanups More type-safety added Fixed SB client references General fixes/updates other stuff... + cleanups --- .gitignore | 1 + nodejs/.eslintignore | 1 - nodejs/development/tsconfig-release.json | 11 +- nodejs/nodemon.json | 2 +- nodejs/package-lock.json | 3557 ++++++++++++++++- nodejs/package.json | 11 +- nodejs/postinstall.js | 37 - nodejs/src/base/PluginEvents.ts | 68 +- nodejs/src/base/PluginLogger.ts | 5 +- nodejs/src/base/base.ts | 171 +- nodejs/src/base/config.ts | 26 +- nodejs/src/base/errorMessages.ts | 4 +- nodejs/src/base/events.ts | 47 +- nodejs/src/base/functions.ts | 12 +- nodejs/src/base/index.ts | 1 + nodejs/src/base/logFormatter.ts | 2 +- nodejs/src/base/logging.ts | 47 +- nodejs/src/base/pluginConfig.ts | 95 + nodejs/src/base/service.ts | 93 +- nodejs/src/base/serviceClient.ts | 32 +- nodejs/src/base/serviceConfig.ts | 25 - nodejs/src/client.ts | 17 +- nodejs/src/initAppConfig.ts | 25 - nodejs/src/install.ts | 244 -- nodejs/src/interfaces/events.ts | 10 +- nodejs/src/interfaces/index.ts | 1 - nodejs/src/interfaces/plugins.ts | 22 +- .../src/plugins/config-default/interfaces.ts | 2 +- nodejs/src/plugins/config-default/plugin.ts | 24 +- .../events-default/events/broadcast.ts | 4 +- .../src/plugins/events-default/events/emit.ts | 4 +- .../events-default/events/emitAndReturn.ts | 12 +- .../events/emitStreamAndReceiveStream.ts | 4 +- .../plugins/events-default/events/index.ts | 4 + nodejs/src/plugins/events-default/plugin.ts | 15 +- .../plugins/events-test/events/broadcast.ts | 38 + nodejs/src/plugins/events-test/events/emit.ts | 56 + .../events-test/events/emitAndReturn.ts | 62 + .../events/emitStreamAndReceiveStream.ts | 91 + nodejs/src/plugins/events-test/plugin.ts | 96 + nodejs/src/plugins/logging-default/plugin.ts | 12 +- nodejs/src/plugins/service-default0/plugin.ts | 46 +- .../plugins/service-default0/sec-config.ts | 30 - nodejs/src/plugins/service-default1/index.ts | 36 + nodejs/src/plugins/service-default1/plugin.ts | 46 +- nodejs/src/plugins/service-default2/plugin.ts | 6 +- .../plugins/service-default2/sec.config.ts | 19 - nodejs/src/plugins/service-default3/plugin.ts | 6 +- .../plugins/service-default3/sec.config.ts | 19 - nodejs/src/serviceBase/config.ts | 28 +- nodejs/src/serviceBase/events.ts | 11 +- nodejs/src/serviceBase/logging.ts | 33 +- nodejs/src/serviceBase/plugins.ts | 59 +- nodejs/src/serviceBase/serviceBase.ts | 34 +- nodejs/src/serviceBase/services.ts | 39 +- nodejs/src/tests.ts | 1 + nodejs/src/tests/events.x.ts.txt | 91 - nodejs/src/tests/logger.js | 43 - nodejs/src/tests/logger/logFormatter.ts | 42 +- .../tests/plugins/events-default/plugin.ts | 70 + nodejs/src/tests/plugins/events/plugin.ts | 118 - .../plugin.ts | 24 +- .../events => sb/plugins}/events/broadcast.ts | 40 +- .../events => sb/plugins}/events/emit.ts | 20 +- .../plugins}/events/emitAndReturn.ts | 122 +- .../events/emitStreamAndReceiveStream.ts | 27 +- nodejs/src/tests/sb/plugins/events/plugin.ts | 68 + nodejs/src/tests/serviceBase/services.ts | 271 -- nodejs/src/tests/test-logger.ts | 46 - nodejs/src/tests/virt-clientLogger.ts.txt | 34 - nodejs/tsconfig-release.json | 3 +- nodejs/tsconfig.json | 10 +- 72 files changed, 4580 insertions(+), 1853 deletions(-) delete mode 100644 nodejs/postinstall.js create mode 100644 nodejs/src/base/pluginConfig.ts delete mode 100644 nodejs/src/base/serviceConfig.ts delete mode 100644 nodejs/src/initAppConfig.ts delete mode 100644 nodejs/src/install.ts create mode 100644 nodejs/src/plugins/events-default/events/index.ts create mode 100644 nodejs/src/plugins/events-test/events/broadcast.ts create mode 100644 nodejs/src/plugins/events-test/events/emit.ts create mode 100644 nodejs/src/plugins/events-test/events/emitAndReturn.ts create mode 100644 nodejs/src/plugins/events-test/events/emitStreamAndReceiveStream.ts create mode 100644 nodejs/src/plugins/events-test/plugin.ts delete mode 100644 nodejs/src/plugins/service-default0/sec-config.ts create mode 100644 nodejs/src/plugins/service-default1/index.ts delete mode 100644 nodejs/src/plugins/service-default2/sec.config.ts delete mode 100644 nodejs/src/plugins/service-default3/sec.config.ts create mode 100644 nodejs/src/tests.ts delete mode 100644 nodejs/src/tests/events.x.ts.txt delete mode 100644 nodejs/src/tests/logger.js create mode 100644 nodejs/src/tests/plugins/events-default/plugin.ts delete mode 100644 nodejs/src/tests/plugins/events/plugin.ts rename nodejs/src/tests/plugins/{log-default => logging-default}/plugin.ts (95%) rename nodejs/src/tests/{plugins/events => sb/plugins}/events/broadcast.ts (93%) rename nodejs/src/tests/{plugins/events => sb/plugins}/events/emit.ts (92%) rename nodejs/src/tests/{plugins/events => sb/plugins}/events/emitAndReturn.ts (83%) rename nodejs/src/tests/{plugins/events => sb/plugins}/events/emitStreamAndReceiveStream.ts (91%) create mode 100644 nodejs/src/tests/sb/plugins/events/plugin.ts delete mode 100644 nodejs/src/tests/serviceBase/services.ts delete mode 100644 nodejs/src/tests/test-logger.ts delete mode 100644 nodejs/src/tests/virt-clientLogger.ts.txt diff --git a/.gitignore b/.gitignore index 518c726..73cc8a3 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ node_modules /nodejs/.nyc_output /nodejs/lib /nodejs/coverage +/nodejs/development/tsconfig.json /dotnet/[Dd]ebug/ /dotnet/[Dd]ebugPublic/ /dotnet/[Rr]elease/ diff --git a/nodejs/.eslintignore b/nodejs/.eslintignore index e323a2b..fbee89d 100644 --- a/nodejs/.eslintignore +++ b/nodejs/.eslintignore @@ -4,7 +4,6 @@ node_modules lib _exports src/plugins/-*/*.* -src/tests/**/*.* templates docker build \ No newline at end of file diff --git a/nodejs/development/tsconfig-release.json b/nodejs/development/tsconfig-release.json index a224c0f..e879a0c 100644 --- a/nodejs/development/tsconfig-release.json +++ b/nodejs/development/tsconfig-release.json @@ -25,19 +25,14 @@ "moduleResolution": "node" }, "linterOptions": { - "exclude": [ - "src/plugins/-*/**/*.*", - "src/tests/**/*.*" - ] + "exclude": ["src/plugins/-*/**/*.*", "src/tests/**/*.*"] }, "compileOnSave": true, - "include": [ - "src" - ], + "include": ["src"], "exclude": [ "node_modules/**", "src/plugins/*-test*/**/*.*", "src/plugins/-*/**/*.*", "src/tests/**/*.*" ] -} \ No newline at end of file +} diff --git a/nodejs/nodemon.json b/nodejs/nodemon.json index 8e85973..a1e9b31 100644 --- a/nodejs/nodemon.json +++ b/nodejs/nodemon.json @@ -8,7 +8,7 @@ ], "delay": 2000, "signal": "SIGHUP", - "exec": "ts-node src/dev.js", + "exec": "ts-node src/cli.ts", "watch": [ "src/**/*.ts", "sec-config.yaml" diff --git a/nodejs/package-lock.json b/nodejs/package-lock.json index f410441..6924df8 100644 --- a/nodejs/package-lock.json +++ b/nodejs/package-lock.json @@ -18,17 +18,21 @@ "bsb": "lib/cli.js" }, "devDependencies": { + "@ts-ast-parser/core": "^0.6.3", "@types/assert": "^1.5.10", "@types/chai": "^4.3.11", "@types/mocha": "^10.0.6", - "@types/node": "^20.10.5", + "@types/node": "^20.10.6", "@types/yargs": "^17.0.32", "@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/parser": "^6.15.0", "chai": "^4.3.10", "eslint": "^8.56.0", + "install": "^0.13.0", "mocha": "^10.2.0", + "npm": "^10.2.5", "nyc": "^15.1.0", + "ts-morph": "^21.0.1", "ts-node": "^10.9.2", "typescript": "^5.3.3" }, @@ -153,9 +157,9 @@ } }, "node_modules/@babel/core": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.6.tgz", - "integrity": "sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz", + "integrity": "sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -163,10 +167,10 @@ "@babel/generator": "^7.23.6", "@babel/helper-compilation-targets": "^7.23.6", "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.23.6", + "@babel/helpers": "^7.23.7", "@babel/parser": "^7.23.6", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.6", + "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -354,13 +358,13 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.6.tgz", - "integrity": "sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.7.tgz", + "integrity": "sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==", "dev": true, "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.6", + "@babel/traverse": "^7.23.7", "@babel/types": "^7.23.6" }, "engines": { @@ -479,9 +483,9 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.6", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.6.tgz", - "integrity": "sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ==", + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.7.tgz", + "integrity": "sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==", "dev": true, "dependencies": { "@babel/code-frame": "^7.23.5", @@ -599,6 +603,28 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { "version": "8.56.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", @@ -622,6 +648,28 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -832,6 +880,60 @@ "node": ">= 8" } }, + "node_modules/@sindresorhus/merge-streams": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-1.0.0.tgz", + "integrity": "sha512-rUV5WyJrJLoloD4NDN1V1+LDMDWOa4OTsT4yYJwQNpTU6FWxkxHpL7eu4w+DmiH8x/EAM1otkPE1+LaspIbplw==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ts-ast-parser/comment": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@ts-ast-parser/comment/-/comment-0.1.0.tgz", + "integrity": "sha512-SLN5vUMcu0FwhsW7ngVFhwCI9p5r5MGIRT1nGyVKlrXSXMHGcKnU9oulH5Gz9s6epRQooA2TJmU/4hW9z8zy9A==", + "dev": true, + "dependencies": { + "tslib": "^2.6.1" + }, + "engines": { + "node": "^16.0.0 || ^18.0.0 || ^20.0.0" + } + }, + "node_modules/@ts-ast-parser/core": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/@ts-ast-parser/core/-/core-0.6.3.tgz", + "integrity": "sha512-tRBa6eoiAUx/fNIEkxbYLYJlGur1JvKJc/6hGjlILlw9QPo9kS/Ae/dBnSLBkJV8rhOvl33TE1YmQDsNe4PdLg==", + "dev": true, + "dependencies": { + "@ts-ast-parser/comment": "0.1.0", + "globby": "^14.0.0", + "package-json-type": "^1.0.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0" + }, + "peerDependencies": { + "typescript": "^4.6.x || 5.0.x || 5.1.x || 5.2.x || 5.3.x" + } + }, + "node_modules/@ts-morph/common": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.22.0.tgz", + "integrity": "sha512-HqNBuV/oIlMKdkLshXd1zKBqNQCsuPEsgQOkfFQ/eUKjRlwndXW1AjN9LVkBEIukm00gGXSRmfkl0Wv5VXLnlw==", + "dev": true, + "dependencies": { + "fast-glob": "^3.3.2", + "minimatch": "^9.0.3", + "mkdirp": "^3.0.1", + "path-browserify": "^1.0.1" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -881,9 +983,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.10.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", - "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "version": "20.10.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", + "integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -911,16 +1013,16 @@ "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.15.0.tgz", - "integrity": "sha512-j5qoikQqPccq9QoBAupOP+CBu8BaJ8BLjaXSioDISeTZkVO3ig7oSIKh3H+rEpee7xCXtWwSB4KIL5l6hWZzpg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.0.tgz", + "integrity": "sha512-3lqEvQUdCozi6d1mddWqd+kf8KxmGq2Plzx36BlkjuQe3rSTm/O98cLf0A4uDO+a5N1KD2SeEEl6fW97YHY+6w==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.15.0", - "@typescript-eslint/type-utils": "6.15.0", - "@typescript-eslint/utils": "6.15.0", - "@typescript-eslint/visitor-keys": "6.15.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/type-utils": "6.18.0", + "@typescript-eslint/utils": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -946,15 +1048,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.15.0.tgz", - "integrity": "sha512-MkgKNnsjC6QwcMdlNAel24jjkEO/0hQaMDLqP4S9zq5HBAUJNQB6y+3DwLjX7b3l2b37eNAxMPLwb3/kh8VKdA==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.0.tgz", + "integrity": "sha512-v6uR68SFvqhNQT41frCMCQpsP+5vySy6IdgjlzUWoo7ALCnpaWYcz/Ij2k4L8cEsL0wkvOviCMpjmtRtHNOKzA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.15.0", - "@typescript-eslint/types": "6.15.0", - "@typescript-eslint/typescript-estree": "6.15.0", - "@typescript-eslint/visitor-keys": "6.15.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4" }, "engines": { @@ -974,13 +1076,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.15.0.tgz", - "integrity": "sha512-+BdvxYBltqrmgCNu4Li+fGDIkW9n//NrruzG9X1vBzaNK+ExVXPoGB71kneaVw/Jp+4rH/vaMAGC6JfMbHstVg==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.0.tgz", + "integrity": "sha512-o/UoDT2NgOJ2VfHpfr+KBY2ErWvCySNUIX/X7O9g8Zzt/tXdpfEU43qbNk8LVuWUT2E0ptzTWXh79i74PP0twA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.15.0", - "@typescript-eslint/visitor-keys": "6.15.0" + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -991,13 +1093,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.15.0.tgz", - "integrity": "sha512-CnmHKTfX6450Bo49hPg2OkIm/D/TVYV7jO1MCfPYGwf6x3GO0VU8YMO5AYMn+u3X05lRRxA4fWCz87GFQV6yVQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.0.tgz", + "integrity": "sha512-ZeMtrXnGmTcHciJN1+u2CigWEEXgy1ufoxtWcHORt5kGvpjjIlK9MUhzHm4RM8iVy6dqSaZA/6PVkX6+r+ChjQ==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.15.0", - "@typescript-eslint/utils": "6.15.0", + "@typescript-eslint/typescript-estree": "6.18.0", + "@typescript-eslint/utils": "6.18.0", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -1018,9 +1120,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.15.0.tgz", - "integrity": "sha512-yXjbt//E4T/ee8Ia1b5mGlbNj9fB9lJP4jqLbZualwpP2BCQ5is6BcWwxpIsY4XKAhmdv3hrW92GdtJbatC6dQ==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.0.tgz", + "integrity": "sha512-/RFVIccwkwSdW/1zeMx3hADShWbgBxBnV/qSrex6607isYjj05t36P6LyONgqdUrNLl5TYU8NIKdHUYpFvExkA==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -1031,16 +1133,17 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.15.0.tgz", - "integrity": "sha512-7mVZJN7Hd15OmGuWrp2T9UvqR2Ecg+1j/Bp1jXUEY2GZKV6FXlOIoqVDmLpBiEiq3katvj/2n2mR0SDwtloCew==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.0.tgz", + "integrity": "sha512-klNvl+Ql4NsBNGB4W9TZ2Od03lm7aGvTbs0wYaFYsplVPhr+oeXjlPZCDI4U9jgJIDK38W1FKhacCFzCC+nbIg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.15.0", - "@typescript-eslint/visitor-keys": "6.15.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/visitor-keys": "6.18.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", + "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" }, @@ -1057,18 +1160,47 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/@typescript-eslint/utils": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.15.0.tgz", - "integrity": "sha512-eF82p0Wrrlt8fQSRL0bGXzK5nWPRV2dYQZdajcfzOD9+cQz9O7ugifrJxclB+xVOvWvagXfqS4Es7vpLP4augw==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.0.tgz", + "integrity": "sha512-wiKKCbUeDPGaYEYQh1S580dGxJ/V9HI7K5sbGAVklyf+o5g3O+adnS4UNJajplF4e7z2q0uVBaTdT/yLb4XAVA==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@types/json-schema": "^7.0.12", "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.15.0", - "@typescript-eslint/types": "6.15.0", - "@typescript-eslint/typescript-estree": "6.15.0", + "@typescript-eslint/scope-manager": "6.18.0", + "@typescript-eslint/types": "6.18.0", + "@typescript-eslint/typescript-estree": "6.18.0", "semver": "^7.5.4" }, "engines": { @@ -1083,12 +1215,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.15.0.tgz", - "integrity": "sha512-1zvtdC1a9h5Tb5jU9x3ADNXO9yjP8rXlaoChu0DQX40vf5ACVpYIVIZhIMZ6d5sDXH7vq4dsZBT1fEGj8D2n2w==", + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.0.tgz", + "integrity": "sha512-1wetAlSZpewRDb2h9p/Q8kRjdGuqdTAQbkJIOUMLug2LBLG+QOjiWoSj6/3B/hA9/tVTFFdtiKvAYoYnSRW/RA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.15.0", + "@typescript-eslint/types": "6.18.0", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -1106,9 +1238,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", - "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1272,13 +1404,12 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -1365,9 +1496,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001570", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz", - "integrity": "sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw==", + "version": "1.0.30001574", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001574.tgz", + "integrity": "sha512-BtYEK4r/iHt/txm81KBudCUcTy7t+s9emrIaHqjYurQ10x71zJ5VQ9x1dYPcz/b+pKSp4y/v1xSI67A+LzpNyg==", "dev": true, "funding": [ { @@ -1385,9 +1516,9 @@ ] }, "node_modules/chai": { - "version": "4.3.10", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.3.10.tgz", - "integrity": "sha512-0UXG04VuVbruMUYbJ6JctvH0YnC/4q3/AkT18q4NaITo91CUm0liMS9VqzT9vZhVQ/1eqPanMWjBM+Juhfb/9g==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.0.tgz", + "integrity": "sha512-x9cHNq1uvkCdU+5xTkNh5WtgD4e4yDFCsp9jVc7N7qVeKeftv3gO/ZrviX5d+3ZfxdYnZXZYujjRInu1RogU6A==", "dev": true, "dependencies": { "assertion-error": "^1.1.0", @@ -1491,6 +1622,12 @@ "node": ">=12" } }, + "node_modules/code-block-writer": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-12.0.0.tgz", + "integrity": "sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w==", + "dev": true + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1625,6 +1762,15 @@ "node": ">=8" } }, + "node_modules/dir-glob/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -1638,9 +1784,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.615", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.615.tgz", - "integrity": "sha512-/bKPPcgZVUziECqDc+0HkT87+0zhaWSZHNXqF8FLd2lQcptpmUFwoCSWjCdOng9Gdq+afKArPdEg/0ZW461Eng==", + "version": "1.4.623", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.623.tgz", + "integrity": "sha512-lKoz10iCYlP1WtRYdh5MvocQPWVRoI7ysp6qf18bmeBgR8abE6+I2CsfyNKztRDZvhdWc+krKT6wS7Neg8sw3A==", "dev": true }, "node_modules/emoji-regex": { @@ -1757,6 +1903,28 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -2090,6 +2258,28 @@ "node": ">=10.13.0" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -2106,20 +2296,20 @@ } }, "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.0.tgz", + "integrity": "sha512-/1WM/LNHRAOH9lZta77uGbq0dAEQM+XjNesWwhlERDVenqothRbnzTrL3/LrIoEPPjeUHC3vrS6TwoyxeHs7MQ==", "dev": true, "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "@sindresorhus/merge-streams": "^1.0.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -2245,6 +2435,15 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/install": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/install/-/install-0.13.0.tgz", + "integrity": "sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-binary-path": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", @@ -2677,15 +2876,33 @@ } }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/mocha": { @@ -2728,15 +2945,6 @@ "url": "https://opencollective.com/mochajs" } }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/mocha/node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -2850,73 +3058,3040 @@ "node": ">=0.10.0" } }, - "node_modules/nyc": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", - "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "node_modules/npm": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.2.5.tgz", + "integrity": "sha512-lXdZ7titEN8CH5YJk9C/aYRU9JeDxQ4d8rwIIDsvH3SMjLjHTukB2CFstMiB30zXs4vCrPN2WH6cDq1yHBeJAw==", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/config", + "@npmcli/fs", + "@npmcli/map-workspaces", + "@npmcli/package-json", + "@npmcli/promise-spawn", + "@npmcli/run-script", + "@sigstore/tuf", + "abbrev", + "archy", + "cacache", + "chalk", + "ci-info", + "cli-columns", + "cli-table3", + "columnify", + "fastest-levenshtein", + "fs-minipass", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmhook", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minimatch", + "minipass", + "minipass-pipeline", + "ms", + "node-gyp", + "nopt", + "normalize-package-data", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "npmlog", + "p-map", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "semver", + "spdx-expression-parse", + "ssri", + "strip-ansi", + "supports-color", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which", + "write-file-atomic" + ], "dev": true, "dependencies": { - "@istanbuljs/load-nyc-config": "^1.0.0", - "@istanbuljs/schema": "^0.1.2", - "caching-transform": "^4.0.0", - "convert-source-map": "^1.7.0", - "decamelize": "^1.2.0", - "find-cache-dir": "^3.2.0", - "find-up": "^4.1.0", - "foreground-child": "^2.0.0", - "get-package-type": "^0.1.0", - "glob": "^7.1.6", - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-hook": "^3.0.0", - "istanbul-lib-instrument": "^4.0.0", - "istanbul-lib-processinfo": "^2.0.2", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^4.0.0", - "istanbul-reports": "^3.0.2", - "make-dir": "^3.0.0", - "node-preload": "^0.2.1", - "p-map": "^3.0.0", - "process-on-spawn": "^1.0.0", - "resolve-from": "^5.0.0", - "rimraf": "^3.0.0", - "signal-exit": "^3.0.2", - "spawn-wrap": "^2.0.0", - "test-exclude": "^6.0.0", - "yargs": "^15.0.2" + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^7.2.1", + "@npmcli/config": "^8.0.2", + "@npmcli/fs": "^3.1.0", + "@npmcli/map-workspaces": "^3.0.4", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.2", + "@sigstore/tuf": "^2.2.0", + "abbrev": "^2.0.0", + "archy": "~1.0.0", + "cacache": "^18.0.1", + "chalk": "^5.3.0", + "ci-info": "^4.0.0", + "cli-columns": "^4.0.0", + "cli-table3": "^0.6.3", + "columnify": "^1.6.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^7.0.1", + "ini": "^4.1.1", + "init-package-json": "^6.0.0", + "is-cidr": "^5.0.3", + "json-parse-even-better-errors": "^3.0.1", + "libnpmaccess": "^8.0.1", + "libnpmdiff": "^6.0.3", + "libnpmexec": "^7.0.4", + "libnpmfund": "^5.0.1", + "libnpmhook": "^10.0.0", + "libnpmorg": "^6.0.1", + "libnpmpack": "^6.0.3", + "libnpmpublish": "^9.0.2", + "libnpmsearch": "^7.0.0", + "libnpmteam": "^6.0.0", + "libnpmversion": "^5.0.1", + "make-fetch-happen": "^13.0.0", + "minimatch": "^9.0.3", + "minipass": "^7.0.4", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^10.0.1", + "nopt": "^7.2.0", + "normalize-package-data": "^6.0.0", + "npm-audit-report": "^5.0.0", + "npm-install-checks": "^6.3.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-profile": "^9.0.0", + "npm-registry-fetch": "^16.1.0", + "npm-user-validate": "^2.0.0", + "npmlog": "^7.0.1", + "p-map": "^4.0.0", + "pacote": "^17.0.5", + "parse-conflict-json": "^3.0.1", + "proc-log": "^3.0.0", + "qrcode-terminal": "^0.12.0", + "read": "^2.1.0", + "semver": "^7.5.4", + "spdx-expression-parse": "^3.0.1", + "ssri": "^10.0.5", + "strip-ansi": "^7.1.0", + "supports-color": "^9.4.0", + "tar": "^6.2.0", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^5.0.0", + "which": "^4.0.0", + "write-file-atomic": "^5.0.1" }, "bin": { - "nyc": "bin/nyc.js" + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" }, "engines": { - "node": ">=8.9" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/nyc/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "node_modules/npm/node_modules/@colors/colors": { + "version": "1.5.0", "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" } }, - "node_modules/nyc/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/npm/node_modules/@isaacs/cliui": { + "version": "8.0.2", "dev": true, + "inBundle": true, + "license": "ISC", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/nyc/node_modules/locate-path": { - "version": "5.0.0", + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/agent": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "7.2.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^3.1.0", + "@npmcli/installed-package-contents": "^2.0.2", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^7.0.0", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/query": "^3.0.1", + "@npmcli/run-script": "^7.0.2", + "bin-links": "^4.0.1", + "cacache": "^18.0.0", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^7.0.1", + "json-parse-even-better-errors": "^3.0.0", + "json-stringify-nice": "^1.1.4", + "minimatch": "^9.0.0", + "nopt": "^7.0.0", + "npm-install-checks": "^6.2.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^1.0.2", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^10.0.5", + "treeverse": "^3.0.0", + "walk-up-path": "^3.0.1" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/config": { + "version": "8.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/map-workspaces": "^3.0.2", + "ci-info": "^4.0.0", + "ini": "^4.1.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.5", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/disparity-colors": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ansi-styles": "^4.3.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/disparity-colors/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "5.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cacache": "^18.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^17.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/query": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^6.0.10" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/@sigstore/bundle": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/protobuf-specs": { + "version": "0.2.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/sign": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/tuf": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.1", + "tuf-js": "^2.1.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tufjs/models": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/abort-controller": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/npm/node_modules/agent-base": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/aggregate-error": { + "version": "3.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ansi-regex": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/npm/node_modules/ansi-styles": { + "version": "6.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/are-we-there-yet": { + "version": "4.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^4.1.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/base64-js": { + "version": "1.5.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/bin-links": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/binary-extensions": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm/node_modules/buffer": { + "version": "6.0.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/npm/node_modules/builtins": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/npm/node_modules/cacache": { + "version": "18.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/chalk": { + "version": "5.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ci-info": { + "version": "4.0.0", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "4.0.3", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "ip-regex": "^5.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/clean-stack": { + "version": "2.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/cli-columns": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/npm/node_modules/cli-columns/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cli-columns/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cli-table3": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/npm/node_modules/clone": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/color-convert": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/npm/node_modules/color-name": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/color-support": { + "version": "1.1.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/npm/node_modules/columnify": { + "version": "1.6.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/npm/node_modules/columnify/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/columnify/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/console-control-strings": { + "version": "1.1.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/cross-spawn": { + "version": "7.0.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/debug": { + "version": "4.3.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/defaults": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/delegates": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/diff": { + "version": "5.1.0", + "dev": true, + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/npm/node_modules/eastasianwidth": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/emoji-regex": { + "version": "8.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/encoding": { + "version": "0.1.13", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/err-code": { + "version": "2.0.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/event-target-shim": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/events": { + "version": "3.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/npm/node_modules/foreground-child": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/function-bind": { + "version": "1.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/npm/node_modules/gauge": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^4.0.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "10.3.10", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.11", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/has-unicode": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/hasown": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "7.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm/node_modules/ieee754": { + "version": "1.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "6.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/npm/node_modules/indent-string": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ini": { + "version": "4.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^11.0.0", + "promzard": "^1.0.0", + "read": "^2.0.0", + "read-package-json": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/ip": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/ip-regex": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "5.0.3", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "cidr-regex": "4.0.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/npm/node_modules/is-core-module": { + "version": "2.13.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/npm/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/is-lambda": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/isexe": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/jackspeak": { + "version": "2.3.6", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "dev": true, + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "5.5.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "6.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/disparity-colors": "^3.0.0", + "@npmcli/installed-package-contents": "^2.0.2", + "binary-extensions": "^2.2.0", + "diff": "^5.1.0", + "minimatch": "^9.0.0", + "npm-package-arg": "^11.0.1", + "pacote": "^17.0.4", + "tar": "^6.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmexec": { + "version": "7.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/run-script": "^7.0.2", + "ci-info": "^4.0.0", + "npm-package-arg": "^11.0.1", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "proc-log": "^3.0.0", + "read": "^2.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "walk-up-path": "^3.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmfund": { + "version": "5.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^7.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmhook": { + "version": "10.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "6.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmpack": { + "version": "6.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/run-script": "^7.0.2", + "npm-package-arg": "^11.0.1", + "pacote": "^17.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "9.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ci-info": "^4.0.0", + "normalize-package-data": "^6.0.0", + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7", + "sigstore": "^2.1.0", + "ssri": "^10.0.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/libnpmversion": { + "version": "5.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^5.0.3", + "@npmcli/run-script": "^7.0.2", + "json-parse-even-better-errors": "^3.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "10.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "13.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "9.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/minipass": { + "version": "7.0.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-collect": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-json-stream": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/npm/node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized": { + "version": "1.0.3", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minizlib": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/mkdirp": { + "version": "1.0.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/negotiator": { + "version": "0.6.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "10.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "7.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/normalize-package-data": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-audit-report": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "6.3.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "11.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "8.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^6.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "9.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "16.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npmlog": { + "version": "7.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "are-we-there-yet": "^4.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^5.0.0", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/p-map": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/pacote": { + "version": "17.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/path-key": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/path-scurry": { + "version": "1.10.1", + "dev": true, + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/postcss-selector-parser": { + "version": "6.0.13", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/proc-log": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/process": { + "version": "0.11.10", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-call-limit": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-inflight": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/promise-retry": { + "version": "2.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "1.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~1.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/read-package-json": { + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/read-package-json-fast": { + "version": "3.0.2", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/readable-stream": { + "version": "4.4.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm/node_modules/safe-buffer": { + "version": "5.2.1", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/npm/node_modules/semver": { + "version": "7.5.4", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/set-blocking": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/shebang-command": { + "version": "2.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/shebang-regex": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "4.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/sigstore": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/sign": "^2.1.0", + "@sigstore/tuf": "^2.1.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.7.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "8.0.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/spdx-correct": { + "version": "3.2.0", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.3.0", + "dev": true, + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.16", + "dev": true, + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/ssri": { + "version": "10.0.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/string_decoder": { + "version": "1.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/npm/node_modules/string-width": { + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/strip-ansi": { + "version": "7.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/supports-color": { + "version": "9.4.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "6.2.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "1.3.0", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/treeverse": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/tuf-js": { + "version": "2.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/unique-filename": { + "version": "3.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/unique-slug": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/validate-npm-package-license": { + "version": "3.0.4", + "dev": true, + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "5.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/walk-up-path": { + "version": "3.0.1", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/wcwidth": { + "version": "1.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/npm/node_modules/which": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/npm/node_modules/wide-align": { + "version": "1.1.5", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/npm/node_modules/wrap-ansi": { + "version": "8.1.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "dev": true, + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/write-file-atomic": { + "version": "5.0.1", + "dev": true, + "inBundle": true, + "license": "ISC", + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/yallist": { + "version": "4.0.0", + "dev": true, + "inBundle": true, + "license": "ISC" + }, + "node_modules/nyc": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/nyc/-/nyc-15.1.0.tgz", + "integrity": "sha512-jMW04n9SxKdKi1ZMGhvUTHBN0EICCRkHemEoE5jm6mTYcqcdas0ATzgUgejlQUHMvpnOZqGB5Xxsv9KxJW1j8A==", + "dev": true, + "dependencies": { + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "caching-transform": "^4.0.0", + "convert-source-map": "^1.7.0", + "decamelize": "^1.2.0", + "find-cache-dir": "^3.2.0", + "find-up": "^4.1.0", + "foreground-child": "^2.0.0", + "get-package-type": "^0.1.0", + "glob": "^7.1.6", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-hook": "^3.0.0", + "istanbul-lib-instrument": "^4.0.0", + "istanbul-lib-processinfo": "^2.0.2", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "make-dir": "^3.0.0", + "node-preload": "^0.2.1", + "p-map": "^3.0.0", + "process-on-spawn": "^1.0.0", + "resolve-from": "^5.0.0", + "rimraf": "^3.0.0", + "signal-exit": "^3.0.2", + "spawn-wrap": "^2.0.0", + "test-exclude": "^6.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "nyc": "bin/nyc.js" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/nyc/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/nyc/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nyc/node_modules/locate-path": { + "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, @@ -3110,6 +6285,12 @@ "node": ">=8" } }, + "node_modules/package-json-type": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/package-json-type/-/package-json-type-1.0.3.tgz", + "integrity": "sha512-Bey4gdRuOwDbS8Fj1qA3/pTq5r8pqiI5E3tjSqCdhaLSsyGG364VFzXLTIexN5AaNGe/vgdBzLfoKdr7EVg2KQ==", + "dev": true + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3122,6 +6303,12 @@ "node": ">=6" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -3150,12 +6337,15 @@ } }, "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/pathval": { @@ -3499,12 +6689,15 @@ "dev": true }, "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", "dev": true, "engines": { - "node": ">=8" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/source-map": { @@ -3610,6 +6803,28 @@ "node": ">=8" } }, + "node_modules/test-exclude/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/test-exclude/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -3649,6 +6864,16 @@ "typescript": ">=4.2.0" } }, + "node_modules/ts-morph": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-21.0.1.tgz", + "integrity": "sha512-dbDtVdEAncKctzrVZ+Nr7kHpHkv+0JDJb2MjjpBaj8bFeCkePU9rHfMklmhuLFnpeq/EJZk2IhStY6NzqgjOkg==", + "dev": true, + "dependencies": { + "@ts-morph/common": "~0.22.0", + "code-block-writer": "^12.0.0" + } + }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", @@ -3701,6 +6926,12 @@ "node": ">=0.3.1" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -3762,6 +6993,18 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", diff --git a/nodejs/package.json b/nodejs/package.json index 92a8b29..647ccbc 100644 --- a/nodejs/package.json +++ b/nodejs/package.json @@ -12,8 +12,8 @@ "dev": "nodemon --config ./nodemon.json", "start": "node lib/cli.js", "build": "rm -rfv ./lib && tsc && npm run testDev", - "build-release": "rm -rfv ./lib && tsc --p ./tsconfig-release.json", - "xZpostinstall": "node ./postinstall.js", + "build-release": "rm -rfv ./lib && tsc --p ./tsconfig-release.json && npm run build-release-tsconfig", + "build-release-tsconfig": "rm -fv ./development/tsconfig.json && cp ./tsconfig.json ./development/tsconfig.json", "lint": "eslint src/ --ext .js,.jsx,.ts,.tsx", "test": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js --reporter json --reporter lcov ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts' --reporter json --reporter-options output=junit.json", "testDev": "env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\" }' node ./node_modules/nyc/bin/nyc.js ./node_modules/mocha/bin/mocha.js -r ts-node/register 'src/tests/**/*.ts'" @@ -24,7 +24,6 @@ "files": [ "lib/**/*", "development/**/*", - "tsconfig.json", "README.md", "LICENSE" ], @@ -98,17 +97,21 @@ ] }, "devDependencies": { + "@ts-ast-parser/core": "^0.6.3", "@types/assert": "^1.5.10", "@types/chai": "^4.3.11", "@types/mocha": "^10.0.6", - "@types/node": "^20.10.5", + "@types/node": "^20.10.6", "@types/yargs": "^17.0.32", "@typescript-eslint/eslint-plugin": "^6.15.0", "@typescript-eslint/parser": "^6.15.0", "chai": "^4.3.10", "eslint": "^8.56.0", + "install": "^0.13.0", "mocha": "^10.2.0", + "npm": "^10.2.5", "nyc": "^15.1.0", + "ts-morph": "^21.0.1", "ts-node": "^10.9.2", "typescript": "^5.3.3" }, diff --git a/nodejs/postinstall.js b/nodejs/postinstall.js deleted file mode 100644 index 378ede0..0000000 --- a/nodejs/postinstall.js +++ /dev/null @@ -1,37 +0,0 @@ -const fs = require("fs"); -const path = require("path"); -const process = require("process"); - -if (`${process.env.BSB_CONTAINER || ''}` !== '') return console.warn('Building in BSB container, not running default setup process.'); - -let cwd = process.cwd(); -let hardSetCWD = false; - -for (let argv of process.argv) { - if (argv.indexOf("--cwd=") === 0) { - cwd = argv.split("=")[1].trim(); - hardSetCWD = true; - } -} - -console.log("BSB Post Install: " + cwd); -if (fs.existsSync(path.join(cwd, "./.bsb.local"))) { - console.log("BSB Post Install: Ignore"); -} else { - console.log("BSB Post Install: Run"); - if (cwd.indexOf("/node_modules/") > 0 && hardSetCWD === false) { - console.log("BSB Post Install: Search - we`re in node_modules dir."); - const argSpl = cwd.indexOf('/') >= 0 ? '/' : '\\'; - cwd = cwd.split(`${argSpl}node_modules${argSpl}`)[0]; - console.log("BSB Post Install: Try " + cwd); - } - const bsbBase = path.join(cwd, "./node_modules/@bettercorp/service-base"); - if (!fs.existsSync(bsbBase)) { - console.log("BSB Post Install: Bypass - cannot find service-base."); - process.exit(0); - } - const installer = require(path.join(bsbBase, "./lib/postinstall.js")).default; - //console.log(fs.readdirSync("./build/")); - installer(cwd); - console.log("BSB Post Install: Complete"); -} diff --git a/nodejs/src/base/PluginEvents.ts b/nodejs/src/base/PluginEvents.ts index ce69d84..56f2c68 100644 --- a/nodejs/src/base/PluginEvents.ts +++ b/nodejs/src/base/PluginEvents.ts @@ -1,15 +1,23 @@ import { Readable } from "stream"; +import { DynamicallyReferencedMethodType } from "@bettercorp/tools/lib/Interfaces"; +import { BSBService, BSBServiceClient } from "./index"; import { - DynamicallyReferencedMethodEmitEARIEvents, - DynamicallyReferencedMethodEmitIEvents, + ServiceEventsBase, + DEBUG_MODE, DynamicallyReferencedMethodOnIEvents, -} from "../interfaces/events"; -import { ServiceEventsBase } from "../interfaces/service"; -import { DEBUG_MODE } from "../interfaces/logging"; -import { DynamicallyReferencedMethodType } from "@bettercorp/tools/lib/Interfaces"; -import { SBEvents } from "../serviceBase/events"; -import { BSBService } from "./service"; -import { BSBServiceClient } from "./serviceClient"; + DynamicallyReferencedMethodEmitIEvents, + DynamicallyReferencedMethodEmitEARIEvents, +} from "../interfaces"; +import { SBEvents } from "../serviceBase"; + +export abstract class BSBPluginEvents { + public abstract onEvents: ServiceEventsBase; + public abstract emitEvents: ServiceEventsBase; + public abstract onReturnableEvents: ServiceEventsBase; + public abstract emitReturnableEvents: ServiceEventsBase; + public abstract onBroadcast: ServiceEventsBase; + public abstract emitBroadcast: ServiceEventsBase; +} export class PluginEvents< onEvents = ServiceEventsBase, @@ -20,11 +28,11 @@ export class PluginEvents< emitBroadcast = ServiceEventsBase > { private events: SBEvents; - private service: BSBService | BSBServiceClient; + private service: BSBService | BSBServiceClient; constructor( mode: DEBUG_MODE, events: SBEvents, - context: BSBService | BSBServiceClient + context: BSBService | BSBServiceClient ) { this.events = events; this.service = context; @@ -49,7 +57,7 @@ export class PluginEvents< * }); * ``` */ - public async onBroadcast( + public async onBroadcast( ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, TA, @@ -82,7 +90,7 @@ export class PluginEvents< * /// Do something with the data * }); */ - async emitBroadcast( + async emitBroadcast( ...args: DynamicallyReferencedMethodEmitIEvents< DynamicallyReferencedMethodType, TA @@ -110,7 +118,7 @@ export class PluginEvents< * /// Do something with the data * }); */ - public async onEvent( + public async onEvent( ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, TA, @@ -143,7 +151,7 @@ export class PluginEvents< * /// Do something with the data * }); */ - public async emitEvent( + public async emitEvent( ...args: DynamicallyReferencedMethodEmitIEvents< DynamicallyReferencedMethodType, TA @@ -173,7 +181,7 @@ export class PluginEvents< * /// Do something with the data * }); */ - public async onEventSpecific( + public async onEventSpecific( serverId: string, ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, @@ -210,7 +218,7 @@ export class PluginEvents< * /// Do something with the data * }); */ - public async emitEventSpecific( + public async emitEventSpecific( serverId: string, ...args: DynamicallyReferencedMethodEmitIEvents< DynamicallyReferencedMethodType, @@ -246,7 +254,7 @@ export class PluginEvents< * return 'some result'; * }); */ - public async onReturnableEvent( + public async onReturnableEvent( ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, TA, @@ -280,7 +288,7 @@ export class PluginEvents< * return 'some result'; * }); */ - public async emitEventAndReturn( + public async emitEventAndReturn( ...args: DynamicallyReferencedMethodEmitEARIEvents< DynamicallyReferencedMethodType, TA, @@ -289,7 +297,7 @@ export class PluginEvents< > ): Promise< DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, + DynamicallyReferencedMethodType, TA, false > @@ -326,7 +334,7 @@ export class PluginEvents< * return 'some result'; * }); */ - public async onReturnableEventSpecific( + public async onReturnableEventSpecific( serverId: string, ...args: DynamicallyReferencedMethodOnIEvents< DynamicallyReferencedMethodType, @@ -364,7 +372,9 @@ export class PluginEvents< * return 'some result'; * }); */ - public async emitEventAndReturnSpecific( + public async emitEventAndReturnSpecific< + TA extends keyof emitReturnableEvents + >( serverId: string, ...args: DynamicallyReferencedMethodEmitEARIEvents< DynamicallyReferencedMethodType, @@ -374,7 +384,7 @@ export class PluginEvents< > ): Promise< DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, + DynamicallyReferencedMethodType, TA, false > @@ -474,3 +484,15 @@ export class PluginEvents< ); } } + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBPluginEventsRef extends BSBPluginEvents { + public onEvents: ServiceEventsBase = {}; + public emitEvents: ServiceEventsBase = {}; + public onReturnableEvents: ServiceEventsBase = {}; + public emitReturnableEvents: ServiceEventsBase = {}; + public onBroadcast: ServiceEventsBase = {}; + public emitBroadcast: ServiceEventsBase = {}; +} diff --git a/nodejs/src/base/PluginLogger.ts b/nodejs/src/base/PluginLogger.ts index 82b1862..0b33140 100644 --- a/nodejs/src/base/PluginLogger.ts +++ b/nodejs/src/base/PluginLogger.ts @@ -1,6 +1,5 @@ -import { DEBUG_MODE, SmartLogMeta } from "../interfaces/logging"; -import { IPluginLogger } from "../interfaces/logging"; -import { SBLogging } from "../serviceBase/logging"; +import { SBLogging } from "../serviceBase"; +import { DEBUG_MODE, SmartLogMeta, IPluginLogger } from "../interfaces"; export class PluginLogger implements IPluginLogger { private logging: SBLogging; diff --git a/nodejs/src/base/base.ts b/nodejs/src/base/base.ts index 86ffd2b..5a5f228 100644 --- a/nodejs/src/base/base.ts +++ b/nodejs/src/base/base.ts @@ -1,9 +1,14 @@ -import { DEBUG_MODE, IPluginLogger } from "../interfaces/logging"; -import { PluginLogger } from "./PluginLogger"; -import { SBLogging } from "../serviceBase/logging"; -import { z } from "zod"; -import { BSBServiceConfig } from "./serviceConfig"; - +import { DEBUG_MODE, IPluginLogger } from "../interfaces"; +import { SBLogging } from "../serviceBase"; +import { BSBReferenceConfigType, PluginLogger } from "./index"; + +export interface MainBaseConfig { + appId: string; + mode: DEBUG_MODE; + pluginName: string; + cwd: string; + pluginCwd: string; +} export abstract class MainBase { /** * The unique app id of the app that is running @@ -35,18 +40,12 @@ export abstract class MainBase { */ public readonly pluginName!: string; - constructor( - appId: string, - mode: DEBUG_MODE, - pluginName: string, - cwd: string, - pluginCwd: string - ) { - this.appId = appId; - this.mode = mode; - if (pluginName !== "") this.pluginName = pluginName; - this.cwd = cwd; - this.pluginCwd = pluginCwd; + constructor(config: MainBaseConfig) { + this.appId = config.appId; + this.mode = config.mode; + if (config.pluginName !== "") this.pluginName = config.pluginName; + this.cwd = config.cwd; + this.pluginCwd = config.pluginCwd; } /** @@ -60,14 +59,8 @@ export abstract class MainBase { } export abstract class Base extends MainBase { - constructor( - appId: string, - mode: DEBUG_MODE, - pluginName: string, - cwd: string, - pluginCwd: string - ) { - super(appId, mode, pluginName, cwd, pluginCwd); + constructor(config: MainBaseConfig) { + super(config); } /** @@ -102,113 +95,81 @@ export abstract class Base extends MainBase { abstract run?(): Promise | void; } -/** - * The definition of the config with zod validation - * @example - * const configDefinition = z.object({ - * a: z.string(), - * }); - */ -export type BSBConfigType = z.ZodTypeAny | undefined; -export type BSBConfigDefinition = BSBServiceConfig; -/** - * Config migration handler, allows for config migrations when the plugin version changes or a new plugin setup is done - * @example simple version change and basic setup - * const configMigration = async (versionFrom: string | null, versionTo: string, existingConfig?: z.infer) => { - * if (versionFrom === null) { - * return { - * a: "a", - * }; - * } - * return { - * a: "b", - * }; - * @example basic setup and no version change handling - * const configMigration = async (versionFrom: string | null, versionTo: string, existingConfig?: z.infer) => { - * if (versionFrom === null || existingConfig === undefined) { - * return { - * a: "a", - * }; - * } - * return existingConfig; - */ -export type BSBConfigMigration = ( - versionFrom: string | null, - versionTo: string, - existingConfig?: z.infer> -) => Promise>>; - -export type BSBConfigDefintionReference< - T extends BSBConfigType, - AS = undefined -> = T extends undefined ? AS : z.infer>; +export type ConfigPropertyTypeSafe< + ReferencedConfig extends BSBReferenceConfigType +> = ReferencedConfig extends undefined + ? undefined + : ReferencedConfig extends null + ? undefined + : ReferencedConfig; + +export interface BaseWithConfigConfig< + ReferencedConfig extends BSBReferenceConfigType +> extends MainBaseConfig { + config: ConfigPropertyTypeSafe; +} // used by logging plugins (does not need events or logging since logging logs its own logs) export abstract class BaseWithConfig< - ReferencedConfig extends BSBConfigDefinition + ReferencedConfig extends BSBReferenceConfigType > extends Base { /** * The config of the plugin * @type {PluginConfig} * @readonly */ - protected readonly config: BSBConfigDefintionReference< - ReferencedConfig["validationSchema"], - null - >; - - constructor( - appId: string, - mode: DEBUG_MODE, - pluginName: string, - cwd: string, - pluginCwd: string, - config: any - ) { - super(appId, mode, pluginName, cwd, pluginCwd); - this.config = config; + protected readonly config: ConfigPropertyTypeSafe; + + constructor(config: BaseWithConfigConfig) { + super(config); + this.config = config.config; } } +export interface BaseWithLoggingConfig extends MainBaseConfig { + sbLogging: SBLogging; +} // used by config plugins (does not need events) export abstract class BaseWithLogging extends Base { protected log: IPluginLogger; //protected createNewLogger: { (plugin: string): IPluginLogger }; - constructor( - appId: string, - mode: DEBUG_MODE, - pluginName: string, - cwd: string, - pluginCwd: string, - sbLogging: SBLogging - ) { - super(appId, mode, pluginName, cwd, pluginCwd); - this.log = new PluginLogger(mode, pluginName, sbLogging); + constructor(config: BaseWithLoggingConfig) { + super(config); + this.log = new PluginLogger( + config.mode, + config.pluginName, + config.sbLogging + ); /*this.createNewLogger = (plugin: string) => new PluginLogger(mode, `${pluginName}-${plugin}`, sbLogging);*/ } } +export interface BaseWithLoggingAndConfigConfig< + ReferencedConfig extends BSBReferenceConfigType +> extends BaseWithLoggingConfig, + BaseWithConfigConfig {} + // used by events plugins (does not need events) export abstract class BaseWithLoggingAndConfig< - ReferencedConfig extends BSBConfigDefinition + ReferencedConfig extends BSBReferenceConfigType > extends BaseWithConfig { protected log: IPluginLogger; protected createNewLogger: { (plugin: string): IPluginLogger }; - constructor( - appId: string, - mode: DEBUG_MODE, - pluginName: string, - cwd: string, - pluginCwd: string, - config: any, - sbLogging: SBLogging - ) { - super(appId, mode, pluginName, cwd, pluginCwd, config); - this.log = new PluginLogger(mode, pluginName, sbLogging); + constructor(config: BaseWithLoggingAndConfigConfig) { + super(config); + this.log = new PluginLogger( + config.mode, + config.pluginName, + config.sbLogging + ); this.createNewLogger = (plugin: string) => - new PluginLogger(mode, `${pluginName}-${plugin}`, sbLogging); + new PluginLogger( + config.mode, + `${config.pluginName}-${plugin}`, + config.sbLogging + ); } } diff --git a/nodejs/src/base/config.ts b/nodejs/src/base/config.ts index 8c1d32f..9889fa1 100644 --- a/nodejs/src/base/config.ts +++ b/nodejs/src/base/config.ts @@ -1,29 +1,25 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import { DEBUG_MODE } from "../interfaces/logging"; -import { SBLogging } from "../serviceBase/logging"; import { - EventsConfig, LoggingConfig, + EventsConfig, PluginDefition, PluginType, -} from "../interfaces/plugins"; -import { BaseWithLogging } from "./base"; -import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./errorMessages"; +} from "../interfaces"; +import { + BaseWithLogging, + BaseWithLoggingConfig, + BSB_ERROR_METHOD_NOT_IMPLEMENTED, +} from "./index"; + +export interface BSBConfigConstructor extends BaseWithLoggingConfig {} /** * Abstract class representing the configuration for the Better Service Base. * @template T - The type of config for the plugin */ export abstract class BSBConfig extends BaseWithLogging { - constructor( - appId: string, - mode: DEBUG_MODE, - pluginName: string, - cwd: string, - pluginCwd: string, - logging: SBLogging - ) { - super(appId, mode, pluginName, cwd, pluginCwd, logging); + constructor(config: BSBConfigConstructor) { + super(config); } /** * This function is never used for events plugins. diff --git a/nodejs/src/base/errorMessages.ts b/nodejs/src/base/errorMessages.ts index 78a922c..2c725d3 100644 --- a/nodejs/src/base/errorMessages.ts +++ b/nodejs/src/base/errorMessages.ts @@ -1,5 +1,5 @@ -import { LogMeta } from "../interfaces/logging"; -import { LogFormatter } from "./logFormatter"; +import { LogFormatter } from "./index"; +import { LogMeta } from "../interfaces"; export class BSBError extends Error { constructor(errorKey: string, message: T, meta: LogMeta); diff --git a/nodejs/src/base/events.ts b/nodejs/src/base/events.ts index 0e8bf8f..7b33abc 100644 --- a/nodejs/src/base/events.ts +++ b/nodejs/src/base/events.ts @@ -1,33 +1,30 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { Readable } from "stream"; -import { BSBConfigDefinition, BaseWithLoggingAndConfig } from "./base"; -import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./errorMessages"; -import { DEBUG_MODE } from "../interfaces"; -import { SBLogging } from "../serviceBase"; +import { + BaseWithLoggingAndConfig, + BaseWithLoggingAndConfigConfig, + BSBReferencePluginConfigType, + BSBReferencePluginConfigDefinition, + BSB_ERROR_METHOD_NOT_IMPLEMENTED, +} from "./index"; -export interface BSBEventsConstructor { - appId: string; - mode: DEBUG_MODE; - pluginName: string; - cwd: string; - pluginCwd: string; - config: any; - sbLogging: SBLogging; -} +export interface BSBEventsConstructor< + ReferencedConfig extends BSBReferencePluginConfigType = any +> extends BaseWithLoggingAndConfigConfig< + ReferencedConfig extends null + ? null + : BSBReferencePluginConfigDefinition + > {} export abstract class BSBEvents< - PluginConfigType extends BSBConfigDefinition = any -> extends BaseWithLoggingAndConfig { - constructor(config: BSBEventsConstructor) { - super( - config.appId, - config.mode, - config.pluginName, - config.cwd, - config.pluginCwd, - config.config, - config.sbLogging - ); + ReferencedConfig extends BSBReferencePluginConfigType = any +> extends BaseWithLoggingAndConfig< + ReferencedConfig extends null + ? null + : BSBReferencePluginConfigDefinition +> { + constructor(config: BSBEventsConstructor) { + super(config); } /** diff --git a/nodejs/src/base/functions.ts b/nodejs/src/base/functions.ts index b913193..1918f43 100644 --- a/nodejs/src/base/functions.ts +++ b/nodejs/src/base/functions.ts @@ -1,4 +1,4 @@ -import { BSBError } from "."; +import { BSBError } from "./index"; type SmartFunctionCallFunc = { [Symbol.toStringTag]?: string; @@ -11,7 +11,10 @@ export async function SmartFunctionCallAsync( ): Promise | void> { if (typeof input !== "function") return; if (typeof context !== "object") - throw new BSBError("INCORRECT_REFERENCE", "SmartFunctionCallAsync: context is not an object"); + throw new BSBError( + "INCORRECT_REFERENCE", + "SmartFunctionCallAsync: context is not an object" + ); if (input[Symbol.toStringTag] === "AsyncFunction") { return await input.call(context, ...params); } @@ -24,6 +27,9 @@ export function SmartFunctionCallSync( ): ReturnType | void { if (typeof input !== "function") return; if (typeof context !== "object") - throw new BSBError("INCORRECT_REFERENCE", "SmartFunctionCallSync: context is not an object"); + throw new BSBError( + "INCORRECT_REFERENCE", + "SmartFunctionCallSync: context is not an object" + ); return input.call(context, ...params); } diff --git a/nodejs/src/base/index.ts b/nodejs/src/base/index.ts index e3a6d0c..c5cc759 100644 --- a/nodejs/src/base/index.ts +++ b/nodejs/src/base/index.ts @@ -8,3 +8,4 @@ export * from "./PluginEvents"; export * from "./PluginLogger"; export * from "./service"; export * from "./serviceClient"; +export * from "./pluginConfig"; diff --git a/nodejs/src/base/logFormatter.ts b/nodejs/src/base/logFormatter.ts index a896367..9c42a06 100644 --- a/nodejs/src/base/logFormatter.ts +++ b/nodejs/src/base/logFormatter.ts @@ -1,5 +1,5 @@ import { Tools } from "@bettercorp/tools/lib/Tools"; -import { LogMeta, SafeLogData, UnsafeLogData } from "../interfaces/logging"; +import { LogMeta, SafeLogData, UnsafeLogData } from "../interfaces"; export class LogFormatter { private isUnsafeLogData(value: any): value is UnsafeLogData { diff --git a/nodejs/src/base/logging.ts b/nodejs/src/base/logging.ts index fe1746f..1f33595 100644 --- a/nodejs/src/base/logging.ts +++ b/nodejs/src/base/logging.ts @@ -1,29 +1,30 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import { BSBConfigDefinition, BaseWithConfig } from "./base"; -import { DEBUG_MODE, LogMeta } from "../interfaces/logging"; -import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./errorMessages"; +import { LogMeta } from "../interfaces"; +import { + BaseWithConfig, + BaseWithConfigConfig, + BSB_ERROR_METHOD_NOT_IMPLEMENTED, + BSBReferencePluginConfigDefinition, + BSBReferencePluginConfigType, +} from "./index"; -export interface BSBLoggingConstructor { - appId: string; - mode: DEBUG_MODE; - pluginName: string; - cwd: string; - pluginCwd: string; - config: any; -} +export interface BSBLoggingConstructor< + ReferencedConfig extends BSBReferencePluginConfigType = any +> extends BaseWithConfigConfig< + ReferencedConfig extends null + ? null + : BSBReferencePluginConfigDefinition + > {} export abstract class BSBLogging< - ReferencedConfig extends BSBConfigDefinition -> extends BaseWithConfig { - constructor(config: BSBLoggingConstructor) { - super( - config.appId, - config.mode, - config.pluginName, - config.cwd, - config.pluginCwd, - config.config - ); + ReferencedConfig extends BSBReferencePluginConfigType = any +> extends BaseWithConfig< + ReferencedConfig extends null + ? null + : BSBReferencePluginConfigDefinition +> { + constructor(config: BSBLoggingConstructor) { + super(config); } /** @@ -145,7 +146,7 @@ export abstract class BSBLogging< /** * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS */ -export class BSBLoggingRef extends BSBLogging { +export class BSBLoggingRef extends BSBLogging { // eslint-disable-next-line @typescript-eslint/no-unused-vars public reportStat(plugin: string, key: string, value: number): void { throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBLoggingRef", "reportStat"); diff --git a/nodejs/src/base/pluginConfig.ts b/nodejs/src/base/pluginConfig.ts new file mode 100644 index 0000000..4890c1e --- /dev/null +++ b/nodejs/src/base/pluginConfig.ts @@ -0,0 +1,95 @@ +import { z } from "zod"; +import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./index"; + +/** + * The definition of the config with zod validation + * @example + * const configDefinition = z.object({ + * a: z.string(), + * }); + */ +export type BSBPluginConfigType = z.ZodTypeAny | undefined; +export type BSBPluginConfigDefinition = BSBPluginConfig; + +/** + * Config migration handler, allows for config migrations when the plugin version changes or a new plugin setup is done + * @example simple version change and basic setup + * const configMigration = async (versionFrom: string | null, versionTo: string, existingConfig?: z.infer) => { + * if (versionFrom === null) { + * return { + * a: "a", + * }; + * } + * return { + * a: "b", + * }; + * @example basic setup and no version change handling + * const configMigration = async (versionFrom: string | null, versionTo: string, existingConfig?: z.infer) => { + * if (versionFrom === null || existingConfig === undefined) { + * return { + * a: "a", + * }; + * } + * return existingConfig; + */ +export type BSBConfigMigration = ( + versionFrom: string | null, + versionTo: string, + existingConfig?: z.infer> +) => Promise>>; + +export type BSBConfigDefintionReference< + T extends BSBPluginConfigType, + AS = undefined +> = T extends undefined ? AS : z.infer>; + +export type BSBReferenceConfigType = BSBPluginConfigType | null; +export type BSBReferencePluginConfigType = BSBPluginConfigDefinition | null; +export type BSBReferenceConfigDefinition< + ReferencedConfig extends BSBReferenceConfigType +> = ReferencedConfig extends null ? null : ReferencedConfig; +export type BSBReferencePluginConfigDefinition< + ReferencedConfig extends BSBReferencePluginConfigType +> = ReferencedConfig extends null + ? null + : ReferencedConfig extends BSBPluginConfigDefinition + ? z.infer + : null; + +export abstract class BSBPluginConfig< + MyPluginConfig extends Exclude | null = null +> { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + constructor(cwd: string, pluginCwd: string, pluginName: string) {} + public abstract validationSchema: MyPluginConfig; + /** + * Migrate the config from one version to another + * + * @todo Future feature - not implemented yet + * @todo write your migration code if you do make changes you'd like to have migratable + */ + public abstract migrate?( + toVersion: string, + fromVersion: string | null, + fromConfig: any | null + ): MyPluginConfig extends BSBPluginConfigType + ? z.infer + : null; +} + +/** + * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS + */ +export class BSBPluginConfigRef extends BSBPluginConfig { + public validationSchema = {}; + public migrate?( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + toVersion: string, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + fromVersion: string | null, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + fromConfig: any + ) { + throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBPluginConfigRef", "migrate"); + } +} diff --git a/nodejs/src/base/service.ts b/nodejs/src/base/service.ts index 066cfb0..93c5d45 100644 --- a/nodejs/src/base/service.ts +++ b/nodejs/src/base/service.ts @@ -1,49 +1,48 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import { BSBConfigDefinition, BaseWithLoggingAndConfig } from "./base"; -import { ServiceEventsBase, ServiceEventsDefault } from "../interfaces/service"; -import { DEBUG_MODE } from "../interfaces/logging"; -import { SBLogging } from "../serviceBase/logging"; -import { PluginEvents } from "./PluginEvents"; -import { SBEvents } from "../serviceBase/events"; -import { BSBServiceClient } from "./serviceClient"; +import { ServiceEventsBase } from "../interfaces"; +import { SBEvents } from "../serviceBase"; +import { + BaseWithLoggingAndConfig, + BaseWithLoggingAndConfigConfig, + BSBPluginEvents, + BSBPluginEventsRef, + PluginEvents, + BSBServiceClient, + BSBReferencePluginConfigType, + BSBReferencePluginConfigDefinition, +} from "./index"; -export interface BSBServiceTypes { - onEvents: ServiceEventsBase; - emitEvents: ServiceEventsBase; - onReturnableEvents: ServiceEventsBase; - emitReturnableEvents: ServiceEventsBase; - onBroadcast: ServiceEventsBase; - emitBroadcast: ServiceEventsBase; - methods: ServiceEventsBase; -} -export interface BSBServiceTypesDefault extends BSBServiceTypes { - onEvents: ServiceEventsDefault; - emitEvents: ServiceEventsDefault; - onReturnableEvents: ServiceEventsDefault; - emitReturnableEvents: ServiceEventsDefault; - onBroadcast: ServiceEventsDefault; - emitBroadcast: ServiceEventsDefault; - methods: {}; -} -export interface BSBServiceConstructor { - appId: string; - mode: DEBUG_MODE; - pluginName: string; - cwd: string; - pluginCwd: string; - config: any; - sbLogging: SBLogging; +export interface BSBServiceConstructor< + ReferencedConfig extends BSBReferencePluginConfigType = any +> extends BaseWithLoggingAndConfigConfig< + ReferencedConfig extends null + ? null + : BSBReferencePluginConfigDefinition + > { sbEvents: SBEvents; } + export abstract class BSBService< - PluginConfigType extends BSBConfigDefinition = any, - Events extends BSBServiceTypes = BSBServiceTypesDefault -> extends BaseWithLoggingAndConfig { + ReferencedConfig extends BSBReferencePluginConfigType = any, + Events extends BSBPluginEvents = BSBPluginEventsRef +> extends BaseWithLoggingAndConfig< + ReferencedConfig extends null + ? null + : BSBReferencePluginConfigDefinition +> { public abstract readonly initBeforePlugins?: Array; public abstract readonly initAfterPlugins?: Array; public abstract readonly runBeforePlugins?: Array; public abstract readonly runAfterPlugins?: Array; - public abstract readonly methods: Events["methods"]; + public abstract readonly methods: ServiceEventsBase; + public readonly _virtual_internal_events: { + onEvents: Events["onEvents"]; + emitEvents: Events["emitEvents"]; + onReturnableEvents: Events["onReturnableEvents"]; + emitReturnableEvents: Events["emitReturnableEvents"]; + onBroadcast: Events["onBroadcast"]; + emitBroadcast: Events["emitBroadcast"]; + } = {} as any; public readonly events: PluginEvents< Events["onEvents"], Events["emitEvents"], @@ -52,18 +51,10 @@ export abstract class BSBService< Events["onBroadcast"], Events["emitBroadcast"] >; - public _clients: Array> = []; + public _clients: Array = []; - constructor(config: BSBServiceConstructor) { - super( - config.appId, - config.mode, - config.pluginName, - config.cwd, - config.pluginCwd, - config.config, - config.sbLogging - ); + constructor(config: BSBServiceConstructor) { + super(config); this.events = new PluginEvents(config.mode, config.sbEvents, this); } } @@ -71,16 +62,16 @@ export abstract class BSBService< /** * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS */ -export class BSBServiceRef extends BSBService { +export class BSBServiceRef extends BSBService { + public methods = {}; public initBeforePlugins?: string[] | undefined; public initAfterPlugins?: string[] | undefined; public runBeforePlugins?: string[] | undefined; public runAfterPlugins?: string[] | undefined; - public methods = {}; dispose?(): void; init?(): void | Promise; run?(): void | Promise; - constructor(config: BSBServiceConstructor) { + constructor(config: BSBServiceConstructor) { super(config); } } diff --git a/nodejs/src/base/serviceClient.ts b/nodejs/src/base/serviceClient.ts index e2729ad..6efb92f 100644 --- a/nodejs/src/base/serviceClient.ts +++ b/nodejs/src/base/serviceClient.ts @@ -1,30 +1,28 @@ -import { PluginEvents } from "./PluginEvents"; -import { IPluginLogger } from "../interfaces/logging"; -import { BSBService, BSBServiceTypes, BSBServiceTypesDefault } from "./service"; -import { DynamicallyReferencedMethodCallable } from "../interfaces/events"; +import { + IPluginLogger, + DynamicallyReferencedMethodCallable, +} from "../interfaces"; +import { BSBService, BSBError, PluginEvents } from "./index"; import { DynamicallyReferencedMethodType } from "@bettercorp/tools/lib/Interfaces"; -import { BSBError } from "./errorMessages"; -export abstract class BSBServiceClient< - Events extends BSBServiceTypes = BSBServiceTypesDefault -> { +export abstract class BSBServiceClient { protected readonly log!: IPluginLogger; protected readonly events!: PluginEvents< - Events["emitEvents"], - Events["onEvents"], - Events["emitReturnableEvents"], - Events["onReturnableEvents"], - Events["emitBroadcast"], - Events["onBroadcast"] + Service["_virtual_internal_events"]["emitEvents"], + Service["_virtual_internal_events"]["onEvents"], + Service["_virtual_internal_events"]["emitReturnableEvents"], + Service["_virtual_internal_events"]["onReturnableEvents"], + Service["_virtual_internal_events"]["emitBroadcast"], + Service["_virtual_internal_events"]["onBroadcast"] >; public callMethod( // eslint-disable-next-line @typescript-eslint/no-unused-vars ...args: DynamicallyReferencedMethodCallable< - DynamicallyReferencedMethodType, + DynamicallyReferencedMethodType, TA > ): DynamicallyReferencedMethodCallable< - DynamicallyReferencedMethodType, + DynamicallyReferencedMethodType, TA, false > { @@ -35,7 +33,7 @@ export abstract class BSBServiceClient< } ); } - constructor(context: BSBService) { + constructor(context: BSBService) { context._clients.push(this); } public abstract readonly pluginName: string; diff --git a/nodejs/src/base/serviceConfig.ts b/nodejs/src/base/serviceConfig.ts deleted file mode 100644 index b50c540..0000000 --- a/nodejs/src/base/serviceConfig.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { z } from "zod"; -import { BSB_ERROR_METHOD_NOT_IMPLEMENTED } from "./errorMessages"; -import { BSBConfigType } from './base'; - -export abstract class BSBServiceConfig> { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - constructor(cwd: string, pluginCwd: string, pluginName: string) {} - abstract validationSchema: MyPluginConfig; - abstract migrate( - toVersion: string, - fromVersion: string | null, - fromConfig: any | null - ): z.infer; -} - -/** - * DO NOT REFERENCE/USE THIS CLASS - IT IS AN INTERNALLY REFERENCED CLASS - */ -export class BSBServiceConfigRef extends BSBServiceConfig { - validationSchema = {}; - // eslint-disable-next-line @typescript-eslint/no-unused-vars - migrate(toVersion: string, fromVersion: string | null, fromConfig: any) { - throw BSB_ERROR_METHOD_NOT_IMPLEMENTED("BSBServiceConfigRef", "migrate"); - } -} diff --git a/nodejs/src/client.ts b/nodejs/src/client.ts index 63d0d71..829b6bc 100644 --- a/nodejs/src/client.ts +++ b/nodejs/src/client.ts @@ -1,5 +1,6 @@ import { BSBConfig, + BSBConfigConstructor, BSBService, BSBServiceClient, BSBServiceConstructor, @@ -9,9 +10,8 @@ import { EventsConfig, PluginDefition, PluginType, - DEBUG_MODE, } from "./interfaces"; -import { SBLogging, ServiceBase } from "./serviceBase"; +import { ServiceBase } from "./serviceBase"; import { randomUUID } from "crypto"; export class SBClient { @@ -50,7 +50,7 @@ export class SBClient { } } -export class FakeServiceClient extends BSBService { +export class FakeServiceClient extends BSBService { public initBeforePlugins?: string[] | undefined; public initAfterPlugins?: string[] | undefined; public runBeforePlugins?: string[] | undefined; @@ -69,15 +69,8 @@ export class FakeServiceClient extends BSBService { } export class FakeServiceConfig extends BSBConfig { - constructor( - appId: string, - mode: DEBUG_MODE, - pluginName: string, - cwd: string, - pluginCwd: string, - logging: SBLogging - ) { - super(appId, mode, pluginName, cwd, pluginCwd, logging); + constructor(config: BSBConfigConstructor) { + super(config); } async getLoggingPlugins(): Promise> { return {}; diff --git a/nodejs/src/initAppConfig.ts b/nodejs/src/initAppConfig.ts deleted file mode 100644 index ac88bf5..0000000 --- a/nodejs/src/initAppConfig.ts +++ /dev/null @@ -1,25 +0,0 @@ -// import * as fs from "fs"; -// import { cwd } from 'process'; -// import * as path from 'path'; - -// (async () => { -// const SBBaseDir = path.join(cwd(), "./node_modules/@bettercorp/service-base"); -// const secConfigFile = path.join(path.join(cwd(), './sec.config.json')); -// if (!fs.existsSync(secConfigFile)) { -// console.log("INIT: Copy new sec.config.json"); -// fs.copyFileSync(path.join(SBBaseDir, 'templates', 'sec.config.json'), secConfigFile); -// console.log("INIT: Copy new sec.config.json - Completed"); - -// await (new Promise((r) => setTimeout(r, 1000))); - -// const installer = path.join(SBBaseDir, "./lib/ServiceBase.js"); -// console.log("INSTALL FINAL : AUTOLOAD: " + installer); -// const ServiceBase = require(installer); // eslint-disable-line @typescript-eslint/no-var-requires -// const SB = new ServiceBase.default(cwd()); -// SB.config().then(() => console.log("INSTALL COMPLETE FOR @bettercorp/service-base")).catch(() => process.exit(1)); - -// console.log(`sec.config.json ready to go`); -// } else { -// console.warn('sec.config.json already found... we`re not going to do anything'); -// } -// })(); \ No newline at end of file diff --git a/nodejs/src/install.ts b/nodejs/src/install.ts deleted file mode 100644 index 6c22424..0000000 --- a/nodejs/src/install.ts +++ /dev/null @@ -1,244 +0,0 @@ -// //import { Tools } from "@bettercorp/tools/lib/Tools"; -// import * as fs from "fs"; -// //import * as crypto from "crypto"; -// import * as path from "path"; -// import * as os from "os"; -// export default (CWD: string) => { -// console.log(`Install CWD: ${ CWD }`); - -// if (CWD.indexOf("@bettercorp") >= 0) { -// CWD = path.join(CWD, "../../../"); -// } - -// console.log(`INSTALL SCRIPT FOR @bettercorp/service-base in ${ CWD }`); - -// /*const srcDir = path.join(CWD, `./src`); -// if (!fs.existsSync(srcDir)) { -// console.log(`Creating src dir... (${ srcDir })`); -// fs.mkdirSync(srcDir); -// } - -// const pluginsDir = path.join(CWD, `./src/plugins`); -// if (!fs.existsSync(pluginsDir)) { -// console.log(`Creating plugins dir... (${ pluginsDir })`); -// fs.mkdirSync(pluginsDir); -// } - -// const filesToCopyToDest = [ -// { -// src: path.join(CWD, './node_modules/@bettercorp/service-base/build/gitlab-ci.yml'), -// dst: path.join(CWD, './.gitlab-ci.yml'), -// name: 'gitlab-ci' -// }, -// { -// src: path.join(CWD, './node_modules/@bettercorp/service-base/build/eslintignore'), -// dst: path.join(CWD, './.eslintignore'), -// name: 'eslintignore' -// }, -// { -// src: path.join(CWD, './node_modules/@bettercorp/service-base/build/eslintrc.js'), -// dst: path.join(CWD, './.eslintrc.js'), -// name: 'eslintrc' -// }, -// { -// src: path.join(CWD, './node_modules/@bettercorp/service-base/build/tsconfig.json'), -// dst: path.join(CWD, './tsconfig.json'), -// name: 'tsconfig' -// }, -// { -// src: path.join(CWD, './node_modules/@bettercorp/service-base/build/gitignore'), -// dst: path.join(CWD, './.gitignore'), -// name: '.gitignore', -// merge: true -// }, - -// // old build files -// { -// dst: path.join(CWD, './tslint.json'), -// remove: true -// } -// ]; - -// for (const fileInfo of filesToCopyToDest) { -// if (fileInfo.remove === true) { -// if (fs.existsSync(fileInfo.dst)) -// fs.unlinkSync(fileInfo.dst); -// } else { -// if (!fs.existsSync(fileInfo.dst)) { -// console.log(`Creating ${ fileInfo.name } build file... (${ fileInfo.src } -> ${ fileInfo.dst })`); -// fs.copyFileSync(fileInfo.src!, fileInfo.dst!); -// } -// if (fileInfo.merge === true) { -// const srcBuffer = fs.readFileSync(fileInfo.src!).toString().split('\n'); -// const dstBuffer = fs.readFileSync(fileInfo.dst!).toString().split('\n'); -// for (let line of dstBuffer) { -// if (srcBuffer.indexOf(line) >= 0) -// srcBuffer.splice(srcBuffer.indexOf(line), 1); -// } -// for (let line of srcBuffer) { -// dstBuffer.push(line); -// } -// fs.writeFileSync(fileInfo.dst!, dstBuffer.join('\n')); -// } else { -// const srcBuffer = fs.readFileSync(fileInfo.src!); -// const srcHash = crypto.createHash('sha256'); -// srcHash.update(srcBuffer); -// const dstBuffer = fs.readFileSync(fileInfo.dst!); -// const dstHash = crypto.createHash('sha256'); -// dstHash.update(dstBuffer); -// if (srcHash.digest('hex') !== dstHash.digest('hex')) { -// console.log(`Updating ${ fileInfo.name } build file... (${ fileInfo.src } -> ${ fileInfo.dst })`); -// fs.copyFileSync(fileInfo.src!, fileInfo.dst!); -// } -// } -// } -// }*/ - -// if (process.env.NODE_ENV === 'production') { -// const packaggeJSONFile = path.join(CWD, "./package.json"); -// console.log(`Updating package scripts... (${ packaggeJSONFile })`); -// const readPackageJsonFile = JSON.parse(fs.readFileSync(packaggeJSONFile).toString()); -// readPackageJsonFile.scripts = readPackageJsonFile.scripts || {}; -// readPackageJsonFile.scripts.start = "node node_modules/@bettercorp/service-base/lib/index.js"; -// fs.writeFileSync(packaggeJSONFile, JSON.stringify(readPackageJsonFile)); -// } - -// /*const defaultScripts: any = { -// build: "tsc", -// dev: "nodemon --config node_modules/@bettercorp/service-base/build/nodemon.json", -// start: "ts-node node_modules/@bettercorp/service-base/lib/index.js", -// create: "ts-node node_modules/@bettercorp/service-base/lib/bootstrap.js $0", -// version: "node ./node_modules/@bettercorp/service-base/build/version-ci.js $0", -// }; -// const internalAppScripts: any = { -// ...defaultScripts, -// version: "node ./node_modules/@bettercorp/service-base/build/version-internal.js $0" -// }; -// const bcorpLibScripts: any = { -// ...defaultScripts, -// version: "node ./node_modules/@bettercorp/service-base/build/version-bcorp.js $0" -// }; - -// let coreAppInstall = false; -// let libInstall = false; -// let selfInstall = false; - -// const packaggeJSONFile = path.join(CWD, "./package.json"); -// let todoList: Array = []; -// if (fs.existsSync(packaggeJSONFile)) { -// const readPackageJsonFile = JSON.parse(fs.readFileSync(packaggeJSONFile).toString()); - -// const arrOfDevDepts = Object.keys(readPackageJsonFile.devDependencies || {}); -// let paksToRemove: Array = ['tslint']; -// let devPaksToInstall: Array = ['eslint', 'typescript', '@typescript-eslint/parser', '@typescript-eslint/eslint-plugin']; -// for (let i = paksToRemove.length - 1; i >= 0; i--) -// if (arrOfDevDepts.indexOf(paksToRemove[i]) < 0) { -// paksToRemove.splice(i, 1); -// } -// for (let i = devPaksToInstall.length - 1; i >= 0; i--) -// if (arrOfDevDepts.indexOf(devPaksToInstall[i]) >= 0) { -// devPaksToInstall.splice(i, 1); -// } - -// if (paksToRemove.length > 0 || devPaksToInstall.length > 0) { -// todoList.push('You are missing some packages / have depreciated ones. Please run the following commands to clean things up:'); -// if (paksToRemove.length > 0) -// todoList.push(`npm remove ${ paksToRemove.join(' ') }`); -// if (devPaksToInstall.length > 0) -// todoList.push(`npm install --save-dev ${ devPaksToInstall.join(' ') }`); -// } - -// if (readPackageJsonFile.name == "@bettercorp/service-base") { -// console.log("Self install. ignoring install script."); -// process.exit(0); -// } - -// if (readPackageJsonFile.name.indexOf("@bettercorp/core-internal-") === 0) -// coreAppInstall = true; -// if (readPackageJsonFile.name.indexOf("@bettercorp/service-base-") === 0) -// libInstall = true; -// if (readPackageJsonFile.name === "@bettercorp/service-base") -// selfInstall = true; - -// let scripts = defaultScripts; -// if (coreAppInstall) { -// scripts = internalAppScripts; -// } else if (libInstall) { -// scripts = bcorpLibScripts; -// } -// if (Tools.isNullOrUndefined(readPackageJsonFile.scripts)) { -// readPackageJsonFile.scripts = {}; -// } -// let pakUpdates = false; -// for (const key of Object.keys(scripts)) { -// if (Tools.isNullOrUndefined(scripts[key])) continue; - -// if (readPackageJsonFile.scripts[key] !== scripts[key]) { -// readPackageJsonFile.scripts[key] = scripts[key]; -// pakUpdates = true; -// } -// } -// if (Tools.isNullOrUndefined(readPackageJsonFile.files)) { -// readPackageJsonFile.files = ["lib/**[REMOVE" "this]/*"]; -// pakUpdates = true; -// } -// if (readPackageJsonFile.scripts.publish !== undefined && readPackageJsonFile.scripts.publish.indexOf("npm publish") >= 0) { -// pakUpdates = true; -// if (readPackageJsonFile.scripts.publish == "npm publish") -// delete readPackageJsonFile.scripts.publish; -// else -// readPackageJsonFile.scripts.publish = `${ readPackageJsonFile.scripts.publish }`.replace("npm publish", ""); -// } -// if (typeof readPackageJsonFile.bsb_project !== "boolean") { -// readPackageJsonFile.bsb_project = true; -// pakUpdates = true; -// } -// if (pakUpdates) { -// console.log(`Updating package scripts for you... (${ packaggeJSONFile })`); -// fs.writeFileSync(packaggeJSONFile, JSON.stringify(readPackageJsonFile)); -// } - -// if (selfInstall) { -// console.log("Package install. ignoring app install script."); -// process.exit(0); -// } -// }*/ - -// const configFile = path.join(CWD, "./sec.config.json"); -// if (!fs.existsSync(configFile)) { -// console.log(`Creating config file... (${ configFile })`); -// fs.writeFileSync(configFile, `{"identity":"${ os.hostname }","debug":true,"deploymentProfiles": {"default":{}}, "plugins": {}}`); -// } else { -// const tSec = JSON.parse(fs.readFileSync(configFile).toString()); -// const tBefore = JSON.stringify(tSec); -// tSec.identity = tSec.identity || os.hostname; -// tSec.debug = tSec.debug || true; -// tSec.deploymentProfiles = tSec.deploymentProfiles || {}; -// tSec.plugins = tSec.plugins || {}; -// const tAfter = JSON.stringify(tSec); -// if (tBefore != tAfter) -// fs.writeFileSync(configFile, tAfter); -// } -// const installer = path.join(CWD, "./node_modules/@bettercorp/service-base/lib/ServiceBase.js"); -// console.log("INSTALL FINAL : AUTOLOAD: " + installer); -// const ServiceBase = require(installer); // eslint-disable-line @typescript-eslint/no-var-requires -// const SB = new ServiceBase.default(CWD); -// let completedInstaller = false; -// SB.config().then(() => { -// console.log("INSTALL COMPLETE FOR @bettercorp/service-base"); - -// console.log(""); -// console.log(""); -// console.log(""); - -// //for (const todoItem of todoList) console.warn(todoItem); -// completedInstaller = true; -// }).catch((e: any) => { -// console.error(e); -// process.exit(1); -// }); -// let timeoutHandle = setTimeout(() => { -// if (completedInstaller) -// clearTimeout(timeoutHandle); -// }, 100); -// }; diff --git a/nodejs/src/interfaces/events.ts b/nodejs/src/interfaces/events.ts index 356d356..e27481a 100644 --- a/nodejs/src/interfaces/events.ts +++ b/nodejs/src/interfaces/events.ts @@ -2,7 +2,7 @@ import { DynamicallyReferencedMethodBase } from "@bettercorp/tools/lib/Interface export type DynamicallyReferencedMethodCallable< Interface extends DynamicallyReferencedMethodBase, - Method extends string, + Method extends keyof Interface, ArgsReference extends boolean = true //ShowTimeout extends boolean = true > = ArgsReference extends true @@ -18,7 +18,7 @@ export type DynamicallyReferencedMethodCallable< export type DynamicallyReferencedMethodOnIEvents< Interface extends DynamicallyReferencedMethodBase, - Method extends string, + Method extends keyof Interface, hasReturnable extends boolean = false > = Interface[Method] extends (...a: infer Arguments) => infer Return ? [ @@ -33,15 +33,15 @@ export type DynamicallyReferencedMethodOnIEvents< export type DynamicallyReferencedMethodEmitIEvents< Interface extends DynamicallyReferencedMethodBase, - Method extends string + Method extends keyof Interface // eslint-disable-next-line @typescript-eslint/no-unused-vars > = Interface[Method] extends (...a: infer Arguments) => infer Return ? [event: Method, ...a: Arguments] - : [noMatchingEvent: never]; + : [event: Method, noMatchingEvent: never]; export type DynamicallyReferencedMethodEmitEARIEvents< Interface extends DynamicallyReferencedMethodBase, - Method extends string, + Method extends keyof Interface, ArgsReference extends boolean = true //ShowTimeout extends boolean = true > = ArgsReference extends true diff --git a/nodejs/src/interfaces/index.ts b/nodejs/src/interfaces/index.ts index 3ec8c27..1d667c8 100644 --- a/nodejs/src/interfaces/index.ts +++ b/nodejs/src/interfaces/index.ts @@ -2,4 +2,3 @@ export * from "./events"; export * from "./logging"; export * from "./plugins"; export * from "./service"; -export * from "../base/serviceConfig"; diff --git a/nodejs/src/interfaces/plugins.ts b/nodejs/src/interfaces/plugins.ts index 6ea6a50..e5d30a2 100644 --- a/nodejs/src/interfaces/plugins.ts +++ b/nodejs/src/interfaces/plugins.ts @@ -1,11 +1,15 @@ -import { BSBService, BSBServiceRef } from "../base/service"; -import { LoggingEventTypes } from "./logging"; -import { BSBLogging, BSBLoggingRef } from "../base/logging"; -import { BSBConfig, BSBConfigRef } from "../base/config"; -import { EventsEventTypes } from "./events"; -import { BSBEvents } from "../base/events"; -import { BSBEventsRef } from "../base/events"; -import { BSBServiceConfig } from "."; +import { + BSBService, + BSBLogging, + BSBConfig, + BSBEvents, + BSBServiceRef, + BSBLoggingRef, + BSBConfigRef, + BSBEventsRef, + BSBPluginConfig, +} from "../base"; +import { LoggingEventTypes, EventsEventTypes } from "./index"; export const PluginTypes = { config: "config", @@ -105,7 +109,7 @@ export interface LoadedPlugin< name: string; ref: string; version: string; - serviceConfig: BSBServiceConfig | null; + serviceConfig: BSBPluginConfig | null; plugin: ClassType; pluginCWD: string; pluginPath: string; diff --git a/nodejs/src/plugins/config-default/interfaces.ts b/nodejs/src/plugins/config-default/interfaces.ts index 541e806..2507712 100644 --- a/nodejs/src/plugins/config-default/interfaces.ts +++ b/nodejs/src/plugins/config-default/interfaces.ts @@ -2,7 +2,7 @@ import { LoggingConfig, EventsConfig, PluginDefition as ServiceConfig, -} from "../../interfaces/plugins"; +} from "../../"; export interface DeploymentProfile { /** diff --git a/nodejs/src/plugins/config-default/plugin.ts b/nodejs/src/plugins/config-default/plugin.ts index bb14879..8427bbd 100644 --- a/nodejs/src/plugins/config-default/plugin.ts +++ b/nodejs/src/plugins/config-default/plugin.ts @@ -1,19 +1,18 @@ import * as path from "path"; import * as fs from "fs"; -import { ConfigDefinition } from "./interfaces"; import { parse } from "yaml"; -import { BSBConfig } from "../../base/config"; +import { Tools } from "@bettercorp/tools/lib/Tools"; import { + BSBConfig, + BSBConfigConstructor, EventsConfig, LoggingConfig, PluginDefition, PluginType, PluginTypes, -} from "../../interfaces/plugins"; -import { Tools } from "@bettercorp/tools/lib/Tools"; -import { SBLogging } from "../../serviceBase/logging"; -import { DEBUG_MODE } from "../../interfaces/logging"; -import { BSBError } from "../../base/errorMessages"; + BSBError, +} from "../../"; +import { ConfigDefinition } from "./interfaces"; export class Plugin extends BSBConfig { async getServicePluginDefinition( @@ -130,15 +129,8 @@ export class Plugin extends BSBConfig { private _secConfigFilePath: string; private _deploymentProfile: string = "default"; - constructor( - appId: string, - mode: DEBUG_MODE, - pluginName: string, - cwd: string, - pluginCwd: string, - logging: SBLogging - ) { - super(appId, mode, pluginName, cwd, pluginCwd, logging); + constructor(config: BSBConfigConstructor) { + super(config); this._secConfigFilePath = path.join(this.cwd, "./sec-config.yaml"); } diff --git a/nodejs/src/plugins/events-default/events/broadcast.ts b/nodejs/src/plugins/events-default/events/broadcast.ts index 1749e53..4553132 100644 --- a/nodejs/src/plugins/events-default/events/broadcast.ts +++ b/nodejs/src/plugins/events-default/events/broadcast.ts @@ -1,7 +1,7 @@ import { EventEmitter } from "events"; -import { IPluginLogger } from "../../../interfaces/logging"; +import { IPluginLogger } from "../../../"; -export default class broadcast extends EventEmitter { +export class broadcast extends EventEmitter { private log: IPluginLogger; constructor(log: IPluginLogger) { diff --git a/nodejs/src/plugins/events-default/events/emit.ts b/nodejs/src/plugins/events-default/events/emit.ts index b5fbc9a..eeec9f0 100644 --- a/nodejs/src/plugins/events-default/events/emit.ts +++ b/nodejs/src/plugins/events-default/events/emit.ts @@ -1,8 +1,8 @@ import { EventEmitter } from "events"; -import { IPluginLogger } from "../../../interfaces/logging"; +import { IPluginLogger } from "../../../"; import { randomUUID } from "crypto"; -export default class emit extends EventEmitter { +export class emit extends EventEmitter { private log: IPluginLogger; private _lastReceivedMessageIds: Array = []; private set lastReceivedMessageIds(value: string) { diff --git a/nodejs/src/plugins/events-default/events/emitAndReturn.ts b/nodejs/src/plugins/events-default/events/emitAndReturn.ts index fb36bbe..9dc0a76 100644 --- a/nodejs/src/plugins/events-default/events/emitAndReturn.ts +++ b/nodejs/src/plugins/events-default/events/emitAndReturn.ts @@ -1,7 +1,7 @@ import { EventEmitter } from "events"; -import { IPluginLogger } from "../../../interfaces/logging"; +import { IPluginLogger } from "../../../"; -export default class emitAndReturn extends EventEmitter { +export class emitAndReturn extends EventEmitter { private log: IPluginLogger; constructor(log: IPluginLogger) { @@ -17,10 +17,10 @@ export default class emitAndReturn extends EventEmitter { event: string, listener: { (args: Array): Promise } ): Promise { - this.log.debug( - "onReturnableEvent: listening to {pluginName}-{event}", - { pluginName, event } - ); + this.log.debug("onReturnableEvent: listening to {pluginName}-{event}", { + pluginName, + event, + }); this.on(event, async (resolve, reject, data) => { try { resolve(await listener(data)); diff --git a/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts b/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts index 19e1784..a478bdd 100644 --- a/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts +++ b/nodejs/src/plugins/events-default/events/emitStreamAndReceiveStream.ts @@ -1,9 +1,9 @@ import { EventEmitter } from "events"; import { Readable } from "stream"; import { randomUUID } from "crypto"; -import { IPluginLogger } from "../../../interfaces/logging"; +import { IPluginLogger } from "../../../"; -export default class emitStreamAndReceiveStream extends EventEmitter { +export class emitStreamAndReceiveStream extends EventEmitter { // If we try receive or send a stream and the other party is not ready for some reason, we will automatically timeout in 5s. private readonly staticCommsTimeout = 1000; private log: IPluginLogger; diff --git a/nodejs/src/plugins/events-default/events/index.ts b/nodejs/src/plugins/events-default/events/index.ts new file mode 100644 index 0000000..e9f72fa --- /dev/null +++ b/nodejs/src/plugins/events-default/events/index.ts @@ -0,0 +1,4 @@ +export { emit } from "./emit"; +export { emitAndReturn } from "./emitAndReturn"; +export { emitStreamAndReceiveStream } from "./emitStreamAndReceiveStream"; +export { broadcast } from "./broadcast"; diff --git a/nodejs/src/plugins/events-default/plugin.ts b/nodejs/src/plugins/events-default/plugin.ts index 8401ae2..01debd8 100644 --- a/nodejs/src/plugins/events-default/plugin.ts +++ b/nodejs/src/plugins/events-default/plugin.ts @@ -1,12 +1,13 @@ import { Readable } from "stream"; -import emit from "./events/emit"; -import emitAndReturn from "./events/emitAndReturn"; -import emitStreamAndReceiveStream from "./events/emitStreamAndReceiveStream"; -import broadcast from "./events/broadcast"; -import { BSBEvents, BSBEventsConstructor } from "../../base/events"; -import { BSBConfigDefinition } from "../../"; +import { + emit, + broadcast, + emitAndReturn, + emitStreamAndReceiveStream, +} from "./events"; +import { BSBEvents, BSBEventsConstructor } from "../../"; -export class Plugin extends BSBEvents { +export class Plugin extends BSBEvents { init?(): void; protected broadcast!: broadcast; protected emit!: emit; diff --git a/nodejs/src/plugins/events-test/events/broadcast.ts b/nodejs/src/plugins/events-test/events/broadcast.ts new file mode 100644 index 0000000..1749e53 --- /dev/null +++ b/nodejs/src/plugins/events-test/events/broadcast.ts @@ -0,0 +1,38 @@ +import { EventEmitter } from "events"; +import { IPluginLogger } from "../../../interfaces/logging"; + +export default class broadcast extends EventEmitter { + private log: IPluginLogger; + + constructor(log: IPluginLogger) { + super(); + this.log = log; + } + public dispose() { + this.removeAllListeners(); + } + + public async onBroadcast( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + this.log.debug("onBroadcast:listening to {pluginName}-{event}", { + pluginName, + event, + }); + this.on(`${pluginName}-${event}`, listener); + } + + public async emitBroadcast( + pluginName: string, + event: string, + args: Array + ): Promise { + this.log.debug("emitBroadcast: emitting {pluginName}-{event}", { + pluginName, + event, + }); + this.emit(`${pluginName}-${event}`, args); + } +} diff --git a/nodejs/src/plugins/events-test/events/emit.ts b/nodejs/src/plugins/events-test/events/emit.ts new file mode 100644 index 0000000..b5fbc9a --- /dev/null +++ b/nodejs/src/plugins/events-test/events/emit.ts @@ -0,0 +1,56 @@ +import { EventEmitter } from "events"; +import { IPluginLogger } from "../../../interfaces/logging"; +import { randomUUID } from "crypto"; + +export default class emit extends EventEmitter { + private log: IPluginLogger; + private _lastReceivedMessageIds: Array = []; + private set lastReceivedMessageIds(value: string) { + // remove after 50 messages + if (this._lastReceivedMessageIds.length > 50) { + this._lastReceivedMessageIds.shift(); + } + this._lastReceivedMessageIds.push(value); + } + + constructor(log: IPluginLogger) { + super(); + this.log = log; + } + public dispose() { + this.removeAllListeners(); + } + + public async onEvent( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + this.log.debug("onEvent: listening to {pluginName}-{event}", { + pluginName, + event, + }); + this.on(`${pluginName}-${event}`, (args: any) => { + if (this._lastReceivedMessageIds.includes(args.msgID)) { + return; + } + this.lastReceivedMessageIds = args.msgID; + listener(args.data); + }); + } + + public async emitEvent( + pluginName: string, + event: string, + args: Array + ): Promise { + this.log.debug("emitEvent: emitting {pluginName}-{event}", { + pluginName, + event, + }); + this.emit(`${pluginName}-${event}`, { + msgID: randomUUID(), + data: args, + }); + } +} diff --git a/nodejs/src/plugins/events-test/events/emitAndReturn.ts b/nodejs/src/plugins/events-test/events/emitAndReturn.ts new file mode 100644 index 0000000..fb36bbe --- /dev/null +++ b/nodejs/src/plugins/events-test/events/emitAndReturn.ts @@ -0,0 +1,62 @@ +import { EventEmitter } from "events"; +import { IPluginLogger } from "../../../interfaces/logging"; + +export default class emitAndReturn extends EventEmitter { + private log: IPluginLogger; + + constructor(log: IPluginLogger) { + super(); + this.log = log; + } + public dispose() { + this.removeAllListeners(); + } + + public async onReturnableEvent( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + this.log.debug( + "onReturnableEvent: listening to {pluginName}-{event}", + { pluginName, event } + ); + this.on(event, async (resolve, reject, data) => { + try { + resolve(await listener(data)); + } catch (exc) { + reject(exc); + } + }); + } + + public async emitEventAndReturn( + pluginName: string, + event: string, + timeoutSeconds: number, + args: Array + ): Promise { + this.log.debug("emitReturnableEvent: emitting {pluginName}-{event}", { + pluginName, + event, + }); + const self = this; + return new Promise((resolve, reject) => { + const timeoutHandler = setTimeout(() => { + reject("Timeout"); + }, timeoutSeconds * 1000); + self.emit( + event, + (args: any) => { + clearTimeout(timeoutHandler); + resolve(args); + }, + (args: any) => { + clearTimeout(timeoutHandler); + reject(args); + }, + args + ); + }); + } +} diff --git a/nodejs/src/plugins/events-test/events/emitStreamAndReceiveStream.ts b/nodejs/src/plugins/events-test/events/emitStreamAndReceiveStream.ts new file mode 100644 index 0000000..19e1784 --- /dev/null +++ b/nodejs/src/plugins/events-test/events/emitStreamAndReceiveStream.ts @@ -0,0 +1,91 @@ +import { EventEmitter } from "events"; +import { Readable } from "stream"; +import { randomUUID } from "crypto"; +import { IPluginLogger } from "../../../interfaces/logging"; + +export default class emitStreamAndReceiveStream extends EventEmitter { + // If we try receive or send a stream and the other party is not ready for some reason, we will automatically timeout in 5s. + private readonly staticCommsTimeout = 1000; + private log: IPluginLogger; + + constructor(log: IPluginLogger) { + super(); + this.log = log; + } + public dispose() { + this.removeAllListeners(); + } + + async receiveStream( + event: string, + listener: { (error: Error | null, stream: Readable): Promise }, + timeoutSeconds: number = 60 + ): Promise { + const streamId = `${randomUUID()}=${timeoutSeconds}`; + this.log.debug("receiveStream: listening to {streamId}", { + streamId, + }); + const self = this; + return new Promise((resolve) => { + const receiptTimeoutHandler: NodeJS.Timeout = setTimeout(() => { + const err = new Error("Receive Receipt Timeout"); + listener(err, null!); + self.emit(`${streamId}-error`, err); + self.removeAllListeners(streamId); + }, self.staticCommsTimeout); + self.once(streamId, (stream: Readable): void => { + clearTimeout(receiptTimeoutHandler); + self.emit(`${streamId}-emit`); + stream.on("error", (e) => { + self.emit(`${streamId}-error`, e); + }); + stream.on("end", () => { + self.emit(`${streamId}-end`); + }); + listener(null, stream); + }); + resolve(streamId); + }); + } + + async sendStream( + event: string, + streamId: string, + stream: Readable + ): Promise { + const self = this; + this.log.debug("sendStream: emitting _self-{streamId}", { streamId }); + return new Promise((resolve, rejectI) => { + const timeout = Number.parseInt(streamId.split("=")[1]); + const clearSessions = (e?: Error) => { + stream.destroy(e); + if (receiptTimeoutHandler !== null) clearTimeout(receiptTimeoutHandler); + receiptTimeoutHandler = null; + clearTimeout(timeoutHandler); + self.removeAllListeners(`${streamId}-emit`); + self.removeAllListeners(`${streamId}-end`); + self.removeAllListeners(`${streamId}-error`); + }; + const reject = (e: Error) => { + clearSessions(e); + rejectI(e); + }; + let receiptTimeoutHandler: NodeJS.Timeout | null = setTimeout(() => { + reject(new Error("Send Receipt Timeout")); + }, self.staticCommsTimeout); + const timeoutHandler = setTimeout(() => { + reject(new Error("Stream Timeout")); + }, timeout * 1000); + self.once(`${streamId}-emit`, () => { + if (receiptTimeoutHandler !== null) clearTimeout(receiptTimeoutHandler); + receiptTimeoutHandler = null; + }); + self.once(`${streamId}-end`, () => { + clearSessions(); + resolve(); + }); + self.once(`${streamId}-error`, (e: Error) => reject(e)); + self.emit(streamId, stream); + }); + } +} diff --git a/nodejs/src/plugins/events-test/plugin.ts b/nodejs/src/plugins/events-test/plugin.ts new file mode 100644 index 0000000..ee4fc9c --- /dev/null +++ b/nodejs/src/plugins/events-test/plugin.ts @@ -0,0 +1,96 @@ +import { Readable } from "stream"; +import emit from "./events/emit"; +import emitAndReturn from "./events/emitAndReturn"; +import emitStreamAndReceiveStream from "./events/emitStreamAndReceiveStream"; +import broadcast from "./events/broadcast"; +import { BSBEvents, BSBEventsConstructor } from "../../base/events"; + +export class Plugin extends BSBEvents { + init?(): void; + protected broadcast!: broadcast; + protected emit!: emit; + protected ear!: emitAndReturn; + protected eas!: emitStreamAndReceiveStream; + + constructor(config: BSBEventsConstructor) { + super(config); + + this.broadcast = new broadcast(this.createNewLogger("broadcast")); + this.emit = new emit(this.createNewLogger("emit")); + this.ear = new emitAndReturn(this.createNewLogger("emitAndReturn")); + this.eas = new emitStreamAndReceiveStream(this.createNewLogger("stream")); + } + + public dispose() { + this.broadcast.dispose(); + this.emit.dispose(); + this.ear.dispose(); + this.eas.dispose(); + } + + public async onBroadcast( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + await this.broadcast.onBroadcast(pluginName, event, listener); + } + public async emitBroadcast( + pluginName: string, + event: string, + args: Array + ): Promise { + await this.broadcast.emitBroadcast(pluginName, event, args); + } + + public async onEvent( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + await this.emit.onEvent(pluginName, event, listener); + } + public async emitEvent( + pluginName: string, + event: string, + args: Array + ): Promise { + await this.emit.emitEvent(pluginName, event, args); + } + + public async onReturnableEvent( + pluginName: string, + event: string, + listener: { (args: Array): Promise } + ): Promise { + await this.ear.onReturnableEvent(pluginName, event, listener); + } + public async emitEventAndReturn( + pluginName: string, + event: string, + timeoutSeconds: number, + args: Array + ): Promise { + return await this.ear.emitEventAndReturn( + pluginName, + event, + timeoutSeconds, + args + ); + } + + public async receiveStream( + event: string, + listener: { (error: Error | null, stream: Readable): Promise }, + timeoutSeconds?: number + ): Promise { + return this.eas.receiveStream(event, listener, timeoutSeconds); + } + public async sendStream( + event: string, + streamId: string, + stream: Readable + ): Promise { + return this.eas.sendStream(event, streamId, stream); + } +} diff --git a/nodejs/src/plugins/logging-default/plugin.ts b/nodejs/src/plugins/logging-default/plugin.ts index 4c20a5c..fadc0f2 100644 --- a/nodejs/src/plugins/logging-default/plugin.ts +++ b/nodejs/src/plugins/logging-default/plugin.ts @@ -1,8 +1,10 @@ -import { BSBLogging, BSBLoggingConstructor } from "../../base/logging"; -import { LogMeta } from "../../interfaces/logging"; +import { + LogMeta, + BSBLogging, + BSBLoggingConstructor, + LogFormatter, +} from "../../"; import { CONSOLE_COLOURS, ConsoleColours } from "./colours"; -import { LogFormatter } from "../../base/logFormatter"; -import { BSBConfigDefinition } from '../../'; export const LOG_LEVELS = { TSTAT: "Text Statistic", @@ -14,7 +16,7 @@ export const LOG_LEVELS = { } as const; export type LogLevels = (typeof LOG_LEVELS)[keyof typeof LOG_LEVELS]; -export class Plugin extends BSBLogging { +export class Plugin extends BSBLogging { dispose?(): void; init?(): void; private _mockedConsole?: { (level: LogLevels, message: string): void }; diff --git a/nodejs/src/plugins/service-default0/plugin.ts b/nodejs/src/plugins/service-default0/plugin.ts index e7886dd..f85640d 100644 --- a/nodejs/src/plugins/service-default0/plugin.ts +++ b/nodejs/src/plugins/service-default0/plugin.ts @@ -1,15 +1,36 @@ -import { - BSBService, - BSBServiceConstructor, - BSBServiceTypes, -} from "../../base/service"; -import { testClient } from "../service-default1/plugin"; -import { Config } from "./sec-config"; +import { BSBService, BSBServiceConstructor, BSBPluginConfig } from "../../"; +import { testClient } from "../service-default1"; +import { z } from "zod"; -export interface ServiceTypes extends BSBServiceTypes { - methods: { - abc: () => Promise; - }; +export const secSchema = z.object({ + testa: z.number(), + testb: z.number(), +}); +export class Config extends BSBPluginConfig { + validationSchema = secSchema; + + migrate( + toVersion: string, + fromVersion: string | null, + fromConfig: any | null + ) { + if (fromConfig === null) { + // defaults + return { + testa: 1, + testb: 2, + }; + } else { + // migrate + return { + testa: fromConfig.testa, + testb: fromConfig.testb, + }; + } + } +} + +export interface Events { emitEvents: { test: (a: string, b: string) => Promise; }; @@ -19,7 +40,8 @@ export interface ServiceTypes extends BSBServiceTypes { emitBroadcast: {}; onBroadcast: {}; } -export class Plugin extends BSBService { + +export class Plugin extends BSBService { public initBeforePlugins?: string[] | undefined; //public initAfterPlugins: string[] = ["service-default3"]; public initAfterPlugins?: string[] | undefined; diff --git a/nodejs/src/plugins/service-default0/sec-config.ts b/nodejs/src/plugins/service-default0/sec-config.ts deleted file mode 100644 index 137030e..0000000 --- a/nodejs/src/plugins/service-default0/sec-config.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { BSBServiceConfig } from "../../interfaces"; -import { z } from "zod"; - -export const secSchema = z.object({ - testa: z.number(), - testb: z.number(), -}); -export class Config extends BSBServiceConfig { - validationSchema = secSchema; - - migrate( - toVersion: string, - fromVersion: string | null, - fromConfig: any | null - ) { - if (fromConfig === null) { - // defaults - return { - testa: 1, - testb: 2, - }; - } else { - // migrate - return { - testa: fromConfig.testa, - testb: fromConfig.testb, - }; - } - } -} diff --git a/nodejs/src/plugins/service-default1/index.ts b/nodejs/src/plugins/service-default1/index.ts new file mode 100644 index 0000000..26dcc6b --- /dev/null +++ b/nodejs/src/plugins/service-default1/index.ts @@ -0,0 +1,36 @@ +import { BSBServiceClient } from "../../"; +import { Plugin } from "./plugin"; + +export class testClient extends BSBServiceClient { + public initBeforePlugins?: string[] | undefined; + public initAfterPlugins?: string[] | undefined; + public runBeforePlugins?: string[] | undefined; + public runAfterPlugins?: string[] | undefined; + public dispose?(): void; + public run?(): Promise; + public readonly pluginName: string = "service-default1"; + private count = 0; + public async init(): Promise { + this.events.onEvent("onEmittable", async (a: number, b: number) => { + this.log.warn("onEmittable ({a},{b})", { a, b }); + }); + this.events.onReturnableEvent( + "onReverseReturnable", + async (a: number, b: number) => { + this.count++; + console.log("called: " + this.count); + this.log.warn("onReverseReturnable ({a},{b})", { a, b }); + return a * b; + } + ); + await this.events.emitEvent("onReceivable", 56, 7); + } + async abc(a: number, b: number, c: number, d: number): Promise { + this.log.warn("TESTING ABC CALL ({result})", { + result: await this.callMethod("callableMethod", a, b), + }); + this.log.warn("TESTING onReturnable ({result})", { + result: await this.events.emitEventAndReturn("onReturnable", 5, c, d), + }); + } +} diff --git a/nodejs/src/plugins/service-default1/plugin.ts b/nodejs/src/plugins/service-default1/plugin.ts index 1420536..03117b5 100644 --- a/nodejs/src/plugins/service-default1/plugin.ts +++ b/nodejs/src/plugins/service-default1/plugin.ts @@ -1,10 +1,6 @@ -import { BSBService, BSBServiceTypes } from "../../base/service"; -import { BSBServiceClient } from "../../base/serviceClient"; +import { BSBService, BSBPluginEvents } from "../../"; -export interface ServiceTypes extends BSBServiceTypes { - methods: { - callableMethod(a: number, b: number): Promise; - }; +export interface Events extends BSBPluginEvents { emitEvents: { onEmittable(a: number, b: number): Promise; }; @@ -21,7 +17,7 @@ export interface ServiceTypes extends BSBServiceTypes { onBroadcast: {}; } -export class Plugin extends BSBService { +export class Plugin extends BSBService { public initBeforePlugins?: string[] | undefined; public initAfterPlugins?: string[] | undefined; public runBeforePlugins?: string[] | undefined; @@ -41,7 +37,7 @@ export class Plugin extends BSBService { this.log.info("INIT SERVICE"); this.events.onEvent("onReceivable", async (a: number, b: number) => { this.count++; - console.log('calledI: ' + this.count); + console.log("calledI: " + this.count); this.log.warn("received onReceivable ({a},{b}", { a, b }); //process.exit(3); }); @@ -63,37 +59,3 @@ export class Plugin extends BSBService { ); } } - -export class testClient extends BSBServiceClient { - public initBeforePlugins?: string[] | undefined; - public initAfterPlugins?: string[] | undefined; - public runBeforePlugins?: string[] | undefined; - public runAfterPlugins?: string[] | undefined; - public dispose?(): void; - public run?(): Promise; - public readonly pluginName: string = "service-default1"; - private count = 0; - public async init(): Promise { - this.events.onEvent("onEmittable", async (a: number, b: number) => { - this.log.warn("onEmittable ({a},{b})", { a, b }); - }); - this.events.onReturnableEvent( - "onReverseReturnable", - async (a: number, b: number) => { - this.count++; - console.log('called: ' + this.count); - this.log.warn("onReverseReturnable ({a},{b})", { a, b }); - return a * b; - } - ); - await this.events.emitEvent("onReceivable", 56, 7); - } - async abc(a: number, b: number, c: number, d: number): Promise { - this.log.warn("TESTING ABC CALL ({result})", { - result: await this.callMethod("callableMethod", a, b), - }); - this.log.warn("TESTING onReturnable ({result})", { - result: await this.events.emitEventAndReturn("onReturnable", 5, c, d), - }); - } -} diff --git a/nodejs/src/plugins/service-default2/plugin.ts b/nodejs/src/plugins/service-default2/plugin.ts index a1dcb1a..eeb15f5 100644 --- a/nodejs/src/plugins/service-default2/plugin.ts +++ b/nodejs/src/plugins/service-default2/plugin.ts @@ -1,7 +1,7 @@ -import { BSBService, BSBServiceConstructor } from "../../base/service"; -import { testClient } from "../service-default1/plugin"; +import { BSBService, BSBServiceConstructor } from "../../"; +import { testClient } from "../service-default1"; -export class Plugin extends BSBService { +export class Plugin extends BSBService { public initBeforePlugins?: string[] | undefined; public runBeforePlugins?: string[] | undefined; public runAfterPlugins?: string[] | undefined; diff --git a/nodejs/src/plugins/service-default2/sec.config.ts b/nodejs/src/plugins/service-default2/sec.config.ts deleted file mode 100644 index 8a34438..0000000 --- a/nodejs/src/plugins/service-default2/sec.config.ts +++ /dev/null @@ -1,19 +0,0 @@ -// import { SecConfig } from "../../interfaces/serviceConfig"; -// import { IPluginConfig } from "../../interfaces/config"; - -// export interface PluginConfig extends IPluginConfig { -// testa: number -// testb: number -// } - -// export class Config extends SecConfig { -// migrate( -// mappedPluginName: string, -// existingConfig: PluginConfig -// ): PluginConfig { -// return { -// testa: existingConfig.testa || 6, // this value gets a default value -// testb: 5 // this value is unchangable -// }; -// } -// } diff --git a/nodejs/src/plugins/service-default3/plugin.ts b/nodejs/src/plugins/service-default3/plugin.ts index 11a0021..12f5a9a 100644 --- a/nodejs/src/plugins/service-default3/plugin.ts +++ b/nodejs/src/plugins/service-default3/plugin.ts @@ -1,7 +1,7 @@ -import { BSBService, BSBServiceConstructor } from "../../base/service"; -import { testClient } from "../service-default1/plugin"; +import { BSBService, BSBServiceConstructor } from "../../"; +import { testClient } from "../service-default1"; -export class Plugin extends BSBService { +export class Plugin extends BSBService { public initBeforePlugins?: string[] | undefined; public runBeforePlugins?: string[] | undefined; public runAfterPlugins?: string[] | undefined; diff --git a/nodejs/src/plugins/service-default3/sec.config.ts b/nodejs/src/plugins/service-default3/sec.config.ts deleted file mode 100644 index 8a34438..0000000 --- a/nodejs/src/plugins/service-default3/sec.config.ts +++ /dev/null @@ -1,19 +0,0 @@ -// import { SecConfig } from "../../interfaces/serviceConfig"; -// import { IPluginConfig } from "../../interfaces/config"; - -// export interface PluginConfig extends IPluginConfig { -// testa: number -// testb: number -// } - -// export class Config extends SecConfig { -// migrate( -// mappedPluginName: string, -// existingConfig: PluginConfig -// ): PluginConfig { -// return { -// testa: existingConfig.testa || 6, // this value gets a default value -// testb: 5 // this value is unchangable -// }; -// } -// } diff --git a/nodejs/src/serviceBase/config.ts b/nodejs/src/serviceBase/config.ts index f4fc380..46eb160 100644 --- a/nodejs/src/serviceBase/config.ts +++ b/nodejs/src/serviceBase/config.ts @@ -1,5 +1,5 @@ import { DEBUG_MODE, IPluginLogger } from "../interfaces/logging"; -import { Plugin as Config } from "../plugins/config-default/plugin"; +import { Plugin as DefaultConfig } from "../plugins/config-default/plugin"; import { SBPlugins } from "./plugins"; import { SBLogging } from "./logging"; import { PluginLogger } from "../base/PluginLogger"; @@ -38,14 +38,14 @@ export class SBConfig { this.sbLogging = sbLogging; this.sbPlugins = sbPlugins; this.log = new PluginLogger(mode, "sb-config", sbLogging); - this.configPlugin = new Config( + this.configPlugin = new DefaultConfig({ appId, mode, - "sb-config", + pluginName: "sb-config", cwd, - cwd, - sbLogging - ); + pluginCwd: cwd, + sbLogging, + }); } public async getPluginConfig(pluginType: PluginType, name: string) { @@ -73,14 +73,14 @@ export class SBConfig { private configPluginName = "config-default"; public async setConfigPlugin(reference: LoadedPlugin<"config">) { - this.configPlugin = new reference.plugin( - this.appId, - this.mode, - reference.name, - this.cwd, - reference.pluginCWD, - this.sbLogging - ); + this.configPlugin = new reference.plugin({ + appId: this.appId, + mode: this.mode, + pluginName: reference.name, + cwd: this.cwd, + pluginCwd: reference.pluginCWD, + sbLogging: this.sbLogging, + }); this.log.info("Adding {pluginName} as config", { pluginName: reference.name, }); diff --git a/nodejs/src/serviceBase/events.ts b/nodejs/src/serviceBase/events.ts index 8e87632..7f83caa 100644 --- a/nodejs/src/serviceBase/events.ts +++ b/nodejs/src/serviceBase/events.ts @@ -153,7 +153,7 @@ export class SBEvents { pluginName: "events-default", cwd: this.cwd, pluginCwd: this.cwd, - config: {}, + config: null, sbLogging, }), on: undefined, @@ -184,7 +184,7 @@ export class SBEvents { sbLogging: SBLogging, plugin: IPluginDefinition, reference: LoadedPlugin<"events">, - config: object | null, + config: any, filter?: EventsFilter ) { this.log.debug(`Get plugin config: {name}`, { @@ -284,18 +284,19 @@ export class SBEvents { return; } - let pluginConfig = await sbConfig.getPluginConfig("events", plugin.name); + let pluginConfig = + (await sbConfig.getPluginConfig("events", plugin.name)) ?? null; if ( + this.mode !== "production" && !Tools.isNullOrUndefined(newPlugin) && !Tools.isNullOrUndefined(newPlugin.serviceConfig) && Tools.isObject(newPlugin.serviceConfig) && !Tools.isNullOrUndefined(newPlugin.serviceConfig.validationSchema) ) { + this.log.debug("Validate plugin config: {name}", { name: plugin.name }); pluginConfig = newPlugin.serviceConfig.validationSchema.parse(pluginConfig); - } else if (Tools.isNullOrUndefined(pluginConfig)) { - pluginConfig = {}; } await this.addPlugin(sbLogging, plugin, newPlugin, pluginConfig, filter); diff --git a/nodejs/src/serviceBase/logging.ts b/nodejs/src/serviceBase/logging.ts index 1a2ec0b..5bb8cd9 100644 --- a/nodejs/src/serviceBase/logging.ts +++ b/nodejs/src/serviceBase/logging.ts @@ -5,25 +5,21 @@ import { LoggingEventTypes, LoggingEventTypesBase, LoggingEventTypesExlReportStat, -} from "../interfaces/logging"; -import { Plugin as DefaultLogger } from "../plugins/logging-default/plugin"; -import { BSBLogging } from "../base/logging"; -import { PluginLogger } from "../base/PluginLogger"; -import { EventEmitter } from "stream"; -import { + BSBLogging, + PluginLogger, FilterOnType, IPluginDefinition, LoggingFilter, LoggingFilterDetailed, -} from "../interfaces/plugins"; -import { SBPlugins } from "./plugins"; -import { SBConfig } from "./config"; -import { + SBPlugins, + SBConfig, SmartFunctionCallAsync, SmartFunctionCallSync, -} from "../base/functions"; -import { LoadedPlugin } from "../interfaces"; -import { Tools } from '@bettercorp/tools/lib/Tools'; + LoadedPlugin, +} from "../"; +import { Plugin as DefaultLogger } from "../plugins/logging-default/plugin"; +import { EventEmitter } from "stream"; +import { Tools } from "@bettercorp/tools/lib/Tools"; export class SBLogging { private loggers: Array<{ @@ -55,7 +51,7 @@ export class SBLogging { pluginName: "logging-default", cwd: this.cwd, pluginCwd: this.cwd, - config: {}, + config: null, }), onTypeof: "all", }); @@ -257,7 +253,7 @@ export class SBLogging { public async addPlugin( plugin: IPluginDefinition, reference: LoadedPlugin<"logging">, - config: object | null, + config: any, filter?: LoggingFilter ) { this.log.debug(`Construct logging plugin: {name}`, { @@ -354,18 +350,19 @@ export class SBLogging { name: plugin.name, }); - let pluginConfig = await sbConfig.getPluginConfig("logging", plugin.name); + let pluginConfig = + (await sbConfig.getPluginConfig("logging", plugin.name)) ?? null; if ( + this.mode !== "production" && !Tools.isNullOrUndefined(newPlugin) && !Tools.isNullOrUndefined(newPlugin.serviceConfig) && Tools.isObject(newPlugin.serviceConfig) && !Tools.isNullOrUndefined(newPlugin.serviceConfig.validationSchema) ) { + this.log.debug("Validate plugin config: {name}", { name: plugin.name }); pluginConfig = newPlugin.serviceConfig.validationSchema.parse(pluginConfig); - } else if (Tools.isNullOrUndefined(pluginConfig)) { - pluginConfig = {}; } await this.addPlugin(plugin, newPlugin, pluginConfig, filter); diff --git a/nodejs/src/serviceBase/plugins.ts b/nodejs/src/serviceBase/plugins.ts index 0c75fcd..bf9ff5d 100644 --- a/nodejs/src/serviceBase/plugins.ts +++ b/nodejs/src/serviceBase/plugins.ts @@ -1,13 +1,14 @@ import { existsSync, readFileSync } from "fs"; import { join } from "path"; -import { PluginType, PluginTypeDefinitionRef } from "../interfaces/plugins"; -import { IPluginLogger } from "../interfaces/logging"; -import { BSBError } from "../base/errorMessages"; import { - BSBServiceConfig, - BSBServiceConfigRef, + PluginType, + PluginTypeDefinitionRef, + IPluginLogger, + BSBError, LoadedPlugin, -} from "../interfaces"; + BSBPluginConfig, + BSBPluginConfigRef, +} from "../"; export class SBPlugins { protected cwd: string; @@ -78,8 +79,7 @@ export class SBPlugins { }); let pluginFile = join(pluginPath, "./plugin.js"); - let configDefFile: string | null = null; - let serviceConfigDef: BSBServiceConfig | null = null; + let serviceConfigDef: BSBPluginConfig | null = null; //if (this.devMode) { const tsPluginFile = join(pluginPath, "./plugin.ts"); if (existsSync(tsPluginFile)) { @@ -88,42 +88,6 @@ export class SBPlugins { }); pluginFile = tsPluginFile; } - // sec-.ts - configDefFile = join(pluginPath, "./sec-config.js"); - const tsInstallerFile = join(pluginPath, "./sec-config.ts"); - if (existsSync(tsInstallerFile)) { - log.debug("PLUGIN {pluginName} running development mode installer", { - pluginName: name, - }); - configDefFile = tsInstallerFile; - } else if (!existsSync(configDefFile)) { - log.debug("PLUGIN {pluginName} does not have an installer file", { - pluginName: name, - }); - configDefFile = null; - } else { - log.debug("PLUGIN {pluginName} does not have an installer file", { - pluginName: name, - }); - } - - if (configDefFile !== null) { - const importedConfig = await import(configDefFile); - if (importedConfig.Config === undefined) - throw new BSBError( - "PLUGIN {pluginName} sec-config.ts/js does not export a Config class - so possibly not a valid BSB Plugin Config", - { - pluginName: name, - } - ); - serviceConfigDef = - new (importedConfig.Config as typeof BSBServiceConfigRef)( - this.cwd, - pluginCWD, - name - ); - } - //} if (!existsSync(pluginFile)) throw new BSBError("PLUGIN {pluginName} not found at {location}", { @@ -140,6 +104,13 @@ export class SBPlugins { pluginName: name, } ); + if (importedPlugin.Config !== undefined) + serviceConfigDef = + new (importedPlugin.Config as typeof BSBPluginConfigRef)( + this.cwd, + pluginCWD, + name + ); return { name: name, diff --git a/nodejs/src/serviceBase/serviceBase.ts b/nodejs/src/serviceBase/serviceBase.ts index aa42ac7..6c11af8 100644 --- a/nodejs/src/serviceBase/serviceBase.ts +++ b/nodejs/src/serviceBase/serviceBase.ts @@ -1,19 +1,25 @@ -import { DEBUG_MODE, IPluginLogger, LogMeta } from "../interfaces/logging"; -import { SBLogging } from "./logging"; -import { SBPlugins } from "./plugins"; -import { SBServices } from "./services"; -import { IDictionary } from "@bettercorp/tools/lib/Interfaces"; -import { SBConfig } from "./config"; +import { + DEBUG_MODE, + IPluginLogger, + LogMeta, + SBLogging, + SBPlugins, + SBServices, + SBConfig, + PluginLogger, + SmartFunctionCallSync, + SBEvents, + PluginTypeDefinitionRef, + BSBConfig, + BSBError, + BSBLogging, + BSBEvents, + BSBService, +} from "../"; +import { Tools } from "@bettercorp/tools/lib/Tools"; import { randomUUID } from "crypto"; import { hostname } from "os"; -import { Tools } from "@bettercorp/tools/lib/Tools"; -import { PluginLogger } from "../base/PluginLogger"; -import { SmartFunctionCallSync } from "../base/functions"; -import { SBEvents } from "./events"; -import { PluginTypeDefinitionRef } from "../interfaces"; -import { BSBConfig, BSBError, BSBLogging } from "../base"; -import { BSBEvents } from "../base"; -import { BSBService } from "../base"; +import { IDictionary } from "@bettercorp/tools/lib/Interfaces"; export const BOOT_STAT_KEYS = { BSB: "BSB", diff --git a/nodejs/src/serviceBase/services.ts b/nodejs/src/serviceBase/services.ts index 91b2015..dabaddd 100644 --- a/nodejs/src/serviceBase/services.ts +++ b/nodejs/src/serviceBase/services.ts @@ -1,20 +1,20 @@ -import { BSBService } from "../base/service"; -import { PluginLogger } from "../base/PluginLogger"; -import { IPluginLogger } from "../interfaces/logging"; -import { DEBUG_MODE } from "../interfaces/logging"; -import { SBConfig } from "./config"; -import { SBEvents } from "./events"; import { + BSBService, + PluginLogger, + IPluginLogger, + DEBUG_MODE, + SBConfig, + SBEvents, SmartFunctionCallAsync, SmartFunctionCallSync, -} from "../base/functions"; -import { SBLogging } from "./logging"; -import { SBPlugins } from "./plugins"; -import { IPluginDefinition } from "../interfaces/plugins"; -import { BSBError } from "../base/errorMessages"; -import { BSBServiceClient } from "../base/serviceClient"; -import { PluginEvents } from "../base/PluginEvents"; -import { LoadedPlugin } from "../interfaces"; + SBLogging, + SBPlugins, + IPluginDefinition, + BSBError, + BSBServiceClient, + PluginEvents, + LoadedPlugin, +} from "../"; import { Tools } from "@bettercorp/tools/lib/Tools"; export class SBServices { @@ -134,7 +134,7 @@ export class SBServices { sbEvents: SBEvents, plugin: IPluginDefinition, reference: LoadedPlugin<"service">, - config: object | null + config: any ) { this.log.debug(`Construct service plugin: {name}`, { name: plugin.name, @@ -225,18 +225,19 @@ export class SBServices { name: plugin.name, }); - let pluginConfig = await sbConfig.getPluginConfig("service", plugin.name); + let pluginConfig = + (await sbConfig.getPluginConfig("service", plugin.name)) ?? null; if ( + this.mode !== "production" && !Tools.isNullOrUndefined(newPlugin) && !Tools.isNullOrUndefined(newPlugin.serviceConfig) && Tools.isObject(newPlugin.serviceConfig) && !Tools.isNullOrUndefined(newPlugin.serviceConfig.validationSchema) ) { + this.log.debug("Validate plugin config: {name}", { name: plugin.name }); pluginConfig = newPlugin.serviceConfig.validationSchema.parse(pluginConfig); - } else if (Tools.isNullOrUndefined(pluginConfig)) { - pluginConfig = {}; } await this.addPlugin( @@ -259,7 +260,7 @@ export class SBServices { if (contextPlugin.enabled) { const referencedServiceContext = this._activeServices.find( (x) => x.pluginName === contextPlugin.name - ) as BSBService; + ) as BSBService; if (referencedServiceContext === undefined) { throw new BSBError( "The plugin {plugin} is not enabled so you cannot call methods from it", diff --git a/nodejs/src/tests.ts b/nodejs/src/tests.ts new file mode 100644 index 0000000..ee6a258 --- /dev/null +++ b/nodejs/src/tests.ts @@ -0,0 +1 @@ +export * from "./tests/sb/plugins/events/plugin"; diff --git a/nodejs/src/tests/events.x.ts.txt b/nodejs/src/tests/events.x.ts.txt deleted file mode 100644 index 632e2e4..0000000 --- a/nodejs/src/tests/events.x.ts.txt +++ /dev/null @@ -1,91 +0,0 @@ -import { DynamicallyReferencedMethodType } from '@bettercorp/tools/lib/Interfaces'; -import { DynamicPluginsList } from '../src/interfaces/DynamicPluginsList'; -import { IPluginEvents, DynamicallyReferencedMethodOnIEvents, DynamicallyReferencedMethodEmitIEvents, DynamicallyReferencedMethodEmitEARIEvents } from '../src/interfaces/events'; - -interface testEmit { - sendEvent(a: boolean): Promise; -} -interface testEmit2 { - onSend(a: boolean): Promise; -} -interface testEmit3 { - onEar(a: boolean): Promise; -} -interface testEmi23 { - eEar(a: boolean): Promise; -} - -class aaa { - events: IPluginEvents = { - onEvent: async ( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - false - > - ) => {}, - onReturnableEvent: async ( - ...args: DynamicallyReferencedMethodOnIEvents< - DynamicallyReferencedMethodType, - TA, - true - > - ) => {}, - emitEvent: async ( - ...args: DynamicallyReferencedMethodEmitIEvents< - DynamicallyReferencedMethodType, - TA - > - ) => {}, - emitEventAndReturn: ( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - false - > - ) => { - return 1 as any; - }, - emitEventAndReturnTimed: ( - ...args: DynamicallyReferencedMethodEmitEARIEvents< - DynamicallyReferencedMethodType, - TA, - true, - true - > - ) => { - return 1 as any; - }, - receiveStream: async ( - listener: { (error: Error | null, stream: any): Promise }, - timeoutSeconds?: number - ): Promise => { - return ""; - }, - sendStream: async (streamId: string, stream: any): Promise => {}, - }; - - public async testt() { - this.events.emitEvent(DynamicPluginsList.bsbDemoPlugin, "sendEvent", false); - this.events.onEvent( - DynamicPluginsList.bsbDemoPlugin, - "onSend", - async (a: boolean): Promise => { - return; - } - ); - this.events.onReturnableEvent( - DynamicPluginsList.bsbDemoPlugin, - "onEar", - async (a: boolean): Promise => { - return true; - } - ); - await this.events.emitEventAndReturn( - DynamicPluginsList.bsbDemoPlugin, - "eEar", - true - ); - } -} diff --git a/nodejs/src/tests/logger.js b/nodejs/src/tests/logger.js deleted file mode 100644 index ff2b7f4..0000000 --- a/nodejs/src/tests/logger.js +++ /dev/null @@ -1,43 +0,0 @@ -const events = require('../lib/events/events').Events; - -const logger_Def = require("../lib/logger/logger").Logger; -const testogger = require('./virt-clientLogger.ts.txt').testogger; -const emit = require('./events/emit').default; -const emitAndReturn = require('./events/emitAndReturn').default; -const emitStreamAndReceiveStream = require('./events/emitStreamAndReceiveStream').default; - -const fakeLogger = new testogger('test-plugin', process.cwd(), - new logger_Def('test-plugin', process.cwd(), null, { - runningInDebug: false - }), null, { - error: (e) => assert.fail(new Error(e)), - fatal: (e) => assert.fail(new Error(e)) - }); - -describe('Logger', () => { - emit(async () => { - const refP = new events('test-plugin', process.cwd(), fakeLogger, { - runningInDebug: true - }); - if (refP.init !== undefined) - await refP.init(); - return refP; - }, 10); - emitAndReturn(async () => { - const refP = new events('test-plugin', process.cwd(), fakeLogger, { - runningInDebug: true - }); - if (refP.init !== undefined) - await refP.init(); - return refP; - }, 10); - emitStreamAndReceiveStream(async () => { - const refP = new events('test-plugin', process.cwd(), fakeLogger, { - runningInDebug: true - }); - if (refP.init !== undefined) - await refP.init(); - refP.eas.staticCommsTimeout = 25; - return refP; - }, 50); -}); \ No newline at end of file diff --git a/nodejs/src/tests/logger/logFormatter.ts b/nodejs/src/tests/logger/logFormatter.ts index 37e3a1d..c768dca 100644 --- a/nodejs/src/tests/logger/logFormatter.ts +++ b/nodejs/src/tests/logger/logFormatter.ts @@ -4,58 +4,58 @@ import { LogFormatter } from "../../base"; describe("logFormatter", function () { describe("formatLog", function () { it("Should return string when meta is undefined", async () => { - let ojb = new LogFormatter(); + const ojb = new LogFormatter(); assert.strictEqual(ojb.formatLog("TEST"), "TEST"); }); it("Should return string when meta is null", async () => { - let ojb = new LogFormatter(); + const ojb = new LogFormatter(); assert.strictEqual(ojb.formatLog("TEST", null as any), "TEST"); // ts picks up this issue }); it("Should return string when meta is a string", async () => { - let ojb = new LogFormatter(); + const ojb = new LogFormatter(); assert.strictEqual(ojb.formatLog("TEST", ""), "TEST"); }); it("Should return string when meta is a number", async () => { - let ojb = new LogFormatter(); + const ojb = new LogFormatter(); assert.strictEqual(ojb.formatLog("TEST", 5), "TEST"); }); it("Should format correctly", async () => { - let ojb = new LogFormatter(); + const ojb = new LogFormatter(); assert.strictEqual(ojb.formatLog("HTEST {a}", { a: "B" }), "HTEST B"); }); it("Should format *null/undefined* when a value found doesnt exist", async () => { - let ojb = new LogFormatter(); + const ojb = new LogFormatter(); assert.strictEqual( ojb.formatLog("HTEST {a}", {} as any), // ts picks up this issue "HTEST *null/undefined*" ); }); it("Should format *null/undefined* when a value found is undefined", async () => { - let ojb = new LogFormatter(); + const ojb = new LogFormatter(); assert.strictEqual( ojb.formatLog("HTEST {a}", { a: undefined } as any), // ts picks up this issue "HTEST *null/undefined*" ); }); it("Should format DT in ISO when a value found is a date", async () => { - let ojb = new LogFormatter(); - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + const ojb = new LogFormatter(); + const dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT assert.strictEqual( ojb.formatLog("HTEST {f}", { f: dt }), "HTEST 2023-07-22T15:38:30.000Z" ); }); it("Should format DT in ISO when a value found is a date 2", async () => { - let ojb = new LogFormatter(); - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + const ojb = new LogFormatter(); + const dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT assert.strictEqual( ojb.formatLog("HTEST {f}@{e}", { e: "DD", f: dt }), "HTEST 2023-07-22T15:38:30.000Z@DD" ); }); it("Should fail to format DT when a value found is inside an object", async () => { - let ojb = new LogFormatter(); - let dt = new Date(1689694710000); // 18 Jul 2023 15:38:30 GMT + const ojb = new LogFormatter(); + const dt = new Date(1689694710000); // 18 Jul 2023 15:38:30 GMT assert.strictEqual( ojb.formatLog("HTEST {f.y}@{e}", { e: "DD", f: { y: dt } } as any), // ts picks up this issue "HTEST *null/undefined*@DD" @@ -75,16 +75,16 @@ describe("logFormatter", function () { // ); // ts picks up this issue // }); it("Should format json when a value found is an object", async () => { - let ojb = new LogFormatter(); - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + const ojb = new LogFormatter(); + const dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT assert.strictEqual( ojb.formatLog("HTEST {f}@{e}", { e: "DD", f: { y: dt } }), 'HTEST {"y":"2023-07-22T15:38:30.000Z"}@DD' ); }); it("Should format direct date", async () => { - let ojb = new LogFormatter(); - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + const ojb = new LogFormatter(); + const dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT assert.strictEqual( ojb.formatLog("{y}", { y: dt }), "2023-07-22T15:38:30.000Z" @@ -99,13 +99,13 @@ describe("logFormatter", function () { d instanceof Date && !isNaN(d.getTime()) && d.toISOString() === str ); // valid date }; - let ojb = new LogFormatter(); - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + const ojb = new LogFormatter(); + const dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT assert.strictEqual(isIsoDate(ojb.formatLog("{y}", { y: dt })), true); }); it("Should format json when a value found is an array", async () => { - let ojb = new LogFormatter(); - let dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT + const ojb = new LogFormatter(); + const dt = new Date(1690040310000); // Sat, 22 Jul 2023 15:38:30 GMT assert.strictEqual( ojb.formatLog("HTEST {f}@{e}:{a}", { a: ["E", "F"], diff --git a/nodejs/src/tests/plugins/events-default/plugin.ts b/nodejs/src/tests/plugins/events-default/plugin.ts new file mode 100644 index 0000000..df18275 --- /dev/null +++ b/nodejs/src/tests/plugins/events-default/plugin.ts @@ -0,0 +1,70 @@ +import assert from "assert"; +import { Plugin } from "../../../plugins/events-default/plugin"; +import { emit as emitDirect } from "../../../plugins/events-default/events/emit"; +import { randomUUID } from "crypto"; +import { + RunEventsPluginTests, + generateNullLogging, +} from "../../../tests/sb/plugins/events/plugin"; + +describe("plugins/events-default", () => { + describe("Events Emit", async () => { + it("_lastReceivedMessageIds should be empty on init", async () => { + const emit = new emitDirect(generateNullLogging()); + assert.equal((emit as any)._lastReceivedMessageIds.length, 0); + }); + it("_lastReceivedMessageIds should contain latest emit ID", async () => { + const emit = new emitDirect(generateNullLogging()); + await emit.onEvent("b", "c", async () => {}); + await emit.emitEvent("b", "c", []); + assert.equal((emit as any)._lastReceivedMessageIds.length, 1); + }); + it("_lastReceivedMessageIds should call only once", async () => { + const emit = new emitDirect(generateNullLogging()); + const testID = randomUUID(); + let called = 0; + await emit.onEvent("b", "c", async () => { + called++; + }); + emit.emit(`b-c`, { + msgID: testID, + data: [], + }); + assert.equal(called, 1); + }); + it("_lastReceivedMessageIds should call only once, per id", async () => { + const emit = new emitDirect(generateNullLogging()); + const testID1 = randomUUID(); + const testID2 = randomUUID(); + let called = 0; + await emit.onEvent("b", "c", async () => { + called++; + }); + emit.emit(`b-c`, { + msgID: testID1, + data: [], + }); + emit.emit(`b-c`, { + msgID: testID2, + data: [], + }); + assert.equal(called, 2); + }); + it("_lastReceivedMessageIds should cycle ids > 50", async () => { + const emit = new emitDirect(generateNullLogging()); + const testIDs: Array = "." + .repeat(100) + .split("") + .map(() => randomUUID()); + await emit.onEvent("b", "c", async () => {}); + for (const emitID of testIDs) + emit.emit(`b-c`, { + msgID: emitID, + data: [], + }); + assert.equal((emit as any)._lastReceivedMessageIds.length, 51); + }); + }); + + RunEventsPluginTests(Plugin); +}); diff --git a/nodejs/src/tests/plugins/events/plugin.ts b/nodejs/src/tests/plugins/events/plugin.ts deleted file mode 100644 index fca99c7..0000000 --- a/nodejs/src/tests/plugins/events/plugin.ts +++ /dev/null @@ -1,118 +0,0 @@ -import assert from "assert"; -//import { Logger } from "./test-logger"; -import { Plugin as events } from "../../../plugins/events-default/plugin"; -import * as emitDirect from "../../../plugins/events-default/events/emit"; -import { broadcast } from "./events/broadcast"; -import { emit } from "./events/emit"; -import { emitAndReturn } from "./events/emitAndReturn"; -import { emitStreamAndReceiveStream } from "./events/emitStreamAndReceiveStream"; -import { randomUUID } from "crypto"; -import { BSBEventsConstructor, PluginLogger } from "../../../base"; -import { SBLogging } from "../../../serviceBase"; - -const newSBLogging = () => { - const sbLogging = new SBLogging( - "test-app", - "development", - process.cwd(), - {} as any - ); - sbLogging.logBus.removeAllListeners(); - return sbLogging; -}; -const generateNullLogging = () => { - const sbLogging = newSBLogging(); - return new PluginLogger("development", "test-plugin", sbLogging); -}; -const getEventsConstructorConfig = (): BSBEventsConstructor => { - return { - appId: "test-app", - pluginCwd: process.cwd(), - cwd: process.cwd(), - mode: "development", - pluginName: "test-plugin", - sbLogging: newSBLogging(), - config: {}, - }; -}; - -describe("plugins/events-default", () => { - describe("Events Emit", async () => { - it("_lastReceivedMessageIds should be empty on init", async () => { - let emit = new emitDirect.default(generateNullLogging()); - assert.equal((emit as any)._lastReceivedMessageIds.length, 0); - }); - it("_lastReceivedMessageIds should contain latest emit ID", async () => { - let emit = new emitDirect.default(generateNullLogging()); - await emit.onEvent("b", "c", async () => {}); - await emit.emitEvent("b", "c", []); - assert.equal((emit as any)._lastReceivedMessageIds.length, 1); - }); - it("_lastReceivedMessageIds should call only once", async () => { - let emit = new emitDirect.default(generateNullLogging()); - let testID = randomUUID(); - let called = 0; - await emit.onEvent("b", "c", async () => { - called++; - }); - emit.emit(`b-c`, { - msgID: testID, - data: [], - }); - assert.equal(called, 1); - }); - it("_lastReceivedMessageIds should call only once, per id", async () => { - let emit = new emitDirect.default(generateNullLogging()); - let testID1 = randomUUID(); - let testID2 = randomUUID(); - let called = 0; - await emit.onEvent("b", "c", async () => { - called++; - }); - emit.emit(`b-c`, { - msgID: testID1, - data: [], - }); - emit.emit(`b-c`, { - msgID: testID2, - data: [], - }); - assert.equal(called, 2); - }); - it("_lastReceivedMessageIds should cycle ids > 50", async () => { - let emit = new emitDirect.default(generateNullLogging()); - let testIDs: Array = "." - .repeat(100) - .split("") - .map(() => randomUUID()); - await emit.onEvent("b", "c", async () => {}); - for (let emitID of testIDs) - emit.emit(`b-c`, { - msgID: emitID, - data: [], - }); - assert.equal((emit as any)._lastReceivedMessageIds.length, 51); - }); - }); - broadcast(async () => { - const refP = new events(getEventsConstructorConfig()); - if (refP.init !== undefined) await refP.init(); - return refP; - }, 10); - emit(async () => { - const refP = new events(getEventsConstructorConfig()); - if (refP.init !== undefined) await refP.init(); - return refP; - }, 10); - emitAndReturn(async () => { - const refP = new events(getEventsConstructorConfig()); - if (refP.init !== undefined) await refP.init(); - return refP; - }, 10); - emitStreamAndReceiveStream(async () => { - const refP = new events(getEventsConstructorConfig()); - if (refP.init !== undefined) await refP.init(); - //refP.eas.staticCommsTimeout = 25; - return refP; - }, 50); -}); diff --git a/nodejs/src/tests/plugins/log-default/plugin.ts b/nodejs/src/tests/plugins/logging-default/plugin.ts similarity index 95% rename from nodejs/src/tests/plugins/log-default/plugin.ts rename to nodejs/src/tests/plugins/logging-default/plugin.ts index 827b7f1..781845c 100644 --- a/nodejs/src/tests/plugins/log-default/plugin.ts +++ b/nodejs/src/tests/plugins/logging-default/plugin.ts @@ -16,13 +16,13 @@ const getLoggingConstructorConfig = ( cwd: process.cwd(), mode: mode, pluginName: "test-plugin", - config: {}, + config: undefined, }; }; -describe("plugins/log-default", () => { +describe("plugins/logging-default", () => { describe("console.x", () => { - let tempCCStore: any = { + const tempCCStore: any = { log: null, error: null, warn: null, @@ -37,37 +37,37 @@ describe("plugins/log-default", () => { expectMessageContent?: Array ) => { consoleEventCalled = 0; - for (let consol of listOfConsoles) + for (const consol of listOfConsoles) tempCCStore[consol] = (console as any)[consol]; if (expectMessageContent !== undefined) { consoleExpectMessageContent = { expectMessageContent, logs: [], }; - for (let consol of listOfConsoles.filter((x) => x !== expect)) + for (const consol of listOfConsoles.filter((x) => x !== expect)) (console as any)[consol] = () => { consoleEventCalled = 1; assert.fail("Invalid console called!: " + consol); }; - for (let consol of listOfConsoles.filter((x) => x === expect)) + for (const consol of listOfConsoles.filter((x) => x === expect)) (console as any)[consol] = (...data: Array) => { consoleEventCalled = 1; consoleExpectMessageContent.logs.push(data); }; } else if (expectMessage === undefined) { consoleEventCalled = 1; - for (let consol of listOfConsoles) + for (const consol of listOfConsoles) (console as any)[consol] = () => { consoleEventCalled = 0; assert.fail("Invalid console called!: " + consol); }; } else { - for (let consol of listOfConsoles.filter((x) => x !== expect)) + for (const consol of listOfConsoles.filter((x) => x !== expect)) (console as any)[consol] = () => { consoleEventCalled = 1; assert.fail("Invalid console called!: " + consol); }; - for (let consol of listOfConsoles.filter((x) => x === expect)) + for (const consol of listOfConsoles.filter((x) => x === expect)) (console as any)[consol] = (...data: Array) => { consoleEventCalled = 1; assert.equal(data.length, expectMessage.length); @@ -79,7 +79,7 @@ describe("plugins/log-default", () => { } }; const restoreConsole = () => { - for (let consol of listOfConsoles as any) + for (const consol of listOfConsoles as any) (console as any)[consol] = tempCCStore[consol]; if (consoleEventCalled === -1) assert.fail("Console not setup!"); if (consoleEventCalled === 0) assert.fail("No console called!"); @@ -90,7 +90,7 @@ describe("plugins/log-default", () => { xx++ ) { let has = false; - for (let item of consoleExpectMessageContent.logs) { + for (const item of consoleExpectMessageContent.logs) { if ( item .toString() @@ -286,7 +286,7 @@ describe("plugins/log-default", () => { const plugin = new Plugin(getLoggingConstructorConfig()); storeConsole("error", undefined, [ "test-error", - "src/tests/plugins/log-default/plugin.ts:", + "src/tests/plugins/logging-default/plugin.ts:", ]); await plugin.error("infW-DbG", new Error("test-error")); restoreConsole(); diff --git a/nodejs/src/tests/plugins/events/events/broadcast.ts b/nodejs/src/tests/sb/plugins/events/broadcast.ts similarity index 93% rename from nodejs/src/tests/plugins/events/events/broadcast.ts rename to nodejs/src/tests/sb/plugins/events/broadcast.ts index 02f6ca1..4c0b049 100644 --- a/nodejs/src/tests/plugins/events/events/broadcast.ts +++ b/nodejs/src/tests/sb/plugins/events/broadcast.ts @@ -1,6 +1,6 @@ import assert from "assert"; import { randomUUID } from "crypto"; -import { BSBEvents, SmartFunctionCallSync } from "../../../../"; +import { BSBEvents, SmartFunctionCallSync } from "../../../.."; const randomName = () => randomUUID(); @@ -30,10 +30,10 @@ export function broadcast( if (receiveCounter === 0) return assert.fail("Event not received"); assert.fail("Received " + receiveCounter + " events"); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast(thisPlugin, thisEvent, async (data: any) => { + await emitter.onBroadcast(thisPlugin, thisEvent, async () => { receiveCounter++; }); - await emitter.onBroadcast(thisPlugin, thisEvent, async (data: any) => { + await emitter.onBroadcast(thisPlugin, thisEvent, async () => { receiveCounter++; }); await emitter.emitBroadcast(thisPlugin, thisEvent, [emitData]); @@ -90,7 +90,7 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast(thisPlugin, thisEvent, async (data: any) => { + await emitter.onBroadcast(thisPlugin, thisEvent, async () => { clearTimeout(emitTimeout); assert.fail("Event received"); @@ -105,7 +105,7 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast(thisCaller, thisEvent, async (data: any) => { + await emitter.onBroadcast(thisCaller, thisEvent, async () => { clearTimeout(emitTimeout); assert.fail("Event received"); @@ -151,7 +151,7 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast(thisPlugin, thisEvent, async (data: any) => { + await emitter.onBroadcast(thisPlugin, thisEvent, async () => { clearTimeout(emitTimeout); assert.fail("Event received"); @@ -166,7 +166,7 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast(thisCaller, thisEvent, async (data: any) => { + await emitter.onBroadcast(thisCaller, thisEvent, async () => { clearTimeout(emitTimeout); assert.fail("Event received"); @@ -215,7 +215,7 @@ export function broadcast( }, }, ]; - for (let typeToTest of typesToTest) + for (const typeToTest of typesToTest) describe(`emitBroadcast ${typeToTest.name}`, async () => { it("should be able to emit to events with plugin name defined", async () => { const thisPlugin = randomName(); @@ -261,15 +261,11 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisPlugin, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisPlugin, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); + assert.fail("Event received"); + }); await emitter.emitBroadcast(thisPlugin, thisEvent2, [ typeToTest.data, ]); @@ -282,15 +278,11 @@ export function broadcast( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onBroadcast( - thisCaller, - thisEvent, - async (data: any) => { - clearTimeout(emitTimeout); + await emitter.onBroadcast(thisCaller, thisEvent, async () => { + clearTimeout(emitTimeout); - assert.fail("Event received"); - } - ); + assert.fail("Event received"); + }); await emitter.emitBroadcast(thisCaller, thisEvent2, [ typeToTest.data, ]); diff --git a/nodejs/src/tests/plugins/events/events/emit.ts b/nodejs/src/tests/sb/plugins/events/emit.ts similarity index 92% rename from nodejs/src/tests/plugins/events/events/emit.ts rename to nodejs/src/tests/sb/plugins/events/emit.ts index 7980010..6094773 100644 --- a/nodejs/src/tests/plugins/events/events/emit.ts +++ b/nodejs/src/tests/sb/plugins/events/emit.ts @@ -1,6 +1,6 @@ import assert from "assert"; import { randomUUID } from "crypto"; -import { BSBEvents, SmartFunctionCallSync } from "../../../../"; +import { BSBEvents, SmartFunctionCallSync } from "../../../.."; const randomName = () => randomUUID(); @@ -30,10 +30,10 @@ export function emit( if (receiveCounter === 0) return assert.fail("Event not received"); assert.fail("Received " + receiveCounter + " events"); }, maxTimeoutToExpectAResponse); - await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + await emitter.onEvent(thisPlugin, thisEvent, async () => { receiveCounter++; }); - await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + await emitter.onEvent(thisPlugin, thisEvent, async () => { receiveCounter++; }); await emitter.emitEvent(thisPlugin, thisEvent, [emitData]); @@ -90,7 +90,7 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + await emitter.onEvent(thisPlugin, thisEvent, async () => { clearTimeout(emitTimeout); assert.fail("Event received"); @@ -105,7 +105,7 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + await emitter.onEvent(thisCaller, thisEvent, async () => { clearTimeout(emitTimeout); assert.fail("Event received"); @@ -151,7 +151,7 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + await emitter.onEvent(thisPlugin, thisEvent, async () => { clearTimeout(emitTimeout); assert.fail("Event received"); @@ -166,7 +166,7 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + await emitter.onEvent(thisCaller, thisEvent, async () => { clearTimeout(emitTimeout); assert.fail("Event received"); @@ -215,7 +215,7 @@ export function emit( }, }, ]; - for (let typeToTest of typesToTest) + for (const typeToTest of typesToTest) describe(`emitEvent ${typeToTest.name}`, async () => { it("should be able to emit to events with plugin name defined", async () => { const thisPlugin = randomName(); @@ -253,7 +253,7 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent(thisPlugin, thisEvent, async (data: any) => { + await emitter.onEvent(thisPlugin, thisEvent, async () => { clearTimeout(emitTimeout); assert.fail("Event received"); @@ -268,7 +268,7 @@ export function emit( const emitTimeout = setTimeout(() => { assert.ok(true); }, maxTimeoutToExpectAResponse); - await emitter.onEvent(thisCaller, thisEvent, async (data: any) => { + await emitter.onEvent(thisCaller, thisEvent, async () => { clearTimeout(emitTimeout); assert.fail("Event received"); diff --git a/nodejs/src/tests/plugins/events/events/emitAndReturn.ts b/nodejs/src/tests/sb/plugins/events/emitAndReturn.ts similarity index 83% rename from nodejs/src/tests/plugins/events/events/emitAndReturn.ts rename to nodejs/src/tests/sb/plugins/events/emitAndReturn.ts index 6921ddd..a52e15a 100644 --- a/nodejs/src/tests/plugins/events/events/emitAndReturn.ts +++ b/nodejs/src/tests/sb/plugins/events/emitAndReturn.ts @@ -1,4 +1,4 @@ -import { BSBEvents, SmartFunctionCallSync } from "../../../../"; +import { BSBEvents, SmartFunctionCallSync } from "../../../.."; import assert from "assert"; import { randomUUID } from "crypto"; @@ -6,9 +6,7 @@ const randomName = () => randomUUID(); export function emitAndReturn( genNewPlugin: { (): Promise }, - maxTimeoutToExpectAResponse: number, - a = true, - b = true + maxTimeoutToExpectAResponse: number ) { let emitter: BSBEvents; beforeEach(async () => { @@ -18,8 +16,6 @@ export function emitAndReturn( SmartFunctionCallSync(emitter, emitter.dispose); }); describe("EmitAndReturn", async () => { - //if (a) this.timeout(maxTimeoutToExpectAResponse + 20); - //if (b) this.afterEach(done => setTimeout(done, maxTimeoutToExpectAResponse)); const timermaxTimeoutToExpectAResponse = maxTimeoutToExpectAResponse + 10; describe("emitEventAndReturn", async () => { const emitData = true; @@ -31,17 +27,13 @@ export function emitAndReturn( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisPlugin, - thisEvent, - async (data: Array) => { - setTimeout(() => { - console.log("Received onEvent"); - assert.ok(true, "Received onEvent"); - }, 1); - return emitData2; - } - ); + await emitter.onReturnableEvent(thisPlugin, thisEvent, async () => { + setTimeout(() => { + console.log("Received onEvent"); + assert.ok(true, "Received onEvent"); + }, 1); + return emitData2; + }); console.log("!!Received onEvent"); await emitter.emitEventAndReturn( thisPlugin, @@ -60,14 +52,10 @@ export function emitAndReturn( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisEvent, - async (data: Array) => { - assert.ok(true, "Received onEvent"); - return emitData2; - } - ); + await emitter.onReturnableEvent(thisCaller, thisEvent, async () => { + assert.ok(true, "Received onEvent"); + return emitData2; + }); await emitter.emitEventAndReturn( thisCaller, thisEvent, @@ -85,13 +73,9 @@ export function emitAndReturn( const emitTimeout = setTimeout(() => { assert.ok(true); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisPlugin, - thisEvent, - (data: Array) => { - assert.fail("EEAR MSG Received"); - } - ); + await emitter.onReturnableEvent(thisPlugin, thisEvent, () => { + assert.fail("EEAR MSG Received"); + }); try { await emitter.emitEventAndReturn( thisPlugin, @@ -114,13 +98,9 @@ export function emitAndReturn( const emitTimeout = setTimeout(() => { assert.ok(true); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisEvent, - (data: Array) => { - assert.fail("EEAR MSG Received"); - } - ); + await emitter.onReturnableEvent(thisCaller, thisEvent, () => { + assert.fail("EEAR MSG Received"); + }); try { await emitter.emitEventAndReturn( thisCaller, @@ -142,11 +122,7 @@ export function emitAndReturn( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisEvent, - async (data: Array) => {} - ); + await emitter.onReturnableEvent(thisCaller, thisEvent, async () => {}); try { await emitter.emitEventAndReturn( thisCaller, @@ -168,13 +144,9 @@ export function emitAndReturn( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisEvent, - (data: Array) => { - throw "THISISANERROR"; - } - ); + await emitter.onReturnableEvent(thisCaller, thisEvent, () => { + throw "THISISANERROR"; + }); try { await emitter.emitEventAndReturn( thisCaller, @@ -237,7 +209,7 @@ export function emitAndReturn( }, }, ]; - for (let typeToTest of typesToTest) { + for (const typeToTest of typesToTest) { describe(`emitEventAndReturn ${typeToTest.name}`, async () => { it("should be able to emit to events with plugin name defined", async () => { const thisPlugin = randomName(); @@ -246,15 +218,11 @@ export function emitAndReturn( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisPlugin, - thisEvent, - async (data: Array) => { - return typeToTest.rData !== undefined - ? typeToTest.rData - : typeToTest.data; - } - ); + await emitter.onReturnableEvent(thisPlugin, thisEvent, async () => { + return typeToTest.rData !== undefined + ? typeToTest.rData + : typeToTest.data; + }); const resp = await emitter.emitEventAndReturn( thisPlugin, thisEvent, @@ -313,13 +281,9 @@ export function emitAndReturn( const emitTimeout = setTimeout(() => { assert.ok(true); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisPlugin, - thisEvent, - (data: Array) => { - assert.fail("EEAR MSG Received"); - } - ); + await emitter.onReturnableEvent(thisPlugin, thisEvent, () => { + assert.fail("EEAR MSG Received"); + }); try { await emitter.emitEventAndReturn( thisPlugin, @@ -342,13 +306,9 @@ export function emitAndReturn( const emitTimeout = setTimeout(() => { assert.ok(true); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisEvent, - (data: Array) => { - assert.fail("EEAR MSG Received"); - } - ); + await emitter.onReturnableEvent(thisCaller, thisEvent, () => { + assert.fail("EEAR MSG Received"); + }); try { await emitter.emitEventAndReturn( thisCaller, @@ -373,7 +333,7 @@ export function emitAndReturn( await emitter.onReturnableEvent( thisCaller, thisEvent, - async (data: Array) => {} + async () => {} ); try { await emitter.emitEventAndReturn( @@ -417,13 +377,9 @@ export function emitAndReturn( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - await emitter.onReturnableEvent( - thisCaller, - thisEvent, - (data: Array) => { - throw typeToTest.rData || typeToTest.data; - } - ); + await emitter.onReturnableEvent(thisCaller, thisEvent, () => { + throw typeToTest.rData || typeToTest.data; + }); try { await emitter.emitEventAndReturn( thisCaller, diff --git a/nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts b/nodejs/src/tests/sb/plugins/events/emitStreamAndReceiveStream.ts similarity index 91% rename from nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts rename to nodejs/src/tests/sb/plugins/events/emitStreamAndReceiveStream.ts index 2637343..1a9fce9 100644 --- a/nodejs/src/tests/plugins/events/events/emitStreamAndReceiveStream.ts +++ b/nodejs/src/tests/sb/plugins/events/emitStreamAndReceiveStream.ts @@ -3,12 +3,12 @@ import * as crypto from "crypto"; import { exec } from "child_process"; import { pipeline } from "stream"; import assert from "assert"; -import { BSBEvents, SmartFunctionCallSync } from "../../../../"; +import { BSBEvents, SmartFunctionCallSync } from "../../../.."; const randomName = () => crypto.randomUUID(); const mockBareFakeStream = () => { - let obj: any = { + const obj: any = { listeners: {}, emit: (name: any, data?: any) => { if (obj.listeners[name] !== undefined) obj.listeners[name](data); @@ -23,9 +23,9 @@ const mockBareFakeStream = () => { const getFileHash = (filename: any) => new Promise((resolve, reject) => { - var fd = fs.createReadStream(filename); + const fd = fs.createReadStream(filename); // deepcode ignore InsecureHash/test: not production, just using to verify the files hash - var hash = crypto.createHash("sha1"); + const hash = crypto.createHash("sha1"); hash.setEncoding("hex"); fd.on("error", reject); @@ -90,7 +90,7 @@ export function emitStreamAndReceiveStream( it("receiveStream creates a should generate a valid string", async () => { const thisCaller = randomName(); - let uuid = await emitter.receiveStream( + const uuid = await emitter.receiveStream( thisCaller, async () => {}, maxTimeoutToExpectAResponse @@ -114,7 +114,7 @@ export function emitStreamAndReceiveStream( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - let uuid = await emitter.receiveStream( + const uuid = await emitter.receiveStream( thisCaller, async (err: any, stream: { emit: (arg0: string) => void }) => { clearTimeout(emitTimeout); @@ -126,6 +126,7 @@ export function emitStreamAndReceiveStream( try { await emitter.sendStream(thisCaller, uuid, mockBareFakeStream()); console.log("endededed"); + // eslint-disable-next-line no-empty } catch (xx) {} }); describe("sendStream triggers receiveStream listener passing in the stream", async () => { @@ -135,7 +136,7 @@ export function emitStreamAndReceiveStream( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - let uuid = await emitter.receiveStream( + const uuid = await emitter.receiveStream( thisCaller, async (err: any, stream: { emit: (arg0: string) => void }) => { clearTimeout(emitTimeout); @@ -146,6 +147,7 @@ export function emitStreamAndReceiveStream( ); try { await emitter.sendStream(thisCaller, uuid, mockBareFakeStream()); + // eslint-disable-next-line no-empty } catch (xx) {} }); it("should call the listener with a stream", async () => { @@ -154,7 +156,7 @@ export function emitStreamAndReceiveStream( const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - let uuid = await emitter.receiveStream( + const uuid = await emitter.receiveStream( thisCaller, async (err: any, stream: { emit: (arg0: string) => void }) => { clearTimeout(emitTimeout); @@ -169,6 +171,7 @@ export function emitStreamAndReceiveStream( ); try { await emitter.sendStream(thisCaller, uuid, mockBareFakeStream()); + // eslint-disable-next-line no-empty } catch (xx) {} }); }); @@ -179,8 +182,8 @@ export function emitStreamAndReceiveStream( this.timeout(120000); const thisCaller = randomName(); const now = new Date().getTime(); - let fileName = `./test-file-${size}`; - let fileNameOut = fileName + "-out"; + const fileName = `./test-file-${size}`; + const fileNameOut = fileName + "-out"; try { await runCMD( `dd if=/dev/urandom of=${fileName} bs=${size} count=${count}` @@ -196,12 +199,12 @@ export function emitStreamAndReceiveStream( const fileBytes = fs.statSync(fileName).size; const fullBytes = convertBytes(fileBytes); console.log(` ${size} act size: ${fullBytes}`); - let srcFileHash = await getFileHash(fileName); + const srcFileHash = await getFileHash(fileName); const emitTimeout = setTimeout(() => { assert.fail("Event not received"); }, timermaxTimeoutToExpectAResponse); - let uuid = await emitter.receiveStream( + const uuid = await emitter.receiveStream( thisCaller, async (err: any, stream: any): Promise => { if (err) return assert.fail(err); diff --git a/nodejs/src/tests/sb/plugins/events/plugin.ts b/nodejs/src/tests/sb/plugins/events/plugin.ts new file mode 100644 index 0000000..4f3a456 --- /dev/null +++ b/nodejs/src/tests/sb/plugins/events/plugin.ts @@ -0,0 +1,68 @@ +import { broadcast } from "./broadcast"; +import { emit } from "./emit"; +import { emitAndReturn } from "./emitAndReturn"; +import { emitStreamAndReceiveStream } from "./emitStreamAndReceiveStream"; +import { + BSBEventsConstructor, + BSBEventsRef, + PluginLogger, +} from "../../../../base"; +import { SBLogging, SmartFunctionCallSync } from "../../../../serviceBase"; + +export const newSBLogging = () => { + const sbLogging = new SBLogging( + "test-app", + "development", + process.cwd(), + {} as any + ); + for (const logger of (sbLogging as any).loggers) { + SmartFunctionCallSync(logger, logger.dispose); + } + (sbLogging as any).loggers = []; + return sbLogging; +}; +export const generateNullLogging = () => { + const sbLogging = newSBLogging(); + return new PluginLogger("development", "test-plugin", sbLogging); +}; +export const getEventsConstructorConfig = ( + config: any +): BSBEventsConstructor => { + return { + appId: "test-app", + pluginCwd: process.cwd(), + cwd: process.cwd(), + mode: "development", + pluginName: "test-plugin", + sbLogging: newSBLogging(), + config: config, + }; +}; + +export const RunEventsPluginTests = ( + eventsPlugin: typeof BSBEventsRef, + config: any = undefined +) => { + broadcast(async () => { + const refP = new eventsPlugin(getEventsConstructorConfig(config)); + if (refP.init !== undefined) await refP.init(); + return refP; + }, 10); + emit(async () => { + const refP = new eventsPlugin(getEventsConstructorConfig(config)); + if (refP.init !== undefined) await refP.init(); + return refP; + }, 10); + emitAndReturn(async () => { + const refP = new eventsPlugin(getEventsConstructorConfig(config)); + if (refP.init !== undefined) await refP.init(); + return refP; + }, 10); + emitStreamAndReceiveStream(async () => { + const refP = new eventsPlugin(getEventsConstructorConfig(config)); + if (refP.init !== undefined) await refP.init(); + //refP.eas.staticCommsTimeout = 25; + return refP; + }, 50); +}; diff --git a/nodejs/src/tests/serviceBase/services.ts b/nodejs/src/tests/serviceBase/services.ts deleted file mode 100644 index f07b370..0000000 --- a/nodejs/src/tests/serviceBase/services.ts +++ /dev/null @@ -1,271 +0,0 @@ -// import assert from "assert"; -// import { IPluginLogger, LogMeta } from "../../interfaces/logging"; -// import { ServicesBase } from "../../service/service"; -// import { SBServices } from "../../serviceBase/services"; - -// //const debug = console.log; -// const debug = (...a: any) => {}; -// const fakeLogger: IPluginLogger = { -// reportStat: async (key, value): Promise => {}, -// reportTextStat: async (message, meta, hasPIData): Promise => { -// debug(message, meta); -// }, -// info: async (message, meta, hasPIData): Promise => { -// debug(message, meta); -// }, -// warn: async (message, meta, hasPIData): Promise => { -// debug(message, meta); -// }, -// error: async ( -// messageOrError: string | Error, -// meta?: LogMeta, -// hasPIData?: boolean -// ): Promise => { -// debug(messageOrError, meta); -// assert.fail( -// typeof messageOrError === "string" -// ? new Error(messageOrError) -// : messageOrError -// ); -// }, -// fatal: async ( -// messageOrError: string | Error, -// meta?: LogMeta, -// hasPIData?: boolean -// ): Promise => { -// debug(messageOrError, meta); -// assert.fail( -// typeof messageOrError === "string" -// ? new Error(messageOrError) -// : messageOrError -// ); -// }, -// debug: async (message, meta, hasPIData): Promise => { -// debug(message, meta); -// }, -// }; - -// describe("serviceBase/services", () => { -// it("Should re-order plugins that require other plugins", async () => { -// let services = new SBServices(fakeLogger); -// let plugins: { -// name: string; -// after: string[]; -// before: string[]; -// ref: ServicesBase; -// }[] = [ -// { -// name: "plugin1", -// after: ["plugin2"], -// before: [], -// ref: {} as any, -// }, -// { -// name: "plugin2", -// after: [], -// before: [], -// ref: {} as any, -// }, -// { -// name: "plugin3", -// after: [], -// before: [], -// ref: {} as any, -// }, -// ]; -// plugins = await services.makeAfterRequired( -// { -// getAppPluginMappedName: async (x: string) => { -// return x; -// }, -// } as any, -// plugins -// ); -// services.dispose(); -// assert.equal(plugins[0].name, "plugin2"); -// assert.equal(plugins[1].name, "plugin1"); -// assert.equal(plugins[2].name, "plugin3"); -// }); -// it("Should re-order plugins that before other plugins", async () => { -// let services = new SBServices(fakeLogger); -// let plugins: { -// name: string; -// after: string[]; -// before: string[]; -// ref: ServicesBase; -// }[] = [ -// { -// name: "plugin1", -// after: ["plugin2"], -// before: [], -// ref: {} as any, -// }, -// { -// name: "plugin2", -// after: [], -// before: [], -// ref: {} as any, -// }, -// { -// name: "plugin3", -// after: [], -// before: ["plugin1"], -// ref: {} as any, -// }, -// ]; -// plugins = await services.makeBeforeRequired( -// { -// getAppPluginMappedName: async (x: string) => { -// return x; -// }, -// } as any, -// plugins -// ); -// assert.equal(plugins[0].after.length, 2); -// assert.equal(plugins[0].after[0], "plugin2"); -// assert.equal(plugins[0].after[1], "plugin3"); -// assert.equal(plugins[1].after.length, 0); -// assert.equal(plugins[2].after.length, 0); -// plugins = await services.makeAfterRequired( -// { -// getAppPluginMappedName: async (x: string) => { -// return x; -// }, -// } as any, -// plugins -// ); -// services.dispose(); -// assert.equal(plugins[0].name, "plugin2"); -// assert.equal(plugins[1].name, "plugin3"); -// assert.equal(plugins[2].name, "plugin1"); -// }); -// it("Should re-order plugins that before or require other plugins", async () => { -// let services = new SBServices(fakeLogger); -// let plugins: { -// name: string; -// after: string[]; -// before: string[]; -// ref: ServicesBase; -// }[] = [ -// { -// name: "plugin1", -// after: ["plugin2"], -// before: [], -// ref: {} as any, -// }, -// { -// name: "plugin2", -// after: [], -// before: [], -// ref: {} as any, -// }, -// { -// name: "plugin3", -// after: [], -// before: ["plugin1"], -// ref: {} as any, -// }, -// { -// name: "plugin4", -// after: ["plugin3"], -// before: ["plugin1"], -// ref: {} as any, -// }, -// ]; -// plugins = await services.makeBeforeRequired( -// { -// getAppPluginMappedName: async (x: string) => { -// return x; -// }, -// } as any, -// plugins -// ); -// plugins = await services.makeAfterRequired( -// { -// getAppPluginMappedName: async (x: string) => { -// return x; -// }, -// } as any, -// plugins -// ); -// services.dispose(); -// assert.equal(plugins[3].name, "plugin1", "plugin 1 not last"); -// assert.equal(plugins[3].after.length, 3, "length of after does not match"); -// assert.equal(plugins[3].after[0], "plugin2", "plugin 1 required plugin 2"); -// assert.equal(plugins[3].after[1], "plugin3", "plugin 1 required plugin 3"); -// assert.equal(plugins[3].after[2], "plugin4", "plugin 1 required plugin 4"); -// assert.equal(plugins[0].after.length, 0, "plugin 2 after nothing"); -// assert.equal(plugins[1].after.length, 0, "plugin 3 after nothing"); -// assert.equal(plugins[0].name, "plugin2"); -// assert.equal(plugins[1].name, "plugin3"); -// assert.equal(plugins[2].name, "plugin4"); -// assert.equal(plugins[3].name, "plugin1"); -// }); - -// it("Should re-order plugins that before or require other plugins (mapped names)", async () => { -// let services = new SBServices(fakeLogger); -// let plugins: { -// name: string; -// after: string[]; -// before: string[]; -// ref: ServicesBase; -// _mappedName: string; -// }[] = [ -// { -// name: "pligin1", -// after: ["plugin2"], -// before: [], -// ref: {} as any, -// _mappedName: "plugin1", -// }, -// { -// name: "pligin2", -// after: [], -// before: [], -// ref: {} as any, -// _mappedName: "plugin2", -// }, -// { -// name: "pligin3", -// after: [], -// before: ["plugin1"], -// ref: {} as any, -// _mappedName: "plugin3", -// }, -// { -// name: "pligin4", -// after: ["plugin3"], -// before: ["plugin1"], -// ref: {} as any, -// _mappedName: "plugin4", -// }, -// ]; -// const appConfigPass = { -// getAppPluginMappedName: async (x: string) => { -// for (let plugin of plugins) { -// if (plugin._mappedName === x) { -// return plugin.name; -// } -// } -// return x; -// }, -// } as any; -// plugins = (await services.makeBeforeRequired( -// appConfigPass, -// plugins -// )) as any; -// plugins = (await services.makeAfterRequired(appConfigPass, plugins)) as any; -// services.dispose(); -// assert.equal(plugins[3].name, "pligin1", "plugin 1 not last"); -// assert.equal(plugins[3].after.length, 3, "length of after does not match"); -// assert.equal(plugins[3].after[0], "pligin2", "plugin 1 required plugin 2"); -// assert.equal(plugins[3].after[1], "pligin3", "plugin 1 required plugin 3"); -// assert.equal(plugins[3].after[2], "pligin4", "plugin 1 required plugin 4"); -// assert.equal(plugins[0].after.length, 0, "plugin 2 after nothing"); -// assert.equal(plugins[1].after.length, 0, "plugin 3 after nothing"); -// assert.equal(plugins[0].name, "pligin2"); -// assert.equal(plugins[1].name, "pligin3"); -// assert.equal(plugins[2].name, "pligin4"); -// assert.equal(plugins[3].name, "pligin1"); -// }); -// }); diff --git a/nodejs/src/tests/test-logger.ts b/nodejs/src/tests/test-logger.ts deleted file mode 100644 index 71a2021..0000000 --- a/nodejs/src/tests/test-logger.ts +++ /dev/null @@ -1,46 +0,0 @@ -// import assert from "assert"; -// import { IPluginLogger, LogMeta } from "../interfaces/logging"; -// import { LoggerBase } from "../logger/logger"; - -// export class Logger extends LoggerBase { -// constructor( -// pluginName: string, -// cwd: string, -// pluginCwd: string, -// defaultLogger: IPluginLogger -// ) { -// super(pluginName, cwd, pluginCwd, defaultLogger); -// } - -// public async reportStat( -// plugin: string, -// key: string, -// value: number -// ): Promise {} -// public async debug( -// plugin: string, -// message: T, -// meta?: LogMeta, -// hasPIData?: boolean -// ): Promise {} -// public async info( -// plugin: string, -// message: T, -// meta?: LogMeta, -// hasPIData?: boolean -// ): Promise {} -// public async warn( -// plugin: string, -// message: T, -// meta?: LogMeta, -// hasPIData?: boolean -// ): Promise {} -// public async error( -// plugin: string, -// message: T, -// meta?: LogMeta, -// hasPIData?: boolean -// ): Promise { -// assert.fail(new Error(message)); -// } -// } diff --git a/nodejs/src/tests/virt-clientLogger.ts.txt b/nodejs/src/tests/virt-clientLogger.ts.txt deleted file mode 100644 index 469d68a..0000000 --- a/nodejs/src/tests/virt-clientLogger.ts.txt +++ /dev/null @@ -1,34 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { - value: true -}); -const logger_1 = require("../lib/interfaces/logger"); -class Logger extends logger_1.CLogger { - events = {}; - constructor(pluginName, cwd, log, appConfig, events) { - super(pluginName, cwd, log, appConfig); - this.events = events; - } - async thisLog(key, plugin, ...data) { - if (this.events[key] !== undefined) - this.events[key](...data); - else - await this.log[key](plugin, ...data); - } - async debug(plugin, ...data) { - await this.thisLog('debug', plugin, `[DEBUG][${plugin.toUpperCase()}]`, data); - } - async info(plugin, ...data) { - await this.thisLog('debug', plugin, `[${plugin.toUpperCase()}]`, data); - } - async warn(plugin, ...data) { - await this.thisLog('warn', plugin, `[${plugin.toUpperCase()}]`, data); - } - async error(plugin, ...data) { - await this.thisLog('error', plugin, `[${plugin.toUpperCase()}]`, data); - } - async fatal(plugin, ...data) { - await this.thisLog('fatal', plugin, 'FATAL', ...data); - } -} -exports.testogger = Logger; \ No newline at end of file diff --git a/nodejs/tsconfig-release.json b/nodejs/tsconfig-release.json index e064aaf..1874362 100644 --- a/nodejs/tsconfig-release.json +++ b/nodejs/tsconfig-release.json @@ -32,7 +32,8 @@ }, "compileOnSave": true, "include": [ - "src" + "src", + "src/tests/sb/**/*.*" ], "exclude": [ "node_modules/**", diff --git a/nodejs/tsconfig.json b/nodejs/tsconfig.json index cb80be8..95cf69a 100644 --- a/nodejs/tsconfig.json +++ b/nodejs/tsconfig.json @@ -25,17 +25,13 @@ "moduleResolution": "node" }, "linterOptions": { - "exclude": [ - "src/plugins/-*/**/*.*" - ] + "exclude": ["src/plugins/-*/**/*.*"] }, "compileOnSave": true, - "include": [ - "src" - ], + "include": ["src"], "exclude": [ "node_modules/**", "src/plugins/*-test*/**/*.*", "src/plugins/-*/**/*.*" ] -} \ No newline at end of file +}