node-server-engine 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -679,6 +679,47 @@ The server engine standardizes the way errors are handled and reported. The erro
679
679
 
680
680
  Errors are a crucial part of the application, they are what helps us to properly debug the program and offer support when need, as well as what exposes issues to the client.
681
681
 
682
+ #### Log Output Formats
683
+
684
+ The engine automatically adapts log output based on the environment:
685
+
686
+ **Local Development (Readable Format)**
687
+ - Colorized output with severity levels
688
+ - Formatted timestamps and file locations
689
+ - Pretty-printed data objects
690
+ - Stack traces with proper formatting
691
+ - HTTP request context when available
692
+
693
+ **Production/GCP (JSON Format)**
694
+ - Structured JSON for log aggregation
695
+ - Google Cloud Error Reporting integration
696
+ - Kubernetes pod information
697
+ - Service context metadata
698
+
699
+ **Control Log Format**
700
+
701
+ You can override the automatic detection:
702
+
703
+ ```bash
704
+ # Force readable local format (useful for local Docker)
705
+ LOG_FORMAT=local npm start
706
+
707
+ # Force JSON format (useful for local testing)
708
+ LOG_FORMAT=json npm start
709
+ ```
710
+
711
+ **Example Local Output:**
712
+ ```
713
+ [2025-12-10T10:30:45.123Z] ERROR src/endpoints/users.ts:42 User not found
714
+ Error Code: user-not-found
715
+ Status: 404
716
+ Data:
717
+ {
718
+ "userId": "abc-123",
719
+ "requestId": "req-456"
720
+ }
721
+ ```
722
+
682
723
  By standard, the client receives the following body when an error happens.
683
724
 
