UNPKG

@zerva/core

Version:

🌱 Simple event driven server

1 lines • 25.1 kB
{"version":3,"sources":["../src/config.ts","../src/types.ts","../src/context.ts","../src/register.ts","../src/serve.ts"],"names":["ZContext","Emitter","__publicField","uname","log","Logger","context","setContext","newContext","getContext","_global","getGlobalContext","zerva","emit","event","args","o","ctx","on","first","listener","dispose","useDispose","k","v","once","withContext","handler","previousContext","createContext","getConfig","schema","options","assert","isSchemaObjectFlat","parseSchemaEnv","dumpConfig","dump","info","name","prefix","stringFromSchemaEnv","getModuleContext","moduleName","hasModule","strict","has","requireModules","requiredModules","arrayFlatten","module","ok","assertModules","missing","register","dependencies","modules","registerModule","moduleOptions","requires","configOptions","configSchema","config","configFromSchema","LoggerFromConfig","LogLevelAll","message","use","serverStarted","serverRunning","serverStoping","onInit","onStart","onStop","serveStop","resolve","serve","fn","serverCheck","process","signals","isPerformingExit","signal","err"],"mappings":"2KACA,IAAA,CAAA,CAAA,MAAA,CAAA,cAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,UAAA,CAAA,IAAA,CAAA,YAAA,CAAA,IAAA,CAAA,QAAA,CAAA,IAAA,CAAA,KAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,IAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CAAA,GAAA,CAAA,CAAA,CAAA,CAAA,OAAA,CAAA,EAAA,QAAA,CAAA,CAAA,CAAA,EAAA,CAAA,CAAA,CAAA,CAAA,CAAA,CCgBaA,IAAAA,CAAAA,CAAN,cAAuBC,YAAwB,CAA/C,kCACLC,CAAA,CAAA,IAAA,CAAA,MAAA,CAAeC,UAAM,CAAA,SAAS,GAC9BD,CAAA,CAAA,IAAA,CAAA,SAAA,CAAoB,EACpBA,CAAAA,CAAAA,CAAAA,CAAA,yBAA6C,EAAC,CAAA,CAC9CA,CAAA,CAAA,IAAA,CAAA,MAAA,CAAgD,EAElD,EAAA,CAAA,MCnBME,CAAMC,CAAAA,WAAAA,CAAO,eAAe,CAM9BC,CAAAA,CAAAA,CAAU,IAAIN,CAAAA,CAGPO,mBAAcC,CAAgC,EAAA,CACvDF,EAAUE,CAAc,EAAA,IAAIR,EAC9B,CAGWS,CAAAA,kBAAAA,CAAa,IAAgBH,EAExC,GAAI,CACF,IAAMI,EAAUC,qBAAiB,EAAA,CAC7BD,GAAS,KAAS,EAAA,IAAA,CACpBA,EAAQ,KAAQJ,CAAAA,CAAAA,CAEhBA,EAAUI,CAAQ,CAAA,KAAA,CAEpBH,mBAAcC,CAA0B,EAAA,CACtC,IAAMF,CAAUE,CAAAA,CAAAA,EAAc,IAAIR,CAAAA,CAClCI,EAAI,aAAeE,CAAAA,CAAAA,CAAQ,IAAI,CAC/BI,CAAAA,CAAAA,CAAQ,MAAQJ,EAClB,CAAA,CACAG,kBAAa,CAAA,IAAgBC,EAAQ,MACvC,CAAA,KACU,CACRN,CAAI,CAAA,IAAA,CAAK,2CAA2C,EACtD,CAGaQ,IAAAA,EAAAA,CAAQN,EAGrB,eAAsBO,CAAAA,CACpBC,KACGC,CACe,CAAA,CAClBX,EAAI,MAAQU,CAAAA,CAAAA,CAAO,KAAK,SAAUC,CAAAA,CAAAA,CAAK,IAAIC,CAAK,EAAA,OAAOA,CAAC,CAAC,CAAC,EAC1D,IAAMC,CAAAA,CAAMR,kBAAW,EAAA,CACvB,OAAAQ,CAAI,CAAA,iBAAA,CAAkBH,CAAK,CAAI,CAAA,IAAA,CACxB,MAAMG,CAAI,CAAA,IAAA,CAAKH,CAAO,CAAA,GAAGC,CAAI,CACtC,CAYO,SAASG,CACdC,CAAAA,CAAAA,CACAC,EACkB,CAClB,IAAMH,CAAMR,CAAAA,kBAAAA,GAGZ,GAAI,OAAOU,GAAU,QAAYC,EAAAA,CAAAA,EAAY,KAC3C,OAAIH,CAAAA,CAAI,kBAAkBE,CAAK,CAAA,EAC7Bf,EAAI,IAAK,CAAA,CAAA,OAAA,EAAUe,CAAK,CAAsD,oDAAA,CAAA,CAAA,CACzEF,EAAI,EAAGE,CAAAA,CAAAA,CAAOC,CAAQ,CAAA,CAI/B,IAAMC,CAAUC,CAAAA,eAAAA,GAChB,OAAO,MAAA,CAAA,OAAA,CAAQH,CAAK,CAAE,CAAA,OAAA,CAAQ,CAAC,CAACI,EAAGC,CAAC,CAAA,GAAM,CACpCP,CAAI,CAAA,iBAAA,CAAkBM,CAAC,CACzBnB,EAAAA,CAAAA,CAAI,IAAK,CAAA,CAAA,OAAA,EAAUe,CAAK,CAAsD,oDAAA,CAAA,CAAA,CAChFE,EAAQ,GAAIJ,CAAAA,CAAAA,CAAI,GAAGM,CAAUC,CAAAA,CAAC,CAAC,EACjC,CAAC,CACMH,CAAAA,CACT,CAOO,SAASI,CAAAA,CACdN,EACAC,CACkB,CAAA,CAClB,IAAMH,CAAAA,CAAMR,oBAGZ,CAAA,GAAI,OAAOU,CAAU,EAAA,QAAA,EAAYC,GAAY,IAC3C,CAAA,OAAIH,CAAI,CAAA,iBAAA,CAAkBE,CAAK,CAC7Bf,EAAAA,CAAAA,CAAI,KAAK,CAAUe,OAAAA,EAAAA,CAAK,sDAAsD,CACzEF,CAAAA,CAAAA,CAAI,IAAKE,CAAAA,CAAAA,CAAOC,CAAQ,CAIjC,CAAA,IAAMC,EAAUC,eAAW,EAAA,CAC3B,cAAO,OAAQH,CAAAA,CAAK,EAAE,OAAQ,CAAA,CAAC,CAACI,CAAGC,CAAAA,CAAC,IAAM,CACpCP,CAAAA,CAAI,kBAAkBM,CAAC,CAAA,EACzBnB,CAAI,CAAA,IAAA,CAAK,UAAUe,CAAK,CAAA,oDAAA,CAAsD,EAChFE,CAAQ,CAAA,GAAA,CAAIJ,EAAI,IAAKM,CAAAA,CAAAA,CAAUC,CAAC,CAAC,EACnC,CAAC,CAAA,CACMH,CACT,CASO,SAASK,EACdlB,CACAmB,CAAAA,CAAAA,CACA,CACAvB,CAAAA,CAAI,aAAa,CACjB,CAAA,IAAMwB,EAAkBnB,kBAAW,EAAA,CACnCF,mBAAWC,CAAU,CAAA,CACrBmB,EAAQnB,CAAU,CAAA,CAClBD,mBAAWqB,CAAe,EAC5B,CAOO,SAASC,EAAAA,CAAcF,EAAuC,CACnED,CAAAA,CAAY,MAAWC,CAAAA,CAAO,EAChC,CF3HO,SAASG,EAA+BC,CAAWC,CAAAA,CAAAA,CAA2C,CACnG,OAAAC,WAAAA,CAAOC,uBAAmBH,CAAAA,CAAM,EAAG,+CAA+C,CAAA,CAEnEI,oBAAeJ,CAAQC,CAAAA,CAAO,CAG/C,CAMO,SAASI,EAAqB,EAAA,CACnC,IAAMC,CAAiB,CAAA,GACvB,IAAWC,IAAAA,CAAAA,IAAQ,OAAO,MAAO7B,CAAAA,kBAAAA,GAAa,IAAI,CAAA,CAAG,CACnD,IAAM8B,CAAAA,CAAOD,EAAK,IACdC,CAAAA,CAAAA,EACFF,EAAK,IAAK,CAAA,CAAA;AAAA,UAAA,EAAgBE,CAAI;AAAA;AAAA,CAAO,CAEvC,CAAA,IAAMR,CAASO,CAAAA,CAAAA,CAAK,aAAe,EAAA,YAAA,CACnC,GAAIP,CAAAA,CAAQ,CACV,IAAMS,CAASF,CAAAA,CAAAA,CAAK,eAAe,aAAe,EAAA,MAAA,EAAU,CAAGC,EAAAA,CAAAA,CAAK,WAAY,EAAC,CACjFF,CAAAA,CAAAA,CAAAA,CAAAA,CAAK,KAAKI,wBAAoBV,CAAAA,CAAAA,CAAQS,CAAM,CAAC,EAC/C,CACF,CACA,OAAOH,EAAK,IAAK,CAAA;AAAA,CAAI,CACvB,CGnCA,IAAMjC,EAAuBC,WAAO,CAAA,gBAAgB,CAE7C,CAAA,SAASqC,EAAsDH,CAAAA,CAAAA,CAAiD,CACrH,IAAMI,EAAaJ,CAAK,CAAA,WAAA,EAClBjC,CAAAA,CAAAA,CAAUG,kBAAW,EAAA,CAC3B,GAAIH,CAAAA,CAAQ,KAAKqC,CAAU,CAAA,EAAK,IAC9B,CAAA,OAAOrC,CAAQ,CAAA,IAAA,CAAKqC,CAAU,CAAA,CAEhCvC,EAAI,IAAK,CAAA,CAAA,QAAA,EAAWuC,CAAU,CAAA,2BAAA,CAA6B,EAE7D,CASO,SAASC,CAAAA,CAAUL,EAAcM,CAAS,CAAA,KAAA,CAAgB,CAC/D,IAAMF,CAAaJ,CAAAA,CAAAA,CAAK,WAAY,EAAA,CAC9BO,EAAMrC,kBAAW,EAAA,CAAE,OAAQ,CAAA,QAAA,CAASkC,CAAU,CAAA,EAAKlC,kBAAW,EAAA,CAAE,KAAKkC,CAAU,CAAA,EAAK,IAE1F,CAAA,OAAIE,CAAU,EAAA,CAACC,CACb1C,EAAAA,CAAAA,CAAI,MAAM,CAAWmC,QAAAA,EAAAA,CAAI,CAAc,YAAA,CAAA,CAAA,CAClCO,CACT,CAKO,SAASC,EAAAA,CAAAA,GACXC,EACM,CAET,OAAO,CADSC,iBAAAA,CAAaD,CAAe,CAAA,CAC5B,GAAIE,CAAAA,CAAAA,EAAUN,EAAUM,CAAQ,CAAA,IAAI,CAAC,CAAA,CAAE,IAAKC,CAAAA,CAAAA,EAAM,CAACA,CAAE,CACvE,CAEO,SAASC,CAAiBJ,CAAAA,GAAAA,CAAAA,CAA8C,CAE7E,IAAMK,CADUJ,CAAAA,iBAAAA,CAAaD,CAAe,CACpB,CAAA,MAAA,CAAOE,CAAU,EAAA,CAACN,CAAUM,CAAAA,CAAM,CAAC,CAAA,CAC3D,GAAIG,CAAQ,CAAA,MAAA,CAAS,CACnB,CAAA,MAAAjD,CAAI,CAAA,KAAA,CAAM,CAA2BiD,wBAAAA,EAAAA,CAAO,EAAE,CACxC,CAAA,IAAI,KAAM,CAAA,CAAA,wBAAA,EAA2BA,CAAO,CAAE,CAAA,CAExD,CASO,SAASC,GACdX,CACGY,CAAAA,GAAAA,CAAAA,CACM,CACTZ,CAAAA,CAAaA,CAAW,CAAA,WAAA,EACxB,CAAA,IAAMa,EAAUP,iBAAaM,CAAAA,CAAY,CACzC,CAAA,OAAAnD,CAAI,CAAA,CAAA,SAAA,EAAYuC,CAAU,CAAA,CAAA,EAAIa,EAAQ,MAAS,CAAA,CAAA,kBAAA,EAAqBA,CAAO,CAAA,CAAA,CAAK,EAAE,CAAA,CAAE,CAChFZ,CAAAA,CAAAA,CAAUD,CAAU,CACtBvC,EAAAA,CAAAA,CAAI,IAAK,CAAA,CAAA,YAAA,EAAeuC,CAAU,CAAA,mCAAA,CAAqC,CACzElC,CAAAA,kBAAAA,GAAa,OAAQ,CAAA,IAAA,CAAKkC,CAAU,CAAA,CACpCS,CAAcI,CAAAA,CAAO,CACd,CAAA,IACT,CA2CO,SAASC,CAAAA,CAAoDlB,CAAcmB,CAAAA,CAAAA,CAA8D,CAC9I,GAAM,CAAE,QAAA,CAAAC,EAAW,EAAC,CAAG,aAAAC,CAAAA,CAAAA,CAAe,YAAAC,CAAAA,CAAAA,CAAc,OAAA7B,CAAAA,CAAQ,EAAI0B,CAAiB,EAAA,EAG3Ef,CAAAA,CAAAA,CAAaJ,CAAK,CAAA,WAAA,EAGlBuB,CAAAA,CAAAA,CAAc,CAAE,GAAG9B,CAAQ,CACjC,CAAA,GAAI6B,CAAgB,EAAA,IAAA,CAAM,CACxB,IAAME,EAAmBjC,CAAU+B,CAAAA,CAAAA,CAAc,CAC/C,QAAA,CAAU7B,CACV,CAAA,MAAA,CAAQ,CAAGW,EAAAA,CAAAA,CAAW,aAAa,CAAA,CAAA,CAAA,CACnC,UAAAA,CAAAA,CAAAA,CACA,GAAGiB,CACL,CAAC,CAAA,CACD,OAAO,MAAOE,CAAAA,CAAAA,CAAQC,CAAgB,EAMxC,CAGA,IAAM3D,CAAM4D,CAAAA,qBAAAA,CAAiBF,GAAQ,GAAOJ,EAAAA,CAAAA,EAAe,GAAO,EAAA,IAAA,CAAMf,CAAYe,CAAAA,CAAAA,EAAe,QAAYO,EAAAA,gBAAW,EAC1H7D,CAAI,CAAA,IAAA,CAAK,CAAOuC,IAAAA,EAAAA,CAAU,CAAiBmB,aAAAA,CAAAA,CAAAA,CAAM,CAG7ClB,CAAAA,CAAAA,CAAUD,CAAU,CACtBvC,EAAAA,CAAAA,CAAI,IAAK,CAAA,CAAA,YAAA,EAAeuC,CAAU,CAAA,mCAAA,CAAqC,CAIzE,CAAA,IAAMU,EADUJ,iBAAaU,CAAAA,CAAQ,CACb,CAAA,MAAA,CAAOT,GAAU,CAACN,CAAAA,CAAUM,CAAM,CAAC,EAC3D,GAAIG,CAAAA,CAAQ,MAAS,CAAA,CAAA,CAAG,CACtB,IAAMa,CAAU,CAAA,CAAA,cAAA,EAAiBvB,CAAU,CAAuBU,oBAAAA,EAAAA,CAAO,CACzE,CAAA,CAAA,MAAAjD,CAAI,CAAA,KAAA,CAAM8D,CAAO,CAAA,CACX,IAAI,KAAMA,CAAAA,CAAO,CACzB,CAEA,IAAM5D,CAAAA,CAAiC,CAAE,IAAA,CAAMqC,EAAY,GAAAvC,CAAAA,CAAAA,CAAK,MAAA0D,CAAAA,CAAAA,CAAQ,EAAA5C,CAAAA,CAAAA,CAAI,IAAAO,CAAAA,CAAAA,CAAM,KAAAZ,CAAM,CAAA,aAAA,CAAA6C,CAAc,CAAA,CACtG,OAAAjD,kBAAAA,EAAa,CAAA,IAAA,CAAKkC,CAAU,CAAIrC,CAAAA,CAAAA,CACzBA,CACT,CAEO,SAAS6D,EAAAA,CACdT,CAIoC,CAAA,CACpC,OAAQ1B,CACC0B,EAAAA,CAAAA,CAAc,KACnBD,CAAAA,CAAAA,CAAeC,CAAc,CAAA,IAAA,CAAM,CACjC,OAAA,CAAA1B,EACA,GAAG0B,CACL,CAAC,CAAC,CAER,CCzKA,IAAMtD,CAAAA,CAAMC,WAAO,CAAA,aAAa,EAY5B+D,CAAgB,CAAA,KAAA,CAChBC,CAAgB,CAAA,KAAA,CAChBC,CAAgB,CAAA,KAAA,CAKb,SAASC,EAAAA,CAAO5C,EAAqB,CAC1CT,CAAAA,CAAG,WAAaS,CAAAA,CAAO,EACzB,CAGO,SAAS6C,EAAAA,CAAQ7C,EAAqB,CAC3CT,CAAAA,CAAG,YAAcS,CAAAA,CAAO,EAC1B,CAGO,SAAS8C,EAAAA,CAAO9C,EAAqB,CAC1CT,CAAAA,CAAG,WAAaS,CAAAA,CAAO,EACzB,CAEA,eAAsB+C,CAAAA,EAAY,CAE5BJ,CACF,CAAA,MAAM,IAAI,OAAA,CAAQK,CAAWlE,EAAAA,kBAAAA,EAAa,CAAA,IAAA,CAAK,eAAgB,IAAMkE,CAAAA,CAAQ,IAAI,CAAC,CAAC,CAAA,CAE5EN,CACPA,GAAAA,CAAAA,CAAgB,MAChBC,CAAgB,CAAA,IAAA,CAChB,MAAMzD,CAAAA,CAAK,WAAW,CACtByD,CAAAA,CAAAA,CAAgB,KAChB,CAAA,MAAMzD,EAAK,cAAc,CAAA,EAG7B,CAEAK,CAAAA,CAAG,YAAc,CAAA,IAAM,CACrBmD,CAAAA,CAAgB,KAClB,CAAC,CAAA,CAEDnD,CAAG,CAAA,WAAA,CAAa,IAAM,CAChBoD,CAAkB,GAAA,IAAA,GAEpBlE,EAAI,IAAK,CAAA,8DAA8D,CAGvE,CAAA,OAAA,CAAQ,KAAM,EAAA,EAElB,CAAC,CAAA,CAOD,eAAsBwE,CAAMC,CAAAA,CAAAA,CAAiB,CAC3CzE,CAAAA,CAAI,OAAO,CAAA,CACXgE,CAAgB,CAAA,IAAA,CAEZS,IACFzE,CAAI,CAAA,QAAQ,CACZyE,CAAAA,CAAAA,EAEFzE,CAAAA,CAAAA,CAAAA,CAAI,MAAM,CAAA,CACV,MAAMS,CAAK,CAAA,WAAW,CACtBT,CAAAA,CAAAA,CAAI,OAAO,CAAA,CACX,MAAMS,CAAAA,CAAK,YAAY,CACvBT,CAAAA,CAAAA,CAAI,OAAO,EACb,CAEA,eAAe0E,CAAc,EAAA,CACvBV,IAAkB,IACpBhE,EAAAA,CAAAA,CAAI,IAAK,CAAA,sDAAsD,CAC1DwE,CAAAA,CAAAA,EAEEP,EAAAA,CAAAA,GAAkB,OACzBjE,CAAI,CAAA,0CAA0C,CAC9C,CAAA,MAAMsE,CAAU,EAAA,EAEpB,CAEAK,kBAAAA,CAAQ,GAAG,YAAcD,CAAAA,CAAW,CAMpC,CAAA,IAAME,CAAe,CAAA,CACnB,MAAQ,CAAA,CAAA,CACR,OAAQ,CACR,CAAA,OAAA,CAAS,EACX,CAAA,CAEIC,CAAmB,CAAA,KAAA,CAIvB,MAAO,CAAA,IAAA,CAAKD,CAAO,CAAE,CAAA,OAAA,CAASE,CAAW,EAAA,CACvCH,kBAAQ,CAAA,EAAA,CAAGG,CAAQ,CAAA,IAAM,CAClBD,CAYH7E,CAAAA,CAAAA,CAAI,CAAgC8E,6BAAAA,EAAAA,CAAM,CAAS,OAAA,CAAA,CAAA,EAXnDD,CAAmB,CAAA,IAAA,CACnB7E,EAAI,CAAsB8E,mBAAAA,EAAAA,CAAM,CAAS,OAAA,CAAA,CAAA,CACzCR,CAAU,EAAA,CAAE,IAAK,CAAA,IAAM,CAGrBK,kBAAQ,CAAA,IAAA,CAAK,CAAC,EAChB,CAAC,CAAA,CAAE,KAAOI,CAAAA,CAAAA,EAAQ,CAChB/E,CAAI,CAAA,KAAA,CAAM,CAAuB+E,oBAAAA,EAAAA,CAAG,EAAE,EACxC,CAAC,CAKL,EAAA,CAAC,EACH,CAAC,CAAA","file":"index.cjs","sourcesContent":["import type { Infer, SchemaEnvOptions, Type } from 'zeed'\nimport { assert, isSchemaObjectFlat, parseSchemaEnv, stringFromSchemaEnv } from 'zeed'\nimport { getContext } from './context'\n\nexport interface ZervaConfigOptions<T> extends SchemaEnvOptions<T> {\n moduleName?: string\n}\n\n/**\n * Get the configuration object based on the provided schema and environment variables.\n *\n * @param schema Description of the configuration as schema.\n * @param options ZervaConfigOptions\n * @returns The configuration object inferred from the schema and the environment variables.\n */\nexport function getConfig<T extends Type<any>>(schema: T, options?: ZervaConfigOptions<T>): Infer<T> {\n assert(isSchemaObjectFlat(schema), 'getConfig schema must be a flat object schema')\n // const { env = process.env, existing, moduleName } = options || {}\n const config = parseSchemaEnv(schema, options)\n // schemaList.push({ module: moduleName, schema, options })\n return config\n}\n\n/**\n *\n * @returns A string representation suitable as template for an .env file.\n */\nexport function dumpConfig(): string {\n const dump: string[] = []\n for (const info of Object.values(getContext().uses)) {\n const name = info.name\n if (name) {\n dump.push(`#\\n# Module: ${name}\\n#\\n`)\n }\n const schema = info.moduleOptions?.configSchema\n if (schema) {\n const prefix = info.moduleOptions?.configOptions?.prefix ?? `${name.toUpperCase()}_`\n dump.push(stringFromSchemaEnv(schema, prefix))\n }\n }\n return dump.join('\\n')\n}\n","import type { ZervaModuleContext } from './register'\nimport { Emitter, uname } from 'zeed'\n\ndeclare global {\n interface ZContextEvents {\n close: () => void\n }\n\n interface ZeedGlobalContext {\n zerva?: ZContext\n }\n\n const ZERVA_DEVELOPMENT: boolean\n const ZERVA_PRODUCTION: boolean\n const ZERVA_VERSION: string\n}\n\nexport class ZContext extends Emitter<ZContextEvents> {\n name: string = uname('context')\n modules: string[] = []\n eventNamesEmitted: Record<string, boolean> = {}\n uses: Record<string, ZervaModuleContext<any>> = {}\n // config: any\n}\n","import type { DisposerFunction } from 'zeed'\nimport { getGlobalContext, Logger, useDispose } from 'zeed'\nimport { ZContext } from './types'\n\nconst log = Logger('zerva:context')\n\n// Others would probably call it \"hub\" or \"bus\"...\n\n// Global logger to guarantee all submodules use the same logger instance\n\nlet context = new ZContext()\n\n// eslint-disable-next-line import/no-mutable-exports\nexport let setContext = (newContext?: ZContext): void => {\n context = newContext || new ZContext()\n}\n\n// eslint-disable-next-line import/no-mutable-exports\nexport let getContext = (): ZContext => context\n\ntry {\n const _global = getGlobalContext()\n if (_global?.zerva == null)\n _global.zerva = context\n else\n context = _global.zerva\n\n setContext = (newContext?: ZContext) => {\n const context = newContext || new ZContext()\n log('set context', context.name)\n _global.zerva = context\n }\n getContext = (): ZContext => _global.zerva as ZContext\n}\ncatch (e) {\n log.warn('Unable to register Zerva Context globally')\n}\n\n/** The global context as constant */\nexport const zerva = context\n\n/** Emit via the current global context */\nexport async function emit<U extends keyof ZContextEvents>(\n event: U,\n ...args: Parameters<ZContextEvents[U]>\n): Promise<boolean> {\n log('emit', event, JSON.stringify(args.map(o => typeof o)))\n const ctx = getContext()\n ctx.eventNamesEmitted[event] = true\n return await ctx.emit(event, ...args)\n}\n\n/** Listener that binds to the current global context */\nexport function on<U extends keyof ZContextEvents>(\n first: Partial<ZContextEvents>\n): DisposerFunction // Overload!\n\nexport function on<U extends keyof ZContextEvents>(\n first: U,\n listener: ZContextEvents[U]\n): DisposerFunction // Overload!\n\nexport function on<U extends keyof ZContextEvents>(\n first: Partial<ZContextEvents> | U,\n listener?: ZContextEvents[U],\n): DisposerFunction {\n const ctx = getContext()\n\n // Single\n if (typeof first === 'string' && listener != null) {\n if (ctx.eventNamesEmitted[first])\n log.warn(`Event '${first}' has already been emitted before listener was added`)\n return ctx.on(first, listener)\n }\n\n // Multiple\n const dispose = useDispose()\n Object.entries(first).forEach(([k, v]) => {\n if (ctx.eventNamesEmitted[k])\n log.warn(`Event '${first}' has already been emitted before listener was added`)\n dispose.add(ctx.on(k as any, v))\n })\n return dispose\n}\n\nexport function once<U extends keyof ZContextEvents>(\n first: U,\n listener: ZContextEvents[U]\n): DisposerFunction // Overload!\n\nexport function once<U extends keyof ZContextEvents>(\n first: Partial<ZContextEvents> | U,\n listener?: ZContextEvents[U],\n): DisposerFunction {\n const ctx = getContext()\n\n // Single\n if (typeof first === 'string' && listener != null) {\n if (ctx.eventNamesEmitted[first])\n log.warn(`Event '${first}' has already been emitted before listener was added`)\n return ctx.once(first, listener)\n }\n\n // Multiple\n const dispose = useDispose()\n Object.entries(first).forEach(([k, v]) => {\n if (ctx.eventNamesEmitted[k])\n log.warn(`Event '${first}' has already been emitted before listener was added`)\n dispose.add(ctx.once(k as any, v))\n })\n return dispose\n}\n\n/**\n * Set a different global context. Restores previous context after execution.\n * This is not async to avoid sideeffects!\n *\n * @param newContext New context\n * @param handler Executed with `newContext` set as global context\n */\nexport function withContext(\n newContext: ZContext | undefined,\n handler: (context?: ZContext) => void,\n) {\n log('withContext')\n const previousContext = getContext()\n setContext(newContext)\n handler(newContext)\n setContext(previousContext)\n}\n\n/**\n * Set a different global context. Restores previous context after execution.\n *\n * @param handler Executed with `newContext` set as global context\n */\nexport function createContext(handler: (context?: ZContext) => void) {\n withContext(undefined, handler)\n}\n","import type { Infer, LogConfig, LoggerInterface, LogLevel, Type } from 'zeed'\nimport type { ZervaConfigOptions } from './config'\nimport { arrayFlatten, Logger, LoggerFromConfig, LogLevelAll } from 'zeed'\nimport { getConfig } from './config'\nimport { emit, getContext, on, once } from './context'\n\nconst log: LoggerInterface = Logger('zerva:register')\n\nexport function getModuleContext<T extends Type<unknown> = Type<any>>(name: string): ZervaModuleContext<T> | undefined {\n const moduleName = name.toLowerCase()\n const context = getContext()\n if (context.uses[moduleName] != null) {\n return context.uses[moduleName] as ZervaModuleContext<T>\n }\n log.warn(`Module '${moduleName}' not found in context uses`)\n return undefined\n}\n\n/**\n * Check existance of registered module.\n *\n * @param name Name of module\n * @param strict Log error if check fails\n * @returns `true` if `module` has been registered before\n */\nexport function hasModule(name: string, strict = false): boolean {\n const moduleName = name.toLowerCase()\n const has = getContext().modules.includes(moduleName) || getContext().uses[moduleName] != null\n // log(`hasModule ${module} => ${has} (strict=${strict})`)\n if (strict && !has)\n log.error(`module '${name}' is missing`)\n return has\n}\n\n/**\n * Check existance of registered modules, log error if missing.\n */\nexport function requireModules(\n ...requiredModules: (string | string[])[]\n): boolean {\n const modules = arrayFlatten(requiredModules)\n return !modules.map(module => hasModule(module, true)).some(ok => !ok)\n}\n\nexport function assertModules(...requiredModules: (string | string[])[]): void {\n const modules = arrayFlatten(requiredModules)\n const missing = modules.filter(module => !hasModule(module))\n if (missing.length > 0) {\n log.error(`Zerva modules required: ${missing}`)\n throw new Error(`Zerva modules required: ${missing}`)\n }\n}\n\n/**\n * Register module by name and check for modules it depends on\n *\n * @param moduleName Module name to register\n * @param dependencies List of modules names that have to be registered before in this context\n * @deprecation Use `registerModule` instead\n */\nexport function register(\n moduleName: string,\n ...dependencies: (string | string[])[]\n): boolean {\n moduleName = moduleName.toLowerCase()\n const modules = arrayFlatten(dependencies)\n log(`register ${moduleName} ${modules.length ? `with dependencies=${modules}` : ''}`)\n if (hasModule(moduleName))\n log.warn(`The module '${moduleName} has been registered multiple times`)\n getContext().modules.push(moduleName)\n assertModules(modules)\n return true\n}\n\nexport interface ZervaModuleOptions<T> {\n name?: string\n description?: string\n url?: string\n\n requires?: string[] | string\n\n configSchema?: T\n configOptions?: ZervaConfigOptions<T>\n options?: Partial<Infer<T>>\n\n log?: LogConfig\n logLevel?: LogLevel\n}\n\nexport interface ZervaModuleContext<T> {\n name: string\n config: Infer<T>\n moduleOptions?: ZervaModuleOptions<T>\n log: LoggerInterface\n on: typeof on\n once: typeof once\n emit: typeof emit\n}\n\n/**\n * Register a module with its configuration and dependencies.\n *\n * This function registers a module by its name, checks for required modules,\n * and retrieves its configuration based on the provided schema.\n *\n * It also initializes a logger for the module, where log details can be customized.\n * If `configSchema.log` is of type `LogConfig` the logger will be created from it.\n *\n * `options` can be used to override the default configuration values i.e. first\n * apply `options` and then the `configSchema` values.\n *\n * @param name Name of the module to register\n * @param moduleOptions Additional options for the module\n * @returns { name: string, config: Infer<T>, log: LoggerInterface }\n */\nexport function registerModule<T extends Type<unknown> = Type<any>>(name: string, moduleOptions?: ZervaModuleOptions<T>): ZervaModuleContext<T> {\n const { requires = [], configOptions, configSchema, options } = moduleOptions || {}\n\n // Module name\n const moduleName = name.toLowerCase()\n\n // Config and options\n const config: any = { ...options }\n if (configSchema != null) {\n const configFromSchema = getConfig(configSchema, {\n existing: options as any,\n prefix: `${moduleName.toUpperCase()}_`,\n moduleName,\n ...configOptions,\n })\n Object.assign(config, configFromSchema)\n // Object.entries(configFromSchema as any).forEach(([key, value]) => {\n // if (value !== undefined) {\n // config[key] = value\n // }\n // })\n }\n\n // Logging\n const log = LoggerFromConfig(config?.log ?? moduleOptions?.log ?? true, moduleName, moduleOptions?.logLevel ?? LogLevelAll)\n log.info(`use ${moduleName} with config:`, config)\n\n // Register module in context\n if (hasModule(moduleName))\n log.warn(`The module '${moduleName} has been registered multiple times`)\n\n // Check required modules\n const modules = arrayFlatten(requires)\n const missing = modules.filter(module => !hasModule(module))\n if (missing.length > 0) {\n const message = `Zerva module '${moduleName}' requires modules: ${missing}`\n log.error(message)\n throw new Error(message)\n }\n\n const context: ZervaModuleContext<T> = { name: moduleName, log, config, on, once, emit, moduleOptions }\n getContext().uses[moduleName] = context\n return context\n}\n\nexport function use<T extends Type<unknown> = Type<any>, R = any>(\n moduleOptions: ZervaModuleOptions<T> & {\n name: string\n setup: (context: ZervaModuleContext<T>) => R\n },\n): (options?: Partial<Infer<T>>) => R {\n return (options) => {\n return moduleOptions.setup(\n registerModule(moduleOptions.name, {\n options,\n ...moduleOptions,\n }))\n }\n}\n","import process from 'node:process'\nimport { Logger } from 'zeed'\nimport { emit, getContext, on } from './context'\n\nconst log = Logger('zerva:serve')\n\ndeclare global {\n interface ZContextEvents {\n serveInit: () => void\n serveStart: () => void\n serveStop: () => void\n serveDispose: () => void\n }\n}\n\n// todo context sensitive?\nlet serverStarted = false\nlet serverRunning = false\nlet serverStoping = false\n\n// Shortcuts\n\n/** @deprecated use `on('serveInit', handler)` */\nexport function onInit(handler: () => void) {\n on('serveInit', handler)\n}\n\n/** @deprecated use `on('serveStart', handler)` */\nexport function onStart(handler: () => void) {\n on('serveStart', handler)\n}\n\n/** @deprecated use `on('serveStop', handler)` */\nexport function onStop(handler: () => void) {\n on('serveStop', handler)\n}\n\nexport async function serveStop() {\n // log('serveStop called')\n if (serverStoping) {\n await new Promise(resolve => getContext().once('serveDispose', () => resolve(true)))\n }\n else if (serverRunning) {\n serverRunning = false\n serverStoping = true\n await emit('serveStop')\n serverStoping = false\n await emit('serveDispose')\n }\n // log('serveStop done')\n}\n\non('serveStart', () => {\n serverRunning = true\n})\n\non('serveStop', () => {\n if (serverStoping !== true) {\n // throw new Error('You should call `serveStop` instead of emitting `serveStop`!')\n log.warn('You should call `serveStop` instead of emitting `serveStop`!')\n\n // eslint-disable-next-line no-console\n console.trace()\n }\n})\n\n/**\n * A simple context to serve modules. Most modules listen to the evnts emitted by it.\n *\n * @param fn Call your modules in here to add them to the context\n */\nexport async function serve(fn?: () => void) {\n log('serve')\n serverStarted = true\n\n if (fn) {\n log('launch')\n fn()\n }\n log('init')\n await emit('serveInit')\n log('start')\n await emit('serveStart')\n log('serve')\n}\n\nasync function serverCheck() {\n if (serverStarted !== true) {\n log.info('Zerva has not been started manually, will start now!')\n void serve()\n }\n else if (serverRunning === true) {\n log('Reached the end, will finish gracefully.')\n await serveStop()\n }\n}\n\nprocess.on('beforeExit', serverCheck)\n// process.on('exit', serveStop)\n\n// Graceful exit\n\n// NOTE: although it is tempting, the SIGKILL signal (9) cannot be intercepted and handled\nconst signals: any = {\n SIGHUP: 1,\n SIGINT: 2,\n SIGTERM: 15,\n}\n\nlet isPerformingExit = false\n\n// on('serveDispose', () => process.exit(0))\n\nObject.keys(signals).forEach((signal) => {\n process.on(signal, () => {\n if (!isPerformingExit) {\n isPerformingExit = true\n log(`Process received a ${signal} signal`)\n serveStop().then(() => {\n // process.exit(128 + (+signals[signal] ?? 0))\n // log('Process EXIT')\n process.exit(0)\n }).catch((err) => {\n log.error(`Error on serveStop: ${err}`)\n })\n }\n else {\n log(`Ignoring: Process received a ${signal} signal`)\n }\n })\n})\n"]}