684
725
  ```javascript
@@ -14,6 +14,7 @@ var _Sequelize = _interopRequireDefault(require("./Sequelize.config"));
14
14
  var _Sequelize2 = require("./Sequelize.validate");
15
15
  var _EngineError = require("../EngineError");
16
16
  var _LifecycleController = require("../LifecycleController");
17
+ var _report = require("../../utils/report");
17
18
  let sequelizeClient = exports.sequelizeClient = void 0;
18
19
 
19
20
  /**
@@ -44,7 +45,9 @@ function init() {
44
45
  // Ignore if already initialized
45
46
  if (sequelizeClient) return;
46
47
  exports.sequelizeClient = sequelizeClient = createSequelizeClient();
47
- sequelizeClient.authenticate().then(() => console.log('Connected to database.')).catch(err => console.error('Unable to connect to the database:', err));
48
+ sequelizeClient.authenticate().then(() => (0, _report.reportInfo)({
49
+ message: 'Connected to database successfully'
50
+ })).catch(err => (0, _report.reportError)(err));
48
51
  _LifecycleController.LifecycleController.register(sequelize);
49
52
  }
50
53
 
@@ -1 +1 @@
1
- {"version":3,"file":"Sequelize.js","names":["_sequelizeTypescript","require","_Sequelize","_interopRequireDefault","_Sequelize2","_EngineError","_LifecycleController","sequelizeClient","exports","sequelize","Proxy","get","target","property","init","shutdown","addModels","EngineError","message","createSequelizeClient","authenticate","then","console","log","catch","err","error","LifecycleController","register","close","undefined","models","sync","validateSequelizeEnvironment","Sequelize","process","env","SQL_DB","SQL_USER","SQL_PASSWORD","dbConfig"],"sources":["../../../src/entities/Sequelize/Sequelize.ts"],"sourcesContent":["import { Sequelize, ModelCtor } from 'sequelize-typescript';\nimport dbConfig from './Sequelize.config';\nimport { Sequelize as SequelizeInterface } from './Sequelize.types';\nimport { validateSequelizeEnvironment } from './Sequelize.validate';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\n\nexport let sequelizeClient: undefined | Sequelize;\n\n/**\n * We use a proxy to extend the Sequelize behavior and allow initialization of the client only when needed while keeping the same interface\n */\nexport const sequelize = new Proxy<SequelizeInterface>(\n // Due to how we do the proxying, we are forced to ignore ts-errors, we could never create an object that respects the interface properly\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n {},\n {\n get: function (target, property): unknown {\n if (property === 'init') return init;\n if (property === 'shutdown') return shutdown;\n if (property === 'addModels') return addModels;\n // Create the sequelize client if it does not exist\n if (!sequelizeClient)\n throw new EngineError({\n message: 'Sequelize client was not initialized'\n });\n // Call the function on the sequelize client\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n return sequelizeClient[property] as unknown;\n }\n }\n);\n\n/** On init create client and connect */\nexport function init(): void {\n // Ignore if already initialized\n if (sequelizeClient) return;\n sequelizeClient = createSequelizeClient();\n sequelizeClient\n .authenticate()\n .then(() => console.log('Connected to database.'))\n .catch((err: Error) =>\n console.error('Unable to connect to the database:', err)\n );\n LifecycleController.register(sequelize);\n}\n\n/** On shutdown close connection and clear client */\nexport async function shutdown(): Promise<void> {\n if (sequelizeClient) await sequelizeClient.close();\n sequelizeClient = undefined;\n}\n\nexport function addModels(models: Array<ModelCtor>): void {\n if (!sequelizeClient)\n throw new EngineError({\n message: 'Sequelize client was not initialized'\n });\n sequelizeClient.addModels(models);\n sequelizeClient.sync();\n}\n\n/** Create Sequelize client */\nexport function createSequelizeClient(): Sequelize {\n // Throw an error if there is no host initial\n validateSequelizeEnvironment();\n return new Sequelize(\n process.env.SQL_DB as string,\n process.env.SQL_USER as string,\n process.env.SQL_PASSWORD as string,\n dbConfig\n );\n}\n"],"mappings":";;;;;;;;;;;AAAA,IAAAA,oBAAA,GAAAC,OAAA;AACA,IAAAC,UAAA,GAAAC,sBAAA,CAAAF,OAAA;AAEA,IAAAG,WAAA,GAAAH,OAAA;AACA,IAAAI,YAAA,GAAAJ,OAAA;AACA,IAAAK,oBAAA,GAAAL,OAAA;AAEO,IAAIM,eAAsC,GAAAC,OAAA,CAAAD,eAAA;;AAEjD;AACA;AACA;AACO,MAAME,SAAS,GAAAD,OAAA,CAAAC,SAAA,GAAG,IAAIC,KAAK;AAChC;AACA;AACA;AACA,CAAC,CAAC,EACF;EACEC,GAAG,EAAE,SAAAA,CAAUC,MAAM,EAAEC,QAAQ,EAAW;IACxC,IAAIA,QAAQ,KAAK,MAAM,EAAE,OAAOC,IAAI;IACpC,IAAID,QAAQ,KAAK,UAAU,EAAE,OAAOE,QAAQ;IAC5C,IAAIF,QAAQ,KAAK,WAAW,EAAE,OAAOG,SAAS;IAC9C;IACA,IAAI,CAACT,eAAe,EAClB,MAAM,IAAIU,wBAAW,CAAC;MACpBC,OAAO,EAAE;IACX,CAAC,CAAC;IACJ;IACA;IACA;IACA,OAAOX,eAAe,CAACM,QAAQ,CAAC;EAClC;AACF,CACF,CAAC;;AAED;AACO,SAASC,IAAIA,CAAA,EAAS;EAC3B;EACA,IAAIP,eAAe,EAAE;EACrBC,OAAA,CAAAD,eAAA,GAAAA,eAAe,GAAGY,qBAAqB,CAAC,CAAC;EACzCZ,eAAe,CACZa,YAAY,CAAC,CAAC,CACdC,IAAI,CAAC,MAAMC,OAAO,CAACC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CACjDC,KAAK,CAAEC,GAAU,IAChBH,OAAO,CAACI,KAAK,CAAC,oCAAoC,EAAED,GAAG,CACzD,CAAC;EACHE,wCAAmB,CAACC,QAAQ,CAACnB,SAAS,CAAC;AACzC;;AAEA;AACO,eAAeM,QAAQA,CAAA,EAAkB;EAC9C,IAAIR,eAAe,EAAE,MAAMA,eAAe,CAACsB,KAAK,CAAC,CAAC;EAClDrB,OAAA,CAAAD,eAAA,GAAAA,eAAe,GAAGuB,SAAS;AAC7B;AAEO,SAASd,SAASA,CAACe,MAAwB,EAAQ;EACxD,IAAI,CAACxB,eAAe,EAClB,MAAM,IAAIU,wBAAW,CAAC;IACpBC,OAAO,EAAE;EACX,CAAC,CAAC;EACJX,eAAe,CAACS,SAAS,CAACe,MAAM,CAAC;EACjCxB,eAAe,CAACyB,IAAI,CAAC,CAAC;AACxB;;AAEA;AACO,SAASb,qBAAqBA,CAAA,EAAc;EACjD;EACA,IAAAc,wCAA4B,EAAC,CAAC;EAC9B,OAAO,IAAIC,8BAAS,CAClBC,OAAO,CAACC,GAAG,CAACC,MAAM,EAClBF,OAAO,CAACC,GAAG,CAACE,QAAQ,EACpBH,OAAO,CAACC,GAAG,CAACG,YAAY,EACxBC,kBACF,CAAC;AACH","ignoreList":[]}
1
+ {"version":3,"file":"Sequelize.js","names":["_sequelizeTypescript","require","_Sequelize","_interopRequireDefault","_Sequelize2","_EngineError","_LifecycleController","_report","sequelizeClient","exports","sequelize","Proxy","get","target","property","init","shutdown","addModels","EngineError","message","createSequelizeClient","authenticate","then","reportInfo","catch","err","reportError","LifecycleController","register","close","undefined","models","sync","validateSequelizeEnvironment","Sequelize","process","env","SQL_DB","SQL_USER","SQL_PASSWORD","dbConfig"],"sources":["../../../src/entities/Sequelize/Sequelize.ts"],"sourcesContent":["import { Sequelize, ModelCtor } from 'sequelize-typescript';\nimport dbConfig from './Sequelize.config';\nimport { Sequelize as SequelizeInterface } from './Sequelize.types';\nimport { validateSequelizeEnvironment } from './Sequelize.validate';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\nimport { reportInfo, reportError } from 'utils/report';\n\nexport let sequelizeClient: undefined | Sequelize;\n\n/**\n * We use a proxy to extend the Sequelize behavior and allow initialization of the client only when needed while keeping the same interface\n */\nexport const sequelize = new Proxy<SequelizeInterface>(\n // Due to how we do the proxying, we are forced to ignore ts-errors, we could never create an object that respects the interface properly\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n {},\n {\n get: function (target, property): unknown {\n if (property === 'init') return init;\n if (property === 'shutdown') return shutdown;\n if (property === 'addModels') return addModels;\n // Create the sequelize client if it does not exist\n if (!sequelizeClient)\n throw new EngineError({\n message: 'Sequelize client was not initialized'\n });\n // Call the function on the sequelize client\n // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n // @ts-ignore\n return sequelizeClient[property] as unknown;\n }\n }\n);\n\n/** On init create client and connect */\nexport function init(): void {\n // Ignore if already initialized\n if (sequelizeClient) return;\n sequelizeClient = createSequelizeClient();\n sequelizeClient\n .authenticate()\n .then(() => reportInfo({ message: 'Connected to database successfully' }))\n .catch((err: Error) => reportError(err));\n LifecycleController.register(sequelize);\n}\n\n/** On shutdown close connection and clear client */\nexport async function shutdown(): Promise<void> {\n if (sequelizeClient) await sequelizeClient.close();\n sequelizeClient = undefined;\n}\n\nexport function addModels(models: Array<ModelCtor>): void {\n if (!sequelizeClient)\n throw new EngineError({\n message: 'Sequelize client was not initialized'\n });\n sequelizeClient.addModels(models);\n sequelizeClient.sync();\n}\n\n/** Create Sequelize client */\nexport function createSequelizeClient(): Sequelize {\n // Throw an error if there is no host initial\n validateSequelizeEnvironment();\n return new Sequelize(\n process.env.SQL_DB as string,\n process.env.SQL_USER as string,\n process.env.SQL_PASSWORD as string,\n dbConfig\n );\n}\n"],"mappings":";;;;;;;;;;;AAAA,IAAAA,oBAAA,GAAAC,OAAA;AACA,IAAAC,UAAA,GAAAC,sBAAA,CAAAF,OAAA;AAEA,IAAAG,WAAA,GAAAH,OAAA;AACA,IAAAI,YAAA,GAAAJ,OAAA;AACA,IAAAK,oBAAA,GAAAL,OAAA;AACA,IAAAM,OAAA,GAAAN,OAAA;AAEO,IAAIO,eAAsC,GAAAC,OAAA,CAAAD,eAAA;;AAEjD;AACA;AACA;AACO,MAAME,SAAS,GAAAD,OAAA,CAAAC,SAAA,GAAG,IAAIC,KAAK;AAChC;AACA;AACA;AACA,CAAC,CAAC,EACF;EACEC,GAAG,EAAE,SAAAA,CAAUC,MAAM,EAAEC,QAAQ,EAAW;IACxC,IAAIA,QAAQ,KAAK,MAAM,EAAE,OAAOC,IAAI;IACpC,IAAID,QAAQ,KAAK,UAAU,EAAE,OAAOE,QAAQ;IAC5C,IAAIF,QAAQ,KAAK,WAAW,EAAE,OAAOG,SAAS;IAC9C;IACA,IAAI,CAACT,eAAe,EAClB,MAAM,IAAIU,wBAAW,CAAC;MACpBC,OAAO,EAAE;IACX,CAAC,CAAC;IACJ;IACA;IACA;IACA,OAAOX,eAAe,CAACM,QAAQ,CAAC;EAClC;AACF,CACF,CAAC;;AAED;AACO,SAASC,IAAIA,CAAA,EAAS;EAC3B;EACA,IAAIP,eAAe,EAAE;EACrBC,OAAA,CAAAD,eAAA,GAAAA,eAAe,GAAGY,qBAAqB,CAAC,CAAC;EACzCZ,eAAe,CACZa,YAAY,CAAC,CAAC,CACdC,IAAI,CAAC,MAAM,IAAAC,kBAAU,EAAC;IAAEJ,OAAO,EAAE;EAAqC,CAAC,CAAC,CAAC,CACzEK,KAAK,CAAEC,GAAU,IAAK,IAAAC,mBAAW,EAACD,GAAG,CAAC,CAAC;EAC1CE,wCAAmB,CAACC,QAAQ,CAAClB,SAAS,CAAC;AACzC;;AAEA;AACO,eAAeM,QAAQA,CAAA,EAAkB;EAC9C,IAAIR,eAAe,EAAE,MAAMA,eAAe,CAACqB,KAAK,CAAC,CAAC;EAClDpB,OAAA,CAAAD,eAAA,GAAAA,eAAe,GAAGsB,SAAS;AAC7B;AAEO,SAASb,SAASA,CAACc,MAAwB,EAAQ;EACxD,IAAI,CAACvB,eAAe,EAClB,MAAM,IAAIU,wBAAW,CAAC;IACpBC,OAAO,EAAE;EACX,CAAC,CAAC;EACJX,eAAe,CAACS,SAAS,CAACc,MAAM,CAAC;EACjCvB,eAAe,CAACwB,IAAI,CAAC,CAAC;AACxB;;AAEA;AACO,SAASZ,qBAAqBA,CAAA,EAAc;EACjD;EACA,IAAAa,wCAA4B,EAAC,CAAC;EAC9B,OAAO,IAAIC,8BAAS,CAClBC,OAAO,CAACC,GAAG,CAACC,MAAM,EAClBF,OAAO,CAACC,GAAG,CAACE,QAAQ,EACpBH,OAAO,CAACC,GAAG,CAACG,YAAY,EACxBC,kBACF,CAAC;AACH","ignoreList":[]}
@@ -227,21 +227,18 @@ let Server = exports.Server = /*#__PURE__*/function () {
227
227
 
228
228
  // Close all socket connections
229
229
  if (this.wss) {
230
- // First ask then to close gracefully
230
+ // First ask them to close gracefully
231
231
  this.wss.clients.forEach(socket => {
232
232
  socket.close();
233
233
  });
234
+
234
235
  // Hard terminate all connections still open after a defined time
235
- const socketKillTimeout = process.env.WEBSOCKET_CLOSE_TIMEOUT ? parseInt(process.env.WEBSOCKET_CLOSE_TIMEOUT) : 5000;
236
- await new Promise(resolve => {
237
- setTimeout(() => {
238
- this.wss.clients.forEach(socket => {
239
- if (socket.readyState === socket.CLOSING || socket.readyState === socket.OPEN) {
240
- socket.terminate();
241
- }
242
- });
243
- resolve();
244
- }, socketKillTimeout);
236
+ const socketKillTimeout = process.env.WEBSOCKET_CLOSE_TIMEOUT ? parseInt(process.env.WEBSOCKET_CLOSE_TIMEOUT, 10) : 5000;
237
+ await (0, _promises.setTimeout)(socketKillTimeout);
238
+ this.wss.clients.forEach(socket => {
239
+ if (socket.readyState === socket.CLOSING || socket.readyState === socket.OPEN) {
240
+ socket.terminate();
241
+ }
245
242
  });
246
243
  }
247
244
 
@@ -1 +1 @@
1
- {"version":3,"file":"Server.js","names":["_fs","_interopRequireDefault","require","_path","_promises","_express","_cors","_ws","_SocketClient","_Server2","_Endpoint","_EngineError","_LifecycleController","_PubSub","_utils","_jwt","_report","_tlsConfig","namespace","Server","exports","config","_classCallCheck2","default","_defineProperty2","AbortController","validate","reportDebug","message","endpoints","globalMiddleware","errorMiddleware","initCallbacks","shutdownCallbacks","syncCallbacks","cron","auth","noFetch","checkEnvironment","process","env","RUN_MIGRATION","UNDO_MIGRATION","SQL_HOST","envAssert","isHost","SQL_USER","isString","SQL_PASSWORD","SQL_DB","NODE_ENV","PORT","isPort","SECONDARY_PORT","app","express","use","cors","origin","CORS_ORIGIN","methods","allowedHeaders","registerMiddleware","httpServer","createHttpServer","secondaryApp","secondaryMiddleware","defaultErrorMiddleware","forEach","middleware","secondaryHttpServer","disable","server","headersTimeout","keepAliveTimeout","webSocket","attachWebSocket","_createClass2","key","value","setupGlobalErrorLogging","on","err","console","error","stack","reason","Error","code","init","initKeySets","callback","runCallback","Promise","all","map","PubSub","job","runCronJob","resolve","listen","reportInfo","data","port","secondaryPort","nodeEnv","handleSignal","watchTlsCaFileChange","shutdown","listening","address","reportError","exit","close","wss","clients","socket","socketKillTimeout","WEBSOCKET_CLOSE_TIMEOUT","parseInt","setTimeout","readyState","CLOSING","OPEN","terminate","LifecycleController","shutdownRunningInstances","abortController","abort","shutdownKeySets","shutdownSignals","signal","removeAllListeners","getApp","getSecondaryApp","defaultMiddleware","path","endpoint","register","options","WebSocketServer","request","SocketClient","client","catch","file","fs","watch","event","loadTlsConfig","setSecureContext","tlsConfig","handler","name","interval","setTimeoutPromise","undefined","function","apply","parameters","some","Endpoint","EngineError","Object","values","validator","Array"],"sources":["../../../src/entities/Server/Server.ts"],"sourcesContent":["import fs from 'fs';\nimport http from 'http';\nimport https from 'https';\nimport { AddressInfo } from 'net';\nimport path from 'path';\nimport { setTimeout as setTimeoutPromise } from 'timers/promises';\nimport { ValidatorSpec } from 'envalid';\nimport express, { Application } from 'express';\nimport cors from 'cors';\nimport { Server as WebSocketServer } from 'ws';\nimport { SocketClient } from '../SocketClient';\nimport {\n defaultMiddleware,\n defaultErrorMiddleware,\n secondaryMiddleware,\n shutdownSignals\n} from './Server.const';\nimport {\n ServerOptions,\n ServerCronJon,\n ServerAuthConfig,\n ServerWebSocketConfig,\n ServerGlobalMiddleware,\n ServerErrorMiddleWare,\n ServerCallback\n} from './Server.types';\nimport { Endpoint } from 'entities/Endpoint';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\nimport { PubSub } from 'entities/PubSub';\nimport { checkEnvironment, envAssert, createHttpServer } from 'utils';\nimport { initKeySets, shutdownKeySets } from 'utils/jwt';\nimport { reportInfo, reportError, reportDebug } from 'utils/report';\nimport { tlsConfig, loadTlsConfig, TlsConfig } from 'utils/tlsConfig';\n\nconst namespace = 'engine:Server';\n\n/** Main server class */\nexport class Server {\n /** The express application powering the main endpoints */\n private app: Application;\n /** The node HTTP(S) server, serving the main express application */\n private httpServer: http.Server | https.Server;\n /** The express application powering the support endpoints */\n private secondaryApp: Application;\n /** The node HTTP(S) server, serving the secondary express application */\n private secondaryHttpServer: http.Server | https.Server;\n /** List of endpoint instances that the server should handle */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private endpoints: Array<Endpoint<any>>;\n /** Mapping of env variable name with functions that should run to check their validity */\n private checkEnvironment: Record<string, ValidatorSpec<unknown>>;\n /** Middleware that should run on every request before the endpoint specific logic */\n private globalMiddleware: Array<ServerGlobalMiddleware>;\n /** Error middleware that should run on every request after the endpoint specific logic, but before the generic global middleware */\n private errorMiddleware: Array<\n ServerGlobalMiddleware | ServerErrorMiddleWare\n >;\n /** Functions that should be called on server startup */\n private initCallbacks: Array<ServerCallback>;\n /** Functions that should be called on server shutdown */\n private shutdownCallbacks: Array<ServerCallback>;\n /** When set to true, this indicates that init callbacks should run synchronously in the order they are declared. By default they all run in parallel */\n private syncCallbacks: boolean;\n /** Config to set regularly running jobs on the server */\n private cron?: Array<ServerCronJon>;\n /** Global auth related configuration */\n private auth: ServerAuthConfig;\n /** WebSocket server instance, if configured */\n private wss?: WebSocketServer;\n /** Abort controller that handles signals for the server */\n private abortController = new AbortController();\n\n /** Create a server */\n public constructor(config: ServerOptions) {\n this.validate(config);\n\n reportDebug({\n namespace,\n message: `Creating server`\n });\n\n this.endpoints = config.endpoints;\n this.globalMiddleware = config.globalMiddleware ?? [];\n this.errorMiddleware = config.errorMiddleware ?? [];\n this.initCallbacks = config.initCallbacks ?? [];\n this.shutdownCallbacks = config.shutdownCallbacks ?? [];\n this.syncCallbacks = config.syncCallbacks ?? false;\n this.cron = config.cron;\n this.auth = { noFetch: false, ...config.auth };\n\n // The minimal environment check is different between the migration modes of execution and the regular server execution mode\n // When running in migration mode, we only check that we have SQL related environment variables\n this.checkEnvironment =\n process.env.RUN_MIGRATION === 'true' ||\n process.env.UNDO_MIGRATION === 'true'\n ? {\n SQL_HOST: envAssert.isHost(),\n SQL_USER: envAssert.isString(),\n SQL_PASSWORD: envAssert.isString(),\n SQL_DB: envAssert.isString()\n }\n : {\n NODE_ENV: envAssert.isString(),\n PORT: envAssert.isPort(),\n SECONDARY_PORT: envAssert.isPort(),\n ...config.checkEnvironment\n };\n\n checkEnvironment(this.checkEnvironment);\n\n // Create the primary express core that serves the business logic\n this.app = express();\n this.app.use(\n cors({\n origin: process.env.CORS_ORIGIN ?? '*',\n methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],\n allowedHeaders: ['Content-Type', 'Authorization']\n })\n );\n this.registerMiddleware(this.app);\n this.httpServer = createHttpServer(this.app);\n\n // Create a secondary express core that servers metrics and analytics\n // This will be served on a different port, allowing to specify different firewall rules for these routes\n this.secondaryApp = express();\n [...secondaryMiddleware, ...defaultErrorMiddleware].forEach(\n (middleware) => {\n if (middleware) this.secondaryApp.use(middleware);\n }\n );\n this.secondaryHttpServer = createHttpServer(this.secondaryApp);\n\n // Remove the express headers\n this.app.disable('x-powered-by');\n this.secondaryApp.disable('x-powered-by');\n\n // We remove all node timeout on connections and requests\n // This responsibility is delegated to the front-facing load balancer\n [this.httpServer, this.secondaryHttpServer].forEach((server) => {\n server.headersTimeout = 0;\n server.keepAliveTimeout = 0;\n });\n\n if (config.webSocket) {\n this.attachWebSocket(config.webSocket);\n }\n }\n\n private setupGlobalErrorLogging(): void {\n process.on('uncaughtException', (err) => {\n console.error(\n '💥 uncaughtException:',\n err && err.stack ? err.stack : err\n );\n });\n process.on('unhandledRejection', (reason: unknown) => {\n if (reason instanceof Error) {\n console.error('💥 unhandledRejection:', reason.stack || reason.message);\n } else {\n console.error('💥 unhandledRejection:', reason);\n }\n });\n process.on('beforeExit', (code) =>\n console.error('process.beforeExit', code)\n );\n }\n\n /** Start the server */\n public async init(): Promise<void> {\n // this.setupGlobalErrorLogging();\n reportDebug({ namespace, message: `Starting Server` });\n // Fetch the keys for JWT authentication\n // Ignore in test environment as we do symmetrical token signing\n if (process.env.NODE_ENV !== 'test' && !this.auth.noFetch)\n await initKeySets();\n // Run all the init callbacks\n // We can either run them all 1/1 synchronously or run them all in parallel (default)\n // Callback can either be direct function or an object with function and parameters attributes\n\n if (this.syncCallbacks) {\n for (const callback of this.initCallbacks) {\n await this.runCallback(callback);\n }\n } else {\n await Promise.all(\n this.initCallbacks.map((callback) => this.runCallback(callback))\n );\n }\n\n // Initialize the Pub/Sub module\n await PubSub.init();\n // Run all the cronjob\n if (this.cron) {\n this.cron.forEach((job) => {\n this.runCronJob(job);\n });\n }\n\n // Start listening to requests\n await Promise.all([\n new Promise<void>((resolve) =>\n this.httpServer.listen(process.env.PORT, () => {\n resolve();\n })\n ),\n new Promise<void>((resolve) =>\n this.secondaryHttpServer.listen(process.env.SECONDARY_PORT, () => {\n resolve();\n })\n )\n ]);\n reportInfo({\n message: 'SERVER_RUNNING',\n data: {\n port: process.env.PORT,\n secondaryPort: process.env.SECONDARY_PORT,\n nodeEnv: process.env.NODE_ENV\n }\n });\n\n this.handleSignal();\n\n // Watch TSL config files changing\n this.watchTlsCaFileChange();\n }\n\n /** Graceful shutdown */\n public async shutdown(): Promise<void> {\n reportDebug({ namespace, message: `Shutting down Server` });\n\n // Stop listening to HTTP requests\n await Promise.all(\n [this.httpServer, this.secondaryHttpServer].map((server) => {\n // Ignore if the server was already stopped\n // We have observed cases where SIGTERM was thrown multiple times\n if (!server.listening) return;\n const { port } = server.address() as AddressInfo;\n server.on('close', (error: unknown) => {\n if (error) {\n reportError(error);\n process.exit(1);\n } else {\n reportInfo({\n message: `Stopped listening to requests on port ${port}`\n });\n }\n });\n server.close();\n })\n );\n\n // Close all socket connections\n if (this.wss) {\n // First ask then to close gracefully\n this.wss.clients.forEach((socket) => {\n socket.close();\n });\n // Hard terminate all connections still open after a defined time\n const socketKillTimeout = process.env.WEBSOCKET_CLOSE_TIMEOUT\n ? parseInt(process.env.WEBSOCKET_CLOSE_TIMEOUT)\n : 5000;\n await new Promise<void>((resolve) => {\n setTimeout(() => {\n (this.wss as WebSocketServer).clients.forEach((socket) => {\n if (\n socket.readyState === socket.CLOSING ||\n socket.readyState === socket.OPEN\n ) {\n socket.terminate();\n }\n });\n resolve();\n }, socketKillTimeout);\n });\n }\n\n // Run all the shutdown callback\n if (this.syncCallbacks) {\n for (const callback of this.shutdownCallbacks) {\n await this.runCallback(callback);\n }\n } else {\n await Promise.all(\n this.shutdownCallbacks.map((callback) => this.runCallback(callback))\n );\n }\n\n // Shutdown all the running entities\n await LifecycleController.shutdownRunningInstances();\n\n // Abort all the cronjob\n if (this.abortController) this.abortController.abort();\n\n // Stop the keyset timers\n shutdownKeySets();\n\n shutdownSignals.forEach((signal) => process.removeAllListeners(signal));\n }\n\n /** Get the express app instance of the server */\n public getApp(): Application {\n return this.app;\n }\n\n /** Get the express app instance of the server */\n public getSecondaryApp(): Application {\n return this.secondaryApp;\n }\n\n /** Registers all the middleware with the express app */\n private registerMiddleware(app: Application): void {\n // Global middleware can specify a path to which they apply\n [...defaultMiddleware, ...this.globalMiddleware].forEach((middleware) => {\n if (typeof middleware === 'function') {\n app.use(middleware);\n } else {\n app.use(middleware.path, middleware.middleware);\n }\n });\n // Call the register method of each endpoint\n this.endpoints.forEach((endpoint) => {\n endpoint.register(app);\n });\n // Add error middleware\n [...this.errorMiddleware, ...defaultErrorMiddleware].forEach(\n (middleware) => {\n if (typeof middleware === 'function') {\n app.use(middleware);\n } else {\n app.use(middleware.path, middleware.middleware);\n }\n }\n );\n }\n\n /** Add a handler for WebSocket connections */\n private attachWebSocket(options: ServerWebSocketConfig): void {\n this.wss = new WebSocketServer({\n ...options.server,\n server: this.httpServer\n })\n .on('connection', (webSocket, request) => {\n new SocketClient(webSocket, request, options.client);\n })\n .on('error', (error) => {\n reportError(error);\n });\n }\n\n /** Call shutdown if signal gets sent to the process */\n private handleSignal(): void {\n shutdownSignals.forEach((signal) =>\n process.on(signal, () => {\n (async (): Promise<void> => {\n reportInfo(`Received shutdown signal [${signal}]`);\n await this.shutdown();\n })().catch((error) => {\n reportError(error);\n });\n })\n );\n }\n\n /** Watch the TLS certificate change event */\n private watchTlsCaFileChange(): void {\n [\n 'TLS_REQUEST_KEY',\n 'TLS_REQUEST_CERT',\n 'TLS_REQUEST_CA',\n 'TLS_SERVER_KEY',\n 'TLS_SERVER_CERT',\n 'TLS_CA'\n ].forEach((key) => {\n const file = process.env[key];\n if (file)\n fs.watch(path.resolve(file), (event) => {\n if (event !== 'change') return;\n reportInfo(`Reloading TLS config [${file} changed]`);\n loadTlsConfig();\n (this.httpServer as https.Server).setSecureContext(\n tlsConfig as TlsConfig\n );\n });\n });\n }\n\n /** Executes a recurring job */\n private runCronJob(job: ServerCronJon): void {\n (async (): Promise<void> => {\n reportInfo({ message: `Starting scheduled job \"${job.handler.name}\"` });\n try {\n await job.handler();\n reportInfo({\n message: `Job \"${job.handler.name}\" finished, starting again in ${job.interval} seconds`\n });\n await setTimeoutPromise(job.interval * 1000, undefined, {\n signal: this.abortController.signal\n });\n this.runCronJob(job);\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n reportDebug({\n namespace,\n message: `Scheduled job \"${job.handler?.name}\" has been aborted`\n });\n } else {\n throw error;\n }\n }\n })().catch((error) => {\n reportError(error);\n });\n }\n\n /** Run a shutdown/init callback */\n private runCallback(callback: ServerCallback): unknown {\n return typeof callback === 'function'\n ? callback()\n : callback.function.apply(null, callback.parameters ?? []);\n }\n\n /**\n * Validate the Server constructor configuration\n */\n private validate(config: ServerOptions): void {\n if (\n !config.endpoints ||\n config.endpoints.some((endpoint) => !(endpoint instanceof Endpoint))\n )\n throw new EngineError(\n 'Server endpoints should be declared and all be Endpoint instances'\n );\n\n if (\n config.checkEnvironment &&\n Object.values(config.checkEnvironment).some(\n (validator) => typeof validator !== 'function'\n )\n )\n throw new EngineError(\n 'Some of the environment checks are not valid functions'\n );\n\n if (\n config.initCallbacks &&\n (!(config.initCallbacks instanceof Array) ||\n config.initCallbacks.some(\n (callback) =>\n !(\n typeof callback === 'function' ||\n typeof callback?.function === 'function'\n )\n ))\n )\n throw new EngineError('Init callbacks is not a list of functions');\n\n if (\n config.shutdownCallbacks &&\n (!(config.shutdownCallbacks instanceof Array) ||\n config.shutdownCallbacks.some(\n (callback) =>\n !(\n typeof callback === 'function' ||\n typeof callback?.function === 'function'\n )\n ))\n )\n throw new EngineError('Shutdown callbacks is not a list of functions');\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"Server.js","names":["_fs","_interopRequireDefault","require","_path","_promises","_express","_cors","_ws","_SocketClient","_Server2","_Endpoint","_EngineError","_LifecycleController","_PubSub","_utils","_jwt","_report","_tlsConfig","namespace","Server","exports","config","_classCallCheck2","default","_defineProperty2","AbortController","validate","reportDebug","message","endpoints","globalMiddleware","errorMiddleware","initCallbacks","shutdownCallbacks","syncCallbacks","cron","auth","noFetch","checkEnvironment","process","env","RUN_MIGRATION","UNDO_MIGRATION","SQL_HOST","envAssert","isHost","SQL_USER","isString","SQL_PASSWORD","SQL_DB","NODE_ENV","PORT","isPort","SECONDARY_PORT","app","express","use","cors","origin","CORS_ORIGIN","methods","allowedHeaders","registerMiddleware","httpServer","createHttpServer","secondaryApp","secondaryMiddleware","defaultErrorMiddleware","forEach","middleware","secondaryHttpServer","disable","server","headersTimeout","keepAliveTimeout","webSocket","attachWebSocket","_createClass2","key","value","setupGlobalErrorLogging","on","err","console","error","stack","reason","Error","code","init","initKeySets","callback","runCallback","Promise","all","map","PubSub","job","runCronJob","resolve","listen","reportInfo","data","port","secondaryPort","nodeEnv","handleSignal","watchTlsCaFileChange","shutdown","listening","address","reportError","exit","close","wss","clients","socket","socketKillTimeout","WEBSOCKET_CLOSE_TIMEOUT","parseInt","setTimeoutPromise","readyState","CLOSING","OPEN","terminate","LifecycleController","shutdownRunningInstances","abortController","abort","shutdownKeySets","shutdownSignals","signal","removeAllListeners","getApp","getSecondaryApp","defaultMiddleware","path","endpoint","register","options","WebSocketServer","request","SocketClient","client","catch","file","fs","watch","event","loadTlsConfig","setSecureContext","tlsConfig","handler","name","interval","undefined","function","apply","parameters","some","Endpoint","EngineError","Object","values","validator","Array"],"sources":["../../../src/entities/Server/Server.ts"],"sourcesContent":["import fs from 'fs';\nimport http from 'http';\nimport https from 'https';\nimport { AddressInfo } from 'net';\nimport path from 'path';\nimport { setTimeout as setTimeoutPromise } from 'timers/promises';\nimport { ValidatorSpec } from 'envalid';\nimport express, { Application } from 'express';\nimport cors from 'cors';\nimport { Server as WebSocketServer } from 'ws';\nimport { SocketClient } from '../SocketClient';\nimport {\n defaultMiddleware,\n defaultErrorMiddleware,\n secondaryMiddleware,\n shutdownSignals\n} from './Server.const';\nimport {\n ServerOptions,\n ServerCronJon,\n ServerAuthConfig,\n ServerWebSocketConfig,\n ServerGlobalMiddleware,\n ServerErrorMiddleWare,\n ServerCallback\n} from './Server.types';\nimport { Endpoint } from 'entities/Endpoint';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\nimport { PubSub } from 'entities/PubSub';\nimport { checkEnvironment, envAssert, createHttpServer } from 'utils';\nimport { initKeySets, shutdownKeySets } from 'utils/jwt';\nimport { reportInfo, reportError, reportDebug } from 'utils/report';\nimport { tlsConfig, loadTlsConfig, TlsConfig } from 'utils/tlsConfig';\n\nconst namespace = 'engine:Server';\n\n/** Main server class */\nexport class Server {\n /** The express application powering the main endpoints */\n private app: Application;\n /** The node HTTP(S) server, serving the main express application */\n private httpServer: http.Server | https.Server;\n /** The express application powering the support endpoints */\n private secondaryApp: Application;\n /** The node HTTP(S) server, serving the secondary express application */\n private secondaryHttpServer: http.Server | https.Server;\n /** List of endpoint instances that the server should handle */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private endpoints: Array<Endpoint<any>>;\n /** Mapping of env variable name with functions that should run to check their validity */\n private checkEnvironment: Record<string, ValidatorSpec<unknown>>;\n /** Middleware that should run on every request before the endpoint specific logic */\n private globalMiddleware: Array<ServerGlobalMiddleware>;\n /** Error middleware that should run on every request after the endpoint specific logic, but before the generic global middleware */\n private errorMiddleware: Array<\n ServerGlobalMiddleware | ServerErrorMiddleWare\n >;\n /** Functions that should be called on server startup */\n private initCallbacks: Array<ServerCallback>;\n /** Functions that should be called on server shutdown */\n private shutdownCallbacks: Array<ServerCallback>;\n /** When set to true, this indicates that init callbacks should run synchronously in the order they are declared. By default they all run in parallel */\n private syncCallbacks: boolean;\n /** Config to set regularly running jobs on the server */\n private cron?: Array<ServerCronJon>;\n /** Global auth related configuration */\n private auth: ServerAuthConfig;\n /** WebSocket server instance, if configured */\n private wss?: WebSocketServer;\n /** Abort controller that handles signals for the server */\n private abortController = new AbortController();\n\n /** Create a server */\n public constructor(config: ServerOptions) {\n this.validate(config);\n\n reportDebug({\n namespace,\n message: `Creating server`\n });\n\n this.endpoints = config.endpoints;\n this.globalMiddleware = config.globalMiddleware ?? [];\n this.errorMiddleware = config.errorMiddleware ?? [];\n this.initCallbacks = config.initCallbacks ?? [];\n this.shutdownCallbacks = config.shutdownCallbacks ?? [];\n this.syncCallbacks = config.syncCallbacks ?? false;\n this.cron = config.cron;\n this.auth = { noFetch: false, ...config.auth };\n\n // The minimal environment check is different between the migration modes of execution and the regular server execution mode\n // When running in migration mode, we only check that we have SQL related environment variables\n this.checkEnvironment =\n process.env.RUN_MIGRATION === 'true' ||\n process.env.UNDO_MIGRATION === 'true'\n ? {\n SQL_HOST: envAssert.isHost(),\n SQL_USER: envAssert.isString(),\n SQL_PASSWORD: envAssert.isString(),\n SQL_DB: envAssert.isString()\n }\n : {\n NODE_ENV: envAssert.isString(),\n PORT: envAssert.isPort(),\n SECONDARY_PORT: envAssert.isPort(),\n ...config.checkEnvironment\n };\n\n checkEnvironment(this.checkEnvironment);\n\n // Create the primary express core that serves the business logic\n this.app = express();\n this.app.use(\n cors({\n origin: process.env.CORS_ORIGIN ?? '*',\n methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],\n allowedHeaders: ['Content-Type', 'Authorization']\n })\n );\n this.registerMiddleware(this.app);\n this.httpServer = createHttpServer(this.app);\n\n // Create a secondary express core that servers metrics and analytics\n // This will be served on a different port, allowing to specify different firewall rules for these routes\n this.secondaryApp = express();\n [...secondaryMiddleware, ...defaultErrorMiddleware].forEach(\n (middleware) => {\n if (middleware) this.secondaryApp.use(middleware);\n }\n );\n this.secondaryHttpServer = createHttpServer(this.secondaryApp);\n\n // Remove the express headers\n this.app.disable('x-powered-by');\n this.secondaryApp.disable('x-powered-by');\n\n // We remove all node timeout on connections and requests\n // This responsibility is delegated to the front-facing load balancer\n [this.httpServer, this.secondaryHttpServer].forEach((server) => {\n server.headersTimeout = 0;\n server.keepAliveTimeout = 0;\n });\n\n if (config.webSocket) {\n this.attachWebSocket(config.webSocket);\n }\n }\n\n private setupGlobalErrorLogging(): void {\n process.on('uncaughtException', (err) => {\n console.error(\n '💥 uncaughtException:',\n err && err.stack ? err.stack : err\n );\n });\n process.on('unhandledRejection', (reason: unknown) => {\n if (reason instanceof Error) {\n console.error('💥 unhandledRejection:', reason.stack || reason.message);\n } else {\n console.error('💥 unhandledRejection:', reason);\n }\n });\n process.on('beforeExit', (code) =>\n console.error('process.beforeExit', code)\n );\n }\n\n /** Start the server */\n public async init(): Promise<void> {\n // this.setupGlobalErrorLogging();\n reportDebug({ namespace, message: `Starting Server` });\n // Fetch the keys for JWT authentication\n // Ignore in test environment as we do symmetrical token signing\n if (process.env.NODE_ENV !== 'test' && !this.auth.noFetch)\n await initKeySets();\n // Run all the init callbacks\n // We can either run them all 1/1 synchronously or run them all in parallel (default)\n // Callback can either be direct function or an object with function and parameters attributes\n\n if (this.syncCallbacks) {\n for (const callback of this.initCallbacks) {\n await this.runCallback(callback);\n }\n } else {\n await Promise.all(\n this.initCallbacks.map((callback) => this.runCallback(callback))\n );\n }\n\n // Initialize the Pub/Sub module\n await PubSub.init();\n // Run all the cronjob\n if (this.cron) {\n this.cron.forEach((job) => {\n this.runCronJob(job);\n });\n }\n\n // Start listening to requests\n await Promise.all([\n new Promise<void>((resolve) =>\n this.httpServer.listen(process.env.PORT, () => {\n resolve();\n })\n ),\n new Promise<void>((resolve) =>\n this.secondaryHttpServer.listen(process.env.SECONDARY_PORT, () => {\n resolve();\n })\n )\n ]);\n reportInfo({\n message: 'SERVER_RUNNING',\n data: {\n port: process.env.PORT,\n secondaryPort: process.env.SECONDARY_PORT,\n nodeEnv: process.env.NODE_ENV\n }\n });\n\n this.handleSignal();\n\n // Watch TSL config files changing\n this.watchTlsCaFileChange();\n }\n\n /** Graceful shutdown */\n public async shutdown(): Promise<void> {\n reportDebug({ namespace, message: `Shutting down Server` });\n\n // Stop listening to HTTP requests\n await Promise.all(\n [this.httpServer, this.secondaryHttpServer].map((server) => {\n // Ignore if the server was already stopped\n // We have observed cases where SIGTERM was thrown multiple times\n if (!server.listening) return;\n const { port } = server.address() as AddressInfo;\n server.on('close', (error: unknown) => {\n if (error) {\n reportError(error);\n process.exit(1);\n } else {\n reportInfo({\n message: `Stopped listening to requests on port ${port}`\n });\n }\n });\n server.close();\n })\n );\n\n // Close all socket connections\n if (this.wss) {\n // First ask them to close gracefully\n this.wss.clients.forEach((socket) => {\n socket.close();\n });\n \n // Hard terminate all connections still open after a defined time\n const socketKillTimeout = process.env.WEBSOCKET_CLOSE_TIMEOUT\n ? parseInt(process.env.WEBSOCKET_CLOSE_TIMEOUT, 10)\n : 5000;\n \n await setTimeoutPromise(socketKillTimeout);\n \n this.wss.clients.forEach((socket) => {\n if (\n socket.readyState === socket.CLOSING ||\n socket.readyState === socket.OPEN\n ) {\n socket.terminate();\n }\n });\n }\n\n // Run all the shutdown callback\n if (this.syncCallbacks) {\n for (const callback of this.shutdownCallbacks) {\n await this.runCallback(callback);\n }\n } else {\n await Promise.all(\n this.shutdownCallbacks.map((callback) => this.runCallback(callback))\n );\n }\n\n // Shutdown all the running entities\n await LifecycleController.shutdownRunningInstances();\n\n // Abort all the cronjob\n if (this.abortController) this.abortController.abort();\n\n // Stop the keyset timers\n shutdownKeySets();\n\n shutdownSignals.forEach((signal) => process.removeAllListeners(signal));\n }\n\n /** Get the express app instance of the server */\n public getApp(): Application {\n return this.app;\n }\n\n /** Get the express app instance of the server */\n public getSecondaryApp(): Application {\n return this.secondaryApp;\n }\n\n /** Registers all the middleware with the express app */\n private registerMiddleware(app: Application): void {\n // Global middleware can specify a path to which they apply\n [...defaultMiddleware, ...this.globalMiddleware].forEach((middleware) => {\n if (typeof middleware === 'function') {\n app.use(middleware);\n } else {\n app.use(middleware.path, middleware.middleware);\n }\n });\n // Call the register method of each endpoint\n this.endpoints.forEach((endpoint) => {\n endpoint.register(app);\n });\n // Add error middleware\n [...this.errorMiddleware, ...defaultErrorMiddleware].forEach(\n (middleware) => {\n if (typeof middleware === 'function') {\n app.use(middleware);\n } else {\n app.use(middleware.path, middleware.middleware);\n }\n }\n );\n }\n\n /** Add a handler for WebSocket connections */\n private attachWebSocket(options: ServerWebSocketConfig): void {\n this.wss = new WebSocketServer({\n ...options.server,\n server: this.httpServer\n })\n .on('connection', (webSocket, request) => {\n new SocketClient(webSocket, request, options.client);\n })\n .on('error', (error) => {\n reportError(error);\n });\n }\n\n /** Call shutdown if signal gets sent to the process */\n private handleSignal(): void {\n shutdownSignals.forEach((signal) =>\n process.on(signal, () => {\n (async (): Promise<void> => {\n reportInfo(`Received shutdown signal [${signal}]`);\n await this.shutdown();\n })().catch((error) => {\n reportError(error);\n });\n })\n );\n }\n\n /** Watch the TLS certificate change event */\n private watchTlsCaFileChange(): void {\n [\n 'TLS_REQUEST_KEY',\n 'TLS_REQUEST_CERT',\n 'TLS_REQUEST_CA',\n 'TLS_SERVER_KEY',\n 'TLS_SERVER_CERT',\n 'TLS_CA'\n ].forEach((key) => {\n const file = process.env[key];\n if (file)\n fs.watch(path.resolve(file), (event) => {\n if (event !== 'change') return;\n reportInfo(`Reloading TLS config [${file} changed]`);\n loadTlsConfig();\n (this.httpServer as https.Server).setSecureContext(\n tlsConfig as TlsConfig\n );\n });\n });\n }\n\n /** Executes a recurring job */\n private runCronJob(job: ServerCronJon): void {\n (async (): Promise<void> => {\n reportInfo({ message: `Starting scheduled job \"${job.handler.name}\"` });\n try {\n await job.handler();\n reportInfo({\n message: `Job \"${job.handler.name}\" finished, starting again in ${job.interval} seconds`\n });\n await setTimeoutPromise(job.interval * 1000, undefined, {\n signal: this.abortController.signal\n });\n this.runCronJob(job);\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n reportDebug({\n namespace,\n message: `Scheduled job \"${job.handler?.name}\" has been aborted`\n });\n } else {\n throw error;\n }\n }\n })().catch((error) => {\n reportError(error);\n });\n }\n\n /** Run a shutdown/init callback */\n private runCallback(callback: ServerCallback): unknown {\n return typeof callback === 'function'\n ? callback()\n : callback.function.apply(null, callback.parameters ?? []);\n }\n\n /**\n * Validate the Server constructor configuration\n */\n private validate(config: ServerOptions): void {\n if (\n !config.endpoints ||\n config.endpoints.some((endpoint) => !(endpoint instanceof Endpoint))\n )\n throw new EngineError(\n 'Server endpoints should be declared and all be Endpoint instances'\n );\n\n if (\n config.checkEnvironment &&\n Object.values(config.checkEnvironment).some(\n (validator) => typeof validator !== 'function'\n )\n )\n throw new EngineError(\n 'Some of the environment checks are not valid functions'\n );\n\n if (\n config.initCallbacks &&\n (!(config.initCallbacks instanceof Array) ||\n config.initCallbacks.some(\n (callback) =>\n !(\n typeof callback === 'function' ||\n typeof callback?.function === 'function'\n )\n ))\n )\n throw new EngineError('Init callbacks is not a list of functions');\n\n if (\n config.shutdownCallbacks &&\n (!(config.shutdownCallbacks instanceof Array) ||\n config.shutdownCallbacks.some(\n (callback) =>\n !(\n typeof callback === 'function' ||\n typeof callback?.function === 'function'\n )\n ))\n )\n throw new EngineError('Shutdown callbacks is not a list of functions');\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -41,8 +41,11 @@ export declare class SocketClient {
41
41
  private pingInterval;
42
42
  /**
43
43
  * Create a WS client
44
+ * @param webSocket - The WebSocket instance
45
+ * @param _request - The incoming HTTP request (reserved for future use)
46
+ * @param options - Socket client configuration options
44
47
  */
45
- constructor(webSocket: WS, request: IncomingMessage, options: SocketClientOptions);
48
+ constructor(webSocket: WS, _request: IncomingMessage, options: SocketClientOptions);
46
49
  /** Get the list of all connected clients indexed by ID */
47
50
  static getSocketClients(): SocketClientList;
48
51
  /** Get a client by his ID */
@@ -25,8 +25,11 @@ const namespace = 'SocketClient';
25
25
  let SocketClient = exports.SocketClient = /*#__PURE__*/function () {
26
26
  /**
27
27
  * Create a WS client
28
+ * @param webSocket - The WebSocket instance
29
+ * @param _request - The incoming HTTP request (reserved for future use)
30
+ * @param options - Socket client configuration options
28
31
  */
29
- function SocketClient(webSocket, request, options) {
32
+ function SocketClient(webSocket, _request, options) {
30
33
  (0, _classCallCheck2.default)(this, SocketClient);
31
34
  /** Unique identifier of the client */
32
35
  (0, _defineProperty2.default)(this, "id", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"SocketClient.js","names":["_crypto","require","_parseMessage","_const","_EngineError","_MessageHandler","_ValidationError","_WebError","_jwt","_report","namespace","SocketClient","exports","webSocket","request","options","_classCallCheck2","default","_defineProperty2","id","randomUUID","ws","establishedAt","Date","reportDebug","message","initCallbacks","Array","authCallbacks","shutdownCallbacks","handlers","handler","MessageHandler","EngineError","socketClients","reportInfo","on","handleClose","bind","catch","error","reportError","severity","LogSeverity","WARNING","data","handleMessage","callbackResults","Promise","allSettled","map","callback","forEach","result","status","reason","pingInterval","setInterval","isAlive","terminate","ping","process","env","WS_PING_INTERVAL","parseInt","_createClass2","key","value","sendMessage","type","payload","send","noAuth","authenticated","audience","includes","DEFAULT_MESSAGE_AUDIENCE","JSON","stringify","isAuthenticated","getUser","userId","deviceId","tokenId","undefined","parseMessage","toString","authenticate","handle","handleError","token","WebError","errorCode","jwtVerify","setUserData","authExpiration","exp","now","clearTimeouts","authRenewTimer","setTimeout","authExpireTimer","clearTimeout","sub","dev","jti","aud","hint","ValidationError","code","clearInterval","getSocketClients","getSocketClient"],"sources":["../../../src/entities/SocketClient/SocketClient.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport { IncomingMessage } from 'http';\nimport WS, { RawData } from 'ws';\nimport { parseMessage } from './parseMessage';\nimport {\n SocketClientOptions,\n SocketClientSendMessageOptions,\n SocketAuthenticationMessage,\n SocketClientCallback,\n SocketClientList,\n SocketUser\n} from './SocketClient.types';\nimport { LogSeverity } from 'const';\nimport { EngineError } from 'entities/EngineError';\nimport { MessageHandler } from 'entities/MessageHandler';\nimport { ValidationError } from 'entities/ValidationError';\nimport { WebError } from 'entities/WebError';\nimport { jwtVerify, UserTokenPayload } from 'utils/jwt';\nimport { reportInfo, reportError, reportDebug } from 'utils/report';\n\nconst namespace = 'SocketClient';\n\n/**\n * Class where each instance represents a client connected through web-sockets\n */\nexport class SocketClient {\n /** Mapping of all the connected socket clients */\n private static socketClients: SocketClientList = {};\n /** Unique identifier of the client */\n public readonly id: string;\n /** Date at which the client connection was established */\n public readonly establishedAt: Date;\n /** WS instance of the client connection */\n private ws: WS;\n /** List of message handlers that are registered with the client */\n private handlers: Array<MessageHandler>;\n /** Callback function that are called when the client is created */\n private initCallbacks: Array<SocketClientCallback> = [];\n /** Callback function that are called when the client successfully authenticates */\n private authCallbacks: Array<SocketClientCallback> = [];\n /** Callback function that are called when the client connection is terminated */\n private shutdownCallbacks: Array<SocketClientCallback> = [];\n /** Authentication status of the client */\n private authenticated = false;\n /** Timer used to track when to send authentication renewal reminder to the client */\n private authRenewTimer: NodeJS.Timeout | string | number | undefined;\n /** Timers used to track the time at which a user losses authentication */\n private authExpireTimer: NodeJS.Timeout | string | number | undefined;\n /** ID of the user that is authenticated */\n private userId: undefined | string;\n /** ID of the device with which the client authenticated */\n private deviceId: undefined | string;\n /** Id of the token with which the client authenticated */\n private tokenId: undefined | string;\n /** Audience claims that were in the latest authentication token used by the client */\n private audience: undefined | Array<string>;\n /** Status tracking variable used to check the liveness of connections */\n private isAlive = true;\n /** Timer used to track interval between client pinging */\n private pingInterval: NodeJS.Timeout | string | number | undefined;\n\n /**\n * Create a WS client\n */\n public constructor(\n webSocket: WS,\n request: IncomingMessage,\n options: SocketClientOptions\n ) {\n this.id = randomUUID();\n this.ws = webSocket;\n this.establishedAt = new Date();\n\n reportDebug({ namespace, message: `Creating socket client [${this.id}]` });\n\n // Make sure that callbacks are made as lists of functions\n // Init\n if (typeof options.initCallbacks === 'function')\n this.initCallbacks = [options.initCallbacks];\n else if (options.initCallbacks instanceof Array)\n this.initCallbacks = options.initCallbacks;\n // Auth\n if (typeof options.authCallbacks === 'function')\n this.authCallbacks = [options.authCallbacks];\n else if (options.authCallbacks instanceof Array)\n this.authCallbacks = options.authCallbacks;\n // Shutdown\n if (typeof options.shutdownCallbacks === 'function')\n this.shutdownCallbacks = [options.shutdownCallbacks];\n else if (options.shutdownCallbacks instanceof Array)\n this.shutdownCallbacks = options.shutdownCallbacks;\n\n // Check that all handlers are valid\n this.handlers = options.handlers;\n for (const handler of this.handlers) {\n if (!(handler instanceof MessageHandler))\n throw new EngineError({\n message: 'Handler is not an instance of MessageHandler'\n });\n }\n // Register in clients list\n SocketClient.socketClients[this.id] = this;\n\n reportInfo({ message: `Client connected [${this.id}]` });\n // On socket close, deregister from clients list\n this.ws.on('close', () => {\n this.handleClose\n .bind(this)()\n .catch((error) => {\n reportError(error);\n });\n });\n // On socket error, log the error\n this.ws.on('error', (error) => {\n reportError(\n new EngineError({\n severity: LogSeverity.WARNING,\n message: `Error [${this.id}]`\n })\n );\n reportError(error);\n });\n // When receiving a message, call message handler\n this.ws.on('message', (data) => {\n this.handleMessage\n .bind(this)(data)\n .catch((error) => {\n reportError(error);\n });\n });\n\n // Run all the init callbacks\n // For proper error handling of potential asynchronous callbacks, we wrap the execution in an auto-executing async function\n (async (): Promise<void> => {\n const callbackResults = await Promise.allSettled(\n this.initCallbacks.map((callback) => callback(this))\n );\n callbackResults.forEach((result) => {\n if (result.status === 'rejected') reportError(result.reason);\n });\n })().catch((error) => {\n reportError(error);\n });\n\n // Server -> client ping mechanism using WS standard ping control frames\n // We terminate the connection if we did not get a reply in the previous interval\n this.pingInterval = setInterval(\n () => {\n if (!this.isAlive) {\n reportError(\n new EngineError({\n severity: LogSeverity.WARNING,\n message: `Terminating socket connection, ping timeout [${this.id}]`\n })\n );\n this.ws.terminate();\n return;\n }\n this.isAlive = false;\n this.ws.ping();\n reportDebug({ namespace, message: `Ping sent to client [${this.id}]` });\n },\n process.env.WS_PING_INTERVAL\n ? parseInt(process.env.WS_PING_INTERVAL) * 1000\n : 30000\n );\n\n // Track the connection as alive as we get a pong back\n this.ws.on('pong', () => {\n reportDebug({\n namespace,\n message: `Client responded to ping [${this.id}]`\n });\n this.isAlive = true;\n });\n }\n\n /** Get the list of all connected clients indexed by ID */\n public static getSocketClients(): SocketClientList {\n return this.socketClients;\n }\n\n /** Get a client by his ID */\n public static getSocketClient(id: string): SocketClient | undefined {\n return this.socketClients[id];\n }\n\n /**\n * Send a message to the client\n */\n public sendMessage(\n type: string,\n payload: unknown = {},\n options: SocketClientSendMessageOptions = {}\n ): void {\n reportDebug({\n namespace,\n message: `Received request to send message to client of type \"${type}\" [${this.id}]`,\n data: { options }\n });\n let send = false;\n // If the message is sent to unauthenticated user skip auth check\n if (options.noAuth) send = true;\n // If the message is authenticated and with the correct audience, it gets sent\n else if (\n this.authenticated &&\n (this.audience as Array<string>).includes(\n options.audience ?? (process.env.DEFAULT_MESSAGE_AUDIENCE as string)\n )\n )\n send = true;\n\n if (send) {\n reportDebug({\n namespace,\n message: `Sending message to client of type \"${type ?? 'unknown'}\" [${this.id}]`\n });\n this.ws.send(JSON.stringify({ type, payload }));\n }\n }\n\n /** Get the client authentication status */\n public isAuthenticated(): boolean {\n return this.authenticated;\n }\n\n /** Fetch data on the user if he is authenticated */\n public getUser(): SocketUser | undefined {\n if (this.authenticated)\n return {\n userId: this.userId as string,\n deviceId: this.deviceId as string,\n tokenId: this.tokenId as string,\n audience: this.audience as Array<string>\n };\n return undefined;\n }\n\n /** Process an incoming message */\n private async handleMessage(data: RawData): Promise<void> {\n try {\n const message = parseMessage(data.toString('utf-8'));\n reportInfo({\n message: `Received message of type \"${message?.type ?? 'unknown'}\" [${this.id}]`\n });\n switch (message.type) {\n case 'authenticate':\n await this.authenticate(message as SocketAuthenticationMessage);\n break;\n // As not all client libraries allow sending pings through WS control frames,\n // we add a higher level ping mechanism\n case 'ping':\n reportDebug({\n namespace,\n message: `Received ping from client [${this.id}]`\n });\n this.sendMessage('pong', {}, { noAuth: true });\n break;\n default:\n for (const handler of this.handlers) {\n await handler.handle(message, this);\n }\n }\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Process an authentication request\n * @param {String} message - Authentication message\n */\n private async authenticate(\n message: SocketAuthenticationMessage\n ): Promise<void> {\n const token = message.payload?.token;\n if (!token) {\n throw new WebError({\n errorCode: 'no-token',\n message: 'No token was given',\n data: { message }\n });\n }\n const payload = await jwtVerify(token);\n this.setUserData(payload);\n\n this.authenticated = true;\n // Time remaining before token expiration\n const authExpiration = payload.exp * 1000 - Date.now();\n // Clear previously created timers\n this.clearTimeouts();\n // Send a refresh request to the client 1 minute before expiration\n this.authRenewTimer = setTimeout(\n () => {\n this.sendMessage('renewAuthentication');\n },\n authExpiration - 60 * 1000\n );\n // Expire client authentication\n this.authExpireTimer = setTimeout(() => {\n this.authenticated = false;\n }, authExpiration);\n\n // Run all the post-authentication callbacks\n const callbackResults = await Promise.allSettled(\n this.authCallbacks.map((callback) => callback(this))\n );\n callbackResults.forEach((result) => {\n if (result.status === 'rejected') reportError(result.reason);\n });\n }\n\n // Clear all the pending timers\n /** */\n private clearTimeouts(): void {\n if (this.authRenewTimer) clearTimeout(this.authRenewTimer);\n if (this.authExpireTimer) clearTimeout(this.authExpireTimer);\n }\n\n /**\n * Fetch the user's data and attach it to the connection for new connections. For existing connections, it checks that the authentication is done on the same user.\n */\n private setUserData({ sub, dev, jti, aud }: UserTokenPayload): void {\n // Check if the user is already authenticated\n if (this.userId) {\n // Check that the token is for the same connection as before\n if (this.userId && this.userId !== sub)\n throw new WebError({\n errorCode: 'wrong-user-token',\n message:\n 'A user tried to authenticate with a token that is not for him [userId]'\n });\n } else {\n // Set the user's ID\n this.userId = sub;\n // Set the user's Device Id\n this.deviceId = dev;\n // Set the token ID\n this.tokenId = jti;\n // Set the aud\n this.audience = aud instanceof Array ? aud : [aud];\n\n reportDebug({\n namespace,\n message: `Successfully authenticated client [${this.id}]`,\n data: {\n userId: this.userId,\n deviceId: this.deviceId,\n tokenId: this.tokenId,\n audience: this.audience\n }\n });\n }\n }\n\n /**\n * Properly return errors to clients\n */\n private handleError(error: unknown): void {\n reportError(error);\n if (error instanceof WebError) {\n this.sendMessage(\n 'error',\n { errorCode: error.errorCode, hint: error.hint },\n { noAuth: true }\n );\n } else if (error instanceof ValidationError) {\n this.sendMessage(\n 'error',\n { errorCode: 'validation-error', hint: error.data },\n { noAuth: true }\n );\n } else {\n this.sendMessage(\n 'error',\n { errorCode: 'server-error' },\n { noAuth: true }\n );\n }\n }\n\n /**\n * Process a socket close event\n */\n private async handleClose(code?: string, reason?: string): Promise<void> {\n delete SocketClient.socketClients[this.id];\n this.clearTimeouts();\n // Stop ping process\n if (this.pingInterval) clearInterval(this.pingInterval);\n // Run all the shutdown callbacks\n const callbackResults = await Promise.allSettled(\n this.shutdownCallbacks.map((callback) => callback(this))\n );\n callbackResults.forEach((result) => {\n if (result.status === 'rejected') reportError(result.reason);\n });\n reportInfo({\n message: `Client disconnected [${this.id}]`,\n data: { code, reason }\n });\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"SocketClient.js","names":["_crypto","require","_parseMessage","_const","_EngineError","_MessageHandler","_ValidationError","_WebError","_jwt","_report","namespace","SocketClient","exports","webSocket","_request","options","_classCallCheck2","default","_defineProperty2","id","randomUUID","ws","establishedAt","Date","reportDebug","message","initCallbacks","Array","authCallbacks","shutdownCallbacks","handlers","handler","MessageHandler","EngineError","socketClients","reportInfo","on","handleClose","bind","catch","error","reportError","severity","LogSeverity","WARNING","data","handleMessage","callbackResults","Promise","allSettled","map","callback","forEach","result","status","reason","pingInterval","setInterval","isAlive","terminate","ping","process","env","WS_PING_INTERVAL","parseInt","_createClass2","key","value","sendMessage","type","payload","send","noAuth","authenticated","audience","includes","DEFAULT_MESSAGE_AUDIENCE","JSON","stringify","isAuthenticated","getUser","userId","deviceId","tokenId","undefined","parseMessage","toString","authenticate","handle","handleError","token","WebError","errorCode","jwtVerify","setUserData","authExpiration","exp","now","clearTimeouts","authRenewTimer","setTimeout","authExpireTimer","clearTimeout","sub","dev","jti","aud","hint","ValidationError","code","clearInterval","getSocketClients","getSocketClient"],"sources":["../../../src/entities/SocketClient/SocketClient.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport { IncomingMessage } from 'http';\nimport WS, { RawData } from 'ws';\nimport { parseMessage } from './parseMessage';\nimport {\n SocketClientOptions,\n SocketClientSendMessageOptions,\n SocketAuthenticationMessage,\n SocketClientCallback,\n SocketClientList,\n SocketUser\n} from './SocketClient.types';\nimport { LogSeverity } from 'const';\nimport { EngineError } from 'entities/EngineError';\nimport { MessageHandler } from 'entities/MessageHandler';\nimport { ValidationError } from 'entities/ValidationError';\nimport { WebError } from 'entities/WebError';\nimport { jwtVerify, UserTokenPayload } from 'utils/jwt';\nimport { reportInfo, reportError, reportDebug } from 'utils/report';\n\nconst namespace = 'SocketClient';\n\n/**\n * Class where each instance represents a client connected through web-sockets\n */\nexport class SocketClient {\n /** Mapping of all the connected socket clients */\n private static socketClients: SocketClientList = {};\n /** Unique identifier of the client */\n public readonly id: string;\n /** Date at which the client connection was established */\n public readonly establishedAt: Date;\n /** WS instance of the client connection */\n private ws: WS;\n /** List of message handlers that are registered with the client */\n private handlers: Array<MessageHandler>;\n /** Callback function that are called when the client is created */\n private initCallbacks: Array<SocketClientCallback> = [];\n /** Callback function that are called when the client successfully authenticates */\n private authCallbacks: Array<SocketClientCallback> = [];\n /** Callback function that are called when the client connection is terminated */\n private shutdownCallbacks: Array<SocketClientCallback> = [];\n /** Authentication status of the client */\n private authenticated = false;\n /** Timer used to track when to send authentication renewal reminder to the client */\n private authRenewTimer: NodeJS.Timeout | string | number | undefined;\n /** Timers used to track the time at which a user losses authentication */\n private authExpireTimer: NodeJS.Timeout | string | number | undefined;\n /** ID of the user that is authenticated */\n private userId: undefined | string;\n /** ID of the device with which the client authenticated */\n private deviceId: undefined | string;\n /** Id of the token with which the client authenticated */\n private tokenId: undefined | string;\n /** Audience claims that were in the latest authentication token used by the client */\n private audience: undefined | Array<string>;\n /** Status tracking variable used to check the liveness of connections */\n private isAlive = true;\n /** Timer used to track interval between client pinging */\n private pingInterval: NodeJS.Timeout | string | number | undefined;\n\n /**\n * Create a WS client\n * @param webSocket - The WebSocket instance\n * @param _request - The incoming HTTP request (reserved for future use)\n * @param options - Socket client configuration options\n */\n public constructor(\n webSocket: WS,\n _request: IncomingMessage,\n options: SocketClientOptions\n ) {\n this.id = randomUUID();\n this.ws = webSocket;\n this.establishedAt = new Date();\n\n reportDebug({ namespace, message: `Creating socket client [${this.id}]` });\n\n // Make sure that callbacks are made as lists of functions\n // Init\n if (typeof options.initCallbacks === 'function')\n this.initCallbacks = [options.initCallbacks];\n else if (options.initCallbacks instanceof Array)\n this.initCallbacks = options.initCallbacks;\n // Auth\n if (typeof options.authCallbacks === 'function')\n this.authCallbacks = [options.authCallbacks];\n else if (options.authCallbacks instanceof Array)\n this.authCallbacks = options.authCallbacks;\n // Shutdown\n if (typeof options.shutdownCallbacks === 'function')\n this.shutdownCallbacks = [options.shutdownCallbacks];\n else if (options.shutdownCallbacks instanceof Array)\n this.shutdownCallbacks = options.shutdownCallbacks;\n\n // Check that all handlers are valid\n this.handlers = options.handlers;\n for (const handler of this.handlers) {\n if (!(handler instanceof MessageHandler))\n throw new EngineError({\n message: 'Handler is not an instance of MessageHandler'\n });\n }\n // Register in clients list\n SocketClient.socketClients[this.id] = this;\n\n reportInfo({ message: `Client connected [${this.id}]` });\n // On socket close, deregister from clients list\n this.ws.on('close', () => {\n this.handleClose\n .bind(this)()\n .catch((error) => {\n reportError(error);\n });\n });\n // On socket error, log the error\n this.ws.on('error', (error) => {\n reportError(\n new EngineError({\n severity: LogSeverity.WARNING,\n message: `Error [${this.id}]`\n })\n );\n reportError(error);\n });\n // When receiving a message, call message handler\n this.ws.on('message', (data) => {\n this.handleMessage\n .bind(this)(data)\n .catch((error) => {\n reportError(error);\n });\n });\n\n // Run all the init callbacks\n // For proper error handling of potential asynchronous callbacks, we wrap the execution in an auto-executing async function\n (async (): Promise<void> => {\n const callbackResults = await Promise.allSettled(\n this.initCallbacks.map((callback) => callback(this))\n );\n callbackResults.forEach((result) => {\n if (result.status === 'rejected') reportError(result.reason);\n });\n })().catch((error) => {\n reportError(error);\n });\n\n // Server -> client ping mechanism using WS standard ping control frames\n // We terminate the connection if we did not get a reply in the previous interval\n this.pingInterval = setInterval(\n () => {\n if (!this.isAlive) {\n reportError(\n new EngineError({\n severity: LogSeverity.WARNING,\n message: `Terminating socket connection, ping timeout [${this.id}]`\n })\n );\n this.ws.terminate();\n return;\n }\n this.isAlive = false;\n this.ws.ping();\n reportDebug({ namespace, message: `Ping sent to client [${this.id}]` });\n },\n process.env.WS_PING_INTERVAL\n ? parseInt(process.env.WS_PING_INTERVAL) * 1000\n : 30000\n );\n\n // Track the connection as alive as we get a pong back\n this.ws.on('pong', () => {\n reportDebug({\n namespace,\n message: `Client responded to ping [${this.id}]`\n });\n this.isAlive = true;\n });\n }\n\n /** Get the list of all connected clients indexed by ID */\n public static getSocketClients(): SocketClientList {\n return this.socketClients;\n }\n\n /** Get a client by his ID */\n public static getSocketClient(id: string): SocketClient | undefined {\n return this.socketClients[id];\n }\n\n /**\n * Send a message to the client\n */\n public sendMessage(\n type: string,\n payload: unknown = {},\n options: SocketClientSendMessageOptions = {}\n ): void {\n reportDebug({\n namespace,\n message: `Received request to send message to client of type \"${type}\" [${this.id}]`,\n data: { options }\n });\n let send = false;\n // If the message is sent to unauthenticated user skip auth check\n if (options.noAuth) send = true;\n // If the message is authenticated and with the correct audience, it gets sent\n else if (\n this.authenticated &&\n (this.audience as Array<string>).includes(\n options.audience ?? (process.env.DEFAULT_MESSAGE_AUDIENCE as string)\n )\n )\n send = true;\n\n if (send) {\n reportDebug({\n namespace,\n message: `Sending message to client of type \"${type ?? 'unknown'}\" [${this.id}]`\n });\n this.ws.send(JSON.stringify({ type, payload }));\n }\n }\n\n /** Get the client authentication status */\n public isAuthenticated(): boolean {\n return this.authenticated;\n }\n\n /** Fetch data on the user if he is authenticated */\n public getUser(): SocketUser | undefined {\n if (this.authenticated)\n return {\n userId: this.userId as string,\n deviceId: this.deviceId as string,\n tokenId: this.tokenId as string,\n audience: this.audience as Array<string>\n };\n return undefined;\n }\n\n /** Process an incoming message */\n private async handleMessage(data: RawData): Promise<void> {\n try {\n const message = parseMessage(data.toString('utf-8'));\n reportInfo({\n message: `Received message of type \"${message?.type ?? 'unknown'}\" [${this.id}]`\n });\n switch (message.type) {\n case 'authenticate':\n await this.authenticate(message as SocketAuthenticationMessage);\n break;\n // As not all client libraries allow sending pings through WS control frames,\n // we add a higher level ping mechanism\n case 'ping':\n reportDebug({\n namespace,\n message: `Received ping from client [${this.id}]`\n });\n this.sendMessage('pong', {}, { noAuth: true });\n break;\n default:\n for (const handler of this.handlers) {\n await handler.handle(message, this);\n }\n }\n } catch (error) {\n this.handleError(error);\n }\n }\n\n /**\n * Process an authentication request\n * @param {String} message - Authentication message\n */\n private async authenticate(\n message: SocketAuthenticationMessage\n ): Promise<void> {\n const token = message.payload?.token;\n if (!token) {\n throw new WebError({\n errorCode: 'no-token',\n message: 'No token was given',\n data: { message }\n });\n }\n const payload = await jwtVerify(token);\n this.setUserData(payload);\n\n this.authenticated = true;\n // Time remaining before token expiration\n const authExpiration = payload.exp * 1000 - Date.now();\n // Clear previously created timers\n this.clearTimeouts();\n // Send a refresh request to the client 1 minute before expiration\n this.authRenewTimer = setTimeout(\n () => {\n this.sendMessage('renewAuthentication');\n },\n authExpiration - 60 * 1000\n );\n // Expire client authentication\n this.authExpireTimer = setTimeout(() => {\n this.authenticated = false;\n }, authExpiration);\n\n // Run all the post-authentication callbacks\n const callbackResults = await Promise.allSettled(\n this.authCallbacks.map((callback) => callback(this))\n );\n callbackResults.forEach((result) => {\n if (result.status === 'rejected') reportError(result.reason);\n });\n }\n\n // Clear all the pending timers\n /** */\n private clearTimeouts(): void {\n if (this.authRenewTimer) clearTimeout(this.authRenewTimer);\n if (this.authExpireTimer) clearTimeout(this.authExpireTimer);\n }\n\n /**\n * Fetch the user's data and attach it to the connection for new connections. For existing connections, it checks that the authentication is done on the same user.\n */\n private setUserData({ sub, dev, jti, aud }: UserTokenPayload): void {\n // Check if the user is already authenticated\n if (this.userId) {\n // Check that the token is for the same connection as before\n if (this.userId && this.userId !== sub)\n throw new WebError({\n errorCode: 'wrong-user-token',\n message:\n 'A user tried to authenticate with a token that is not for him [userId]'\n });\n } else {\n // Set the user's ID\n this.userId = sub;\n // Set the user's Device Id\n this.deviceId = dev;\n // Set the token ID\n this.tokenId = jti;\n // Set the aud\n this.audience = aud instanceof Array ? aud : [aud];\n\n reportDebug({\n namespace,\n message: `Successfully authenticated client [${this.id}]`,\n data: {\n userId: this.userId,\n deviceId: this.deviceId,\n tokenId: this.tokenId,\n audience: this.audience\n }\n });\n }\n }\n\n /**\n * Properly return errors to clients\n */\n private handleError(error: unknown): void {\n reportError(error);\n if (error instanceof WebError) {\n this.sendMessage(\n 'error',\n { errorCode: error.errorCode, hint: error.hint },\n { noAuth: true }\n );\n } else if (error instanceof ValidationError) {\n this.sendMessage(\n 'error',\n { errorCode: 'validation-error', hint: error.data },\n { noAuth: true }\n );\n } else {\n this.sendMessage(\n 'error',\n { errorCode: 'server-error' },\n { noAuth: true }\n );\n }\n }\n\n /**\n * Process a socket close event\n */\n private async handleClose(code?: string, reason?: string): Promise<void> {\n delete SocketClient.socketClients[this.id];\n this.clearTimeouts();\n // Stop ping process\n if (this.pingInterval) clearInterval(this.pingInterval);\n // Run all the shutdown callbacks\n const callbackResults = await Promise.allSettled(\n this.shutdownCallbacks.map((callback) => callback(this))\n );\n callbackResults.forEach((result) => {\n if (result.status === 'rejected') reportError(result.reason);\n });\n reportInfo({\n message: `Client disconnected [${this.id}]`,\n data: { code, reason }\n });\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,2 +1,6 @@
1
- /** Deep sort the objects keys alphabetically */
1
+ /**
2
+ * Deep sort object keys alphabetically
3
+ * @param data - The object to sort
4
+ * @returns A new object with sorted keys
5
+ */
2
6
  export declare function createSortedObject<T>(data: T): T;
@@ -4,14 +4,23 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.createSortedObject = createSortedObject;
7
- /** Deep sort the objects keys alphabetically */
7
+ /**
8
+ * Deep sort object keys alphabetically
9
+ * @param data - The object to sort
10
+ * @returns A new object with sorted keys
11
+ */
8
12
  function createSortedObject(data) {
9
- if (!(data instanceof Object)) throw new Error('Non');
13
+ if (typeof data !== 'object' || data === null) {
14
+ throw new Error('Input must be a non-null object');
15
+ }
16
+ if (Array.isArray(data)) {
17
+ return data.map(item => typeof item === 'object' && item !== null ? createSortedObject(item) : item);
18
+ }
10
19
  const result = {};
11
20
  Object.keys(data).sort().forEach(key => {
12
21
  const value = data[key];
13
- if (typeof value !== 'object' || value instanceof Array || value === null) {
14
- result[key] = value;
22
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
23
+ result[key] = Array.isArray(value) ? value.map(item => typeof item === 'object' && item !== null ? createSortedObject(item) : item) : value;
15
24
  } else {
16
25
  result[key] = createSortedObject(value);
17
26
  }
@@ -1 +1 @@
1
- {"version":3,"file":"createSortedObject.js","names":["createSortedObject","data","Object","Error","result","keys","sort","forEach","key","value","Array"],"sources":["../../../src/utils/createSortedObject/createSortedObject.ts"],"sourcesContent":["/** Deep sort the objects keys alphabetically */\nexport function createSortedObject<T>(data: T): T {\n if (!(data instanceof Object)) throw new Error('Non');\n const result: Record<string, unknown> = {};\n Object.keys(data)\n .sort()\n .forEach((key: string) => {\n const value = (data as Record<string, unknown>)[key];\n if (\n typeof value !== 'object' ||\n value instanceof Array ||\n value === null\n ) {\n result[key] = value;\n } else {\n result[key] = createSortedObject(value);\n }\n });\n return result as T;\n}\n"],"mappings":";;;;;;AAAA;AACO,SAASA,kBAAkBA,CAAIC,IAAO,EAAK;EAChD,IAAI,EAAEA,IAAI,YAAYC,MAAM,CAAC,EAAE,MAAM,IAAIC,KAAK,CAAC,KAAK,CAAC;EACrD,MAAMC,MAA+B,GAAG,CAAC,CAAC;EAC1CF,MAAM,CAACG,IAAI,CAACJ,IAAI,CAAC,CACdK,IAAI,CAAC,CAAC,CACNC,OAAO,CAAEC,GAAW,IAAK;IACxB,MAAMC,KAAK,GAAIR,IAAI,CAA6BO,GAAG,CAAC;IACpD,IACE,OAAOC,KAAK,KAAK,QAAQ,IACzBA,KAAK,YAAYC,KAAK,IACtBD,KAAK,KAAK,IAAI,EACd;MACAL,MAAM,CAACI,GAAG,CAAC,GAAGC,KAAK;IACrB,CAAC,MAAM;MACLL,MAAM,CAACI,GAAG,CAAC,GAAGR,kBAAkB,CAACS,KAAK,CAAC;IACzC;EACF,CAAC,CAAC;EACJ,OAAOL,MAAM;AACf","ignoreList":[]}
1
+ {"version":3,"file":"createSortedObject.js","names":["createSortedObject","data","Error","Array","isArray","map","item","result","Object","keys","sort","forEach","key","value"],"sources":["../../../src/utils/createSortedObject/createSortedObject.ts"],"sourcesContent":["/**\n * Deep sort object keys alphabetically\n * @param data - The object to sort\n * @returns A new object with sorted keys\n */\nexport function createSortedObject<T>(data: T): T {\n if (typeof data !== 'object' || data === null) {\n throw new Error('Input must be a non-null object');\n }\n\n if (Array.isArray(data)) {\n return data.map((item) =>\n typeof item === 'object' && item !== null ? createSortedObject(item) : item\n ) as T;\n }\n\n const result: Record<string, unknown> = {};\n \n Object.keys(data)\n .sort()\n .forEach((key: string) => {\n const value = (data as Record<string, unknown>)[key];\n \n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n result[key] = Array.isArray(value)\n ? value.map((item) =>\n typeof item === 'object' && item !== null\n ? createSortedObject(item)\n : item\n )\n : value;\n } else {\n result[key] = createSortedObject(value);\n }\n });\n \n return result as T;\n}\n"],"mappings":";;;;;;AAAA;AACA;AACA;AACA;AACA;AACO,SAASA,kBAAkBA,CAAIC,IAAO,EAAK;EAChD,IAAI,OAAOA,IAAI,KAAK,QAAQ,IAAIA,IAAI,KAAK,IAAI,EAAE;IAC7C,MAAM,IAAIC,KAAK,CAAC,iCAAiC,CAAC;EACpD;EAEA,IAAIC,KAAK,CAACC,OAAO,CAACH,IAAI,CAAC,EAAE;IACvB,OAAOA,IAAI,CAACI,GAAG,CAAEC,IAAI,IACnB,OAAOA,IAAI,KAAK,QAAQ,IAAIA,IAAI,KAAK,IAAI,GAAGN,kBAAkB,CAACM,IAAI,CAAC,GAAGA,IACzE,CAAC;EACH;EAEA,MAAMC,MAA+B,GAAG,CAAC,CAAC;EAE1CC,MAAM,CAACC,IAAI,CAACR,IAAI,CAAC,CACdS,IAAI,CAAC,CAAC,CACNC,OAAO,CAAEC,GAAW,IAAK;IACxB,MAAMC,KAAK,GAAIZ,IAAI,CAA6BW,GAAG,CAAC;IAEpD,IAAIC,KAAK,KAAK,IAAI,IAAI,OAAOA,KAAK,KAAK,QAAQ,IAAIV,KAAK,CAACC,OAAO,CAACS,KAAK,CAAC,EAAE;MACvEN,MAAM,CAACK,GAAG,CAAC,GAAGT,KAAK,CAACC,OAAO,CAACS,KAAK,CAAC,GAC9BA,KAAK,CAACR,GAAG,CAAEC,IAAI,IACb,OAAOA,IAAI,KAAK,QAAQ,IAAIA,IAAI,KAAK,IAAI,GACrCN,kBAAkB,CAACM,IAAI,CAAC,GACxBA,IACN,CAAC,GACDO,KAAK;IACX,CAAC,MAAM;MACLN,MAAM,CAACK,GAAG,CAAC,GAAGZ,kBAAkB,CAACa,KAAK,CAAC;IACzC;EACF,CAAC,CAAC;EAEJ,OAAON,MAAM;AACf","ignoreList":[]}
@@ -16,9 +16,7 @@ var _EngineError = require("../../entities/EngineError");
16
16
  var _Sequelize = require("../../entities/Sequelize");
17
17
  var _report = require("../report");
18
18
  var _semverCompare = require("../semverCompare");
19
- /* eslint-disable @typescript-eslint/no-require-imports */
20
- // Register ts-node at the top of runMigrations.ts
21
- require('ts-node/register');
19
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
22
20
  const namespace = 'engine:utils:dbMigration';
23
21
  function getMigrationPaths() {
24
22
  // We look between possibilities for the first directory that exists and matches our expectations
@@ -57,7 +55,9 @@ async function runPendingMigrations() {
57
55
  });
58
56
  return;
59
57
  }
60
- migrationPaths?.forEach(async path => {
58
+
59
+ // Process migrations sequentially to avoid race conditions
60
+ for (const path of migrationPaths) {
61
61
  const migrator = new _umzug.Umzug({
62
62
  migrations: {
63
63
  glob: path,
@@ -66,12 +66,18 @@ async function runPendingMigrations() {
66
66
  path,
67
67
  context
68
68
  }) => {
69
- // Use require to import the migration file
70
- const migration = require(path || '');
69
+ // Use dynamic import for better TypeScript/ES module support
70
+ const migrationPromise = (specifier => new Promise(r => r(`${specifier}`)).then(s => _interopRequireWildcard(require(s))))(path || '');
71
71
  return {
72
72
  name,
73
- up: async () => migration.up(context),
74
- down: async () => migration.down(context)
73
+ up: async () => {
74
+ const migration = await migrationPromise;
75
+ return migration.up(context);
76
+ },
77
+ down: async () => {
78
+ const migration = await migrationPromise;
79
+ return migration.down(context);
80
+ }
75
81
  };
76
82
  }
77
83
  },
@@ -89,8 +95,13 @@ async function runPendingMigrations() {
89
95
  }
90
96
  });
91
97
  await migrator.up();
92
- console.log('Db Migration Completed');
93
- });
98
+ (0, _report.reportInfo)({
99
+ message: 'Database migration completed successfully',
100
+ data: {
101
+ path
102
+ }
103
+ });
104
+ }
94
105
  }
95
106
 
96
107
  /** Rollback all migrations up to a specified target version */
@@ -129,7 +140,9 @@ async function rollbackMigrations() {
129
140
  });
130
141
  return;
131
142
  }
132
- migrationPaths.forEach(async path => {
143
+
144
+ // Process rollback migrations sequentially
145
+ for (const path of migrationPaths) {
133
146
  const migrator = new _umzug.Umzug({
134
147
  migrations: {
135
148
  glob: path,
@@ -138,11 +151,17 @@ async function rollbackMigrations() {
138
151
  path,
139
152
  context
140
153
  }) => {
141
- const migration = require(path || '');
154
+ const migrationPromise = (specifier => new Promise(r => r(`${specifier}`)).then(s => _interopRequireWildcard(require(s))))(path || '');
142
155
  return {
143
156
  name,
144
- up: async () => migration.up(context),
145
- down: async () => migration.down(context)
157
+ up: async () => {
158
+ const migration = await migrationPromise;
159
+ return migration.up(context);
160
+ },
161
+ down: async () => {
162
+ const migration = await migrationPromise;
163
+ return migration.down(context);
164
+ }
146
165
  };
147
166
  }
148
167
  },
@@ -162,7 +181,7 @@ async function rollbackMigrations() {
162
181
  await migrator.down({
163
182
  to: rollbackUntil.name
164
183
  });
165
- });
184
+ }
166
185
  }
167
186
 
168
187
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"dbMigration.js","names":["_fs","require","_path","_umzug","_migrateMetadataTable","_models","_EngineError","_Sequelize","_report","_semverCompare","namespace","getMigrationPaths","prodDefaultPath","join","process","cwd","devDefaultPath","path","env","DB_MIGRATIONS_DIR","NODE_ENV","filter","existsSync","lstatSync","isDirectory","reportDebug","message","data","prodPath","devPath","customPath","map","p","runPendingMigrations","sequelize","EngineError","migrateMetadataTable","migrationPaths","length","forEach","migrator","Umzug","migrations","glob","resolve","name","context","migration","up","down","getQueryInterface","storage","SequelizeStorage","logger","console","log","rollbackMigrations","BUILD_ID","SequelizeMeta","findAll","order","raw","rollbackUntil","find","version","semverCompare","buildId","to","testRecreateDB","options","query","SQL_TYPE","clean","testClearDB","transaction","clearDbTransaction","t","model","Object","keys","models","includeMetadata","table","tableName"],"sources":["../../../src/utils/dbMigration/dbMigration.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-require-imports */\n// Register ts-node at the top of runMigrations.ts\nrequire('ts-node/register');\n\nimport { existsSync, lstatSync } from 'fs';\nimport { join } from 'path';\nimport { Sequelize, Transaction } from 'sequelize';\nimport { Umzug, SequelizeStorage } from 'umzug';\nimport { ClearDbOptions, RecreateDbOptions } from './dbMigration.types';\nimport { migrateMetadataTable } from './migrateMetadataTable';\nimport { SequelizeMeta } from 'db/models';\nimport { EngineError } from 'entities/EngineError';\nimport { sequelize } from 'entities/Sequelize';\nimport { reportDebug } from 'utils/report';\nimport { semverCompare } from 'utils/semverCompare';\n\nconst namespace = 'engine:utils:dbMigration';\n\nfunction getMigrationPaths(): Array<string> | undefined {\n // We look between possibilities for the first directory that exists and matches our expectations\n // First a user specified one, then the production default, then the development default\n const prodDefaultPath = join(process.cwd(), './dist/db/migrations');\n const devDefaultPath = join(process.cwd(), './src/db/migrations');\n const path = [\n process.env.DB_MIGRATIONS_DIR,\n process.env.NODE_ENV === 'prod' ? prodDefaultPath : devDefaultPath\n ].filter((path) => path && existsSync(path) && lstatSync(path).isDirectory());\n reportDebug({\n namespace,\n message: 'Obtaining Umzug migration options',\n data: {\n path,\n prodPath: prodDefaultPath,\n devPath: devDefaultPath,\n customPath: process.env.DB_MIGRATIONS_DIR\n }\n });\n return path.map((p) =>\n process.env.NODE_ENV === 'prod' ? `${p}/*.js` : `${p}/*.ts`\n );\n}\n\n/** Run all the non-executed migrations one by one */\nexport async function runPendingMigrations(): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n // First make sure that the metadata table is up to date\n await migrateMetadataTable(sequelize);\n const migrationPaths = getMigrationPaths();\n\n if (!migrationPaths || migrationPaths.length <= 0) {\n reportDebug({\n namespace,\n message: 'No valid migration paths found.',\n data: { migrationPaths }\n });\n return;\n }\n\n migrationPaths?.forEach(async (path) => {\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n // Use require to import the migration file\n const migration = require(path || '');\n return {\n name,\n up: async () => migration.up(context),\n down: async () => migration.down(context)\n };\n }\n },\n context: sequelize.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize }),\n logger: console\n });\n\n reportDebug({\n namespace,\n message: 'Starting pending database migrations',\n data: { path }\n });\n await migrator.up();\n console.log('Db Migration Completed');\n });\n}\n\n/** Rollback all migrations up to a specified target version */\nexport async function rollbackMigrations(): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n if (!process.env.BUILD_ID)\n throw new EngineError({ message: 'BUILD_ID is not defined' });\n\n // Fetch executed migrations in ascending order\n const migrations = await SequelizeMeta.findAll({\n order: [['name', 'ASC']],\n raw: true\n });\n const rollbackUntil = migrations.find(\n (migration) =>\n migration.version &&\n semverCompare(migration.version, process.env.BUILD_ID as string) === 1\n );\n\n if (!rollbackUntil) {\n reportDebug({\n namespace,\n message: 'No rollback target found for the current BUILD_ID.',\n data: { buildId: process.env.BUILD_ID }\n });\n return;\n }\n\n const migrationPaths = getMigrationPaths();\n\n if (!migrationPaths || migrationPaths.length <= 0) {\n reportDebug({\n namespace,\n message: 'No valid migration paths found for rollback.',\n data: { migrationPaths }\n });\n return;\n }\n\n migrationPaths.forEach(async (path) => {\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n const migration = require(path || '');\n return {\n name,\n up: async () => migration.up(context),\n down: async () => migration.down(context)\n };\n }\n },\n context: sequelize.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize }),\n logger: console\n });\n\n reportDebug({\n namespace,\n message: `Rolling back migrations up to: ${rollbackUntil.name}`,\n data: { path }\n });\n\n await migrator.down({ to: rollbackUntil.name });\n });\n}\n\n/**\n * Recreate the whole database\n * Quick way to make sure that we are working on a clean database\n * /!\\ Should only be used when running tests\n */\nexport async function testRecreateDB(\n options: RecreateDbOptions = {}\n): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n await sequelize.query(\n `DROP SCHEMA public${process.env.SQL_TYPE === 'postgres' ? ' CASCADE' : ''}`\n );\n await sequelize.query(`CREATE SCHEMA public`);\n if (!options.clean) await runPendingMigrations();\n}\n\n/**\n * Empty all the schemas in the database\n * Quick way to flush the database data while keep the structure\n * /!\\ Should only be used when running tests\n */\nexport async function testClearDB(options: ClearDbOptions = {}): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n await sequelize.transaction(clearDbTransaction(sequelize, options));\n}\n\n/** DB clearing transaction */\nfunction clearDbTransaction(sequelize: Sequelize, options: ClearDbOptions) {\n return async (t: Transaction): Promise<void> => {\n for (const model of Object.keys(sequelize.models)) {\n // We ignore the migration metadata schema\n if (!options.includeMetadata && model === 'sequelizeMeta') continue;\n const table = sequelize.models[model].tableName;\n await sequelize.query(\n `TRUNCATE ${table}${process.env.SQL_TYPE === 'postgres' ? ' CASCADE' : ''};`,\n {\n raw: true,\n transaction: t\n }\n );\n }\n };\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"dbMigration.js","names":["_fs","require","_path","_umzug","_migrateMetadataTable","_models","_EngineError","_Sequelize","_report","_semverCompare","_interopRequireWildcard","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","namespace","getMigrationPaths","prodDefaultPath","join","process","cwd","devDefaultPath","path","env","DB_MIGRATIONS_DIR","NODE_ENV","filter","existsSync","lstatSync","isDirectory","reportDebug","message","data","prodPath","devPath","customPath","map","p","runPendingMigrations","sequelize","EngineError","migrateMetadataTable","migrationPaths","length","migrator","Umzug","migrations","glob","resolve","name","context","migrationPromise","specifier","Promise","then","s","up","migration","down","getQueryInterface","storage","SequelizeStorage","logger","console","reportInfo","rollbackMigrations","BUILD_ID","SequelizeMeta","findAll","order","raw","rollbackUntil","find","version","semverCompare","buildId","to","testRecreateDB","options","query","SQL_TYPE","clean","testClearDB","transaction","clearDbTransaction","model","keys","models","includeMetadata","table","tableName"],"sources":["../../../src/utils/dbMigration/dbMigration.ts"],"sourcesContent":["import { existsSync, lstatSync } from 'fs';\nimport { join } from 'path';\nimport { Sequelize, Transaction } from 'sequelize';\nimport { Umzug, SequelizeStorage } from 'umzug';\nimport { ClearDbOptions, RecreateDbOptions } from './dbMigration.types';\nimport { migrateMetadataTable } from './migrateMetadataTable';\nimport { SequelizeMeta } from 'db/models';\nimport { EngineError } from 'entities/EngineError';\nimport { sequelize } from 'entities/Sequelize';\nimport { reportDebug, reportInfo } from 'utils/report';\nimport { semverCompare } from 'utils/semverCompare';\n\nconst namespace = 'engine:utils:dbMigration';\n\nfunction getMigrationPaths(): Array<string> | undefined {\n // We look between possibilities for the first directory that exists and matches our expectations\n // First a user specified one, then the production default, then the development default\n const prodDefaultPath = join(process.cwd(), './dist/db/migrations');\n const devDefaultPath = join(process.cwd(), './src/db/migrations');\n const path = [\n process.env.DB_MIGRATIONS_DIR,\n process.env.NODE_ENV === 'prod' ? prodDefaultPath : devDefaultPath\n ].filter((path) => path && existsSync(path) && lstatSync(path).isDirectory());\n reportDebug({\n namespace,\n message: 'Obtaining Umzug migration options',\n data: {\n path,\n prodPath: prodDefaultPath,\n devPath: devDefaultPath,\n customPath: process.env.DB_MIGRATIONS_DIR\n }\n });\n return path.map((p) =>\n process.env.NODE_ENV === 'prod' ? `${p}/*.js` : `${p}/*.ts`\n );\n}\n\n/** Run all the non-executed migrations one by one */\nexport async function runPendingMigrations(): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n // First make sure that the metadata table is up to date\n await migrateMetadataTable(sequelize);\n const migrationPaths = getMigrationPaths();\n\n if (!migrationPaths || migrationPaths.length <= 0) {\n reportDebug({\n namespace,\n message: 'No valid migration paths found.',\n data: { migrationPaths }\n });\n return;\n }\n\n // Process migrations sequentially to avoid race conditions\n for (const path of migrationPaths) {\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n // Use dynamic import for better TypeScript/ES module support\n const migrationPromise = import(path || '');\n return {\n name,\n up: async () => {\n const migration = await migrationPromise;\n return migration.up(context);\n },\n down: async () => {\n const migration = await migrationPromise;\n return migration.down(context);\n }\n };\n }\n },\n context: sequelize.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize }),\n logger: console\n });\n\n reportDebug({\n namespace,\n message: 'Starting pending database migrations',\n data: { path }\n });\n await migrator.up();\n reportInfo({\n message: 'Database migration completed successfully',\n data: { path }\n });\n }\n}\n\n/** Rollback all migrations up to a specified target version */\nexport async function rollbackMigrations(): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n if (!process.env.BUILD_ID)\n throw new EngineError({ message: 'BUILD_ID is not defined' });\n\n // Fetch executed migrations in ascending order\n const migrations = await SequelizeMeta.findAll({\n order: [['name', 'ASC']],\n raw: true\n });\n const rollbackUntil = migrations.find(\n (migration) =>\n migration.version &&\n semverCompare(migration.version, process.env.BUILD_ID as string) === 1\n );\n\n if (!rollbackUntil) {\n reportDebug({\n namespace,\n message: 'No rollback target found for the current BUILD_ID.',\n data: { buildId: process.env.BUILD_ID }\n });\n return;\n }\n\n const migrationPaths = getMigrationPaths();\n\n if (!migrationPaths || migrationPaths.length <= 0) {\n reportDebug({\n namespace,\n message: 'No valid migration paths found for rollback.',\n data: { migrationPaths }\n });\n return;\n }\n\n // Process rollback migrations sequentially\n for (const path of migrationPaths) {\n const migrator = new Umzug({\n migrations: {\n glob: path,\n resolve: ({ name, path, context }) => {\n const migrationPromise = import(path || '');\n return {\n name,\n up: async () => {\n const migration = await migrationPromise;\n return migration.up(context);\n },\n down: async () => {\n const migration = await migrationPromise;\n return migration.down(context);\n }\n };\n }\n },\n context: sequelize.getQueryInterface(),\n storage: new SequelizeStorage({ sequelize }),\n logger: console\n });\n\n reportDebug({\n namespace,\n message: `Rolling back migrations up to: ${rollbackUntil.name}`,\n data: { path }\n });\n\n await migrator.down({ to: rollbackUntil.name });\n }\n}\n\n/**\n * Recreate the whole database\n * Quick way to make sure that we are working on a clean database\n * /!\\ Should only be used when running tests\n */\nexport async function testRecreateDB(\n options: RecreateDbOptions = {}\n): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n await sequelize.query(\n `DROP SCHEMA public${process.env.SQL_TYPE === 'postgres' ? ' CASCADE' : ''}`\n );\n await sequelize.query(`CREATE SCHEMA public`);\n if (!options.clean) await runPendingMigrations();\n}\n\n/**\n * Empty all the schemas in the database\n * Quick way to flush the database data while keep the structure\n * /!\\ Should only be used when running tests\n */\nexport async function testClearDB(options: ClearDbOptions = {}): Promise<void> {\n if (!sequelize)\n throw new EngineError({ message: 'Sequelize is not initialized' });\n await sequelize.transaction(clearDbTransaction(sequelize, options));\n}\n\n/** DB clearing transaction */\nfunction clearDbTransaction(sequelize: Sequelize, options: ClearDbOptions) {\n return async (t: Transaction): Promise<void> => {\n for (const model of Object.keys(sequelize.models)) {\n // We ignore the migration metadata schema\n if (!options.includeMetadata && model === 'sequelizeMeta') continue;\n const table = sequelize.models[model].tableName;\n await sequelize.query(\n `TRUNCATE ${table}${process.env.SQL_TYPE === 'postgres' ? ' CASCADE' : ''};`,\n {\n raw: true,\n transaction: t\n }\n );\n }\n };\n}\n"],"mappings":";;;;;;;;;AAAA,IAAAA,GAAA,GAAAC,OAAA;AACA,IAAAC,KAAA,GAAAD,OAAA;AAEA,IAAAE,MAAA,GAAAF,OAAA;AAEA,IAAAG,qBAAA,GAAAH,OAAA;AACA,IAAAI,OAAA,GAAAJ,OAAA;AACA,IAAAK,YAAA,GAAAL,OAAA;AACA,IAAAM,UAAA,GAAAN,OAAA;AACA,IAAAO,OAAA,GAAAP,OAAA;AACA,IAAAQ,cAAA,GAAAR,OAAA;AAAoD,SAAAS,wBAAAC,CAAA,EAAAC,CAAA,6BAAAC,OAAA,MAAAC,CAAA,OAAAD,OAAA,IAAAE,CAAA,OAAAF,OAAA,YAAAH,uBAAA,YAAAA,CAAAC,CAAA,EAAAC,CAAA,SAAAA,CAAA,IAAAD,CAAA,IAAAA,CAAA,CAAAK,UAAA,SAAAL,CAAA,MAAAM,CAAA,EAAAC,CAAA,EAAAC,CAAA,KAAAC,SAAA,QAAAC,OAAA,EAAAV,CAAA,iBAAAA,CAAA,uBAAAA,CAAA,yBAAAA,CAAA,SAAAQ,CAAA,MAAAF,CAAA,GAAAL,CAAA,GAAAG,CAAA,GAAAD,CAAA,QAAAG,CAAA,CAAAK,GAAA,CAAAX,CAAA,UAAAM,CAAA,CAAAM,GAAA,CAAAZ,CAAA,GAAAM,CAAA,CAAAO,GAAA,CAAAb,CAAA,EAAAQ,CAAA,gBAAAP,CAAA,IAAAD,CAAA,gBAAAC,CAAA,OAAAa,cAAA,CAAAC,IAAA,CAAAf,CAAA,EAAAC,CAAA,OAAAM,CAAA,IAAAD,CAAA,GAAAU,MAAA,CAAAC,cAAA,KAAAD,MAAA,CAAAE,wBAAA,CAAAlB,CAAA,EAAAC,CAAA,OAAAM,CAAA,CAAAK,GAAA,IAAAL,CAAA,CAAAM,GAAA,IAAAP,CAAA,CAAAE,CAAA,EAAAP,CAAA,EAAAM,CAAA,IAAAC,CAAA,CAAAP,CAAA,IAAAD,CAAA,CAAAC,CAAA,WAAAO,CAAA,KAAAR,CAAA,EAAAC,CAAA;AAEpD,MAAMkB,SAAS,GAAG,0BAA0B;AAE5C,SAASC,iBAAiBA,CAAA,EAA8B;EACtD;EACA;EACA,MAAMC,eAAe,GAAG,IAAAC,UAAI,EAACC,OAAO,CAACC,GAAG,CAAC,CAAC,EAAE,sBAAsB,CAAC;EACnE,MAAMC,cAAc,GAAG,IAAAH,UAAI,EAACC,OAAO,CAACC,GAAG,CAAC,CAAC,EAAE,qBAAqB,CAAC;EACjE,MAAME,IAAI,GAAG,CACXH,OAAO,CAACI,GAAG,CAACC,iBAAiB,EAC7BL,OAAO,CAACI,GAAG,CAACE,QAAQ,KAAK,MAAM,GAAGR,eAAe,GAAGI,cAAc,CACnE,CAACK,MAAM,CAAEJ,IAAI,IAAKA,IAAI,IAAI,IAAAK,cAAU,EAACL,IAAI,CAAC,IAAI,IAAAM,aAAS,EAACN,IAAI,CAAC,CAACO,WAAW,CAAC,CAAC,CAAC;EAC7E,IAAAC,mBAAW,EAAC;IACVf,SAAS;IACTgB,OAAO,EAAE,mCAAmC;IAC5CC,IAAI,EAAE;MACJV,IAAI;MACJW,QAAQ,EAAEhB,eAAe;MACzBiB,OAAO,EAAEb,cAAc;MACvBc,UAAU,EAAEhB,OAAO,CAACI,GAAG,CAACC;IAC1B;EACF,CAAC,CAAC;EACF,OAAOF,IAAI,CAACc,GAAG,CAAEC,CAAC,IAChBlB,OAAO,CAACI,GAAG,CAACE,QAAQ,KAAK,MAAM,GAAG,GAAGY,CAAC,OAAO,GAAG,GAAGA,CAAC,OACtD,CAAC;AACH;;AAEA;AACO,eAAeC,oBAAoBA,CAAA,EAAkB;EAC1D,IAAI,CAACC,oBAAS,EACZ,MAAM,IAAIC,wBAAW,CAAC;IAAET,OAAO,EAAE;EAA+B,CAAC,CAAC;EACpE;EACA,MAAM,IAAAU,0CAAoB,EAACF,oBAAS,CAAC;EACrC,MAAMG,cAAc,GAAG1B,iBAAiB,CAAC,CAAC;EAE1C,IAAI,CAAC0B,cAAc,IAAIA,cAAc,CAACC,MAAM,IAAI,CAAC,EAAE;IACjD,IAAAb,mBAAW,EAAC;MACVf,SAAS;MACTgB,OAAO,EAAE,iCAAiC;MAC1CC,IAAI,EAAE;QAAEU;MAAe;IACzB,CAAC,CAAC;IACF;EACF;;EAEA;EACA,KAAK,MAAMpB,IAAI,IAAIoB,cAAc,EAAE;IACjC,MAAME,QAAQ,GAAG,IAAIC,YAAK,CAAC;MACzBC,UAAU,EAAE;QACVC,IAAI,EAAEzB,IAAI;QACV0B,OAAO,EAAEA,CAAC;UAAEC,IAAI;UAAE3B,IAAI;UAAE4B;QAAQ,CAAC,KAAK;UACpC;UACA,MAAMC,gBAAgB,IAAAC,SAAA,QAAAC,OAAA,CAAAtD,CAAA,IAAAA,CAAA,IAAAqD,SAAA,KAAAE,IAAA,CAAAC,CAAA,IAAA5D,uBAAA,CAAAT,OAAA,CAAAqE,CAAA,KAAUjC,IAAI,IAAI,EAAE,CAAC;UAC3C,OAAO;YACL2B,IAAI;YACJO,EAAE,EAAE,MAAAA,CAAA,KAAY;cACd,MAAMC,SAAS,GAAG,MAAMN,gBAAgB;cACxC,OAAOM,SAAS,CAACD,EAAE,CAACN,OAAO,CAAC;YAC9B,CAAC;YACDQ,IAAI,EAAE,MAAAA,CAAA,KAAY;cAChB,MAAMD,SAAS,GAAG,MAAMN,gBAAgB;cACxC,OAAOM,SAAS,CAACC,IAAI,CAACR,OAAO,CAAC;YAChC;UACF,CAAC;QACH;MACF,CAAC;MACDA,OAAO,EAAEX,oBAAS,CAACoB,iBAAiB,CAAC,CAAC;MACtCC,OAAO,EAAE,IAAIC,uBAAgB,CAAC;QAAEtB,SAAS,EAATA;MAAU,CAAC,CAAC;MAC5CuB,MAAM,EAAEC;IACV,CAAC,CAAC;IAEF,IAAAjC,mBAAW,EAAC;MACVf,SAAS;MACTgB,OAAO,EAAE,sCAAsC;MAC/CC,IAAI,EAAE;QAAEV;MAAK;IACf,CAAC,CAAC;IACF,MAAMsB,QAAQ,CAACY,EAAE,CAAC,CAAC;IACnB,IAAAQ,kBAAU,EAAC;MACTjC,OAAO,EAAE,2CAA2C;MACpDC,IAAI,EAAE;QAAEV;MAAK;IACf,CAAC,CAAC;EACJ;AACF;;AAEA;AACO,eAAe2C,kBAAkBA,CAAA,EAAkB;EACxD,IAAI,CAAC1B,oBAAS,EACZ,MAAM,IAAIC,wBAAW,CAAC;IAAET,OAAO,EAAE;EAA+B,CAAC,CAAC;EACpE,IAAI,CAACZ,OAAO,CAACI,GAAG,CAAC2C,QAAQ,EACvB,MAAM,IAAI1B,wBAAW,CAAC;IAAET,OAAO,EAAE;EAA0B,CAAC,CAAC;;EAE/D;EACA,MAAMe,UAAU,GAAG,MAAMqB,qBAAa,CAACC,OAAO,CAAC;IAC7CC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACxBC,GAAG,EAAE;EACP,CAAC,CAAC;EACF,MAAMC,aAAa,GAAGzB,UAAU,CAAC0B,IAAI,CAClCf,SAAS,IACRA,SAAS,CAACgB,OAAO,IACjB,IAAAC,4BAAa,EAACjB,SAAS,CAACgB,OAAO,EAAEtD,OAAO,CAACI,GAAG,CAAC2C,QAAkB,CAAC,KAAK,CACzE,CAAC;EAED,IAAI,CAACK,aAAa,EAAE;IAClB,IAAAzC,mBAAW,EAAC;MACVf,SAAS;MACTgB,OAAO,EAAE,oDAAoD;MAC7DC,IAAI,EAAE;QAAE2C,OAAO,EAAExD,OAAO,CAACI,GAAG,CAAC2C;MAAS;IACxC,CAAC,CAAC;IACF;EACF;EAEA,MAAMxB,cAAc,GAAG1B,iBAAiB,CAAC,CAAC;EAE1C,IAAI,CAAC0B,cAAc,IAAIA,cAAc,CAACC,MAAM,IAAI,CAAC,EAAE;IACjD,IAAAb,mBAAW,EAAC;MACVf,SAAS;MACTgB,OAAO,EAAE,8CAA8C;MACvDC,IAAI,EAAE;QAAEU;MAAe;IACzB,CAAC,CAAC;IACF;EACF;;EAEA;EACA,KAAK,MAAMpB,IAAI,IAAIoB,cAAc,EAAE;IACjC,MAAME,QAAQ,GAAG,IAAIC,YAAK,CAAC;MACzBC,UAAU,EAAE;QACVC,IAAI,EAAEzB,IAAI;QACV0B,OAAO,EAAEA,CAAC;UAAEC,IAAI;UAAE3B,IAAI;UAAE4B;QAAQ,CAAC,KAAK;UACpC,MAAMC,gBAAgB,IAAAC,SAAA,QAAAC,OAAA,CAAAtD,CAAA,IAAAA,CAAA,IAAAqD,SAAA,KAAAE,IAAA,CAAAC,CAAA,IAAA5D,uBAAA,CAAAT,OAAA,CAAAqE,CAAA,KAAUjC,IAAI,IAAI,EAAE,CAAC;UAC3C,OAAO;YACL2B,IAAI;YACJO,EAAE,EAAE,MAAAA,CAAA,KAAY;cACd,MAAMC,SAAS,GAAG,MAAMN,gBAAgB;cACxC,OAAOM,SAAS,CAACD,EAAE,CAACN,OAAO,CAAC;YAC9B,CAAC;YACDQ,IAAI,EAAE,MAAAA,CAAA,KAAY;cAChB,MAAMD,SAAS,GAAG,MAAMN,gBAAgB;cACxC,OAAOM,SAAS,CAACC,IAAI,CAACR,OAAO,CAAC;YAChC;UACF,CAAC;QACH;MACF,CAAC;MACDA,OAAO,EAAEX,oBAAS,CAACoB,iBAAiB,CAAC,CAAC;MACtCC,OAAO,EAAE,IAAIC,uBAAgB,CAAC;QAAEtB,SAAS,EAATA;MAAU,CAAC,CAAC;MAC5CuB,MAAM,EAAEC;IACV,CAAC,CAAC;IAEF,IAAAjC,mBAAW,EAAC;MACVf,SAAS;MACTgB,OAAO,EAAE,kCAAkCwC,aAAa,CAACtB,IAAI,EAAE;MAC/DjB,IAAI,EAAE;QAAEV;MAAK;IACf,CAAC,CAAC;IAEF,MAAMsB,QAAQ,CAACc,IAAI,CAAC;MAAEkB,EAAE,EAAEL,aAAa,CAACtB;IAAK,CAAC,CAAC;EACjD;AACF;;AAEA;AACA;AACA;AACA;AACA;AACO,eAAe4B,cAAcA,CAClCC,OAA0B,GAAG,CAAC,CAAC,EAChB;EACf,IAAI,CAACvC,oBAAS,EACZ,MAAM,IAAIC,wBAAW,CAAC;IAAET,OAAO,EAAE;EAA+B,CAAC,CAAC;EACpE,MAAMQ,oBAAS,CAACwC,KAAK,CACnB,qBAAqB5D,OAAO,CAACI,GAAG,CAACyD,QAAQ,KAAK,UAAU,GAAG,UAAU,GAAG,EAAE,EAC5E,CAAC;EACD,MAAMzC,oBAAS,CAACwC,KAAK,CAAC,sBAAsB,CAAC;EAC7C,IAAI,CAACD,OAAO,CAACG,KAAK,EAAE,MAAM3C,oBAAoB,CAAC,CAAC;AAClD;;AAEA;AACA;AACA;AACA;AACA;AACO,eAAe4C,WAAWA,CAACJ,OAAuB,GAAG,CAAC,CAAC,EAAiB;EAC7E,IAAI,CAACvC,oBAAS,EACZ,MAAM,IAAIC,wBAAW,CAAC;IAAET,OAAO,EAAE;EAA+B,CAAC,CAAC;EACpE,MAAMQ,oBAAS,CAAC4C,WAAW,CAACC,kBAAkB,CAAC7C,oBAAS,EAAEuC,OAAO,CAAC,CAAC;AACrE;;AAEA;AACA,SAASM,kBAAkBA,CAAC7C,SAAoB,EAAEuC,OAAuB,EAAE;EACzE,OAAO,MAAOjF,CAAc,IAAoB;IAC9C,KAAK,MAAMwF,KAAK,IAAIzE,MAAM,CAAC0E,IAAI,CAAC/C,SAAS,CAACgD,MAAM,CAAC,EAAE;MACjD;MACA,IAAI,CAACT,OAAO,CAACU,eAAe,IAAIH,KAAK,KAAK,eAAe,EAAE;MAC3D,MAAMI,KAAK,GAAGlD,SAAS,CAACgD,MAAM,CAACF,KAAK,CAAC,CAACK,SAAS;MAC/C,MAAMnD,SAAS,CAACwC,KAAK,CACnB,YAAYU,KAAK,GAAGtE,OAAO,CAACI,GAAG,CAACyD,QAAQ,KAAK,UAAU,GAAG,UAAU,GAAG,EAAE,GAAG,EAC5E;QACEV,GAAG,EAAE,IAAI;QACTa,WAAW,EAAEtF;MACf,CACF,CAAC;IACH;EACF,CAAC;AACH","ignoreList":[]}
@@ -8,6 +8,7 @@ exports.geminiFileUpload = geminiFileUpload;
8
8
  var _server = require("@google/generative-ai/server");
9
9
  var _fs = _interopRequireDefault(require("fs"));
10
10
  var _path = _interopRequireDefault(require("path"));
11
+ var _promises = require("timers/promises");
11
12
  var _tmp = _interopRequireDefault(require("tmp"));
12
13
  var _report = require("../report");
13
14
  const namespace = 'engine:utils:geminiFileUpload';
@@ -47,7 +48,7 @@ async function geminiFileUpload(buffer, mimeType, originalName) {
47
48
  let geminiFile = await fileManager.getFile(file.name);
48
49
  while (geminiFile?.state === 'PROCESSING') {
49
50
  process.stdout.write('.');
50
- await new Promise(resolve => setTimeout(resolve, 10000));
51
+ await (0, _promises.setTimeout)(10000);
51
52
  geminiFile = await fileManager.getFile(file.name);
52
53
  }
53
54
  if (!geminiFile || geminiFile.state !== 'ACTIVE') {
@@ -1 +1 @@
1
- {"version":3,"file":"geminiFileUpload.js","names":["_server","require","_fs","_interopRequireDefault","_path","_tmp","_report","namespace","fileManager","GoogleAIFileManager","process","env","GOOGLE_AI_KEY","geminiFileUpload","buffer","mimeType","originalName","tempFile","tmp","fileSync","postfix","path","extname","fs","writeFileSync","name","uploadResult","uploadFile","displayName","file","Error","reportDebug","message","data","geminiFile","getFile","state","stdout","write","Promise","resolve","setTimeout","errorMessage","reportError","success","error","originalname","fileUri","uri","removeCallback","cleanupError"],"sources":["../../../src/utils/geminiFileUpload/geminiFileUpload.ts"],"sourcesContent":["import { GoogleAIFileManager } from '@google/generative-ai/server';\nimport fs from 'fs';\nimport path from 'path';\nimport tmp from 'tmp';\nimport { reportError, reportDebug } from 'utils/report';\n\nconst namespace = 'engine:utils:geminiFileUpload';\n\nconst fileManager = new GoogleAIFileManager(process.env.GOOGLE_AI_KEY || '');\n\nexport async function geminiFileUpload(\n buffer: Buffer,\n mimeType: string,\n originalName: string\n): Promise<\n | { success: true; originalname: string; fileUri: string; mimeType: string }\n | { success: false; error: unknown }\n> {\n let tempFile;\n try {\n // 1. Create Temp File\n tempFile = tmp.fileSync({ postfix: path.extname(originalName) });\n fs.writeFileSync(tempFile.name, buffer);\n\n // 2. Upload File\n const uploadResult = await fileManager.uploadFile(tempFile.name, {\n mimeType,\n displayName: originalName\n });\n\n if (!uploadResult || !uploadResult.file) {\n throw new Error('Upload failed: No file returned');\n }\n\n const file = uploadResult.file;\n reportDebug({\n namespace,\n message: 'Uploaded file successfully',\n data: { displayName: file.displayName, name: file.name }\n });\n\n reportDebug({\n namespace,\n message: 'Waiting for file processing...'\n });\n\n // 3. Poll Until File is Processed\n let geminiFile = await fileManager.getFile(file.name);\n while (geminiFile?.state === 'PROCESSING') {\n process.stdout.write('.');\n await new Promise((resolve) => setTimeout(resolve, 10000));\n geminiFile = await fileManager.getFile(file.name);\n }\n\n if (!geminiFile || geminiFile.state !== 'ACTIVE') {\n const errorMessage = `File processing failed for ${file.name}`;\n reportError(errorMessage);\n return { success: false, error: new Error(errorMessage) };\n }\n\n reportDebug({\n namespace,\n message: 'File is ready'\n });\n\n return {\n success: true,\n originalname: file.name,\n fileUri: file.uri,\n mimeType: file.mimeType\n };\n } catch (error) {\n reportError({\n namespace,\n message: 'Error during Gemini file upload and processing',\n error\n });\n return { success: false, error };\n } finally {\n // Ensure cleanup of temp file\n if (tempFile) {\n try {\n tempFile.removeCallback();\n } catch (cleanupError) {\n reportError({\n namespace,\n message: 'Error cleaning up temp file',\n error: cleanupError\n });\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"geminiFileUpload.js","names":["_server","require","_fs","_interopRequireDefault","_path","_promises","_tmp","_report","namespace","fileManager","GoogleAIFileManager","process","env","GOOGLE_AI_KEY","geminiFileUpload","buffer","mimeType","originalName","tempFile","tmp","fileSync","postfix","path","extname","fs","writeFileSync","name","uploadResult","uploadFile","displayName","file","Error","reportDebug","message","data","geminiFile","getFile","state","stdout","write","setTimeoutPromise","errorMessage","reportError","success","error","originalname","fileUri","uri","removeCallback","cleanupError"],"sources":["../../../src/utils/geminiFileUpload/geminiFileUpload.ts"],"sourcesContent":["import { GoogleAIFileManager } from '@google/generative-ai/server';\nimport fs from 'fs';\nimport path from 'path';\nimport { setTimeout as setTimeoutPromise } from 'timers/promises';\nimport tmp from 'tmp';\nimport { reportError, reportDebug } from 'utils/report';\n\nconst namespace = 'engine:utils:geminiFileUpload';\n\nconst fileManager = new GoogleAIFileManager(process.env.GOOGLE_AI_KEY || '');\n\nexport async function geminiFileUpload(\n buffer: Buffer,\n mimeType: string,\n originalName: string\n): Promise<\n | { success: true; originalname: string; fileUri: string; mimeType: string }\n | { success: false; error: unknown }\n> {\n let tempFile;\n try {\n // 1. Create Temp File\n tempFile = tmp.fileSync({ postfix: path.extname(originalName) });\n fs.writeFileSync(tempFile.name, buffer);\n\n // 2. Upload File\n const uploadResult = await fileManager.uploadFile(tempFile.name, {\n mimeType,\n displayName: originalName\n });\n\n if (!uploadResult || !uploadResult.file) {\n throw new Error('Upload failed: No file returned');\n }\n\n const file = uploadResult.file;\n reportDebug({\n namespace,\n message: 'Uploaded file successfully',\n data: { displayName: file.displayName, name: file.name }\n });\n\n reportDebug({\n namespace,\n message: 'Waiting for file processing...'\n });\n\n // 3. Poll Until File is Processed\n let geminiFile = await fileManager.getFile(file.name);\n while (geminiFile?.state === 'PROCESSING') {\n process.stdout.write('.');\n await setTimeoutPromise(10000);\n geminiFile = await fileManager.getFile(file.name);\n }\n\n if (!geminiFile || geminiFile.state !== 'ACTIVE') {\n const errorMessage = `File processing failed for ${file.name}`;\n reportError(errorMessage);\n return { success: false, error: new Error(errorMessage) };\n }\n\n reportDebug({\n namespace,\n message: 'File is ready'\n });\n\n return {\n success: true,\n originalname: file.name,\n fileUri: file.uri,\n mimeType: file.mimeType\n };\n } catch (error) {\n reportError({\n namespace,\n message: 'Error during Gemini file upload and processing',\n error\n });\n return { success: false, error };\n } finally {\n // Ensure cleanup of temp file\n if (tempFile) {\n try {\n tempFile.removeCallback();\n } catch (cleanupError) {\n reportError({\n namespace,\n message: 'Error cleaning up temp file',\n error: cleanupError\n });\n }\n }\n }\n}\n"],"mappings":"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","ignoreList":[]}
@@ -9,9 +9,115 @@ exports.output = output;
9
9
  var _crypto = require("crypto");
10
10
  var _callsite = _interopRequireDefault(require("callsite"));
11
11
  var _jsonStringifySafe = _interopRequireDefault(require("json-stringify-safe"));
12
+ var _const = require("../../const");
12
13
  // NOTE: Server instance id (helpful for distributed logs)
13
14
  const INSTANCE_ID = exports.INSTANCE_ID = (0, _crypto.randomUUID)();
14
15
 
16
+ // ANSI color codes for terminal output
17
+ const colors = {
18
+ reset: '\x1b[0m',
19
+ bright: '\x1b[1m',
20
+ dim: '\x1b[2m',
21
+ red: '\x1b[31m',
22
+ green: '\x1b[32m',
23
+ yellow: '\x1b[33m',
24
+ blue: '\x1b[34m',
25
+ magenta: '\x1b[35m',
26
+ cyan: '\x1b[36m',
27
+ white: '\x1b[37m',
28
+ gray: '\x1b[90m'
29
+ };
30
+
31
+ /**
32
+ * Get color for log severity level
33
+ */
34
+ function getSeverityColor(severity) {
35
+ switch (severity) {
36
+ case _const.LogSeverity.DEBUG:
37
+ return colors.cyan;
38
+ case _const.LogSeverity.INFO:
39
+ return colors.green;
40
+ case _const.LogSeverity.WARNING:
41
+ return colors.yellow;
42
+ case _const.LogSeverity.ERROR:
43
+ return colors.red;
44
+ case _const.LogSeverity.CRITICAL:
45
+ return `${colors.bright}${colors.red}`;
46
+ default:
47
+ return colors.white;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Format log entry for human-readable local development output
53
+ */
54
+ function formatLocalLog(entry) {
55
+ const timestamp = new Date().toISOString();
56
+ const severity = entry.severity || 'INFO';
57
+ const severityColor = getSeverityColor(severity);
58
+ const parts = [];
59
+
60
+ // Timestamp and severity
61
+ parts.push(`${colors.gray}[${timestamp}]${colors.reset} ${severityColor}${severity.padEnd(8)}${colors.reset}`);
62
+
63
+ // File location
64
+ if (entry.fileName) {
65
+ parts.push(`${colors.dim}${entry.fileName}:${entry.lineNumber || '?'}${colors.reset}`);
66
+ }
67
+
68
+ // Message
69
+ if (entry.message) {
70
+ parts.push(`${colors.bright}${entry.message}${colors.reset}`);
71
+ }
72
+ let output = parts.join(' ');
73
+
74
+ // Error details
75
+ if (entry.errorType) {
76
+ output += `\n ${colors.red}Error Type:${colors.reset} ${entry.errorType}`;
77
+ }
78
+ if (entry.errorCode) {
79
+ output += `\n ${colors.red}Error Code:${colors.reset} ${entry.errorCode}`;
80
+ }
81
+ if (entry.statusCode) {
82
+ const statusColor = entry.statusCode >= 500 ? colors.red : entry.statusCode >= 400 ? colors.yellow : colors.green;
83
+ output += `\n ${colors.cyan}Status:${colors.reset} ${statusColor}${entry.statusCode}${colors.reset}`;
84
+ }
85
+
86
+ // Stack trace
87
+ if (entry.stack_trace) {
88
+ output += `\n${colors.gray}Stack Trace:${colors.reset}\n${colors.dim}${entry.stack_trace}${colors.reset}`;
89
+ }
90
+
91
+ // Additional data
92
+ if (entry.data && Object.keys(entry.data).length > 0) {
93
+ output += `\n${colors.cyan}Data:${colors.reset}\n${colors.dim}${JSON.stringify(entry.data, null, 2)}${colors.reset}`;
94
+ }
95
+
96
+ // HTTP request context
97
+ if (entry.context?.httpRequest) {
98
+ const req = entry.context.httpRequest;
99
+ output += `\n${colors.magenta}Request:${colors.reset}`;
100
+ output += `\n ${colors.dim}${req.method} ${req.url}${colors.reset}`;
101
+ if (req.userAgent) {
102
+ output += `\n ${colors.dim}User-Agent: ${req.userAgent}${colors.reset}`;
103
+ }
104
+ if (req.remoteIp) {
105
+ output += `\n ${colors.dim}IP: ${req.remoteIp}${colors.reset}`;
106
+ }
107
+ }
108
+ return output;
109
+ }
110
+
111
+ /**
112
+ * Check if running in local development environment
113
+ */
114
+ function isLocalDevelopment() {
115
+ // Allow forcing local format via environment variable
116
+ if (process.env.LOG_FORMAT === 'local') return true;
117
+ if (process.env.LOG_FORMAT === 'json') return false;
118
+ return process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'dev' || !process.env.NODE_ENV && !process.env.KUBERNETES_POD_NAME && !process.env.CLOUD_RUN_JOB;
119
+ }
120
+
15
121
  /** Add metadata to the log entry and print it */
16
122
  function output(data) {
17
123
  // Gather useful information about where the logger was called from
@@ -29,20 +135,30 @@ function output(data) {
29
135
  instance: process.env.KUBERNETES_POD_NAME ?? INSTANCE_ID
30
136
  }
31
137
  };
32
- const entry = (0, _jsonStringifySafe.default)(fullEntry);
138
+
33
139
  // Ignore when silenced
34
140
  if (process.env.SILENCE_REPORT) return fullEntry;
35
141
  if (process.env.NODE_ENV === 'test') {
36
- // In test mode pretty print
142
+ // In test mode pretty print with full depth
37
143
  console.dir(fullEntry, {
38
144
  depth: 5
39
145
  });
40
- } else if (data.statusCode && data.statusCode >= 500) {
41
- // Log to stderr when it is a 500+ error
42
- console.error(entry);
146
+ } else if (isLocalDevelopment()) {
147
+ // Local development: use formatted, colorized output
148
+ const formattedLog = formatLocalLog(fullEntry);
149
+ if (data.severity === _const.LogSeverity.ERROR || data.severity === _const.LogSeverity.CRITICAL || data.statusCode && data.statusCode >= 500) {
150
+ console.error(formattedLog);
151
+ } else {
152
+ console.log(formattedLog);
153
+ }
43
154
  } else {
44
- // Default to regular logging
45
- console.log(entry);
155
+ // Production/GCP: use JSON format for structured logging
156
+ const entry = (0, _jsonStringifySafe.default)(fullEntry);
157
+ if (data.statusCode && data.statusCode >= 500) {
158
+ console.error(entry);
159
+ } else {
160
+ console.log(entry);
161
+ }
46
162
  }
47
163
  return fullEntry;
48
164
  }
@@ -1 +1 @@
1
- {"version":3,"file":"output.js","names":["_crypto","require","_callsite","_interopRequireDefault","_jsonStringifySafe","INSTANCE_ID","exports","randomUUID","output","data","call","callsite","fullEntry","lineNumber","getLineNumber","fileName","getFileName","replace","serviceContext","service","process","env","CHART","HOSTNAME","version","BUILD_ID","environment","NODE_ENV","instance","KUBERNETES_POD_NAME","entry","stringify","SILENCE_REPORT","console","dir","depth","statusCode","error","log"],"sources":["../../../src/utils/report/output.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport callsite from 'callsite';\nimport stringify from 'json-stringify-safe';\nimport { LogEntry, FullLogEntry } from './output.types';\n\n// NOTE: Server instance id (helpful for distributed logs)\nexport const INSTANCE_ID = randomUUID();\n\n/** Add metadata to the log entry and print it */\nexport function output(data: LogEntry): FullLogEntry {\n // Gather useful information about where the logger was called from\n const call = callsite()[2];\n\n // Append additional metadata to the log entry\n const fullEntry: FullLogEntry = {\n ...data,\n lineNumber: call.getLineNumber(),\n fileName: call\n .getFileName()\n .replace(/.*node_modules\\//, '')\n .replace(/.*src\\//, 'src/'),\n serviceContext: {\n service: process.env.CHART ?? process.env.HOSTNAME,\n version: process.env.BUILD_ID,\n environment: process.env.NODE_ENV,\n instance: process.env.KUBERNETES_POD_NAME ?? INSTANCE_ID\n }\n };\n\n const entry = stringify(fullEntry);\n // Ignore when silenced\n if (process.env.SILENCE_REPORT) return fullEntry;\n\n if (process.env.NODE_ENV === 'test') {\n // In test mode pretty print\n console.dir(fullEntry, { depth: 5 });\n } else if (data.statusCode && data.statusCode >= 500) {\n // Log to stderr when it is a 500+ error\n console.error(entry);\n } else {\n // Default to regular logging\n console.log(entry);\n }\n return fullEntry;\n}\n"],"mappings":";;;;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,SAAA,GAAAC,sBAAA,CAAAF,OAAA;AACA,IAAAG,kBAAA,GAAAD,sBAAA,CAAAF,OAAA;AAGA;AACO,MAAMI,WAAW,GAAAC,OAAA,CAAAD,WAAA,GAAG,IAAAE,kBAAU,EAAC,CAAC;;AAEvC;AACO,SAASC,MAAMA,CAACC,IAAc,EAAgB;EACnD;EACA,MAAMC,IAAI,GAAG,IAAAC,iBAAQ,EAAC,CAAC,CAAC,CAAC,CAAC;;EAE1B;EACA,MAAMC,SAAuB,GAAG;IAC9B,GAAGH,IAAI;IACPI,UAAU,EAAEH,IAAI,CAACI,aAAa,CAAC,CAAC;IAChCC,QAAQ,EAAEL,IAAI,CACXM,WAAW,CAAC,CAAC,CACbC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAC/BA,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;IAC7BC,cAAc,EAAE;MACdC,OAAO,EAAEC,OAAO,CAACC,GAAG,CAACC,KAAK,IAAIF,OAAO,CAACC,GAAG,CAACE,QAAQ;MAClDC,OAAO,EAAEJ,OAAO,CAACC,GAAG,CAACI,QAAQ;MAC7BC,WAAW,EAAEN,OAAO,CAACC,GAAG,CAACM,QAAQ;MACjCC,QAAQ,EAAER,OAAO,CAACC,GAAG,CAACQ,mBAAmB,IAAIxB;IAC/C;EACF,CAAC;EAED,MAAMyB,KAAK,GAAG,IAAAC,0BAAS,EAACnB,SAAS,CAAC;EAClC;EACA,IAAIQ,OAAO,CAACC,GAAG,CAACW,cAAc,EAAE,OAAOpB,SAAS;EAEhD,IAAIQ,OAAO,CAACC,GAAG,CAACM,QAAQ,KAAK,MAAM,EAAE;IACnC;IACAM,OAAO,CAACC,GAAG,CAACtB,SAAS,EAAE;MAAEuB,KAAK,EAAE;IAAE,CAAC,CAAC;EACtC,CAAC,MAAM,IAAI1B,IAAI,CAAC2B,UAAU,IAAI3B,IAAI,CAAC2B,UAAU,IAAI,GAAG,EAAE;IACpD;IACAH,OAAO,CAACI,KAAK,CAACP,KAAK,CAAC;EACtB,CAAC,MAAM;IACL;IACAG,OAAO,CAACK,GAAG,CAACR,KAAK,CAAC;EACpB;EACA,OAAOlB,SAAS;AAClB","ignoreList":[]}
1
+ {"version":3,"file":"output.js","names":["_crypto","require","_callsite","_interopRequireDefault","_jsonStringifySafe","_const","INSTANCE_ID","exports","randomUUID","colors","reset","bright","dim","red","green","yellow","blue","magenta","cyan","white","gray","getSeverityColor","severity","LogSeverity","DEBUG","INFO","WARNING","ERROR","CRITICAL","formatLocalLog","entry","timestamp","Date","toISOString","severityColor","parts","push","padEnd","fileName","lineNumber","message","output","join","errorType","errorCode","statusCode","statusColor","stack_trace","data","Object","keys","length","JSON","stringify","context","httpRequest","req","method","url","userAgent","remoteIp","isLocalDevelopment","process","env","LOG_FORMAT","NODE_ENV","KUBERNETES_POD_NAME","CLOUD_RUN_JOB","call","callsite","fullEntry","getLineNumber","getFileName","replace","serviceContext","service","CHART","HOSTNAME","version","BUILD_ID","environment","instance","SILENCE_REPORT","console","dir","depth","formattedLog","error","log"],"sources":["../../../src/utils/report/output.ts"],"sourcesContent":["import { randomUUID } from 'crypto';\nimport callsite from 'callsite';\nimport stringify from 'json-stringify-safe';\nimport { LogEntry, FullLogEntry } from './output.types';\nimport { LogSeverity } from 'const';\n\n// NOTE: Server instance id (helpful for distributed logs)\nexport const INSTANCE_ID = randomUUID();\n\n// ANSI color codes for terminal output\nconst colors = {\n reset: '\\x1b[0m',\n bright: '\\x1b[1m',\n dim: '\\x1b[2m',\n red: '\\x1b[31m',\n green: '\\x1b[32m',\n yellow: '\\x1b[33m',\n blue: '\\x1b[34m',\n magenta: '\\x1b[35m',\n cyan: '\\x1b[36m',\n white: '\\x1b[37m',\n gray: '\\x1b[90m'\n};\n\n/**\n * Get color for log severity level\n */\nfunction getSeverityColor(severity?: string): string {\n switch (severity) {\n case LogSeverity.DEBUG:\n return colors.cyan;\n case LogSeverity.INFO:\n return colors.green;\n case LogSeverity.WARNING:\n return colors.yellow;\n case LogSeverity.ERROR:\n return colors.red;\n case LogSeverity.CRITICAL:\n return `${colors.bright}${colors.red}`;\n default:\n return colors.white;\n }\n}\n\n/**\n * Format log entry for human-readable local development output\n */\nfunction formatLocalLog(entry: FullLogEntry): string {\n const timestamp = new Date().toISOString();\n const severity = entry.severity || 'INFO';\n const severityColor = getSeverityColor(severity);\n \n const parts: string[] = [];\n \n // Timestamp and severity\n parts.push(\n `${colors.gray}[${timestamp}]${colors.reset} ${severityColor}${severity.padEnd(8)}${colors.reset}`\n );\n \n // File location\n if (entry.fileName) {\n parts.push(`${colors.dim}${entry.fileName}:${entry.lineNumber || '?'}${colors.reset}`);\n }\n \n // Message\n if (entry.message) {\n parts.push(`${colors.bright}${entry.message}${colors.reset}`);\n }\n \n let output = parts.join(' ');\n \n // Error details\n if (entry.errorType) {\n output += `\\n ${colors.red}Error Type:${colors.reset} ${entry.errorType}`;\n }\n \n if (entry.errorCode) {\n output += `\\n ${colors.red}Error Code:${colors.reset} ${entry.errorCode}`;\n }\n \n if (entry.statusCode) {\n const statusColor = entry.statusCode >= 500 ? colors.red : entry.statusCode >= 400 ? colors.yellow : colors.green;\n output += `\\n ${colors.cyan}Status:${colors.reset} ${statusColor}${entry.statusCode}${colors.reset}`;\n }\n \n // Stack trace\n if (entry.stack_trace) {\n output += `\\n${colors.gray}Stack Trace:${colors.reset}\\n${colors.dim}${entry.stack_trace}${colors.reset}`;\n }\n \n // Additional data\n if (entry.data && Object.keys(entry.data).length > 0) {\n output += `\\n${colors.cyan}Data:${colors.reset}\\n${colors.dim}${JSON.stringify(entry.data, null, 2)}${colors.reset}`;\n }\n \n // HTTP request context\n if (entry.context?.httpRequest) {\n const req = entry.context.httpRequest;\n output += `\\n${colors.magenta}Request:${colors.reset}`;\n output += `\\n ${colors.dim}${req.method} ${req.url}${colors.reset}`;\n if (req.userAgent) {\n output += `\\n ${colors.dim}User-Agent: ${req.userAgent}${colors.reset}`;\n }\n if (req.remoteIp) {\n output += `\\n ${colors.dim}IP: ${req.remoteIp}${colors.reset}`;\n }\n }\n \n return output;\n}\n\n/**\n * Check if running in local development environment\n */\nfunction isLocalDevelopment(): boolean {\n // Allow forcing local format via environment variable\n if (process.env.LOG_FORMAT === 'local') return true;\n if (process.env.LOG_FORMAT === 'json') return false;\n \n return (\n process.env.NODE_ENV === 'development' ||\n process.env.NODE_ENV === 'dev' ||\n (!process.env.NODE_ENV && !process.env.KUBERNETES_POD_NAME && !process.env.CLOUD_RUN_JOB)\n );\n}\n\n/** Add metadata to the log entry and print it */\nexport function output(data: LogEntry): FullLogEntry {\n // Gather useful information about where the logger was called from\n const call = callsite()[2];\n\n // Append additional metadata to the log entry\n const fullEntry: FullLogEntry = {\n ...data,\n lineNumber: call.getLineNumber(),\n fileName: call\n .getFileName()\n .replace(/.*node_modules\\//, '')\n .replace(/.*src\\//, 'src/'),\n serviceContext: {\n service: process.env.CHART ?? process.env.HOSTNAME,\n version: process.env.BUILD_ID,\n environment: process.env.NODE_ENV,\n instance: process.env.KUBERNETES_POD_NAME ?? INSTANCE_ID\n }\n };\n\n // Ignore when silenced\n if (process.env.SILENCE_REPORT) return fullEntry;\n\n if (process.env.NODE_ENV === 'test') {\n // In test mode pretty print with full depth\n console.dir(fullEntry, { depth: 5 });\n } else if (isLocalDevelopment()) {\n // Local development: use formatted, colorized output\n const formattedLog = formatLocalLog(fullEntry);\n if (data.severity === LogSeverity.ERROR || data.severity === LogSeverity.CRITICAL || (data.statusCode && data.statusCode >= 500)) {\n console.error(formattedLog);\n } else {\n console.log(formattedLog);\n }\n } else {\n // Production/GCP: use JSON format for structured logging\n const entry = stringify(fullEntry);\n if (data.statusCode && data.statusCode >= 500) {\n console.error(entry);\n } else {\n console.log(entry);\n }\n }\n \n return fullEntry;\n}\n"],"mappings":";;;;;;;;AAAA,IAAAA,OAAA,GAAAC,OAAA;AACA,IAAAC,SAAA,GAAAC,sBAAA,CAAAF,OAAA;AACA,IAAAG,kBAAA,GAAAD,sBAAA,CAAAF,OAAA;AAEA,IAAAI,MAAA,GAAAJ,OAAA;AAEA;AACO,MAAMK,WAAW,GAAAC,OAAA,CAAAD,WAAA,GAAG,IAAAE,kBAAU,EAAC,CAAC;;AAEvC;AACA,MAAMC,MAAM,GAAG;EACbC,KAAK,EAAE,SAAS;EAChBC,MAAM,EAAE,SAAS;EACjBC,GAAG,EAAE,SAAS;EACdC,GAAG,EAAE,UAAU;EACfC,KAAK,EAAE,UAAU;EACjBC,MAAM,EAAE,UAAU;EAClBC,IAAI,EAAE,UAAU;EAChBC,OAAO,EAAE,UAAU;EACnBC,IAAI,EAAE,UAAU;EAChBC,KAAK,EAAE,UAAU;EACjBC,IAAI,EAAE;AACR,CAAC;;AAED;AACA;AACA;AACA,SAASC,gBAAgBA,CAACC,QAAiB,EAAU;EACnD,QAAQA,QAAQ;IACd,KAAKC,kBAAW,CAACC,KAAK;MACpB,OAAOf,MAAM,CAACS,IAAI;IACpB,KAAKK,kBAAW,CAACE,IAAI;MACnB,OAAOhB,MAAM,CAACK,KAAK;IACrB,KAAKS,kBAAW,CAACG,OAAO;MACtB,OAAOjB,MAAM,CAACM,MAAM;IACtB,KAAKQ,kBAAW,CAACI,KAAK;MACpB,OAAOlB,MAAM,CAACI,GAAG;IACnB,KAAKU,kBAAW,CAACK,QAAQ;MACvB,OAAO,GAAGnB,MAAM,CAACE,MAAM,GAAGF,MAAM,CAACI,GAAG,EAAE;IACxC;MACE,OAAOJ,MAAM,CAACU,KAAK;EACvB;AACF;;AAEA;AACA;AACA;AACA,SAASU,cAAcA,CAACC,KAAmB,EAAU;EACnD,MAAMC,SAAS,GAAG,IAAIC,IAAI,CAAC,CAAC,CAACC,WAAW,CAAC,CAAC;EAC1C,MAAMX,QAAQ,GAAGQ,KAAK,CAACR,QAAQ,IAAI,MAAM;EACzC,MAAMY,aAAa,GAAGb,gBAAgB,CAACC,QAAQ,CAAC;EAEhD,MAAMa,KAAe,GAAG,EAAE;;EAE1B;EACAA,KAAK,CAACC,IAAI,CACR,GAAG3B,MAAM,CAACW,IAAI,IAAIW,SAAS,IAAItB,MAAM,CAACC,KAAK,IAAIwB,aAAa,GAAGZ,QAAQ,CAACe,MAAM,CAAC,CAAC,CAAC,GAAG5B,MAAM,CAACC,KAAK,EAClG,CAAC;;EAED;EACA,IAAIoB,KAAK,CAACQ,QAAQ,EAAE;IAClBH,KAAK,CAACC,IAAI,CAAC,GAAG3B,MAAM,CAACG,GAAG,GAAGkB,KAAK,CAACQ,QAAQ,IAAIR,KAAK,CAACS,UAAU,IAAI,GAAG,GAAG9B,MAAM,CAACC,KAAK,EAAE,CAAC;EACxF;;EAEA;EACA,IAAIoB,KAAK,CAACU,OAAO,EAAE;IACjBL,KAAK,CAACC,IAAI,CAAC,GAAG3B,MAAM,CAACE,MAAM,GAAGmB,KAAK,CAACU,OAAO,GAAG/B,MAAM,CAACC,KAAK,EAAE,CAAC;EAC/D;EAEA,IAAI+B,MAAM,GAAGN,KAAK,CAACO,IAAI,CAAC,GAAG,CAAC;;EAE5B;EACA,IAAIZ,KAAK,CAACa,SAAS,EAAE;IACnBF,MAAM,IAAI,OAAOhC,MAAM,CAACI,GAAG,cAAcJ,MAAM,CAACC,KAAK,IAAIoB,KAAK,CAACa,SAAS,EAAE;EAC5E;EAEA,IAAIb,KAAK,CAACc,SAAS,EAAE;IACnBH,MAAM,IAAI,OAAOhC,MAAM,CAACI,GAAG,cAAcJ,MAAM,CAACC,KAAK,IAAIoB,KAAK,CAACc,SAAS,EAAE;EAC5E;EAEA,IAAId,KAAK,CAACe,UAAU,EAAE;IACpB,MAAMC,WAAW,GAAGhB,KAAK,CAACe,UAAU,IAAI,GAAG,GAAGpC,MAAM,CAACI,GAAG,GAAGiB,KAAK,CAACe,UAAU,IAAI,GAAG,GAAGpC,MAAM,CAACM,MAAM,GAAGN,MAAM,CAACK,KAAK;IACjH2B,MAAM,IAAI,OAAOhC,MAAM,CAACS,IAAI,UAAUT,MAAM,CAACC,KAAK,IAAIoC,WAAW,GAAGhB,KAAK,CAACe,UAAU,GAAGpC,MAAM,CAACC,KAAK,EAAE;EACvG;;EAEA;EACA,IAAIoB,KAAK,CAACiB,WAAW,EAAE;IACrBN,MAAM,IAAI,KAAKhC,MAAM,CAACW,IAAI,eAAeX,MAAM,CAACC,KAAK,KAAKD,MAAM,CAACG,GAAG,GAAGkB,KAAK,CAACiB,WAAW,GAAGtC,MAAM,CAACC,KAAK,EAAE;EAC3G;;EAEA;EACA,IAAIoB,KAAK,CAACkB,IAAI,IAAIC,MAAM,CAACC,IAAI,CAACpB,KAAK,CAACkB,IAAI,CAAC,CAACG,MAAM,GAAG,CAAC,EAAE;IACpDV,MAAM,IAAI,KAAKhC,MAAM,CAACS,IAAI,QAAQT,MAAM,CAACC,KAAK,KAAKD,MAAM,CAACG,GAAG,GAAGwC,IAAI,CAACC,SAAS,CAACvB,KAAK,CAACkB,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,GAAGvC,MAAM,CAACC,KAAK,EAAE;EACtH;;EAEA;EACA,IAAIoB,KAAK,CAACwB,OAAO,EAAEC,WAAW,EAAE;IAC9B,MAAMC,GAAG,GAAG1B,KAAK,CAACwB,OAAO,CAACC,WAAW;IACrCd,MAAM,IAAI,KAAKhC,MAAM,CAACQ,OAAO,WAAWR,MAAM,CAACC,KAAK,EAAE;IACtD+B,MAAM,IAAI,OAAOhC,MAAM,CAACG,GAAG,GAAG4C,GAAG,CAACC,MAAM,IAAID,GAAG,CAACE,GAAG,GAAGjD,MAAM,CAACC,KAAK,EAAE;IACpE,IAAI8C,GAAG,CAACG,SAAS,EAAE;MACjBlB,MAAM,IAAI,OAAOhC,MAAM,CAACG,GAAG,eAAe4C,GAAG,CAACG,SAAS,GAAGlD,MAAM,CAACC,KAAK,EAAE;IAC1E;IACA,IAAI8C,GAAG,CAACI,QAAQ,EAAE;MAChBnB,MAAM,IAAI,OAAOhC,MAAM,CAACG,GAAG,OAAO4C,GAAG,CAACI,QAAQ,GAAGnD,MAAM,CAACC,KAAK,EAAE;IACjE;EACF;EAEA,OAAO+B,MAAM;AACf;;AAEA;AACA;AACA;AACA,SAASoB,kBAAkBA,CAAA,EAAY;EACrC;EACA,IAAIC,OAAO,CAACC,GAAG,CAACC,UAAU,KAAK,OAAO,EAAE,OAAO,IAAI;EACnD,IAAIF,OAAO,CAACC,GAAG,CAACC,UAAU,KAAK,MAAM,EAAE,OAAO,KAAK;EAEnD,OACEF,OAAO,CAACC,GAAG,CAACE,QAAQ,KAAK,aAAa,IACtCH,OAAO,CAACC,GAAG,CAACE,QAAQ,KAAK,KAAK,IAC7B,CAACH,OAAO,CAACC,GAAG,CAACE,QAAQ,IAAI,CAACH,OAAO,CAACC,GAAG,CAACG,mBAAmB,IAAI,CAACJ,OAAO,CAACC,GAAG,CAACI,aAAc;AAE7F;;AAEA;AACO,SAAS1B,MAAMA,CAACO,IAAc,EAAgB;EACnD;EACA,MAAMoB,IAAI,GAAG,IAAAC,iBAAQ,EAAC,CAAC,CAAC,CAAC,CAAC;;EAE1B;EACA,MAAMC,SAAuB,GAAG;IAC9B,GAAGtB,IAAI;IACPT,UAAU,EAAE6B,IAAI,CAACG,aAAa,CAAC,CAAC;IAChCjC,QAAQ,EAAE8B,IAAI,CACXI,WAAW,CAAC,CAAC,CACbC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAC/BA,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;IAC7BC,cAAc,EAAE;MACdC,OAAO,EAAEb,OAAO,CAACC,GAAG,CAACa,KAAK,IAAId,OAAO,CAACC,GAAG,CAACc,QAAQ;MAClDC,OAAO,EAAEhB,OAAO,CAACC,GAAG,CAACgB,QAAQ;MAC7BC,WAAW,EAAElB,OAAO,CAACC,GAAG,CAACE,QAAQ;MACjCgB,QAAQ,EAAEnB,OAAO,CAACC,GAAG,CAACG,mBAAmB,IAAI5D;IAC/C;EACF,CAAC;;EAED;EACA,IAAIwD,OAAO,CAACC,GAAG,CAACmB,cAAc,EAAE,OAAOZ,SAAS;EAEhD,IAAIR,OAAO,CAACC,GAAG,CAACE,QAAQ,KAAK,MAAM,EAAE;IACnC;IACAkB,OAAO,CAACC,GAAG,CAACd,SAAS,EAAE;MAAEe,KAAK,EAAE;IAAE,CAAC,CAAC;EACtC,CAAC,MAAM,IAAIxB,kBAAkB,CAAC,CAAC,EAAE;IAC/B;IACA,MAAMyB,YAAY,GAAGzD,cAAc,CAACyC,SAAS,CAAC;IAC9C,IAAItB,IAAI,CAAC1B,QAAQ,KAAKC,kBAAW,CAACI,KAAK,IAAIqB,IAAI,CAAC1B,QAAQ,KAAKC,kBAAW,CAACK,QAAQ,IAAKoB,IAAI,CAACH,UAAU,IAAIG,IAAI,CAACH,UAAU,IAAI,GAAI,EAAE;MAChIsC,OAAO,CAACI,KAAK,CAACD,YAAY,CAAC;IAC7B,CAAC,MAAM;MACLH,OAAO,CAACK,GAAG,CAACF,YAAY,CAAC;IAC3B;EACF,CAAC,MAAM;IACL;IACA,MAAMxD,KAAK,GAAG,IAAAuB,0BAAS,EAACiB,SAAS,CAAC;IAClC,IAAItB,IAAI,CAACH,UAAU,IAAIG,IAAI,CAACH,UAAU,IAAI,GAAG,EAAE;MAC7CsC,OAAO,CAACI,KAAK,CAACzD,KAAK,CAAC;IACtB,CAAC,MAAM;MACLqD,OAAO,CAACK,GAAG,CAAC1D,KAAK,CAAC;IACpB;EACF;EAEA,OAAOwC,SAAS;AAClB","ignoreList":[]}
@@ -7,10 +7,16 @@ import { WebError } from '../../entities/WebError';
7
7
  export declare function reportInfo(data: InfoLogEntry | string): FullLogEntry;
8
8
  /** Error specific logger */
9
9
  export declare function reportError(error: unknown | Error | EngineError | WebError, request?: Request): FullLogEntry;
10
- export declare let NAMESPACE_SELECTORS: undefined | Array<RegExp>;
11
- /** Reset the namespace selectors */
10
+ export declare let NAMESPACE_SELECTORS: Array<RegExp> | undefined;
11
+ /**
12
+ * Reset the namespace selectors
13
+ */
12
14
  export declare function resetNamespaceSelector(): void;
13
- /** Log a message for debugging purpose, based on a namespace specified in an environment variable */
15
+ /**
16
+ * Log a message for debugging purposes, based on a namespace specified in an environment variable
17
+ * @param data - Debug log entry data
18
+ * @returns The full log entry if namespace matches, undefined otherwise
19
+ */
14
20
  export declare function reportDebug(data: DebugLogEntry): FullLogEntry | undefined;
15
21
  export declare namespace reportDebug {
16
22
  var setNameSpace: (globalNamespace: string) => void;
@@ -72,31 +72,43 @@ function reportError(error, request) {
72
72
  }
73
73
  let NAMESPACE_SELECTORS = exports.NAMESPACE_SELECTORS = void 0;
74
74
 
75
- /** Generate the namespace selectors based on the debug variable */
75
+ /**
76
+ * Generate the namespace selectors based on the DEBUG environment variable
77
+ */
76
78
  function initNamespaceSelector() {
77
- if (process.env.DEBUG) exports.NAMESPACE_SELECTORS = NAMESPACE_SELECTORS = process.env.DEBUG.split(',').map(namespace => new RegExp('^' + namespace.replace(/\*/g, '.*?') + '$'));
79
+ if (process.env.DEBUG) {
80
+ exports.NAMESPACE_SELECTORS = NAMESPACE_SELECTORS = process.env.DEBUG.split(',').map(namespace => new RegExp(`^${namespace.replace(/\*/g, '.*?')}$`));
81
+ }
78
82
  }
79
83
 
80
- /** Reset the namespace selectors */
84
+ /**
85
+ * Reset the namespace selectors
86
+ */
81
87
  function resetNamespaceSelector() {
82
88
  exports.NAMESPACE_SELECTORS = NAMESPACE_SELECTORS = undefined;
83
89
  }
84
90
  let debugNamespace;
85
91
 
86
- /** Log a message for debugging purpose, based on a namespace specified in an environment variable */
92
+ /**
93
+ * Log a message for debugging purposes, based on a namespace specified in an environment variable
94
+ * @param data - Debug log entry data
95
+ * @returns The full log entry if namespace matches, undefined otherwise
96
+ */
87
97
  function reportDebug(data) {
88
- if (!NAMESPACE_SELECTORS) initNamespaceSelector();
98
+ if (!NAMESPACE_SELECTORS) {
99
+ initNamespaceSelector();
100
+ }
89
101
  let {
90
102
  namespace
91
103
  } = data;
92
- const isEngineReport = namespace ? namespace.startsWith('engine') : false;
93
- if (debugNamespace && !isEngineReport) {
94
- namespace = debugNamespace + ':' + namespace;
104
+ const isEngineReport = namespace?.startsWith('engine') ?? false;
105
+ if (debugNamespace && !isEngineReport && namespace) {
106
+ namespace = `${debugNamespace}:${namespace}`;
95
107
  }
96
108
  const match = namespace && NAMESPACE_SELECTORS && NAMESPACE_SELECTORS.some(selector => selector.test(namespace));
97
- if (!match) return;
109
+ if (!match) return undefined;
98
110
 
99
- // Generate a prefix with the right most part of the namespace
111
+ // Generate a prefix with the rightmost part of the namespace
100
112
  const spaces = namespace.split(':');
101
113
  const prefix = spaces[spaces.length - 1];
102
114
  return (0, _output.output)({
@@ -106,12 +118,17 @@ function reportDebug(data) {
106
118
  });
107
119
  }
108
120
 
109
- /** Specify a global debugging namespace */
121
+ /**
122
+ * Specify a global debugging namespace
123
+ * @param globalNamespace - The namespace to set globally
124
+ */
110
125
  reportDebug.setNameSpace = function (globalNamespace) {
111
126
  debugNamespace = globalNamespace;
112
127
  };
113
128
 
114
- /** Remove any defined global namespace */
129
+ /**
130
+ * Remove any defined global namespace
131
+ */
115
132
  reportDebug.clearNamespace = function () {
116
133
  debugNamespace = undefined;
117
134
  };
@@ -1 +1 @@
1
- {"version":3,"file":"report.js","names":["_output","require","_const","_EngineError","_WebError","reportInfo","data","output","severity","LogSeverity","INFO","message","reportError","error","request","logEntry","Error","stack_trace","stack","ERROR","CRITICAL","EngineError","errorType","constructor","name","WebError","statusCode","undefined","errorCode","context","user","id","hosts","join","httpRequest","url","originalUrl","method","referrer","header","userAgent","remoteIp","ip","responseStatusCode","NAMESPACE_SELECTORS","exports","initNamespaceSelector","process","env","DEBUG","split","map","namespace","RegExp","replace","resetNamespaceSelector","debugNamespace","reportDebug","isEngineReport","startsWith","match","some","selector","test","spaces","prefix","length","setNameSpace","globalNamespace","clearNamespace"],"sources":["../../../src/utils/report/report.ts"],"sourcesContent":["import { Request } from 'express';\nimport { output } from './output';\nimport { LogEntry, FullLogEntry } from './output.types';\nimport { DebugLogEntry, InfoLogEntry } from './report.types';\nimport { LogSeverity } from 'const';\nimport { EngineError } from 'entities/EngineError';\nimport { WebError } from 'entities/WebError';\nimport {} from 'middleware/authHmac/authHmac.types';\nimport {} from 'middleware/authJwt/authJwt.types';\nimport {} from 'middleware/authTls/authTls.types';\n\n/** Default generic logger */\nexport function reportInfo(data: InfoLogEntry | string): FullLogEntry {\n return output({\n severity: LogSeverity.INFO,\n ...(typeof data === 'string' ? { message: data } : data)\n });\n}\n\n/** Error specific logger */\nexport function reportError(\n error: unknown | Error | EngineError | WebError,\n request?: Request\n): FullLogEntry {\n let logEntry: LogEntry =\n error instanceof Error\n ? {\n message: error.message,\n stack_trace: error.stack,\n severity: LogSeverity.ERROR\n }\n : {\n message: 'An unknown error occurred',\n data: error,\n severity: LogSeverity.CRITICAL\n };\n\n if (error instanceof EngineError) {\n logEntry = {\n ...logEntry,\n severity: error.severity,\n errorType: error.constructor.name,\n data: error.data,\n '@type':\n !(error instanceof WebError) || error.statusCode >= 500\n ? 'type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent'\n : undefined\n };\n }\n\n if (error instanceof WebError) {\n logEntry = {\n ...logEntry,\n errorCode: error.errorCode,\n statusCode: error.statusCode\n };\n }\n\n if (request) {\n logEntry = {\n ...logEntry,\n context: {\n user:\n request.user?.id ?? request.hosts?.join(','),\n httpRequest: {\n url: request.originalUrl,\n method: request.method,\n referrer: request.header('Referer'),\n userAgent: request.header('User-Agent'),\n remoteIp: request.ip,\n responseStatusCode:\n error instanceof WebError ? error.statusCode : undefined\n }\n }\n };\n }\n\n return output(logEntry);\n}\n\nexport let NAMESPACE_SELECTORS: undefined | Array<RegExp>;\n\n/** Generate the namespace selectors based on the debug variable */\nfunction initNamespaceSelector(): void {\n if (process.env.DEBUG)\n NAMESPACE_SELECTORS = process.env.DEBUG.split(',').map(\n (namespace) => new RegExp('^' + namespace.replace(/\\*/g, '.*?') + '$')\n );\n}\n\n/** Reset the namespace selectors */\nexport function resetNamespaceSelector(): void {\n NAMESPACE_SELECTORS = undefined;\n}\n\nlet debugNamespace: string | undefined;\n\n/** Log a message for debugging purpose, based on a namespace specified in an environment variable */\nexport function reportDebug(data: DebugLogEntry): FullLogEntry | undefined {\n if (!NAMESPACE_SELECTORS) initNamespaceSelector();\n let { namespace } = data;\n const isEngineReport = namespace ? namespace.startsWith('engine') : false;\n\n if (debugNamespace && !isEngineReport) {\n namespace = debugNamespace + ':' + namespace;\n }\n\n const match =\n namespace &&\n NAMESPACE_SELECTORS &&\n NAMESPACE_SELECTORS.some((selector) => selector.test(namespace));\n if (!match) return;\n\n // Generate a prefix with the right most part of the namespace\n const spaces = namespace.split(':');\n const prefix = spaces[spaces.length - 1];\n\n return output({\n severity: LogSeverity.DEBUG,\n ...data,\n message: `[${prefix}] ${data.message}`\n });\n}\n\n/** Specify a global debugging namespace */\nreportDebug.setNameSpace = function (globalNamespace: string): void {\n debugNamespace = globalNamespace;\n};\n\n/** Remove any defined global namespace */\nreportDebug.clearNamespace = function (): void {\n debugNamespace = undefined;\n};\n"],"mappings":";;;;;;;;;;AACA,IAAAA,OAAA,GAAAC,OAAA;AAGA,IAAAC,MAAA,GAAAD,OAAA;AACA,IAAAE,YAAA,GAAAF,OAAA;AACA,IAAAG,SAAA,GAAAH,OAAA;AACAA,OAAA;AACAA,OAAA;AACAA,OAAA;AAEA;AACO,SAASI,UAAUA,CAACC,IAA2B,EAAgB;EACpE,OAAO,IAAAC,cAAM,EAAC;IACZC,QAAQ,EAAEC,kBAAW,CAACC,IAAI;IAC1B,IAAI,OAAOJ,IAAI,KAAK,QAAQ,GAAG;MAAEK,OAAO,EAAEL;IAAK,CAAC,GAAGA,IAAI;EACzD,CAAC,CAAC;AACJ;;AAEA;AACO,SAASM,WAAWA,CACzBC,KAA+C,EAC/CC,OAAiB,EACH;EACd,IAAIC,QAAkB,GACpBF,KAAK,YAAYG,KAAK,GAClB;IACEL,OAAO,EAAEE,KAAK,CAACF,OAAO;IACtBM,WAAW,EAAEJ,KAAK,CAACK,KAAK;IACxBV,QAAQ,EAAEC,kBAAW,CAACU;EACxB,CAAC,GACD;IACER,OAAO,EAAE,2BAA2B;IACpCL,IAAI,EAAEO,KAAK;IACXL,QAAQ,EAAEC,kBAAW,CAACW;EACxB,CAAC;EAEP,IAAIP,KAAK,YAAYQ,wBAAW,EAAE;IAChCN,QAAQ,GAAG;MACT,GAAGA,QAAQ;MACXP,QAAQ,EAAEK,KAAK,CAACL,QAAQ;MACxBc,SAAS,EAAET,KAAK,CAACU,WAAW,CAACC,IAAI;MACjClB,IAAI,EAAEO,KAAK,CAACP,IAAI;MAChB,OAAO,EACL,EAAEO,KAAK,YAAYY,kBAAQ,CAAC,IAAIZ,KAAK,CAACa,UAAU,IAAI,GAAG,GACnD,oFAAoF,GACpFC;IACR,CAAC;EACH;EAEA,IAAId,KAAK,YAAYY,kBAAQ,EAAE;IAC7BV,QAAQ,GAAG;MACT,GAAGA,QAAQ;MACXa,SAAS,EAAEf,KAAK,CAACe,SAAS;MAC1BF,UAAU,EAAEb,KAAK,CAACa;IACpB,CAAC;EACH;EAEA,IAAIZ,OAAO,EAAE;IACXC,QAAQ,GAAG;MACT,GAAGA,QAAQ;MACXc,OAAO,EAAE;QACPC,IAAI,EACFhB,OAAO,CAACgB,IAAI,EAAEC,EAAE,IAAIjB,OAAO,CAACkB,KAAK,EAAEC,IAAI,CAAC,GAAG,CAAC;QAC9CC,WAAW,EAAE;UACXC,GAAG,EAAErB,OAAO,CAACsB,WAAW;UACxBC,MAAM,EAAEvB,OAAO,CAACuB,MAAM;UACtBC,QAAQ,EAAExB,OAAO,CAACyB,MAAM,CAAC,SAAS,CAAC;UACnCC,SAAS,EAAE1B,OAAO,CAACyB,MAAM,CAAC,YAAY,CAAC;UACvCE,QAAQ,EAAE3B,OAAO,CAAC4B,EAAE;UACpBC,kBAAkB,EAChB9B,KAAK,YAAYY,kBAAQ,GAAGZ,KAAK,CAACa,UAAU,GAAGC;QACnD;MACF;IACF,CAAC;EACH;EAEA,OAAO,IAAApB,cAAM,EAACQ,QAAQ,CAAC;AACzB;AAEO,IAAI6B,mBAA8C,GAAAC,OAAA,CAAAD,mBAAA;;AAEzD;AACA,SAASE,qBAAqBA,CAAA,EAAS;EACrC,IAAIC,OAAO,CAACC,GAAG,CAACC,KAAK,EACnBJ,OAAA,CAAAD,mBAAA,GAAAA,mBAAmB,GAAGG,OAAO,CAACC,GAAG,CAACC,KAAK,CAACC,KAAK,CAAC,GAAG,CAAC,CAACC,GAAG,CACnDC,SAAS,IAAK,IAAIC,MAAM,CAAC,GAAG,GAAGD,SAAS,CAACE,OAAO,CAAC,KAAK,EAAE,KAAK,CAAC,GAAG,GAAG,CACvE,CAAC;AACL;;AAEA;AACO,SAASC,sBAAsBA,CAAA,EAAS;EAC7CV,OAAA,CAAAD,mBAAA,GAAAA,mBAAmB,GAAGjB,SAAS;AACjC;AAEA,IAAI6B,cAAkC;;AAEtC;AACO,SAASC,WAAWA,CAACnD,IAAmB,EAA4B;EACzE,IAAI,CAACsC,mBAAmB,EAAEE,qBAAqB,CAAC,CAAC;EACjD,IAAI;IAAEM;EAAU,CAAC,GAAG9C,IAAI;EACxB,MAAMoD,cAAc,GAAGN,SAAS,GAAGA,SAAS,CAACO,UAAU,CAAC,QAAQ,CAAC,GAAG,KAAK;EAEzE,IAAIH,cAAc,IAAI,CAACE,cAAc,EAAE;IACrCN,SAAS,GAAGI,cAAc,GAAG,GAAG,GAAGJ,SAAS;EAC9C;EAEA,MAAMQ,KAAK,GACTR,SAAS,IACTR,mBAAmB,IACnBA,mBAAmB,CAACiB,IAAI,CAAEC,QAAQ,IAAKA,QAAQ,CAACC,IAAI,CAACX,SAAS,CAAC,CAAC;EAClE,IAAI,CAACQ,KAAK,EAAE;;EAEZ;EACA,MAAMI,MAAM,GAAGZ,SAAS,CAACF,KAAK,CAAC,GAAG,CAAC;EACnC,MAAMe,MAAM,GAAGD,MAAM,CAACA,MAAM,CAACE,MAAM,GAAG,CAAC,CAAC;EAExC,OAAO,IAAA3D,cAAM,EAAC;IACZC,QAAQ,EAAEC,kBAAW,CAACwC,KAAK;IAC3B,GAAG3C,IAAI;IACPK,OAAO,EAAE,IAAIsD,MAAM,KAAK3D,IAAI,CAACK,OAAO;EACtC,CAAC,CAAC;AACJ;;AAEA;AACA8C,WAAW,CAACU,YAAY,GAAG,UAAUC,eAAuB,EAAQ;EAClEZ,cAAc,GAAGY,eAAe;AAClC,CAAC;;AAED;AACAX,WAAW,CAACY,cAAc,GAAG,YAAkB;EAC7Cb,cAAc,GAAG7B,SAAS;AAC5B,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"report.js","names":["_output","require","_const","_EngineError","_WebError","reportInfo","data","output","severity","LogSeverity","INFO","message","reportError","error","request","logEntry","Error","stack_trace","stack","ERROR","CRITICAL","EngineError","errorType","constructor","name","WebError","statusCode","undefined","errorCode","context","user","id","hosts","join","httpRequest","url","originalUrl","method","referrer","header","userAgent","remoteIp","ip","responseStatusCode","NAMESPACE_SELECTORS","exports","initNamespaceSelector","process","env","DEBUG","split","map","namespace","RegExp","replace","resetNamespaceSelector","debugNamespace","reportDebug","isEngineReport","startsWith","match","some","selector","test","spaces","prefix","length","setNameSpace","globalNamespace","clearNamespace"],"sources":["../../../src/utils/report/report.ts"],"sourcesContent":["import { Request } from 'express';\nimport { output } from './output';\nimport { LogEntry, FullLogEntry } from './output.types';\nimport { DebugLogEntry, InfoLogEntry } from './report.types';\nimport { LogSeverity } from 'const';\nimport { EngineError } from 'entities/EngineError';\nimport { WebError } from 'entities/WebError';\nimport {} from 'middleware/authHmac/authHmac.types';\nimport {} from 'middleware/authJwt/authJwt.types';\nimport {} from 'middleware/authTls/authTls.types';\n\n/** Default generic logger */\nexport function reportInfo(data: InfoLogEntry | string): FullLogEntry {\n return output({\n severity: LogSeverity.INFO,\n ...(typeof data === 'string' ? { message: data } : data)\n });\n}\n\n/** Error specific logger */\nexport function reportError(\n error: unknown | Error | EngineError | WebError,\n request?: Request\n): FullLogEntry {\n let logEntry: LogEntry =\n error instanceof Error\n ? {\n message: error.message,\n stack_trace: error.stack,\n severity: LogSeverity.ERROR\n }\n : {\n message: 'An unknown error occurred',\n data: error,\n severity: LogSeverity.CRITICAL\n };\n\n if (error instanceof EngineError) {\n logEntry = {\n ...logEntry,\n severity: error.severity,\n errorType: error.constructor.name,\n data: error.data,\n '@type':\n !(error instanceof WebError) || error.statusCode >= 500\n ? 'type.googleapis.com/google.devtools.clouderrorreporting.v1beta1.ReportedErrorEvent'\n : undefined\n };\n }\n\n if (error instanceof WebError) {\n logEntry = {\n ...logEntry,\n errorCode: error.errorCode,\n statusCode: error.statusCode\n };\n }\n\n if (request) {\n logEntry = {\n ...logEntry,\n context: {\n user:\n request.user?.id ?? request.hosts?.join(','),\n httpRequest: {\n url: request.originalUrl,\n method: request.method,\n referrer: request.header('Referer'),\n userAgent: request.header('User-Agent'),\n remoteIp: request.ip,\n responseStatusCode:\n error instanceof WebError ? error.statusCode : undefined\n }\n }\n };\n }\n\n return output(logEntry);\n}\n\nexport let NAMESPACE_SELECTORS: Array<RegExp> | undefined;\n\n/**\n * Generate the namespace selectors based on the DEBUG environment variable\n */\nfunction initNamespaceSelector(): void {\n if (process.env.DEBUG) {\n NAMESPACE_SELECTORS = process.env.DEBUG.split(',').map(\n (namespace) => new RegExp(`^${namespace.replace(/\\*/g, '.*?')}$`)\n );\n }\n}\n\n/**\n * Reset the namespace selectors\n */\nexport function resetNamespaceSelector(): void {\n NAMESPACE_SELECTORS = undefined;\n}\n\nlet debugNamespace: string | undefined;\n\n/**\n * Log a message for debugging purposes, based on a namespace specified in an environment variable\n * @param data - Debug log entry data\n * @returns The full log entry if namespace matches, undefined otherwise\n */\nexport function reportDebug(data: DebugLogEntry): FullLogEntry | undefined {\n if (!NAMESPACE_SELECTORS) {\n initNamespaceSelector();\n }\n \n let { namespace } = data;\n const isEngineReport = namespace?.startsWith('engine') ?? false;\n\n if (debugNamespace && !isEngineReport && namespace) {\n namespace = `${debugNamespace}:${namespace}`;\n }\n\n const match =\n namespace &&\n NAMESPACE_SELECTORS &&\n NAMESPACE_SELECTORS.some((selector) => selector.test(namespace));\n \n if (!match) return undefined;\n\n // Generate a prefix with the rightmost part of the namespace\n const spaces = namespace.split(':');\n const prefix = spaces[spaces.length - 1];\n\n return output({\n severity: LogSeverity.DEBUG,\n ...data,\n message: `[${prefix}] ${data.message}`\n });\n}\n\n/**\n * Specify a global debugging namespace\n * @param globalNamespace - The namespace to set globally\n */\nreportDebug.setNameSpace = function (globalNamespace: string): void {\n debugNamespace = globalNamespace;\n};\n\n/**\n * Remove any defined global namespace\n */\nreportDebug.clearNamespace = function (): void {\n debugNamespace = undefined;\n};\n"],"mappings":"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","ignoreList":[]}
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.secretCache = exports.initializeSecrets = void 0;
7
7
  var _secretManager = require("@google-cloud/secret-manager");
8
8
  var _EngineError = require("../../entities/EngineError");
9
+ var _report = require("../report");
9
10
  // Cache to store preloaded secrets
10
11
  const secretCache = exports.secretCache = {};
11
12
  let secretClient;
@@ -16,7 +17,10 @@ let secretClient;
16
17
  */
17
18
  const initializeSecrets = async secretEnvVars => {
18
19
  if (process.env.NODE_ENV !== 'production') {
19
- console.log('Development mode → using local files for secrets');
20
+ (0, _report.reportDebug)({
21
+ namespace: 'engine:secretManager',
22
+ message: 'Development mode → using local files for secrets'
23
+ });
20
24
  return; // No need to preload anything
21
25
  }
22
26
  try {
@@ -1 +1 @@
1
- {"version":3,"file":"secretLoader.js","names":["_secretManager","require","_EngineError","secretCache","exports","secretClient","initializeSecrets","secretEnvVars","process","env","NODE_ENV","console","log","SecretManagerServiceClient","secretNames","filter","name","length","EngineError","message","secretPath","version","accessSecretVersion","payload","data","toString","err"],"sources":["../../../src/utils/secretManager/secretLoader.ts"],"sourcesContent":["import { SecretManagerServiceClient } from '@google-cloud/secret-manager';\nimport { EngineError } from 'entities/EngineError';\n\n// Cache to store preloaded secrets\nexport const secretCache: { [key: string]: string } = {};\nlet secretClient: SecretManagerServiceClient;\n\n/**\n * Initialize the Secret Manager client and preload secrets.\n * @param secretEnvVars List of env var names that contain secret paths\n */\nexport const initializeSecrets = async (\n secretEnvVars: string[]\n): Promise<void> => {\n if (process.env.NODE_ENV !== 'production') {\n console.log('Development mode → using local files for secrets');\n return; // No need to preload anything\n }\n\n try {\n // Default creds (for GCP runtime)\n secretClient = new SecretManagerServiceClient();\n\n const secretNames = secretEnvVars.filter((name) => process.env[name]);\n if (secretNames.length === 0) {\n throw new EngineError({\n message: 'No secret names defined in environment variables'\n });\n }\n\n // Fetch all secrets from GCP Secret Manager\n for (const name of secretNames) {\n const secretPath = process.env[name];\n if (!secretPath) {\n throw new EngineError({\n message: `Secret path for ${name} is not defined`\n });\n }\n\n try {\n const [version] = await secretClient.accessSecretVersion({\n name: secretPath\n });\n const payload = version.payload?.data?.toString('utf-8');\n if (!payload) {\n throw new EngineError({\n message: `Secret ${name} not found or empty`\n });\n }\n secretCache[name] = payload;\n } catch (err) {\n throw new EngineError({\n message: `Error accessing secret ${name}: ${(err as Error).message}`\n });\n }\n }\n } catch (err) {\n throw new EngineError({\n message: `Failed to initialize secrets: ${(err as Error).message}`\n });\n }\n};\n"],"mappings":";;;;;;AAAA,IAAAA,cAAA,GAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AAEA;AACO,MAAME,WAAsC,GAAAC,OAAA,CAAAD,WAAA,GAAG,CAAC,CAAC;AACxD,IAAIE,YAAwC;;AAE5C;AACA;AACA;AACA;AACO,MAAMC,iBAAiB,GAAG,MAC/BC,aAAuB,IACL;EAClB,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,YAAY,EAAE;IACzCC,OAAO,CAACC,GAAG,CAAC,kDAAkD,CAAC;IAC/D,OAAO,CAAC;EACV;EAEA,IAAI;IACF;IACAP,YAAY,GAAG,IAAIQ,yCAA0B,CAAC,CAAC;IAE/C,MAAMC,WAAW,GAAGP,aAAa,CAACQ,MAAM,CAAEC,IAAI,IAAKR,OAAO,CAACC,GAAG,CAACO,IAAI,CAAC,CAAC;IACrE,IAAIF,WAAW,CAACG,MAAM,KAAK,CAAC,EAAE;MAC5B,MAAM,IAAIC,wBAAW,CAAC;QACpBC,OAAO,EAAE;MACX,CAAC,CAAC;IACJ;;IAEA;IACA,KAAK,MAAMH,IAAI,IAAIF,WAAW,EAAE;MAC9B,MAAMM,UAAU,GAAGZ,OAAO,CAACC,GAAG,CAACO,IAAI,CAAC;MACpC,IAAI,CAACI,UAAU,EAAE;QACf,MAAM,IAAIF,wBAAW,CAAC;UACpBC,OAAO,EAAE,mBAAmBH,IAAI;QAClC,CAAC,CAAC;MACJ;MAEA,IAAI;QACF,MAAM,CAACK,OAAO,CAAC,GAAG,MAAMhB,YAAY,CAACiB,mBAAmB,CAAC;UACvDN,IAAI,EAAEI;QACR,CAAC,CAAC;QACF,MAAMG,OAAO,GAAGF,OAAO,CAACE,OAAO,EAAEC,IAAI,EAAEC,QAAQ,CAAC,OAAO,CAAC;QACxD,IAAI,CAACF,OAAO,EAAE;UACZ,MAAM,IAAIL,wBAAW,CAAC;YACpBC,OAAO,EAAE,UAAUH,IAAI;UACzB,CAAC,CAAC;QACJ;QACAb,WAAW,CAACa,IAAI,CAAC,GAAGO,OAAO;MAC7B,CAAC,CAAC,OAAOG,GAAG,EAAE;QACZ,MAAM,IAAIR,wBAAW,CAAC;UACpBC,OAAO,EAAE,0BAA0BH,IAAI,KAAMU,GAAG,CAAWP,OAAO;QACpE,CAAC,CAAC;MACJ;IACF;EACF,CAAC,CAAC,OAAOO,GAAG,EAAE;IACZ,MAAM,IAAIR,wBAAW,CAAC;MACpBC,OAAO,EAAE,iCAAkCO,GAAG,CAAWP,OAAO;IAClE,CAAC,CAAC;EACJ;AACF,CAAC;AAACf,OAAA,CAAAE,iBAAA,GAAAA,iBAAA","ignoreList":[]}
1
+ {"version":3,"file":"secretLoader.js","names":["_secretManager","require","_EngineError","_report","secretCache","exports","secretClient","initializeSecrets","secretEnvVars","process","env","NODE_ENV","reportDebug","namespace","message","SecretManagerServiceClient","secretNames","filter","name","length","EngineError","secretPath","version","accessSecretVersion","payload","data","toString","err"],"sources":["../../../src/utils/secretManager/secretLoader.ts"],"sourcesContent":["import { SecretManagerServiceClient } from '@google-cloud/secret-manager';\nimport { EngineError } from 'entities/EngineError';\nimport { reportDebug } from 'utils/report';\n\n// Cache to store preloaded secrets\nexport const secretCache: { [key: string]: string } = {};\nlet secretClient: SecretManagerServiceClient;\n\n/**\n * Initialize the Secret Manager client and preload secrets.\n * @param secretEnvVars List of env var names that contain secret paths\n */\nexport const initializeSecrets = async (\n secretEnvVars: string[]\n): Promise<void> => {\n if (process.env.NODE_ENV !== 'production') {\n reportDebug({\n namespace: 'engine:secretManager',\n message: 'Development mode → using local files for secrets'\n });\n return; // No need to preload anything\n }\n\n try {\n // Default creds (for GCP runtime)\n secretClient = new SecretManagerServiceClient();\n\n const secretNames = secretEnvVars.filter((name) => process.env[name]);\n if (secretNames.length === 0) {\n throw new EngineError({\n message: 'No secret names defined in environment variables'\n });\n }\n\n // Fetch all secrets from GCP Secret Manager\n for (const name of secretNames) {\n const secretPath = process.env[name];\n if (!secretPath) {\n throw new EngineError({\n message: `Secret path for ${name} is not defined`\n });\n }\n\n try {\n const [version] = await secretClient.accessSecretVersion({\n name: secretPath\n });\n const payload = version.payload?.data?.toString('utf-8');\n if (!payload) {\n throw new EngineError({\n message: `Secret ${name} not found or empty`\n });\n }\n secretCache[name] = payload;\n } catch (err) {\n throw new EngineError({\n message: `Error accessing secret ${name}: ${(err as Error).message}`\n });\n }\n }\n } catch (err) {\n throw new EngineError({\n message: `Failed to initialize secrets: ${(err as Error).message}`\n });\n }\n};\n"],"mappings":";;;;;;AAAA,IAAAA,cAAA,GAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AAEA;AACO,MAAMG,WAAsC,GAAAC,OAAA,CAAAD,WAAA,GAAG,CAAC,CAAC;AACxD,IAAIE,YAAwC;;AAE5C;AACA;AACA;AACA;AACO,MAAMC,iBAAiB,GAAG,MAC/BC,aAAuB,IACL;EAClB,IAAIC,OAAO,CAACC,GAAG,CAACC,QAAQ,KAAK,YAAY,EAAE;IACzC,IAAAC,mBAAW,EAAC;MACVC,SAAS,EAAE,sBAAsB;MACjCC,OAAO,EAAE;IACX,CAAC,CAAC;IACF,OAAO,CAAC;EACV;EAEA,IAAI;IACF;IACAR,YAAY,GAAG,IAAIS,yCAA0B,CAAC,CAAC;IAE/C,MAAMC,WAAW,GAAGR,aAAa,CAACS,MAAM,CAAEC,IAAI,IAAKT,OAAO,CAACC,GAAG,CAACQ,IAAI,CAAC,CAAC;IACrE,IAAIF,WAAW,CAACG,MAAM,KAAK,CAAC,EAAE;MAC5B,MAAM,IAAIC,wBAAW,CAAC;QACpBN,OAAO,EAAE;MACX,CAAC,CAAC;IACJ;;IAEA;IACA,KAAK,MAAMI,IAAI,IAAIF,WAAW,EAAE;MAC9B,MAAMK,UAAU,GAAGZ,OAAO,CAACC,GAAG,CAACQ,IAAI,CAAC;MACpC,IAAI,CAACG,UAAU,EAAE;QACf,MAAM,IAAID,wBAAW,CAAC;UACpBN,OAAO,EAAE,mBAAmBI,IAAI;QAClC,CAAC,CAAC;MACJ;MAEA,IAAI;QACF,MAAM,CAACI,OAAO,CAAC,GAAG,MAAMhB,YAAY,CAACiB,mBAAmB,CAAC;UACvDL,IAAI,EAAEG;QACR,CAAC,CAAC;QACF,MAAMG,OAAO,GAAGF,OAAO,CAACE,OAAO,EAAEC,IAAI,EAAEC,QAAQ,CAAC,OAAO,CAAC;QACxD,IAAI,CAACF,OAAO,EAAE;UACZ,MAAM,IAAIJ,wBAAW,CAAC;YACpBN,OAAO,EAAE,UAAUI,IAAI;UACzB,CAAC,CAAC;QACJ;QACAd,WAAW,CAACc,IAAI,CAAC,GAAGM,OAAO;MAC7B,CAAC,CAAC,OAAOG,GAAG,EAAE;QACZ,MAAM,IAAIP,wBAAW,CAAC;UACpBN,OAAO,EAAE,0BAA0BI,IAAI,KAAMS,GAAG,CAAWb,OAAO;QACpE,CAAC,CAAC;MACJ;IACF;EACF,CAAC,CAAC,OAAOa,GAAG,EAAE;IACZ,MAAM,IAAIP,wBAAW,CAAC;MACpBN,OAAO,EAAE,iCAAkCa,GAAG,CAAWb,OAAO;IAClE,CAAC,CAAC;EACJ;AACF,CAAC;AAACT,OAAA,CAAAE,iBAAA,GAAAA,iBAAA","ignoreList":[]}
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Comparison function for our SemVer strings, includes support ofr pre-releases
3
- * @param {string} v1
4
- * @param {string} v2
5
- * @return {number} - -1 if v1 < v2, 0 if v1 = v2, +1 if v1 > v2
2
+ * Comparison function for our SemVer strings, includes support for pre-releases
3
+ * @param v1 - First version string to compare
4
+ * @param v2 - Second version string to compare
5
+ * @returns -1 if v1 < v2, 0 if v1 = v2, +1 if v1 > v2
6
6
  */
7
7
  export declare function semverCompare(v1: string, v2: string): 1 | -1 | 0;
@@ -11,23 +11,25 @@ var _EngineError = require("../../entities/EngineError");
11
11
  const SEMVER_REGEX = /^v?(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(?:(alpha|beta|rc)(?:\.(0|[1-9]\d*))))?$/;
12
12
 
13
13
  /**
14
- * Comparison function for our SemVer strings, includes support ofr pre-releases
15
- * @param {string} v1
16
- * @param {string} v2
17
- * @return {number} - -1 if v1 < v2, 0 if v1 = v2, +1 if v1 > v2
14
+ * Comparison function for our SemVer strings, includes support for pre-releases
15
+ * @param v1 - First version string to compare
16
+ * @param v2 - Second version string to compare
17
+ * @returns -1 if v1 < v2, 0 if v1 = v2, +1 if v1 > v2
18
18
  */
19
19
  function semverCompare(v1, v2) {
20
20
  const [match1, match2] = [v1, v2].map(v => v.match(SEMVER_REGEX));
21
- if (!match1 || !match2) throw new _EngineError.EngineError({
22
- message: 'Provided invalid SemVer string, can not compare',
23
- data: {
24
- v1,
25
- v2
26
- }
27
- });
28
- const [[_1, major1, minor1, patch1, preType1, preVersion1], [_2, major2, minor2, patch2, preType2, preVersion2]] = [match1, match2].map(group =>
29
- // We parse to int the parts that can be
30
- group.map(item => item && _validator.default.isInt(item) ? parseInt(item) : item));
21
+ if (!match1 || !match2) {
22
+ throw new _EngineError.EngineError({
23
+ message: 'Provided invalid SemVer string, cannot compare',
24
+ data: {
25
+ v1,
26
+ v2
27
+ }
28
+ });
29
+ }
30
+ const [[, major1, minor1, patch1, preType1, preVersion1], [, major2, minor2, patch2, preType2, preVersion2]] = [match1, match2].map(group =>
31
+ // Parse numeric values
32
+ group.map(item => item && _validator.default.isInt(item) ? parseInt(item, 10) : item));
31
33
 
32
34
  // Compare majors first
33
35
  if (major1 < major2) return -1;
@@ -1 +1 @@
1
- {"version":3,"file":"semverCompare.js","names":["_validator","_interopRequireDefault","require","_EngineError","SEMVER_REGEX","semverCompare","v1","v2","match1","match2","map","v","match","EngineError","message","data","_1","major1","minor1","patch1","preType1","preVersion1","_2","major2","minor2","patch2","preType2","preVersion2","group","item","validator","isInt","parseInt"],"sources":["../../../src/utils/semverCompare/semverCompare.ts"],"sourcesContent":["import validator from 'validator';\nimport { EngineError } from 'entities/EngineError';\n\n// Regex to validate our SemVer style and capture the different parts\nconst SEMVER_REGEX =\n /^v?(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-(?:(alpha|beta|rc)(?:\\.(0|[1-9]\\d*))))?$/;\n\n/**\n * Comparison function for our SemVer strings, includes support ofr pre-releases\n * @param {string} v1\n * @param {string} v2\n * @return {number} - -1 if v1 < v2, 0 if v1 = v2, +1 if v1 > v2\n */\nexport function semverCompare(v1: string, v2: string): 1 | -1 | 0 {\n const [match1, match2] = [v1, v2].map((v) => v.match(SEMVER_REGEX));\n if (!match1 || !match2)\n throw new EngineError({\n message: 'Provided invalid SemVer string, can not compare',\n data: { v1, v2 }\n });\n const [\n \n [_1, major1, minor1, patch1, preType1, preVersion1],\n \n [_2, major2, minor2, patch2, preType2, preVersion2]\n ] = [match1, match2].map((group) =>\n // We parse to int the parts that can be\n group.map((item) => (item && validator.isInt(item) ? parseInt(item) : item))\n );\n\n // Compare majors first\n if (major1 < major2) return -1;\n if (major1 > major2) return 1;\n\n // Compare minors second\n if (minor1 < minor2) return -1;\n if (minor1 > minor2) return 1;\n\n // Compare patch third\n if (patch1 < patch2) return -1;\n if (patch1 > patch2) return 1;\n\n // Compare pre-release type\n // Release > pre-release\n if (!preType1 && !preType2) return 0;\n if (preType1 && !preType2) return -1;\n if (!preType1 && preType2) return 1;\n\n // RC > Beta > Alpha\n if (preType1 !== 'rc' && preType2 === 'rc') return -1;\n if (preType1 === 'rc' && preType2 !== 'rc') return 1;\n if (preType1 !== 'beta' && preType2 === 'beta') return -1;\n if (preType1 === 'beta' && preType2 !== 'beta') return 1;\n\n // Finally compare the pre-release versions\n if (preVersion1 < preVersion2) return -1;\n if (preVersion1 > preVersion2) return 1;\n\n return 0;\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,UAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AAEA;AACA,MAAME,YAAY,GAChB,yFAAyF;;AAE3F;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,aAAaA,CAACC,EAAU,EAAEC,EAAU,EAAc;EAChE,MAAM,CAACC,MAAM,EAAEC,MAAM,CAAC,GAAG,CAACH,EAAE,EAAEC,EAAE,CAAC,CAACG,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACC,KAAK,CAACR,YAAY,CAAC,CAAC;EACnE,IAAI,CAACI,MAAM,IAAI,CAACC,MAAM,EACpB,MAAM,IAAII,wBAAW,CAAC;IACpBC,OAAO,EAAE,iDAAiD;IAC1DC,IAAI,EAAE;MAAET,EAAE;MAAEC;IAAG;EACjB,CAAC,CAAC;EACJ,MAAM,CAEJ,CAACS,EAAE,EAAEC,MAAM,EAAEC,MAAM,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,WAAW,CAAC,EAEnD,CAACC,EAAE,EAAEC,MAAM,EAAEC,MAAM,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,WAAW,CAAC,CACpD,GAAG,CAACnB,MAAM,EAAEC,MAAM,CAAC,CAACC,GAAG,CAAEkB,KAAK;EAC7B;EACAA,KAAK,CAAClB,GAAG,CAAEmB,IAAI,IAAMA,IAAI,IAAIC,kBAAS,CAACC,KAAK,CAACF,IAAI,CAAC,GAAGG,QAAQ,CAACH,IAAI,CAAC,GAAGA,IAAK,CAC7E,CAAC;;EAED;EACA,IAAIZ,MAAM,GAAGM,MAAM,EAAE,OAAO,CAAC,CAAC;EAC9B,IAAIN,MAAM,GAAGM,MAAM,EAAE,OAAO,CAAC;;EAE7B;EACA,IAAIL,MAAM,GAAGM,MAAM,EAAE,OAAO,CAAC,CAAC;EAC9B,IAAIN,MAAM,GAAGM,MAAM,EAAE,OAAO,CAAC;;EAE7B;EACA,IAAIL,MAAM,GAAGM,MAAM,EAAE,OAAO,CAAC,CAAC;EAC9B,IAAIN,MAAM,GAAGM,MAAM,EAAE,OAAO,CAAC;;EAE7B;EACA;EACA,IAAI,CAACL,QAAQ,IAAI,CAACM,QAAQ,EAAE,OAAO,CAAC;EACpC,IAAIN,QAAQ,IAAI,CAACM,QAAQ,EAAE,OAAO,CAAC,CAAC;EACpC,IAAI,CAACN,QAAQ,IAAIM,QAAQ,EAAE,OAAO,CAAC;;EAEnC;EACA,IAAIN,QAAQ,KAAK,IAAI,IAAIM,QAAQ,KAAK,IAAI,EAAE,OAAO,CAAC,CAAC;EACrD,IAAIN,QAAQ,KAAK,IAAI,IAAIM,QAAQ,KAAK,IAAI,EAAE,OAAO,CAAC;EACpD,IAAIN,QAAQ,KAAK,MAAM,IAAIM,QAAQ,KAAK,MAAM,EAAE,OAAO,CAAC,CAAC;EACzD,IAAIN,QAAQ,KAAK,MAAM,IAAIM,QAAQ,KAAK,MAAM,EAAE,OAAO,CAAC;;EAExD;EACA,IAAIL,WAAW,GAAGM,WAAW,EAAE,OAAO,CAAC,CAAC;EACxC,IAAIN,WAAW,GAAGM,WAAW,EAAE,OAAO,CAAC;EAEvC,OAAO,CAAC;AACV","ignoreList":[]}
1
+ {"version":3,"file":"semverCompare.js","names":["_validator","_interopRequireDefault","require","_EngineError","SEMVER_REGEX","semverCompare","v1","v2","match1","match2","map","v","match","EngineError","message","data","major1","minor1","patch1","preType1","preVersion1","major2","minor2","patch2","preType2","preVersion2","group","item","validator","isInt","parseInt"],"sources":["../../../src/utils/semverCompare/semverCompare.ts"],"sourcesContent":["import validator from 'validator';\nimport { EngineError } from 'entities/EngineError';\n\n// Regex to validate our SemVer style and capture the different parts\nconst SEMVER_REGEX =\n /^v?(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-(?:(alpha|beta|rc)(?:\\.(0|[1-9]\\d*))))?$/;\n\n/**\n * Comparison function for our SemVer strings, includes support for pre-releases\n * @param v1 - First version string to compare\n * @param v2 - Second version string to compare\n * @returns -1 if v1 < v2, 0 if v1 = v2, +1 if v1 > v2\n */\nexport function semverCompare(v1: string, v2: string): 1 | -1 | 0 {\n const [match1, match2] = [v1, v2].map((v) => v.match(SEMVER_REGEX));\n \n if (!match1 || !match2) {\n throw new EngineError({\n message: 'Provided invalid SemVer string, cannot compare',\n data: { v1, v2 }\n });\n }\n\n const [\n [, major1, minor1, patch1, preType1, preVersion1],\n [, major2, minor2, patch2, preType2, preVersion2]\n ] = [match1, match2].map((group) =>\n // Parse numeric values\n group.map((item) => (item && validator.isInt(item) ? parseInt(item, 10) : item))\n );\n\n // Compare majors first\n if (major1 < major2) return -1;\n if (major1 > major2) return 1;\n\n // Compare minors second\n if (minor1 < minor2) return -1;\n if (minor1 > minor2) return 1;\n\n // Compare patch third\n if (patch1 < patch2) return -1;\n if (patch1 > patch2) return 1;\n\n // Compare pre-release type\n // Release > pre-release\n if (!preType1 && !preType2) return 0;\n if (preType1 && !preType2) return -1;\n if (!preType1 && preType2) return 1;\n\n // RC > Beta > Alpha\n if (preType1 !== 'rc' && preType2 === 'rc') return -1;\n if (preType1 === 'rc' && preType2 !== 'rc') return 1;\n if (preType1 !== 'beta' && preType2 === 'beta') return -1;\n if (preType1 === 'beta' && preType2 !== 'beta') return 1;\n\n // Finally compare the pre-release versions\n if (preVersion1 < preVersion2) return -1;\n if (preVersion1 > preVersion2) return 1;\n\n return 0;\n}\n"],"mappings":";;;;;;;AAAA,IAAAA,UAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,YAAA,GAAAD,OAAA;AAEA;AACA,MAAME,YAAY,GAChB,yFAAyF;;AAE3F;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,aAAaA,CAACC,EAAU,EAAEC,EAAU,EAAc;EAChE,MAAM,CAACC,MAAM,EAAEC,MAAM,CAAC,GAAG,CAACH,EAAE,EAAEC,EAAE,CAAC,CAACG,GAAG,CAAEC,CAAC,IAAKA,CAAC,CAACC,KAAK,CAACR,YAAY,CAAC,CAAC;EAEnE,IAAI,CAACI,MAAM,IAAI,CAACC,MAAM,EAAE;IACtB,MAAM,IAAII,wBAAW,CAAC;MACpBC,OAAO,EAAE,gDAAgD;MACzDC,IAAI,EAAE;QAAET,EAAE;QAAEC;MAAG;IACjB,CAAC,CAAC;EACJ;EAEA,MAAM,CACJ,GAAGS,MAAM,EAAEC,MAAM,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,WAAW,CAAC,EACjD,GAAGC,MAAM,EAAEC,MAAM,EAAEC,MAAM,EAAEC,QAAQ,EAAEC,WAAW,CAAC,CAClD,GAAG,CAACjB,MAAM,EAAEC,MAAM,CAAC,CAACC,GAAG,CAAEgB,KAAK;EAC7B;EACAA,KAAK,CAAChB,GAAG,CAAEiB,IAAI,IAAMA,IAAI,IAAIC,kBAAS,CAACC,KAAK,CAACF,IAAI,CAAC,GAAGG,QAAQ,CAACH,IAAI,EAAE,EAAE,CAAC,GAAGA,IAAK,CACjF,CAAC;;EAED;EACA,IAAIX,MAAM,GAAGK,MAAM,EAAE,OAAO,CAAC,CAAC;EAC9B,IAAIL,MAAM,GAAGK,MAAM,EAAE,OAAO,CAAC;;EAE7B;EACA,IAAIJ,MAAM,GAAGK,MAAM,EAAE,OAAO,CAAC,CAAC;EAC9B,IAAIL,MAAM,GAAGK,MAAM,EAAE,OAAO,CAAC;;EAE7B;EACA,IAAIJ,MAAM,GAAGK,MAAM,EAAE,OAAO,CAAC,CAAC;EAC9B,IAAIL,MAAM,GAAGK,MAAM,EAAE,OAAO,CAAC;;EAE7B;EACA;EACA,IAAI,CAACJ,QAAQ,IAAI,CAACK,QAAQ,EAAE,OAAO,CAAC;EACpC,IAAIL,QAAQ,IAAI,CAACK,QAAQ,EAAE,OAAO,CAAC,CAAC;EACpC,IAAI,CAACL,QAAQ,IAAIK,QAAQ,EAAE,OAAO,CAAC;;EAEnC;EACA,IAAIL,QAAQ,KAAK,IAAI,IAAIK,QAAQ,KAAK,IAAI,EAAE,OAAO,CAAC,CAAC;EACrD,IAAIL,QAAQ,KAAK,IAAI,IAAIK,QAAQ,KAAK,IAAI,EAAE,OAAO,CAAC;EACpD,IAAIL,QAAQ,KAAK,MAAM,IAAIK,QAAQ,KAAK,MAAM,EAAE,OAAO,CAAC,CAAC;EACzD,IAAIL,QAAQ,KAAK,MAAM,IAAIK,QAAQ,KAAK,MAAM,EAAE,OAAO,CAAC;;EAExD;EACA,IAAIJ,WAAW,GAAGK,WAAW,EAAE,OAAO,CAAC,CAAC;EACxC,IAAIL,WAAW,GAAGK,WAAW,EAAE,OAAO,CAAC;EAEvC,OAAO,CAAC;AACV","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-server-engine",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Framework used to develop backend services. This package ships with a lot of features to standardize the creation of services, letting you focus on the business logic.",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {